diff options
Diffstat (limited to 'src/appl/bsd/krshd.c')
-rw-r--r-- | src/appl/bsd/krshd.c | 619 |
1 files changed, 89 insertions, 530 deletions
diff --git a/src/appl/bsd/krshd.c b/src/appl/bsd/krshd.c index 8ea3840199..6e4cf677c5 100644 --- a/src/appl/bsd/krshd.c +++ b/src/appl/bsd/krshd.c @@ -75,9 +75,6 @@ static char sccsid[] = "@(#)rshd.c 5.12 (Berkeley) 9/12/88"; * SERVE_V4 - Define this if v4 rlogin clients are also to be served. * ALWAYS_V5_KUSEROK - Define this if you want .k5login to be * checked even for v4 clients (instead of .klogin). - * SERVE_NON_KRB - Define this is non-kerberized rlogin clients are - * to be served. NOTE HOWEVER THAT THIS IS A SERIOUS - * SECURITY FLAW! * LOG_ALL_LOGINS - Define this if you want to log all logins. * LOG_OTHER_USERS - Define this if you want to log all principals that do * not map onto the local user. @@ -123,6 +120,7 @@ static char sccsid[] = "@(#)rshd.c 5.12 (Berkeley) 9/12/88"; #include <errno.h> #include <pwd.h> #include <ctype.h> +#include <string.h> #ifdef sun #include <sys/label.h> @@ -179,7 +177,6 @@ extern #endif /* CRAY */ int errno; -char *index(), *rindex(), *strncat(); /*VARARGS1*/ int error(); @@ -199,7 +196,7 @@ main(argc, argv) char *options, ch; int i; int fd; - int debug_port; + int debug_port = 0; #ifdef CRAY secflag = sysconf(_SC_CRAY_SECURE_SYS); @@ -385,7 +382,6 @@ char cmdbuf[NCARGS+1]; char *kremuser; krb5_principal client; krb5_authenticator *kdata; -krb5_ticket *ticket = 0; #ifdef SERVE_V4 #include <kerberosIV/krb.h> @@ -393,7 +389,10 @@ AUTH_DAT *v4_kdata; KTEXT v4_ticket; #endif -int V4 = 0; /* Set when connection is seen to be from a V4 client */ +int auth_sys = 0; /* Which version of Kerberos used to authenticate */ + +#define KRB5_RECVAUTH_V4 4 +#define KRB5_RECVAUTH_V5 5 doit(f, fromp) int f; @@ -479,6 +478,7 @@ doit(f, fromp) exit(1); } #ifdef KERBEROS + krb5_init_ets(); if ((must_pass_rhosts || must_pass_one) && (fromp->sin_port >= IPPORT_RESERVED || fromp->sin_port < IPPORT_RESERVED/2)) @@ -882,7 +882,7 @@ doit(f, fromp) failed_k5 = 1; } #else - if (V4) { + if (auth_sys == KRB5_RECVAUTH_V4) { /* kuserok returns 0 if OK */ if (kuserok(v4_kdata, locuser)){ syslog(LOG_ERR , @@ -1066,7 +1066,7 @@ doit(f, fromp) strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); strncat(shell, pwd->pw_shell, sizeof(shell)-7); strncat(username, pwd->pw_name, sizeof(username)-6); - cp = rindex(pwd->pw_shell, '/'); + cp = strrchr(pwd->pw_shell, '/'); if (cp) cp++; else @@ -1374,557 +1374,116 @@ recvauth(netf, peersin, peeraddr) struct sockaddr_in peersin; krb5_address peeraddr; { - char hostname[100]; - krb5_principal server; krb5_error_code status; + struct sockaddr_in laddr; char krb_vers[KRB_SENDAUTH_VLEN + 1]; int len; + krb5_principal server; + krb5_data inbuf; + char v4_instance[INST_SZ]; /* V4 Instance */ + char v4_version[9]; + krb5_ticket *ticket; - len = sizeof(int); - if ((status = krb5_net_read(netf, krb_vers, len)) != len) - return((status < 0) ? errno : ECONNABORTED); - - krb_vers[len] = '\0'; - - if (!strncmp(krb_vers, KRB_SENDAUTH_VERS, len)) { - /* Must be V4 rlogin client */ -#ifdef SERVE_V4 - char version[9]; - struct sockaddr_in faddr; - char instance[INST_SZ]; - long authoptions; - int len; - - V4 = 1; - - authoptions = 0L; - - len = sizeof(faddr); - if (getsockname(0, (struct sockaddr *)&faddr, &len)) { + len = sizeof(laddr); + if (getsockname(netf, (struct sockaddr *)&laddr, &len)) { exit(1); - } - - v4_kdata = (AUTH_DAT *)malloc( sizeof(AUTH_DAT) ); - v4_ticket = (KTEXT) malloc(sizeof(KTEXT_ST)); - - strcpy(instance, "*"); - - if (status = v4_recvauth(krb_vers, authoptions, netf, - v4_ticket, "rcmd", - instance, &peersin, &faddr, - v4_kdata, "", (bit_64 *)0, version)) { - return(status); - } - - getstr(netf, locuser, sizeof (locuser), "locuser"); - getstr(netf, cmdbuf, sizeof(cmdbuf), "command"); - /* We do not really know the remote user's login name. - * Assume it to be the same as the first component of the - * principal's name. - */ - strcpy(remuser, v4_kdata->pname); - kremuser = (char *) malloc(strlen(v4_kdata->pname) + 1 + - strlen(v4_kdata->pinst) + 1 + - strlen(v4_kdata->prealm) + 1); - sprintf(kremuser, "%s/%s@%s", v4_kdata->pname, - v4_kdata->pinst, v4_kdata->prealm); - - if (status = krb5_parse_name(kremuser, &client)) - return(status); -#else - syslog(LOG_ERR, "Kerberos V4 authentication: rejected!"); - error("Permission denied"); -#endif - } - else if (isprint(krb_vers[0])) { - /* Un-kerberized rlogin client */ -#ifdef SERVE_NON_KRB - strncpy(remuser, krb_vers, sizeof(int)); - getstr(netf, remuser+4, sizeof(remuser)-sizeof(int), "remuser"); - getstr(netf, locuser, sizeof(locuser), "locuser"); - getstr(netf, cmdbuf, sizeof(cmdbuf), "command"); -#else - syslog(LOG_ERR, "Un-kerberized client: authentication rejected!"); - error( "Permission denied"); -#endif } - else { - /* Must be V5 rlogin client */ - krb5_principal server; - krb5_data inbuf; - int len; - - /* - * First read the sendauth version string and check it. - */ - inbuf.length = ntohl(*((int *) krb_vers)); - - if (inbuf.length < 0 || inbuf.length > 25) - return 255; - - if (!(inbuf.data = malloc(inbuf.length))) { - return(ENOMEM); - } - if ((len = krb5_net_read(netf, inbuf.data, inbuf.length)) != - inbuf.length) { - krb5_xfree(inbuf.data); - return((len < 0) ? errno : ECONNABORTED); - } - - if (strcmp(inbuf.data, "KRB5_SENDAUTH_V1.0")) { - krb5_xfree(inbuf.data); - status = KRB5_SENDAUTH_BADAUTHVERS; - return status; - } - krb5_xfree(inbuf.data); - #ifdef unicos61 #define SIZEOF_INADDR SIZEOF_in_addr #else #define SIZEOF_INADDR sizeof(struct in_addr) #endif - gethostname(hostname, 100); - if (status = krb5_sname_to_principal(hostname,"host", KRB5_NT_SRV_HST, - &server)) { + if (status = krb5_sname_to_principal(NULL, "host", KRB5_NT_SRV_HST, + &server)) { syslog(LOG_ERR, "parse server name %s: %s", "host", error_message(status)); exit(1); - } - krb5_princ_type(server) = KRB5_NT_SRV_HST; - - krb5_init_ets(); - - if (status = v5_recvauth(&netf, - "KCMDV0.1", - server, /* Specify daemon principal */ - &peeraddr, /* We do want to match this - against caddrs in the - ticket. */ - 0, /* use srv5tab */ - 0, /* no keyproc */ - 0, /* no keyproc arg */ - 0, /* no rc_type */ - 0, /* no seq number */ - &client, /* return client */ - &ticket, /* return ticket */ - &kdata /* return authenticator */ - )) { - error("Kerberos rsh or rcp failed: %s\n", - error_message(status)); - exit(1); - } - krb5_unparse_name(kdata->client,&kremuser); - - getstr(netf, locuser, sizeof(locuser), "locuser"); - getstr(netf, cmdbuf, sizeof(cmdbuf), "command"); - getstr(netf, remuser, sizeof(locuser), "remuser"); - - if (status = krb5_read_message((krb5_pointer)&netf, &inbuf)) { - error("Error reading message: %s\n", - error_message(status)); - exit(1); - } - - if (inbuf.length) { - if (status = rd_and_store_for_creds(&inbuf, ticket, locuser)) { - error("Can't get forwarded credentials: %s\n", - error_message(status)); - exit(1); - } - } } - return 0; -} - -#ifdef SERVE_V4 - -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#endif /* max */ -krb5_error_code -v4_recvauth(krb_vers, options, fd, ticket, service, instance, faddr, - laddr, kdata, filename, schedule, version) - char *krb_vers; - long options; /* bit-pattern of options */ - int fd; /* file descr. to read from */ - KTEXT ticket; /* storage for client's ticket */ - char *service; /* service expected */ - char *instance; /* inst expected (may be filled in) */ - struct sockaddr_in *faddr; /* address of foreign host on fd */ - struct sockaddr_in *laddr; /* local address */ - AUTH_DAT *kdata; /* kerberos data (returned) */ - char *filename; /* name of file with service keys */ - Key_schedule schedule; /* key schedule (return) */ - char *version; /* version string (filled in) */ -{ - - int i, cc, old_vers = 0; - char *cp; - int rem; - long tkt_len, priv_len; - u_long cksum; - u_char tmp_buf[MAX_KTXT_LEN+max(KRB_SENDAUTH_VLEN+1,21)]; - - /* read the protocol version number */ - if (krb_net_read(fd, krb_vers+sizeof(int), - KRB_SENDAUTH_VLEN-sizeof(int)) != - KRB_SENDAUTH_VLEN-sizeof(int)) - return(errno); - krb_vers[KRB_SENDAUTH_VLEN] = '\0'; - - /* check version string */ - if (strcmp(krb_vers,KRB_SENDAUTH_VERS)) { - return(KFAILURE); - } else { - /* read the application version string */ - if (krb_net_read(fd, version, KRB_SENDAUTH_VLEN) != - KRB_SENDAUTH_VLEN) - return(errno); - version[KRB_SENDAUTH_VLEN] = '\0'; - - /* get the length of the ticket */ - if (krb_net_read(fd, (char *)&tkt_len, sizeof(tkt_len)) != - sizeof(tkt_len)) - return(errno); - - /* sanity check */ - ticket->length = ntohl((unsigned long)tkt_len); - if ((ticket->length <= 0) || (ticket->length > MAX_KTXT_LEN)) { - if (options & KOPT_DO_MUTUAL) { - rem = KFAILURE; - goto mutual_fail; - } else - return(KFAILURE); /* XXX there may still be junk on the fd? */ - } - - /* read the ticket */ - if (krb_net_read(fd, (char *) ticket->dat, ticket->length) - != ticket->length) - return(errno); - } - /* - * now have the ticket. decrypt it to get the authenticated - * data. - */ - rem = krb_rd_req(ticket,service,instance,faddr->sin_addr.s_addr, - kdata,filename); - - if (old_vers) return(rem); /* XXX can't do mutual with old client */ - - /* if we are doing mutual auth (used by erlogin), compose a response */ - if (options & KOPT_DO_MUTUAL) { - if (rem != KSUCCESS) - /* the krb_rd_req failed */ - goto mutual_fail; - - /* add one to the (formerly) sealed checksum, and re-seal it - for return to the client */ - cksum = kdata->checksum + 1; - cksum = htonl(cksum); -#ifdef CRYPT - key_sched(kdata->session,schedule); -#endif - priv_len = krb_mk_priv((unsigned char *)&cksum, - tmp_buf, - (unsigned long) sizeof(cksum), - schedule, - kdata->session, - laddr, - faddr); - if (priv_len < 0) { - /* re-sealing failed; notify the client */ - rem = KFAILURE; /* XXX */ - mutual_fail: - priv_len = -1; - tkt_len = htonl((unsigned long) priv_len); - /* a length of -1 is interpreted as an authentication - failure by the client */ - if ((cc = krb_net_write(fd, (char *)&tkt_len, sizeof(tkt_len))) - != sizeof(tkt_len)) - return(cc); - return(rem); - } else { - /* re-sealing succeeded, send the private message */ - tkt_len = htonl((unsigned long)priv_len); - if ((cc = krb_net_write(fd, (char *)&tkt_len, sizeof(tkt_len))) - != sizeof(tkt_len)) - return(cc); - if ((cc = krb_net_write(fd, (char *)tmp_buf, (int) priv_len)) - != (int) priv_len) - return(cc); + strcpy(v4_instance, "*"); + + status = krb5_compat_recvauth(&netf, + "KCMDV0.1", + server, /* Specify daemon principal */ + &peeraddr, /* We do want to match */ + /* this against caddrs in */ + /* the ticket */ + 0, /* use v5srvtab */ + 0, /* no keyproc */ + 0, /* no keyprocarg */ + 0, /* default rc_type */ + 0, /* no flags */ + + 0, /*v4_opts*/ + "rcmd", /* v4_service */ + v4_instance, /* v4_instance */ + &peersin, /* foriegn address */ + &laddr, /* our local address */ + "", /* use default srvtab */ + + &auth_sys, /* which authentication system */ + 0, /* no seq number */ + &client, /* return client */ + &ticket, /* return ticket */ + &kdata, /* return authenticator */ + + &v4_kdata, 0, v4_version); + + if (status) { + if (auth_sys == KRB5_RECVAUTH_V5) { + /* + * clean up before exiting + */ + getstr(netf, locuser, sizeof(locuser), "locuser"); + getstr(netf, cmdbuf, sizeof(cmdbuf), "command"); + getstr(netf, remuser, sizeof(locuser), "remuser"); } + return status; } - return(0); -} - -#endif /* SERVE_V4 */ -extern krb5_flags krb5_kdc_default_options; + getstr(netf, locuser, sizeof(locuser), "locuser"); + getstr(netf, cmdbuf, sizeof(cmdbuf), "command"); -krb5_error_code -v5_recvauth(/* IN */ - fd, appl_version, server, sender_addr, fetch_from, - keyproc, keyprocarg, rc_type, - /* OUT */ - seq_number, client, ticket, authent) - krb5_pointer fd; - char *appl_version; - krb5_principal server; - krb5_address *sender_addr; - krb5_pointer fetch_from; - krb5_int32 *seq_number; - char *rc_type; - krb5_rdreq_key_proc keyproc; - krb5_pointer keyprocarg; - krb5_principal *client; - krb5_ticket **ticket; - krb5_authenticator **authent; -{ - krb5_error_code retval, problem; - krb5_data inbuf; - krb5_tkt_authent *authdat; - krb5_data outbuf; - krb5_rcache rcache; - krb5_octet response; - krb5_data *server_name; - char *cachename; - extern krb5_deltat krb5_clockskew; - static char *rc_base = "rc_"; - - /* - * Zero out problem variable. If problem is set at the end of - * the intial version negotiation section, it means that we - * need to send an error code back to the client application - * and exit. - */ - problem = 0; - - /* - * Read and check the application version string. - */ - if (retval = krb5_read_message(fd, &inbuf)) - return(retval); - if (strcmp(inbuf.data, appl_version)) { - krb5_xfree(inbuf.data); - if (!problem) - problem = KRB5_SENDAUTH_BADAPPLVERS; - } - krb5_xfree(inbuf.data); - /* - * OK, now check the problem variable. If it's zero, we're - * fine and we can continue. Otherwise, we have to signal an - * error to the client side and bail out. - */ - switch (problem) { - case 0: - response = 0; - break; - case KRB5_SENDAUTH_BADAUTHVERS: - response = 1; - break; - case KRB5_SENDAUTH_BADAPPLVERS: - response = 2; - break; - default: - /* - * Should never happen! - */ - response = 255; -#ifdef SENDAUTH_DEBUG - fprintf(stderr, "Programming botch in recvauth! problem = %d", - problem); - abort(); -#endif - break; + if (auth_sys == KRB5_RECVAUTH_V4) { + /* We do not really know the remote user's login name. + * Assume it to be the same as the first component of the + * principal's name. + */ + strcpy(remuser, v4_kdata->pname); + kremuser = (char *) malloc(strlen(v4_kdata->pname) + 1 + + strlen(v4_kdata->pinst) + 1 + + strlen(v4_kdata->prealm) + 1); + sprintf(kremuser, "%s/%s@%s", v4_kdata->pname, + v4_kdata->pinst, v4_kdata->prealm); + + if (status = krb5_parse_name(kremuser, &client)) + return(status); + return 0; } - /* - * Now we actually write the response. If the response is non-zero, - * exit with a return value of problem - */ - if ((krb5_net_write(*((int *) fd), (char *)&response, 1)) < 0) { - return(problem); /* We'll return the top-level problem */ - } - if (problem) - return(problem); - rcache = NULL; -#ifdef WORKING_RCACHE - /* - * Setup the replay cache. - */ - if (!(rcache = (krb5_rcache) malloc(sizeof(*rcache)))) - problem = ENOMEM; - if (!problem) - problem = krb5_rc_resolve_type(&rcache, - rc_type ? rc_type : "dfl"); - cachename = NULL; - server_name = krb5_princ_component(server, 0); - if (!problem && !(cachename = malloc(server_name->length+1+strlen(rc_base)))) - problem = ENOMEM; - if (!problem) { - strcpy(cachename, rc_base ? rc_base : "rc_"); - strncat(cachename, server_name->data, server_name->length); - cachename[server_name->length+strlen(rc_base)] = '\0'; - problem = krb5_rc_resolve(rcache, cachename); - } - if (!problem) { - if (krb5_rc_recover(rcache)) - /* - * If the rc_recover didn't work, then try - * initializing the replay cache. - */ - problem = krb5_rc_initialize(rcache, krb5_clockskew); - if (problem) { - krb5_rc_close(rcache); - rcache = NULL; - } - } -#endif + /* Must be V5 */ + + getstr(netf, remuser, sizeof(locuser), "remuser"); - /* - * Now, let's read the AP_REQ message and decode it - */ - if (retval = krb5_read_message(fd, &inbuf)) { -#ifdef WORKING_RCACHE - (void) krb5_rc_close(rcache); - if (cachename) - free(cachename); -#endif - return(retval); - } - authdat = 0; /* so we can tell if we need to - free it later... */ - if (!problem) - problem = krb5_rd_req(&inbuf, server, sender_addr, fetch_from, - keyproc, keyprocarg, rcache, &authdat); - krb5_xfree(inbuf.data); -#ifdef WORKING_RCACHE - if (rcache) - retval = krb5_rc_close(rcache); -#endif - if (!problem && retval) - problem = retval; -#ifdef WORKING_RCACHE - if (cachename) - free(cachename); -#endif + if (status = krb5_unparse_name(client, &kremuser)) + return status; - /* - * If there was a problem, send back a krb5_error message, - * preceeded by the length of the krb5_error message. If - * everything's ok, send back 0 for the length. - */ - if (problem) { - krb5_error error; - const char *message; - - memset((char *)&error, 0, sizeof(error)); - krb5_us_timeofday(&error.stime, &error.susec); - error.server = server; - error.error = problem - ERROR_TABLE_BASE_krb5; - if (error.error > 127) - error.error = KRB_ERR_GENERIC; - message = error_message(problem); - error.text.length = strlen(message) + 1; - if (!(error.text.data = malloc(error.text.length))) - return(ENOMEM); - strcpy(error.text.data, message); - if (retval = krb5_mk_error(&error, &outbuf)) { - free(error.text.data); - return(retval); - } - free(error.text.data); - } else { - outbuf.length = 0; - outbuf.data = 0; - } - if (retval = krb5_write_message(fd, &outbuf)) { - if (outbuf.data) - krb5_xfree(outbuf.data); - if (!problem) - krb5_free_tkt_authent(authdat); - return(retval); - } - if (problem) { - /* - * We sent back an error, we need to return - */ - if (authdat) krb5_free_tkt_authent(authdat); - return(problem); + if (status = krb5_read_message((krb5_pointer)&netf, &inbuf)) { + error("Error reading message: %s\n", + error_message(status)); + exit(1); } - /* - * Here lies the mutual authentication stuff... - * - * We're going to compose and send a AP_REP message. - */ - if ((authdat->ap_options & AP_OPTS_MUTUAL_REQUIRED)) { - krb5_ap_rep_enc_part repl; - - /* - * Generate a random sequence number - */ - if (seq_number && - (retval = krb5_generate_seq_number(authdat->ticket->enc_part2->session, - seq_number))) { - krb5_free_tkt_authent(authdat); - return(retval); - } - - repl.ctime = authdat->authenticator->ctime; - repl.cusec = authdat->authenticator->cusec; - repl.subkey = authdat->authenticator->subkey; - if (seq_number) - repl.seq_number = *seq_number; - else - repl.seq_number = 0; - - if (retval = krb5_mk_rep(&repl, - authdat->ticket->enc_part2->session, - &outbuf)) { - krb5_free_tkt_authent(authdat); - return(retval); - } - if (retval = krb5_write_message(fd, &outbuf)) { - krb5_xfree(outbuf.data); - krb5_free_tkt_authent(authdat); - return(retval); + if (inbuf.length) { /* Forwarding being done, read creds */ + if (status = rd_and_store_for_creds(&inbuf, ticket, locuser)) { + error("Can't get forwarded credentials: %s\n", + error_message(status)); + exit(1); } - krb5_xfree(outbuf.data); } - - /* - * At this point, we've won. We just need to copy whatever - * parts of the authdat structure which the user wants, clean - * up, and exit. - */ - if (client) - if (retval = - krb5_copy_principal(authdat->ticket->enc_part2->client, - client)) - return(retval); - /* - * The following efficiency hack assumes knowledge about the - * structure of krb5_tkt_authent. If we later add additional - * allocated substructures to krb5_tkt_authent, they will have - * to be reflected here; otherwise, we will probably have a - * memory leak. - * - * If the user wants that part of the authdat structure, - * return it; otherwise free it. - */ - if (ticket) - *ticket = authdat->ticket; - else - krb5_free_ticket(authdat->ticket); - if (authent) - *authent = authdat->authenticator; - else - krb5_free_authenticator(authdat->authenticator); - krb5_xfree(authdat); + krb5_free_ticket(ticket); return 0; } |