/* * * Copyright (C) 1988, 1989 by the Massachusetts Institute of Technology * Developed by the MIT Student Information Processing Board (SIPB). * For copying information, see the file mit-copyright.h in this release. * */ /* * * rpproc.c -- Procedures to implement a simple (perhaps brain-asleep) RPC * protocol over a TCP connection. * This file handles the server's side of the connection. * */ /* * * $Id: rpproc.c,v 1.23 2007-08-09 20:41:33 amb Exp $ * */ #ifdef NOKERBEROS #undef HAVE_KRB4 #undef HAVE_KRB5 #endif /* NOKERBEROS */ #ifdef INETD #define ASSOC 1 #endif #ifdef SUBPROC #define ASSOC 1 #endif /* Includes */ #include #if HAVE_FCNTL_H #include #endif #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_KRB4 #include #endif #ifdef HAVE_KRB5 #include #endif #include #include "rpc.h" #include #include "config.h" #define SUCCESS 1 #define ERROR -1 #define min(a, b) (a < b ? a : b) /* When both krb4 and krb5 are available, the server will try to * authenticate clients with krb5 and then fall back to krb4. To * avoid writing entirely separate code for the case where krb4 is * not available, we fake some of the constants and data structures. */ #ifndef HAVE_KRB4 #define ANAME_SZ 40 #define REALM_SZ 40 #define INST_SZ 40 #define MAX_KTXT_LEN 1250 #define MAX_K_NAME_SZ (ANAME_SZ + INST_SZ + REALM_SZ + 2) struct ktext { int length; unsigned char dat[MAX_KTXT_LEN]; unsigned long mbz; }; typedef struct ktext KTEXT_ST; struct partial_auth_dat { /* Just enough of the struct for our purposes */ char pname[ANAME_SZ]; char pinst[INST_SZ]; char prealm[REALM_SZ]; }; typedef struct partial_auth_dat AUTH_DAT; #endif /* HAVE_KRB4 */ /* global */ #if defined(HAVE_KRB4) || defined(HAVE_KRB5) char rpc_caller[MAX_K_NAME_SZ + 1]; #else char rpc_caller[50]; #endif /* HAVE_KRB4 || HAVE_KRB5 */ static long hostaddr; extern int numprocs; extern struct proc_table procs []; #if defined(HAVE_KRB4) || defined(HAVE_KRB5) static char serv_name[20]; #endif /* HAVE_KRB4 || HAVE_KRB5 */ short recvshort(); int rpc_err; extern tfile net_tfile (); /* Static variables */ /* connections & socket info */ static USPStream *us = NULL; /* * * init_rpc () -- Initialize the RPC mechanism * */ init_rpc (service,code) char *service; int *code; { #ifdef INETD int d; #endif int snew; /* socket we're reading from */ #ifdef SUBPROC int uid; struct passwd *pwent; #endif #ifndef ASSOC struct protoent *pe; struct servent *se; struct sockaddr_in sai; int sock_len = sizeof (sai); int s; #endif #if defined(HAVE_KRB4) || defined(HAVE_KRB5) int fromlen,i; struct sockaddr_in from; char hostname[50]; struct hostent *hp; USPCardinal bt; #endif /* HAVE_KRB4 || HAVE_KRB5 */ #if defined(__APPLE__) && defined(__MACH__) add_error_table(&et_rpc_error_table); #else initialize_rpc_error_table(); #endif #ifdef INETD d = open ("/dev/null", 2); dup2(d, 1); dup2(d, 2); close(d); if (geteuid() == 0) panic ("Can't run as root."); /* just in case setuid bit off */ #endif #ifdef ASSOC /* safety check -- 0 better be a socket, not a pipe or file */ { if (isatty (0)) { *code = RPC_NOT_SUBPROC; return; } } #ifdef SUBPROC { int s; for (s = 1; s < 10; s++) (void) close (s); } { int fd; fd = open("/dev/null", 2); if (fd != 1) { (void) dup2 (fd, 1); (void) close (fd); } (void) dup2(1, 2); } { setpgrp(0, getpid()); /* So we don't get tty signals */ } #endif snew = 0; us = USP_associate (snew); #else /* to be added */ setprotoent(0); /* get protocol information */ pe = getprotobyname("tcp"); setservent(0); /* get service information */ se = getservbyname(SERVICE_NAME, "tcp"); sai.sin_addr.s_addr = INADDR_ANY; sai.sin_port = (se) ? se->s_port : htons(DISCUSS_FALLBACK_PORT); /* set up socket */ if((s = socket(AF_INET, SOCK_STREAM, pe->p_proto)) < 0) { *code = errno; return; } if(bind(s, (struct sockaddr *)&sai, sizeof(sai))) { /* bind service name */ *code = errno; return; } listen(s, SOMAXCONN); /* listen for connection */ if((snew = accept(s, (struct sockaddr *)&sai, &sock_len)) < 0) { /* accept connection */ *code = errno; return; } us = USP_associate (snew); if (us == NULL) { *code = errno; return; } #endif strcpy (rpc_caller, "???"); /* safety drop */ #ifdef SUBPROC uid = getuid (); pwent = getpwuid(uid); if (pwent != 0) { strcpy (rpc_caller, pwent -> pw_name); } #endif strcat (rpc_caller, "@"); strcat (rpc_caller, REALM); #if defined(HAVE_KRB4) || defined(HAVE_KRB5) strcpy(serv_name, service); fromlen = sizeof (from); if (getpeername (snew, (struct sockaddr *)&from, &fromlen) < 0) { *code = errno; return; } if (fromlen == 0) { /* no len, UNIX domain = me */ gethostname(hostname, sizeof(hostname)); hp = gethostbyname(hostname); memcpy(&hostaddr, hp -> h_addr, 4); } else { memcpy(&hostaddr, &from.sin_addr, 4); } if ((USP_rcv_blk(us, &bt) != SUCCESS) || (bt != KRB_TICKET && bt != KRB_TICKET2)) { *code = RPC_PROTOCOL; return; } handle_kerberos(bt,serv_name,hostaddr); #endif /* HAVE_KRB4 || HAVE_KRB5 */ *code = 0; return; } #if defined(HAVE_KRB4) || defined(HAVE_KRB5) handle_kerberos(bt,service,haddr) USPCardinal bt; char *service; long haddr; { int i,result; char hostname[50]; char filename[50]; char instance[INST_SZ]; AUTH_DAT kdata; KTEXT_ST ticket; #ifdef HAVE_KRB5 char *envvar; krb5_context context; krb5_auth_context auth_context = NULL; krb5_data packet; krb5_principal sprinc; krb5_keytab keytab = NULL; krb5_ticket *processed_ticket = NULL; #endif /* HAVE_KRB5 */ strcpy (rpc_caller, "???@"); /* safety drop */ strcat (rpc_caller, REALM); /* read authenticator off net */ ticket.length = recvshort(); if ((ticket.length<=0) || (ticket.length>MAX_KTXT_LEN)) { result = RPC_PROTOCOL; goto punt_kerberos; } for (i=0; ienc_part2->client, kdata.pname, kdata.pinst, kdata.prealm); if (result) { com_err(service, result, "while converting principal to krb4"); goto punt_kerberos; } } else { /* Let's try krb4 */ /* First, log the krb5 error. */ com_err(service, result, "while reading request"); #endif /* HAVE_KRB5 */ #ifdef HAVE_KRB4 result = krb_rd_req (&ticket, service, instance, haddr, &kdata, filename); if (result) { result += ERROR_TABLE_BASE_krb; goto punt_kerberos; } #endif /* HAVE_KRB4 */ #ifdef HAVE_KRB5 } #endif /* HAVE_KRB5 */ strcpy(rpc_caller, kdata.pname); if (kdata.pinst[0] != '\0') { strcat(rpc_caller, "."); strcat(rpc_caller, kdata.pinst); } strcat(rpc_caller, "@"); strcat(rpc_caller, kdata.prealm); punt_kerberos: USP_flush_block(us); if (bt == KRB_TICKET2) { USP_begin_block(us,TICKET_REPLY); USP_put_long_integer(us, i); USP_end_block(us); } } #endif /* HAVE_KRB4 || HAVE_KRB5 */ /* * * recvit () -- Routine to accept an RPC call. * */ recvit (code) int *code; { USPCardinal bt; int procno; if (USP_rcv_blk(us, &bt) != SUCCESS) { if (errno == ECONNRESET) { /* he went away, so do we */ *code = errno; } *code = errno; return; } #if defined(HAVE_KRB4) || defined(HAVE_KRB5) if (bt == KRB_TICKET || bt == KRB_TICKET2) { handle_kerberos(bt, serv_name, hostaddr); *code = 0; return; } #endif /* HAVE_KRB4 || HAVE_KRB5 */ procno = bt - PROC_BASE; if (procno == 0) { *code = RPC_PROTOCOL; return; } if (procno > numprocs) { USP_flush_block(us); senddunno(); *code = 0; return; } rpc_err = 0; dispatch (procno); *code = rpc_err; return; } int recvint () { USPLong_integer li; if (USP_get_long_integer(us, &li) != SUCCESS) { rpc_err = errno; return(0); } return (li); } short recvshort () { USPInteger li; if (USP_get_integer(us, &li) != SUCCESS) { rpc_err = errno; return(0); } return (li); } /* * * recvstr () -- Receive a string from an RPC call * */ char *recvstr () { USPString str; if (USP_get_string(us, &str) != SUCCESS) { rpc_err = errno; return(""); } return (str); } /* * * recvbool () -- Receive a boolean in an RPC call. * */ bool recvbool() { USPBoolean flag; if (USP_get_boolean(us, &flag) != SUCCESS) { rpc_err = errno; return(0); } return ((bool)flag); } /* * * recvfile() -- Receive a file in an RPC call. * */ tfile recvfile () { USPLong_integer tfs; tfile tf; if (USP_get_long_integer(us, &tfs) != SUCCESS) { rpc_err = errno; return(0); } tf = net_tfile (tfs,us); return (tf); } /* * * startreply() -- Get ready to send reply of an RPC call. * */ startreply() { USP_begin_block(us,REPLY_TYPE); return; } /* * * sendint(i) -- Send an integer in an RPC return. * */ sendint(i) int i; { if (USP_put_long_integer(us, i) != SUCCESS) { rpc_err = errno + ERROR_TABLE_BASE_rpc; } } /* * * sendstr(i) -- Send a string in an RPC return. * */ sendstr(str) char *str; { if (str == NULL) str = ""; if (USP_put_string(us, str) != SUCCESS) { rpc_err = ERROR_TABLE_BASE_rpc + errno; return; } } /* * * sendbool(b) -- Send a boolean in an RPC return. * */ sendbool(b) bool b; { if (USP_put_boolean(us, (USPBoolean)b) != SUCCESS) { rpc_err = ERROR_TABLE_BASE_rpc + errno; return; } } /* * * sendreply () -- Make the final call. * */ sendreply() { if (USP_end_block(us) != SUCCESS) { rpc_err = ERROR_TABLE_BASE_rpc + errno; return; } return; } /* * * senddunno () -- Send a 'I don't know this call' reply * */ senddunno() { USP_begin_block(us,UNKNOWN_CALL); if (USP_end_block(us) != SUCCESS) { rpc_err = ERROR_TABLE_BASE_rpc + errno; return; } return; }