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

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