syncing with release branch (includes trans2 fixes)
[Samba.git] / source / smbd / password.c
blobc82f58377c6f4e2c72c918b6436d70cfab3b77b3
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
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.
22 #include "includes.h"
24 extern int Protocol;
26 /* users from session setup */
27 static pstring session_users="";
29 extern pstring global_myname;
30 extern fstring global_myworkgroup;
32 /*
33 * track the machine trust account password timeout when
34 * in domain mode security
35 */
36 BOOL global_machine_password_needs_changing = False;
38 /* Data to do lanman1/2 password challenge. */
39 static unsigned char saved_challenge[8];
40 static BOOL challenge_sent=False;
42 /*******************************************************************
43 Get the next challenge value - no repeats.
44 ********************************************************************/
46 void generate_next_challenge(char *challenge)
48 unsigned char buf[8];
50 generate_random_buffer(buf,8,False);
52 memcpy(saved_challenge, buf, 8);
53 memcpy(challenge,buf,8);
54 challenge_sent = True;
57 /*******************************************************************
58 Set the last challenge sent, usually from a password server.
59 ********************************************************************/
61 BOOL set_challenge(unsigned char *challenge)
63 memcpy(saved_challenge,challenge,8);
64 challenge_sent = True;
65 return(True);
68 /*******************************************************************
69 Get the last challenge sent.
70 ********************************************************************/
72 static BOOL last_challenge(unsigned char *challenge)
74 if (!challenge_sent)
75 return(False);
76 memcpy(challenge,saved_challenge,8);
77 return(True);
80 /* this holds info on user ids that are already validated for this VC */
81 static user_struct *validated_users;
82 static int next_vuid = VUID_OFFSET;
83 static int num_validated_vuids;
85 /****************************************************************************
86 Check if a uid has been validated, and return an pointer to the user_struct
87 if it has. NULL if not. vuid is biased by an offset. This allows us to
88 tell random client vuid's (normally zero) from valid vuids.
89 ****************************************************************************/
91 user_struct *get_valid_user_struct(uint16 vuid)
93 user_struct *usp;
94 int count=0;
96 if (vuid == UID_FIELD_INVALID)
97 return NULL;
99 for (usp=validated_users;usp;usp=usp->next,count++) {
100 if (vuid == usp->vuid) {
101 if (count > 10) {
102 DLIST_PROMOTE(validated_users, usp);
104 return usp;
108 return NULL;
111 /****************************************************************************
112 Invalidate a uid.
113 ****************************************************************************/
115 void invalidate_vuid(uint16 vuid)
117 user_struct *vuser = get_valid_user_struct(vuid);
119 if (vuser == NULL)
120 return;
122 session_yield(vuid);
124 DLIST_REMOVE(validated_users, vuser);
126 SAFE_FREE(vuser->groups);
127 delete_nt_token(&vuser->nt_user_token);
128 safe_free(vuser);
129 num_validated_vuids--;
132 /****************************************************************************
133 Invalidate all vuid entries for this process.
134 ****************************************************************************/
136 void invalidate_all_vuids(void)
138 user_struct *usp, *next=NULL;
140 for (usp=validated_users;usp;usp=next) {
141 next = usp->next;
143 invalidate_vuid(usp->vuid);
147 /****************************************************************************
148 Return a validated username.
149 ****************************************************************************/
151 char *validated_username(uint16 vuid)
153 user_struct *vuser = get_valid_user_struct(vuid);
154 if (vuser == NULL)
155 return 0;
156 return(vuser->user.unix_name);
159 /****************************************************************************
160 Return a validated domain.
161 ****************************************************************************/
163 char *validated_domain(uint16 vuid)
165 user_struct *vuser = get_valid_user_struct(vuid);
166 if (vuser == NULL)
167 return 0;
168 return(vuser->user.domain);
171 /****************************************************************************
172 Create the SID list for this user.
173 ****************************************************************************/
175 NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups, BOOL is_guest, NT_USER_TOKEN *sup_tok)
177 extern DOM_SID global_sid_World;
178 extern DOM_SID global_sid_Network;
179 extern DOM_SID global_sid_Builtin_Guests;
180 extern DOM_SID global_sid_Authenticated_Users;
181 NT_USER_TOKEN *token;
182 DOM_SID *psids;
183 int i, psid_ndx = 0;
184 size_t num_sids = 0;
185 fstring sid_str;
187 if ((token = (NT_USER_TOKEN *)malloc( sizeof(NT_USER_TOKEN) ) ) == NULL)
188 return NULL;
190 ZERO_STRUCTP(token);
192 /* We always have uid/gid plus World and Network and Authenticated Users or Guest SIDs. */
193 num_sids = 5 + ngroups;
195 if (sup_tok && sup_tok->num_sids)
196 num_sids += sup_tok->num_sids;
198 if ((token->user_sids = (DOM_SID *)malloc( num_sids*sizeof(DOM_SID))) == NULL) {
199 SAFE_FREE(token);
200 return NULL;
203 psids = token->user_sids;
206 * Note - user SID *MUST* be first in token !
207 * se_access_check depends on this.
210 uid_to_sid( &psids[PRIMARY_USER_SID_INDEX], uid);
211 psid_ndx++;
214 * Primary group SID is second in token. Convention.
217 gid_to_sid( &psids[PRIMARY_GROUP_SID_INDEX], gid);
218 psid_ndx++;
220 /* Now add the group SIDs. */
222 for (i = 0; i < ngroups; i++) {
223 if (groups[i] != gid) {
224 gid_to_sid( &psids[psid_ndx++], groups[i]);
228 /* Now add the additional SIDs from the supplimentary token. */
229 if (sup_tok) {
230 for (i = 0; i < sup_tok->num_sids; i++)
231 sid_copy( &psids[psid_ndx++], &sup_tok->user_sids[i] );
235 * Finally add the "standard" SIDs.
236 * The only difference between guest and "anonymous" (which we
237 * don't really support) is the addition of Authenticated_Users.
240 sid_copy( &psids[psid_ndx++], &global_sid_World);
241 sid_copy( &psids[psid_ndx++], &global_sid_Network);
243 if (is_guest)
244 sid_copy( &psids[psid_ndx++], &global_sid_Builtin_Guests);
245 else
246 sid_copy( &psids[psid_ndx++], &global_sid_Authenticated_Users);
248 token->num_sids = psid_ndx;
250 /* Dump list of sids in token */
252 for (i = 0; i < token->num_sids; i++) {
253 DEBUG(5, ("user token sid %s\n",
254 sid_to_string(sid_str, &token->user_sids[i])));
257 return token;
260 /****************************************************************************
261 Register a uid/name pair as being valid and that a valid password
262 has been given. vuid is biased by an offset. This allows us to
263 tell random client vuid's (normally zero) from valid vuids.
264 ****************************************************************************/
266 int register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name,
267 char *domain,BOOL guest, NT_USER_TOKEN **pptok)
269 user_struct *vuser = NULL;
270 struct passwd *pwfile; /* for getting real name from passwd file */
272 /* Ensure no vuid gets registered in share level security. */
273 if(lp_security() == SEC_SHARE)
274 return UID_FIELD_INVALID;
276 /* Limit allowed vuids to 16bits - VUID_OFFSET. */
277 if (num_validated_vuids >= 0xFFFF-VUID_OFFSET)
278 return UID_FIELD_INVALID;
280 if((vuser = (user_struct *)malloc( sizeof(user_struct) )) == NULL) {
281 DEBUG(0,("Failed to malloc users struct!\n"));
282 return UID_FIELD_INVALID;
285 ZERO_STRUCTP(vuser);
287 DEBUG(10,("register_vuid: (%u,%u) %s %s %s guest=%d\n", (unsigned int)uid, (unsigned int)gid,
288 unix_name, requested_name, domain, guest ));
290 /* Allocate a free vuid. Yes this is a linear search... :-) */
291 while( get_valid_user_struct(next_vuid) != NULL ) {
292 next_vuid++;
293 /* Check for vuid wrap. */
294 if (next_vuid == UID_FIELD_INVALID)
295 next_vuid = VUID_OFFSET;
298 DEBUG(10,("register_vuid: allocated vuid = %u\n", (unsigned int)next_vuid ));
300 vuser->vuid = next_vuid;
301 vuser->uid = uid;
302 vuser->gid = gid;
303 vuser->guest = guest;
304 fstrcpy(vuser->user.unix_name,unix_name);
305 fstrcpy(vuser->user.smb_name,requested_name);
306 fstrcpy(vuser->user.domain,domain);
308 vuser->n_groups = 0;
309 vuser->groups = NULL;
311 /* Find all the groups this uid is in and store them.
312 Used by change_to_user() */
313 initialise_groups(unix_name, uid, gid);
314 get_current_groups( vuser->gid, &vuser->n_groups, &vuser->groups);
316 #ifdef HAVE_GETGROUPS_TOO_MANY_EGIDS
318 * Under OSes to which this applies, we get GID 0 as the first
319 * element of vuser->groups, so we put GID back in there.
320 * It is ignored by setgroups
322 if (vuser->n_groups) vuser->groups[0] = gid;
323 #endif /* HAVE_GETGROUPS_TOO_MANY_EGIDS */
325 if (*pptok)
326 add_supplementary_nt_login_groups(&vuser->n_groups, &vuser->groups, pptok);
328 /* Create an NT_USER_TOKEN struct for this user. */
329 vuser->nt_user_token = create_nt_token(uid,gid, vuser->n_groups, vuser->groups, guest, *pptok);
331 next_vuid++;
332 num_validated_vuids++;
334 DLIST_ADD(validated_users, vuser);
336 DEBUG(3,("uid %d registered to name %s\n",(int)uid,unix_name));
338 DEBUG(3, ("Clearing default real name\n"));
339 if ((pwfile=sys_getpwnam(vuser->user.unix_name))!= NULL) {
340 DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->user.unix_name,pwfile->pw_gecos));
341 fstrcpy(vuser->user.full_name, pwfile->pw_gecos);
344 if (!session_claim(vuser->vuid)) {
345 DEBUG(1,("Failed to claim session for vuid=%d\n", vuser->vuid));
346 invalidate_vuid(vuser->vuid);
347 return -1;
350 return vuser->vuid;
353 /****************************************************************************
354 Add a name to the session users list.
355 ****************************************************************************/
357 void add_session_user(char *user)
359 fstring suser;
360 StrnCpy(suser,user,sizeof(suser)-1);
362 if (!Get_Pwnam(suser,True))
363 return;
365 if (suser && *suser && !in_list(suser,session_users,False)) {
366 if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring))
367 DEBUG(1,("Too many session users??\n"));
368 else {
369 pstrcat(session_users," ");
370 pstrcat(session_users,suser);
375 /****************************************************************************
376 Update the encrypted smbpasswd file from the plaintext username and password.
377 *****************************************************************************/
379 static BOOL update_smbpassword_file(char *user, char *password)
381 SAM_ACCOUNT *sampass = NULL;
382 BOOL ret;
384 pdb_init_sam(&sampass);
386 become_root();
387 ret = pdb_getsampwnam(sampass, user);
388 unbecome_root();
390 if(!ret) {
391 DEBUG(0,("update_smbpassword_file: pdb_getsampwnam failed to locate %s\n", user));
392 return False;
396 * Remove the account disabled flag - we are updating the
397 * users password from a login.
399 pdb_set_acct_ctrl(sampass, pdb_get_acct_ctrl(sampass) & ~ACB_DISABLED);
401 /* Here, the flag is one, because we want to ignore the
402 XXXXXXX'd out password */
403 ret = change_oem_password( sampass, password, True);
404 if (ret == False) {
405 DEBUG(3,("change_oem_password returned False\n"));
408 if (sampass)
409 pdb_free_sam(sampass);
411 return ret;
414 /****************************************************************************
415 Core of smb password checking routine.
416 ****************************************************************************/
418 BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8)
420 /* Finish the encryption of part_passwd. */
421 unsigned char p21[21];
422 unsigned char p24[24];
424 if (part_passwd == NULL)
425 DEBUG(10,("No password set - allowing access\n"));
427 /* No password set - always true ! */
428 if (part_passwd == NULL)
429 return True;
431 memset(p21,'\0',21);
432 memcpy(p21,part_passwd,16);
433 E_P24(p21, c8, p24);
434 #if DEBUG_PASSWORD
436 int i;
437 DEBUG(100,("Part password (P16) was |"));
438 for(i = 0; i < 16; i++)
439 DEBUG(100,("%X ", (unsigned char)part_passwd[i]));
440 DEBUG(100,("|\n"));
441 DEBUG(100,("Password from client was |"));
442 for(i = 0; i < 24; i++)
443 DEBUG(100,("%X ", (unsigned char)password[i]));
444 DEBUG(100,("|\n"));
445 DEBUG(100,("Given challenge was |"));
446 for(i = 0; i < 8; i++)
447 DEBUG(100,("%X ", (unsigned char)c8[i]));
448 DEBUG(100,("|\n"));
449 DEBUG(100,("Value from encryption was |"));
450 for(i = 0; i < 24; i++)
451 DEBUG(100,("%X ", (unsigned char)p24[i]));
452 DEBUG(100,("|\n"));
454 #endif
455 return (memcmp(p24, password, 24) == 0);
458 /****************************************************************************
459 Do a specific test for an smb password being correct, given a smb_password and
460 the lanman and NT responses.
461 ****************************************************************************/
463 BOOL smb_password_ok(SAM_ACCOUNT *sampass, uchar chal[8],
464 uchar lm_pass[24], uchar nt_pass[24])
466 uchar challenge[8];
467 char* user_name;
468 uint8 *nt_pw, *lm_pw;
470 if (!lm_pass || !sampass)
471 return(False);
473 user_name = pdb_get_username(sampass);
475 DEBUG(4,("smb_password_ok: Checking SMB password for user %s\n",user_name));
477 if(pdb_get_acct_ctrl(sampass) & ACB_DISABLED) {
478 DEBUG(1,("smb_password_ok: account for user %s was disabled.\n", user_name));
479 return(False);
482 if (chal == NULL) {
483 DEBUG(5,("smb_password_ok: use last SMBnegprot challenge\n"));
484 if (!last_challenge(challenge)) {
485 DEBUG(1,("smb_password_ok: no challenge done - password failed\n"));
486 return False;
488 } else {
489 DEBUG(5,("smb_password_ok: challenge received\n"));
490 memcpy(challenge, chal, 8);
493 nt_pw = pdb_get_nt_passwd(sampass);
495 if ((Protocol >= PROTOCOL_NT1) && (nt_pw != NULL)) {
496 /* We have the NT MD4 hash challenge available - see if we can
497 use it (ie. does it exist in the smbpasswd file).
499 DEBUG(4,("smb_password_ok: Checking NT MD4 password\n"));
500 if (smb_password_check((char *)nt_pass, (uchar *)nt_pw, challenge)) {
501 DEBUG(4,("smb_password_ok: NT MD4 password check succeeded\n"));
502 return(True);
504 DEBUG(4,("smb_password_ok: NT MD4 password check failed\n"));
507 /* Try against the lanman password. pdb_get_lanman_passwd(sampass) == NULL
508 means no password, allow access. */
510 lm_pw = pdb_get_lanman_passwd(sampass);
512 if((lm_pw == NULL) && (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ)) {
513 DEBUG(4,("smb_password_ok: no password required for user %s\n",user_name));
514 return True;
517 if(lp_lanman_auth() && (lm_pw != NULL)) {
518 DEBUG(4,("smb_password_ok: Checking LM password\n"));
519 if(smb_password_check((char *)lm_pass,(uchar *)lm_pw, challenge)) {
520 DEBUG(4,("smb_password_ok: LM password check succeeded\n"));
521 return(True);
523 DEBUG(4,("smb_password_ok: LM password check failed\n"));
526 return False;
529 /****************************************************************************
530 Check if a username/password is OK assuming the password is a 24 byte
531 SMB hash. Return True if the password is correct, False otherwise.
532 ****************************************************************************/
534 BOOL pass_check_smb(char *user, char *domain, uchar *chal,
535 uchar *lm_pwd, uchar *nt_pwd, struct passwd *pwd)
537 SAM_ACCOUNT *sampass = NULL;
539 if (!lm_pwd || !nt_pwd)
540 return(False);
542 /* get the account information */
543 pdb_init_sam(&sampass);
544 if (!pdb_getsampwnam(sampass, user)) {
545 DEBUG(1,("Couldn't find user '%s' in passdb.\n", user));
546 pdb_free_sam(sampass);
547 return(False);
550 /* Quit if the account was disabled. */
551 if(pdb_get_acct_ctrl(sampass) & ACB_DISABLED) {
552 DEBUG(1,("Account for user '%s' was disabled.\n", user));
553 pdb_free_sam(sampass);
554 return(False);
558 if (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ) {
559 if (lp_null_passwords()) {
560 DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", user));
561 pdb_free_sam(sampass);
562 return(True);
563 } else {
564 DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", user));
565 pdb_free_sam(sampass);
566 return(False);
570 if (smb_password_ok(sampass, chal, lm_pwd, nt_pwd)) {
571 pdb_free_sam(sampass);
572 return(True);
575 DEBUG(2,("pass_check_smb failed - invalid password for user [%s]\n", user));
577 pdb_free_sam(sampass);
578 return False;
581 /****************************************************************************
582 Check if a username/password pair is OK either via the system password
583 database or the encrypted SMB password database
584 return True if the password is correct, False otherwise.
585 ****************************************************************************/
587 BOOL password_ok(char *user, char *password, int pwlen, struct passwd *pwd)
590 BOOL ret;
592 if ((pwlen == 0) && !lp_null_passwords()) {
593 DEBUG(4,("Null passwords not allowed.\n"));
594 return False;
597 if (pwlen == 24 || (lp_encrypted_passwords() && (pwlen == 0) && lp_null_passwords())) {
598 /* if 24 bytes long assume it is an encrypted password */
599 uchar challenge[8];
601 if (!last_challenge(challenge)) {
602 DEBUG(0,("Error: challenge not done for user=%s\n", user));
603 return False;
606 ret = pass_check_smb(user, global_myworkgroup,
607 challenge, (uchar *)password, (uchar *)password, pwd);
610 * Try with PAM (may not be compiled in - returns True if not. JRA).
611 * FIXME ! Should this be called if we're using winbindd ? What about
612 * non-local accounts ? JRA.
615 if (ret)
616 return (NT_STATUS_V(smb_pam_accountcheck(user)) == NT_STATUS_V(NT_STATUS_OK));
618 return ret;
621 return (pass_check(user, password, pwlen, pwd,
622 lp_update_encrypted() ?
623 update_smbpassword_file : NULL));
626 /****************************************************************************
627 Check if a username is valid
628 ****************************************************************************/
630 BOOL user_ok(char *user,int snum)
632 pstring valid, invalid;
633 BOOL ret;
635 StrnCpy(valid, lp_valid_users(snum), sizeof(pstring)-1);
636 StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring)-1);
638 pstring_sub(valid,"%S",lp_servicename(snum));
639 pstring_sub(invalid,"%S",lp_servicename(snum));
641 ret = !user_in_list(user,invalid);
643 if (ret && valid && *valid)
644 ret = user_in_list(user,valid);
646 if (ret && lp_onlyuser(snum)) {
647 char *user_list = lp_username(snum);
648 pstring_sub(user_list,"%S",lp_servicename(snum));
649 ret = user_in_list(user,user_list);
652 return(ret);
655 /****************************************************************************
656 Validate a group username entry. Return the username or NULL.
657 ****************************************************************************/
659 static char *validate_group(const char *group,char *password,int pwlen,int snum)
661 #ifdef HAVE_NETGROUP
663 char *host, *user, *domain;
664 setnetgrent(group);
665 while (getnetgrent(&host, &user, &domain)) {
666 if (user) {
667 if (user_ok(user, snum) &&
668 password_ok(user,password,pwlen,NULL)) {
669 endnetgrent();
670 return(user);
674 endnetgrent();
676 #endif
679 struct sys_userlist *user_list = get_users_in_group(group);
680 struct sys_userlist *member;
682 for (member = user_list; member; member = member->next) {
683 static fstring name;
684 fstrcpy(name,member->unix_name);
685 if (user_ok(name,snum) &&
686 password_ok(name,password,pwlen,NULL)) {
687 free_userlist(user_list);
688 return(&name[0]);
691 DEBUG(10,("validate_group = member = %s\n", member->unix_name));
693 free_userlist(user_list);
696 return(NULL);
699 /****************************************************************************
700 Check for authority to login to a service with a given username/password.
701 Note this is *NOT* used when logging on using sessionsetup_and_X.
702 ****************************************************************************/
704 BOOL authorise_login(int snum,char *user,char *password, int pwlen,
705 BOOL *guest,BOOL *force,uint16 vuid)
707 BOOL ok = False;
708 user_struct *vuser = get_valid_user_struct(vuid);
710 #if DEBUG_PASSWORD
711 DEBUG(100,("authorise_login: checking authorisation on user=%s pass=%s\n",
712 user,password));
713 #endif
715 *guest = False;
717 if (GUEST_ONLY(snum))
718 *force = True;
720 if (!GUEST_ONLY(snum) && (lp_security() > SEC_SHARE)) {
723 * We should just use the given vuid from a sessionsetup_and_X.
726 if (!vuser) {
727 DEBUG(1,("authorise_login: refusing user %s with no session setup\n",
728 user));
729 return False;
732 if (!vuser->guest && user_ok(vuser->user.unix_name,snum)) {
733 fstrcpy(user,vuser->user.unix_name);
734 *guest = False;
735 DEBUG(3,("authorise_login: ACCEPTED: validated uid ok as non-guest \
736 (user=%s)\n", user));
737 return True;
741 /* there are several possibilities:
742 1) login as the given user with given password
743 2) login as a previously registered username with the given password
744 3) login as a session list username with the given password
745 4) login as a previously validated user/password pair
746 5) login as the "user =" user with given password
747 6) login as the "user =" user with no password (guest connection)
748 7) login as guest user with no password
750 if the service is guest_only then steps 1 to 5 are skipped
753 if (!(GUEST_ONLY(snum) && GUEST_OK(snum))) {
754 /* check the given username and password */
755 if (!ok && (*user) && user_ok(user,snum)) {
756 ok = password_ok(user,password, pwlen, NULL);
757 if (ok)
758 DEBUG(3,("authorise_login: ACCEPTED: given username (%s) password ok\n",
759 user ));
762 /* check for a previously registered guest username */
763 if (!ok && (vuser != 0) && vuser->guest) {
764 if (user_ok(vuser->user.unix_name,snum) &&
765 password_ok(vuser->user.unix_name, password, pwlen, NULL)) {
766 fstrcpy(user, vuser->user.unix_name);
767 vuser->guest = False;
768 DEBUG(3,("authorise_login: ACCEPTED: given password with registered user %s\n", user));
769 ok = True;
773 /* now check the list of session users */
774 if (!ok) {
775 char *auser;
776 char *user_list = strdup(session_users);
777 if (!user_list)
778 return(False);
780 for (auser=strtok(user_list,LIST_SEP); !ok && auser;
781 auser = strtok(NULL,LIST_SEP)) {
782 fstring user2;
783 fstrcpy(user2,auser);
784 if (!user_ok(user2,snum))
785 continue;
787 if (password_ok(user2,password, pwlen, NULL)) {
788 ok = True;
789 fstrcpy(user,user2);
790 DEBUG(3,("authorise_login: ACCEPTED: session list username (%s) \
791 and given password ok\n", user));
795 SAFE_FREE(user_list);
798 /* check for a previously validated username/password pair */
799 if (!ok && (lp_security() > SEC_SHARE) && (vuser != 0) && !vuser->guest &&
800 user_ok(vuser->user.unix_name,snum)) {
801 fstrcpy(user,vuser->user.unix_name);
802 *guest = False;
803 DEBUG(3,("authorise_login: ACCEPTED: validated uid (%s) as non-guest\n",
804 user));
805 ok = True;
808 /* check for a rhosts entry */
809 if (!ok && user_ok(user,snum) && check_hosts_equiv(user)) {
810 ok = True;
811 DEBUG(3,("authorise_login: ACCEPTED: hosts equiv or rhosts entry for %s\n",
812 user));
815 /* check the user= fields and the given password */
816 if (!ok && lp_username(snum)) {
817 char *auser;
818 pstring user_list;
819 StrnCpy(user_list,lp_username(snum),sizeof(pstring)-1);
821 pstring_sub(user_list,"%S",lp_servicename(snum));
823 for (auser=strtok(user_list,LIST_SEP); auser && !ok;
824 auser = strtok(NULL,LIST_SEP)) {
825 if (*auser == '@') {
826 auser = validate_group(auser+1,password,pwlen,snum);
827 if (auser) {
828 ok = True;
829 fstrcpy(user,auser);
830 DEBUG(3,("authorise_login: ACCEPTED: group username \
831 and given password ok (%s)\n", user));
833 } else {
834 fstring user2;
835 fstrcpy(user2,auser);
836 if (user_ok(user2,snum) && password_ok(user2,password,pwlen,NULL)) {
837 ok = True;
838 fstrcpy(user,user2);
839 DEBUG(3,("authorise_login: ACCEPTED: user list username \
840 and given password ok (%s)\n", user));
845 } /* not guest only */
847 /* check for a normal guest connection */
848 if (!ok && GUEST_OK(snum)) {
849 fstring guestname;
850 StrnCpy(guestname,lp_guestaccount(snum),sizeof(guestname)-1);
851 if (Get_Pwnam(guestname,True)) {
852 fstrcpy(user,guestname);
853 ok = True;
854 DEBUG(3,("authorise_login: ACCEPTED: guest account and guest ok (%s)\n",
855 user));
856 } else {
857 DEBUG(0,("authorise_login: Invalid guest account %s??\n",guestname));
859 *guest = True;
862 if (ok && !user_ok(user,snum)) {
863 DEBUG(0,("authorise_login: rejected invalid user %s\n",user));
864 ok = False;
867 return(ok);
870 /****************************************************************************
871 Read the a hosts.equiv or .rhosts file and check if it
872 allows this user from this machine.
873 ****************************************************************************/
875 static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
877 int plus_allowed = 1;
878 char *file_host;
879 char *file_user;
880 char **lines = file_lines_load(equiv_file, NULL, False);
881 int i;
883 DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
885 if (! lines)
886 return False;
888 for (i=0; lines[i]; i++) {
889 char *buf = lines[i];
890 trim_string(buf," "," ");
892 if (buf[0] != '#' && buf[0] != '\n') {
893 BOOL is_group = False;
894 int plus = 1;
895 char *bp = buf;
896 if (strcmp(buf, "NO_PLUS\n") == 0) {
897 DEBUG(6, ("check_user_equiv NO_PLUS\n"));
898 plus_allowed = 0;
899 } else {
900 if (buf[0] == '+') {
901 bp++;
902 if (*bp == '\n' && plus_allowed) {
903 /* a bare plus means everbody allowed */
904 DEBUG(6, ("check_user_equiv everybody allowed\n"));
905 file_lines_free(lines);
906 return True;
908 } else if (buf[0] == '-') {
909 bp++;
910 plus = 0;
912 if (*bp == '@') {
913 is_group = True;
914 bp++;
916 file_host = strtok(bp, " \t\n");
917 file_user = strtok(NULL, " \t\n");
918 DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)",
919 file_user ? file_user : "(null)" ));
920 if (file_host && *file_host) {
921 BOOL host_ok = False;
923 #if defined(HAVE_NETGROUP) && defined(HAVE_YP_GET_DEFAULT_DOMAIN)
924 if (is_group) {
925 static char *mydomain = NULL;
926 if (!mydomain)
927 yp_get_default_domain(&mydomain);
928 if (mydomain && innetgr(file_host,remote,user,mydomain))
929 host_ok = True;
931 #else
932 if (is_group) {
933 DEBUG(1,("Netgroups not configured\n"));
934 continue;
936 #endif
938 /* is it this host */
939 /* the fact that remote has come from a call of gethostbyaddr
940 * means that it may have the fully qualified domain name
941 * so we could look up the file version to get it into
942 * a canonical form, but I would rather just type it
943 * in full in the equiv file
945 if (!host_ok && !is_group && strequal(remote, file_host))
946 host_ok = True;
948 if (!host_ok)
949 continue;
951 /* is it this user */
952 if (file_user == 0 || strequal(user, file_user)) {
953 DEBUG(5, ("check_user_equiv matched %s%s %s\n",
954 (plus ? "+" : "-"), file_host,
955 (file_user ? file_user : "")));
956 file_lines_free(lines);
957 return (plus ? True : False);
963 file_lines_free(lines);
964 return False;
967 /****************************************************************************
968 Check for a possible hosts equiv or rhosts entry for the user.
969 ****************************************************************************/
971 BOOL check_hosts_equiv(char *user)
973 char *fname = NULL;
974 pstring rhostsfile;
975 struct passwd *pass = Get_Pwnam(user,True);
977 if (!pass)
978 return(False);
980 fname = lp_hosts_equiv();
982 /* note: don't allow hosts.equiv on root */
983 if (fname && *fname && (pass->pw_uid != 0)) {
984 if (check_user_equiv(user,client_name(),fname))
985 return(True);
988 if (lp_use_rhosts()) {
989 char *home = get_user_service_home_dir(user);
990 if (home) {
991 slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home);
992 if (check_user_equiv(user,client_name(),rhostsfile))
993 return(True);
997 return(False);
1000 /****************************************************************************
1001 Return the client state structure.
1002 ****************************************************************************/
1004 struct cli_state *server_client(void)
1006 static struct cli_state pw_cli;
1007 return &pw_cli;
1010 /****************************************************************************
1011 Support for server level security.
1012 ****************************************************************************/
1014 struct cli_state *server_cryptkey(void)
1016 struct cli_state *cli;
1017 fstring desthost;
1018 struct in_addr dest_ip;
1019 char *pserver;
1020 const char *p;
1021 BOOL connected_ok = False;
1023 cli = server_client();
1025 if (!cli_initialise(cli))
1026 return NULL;
1028 pserver = strdup(lp_passwordserver());
1029 p = pserver;
1031 while(next_token( &p, desthost, LIST_SEP, sizeof(desthost))) {
1032 standard_sub_basic(desthost,sizeof(desthost));
1033 strupper(desthost);
1035 if(!resolve_name( desthost, &dest_ip, 0x20)) {
1036 DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost));
1037 continue;
1040 if (ismyip(dest_ip)) {
1041 DEBUG(1,("Password server loop - disabling password server %s\n",desthost));
1042 continue;
1045 if (cli_connect(cli, desthost, &dest_ip)) {
1046 DEBUG(3,("connected to password server %s\n",desthost));
1047 connected_ok = True;
1048 break;
1052 SAFE_FREE(pserver);
1054 if (!connected_ok) {
1055 DEBUG(0,("password server not available\n"));
1056 cli_shutdown(cli);
1057 return NULL;
1060 if (!attempt_netbios_session_request(cli, global_myname, desthost, &dest_ip)) {
1061 cli_shutdown(cli);
1062 return NULL;
1065 DEBUG(3,("got session\n"));
1067 if (!cli_negprot(cli)) {
1068 DEBUG(1,("%s rejected the negprot\n",desthost));
1069 cli_shutdown(cli);
1070 return NULL;
1073 if (cli->protocol < PROTOCOL_LANMAN2 ||
1074 !(cli->sec_mode & 1)) {
1075 DEBUG(1,("%s isn't in user level security mode\n",desthost));
1076 cli_shutdown(cli);
1077 return NULL;
1080 DEBUG(3,("password server OK\n"));
1082 return cli;
1085 /****************************************************************************
1086 Validate a password with the password server.
1087 ****************************************************************************/
1089 BOOL server_validate(char *user, char *domain,
1090 char *pass, int passlen,
1091 char *ntpass, int ntpasslen)
1093 struct cli_state *cli;
1094 static unsigned char badpass[24];
1095 static fstring baduser;
1096 static BOOL tested_password_server = False;
1097 static BOOL bad_password_server = False;
1099 cli = server_client();
1101 if (!cli->initialised) {
1102 DEBUG(1,("password server %s is not connected\n", cli->desthost));
1103 return(False);
1106 if(badpass[0] == 0)
1107 memset(badpass, 0x1f, sizeof(badpass));
1109 if((passlen == sizeof(badpass)) && !memcmp(badpass, pass, passlen)) {
1111 * Very unlikely, our random bad password is the same as the users
1112 * password.
1114 memset(badpass, badpass[0]+1, sizeof(badpass));
1117 if(baduser[0] == 0) {
1118 fstrcpy(baduser, INVALID_USER_PREFIX);
1119 fstrcat(baduser, global_myname);
1123 * Attempt a session setup with a totally incorrect password.
1124 * If this succeeds with the guest bit *NOT* set then the password
1125 * server is broken and is not correctly setting the guest bit. We
1126 * need to detect this as some versions of NT4.x are broken. JRA.
1129 if(!tested_password_server) {
1130 if (cli_session_setup(cli, baduser, (char *)badpass, sizeof(badpass),
1131 (char *)badpass, sizeof(badpass), domain)) {
1134 * We connected to the password server so we
1135 * can say we've tested it.
1137 tested_password_server = True;
1139 if ((SVAL(cli->inbuf,smb_vwv2) & 1) == 0) {
1140 DEBUG(0,("server_validate: password server %s allows users as non-guest \
1141 with a bad password.\n", cli->desthost));
1142 DEBUG(0,("server_validate: This is broken (and insecure) behaviour. Please do not \
1143 use this machine as the password server.\n"));
1144 cli_ulogoff(cli);
1147 * Password server has the bug.
1149 bad_password_server = True;
1150 return False;
1152 cli_ulogoff(cli);
1154 } else {
1157 * We have already tested the password server.
1158 * Fail immediately if it has the bug.
1161 if(bad_password_server) {
1162 DEBUG(0,("server_validate: [1] password server %s allows users as non-guest \
1163 with a bad password.\n", cli->desthost));
1164 DEBUG(0,("server_validate: [1] This is broken (and insecure) behaviour. Please do not \
1165 use this machine as the password server.\n"));
1166 return False;
1171 * Now we know the password server will correctly set the guest bit, or is
1172 * not guest enabled, we can try with the real password.
1175 if (!cli_session_setup(cli, user, pass, passlen, ntpass, ntpasslen, domain)) {
1176 DEBUG(1,("password server %s rejected the password\n", cli->desthost));
1177 return False;
1180 /* if logged in as guest then reject */
1181 if ((SVAL(cli->inbuf,smb_vwv2) & 1) != 0) {
1182 DEBUG(1,("password server %s gave us guest only\n", cli->desthost));
1183 cli_ulogoff(cli);
1184 return(False);
1187 cli_ulogoff(cli);
1189 return(True);
1192 static char *mutex_server_name;
1194 static BOOL grab_server_mutex(const char *name)
1196 mutex_server_name = strdup(name);
1197 if (!mutex_server_name) {
1198 DEBUG(0,("grab_server_mutex: malloc failed for %s\n", name));
1199 return False;
1201 if (!secrets_named_mutex(name, 10)) {
1202 DEBUG(10,("grab_server_mutex: failed for %s\n", name));
1203 SAFE_FREE(mutex_server_name);
1204 return False;
1207 return True;
1210 static void release_server_mutex(void)
1212 if (mutex_server_name) {
1213 secrets_named_mutex_release(mutex_server_name);
1214 SAFE_FREE(mutex_server_name);
1218 /***********************************************************************
1219 Connect to a remote machine for domain security authentication
1220 given a name or IP address.
1221 ************************************************************************/
1223 static BOOL connect_to_domain_password_server(struct cli_state **ppcli,
1224 char *server, unsigned char *trust_passwd)
1226 struct in_addr dest_ip;
1227 fstring remote_machine;
1228 struct cli_state *pcli = NULL;
1230 *ppcli = NULL;
1232 if(!(pcli = cli_initialise(NULL))) {
1233 DEBUG(0,("connect_to_domain_password_server: unable to initialize client connection.\n"));
1234 return False;
1237 if (is_ipaddress(server)) {
1238 struct in_addr to_ip;
1240 /* we shouldn't have 255.255.255.255 forthe IP address of a password server anyways */
1241 if ((to_ip.s_addr=inet_addr(server)) == 0xFFFFFFFF) {
1242 DEBUG (0,("connect_to_domain_password_server: inet_addr(%s) returned 0xFFFFFFFF!\n", server));
1243 cli_shutdown(pcli);
1244 return False;
1247 if (!name_status_find("*", 0, 0x20, to_ip, remote_machine)) {
1248 DEBUG(1, ("connect_to_domain_password_server: Can't " "resolve name for IP %s\n", server));
1249 cli_shutdown(pcli);
1250 return False;
1252 } else {
1253 fstrcpy(remote_machine, server);
1256 standard_sub_basic(remote_machine,sizeof(remote_machine));
1257 strupper(remote_machine);
1259 if(!resolve_name( remote_machine, &dest_ip, 0x20)) {
1260 DEBUG(1,("connect_to_domain_password_server: Can't resolve address for %s\n", remote_machine));
1261 cli_shutdown(pcli);
1262 return False;
1265 if (ismyip(dest_ip)) {
1266 DEBUG(1,("connect_to_domain_password_server: Password server loop - not using password server %s\n",
1267 remote_machine));
1268 cli_shutdown(pcli);
1269 return False;
1272 /* we use a mutex to prevent two connections at once - when a NT PDC gets
1273 two connections where one hasn't completed a negprot yet it will send a
1274 TCP reset to the first connection (tridge) */
1276 if (!grab_server_mutex(server)) {
1277 cli_shutdown(pcli);
1278 return False;
1281 if (!cli_connect(pcli, remote_machine, &dest_ip)) {
1282 DEBUG(0,("connect_to_domain_password_server: unable to connect to SMB server on \
1283 machine %s. Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
1284 cli_shutdown(pcli);
1285 release_server_mutex();
1286 return False;
1289 if (!attempt_netbios_session_request(pcli, global_myname, remote_machine, &dest_ip)) {
1290 DEBUG(0,("connect_to_password_server: machine %s rejected the NetBIOS \
1291 session request. Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
1292 cli_shutdown(pcli);
1293 release_server_mutex();
1294 return False;
1297 pcli->protocol = PROTOCOL_NT1;
1299 if (!cli_negprot(pcli)) {
1300 DEBUG(0,("connect_to_domain_password_server: machine %s rejected the negotiate protocol. \
1301 Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
1302 cli_shutdown(pcli);
1303 release_server_mutex();
1304 return False;
1307 if (pcli->protocol != PROTOCOL_NT1) {
1308 DEBUG(0,("connect_to_domain_password_server: machine %s didn't negotiate NT protocol.\n",
1309 remote_machine));
1310 cli_shutdown(pcli);
1311 release_server_mutex();
1312 return False;
1316 * Do an anonymous session setup.
1319 if (!cli_session_setup(pcli, "", "", 0, "", 0, "")) {
1320 DEBUG(0,("connect_to_domain_password_server: machine %s rejected the session setup. \
1321 Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
1322 cli_shutdown(pcli);
1323 release_server_mutex();
1324 return False;
1327 if (!(pcli->sec_mode & 1)) {
1328 DEBUG(1,("connect_to_domain_password_server: machine %s isn't in user level security mode\n",
1329 remote_machine));
1330 cli_shutdown(pcli);
1331 release_server_mutex();
1332 return False;
1335 if (!cli_send_tconX(pcli, "IPC$", "IPC", "", 1)) {
1336 DEBUG(0,("connect_to_domain_password_server: machine %s rejected the tconX on the IPC$ share. \
1337 Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
1338 cli_shutdown(pcli);
1339 release_server_mutex();
1340 return False;
1344 * We now have an anonymous connection to IPC$ on the domain password server.
1348 * Even if the connect succeeds we need to setup the netlogon
1349 * pipe here. We do this as we may just have changed the domain
1350 * account password on the PDC and yet we may be talking to
1351 * a BDC that doesn't have this replicated yet. In this case
1352 * a successful connect to a DC needs to take the netlogon connect
1353 * into account also. This patch from "Bjart Kvarme" <bjart.kvarme@usit.uio.no>.
1356 if(cli_nt_session_open(pcli, PIPE_NETLOGON) == False) {
1357 DEBUG(0,("connect_to_domain_password_server: unable to open the domain client session to \
1358 machine %s. Error was : %s.\n", remote_machine, cli_errstr(pcli)));
1359 cli_nt_session_close(pcli);
1360 cli_ulogoff(pcli);
1361 cli_shutdown(pcli);
1362 release_server_mutex();
1363 return False;
1366 if (!NT_STATUS_IS_OK(cli_nt_setup_creds(pcli, trust_passwd))) {
1367 DEBUG(0,("connect_to_domain_password_server: unable to setup the PDC credentials to machine \
1368 %s. Error was : %s.\n", remote_machine, cli_errstr(pcli)));
1369 cli_nt_session_close(pcli);
1370 cli_ulogoff(pcli);
1371 cli_shutdown(pcli);
1372 release_server_mutex();
1373 return(False);
1376 *ppcli = pcli;
1378 /* We exit here with the mutex *locked*. JRA */
1379 return True;
1382 /***********************************************************************
1383 Utility function to attempt a connection to an IP address of a DC.
1384 ************************************************************************/
1386 static BOOL attempt_connect_to_dc(struct cli_state **ppcli, struct in_addr *ip, unsigned char *trust_passwd)
1388 fstring dc_name;
1391 * Ignore addresses we have already tried.
1394 if (is_zero_ip(*ip))
1395 return False;
1397 if (!lookup_dc_name(global_myname, lp_workgroup(), ip, dc_name))
1398 return False;
1400 return connect_to_domain_password_server(ppcli, dc_name, trust_passwd);
1403 /***********************************************************************
1404 We have been asked to dynamcially determine the IP addresses of
1405 the PDC and BDC's for this DOMAIN, and query them in turn.
1406 ************************************************************************/
1408 static BOOL find_connect_pdc(struct cli_state **ppcli, unsigned char *trust_passwd, time_t last_change_time)
1410 struct in_addr *ip_list = NULL;
1411 int count = 0;
1412 int i;
1413 BOOL connected_ok = False;
1414 time_t time_now = time(NULL);
1415 BOOL use_pdc_only = False;
1418 * If the time the machine password has changed
1419 * was less than an hour ago then we need to contact
1420 * the PDC only, as we cannot be sure domain replication
1421 * has yet taken place. Bug found by Gerald (way to go
1422 * Gerald !). JRA.
1425 if (time_now - last_change_time < 3600)
1426 use_pdc_only = True;
1428 if (!get_dc_list(use_pdc_only, lp_workgroup(), &ip_list, &count))
1429 return False;
1432 * Firstly try and contact a PDC/BDC who has the same
1433 * network address as any of our interfaces.
1435 for(i = 0; i < count; i++) {
1436 if(!is_local_net(ip_list[i]))
1437 continue;
1439 if((connected_ok = attempt_connect_to_dc(ppcli, &ip_list[i], trust_passwd)))
1440 break;
1442 zero_ip(&ip_list[i]); /* Tried and failed. */
1446 * Secondly try and contact a random PDC/BDC.
1448 if(!connected_ok) {
1449 i = (sys_random() % count);
1451 if (!is_zero_ip(ip_list[i])) {
1452 if (!(connected_ok = attempt_connect_to_dc(ppcli, &ip_list[i], trust_passwd)))
1453 zero_ip(&ip_list[i]); /* Tried and failed. */
1458 * Finally go through the IP list in turn, ignoring any addresses
1459 * we have already tried.
1461 if(!connected_ok) {
1463 * Try and connect to any of the other IP addresses in the PDC/BDC list.
1464 * Note that from a WINS server the #1 IP address is the PDC.
1466 for(i = 0; i < count; i++) {
1467 if (is_zero_ip(ip_list[i]))
1468 continue;
1470 if((connected_ok = attempt_connect_to_dc(ppcli, &ip_list[i], trust_passwd)))
1471 break;
1475 SAFE_FREE(ip_list);
1476 return connected_ok;
1479 /***********************************************************************
1480 Do the same as security=server, but using NT Domain calls and a session
1481 key from the machine password.
1482 ************************************************************************/
1484 BOOL domain_client_validate( char *user, char *domain,
1485 char *smb_apasswd, int smb_apasslen,
1486 char *smb_ntpasswd, int smb_ntpasslen,
1487 BOOL *user_exists, NT_USER_TOKEN **pptoken)
1489 unsigned char local_challenge[8];
1490 unsigned char local_lm_response[24];
1491 unsigned char local_nt_response[24];
1492 unsigned char trust_passwd[16];
1493 fstring remote_machine;
1494 const char *p;
1495 const char *pserver;
1496 NET_ID_INFO_CTR ctr;
1497 NET_USER_INFO_3 info3;
1498 struct cli_state *pcli = NULL;
1499 uint32 smb_uid_low;
1500 BOOL connected_ok = False;
1501 time_t last_change_time;
1502 NTSTATUS status;
1504 if (pptoken)
1505 *pptoken = NULL;
1507 if(user_exists != NULL)
1508 *user_exists = True; /* Only set false on a very specific error. */
1511 * Check that the requested domain is not our own machine name.
1512 * If it is, we should never check the PDC here, we use our own local
1513 * password file.
1516 if(strequal( domain, global_myname)) {
1517 DEBUG(3,("domain_client_validate: Requested domain was for this machine.\n"));
1518 return False;
1522 * Next, check that the passwords given were encrypted.
1525 if(((smb_apasslen != 24) && (smb_apasslen != 0)) ||
1526 ((smb_ntpasslen != 24) && (smb_ntpasslen != 0))) {
1529 * Not encrypted - do so.
1532 DEBUG(3,("domain_client_validate: User passwords not in encrypted format.\n"));
1533 generate_random_buffer( local_challenge, 8, False);
1534 SMBencrypt( (uchar *)smb_apasswd, local_challenge, local_lm_response);
1535 SMBNTencrypt((uchar *)smb_ntpasswd, local_challenge, local_nt_response);
1536 smb_apasslen = 24;
1537 smb_ntpasslen = 24;
1538 smb_apasswd = (char *)local_lm_response;
1539 smb_ntpasswd = (char *)local_nt_response;
1540 } else {
1543 * Encrypted - get the challenge we sent for these
1544 * responses.
1547 if (!last_challenge(local_challenge)) {
1548 DEBUG(0,("domain_client_validate: no challenge done - password failed\n"));
1549 return False;
1554 * Get the machine account password for our primary domain
1557 if (!secrets_fetch_trust_account_password(global_myworkgroup, trust_passwd, &last_change_time)) {
1558 DEBUG(0, ("domain_client_validate: could not fetch trust account password for domain %s\n", global_myworkgroup));
1559 return False;
1562 /* Test if machine password is expired and need to be changed */
1563 if (lp_machine_password_timeout()) {
1564 if (time(NULL) > last_change_time + lp_machine_password_timeout()) {
1565 DEBUG(10,("domain_client_validate: machine account password needs changing. \
1566 Last change time = (%u) %s. Machine password timeout = %u seconds\n",
1567 (unsigned int)last_change_time, http_timestring(last_change_time),
1568 (unsigned int)lp_machine_password_timeout() ));
1569 global_machine_password_needs_changing = True;
1574 * At this point, smb_apasswd points to the lanman response to
1575 * the challenge in local_challenge, and smb_ntpasswd points to
1576 * the NT response to the challenge in local_challenge. Ship
1577 * these over the secure channel to a domain controller and
1578 * see if they were valid.
1582 * Treat each name in the 'password server =' line as a potential
1583 * PDC/BDC. Contact each in turn and try and authenticate.
1586 pserver = lp_passwordserver();
1587 if (! *pserver)
1588 pserver = "*";
1589 p = pserver;
1591 while (!connected_ok &&
1592 next_token(&p,remote_machine,LIST_SEP,sizeof(remote_machine))) {
1593 if(strequal(remote_machine, "*")) {
1594 connected_ok = find_connect_pdc(&pcli, trust_passwd, last_change_time);
1595 } else {
1596 connected_ok = connect_to_domain_password_server(&pcli, remote_machine, trust_passwd);
1600 if (!connected_ok) {
1601 DEBUG(0,("domain_client_validate: Domain password server not available.\n"));
1602 if (pcli)
1603 cli_shutdown(pcli);
1604 release_server_mutex();
1605 return False;
1608 /* We really don't care what LUID we give the user. */
1609 generate_random_buffer( (unsigned char *)&smb_uid_low, 4, False);
1611 ZERO_STRUCT(info3);
1613 status = cli_nt_login_network(pcli, domain, user, smb_uid_low, (char *)local_challenge,
1614 ((smb_apasslen != 0) ? smb_apasswd : NULL),
1615 ((smb_ntpasslen != 0) ? smb_ntpasswd : NULL),
1616 &ctr, &info3);
1618 if (!NT_STATUS_IS_OK(status)) {
1620 DEBUG(0,("domain_client_validate: unable to validate password for user %s in domain \
1621 %s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, get_nt_error_msg(status) ));
1622 cli_nt_session_close(pcli);
1623 cli_ulogoff(pcli);
1624 cli_shutdown(pcli);
1625 release_server_mutex();
1627 if((NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NO_SUCH_USER)) && (user_exists != NULL))
1628 *user_exists = False;
1630 return False;
1634 * Here, if we really want it, we have lots of info about the user in info3.
1637 /* Return group membership as returned by NT. This contains group
1638 membership in nested groups which doesn't seem to be accessible by any
1639 other means. We merge this into the NT_USER_TOKEN associated with the vuid
1640 later on. */
1642 if (pptoken && (info3.num_groups2 != 0)) {
1643 NT_USER_TOKEN *ptok;
1644 int i;
1646 *pptoken = NULL;
1648 if ((ptok = (NT_USER_TOKEN *)malloc( sizeof(NT_USER_TOKEN) ) ) == NULL) {
1649 DEBUG(0, ("domain_client_validate: Out of memory allocating NT_USER_TOKEN\n"));
1650 release_server_mutex();
1651 return False;
1654 ptok->num_sids = (size_t)info3.num_groups2 + info3.num_other_sids;
1655 if ((ptok->user_sids = (DOM_SID *)malloc( sizeof(DOM_SID) * ptok->num_sids )) == NULL) {
1656 DEBUG(0, ("domain_client_validate: Out of memory allocating group SIDS\n"));
1657 SAFE_FREE(ptok);
1658 release_server_mutex();
1659 return False;
1662 /* Group membership (including nested groups) is
1663 stored here. */
1665 for (i = 0; i < info3.num_groups2; i++) {
1666 sid_copy(&ptok->user_sids[i], &info3.dom_sid.sid);
1667 sid_append_rid(&ptok->user_sids[i], info3.gids[i].g_rid);
1670 /* Universal group memberships for other domains are
1671 stored in the info3.other_sids field. We also need to
1672 do sid filtering here. */
1674 for (i = 0; i < info3.num_other_sids; i++)
1675 sid_copy(&ptok->user_sids[info3.num_groups2 + i],
1676 &info3.other_sids[i].sid);
1678 *pptoken = ptok;
1681 #if 0
1683 * We don't actually need to do this - plus it fails currently with
1684 * NT_STATUS_INVALID_INFO_CLASS - we need to know *exactly* what to
1685 * send here. JRA.
1688 if(cli_nt_logoff(pcli, &ctr) == False) {
1689 DEBUG(0,("domain_client_validate: unable to log off user %s in domain \
1690 %s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(pcli)));
1691 cli_nt_session_close(pcli);
1692 cli_ulogoff(pcli);
1693 cli_shutdown(pcli);
1694 release_server_mutex();
1695 return False;
1697 #endif /* 0 */
1699 /* Note - once the cli stream is shutdown the mem_ctx used
1700 to allocate the other_sids and gids structures has been deleted - so
1701 these pointers are no longer valid..... */
1703 cli_nt_session_close(pcli);
1704 cli_ulogoff(pcli);
1705 cli_shutdown(pcli);
1706 release_server_mutex();
1707 return True;