2 Unix SMB/Netbios implementation.
4 Password and authentication handling
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.
24 #if (defined(NETGROUP) && defined (AUTOMOUNT))
25 #include "rpcsvc/ypclnt.h"
28 extern int DEBUGLEVEL;
31 /* users from session setup */
32 static pstring session_users="";
34 /* these are kept here to keep the string_combinations function simple */
35 static char this_user[100]="";
36 static char this_salt[100]="";
37 static char this_crypted[100]="";
39 /* Data to do lanman1/2 password challenge. */
40 static unsigned char saved_challenge[8];
41 static BOOL challenge_sent=False;
43 /*******************************************************************
44 Get the next challenge value - no repeats.
45 ********************************************************************/
46 void generate_next_challenge(char *challenge)
50 * Leave this ifdef'd out while we test
51 * the new crypto random number generator.
54 unsigned char buf[16];
55 static int counter = 0;
59 /* get a sort-of random number */
61 v1 = (counter++) + getpid() + tval.tv_sec;
62 v2 = (counter++) * getpid() + tval.tv_usec;
63 SIVAL(challenge,0,v1);
64 SIVAL(challenge,4,v2);
66 /* mash it up with md4 */
67 mdfour(buf, (unsigned char *)challenge, 8);
71 generate_random_buffer(buf,8,False);
73 memcpy(saved_challenge, buf, 8);
74 memcpy(challenge,buf,8);
75 challenge_sent = True;
78 /*******************************************************************
79 set the last challenge sent, usually from a password server
80 ********************************************************************/
81 BOOL set_challenge(char *challenge)
83 memcpy(saved_challenge,challenge,8);
84 challenge_sent = True;
88 /*******************************************************************
89 get the last challenge sent
90 ********************************************************************/
91 BOOL last_challenge(char *challenge)
93 if (!challenge_sent) return(False);
94 memcpy(challenge,saved_challenge,8);
98 /* this holds info on user ids that are already validated for this VC */
99 static user_struct *validated_users = NULL;
100 static int num_validated_users = 0;
102 /****************************************************************************
103 check if a uid has been validated, and return an pointer to the user_struct
104 if it has. NULL if not. vuid is biased by an offset. This allows us to
105 tell random client vuid's (normally zero) from valid vuids.
106 ****************************************************************************/
107 user_struct *get_valid_user_struct(uint16 vuid)
109 if (vuid == UID_FIELD_INVALID)
112 if ((vuid >= (uint16)num_validated_users) ||
113 (validated_users[vuid].uid == -1) || (validated_users[vuid].gid == -1))
115 return &validated_users[vuid];
118 /****************************************************************************
120 ****************************************************************************/
121 void invalidate_vuid(uint16 vuid)
123 user_struct *vuser = get_valid_user_struct(vuid);
125 if (vuser == NULL) return;
132 /* same number of igroups as groups as attrs */
135 if (vuser->groups && (vuser->groups != (gid_t *)vuser->igroups))
138 if (vuser->igroups) free(vuser->igroups);
139 if (vuser->attrs ) free(vuser->attrs);
140 if (vuser->sids ) free(vuser->sids);
144 vuser->igroups = NULL;
145 vuser->groups = NULL;
149 /****************************************************************************
150 return a validated username
151 ****************************************************************************/
152 char *validated_username(uint16 vuid)
154 user_struct *vuser = get_valid_user_struct(vuid);
161 /****************************************************************************
162 Setup the groups a user belongs to.
163 ****************************************************************************/
164 int setup_groups(char *user, int uid, int gid, int *p_ngroups,
165 int **p_igroups, gid_t **p_groups,
168 if (-1 == initgroups(user,gid))
172 DEBUG(0,("Unable to initgroups!\n"));
173 if (gid < 0 || gid > 16000 || uid < 0 || uid > 16000)
174 DEBUG(0,("This is probably a problem with the account %s\n",user));
183 ngroups = getgroups(0,&grp);
186 igroups = (int *)malloc(sizeof(int)*ngroups);
187 attrs = (int *)malloc(sizeof(int)*ngroups);
188 for (i=0;i<ngroups;i++)
190 attrs [i] = 0x7; /* XXXX don't know what NT user attributes are yet! */
191 igroups[i] = 0x42424242;
193 ngroups = getgroups(ngroups,(gid_t *)igroups);
195 if (igroups[0] == 0x42424242)
198 *p_ngroups = ngroups;
201 /* The following bit of code is very strange. It is due to the
202 fact that some OSes use int* and some use gid_t* for
203 getgroups, and some (like SunOS) use both, one in prototypes,
204 and one in man pages and the actual code. Thus we detect it
205 dynamically using some very ugly code */
208 /* does getgroups return ints or gid_t ?? */
209 static BOOL groups_use_ints = True;
211 if (groups_use_ints &&
213 SVAL(igroups,2) == 0x4242)
214 groups_use_ints = False;
216 for (i=0;groups_use_ints && i<ngroups;i++)
217 if (igroups[i] == 0x42424242)
218 groups_use_ints = False;
222 *p_igroups = igroups;
223 *p_groups = (gid_t *)igroups;
227 gid_t *groups = (gid_t *)igroups;
228 igroups = (int *)malloc(sizeof(int)*ngroups);
229 for (i=0;i<ngroups;i++)
231 igroups[i] = groups[i];
233 *p_igroups = igroups;
234 *p_groups = (gid_t *)groups;
237 DEBUG(3,("%s is in %d groups\n",user,ngroups));
238 for (i=0;i<ngroups;i++)
239 DEBUG(3,("%d ",igroups[i]));
246 /****************************************************************************
247 register a uid/name pair as being valid and that a valid password
248 has been given. vuid is biased by an offset. This allows us to
249 tell random client vuid's (normally zero) from valid vuids.
250 ****************************************************************************/
251 uint16 register_vuid(int uid,int gid, char *name,BOOL guest)
254 struct passwd *pwfile; /* for getting real name from passwd file */
256 /* Ensure no vuid gets registered in share level security. */
257 if(lp_security() == SEC_SHARE)
258 return UID_FIELD_INVALID;
262 * After observing MS-Exchange services writing to a Samba share
263 * I belive this code is incorrect. Each service does its own
264 * sessionsetup_and_X for the same user, and as each service shuts
265 * down, it does a user_logoff_and_X. As we are consolidating multiple
266 * sessionsetup_and_X's onto the same vuid here, when the first service
267 * shuts down, it invalidates all the open files for the other services.
268 * Hence I am removing this code and forcing each sessionsetup_and_X
270 * Jeremy Allison. (jallison@whistle.com).
274 for(i = 0; i < num_validated_users; i++) {
275 vuser = &validated_users[i];
276 if ( vuser->uid == uid )
277 return (uint16)(i + VUID_OFFSET); /* User already validated */
281 validated_users = (user_struct *)Realloc(validated_users,
283 (num_validated_users+1));
285 if (!validated_users)
287 DEBUG(0,("Failed to realloc users struct!\n"));
288 num_validated_users = 0;
289 return UID_FIELD_INVALID;
292 vuser = &validated_users[num_validated_users];
293 num_validated_users++;
297 vuser->guest = guest;
298 strcpy(vuser->name,name);
304 vuser->groups = NULL;
305 vuser->igroups = NULL;
308 /* Find all the groups this uid is in and store them.
309 Used by become_user() */
310 setup_groups(name,uid,gid,
316 DEBUG(3,("uid %d registered to name %s\n",uid,name));
318 DEBUG(3, ("Clearing default real name\n"));
319 fstrcpy(vuser->real_name, "<Full Name>\0");
320 if (lp_unix_realname()) {
321 if ((pwfile=getpwnam(vuser->name))!= NULL)
323 DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->name,pwfile->pw_gecos));
324 fstrcpy(vuser->real_name, pwfile->pw_gecos);
328 return (uint16)((num_validated_users - 1) + VUID_OFFSET);
332 /****************************************************************************
333 add a name to the session users list
334 ****************************************************************************/
335 void add_session_user(char *user)
338 StrnCpy(suser,user,sizeof(suser)-1);
340 if (!Get_Pwnam(suser,True)) return;
342 if (suser && *suser && !in_list(suser,session_users,False))
344 if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring))
345 DEBUG(1,("Too many session users??\n"));
348 strcat(session_users," ");
349 strcat(session_users,suser);
356 /* a fake shadow password routine which just fills a fake spwd struct
357 * with the sp_pwdp field. (sreiz@aie.nl)
359 static struct spwd *getspnam(char *username) /* fake shadow password routine */
364 static struct spwd static_spwd;
366 static_spwd.sp_pwdp=0;
367 if (!(f=fopen("/etc/master.passwd", "r")))
369 while (fgets(line, 1024, f)) {
370 if (!strncmp(line, username, strlen(username)) &&
371 line[strlen(username)]==':') { /* found entry */
374 p=line+strlen(username)+1;
375 if ((q=strchr(p, ':'))) {
380 static_spwd.sp_pwdp=pw;
386 if (static_spwd.sp_pwdp)
394 /****************************************************************************
395 an enhanced crypt for OSF1
396 ****************************************************************************/
397 static char *osf1_bigcrypt(char *password,char *salt1)
399 static char result[AUTH_MAX_PASSWD_LENGTH] = "";
404 int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
405 if (strlen(password)%AUTH_CLEARTEXT_SEG_CHARS)
408 StrnCpy(salt,salt1,2);
409 StrnCpy(result,salt1,2);
411 for (i=0; i<parts;i++)
415 StrnCpy(salt,&result[2+i*AUTH_CIPHERTEXT_SEG_CHARS],2);
416 p2 += AUTH_CLEARTEXT_SEG_CHARS;
424 /****************************************************************************
425 update the enhanced security database. Only relevant for OSF1 at the moment.
426 ****************************************************************************/
427 static void update_protected_database( char *user, BOOL result)
430 struct pr_passwd *mypasswd;
433 mypasswd = getprpwnam (user);
434 starttime = time (NULL);
438 mypasswd->ufld.fd_slogin = starttime;
439 mypasswd->ufld.fd_nlogins = 0;
441 putprpwnam(user,mypasswd);
443 DEBUG(3,("Update protected database for Account %s after succesful connection\n",user));
447 mypasswd->ufld.fd_ulogin = starttime;
448 mypasswd->ufld.fd_nlogins = mypasswd->ufld.fd_nlogins + 1;
449 if ( mypasswd->ufld.fd_max_tries != 0 && mypasswd->ufld.fd_nlogins > mypasswd->ufld.fd_max_tries )
451 mypasswd->uflg.fg_lock = 0;
452 DEBUG(3,("Account is disabled -- see Account Administrator.\n"));
454 putprpwnam ( user , mypasswd );
455 DEBUG(3,("Update protected database for Account %s after refusing connection\n",user));
458 DEBUG(6,("Updated database with %s %s\n",user,BOOLSTR(result)));
464 /*******************************************************************
465 check on PAM authentication
466 ********************************************************************/
468 /* We first need some helper functions */
469 #include <security/pam_appl.h>
470 /* Static variables used to communicate between the conversation function
471 * and the server_login function
473 static char *PAM_username;
474 static char *PAM_password;
476 /* PAM conversation function
477 * Here we assume (for now, at least) that echo on means login name, and
478 * echo off means password.
480 static int PAM_conv (int num_msg,
481 const struct pam_message **msg,
482 struct pam_response **resp,
485 struct pam_response *reply = NULL;
487 #define COPY_STRING(s) (s) ? strdup(s) : NULL
489 reply = malloc(sizeof(struct pam_response) * num_msg);
490 if (!reply) return PAM_CONV_ERR;
492 for (replies = 0; replies < num_msg; replies++) {
493 switch (msg[replies]->msg_style) {
494 case PAM_PROMPT_ECHO_ON:
495 reply[replies].resp_retcode = PAM_SUCCESS;
496 reply[replies].resp = COPY_STRING(PAM_username);
499 case PAM_PROMPT_ECHO_OFF:
500 reply[replies].resp_retcode = PAM_SUCCESS;
501 reply[replies].resp = COPY_STRING(PAM_password);
508 reply[replies].resp_retcode = PAM_SUCCESS;
509 reply[replies].resp = NULL;
512 /* Must be an error of some sort... */
517 if (reply) *resp = reply;
520 static struct pam_conv PAM_conversation = {
526 static BOOL pam_auth(char *this_user,char *password)
531 /* Now use PAM to do authentication. For now, we won't worry about
532 * session logging, only authentication. Bail out if there are any
533 * errors. Since this is a limited protocol, and an even more limited
534 * function within a server speaking this protocol, we can't be as
535 * verbose as would otherwise make sense.
536 * Query: should we be using PAM_SILENT to shut PAM up?
538 #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
539 pam_end(pamh, 0); return False; \
541 PAM_password = password;
542 PAM_username = this_user;
543 pam_error = pam_start("samba", this_user, &PAM_conversation, &pamh);
545 /* Setting PAM_SILENT stops generation of error messages to syslog
546 * to enable debugging on Red Hat Linux set:
548 * auth required /lib/security/pam_pwdb.so nullok shadow audit
549 * _OR_ change PAM_SILENT to 0 to force detailed reporting (logging)
551 pam_error = pam_authenticate(pamh, PAM_SILENT);
553 /* It is not clear to me that account management is the right thing
554 * to do, but it is not clear that it isn't, either. This can be
555 * removed if no account management should be done. Alternately,
556 * put a pam_allow.so entry in /etc/pam.conf for account handling. */
557 pam_error = pam_acct_mgmt(pamh, PAM_SILENT);
559 pam_end(pamh, PAM_SUCCESS);
560 /* If this point is reached, the user has been authenticated. */
567 /*******************************************************************
568 check on AFS authentication
569 ********************************************************************/
570 static BOOL afs_auth(char *this_user,char *password)
572 long password_expires = 0;
575 /* For versions of AFS prior to 3.3, this routine has few arguments, */
576 /* but since I can't find the old documentation... :-) */
578 if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
580 (char *) 0, /* instance */
581 (char *) 0, /* cell */
583 0, /* lifetime, default */
584 &password_expires, /*days 'til it expires */
595 sec_login_handle_t my_dce_sec_context;
596 int dcelogin_atmost_once = 0;
598 /*******************************************************************
599 check on a DCE/DFS authentication
600 ********************************************************************/
601 static BOOL dfs_auth(char *this_user,char *password)
606 boolean32 password_reset;
607 sec_passwd_rec_t my_dce_password;
608 sec_login_auth_src_t auth_src = sec_login_auth_src_network;
609 unsigned char dce_errstr[dce_c_error_string_len];
612 * We only go for a DCE login context if the given password
613 * matches that stored in the local password file..
614 * Assumes local passwd file is kept in sync w/ DCE RGY!
617 /* Fix for original (broken) code from Brett Wooldridge <brettw@austin.ibm.com> */
618 if (dcelogin_atmost_once)
620 /* This can be ifdefed as the DCE check below is stricter... */
622 if ( strcmp((char *)crypt(password,this_salt),this_crypted) )
626 if (sec_login_setup_identity(
627 (unsigned char *)this_user,
632 dce_error_inq_text(err, dce_errstr, &err2);
633 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
634 this_user,dce_errstr));
638 my_dce_password.version_number = sec_passwd_c_version_none;
639 my_dce_password.pepper = NULL;
640 my_dce_password.key.key_type = sec_passwd_plain;
641 my_dce_password.key.tagged_union.plain = (idl_char *)password;
643 if (sec_login_valid_and_cert_ident(my_dce_sec_context,
649 dce_error_inq_text(err, dce_errstr, &err2);
650 DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
651 this_user,dce_errstr));
656 sec_login_set_context(my_dce_sec_context, &err);
657 if (err != error_status_ok )
659 dce_error_inq_text(err, dce_errstr, &err2);
660 DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
661 this_user,dce_errstr));
662 sec_login_purge_context(my_dce_sec_context, &err);
667 DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
668 this_user, getpid()));
671 dcelogin_atmost_once = 1;
675 void dfs_unlogin(void)
679 unsigned char dce_errstr[dce_c_error_string_len];
681 sec_login_purge_context(my_dce_sec_context, &err);
682 if (err != error_status_ok )
684 dce_error_inq_text(err, dce_errstr, &err2);
685 DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
686 getpid(), dce_errstr));
693 /*******************************************************************
694 check on Kerberos authentication
695 ********************************************************************/
696 static BOOL krb5_auth(char *this_user,char *password)
698 krb5_data tgtname = {
703 krb5_context kcontext;
704 krb5_principal kprinc;
705 krb5_principal server;
708 krb5_address **addrs = (krb5_address **)0;
709 krb5_preauthtype *preauth = NULL;
710 krb5_keytab keytab = NULL;
712 krb5_ccache ccache = NULL;
716 if ( retval=krb5_init_context(&kcontext))
721 if ( retval = krb5_timeofday(kcontext, &now) )
726 if ( retval = krb5_cc_default(kcontext, &ccache) )
731 if ( retval = krb5_parse_name(kcontext, this_user, &kprinc) )
736 memset((char *)&kcreds, 0, sizeof(kcreds));
738 kcreds.client = kprinc;
740 if ((retval = krb5_build_principal_ext(kcontext, &server,
741 krb5_princ_realm(kcontext, kprinc)->length,
742 krb5_princ_realm(kcontext, kprinc)->data,
745 krb5_princ_realm(kcontext, kprinc)->length,
746 krb5_princ_realm(kcontext, kprinc)->data,
752 kcreds.server = server;
754 retval = krb5_get_in_tkt_with_password(kcontext,
771 #endif /* KRB5_AUTH */
774 /*******************************************************************
775 check on Kerberos authentication
776 ********************************************************************/
777 static BOOL krb4_auth(char *this_user,char *password)
779 char realm[REALM_SZ];
780 char tkfile[MAXPATHLEN];
782 if (krb_get_lrealm(realm, 1) != KSUCCESS)
783 (void) strncpy(realm, KRB_REALM, sizeof (realm));
785 (void) sprintf(tkfile, "/tmp/samba_tkt_%d", getpid());
787 krb_set_tkt_string(tkfile);
788 if (krb_verify_user(this_user, "", realm,
790 "rmcd") == KSUCCESS) {
797 #endif /* KRB4_AUTH */
799 #ifdef LINUX_BIGCRYPT
800 /****************************************************************************
801 an enhanced crypt for Linux to handle password longer than 8 characters
802 ****************************************************************************/
803 static int linux_bigcrypt(char *password,char *salt1, char *crypted)
805 #define LINUX_PASSWORD_SEG_CHARS 8
809 StrnCpy(salt,salt1,2);
812 for ( i=strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
813 char * p = crypt(password,salt) + 2;
814 if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
816 password += LINUX_PASSWORD_SEG_CHARS;
817 crypted += strlen(p);
825 /****************************************************************************
826 apply a function to upper/lower case combinations
827 of a string and return true if one of them returns true.
828 try all combinations with N uppercase letters.
829 offset is the first char to try and change (start with 0)
830 it assumes the string starts lowercased
831 ****************************************************************************/
832 static BOOL string_combinations2(char *s,int offset,BOOL (*fn)(char *),int N)
837 #ifdef PASSWORD_LENGTH
838 len = MIN(len,PASSWORD_LENGTH);
841 if (N <= 0 || offset >= len)
844 for (i=offset;i<(len-(N-1));i++)
847 if (!islower(c)) continue;
849 if (string_combinations2(s,i+1,fn,N-1))
856 /****************************************************************************
857 apply a function to upper/lower case combinations
858 of a string and return true if one of them returns true.
859 try all combinations with up to N uppercase letters.
860 offset is the first char to try and change (start with 0)
861 it assumes the string starts lowercased
862 ****************************************************************************/
863 static BOOL string_combinations(char *s,BOOL (*fn)(char *),int N)
867 if (string_combinations2(s,0,fn,n)) return(True);
873 /****************************************************************************
874 core of password checking routine
875 ****************************************************************************/
876 BOOL password_check(char *password)
880 /* This falls through if the password check fails
881 - if NO_CRYPT is defined this causes an error msg
882 saying Warning - no crypt available
883 - if NO_CRYPT is NOT defined this is a potential security hole
884 as it may authenticate via the crypt call when PAM
885 settings say it should fail.
886 if (pam_auth(this_user,password)) return(True);
887 Hence we make a direct return to avoid a second chance!!!
889 return (pam_auth(this_user,password));
893 if (afs_auth(this_user,password)) return(True);
897 if (dfs_auth(this_user,password)) return(True);
901 if (krb5_auth(this_user,password)) return(True);
905 if (krb4_auth(this_user,password)) return(True);
909 if (pwdauth(this_user,password) == 0)
914 return(strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0);
918 return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
921 #ifdef LINUX_BIGCRYPT
922 return(linux_bigcrypt(password,this_salt,this_crypted));
925 #ifdef HPUX_10_TRUSTED
926 return(bigcrypt(password,this_salt,this_crypted));
930 DEBUG(1,("Warning - no crypt available\n"));
933 return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
937 /****************************************************************************
938 core of smb password checking routine.
939 ****************************************************************************/
940 BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8)
942 /* Finish the encryption of part_passwd. */
943 unsigned char p21[21];
944 unsigned char p24[24];
946 if (part_passwd == NULL)
947 DEBUG(10,("No password set - allowing access\n"));
948 /* No password set - always true ! */
949 if (part_passwd == NULL)
953 memcpy(p21,part_passwd,16);
958 DEBUG(100,("Part password (P16) was |"));
959 for(i = 0; i < 16; i++)
960 DEBUG(100,("%X ", (unsigned char)part_passwd[i]));
962 DEBUG(100,("Password from client was |"));
963 for(i = 0; i < 24; i++)
964 DEBUG(100,("%X ", (unsigned char)password[i]));
966 DEBUG(100,("Given challenge was |"));
967 for(i = 0; i < 8; i++)
968 DEBUG(100,("%X ", (unsigned char)c8[i]));
970 DEBUG(100,("Value from encryption was |"));
971 for(i = 0; i < 24; i++)
972 DEBUG(100,("%X ", (unsigned char)p24[i]));
976 return (memcmp(p24, password, 24) == 0);
979 /****************************************************************************
980 Do a specific test for an smb password being correct, given a smb_password and
981 the lanman and NT responses.
982 ****************************************************************************/
984 BOOL smb_password_ok(struct smb_passwd *smb_pass,
985 uchar lm_pass[24], uchar nt_pass[24])
989 if (!lm_pass || !smb_pass) return(False);
991 if(smb_pass->acct_ctrl & ACB_DISABLED)
993 DEBUG(3,("smb_password_ok: account for user %s was disabled.\n", smb_pass->smb_name));
997 if (!last_challenge(challenge))
999 DEBUG(1,("smb_password_ok: no challenge done - password failed\n"));
1003 DEBUG(4,("smb_password_ok: Checking SMB password for user %s\n", smb_pass->smb_name));
1005 if ((Protocol >= PROTOCOL_NT1) && (smb_pass->smb_nt_passwd != NULL))
1007 /* We have the NT MD4 hash challenge available - see if we can
1008 use it (ie. does it exist in the smbpasswd file).
1010 DEBUG(4,("smb_password_ok: Checking NT MD4 password\n"));
1011 if (smb_password_check(nt_pass, smb_pass->smb_nt_passwd, challenge))
1013 DEBUG(4,("smb_password_ok: NT MD4 password check succeeded\n"));
1016 DEBUG(4,("smb_password_ok: NT MD4 password check failed\n"));
1019 /* Try against the lanman password. smb_pass->smb_passwd == NULL means
1020 no password, allow access. */
1022 DEBUG(4,("Checking LM MD4 password\n"));
1024 if((smb_pass->smb_passwd == NULL) && (smb_pass->acct_ctrl & ACB_PWNOTREQ))
1026 DEBUG(4,("smb_password_ok: no password required for user %s\n", smb_pass->smb_name));
1030 if((smb_pass->smb_passwd != NULL) && smb_password_check(lm_pass, smb_pass->smb_passwd, challenge))
1032 DEBUG(4,("smb_password_ok: LM MD4 password check succeeded\n"));
1036 DEBUG(4,("smb_password_ok: LM MD4 password check failed\n"));
1041 /****************************************************************************
1042 check if a username/password is OK
1043 ****************************************************************************/
1044 BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd)
1047 int level = lp_passwordlevel();
1048 struct passwd *pass;
1050 struct smb_passwd *smb_pass;
1051 BOOL challenge_done = False;
1053 if (password) password[pwlen] = 0;
1056 challenge_done = last_challenge(challenge);
1062 DEBUG(100,("checking user=[%s] pass=[",user));
1063 for( i = 0; i < 24; i++)
1064 DEBUG(100,("%0x ", (unsigned char)password[i]));
1067 DEBUG(100,("checking user=[%s] pass=[%s]\n",user,password));
1074 if (((!*password) || (!pwlen)) && !lp_null_passwords())
1079 pass = (struct passwd *) pwd;
1080 user = pass->pw_name;
1083 pass = Get_Pwnam(user,True);
1085 DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen, challenge_done));
1087 if ((pwlen == 24) && challenge_done)
1089 DEBUG(4,("Checking SMB password for user %s (l=24)\n",user));
1093 DEBUG(3,("Couldn't find user %s\n",user));
1097 smb_pass = getsmbpwnam(user);
1101 DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
1105 /* Quit if the account was disabled. */
1106 if(smb_pass->acct_ctrl & ACB_DISABLED)
1108 DEBUG(3,("password_ok: account for user %s was disabled.\n", user));
1112 /* Ensure the uid's match */
1113 if (smb_pass->smb_userid != pass->pw_uid)
1115 DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
1119 if(smb_password_ok( smb_pass, password, password))
1121 update_protected_database(user,True);
1125 DEBUG(3,("Error smb_password_check failed\n"));
1128 DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
1132 DEBUG(3,("Couldn't find user %s\n",user));
1140 /* many shadow systems require you to be root to get the password,
1141 in most cases this should already be the case when this
1142 function is called, except perhaps for IPC password changing
1145 spass = getspnam(pass->pw_name);
1146 if (spass && spass->sp_pwdp)
1147 pass->pw_passwd = spass->sp_pwdp;
1149 #elif defined(IA_UINFO)
1151 /* Need to get password with SVR4.2's ia_ functions instead of
1152 get{sp,pw}ent functions. Required by UnixWare 2.x, tested on
1153 version 2.1. (tangent@cyberport.com) */
1155 if (ia_openinfo(pass->pw_name, &uinfo) != -1)
1156 ia_get_logpwd(uinfo, &(pass->pw_passwd));
1162 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
1163 if (pr_pw && pr_pw->ufld.fd_encrypt)
1164 pass->pw_passwd = pr_pw->ufld.fd_encrypt;
1168 #ifdef HPUX_10_TRUSTED
1170 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
1171 if (pr_pw && pr_pw->ufld.fd_encrypt)
1172 pass->pw_passwd = pr_pw->ufld.fd_encrypt;
1178 struct pr_passwd *mypasswd;
1179 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user));
1180 mypasswd = getprpwnam (user);
1183 strcpy(pass->pw_name,mypasswd->ufld.fd_name);
1184 strcpy(pass->pw_passwd,mypasswd->ufld.fd_encrypt);
1188 DEBUG(5,("No entry for user %s in protected database !\n",user));
1196 AUTHORIZATION *ap = getauthuid( pass->pw_uid );
1199 strcpy( pass->pw_passwd, ap->a_password );
1205 /* extract relevant info */
1206 strcpy(this_user,pass->pw_name);
1207 strcpy(this_salt,pass->pw_passwd);
1209 /* The crypt on HPUX won't work with more than 2 salt characters. */
1212 strcpy(this_crypted,pass->pw_passwd);
1214 if (!*this_crypted) {
1215 if (!lp_null_passwords()) {
1216 DEBUG(2,("Disallowing access to %s due to null password\n",this_user));
1221 DEBUG(3,("Allowing access to %s with null password\n",this_user));
1227 /* try it as it came to us */
1228 if (password_check(password))
1230 update_protected_database(user,True);
1234 /* if the password was given to us with mixed case then we don't
1235 need to proceed as we know it hasn't been case modified by the
1237 if (strhasupper(password) && strhaslower(password))
1240 /* make a copy of it */
1241 StrnCpy(pass2,password,sizeof(pstring)-1);
1243 /* try all lowercase */
1245 if (password_check(password))
1247 update_protected_database(user,True);
1254 update_protected_database(user,False);
1257 strcpy(password,pass2);
1262 /* last chance - all combinations of up to level chars upper! */
1265 if (string_combinations(password,password_check,level))
1267 update_protected_database(user,True);
1271 update_protected_database(user,False);
1274 strcpy(password,pass2);
1281 /****************************************************************************
1282 check if a username is valid
1283 ****************************************************************************/
1284 BOOL user_ok(char *user,int snum)
1286 pstring valid, invalid;
1289 StrnCpy(valid, lp_valid_users(snum), sizeof(pstring));
1290 StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring));
1292 string_sub(valid,"%S",lp_servicename(snum));
1293 string_sub(invalid,"%S",lp_servicename(snum));
1295 ret = !user_in_list(user,invalid);
1297 if (ret && valid && *valid)
1298 ret = user_in_list(user,valid);
1300 if (ret && lp_onlyuser(snum)) {
1301 char *user_list = lp_username(snum);
1302 string_sub(user_list,"%S",lp_servicename(snum));
1303 ret = user_in_list(user,user_list);
1312 /****************************************************************************
1313 validate a group username entry. Return the username or NULL
1314 ****************************************************************************/
1315 static char *validate_group(char *group,char *password,int pwlen,int snum)
1319 char *host, *user, *domain;
1321 while (getnetgrent(&host, &user, &domain)) {
1323 if (user_ok(user, snum) &&
1324 password_ok(user,password,pwlen,NULL)) {
1336 struct group *gptr = (struct group *)getgrnam(group);
1340 member = gptr->gr_mem;
1341 while (member && *member)
1343 static fstring name;
1344 strcpy(name,*member);
1345 if (user_ok(name,snum) &&
1346 password_ok(name,password,pwlen,NULL))
1350 #ifdef GROUP_CHECK_PWENT
1356 while (pwd = getpwent ()) {
1357 if (*(pwd->pw_passwd) && pwd->pw_gid == gptr->gr_gid) {
1358 /* This Entry have PASSWORD and same GID then check pwd */
1359 if (password_ok(NULL, password, pwlen, pwd)) {
1360 strcpy(tm, pwd->pw_name);
1368 #endif /* GROUP_CHECK_PWENT */
1377 /****************************************************************************
1378 check for authority to login to a service with a given username/password
1379 ****************************************************************************/
1380 BOOL authorise_login(int snum,char *user,char *password, int pwlen,
1381 BOOL *guest,BOOL *force,uint16 vuid)
1388 DEBUG(100,("checking authorisation on user=%s pass=%s\n",user,password));
1391 /* there are several possibilities:
1392 1) login as the given user with given password
1393 2) login as a previously registered username with the given password
1394 3) login as a session list username with the given password
1395 4) login as a previously validated user/password pair
1396 5) login as the "user =" user with given password
1397 6) login as the "user =" user with no password (guest connection)
1398 7) login as guest user with no password
1400 if the service is guest_only then steps 1 to 5 are skipped
1403 if (GUEST_ONLY(snum)) *force = True;
1405 if (!(GUEST_ONLY(snum) && GUEST_OK(snum)))
1408 user_struct *vuser = get_valid_user_struct(vuid);
1410 /* check the given username and password */
1411 if (!ok && (*user) && user_ok(user,snum)) {
1412 ok = password_ok(user,password, pwlen, NULL);
1413 if (ok) DEBUG(3,("ACCEPTED: given username password ok\n"));
1416 /* check for a previously registered guest username */
1417 if (!ok && (vuser != 0) && vuser->guest) {
1418 if (user_ok(vuser->name,snum) &&
1419 password_ok(vuser->name, password, pwlen, NULL)) {
1420 strcpy(user, vuser->name);
1421 vuser->guest = False;
1422 DEBUG(3,("ACCEPTED: given password with registered user %s\n", user));
1428 /* now check the list of session users */
1432 char *user_list = strdup(session_users);
1433 if (!user_list) return(False);
1435 for (auser=strtok(user_list,LIST_SEP);
1437 auser = strtok(NULL,LIST_SEP))
1440 strcpy(user2,auser);
1441 if (!user_ok(user2,snum)) continue;
1443 if (password_ok(user2,password, pwlen, NULL)) {
1446 DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
1452 /* check for a previously validated username/password pair */
1453 if (!ok && !lp_revalidate(snum) &&
1454 (vuser != 0) && !vuser->guest &&
1455 user_ok(vuser->name,snum)) {
1456 strcpy(user,vuser->name);
1458 DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
1462 /* check for a rhosts entry */
1463 if (!ok && user_ok(user,snum) && check_hosts_equiv(user)) {
1465 DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
1468 /* check the user= fields and the given password */
1469 if (!ok && lp_username(snum)) {
1472 StrnCpy(user_list,lp_username(snum),sizeof(pstring));
1474 string_sub(user_list,"%S",lp_servicename(snum));
1476 for (auser=strtok(user_list,LIST_SEP);
1478 auser = strtok(NULL,LIST_SEP))
1482 auser = validate_group(auser+1,password,pwlen,snum);
1487 DEBUG(3,("ACCEPTED: group username and given password ok\n"));
1493 strcpy(user2,auser);
1494 if (user_ok(user2,snum) &&
1495 password_ok(user2,password,pwlen,NULL))
1499 DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
1504 } /* not guest only */
1506 /* check for a normal guest connection */
1507 if (!ok && GUEST_OK(snum))
1510 StrnCpy(guestname,lp_guestaccount(snum),sizeof(guestname)-1);
1511 if (Get_Pwnam(guestname,True))
1513 strcpy(user,guestname);
1515 DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
1518 DEBUG(0,("Invalid guest account %s??\n",guestname));
1523 if (ok && !user_ok(user,snum))
1525 DEBUG(0,("rejected invalid user %s\n",user));
1533 /****************************************************************************
1534 read the a hosts.equiv or .rhosts file and check if it
1535 allows this user from this machine
1536 ****************************************************************************/
1537 static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
1540 int plus_allowed = 1;
1543 FILE *fp = fopen(equiv_file, "r");
1544 DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
1545 if (! fp) return False;
1546 while(fgets(buf, sizeof(buf), fp))
1548 trim_string(buf," "," ");
1550 if (buf[0] != '#' && buf[0] != '\n')
1552 BOOL is_group = False;
1555 if (strcmp(buf, "NO_PLUS\n") == 0)
1557 DEBUG(6, ("check_user_equiv NO_PLUS\n"));
1564 if (*bp == '\n' && plus_allowed)
1566 /* a bare plus means everbody allowed */
1567 DEBUG(6, ("check_user_equiv everybody allowed\n"));
1572 else if (buf[0] == '-')
1582 file_host = strtok(bp, " \t\n");
1583 file_user = strtok(NULL, " \t\n");
1584 DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)",
1585 file_user ? file_user : "(null)" ));
1586 if (file_host && *file_host)
1588 BOOL host_ok = False;
1593 static char *mydomain = NULL;
1595 yp_get_default_domain(&mydomain);
1596 if (mydomain && innetgr(file_host,remote,user,mydomain))
1602 DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n"));
1607 /* is it this host */
1608 /* the fact that remote has come from a call of gethostbyaddr
1609 * means that it may have the fully qualified domain name
1610 * so we could look up the file version to get it into
1611 * a canonical form, but I would rather just type it
1612 * in full in the equiv file
1614 if (!host_ok && !is_group && strequal(remote, file_host))
1620 /* is it this user */
1621 if (file_user == 0 || strequal(user, file_user))
1624 DEBUG(5, ("check_user_equiv matched %s%s %s\n",
1625 (plus ? "+" : "-"), file_host,
1626 (file_user ? file_user : "")));
1627 return (plus ? True : False);
1638 /****************************************************************************
1639 check for a possible hosts equiv or rhosts entry for the user
1640 ****************************************************************************/
1641 BOOL check_hosts_equiv(char *user)
1645 struct passwd *pass = Get_Pwnam(user,True);
1650 fname = lp_hosts_equiv();
1652 /* note: don't allow hosts.equiv on root */
1653 if (fname && *fname && (pass->pw_uid != 0)) {
1655 if (check_user_equiv(user,client_name(Client),fname))
1659 if (lp_use_rhosts())
1661 char *home = get_home_dir(user);
1664 sprintf(rhostsfile, "%s/.rhosts", home);
1665 if (check_user_equiv(user,client_name(Client),rhostsfile))
1674 static struct cli_state cli;
1676 /****************************************************************************
1677 return the client state structure
1678 ****************************************************************************/
1679 struct cli_state *server_client(void)
1684 /****************************************************************************
1685 support for server level security
1686 ****************************************************************************/
1687 struct cli_state *server_cryptkey(void)
1690 struct in_addr dest_ip;
1691 extern fstring local_machine;
1694 if (!cli_initialise(&cli))
1697 for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) {
1698 fstrcpy(desthost,p);
1699 standard_sub_basic(desthost);
1702 if(!resolve_name( desthost, &dest_ip)) {
1703 DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",p));
1707 if (ismyip(dest_ip)) {
1708 DEBUG(1,("Password server loop - disabling password server %s\n",p));
1712 if (cli_connect(&cli, desthost, &dest_ip)) {
1713 DEBUG(3,("connected to password server %s\n",p));
1719 DEBUG(1,("password server not available\n"));
1724 if (!cli_session_request(&cli, desthost, 0x20, local_machine)) {
1725 DEBUG(1,("%s rejected the session\n",desthost));
1730 DEBUG(3,("got session\n"));
1732 if (!cli_negprot(&cli)) {
1733 DEBUG(1,("%s rejected the negprot\n",desthost));
1738 if (cli.protocol < PROTOCOL_LANMAN2 ||
1739 !(cli.sec_mode & 1)) {
1740 DEBUG(1,("%s isn't in user level security mode\n",desthost));
1745 DEBUG(3,("password server OK\n"));
1750 /****************************************************************************
1751 validate a password with the password server
1752 ****************************************************************************/
1753 BOOL server_validate(char *user, char *domain,
1754 char *pass, int passlen,
1755 char *ntpass, int ntpasslen)
1757 extern fstring local_machine;
1759 if (!cli.initialised) {
1760 DEBUG(1,("password server %s is not connected\n", cli.desthost));
1764 if (!cli_session_setup(&cli, user, pass, passlen, ntpass, ntpasslen, domain)) {
1765 DEBUG(1,("password server %s rejected the password\n", cli.desthost));
1769 /* if logged in as guest then reject */
1770 if ((SVAL(cli.inbuf,smb_vwv2) & 1) != 0) {
1771 DEBUG(1,("password server %s gave us guest only\n", cli.desthost));
1777 if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
1778 DEBUG(1,("password server %s refused IPC$ connect\n", cli.desthost));
1784 * This patch from Rob Nielsen <ran@adc.com> makes doing
1785 * the NetWksaUserLogon a dynamic, rather than compile-time
1786 * parameter, defaulting to on. This is somewhat dangerous
1787 * as it allows people to turn off this neccessary check,
1788 * but so many people have had problems with this that I
1789 * think it is a neccessary change. JRA.
1792 if (lp_net_wksta_user_logon()) {
1793 DEBUG(3,("trying NetWkstaUserLogon with password server %s\n", cli.desthost));
1794 if (!cli_NetWkstaUserLogon(&cli,user,local_machine)) {
1795 DEBUG(1,("password server %s failed NetWkstaUserLogon\n", cli.desthost));
1801 if (cli.privilages == 0) {
1802 DEBUG(1,("password server %s gave guest privilages\n", cli.desthost));
1808 if (!strequal(cli.eff_name, user)) {
1809 DEBUG(1,("password server %s gave different username %s\n",
1818 DEBUG(3,("skipping NetWkstaUserLogon with password server %s\n", cli.desthost));
1821 DEBUG(3,("password server %s accepted the password\n", cli.desthost));