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()
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;
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
&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) {
#include <ctype.h>
#include <netdb.h>
#include <errno.h>
+#include <string.h>
#ifdef KERBEROS
#include <krb5/krb5.h>
#endif /* KERBEROS */
int rem;
-char *colon(), *index(), *rindex(), *strcpy();
+char *colon();
int errs;
krb5_sigtype lostconn();
int errno;
/* 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];
*src++ = 0;
if (*src == 0)
src = ".";
- host = index(argv[i], '@');
+ host = strchr(argv[i], '@');
if (host) {
*host++ = 0;
suser = argv[i];
*src++ = 0;
if (*src == 0)
src = ".";
- host = index(argv[i], '@');
+ host = strchr(argv[i], '@');
if (host) {
*host++ = 0;
suser = argv[i];
error("rcp: %s: not a plain file\n", name);
continue;
}
- last = rindex(name, '/');
+ last = strrchr(name, '/');
if (last == 0)
last = name;
else
error("rcp: %s: %s\n", name, sys_errlist[errno]);
return;
}
- last = rindex(name, '/');
+ last = strrchr(name, '/');
if (last == 0)
last = name;
else
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;
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",
exit(1);
}
- creds.server = sprinc;
-
/* Get TGT from credentials cache */
if (status = krb5_get_credentials(KRB5_GC_CACHED, cc, &creds)){
fprintf(stderr,
}
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
* 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.
#include <krb5/crc-32.h>
#include <krb5/mit-des.h>
#include <krb5/los-proto.h>
+#include <kerberosIV/krb.h>
#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 <kerberosIV/krb.h>
+
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
#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();
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];
write(f, "", 1);
if (getpty(&p,line))
fatal(f, "Out of ptys");
+ Pfd = p;
#ifdef TIOCSWINSZ
(void) ioctl(p, TIOCSWINSZ, &win);
#endif
/* 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
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
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
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);
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 ){
/*
*p = 'p';
(void)chmod(line, 0666);
(void)chown(line, 0, 0);
+#endif
+#ifdef VHANG_LAST
+ close(Pfd);
+ vhangup();
#endif
shutdown(netf, 2);
exit(1);
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++;
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.
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
(void) pcbc_encrypt(des_inbuf,
storage,
(net_len < 8) ? 8 : net_len,
- schedule,
+ v4_schedule,
v4_kdata->session,
DECRYPT);
/*
(void) pcbc_encrypt((len < 8) ? garbage_buf : buf,
des_outbuf,
(len < 8) ? 8 : len,
- schedule,
+ v4_schedule,
v4_kdata->session,
ENCRYPT);
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))
* 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.
#include <errno.h>
#include <pwd.h>
#include <ctype.h>
+#include <string.h>
#ifdef sun
#include <sys/label.h>
#endif /* CRAY */
int errno;
-char *index(), *rindex(), *strncat();
/*VARARGS1*/
int error();
char *options, ch;
int i;
int fd;
- int debug_port;
+ int debug_port = 0;
#ifdef CRAY
secflag = sysconf(_SC_CRAY_SECURE_SYS);
char *kremuser;
krb5_principal client;
krb5_authenticator *kdata;
-krb5_ticket *ticket = 0;
#ifdef SERVE_V4
#include <kerberosIV/krb.h>
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;
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))
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 ,
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
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;
}
* 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 <sys/types.h>
#include <sys/param.h>
-#ifndef VFS
+#ifdef OQUOTA
#include <sys/quota.h>
-#endif VFS
+#endif
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <utmp.h>
#include <signal.h>
+
+#if !defined(_AIX)
#include <lastlog.h>
+#endif
+
#include <errno.h>
#ifndef NOTTYENT
#include <ttyent.h>
#include <setjmp.h>
#include <stdio.h>
#include <strings.h>
-
+#ifdef KRB4
+#include <krb.h>
#include <netdb.h>
-#include <string.h>
+#include <netinet/in.h>
+#ifdef BIND_HACK
+#include <arpa/nameser.h>
+#include <arpa/resolv.h>
+#endif /* BIND_HACK */
+#endif /* KRB4 */
+
+#ifdef POSIX
+#include <stdlib.h>
+#include <termios.h>
+#ifdef _AIX
+#include <termio.h>
+#endif
+#endif
+
+#ifdef _IBMR2
+#include <usersec.h>
+#include <sys/id.h>
+#endif
+
+#if defined(_AIX)
+#define PRIO_OFFSET 20
+#else
+#define PRIO_OFFSET 0
+#endif
#ifdef UIDGID_T
uid_t 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.
struct passwd *pwd;
char term[64], *hostname, *username;
+#ifndef POSIX
struct sgttyb sgttyb;
struct tchars tc = {
CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
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;
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;
pflag = 1;
break;
case 'r':
- EXCL_TEST;
+ EXCL_AUTH_TEST;
+ EXCL_HOST_TEST;
if (getuid()) {
fprintf(stderr,
"login: -r for super-user only.\n");
}
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;
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);
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
#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
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);
}
/*
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) {
/*
* 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);
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:
}
sleepexit(0);
}
-#endif /* !VFS */
+#endif
if (chdir(pwd->pw_dir) < 0) {
printf("No directory %s!\n", pwd->pw_dir);
{
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,
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);
(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)
(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: ");
}
#ifdef NOTTYENT
-int root_tty_security = 0;
+int root_tty_security = 1;
#endif
rootterm(tty)
char *tty;
struct ttyent *t;
return((t = getttynam(tty)) && t->ty_status&TTY_SECURE);
-#endif NOTTYENT
+#endif /* NOTTYENT */
}
jmp_buf motdinterrupt;
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);
int quiet;
char *tty;
{
+#if !defined(_AIX)
struct lastlog ll;
int fd;
(void)write(fd, (char *)&ll, sizeof(ll));
(void)close(fd);
}
+#endif
}
#undef UNKNOWN
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)
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;
#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 <sys/wait.h>
+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
* 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 <sys/types.h>
#include <sys/file.h>
#if defined (CRAY) || defined (sgi)
#endif
#include <utmp.h>
#include <stdio.h>
+#include <strings.h>
#include <sys/time.h>
#include <sys/stat.h>
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);
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
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);