X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/653d5f86b8e4b6939806b46ef124b70947404404..8fbc356de176c10b7d4503b6c6bbbe9954f95b77:/session.c diff --git a/session.c b/session.c index 0d7b8fa3..1e9e3228 100644 --- a/session.c +++ b/session.c @@ -9,7 +9,7 @@ * called by a name other than "ssh" or "Secure Shell". * * SSH2 support by Markus Friedl. - * Copyright (c) 2000 Markus Friedl. All rights reserved. + * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,7 +33,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: session.c,v 1.86 2001/06/12 16:10:38 markus Exp $"); +RCSID("$OpenBSD: session.c,v 1.100 2001/08/16 19:18:34 jakob Exp $"); #include "ssh.h" #include "ssh1.h" @@ -99,7 +99,8 @@ typedef struct Session Session; struct Session { int used; int self; - struct passwd *pw; + struct passwd *pw; + Authctxt *authctxt; pid_t pid; /* tty */ char *term; @@ -120,25 +121,23 @@ struct Session { /* func */ Session *session_new(void); -void session_set_fds(Session *s, int fdin, int fdout, int fderr); -void session_pty_cleanup(void *session); -int session_pty_req(Session *s); -void session_proctitle(Session *s); -int session_setup_x11fwd(Session *s); -void session_close(Session *s); -void do_exec_pty(Session *s, const char *command); -void do_exec_no_pty(Session *s, const char *command); -void do_login(Session *s, const char *command); -#ifdef LOGIN_NEEDS_UTMPX -void do_pre_login(Session *s); -#endif -void do_child(Session *s, const char *command); +void session_set_fds(Session *, int, int, int); +static void session_pty_cleanup(void *); +void session_proctitle(Session *); +int session_setup_x11fwd(Session *); +void do_exec_pty(Session *, const char *); +void do_exec_no_pty(Session *, const char *); +void do_exec(Session *, const char *); +void do_login(Session *, const char *); +void do_child(Session *, const char *); void do_motd(void); -int check_quietlogin(Session *s, const char *command); -void xauthfile_cleanup_proc(void *pw); +int check_quietlogin(Session *, const char *); -void do_authenticated1(Authctxt *authctxt); -void do_authenticated2(Authctxt *authctxt); +static void do_authenticated1(Authctxt *); +static void do_authenticated2(Authctxt *); + +static void session_close(Session *); +static int session_pty_req(Session *); /* import */ extern ServerOptions options; @@ -149,11 +148,8 @@ extern u_int utmp_len; extern int startup_pipe; extern void destroy_sensitive_data(void); -/* Local Xauthority file. */ -static char *xauthfile; - /* original command from peer. */ -char *original_command = NULL; +const char *original_command = NULL; /* data */ #define MAX_SESSIONS 10 @@ -201,35 +197,17 @@ do_authenticated(Authctxt *authctxt) else do_authenticated1(authctxt); - /* remote user's local Xauthority file and agent socket */ - if (xauthfile) - xauthfile_cleanup_proc(authctxt->pw); + /* remove agent socket */ if (auth_get_socket_name()) auth_sock_cleanup_proc(authctxt->pw); -} - -/* - * Remove local Xauthority file. - */ -void -xauthfile_cleanup_proc(void *_pw) -{ - struct passwd *pw = _pw; - char *p; - - debug("xauthfile_cleanup_proc called"); - if (xauthfile != NULL) { - temporarily_use_uid(pw); - unlink(xauthfile); - p = strrchr(xauthfile, '/'); - if (p != NULL) { - *p = '\0'; - rmdir(xauthfile); - } - xfree(xauthfile); - xauthfile = NULL; - restore_uid(); - } +#ifdef KRB4 + if (options.kerberos_ticket_cleanup) + krb4_cleanup_proc(authctxt); +#endif +#ifdef KRB5 + if (options.kerberos_ticket_cleanup) + krb5_cleanup_proc(authctxt); +#endif } /* @@ -238,7 +216,7 @@ xauthfile_cleanup_proc(void *_pw) * terminals are allocated, X11, TCP/IP, and authentication agent forwardings * are requested, etc. */ -void +static void do_authenticated1(Authctxt *authctxt) { Session *s; @@ -248,6 +226,7 @@ do_authenticated1(Authctxt *authctxt) u_int proto_len, data_len, dlen; s = session_new(); + s->authctxt = authctxt; s->pw = authctxt->pw; /* @@ -332,28 +311,70 @@ do_authenticated1(Authctxt *authctxt) if (packet_set_maxsize(packet_get_int()) > 0) success = 1; break; + +#if defined(AFS) || defined(KRB5) + case SSH_CMSG_HAVE_KERBEROS_TGT: + if (!options.kerberos_tgt_passing) { + verbose("Kerberos TGT passing disabled."); + } else { + char *kdata = packet_get_string(&dlen); + packet_integrity_check(plen, 4 + dlen, type); + + /* XXX - 0x41, see creds_to_radix version */ + if (kdata[0] != 0x41) { +#ifdef KRB5 + krb5_data tgt; + tgt.data = kdata; + tgt.length = dlen; + + if (auth_krb5_tgt(s->authctxt, &tgt)) + success = 1; + else + verbose("Kerberos v5 TGT refused for %.100s", s->authctxt->user); +#endif /* KRB5 */ + } else { +#ifdef AFS + if (auth_krb4_tgt(s->authctxt, kdata)) + success = 1; + else + verbose("Kerberos v4 TGT refused for %.100s", s->authctxt->user); +#endif /* AFS */ + } + xfree(kdata); + } + break; +#endif /* AFS || KRB5 */ + +#ifdef AFS + case SSH_CMSG_HAVE_AFS_TOKEN: + if (!options.afs_token_passing || !k_hasafs()) { + verbose("AFS token passing disabled."); + } else { + /* Accept AFS token. */ + char *token = packet_get_string(&dlen); + packet_integrity_check(plen, 4 + dlen, type); + + if (auth_afs_token(s->authctxt, token)) + success = 1; + else + verbose("AFS token refused for %.100s", + s->authctxt->user); + xfree(token); + } + break; +#endif /* AFS */ case SSH_CMSG_EXEC_SHELL: case SSH_CMSG_EXEC_CMD: if (type == SSH_CMSG_EXEC_CMD) { command = packet_get_string(&dlen); debug("Exec command '%.500s'", command); - packet_integrity_check(plen, 4 + dlen, type); + do_exec(s, command); + xfree(command); } else { - command = NULL; - packet_integrity_check(plen, 0, type); - } - if (forced_command != NULL) { - original_command = command; - command = forced_command; - debug("Forced command '%.500s'", forced_command); + do_exec(s, NULL); } - if (s->ttyfd != -1) - do_exec_pty(s, command); - else - do_exec_no_pty(s, command); - if (command != NULL) - xfree(command); + packet_done(); session_close(s); return; @@ -406,6 +427,7 @@ do_exec_no_pty(Session *s, const char *command) session_proctitle(s); #if defined(USE_PAM) + do_pam_session(s->pw->pw_name, NULL); do_pam_setcred(1); #endif /* USE_PAM */ @@ -526,9 +548,9 @@ do_exec_pty(Session *s, const char *command) /* Fork the child. */ if ((pid = fork()) == 0) { + /* Child. Reinitialize the log because the pid has changed. */ log_init(__progname, options.log_level, options.log_facility, log_stderr); - /* Close the master side of the pseudo tty. */ close(ptyfd); @@ -628,6 +650,27 @@ do_pre_login(Session *s) } #endif +/* + * This is called to fork and execute a command. If another command is + * to be forced, execute that instead. + */ +void +do_exec(Session *s, const char *command) +{ + if (forced_command) { + original_command = command; + command = forced_command; + debug("Forced command '%.900s'", command); + } + + if (s->ttyfd != -1) + do_exec_pty(s, command); + else + do_exec_no_pty(s, command); + + original_command = NULL; +} + /* administrative, login(1)-like work */ void do_login(Session *s, const char *command) @@ -734,7 +777,7 @@ int check_quietlogin(Session *s, const char *command) { char buf[256]; - struct passwd * pw = s->pw; + struct passwd *pw = s->pw; struct stat st; /* Return 1 if .hushlogin exists or a command given. */ @@ -755,7 +798,7 @@ check_quietlogin(Session *s, const char *command) * Sets the value of the given variable in the environment. If the variable * already exists, its value is overriden. */ -void +static void child_set_env(char ***envp, u_int *envsizep, const char *name, const char *value) { @@ -796,7 +839,7 @@ child_set_env(char ***envp, u_int *envsizep, const char *name, * Otherwise, it must consist of empty lines, comments (line starts with '#') * and assignments of the form name=value. No other forms are allowed. */ -void +static void read_environment_file(char ***env, u_int *envsize, const char *filename) { @@ -835,7 +878,7 @@ read_environment_file(char ***env, u_int *envsize, /* * Sets any environment variables which have been specified by PAM */ -void do_pam_environment(char ***env, int *envsize) +void do_pam_environment(char ***env, u_int *envsize) { char *equals, var_name[512], var_val[512]; char **pam_env; @@ -864,7 +907,7 @@ void do_pam_environment(char ***env, int *envsize) #endif /* USE_PAM */ #ifdef HAVE_CYGWIN -void copy_environment(char ***env, int *envsize) +void copy_environment(char ***env, u_int *envsize) { char *equals, var_name[512], var_val[512]; int i; @@ -976,7 +1019,7 @@ void do_child(Session *s, const char *command) { const char *shell, *hostname = NULL, *cp = NULL; - struct passwd * pw = s->pw; + struct passwd *pw = s->pw; char buf[256]; char cmd[1024]; FILE *f = NULL; @@ -1007,7 +1050,7 @@ do_child(Session *s, const char *command) if (options.use_login && command != NULL) options.use_login = 0; -#if !defined(USE_PAM) && !defined(HAVE_OSF_SIA) +#if !defined(HAVE_OSF_SIA) if (!options.use_login) { # ifdef HAVE_LOGIN_CAP if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid) @@ -1025,7 +1068,7 @@ do_child(Session *s, const char *command) exit(254); } } -#endif /* USE_PAM || HAVE_OSF_SIA */ +#endif /* HAVE_OSF_SIA */ /* Set login name, uid, gid, and groups. */ /* Login(1) does this as well, and it needs uid 0 for the "-h" @@ -1155,10 +1198,10 @@ do_child(Session *s, const char *command) /* Try to get AFS tokens for the local cell. */ if (k_hasafs()) { char cell[64]; - + if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0) krb_afslog(cell, 0); - + krb_afslog(0, 0); } #endif /* AFS */ @@ -1242,23 +1285,21 @@ do_child(Session *s, const char *command) child_set_env(&env, &envsize, "KRB5CCNAME", cp); read_environment_file(&env, &envsize, "/etc/environment"); #endif - #ifdef KRB4 - { - extern char *ticket; - - if (ticket) - child_set_env(&env, &envsize, "KRBTKFILE", ticket); - } -#endif /* KRB4 */ - + if (s->authctxt->krb4_ticket_file) + child_set_env(&env, &envsize, "KRBTKFILE", + s->authctxt->krb4_ticket_file); +#endif +#ifdef KRB5 + if (s->authctxt->krb5_ticket_file) + child_set_env(&env, &envsize, "KRB5CCNAME", + s->authctxt->krb5_ticket_file); +#endif #ifdef USE_PAM /* Pull in any environment variables that may have been set by PAM. */ do_pam_environment(&env, &envsize); #endif /* USE_PAM */ - if (xauthfile) - child_set_env(&env, &envsize, "XAUTHORITY", xauthfile); if (auth_get_socket_name() != NULL) child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, auth_get_socket_name()); @@ -1418,25 +1459,6 @@ do_child(Session *s, const char *command) if (!options.use_login) { char buf[256]; - /* - * Check for mail if we have a tty and it was enabled - * in server options. - */ - if (s->ttyfd != -1 && options.check_mail) { - char *mailbox; - struct stat mailstat; - - mailbox = getenv("MAIL"); - if (mailbox != NULL) { - if (stat(mailbox, &mailstat) != 0 || - mailstat.st_size == 0) - printf("No mail.\n"); - else if (mailstat.st_mtime < mailstat.st_atime) - printf("You have mail.\n"); - else - printf("You have new mail.\n"); - } - } /* Start the shell. Set initial character to '-'. */ buf[0] = '-'; strncpy(buf + 1, cp, sizeof(buf) - 1); @@ -1458,7 +1480,7 @@ do_child(Session *s, const char *command) #ifdef LOGIN_NEEDS_TERM s->term? s->term : "unknown", #endif - "-p", "-f", "--", pw->pw_name, NULL); + "-p", "-f", "--", pw->pw_name, (char *)NULL); /* Login couldn't be executed, die. */ @@ -1507,7 +1529,7 @@ session_new(void) return NULL; } -void +static void session_dump(void) { int i; @@ -1523,7 +1545,7 @@ session_dump(void) } int -session_open(int chanid) +session_open(Authctxt *authctxt, int chanid) { Session *s = session_new(); debug("session_open: channel %d", chanid); @@ -1531,7 +1553,8 @@ session_open(int chanid) error("no more sessions"); return 0; } - s->pw = auth_get_user(); + s->authctxt = authctxt; + s->pw = authctxt->pw; if (s->pw == NULL) fatal("no user for session %d", s->self); debug("session_open: session %d: link with channel %d", s->self, chanid); @@ -1539,7 +1562,7 @@ session_open(int chanid) return 1; } -Session * +static Session * session_by_channel(int id) { int i; @@ -1555,7 +1578,7 @@ session_by_channel(int id) return NULL; } -Session * +static Session * session_by_pid(pid_t pid) { int i; @@ -1570,7 +1593,7 @@ session_by_pid(pid_t pid) return NULL; } -int +static int session_window_change_req(Session *s) { s->col = packet_get_int(); @@ -1582,7 +1605,7 @@ session_window_change_req(Session *s) return 1; } -int +static int session_pty_req(Session *s) { u_int len; @@ -1647,7 +1670,7 @@ session_pty_req(Session *s) return 1; } -int +static int session_subsystem_req(Session *s) { u_int len; @@ -1674,7 +1697,7 @@ session_subsystem_req(Session *s) return success; } -int +static int session_x11_req(Session *s) { int success; @@ -1695,40 +1718,26 @@ session_x11_req(Session *s) return success; } -int +static int session_shell_req(Session *s) { - /* if forced_command == NULL, the shell is execed */ - char *shell = forced_command; packet_done(); - if (s->ttyfd == -1) - do_exec_no_pty(s, shell); - else - do_exec_pty(s, shell); + do_exec(s, NULL); return 1; } -int +static int session_exec_req(Session *s) { u_int len; char *command = packet_get_string(&len); packet_done(); - if (forced_command) { - original_command = command; - command = forced_command; - debug("Forced command '%.500s'", forced_command); - } - if (s->ttyfd == -1) - do_exec_no_pty(s, command); - else - do_exec_pty(s, command); - if (forced_command == NULL) - xfree(command); + do_exec(s, command); + xfree(command); return 1; } -int +static int session_auth_agent_req(Session *s) { static int called = 0; @@ -1821,7 +1830,7 @@ session_set_fds(Session *s, int fdin, int fdout, int fderr) * Function to perform pty cleanup. Also called if we get aborted abnormally * (e.g., due to a dropped connection). */ -void +static void session_pty_cleanup(void *session) { Session *s = session; @@ -1851,7 +1860,7 @@ session_pty_cleanup(void *session) error("close(s->ptymaster): %s", strerror(errno)); } -void +static void session_exit_message(Session *s, int status) { Channel *c; @@ -1900,7 +1909,7 @@ session_exit_message(Session *s, int status) s->chanid = -1; } -void +static void session_close(Session *s) { debug("session_close: session %d pid %d", s->self, s->pid); @@ -1925,7 +1934,7 @@ session_close_by_pid(pid_t pid, int status) { Session *s = session_by_pid(pid); if (s == NULL) { - debug("session_close_by_pid: no session for pid %d", s->pid); + debug("session_close_by_pid: no session for pid %d", pid); return; } if (s->chanid != -1) @@ -1933,6 +1942,22 @@ session_close_by_pid(pid_t pid, int status) session_close(s); } +int +session_have_children(void) +{ + int i; + + for(i = 0; i < MAX_SESSIONS; i++) { + Session *s = &sessions[i]; + if (s->used && s->pid != -1) { + debug("session_have_children: id %d pid %d", i, s->pid); + return 1; + } + } + debug("session_have_children: no more children"); + return 0; +} + /* * this is called when a channel dies before * the session 'child' itself dies @@ -1961,7 +1986,7 @@ session_close_by_channel(int id, void *arg) } } -char * +static char * session_tty_list(void) { static char buf[1024]; @@ -1992,7 +2017,6 @@ session_proctitle(Session *s) int session_setup_x11fwd(Session *s) { - int fd; struct stat st; if (no_x11_forwarding_flag) { @@ -2008,37 +2032,25 @@ session_setup_x11fwd(Session *s) packet_send_debug("No xauth program; cannot forward with spoofing."); return 0; } - if (s->display != NULL || xauthfile != NULL) { - debug("X11 display already set."); + if (options.use_login) { + packet_send_debug("X11 forwarding disabled; " + "not compatible with UseLogin=yes."); return 0; } - xauthfile = xmalloc(MAXPATHLEN); - strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN); - temporarily_use_uid(s->pw); - if (mkdtemp(xauthfile) == NULL) { - error("private X11 dir: mkdtemp %s failed: %s", - xauthfile, strerror(errno)); - restore_uid(); - xfree(xauthfile); - xauthfile = NULL; + if (s->display != NULL) { + debug("X11 display already set."); return 0; } - strlcat(xauthfile, "/cookies", MAXPATHLEN); - fd = open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600); - if (fd >= 0) - close(fd); - restore_uid(); s->display = x11_create_display_inet(s->screen, options.x11_display_offset); if (s->display == NULL) { - xauthfile_cleanup_proc(s->pw); + debug("x11_create_display_inet failed."); return 0; } - fatal_add_cleanup(xauthfile_cleanup_proc, s->pw); return 1; } -void +static void do_authenticated2(Authctxt *authctxt) { - server_loop2(); + server_loop2(authctxt); }