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.
RevLine 
[171]1/*
2 *
[1939]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 *
[171]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
[357]16/*
17 *
[22658]18 *      $Id: rpproc.c,v 1.23 2007-08-09 20:41:33 amb Exp $
[357]19 *
20 */
21
22
[23920]23#ifdef NOKERBEROS
24#undef HAVE_KRB4
25#undef HAVE_KRB5
26#endif /* NOKERBEROS */
27
[171]28#ifdef INETD
29#define ASSOC 1
30#endif
31
32#ifdef SUBPROC
33#define ASSOC 1
34#endif
35
36/* Includes */
37
[357]38#include <sys/ioctl.h>
[12439]39#if HAVE_FCNTL_H
[357]40#include <fcntl.h>
[12439]41#endif
[171]42#include <sys/types.h>
43#include <sys/socket.h>
44#include <stdio.h>
[22404]45#include <stdlib.h>
[171]46#include <netinet/in.h>
47#include <sys/stat.h>
48#include <netdb.h>
49#include <errno.h>
50#include <pwd.h>
[1721]51#include <string.h>
[23807]52#ifdef HAVE_KRB4
[171]53#include <krb.h>
54#endif
[23807]55#ifdef HAVE_KRB5
[22658]56#include <krb5.h>
57#endif
[1721]58#include <discuss/tfile.h>
59#include "rpc.h"
60#include <discuss/types.h>
61#include "config.h"
[171]62
63#define SUCCESS 1
64#define ERROR   -1
65#define min(a, b) (a < b ? a : b)
66
[23922]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
[171]92/* global */
[23922]93#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
[10115]94char rpc_caller[MAX_K_NAME_SZ + 1];
95#else
[171]96char rpc_caller[50];
[23922]97#endif /* HAVE_KRB4 || HAVE_KRB5 */
[1728]98static long hostaddr;
[171]99
100extern int numprocs;
[1509]101extern struct proc_table procs [];
[23922]102#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
[1728]103static char serv_name[20];
[23922]104#endif /* HAVE_KRB4 || HAVE_KRB5 */
[171]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)
[1509]120    char *service;
121    int *code;
[171]122{
123#ifdef INETD
[1509]124    int d;
[171]125#endif
[1509]126    int snew;                   /* socket we're reading from */
127   
[171]128#ifdef SUBPROC
[1509]129    int uid;
130    struct passwd *pwent;
[171]131#endif
[1509]132   
[171]133#ifndef ASSOC
[1509]134    struct protoent *pe;
135    struct servent *se;
136    struct sockaddr_in sai;
137    int sock_len = sizeof (sai);
138    int s;
[171]139#endif
[1509]140   
[23922]141#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
[1509]142    int fromlen,i;
143    struct sockaddr_in from;
144    char hostname[50];
145    struct hostent *hp;
146    USPCardinal bt;
[23922]147#endif /* HAVE_KRB4 || HAVE_KRB5 */
[171]148
[23271]149#if defined(__APPLE__) && defined(__MACH__)
150    add_error_table(&et_rpc_error_table);
151#else
[22864]152    initialize_rpc_error_table();
[23271]153#endif
[1509]154
[171]155#ifdef INETD
[1509]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 */
[171]162#endif
[1509]163   
[171]164#ifdef ASSOC
[1509]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    }
[171]172
[357]173#ifdef SUBPROC
[1509]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    {
[3078]189        setpgrp(0, getpid());           /* So we don't get tty signals */
[1509]190    }
[357]191#endif
[1509]192   
193    snew = 0;
194    us = USP_associate (snew);
[171]195#else   
[1509]196    /* to be added */
197    setprotoent(0);                         /* get protocol information */
198    pe = getprotobyname("tcp");
199    setservent(0);                          /* get service information */
200   
[22713]201    se = getservbyname(SERVICE_NAME, "tcp");
[1509]202    sai.sin_addr.s_addr = INADDR_ANY;
[22713]203    sai.sin_port = (se) ? se->s_port : htons(DISCUSS_FALLBACK_PORT);
204                                            /* set up socket */
[1509]205    if((s = socket(AF_INET, SOCK_STREAM, pe->p_proto)) < 0) {
206        *code = errno;
207        return;
208    }
[12439]209    if(bind(s, (struct sockaddr *)&sai, sizeof(sai))) {  /* bind service name */
[1509]210        *code = errno;
211        return;
212    }   
213    listen(s, SOMAXCONN);               /* listen for connection */
[12439]214    if((snew = accept(s, (struct sockaddr *)&sai, &sock_len)) < 0) {
215                                        /* accept connection */
[1509]216        *code = errno;
217        return;
218    }
219   
220    us = USP_associate (snew);
221    if (us == NULL) {
222        *code = errno;
223        return;
224    }
[171]225#endif
[1509]226   
227    strcpy (rpc_caller, "???");         /* safety drop */
228   
[171]229#ifdef SUBPROC
[1509]230    uid = getuid ();
231    pwent = getpwuid(uid);
232    if (pwent != 0) {
233        strcpy (rpc_caller, pwent -> pw_name);
234    }
[171]235#endif
[1509]236    strcat (rpc_caller, "@");
237    strcat (rpc_caller, REALM);
238   
[23922]239#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
[1728]240
241    strcpy(serv_name, service);
[1509]242    fromlen = sizeof (from);
[12439]243    if (getpeername (snew, (struct sockaddr *)&from, &fromlen) < 0) {
[1509]244        *code = errno;
245        return;
246    }
247    if (fromlen == 0) {         /* no len, UNIX domain = me */
248        gethostname(hostname, sizeof(hostname));
249        hp = gethostbyname(hostname);
[8855]250        memcpy(&hostaddr, hp -> h_addr,  4);
[1509]251    } else {
[8855]252        memcpy(&hostaddr, &from.sin_addr, 4);
[1509]253    }
[7186]254
[1509]255   
[1728]256    if ((USP_rcv_blk(us, &bt) != SUCCESS) || (bt != KRB_TICKET &&
257                                              bt != KRB_TICKET2)) {
[1509]258        *code = RPC_PROTOCOL;
259        return;
260    }
261   
[1728]262    handle_kerberos(bt,serv_name,hostaddr);
[23922]263#endif /* HAVE_KRB4 || HAVE_KRB5 */
[1728]264    *code = 0;
265    return;
266}
267
[23922]268#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
[1728]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
[23807]281#ifdef HAVE_KRB5
[22658]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;
[23807]289#endif /* HAVE_KRB5 */
[22658]290
[1728]291    strcpy (rpc_caller, "???@");                /* safety drop */
292    strcat (rpc_caller, REALM);
293
[1509]294    /* read authenticator off net */
295    ticket.length = recvshort();
296    if ((ticket.length<=0) || (ticket.length>MAX_KTXT_LEN)) {
[1728]297        result = RPC_PROTOCOL;
[1509]298        goto punt_kerberos;
299    }
300    for (i=0; i<ticket.length; i++) {
301        ticket.dat[i] = recvshort();
302    }
[23807]303#ifdef HAVE_KRB5
[22658]304    packet.length = ticket.length;
305    packet.data = (krb5_pointer) ticket.dat;
[1509]306   
[11388]307    envvar = malloc(strlen(service) + 50);
308    if (envvar) {
309        sprintf(envvar, "KRB5_KTNAME=/var/spool/%s/krb5.keytab", service);
310        putenv(envvar);
311    }
[23807]312#endif /* HAVE_KRB5 */
[1509]313    /* make filename from service */
[11295]314    strcpy (filename, "/var/spool/");
[1509]315    strcat (filename, service);
316    strcat (filename, "/srvtab");
[22658]317
318    strcpy(instance, "*");
319
[23807]320#ifdef HAVE_KRB5
[22658]321    result = krb5_init_context(&context);
322    if (result) {
323        com_err(service, result, "while initializing krb5");
324        goto punt_kerberos;
[1509]325    }
[22658]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);
[1509]330        goto punt_kerberos;
331    }
[22658]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");
[23807]347#endif /* HAVE_KRB5 */
[23922]348#ifdef HAVE_KRB4
[22658]349        result = krb_rd_req (&ticket, service, instance, haddr, &kdata,
350                             filename);
351        if (result) {
[22864]352            result += ERROR_TABLE_BASE_krb;
[22658]353            goto punt_kerberos;
354        }
[23922]355#endif /* HAVE_KRB4 */
[23807]356#ifdef HAVE_KRB5
[22658]357    }
[23807]358#endif /* HAVE_KRB5 */
[22658]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
[171]368punt_kerberos:
[1509]369    USP_flush_block(us);
[1728]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    }
[171]375}
[23922]376#endif /* HAVE_KRB4 || HAVE_KRB5 */
[171]377
378/*
379 *
380 * recvit ()  -- Routine to accept an RPC call.
381 *
382 */
383recvit (code)
[1509]384    int *code;
[171]385{
[1509]386    USPCardinal bt;
387    int procno;
[1721]388
[1509]389    if (USP_rcv_blk(us, &bt) != SUCCESS) {
[23149]390        if (errno == ECONNRESET) {              /* he went away, so do we */
[1509]391            *code = errno;
392        }
393        *code = errno;
394        return;
395    }
[1721]396
[23922]397#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
[1728]398    if (bt == KRB_TICKET || bt == KRB_TICKET2) {
399         handle_kerberos(bt, serv_name, hostaddr);
400         *code = 0;
401         return;
402    }
[23922]403#endif /* HAVE_KRB4 || HAVE_KRB5 */
[1728]404
[1509]405    procno = bt - PROC_BASE;
[1721]406
[1509]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    }
[1721]417
[1509]418    rpc_err = 0;
419    dispatch (procno);
420    *code = rpc_err;
421    return;
[171]422}
423
424int recvint ()
425{
[1509]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);
[171]434}
435short recvshort ()
436{
[1509]437    USPInteger li;
438   
439    if (USP_get_integer(us, &li) != SUCCESS) {
440        rpc_err = errno;
441        return(0);
442    }
443   
444    return (li);
[171]445}
446
447/*
448 *
449 * recvstr ()  -- Receive a string from an RPC call
450 *
451 */
452char *recvstr ()
453{
[1509]454    USPString str;
455   
456    if (USP_get_string(us, &str) != SUCCESS) {
457        rpc_err = errno;
458        return("");
459    }
460   
461    return (str);
[171]462}
463
464/*
465 *
466 * recvbool ()  -- Receive a boolean in an RPC call.
467 *
468 */
469bool recvbool()
470{
[1509]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);
[171]479}
480
481/*
482 *
483 * recvfile() -- Receive a file in an RPC call.
484 *
485 */
486tfile recvfile ()
487{
[1509]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);
[171]499}
500
501/*
502 *
503 * startreply()  -- Get ready to send reply of an RPC call.
504 *
505 */
506startreply()
507{
[1509]508    USP_begin_block(us,REPLY_TYPE);
509   
510    return;
[171]511}
512
513/*
514 *
515 * sendint(i)  -- Send an integer in an RPC return.
516 *
517 */
518sendint(i)
[1509]519    int i;
[171]520{
[1509]521    if (USP_put_long_integer(us, i) != SUCCESS) {
[22864]522        rpc_err = errno + ERROR_TABLE_BASE_rpc;
[1509]523    }
[171]524}
525
526/*
527 *
528 * sendstr(i)  -- Send a string in an RPC return.
529 *
530 */
531sendstr(str)
[1509]532    char *str;
[171]533{
[15187]534    if (str == NULL)
[15171]535      str = "";
[1509]536    if (USP_put_string(us, str) != SUCCESS) {
[22864]537        rpc_err = ERROR_TABLE_BASE_rpc + errno;
[1509]538        return;
539    }
[171]540}
541
542/*
543 *
544 * sendbool(b)  -- Send a boolean in an RPC return.
545 *
546 */
547sendbool(b)
[1509]548    bool b;
[171]549{
[1509]550    if (USP_put_boolean(us, (USPBoolean)b) != SUCCESS) {
[22864]551        rpc_err = ERROR_TABLE_BASE_rpc + errno;
[1509]552        return;
553    }
[171]554}
555
556/*
557 *
558 * sendreply () -- Make the final call.
559 *
560 */
561sendreply()
562{
[1509]563    if (USP_end_block(us) != SUCCESS) {
[22864]564        rpc_err = ERROR_TABLE_BASE_rpc + errno;
[1509]565        return;
566    }
567    return;
[171]568}
[261]569
570/*
571 *
572 * senddunno () -- Send a 'I don't know this call' reply
573 *
574 */
575senddunno()
576{
[1509]577    USP_begin_block(us,UNKNOWN_CALL);
578    if (USP_end_block(us) != SUCCESS) {
[22864]579        rpc_err = ERROR_TABLE_BASE_rpc + errno;
[1509]580        return;
581    }
582    return;
[261]583}
Note: See TracBrowser for help on using the repository browser.