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 extern int DEBUGLEVEL;
29 /* these are kept here to keep the string_combinations function simple */
30 static char this_user[100] = "";
31 static char this_salt[100] = "";
32 static char this_crypted[100] = "";
36 /*******************************************************************
37 check on PAM authentication
38 ********************************************************************/
40 /* We first need some helper functions */
41 #include <security/pam_appl.h>
42 /* Static variables used to communicate between the conversation function
43 * and the server_login function
45 static char *PAM_username;
46 static char *PAM_password;
48 /* PAM conversation function
49 * Here we assume (for now, at least) that echo on means login name, and
50 * echo off means password.
52 static int PAM_conv(int num_msg,
53 const struct pam_message **msg,
54 struct pam_response **resp, void *appdata_ptr)
57 struct pam_response *reply = NULL;
59 #define COPY_STRING(s) (s) ? strdup(s) : NULL
61 reply = malloc(sizeof(struct pam_response) * num_msg);
65 for (replies = 0; replies < num_msg; replies++)
67 switch (msg[replies]->msg_style)
69 case PAM_PROMPT_ECHO_ON:
70 reply[replies].resp_retcode = PAM_SUCCESS;
72 COPY_STRING(PAM_username);
75 case PAM_PROMPT_ECHO_OFF:
76 reply[replies].resp_retcode = PAM_SUCCESS;
78 COPY_STRING(PAM_password);
85 reply[replies].resp_retcode = PAM_SUCCESS;
86 reply[replies].resp = NULL;
89 /* Must be an error of some sort... */
98 static struct pam_conv PAM_conversation = {
104 static BOOL pam_auth(char *user, char *password)
109 /* Now use PAM to do authentication. For now, we won't worry about
110 * session logging, only authentication. Bail out if there are any
111 * errors. Since this is a limited protocol, and an even more limited
112 * function within a server speaking this protocol, we can't be as
113 * verbose as would otherwise make sense.
114 * Query: should we be using PAM_SILENT to shut PAM up?
116 #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
117 pam_end(pamh, 0); return False; \
119 PAM_password = password;
121 pam_error = pam_start("samba", user, &PAM_conversation, &pamh);
123 /* Setting PAM_SILENT stops generation of error messages to syslog
124 * to enable debugging on Red Hat Linux set:
126 * auth required /lib/security/pam_pwdb.so nullok shadow audit
127 * _OR_ change PAM_SILENT to 0 to force detailed reporting (logging)
129 pam_error = pam_authenticate(pamh, PAM_SILENT);
131 /* It is not clear to me that account management is the right thing
132 * to do, but it is not clear that it isn't, either. This can be
133 * removed if no account management should be done. Alternately,
134 * put a pam_allow.so entry in /etc/pam.conf for account handling. */
135 pam_error = pam_acct_mgmt(pamh, PAM_SILENT);
139 * This will allow samba to aquire a kerberos token. And, when
140 * exporting an AFS cell, be able to /write/ to this cell.
142 pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT));
145 pam_end(pamh, PAM_SUCCESS);
146 /* If this point is reached, the user has been authenticated. */
154 #include <afs/stds.h>
155 #include <afs/kautils.h>
157 /*******************************************************************
158 check on AFS authentication
159 ********************************************************************/
160 static BOOL afs_auth(char *user, char *password)
162 long password_expires = 0;
165 /* For versions of AFS prior to 3.3, this routine has few arguments, */
166 /* but since I can't find the old documentation... :-) */
168 if (ka_UserAuthenticateGeneral
169 (KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG, user, (char *)0, /* instance */
170 (char *)0, /* cell */
171 password, 0, /* lifetime, default */
172 &password_expires, /*days 'til it expires */
179 ("AFS authentication for \"%s\" failed (%s)\n", user, reason));
187 #include <dce/dce_error.h>
188 #include <dce/sec_login.h>
190 /*****************************************************************
191 This new version of the DFS_AUTH code was donated by Karsten Muuss
192 <muuss@or.uni-bonn.de>. It fixes the following problems with the
195 - Server credentials may expire
196 - Client credential cache files have wrong owner
197 - purge_context() function is called with invalid argument
199 This new code was modified to ensure that on exit the uid/gid is
200 still root, and the original directory is restored. JRA.
201 ******************************************************************/
203 sec_login_handle_t my_dce_sec_context;
204 int dcelogin_atmost_once = 0;
206 /*******************************************************************
207 check on a DCE/DFS authentication
208 ********************************************************************/
209 static BOOL dfs_auth(char *user, char *password)
214 signed32 expire_time, current_time;
215 boolean32 password_reset;
217 sec_passwd_rec_t passwd_rec;
218 sec_login_auth_src_t auth_src = sec_login_auth_src_network;
219 unsigned char dce_errstr[dce_c_error_string_len];
222 if (dcelogin_atmost_once)
227 * We only go for a DCE login context if the given password
228 * matches that stored in the local password file..
229 * Assumes local passwd file is kept in sync w/ DCE RGY!
232 if (strcmp((char *)crypt(password, this_salt), this_crypted))
238 sec_login_get_current_context(&my_dce_sec_context, &err);
239 if (err != error_status_ok)
241 dce_error_inq_text(err, dce_errstr, &err2);
242 DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
247 sec_login_certify_identity(my_dce_sec_context, &err);
248 if (err != error_status_ok)
250 dce_error_inq_text(err, dce_errstr, &err2);
251 DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
256 sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
257 if (err != error_status_ok)
259 dce_error_inq_text(err, dce_errstr, &err2);
260 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
267 if (expire_time < (current_time + 60))
270 sec_passwd_rec_t *key;
272 sec_login_get_pwent(my_dce_sec_context,
273 (sec_login_passwd_t *) & pw, &err);
274 if (err != error_status_ok)
276 dce_error_inq_text(err, dce_errstr, &err2);
277 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
282 sec_login_refresh_identity(my_dce_sec_context, &err);
283 if (err != error_status_ok)
285 dce_error_inq_text(err, dce_errstr, &err2);
286 DEBUG(0, ("DCE can't refresh identity. %s\n",
292 sec_key_mgmt_get_key(rpc_c_authn_dce_secret, NULL,
293 (unsigned char *)pw->pw_name,
294 sec_c_key_version_none,
295 (void **)&key, &err);
296 if (err != error_status_ok)
298 dce_error_inq_text(err, dce_errstr, &err2);
299 DEBUG(0, ("DCE can't get key for %s. %s\n",
300 pw->pw_name, dce_errstr));
305 sec_login_valid_and_cert_ident(my_dce_sec_context, key,
306 &password_reset, &auth_src,
308 if (err != error_status_ok)
310 dce_error_inq_text(err, dce_errstr, &err2);
312 ("DCE can't validate and certify identity for %s. %s\n",
313 pw->pw_name, dce_errstr));
316 sec_key_mgmt_free_key(key, &err);
317 if (err != error_status_ok)
319 dce_error_inq_text(err, dce_errstr, &err2);
320 DEBUG(0, ("DCE can't free key.\n", dce_errstr));
324 if (sec_login_setup_identity((unsigned char *)user,
326 &my_dce_sec_context, &err) == 0)
328 dce_error_inq_text(err, dce_errstr, &err2);
329 DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
334 sec_login_get_pwent(my_dce_sec_context,
335 (sec_login_passwd_t *) & pw, &err);
336 if (err != error_status_ok)
338 dce_error_inq_text(err, dce_errstr, &err2);
339 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
344 sec_login_purge_context(&my_dce_sec_context, &err);
345 if (err != error_status_ok)
347 dce_error_inq_text(err, dce_errstr, &err2);
348 DEBUG(0, ("DCE can't purge context. %s\n", dce_errstr));
354 * NB. I'd like to change these to call something like become_user()
355 * instead but currently we don't have a connection
356 * context to become the correct user. This is already
357 * fairly platform specific code however, so I think
358 * this should be ok. I have added code to go
359 * back to being root on error though. JRA.
364 set_effective_gid(pw->pw_gid);
365 set_effective_uid(pw->pw_uid);
367 if (sec_login_setup_identity((unsigned char *)user,
369 &my_dce_sec_context, &err) == 0)
371 dce_error_inq_text(err, dce_errstr, &err2);
372 DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
377 sec_login_get_pwent(my_dce_sec_context,
378 (sec_login_passwd_t *) & pw, &err);
379 if (err != error_status_ok)
381 dce_error_inq_text(err, dce_errstr, &err2);
382 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
386 passwd_rec.version_number = sec_passwd_c_version_none;
387 passwd_rec.pepper = NULL;
388 passwd_rec.key.key_type = sec_passwd_plain;
389 passwd_rec.key.tagged_union.plain = (idl_char *) password;
391 sec_login_validate_identity(my_dce_sec_context,
392 &passwd_rec, &password_reset,
394 if (err != error_status_ok)
396 dce_error_inq_text(err, dce_errstr, &err2);
398 ("DCE Identity Validation failed for principal %s: %s\n",
403 sec_login_certify_identity(my_dce_sec_context, &err);
404 if (err != error_status_ok)
406 dce_error_inq_text(err, dce_errstr, &err2);
407 DEBUG(0, ("DCE certify identity failed: %s\n", dce_errstr));
411 if (auth_src != sec_login_auth_src_network)
413 DEBUG(0, ("DCE context has no network credentials.\n"));
416 sec_login_set_context(my_dce_sec_context, &err);
417 if (err != error_status_ok)
419 dce_error_inq_text(err, dce_errstr, &err2);
421 ("DCE login failed for principal %s, cant set context: %s\n",
424 sec_login_purge_context(&my_dce_sec_context, &err);
428 sec_login_get_pwent(my_dce_sec_context,
429 (sec_login_passwd_t *) & pw, &err);
430 if (err != error_status_ok)
432 dce_error_inq_text(err, dce_errstr, &err2);
433 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
437 DEBUG(0, ("DCE login succeeded for principal %s on pid %d\n",
438 user, sys_getpid()));
440 DEBUG(3, ("DCE principal: %s\n"
443 pw->pw_name, pw->pw_uid, pw->pw_gid));
444 DEBUG(3, (" info: %s\n"
447 pw->pw_gecos, pw->pw_dir, pw->pw_shell));
449 sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
450 if (err != error_status_ok)
452 dce_error_inq_text(err, dce_errstr, &err2);
453 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
457 set_effective_uid(0);
458 set_effective_gid(0);
461 ("DCE context expires: %s", asctime(localtime(&expire_time))));
463 dcelogin_atmost_once = 1;
468 /* Go back to root, JRA. */
469 set_effective_uid(0);
470 set_effective_gid(egid);
474 void dfs_unlogin(void)
478 unsigned char dce_errstr[dce_c_error_string_len];
480 sec_login_purge_context(&my_dce_sec_context, &err);
481 if (err != error_status_ok)
483 dce_error_inq_text(err, dce_errstr, &err2);
485 ("DCE purge login context failed for server instance %d: %s\n",
486 sys_getpid(), dce_errstr));
495 /*******************************************************************
496 check on Kerberos authentication
497 ********************************************************************/
498 static BOOL krb5_auth(char *user, char *password)
500 krb5_data tgtname = {
505 krb5_context kcontext;
506 krb5_principal kprinc;
507 krb5_principal server;
510 krb5_address **addrs = (krb5_address **) 0;
511 krb5_preauthtype *preauth = NULL;
512 krb5_keytab keytab = NULL;
514 krb5_ccache ccache = NULL;
518 if (retval = krb5_init_context(&kcontext))
523 if (retval = krb5_timeofday(kcontext, &now))
528 if (retval = krb5_cc_default(kcontext, &ccache))
533 if (retval = krb5_parse_name(kcontext, user, &kprinc))
540 kcreds.client = kprinc;
542 if ((retval = krb5_build_principal_ext(kcontext, &server,
543 krb5_princ_realm(kcontext,
546 krb5_princ_realm(kcontext,
548 tgtname.length, tgtname.data,
549 krb5_princ_realm(kcontext,
552 krb5_princ_realm(kcontext,
559 kcreds.server = server;
561 retval = krb5_get_in_tkt_with_password(kcontext,
566 password, 0, &kcreds, 0);
575 #endif /* KRB5_AUTH */
580 /*******************************************************************
581 check on Kerberos authentication
582 ********************************************************************/
583 static BOOL krb4_auth(char *user, char *password)
585 char realm[REALM_SZ];
586 char tkfile[MAXPATHLEN];
588 if (krb_get_lrealm(realm, 1) != KSUCCESS)
590 (void)safe_strcpy(realm, KRB_REALM, sizeof(realm) - 1);
593 (void)slprintf(tkfile, sizeof(tkfile) - 1, "/tmp/samba_tkt_%d",
596 krb_set_tkt_string(tkfile);
597 if (krb_verify_user(user, "", realm, password, 0, "rmcd") == KSUCCESS)
605 #endif /* KRB4_AUTH */
607 #ifdef LINUX_BIGCRYPT
608 /****************************************************************************
609 an enhanced crypt for Linux to handle password longer than 8 characters
610 ****************************************************************************/
611 static int linux_bigcrypt(char *password, char *salt1, char *crypted)
613 #define LINUX_PASSWORD_SEG_CHARS 8
617 StrnCpy(salt, salt1, 2);
620 for (i = strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS)
622 char *p = crypt(password, salt) + 2;
623 if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
625 password += LINUX_PASSWORD_SEG_CHARS;
626 crypted += strlen(p);
634 /****************************************************************************
635 an enhanced crypt for OSF1
636 ****************************************************************************/
637 static char *osf1_bigcrypt(char *password, char *salt1)
639 static char result[AUTH_MAX_PASSWD_LENGTH] = "";
644 int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
645 if (strlen(password) % AUTH_CLEARTEXT_SEG_CHARS)
650 StrnCpy(salt, salt1, 2);
651 StrnCpy(result, salt1, 2);
654 for (i = 0; i < parts; i++)
656 p1 = crypt(p2, salt);
657 strncat(result, p1 + 2,
658 AUTH_MAX_PASSWD_LENGTH - strlen(p1 + 2) - 1);
659 StrnCpy(salt, &result[2 + i * AUTH_CIPHERTEXT_SEG_CHARS], 2);
660 p2 += AUTH_CLEARTEXT_SEG_CHARS;
668 /****************************************************************************
669 apply a function to upper/lower case combinations
670 of a string and return true if one of them returns true.
671 try all combinations with N uppercase letters.
672 offset is the first char to try and change (start with 0)
673 it assumes the string starts lowercased
674 ****************************************************************************/
675 static BOOL string_combinations2(char *s, int offset, BOOL (*fn) (char *),
681 #ifdef PASSWORD_LENGTH
682 len = MIN(len, PASSWORD_LENGTH);
685 if (N <= 0 || offset >= len)
690 for (i = offset; i < (len - (N - 1)); i++)
696 if (string_combinations2(s, i + 1, fn, N - 1))
703 /****************************************************************************
704 apply a function to upper/lower case combinations
705 of a string and return true if one of them returns true.
706 try all combinations with up to N uppercase letters.
707 offset is the first char to try and change (start with 0)
708 it assumes the string starts lowercased
709 ****************************************************************************/
710 static BOOL string_combinations(char *s, BOOL (*fn) (char *), int N)
713 for (n = 1; n <= N; n++)
714 if (string_combinations2(s, 0, fn, n))
720 /****************************************************************************
721 core of password checking routine
722 ****************************************************************************/
723 static BOOL password_check(char *password)
727 /* This falls through if the password check fails
728 - if HAVE_CRYPT is not defined this causes an error msg
729 saying Warning - no crypt available
730 - if HAVE_CRYPT is defined this is a potential security hole
731 as it may authenticate via the crypt call when PAM
732 settings say it should fail.
733 if (pam_auth(user,password)) return(True);
734 Hence we make a direct return to avoid a second chance!!!
736 return (pam_auth(this_user, password));
737 #endif /* WITH_PAM */
740 if (afs_auth(this_user, password))
742 #endif /* WITH_AFS */
745 if (dfs_auth(this_user, password))
747 #endif /* WITH_DFS */
750 if (krb5_auth(this_user, password))
752 #endif /* KRB5_AUTH */
755 if (krb4_auth(this_user, password))
757 #endif /* KRB4_AUTH */
763 (osf1_bigcrypt(password, this_salt),
768 ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
771 ((char *)crypt(password, this_salt),
776 #endif /* OSF1_ENH_SEC */
779 return (strcmp((char *)crypt16(password, this_salt), this_crypted) ==
781 #endif /* ULTRIX_AUTH */
783 #ifdef LINUX_BIGCRYPT
784 return (linux_bigcrypt(password, this_salt, this_crypted));
785 #endif /* LINUX_BIGCRYPT */
787 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
790 * Some systems have bigcrypt in the C library but might not
791 * actually use it for the password hashes (HPUX 10.20) is
792 * a noteable example. So we try bigcrypt first, followed
796 if (strcmp(bigcrypt(password, this_salt), this_crypted) == 0)
800 ((char *)crypt(password, this_salt),
802 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
805 return (strcmp(bigcrypt(password, this_salt), this_crypted) == 0);
806 #endif /* HAVE_BIGCRYPT */
809 DEBUG(1, ("Warning - no crypt available\n"));
811 #else /* HAVE_CRYPT */
812 return (strcmp((char *)crypt(password, this_salt), this_crypted) ==
814 #endif /* HAVE_CRYPT */
815 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
820 /****************************************************************************
821 check if a username/password is OK
822 the function pointer fn() points to a function to call when a successful
823 match is found and is used to update the encrypted password file
824 return True on correct match, False otherwise
825 ****************************************************************************/
826 BOOL pass_check(char *user, char *password, int pwlen, struct passwd *pwd,
827 BOOL (*fn) (char *, char *))
830 int level = lp_passwordlevel();
837 DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
845 if (((!*password) || (!pwlen)) && !lp_null_passwords())
852 pass = (struct passwd *)pwd;
853 user = pass->pw_name;
857 pass = Get_Pwnam(user, True);
861 DEBUG(4, ("Checking password for user %s (l=%d)\n", user, pwlen));
865 DEBUG(3, ("Couldn't find user %s\n", user));
873 /* many shadow systems require you to be root to get
874 the password, in most cases this should already be
875 the case when this function is called, except
876 perhaps for IPC password changing requests */
878 spass = getspnam(pass->pw_name);
879 if (spass && spass->sp_pwdp)
881 pstrcpy(pass->pw_passwd, spass->sp_pwdp);
884 #elif defined(IA_UINFO)
886 /* Need to get password with SVR4.2's ia_ functions
887 instead of get{sp,pw}ent functions. Required by
888 UnixWare 2.x, tested on version
889 2.1. (tangent@cyberport.com) */
891 if (ia_openinfo(pass->pw_name, &uinfo) != -1)
893 ia_get_logpwd(uinfo, &(pass->pw_passwd));
898 #ifdef HAVE_GETPRPWNAM
900 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
901 if (pr_pw && pr_pw->ufld.fd_encrypt)
902 pstrcpy(pass->pw_passwd, pr_pw->ufld.fd_encrypt);
908 struct pr_passwd *mypasswd;
909 DEBUG(5, ("Checking password for user %s in OSF1_ENH_SEC\n",
911 mypasswd = getprpwnam(user);
914 fstrcpy(pass->pw_name, mypasswd->ufld.fd_name);
915 fstrcpy(pass->pw_passwd, mypasswd->ufld.fd_encrypt);
920 ("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
928 AUTHORIZATION *ap = getauthuid(pass->pw_uid);
931 fstrcpy(pass->pw_passwd, ap->a_password);
937 /* extract relevant info */
938 fstrcpy(this_user, pass->pw_name);
939 fstrcpy(this_salt, pass->pw_passwd);
941 #if defined(HAVE_TRUNCATED_SALT)
942 /* crypt on some platforms (HPUX in particular)
943 won't work with more than 2 salt characters. */
947 fstrcpy(this_crypted, pass->pw_passwd);
951 if (!lp_null_passwords())
953 DEBUG(2, ("Disallowing %s with null password\n",
960 ("Allowing access to %s with null password\n",
966 /* try it as it came to us */
967 if (password_check(password))
974 /* if the password was given to us with mixed case then we don't
975 need to proceed as we know it hasn't been case modified by the
977 if (strhasupper(password) && strhaslower(password))
982 /* make a copy of it */
983 StrnCpy(pass2, password, sizeof(pstring) - 1);
985 /* try all lowercase */
987 if (password_check(password))
999 fstrcpy(password, pass2);
1004 /* last chance - all combinations of up to level chars upper! */
1007 if (string_combinations(password, password_check, level))
1015 fstrcpy(password, pass2);