From cfe0d7331bf6aa757e57e4e4b535db0f8b50cd00 Mon Sep 17 00:00:00 2001 From: Theodore Tso Date: Fri, 24 Dec 1993 22:45:23 +0000 Subject: [PATCH] Lots of cleanup. V4/V5 compatibility recvauth moved to separate library function. Folded in rest of GZA's patches. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@3278 dc483132-0cff-0310-8789-dd5450dbe970 --- src/appl/bsd/Imakefile | 4 +- src/appl/bsd/kcmd.c | 37 +- src/appl/bsd/krcp.c | 22 +- src/appl/bsd/krlogind.c | 718 ++++++++------------------------------- src/appl/bsd/krsh.c | 5 + src/appl/bsd/krshd.c | 619 +++++---------------------------- src/appl/bsd/login.c | 735 +++++++++++++++++++++++++++++++++++----- src/appl/bsd/logutil.c | 90 ++--- 8 files changed, 967 insertions(+), 1263 deletions(-) diff --git a/src/appl/bsd/Imakefile b/src/appl/bsd/Imakefile index 995c1ad9f..10bfa37a3 100644 --- a/src/appl/bsd/Imakefile +++ b/src/appl/bsd/Imakefile @@ -74,8 +74,8 @@ Krb5InstallServerProgram(krshd) NormalProgramTarget(krlogind,krlogind.o logutil.o kcmd.o forward.o,$(DEPLIBS),$(LOCAL_LIBRARIES),$(K4LIB)) Krb5InstallServerProgram(krlogind) -NormalProgramTarget(login.krb,login.o logutil.o setenv.o,,,) -InstallProgram(login.krb,$(SERVER_BINDIR)) +NormalProgramTarget(login.krb5,login.o logutil.o setenv.o,$(DEPLIBS),$(LOCAL_LIBRARIES),) +InstallProgram(login.krb5,$(SERVER_BINDIR)) #endif DependTarget() diff --git a/src/appl/bsd/kcmd.c b/src/appl/bsd/kcmd.c index 5e27f5cc0..542a35857 100644 --- a/src/appl/bsd/kcmd.c +++ b/src/appl/bsd/kcmd.c @@ -100,7 +100,7 @@ kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, service, realm, krb5_ap_rep_enc_part *rep_ret; krb5_checksum send_cksum; char *tmpstr = 0; - krb5_error *error; + krb5_error *error = 0; int sin_len; krb5_ccache cc; krb5_data outbuf; @@ -139,14 +139,19 @@ kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, service, realm, fprintf(stderr,"kcmd: no memory\n"); return(-1); } - if ((realm == NULL) || (realm[0] == '\0')) { - krb5_sname_to_principal(host_save,service,KRB5_NT_SRV_HST, - &ret_cred->server); - } - else { - sprintf(tmpstr,"%s/%s@%s",service,host_save,realm); - krb5_parse_name(tmpstr,&ret_cred->server); - } + krb5_sname_to_principal(host_save,service,KRB5_NT_SRV_HST, + &ret_cred->server); + if (realm && *realm) { + char *copyrealm; + krb5_data rdata; + + rdata.length = strlen(realm); + rdata.data = (char *) malloc(rdata.length+1); + strcpy(rdata.data, realm); + + /* XXX we should free the old realm first */ + krb5_princ_set_realm(ret_cred->server, &rdata); + } #ifdef sgi oldmask = sigignore(sigmask(SIGURG)); #else @@ -312,11 +317,17 @@ kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, service, realm, &error, /* No error return */ &rep_ret); if (status) { - printf("We have a sendauth error %d\n", error->error); - if (error->text.length) { - fprintf(stderr, "Text: %s\n", error->text.data); + printf("Couldn't authenticate to server: %s\n", error_message(status)); + if (error) { + printf("Server returned error code %d (%s)\n", error->error, + error_message(ERROR_TABLE_BASE_krb5 + error->error)); + if (error->text.length) { + fprintf(stderr, "Error text sent from server: %s\n", + error->text.data); + } + krb5_free_error(error); + error = 0; } - krb5_free_error(error); } if (status) goto bad3; if (rep_ret && server_seqno) { diff --git a/src/appl/bsd/krcp.c b/src/appl/bsd/krcp.c index ec0807a39..361574927 100644 --- a/src/appl/bsd/krcp.c +++ b/src/appl/bsd/krcp.c @@ -58,6 +58,7 @@ static char sccsid[] = "@(#)rcp.c 5.10 (Berkeley) 9/20/88"; #include #include #include +#include #ifdef KERBEROS #include @@ -102,7 +103,7 @@ int encryptflag = 0; #endif /* KERBEROS */ int rem; -char *colon(), *index(), *rindex(), *strcpy(); +char *colon(); int errs; krb5_sigtype lostconn(); int errno; @@ -273,7 +274,7 @@ main(argc, argv) /* Target machine is some remote machine */ if (*targ == 0) targ = "."; - thost = index(argv[argc - 1], '@'); + thost = strchr(argv[argc - 1], '@'); if (thost) { *thost++ = 0; tuser = argv[argc - 1]; @@ -291,7 +292,7 @@ main(argc, argv) *src++ = 0; if (*src == 0) src = "."; - host = index(argv[i], '@'); + host = strchr(argv[i], '@'); if (host) { *host++ = 0; suser = argv[i]; @@ -401,7 +402,7 @@ main(argc, argv) *src++ = 0; if (*src == 0) src = "."; - host = index(argv[i], '@'); + host = strchr(argv[i], '@'); if (host) { *host++ = 0; suser = argv[i]; @@ -576,7 +577,7 @@ source(argc, argv) error("rcp: %s: not a plain file\n", name); continue; } - last = rindex(name, '/'); + last = strrchr(name, '/'); if (last == 0) last = name; else @@ -653,7 +654,7 @@ rsource(name, statp) error("rcp: %s: %s\n", name, sys_errlist[errno]); return; } - last = rindex(name, '/'); + last = strrchr(name, '/'); if (last == 0) last = name; else @@ -1086,7 +1087,6 @@ void send_auth() char *princ; /* principal in credentials cache */ krb5_ccache cc; krb5_creds creds; - krb5_principal sprinc; /* principal of server */ krb5_data reply, msg, princ_data; krb5_tkt_authent *authdat; krb5_error_code status; @@ -1116,7 +1116,7 @@ void send_auth() krb5_cc_close(cc); exit(1); } - if (status = krb5_build_principal_ext(&sprinc, + if (status = krb5_build_principal_ext(&creds.server, krb5_princ_realm(creds.client)->length, krb5_princ_realm(creds.client)->data, 6, "krbtgt", @@ -1130,8 +1130,6 @@ void send_auth() exit(1); } - creds.server = sprinc; - /* Get TGT from credentials cache */ if (status = krb5_get_credentials(KRB5_GC_CACHED, cc, &creds)){ fprintf(stderr, @@ -1142,10 +1140,6 @@ void send_auth() } krb5_cc_close(cc); - krb5_free_principal(sprinc); /* creds.server is replaced - upon retrieval */ - - princ_data.data = princ; princ_data.length = strlen(princ_data.data) + 1; /* include null terminator for diff --git a/src/appl/bsd/krlogind.c b/src/appl/bsd/krlogind.c index d96abbd01..fdd3a31da 100644 --- a/src/appl/bsd/krlogind.c +++ b/src/appl/bsd/krlogind.c @@ -91,9 +91,6 @@ static char sccsid[] = "@(#)rlogind.c 5.17 (Berkeley) 8/31/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 if 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. @@ -174,21 +171,23 @@ struct winsize { #include #include #include +#include #ifdef BUFSIZ #undef BUFSIZ #endif -int V4 = 0; /* set when v4 client detected. */ +int auth_sys = 0; /* Which version of Kerberos used to authenticate */ + +#define KRB5_RECVAUTH_V4 4 +#define KRB5_RECVAUTH_V5 5 + int non_privileged = 0; /* set when connection is seen to be from */ /* a non-privileged port */ -#ifdef SERVE_V4 -#include + AUTH_DAT *v4_kdata; -KTEXT v4_ticket; -Key_schedule schedule; +Key_schedule v4_schedule; int v4_des_read(), v4_des_write(); -#endif #define BUFSIZ 5120 @@ -252,6 +251,16 @@ char *malloc(); #endif char *progname; +static int Pfd; + +#if (defined(_AIX) && defined(i386)) || defined(ibm032) || (defined(vax) && !defined(ultrix)) || (defined(SunOS) && SunOS > 40) || defined(solaris20) +#define VHANG_FIRST +#endif + +#if defined(ultrix) +#define VHANG_LAST /* vhangup must occur on close, not open */ +#endif + void fatal(), fatalperror(), doit(), usage(), do_krb_login(); int princ_maps_to_lname(), default_realm(); @@ -447,7 +456,7 @@ void doit(f, fromp) int f; struct sockaddr_in *fromp; { - int i, p, t, on = 1; + int i, p, t, vfd, on = 1; register struct hostent *hp; char c; char buferror[255]; @@ -512,6 +521,7 @@ void doit(f, fromp) write(f, "", 1); if (getpty(&p,line)) fatal(f, "Out of ptys"); + Pfd = p; #ifdef TIOCSWINSZ (void) ioctl(p, TIOCSWINSZ, &win); #endif @@ -521,13 +531,14 @@ void doit(f, fromp) /* Make sure we can open slave pty, then close it for system 5 so that the process group is set correctly..... */ - t = open(line, O_RDWR); - if (t < 0) +#ifdef VHANG_FIRST + vfd = open(line, O_RDWR); + if (vfd < 0) fatalperror(f, line); #ifdef NOFCHMOD - if (chmod(t,0)) + if (chmod(vfd,0)) #else - if (fchmod(t, 0)) + if (fchmod(vfd, 0)) #endif fatalperror(f, line); #ifndef SYSV @@ -536,18 +547,20 @@ void doit(f, fromp) vhangup(); signal(SIGHUP, SIG_DFL); } -#ifdef ultrix /* Someone needs to cleanup all this and have a consistant - way of associating controlling tty to a process. */ - setpgrp(); -#endif +#endif +#endif /* VHANG_FIRST */ #if defined (sun) || defined (POSIX) setsid(); #endif t = open(line, O_RDWR); +#ifdef VHANG_FIRST +#ifndef VHANG_NO_CLOSE + (void) close(vfd); +#endif +#endif /* VHANG_FIRST */ if (t < 0) fatalperror(f, line); -#endif #ifdef SYSV close(t); #endif @@ -600,7 +613,17 @@ void doit(f, fromp) pid = getpgrp(getpid()); #endif #endif - ioctl(t, TIOCSPGRP, &pid); +#ifdef POSIX /* solaris */ + /* we've already done setsid above. Just do tcsetpgrp here. */ + tcsetpgrp(0, pid); +#else +#ifndef hpux + ioctl(0, TIOCSPGRP, &pid); +#else + /* we've already done setsid above. Just do tcsetpgrp here. */ + tcsetpgrp(0, pid); +#endif +#endif /* posix */ pid = 0; /*reset pid incase exec fails*/ #endif #ifdef STREAMS @@ -684,9 +707,9 @@ void doit(f, fromp) execl(LOGIN_PROGRAM, "login", "-r", rhost_name, 0); #else if (passwd_req) - execl(LOGIN_PROGRAM, "login","-r", rhost_name, 0); + execl(LOGIN_PROGRAM, "login","-h", rhost_name, lusername, 0); else - execl(LOGIN_PROGRAM, "login", "-fr", rhost_name, 0); + execl(LOGIN_PROGRAM, "login", "-h", rhost_name, "-e", lusername, 0); #endif fatalperror(2, LOGIN_PROGRAM, errno); @@ -735,9 +758,11 @@ void doit(f, fromp) setpgrp(0, 0); #endif +#ifdef DO_NOT_USE_K_LOGIN /* Pass down rusername and lusername to login. */ (void) write(p, rusername, strlen(rusername) +1); (void) write(p, lusername, strlen(lusername) +1); +#endif /* stuff term info down to login */ if( write(p, term, strlen(term)+1) <= 0 ){ /* @@ -950,6 +975,10 @@ int cleanup() *p = 'p'; (void)chmod(line, 0666); (void)chown(line, 0, 0); +#endif +#ifdef VHANG_LAST + close(Pfd); + vhangup(); #endif shutdown(netf, 2); exit(1); @@ -1038,7 +1067,7 @@ do_krb_login(host) if (client && krb5_kuserok(client, lusername)) passed_krb++; #else - if (V4) { + if (auth_sys == KRB5_RECVAUTH_V4) { /* kuserok returns 0 if OK */ if (!kuserok(v4_kdata, lusername)) passed_krb++; @@ -1348,60 +1377,92 @@ krb5_error_code recvauth() { krb5_error_code status; - struct sockaddr_in peersin; + struct sockaddr_in peersin, laddr; char krb_vers[KRB_SENDAUTH_VLEN + 1]; int len; - + krb5_principal server; + krb5_address peeraddr; + krb5_data inbuf; + char v4_instance[INST_SZ]; /* V4 Instance */ + char v4_version[9]; + + len = sizeof(laddr); + if (getsockname(netf, (struct sockaddr *)&laddr, &len)) { + exit(1); + } + len = sizeof(peersin); if (getpeername(netf, (struct sockaddr *)&peersin, &len)) { syslog(LOG_ERR, "get peer name failed %d", netf); exit(1); } - len = sizeof(int); - if ((status = krb5_net_read(netf, krb_vers, len)) != len) - return((status < 0) ? errno : ECONNABORTED); +#ifdef unicos61 +#define SIZEOF_INADDR SIZEOF_in_addr +#else +#define SIZEOF_INADDR sizeof(struct in_addr) +#endif - krb_vers[len] = '\0'; + peeraddr.addrtype = peersin.sin_family; + peeraddr.length = SIZEOF_INADDR; + peeraddr.contents = (krb5_octet *)&peersin.sin_addr; + + 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); + } - 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; + 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 */ + + do_encrypt ? KOPT_DO_MUTUAL : 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, v4_schedule, v4_version); + + if (status) { + if (auth_sys == KRB5_RECVAUTH_V5) { + /* + * clean up before exiting + */ + getstr(netf, lusername, sizeof (lusername), "locuser"); + getstr(netf, term, sizeof(term), "Terminal type"); + getstr(netf, rusername, sizeof(rusername), "remuser"); + } + return status; + } - V4 = 1; /* Set flag for rest of code */ + getstr(netf, lusername, sizeof (lusername), "locuser"); + getstr(netf, term, sizeof(term), "Terminal type"); + + if (auth_sys == KRB5_RECVAUTH_V4) { des_read = v4_des_read; des_write = v4_des_write; - if (do_encrypt) - authoptions = KOPT_DO_MUTUAL; - else - authoptions = 0L; - - len = sizeof(faddr); - if (getsockname(netf, (struct sockaddr *)&faddr, &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, "", - schedule, version)) { - return(status); - } - - getstr(netf, lusername, sizeof (lusername), "locuser"); - getstr(netf, term, sizeof(term), "Terminal type"); /* 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. @@ -1415,523 +1476,40 @@ recvauth() if (status = krb5_parse_name(krusername, &client)) return(status); -#else - syslog(LOG_ERR, "Kerberos V4 authentication: rejected!"); - fatal(netf, "Permission denied"); -#endif - } - else if (isprint(krb_vers[0])) { - /* Un-kerberized rlogin client */ -#ifdef SERVE_NON_KRB - des_read = read; - des_write = write; - - strncpy(rusername, krb_vers, sizeof(int)); - getstr(netf, rusername+4, sizeof(rusername)-sizeof(int), "remuser"); - getstr(netf, lusername, sizeof(lusername), "locuser"); - getstr(netf, term, sizeof(term), "Terminal type"); -#else - syslog(LOG_ERR, "Un-kerberized client: authentication rejected!"); - fatal(netf, "Permission denied"); -#endif + return 0; } - else { - /* Must be V5 rlogin client */ - krb5_principal server; - krb5_address peeraddr; - krb5_data inbuf; - - des_read = v5_des_read; - des_write = v5_des_write; - - /* - * First read the sendauth version string and check it. - */ - inbuf.length = ntohl(*((int *) krb_vers)); - if (inbuf.length < 0 || inbuf.length > 25) - return 255; + /* Must be V5 */ - 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); - } + des_read = v5_des_read; + des_write = v5_des_write; - if (strcmp(inbuf.data, "KRB5_SENDAUTH_V1.0")) { - krb5_xfree(inbuf.data); - status = KRB5_SENDAUTH_BADAUTHVERS; - return status; - } - krb5_xfree(inbuf.data); + getstr(netf, rusername, sizeof(rusername), "remuser"); -#ifdef unicos61 -#define SIZEOF_INADDR SIZEOF_in_addr -#else -#define SIZEOF_INADDR sizeof(struct in_addr) -#endif - - peeraddr.addrtype = peersin.sin_family; - peeraddr.length = SIZEOF_INADDR; - peeraddr.contents = (krb5_octet *)&peersin.sin_addr; - - 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); - } - - 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 v5srvtab */ - 0, /* no keyproc */ - 0, /* no keyproc arg */ - 0, /* no rc_type */ - 0, /* no seq number */ - &client, /* return client */ - &ticket, /* return ticket */ - &kdata /* return authenticator */ - )) { - /* Dummy forwarding reads */ - if (status = krb5_read_message((krb5_pointer)&netf, &inbuf)) - fatal(netf, "Error reading message"); - if (status = krb5_read_message((krb5_pointer)&netf, &inbuf)) - fatal(netf, "Error reading message"); - - /* Dont exit out for klogin, but - grab locuser, terminal, and remuser. - */ - getstr(netf, lusername, sizeof(lusername), "locuser"); - getstr(netf, term, sizeof(term), "Terminal type"); - getstr(netf, rusername, sizeof(rusername), "remuser"); - return status; - } - - if (status = krb5_unparse_name(client, &krusername)) - return status; + if (status = krb5_unparse_name(client, &krusername)) + return status; - /* Setup up eblock if encrypted login session */ - /* otherwise zero out session key */ - if (do_encrypt) { - krb5_use_keytype(&eblock, - ticket->enc_part2->session->keytype); - if (status = krb5_process_key(&eblock, - ticket->enc_part2->session)) - fatal(netf, "Permission denied"); - } - - getstr(netf, lusername, sizeof(lusername), "locuser"); - getstr(netf, term, sizeof(term), "Terminal type"); - getstr(netf, rusername, sizeof(rusername), "remuser"); - - if (status = krb5_read_message((krb5_pointer)&netf, &inbuf)) - fatal(netf, "Error reading message"); - - if (inbuf.length) { /* Forwarding being done, read creds */ - if (status = rd_and_store_for_creds(&inbuf, ticket, lusername)) - fatal(netf, "Can't get forwarded credentials"); - } + /* Setup up eblock if encrypted login session */ + /* otherwise zero out session key */ + if (do_encrypt) { + krb5_use_keytype(&eblock, + ticket->enc_part2->session->keytype); + if (status = krb5_process_key(&eblock, + ticket->enc_part2->session)) + fatal(netf, "Permission denied"); + } + + if (status = krb5_read_message((krb5_pointer)&netf, &inbuf)) + fatal(netf, "Error reading message"); + + if (inbuf.length) { /* Forwarding being done, read creds */ + if (status = rd_and_store_for_creds(&inbuf, ticket, lusername)) + fatal(netf, "Can't get forwarded credentials"); } 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; - 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. - */ - if (rem = krb_rd_req(ticket,service,instance,faddr->sin_addr.s_addr, - kdata,filename)) - return(KFAILURE); - - /* 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); - } - } - return(0); -} - -#endif /* SERVE_V4 */ - -extern krb5_flags krb5_kdc_default_options; - -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; - } - - /* - * 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 - - /* - * 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 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); - } - /* - * 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); - } - 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); - return 0; -} - #ifdef SERVE_V4 int @@ -1982,7 +1560,7 @@ int len; (void) pcbc_encrypt(des_inbuf, storage, (net_len < 8) ? 8 : net_len, - schedule, + v4_schedule, v4_kdata->session, DECRYPT); /* @@ -2054,7 +1632,7 @@ int len; (void) pcbc_encrypt((len < 8) ? garbage_buf : buf, des_outbuf, (len < 8) ? 8 : len, - schedule, + v4_schedule, v4_kdata->session, ENCRYPT); diff --git a/src/appl/bsd/krsh.c b/src/appl/bsd/krsh.c index 194ef9700..8e878b308 100644 --- a/src/appl/bsd/krsh.c +++ b/src/appl/bsd/krsh.c @@ -77,10 +77,15 @@ krb5_sigtype sendsig(); char *krb_realm = (char *)0; void try_normal(); #define UCB_RSH "/usr/ucb/rsh" +#endif + +#ifndef RLOGIN_PROGRAM +#ifdef KERBEROS #define RLOGIN_PROGRAM KRB5_PATH_RLOGIN #else /* KERBEROS */ #define RLOGIN_PROGRAM "/usr/ucb/rlogin" #endif /* KERBEROS */ +#endif /* !RLOGIN_PROGRAM */ #define mask(s) (1 << ((s) - 1)) diff --git a/src/appl/bsd/krshd.c b/src/appl/bsd/krshd.c index 8ea384019..6e4cf677c 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 #include #include +#include #ifdef sun #include @@ -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 @@ -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; } diff --git a/src/appl/bsd/login.c b/src/appl/bsd/login.c index 55118414a..e09a80f33 100644 --- a/src/appl/bsd/login.c +++ b/src/appl/bsd/login.c @@ -40,15 +40,22 @@ static char sccsid[] = "@(#)login.c 5.25 (Berkeley) 1/6/89"; * login -r hostname (for rlogind) * login -h hostname (for telnetd, etc.) * login -f name (for pre-authenticated login: datakit, xterm, etc.) + * login -e name (for pre-authenticated encrypted, must do term + * negotiation) + * ifdef KRB4 + * login -k hostname (for Kerberos V4 rlogind with password access) + * login -K hostname (for Kerberos V4 rlogind with restricted access) + * endif KRB4 + * + * only one of: -r -f -e -k -K + * only one of: -r -h -k -K */ -#define VFS -#define BYPASS_ROOT_CHK - +#include #include -#ifndef VFS +#ifdef OQUOTA #include -#endif VFS +#endif #include #include #include @@ -57,7 +64,11 @@ static char sccsid[] = "@(#)login.c 5.25 (Berkeley) 1/6/89"; #include #include + +#if !defined(_AIX) #include +#endif + #include #ifndef NOTTYENT #include @@ -68,9 +79,34 @@ static char sccsid[] = "@(#)login.c 5.25 (Berkeley) 1/6/89"; #include #include #include - +#ifdef KRB4 +#include #include -#include +#include +#ifdef BIND_HACK +#include +#include +#endif /* BIND_HACK */ +#endif /* KRB4 */ + +#ifdef POSIX +#include +#include +#ifdef _AIX +#include +#endif +#endif + +#ifdef _IBMR2 +#include +#include +#endif + +#if defined(_AIX) +#define PRIO_OFFSET 20 +#else +#define PRIO_OFFSET 0 +#endif #ifdef UIDGID_T uid_t getuid(); @@ -91,13 +127,24 @@ int getuid(); #define LASTLOG "/usr/adm/lastlog" #define BSHELL "/bin/sh" -#ifdef VFS +#if !defined(OQUOTA) && !defined(QUOTAWARN) #define QUOTAWARN "/usr/ucb/quota" /* warn user about quotas */ -#endif VFS +#endif + +#define PROTOTYPE_DIR "/usr/athena/lib/prototype_tmpuser" +#define TEMP_DIR_PERM 0711 + +#define NOATTACH "/etc/noattach" +#define NOCREATE "/etc/nocreate" +#define NOREMOTE "/etc/noremote" +#define REGISTER "/usr/etc/go_register" +#define GET_MOTD "/bin/athena/get_message" #define UT_HOSTSIZE sizeof(((struct utmp *)0)->ut_host) #define UT_NAMESIZE sizeof(((struct utmp *)0)->ut_name) +#define MAXENVIRON 32 + /* * This bounds the time given to login. Not a define so it can * be patched on machines where it's too small. @@ -107,6 +154,7 @@ int timeout = 300; struct passwd *pwd; char term[64], *hostname, *username; +#ifndef POSIX struct sgttyb sgttyb; struct tchars tc = { CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK @@ -114,20 +162,49 @@ struct tchars tc = { struct ltchars ltc = { CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT }; +#endif extern int errno; +#ifdef KRB4 +#define KRB_ENVIRON "KRBTKFILE" /* Ticket file environment variable */ +#define KRB_TK_DIR "/tmp/tkt_" /* Where to put the ticket */ +#define MAXPWSIZE 128 /* Biggest string accepted for KRB4 + passsword */ + +extern char *krb_err_txt[]; /* From libkrb */ + +AUTH_DAT *kdata = (AUTH_DAT *) NULL; +KTEXT ticket = (KTEXT) NULL; +char tkfile[MAXPATHLEN]; +int krbflag = 0; /* set if tickets have been obtained */ +#ifdef SETPAG +int pagflag = 0; /* true if setpag() has been called */ +#endif /* SETPAG */ +#endif /* KRB4 */ + +char *getenv(); +char *strsave(); +void dofork(); + #ifdef POSIX typedef void sigtype; #else typedef int sigtype; #endif /* POSIX */ -#define EXCL_TEST if (rflag || hflag) { \ - fprintf(stderr, \ - "login: only one of -r and -h allowed.\n"); \ - exit(1);\ - } +#define EXCL_AUTH_TEST if (rflag || kflag || Kflag || eflag) { \ + fprintf(stderr, \ + "login: only one of -r, -k, -K, -e, and -f allowed.\n"); \ + exit(1);\ + } + +#define EXCL_HOST_TEST if (rflag || kflag || Kflag || hflag) { \ + fprintf(stderr, \ + "login: only one of -r, -k, -K, and -h allowed.\n"); \ + exit(1);\ + } + main(argc, argv) int argc; char **argv; @@ -135,53 +212,62 @@ main(argc, argv) extern int optind; extern char *optarg, **environ; struct group *gr; - register int ch; + register int ch, i; register char *p; int fflag, hflag, pflag, rflag, cnt; + int kflag, Kflag, eflag; int quietlog, passwd_req, ioctlval; sigtype timedout(); - char *domain, *salt, *envinit[1], *ttyn, *tty; + char *domain, *salt, **envinit, *ttyn, *tty, *ktty; char tbuf[MAXPATHLEN + 2]; char *ttyname(), *stypeof(), *crypt(), *getpass(); - time_t time(); + time_t time(), login_time; off_t lseek(); - struct hostent *hp; +#ifdef POSIX + struct termios tc; +#endif (void)signal(SIGALRM, timedout); (void)alarm((u_int)timeout); (void)signal(SIGQUIT, SIG_IGN); (void)signal(SIGINT, SIG_IGN); - (void)setpriority(PRIO_PROCESS, 0, 0); -#ifndef VFS + (void)setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET); +#ifdef OQUOTA (void)quota(Q_SETUID, 0, 0, 0); -#endif VFS +#endif /* * -p is used by getty to tell login not to destroy the environment * -r is used by rlogind to cause the autologin protocol; * -f is used to skip a second login authentication + * -e is used to skip a second login authentication, but allows + * login as root. * -h is used by other servers to pass the name of the * remote host to login so that it may be placed in utmp and wtmp + * -k is used by klogind to cause the Kerberos V4 autologin protocol; + * -K is used by klogind to cause the Kerberos V4 autologin + * protocol with restricted access. */ (void)gethostname(tbuf, sizeof(tbuf)); - domain = index(tbuf, '.'); + domain = strchr(tbuf, '.'); - fflag = hflag = pflag = rflag = 0; + fflag = hflag = pflag = rflag = kflag = Kflag = eflag = 0; passwd_req = 1; - while ((ch = getopt(argc, argv, "fh:pr:")) != EOF) + while ((ch = getopt(argc, argv, "feh:pr:k:K:")) != EOF) switch (ch) { case 'f': + EXCL_AUTH_TEST; fflag = 1; break; case 'h': - EXCL_TEST; + EXCL_HOST_TEST; if (getuid()) { fprintf(stderr, "login: -h for super-user only.\n"); exit(1); } hflag = 1; - if (domain && (p = index(optarg, '.')) && + if (domain && (p = strchr(optarg, '.')) && strcmp(p, domain) == 0) *p = 0; hostname = optarg; @@ -190,7 +276,8 @@ main(argc, argv) pflag = 1; break; case 'r': - EXCL_TEST; + EXCL_AUTH_TEST; + EXCL_HOST_TEST; if (getuid()) { fprintf(stderr, "login: -r for super-user only.\n"); @@ -203,14 +290,51 @@ main(argc, argv) } rflag = 1; passwd_req = (doremotelogin(optarg) == -1); - if (domain && (p = index(optarg, '.')) && + if (domain && (p = strchr(optarg, '.')) && !strcmp(p, domain)) *p = '\0'; hostname = optarg; break; +#ifdef KRB4 + case 'k': + case 'K': + EXCL_AUTH_TEST; + EXCL_HOST_TEST; + if (getuid()) { + fprintf(stderr, + "login: -%c for super-user only.\n", ch); + exit(1); + } + /* "-k hostname" must be last args */ + if (optind != argc) { + fprintf(stderr, "Syntax error.\n"); + exit(1); + } + if (ch == 'K') + Kflag = 1; + else + kflag = 1; + passwd_req = (do_krb_login(optarg, + Kflag ? 1 : 0) == -1); + if (domain && (p = strchr(optarg, '.')) && + !strcmp(p, domain)) + *p = '\0'; + hostname = optarg; + break; +#endif /* KRB4 */ + case 'e': + EXCL_AUTH_TEST; + if (getuid()) { + fprintf(stderr, + "login: -e for super-user only.\n"); + exit(1); + } + eflag = 1; + passwd_req = 0; + break; case '?': default: - fprintf(stderr, "usage: login [-fp] [-h hostname] [-r hostname] [username] \n"); + fprintf(stderr, "usage: login [-fp] [username]\n"); exit(1); } argc -= optind; @@ -218,34 +342,69 @@ main(argc, argv) if (*argv) username = *argv; - if (!(hp = gethostbyname(hostname))) { - fprintf(stderr, "Unknown host: %s\n", hostname); - exit(1); - } - hostname = malloc(strlen(hp->h_name)+1); - if (!hostname) { - fprintf(stderr, "Couldn't malloc space for hostname.\n"); - exit(1); - } - strcpy(hostname, hp->h_name); - +#if !defined(_AIX) ioctlval = 0; (void)ioctl(0, TIOCLSET, (char *)&ioctlval); (void)ioctl(0, TIOCNXCL, (char *)0); (void)fcntl(0, F_SETFL, ioctlval); +#endif +#ifdef POSIX + (void)tcgetattr(0, &tc); +#else (void)ioctl(0, TIOCGETP, (char *)&sgttyb); +#endif /* * If talking to an rlogin process, propagate the terminal type and * baud rate across the network. */ - if (rflag) + if (eflag) + lgetstr(term, sizeof(term), "Terminal type"); +#ifdef POSIX + if (rflag || kflag || Kflag || eflag) + doremoteterm(&tc); + tc.c_cc[VMIN] = 1; + tc.c_cc[VTIME] = 0; + tc.c_cc[VERASE] = CERASE; + tc.c_cc[VKILL] = CKILL; + tc.c_cc[VEOF] = CEOF; + tc.c_cc[VINTR] = CINTR; + tc.c_cc[VQUIT] = CQUIT; + tc.c_cc[VSTART] = CSTART; + tc.c_cc[VSTOP] = CSTOP; + tc.c_cc[VEOL] = CNUL; + /* The following are common extensions to POSIX */ +#ifdef VEOL2 + tc.c_cc[VEOL2] = CNUL; +#endif +#ifdef VSUSP + tc.c_cc[VSUSP] = CSUSP; +#endif +#ifdef VDSUSP + tc.c_cc[VDSUSP] = CDSUSP; +#endif +#ifdef VLNEXT + tc.c_cc[VLNEXT] = CLNEXT; +#endif +#ifdef VREPRINT + tc.c_cc[VREPRINT] = CRPRNT; +#endif +#ifdef VDISCRD + tc.c_cc[VDISCRD] = CFLUSH; +#endif +#ifdef VWERSE + tc.c_cc[VWERSE] = CWERASE; +#endif + tcsetattr(0, TCSANOW, &tc); +#else + if (rflag || kflag || Kflag || eflag) doremoteterm(&sgttyb); sgttyb.sg_erase = CERASE; sgttyb.sg_kill = CKILL; (void)ioctl(0, TIOCSLTC, (char *)<c); (void)ioctl(0, TIOCSETC, (char *)&tc); (void)ioctl(0, TIOCSETP, (char *)&sgttyb); +#endif for (cnt = getdtablesize(); cnt > 2; cnt--) (void) close(cnt); @@ -253,11 +412,19 @@ main(argc, argv) ttyn = ttyname(0); if (ttyn == NULL || *ttyn == '\0') ttyn = "/dev/tty??"; - if (tty = rindex(ttyn, '/')) + + /* This allows for tty names of the form /dev/pts/4 as well */ + if ((tty = strchr(ttyn, '/')) && (tty = strchr(tty+1, '/'))) ++tty; else tty = ttyn; + /* For kerberos tickets, extract only the last part of the ttyname */ + if (ktty = strrchr(tty, '/')) + ++ktty; + else + ktty = tty; + #ifndef LOG_ODELAY /* 4.2 syslog ... */ openlog("login", 0); #else @@ -265,13 +432,28 @@ main(argc, argv) #endif /* 4.2 syslog */ for (cnt = 0;; username = NULL) { +#ifdef KRB4 + char pp[9], pp2[MAXPWSIZE], *namep; + int krbval; + char realm[REALM_SZ]; + int kpass_ok,lpass_ok; +#ifdef NOENCRYPTION +#define read_long_pw_string placebo_read_pw_string +#else +#define read_long_pw_string des_read_pw_string +#endif + int read_long_pw_string(); +#endif /* KRB4 */ +#if !defined(_IBMR2) ioctlval = 0; (void)ioctl(0, TIOCSETD, (char *)&ioctlval); +#endif if (username == NULL) { fflag = 0; getloginname(); } + if (pwd = getpwnam(username)) salt = pwd->pw_passwd; else @@ -288,12 +470,8 @@ main(argc, argv) if (fflag && pwd) { int uid = (int) getuid(); - passwd_req = (uid && uid != pwd->pw_uid) -#ifndef BYPASS_ROOT_CHK - || (pwd->pw_uid == 0); -#else - ; -#endif + passwd_req = pwd->pw_uid == 0 || + (uid && uid != pwd->pw_uid); } /* @@ -303,11 +481,115 @@ main(argc, argv) if (!passwd_req || pwd && !*pwd->pw_passwd) break; - (void) setpriority(PRIO_PROCESS, 0, -4); - p = crypt(getpass("Password:"), salt); - (void) setpriority(PRIO_PROCESS, 0, 0); +#ifdef KRB4 + kpass_ok = 0; + lpass_ok = 0; + + (void) setpriority(PRIO_PROCESS, 0, -4 + PRIO_OFFSET); + if (read_long_pw_string(pp2, sizeof(pp2)-1, "Password: ", 0)) { + /* reading password failed... */ + (void) setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET); + goto bad_login; + } + if (!pwd) /* avoid doing useless work */ + goto bad_login; + + /* Modifications for Kerberos authentication -- asp */ + (void) strncpy(pp, pp2, sizeof(pp)); + pp[8]='\0'; + namep = crypt(pp, pwd->pw_passwd); + bzero (pp, sizeof(pp)); /* To the best of my recollection, Senator... */ + lpass_ok = !strcmp (namep, pwd->pw_passwd); + + if (pwd->pw_uid != 0) { /* Don't get tickets for root */ + + if (krb_get_lrealm(realm, 1) != KSUCCESS) { + (void) strncpy(realm, KRB_REALM, sizeof(realm)); + } +#ifdef BIND_HACK + /* Set name server timeout to be reasonable, + so that people don't take 5 minutes to + log in. Can you say abstraction violation? */ + _res.retrans = 1; +#endif /* BIND_HACK */ +#if 0 /* XXX krb5 has defaults; don't do this. */ + /* Set up the ticket file environment variable */ + strncpy(tkfile, KRB_TK_DIR, sizeof(tkfile)); + strncat(tkfile, ktty, + sizeof(tkfile) - strlen(tkfile) - 1); + (void) setenv(KRB_ENVIRON, tkfile, 1); + krb_set_tkt_string(tkfile); +#endif + +#ifdef _IBMR2 + krbval = setuidx(ID_REAL|ID_EFFECTIVE, pwd->pw_uid); +#else + krbval = setreuid(pwd->pw_uid, -1); +#endif + if (krbval) { + /* can't set ruid to user! */ + krbval = -1; + fprintf(stderr, + "login: Can't set ruid for ticket file.\n"); + } else + krbval = krb_get_pw_in_tkt(username, "", + realm, "krbtgt", + realm, + DEFAULT_TKT_LIFE, pp2); + bzero (pp2, sizeof(pp2)); + (void) setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET); + switch (krbval) { + case INTK_OK: + kpass_ok = 1; + krbflag = 1; + break; + + /* These errors should be silent */ + /* So the Kerberos database can't be probed */ + case KDC_NULL_KEY: + case KDC_PR_UNKNOWN: + case INTK_BADPW: + case KDC_PR_N_UNIQUE: + case -1: + break; + /* These should be printed but are not fatal */ + case INTK_W_NOTALL: + krbflag = 1; + kpass_ok = 1; + fprintf(stderr, "Kerberos error: %s\n", + krb_err_txt[krbval]); + break; + default: + fprintf(stderr, "Kerberos error: %s\n", + krb_err_txt[krbval]); + break; + } + } else { + (void) bzero (pp2, sizeof(pp2)); + (void) setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET); + } + + /* Policy: If local password is good, user is good. + We really can't trust the Kerberos password, + because somebody on the net could spoof the + Kerberos server (not easy, but possible). + Some sites might want to use it anyways, in + which case they should change this line + to: + if (kpass_ok) + */ + if (lpass_ok) + break; +bad_login: + if (krbflag) + dest_tkt(); /* clean up tickets if login fails */ +#else /* !KRB4 */ + (void) setpriority(PRIO_PROCESS, 0, -4 + PRIO_OFFSET); + p = crypt(getpass("password:"), salt); + (void) setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET); if (pwd && !strcmp(p, pwd->pw_passwd)) break; +#endif /* KRB4 */ printf("Login incorrect\n"); if (++cnt >= 5) { @@ -331,9 +613,10 @@ main(argc, argv) /* * If valid so far and root is logging in, see if root logins on * this terminal are permitted. + * + * We allow authenticated remote root logins (except -r style) */ -#ifndef BYPASS_ROOT_CHK - if (pwd->pw_uid == 0 && !rootterm(tty)) { + if (pwd->pw_uid == 0 && !rootterm(tty) && (passwd_req || rflag)) { if (hostname) syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s FROM %.*s", tty, UT_HOSTSIZE, hostname); @@ -342,9 +625,8 @@ main(argc, argv) printf("Login incorrect\n"); sleepexit(1); } -#endif -#ifndef VFS +#ifdef OQUOTA if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { switch(errno) { case EUSERS: @@ -360,7 +642,7 @@ main(argc, argv) } sleepexit(0); } -#endif /* !VFS */ +#endif if (chdir(pwd->pw_dir) < 0) { printf("No directory %s!\n", pwd->pw_dir); @@ -374,7 +656,8 @@ main(argc, argv) { struct utmp utmp; - (void)time(&utmp.ut_time); + bzero((char *)&utmp, sizeof(utmp)); + login_time = time(&utmp.ut_time); (void) strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); if (hostname) (void) strncpy(utmp.ut_host, hostname, @@ -388,7 +671,7 @@ main(argc, argv) quietlog = access(HUSHLOGIN, F_OK) == 0; dolastlog(quietlog, tty); - if (!hflag && !rflag) { /* XXX */ + if (!hflag && !rflag && !kflag && !Kflag && !eflag) { /* XXX */ static struct winsize win = { 0, 0, 0, 0 }; (void)ioctl(0, TIOCSWINSZ, (char *)&win); @@ -396,48 +679,144 @@ main(argc, argv) (void)chown(ttyn, pwd->pw_uid, (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); +#ifdef KRB4 + if(krbflag) + (void) chown(getenv(KRB_ENVIRON), pwd->pw_uid, pwd->pw_gid); +#endif (void)chmod(ttyn, 0620); - +#ifdef KRB4 +#ifdef SETPAG + if (pwd->pw_uid) { + /* Only reset the pag for non-root users. */ + /* This allows root to become anything. */ + pagflag = 1; + setpag(); + } +#endif + /* Fork so that we can call kdestroy */ + dofork(); +#endif /* KRB4 */ (void)setgid((gid_type) pwd->pw_gid); - (void) initgroups(username, pwd->pw_gid); -#ifndef VFS +#ifdef OQUOTA quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); #endif - (void)setuid((uid_type) pwd->pw_uid); + /* This call MUST succeed */ +#ifdef _IBMR2 + setuidx(ID_LOGIN, pwd->pw_uid); +#endif + if(setuid((uid_type) pwd->pw_uid) < 0) { + perror("setuid"); + sleepexit(1); + } if (*pwd->pw_shell == '\0') pwd->pw_shell = BSHELL; /* turn on new line discipline for the csh */ else if (!strcmp(pwd->pw_shell, "/bin/csh")) { +#if !defined(_IBMR2) ioctlval = NTTYDISC; (void)ioctl(0, TIOCSETD, (char *)&ioctlval); +#endif } /* destroy environment unless user has requested preservation */ + envinit = (char **)malloc(MAXENVIRON * sizeof(char *)); + if (envinit == 0) { + fprintf(stderr, "Can't malloc empty environment.\n"); + sleepexit(1); + } if (!pflag) environ = envinit; - (void)setenv("HOME", pwd->pw_dir, 1); - (void)setenv("SHELL", pwd->pw_shell, 1); + + i = 0; + +#if defined(_AIX) && defined(_IBMR2) + { + FILE *fp; + if ((fp = fopen("/etc/environment", "r")) != NULL) { + while(fgets(tbuf, sizeof(tbuf), fp)) { + if ((tbuf[0] == '#') || (strchr(tbuf, '=') == 0)) + continue; + for (p = tbuf; *p; p++) + if (*p == '\n') { + *p = '\0'; + break; + } + envinit[i++] = strsave(tbuf); + } + fclose(fp); + } + } +#endif + sprintf(tbuf,"LOGNAME=%s",pwd->pw_name); + envinit[i++] = strsave(tbuf); + sprintf(tbuf,"LOGIN=%s",pwd->pw_name); + envinit[i++] = strsave(tbuf); + + envinit[i++] = NULL; + + setenv("HOME", pwd->pw_dir, 0); + setenv("PATH", "/usr/local/krb5/bin:/usr/local/bin:/usr/bin/X11:/usr/ucb:/bin:/usr/bin:.", 0); + setenv("USER", pwd->pw_name, 0); + setenv("SHELL", pwd->pw_shell, 0); + if (term[0] == '\0') (void) strncpy(term, stypeof(tty), sizeof(term)); (void)setenv("TERM", term, 0); - (void)setenv("USER", pwd->pw_name, 1); - (void)setenv("PATH", ":/usr/ucb:/bin:/usr/bin", 0); +#ifdef KRB4 + /* tkfile[0] is only set if we got tickets above */ + if (tkfile[0]) + (void) setenv(KRB_ENVIRON, tkfile, 1); +#endif /* KRB4 */ + +#if 0 + strcpy(wgfile, "/tmp/wg.XXXXXX"); + mktemp(wgfile); + setenv("WGFILE", wgfile, 0); +#endif if (tty[sizeof("tty")-1] == 'd') syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); if (pwd->pw_uid == 0) if (hostname) +#ifdef KRB4 + if (kdata) { + /* @*$&@#*($)#@$ syslog doesn't handle very + many arguments */ + char buf[BUFSIZ]; + (void) sprintf(buf, + "ROOT LOGIN (krb) %s from %.*s, %s.%s@%s", + tty, UT_HOSTSIZE, hostname, + kdata->pname, kdata->pinst, + kdata->prealm); + syslog(LOG_NOTICE, buf); + } else { +#endif /* KRB4 */ syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s", tty, UT_HOSTSIZE, hostname); +#ifdef KRB4 + } + else + if (kdata) { + syslog(LOG_NOTICE, + "ROOT LOGIN (krb) %s, %s.%s@%s", + tty, + kdata->pname, kdata->pinst, + kdata->prealm); + } +#endif /* KRB4 */ else syslog(LOG_NOTICE, "ROOT LOGIN %s", tty); if (!quietlog) { struct stat st; +#ifdef KRB4 + if (!krbflag) + printf("\nWarning: No Kerberos tickets obtained.\n\n"); +#endif /* KRB4 */ motd(); (void)sprintf(tbuf, "%s/%s", MAILDIR, pwd->pw_name); if (stat(tbuf, &st) == 0 && st.st_size != 0) @@ -445,16 +824,16 @@ main(argc, argv) (st.st_mtime > st.st_atime) ? "new " : ""); } -#ifdef VFS +#ifndef OQUOTA if (! access( QUOTAWARN, X_OK)) (void) system(QUOTAWARN); -#endif VFS +#endif (void)signal(SIGALRM, SIG_DFL); (void)signal(SIGQUIT, SIG_DFL); (void)signal(SIGINT, SIG_DFL); (void)signal(SIGTSTP, SIG_IGN); tbuf[0] = '-'; - (void) strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ? + (void) strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ? p + 1 : pwd->pw_shell); execlp(pwd->pw_shell, tbuf, 0); fprintf(stderr, "login: no shell: "); @@ -496,7 +875,7 @@ timedout() } #ifdef NOTTYENT -int root_tty_security = 0; +int root_tty_security = 1; #endif rootterm(tty) char *tty; @@ -507,7 +886,7 @@ rootterm(tty) struct ttyent *t; return((t = getttynam(tty)) && t->ty_status&TTY_SECURE); -#endif NOTTYENT +#endif /* NOTTYENT */ } jmp_buf motdinterrupt; @@ -520,7 +899,7 @@ motd() if ((fd = open(MOTDFILE, O_RDONLY, 0)) < 0) return; - oldint = (sigtype (*)())signal(SIGINT, sigint); + oldint = signal(SIGINT, sigint); if (setjmp(motdinterrupt) == 0) while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) (void)write(fileno(stdout), tbuf, nchars); @@ -550,6 +929,7 @@ dolastlog(quiet, tty) int quiet; char *tty; { +#if !defined(_AIX) struct lastlog ll; int fd; @@ -578,6 +958,7 @@ dolastlog(quiet, tty) (void)write(fd, (char *)&ll, sizeof(ll)); (void)close(fd); } +#endif } #undef UNKNOWN @@ -602,9 +983,9 @@ doremotelogin(host) static char lusername[UT_NAMESIZE+1]; char rusername[UT_NAMESIZE+1]; - getstr(rusername, sizeof(rusername), "remuser"); - getstr(lusername, sizeof(lusername), "locuser"); - getstr(term, sizeof(term), "Terminal type"); + lgetstr(rusername, sizeof(rusername), "Remote user"); + lgetstr(lusername, sizeof(lusername), "Local user"); + lgetstr(term, sizeof(term), "Terminal type"); username = lusername; pwd = getpwnam(username); if (pwd == NULL) @@ -612,17 +993,114 @@ doremotelogin(host) return(ruserok(host, (pwd->pw_uid == 0), rusername, username)); } -getstr(buf, cnt, err) +#ifdef KRB4 +do_krb_login(host, strict) + char *host; + int strict; +{ + int rc; + struct sockaddr_in sin; + char instance[INST_SZ], version[9]; + long authoptions = 0L; + struct hostent *hp = gethostbyname(host); + static char lusername[UT_NAMESIZE+1]; + + /* + * Kerberos autologin protocol. + */ + + (void) bzero((char *) &sin, (int) sizeof(sin)); + + if (hp) + (void) bcopy (hp->h_addr, (char *)&sin.sin_addr, + sizeof(sin.sin_addr)); + else + sin.sin_addr.s_addr = inet_addr(host); + + if ((hp == NULL) && (sin.sin_addr.s_addr == -1)) { + printf("Hostname did not resolve to an address, so Kerberos authentication failed\r\n"); + /* + * No host addr prevents auth, so + * punt krb and require password + */ + if (strict) { + goto paranoid; + } else { + pwd = NULL; + return(-1); + } + } + + kdata = (AUTH_DAT *)malloc( sizeof(AUTH_DAT) ); + ticket = (KTEXT) malloc(sizeof(KTEXT_ST)); + + (void) strcpy(instance, "*"); + if (rc=krb_recvauth(authoptions, 0, ticket, "rcmd", + instance, &sin, + (struct sockaddr_in *)0, + kdata, "", (bit_64 *) 0, version)) { + printf("Kerberos rlogin failed: %s\r\n",krb_err_txt[rc]); + if (strict) { +paranoid: + /* + * Paranoid hosts, such as a Kerberos server, + * specify the Klogind daemon to disallow + * even password access here. + */ + printf("Sorry, you must have Kerberos authentication to access this host.\r\n"); + exit(1); + } + } + (void) lgetstr(lusername, sizeof (lusername), "Local user"); + (void) lgetstr(term, sizeof(term), "Terminal type"); + username = lusername; + if (getuid()) { + pwd = NULL; + return(-1); + } + pwd = getpwnam(lusername); + if (pwd == NULL) { + pwd = NULL; + return(-1); + } + + /* + * if Kerberos login failed because of an error in krb_recvauth, + * return the indication of a bad attempt. User will be prompted + * for a password. We CAN'T check the .rhost file, because we need + * the remote username to do that, and the remote username is in the + * Kerberos ticket. This affects ONLY the case where there is + * Kerberos on both ends, but Kerberos fails on the server end. + */ + if (rc) { + return(-1); + } + + if (rc=kuserok(kdata,lusername)) { + printf("login: %s has not given you permission to login without a password.\r\n",lusername); + if (strict) { + exit(1); + } + return(-1); + } + return(0); +} +#endif /* KRB4 */ + +lgetstr(buf, cnt, err) char *buf, *err; int cnt; { + int ocnt = cnt; + char *obuf = buf; char ch; do { if (read(0, &ch, sizeof(ch)) != sizeof(ch)) exit(1); if (--cnt < 0) { - fprintf(stderr, "%s too long\r\n", err); + fprintf(stderr,"%s '%.*s' too long, %d characters maximum.\r\n", + err, ocnt, obuf, ocnt-1); sleepexit(1); } *buf++ = ch; @@ -636,29 +1114,128 @@ char *speeds[] = { #define NSPEEDS (sizeof(speeds) / sizeof(speeds[0])) doremoteterm(tp) +#ifdef POSIX + struct termios *tp; +#else struct sgttyb *tp; +#endif { - register char *cp = index(term, '/'), **cpp; + register char *cp = strchr(term, '/'), **cpp; char *speed; if (cp) { *cp++ = '\0'; speed = cp; - cp = index(speed, '/'); + cp = strchr(speed, '/'); if (cp) *cp++ = '\0'; for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++) if (strcmp(*cpp, speed) == 0) { +#ifdef POSIX + tp->c_cflag = + (tp->c_cflag & ~CBAUD) | (cpp-speeds); +#else tp->sg_ispeed = tp->sg_ospeed = cpp-speeds; +#endif break; } } +#ifdef POSIX + /* set all standard echo, edit, and job control options */ + tp->c_lflag = ECHO|ECHOE|ECHOK|ICANON|ISIG; + tp->c_iflag |= ICRNL|BRKINT; + tp->c_oflag |= ONLCR|OPOST|TAB3; +#else /* !POSIX */ tp->sg_flags = ECHO|CRMOD|ANYP|XTABS; +#endif } sleepexit(eval) int eval; { +#ifdef KRB4 + if (krbflag) + (void) dest_tkt(); +#endif /* KRB4 */ sleep((u_int)5); exit(eval); } + +#ifdef KRB4 +/* + * This routine handles cleanup stuff, and the like. + * It exits only in the child process. + */ +#include +void +dofork() +{ + int child; + +#ifdef _IBMR2 + update_ref_count(1); +#endif + if(!(child=fork())) + return; /* Child process */ + + /* Setup stuff? This would be things we could do in parallel with login */ + (void) chdir("/"); /* Let's not keep the fs busy... */ + + /* If we're the parent, watch the child until it dies */ + while(wait((union wait *)0) != child) + ; + + /* Cleanup stuff */ + /* Run dest_tkt to destroy tickets */ + (void) dest_tkt(); /* If this fails, we lose quietly */ +#ifdef SETPAG + if (pagflag) + ktc_ForgetAllTokens(); +#endif +#ifdef _IBMR2 + update_ref_count(-1); +#endif + + /* Leave */ + exit(0); +} +#endif /* KRB4 */ + + +char *strsave(s) +char *s; +{ + char *ret = (char *)malloc(strlen(s) + 1); + strcpy(ret, s); + return(ret); +} + +#ifdef _IBMR2 +update_ref_count(int adj) +{ + static char *empty = "\0"; + char *grp; + int i; + + /* Update reference count on all user's temporary groups */ + setuserdb(S_READ|S_WRITE); + if (getuserattr(username, S_GROUPS, (void *)&grp, SEC_LIST) == 0) { + while (*grp) { + if (getgroupattr(grp, "athena_temp", (void *)&i, SEC_INT) == 0) { + i += adj; + if (i > 0) { + putgroupattr(grp, "athena_temp", (void *)i, SEC_INT); + putgroupattr(grp, (char *)0, (void *)0, SEC_COMMIT); + } else { + putgroupattr(grp, S_USERS, (void *)empty, SEC_LIST); + putgroupattr(grp, (char *)0, (void *)0, SEC_COMMIT); + rmufile(grp, 0, GROUP_TABLE); + } + } + while (*grp) grp++; + grp++; + } + } + enduserdb(); +} +#endif diff --git a/src/appl/bsd/logutil.c b/src/appl/bsd/logutil.c index 645df5459..861fa89d8 100644 --- a/src/appl/bsd/logutil.c +++ b/src/appl/bsd/logutil.c @@ -15,10 +15,6 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)login.c 5.1 (Berkeley) 9/27/88"; -#endif /* LIBC_SCCS and not lint */ - #include #include #if defined (CRAY) || defined (sgi) @@ -28,6 +24,7 @@ static char sccsid[] = "@(#)login.c 5.1 (Berkeley) 9/27/88"; #endif #include #include +#include #include #include @@ -46,64 +43,61 @@ void login(ut) struct utmp *ut; { register int fd; + struct utmp utmp; int tty; - off_t lseek(); +#if defined(_AIX) + if (!ut->ut_pid) + ut->ut_pid = getppid(); + ut->ut_type = USER_PROCESS; + (void) strncpy(ut->ut_id, ut->ut_line, sizeof(ut->ut_id)); + + (void) setutent(); + (void) bzero((char *)&utmp, sizeof(utmp)); + (void) strncpy(utmp.ut_id, ut->ut_id, sizeof(utmp.ut_id)); + utmp.ut_type = DEAD_PROCESS; + (void) getutid(&utmp); + + (void) pututline(ut); + (void) endutent(); +#else tty = ttyslot(); if (tty > 0 && (fd = open(UTMP_FILE, O_WRONLY, 0)) >= 0) { (void)lseek(fd, (long)(tty * sizeof(struct utmp)), L_SET); (void)write(fd, (char *)ut, sizeof(struct utmp)); (void)close(fd); } +#endif if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) >= 0) { (void)write(fd, (char *)ut, sizeof(struct utmp)); (void)close(fd); } } - - -/* - * Copyright (c) 1988 The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the University of California, Berkeley. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)logout.c 5.1 (Berkeley) 8/31/88"; -#endif /* LIBC_SCCS and not lint */ - logout(line) - register char *line; + register char *line; { register FILE *fp; struct utmp ut; int rval; - time_t time(); if (!(fp = fopen(UTMP_FILE, "r+"))) - return(0); + return(0); rval = 1; while (fread((char *)&ut, sizeof(struct utmp), 1, fp) == 1) { if (!ut.ut_name[0] || strncmp(ut.ut_line, line, sizeof(ut.ut_line))) - continue; + continue; memset(ut.ut_name,0, sizeof(ut.ut_name)); #ifndef NO_UT_HOST memset(ut.ut_host,0, sizeof(ut.ut_host)); #endif (void)time(&ut.ut_time); +#if defined(_AIX) + memset(ut.ut_id, 0, sizeof(ut.ut_id)); + ut.ut_pid = ut.ut_exit.e_exit = 0; + ut.ut_type = EMPTY; +#endif (void)fseek(fp, (long)-sizeof(struct utmp), L_INCR); (void)fwrite((char *)&ut, sizeof(struct utmp), 1, fp); (void)fseek(fp, (long)0, L_INCR); @@ -113,29 +107,6 @@ logout(line) return(rval); } - - -/* - * Copyright (c) 1988 The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the University of California, Berkeley. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)logwtmp.c 5.2 (Berkeley) 9/20/88"; -#endif /* LIBC_SCCS and not lint */ - static int fd = -1; #ifndef SYSV @@ -169,6 +140,15 @@ logwtmp(line, name, host, keep_open, logingin) ut.ut_pid = getpid(); #endif (void)time(&ut.ut_time); +#if defined(_AIX) + if (*name) { + if (!ut.ut_pid) + ut.ut_pid = getpid(); + ut.ut_type = USER_PROCESS; + } else { + ut.ut_type = EMPTY; + } +#endif if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp)) (void)ftruncate(fd, buf.st_size); -- 2.26.2