2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1992-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 /* this module is for checking a username/password against a system
23 password database. The SMB encrypted password support is elsewhere */
27 /* these are kept here to keep the string_combinations function simple */
28 static fstring this_user
;
29 static fstring this_salt
;
30 static fstring this_crypted
;
35 #include <afs/kautils.h>
37 /*******************************************************************
38 check on AFS authentication
39 ********************************************************************/
40 static BOOL
afs_auth(char *user
, char *password
)
42 long password_expires
= 0;
45 /* For versions of AFS prior to 3.3, this routine has few arguments, */
46 /* but since I can't find the old documentation... :-) */
48 if (ka_UserAuthenticateGeneral
49 (KA_USERAUTH_VERSION
+ KA_USERAUTH_DOSETPAG
, user
, (char *)0, /* instance */
51 password
, 0, /* lifetime, default */
52 &password_expires
, /*days 'til it expires */
59 ("AFS authentication for \"%s\" failed (%s)\n", user
, reason
));
67 #include <dce/dce_error.h>
68 #include <dce/sec_login.h>
70 /*****************************************************************
71 This new version of the DFS_AUTH code was donated by Karsten Muuss
72 <muuss@or.uni-bonn.de>. It fixes the following problems with the
75 - Server credentials may expire
76 - Client credential cache files have wrong owner
77 - purge_context() function is called with invalid argument
79 This new code was modified to ensure that on exit the uid/gid is
80 still root, and the original directory is restored. JRA.
81 ******************************************************************/
83 sec_login_handle_t my_dce_sec_context
;
84 int dcelogin_atmost_once
= 0;
86 /*******************************************************************
87 check on a DCE/DFS authentication
88 ********************************************************************/
89 static BOOL
dfs_auth(char *user
, char *password
)
94 signed32 expire_time
, current_time
;
95 boolean32 password_reset
;
97 sec_passwd_rec_t passwd_rec
;
98 sec_login_auth_src_t auth_src
= sec_login_auth_src_network
;
99 unsigned char dce_errstr
[dce_c_error_string_len
];
102 if (dcelogin_atmost_once
)
107 * We only go for a DCE login context if the given password
108 * matches that stored in the local password file..
109 * Assumes local passwd file is kept in sync w/ DCE RGY!
112 if (strcmp((char *)crypt(password
, this_salt
), this_crypted
))
118 sec_login_get_current_context(&my_dce_sec_context
, &err
);
119 if (err
!= error_status_ok
)
121 dce_error_inq_text(err
, dce_errstr
, &err2
);
122 DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr
));
127 sec_login_certify_identity(my_dce_sec_context
, &err
);
128 if (err
!= error_status_ok
)
130 dce_error_inq_text(err
, dce_errstr
, &err2
);
131 DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr
));
136 sec_login_get_expiration(my_dce_sec_context
, &expire_time
, &err
);
137 if (err
!= error_status_ok
)
139 dce_error_inq_text(err
, dce_errstr
, &err2
);
140 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr
));
147 if (expire_time
< (current_time
+ 60))
150 sec_passwd_rec_t
*key
;
152 sec_login_get_pwent(my_dce_sec_context
,
153 (sec_login_passwd_t
*) & pw
, &err
);
154 if (err
!= error_status_ok
)
156 dce_error_inq_text(err
, dce_errstr
, &err2
);
157 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr
));
162 sec_login_refresh_identity(my_dce_sec_context
, &err
);
163 if (err
!= error_status_ok
)
165 dce_error_inq_text(err
, dce_errstr
, &err2
);
166 DEBUG(0, ("DCE can't refresh identity. %s\n",
172 sec_key_mgmt_get_key(rpc_c_authn_dce_secret
, NULL
,
173 (unsigned char *)pw
->pw_name
,
174 sec_c_key_version_none
,
175 (void **)&key
, &err
);
176 if (err
!= error_status_ok
)
178 dce_error_inq_text(err
, dce_errstr
, &err2
);
179 DEBUG(0, ("DCE can't get key for %s. %s\n",
180 pw
->pw_name
, dce_errstr
));
185 sec_login_valid_and_cert_ident(my_dce_sec_context
, key
,
186 &password_reset
, &auth_src
,
188 if (err
!= error_status_ok
)
190 dce_error_inq_text(err
, dce_errstr
, &err2
);
192 ("DCE can't validate and certify identity for %s. %s\n",
193 pw
->pw_name
, dce_errstr
));
196 sec_key_mgmt_free_key(key
, &err
);
197 if (err
!= error_status_ok
)
199 dce_error_inq_text(err
, dce_errstr
, &err2
);
200 DEBUG(0, ("DCE can't free key.\n", dce_errstr
));
204 if (sec_login_setup_identity((unsigned char *)user
,
206 &my_dce_sec_context
, &err
) == 0)
208 dce_error_inq_text(err
, dce_errstr
, &err2
);
209 DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
214 sec_login_get_pwent(my_dce_sec_context
,
215 (sec_login_passwd_t
*) & pw
, &err
);
216 if (err
!= error_status_ok
)
218 dce_error_inq_text(err
, dce_errstr
, &err2
);
219 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr
));
224 sec_login_purge_context(&my_dce_sec_context
, &err
);
225 if (err
!= error_status_ok
)
227 dce_error_inq_text(err
, dce_errstr
, &err2
);
228 DEBUG(0, ("DCE can't purge context. %s\n", dce_errstr
));
234 * NB. I'd like to change these to call something like change_to_user()
235 * instead but currently we don't have a connection
236 * context to become the correct user. This is already
237 * fairly platform specific code however, so I think
238 * this should be ok. I have added code to go
239 * back to being root on error though. JRA.
244 set_effective_gid(pw
->pw_gid
);
245 set_effective_uid(pw
->pw_uid
);
247 if (sec_login_setup_identity((unsigned char *)user
,
249 &my_dce_sec_context
, &err
) == 0)
251 dce_error_inq_text(err
, dce_errstr
, &err2
);
252 DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
257 sec_login_get_pwent(my_dce_sec_context
,
258 (sec_login_passwd_t
*) & pw
, &err
);
259 if (err
!= error_status_ok
)
261 dce_error_inq_text(err
, dce_errstr
, &err2
);
262 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr
));
266 passwd_rec
.version_number
= sec_passwd_c_version_none
;
267 passwd_rec
.pepper
= NULL
;
268 passwd_rec
.key
.key_type
= sec_passwd_plain
;
269 passwd_rec
.key
.tagged_union
.plain
= (idl_char
*) password
;
271 sec_login_validate_identity(my_dce_sec_context
,
272 &passwd_rec
, &password_reset
,
274 if (err
!= error_status_ok
)
276 dce_error_inq_text(err
, dce_errstr
, &err2
);
278 ("DCE Identity Validation failed for principal %s: %s\n",
283 sec_login_certify_identity(my_dce_sec_context
, &err
);
284 if (err
!= error_status_ok
)
286 dce_error_inq_text(err
, dce_errstr
, &err2
);
287 DEBUG(0, ("DCE certify identity failed: %s\n", dce_errstr
));
291 if (auth_src
!= sec_login_auth_src_network
)
293 DEBUG(0, ("DCE context has no network credentials.\n"));
296 sec_login_set_context(my_dce_sec_context
, &err
);
297 if (err
!= error_status_ok
)
299 dce_error_inq_text(err
, dce_errstr
, &err2
);
301 ("DCE login failed for principal %s, cant set context: %s\n",
304 sec_login_purge_context(&my_dce_sec_context
, &err
);
308 sec_login_get_pwent(my_dce_sec_context
,
309 (sec_login_passwd_t
*) & pw
, &err
);
310 if (err
!= error_status_ok
)
312 dce_error_inq_text(err
, dce_errstr
, &err2
);
313 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr
));
317 DEBUG(0, ("DCE login succeeded for principal %s on pid %d\n",
318 user
, sys_getpid()));
320 DEBUG(3, ("DCE principal: %s\n"
323 pw
->pw_name
, pw
->pw_uid
, pw
->pw_gid
));
324 DEBUG(3, (" info: %s\n"
327 pw
->pw_gecos
, pw
->pw_dir
, pw
->pw_shell
));
329 sec_login_get_expiration(my_dce_sec_context
, &expire_time
, &err
);
330 if (err
!= error_status_ok
)
332 dce_error_inq_text(err
, dce_errstr
, &err2
);
333 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr
));
337 set_effective_uid(0);
338 set_effective_gid(0);
341 ("DCE context expires: %s", asctime(localtime(&expire_time
))));
343 dcelogin_atmost_once
= 1;
348 /* Go back to root, JRA. */
349 set_effective_uid(0);
350 set_effective_gid(egid
);
354 void dfs_unlogin(void)
358 unsigned char dce_errstr
[dce_c_error_string_len
];
360 sec_login_purge_context(&my_dce_sec_context
, &err
);
361 if (err
!= error_status_ok
)
363 dce_error_inq_text(err
, dce_errstr
, &err2
);
365 ("DCE purge login context failed for server instance %d: %s\n",
366 sys_getpid(), dce_errstr
));
375 /*******************************************************************
376 check on Kerberos authentication
377 ********************************************************************/
378 static BOOL
krb5_auth(char *user
, char *password
)
380 krb5_data tgtname
= {
385 krb5_context kcontext
;
386 krb5_principal kprinc
;
387 krb5_principal server
;
390 krb5_address
**addrs
= (krb5_address
**) 0;
391 krb5_preauthtype
*preauth
= NULL
;
392 krb5_keytab keytab
= NULL
;
394 krb5_ccache ccache
= NULL
;
398 if (retval
= krb5_init_context(&kcontext
))
403 if (retval
= krb5_timeofday(kcontext
, &now
))
408 if (retval
= krb5_cc_default(kcontext
, &ccache
))
413 if (retval
= krb5_parse_name(kcontext
, user
, &kprinc
))
420 kcreds
.client
= kprinc
;
422 if ((retval
= krb5_build_principal_ext(kcontext
, &server
,
423 krb5_princ_realm(kcontext
,
426 krb5_princ_realm(kcontext
,
428 tgtname
.length
, tgtname
.data
,
429 krb5_princ_realm(kcontext
,
432 krb5_princ_realm(kcontext
,
439 kcreds
.server
= server
;
441 retval
= krb5_get_in_tkt_with_password(kcontext
,
446 password
, 0, &kcreds
, 0);
455 #endif /* KRB5_AUTH */
460 /*******************************************************************
461 check on Kerberos authentication
462 ********************************************************************/
463 static BOOL
krb4_auth(char *user
, char *password
)
465 char realm
[REALM_SZ
];
466 char tkfile
[MAXPATHLEN
];
468 if (krb_get_lrealm(realm
, 1) != KSUCCESS
)
470 (void)safe_strcpy(realm
, KRB_REALM
, sizeof(realm
) - 1);
473 (void)slprintf(tkfile
, sizeof(tkfile
) - 1, "/tmp/samba_tkt_%d",
476 krb_set_tkt_string(tkfile
);
477 if (krb_verify_user(user
, "", realm
, password
, 0, "rmcd") == KSUCCESS
)
485 #endif /* KRB4_AUTH */
487 #ifdef LINUX_BIGCRYPT
488 /****************************************************************************
489 an enhanced crypt for Linux to handle password longer than 8 characters
490 ****************************************************************************/
491 static int linux_bigcrypt(char *password
, char *salt1
, char *crypted
)
493 #define LINUX_PASSWORD_SEG_CHARS 8
497 StrnCpy(salt
, salt1
, 2);
500 for (i
= strlen(password
); i
> 0; i
-= LINUX_PASSWORD_SEG_CHARS
) {
501 char *p
= crypt(password
, salt
) + 2;
502 if (strncmp(p
, crypted
, LINUX_PASSWORD_SEG_CHARS
) != 0)
504 password
+= LINUX_PASSWORD_SEG_CHARS
;
505 crypted
+= strlen(p
);
513 /****************************************************************************
514 an enhanced crypt for OSF1
515 ****************************************************************************/
516 static char *osf1_bigcrypt(char *password
, char *salt1
)
518 static char result
[AUTH_MAX_PASSWD_LENGTH
] = "";
523 int parts
= strlen(password
) / AUTH_CLEARTEXT_SEG_CHARS
;
524 if (strlen(password
) % AUTH_CLEARTEXT_SEG_CHARS
)
527 StrnCpy(salt
, salt1
, 2);
528 StrnCpy(result
, salt1
, 2);
531 for (i
= 0; i
< parts
; i
++) {
532 p1
= crypt(p2
, salt
);
533 strncat(result
, p1
+ 2,
534 AUTH_MAX_PASSWD_LENGTH
- strlen(p1
+ 2) - 1);
535 StrnCpy(salt
, &result
[2 + i
* AUTH_CIPHERTEXT_SEG_CHARS
], 2);
536 p2
+= AUTH_CLEARTEXT_SEG_CHARS
;
544 /****************************************************************************
545 apply a function to upper/lower case combinations
546 of a string and return true if one of them returns true.
547 try all combinations with N uppercase letters.
548 offset is the first char to try and change (start with 0)
549 it assumes the string starts lowercased
550 ****************************************************************************/
551 static BOOL
string_combinations2(char *s
, int offset
, BOOL (*fn
) (char *),
557 #ifdef PASSWORD_LENGTH
558 len
= MIN(len
, PASSWORD_LENGTH
);
561 if (N
<= 0 || offset
>= len
)
564 for (i
= offset
; i
< (len
- (N
- 1)); i
++) {
569 if (string_combinations2(s
, i
+ 1, fn
, N
- 1))
576 /****************************************************************************
577 apply a function to upper/lower case combinations
578 of a string and return true if one of them returns true.
579 try all combinations with up to N uppercase letters.
580 offset is the first char to try and change (start with 0)
581 it assumes the string starts lowercased
582 ****************************************************************************/
583 static BOOL
string_combinations(char *s
, BOOL (*fn
) (char *), int N
)
586 for (n
= 1; n
<= N
; n
++)
587 if (string_combinations2(s
, 0, fn
, n
))
593 /****************************************************************************
594 core of password checking routine
595 ****************************************************************************/
596 static BOOL
password_check(char *password
)
600 return (NT_STATUS_IS_OK(smb_pam_passcheck(this_user
, password
)));
601 #endif /* WITH_PAM */
604 if (afs_auth(this_user
, password
))
606 #endif /* WITH_AFS */
609 if (dfs_auth(this_user
, password
))
611 #endif /* WITH_DFS */
614 if (krb5_auth(this_user
, password
))
616 #endif /* KRB5_AUTH */
619 if (krb4_auth(this_user
, password
))
621 #endif /* KRB4_AUTH */
627 (osf1_bigcrypt(password
, this_salt
),
631 ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
632 ret
= (strcmp((char *)crypt(password
, this_salt
), this_crypted
) == 0);
636 #endif /* OSF1_ENH_SEC */
639 return (strcmp((char *)crypt16(password
, this_salt
), this_crypted
) == 0);
640 #endif /* ULTRIX_AUTH */
642 #ifdef LINUX_BIGCRYPT
643 return (linux_bigcrypt(password
, this_salt
, this_crypted
));
644 #endif /* LINUX_BIGCRYPT */
646 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
649 * Some systems have bigcrypt in the C library but might not
650 * actually use it for the password hashes (HPUX 10.20) is
651 * a noteable example. So we try bigcrypt first, followed
655 if (strcmp(bigcrypt(password
, this_salt
), this_crypted
) == 0)
658 return (strcmp((char *)crypt(password
, this_salt
), this_crypted
) == 0);
659 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
662 return (strcmp(bigcrypt(password
, this_salt
), this_crypted
) == 0);
663 #endif /* HAVE_BIGCRYPT */
666 DEBUG(1, ("Warning - no crypt available\n"));
668 #else /* HAVE_CRYPT */
669 return (strcmp((char *)crypt(password
, this_salt
), this_crypted
) == 0);
670 #endif /* HAVE_CRYPT */
671 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
676 /****************************************************************************
677 check if a username/password is OK
678 the function pointer fn() points to a function to call when a successful
679 match is found and is used to update the encrypted password file
680 return True on correct match, False otherwise
681 ****************************************************************************/
683 BOOL
pass_check(char *user
, char *password
, int pwlen
, struct passwd
*pwd
,
684 BOOL (*fn
) (char *, char *))
687 int level
= lp_passwordlevel();
688 struct passwd
*pass
= NULL
;
694 DEBUG(100, ("checking user=[%s] pass=[%s]\n", user
, password
));
700 if (((!*password
) || (!pwlen
)) && !lp_null_passwords())
704 pass
= (struct passwd
*)pwd
;
705 user
= pass
->pw_name
;
707 pass
= Get_Pwnam(user
, True
);
713 * If we're using PAM we want to short-circuit all the
714 * checks below and dive straight into the PAM code.
717 fstrcpy(this_user
, user
);
719 DEBUG(4, ("pass_check: Checking (PAM) password for user %s (l=%d)\n", user
, pwlen
));
721 #else /* Not using PAM */
723 DEBUG(4, ("pass_check: Checking password for user %s (l=%d)\n", user
, pwlen
));
726 DEBUG(3, ("Couldn't find user %s\n", user
));
734 /* many shadow systems require you to be root to get
735 the password, in most cases this should already be
736 the case when this function is called, except
737 perhaps for IPC password changing requests */
739 spass
= getspnam(pass
->pw_name
);
740 if (spass
&& spass
->sp_pwdp
)
741 pstrcpy(pass
->pw_passwd
, spass
->sp_pwdp
);
743 #elif defined(IA_UINFO)
745 /* Need to get password with SVR4.2's ia_ functions
746 instead of get{sp,pw}ent functions. Required by
747 UnixWare 2.x, tested on version
748 2.1. (tangent@cyberport.com) */
750 if (ia_openinfo(pass
->pw_name
, &uinfo
) != -1)
751 ia_get_logpwd(uinfo
, &(pass
->pw_passwd
));
755 #ifdef HAVE_GETPRPWNAM
757 struct pr_passwd
*pr_pw
= getprpwnam(pass
->pw_name
);
758 if (pr_pw
&& pr_pw
->ufld
.fd_encrypt
)
759 pstrcpy(pass
->pw_passwd
, pr_pw
->ufld
.fd_encrypt
);
765 struct pr_passwd
*mypasswd
;
766 DEBUG(5, ("Checking password for user %s in OSF1_ENH_SEC\n",
768 mypasswd
= getprpwnam(user
);
770 fstrcpy(pass
->pw_name
, mypasswd
->ufld
.fd_name
);
771 fstrcpy(pass
->pw_passwd
, mypasswd
->ufld
.fd_encrypt
);
774 ("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
782 AUTHORIZATION
*ap
= getauthuid(pass
->pw_uid
);
784 fstrcpy(pass
->pw_passwd
, ap
->a_password
);
790 /* extract relevant info */
791 fstrcpy(this_user
, pass
->pw_name
);
792 fstrcpy(this_salt
, pass
->pw_passwd
);
794 #if defined(HAVE_TRUNCATED_SALT)
795 /* crypt on some platforms (HPUX in particular)
796 won't work with more than 2 salt characters. */
800 fstrcpy(this_crypted
, pass
->pw_passwd
);
802 if (!*this_crypted
) {
803 if (!lp_null_passwords()) {
804 DEBUG(2, ("Disallowing %s with null password\n",
810 ("Allowing access to %s with null password\n",
816 #endif /* WITH_PAM */
818 /* try it as it came to us */
819 if (password_check(password
)) {
825 /* if the password was given to us with mixed case then we don't
826 need to proceed as we know it hasn't been case modified by the
828 if (strhasupper(password
) && strhaslower(password
)) {
832 /* make a copy of it */
833 StrnCpy(pass2
, password
, sizeof(pass2
) - 1);
835 /* try all lowercase if it's currently all uppercase */
836 if (strhasupper(password
)) {
838 if (password_check(password
)) {
848 fstrcpy(password
, pass2
);
852 /* last chance - all combinations of up to level chars upper! */
855 if (string_combinations(password
, password_check
, level
)) {
862 fstrcpy(password
, pass2
);