source: trunk/athena/bin/discuss/server/rpproc.c @ 23922

Revision 23922, 11.5 KB checked in by broder, 15 years ago (diff)
In discuss: * Patch discuss server to work without krb4. Patch by Mitch Berger.
Line 
1/*
2 *
3 *      Copyright (C) 1988, 1989 by the Massachusetts Institute of Technology
4 *      Developed by the MIT Student Information Processing Board (SIPB).
5 *      For copying information, see the file mit-copyright.h in this release.
6 *
7 */
8/*
9 *
10 *  rpproc.c -- Procedures to implement a simple (perhaps brain-asleep) RPC
11 *              protocol over a TCP connection.
12 *              This file handles the server's side of the connection.
13 *
14 */
15
16/*
17 *
18 *      $Id: rpproc.c,v 1.23 2007-08-09 20:41:33 amb Exp $
19 *
20 */
21
22
23#ifdef NOKERBEROS
24#undef HAVE_KRB4
25#undef HAVE_KRB5
26#endif /* NOKERBEROS */
27
28#ifdef INETD
29#define ASSOC 1
30#endif
31
32#ifdef SUBPROC
33#define ASSOC 1
34#endif
35
36/* Includes */
37
38#include <sys/ioctl.h>
39#if HAVE_FCNTL_H
40#include <fcntl.h>
41#endif
42#include <sys/types.h>
43#include <sys/socket.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <netinet/in.h>
47#include <sys/stat.h>
48#include <netdb.h>
49#include <errno.h>
50#include <pwd.h>
51#include <string.h>
52#ifdef HAVE_KRB4
53#include <krb.h>
54#endif
55#ifdef HAVE_KRB5
56#include <krb5.h>
57#endif
58#include <discuss/tfile.h>
59#include "rpc.h"
60#include <discuss/types.h>
61#include "config.h"
62
63#define SUCCESS 1
64#define ERROR   -1
65#define min(a, b) (a < b ? a : b)
66
67/* When both krb4 and krb5 are available, the server will try to
68 * authenticate clients with krb5 and then fall back to krb4.  To
69 * avoid writing entirely separate code for the case where krb4 is
70 * not available, we fake some of the constants and data structures.
71 */
72#ifndef HAVE_KRB4
73#define ANAME_SZ      40
74#define REALM_SZ      40
75#define INST_SZ       40
76#define MAX_KTXT_LEN  1250
77#define MAX_K_NAME_SZ (ANAME_SZ + INST_SZ + REALM_SZ + 2)
78struct ktext {
79    int length;
80    unsigned char dat[MAX_KTXT_LEN];
81    unsigned long mbz;
82};
83typedef struct ktext KTEXT_ST;
84struct partial_auth_dat { /* Just enough of the struct for our purposes */
85    char pname[ANAME_SZ];
86    char pinst[INST_SZ];
87    char prealm[REALM_SZ];
88};
89typedef struct partial_auth_dat AUTH_DAT;
90#endif /* HAVE_KRB4 */
91
92/* global */
93#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
94char rpc_caller[MAX_K_NAME_SZ + 1];
95#else
96char rpc_caller[50];
97#endif /* HAVE_KRB4 || HAVE_KRB5 */
98static long hostaddr;
99
100extern int numprocs;
101extern struct proc_table procs [];
102#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
103static char serv_name[20];
104#endif /* HAVE_KRB4 || HAVE_KRB5 */
105short recvshort();
106int rpc_err;
107extern tfile net_tfile ();
108
109/* Static variables */
110
111/* connections & socket info */
112static USPStream *us = NULL;
113
114/*
115 *
116 * init_rpc () -- Initialize the RPC mechanism
117 *
118 */
119init_rpc (service,code)
120    char *service;
121    int *code;
122{
123#ifdef INETD
124    int d;
125#endif
126    int snew;                   /* socket we're reading from */
127   
128#ifdef SUBPROC
129    int uid;
130    struct passwd *pwent;
131#endif
132   
133#ifndef ASSOC
134    struct protoent *pe;
135    struct servent *se;
136    struct sockaddr_in sai;
137    int sock_len = sizeof (sai);
138    int s;
139#endif
140   
141#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
142    int fromlen,i;
143    struct sockaddr_in from;
144    char hostname[50];
145    struct hostent *hp;
146    USPCardinal bt;
147#endif /* HAVE_KRB4 || HAVE_KRB5 */
148
149#if defined(__APPLE__) && defined(__MACH__)
150    add_error_table(&et_rpc_error_table);
151#else
152    initialize_rpc_error_table();
153#endif
154
155#ifdef INETD
156    d = open ("/dev/null", 2);
157    dup2(d, 1);
158    dup2(d, 2);
159    close(d);
160    if (geteuid() == 0)
161        panic ("Can't run as root."); /* just in case setuid bit off */
162#endif
163   
164#ifdef ASSOC
165    /* safety check -- 0 better be a socket, not a pipe or file */
166    {
167        if (isatty (0)) {
168            *code = RPC_NOT_SUBPROC;
169            return;
170        }
171    }
172
173#ifdef SUBPROC
174    {
175        int s;
176        for (s = 1; s < 10; s++)
177            (void) close (s);
178    }
179    {
180        int fd;
181        fd = open("/dev/null", 2);
182        if (fd != 1) {
183            (void) dup2 (fd, 1);
184            (void) close (fd);
185        }
186        (void) dup2(1, 2);
187    }
188    {
189        setpgrp(0, getpid());           /* So we don't get tty signals */
190    }
191#endif
192   
193    snew = 0;
194    us = USP_associate (snew);
195#else   
196    /* to be added */
197    setprotoent(0);                         /* get protocol information */
198    pe = getprotobyname("tcp");
199    setservent(0);                          /* get service information */
200   
201    se = getservbyname(SERVICE_NAME, "tcp");
202    sai.sin_addr.s_addr = INADDR_ANY;
203    sai.sin_port = (se) ? se->s_port : htons(DISCUSS_FALLBACK_PORT);
204                                            /* set up socket */
205    if((s = socket(AF_INET, SOCK_STREAM, pe->p_proto)) < 0) {
206        *code = errno;
207        return;
208    }
209    if(bind(s, (struct sockaddr *)&sai, sizeof(sai))) {  /* bind service name */
210        *code = errno;
211        return;
212    }   
213    listen(s, SOMAXCONN);               /* listen for connection */
214    if((snew = accept(s, (struct sockaddr *)&sai, &sock_len)) < 0) {
215                                        /* accept connection */
216        *code = errno;
217        return;
218    }
219   
220    us = USP_associate (snew);
221    if (us == NULL) {
222        *code = errno;
223        return;
224    }
225#endif
226   
227    strcpy (rpc_caller, "???");         /* safety drop */
228   
229#ifdef SUBPROC
230    uid = getuid ();
231    pwent = getpwuid(uid);
232    if (pwent != 0) {
233        strcpy (rpc_caller, pwent -> pw_name);
234    }
235#endif
236    strcat (rpc_caller, "@");
237    strcat (rpc_caller, REALM);
238   
239#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
240
241    strcpy(serv_name, service);
242    fromlen = sizeof (from);
243    if (getpeername (snew, (struct sockaddr *)&from, &fromlen) < 0) {
244        *code = errno;
245        return;
246    }
247    if (fromlen == 0) {         /* no len, UNIX domain = me */
248        gethostname(hostname, sizeof(hostname));
249        hp = gethostbyname(hostname);
250        memcpy(&hostaddr, hp -> h_addr,  4);
251    } else {
252        memcpy(&hostaddr, &from.sin_addr, 4);
253    }
254
255   
256    if ((USP_rcv_blk(us, &bt) != SUCCESS) || (bt != KRB_TICKET &&
257                                              bt != KRB_TICKET2)) {
258        *code = RPC_PROTOCOL;
259        return;
260    }
261   
262    handle_kerberos(bt,serv_name,hostaddr);
263#endif /* HAVE_KRB4 || HAVE_KRB5 */
264    *code = 0;
265    return;
266}
267
268#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
269handle_kerberos(bt,service,haddr)
270USPCardinal bt;
271char *service;
272long haddr;
273{
274    int i,result;
275    char hostname[50];
276    char filename[50];
277    char instance[INST_SZ];
278    AUTH_DAT kdata;
279    KTEXT_ST ticket;
280
281#ifdef HAVE_KRB5
282    char *envvar;
283    krb5_context context;
284    krb5_auth_context auth_context = NULL;
285    krb5_data packet;
286    krb5_principal sprinc;
287    krb5_keytab keytab = NULL;
288    krb5_ticket *processed_ticket = NULL;
289#endif /* HAVE_KRB5 */
290
291    strcpy (rpc_caller, "???@");                /* safety drop */
292    strcat (rpc_caller, REALM);
293
294    /* read authenticator off net */
295    ticket.length = recvshort();
296    if ((ticket.length<=0) || (ticket.length>MAX_KTXT_LEN)) {
297        result = RPC_PROTOCOL;
298        goto punt_kerberos;
299    }
300    for (i=0; i<ticket.length; i++) {
301        ticket.dat[i] = recvshort();
302    }
303#ifdef HAVE_KRB5
304    packet.length = ticket.length;
305    packet.data = (krb5_pointer) ticket.dat;
306   
307    envvar = malloc(strlen(service) + 50);
308    if (envvar) {
309        sprintf(envvar, "KRB5_KTNAME=/var/spool/%s/krb5.keytab", service);
310        putenv(envvar);
311    }
312#endif /* HAVE_KRB5 */
313    /* make filename from service */
314    strcpy (filename, "/var/spool/");
315    strcat (filename, service);
316    strcat (filename, "/srvtab");
317
318    strcpy(instance, "*");
319
320#ifdef HAVE_KRB5
321    result = krb5_init_context(&context);
322    if (result) {
323        com_err(service, result, "while initializing krb5");
324        goto punt_kerberos;
325    }
326    result = krb5_sname_to_principal(context, NULL, service, KRB5_NT_SRV_HST,
327                                     &sprinc);
328    if (result) {
329        com_err(service, result, "while generating srv name %s", service);
330        goto punt_kerberos;
331    }
332    result = krb5_rd_req(context, &auth_context, &packet, sprinc, keytab,
333                         NULL, &processed_ticket);
334    if (result == 0) {  /* It's a valid krb5 request */
335        result = krb5_524_conv_principal(context,
336                                         processed_ticket->enc_part2->client,
337                                         kdata.pname, kdata.pinst,
338                                         kdata.prealm);
339        if (result) {
340            com_err(service, result, "while converting principal to krb4");
341            goto punt_kerberos;
342        }
343    }
344    else {  /* Let's try krb4 */
345        /* First, log the krb5 error. */
346        com_err(service, result, "while reading request");
347#endif /* HAVE_KRB5 */
348#ifdef HAVE_KRB4
349        result = krb_rd_req (&ticket, service, instance, haddr, &kdata,
350                             filename);
351        if (result) {
352            result += ERROR_TABLE_BASE_krb;
353            goto punt_kerberos;
354        }
355#endif /* HAVE_KRB4 */
356#ifdef HAVE_KRB5
357    }
358#endif /* HAVE_KRB5 */
359
360    strcpy(rpc_caller, kdata.pname);
361    if (kdata.pinst[0] != '\0') {
362        strcat(rpc_caller, ".");
363        strcat(rpc_caller, kdata.pinst);
364    }
365    strcat(rpc_caller, "@");
366    strcat(rpc_caller, kdata.prealm);
367
368punt_kerberos:
369    USP_flush_block(us);
370    if (bt == KRB_TICKET2) {
371         USP_begin_block(us,TICKET_REPLY);
372         USP_put_long_integer(us, i);
373         USP_end_block(us);
374    }
375}
376#endif /* HAVE_KRB4 || HAVE_KRB5 */
377
378/*
379 *
380 * recvit ()  -- Routine to accept an RPC call.
381 *
382 */
383recvit (code)
384    int *code;
385{
386    USPCardinal bt;
387    int procno;
388
389    if (USP_rcv_blk(us, &bt) != SUCCESS) {
390        if (errno == ECONNRESET) {              /* he went away, so do we */
391            *code = errno;
392        }
393        *code = errno;
394        return;
395    }
396
397#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
398    if (bt == KRB_TICKET || bt == KRB_TICKET2) {
399         handle_kerberos(bt, serv_name, hostaddr);
400         *code = 0;
401         return;
402    }
403#endif /* HAVE_KRB4 || HAVE_KRB5 */
404
405    procno = bt - PROC_BASE;
406
407    if (procno == 0) {
408        *code = RPC_PROTOCOL;
409        return;
410    }
411    if (procno > numprocs) {
412        USP_flush_block(us);
413        senddunno();
414        *code = 0;
415        return;
416    }
417
418    rpc_err = 0;
419    dispatch (procno);
420    *code = rpc_err;
421    return;
422}
423
424int recvint ()
425{
426    USPLong_integer li;
427   
428    if (USP_get_long_integer(us, &li) != SUCCESS) {
429        rpc_err = errno;
430        return(0);
431    }
432   
433    return (li);
434}
435short recvshort ()
436{
437    USPInteger li;
438   
439    if (USP_get_integer(us, &li) != SUCCESS) {
440        rpc_err = errno;
441        return(0);
442    }
443   
444    return (li);
445}
446
447/*
448 *
449 * recvstr ()  -- Receive a string from an RPC call
450 *
451 */
452char *recvstr ()
453{
454    USPString str;
455   
456    if (USP_get_string(us, &str) != SUCCESS) {
457        rpc_err = errno;
458        return("");
459    }
460   
461    return (str);
462}
463
464/*
465 *
466 * recvbool ()  -- Receive a boolean in an RPC call.
467 *
468 */
469bool recvbool()
470{
471    USPBoolean flag;
472   
473    if (USP_get_boolean(us, &flag) != SUCCESS) {
474        rpc_err = errno;
475        return(0);
476    }
477   
478    return ((bool)flag);
479}
480
481/*
482 *
483 * recvfile() -- Receive a file in an RPC call.
484 *
485 */
486tfile recvfile ()
487{
488    USPLong_integer tfs;
489    tfile tf;
490   
491    if (USP_get_long_integer(us, &tfs) != SUCCESS) {
492        rpc_err = errno;
493        return(0);
494    }
495   
496    tf = net_tfile (tfs,us);
497   
498    return (tf);
499}
500
501/*
502 *
503 * startreply()  -- Get ready to send reply of an RPC call.
504 *
505 */
506startreply()
507{
508    USP_begin_block(us,REPLY_TYPE);
509   
510    return;
511}
512
513/*
514 *
515 * sendint(i)  -- Send an integer in an RPC return.
516 *
517 */
518sendint(i)
519    int i;
520{
521    if (USP_put_long_integer(us, i) != SUCCESS) {
522        rpc_err = errno + ERROR_TABLE_BASE_rpc;
523    }
524}
525
526/*
527 *
528 * sendstr(i)  -- Send a string in an RPC return.
529 *
530 */
531sendstr(str)
532    char *str;
533{
534    if (str == NULL)
535      str = "";
536    if (USP_put_string(us, str) != SUCCESS) {
537        rpc_err = ERROR_TABLE_BASE_rpc + errno;
538        return;
539    }
540}
541
542/*
543 *
544 * sendbool(b)  -- Send a boolean in an RPC return.
545 *
546 */
547sendbool(b)
548    bool b;
549{
550    if (USP_put_boolean(us, (USPBoolean)b) != SUCCESS) {
551        rpc_err = ERROR_TABLE_BASE_rpc + errno;
552        return;
553    }
554}
555
556/*
557 *
558 * sendreply () -- Make the final call.
559 *
560 */
561sendreply()
562{
563    if (USP_end_block(us) != SUCCESS) {
564        rpc_err = ERROR_TABLE_BASE_rpc + errno;
565        return;
566    }
567    return;
568}
569
570/*
571 *
572 * senddunno () -- Send a 'I don't know this call' reply
573 *
574 */
575senddunno()
576{
577    USP_begin_block(us,UNKNOWN_CALL);
578    if (USP_end_block(us) != SUCCESS) {
579        rpc_err = ERROR_TABLE_BASE_rpc + errno;
580        return;
581    }
582    return;
583}
Note: See TracBrowser for help on using the repository browser.