1 | /* |
---|
2 | |
---|
3 | auth-passwd.c |
---|
4 | |
---|
5 | Author: Tatu Ylonen <ylo@cs.hut.fi> |
---|
6 | |
---|
7 | Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
---|
8 | All rights reserved |
---|
9 | |
---|
10 | Created: Sat Mar 18 05:11:38 1995 ylo |
---|
11 | |
---|
12 | Password authentication. This file contains the functions to check whether |
---|
13 | the password is valid for the user. |
---|
14 | |
---|
15 | */ |
---|
16 | |
---|
17 | /* |
---|
18 | * $Id: auth-passwd.c,v 1.14 1999-03-08 18:20:01 danw Exp $ |
---|
19 | * $Log: not supported by cvs2svn $ |
---|
20 | * Revision 1.13 1998/12/31 23:53:20 ghudson |
---|
21 | * Revert 1.11. We have a krb5 master KDC now, so we don't need to |
---|
22 | * prefer krb4 reuslts. |
---|
23 | * |
---|
24 | * Revision 1.12 1998/08/03 21:49:57 danw |
---|
25 | * don't free saved_pw_name and saved_pw_passwd until krb4 auth has |
---|
26 | * succeeded. |
---|
27 | * |
---|
28 | * Revision 1.11 1998/05/14 19:23:39 danw |
---|
29 | * Deal with potential krb5/krb4 password skew (by ignoring errors when |
---|
30 | * getting krb5 tickets) |
---|
31 | * |
---|
32 | * Revision 1.10 1998/05/13 20:18:46 danw |
---|
33 | * merge in changes from 1.2.23 |
---|
34 | * |
---|
35 | * Revision 1.9 1998/04/09 22:51:45 ghudson |
---|
36 | * Support local accounts as determined by libal. |
---|
37 | * |
---|
38 | * Revision 1.8 1998/03/08 17:52:01 danw |
---|
39 | * From nathanw: use same krb5 options (proxy+forward) as other programs. |
---|
40 | * Use krb_set_tkt_string before get_pw_in_tkt in case the krb4 lib has |
---|
41 | * already cached another ticket location (while trying to do ticket forwarding, |
---|
42 | * for example) |
---|
43 | * |
---|
44 | * Revision 1.7 1998/01/24 01:47:21 danw |
---|
45 | * merge in changes for 1.2.22 |
---|
46 | * |
---|
47 | * Revision 1.6 1998/01/09 22:57:55 danw |
---|
48 | * fix krb4 ticket lifetime bug |
---|
49 | * |
---|
50 | * Revision 1.5 1997/11/19 20:52:24 danw |
---|
51 | * small security fix (originally from Matt Power) |
---|
52 | * |
---|
53 | * Revision 1.4 1997/11/19 20:44:43 danw |
---|
54 | * do chown later |
---|
55 | * |
---|
56 | * Revision 1.3 1997/11/15 00:04:13 danw |
---|
57 | * Use atexit() functions to destroy tickets and call al_acct_revert. |
---|
58 | * Work around Solaris lossage with libucb and grantpt. |
---|
59 | * |
---|
60 | * Revision 1.2 1997/11/12 21:16:09 danw |
---|
61 | * Athena-login changes (including some krb4 stuff) |
---|
62 | * |
---|
63 | * Revision 1.1.1.1 1997/10/17 22:26:01 danw |
---|
64 | * Import of ssh 1.2.21 |
---|
65 | * |
---|
66 | * Revision 1.1.1.2 1998/01/24 01:25:19 danw |
---|
67 | * Import of ssh 1.2.22 |
---|
68 | * |
---|
69 | * Revision 1.1.1.3 1998/05/13 19:11:11 danw |
---|
70 | * Import of ssh 1.2.23 |
---|
71 | * |
---|
72 | * Revision 1.1.1.4 1999/03/08 17:43:03 danw |
---|
73 | * Import of ssh 1.2.26 |
---|
74 | * |
---|
75 | * Revision 1.19 1998/07/08 01:44:46 kivinen |
---|
76 | * Added one missing space. |
---|
77 | * |
---|
78 | * Revision 1.18 1998/07/08 00:36:44 kivinen |
---|
79 | * Changed to use PASSWD_PATH. Better HPUX TCB AUTH support. |
---|
80 | * |
---|
81 | * Revision 1.17 1998/06/11 00:03:38 kivinen |
---|
82 | * Added username to /bin/password commands. |
---|
83 | * |
---|
84 | * Revision 1.16 1998/05/23 20:19:40 kivinen |
---|
85 | * Removed #define uint32 rpc_unt32, because md5 uint32 is now |
---|
86 | * md5_uint32. Changed () -> (void). Changed osf1c2_getprpwent |
---|
87 | * function to return true/false. Added |
---|
88 | * forced_empty_passwd_change support. |
---|
89 | * |
---|
90 | * Revision 1.15 1998/05/11 21:27:47 kivinen |
---|
91 | * Set correct_passwd to contain 255...255 so even if some |
---|
92 | * function doesn't set it, it cannot contain empty password. |
---|
93 | * |
---|
94 | * Revision 1.14 1998/04/30 01:50:20 kivinen |
---|
95 | * Added code that will force /bin/passwd command if password is |
---|
96 | * expired. |
---|
97 | * |
---|
98 | * Revision 1.13 1998/03/27 16:53:09 kivinen |
---|
99 | * Added aix authenticate function support. |
---|
100 | * |
---|
101 | * Revision 1.12 1998/01/02 06:14:31 kivinen |
---|
102 | * Fixed kerberos ticket name handling. Added OSF C2 account |
---|
103 | * locking and expiration support. |
---|
104 | * |
---|
105 | * Revision 1.11 1997/04/17 03:57:05 kivinen |
---|
106 | * Kept FILE: prefix in kerberos ticket filename as DCE cache |
---|
107 | * code requires it (patch from Doug Engert <DEEngert@anl.gov>). |
---|
108 | * |
---|
109 | * Revision 1.10 1997/04/05 21:45:25 kivinen |
---|
110 | * Changed verify_krb_v5_tgt to take *error_code instead of |
---|
111 | * error_code. |
---|
112 | * |
---|
113 | * Revision 1.9 1997/03/27 03:09:20 kivinen |
---|
114 | * Added kerberos patches from Glenn Machin. |
---|
115 | * |
---|
116 | * Revision 1.8 1997/03/26 06:59:18 kivinen |
---|
117 | * Changed uid 0 to UID_ROOT. |
---|
118 | * |
---|
119 | * Revision 1.7 1997/03/19 15:57:21 kivinen |
---|
120 | * Added SECURE_RPC, SECURE_NFS and NIS_PLUS support from Andy |
---|
121 | * Polyakov <appro@fy.chalmers.se>. |
---|
122 | * |
---|
123 | * Revision 1.6 1996/10/30 04:22:43 kivinen |
---|
124 | * Added #ifdef HAVE_SHADOW_H around shadow.h including. |
---|
125 | * |
---|
126 | * Revision 1.5 1996/10/29 22:33:59 kivinen |
---|
127 | * log -> log_msg. |
---|
128 | * |
---|
129 | * Revision 1.4 1996/10/08 13:50:44 ttsalo |
---|
130 | * Allow long passwords for HP-UX TCB authentication |
---|
131 | * |
---|
132 | * Revision 1.3 1996/09/08 17:36:51 ttsalo |
---|
133 | * Patches for HPUX 10.x shadow passwords from |
---|
134 | * vincent@ucthpx.uct.ac.za (Russell Vincent) merged. |
---|
135 | * |
---|
136 | * Revision 1.2 1996/02/18 21:53:45 ylo |
---|
137 | * Test for HAVE_ULTRIX_SHADOW_PASSWORDS instead of ultrix |
---|
138 | * (mips-dec-mach3 has ultrix defined, but does not support the |
---|
139 | * shadow password stuff). |
---|
140 | * |
---|
141 | * Revision 1.1.1.1 1996/02/18 21:38:12 ylo |
---|
142 | * Imported ssh-1.2.13. |
---|
143 | * |
---|
144 | * Revision 1.8 1995/09/27 02:10:34 ylo |
---|
145 | * Added support for SCO unix shadow passwords. |
---|
146 | * |
---|
147 | * Revision 1.7 1995/09/10 22:44:41 ylo |
---|
148 | * Added OSF/1 C2 extended security stuff. |
---|
149 | * |
---|
150 | * Revision 1.6 1995/08/21 23:20:29 ylo |
---|
151 | * Fixed a typo. |
---|
152 | * |
---|
153 | * Revision 1.5 1995/08/19 13:15:56 ylo |
---|
154 | * Changed securid code to initialize itself only once. |
---|
155 | * |
---|
156 | * Revision 1.4 1995/08/18 22:42:51 ylo |
---|
157 | * Added General Dynamics SecurID support from Donald McKillican |
---|
158 | * <dmckilli@qc.bell.ca>. |
---|
159 | * |
---|
160 | * Revision 1.3 1995/07/13 01:12:34 ylo |
---|
161 | * Removed the "Last modified" header. |
---|
162 | * |
---|
163 | * Revision 1.2 1995/07/13 01:09:50 ylo |
---|
164 | * Added cvs log. |
---|
165 | * |
---|
166 | * $Endlog$ |
---|
167 | */ |
---|
168 | |
---|
169 | #include "includes.h" |
---|
170 | #ifdef HAVE_SCO_ETC_SHADOW |
---|
171 | # include <sys/security.h> |
---|
172 | # include <sys/audit.h> |
---|
173 | # include <prot.h> |
---|
174 | #else /* HAVE_SCO_ETC_SHADOW */ |
---|
175 | #ifdef HAVE_HPUX_TCB_AUTH |
---|
176 | # include <sys/types.h> |
---|
177 | # include <hpsecurity.h> |
---|
178 | # include <prot.h> |
---|
179 | #else /* HAVE_HPUX_TCB_AUTH */ |
---|
180 | #ifdef HAVE_ETC_SHADOW |
---|
181 | #ifdef HAVE_SHADOW_H |
---|
182 | #include <shadow.h> |
---|
183 | #endif |
---|
184 | #endif /* HAVE_ETC_SHADOW */ |
---|
185 | #endif /* HAVE_HPUX_TCB_AUTH */ |
---|
186 | #endif /* HAVE_SCO_ETC_SHADOW */ |
---|
187 | #ifdef HAVE_ETC_SECURITY_PASSWD_ADJUNCT |
---|
188 | #include <sys/label.h> |
---|
189 | #include <sys/audit.h> |
---|
190 | #include <pwdadj.h> |
---|
191 | #endif /* HAVE_ETC_SECURITY_PASSWD_ADJUNCT */ |
---|
192 | #ifdef HAVE_ULTRIX_SHADOW_PASSWORDS |
---|
193 | #include <auth.h> |
---|
194 | #include <sys/svcinfo.h> |
---|
195 | #endif /* HAVE_ULTRIX_SHADOW_PASSWORDS */ |
---|
196 | #include "packet.h" |
---|
197 | #include "ssh.h" |
---|
198 | #include "servconf.h" |
---|
199 | #include "xmalloc.h" |
---|
200 | |
---|
201 | extern int al_local_acct; |
---|
202 | |
---|
203 | #ifdef SECURE_RPC |
---|
204 | /* |
---|
205 | * refer to ftp://playground.sun.com/pub/rpc/tirpcsrc2.3.tar.Z for |
---|
206 | * detailed information about stuff you can't find in manual pages:-) |
---|
207 | */ |
---|
208 | #ifdef KEYBYTES |
---|
209 | #undef KEYBYTES /* conflicts with blowfish.h */ |
---|
210 | #endif |
---|
211 | |
---|
212 | #include <rpc/rpc.h> |
---|
213 | #include <rpc/key_prot.h> |
---|
214 | |
---|
215 | static uid_t uid_keylogged = 0; |
---|
216 | |
---|
217 | #ifdef SECURE_NFS |
---|
218 | #include <nfs/export.h> |
---|
219 | #include <nfs/nfs.h> |
---|
220 | #include <nfs/nfssys.h> |
---|
221 | |
---|
222 | void nfs_revauth(uid_t uid) |
---|
223 | { |
---|
224 | struct nfs_revauth_args _nfssysarg; |
---|
225 | |
---|
226 | _nfssysarg.authtype = AUTH_DES; |
---|
227 | _nfssysarg.uid = uid; |
---|
228 | _nfssys (NFS_REVAUTH,&_nfssysarg); |
---|
229 | } |
---|
230 | #endif /* SECURE_NFS */ |
---|
231 | |
---|
232 | /* do /usr/bin/keylogout's job */ |
---|
233 | /* caller sets effective uid! */ |
---|
234 | void keylogout(void) |
---|
235 | { |
---|
236 | char secret [HEXKEYBYTES]; |
---|
237 | |
---|
238 | if (!uid_keylogged || uid_keylogged != geteuid()) |
---|
239 | return; |
---|
240 | |
---|
241 | /* revoke secret key from keyserv(1m) */ |
---|
242 | memset(secret, '\0', sizeof(secret)); |
---|
243 | key_setsecret(secret); /* this one is keyserv.1 interface, |
---|
244 | but it does the job even for keyserv.2 |
---|
245 | and takes the only argument:-) */ |
---|
246 | #ifdef SECURE_NFS |
---|
247 | /* as well as from nfs client module */ |
---|
248 | nfs_revauth(uid_keylogged); |
---|
249 | #endif /* SECURE_NFS */ |
---|
250 | |
---|
251 | uid_keylogged = 0; |
---|
252 | } |
---|
253 | |
---|
254 | void keylogout_atexit (void) |
---|
255 | { |
---|
256 | if (!uid_keylogged || seteuid(uid_keylogged)) |
---|
257 | return; |
---|
258 | keylogout(); |
---|
259 | seteuid(UID_ROOT); |
---|
260 | } |
---|
261 | |
---|
262 | #ifdef KEY_VERS2 /* keyserv protocol version 2 */ |
---|
263 | int my_secretkey_is_set(char *netname) |
---|
264 | { |
---|
265 | return key_secretkey_is_set(); |
---|
266 | } |
---|
267 | #else /* KEY_VERS2 */ |
---|
268 | /* |
---|
269 | * for keyserv.1 we just try to encrypt a session key to talk to ourselves. |
---|
270 | * this should fail if keyserv doesn't have our secret key. well, we can't |
---|
271 | * say if it's the right one, but we can't do any better anyway:-) |
---|
272 | */ |
---|
273 | int my_secretkey_is_set(char *netname) |
---|
274 | { |
---|
275 | des_block block; |
---|
276 | memcpy (block.c, netname, sizeof(block.c)); /* well, whatever... */ |
---|
277 | return (key_encryptsession(netname, &block) == 0); |
---|
278 | } |
---|
279 | #endif /* KEY_VERS2 */ |
---|
280 | |
---|
281 | /* do /usr/bin/keylogin's job */ |
---|
282 | /* caller sets effective uid! */ |
---|
283 | int keylogin(const char *passwd) |
---|
284 | { |
---|
285 | int ret = 0; |
---|
286 | char netnam[MAXNETNAMELEN+1], phrase[9]; |
---|
287 | #ifdef KEY_VERS2 |
---|
288 | key_netstarg key_setnet_arg; |
---|
289 | #define secret key_setnet_arg.st_priv_key |
---|
290 | #define public key_setnet_arg.st_pub_key |
---|
291 | key_setnet_arg.st_netname = netnam; |
---|
292 | #else /* KEY_VERS2 */ |
---|
293 | char secret[HEXKEYBYTES], public[HEXKEYBYTES]; |
---|
294 | #endif /* KEY_VERS2 */ |
---|
295 | |
---|
296 | if (getnetname(netnam) && /* do i exists? */ |
---|
297 | !(ret = my_secretkey_is_set(netnam)) && /* is it already set? */ |
---|
298 | passwd) /* do i have the password? */ |
---|
299 | { |
---|
300 | strncpy(phrase, passwd, 8); |
---|
301 | phrase[8] = '\0'; |
---|
302 | memset(public, '\0', sizeof(public)); |
---|
303 | memset(secret, '\0', sizeof(secret)); |
---|
304 | if (getsecretkey(netnam, secret, phrase) && *secret) |
---|
305 | { |
---|
306 | #ifdef KEY_VERS2 |
---|
307 | /* |
---|
308 | * key_setnet is keyserv.2 interface and is not documented, |
---|
309 | * but used by keylogin(1). and it's real mess with return |
---|
310 | * values:-( so far, namely up to Solaris 2.5.1, it returns |
---|
311 | * 1 on success and -1 when fails. |
---|
312 | */ |
---|
313 | if (ret = (key_setnet(&key_setnet_arg) > 0)) |
---|
314 | #else /* KEY_VERS2 */ |
---|
315 | if (ret = !key_setsecret(secret)) |
---|
316 | #endif /* KEY_VERS2 */ |
---|
317 | { |
---|
318 | uid_keylogged = geteuid(); /* save it for keylogout */ |
---|
319 | atexit(keylogout_atexit); /* clean up after ourselves */ |
---|
320 | } |
---|
321 | memset(secret, '\0', sizeof (secret)); |
---|
322 | } |
---|
323 | memset(phrase, '\0', sizeof(phrase)); |
---|
324 | } |
---|
325 | return ret; /* secret key was set by whomever */ |
---|
326 | } |
---|
327 | #endif /* SECURE_RPC */ |
---|
328 | |
---|
329 | #ifdef HAVE_SECURID |
---|
330 | /* Support for Security Dynamics SecurID card. |
---|
331 | Contributed by Donald McKillican <dmckilli@qc.bell.ca>. */ |
---|
332 | #define SECURID_USERS "/etc/securid.users" |
---|
333 | #include "sdi_athd.h" |
---|
334 | #include "sdi_size.h" |
---|
335 | #include "sdi_type.h" |
---|
336 | #include "sdacmvls.h" |
---|
337 | #include "sdconf.h" |
---|
338 | union config_record configure; |
---|
339 | static int securid_initialized = 0; |
---|
340 | #endif /* HAVE_SECURID */ |
---|
341 | |
---|
342 | #ifdef KERBEROS |
---|
343 | #if defined(KRB5) |
---|
344 | #include <krb5.h> |
---|
345 | extern krb5_context ssh_context; |
---|
346 | extern krb5_auth_context auth_context; |
---|
347 | extern int havecred; |
---|
348 | void krb_cleanup(void); |
---|
349 | #else |
---|
350 | #include <krb.h> |
---|
351 | #endif /* KRB5 */ |
---|
352 | #endif /* KERBEROS */ |
---|
353 | |
---|
354 | #ifdef AFS |
---|
355 | #include <afs/param.h> |
---|
356 | #include <afs/kautils.h> |
---|
357 | #endif /* AFS */ |
---|
358 | |
---|
359 | #if defined(KERBEROS) || defined(AFS_KERBEROS) |
---|
360 | extern char *ticket; |
---|
361 | #endif /* KERBEROS || AFS_KERBEROS */ |
---|
362 | |
---|
363 | /* Tries to authenticate the user using password. Returns true if |
---|
364 | authentication succeeds. */ |
---|
365 | |
---|
366 | #if defined(KERBEROS) && defined(KRB5) |
---|
367 | /* |
---|
368 | * This routine with some modification is from the MIT V5B6 appl/bsd/login.c |
---|
369 | * |
---|
370 | * Verify the Kerberos ticket-granting ticket just retrieved for the |
---|
371 | * user. If the Kerberos server doesn't respond, assume the user is |
---|
372 | * trying to fake us out (since we DID just get a TGT from what is |
---|
373 | * supposedly our KDC). If the host/<host> service is unknown (i.e., |
---|
374 | * the local keytab doesn't have it), let her in. |
---|
375 | * |
---|
376 | * Returns 1 for confirmation, -1 for failure, 0 for uncertainty. |
---|
377 | */ |
---|
378 | static |
---|
379 | int verify_krb_v5_tgt (krb5_context c, krb5_ccache ccache, |
---|
380 | krb5_error_code *error_code) |
---|
381 | { |
---|
382 | char phost[BUFSIZ]; |
---|
383 | int retval, have_keys; |
---|
384 | krb5_principal princ; |
---|
385 | krb5_keyblock *kb = 0; |
---|
386 | krb5_error_code krbval; |
---|
387 | krb5_data packet; |
---|
388 | krb5_auth_context auth_context = NULL; |
---|
389 | krb5_ticket *ticket = NULL; |
---|
390 | |
---|
391 | /* Set packet.data so that we do not free bogus memory below */ |
---|
392 | packet.data = 0; |
---|
393 | |
---|
394 | /* get the server principal for the local host */ |
---|
395 | /* (use defaults of "host" and canonicalized local name) */ |
---|
396 | krbval = krb5_sname_to_principal(c, 0, 0, KRB5_NT_SRV_HST, &princ); |
---|
397 | if (krbval) |
---|
398 | { |
---|
399 | *error_code = krbval; |
---|
400 | return -1; |
---|
401 | } |
---|
402 | |
---|
403 | /* since krb5_sname_to_principal has done the work for us, just |
---|
404 | extract the name directly */ |
---|
405 | strncpy(phost, krb5_princ_component(c, princ, 1)->data, BUFSIZ); |
---|
406 | phost[BUFSIZ - 1] = '\0'; |
---|
407 | |
---|
408 | /* Do we have host/<host> keys? */ |
---|
409 | /* (use default keytab, kvno IGNORE_VNO to get the first match, |
---|
410 | and enctype is currently ignored anyhow.) */ |
---|
411 | krbval = krb5_kt_read_service_key (c, NULL, princ, 0, |
---|
412 | ENCTYPE_DES_CBC_CRC, &kb); |
---|
413 | if (kb) |
---|
414 | krb5_free_keyblock (c, kb); |
---|
415 | /* any failure means we don't have keys at all. */ |
---|
416 | have_keys = krbval ? 0 : 1; |
---|
417 | |
---|
418 | /* talk to the kdc and construct the ticket */ |
---|
419 | krbval = krb5_mk_req(c, &auth_context, 0, "host", phost, |
---|
420 | 0, ccache, &packet); |
---|
421 | /* wipe the auth context for mk_req */ |
---|
422 | if (auth_context) |
---|
423 | { |
---|
424 | krb5_auth_con_free(c, auth_context); |
---|
425 | auth_context = NULL; |
---|
426 | } |
---|
427 | if (krbval == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) |
---|
428 | { |
---|
429 | /* we have a service key, so something should be |
---|
430 | in the database, therefore this error packet could |
---|
431 | have come from an attacker. */ |
---|
432 | if (have_keys) |
---|
433 | { |
---|
434 | retval = -1; |
---|
435 | goto EGRESS; |
---|
436 | } |
---|
437 | /* but if it is unknown and we've got no key, we don't |
---|
438 | have any security anyhow, so it is ok. */ |
---|
439 | else |
---|
440 | { |
---|
441 | retval = 0; |
---|
442 | goto EGRESS; |
---|
443 | } |
---|
444 | } |
---|
445 | else |
---|
446 | if (krbval) |
---|
447 | { |
---|
448 | *error_code = krbval; |
---|
449 | retval = -1; |
---|
450 | goto EGRESS; |
---|
451 | } |
---|
452 | /* got ticket, try to use it */ |
---|
453 | krbval = krb5_rd_req(c, &auth_context, &packet, |
---|
454 | princ, NULL, NULL, &ticket); |
---|
455 | |
---|
456 | |
---|
457 | if (krbval) |
---|
458 | { |
---|
459 | if (!have_keys) |
---|
460 | /* The krb5 errors aren't specified well, but I think |
---|
461 | these values cover the cases we expect. */ |
---|
462 | switch (krbval) |
---|
463 | { |
---|
464 | /* no keytab */ |
---|
465 | case KRB5_KT_NOTFOUND: |
---|
466 | case ENOENT: |
---|
467 | /* keytab found, missing entry */ |
---|
468 | retval = 0; |
---|
469 | break; |
---|
470 | default: |
---|
471 | /* unexpected error: fail */ |
---|
472 | retval = -1; |
---|
473 | break; |
---|
474 | } |
---|
475 | else |
---|
476 | /* Any error here is bad. */ |
---|
477 | retval = -1; |
---|
478 | *error_code = krbval; |
---|
479 | goto EGRESS; |
---|
480 | } |
---|
481 | /* |
---|
482 | * The host/<host> ticket has been received _and_ verified. |
---|
483 | */ |
---|
484 | retval = 1; |
---|
485 | /* do cleanup and return */ |
---|
486 | EGRESS: |
---|
487 | if (auth_context) |
---|
488 | krb5_auth_con_free(c, auth_context); |
---|
489 | if (ticket) |
---|
490 | krb5_free_ticket(c, ticket); |
---|
491 | if (packet.data) |
---|
492 | { |
---|
493 | free(packet.data); |
---|
494 | packet.data = 0; |
---|
495 | } |
---|
496 | krb5_free_principal(c, princ); |
---|
497 | /* possibly ticket and packet need freeing here as well */ |
---|
498 | /* memset (&ticket, 0, sizeof (ticket)); */ |
---|
499 | return retval; |
---|
500 | } |
---|
501 | |
---|
502 | krb5_data tgtname = { |
---|
503 | 0, |
---|
504 | KRB5_TGS_NAME_SIZE, |
---|
505 | KRB5_TGS_NAME |
---|
506 | }; |
---|
507 | |
---|
508 | /* |
---|
509 | * Preauthentication types should be listed prior to 0. |
---|
510 | * The last one tried will be no preauthentication |
---|
511 | * Type 5 is compatible with DCE timestamp |
---|
512 | * Type 2 is MIT current timestamp implementation |
---|
513 | */ |
---|
514 | #ifdef KRB5_PADATA_ENC_UNIX_TIME |
---|
515 | krb5_preauthtype preauth_list[3] = { KRB5_PADATA_ENC_UNIX_TIME, |
---|
516 | KRB5_PADATA_ENC_TIMESTAMP, |
---|
517 | 0 }; |
---|
518 | #else |
---|
519 | krb5_preauthtype preauth_list[2] = { KRB5_PADATA_ENC_TIMESTAMP, |
---|
520 | 0 }; |
---|
521 | #endif |
---|
522 | krb5_preauthtype * preauth = preauth_list; |
---|
523 | #endif /* KERBEROS */ |
---|
524 | |
---|
525 | /* Tries to authenticate the user using password. Returns true if |
---|
526 | authentication succeeds. */ |
---|
527 | #ifdef KERBEROS |
---|
528 | int auth_password(const char *server_user, const char *password, |
---|
529 | krb5_principal client) |
---|
530 | #else /* KERBEROS */ |
---|
531 | int auth_password(const char *server_user, const char *password) |
---|
532 | #endif /* KERBEROS */ |
---|
533 | { |
---|
534 | #if defined(_AIX) && defined(HAVE_AUTHENTICATE) |
---|
535 | char *message; |
---|
536 | int reenter; |
---|
537 | |
---|
538 | reenter = 1; |
---|
539 | if (authenticate(server_user, password, &reenter, &message) == 0) |
---|
540 | { |
---|
541 | return 1; |
---|
542 | } |
---|
543 | else |
---|
544 | { |
---|
545 | return 0; |
---|
546 | } |
---|
547 | #else /* _AIX41 && HAVE_AUTHENTICATE */ |
---|
548 | |
---|
549 | #ifdef KERBEROS |
---|
550 | krb5_error_code problem; |
---|
551 | int krb5_options = KDC_OPT_PROXIABLE | KDC_OPT_FORWARDABLE; |
---|
552 | krb5_deltat rlife = 0; |
---|
553 | krb5_principal server = 0; |
---|
554 | krb5_creds my_creds; |
---|
555 | krb5_timestamp now; |
---|
556 | krb5_ccache ccache; |
---|
557 | char ccname[80], krbtkfile[80], krbtkenv[80]; |
---|
558 | int results, status; |
---|
559 | #endif /* KERBEROS */ |
---|
560 | extern ServerOptions options; |
---|
561 | extern char *crypt(const char *key, const char *salt); |
---|
562 | struct passwd *pw; |
---|
563 | char *encrypted_password; |
---|
564 | char correct_passwd[200]; |
---|
565 | char *saved_pw_name, *saved_pw_passwd; |
---|
566 | |
---|
567 | memset(correct_passwd, 255, sizeof(correct_passwd)); |
---|
568 | if (*password == '\0' && options.permit_empty_passwd == 0) |
---|
569 | { |
---|
570 | packet_send_debug("Server does not permit empty password login."); |
---|
571 | return 0; |
---|
572 | } |
---|
573 | |
---|
574 | /* Get the encrypted password for the user. */ |
---|
575 | pw = getpwnam(server_user); |
---|
576 | if (!pw) |
---|
577 | return 0; |
---|
578 | saved_pw_name = xstrdup(pw->pw_name); |
---|
579 | saved_pw_passwd = xstrdup(pw->pw_passwd); |
---|
580 | |
---|
581 | #if defined(KERBEROS) |
---|
582 | if (options.kerberos_authentication && !al_local_acct) |
---|
583 | { |
---|
584 | #if defined(KRB5) |
---|
585 | sprintf(ccname, "FILE:/tmp/krb5cc_l%d", getpid()); |
---|
586 | |
---|
587 | if (problem = krb5_cc_resolve(ssh_context, ccname, &ccache)) |
---|
588 | goto errout2; |
---|
589 | |
---|
590 | if (problem = krb5_cc_initialize(ssh_context, ccache, client)) |
---|
591 | goto errout; |
---|
592 | |
---|
593 | problem = |
---|
594 | krb5_build_principal_ext(ssh_context, &server, |
---|
595 | krb5_princ_realm(ssh_context, client)->length, |
---|
596 | krb5_princ_realm(ssh_context, client)->data, |
---|
597 | tgtname.length, tgtname.data, |
---|
598 | krb5_princ_realm(ssh_context, client)->length, |
---|
599 | krb5_princ_realm(ssh_context, client)->data, |
---|
600 | 0); |
---|
601 | if (problem) |
---|
602 | goto errout; |
---|
603 | |
---|
604 | memset(&my_creds, 0, sizeof(my_creds)); |
---|
605 | my_creds.client = client; |
---|
606 | my_creds.server = server; |
---|
607 | problem = krb5_timeofday(ssh_context, &now); |
---|
608 | if (problem) |
---|
609 | goto errout; |
---|
610 | my_creds.times.starttime = 0; /* start timer when |
---|
611 | request gets to KDC */ |
---|
612 | my_creds.times.endtime = now + 60*60*10; /* 10 hours */ |
---|
613 | |
---|
614 | problem = krb5_string_to_deltat("7d", &rlife); /* 7 days renew time */ |
---|
615 | if (problem || rlife == 0) |
---|
616 | goto errout; |
---|
617 | |
---|
618 | my_creds.times.renew_till = now + rlife; |
---|
619 | |
---|
620 | |
---|
621 | problem = krb5_get_in_tkt_with_password(ssh_context, krb5_options, 0, |
---|
622 | NULL, preauth, |
---|
623 | password, ccache, |
---|
624 | &my_creds, 0); |
---|
625 | |
---|
626 | /* If not successful try no preauthentication */ |
---|
627 | if (problem) |
---|
628 | problem = krb5_get_in_tkt_with_password(ssh_context, |
---|
629 | krb5_options, 0, |
---|
630 | NULL, 0, |
---|
631 | password, ccache, |
---|
632 | &my_creds, 0); |
---|
633 | krb5_free_principal(ssh_context, server); |
---|
634 | server = 0; |
---|
635 | if (problem) |
---|
636 | goto errout; |
---|
637 | else |
---|
638 | { |
---|
639 | /* Verify tgt just obtained */ |
---|
640 | results = verify_krb_v5_tgt(ssh_context, ccache, &problem); |
---|
641 | |
---|
642 | if (results >= 0) |
---|
643 | { |
---|
644 | /* If results is 0 then put out a log message that |
---|
645 | the TGT was not verified, pass this back to the |
---|
646 | user as well */ |
---|
647 | if (results == 0) |
---|
648 | { |
---|
649 | log_msg("TGT for user %s was not verified.", server_user); |
---|
650 | packet_send_debug("Kerberos TGT could not be verified."); |
---|
651 | } |
---|
652 | |
---|
653 | /* get_name pulls out just the name not the |
---|
654 | type */ |
---|
655 | strcpy(ccname + 5, krb5_cc_get_name(ssh_context, ccache)); |
---|
656 | |
---|
657 | /* If tgt was passed, destroy it */ |
---|
658 | if (ticket) |
---|
659 | { |
---|
660 | if (strcmp(ticket,"none")) |
---|
661 | { |
---|
662 | krb5_ccache fwd_ccache; |
---|
663 | |
---|
664 | if (!krb5_cc_resolve(ssh_context, ticket, &fwd_ccache)) |
---|
665 | krb5_cc_destroy(ssh_context, fwd_ccache); |
---|
666 | dest_tkt(); |
---|
667 | } |
---|
668 | else |
---|
669 | ticket = NULL; |
---|
670 | } |
---|
671 | |
---|
672 | ticket = xmalloc(strlen(ccname) + 1); |
---|
673 | (void) sprintf(ticket, "%s", ccname); |
---|
674 | |
---|
675 | /* Now get v4 tickets */ |
---|
676 | sprintf(krbtkfile, "/tmp/tkt_p%d", getpid()); |
---|
677 | krb_set_tkt_string(krbtkfile); |
---|
678 | |
---|
679 | status = |
---|
680 | krb_get_pw_in_tkt(pw->pw_name, "", |
---|
681 | krb5_princ_realm(ssh_context, client)->data, |
---|
682 | "krbtgt", |
---|
683 | krb5_princ_realm(ssh_context, client)->data, |
---|
684 | 12*10, /* 10 hours in 5-minute increments */ |
---|
685 | password); |
---|
686 | if (status) |
---|
687 | goto errout; |
---|
688 | |
---|
689 | /* Put the name of the ticket file in the environment |
---|
690 | for parts of the login that need it between here |
---|
691 | and the environment variable setting code in do_child(). */ |
---|
692 | sprintf(krbtkenv, "KRBTKFILE=%s", krbtkfile); |
---|
693 | putenv(xstrdup(krbtkenv)); |
---|
694 | |
---|
695 | /* We do not need this so free them up */ |
---|
696 | xfree(saved_pw_name); |
---|
697 | xfree(saved_pw_passwd); |
---|
698 | |
---|
699 | havecred = 1; |
---|
700 | atexit(krb_cleanup); |
---|
701 | return 1; |
---|
702 | } |
---|
703 | if (problem == KRB5_KT_NOTFOUND) |
---|
704 | { |
---|
705 | /* We have potential KDC spoofing here - log it */ |
---|
706 | log_msg("WARNING: Verification of TGT indicates potential KDC spoofing: user %s address %s", server_user, get_remote_ipaddr()); |
---|
707 | packet_send_debug("Verification of TGT indicates potential KDC spoofing."); |
---|
708 | } |
---|
709 | } |
---|
710 | errout: |
---|
711 | krb5_cc_destroy (ssh_context, ccache); |
---|
712 | dest_tkt(); |
---|
713 | errout2: |
---|
714 | if (problem) |
---|
715 | { |
---|
716 | log_msg("Password authentication of user %s using Kerberos failed: %s", |
---|
717 | server_user, error_message(problem)); |
---|
718 | if (server) |
---|
719 | krb5_free_principal(ssh_context, server); |
---|
720 | if (!options.kerberos_or_local_passwd ) |
---|
721 | { |
---|
722 | /* We do not need this so free them up */ |
---|
723 | xfree(saved_pw_name); |
---|
724 | xfree(saved_pw_passwd); |
---|
725 | return 0; |
---|
726 | } |
---|
727 | } |
---|
728 | #endif /* KRB5 */ |
---|
729 | } |
---|
730 | #endif /* KERBEROS */ |
---|
731 | |
---|
732 | #ifdef HAVE_SECURID |
---|
733 | /* Support for Security Dynamics SecurId card. |
---|
734 | Contributed by Donald McKillican <dmckilli@qc.bell.ca>. */ |
---|
735 | { |
---|
736 | /* |
---|
737 | * the way we decide if this user is a securid user or not is |
---|
738 | * to check to see if they are included in /etc/securid.users |
---|
739 | */ |
---|
740 | int found = 0; |
---|
741 | FILE *securid_users = fopen(SECURID_USERS, "r"); |
---|
742 | char *c; |
---|
743 | char su_user[257]; |
---|
744 | |
---|
745 | if (securid_users) |
---|
746 | { |
---|
747 | while (fgets(su_user, sizeof(su_user), securid_users)) |
---|
748 | { |
---|
749 | if (c = strchr(su_user, '\n')) |
---|
750 | *c = '\0'; |
---|
751 | if (strcmp(su_user, server_user) == 0) |
---|
752 | { |
---|
753 | found = 1; |
---|
754 | break; |
---|
755 | } |
---|
756 | } |
---|
757 | } |
---|
758 | fclose(securid_users); |
---|
759 | |
---|
760 | if (found) |
---|
761 | { |
---|
762 | /* The user has a SecurID card. */ |
---|
763 | struct SD_CLIENT sd_dat, *sd; |
---|
764 | log_msg("SecurID authentication for %.100s required.", server_user); |
---|
765 | |
---|
766 | /* |
---|
767 | * if no pass code has been supplied, fail immediately: passing |
---|
768 | * a null pass code to sd_check causes a core dump |
---|
769 | */ |
---|
770 | if (*password == '\0') |
---|
771 | { |
---|
772 | log_msg("No pass code given, authentication rejected."); |
---|
773 | return 0; |
---|
774 | } |
---|
775 | |
---|
776 | sd = &sd_dat; |
---|
777 | if (!securid_initialized) |
---|
778 | { |
---|
779 | memset(&sd_dat, 0, sizeof(sd_dat)); /* clear struct */ |
---|
780 | creadcfg(); /* accesses sdconf.rec */ |
---|
781 | if (sd_init(sd)) |
---|
782 | packet_disconnect("Cannot contact securid server."); |
---|
783 | securid_initialized = 1; |
---|
784 | } |
---|
785 | return sd_check(password, server_user, sd) == ACM_OK; |
---|
786 | } |
---|
787 | } |
---|
788 | /* If the user has no SecurID card specified, we fall to normal |
---|
789 | password code. */ |
---|
790 | #endif /* HAVE_SECURID */ |
---|
791 | |
---|
792 | /* Save the encrypted password. */ |
---|
793 | strncpy(correct_passwd, saved_pw_passwd, sizeof(correct_passwd)); |
---|
794 | |
---|
795 | #ifdef SECURE_RPC |
---|
796 | /* try to register secret key for secure RPC */ |
---|
797 | seteuid(pw->pw_uid); /* just let it fail if ran by user */ |
---|
798 | keylogin(password); |
---|
799 | seteuid(UID_ROOT); /* just let it fail if ran by user */ |
---|
800 | #endif /* SECURE_RPC */ |
---|
801 | |
---|
802 | #ifdef HAVE_OSF1_C2_SECURITY |
---|
803 | if (osf1c2_getprpwent(correct_passwd, saved_pw_name, |
---|
804 | sizeof(correct_passwd))) |
---|
805 | { |
---|
806 | if (options.forced_passwd_change) |
---|
807 | { |
---|
808 | extern char *forced_command; |
---|
809 | forced_command = xmalloc(sizeof(PASSWD_PATH) + |
---|
810 | strlen(server_user) + 1); |
---|
811 | sprintf(forced_command, "%s %s", PASSWD_PATH, server_user); |
---|
812 | packet_send_debug("Password expired, forcing it to be changed."); |
---|
813 | } |
---|
814 | else |
---|
815 | { |
---|
816 | packet_send_debug("\n\tYour password has expired."); |
---|
817 | } |
---|
818 | } |
---|
819 | #else /* HAVE_OSF1_C2_SECURITY */ |
---|
820 | /* If we have shadow passwords, lookup the real encrypted password from |
---|
821 | the shadow file, and replace the saved encrypted password with the |
---|
822 | real encrypted password. */ |
---|
823 | #if defined(HAVE_SCO_ETC_SHADOW) || defined(HAVE_HPUX_TCB_AUTH) |
---|
824 | { |
---|
825 | struct pr_passwd *pr = getprpwnam(saved_pw_name); |
---|
826 | pr = getprpwnam(saved_pw_name); |
---|
827 | if (pr) |
---|
828 | { |
---|
829 | strncpy(correct_passwd, pr->ufld.fd_encrypt, sizeof(correct_passwd)); |
---|
830 | endprpwent(); |
---|
831 | if ( (!pr->uflg.fg_nullpw || !pr->ufld.fd_nullpw) |
---|
832 | && !pr->uflg.fg_pw_admin_num |
---|
833 | && strcmp(correct_passwd,"")==0 ) |
---|
834 | { |
---|
835 | debug("User %.100s not permitted to login with null passwd", |
---|
836 | saved_pw_name); |
---|
837 | packet_send_debug("\n\tNot permitted null passwd."); |
---|
838 | return 0; |
---|
839 | } |
---|
840 | } |
---|
841 | else |
---|
842 | { |
---|
843 | endprpwent(); |
---|
844 | return 0; |
---|
845 | } |
---|
846 | } |
---|
847 | #else /* defined(HAVE_SCO_ETC_SHADOW) || defined(HAVE_HPUX_TCB_AUTH) */ |
---|
848 | #ifdef HAVE_ETC_SHADOW |
---|
849 | { |
---|
850 | struct spwd *sp = getspnam(saved_pw_name); |
---|
851 | #if defined(SECURE_RPC) && defined(NIS_PLUS) |
---|
852 | if (!geteuid() && pw->pw_uid && /* do we have guts? */ |
---|
853 | (!sp || !sp->sp_pwdp || !strcmp(sp->sp_pwdp,"*NP*"))) |
---|
854 | if (seteuid(pw->pw_uid) == UID_ROOT) |
---|
855 | { |
---|
856 | sp = getspnam(saved_pw_name); /* retry as user */ |
---|
857 | seteuid(UID_ROOT); |
---|
858 | } |
---|
859 | #endif /* SECURE_RPC && NIS_PLUS */ |
---|
860 | if (sp) |
---|
861 | strncpy(correct_passwd, sp->sp_pwdp, sizeof(correct_passwd)); |
---|
862 | endspent(); |
---|
863 | } |
---|
864 | #else /* HAVE_ETC_SHADOW */ |
---|
865 | #ifdef HAVE_ETC_SECURITY_PASSWD_ADJUNCT |
---|
866 | { |
---|
867 | struct passwd_adjunct *sp = getpwanam(saved_pw_name); |
---|
868 | if (sp) |
---|
869 | strncpy(correct_passwd, sp->pwa_passwd, sizeof(correct_passwd)); |
---|
870 | endpwaent(); |
---|
871 | } |
---|
872 | #else /* HAVE_ETC_SECURITY_PASSWD_ADJUNCT */ |
---|
873 | #ifdef HAVE_ETC_SECURITY_PASSWD |
---|
874 | { |
---|
875 | FILE *f; |
---|
876 | char line[1024], looking_for_user[200], *cp; |
---|
877 | int found_user = 0; |
---|
878 | f = fopen("/etc/security/passwd", "r"); |
---|
879 | if (f) |
---|
880 | { |
---|
881 | sprintf(looking_for_user, "%.190s:", server_user); |
---|
882 | while (fgets(line, sizeof(line), f)) |
---|
883 | { |
---|
884 | if (strchr(line, '\n')) |
---|
885 | *strchr(line, '\n') = 0; |
---|
886 | if (strcmp(line, looking_for_user) == 0) |
---|
887 | found_user = 1; |
---|
888 | else |
---|
889 | if (line[0] != '\t' && line[0] != ' ') |
---|
890 | found_user = 0; |
---|
891 | else |
---|
892 | if (found_user) |
---|
893 | { |
---|
894 | for (cp = line; *cp == ' ' || *cp == '\t'; cp++) |
---|
895 | ; |
---|
896 | if (strncmp(cp, "password = ", strlen("password = ")) == 0) |
---|
897 | { |
---|
898 | strncpy(correct_passwd, cp + strlen("password = "), |
---|
899 | sizeof(correct_passwd)); |
---|
900 | correct_passwd[sizeof(correct_passwd) - 1] = 0; |
---|
901 | break; |
---|
902 | } |
---|
903 | } |
---|
904 | } |
---|
905 | fclose(f); |
---|
906 | } |
---|
907 | } |
---|
908 | #endif /* HAVE_ETC_SECURITY_PASSWD */ |
---|
909 | #endif /* HAVE_ETC_SECURITY_PASSWD_ADJUNCT */ |
---|
910 | #endif /* HAVE_ETC_SHADOW */ |
---|
911 | #endif /* HAVE_SCO_ETC_SHADOW */ |
---|
912 | #endif /* HAVE_OSF1_C2_SECURITY */ |
---|
913 | |
---|
914 | /* Check for users with no password. */ |
---|
915 | if (strcmp(password, "") == 0 && strcmp(correct_passwd, "") == 0) |
---|
916 | { |
---|
917 | if (options.forced_empty_passwd_change) |
---|
918 | { |
---|
919 | extern char *forced_command; |
---|
920 | forced_command = xmalloc(sizeof(PASSWD_PATH) + |
---|
921 | strlen(server_user) + 1); |
---|
922 | sprintf(forced_command, "%s %s", PASSWD_PATH, server_user); |
---|
923 | packet_send_debug("Password if forced to be set at first login."); |
---|
924 | } |
---|
925 | else |
---|
926 | { |
---|
927 | packet_send_debug("Login permitted without a password because the account has no password."); |
---|
928 | } |
---|
929 | return 1; /* The user has no password and an empty password was tried. */ |
---|
930 | } |
---|
931 | |
---|
932 | xfree(saved_pw_name); |
---|
933 | xfree(saved_pw_passwd); |
---|
934 | |
---|
935 | #ifdef HAVE_ULTRIX_SHADOW_PASSWORDS |
---|
936 | { |
---|
937 | /* Note: we are assuming that pw from above is still valid. */ |
---|
938 | struct svcinfo *svp; |
---|
939 | svp = getsvc(); |
---|
940 | if (svp == NULL) |
---|
941 | { |
---|
942 | error("getsvc() failed in ultrix code in auth_passwd"); |
---|
943 | return 0; |
---|
944 | } |
---|
945 | if ((svp->svcauth.seclevel == SEC_UPGRADE && |
---|
946 | strcmp(pw->pw_passwd, "*") == 0) || |
---|
947 | svp->svcauth.seclevel == SEC_ENHANCED) |
---|
948 | return authenticate_user(pw, password, "/dev/ttypXX") >= 0; |
---|
949 | } |
---|
950 | #endif /* HAVE_ULTRIX_SHADOW_PASSWORDS */ |
---|
951 | |
---|
952 | /* Encrypt the candidate password using the proper salt. */ |
---|
953 | #ifdef HAVE_OSF1_C2_SECURITY |
---|
954 | encrypted_password = (char *)osf1c2crypt(password, |
---|
955 | (correct_passwd[0] && correct_passwd[1]) ? |
---|
956 | correct_passwd : "xx"); |
---|
957 | #else /* HAVE_OSF1_C2_SECURITY */ |
---|
958 | #if defined(HAVE_SCO_ETC_SHADOW) || defined(HAVE_HPUX_TCB_AUTH) |
---|
959 | encrypted_password = bigcrypt(password, |
---|
960 | (correct_passwd[0] && correct_passwd[1]) ? |
---|
961 | correct_passwd : "xx"); |
---|
962 | #else /* defined(HAVE_SCO_ETC_SHADOW) || defined(HAVE_HPUX_TCB_AUTH) */ |
---|
963 | encrypted_password = crypt(password, |
---|
964 | (correct_passwd[0] && correct_passwd[1]) ? |
---|
965 | correct_passwd : "xx"); |
---|
966 | #endif /* HAVE_SCO_ETC_SHADOW */ |
---|
967 | #endif /* HAVE_OSF1_C2_SECURITY */ |
---|
968 | |
---|
969 | /* Authentication is accepted if the encrypted passwords are identical. */ |
---|
970 | return strcmp(encrypted_password, correct_passwd) == 0; |
---|
971 | #endif /* _AIX && HAVE_AUTHENTICATE */ |
---|
972 | } |
---|