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);
137 pam_end(pamh, PAM_SUCCESS);
138 /* If this point is reached, the user has been authenticated. */
146 #include <afs/stds.h>
147 #include <afs/kautils.h>
149 /*******************************************************************
150 check on AFS authentication
151 ********************************************************************/
152 static BOOL afs_auth(char *user, char *password)
154 long password_expires = 0;
157 /* For versions of AFS prior to 3.3, this routine has few arguments, */
158 /* but since I can't find the old documentation... :-) */
160 if (ka_UserAuthenticateGeneral
161 (KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG, user, (char *)0, /* instance */
162 (char *)0, /* cell */
163 password, 0, /* lifetime, default */
164 &password_expires, /*days 'til it expires */
171 ("AFS authentication for \"%s\" failed (%s)\n", user, reason));
179 #include <dce/dce_error.h>
180 #include <dce/sec_login.h>
182 /*****************************************************************
183 This new version of the DFS_AUTH code was donated by Karsten Muuss
184 <muuss@or.uni-bonn.de>. It fixes the following problems with the
187 - Server credentials may expire
188 - Client credential cache files have wrong owner
189 - purge_context() function is called with invalid argument
191 This new code was modified to ensure that on exit the uid/gid is
192 still root, and the original directory is restored. JRA.
193 ******************************************************************/
195 sec_login_handle_t my_dce_sec_context;
196 int dcelogin_atmost_once = 0;
198 /*******************************************************************
199 check on a DCE/DFS authentication
200 ********************************************************************/
201 static BOOL dfs_auth(char *user, char *password)
206 signed32 expire_time, current_time;
207 boolean32 password_reset;
209 sec_passwd_rec_t passwd_rec;
210 sec_login_auth_src_t auth_src = sec_login_auth_src_network;
211 unsigned char dce_errstr[dce_c_error_string_len];
214 if (dcelogin_atmost_once)
219 * We only go for a DCE login context if the given password
220 * matches that stored in the local password file..
221 * Assumes local passwd file is kept in sync w/ DCE RGY!
224 if (strcmp((char *)crypt(password, this_salt), this_crypted))
230 sec_login_get_current_context(&my_dce_sec_context, &err);
231 if (err != error_status_ok)
233 dce_error_inq_text(err, dce_errstr, &err2);
234 DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
239 sec_login_certify_identity(my_dce_sec_context, &err);
240 if (err != error_status_ok)
242 dce_error_inq_text(err, dce_errstr, &err2);
243 DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
248 sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
249 if (err != error_status_ok)
251 dce_error_inq_text(err, dce_errstr, &err2);
252 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
259 if (expire_time < (current_time + 60))
262 sec_passwd_rec_t *key;
264 sec_login_get_pwent(my_dce_sec_context,
265 (sec_login_passwd_t *) & pw, &err);
266 if (err != error_status_ok)
268 dce_error_inq_text(err, dce_errstr, &err2);
269 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
274 sec_login_refresh_identity(my_dce_sec_context, &err);
275 if (err != error_status_ok)
277 dce_error_inq_text(err, dce_errstr, &err2);
278 DEBUG(0, ("DCE can't refresh identity. %s\n",
284 sec_key_mgmt_get_key(rpc_c_authn_dce_secret, NULL,
285 (unsigned char *)pw->pw_name,
286 sec_c_key_version_none,
287 (void **)&key, &err);
288 if (err != error_status_ok)
290 dce_error_inq_text(err, dce_errstr, &err2);
291 DEBUG(0, ("DCE can't get key for %s. %s\n",
292 pw->pw_name, dce_errstr));
297 sec_login_valid_and_cert_ident(my_dce_sec_context, key,
298 &password_reset, &auth_src,
300 if (err != error_status_ok)
302 dce_error_inq_text(err, dce_errstr, &err2);
304 ("DCE can't validate and certify identity for %s. %s\n",
305 pw->pw_name, dce_errstr));
308 sec_key_mgmt_free_key(key, &err);
309 if (err != error_status_ok)
311 dce_error_inq_text(err, dce_errstr, &err2);
312 DEBUG(0, ("DCE can't free key.\n", dce_errstr));
316 if (sec_login_setup_identity((unsigned char *)user,
318 &my_dce_sec_context, &err) == 0)
320 dce_error_inq_text(err, dce_errstr, &err2);
321 DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
326 sec_login_get_pwent(my_dce_sec_context,
327 (sec_login_passwd_t *) & pw, &err);
328 if (err != error_status_ok)
330 dce_error_inq_text(err, dce_errstr, &err2);
331 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
336 sec_login_purge_context(&my_dce_sec_context, &err);
337 if (err != error_status_ok)
339 dce_error_inq_text(err, dce_errstr, &err2);
340 DEBUG(0, ("DCE can't purge context. %s\n", dce_errstr));
346 * NB. I'd like to change these to call something like become_user()
347 * instead but currently we don't have a connection
348 * context to become the correct user. This is already
349 * fairly platform specific code however, so I think
350 * this should be ok. I have added code to go
351 * back to being root on error though. JRA.
356 if (set_effective_gid(pw->pw_gid) != 0)
358 DEBUG(0, ("Can't set egid to %d (%s)\n",
359 pw->pw_gid, strerror(errno)));
363 if (set_effective_uid(pw->pw_uid) != 0)
365 set_effective_gid(egid);
366 DEBUG(0, ("Can't set euid to %d (%s)\n",
367 pw->pw_uid, strerror(errno)));
371 if (sec_login_setup_identity((unsigned char *)user,
373 &my_dce_sec_context, &err) == 0)
375 dce_error_inq_text(err, dce_errstr, &err2);
376 DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
381 sec_login_get_pwent(my_dce_sec_context,
382 (sec_login_passwd_t *) & pw, &err);
383 if (err != error_status_ok)
385 dce_error_inq_text(err, dce_errstr, &err2);
386 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
390 passwd_rec.version_number = sec_passwd_c_version_none;
391 passwd_rec.pepper = NULL;
392 passwd_rec.key.key_type = sec_passwd_plain;
393 passwd_rec.key.tagged_union.plain = (idl_char *) password;
395 sec_login_validate_identity(my_dce_sec_context,
396 &passwd_rec, &password_reset,
398 if (err != error_status_ok)
400 dce_error_inq_text(err, dce_errstr, &err2);
402 ("DCE Identity Validation failed for principal %s: %s\n",
407 sec_login_certify_identity(my_dce_sec_context, &err);
408 if (err != error_status_ok)
410 dce_error_inq_text(err, dce_errstr, &err2);
411 DEBUG(0, ("DCE certify identity failed: %s\n", dce_errstr));
415 if (auth_src != sec_login_auth_src_network)
417 DEBUG(0, ("DCE context has no network credentials.\n"));
420 sec_login_set_context(my_dce_sec_context, &err);
421 if (err != error_status_ok)
423 dce_error_inq_text(err, dce_errstr, &err2);
425 ("DCE login failed for principal %s, cant set context: %s\n",
428 sec_login_purge_context(&my_dce_sec_context, &err);
432 sec_login_get_pwent(my_dce_sec_context,
433 (sec_login_passwd_t *) & pw, &err);
434 if (err != error_status_ok)
436 dce_error_inq_text(err, dce_errstr, &err2);
437 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
441 DEBUG(0, ("DCE login succeeded for principal %s on pid %d\n",
444 DEBUG(3, ("DCE principal: %s\n"
447 pw->pw_name, pw->pw_uid, pw->pw_gid));
448 DEBUG(3, (" info: %s\n"
451 pw->pw_gecos, pw->pw_dir, pw->pw_shell));
453 sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
454 if (err != error_status_ok)
456 dce_error_inq_text(err, dce_errstr, &err2);
457 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
461 set_effective_uid(0);
462 set_effective_gid(0);
465 ("DCE context expires: %s", asctime(localtime(&expire_time))));
467 dcelogin_atmost_once = 1;
472 /* Go back to root, JRA. */
473 set_effective_uid(0);
474 set_effective_gid(egid);
478 void dfs_unlogin(void)
482 unsigned char dce_errstr[dce_c_error_string_len];
484 sec_login_purge_context(&my_dce_sec_context, &err);
485 if (err != error_status_ok)
487 dce_error_inq_text(err, dce_errstr, &err2);
489 ("DCE purge login context failed for server instance %d: %s\n",
490 getpid(), dce_errstr));
499 /*******************************************************************
500 check on Kerberos authentication
501 ********************************************************************/
502 static BOOL krb5_auth(char *user, char *password)
504 krb5_data tgtname = {
509 krb5_context kcontext;
510 krb5_principal kprinc;
511 krb5_principal server;
514 krb5_address **addrs = (krb5_address **) 0;
515 krb5_preauthtype *preauth = NULL;
516 krb5_keytab keytab = NULL;
518 krb5_ccache ccache = NULL;
522 if (retval = krb5_init_context(&kcontext))
527 if (retval = krb5_timeofday(kcontext, &now))
532 if (retval = krb5_cc_default(kcontext, &ccache))
537 if (retval = krb5_parse_name(kcontext, user, &kprinc))
544 kcreds.client = kprinc;
546 if ((retval = krb5_build_principal_ext(kcontext, &server,
547 krb5_princ_realm(kcontext,
550 krb5_princ_realm(kcontext,
552 tgtname.length, tgtname.data,
553 krb5_princ_realm(kcontext,
556 krb5_princ_realm(kcontext,
563 kcreds.server = server;
565 retval = krb5_get_in_tkt_with_password(kcontext,
570 password, 0, &kcreds, 0);
579 #endif /* KRB5_AUTH */
584 /*******************************************************************
585 check on Kerberos authentication
586 ********************************************************************/
587 static BOOL krb4_auth(char *user, char *password)
589 char realm[REALM_SZ];
590 char tkfile[MAXPATHLEN];
592 if (krb_get_lrealm(realm, 1) != KSUCCESS)
594 (void)safe_strcpy(realm, KRB_REALM, sizeof(realm) - 1);
597 (void)slprintf(tkfile, sizeof(tkfile) - 1, "/tmp/samba_tkt_%d",
600 krb_set_tkt_string(tkfile);
601 if (krb_verify_user(user, "", realm, password, 0, "rmcd") == KSUCCESS)
609 #endif /* KRB4_AUTH */
611 #ifdef LINUX_BIGCRYPT
612 /****************************************************************************
613 an enhanced crypt for Linux to handle password longer than 8 characters
614 ****************************************************************************/
615 static int linux_bigcrypt(char *password, char *salt1, char *crypted)
617 #define LINUX_PASSWORD_SEG_CHARS 8
621 StrnCpy(salt, salt1, 2);
624 for (i = strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS)
626 char *p = crypt(password, salt) + 2;
627 if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
629 password += LINUX_PASSWORD_SEG_CHARS;
630 crypted += strlen(p);
638 /****************************************************************************
639 an enhanced crypt for OSF1
640 ****************************************************************************/
641 static char *osf1_bigcrypt(char *password, char *salt1)
643 static char result[AUTH_MAX_PASSWD_LENGTH] = "";
648 int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
649 if (strlen(password) % AUTH_CLEARTEXT_SEG_CHARS)
654 StrnCpy(salt, salt1, 2);
655 StrnCpy(result, salt1, 2);
658 for (i = 0; i < parts; i++)
660 p1 = crypt(p2, salt);
661 strncat(result, p1 + 2,
662 AUTH_MAX_PASSWD_LENGTH - strlen(p1 + 2) - 1);
663 StrnCpy(salt, &result[2 + i * AUTH_CIPHERTEXT_SEG_CHARS], 2);
664 p2 += AUTH_CLEARTEXT_SEG_CHARS;
672 /****************************************************************************
673 apply a function to upper/lower case combinations
674 of a string and return true if one of them returns true.
675 try all combinations with N uppercase letters.
676 offset is the first char to try and change (start with 0)
677 it assumes the string starts lowercased
678 ****************************************************************************/
679 static BOOL string_combinations2(char *s, int offset, BOOL (*fn) (char *),
685 #ifdef PASSWORD_LENGTH
686 len = MIN(len, PASSWORD_LENGTH);
689 if (N <= 0 || offset >= len)
694 for (i = offset; i < (len - (N - 1)); i++)
700 if (string_combinations2(s, i + 1, fn, N - 1))
707 /****************************************************************************
708 apply a function to upper/lower case combinations
709 of a string and return true if one of them returns true.
710 try all combinations with up to N uppercase letters.
711 offset is the first char to try and change (start with 0)
712 it assumes the string starts lowercased
713 ****************************************************************************/
714 static BOOL string_combinations(char *s, BOOL (*fn) (char *), int N)
717 for (n = 1; n <= N; n++)
718 if (string_combinations2(s, 0, fn, n))
724 /****************************************************************************
725 core of password checking routine
726 ****************************************************************************/
727 static BOOL password_check(char *password)
731 /* This falls through if the password check fails
732 - if HAVE_CRYPT is not defined this causes an error msg
733 saying Warning - no crypt available
734 - if HAVE_CRYPT is defined this is a potential security hole
735 as it may authenticate via the crypt call when PAM
736 settings say it should fail.
737 if (pam_auth(user,password)) return(True);
738 Hence we make a direct return to avoid a second chance!!!
740 return (pam_auth(this_user, password));
741 #endif /* WITH_PAM */
744 if (afs_auth(this_user, password))
746 #endif /* WITH_AFS */
749 if (dfs_auth(this_user, password))
751 #endif /* WITH_DFS */
754 if (krb5_auth(this_user, password))
756 #endif /* KRB5_AUTH */
759 if (krb4_auth(this_user, password))
761 #endif /* KRB4_AUTH */
767 (osf1_bigcrypt(password, this_salt),
772 ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
775 ((char *)crypt(password, this_salt),
780 #endif /* OSF1_ENH_SEC */
783 return (strcmp((char *)crypt16(password, this_salt), this_crypted) ==
785 #endif /* ULTRIX_AUTH */
787 #ifdef LINUX_BIGCRYPT
788 return (linux_bigcrypt(password, this_salt, this_crypted));
789 #endif /* LINUX_BIGCRYPT */
791 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
794 * Some systems have bigcrypt in the C library but might not
795 * actually use it for the password hashes (HPUX 10.20) is
796 * a noteable example. So we try bigcrypt first, followed
800 if (strcmp(bigcrypt(password, this_salt), this_crypted) == 0)
804 ((char *)crypt(password, this_salt),
806 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
809 return (strcmp(bigcrypt(password, this_salt), this_crypted) == 0);
810 #endif /* HAVE_BIGCRYPT */
813 DEBUG(1, ("Warning - no crypt available\n"));
815 #else /* HAVE_CRYPT */
816 return (strcmp((char *)crypt(password, this_salt), this_crypted) ==
818 #endif /* HAVE_CRYPT */
819 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
824 /****************************************************************************
825 check if a username/password is OK
826 the function pointer fn() points to a function to call when a successful
827 match is found and is used to update the encrypted password file
828 return True on correct match, False otherwise
829 ****************************************************************************/
830 BOOL pass_check(char *user, char *password, int pwlen, struct passwd *pwd,
831 BOOL (*fn) (char *, char *))
834 int level = lp_passwordlevel();
841 DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
849 if (((!*password) || (!pwlen)) && !lp_null_passwords())
856 pass = (struct passwd *)pwd;
857 user = pass->pw_name;
861 pass = Get_Pwnam(user, True);
865 DEBUG(4, ("Checking password for user %s (l=%d)\n", user, pwlen));
869 DEBUG(3, ("Couldn't find user %s\n", user));
877 /* many shadow systems require you to be root to get
878 the password, in most cases this should already be
879 the case when this function is called, except
880 perhaps for IPC password changing requests */
882 spass = getspnam(pass->pw_name);
883 if (spass && spass->sp_pwdp)
885 pstrcpy(pass->pw_passwd, spass->sp_pwdp);
888 #elif defined(IA_UINFO)
890 /* Need to get password with SVR4.2's ia_ functions
891 instead of get{sp,pw}ent functions. Required by
892 UnixWare 2.x, tested on version
893 2.1. (tangent@cyberport.com) */
895 if (ia_openinfo(pass->pw_name, &uinfo) != -1)
897 ia_get_logpwd(uinfo, &(pass->pw_passwd));
902 #ifdef HAVE_GETPRPWNAM
904 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
905 if (pr_pw && pr_pw->ufld.fd_encrypt)
906 pstrcpy(pass->pw_passwd, pr_pw->ufld.fd_encrypt);
912 struct pr_passwd *mypasswd;
913 DEBUG(5, ("Checking password for user %s in OSF1_ENH_SEC\n",
915 mypasswd = getprpwnam(user);
918 fstrcpy(pass->pw_name, mypasswd->ufld.fd_name);
919 fstrcpy(pass->pw_passwd, mypasswd->ufld.fd_encrypt);
924 ("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
932 AUTHORIZATION *ap = getauthuid(pass->pw_uid);
935 fstrcpy(pass->pw_passwd, ap->a_password);
941 /* extract relevant info */
942 fstrcpy(this_user, pass->pw_name);
943 fstrcpy(this_salt, pass->pw_passwd);
945 #if defined(HAVE_TRUNCATED_SALT)
946 /* crypt on some platforms (HPUX in particular)
947 won't work with more than 2 salt characters. */
951 fstrcpy(this_crypted, pass->pw_passwd);
955 if (!lp_null_passwords())
957 DEBUG(2, ("Disallowing %s with null password\n",
964 ("Allowing access to %s with null password\n",
970 /* try it as it came to us */
971 if (password_check(password))
978 /* if the password was given to us with mixed case then we don't
979 need to proceed as we know it hasn't been case modified by the
981 if (strhasupper(password) && strhaslower(password))
986 /* make a copy of it */
987 StrnCpy(pass2, password, sizeof(pstring) - 1);
989 /* try all lowercase */
991 if (password_check(password))
1003 fstrcpy(password, pass2);
1008 /* last chance - all combinations of up to level chars upper! */
1011 if (string_combinations(password, password_check, level))
1019 fstrcpy(password, pass2);