diff options
Diffstat (limited to 'session.c')
-rw-r--r-- | session.c | 313 |
1 files changed, 204 insertions, 109 deletions
@@ -33,7 +33,7 @@ | |||
33 | */ | 33 | */ |
34 | 34 | ||
35 | #include "includes.h" | 35 | #include "includes.h" |
36 | RCSID("$OpenBSD: session.c,v 1.163 2003/08/31 13:29:05 markus Exp $"); | 36 | RCSID("$OpenBSD: session.c,v 1.172 2004/01/30 09:48:57 markus Exp $"); |
37 | 37 | ||
38 | #include "ssh.h" | 38 | #include "ssh.h" |
39 | #include "ssh1.h" | 39 | #include "ssh1.h" |
@@ -58,6 +58,10 @@ RCSID("$OpenBSD: session.c,v 1.163 2003/08/31 13:29:05 markus Exp $"); | |||
58 | #include "session.h" | 58 | #include "session.h" |
59 | #include "monitor_wrap.h" | 59 | #include "monitor_wrap.h" |
60 | 60 | ||
61 | #if defined(KRB5) && defined(USE_AFS) | ||
62 | #include <kafs.h> | ||
63 | #endif | ||
64 | |||
61 | #ifdef GSSAPI | 65 | #ifdef GSSAPI |
62 | #include "ssh-gss.h" | 66 | #include "ssh-gss.h" |
63 | #endif | 67 | #endif |
@@ -66,7 +70,7 @@ RCSID("$OpenBSD: session.c,v 1.163 2003/08/31 13:29:05 markus Exp $"); | |||
66 | 70 | ||
67 | Session *session_new(void); | 71 | Session *session_new(void); |
68 | void session_set_fds(Session *, int, int, int); | 72 | void session_set_fds(Session *, int, int, int); |
69 | void session_pty_cleanup(void *); | 73 | void session_pty_cleanup(Session *); |
70 | void session_proctitle(Session *); | 74 | void session_proctitle(Session *); |
71 | int session_setup_x11fwd(Session *); | 75 | int session_setup_x11fwd(Session *); |
72 | void do_exec_pty(Session *, const char *); | 76 | void do_exec_pty(Session *, const char *); |
@@ -106,6 +110,8 @@ Session sessions[MAX_SESSIONS]; | |||
106 | login_cap_t *lc; | 110 | login_cap_t *lc; |
107 | #endif | 111 | #endif |
108 | 112 | ||
113 | static int is_child = 0; | ||
114 | |||
109 | /* Name and directory of socket for authentication agent forwarding. */ | 115 | /* Name and directory of socket for authentication agent forwarding. */ |
110 | static char *auth_sock_name = NULL; | 116 | static char *auth_sock_name = NULL; |
111 | static char *auth_sock_dir = NULL; | 117 | static char *auth_sock_dir = NULL; |
@@ -113,10 +119,8 @@ static char *auth_sock_dir = NULL; | |||
113 | /* removes the agent forwarding socket */ | 119 | /* removes the agent forwarding socket */ |
114 | 120 | ||
115 | static void | 121 | static void |
116 | auth_sock_cleanup_proc(void *_pw) | 122 | auth_sock_cleanup_proc(struct passwd *pw) |
117 | { | 123 | { |
118 | struct passwd *pw = _pw; | ||
119 | |||
120 | if (auth_sock_name != NULL) { | 124 | if (auth_sock_name != NULL) { |
121 | temporarily_use_uid(pw); | 125 | temporarily_use_uid(pw); |
122 | unlink(auth_sock_name); | 126 | unlink(auth_sock_name); |
@@ -144,7 +148,7 @@ auth_input_request_forwarding(struct passwd * pw) | |||
144 | /* Allocate a buffer for the socket name, and format the name. */ | 148 | /* Allocate a buffer for the socket name, and format the name. */ |
145 | auth_sock_name = xmalloc(MAXPATHLEN); | 149 | auth_sock_name = xmalloc(MAXPATHLEN); |
146 | auth_sock_dir = xmalloc(MAXPATHLEN); | 150 | auth_sock_dir = xmalloc(MAXPATHLEN); |
147 | strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXX", MAXPATHLEN); | 151 | strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXXXX", MAXPATHLEN); |
148 | 152 | ||
149 | /* Create private directory for socket */ | 153 | /* Create private directory for socket */ |
150 | if (mkdtemp(auth_sock_dir) == NULL) { | 154 | if (mkdtemp(auth_sock_dir) == NULL) { |
@@ -160,9 +164,6 @@ auth_input_request_forwarding(struct passwd * pw) | |||
160 | snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld", | 164 | snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld", |
161 | auth_sock_dir, (long) getpid()); | 165 | auth_sock_dir, (long) getpid()); |
162 | 166 | ||
163 | /* delete agent socket on fatal() */ | ||
164 | fatal_add_cleanup(auth_sock_cleanup_proc, pw); | ||
165 | |||
166 | /* Create the socket. */ | 167 | /* Create the socket. */ |
167 | sock = socket(AF_UNIX, SOCK_STREAM, 0); | 168 | sock = socket(AF_UNIX, SOCK_STREAM, 0); |
168 | if (sock < 0) | 169 | if (sock < 0) |
@@ -180,7 +181,7 @@ auth_input_request_forwarding(struct passwd * pw) | |||
180 | restore_uid(); | 181 | restore_uid(); |
181 | 182 | ||
182 | /* Start listening on the socket. */ | 183 | /* Start listening on the socket. */ |
183 | if (listen(sock, 5) < 0) | 184 | if (listen(sock, SSH_LISTEN_BACKLOG) < 0) |
184 | packet_disconnect("listen: %.100s", strerror(errno)); | 185 | packet_disconnect("listen: %.100s", strerror(errno)); |
185 | 186 | ||
186 | /* Allocate a channel for the authentication agent socket. */ | 187 | /* Allocate a channel for the authentication agent socket. */ |
@@ -192,6 +193,15 @@ auth_input_request_forwarding(struct passwd * pw) | |||
192 | return 1; | 193 | return 1; |
193 | } | 194 | } |
194 | 195 | ||
196 | static void | ||
197 | display_loginmsg(void) | ||
198 | { | ||
199 | if (buffer_len(&loginmsg) > 0) { | ||
200 | buffer_append(&loginmsg, "\0", 1); | ||
201 | printf("%s\n", (char *)buffer_ptr(&loginmsg)); | ||
202 | buffer_clear(&loginmsg); | ||
203 | } | ||
204 | } | ||
195 | 205 | ||
196 | void | 206 | void |
197 | do_authenticated(Authctxt *authctxt) | 207 | do_authenticated(Authctxt *authctxt) |
@@ -207,7 +217,6 @@ do_authenticated(Authctxt *authctxt) | |||
207 | close(startup_pipe); | 217 | close(startup_pipe); |
208 | startup_pipe = -1; | 218 | startup_pipe = -1; |
209 | } | 219 | } |
210 | |||
211 | /* setup the channel layer */ | 220 | /* setup the channel layer */ |
212 | if (!no_port_forwarding_flag && options.allow_tcp_forwarding) | 221 | if (!no_port_forwarding_flag && options.allow_tcp_forwarding) |
213 | channel_permit_all_opens(); | 222 | channel_permit_all_opens(); |
@@ -217,13 +226,7 @@ do_authenticated(Authctxt *authctxt) | |||
217 | else | 226 | else |
218 | do_authenticated1(authctxt); | 227 | do_authenticated1(authctxt); |
219 | 228 | ||
220 | /* remove agent socket */ | 229 | do_cleanup(authctxt); |
221 | if (auth_sock_name != NULL) | ||
222 | auth_sock_cleanup_proc(authctxt->pw); | ||
223 | #ifdef KRB5 | ||
224 | if (options.kerberos_ticket_cleanup) | ||
225 | krb5_cleanup_proc(authctxt); | ||
226 | #endif | ||
227 | } | 230 | } |
228 | 231 | ||
229 | /* | 232 | /* |
@@ -395,17 +398,13 @@ do_exec_no_pty(Session *s, const char *command) | |||
395 | session_proctitle(s); | 398 | session_proctitle(s); |
396 | 399 | ||
397 | #if defined(USE_PAM) | 400 | #if defined(USE_PAM) |
398 | if (options.use_pam) { | 401 | if (options.use_pam && !use_privsep) |
399 | do_pam_setcred(1); | 402 | do_pam_setcred(1); |
400 | if (is_pam_password_change_required()) | ||
401 | packet_disconnect("Password change required but no " | ||
402 | "TTY available"); | ||
403 | } | ||
404 | #endif /* USE_PAM */ | 403 | #endif /* USE_PAM */ |
405 | 404 | ||
406 | /* Fork the child. */ | 405 | /* Fork the child. */ |
407 | if ((pid = fork()) == 0) { | 406 | if ((pid = fork()) == 0) { |
408 | fatal_remove_all_cleanups(); | 407 | is_child = 1; |
409 | 408 | ||
410 | /* Child. Reinitialize the log since the pid has changed. */ | 409 | /* Child. Reinitialize the log since the pid has changed. */ |
411 | log_init(__progname, options.log_level, options.log_facility, log_stderr); | 410 | log_init(__progname, options.log_level, options.log_facility, log_stderr); |
@@ -525,13 +524,14 @@ do_exec_pty(Session *s, const char *command) | |||
525 | #if defined(USE_PAM) | 524 | #if defined(USE_PAM) |
526 | if (options.use_pam) { | 525 | if (options.use_pam) { |
527 | do_pam_set_tty(s->tty); | 526 | do_pam_set_tty(s->tty); |
528 | do_pam_setcred(1); | 527 | if (!use_privsep) |
528 | do_pam_setcred(1); | ||
529 | } | 529 | } |
530 | #endif | 530 | #endif |
531 | 531 | ||
532 | /* Fork the child. */ | 532 | /* Fork the child. */ |
533 | if ((pid = fork()) == 0) { | 533 | if ((pid = fork()) == 0) { |
534 | fatal_remove_all_cleanups(); | 534 | is_child = 1; |
535 | 535 | ||
536 | /* Child. Reinitialize the log because the pid has changed. */ | 536 | /* Child. Reinitialize the log because the pid has changed. */ |
537 | log_init(__progname, options.log_level, options.log_facility, log_stderr); | 537 | log_init(__progname, options.log_level, options.log_facility, log_stderr); |
@@ -627,7 +627,7 @@ do_pre_login(Session *s) | |||
627 | if (getpeername(packet_get_connection_in(), | 627 | if (getpeername(packet_get_connection_in(), |
628 | (struct sockaddr *) & from, &fromlen) < 0) { | 628 | (struct sockaddr *) & from, &fromlen) < 0) { |
629 | debug("getpeername: %.100s", strerror(errno)); | 629 | debug("getpeername: %.100s", strerror(errno)); |
630 | fatal_cleanup(); | 630 | cleanup_exit(255); |
631 | } | 631 | } |
632 | } | 632 | } |
633 | 633 | ||
@@ -687,7 +687,7 @@ do_login(Session *s, const char *command) | |||
687 | if (getpeername(packet_get_connection_in(), | 687 | if (getpeername(packet_get_connection_in(), |
688 | (struct sockaddr *) & from, &fromlen) < 0) { | 688 | (struct sockaddr *) & from, &fromlen) < 0) { |
689 | debug("getpeername: %.100s", strerror(errno)); | 689 | debug("getpeername: %.100s", strerror(errno)); |
690 | fatal_cleanup(); | 690 | cleanup_exit(255); |
691 | } | 691 | } |
692 | } | 692 | } |
693 | 693 | ||
@@ -703,9 +703,10 @@ do_login(Session *s, const char *command) | |||
703 | * If password change is needed, do it now. | 703 | * If password change is needed, do it now. |
704 | * This needs to occur before the ~/.hushlogin check. | 704 | * This needs to occur before the ~/.hushlogin check. |
705 | */ | 705 | */ |
706 | if (options.use_pam && is_pam_password_change_required()) { | 706 | if (options.use_pam && !use_privsep && s->authctxt->force_pwchange) { |
707 | print_pam_messages(); | 707 | display_loginmsg(); |
708 | do_pam_chauthtok(); | 708 | do_pam_chauthtok(); |
709 | s->authctxt->force_pwchange = 0; | ||
709 | /* XXX - signal [net] parent to enable forwardings */ | 710 | /* XXX - signal [net] parent to enable forwardings */ |
710 | } | 711 | } |
711 | #endif | 712 | #endif |
@@ -713,17 +714,7 @@ do_login(Session *s, const char *command) | |||
713 | if (check_quietlogin(s, command)) | 714 | if (check_quietlogin(s, command)) |
714 | return; | 715 | return; |
715 | 716 | ||
716 | #ifdef USE_PAM | 717 | display_loginmsg(); |
717 | if (options.use_pam && !is_pam_password_change_required()) | ||
718 | print_pam_messages(); | ||
719 | #endif /* USE_PAM */ | ||
720 | |||
721 | /* display post-login message */ | ||
722 | if (buffer_len(&loginmsg) > 0) { | ||
723 | buffer_append(&loginmsg, "\0", 1); | ||
724 | printf("%s\n", (char *)buffer_ptr(&loginmsg)); | ||
725 | } | ||
726 | buffer_free(&loginmsg); | ||
727 | 718 | ||
728 | #ifndef NO_SSH_LASTLOG | 719 | #ifndef NO_SSH_LASTLOG |
729 | if (options.print_lastlog && s->last_login_time != 0) { | 720 | if (options.print_lastlog && s->last_login_time != 0) { |
@@ -798,8 +789,9 @@ void | |||
798 | child_set_env(char ***envp, u_int *envsizep, const char *name, | 789 | child_set_env(char ***envp, u_int *envsizep, const char *name, |
799 | const char *value) | 790 | const char *value) |
800 | { | 791 | { |
801 | u_int i, namelen; | ||
802 | char **env; | 792 | char **env; |
793 | u_int envsize; | ||
794 | u_int i, namelen; | ||
803 | 795 | ||
804 | /* | 796 | /* |
805 | * If we're passed an uninitialized list, allocate a single null | 797 | * If we're passed an uninitialized list, allocate a single null |
@@ -826,12 +818,13 @@ child_set_env(char ***envp, u_int *envsizep, const char *name, | |||
826 | xfree(env[i]); | 818 | xfree(env[i]); |
827 | } else { | 819 | } else { |
828 | /* New variable. Expand if necessary. */ | 820 | /* New variable. Expand if necessary. */ |
829 | if (i >= (*envsizep) - 1) { | 821 | envsize = *envsizep; |
830 | if (*envsizep >= 1000) | 822 | if (i >= envsize - 1) { |
831 | fatal("child_set_env: too many env vars," | 823 | if (envsize >= 1000) |
832 | " skipping: %.100s", name); | 824 | fatal("child_set_env: too many env vars"); |
833 | (*envsizep) += 50; | 825 | envsize += 50; |
834 | env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *)); | 826 | env = (*envp) = xrealloc(env, envsize * sizeof(char *)); |
827 | *envsizep = envsize; | ||
835 | } | 828 | } |
836 | /* Need to set the NULL pointer at end of array beyond the new slot. */ | 829 | /* Need to set the NULL pointer at end of array beyond the new slot. */ |
837 | env[i + 1] = NULL; | 830 | env[i + 1] = NULL; |
@@ -912,9 +905,8 @@ static void | |||
912 | read_etc_default_login(char ***env, u_int *envsize, uid_t uid) | 905 | read_etc_default_login(char ***env, u_int *envsize, uid_t uid) |
913 | { | 906 | { |
914 | char **tmpenv = NULL, *var; | 907 | char **tmpenv = NULL, *var; |
915 | u_int i; | 908 | u_int i, tmpenvsize = 0; |
916 | size_t tmpenvsize = 0; | 909 | u_long mask; |
917 | mode_t mask; | ||
918 | 910 | ||
919 | /* | 911 | /* |
920 | * We don't want to copy the whole file to the child's environment, | 912 | * We don't want to copy the whole file to the child's environment, |
@@ -923,17 +915,20 @@ read_etc_default_login(char ***env, u_int *envsize, uid_t uid) | |||
923 | */ | 915 | */ |
924 | read_environment_file(&tmpenv, &tmpenvsize, "/etc/default/login"); | 916 | read_environment_file(&tmpenv, &tmpenvsize, "/etc/default/login"); |
925 | 917 | ||
918 | if (tmpenv == NULL) | ||
919 | return; | ||
920 | |||
926 | if (uid == 0) | 921 | if (uid == 0) |
927 | var = child_get_env(tmpenv, "SUPATH"); | 922 | var = child_get_env(tmpenv, "SUPATH"); |
928 | else | 923 | else |
929 | var = child_get_env(tmpenv, "PATH"); | 924 | var = child_get_env(tmpenv, "PATH"); |
930 | if (var != NULL) | 925 | if (var != NULL) |
931 | child_set_env(env, envsize, "PATH", var); | 926 | child_set_env(env, envsize, "PATH", var); |
932 | 927 | ||
933 | if ((var = child_get_env(tmpenv, "UMASK")) != NULL) | 928 | if ((var = child_get_env(tmpenv, "UMASK")) != NULL) |
934 | if (sscanf(var, "%5lo", &mask) == 1) | 929 | if (sscanf(var, "%5lo", &mask) == 1) |
935 | umask(mask); | 930 | umask((mode_t)mask); |
936 | 931 | ||
937 | for (i = 0; tmpenv[i] != NULL; i++) | 932 | for (i = 0; tmpenv[i] != NULL; i++) |
938 | xfree(tmpenv[i]); | 933 | xfree(tmpenv[i]); |
939 | xfree(tmpenv); | 934 | xfree(tmpenv); |
@@ -958,7 +953,7 @@ void copy_environment(char **source, char ***env, u_int *envsize) | |||
958 | 953 | ||
959 | debug3("Copy environment: %s=%s", var_name, var_val); | 954 | debug3("Copy environment: %s=%s", var_name, var_val); |
960 | child_set_env(env, envsize, var_name, var_val); | 955 | child_set_env(env, envsize, var_name, var_val); |
961 | 956 | ||
962 | xfree(var_name); | 957 | xfree(var_name); |
963 | } | 958 | } |
964 | } | 959 | } |
@@ -985,7 +980,7 @@ do_setup_env(Session *s, const char *shell) | |||
985 | #endif | 980 | #endif |
986 | 981 | ||
987 | #ifdef GSSAPI | 982 | #ifdef GSSAPI |
988 | /* Allow any GSSAPI methods that we've used to alter | 983 | /* Allow any GSSAPI methods that we've used to alter |
989 | * the childs environment as they see fit | 984 | * the childs environment as they see fit |
990 | */ | 985 | */ |
991 | ssh_gssapi_do_child(&env, &envsize); | 986 | ssh_gssapi_do_child(&env, &envsize); |
@@ -1017,7 +1012,7 @@ do_setup_env(Session *s, const char *shell) | |||
1017 | path = child_get_env(env, "PATH"); | 1012 | path = child_get_env(env, "PATH"); |
1018 | # endif /* HAVE_ETC_DEFAULT_LOGIN */ | 1013 | # endif /* HAVE_ETC_DEFAULT_LOGIN */ |
1019 | if (path == NULL || *path == '\0') { | 1014 | if (path == NULL || *path == '\0') { |
1020 | child_set_env(&env, &envsize, "PATH", | 1015 | child_set_env(&env, &envsize, "PATH", |
1021 | s->pw->pw_uid == 0 ? | 1016 | s->pw->pw_uid == 0 ? |
1022 | SUPERUSER_PATH : _PATH_STDPATH); | 1017 | SUPERUSER_PATH : _PATH_STDPATH); |
1023 | } | 1018 | } |
@@ -1100,8 +1095,13 @@ do_setup_env(Session *s, const char *shell) | |||
1100 | * been set by PAM. | 1095 | * been set by PAM. |
1101 | */ | 1096 | */ |
1102 | if (options.use_pam) { | 1097 | if (options.use_pam) { |
1103 | char **p = fetch_pam_environment(); | 1098 | char **p; |
1099 | |||
1100 | p = fetch_pam_child_environment(); | ||
1101 | copy_environment(p, &env, &envsize); | ||
1102 | free_pam_environment(p); | ||
1104 | 1103 | ||
1104 | p = fetch_pam_environment(); | ||
1105 | copy_environment(p, &env, &envsize); | 1105 | copy_environment(p, &env, &envsize); |
1106 | free_pam_environment(p); | 1106 | free_pam_environment(p); |
1107 | } | 1107 | } |
@@ -1174,7 +1174,7 @@ do_rc_files(Session *s, const char *shell) | |||
1174 | if (debug_flag) { | 1174 | if (debug_flag) { |
1175 | fprintf(stderr, | 1175 | fprintf(stderr, |
1176 | "Running %.500s remove %.100s\n", | 1176 | "Running %.500s remove %.100s\n", |
1177 | options.xauth_location, s->auth_display); | 1177 | options.xauth_location, s->auth_display); |
1178 | fprintf(stderr, | 1178 | fprintf(stderr, |
1179 | "%.500s add %.100s %.100s %.100s\n", | 1179 | "%.500s add %.100s %.100s %.100s\n", |
1180 | options.xauth_location, s->auth_display, | 1180 | options.xauth_location, s->auth_display, |
@@ -1240,6 +1240,12 @@ do_setusercontext(struct passwd *pw) | |||
1240 | # ifdef __bsdi__ | 1240 | # ifdef __bsdi__ |
1241 | setpgid(0, 0); | 1241 | setpgid(0, 0); |
1242 | # endif | 1242 | # endif |
1243 | # ifdef USE_PAM | ||
1244 | if (options.use_pam) { | ||
1245 | do_pam_session(); | ||
1246 | do_pam_setcred(0); | ||
1247 | } | ||
1248 | # endif /* USE_PAM */ | ||
1243 | if (setusercontext(lc, pw, pw->pw_uid, | 1249 | if (setusercontext(lc, pw, pw->pw_uid, |
1244 | (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) { | 1250 | (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) { |
1245 | perror("unable to set user context"); | 1251 | perror("unable to set user context"); |
@@ -1266,7 +1272,7 @@ do_setusercontext(struct passwd *pw) | |||
1266 | endgrent(); | 1272 | endgrent(); |
1267 | # ifdef USE_PAM | 1273 | # ifdef USE_PAM |
1268 | /* | 1274 | /* |
1269 | * PAM credentials may take the form of supplementary groups. | 1275 | * PAM credentials may take the form of supplementary groups. |
1270 | * These will have been wiped by the above initgroups() call. | 1276 | * These will have been wiped by the above initgroups() call. |
1271 | * Reestablish them here. | 1277 | * Reestablish them here. |
1272 | */ | 1278 | */ |
@@ -1294,6 +1300,22 @@ do_setusercontext(struct passwd *pw) | |||
1294 | } | 1300 | } |
1295 | 1301 | ||
1296 | static void | 1302 | static void |
1303 | do_pwchange(Session *s) | ||
1304 | { | ||
1305 | fprintf(stderr, "WARNING: Your password has expired.\n"); | ||
1306 | if (s->ttyfd != -1) { | ||
1307 | fprintf(stderr, | ||
1308 | "You must change your password now and login again!\n"); | ||
1309 | execl(_PATH_PASSWD_PROG, "passwd", (char *)NULL); | ||
1310 | perror("passwd"); | ||
1311 | } else { | ||
1312 | fprintf(stderr, | ||
1313 | "Password change required but no TTY available.\n"); | ||
1314 | } | ||
1315 | exit(1); | ||
1316 | } | ||
1317 | |||
1318 | static void | ||
1297 | launch_login(struct passwd *pw, const char *hostname) | 1319 | launch_login(struct passwd *pw, const char *hostname) |
1298 | { | 1320 | { |
1299 | /* Launch login(1). */ | 1321 | /* Launch login(1). */ |
@@ -1314,6 +1336,40 @@ launch_login(struct passwd *pw, const char *hostname) | |||
1314 | exit(1); | 1336 | exit(1); |
1315 | } | 1337 | } |
1316 | 1338 | ||
1339 | static void | ||
1340 | child_close_fds(void) | ||
1341 | { | ||
1342 | int i; | ||
1343 | |||
1344 | if (packet_get_connection_in() == packet_get_connection_out()) | ||
1345 | close(packet_get_connection_in()); | ||
1346 | else { | ||
1347 | close(packet_get_connection_in()); | ||
1348 | close(packet_get_connection_out()); | ||
1349 | } | ||
1350 | /* | ||
1351 | * Close all descriptors related to channels. They will still remain | ||
1352 | * open in the parent. | ||
1353 | */ | ||
1354 | /* XXX better use close-on-exec? -markus */ | ||
1355 | channel_close_all(); | ||
1356 | |||
1357 | /* | ||
1358 | * Close any extra file descriptors. Note that there may still be | ||
1359 | * descriptors left by system functions. They will be closed later. | ||
1360 | */ | ||
1361 | endpwent(); | ||
1362 | |||
1363 | /* | ||
1364 | * Close any extra open file descriptors so that we don\'t have them | ||
1365 | * hanging around in clients. Note that we want to do this after | ||
1366 | * initgroups, because at least on Solaris 2.3 it leaves file | ||
1367 | * descriptors open. | ||
1368 | */ | ||
1369 | for (i = 3; i < 64; i++) | ||
1370 | close(i); | ||
1371 | } | ||
1372 | |||
1317 | /* | 1373 | /* |
1318 | * Performs common processing for the child, such as setting up the | 1374 | * Performs common processing for the child, such as setting up the |
1319 | * environment, closing extra file descriptors, setting the user and group | 1375 | * environment, closing extra file descriptors, setting the user and group |
@@ -1327,11 +1383,18 @@ do_child(Session *s, const char *command) | |||
1327 | char *argv[10]; | 1383 | char *argv[10]; |
1328 | const char *shell, *shell0, *hostname = NULL; | 1384 | const char *shell, *shell0, *hostname = NULL; |
1329 | struct passwd *pw = s->pw; | 1385 | struct passwd *pw = s->pw; |
1330 | u_int i; | ||
1331 | 1386 | ||
1332 | /* remove hostkey from the child's memory */ | 1387 | /* remove hostkey from the child's memory */ |
1333 | destroy_sensitive_data(); | 1388 | destroy_sensitive_data(); |
1334 | 1389 | ||
1390 | /* Force a password change */ | ||
1391 | if (s->authctxt->force_pwchange) { | ||
1392 | do_setusercontext(pw); | ||
1393 | child_close_fds(); | ||
1394 | do_pwchange(s); | ||
1395 | exit(1); | ||
1396 | } | ||
1397 | |||
1335 | /* login(1) is only called if we execute the login shell */ | 1398 | /* login(1) is only called if we execute the login shell */ |
1336 | if (options.use_login && command != NULL) | 1399 | if (options.use_login && command != NULL) |
1337 | options.use_login = 0; | 1400 | options.use_login = 0; |
@@ -1382,39 +1445,39 @@ do_child(Session *s, const char *command) | |||
1382 | * closed before building the environment, as we call | 1445 | * closed before building the environment, as we call |
1383 | * get_remote_ipaddr there. | 1446 | * get_remote_ipaddr there. |
1384 | */ | 1447 | */ |
1385 | if (packet_get_connection_in() == packet_get_connection_out()) | 1448 | child_close_fds(); |
1386 | close(packet_get_connection_in()); | ||
1387 | else { | ||
1388 | close(packet_get_connection_in()); | ||
1389 | close(packet_get_connection_out()); | ||
1390 | } | ||
1391 | /* | ||
1392 | * Close all descriptors related to channels. They will still remain | ||
1393 | * open in the parent. | ||
1394 | */ | ||
1395 | /* XXX better use close-on-exec? -markus */ | ||
1396 | channel_close_all(); | ||
1397 | 1449 | ||
1398 | /* | 1450 | /* |
1399 | * Close any extra file descriptors. Note that there may still be | 1451 | * Must take new environment into use so that .ssh/rc, |
1400 | * descriptors left by system functions. They will be closed later. | 1452 | * /etc/ssh/sshrc and xauth are run in the proper environment. |
1401 | */ | 1453 | */ |
1402 | endpwent(); | 1454 | environ = env; |
1403 | 1455 | ||
1456 | #if defined(KRB5) && defined(USE_AFS) | ||
1404 | /* | 1457 | /* |
1405 | * Close any extra open file descriptors so that we don\'t have them | 1458 | * At this point, we check to see if AFS is active and if we have |
1406 | * hanging around in clients. Note that we want to do this after | 1459 | * a valid Kerberos 5 TGT. If so, it seems like a good idea to see |
1407 | * initgroups, because at least on Solaris 2.3 it leaves file | 1460 | * if we can (and need to) extend the ticket into an AFS token. If |
1408 | * descriptors open. | 1461 | * we don't do this, we run into potential problems if the user's |
1462 | * home directory is in AFS and it's not world-readable. | ||
1409 | */ | 1463 | */ |
1410 | for (i = 3; i < 64; i++) | ||
1411 | close(i); | ||
1412 | 1464 | ||
1413 | /* | 1465 | if (options.kerberos_get_afs_token && k_hasafs() && |
1414 | * Must take new environment into use so that .ssh/rc, | 1466 | (s->authctxt->krb5_ctx != NULL)) { |
1415 | * /etc/ssh/sshrc and xauth are run in the proper environment. | 1467 | char cell[64]; |
1416 | */ | 1468 | |
1417 | environ = env; | 1469 | debug("Getting AFS token"); |
1470 | |||
1471 | k_setpag(); | ||
1472 | |||
1473 | if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0) | ||
1474 | krb5_afslog(s->authctxt->krb5_ctx, | ||
1475 | s->authctxt->krb5_fwd_ccache, cell, NULL); | ||
1476 | |||
1477 | krb5_afslog_home(s->authctxt->krb5_ctx, | ||
1478 | s->authctxt->krb5_fwd_ccache, NULL, NULL, pw->pw_dir); | ||
1479 | } | ||
1480 | #endif | ||
1418 | 1481 | ||
1419 | /* Change current directory to the user\'s home directory. */ | 1482 | /* Change current directory to the user\'s home directory. */ |
1420 | if (chdir(pw->pw_dir) < 0) { | 1483 | if (chdir(pw->pw_dir) < 0) { |
@@ -1537,7 +1600,7 @@ session_open(Authctxt *authctxt, int chanid) | |||
1537 | } | 1600 | } |
1538 | s->authctxt = authctxt; | 1601 | s->authctxt = authctxt; |
1539 | s->pw = authctxt->pw; | 1602 | s->pw = authctxt->pw; |
1540 | if (s->pw == NULL) | 1603 | if (s->pw == NULL || !authctxt->valid) |
1541 | fatal("no user for session %d", s->self); | 1604 | fatal("no user for session %d", s->self); |
1542 | debug("session_open: session %d: link with channel %d", s->self, chanid); | 1605 | debug("session_open: session %d: link with channel %d", s->self, chanid); |
1543 | s->chanid = chanid; | 1606 | s->chanid = chanid; |
@@ -1659,11 +1722,6 @@ session_pty_req(Session *s) | |||
1659 | n_bytes = packet_remaining(); | 1722 | n_bytes = packet_remaining(); |
1660 | tty_parse_modes(s->ttyfd, &n_bytes); | 1723 | tty_parse_modes(s->ttyfd, &n_bytes); |
1661 | 1724 | ||
1662 | /* | ||
1663 | * Add a cleanup function to clear the utmp entry and record logout | ||
1664 | * time in case we call fatal() (e.g., the connection gets closed). | ||
1665 | */ | ||
1666 | fatal_add_cleanup(session_pty_cleanup, (void *)s); | ||
1667 | if (!use_privsep) | 1725 | if (!use_privsep) |
1668 | pty_setowner(s->pw, s->tty); | 1726 | pty_setowner(s->pw, s->tty); |
1669 | 1727 | ||
@@ -1845,10 +1903,8 @@ session_set_fds(Session *s, int fdin, int fdout, int fderr) | |||
1845 | * (e.g., due to a dropped connection). | 1903 | * (e.g., due to a dropped connection). |
1846 | */ | 1904 | */ |
1847 | void | 1905 | void |
1848 | session_pty_cleanup2(void *session) | 1906 | session_pty_cleanup2(Session *s) |
1849 | { | 1907 | { |
1850 | Session *s = session; | ||
1851 | |||
1852 | if (s == NULL) { | 1908 | if (s == NULL) { |
1853 | error("session_pty_cleanup: no session"); | 1909 | error("session_pty_cleanup: no session"); |
1854 | return; | 1910 | return; |
@@ -1879,9 +1935,9 @@ session_pty_cleanup2(void *session) | |||
1879 | } | 1935 | } |
1880 | 1936 | ||
1881 | void | 1937 | void |
1882 | session_pty_cleanup(void *session) | 1938 | session_pty_cleanup(Session *s) |
1883 | { | 1939 | { |
1884 | PRIVSEP(session_pty_cleanup2(session)); | 1940 | PRIVSEP(session_pty_cleanup2(s)); |
1885 | } | 1941 | } |
1886 | 1942 | ||
1887 | static char * | 1943 | static char * |
@@ -1954,10 +2010,8 @@ void | |||
1954 | session_close(Session *s) | 2010 | session_close(Session *s) |
1955 | { | 2011 | { |
1956 | debug("session_close: session %d pid %ld", s->self, (long)s->pid); | 2012 | debug("session_close: session %d pid %ld", s->self, (long)s->pid); |
1957 | if (s->ttyfd != -1) { | 2013 | if (s->ttyfd != -1) |
1958 | fatal_remove_cleanup(session_pty_cleanup, (void *)s); | ||
1959 | session_pty_cleanup(s); | 2014 | session_pty_cleanup(s); |
1960 | } | ||
1961 | if (s->term) | 2015 | if (s->term) |
1962 | xfree(s->term); | 2016 | xfree(s->term); |
1963 | if (s->display) | 2017 | if (s->display) |
@@ -2006,10 +2060,8 @@ session_close_by_channel(int id, void *arg) | |||
2006 | * delay detach of session, but release pty, since | 2060 | * delay detach of session, but release pty, since |
2007 | * the fd's to the child are already closed | 2061 | * the fd's to the child are already closed |
2008 | */ | 2062 | */ |
2009 | if (s->ttyfd != -1) { | 2063 | if (s->ttyfd != -1) |
2010 | fatal_remove_cleanup(session_pty_cleanup, (void *)s); | ||
2011 | session_pty_cleanup(s); | 2064 | session_pty_cleanup(s); |
2012 | } | ||
2013 | return; | 2065 | return; |
2014 | } | 2066 | } |
2015 | /* detach by removing callback */ | 2067 | /* detach by removing callback */ |
@@ -2044,13 +2096,13 @@ session_tty_list(void) | |||
2044 | for (i = 0; i < MAX_SESSIONS; i++) { | 2096 | for (i = 0; i < MAX_SESSIONS; i++) { |
2045 | Session *s = &sessions[i]; | 2097 | Session *s = &sessions[i]; |
2046 | if (s->used && s->ttyfd != -1) { | 2098 | if (s->used && s->ttyfd != -1) { |
2047 | 2099 | ||
2048 | if (strncmp(s->tty, "/dev/", 5) != 0) { | 2100 | if (strncmp(s->tty, "/dev/", 5) != 0) { |
2049 | cp = strrchr(s->tty, '/'); | 2101 | cp = strrchr(s->tty, '/'); |
2050 | cp = (cp == NULL) ? s->tty : cp + 1; | 2102 | cp = (cp == NULL) ? s->tty : cp + 1; |
2051 | } else | 2103 | } else |
2052 | cp = s->tty + 5; | 2104 | cp = s->tty + 5; |
2053 | 2105 | ||
2054 | if (buf[0] != '\0') | 2106 | if (buf[0] != '\0') |
2055 | strlcat(buf, ",", sizeof buf); | 2107 | strlcat(buf, ",", sizeof buf); |
2056 | strlcat(buf, cp, sizeof buf); | 2108 | strlcat(buf, cp, sizeof buf); |
@@ -2150,8 +2202,51 @@ static void | |||
2150 | do_authenticated2(Authctxt *authctxt) | 2202 | do_authenticated2(Authctxt *authctxt) |
2151 | { | 2203 | { |
2152 | server_loop2(authctxt); | 2204 | server_loop2(authctxt); |
2153 | #if defined(GSSAPI) | 2205 | } |
2154 | if (options.gss_cleanup_creds) | 2206 | |
2155 | ssh_gssapi_cleanup_creds(NULL); | 2207 | void |
2208 | do_cleanup(Authctxt *authctxt) | ||
2209 | { | ||
2210 | static int called = 0; | ||
2211 | |||
2212 | debug("do_cleanup"); | ||
2213 | |||
2214 | /* no cleanup if we're in the child for login shell */ | ||
2215 | if (is_child) | ||
2216 | return; | ||
2217 | |||
2218 | /* avoid double cleanup */ | ||
2219 | if (called) | ||
2220 | return; | ||
2221 | called = 1; | ||
2222 | |||
2223 | if (authctxt == NULL) | ||
2224 | return; | ||
2225 | #ifdef KRB5 | ||
2226 | if (options.kerberos_ticket_cleanup && | ||
2227 | authctxt->krb5_ctx) | ||
2228 | krb5_cleanup_proc(authctxt); | ||
2229 | #endif | ||
2230 | |||
2231 | #ifdef GSSAPI | ||
2232 | if (compat20 && options.gss_cleanup_creds) | ||
2233 | ssh_gssapi_cleanup_creds(); | ||
2156 | #endif | 2234 | #endif |
2235 | |||
2236 | #ifdef USE_PAM | ||
2237 | if (options.use_pam) { | ||
2238 | sshpam_cleanup(); | ||
2239 | sshpam_thread_cleanup(); | ||
2240 | } | ||
2241 | #endif | ||
2242 | |||
2243 | /* remove agent socket */ | ||
2244 | auth_sock_cleanup_proc(authctxt->pw); | ||
2245 | |||
2246 | /* | ||
2247 | * Cleanup ptys/utmp only if privsep is disabled, | ||
2248 | * or if running in monitor. | ||
2249 | */ | ||
2250 | if (!use_privsep || mm_is_monitor()) | ||
2251 | session_destroy_all(session_pty_cleanup2); | ||
2157 | } | 2252 | } |