2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1992-1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 /* this module is for checking a username/password against a system
21 password database. The SMB encrypted password support is elsewhere */
26 #define DBGC_CLASS DBGC_AUTH
28 /* these are kept here to keep the string_combinations function simple */
29 static char *ths_user
;
31 static const char *get_this_user(void)
39 #if defined(WITH_PAM) || defined(OSF1_ENH_SEC)
40 static const char *set_this_user(const char *newuser
)
42 char *orig_user
= ths_user
;
43 ths_user
= SMB_STRDUP(newuser
);
49 #if !defined(WITH_PAM)
50 static char *ths_salt
;
51 /* This must be writable. */
52 static char *get_this_salt(void)
57 /* We may be setting a modified version of the same
58 * string, so don't free before use. */
60 static const char *set_this_salt(const char *newsalt
)
62 char *orig_salt
= ths_salt
;
63 ths_salt
= SMB_STRDUP(newsalt
);
68 static char *ths_crypted
;
69 static const char *get_this_crypted(void)
77 static const char *set_this_crypted(const char *newcrypted
)
79 char *orig_crypted
= ths_crypted
;
80 ths_crypted
= SMB_STRDUP(newcrypted
);
81 SAFE_FREE(orig_crypted
);
89 #include <afs/kautils.h>
91 /*******************************************************************
92 check on AFS authentication
93 ********************************************************************/
94 static bool afs_auth(char *user
, char *password
)
96 long password_expires
= 0;
99 /* For versions of AFS prior to 3.3, this routine has few arguments, */
100 /* but since I can't find the old documentation... :-) */
102 if (ka_UserAuthenticateGeneral
103 (KA_USERAUTH_VERSION
+ KA_USERAUTH_DOSETPAG
, user
, (char *)0, /* instance */
104 (char *)0, /* cell */
105 password
, 0, /* lifetime, default */
106 &password_expires
, /*days 'til it expires */
113 ("AFS authentication for \"%s\" failed (%s)\n", user
, reason
));
121 #include <dce/dce_error.h>
122 #include <dce/sec_login.h>
124 /*****************************************************************
125 This new version of the DFS_AUTH code was donated by Karsten Muuss
126 <muuss@or.uni-bonn.de>. It fixes the following problems with the
129 - Server credentials may expire
130 - Client credential cache files have wrong owner
131 - purge_context() function is called with invalid argument
133 This new code was modified to ensure that on exit the uid/gid is
134 still root, and the original directory is restored. JRA.
135 ******************************************************************/
137 sec_login_handle_t my_dce_sec_context
;
138 int dcelogin_atmost_once
= 0;
140 /*******************************************************************
141 check on a DCE/DFS authentication
142 ********************************************************************/
143 static bool dfs_auth(char *user
, char *password
)
149 signed32 expire_time
, current_time
;
150 boolean32 password_reset
;
152 sec_passwd_rec_t passwd_rec
;
153 sec_login_auth_src_t auth_src
= sec_login_auth_src_network
;
154 unsigned char dce_errstr
[dce_c_error_string_len
];
157 if (dcelogin_atmost_once
)
162 * We only go for a DCE login context if the given password
163 * matches that stored in the local password file..
164 * Assumes local passwd file is kept in sync w/ DCE RGY!
167 if (strcmp((char *)crypt(password
, get_this_salt()), get_this_crypted()))
173 sec_login_get_current_context(&my_dce_sec_context
, &err
);
174 if (err
!= error_status_ok
)
176 dce_error_inq_text(err
, dce_errstr
, &err2
);
177 DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr
));
182 sec_login_certify_identity(my_dce_sec_context
, &err
);
183 if (err
!= error_status_ok
)
185 dce_error_inq_text(err
, dce_errstr
, &err2
);
186 DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr
));
191 sec_login_get_expiration(my_dce_sec_context
, &expire_time
, &err
);
192 if (err
!= error_status_ok
)
194 dce_error_inq_text(err
, dce_errstr
, &err2
);
195 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr
));
202 if (expire_time
< (current_time
+ 60))
205 sec_passwd_rec_t
*key
;
207 sec_login_get_pwent(my_dce_sec_context
,
208 (sec_login_passwd_t
*) & pw
, &err
);
209 if (err
!= error_status_ok
)
211 dce_error_inq_text(err
, dce_errstr
, &err2
);
212 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr
));
217 sec_login_refresh_identity(my_dce_sec_context
, &err
);
218 if (err
!= error_status_ok
)
220 dce_error_inq_text(err
, dce_errstr
, &err2
);
221 DEBUG(0, ("DCE can't refresh identity. %s\n",
227 sec_key_mgmt_get_key(rpc_c_authn_dce_secret
, NULL
,
228 (unsigned char *)pw
->pw_name
,
229 sec_c_key_version_none
,
230 (void **)&key
, &err
);
231 if (err
!= error_status_ok
)
233 dce_error_inq_text(err
, dce_errstr
, &err2
);
234 DEBUG(0, ("DCE can't get key for %s. %s\n",
235 pw
->pw_name
, dce_errstr
));
240 sec_login_valid_and_cert_ident(my_dce_sec_context
, key
,
241 &password_reset
, &auth_src
,
243 if (err
!= error_status_ok
)
245 dce_error_inq_text(err
, dce_errstr
, &err2
);
247 ("DCE can't validate and certify identity for %s. %s\n",
248 pw
->pw_name
, dce_errstr
));
251 sec_key_mgmt_free_key(key
, &err
);
252 if (err
!= error_status_ok
)
254 dce_error_inq_text(err
, dce_errstr
, &err2
);
255 DEBUG(0, ("DCE can't free key.\n", dce_errstr
));
259 if (sec_login_setup_identity((unsigned char *)user
,
261 &my_dce_sec_context
, &err
) == 0)
263 dce_error_inq_text(err
, dce_errstr
, &err2
);
264 DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
269 sec_login_get_pwent(my_dce_sec_context
,
270 (sec_login_passwd_t
*) & pw
, &err
);
271 if (err
!= error_status_ok
)
273 dce_error_inq_text(err
, dce_errstr
, &err2
);
274 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr
));
279 sec_login_purge_context(&my_dce_sec_context
, &err
);
280 if (err
!= error_status_ok
)
282 dce_error_inq_text(err
, dce_errstr
, &err2
);
283 DEBUG(0, ("DCE can't purge context. %s\n", dce_errstr
));
289 * NB. I'd like to change these to call something like change_to_user()
290 * instead but currently we don't have a connection
291 * context to become the correct user. This is already
292 * fairly platform specific code however, so I think
293 * this should be ok. I have added code to go
294 * back to being root on error though. JRA.
299 set_effective_gid(pw
->pw_gid
);
300 set_effective_uid(pw
->pw_uid
);
302 if (sec_login_setup_identity((unsigned char *)user
,
304 &my_dce_sec_context
, &err
) == 0)
306 dce_error_inq_text(err
, dce_errstr
, &err2
);
307 DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
312 sec_login_get_pwent(my_dce_sec_context
,
313 (sec_login_passwd_t
*) & pw
, &err
);
314 if (err
!= error_status_ok
)
316 dce_error_inq_text(err
, dce_errstr
, &err2
);
317 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr
));
321 passwd_rec
.version_number
= sec_passwd_c_version_none
;
322 passwd_rec
.pepper
= NULL
;
323 passwd_rec
.key
.key_type
= sec_passwd_plain
;
324 passwd_rec
.key
.tagged_union
.plain
= (idl_char
*) password
;
326 sec_login_validate_identity(my_dce_sec_context
,
327 &passwd_rec
, &password_reset
,
329 if (err
!= error_status_ok
)
331 dce_error_inq_text(err
, dce_errstr
, &err2
);
333 ("DCE Identity Validation failed for principal %s: %s\n",
338 sec_login_certify_identity(my_dce_sec_context
, &err
);
339 if (err
!= error_status_ok
)
341 dce_error_inq_text(err
, dce_errstr
, &err2
);
342 DEBUG(0, ("DCE certify identity failed: %s\n", dce_errstr
));
346 if (auth_src
!= sec_login_auth_src_network
)
348 DEBUG(0, ("DCE context has no network credentials.\n"));
351 sec_login_set_context(my_dce_sec_context
, &err
);
352 if (err
!= error_status_ok
)
354 dce_error_inq_text(err
, dce_errstr
, &err2
);
356 ("DCE login failed for principal %s, cant set context: %s\n",
359 sec_login_purge_context(&my_dce_sec_context
, &err
);
363 sec_login_get_pwent(my_dce_sec_context
,
364 (sec_login_passwd_t
*) & pw
, &err
);
365 if (err
!= error_status_ok
)
367 dce_error_inq_text(err
, dce_errstr
, &err2
);
368 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr
));
372 DEBUG(0, ("DCE login succeeded for principal %s on pid %d\n",
373 user
, sys_getpid()));
375 DEBUG(3, ("DCE principal: %s\n"
378 pw
->pw_name
, pw
->pw_uid
, pw
->pw_gid
));
379 DEBUG(3, (" info: %s\n"
382 pw
->pw_gecos
, pw
->pw_dir
, pw
->pw_shell
));
384 sec_login_get_expiration(my_dce_sec_context
, &expire_time
, &err
);
385 if (err
!= error_status_ok
)
387 dce_error_inq_text(err
, dce_errstr
, &err2
);
388 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr
));
392 set_effective_uid(0);
393 set_effective_gid(0);
395 t
= localtime(&expire_time
);
397 const char *asct
= asctime(t
);
399 DEBUG(0,("DCE context expires: %s", asct
));
403 dcelogin_atmost_once
= 1;
408 /* Go back to root, JRA. */
409 set_effective_uid(0);
410 set_effective_gid(egid
);
414 void dfs_unlogin(void)
418 unsigned char dce_errstr
[dce_c_error_string_len
];
420 sec_login_purge_context(&my_dce_sec_context
, &err
);
421 if (err
!= error_status_ok
)
423 dce_error_inq_text(err
, dce_errstr
, &err2
);
425 ("DCE purge login context failed for server instance %d: %s\n",
426 sys_getpid(), dce_errstr
));
431 #ifdef LINUX_BIGCRYPT
432 /****************************************************************************
433 an enhanced crypt for Linux to handle password longer than 8 characters
434 ****************************************************************************/
435 static int linux_bigcrypt(char *password
, char *salt1
, char *crypted
)
437 #define LINUX_PASSWORD_SEG_CHARS 8
441 StrnCpy(salt
, salt1
, 2);
444 for (i
= strlen(password
); i
> 0; i
-= LINUX_PASSWORD_SEG_CHARS
) {
445 char *p
= crypt(password
, salt
) + 2;
446 if (strncmp(p
, crypted
, LINUX_PASSWORD_SEG_CHARS
) != 0)
448 password
+= LINUX_PASSWORD_SEG_CHARS
;
449 crypted
+= strlen(p
);
457 /****************************************************************************
458 an enhanced crypt for OSF1
459 ****************************************************************************/
460 static char *osf1_bigcrypt(char *password
, char *salt1
)
462 static char result
[AUTH_MAX_PASSWD_LENGTH
] = "";
467 int parts
= strlen(password
) / AUTH_CLEARTEXT_SEG_CHARS
;
468 if (strlen(password
) % AUTH_CLEARTEXT_SEG_CHARS
)
471 StrnCpy(salt
, salt1
, 2);
472 StrnCpy(result
, salt1
, 2);
475 for (i
= 0; i
< parts
; i
++) {
476 p1
= crypt(p2
, salt
);
477 strncat(result
, p1
+ 2,
478 AUTH_MAX_PASSWD_LENGTH
- strlen(p1
+ 2) - 1);
479 StrnCpy(salt
, &result
[2 + i
* AUTH_CIPHERTEXT_SEG_CHARS
], 2);
480 p2
+= AUTH_CLEARTEXT_SEG_CHARS
;
488 /****************************************************************************
489 apply a function to upper/lower case combinations
490 of a string and return true if one of them returns true.
491 try all combinations with N uppercase letters.
492 offset is the first char to try and change (start with 0)
493 it assumes the string starts lowercased
494 ****************************************************************************/
495 static NTSTATUS
string_combinations2(char *s
, int offset
, NTSTATUS (*fn
) (const char *),
502 #ifdef PASSWORD_LENGTH
503 len
= MIN(len
, PASSWORD_LENGTH
);
506 if (N
<= 0 || offset
>= len
)
509 for (i
= offset
; i
< (len
- (N
- 1)); i
++) {
511 if (!islower_ascii(c
))
513 s
[i
] = toupper_ascii(c
);
514 if (!NT_STATUS_EQUAL(nt_status
= string_combinations2(s
, i
+ 1, fn
, N
- 1),NT_STATUS_WRONG_PASSWORD
)) {
519 return (NT_STATUS_WRONG_PASSWORD
);
522 /****************************************************************************
523 apply a function to upper/lower case combinations
524 of a string and return true if one of them returns true.
525 try all combinations with up to N uppercase letters.
526 offset is the first char to try and change (start with 0)
527 it assumes the string starts lowercased
528 ****************************************************************************/
529 static NTSTATUS
string_combinations(char *s
, NTSTATUS (*fn
) (const char *), int N
)
533 for (n
= 1; n
<= N
; n
++)
534 if (!NT_STATUS_EQUAL(nt_status
= string_combinations2(s
, 0, fn
, n
), NT_STATUS_WRONG_PASSWORD
))
536 return NT_STATUS_WRONG_PASSWORD
;
540 /****************************************************************************
541 core of password checking routine
542 ****************************************************************************/
543 static NTSTATUS
password_check(const char *password
)
546 return smb_pam_passcheck(get_this_user(), password
);
552 if (afs_auth(get_this_user(), password
))
554 #endif /* WITH_AFS */
557 if (dfs_auth(get_this_user(), password
))
559 #endif /* WITH_DFS */
563 ret
= (strcmp(osf1_bigcrypt(password
, get_this_salt()),
564 get_this_crypted()) == 0);
567 ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
568 ret
= (strcmp((char *)crypt(password
, get_this_salt()), get_this_crypted()) == 0);
573 return NT_STATUS_WRONG_PASSWORD
;
576 #endif /* OSF1_ENH_SEC */
579 ret
= (strcmp((char *)crypt16(password
, get_this_salt()), get_this_crypted()) == 0);
583 return NT_STATUS_WRONG_PASSWORD
;
586 #endif /* ULTRIX_AUTH */
588 #ifdef LINUX_BIGCRYPT
589 ret
= (linux_bigcrypt(password
, get_this_salt(), get_this_crypted()));
593 return NT_STATUS_WRONG_PASSWORD
;
595 #endif /* LINUX_BIGCRYPT */
597 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
600 * Some systems have bigcrypt in the C library but might not
601 * actually use it for the password hashes (HPUX 10.20) is
602 * a noteable example. So we try bigcrypt first, followed
606 if (strcmp(bigcrypt(password
, get_this_salt()), get_this_crypted()) == 0)
609 ret
= (strcmp((char *)crypt(password
, get_this_salt()), get_this_crypted()) == 0);
613 return NT_STATUS_WRONG_PASSWORD
;
615 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
618 ret
= (strcmp(bigcrypt(password
, get_this_salt()), get_this_crypted()) == 0);
622 return NT_STATUS_WRONG_PASSWORD
;
624 #endif /* HAVE_BIGCRYPT */
627 DEBUG(1, ("Warning - no crypt available\n"));
628 return NT_STATUS_LOGON_FAILURE
;
629 #else /* HAVE_CRYPT */
630 ret
= (strcmp((char *)crypt(password
, get_this_salt()), get_this_crypted()) == 0);
634 return NT_STATUS_WRONG_PASSWORD
;
636 #endif /* HAVE_CRYPT */
637 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
638 #endif /* WITH_PAM */
643 /****************************************************************************
644 CHECK if a username/password is OK
645 the function pointer fn() points to a function to call when a successful
646 match is found and is used to update the encrypted password file
647 return NT_STATUS_OK on correct match, appropriate error otherwise
648 ****************************************************************************/
650 NTSTATUS
pass_check(const struct passwd
*pass
, const char *user
, const char *password
,
651 int pwlen
, bool (*fn
) (const char *, const char *), bool run_cracker
)
654 int level
= lp_passwordlevel();
658 #ifdef DEBUG_PASSWORD
659 DEBUG(100, ("checking user=[%s] pass=[%s]\n", user
, password
));
663 return NT_STATUS_LOGON_FAILURE
;
665 if (((!*password
) || (!pwlen
)) && !lp_null_passwords())
666 return NT_STATUS_LOGON_FAILURE
;
668 #if defined(WITH_PAM)
671 * If we're using PAM we want to short-circuit all the
672 * checks below and dive straight into the PAM code.
675 if (set_this_user(user
) == NULL
) {
676 return NT_STATUS_NO_MEMORY
;
679 DEBUG(4, ("pass_check: Checking (PAM) password for user %s (l=%d)\n", user
, pwlen
));
681 #else /* Not using PAM */
683 DEBUG(4, ("pass_check: Checking password for user %s (l=%d)\n", user
, pwlen
));
686 DEBUG(3, ("Couldn't find user %s\n", user
));
687 return NT_STATUS_NO_SUCH_USER
;
691 /* Copy into global for the convenience of looping code */
692 /* Also the place to keep the 'password' no matter what
693 crazy struct it started in... */
694 if (set_this_crypted(pass
->pw_passwd
) == NULL
) {
695 return NT_STATUS_NO_MEMORY
;
697 if (set_this_salt(pass
->pw_passwd
) == NULL
) {
698 return NT_STATUS_NO_MEMORY
;
705 /* many shadow systems require you to be root to get
706 the password, in most cases this should already be
707 the case when this function is called, except
708 perhaps for IPC password changing requests */
710 spass
= getspnam(pass
->pw_name
);
711 if (spass
&& spass
->sp_pwdp
) {
712 if (set_this_crypted(spass
->sp_pwdp
) == NULL
) {
713 return NT_STATUS_NO_MEMORY
;
715 if (set_this_salt(spass
->sp_pwdp
) == NULL
) {
716 return NT_STATUS_NO_MEMORY
;
720 #elif defined(IA_UINFO)
722 /* Need to get password with SVR4.2's ia_ functions
723 instead of get{sp,pw}ent functions. Required by
724 UnixWare 2.x, tested on version
725 2.1. (tangent@cyberport.com) */
727 if (ia_openinfo(pass
->pw_name
, &uinfo
) != -1)
728 ia_get_logpwd(uinfo
, &(pass
->pw_passwd
));
732 #ifdef HAVE_GETPRPWNAM
734 struct pr_passwd
*pr_pw
= getprpwnam(pass
->pw_name
);
735 if (pr_pw
&& pr_pw
->ufld
.fd_encrypt
) {
736 if (set_this_crypted(pr_pw
->ufld
.fd_encrypt
) == NULL
) {
737 return NT_STATUS_NO_MEMORY
;
743 #ifdef HAVE_GETPWANAM
745 struct passwd_adjunct
*pwret
;
746 pwret
= getpwanam(s
);
747 if (pwret
&& pwret
->pwa_passwd
) {
748 if (set_this_crypted(pwret
->pwa_passwd
) == NULL
) {
749 return NT_STATUS_NO_MEMORY
;
757 struct pr_passwd
*mypasswd
;
758 DEBUG(5, ("Checking password for user %s in OSF1_ENH_SEC\n",
760 mypasswd
= getprpwnam(user
);
762 if (set_this_user(mypasswd
->ufld
.fd_name
) == NULL
) {
763 return NT_STATUS_NO_MEMORY
;
765 if (set_this_crypted(mypasswd
->ufld
.fd_encrypt
) == NULL
) {
766 return NT_STATUS_NO_MEMORY
;
770 ("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
778 AUTHORIZATION
*ap
= getauthuid(pass
->pw_uid
);
780 if (set_this_crypted(ap
->a_password
) == NULL
) {
782 return NT_STATUS_NO_MEMORY
;
789 #if defined(HAVE_TRUNCATED_SALT)
790 /* crypt on some platforms (HPUX in particular)
791 won't work with more than 2 salt characters. */
793 char *trunc_salt
= get_this_salt();
794 if (!trunc_salt
|| strlen(trunc_salt
) < 2) {
795 return NT_STATUS_LOGON_FAILURE
;
798 if (set_this_salt(trunc_salt
) == NULL
) {
799 return NT_STATUS_NO_MEMORY
;
804 if (!get_this_crypted() || !*get_this_crypted()) {
805 if (!lp_null_passwords()) {
806 DEBUG(2, ("Disallowing %s with null password\n",
808 return NT_STATUS_LOGON_FAILURE
;
812 ("Allowing access to %s with null password\n",
818 #endif /* defined(WITH_PAM) */
820 /* try it as it came to us */
821 nt_status
= password_check(password
);
822 if NT_STATUS_IS_OK(nt_status
) {
827 } else if (!NT_STATUS_EQUAL(nt_status
, NT_STATUS_WRONG_PASSWORD
)) {
828 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
836 /* if the password was given to us with mixed case then we don't
837 * need to proceed as we know it hasn't been case modified by the
839 if (strhasupper(password
) && strhaslower(password
)) {
843 /* make a copy of it */
844 pass2
= talloc_strdup(talloc_tos(), password
);
846 return NT_STATUS_NO_MEMORY
;
849 /* try all lowercase if it's currently all uppercase */
850 if (strhasupper(pass2
)) {
852 if NT_STATUS_IS_OK(nt_status
= password_check(pass2
)) {
861 return NT_STATUS_WRONG_PASSWORD
;
864 /* last chance - all combinations of up to level chars upper! */
867 if (NT_STATUS_IS_OK(nt_status
= string_combinations(pass2
, password_check
, level
))) {
873 return NT_STATUS_WRONG_PASSWORD
;