diff options
Diffstat (limited to 'crypto/openssh/session.c')
-rw-r--r-- | crypto/openssh/session.c | 250 |
1 files changed, 242 insertions, 8 deletions
diff --git a/crypto/openssh/session.c b/crypto/openssh/session.c index 53d20c5..e18b2e6 100644 --- a/crypto/openssh/session.c +++ b/crypto/openssh/session.c @@ -5,6 +5,8 @@ /* * SSH2 support by Markus Friedl. * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * $FreeBSD$ */ #include "includes.h" @@ -27,6 +29,15 @@ RCSID("$OpenBSD: session.c,v 1.12 2000/05/03 18:03:07 markus Exp $"); #include "ssh2.h" #include "auth.h" +#ifdef __FreeBSD__ +#define LOGIN_CAP +#define _PATH_CHPASS "/usr/bin/passwd" +#endif /* __FreeBSD__ */ + +#ifdef LOGIN_CAP +#include <login_cap.h> +#endif /* LOGIN_CAP */ + /* types */ #define TTYSZ 64 @@ -504,6 +515,15 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw) struct sockaddr_storage from; struct stat st; time_t last_login_time; +#ifdef LOGIN_CAP + login_cap_t *lc; + char *fname; +#endif /* LOGIN_CAP */ +#ifdef __FreeBSD__ +#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */ + struct timeval tv; + time_t warntime = DEFAULT_WARN; +#endif /* __FreeBSD__ */ if (s == NULL) fatal("do_exec_pty: no session"); @@ -574,6 +594,66 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw) snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir); quiet_login = stat(line, &st) >= 0; +#ifdef LOGIN_CAP + lc = login_getpwclass(pw); + if (lc == NULL) + lc = login_getclassbyname(NULL, pw); + quiet_login = login_getcapbool(lc, "hushlogin", quiet_login); +#endif /* LOGIN_CAP */ + +#ifdef __FreeBSD__ + if (pw->pw_change || pw->pw_expire) + (void)gettimeofday(&tv, NULL); +#ifdef LOGIN_CAP + warntime = login_getcaptime(lc, "warnpassword", + DEFAULT_WARN, DEFAULT_WARN); +#endif /* LOGIN_CAP */ + /* + * If the password change time is set and has passed, give the + * user a password expiry notice and chance to change it. + */ + if (pw->pw_change != 0) { + if (tv.tv_sec >= pw->pw_change) { + (void)printf( + "Sorry -- your password has expired.\n"); + log("%s Password expired - forcing change", + pw->pw_name); + command = _PATH_CHPASS; + } else if (pw->pw_change - tv.tv_sec < warntime && + !quiet_login) + (void)printf( + "Warning: your password expires on %s", + ctime(&pw->pw_change)); + } +#ifdef LOGIN_CAP + warntime = login_getcaptime(lc, "warnexpire", + DEFAULT_WARN, DEFAULT_WARN); +#endif /* LOGIN_CAP */ + if (pw->pw_expire) { + if (tv.tv_sec >= pw->pw_expire) { + (void)printf( + "Sorry -- your account has expired.\n"); + log( + "LOGIN %.200s REFUSED (EXPIRED) FROM %.200s ON TTY %.200s", + pw->pw_name, hostname, ttyname); + exit(254); + } else if (pw->pw_expire - tv.tv_sec < warntime && + !quiet_login) + (void)printf( + "Warning: your account expires on %s", + ctime(&pw->pw_expire)); + } +#endif /* __FreeBSD__ */ +#ifdef LOGIN_CAP + if (!auth_ttyok(lc, ttyname)) { + (void)printf("Permission denied.\n"); + log( + "LOGIN %.200s REFUSED (TTY) FROM %.200s ON TTY %.200s", + pw->pw_name, hostname, ttyname); + exit(254); + } +#endif /* LOGIN_CAP */ + /* * If the user has logged in before, display the time of last * login. However, don't display anything extra if a command @@ -596,6 +676,22 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw) else printf("Last login: %s from %s\r\n", time_string, buf); } + +#ifdef LOGIN_CAP + if (command == NULL && !quiet_login && !options.use_login) { + fname = login_getcapstr(lc, "copyright", NULL, NULL); + if (fname != NULL && (f = fopen(fname, "r")) != NULL) { + while (fgets(line, sizeof(line), f) != NULL) + fputs(line, stdout); + fclose(f); + } else + (void)printf("%s\n\t%s %s\n", + "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994", + "The Regents of the University of California. ", + "All rights reserved."); + } +#endif /* LOGIN_CAP */ + /* * Print /etc/motd unless a command was specified or printing * it was disabled in server options or login(1) will be @@ -604,14 +700,24 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw) */ if (command == NULL && options.print_motd && !quiet_login && !options.use_login) { - /* Print /etc/motd if it exists. */ +#ifdef LOGIN_CAP + fname = login_getcapstr(lc, "welcome", NULL, NULL); + if (fname == NULL || (f = fopen(fname, "r")) == NULL) + f = fopen("/etc/motd", "r"); +#else /* !LOGIN_CAP */ f = fopen("/etc/motd", "r"); +#endif /* LOGIN_CAP */ + /* Print /etc/motd if it exists. */ if (f) { while (fgets(line, sizeof(line), f)) fputs(line, stdout); fclose(f); } } +#ifdef LOGIN_CAP + login_close(lc); +#endif /* LOGIN_CAP */ + /* Do common processing for the child, such as execing the command. */ do_child(command, pw, s->term, s->display, s->auth_proto, s->auth_data, s->tty); /* NOTREACHED */ @@ -735,15 +841,25 @@ do_child(const char *command, struct passwd * pw, const char *term, const char *display, const char *auth_proto, const char *auth_data, const char *ttyname) { - const char *shell, *cp = NULL; + char *shell; + const char *cp = NULL; char buf[256]; FILE *f; unsigned int envsize, i; - char **env; + char **env = NULL; extern char **environ; struct stat st; char *argv[10]; +#ifdef LOGIN_CAP + login_cap_t *lc; + + lc = login_getpwclass(pw); + if (lc == NULL) + lc = login_getclassbyname(NULL, pw); + if (pw->pw_uid != 0) + auth_checknologin(lc); +#else /* !LOGIN_CAP */ f = fopen("/etc/nologin", "r"); if (f) { /* /etc/nologin exists. Print its contents and exit. */ @@ -753,6 +869,11 @@ do_child(const char *command, struct passwd * pw, const char *term, if (pw->pw_uid != 0) exit(254); } +#endif /* LOGIN_CAP */ + +#ifdef LOGIN_CAP + if (options.use_login) +#endif /* LOGIN_CAP */ /* Set login name in the kernel. */ if (setlogin(pw->pw_name) < 0) error("setlogin failed: %s", strerror(errno)); @@ -761,6 +882,42 @@ do_child(const char *command, struct passwd * pw, const char *term, /* Login(1) does this as well, and it needs uid 0 for the "-h" switch, so we let login(1) to this for us. */ if (!options.use_login) { +#ifdef LOGIN_CAP + char **tmpenv; + + /* Initialize temp environment */ + envsize = 64; + env = xmalloc(envsize * sizeof(char *)); + env[0] = NULL; + + child_set_env(&env, &envsize, "PATH", + (pw->pw_uid == 0) ? + _PATH_STDPATH : _PATH_DEFPATH); + + snprintf(buf, sizeof buf, "%.200s/%.50s", + _PATH_MAILDIR, pw->pw_name); + child_set_env(&env, &envsize, "MAIL", buf); + + if (getenv("TZ")) + child_set_env(&env, &envsize, "TZ", getenv("TZ")); + + /* Save parent environment */ + tmpenv = environ; + environ = env; + + if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETALL) < 0) + fatal("setusercontext failed: %s", strerror(errno)); + + /* Restore parent environment */ + env = environ; + environ = tmpenv; + + for (envsize = 0; env[envsize] != NULL; ++envsize) + ; + envsize = (envsize < 100) ? 100 : envsize + 16; + env = xrealloc(env, envsize * sizeof(char *)); + +#else /* !LOGIN_CAP */ if (getuid() == 0 || geteuid() == 0) { if (setgid(pw->pw_gid) < 0) { perror("setgid"); @@ -778,12 +935,16 @@ do_child(const char *command, struct passwd * pw, const char *term, } if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) fatal("Failed to set uids to %d.", (int) pw->pw_uid); +#endif /* LOGIN_CAP */ } /* * Get the shell from the password data. An empty shell field is * legal, and means /bin/sh. */ shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; +#ifdef LOGIN_CAP + shell = login_getcapstr(lc, "shell", shell, shell); +#endif /* LOGIN_CAP */ #ifdef AFS /* Try to get AFS tokens for the local cell. */ @@ -798,24 +959,31 @@ do_child(const char *command, struct passwd * pw, const char *term, #endif /* AFS */ /* Initialize the environment. */ - envsize = 100; - env = xmalloc(envsize * sizeof(char *)); - env[0] = NULL; + if (env == NULL) { + envsize = 100; + env = xmalloc(envsize * sizeof(char *)); + env[0] = NULL; + } if (!options.use_login) { /* Set basic environment. */ child_set_env(&env, &envsize, "USER", pw->pw_name); child_set_env(&env, &envsize, "LOGNAME", pw->pw_name); child_set_env(&env, &envsize, "HOME", pw->pw_dir); +#ifndef LOGIN_CAP child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); snprintf(buf, sizeof buf, "%.200s/%.50s", _PATH_MAILDIR, pw->pw_name); child_set_env(&env, &envsize, "MAIL", buf); +#endif /* !LOGIN_CAP */ /* Normal systems set SHELL by default. */ child_set_env(&env, &envsize, "SHELL", shell); } +#ifdef LOGIN_CAP + if (options.use_login) +#endif /* LOGIN_CAP */ if (getenv("TZ")) child_set_env(&env, &envsize, "TZ", getenv("TZ")); @@ -853,6 +1021,31 @@ do_child(const char *command, struct passwd * pw, const char *term, child_set_env(&env, &envsize, "KRBTKFILE", ticket); } #endif /* KRB4 */ +#ifdef KRB5 +{ + extern krb5_ccache mem_ccache; + + if (mem_ccache) { + krb5_error_code problem; + krb5_ccache ccache; +#ifdef AFS + if (k_hasafs()) + krb5_afslog(ssh_context, mem_ccache, NULL, NULL); +#endif /* AFS */ + + problem = krb5_cc_default(ssh_context, &ccache); + if (problem) {} + else { + problem = krb5_cc_copy_cache(ssh_context, mem_ccache, ccache); + if (problem) {} + } + + krb5_cc_close(ssh_context, ccache); + } + + krb5_cleanup_proc(NULL); + } +#endif /* KRB5 */ if (xauthfile) child_set_env(&env, &envsize, "XAUTHORITY", xauthfile); @@ -903,13 +1096,50 @@ do_child(const char *command, struct passwd * pw, const char *term, * initgroups, because at least on Solaris 2.3 it leaves file * descriptors open. */ - for (i = 3; i < 64; i++) + for (i = 3; i < getdtablesize(); i++) close(i); /* Change current directory to the user\'s home directory. */ - if (chdir(pw->pw_dir) < 0) + if ( +#ifdef __FreeBSD__ + !*pw->pw_dir || +#endif /* __FreeBSD__ */ + chdir(pw->pw_dir) < 0 + ) { +#ifdef __FreeBSD__ + int quiet_login = 0; +#endif /* __FreeBSD__ */ +#ifdef LOGIN_CAP + if (login_getcapbool(lc, "requirehome", 0)) { + (void)printf("Home directory not available\n"); + log("LOGIN %.200s REFUSED (HOMEDIR) ON TTY %.200s", + pw->pw_name, ttyname); + exit(254); + } +#endif /* LOGIN_CAP */ +#ifdef __FreeBSD__ + if (chdir("/") < 0) { + (void)printf("Cannot find root directory\n"); + log("LOGIN %.200s REFUSED (ROOTDIR) ON TTY %.200s", + pw->pw_name, ttyname); + exit(254); + } +#ifdef LOGIN_CAP + quiet_login = login_getcapbool(lc, "hushlogin", 0); +#endif /* LOGIN_CAP */ + if (!quiet_login || *pw->pw_dir) + (void)printf( + "No home directory.\nLogging in with home = \"/\".\n"); + +#else /* !__FreeBSD__ */ + fprintf(stderr, "Could not chdir to home directory %s: %s\n", pw->pw_dir, strerror(errno)); +#endif /* __FreeBSD__ */ + } +#ifdef LOGIN_CAP + login_close(lc); +#endif /* LOGIN_CAP */ /* * Must take new environment into use so that .ssh/rc, /etc/sshrc and @@ -989,7 +1219,11 @@ do_child(const char *command, struct passwd * pw, const char *term, mailbox = getenv("MAIL"); if (mailbox != NULL) { if (stat(mailbox, &mailstat) != 0 || mailstat.st_size == 0) +#ifdef __FreeBSD__ + ; +#else /* !__FreeBSD__ */ printf("No mail.\n"); +#endif /* __FreeBSD__ */ else if (mailstat.st_mtime < mailstat.st_atime) printf("You have mail.\n"); else |