diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | acconfig.h | 5 | ||||
-rw-r--r-- | auth-passwd.c | 98 | ||||
-rw-r--r-- | auth.h | 1 | ||||
-rw-r--r-- | configure.ac | 7 | ||||
-rw-r--r-- | pathnames.h | 5 | ||||
-rw-r--r-- | session.c | 89 |
7 files changed, 147 insertions, 66 deletions
@@ -12,6 +12,12 @@ | |||
12 | - (dtucker) [openbsd-compat/port-aix.c openbsd-compat/port-aix.h] Bug #796: | 12 | - (dtucker) [openbsd-compat/port-aix.c openbsd-compat/port-aix.h] Bug #796: |
13 | Restore previous authdb setting after auth calls. Fixes problems with | 13 | Restore previous authdb setting after auth calls. Fixes problems with |
14 | setpcred failing on accounts that use AFS or NIS password registries. | 14 | setpcred failing on accounts that use AFS or NIS password registries. |
15 | - (dtucker) OpenBSD CVS Sync | ||
16 | - markus@cvs.openbsd.org 2004/01/30 09:48:57 | ||
17 | [auth-passwd.c auth.h pathnames.h session.c] | ||
18 | support for password change; ok dtucker@ | ||
19 | (set password-dead=1w in login.conf to use this). | ||
20 | In -Portable, this is currently only platforms using bsdauth. | ||
15 | 21 | ||
16 | 20040129 | 22 | 20040129 |
17 | - (dtucker) OpenBSD CVS Sync regress/ | 23 | - (dtucker) OpenBSD CVS Sync regress/ |
@@ -1797,4 +1803,4 @@ | |||
1797 | - Fix sshd BindAddress and -b options for systems using fake-getaddrinfo. | 1803 | - Fix sshd BindAddress and -b options for systems using fake-getaddrinfo. |
1798 | Report from murple@murple.net, diagnosis from dtucker@zip.com.au | 1804 | Report from murple@murple.net, diagnosis from dtucker@zip.com.au |
1799 | 1805 | ||
1800 | $Id: ChangeLog,v 1.3211 2004/02/06 05:18:47 dtucker Exp $ | 1806 | $Id: ChangeLog,v 1.3212 2004/02/06 05:24:31 dtucker Exp $ |
diff --git a/acconfig.h b/acconfig.h index 27366ed17..62252d760 100644 --- a/acconfig.h +++ b/acconfig.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $Id: acconfig.h,v 1.172 2004/01/23 11:03:10 dtucker Exp $ */ | 1 | /* $Id: acconfig.h,v 1.173 2004/02/06 05:24:31 dtucker Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 1999-2003 Damien Miller. All rights reserved. | 4 | * Copyright (c) 1999-2003 Damien Miller. All rights reserved. |
@@ -65,6 +65,9 @@ | |||
65 | /* from environment and PATH */ | 65 | /* from environment and PATH */ |
66 | #undef LOGIN_PROGRAM_FALLBACK | 66 | #undef LOGIN_PROGRAM_FALLBACK |
67 | 67 | ||
68 | /* Full path of your "passwd" program */ | ||
69 | #undef _PATH_PASSWD_PROG | ||
70 | |||
68 | /* Define if your password has a pw_class field */ | 71 | /* Define if your password has a pw_class field */ |
69 | #undef HAVE_PW_CLASS_IN_PASSWD | 72 | #undef HAVE_PW_CLASS_IN_PASSWD |
70 | 73 | ||
diff --git a/auth-passwd.c b/auth-passwd.c index a27170ccc..d12996bba 100644 --- a/auth-passwd.c +++ b/auth-passwd.c | |||
@@ -42,11 +42,21 @@ RCSID("$OpenBSD: auth-passwd.c,v 1.30 2003/11/04 08:54:09 djm Exp $"); | |||
42 | #include "log.h" | 42 | #include "log.h" |
43 | #include "servconf.h" | 43 | #include "servconf.h" |
44 | #include "auth.h" | 44 | #include "auth.h" |
45 | #include "auth-options.h" | ||
45 | #ifdef WITH_AIXAUTHENTICATE | 46 | #ifdef WITH_AIXAUTHENTICATE |
46 | # include "canohost.h" | 47 | # include "canohost.h" |
47 | #endif | 48 | #endif |
48 | 49 | ||
49 | extern ServerOptions options; | 50 | extern ServerOptions options; |
51 | int sys_auth_passwd(Authctxt *, const char *); | ||
52 | |||
53 | static void | ||
54 | disable_forwarding(void) | ||
55 | { | ||
56 | no_port_forwarding_flag = 1; | ||
57 | no_agent_forwarding_flag = 1; | ||
58 | no_x11_forwarding_flag = 1; | ||
59 | } | ||
50 | 60 | ||
51 | /* | 61 | /* |
52 | * Tries to authenticate the user using password. Returns true if | 62 | * Tries to authenticate the user using password. Returns true if |
@@ -66,17 +76,21 @@ auth_password(Authctxt *authctxt, const char *password) | |||
66 | return 0; | 76 | return 0; |
67 | 77 | ||
68 | #if defined(HAVE_OSF_SIA) | 78 | #if defined(HAVE_OSF_SIA) |
79 | /* | ||
80 | * XXX: any reason this is before krb? could be moved to | ||
81 | * sys_auth_passwd()? -dt | ||
82 | */ | ||
69 | return auth_sia_password(authctxt, password) && ok; | 83 | return auth_sia_password(authctxt, password) && ok; |
70 | #else | 84 | #endif |
71 | # ifdef KRB5 | 85 | #ifdef KRB5 |
72 | if (options.kerberos_authentication == 1) { | 86 | if (options.kerberos_authentication == 1) { |
73 | int ret = auth_krb5_password(authctxt, password); | 87 | int ret = auth_krb5_password(authctxt, password); |
74 | if (ret == 1 || ret == 0) | 88 | if (ret == 1 || ret == 0) |
75 | return ret && ok; | 89 | return ret && ok; |
76 | /* Fall back to ordinary passwd authentication. */ | 90 | /* Fall back to ordinary passwd authentication. */ |
77 | } | 91 | } |
78 | # endif | 92 | #endif |
79 | # ifdef HAVE_CYGWIN | 93 | #ifdef HAVE_CYGWIN |
80 | if (is_winnt) { | 94 | if (is_winnt) { |
81 | HANDLE hToken = cygwin_logon_user(pw, password); | 95 | HANDLE hToken = cygwin_logon_user(pw, password); |
82 | 96 | ||
@@ -85,41 +99,57 @@ auth_password(Authctxt *authctxt, const char *password) | |||
85 | cygwin_set_impersonation_token(hToken); | 99 | cygwin_set_impersonation_token(hToken); |
86 | return ok; | 100 | return ok; |
87 | } | 101 | } |
88 | # endif | 102 | #endif |
89 | # ifdef WITH_AIXAUTHENTICATE | 103 | return (sys_auth_passwd(authctxt, password) && ok); |
90 | if (aix_authenticate(pw->pw_name, password, | 104 | } |
91 | get_canonical_hostname(options.use_dns)) == 0) | 105 | |
92 | return 0; | 106 | #ifdef BSD_AUTH |
93 | else | 107 | int |
94 | return ok; | 108 | sys_auth_passwd(Authctxt *authctxt, const char *password) |
95 | # endif | 109 | { |
96 | # ifdef BSD_AUTH | 110 | struct passwd *pw = authctxt->pw; |
97 | if (auth_userokay(pw->pw_name, authctxt->style, "auth-ssh", | 111 | auth_session_t *as; |
98 | (char *)password) == 0) | 112 | |
99 | return 0; | 113 | as = auth_usercheck(pw->pw_name, authctxt->style, "auth-ssh", |
100 | else | 114 | (char *)password); |
101 | return ok; | 115 | if (auth_getstate(as) & AUTH_PWEXPIRED) { |
102 | # else | 116 | auth_close(as); |
103 | { | 117 | disable_forwarding(); |
118 | authctxt->force_pwchange = 1; | ||
119 | return (1); | ||
120 | } else { | ||
121 | return (auth_close(as)); | ||
122 | } | ||
123 | } | ||
124 | #elif defined(WITH_AIXAUTHENTICATE) | ||
125 | int | ||
126 | sys_auth_passwd(Authctxt *authctxt, const char *password) | ||
127 | { | ||
128 | return (aix_authenticate(authctxt->pw->pw_name, password, | ||
129 | get_canonical_hostname(options.use_dns))); | ||
130 | } | ||
131 | #else | ||
132 | int | ||
133 | sys_auth_passwd(Authctxt *authctxt, const char *password) | ||
134 | { | ||
135 | struct passwd *pw = authctxt->pw; | ||
136 | char *encrypted_password; | ||
137 | |||
104 | /* Just use the supplied fake password if authctxt is invalid */ | 138 | /* Just use the supplied fake password if authctxt is invalid */ |
105 | char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd; | 139 | char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd; |
106 | 140 | ||
107 | /* Check for users with no password. */ | 141 | /* Check for users with no password. */ |
108 | if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0) | 142 | if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0) |
109 | return ok; | 143 | return (1); |
110 | else { | ||
111 | /* Encrypt the candidate password using the proper salt. */ | ||
112 | char *encrypted_password = xcrypt(password, | ||
113 | (pw_password[0] && pw_password[1]) ? pw_password : "xx"); | ||
114 | 144 | ||
115 | /* | 145 | /* Encrypt the candidate password using the proper salt. */ |
116 | * Authentication is accepted if the encrypted passwords | 146 | encrypted_password = xcrypt(password, |
117 | * are identical. | 147 | (pw_password[0] && pw_password[1]) ? pw_password : "xx"); |
118 | */ | ||
119 | return (strcmp(encrypted_password, pw_password) == 0) && ok; | ||
120 | } | ||
121 | 148 | ||
122 | } | 149 | /* |
123 | # endif | 150 | * Authentication is accepted if the encrypted passwords |
124 | #endif /* !HAVE_OSF_SIA */ | 151 | * are identical. |
152 | */ | ||
153 | return (strcmp(encrypted_password, pw_password) == 0); | ||
125 | } | 154 | } |
155 | #endif | ||
@@ -52,6 +52,7 @@ struct Authctxt { | |||
52 | int valid; /* user exists and is allowed to login */ | 52 | int valid; /* user exists and is allowed to login */ |
53 | int attempt; | 53 | int attempt; |
54 | int failures; | 54 | int failures; |
55 | int force_pwchange; | ||
55 | char *user; /* username sent by the client */ | 56 | char *user; /* username sent by the client */ |
56 | char *service; | 57 | char *service; |
57 | struct passwd *pw; /* set if 'valid' */ | 58 | struct passwd *pw; /* set if 'valid' */ |
diff --git a/configure.ac b/configure.ac index 768b174b2..64645217d 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -1,4 +1,4 @@ | |||
1 | # $Id: configure.ac,v 1.192 2004/02/06 04:59:06 dtucker Exp $ | 1 | # $Id: configure.ac,v 1.193 2004/02/06 05:24:31 dtucker Exp $ |
2 | 2 | ||
3 | AC_INIT | 3 | AC_INIT |
4 | AC_CONFIG_SRCDIR([ssh.c]) | 4 | AC_CONFIG_SRCDIR([ssh.c]) |
@@ -42,6 +42,11 @@ else | |||
42 | fi | 42 | fi |
43 | fi | 43 | fi |
44 | 44 | ||
45 | AC_PATH_PROG(PATH_PASSWD_PROG, passwd) | ||
46 | if test ! -z "$PATH_PASSWD_PROG" ; then | ||
47 | AC_DEFINE_UNQUOTED(_PATH_PASSWD_PROG, "$PATH_PASSWD_PROG") | ||
48 | fi | ||
49 | |||
45 | if test -z "$LD" ; then | 50 | if test -z "$LD" ; then |
46 | LD=$CC | 51 | LD=$CC |
47 | fi | 52 | fi |
diff --git a/pathnames.h b/pathnames.h index 89e22c77a..edeff2de3 100644 --- a/pathnames.h +++ b/pathnames.h | |||
@@ -150,6 +150,11 @@ | |||
150 | #define _PATH_PRIVSEP_CHROOT_DIR "/var/empty" | 150 | #define _PATH_PRIVSEP_CHROOT_DIR "/var/empty" |
151 | #endif | 151 | #endif |
152 | 152 | ||
153 | /* for passwd change */ | ||
154 | #ifndef _PATH_PASSWD_PROG | ||
155 | #define _PATH_PASSWD_PROG "/usr/bin/passwd" | ||
156 | #endif | ||
157 | |||
153 | #ifndef _PATH_LS | 158 | #ifndef _PATH_LS |
154 | #define _PATH_LS "ls" | 159 | #define _PATH_LS "ls" |
155 | #endif | 160 | #endif |
@@ -33,7 +33,7 @@ | |||
33 | */ | 33 | */ |
34 | 34 | ||
35 | #include "includes.h" | 35 | #include "includes.h" |
36 | RCSID("$OpenBSD: session.c,v 1.171 2004/01/13 19:23:15 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" |
@@ -1304,6 +1304,22 @@ do_setusercontext(struct passwd *pw) | |||
1304 | } | 1304 | } |
1305 | 1305 | ||
1306 | static void | 1306 | static void |
1307 | do_pwchange(Session *s) | ||
1308 | { | ||
1309 | fprintf(stderr, "WARNING: Your password has expired.\n"); | ||
1310 | if (s->ttyfd != -1) { | ||
1311 | fprintf(stderr, | ||
1312 | "You must change your password now and login again!\n"); | ||
1313 | execl(_PATH_PASSWD_PROG, "passwd", (char *)NULL); | ||
1314 | perror("passwd"); | ||
1315 | } else { | ||
1316 | fprintf(stderr, | ||
1317 | "Password change required but no TTY available.\n"); | ||
1318 | } | ||
1319 | exit(1); | ||
1320 | } | ||
1321 | |||
1322 | static void | ||
1307 | launch_login(struct passwd *pw, const char *hostname) | 1323 | launch_login(struct passwd *pw, const char *hostname) |
1308 | { | 1324 | { |
1309 | /* Launch login(1). */ | 1325 | /* Launch login(1). */ |
@@ -1324,6 +1340,40 @@ launch_login(struct passwd *pw, const char *hostname) | |||
1324 | exit(1); | 1340 | exit(1); |
1325 | } | 1341 | } |
1326 | 1342 | ||
1343 | static void | ||
1344 | child_close_fds(void) | ||
1345 | { | ||
1346 | int i; | ||
1347 | |||
1348 | if (packet_get_connection_in() == packet_get_connection_out()) | ||
1349 | close(packet_get_connection_in()); | ||
1350 | else { | ||
1351 | close(packet_get_connection_in()); | ||
1352 | close(packet_get_connection_out()); | ||
1353 | } | ||
1354 | /* | ||
1355 | * Close all descriptors related to channels. They will still remain | ||
1356 | * open in the parent. | ||
1357 | */ | ||
1358 | /* XXX better use close-on-exec? -markus */ | ||
1359 | channel_close_all(); | ||
1360 | |||
1361 | /* | ||
1362 | * Close any extra file descriptors. Note that there may still be | ||
1363 | * descriptors left by system functions. They will be closed later. | ||
1364 | */ | ||
1365 | endpwent(); | ||
1366 | |||
1367 | /* | ||
1368 | * Close any extra open file descriptors so that we don\'t have them | ||
1369 | * hanging around in clients. Note that we want to do this after | ||
1370 | * initgroups, because at least on Solaris 2.3 it leaves file | ||
1371 | * descriptors open. | ||
1372 | */ | ||
1373 | for (i = 3; i < 64; i++) | ||
1374 | close(i); | ||
1375 | } | ||
1376 | |||
1327 | /* | 1377 | /* |
1328 | * Performs common processing for the child, such as setting up the | 1378 | * Performs common processing for the child, such as setting up the |
1329 | * environment, closing extra file descriptors, setting the user and group | 1379 | * environment, closing extra file descriptors, setting the user and group |
@@ -1337,11 +1387,18 @@ do_child(Session *s, const char *command) | |||
1337 | char *argv[10]; | 1387 | char *argv[10]; |
1338 | const char *shell, *shell0, *hostname = NULL; | 1388 | const char *shell, *shell0, *hostname = NULL; |
1339 | struct passwd *pw = s->pw; | 1389 | struct passwd *pw = s->pw; |
1340 | u_int i; | ||
1341 | 1390 | ||
1342 | /* remove hostkey from the child's memory */ | 1391 | /* remove hostkey from the child's memory */ |
1343 | destroy_sensitive_data(); | 1392 | destroy_sensitive_data(); |
1344 | 1393 | ||
1394 | /* Force a password change */ | ||
1395 | if (s->authctxt->force_pwchange) { | ||
1396 | do_setusercontext(pw); | ||
1397 | child_close_fds(); | ||
1398 | do_pwchange(s); | ||
1399 | exit(1); | ||
1400 | } | ||
1401 | |||
1345 | /* login(1) is only called if we execute the login shell */ | 1402 | /* login(1) is only called if we execute the login shell */ |
1346 | if (options.use_login && command != NULL) | 1403 | if (options.use_login && command != NULL) |
1347 | options.use_login = 0; | 1404 | options.use_login = 0; |
@@ -1392,33 +1449,7 @@ do_child(Session *s, const char *command) | |||
1392 | * closed before building the environment, as we call | 1449 | * closed before building the environment, as we call |
1393 | * get_remote_ipaddr there. | 1450 | * get_remote_ipaddr there. |
1394 | */ | 1451 | */ |
1395 | if (packet_get_connection_in() == packet_get_connection_out()) | 1452 | child_close_fds(); |
1396 | close(packet_get_connection_in()); | ||
1397 | else { | ||
1398 | close(packet_get_connection_in()); | ||
1399 | close(packet_get_connection_out()); | ||
1400 | } | ||
1401 | /* | ||
1402 | * Close all descriptors related to channels. They will still remain | ||
1403 | * open in the parent. | ||
1404 | */ | ||
1405 | /* XXX better use close-on-exec? -markus */ | ||
1406 | channel_close_all(); | ||
1407 | |||
1408 | /* | ||
1409 | * Close any extra file descriptors. Note that there may still be | ||
1410 | * descriptors left by system functions. They will be closed later. | ||
1411 | */ | ||
1412 | endpwent(); | ||
1413 | |||
1414 | /* | ||
1415 | * Close any extra open file descriptors so that we don\'t have them | ||
1416 | * hanging around in clients. Note that we want to do this after | ||
1417 | * initgroups, because at least on Solaris 2.3 it leaves file | ||
1418 | * descriptors open. | ||
1419 | */ | ||
1420 | for (i = 3; i < 64; i++) | ||
1421 | close(i); | ||
1422 | 1453 | ||
1423 | /* | 1454 | /* |
1424 | * Must take new environment into use so that .ssh/rc, | 1455 | * Must take new environment into use so that .ssh/rc, |