$NetBSD: patch-af,v 1.10 2000/03/20 02:25:50 itojun Exp $ --- sshd.c- Wed May 12 20:19:29 1999 +++ sshd.c Mon Mar 20 09:57:30 2000 @@ -511,7 +511,7 @@ #include "firewall.h" /* TIS authsrv authentication */ #endif -#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H) +#if (defined (__FreeBSD__) || defined(__NetBSD__)) && defined(HAVE_LOGIN_CAP_H) #include #endif @@ -537,15 +537,26 @@ #define O_NOCTTY 0 #endif -#ifdef KERBEROS #ifdef KRB5 #include /* Global the contexts */ krb5_context ssh_context = 0; krb5_auth_context auth_context = 0; #endif /* KRB5 */ -char *ticket = "none\0"; -#endif /* KERBEROS */ + +#ifdef KRB4 +#include +#include +#ifdef AFS +#include +/* Local Xauthority file. */ +char *xauthfile = NULL; +#endif /* AFS */ +#endif /* KRB4 */ + +#if defined(KRB5) || defined(KRB4) +char *ticket = NULL; +#endif /* KRB5 || KRB4 */ /* Server configuration options. */ ServerOptions options; @@ -1115,7 +1126,6 @@ /* Arrange SIGCHLD to be caught. */ signal(SIGCHLD, main_sigchld_handler); -#ifdef KERBEROS #ifdef KRB5 /* Initialize contexts and setup replay cache */ if (!ssh_context) @@ -1128,7 +1138,6 @@ krb5_init_ets(ssh_context); } #endif -#endif /* Stay listening for connections until the system crashes or the daemon is killed with a signal. */ @@ -1407,6 +1416,16 @@ /* Try to remove authentication socket and directory */ auth_delete_socket(NULL); +#ifdef KRB4 + /* Cleanup user's ticket cache file. */ + if (options.kerberos_ticket_cleanup) + (void) dest_tkt(); +#ifdef AFS + /* Cleanup user's local Xauthority file. */ + if (xauthfile) unlink(xauthfile); +#endif /* AFS */ +#endif /* KRB4 */ + /* The connection has been terminated. */ log_msg("Closing connection to %.100s", get_remote_ipaddr()); packet_close(); @@ -1470,17 +1489,17 @@ if (options.tis_authentication) auth_mask |= 1 << SSH_AUTH_TIS; #endif -#ifdef KERBEROS -#ifdef KRB5 +#if defined(KRB4) || defined(KRB5) if (options.kerberos_authentication) auth_mask |= 1 << SSH_AUTH_KERBEROS; #endif -#endif -#ifdef KERBEROS_TGT_PASSING -#ifdef KRB5 +#if defined(AFS) || defined(KRB5) if (options.kerberos_tgt_passing) auth_mask |= 1 << SSH_PASS_KERBEROS_TGT; #endif +#ifdef AFS + if (options.afs_token_passing) + auth_mask |= 1 << SSH_PASS_AFS_TOKEN; #endif if (options.password_authentication) auth_mask |= 1 << SSH_AUTH_PASSWORD; @@ -1677,7 +1696,7 @@ /* XXX No days_before_password_expires calculation here */ } #endif /* HAVE_USERSEC_H */ -#ifdef HAVE_ETC_SHADOW +#if defined(HAVE_ETC_SHADOW) && !defined(KRB4) && !defined(KRB5) { struct spwd *sp; @@ -1783,56 +1802,62 @@ endspent(); } #endif /* HAVE_ETC_SHADOW */ -#ifdef __FreeBSD__ - { +/* Net2,BSD4.4,BSD/OS,NetBSD,FreeBSD and OpenBSD all define BSD4_4 + man passwd(5) says that format has changed since BSD4.3 + */ +#ifdef BSD4_4 + if(pwd->pw_change || pwd->pw_expire) { time_t currtime; - if (pwd->pw_change || pwd->pw_expire) currtime = time(NULL); /* * Check for an expired password */ - if (pwd->pw_change && pwd->pw_change <= currtime) + + if (pwd->pw_change) { - debug("Account %.100s's password is too old - forced to change.", - user); - if (options.forced_passwd_change) + /* PASSWD_CHGNOW seems to be -1 for now but... */ + if ( +#if defined(PASSWD_CHGNOW) && PASSWD_CHGNOW > 0 + pwd->pw_change == PASSWD_CHGNOW || +#endif + pwd->pw_change <= currtime) { - forced_command = xmalloc(sizeof(PASSWD_PATH) + strlen(user) + 2); - snprintf(forced_command, sizeof(PASSWD_PATH) + strlen(user) + 2, - "%.100s %.100s", PASSWD_PATH, user); + packet_send_debug("Password has expired"); + if(options.forced_passwd_change) + { + debug("Account %.99s's password is too old - change forced.", + user); + forced_command = xmalloc(sizeof(PASSWD_PATH) + + strlen(user) + 1); + sprintf(forced_command, "%s %s", PASSWD_PATH, user); } else { return 0; } } - else - { - if (pwd->pw_change) - { +#ifdef PASSWD_CHGNOW + if(pwd->pw_change != PASSWD_CHGNOW) days_before_password_expires = (pwd->pw_change - currtime) / 86400; - } +#endif } /* * Check for expired account */ - if (pwd->pw_expire && pwd->pw_expire <= currtime) + if (pwd->pw_expire) { - debug("Account %.100s has expired - access denied.", user); + if (pwd->pw_expire <= currtime) + { + packet_send_debug("Account has expired"); return 0; } - else - { - if (pwd->pw_expire) - { days_before_account_expires = (pwd->pw_expire - currtime) / 86400; } } - } -#endif /* !FreeBSD */ +#endif /* !BSD4_4 */ #ifdef HAVE_HPUX_TCB_AUTH { @@ -2039,7 +2064,7 @@ } } - /* Check whether logins are deneid for this group. */ + /* Check whether logins are denied for this group. */ grp = getgrgid(pwd->pw_gid); if (grp) group = grp->gr_name; @@ -2151,12 +2176,12 @@ unsigned int client_host_key_bits; MP_INT client_host_key_e, client_host_key_n; int password_attempts = 0; -#if defined(KERBEROS) && defined(KRB5) +#ifdef KRB5 char kuser[256]; krb5_principal client = 0, tkt_client = 0; krb5_data krb5data; -#endif /* defined(KERBEROS) && defined(KRB5) */ -#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H) +#endif /* KRB5 */ +#if (defined (__FreeBSD__) || defined(__NetBSD__)) && defined(HAVE_LOGIN_CAP_H) login_cap_t *lc; const char *hostname; const char *ipaddr; @@ -2167,10 +2192,18 @@ ipaddr = get_remote_ipaddr(); #endif /* HAVE_LOGIN_CAP_H */ +#ifdef AFS + /* If machine has AFS, set process authentication group. */ + if (k_hasafs()) { + k_setpag(); + k_unlog(); + } +#endif /* AFS */ + if (strlen(user) > 255) do_authentication_fail_loop(); -#if defined(KERBEROS) && defined(KRB5) +#ifdef KRB5 /* For KRB5 allow the user to input fully qualified name i.e. "username@realm" as the local user name. Then use this name to call out to krb5_aname_to_localname to find if there is a localname @@ -2203,7 +2236,7 @@ } else krb5_parse_name(ssh_context, user, &client); -#endif /* defined(KERBEROS) && defined(KRB5) */ +#endif /* KRB5 */ /* Verify that the user is a valid user. We disallow usernames starting with any characters that are commonly used to start NIS entries. */ @@ -2218,11 +2251,11 @@ pwcopy.pw_passwd = xstrdup(pw->pw_passwd); pwcopy.pw_uid = pw->pw_uid; pwcopy.pw_gid = pw->pw_gid; -#if (defined (__bsdi__) && _BSDI_VERSION >= 199510) || (defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H)) +#ifdef BSD4_4 pwcopy.pw_class = xstrdup(pw->pw_class); pwcopy.pw_change = pw->pw_change; pwcopy.pw_expire = pw->pw_expire; -#endif /* __bsdi__ && _BSDI_VERSION >= 199510 */ +#endif /* BSD4_4 */ pwcopy.pw_dir = xstrdup(pw->pw_dir); pwcopy.pw_shell = xstrdup(pw->pw_shell); pw = &pwcopy; @@ -2241,11 +2274,11 @@ debug("Attempting authentication for %.100s.", user); -#if defined (KERBEROS) && defined (KRB5) + /* If the user has no password, accept authentication immediately. */ +#ifdef KRB5 if (!options.kerberos_authentication && options.password_authentication && auth_password(user, "", 0)) -#else /* defined(KERBEROS) && defined(KRB5) */ - /* If the user has no password, accept authentication immediately. */ +#else /* KRB5 */ #if defined (HAVE_SIA) /* For SIA, only call auth_password() here if the user really has no password. Otherwise, the call would generate misleading @@ -2254,9 +2287,13 @@ if (options.password_authentication && sia_no_password(user) && auth_password(user, "")) #else /* defined(HAVE_SIA) */ - if (options.password_authentication && auth_password(user, "")) + if (options.password_authentication && +#ifdef KRB4 + options.kerberos_or_local_passwd && +#endif /* KRB4 */ + auth_password(user, "")) #endif /* defined(HAVE_SIA) */ -#endif /* defined(KERBEROS) && defined(KRB5) */ +#endif /* KRB5 */ { /* Authentication with empty password succeeded. */ debug("Login for user %.100s accepted without authentication.", user); @@ -2281,34 +2318,61 @@ /* Process the packet. */ switch (type) { -#ifdef KERBEROS_TGT_PASSING -#ifdef KRB5 +#if defined(KRB5) || defined(AFS) case SSH_CMSG_HAVE_KERBEROS_TGT: +#ifdef KRB5 if (!options.kerberos_tgt_passing || (!(options.kerberos_authentication || options.password_authentication || options.rsa_authentication))) +#else /* KRB5 */ + if (!options.kerberos_tgt_passing) +#endif /* KRB5 */ { packet_get_all(); log_msg("Kerberos tgt passing disabled."); break; } - +#ifdef KRB5 /* Accept Kerberos tgt. */ krb5data.data = packet_get_string((unsigned int *) &krb5data.length); - if (!auth_kerberos_tgt(user, &krb5data, client) || + if (!auth_krb5_tgt(user, &krb5data, client) || !krb5_kuserok(ssh_context, client, user)){ log_msg("Kerberos tgt REFUSED for %.100s", user); debug("Kerberos tgt REFUSED for %.100s", user); } free(krb5data.data); -#endif +#else /* KRB5 */ + { + /* Accept Kerberos tgt. */ + char *tgt = packet_get_string(NULL); + if (!auth_kerberos_tgt(pw, tgt)) + debug("Kerberos tgt REFUSED for %s", user); + xfree(tgt); + } +#endif /* KRB5 */ continue; -#endif /* KERBEROS_TGT_PASSING */ +#endif /* KRB5 || AFS */ -#ifdef KERBEROS -#ifdef KRB5 +#ifdef AFS + case SSH_CMSG_HAVE_AFS_TOKEN: + if (!k_hasafs() || !options.afs_token_passing) { + packet_get_all(); + log_msg("AFS token passing disabled."); + break; + } + else { + /* Accept AFS token. */ + char *token_string = packet_get_string(NULL); + if (!auth_afs_token(user, pw->pw_uid, token_string)) + debug("AFS token REFUSED for %s", user); + xfree(token_string); + continue; + } +#endif /* AFS */ + +#if defined(KRB4) || defined(KRB5) case SSH_CMSG_AUTH_KERBEROS: if (!options.kerberos_authentication) { @@ -2316,9 +2380,10 @@ log_msg("Kerberos authentication disabled."); break; } +#ifdef KRB5 /* Try Kerberos authentication. */ krb5data.data = packet_get_string((unsigned int *) &krb5data.length); - if (auth_kerberos(user, &krb5data, &tkt_client)) + if (auth_krb5(user, &krb5data, &tkt_client)) { char *tkt_user; @@ -2347,11 +2412,31 @@ } free(tkt_user); } -#endif /* KRB5 */ - debug("Kerberos authentication failed for %.100s from %.200s", - user, get_canonical_hostname()); +#else /* !KRB5 XXX - how to make these coexist? */ + else { + /* Try Kerberos v4 authentication. */ + KTEXT_ST auth; + char *tkt_user = NULL; + char *kdata = packet_get_string((unsigned int *)&auth.length); + + memcpy(auth.dat, kdata, auth.length); + xfree(kdata); + + if (auth_krb4(user, &auth, &tkt_user)) { + /* Client has successfully authenticated to us. */ + log_msg("Kerberos authentication accepted %s for account " + "%.100s from %.200s", tkt_user, user, + get_canonical_hostname()); + authentication_type = SSH_AUTH_KERBEROS; + authenticated = 1; + xfree(tkt_user); break; -#endif /* KERBEROS */ + } + log_msg("Kerberos authentication failed for account " + "%.100s from %.200s", user, get_canonical_hostname()); + } +#endif /* KRB5 */ +#endif /* KRB5 || KRB4 */ case SSH_CMSG_AUTH_RHOSTS: if (!options.rhosts_authentication) @@ -2568,7 +2653,7 @@ if (!strncmp(buf, "challenge ", 10) || !strncmp(buf, "chalnecho ", 10)) { snprintf(prompt, sizeof(prompt), - "Challenge \"%.100s\": ",&buf[10]); + "%.100s",&buf[10]); debug("TIS challenge %.500s", buf); packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE); packet_put_string(prompt, strlen(prompt)); @@ -2657,11 +2742,11 @@ password_attempts++; /* Try authentication with the password. */ -#if defined(KERBEROS) && defined(KRB5) +#ifdef KRB5 if (auth_password(user, password, client)) -#else /* defined(KERBEROS) && defined(KRB5) */ +#else /* KRB5 */ if (auth_password(user, password)) -#endif /* defined(KERBEROS) && defined(KRB5) */ +#endif /* KRB5 */ { /* Successful authentication. */ /* Clear the password from memory. */ @@ -2688,7 +2773,7 @@ if (authenticated) break; -#ifdef KERBEROS +#if defined(KRB5) /* If you forwarded a ticket you get one shot for proper authentication. */ /* If tgt was passed unlink file */ @@ -2699,7 +2784,7 @@ else ticket = NULL; } -#endif /* KERBEROS */ +#endif /* KRB5 */ /* Send a message indicating that the authentication attempt failed. */ packet_start(SSH_SMSG_FAILURE); @@ -2724,7 +2809,7 @@ get_canonical_hostname()); } -#if defined (__FreeBSD__) && defined (HAVE_LOGIN_CAP_H) +#if (defined (__FreeBSD__) || defined(__NetBSD__)) && defined (HAVE_LOGIN_CAP_H) lc = login_getclass(pw->pw_class); @@ -2965,6 +3050,21 @@ display = x11_create_display_inet(screen); if (!display) goto fail; +#ifdef AFS + /* Setup to have a local .Xauthority, if homedir is in AFS. */ + { + struct stat st; + char cell[64], *xauthdir = "/ticket"; + + if (k_hasafs() && k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0) { + xauthfile = xmalloc(MAXPATHLEN); + if (stat(xauthdir, &st) < 0) + xauthdir = "/tmp"; + snprintf(xauthfile, MAXPATHLEN, "%s/Xauth%d_%d", xauthdir, + pw->pw_uid, getpid()); + } + } +#endif /* AFS */ break; #else /* XAUTH_PATH */ /* No xauth program; we won't accept forwarding with spoofing. */ @@ -3283,12 +3383,9 @@ struct sockaddr_in from; int fromlen; struct pty_cleanup_context cleanup_context; -#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H) +#if (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(HAVE_LOGIN_CAP_H) login_cap_t *lc; #endif -#if defined (__bsdi__) && _BSDI_VERSION >= 199510 - struct timeval tp; -#endif /* __bsdi__ && _BSDI_VERSION >= 199510 */ /* We no longer need the child running on user's privileges. */ userfile_uninit(); @@ -3389,7 +3486,7 @@ record_login(pid, ttyname, pw->pw_name, pw->pw_uid, hostname, &from); -#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H) +#if (defined (__FreeBSD__) || defined(__NetBSD__)) && defined(HAVE_LOGIN_CAP_H) lc = login_getclass(pw->pw_class); #endif @@ -3398,7 +3495,7 @@ snprintf(line, sizeof(line), "%.200s/.hushlogin", pw->pw_dir); quiet_login = stat(line, &st) >= 0; -#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H) +#if (defined (__FreeBSD__) || defined(__NetBSD__)) && defined(HAVE_LOGIN_CAP_H) quiet_login = login_getcapbool(lc, "hushlogin", quiet_login); #endif @@ -3425,7 +3522,7 @@ } #endif /* HAVE_SIA */ -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__NetBSD__) if (command == NULL && !quiet_login) { #ifdef HAVE_LOGIN_CAP_H @@ -3457,7 +3554,7 @@ FILE *f; /* Print /etc/motd if it exists. */ -#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H) +#if (defined (__FreeBSD__) || defined(__NetBSD__)) && defined(HAVE_LOGIN_CAP_H) f = fopen(login_getcapstr(lc, "welcome", "/etc/motd", "/etc/motd"), "r"); #else @@ -3469,33 +3566,9 @@ fputs(line, stdout); fclose(f); } -#if defined (__bsdi__) && _BSDI_VERSION >= 199510 - if (pw->pw_change || pw->pw_expire) - (void)gettimeofday(&tp, (struct timezone *)NULL); - if (pw->pw_change) - { - if (tp.tv_sec >= pw->pw_change) - { - fprintf(stderr,"Sorry -- your password has expired.\n"); - exit(254); - } - days_before_password_expires = (pw->pw_change - tp.tv_sec) / - 86400; - } - if (pw->pw_expire) - { - if (tp.tv_sec >= pw->pw_expire) - { - fprintf(stderr,"Sorry -- your account has expired.\n"); - exit(254); - } - days_before_account_expires = (pw->pw_expire - tp.tv_sec) / - 86400; - } -#endif /* __bsdi__ & _BSDI_VERSION >= 199510 */ } -#if defined (__FreeBSD__) && defined HAVE_LOGIN_CAP_H +#if (defined (__FreeBSD__) || defined(__NetBSD__)) && defined HAVE_LOGIN_CAP_H login_close(lc); #endif @@ -3883,8 +3956,11 @@ lc = login_getclass(pw->pw_class); auth_checknologin(lc); #else /* !HAVE_LOGIN_CAP_H */ -#if defined (__bsdi__) && _BSDI_VERSION > 199510 +#if ( defined (__bsdi__) && _BSDI_VERSION > 199510 ) || (defined(HAVE_LOGIN_CAP_H) && defined(__NetBSD__)) login_cap_t *lc = 0; +#if defined(__NetBSD__) + char *real_shell; +#endif if ((lc = login_getclass(pw->pw_class)) == NULL) { @@ -4019,7 +4095,7 @@ if (command != NULL || !options.use_login) #endif /* USELOGIN */ { -#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H) +#if (defined (__FreeBSD__) || defined(__NetBSD__)) && defined(HAVE_LOGIN_CAP_H) char *p, *s, **tmpenv; /* Initialize the new environment. @@ -4180,10 +4256,23 @@ and means /bin/sh. */ shell = (user_shell[0] == '\0') ? DEFAULT_SHELL : user_shell; -#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H) +#if (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(HAVE_LOGIN_CAP_H) real_shell = login_getcapstr(lc, "shell", (char*)shell, (char*)shell); login_close(lc); #endif /* HAVE_LOGIN_CAP_H */ + +#ifdef AFS + /* Try to get AFS tokens for the local cell. */ + if (k_hasafs()) { + char cell[64]; + + if (k_afs_cell_of_file(user_dir, cell, sizeof(cell)) == 0) + krb_afslog(cell, 0); + + krb_afslog(0, 0); + } +#endif /* AFS */ + /* Initialize the environment if not already done. In the first part we allocate space for all environment variables. */ if (env == NULL) @@ -4290,13 +4379,21 @@ } #endif -#ifdef KERBEROS - /* Set KRBTKFILE to point to our ticket */ + /* Set KRBTKFILE to point to our ticket. */ #ifdef KRB5 if (ticket) child_set_env(&env, &envsize, "KRB5CCNAME", ticket); #endif /* KRB5 */ -#endif /* KERBEROS */ +#ifdef KRB4 /* XXX - how to make these coexist? */ + if (ticket) + child_set_env(&env, &envsize, "KRBTKFILE", ticket); + +#ifdef AFS + /* Set XAUTHORITY to a local file, if homedir is in AFS. */ + if (xauthfile) + child_set_env(&env, &envsize, "XAUTHORITY", xauthfile); +#endif /* AFS */ +#endif /* KRB4 */ /* Set variable for forwarded authentication connection, if we have one. */ if (auth_get_socket_name() != NULL) @@ -4554,7 +4651,7 @@ /* Execute the shell. */ argv[0] = buf; argv[1] = NULL; -#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H) +#if (defined (__FreeBSD__) || defined(__NetBSD__)) && defined(HAVE_LOGIN_CAP_H) execve(real_shell, argv, env); #else execve(shell, argv, env); @@ -4579,7 +4676,7 @@ argv[1] = "-c"; argv[2] = (char *)command; argv[3] = NULL; -#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H) +#if (defined (__FreeBSD__) || defined(__NetBSD__)) && defined(HAVE_LOGIN_CAP_H) execve(real_shell, argv, env); #else execve(shell, argv, env);