add WITH_SENDFILE profiling data (from Pierre Belanger)
[Samba.git] / source / smbd / password.c
blobc785784652647d7cc2e5a23309c182dd09c114a5
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));
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 *p, *pserver;
1020 BOOL connected_ok = False;
1022 cli = server_client();
1024 if (!cli_initialise(cli))
1025 return NULL;
1027 pserver = strdup(lp_passwordserver());
1028 p = pserver;
1030 while(next_token( &p, desthost, LIST_SEP, sizeof(desthost))) {
1031 standard_sub_basic(desthost,sizeof(desthost));
1032 strupper(desthost);
1034 if(!resolve_name( desthost, &dest_ip, 0x20)) {
1035 DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost));
1036 continue;
1039 if (ismyip(dest_ip)) {
1040 DEBUG(1,("Password server loop - disabling password server %s\n",desthost));
1041 continue;
1044 if (cli_connect(cli, desthost, &dest_ip)) {
1045 DEBUG(3,("connected to password server %s\n",desthost));
1046 connected_ok = True;
1047 break;
1051 SAFE_FREE(pserver);
1053 if (!connected_ok) {
1054 DEBUG(0,("password server not available\n"));
1055 cli_shutdown(cli);
1056 return NULL;
1059 if (!attempt_netbios_session_request(cli, global_myname, desthost, &dest_ip)) {
1060 cli_shutdown(cli);
1061 return NULL;
1064 DEBUG(3,("got session\n"));
1066 if (!cli_negprot(cli)) {
1067 DEBUG(1,("%s rejected the negprot\n",desthost));
1068 cli_shutdown(cli);
1069 return NULL;
1072 if (cli->protocol < PROTOCOL_LANMAN2 ||
1073 !(cli->sec_mode & 1)) {
1074 DEBUG(1,("%s isn't in user level security mode\n",desthost));
1075 cli_shutdown(cli);
1076 return NULL;
1079 DEBUG(3,("password server OK\n"));
1081 return cli;
1084 /****************************************************************************
1085 Validate a password with the password server.
1086 ****************************************************************************/
1088 BOOL server_validate(char *user, char *domain,
1089 char *pass, int passlen,
1090 char *ntpass, int ntpasslen)
1092 struct cli_state *cli;
1093 static unsigned char badpass[24];
1094 static fstring baduser;
1095 static BOOL tested_password_server = False;
1096 static BOOL bad_password_server = False;
1098 cli = server_client();
1100 if (!cli->initialised) {
1101 DEBUG(1,("password server %s is not connected\n", cli->desthost));
1102 return(False);
1105 if(badpass[0] == 0)
1106 memset(badpass, 0x1f, sizeof(badpass));
1108 if((passlen == sizeof(badpass)) && !memcmp(badpass, pass, passlen)) {
1110 * Very unlikely, our random bad password is the same as the users
1111 * password.
1113 memset(badpass, badpass[0]+1, sizeof(badpass));
1116 if(baduser[0] == 0) {
1117 fstrcpy(baduser, INVALID_USER_PREFIX);
1118 fstrcat(baduser, global_myname);
1122 * Attempt a session setup with a totally incorrect password.
1123 * If this succeeds with the guest bit *NOT* set then the password
1124 * server is broken and is not correctly setting the guest bit. We
1125 * need to detect this as some versions of NT4.x are broken. JRA.
1128 if(!tested_password_server) {
1129 if (cli_session_setup(cli, baduser, (char *)badpass, sizeof(badpass),
1130 (char *)badpass, sizeof(badpass), domain)) {
1133 * We connected to the password server so we
1134 * can say we've tested it.
1136 tested_password_server = True;
1138 if ((SVAL(cli->inbuf,smb_vwv2) & 1) == 0) {
1139 DEBUG(0,("server_validate: password server %s allows users as non-guest \
1140 with a bad password.\n", cli->desthost));
1141 DEBUG(0,("server_validate: This is broken (and insecure) behaviour. Please do not \
1142 use this machine as the password server.\n"));
1143 cli_ulogoff(cli);
1146 * Password server has the bug.
1148 bad_password_server = True;
1149 return False;
1151 cli_ulogoff(cli);
1153 } else {
1156 * We have already tested the password server.
1157 * Fail immediately if it has the bug.
1160 if(bad_password_server) {
1161 DEBUG(0,("server_validate: [1] password server %s allows users as non-guest \
1162 with a bad password.\n", cli->desthost));
1163 DEBUG(0,("server_validate: [1] This is broken (and insecure) behaviour. Please do not \
1164 use this machine as the password server.\n"));
1165 return False;
1170 * Now we know the password server will correctly set the guest bit, or is
1171 * not guest enabled, we can try with the real password.
1174 if (!cli_session_setup(cli, user, pass, passlen, ntpass, ntpasslen, domain)) {
1175 DEBUG(1,("password server %s rejected the password\n", cli->desthost));
1176 return False;
1179 /* if logged in as guest then reject */
1180 if ((SVAL(cli->inbuf,smb_vwv2) & 1) != 0) {
1181 DEBUG(1,("password server %s gave us guest only\n", cli->desthost));
1182 cli_ulogoff(cli);
1183 return(False);
1186 cli_ulogoff(cli);
1188 return(True);
1191 static char *mutex_server_name;
1193 static BOOL grab_server_mutex(const char *name)
1195 mutex_server_name = strdup(name);
1196 if (!mutex_server_name) {
1197 DEBUG(0,("grab_server_mutex: malloc failed for %s\n", name));
1198 return False;
1200 if (!secrets_named_mutex(name, 10)) {
1201 DEBUG(10,("grab_server_mutex: failed for %s\n", name));
1202 SAFE_FREE(mutex_server_name);
1203 return False;
1206 return True;
1209 static void release_server_mutex(void)
1211 if (mutex_server_name) {
1212 secrets_named_mutex_release(mutex_server_name);
1213 SAFE_FREE(mutex_server_name);
1217 /***********************************************************************
1218 Connect to a remote machine for domain security authentication
1219 given a name or IP address.
1220 ************************************************************************/
1222 static BOOL connect_to_domain_password_server(struct cli_state **ppcli,
1223 char *server, unsigned char *trust_passwd)
1225 struct in_addr dest_ip;
1226 fstring remote_machine;
1227 struct cli_state *pcli = NULL;
1229 *ppcli = NULL;
1231 if(!(pcli = cli_initialise(NULL))) {
1232 DEBUG(0,("connect_to_domain_password_server: unable to initialize client connection.\n"));
1233 return False;
1236 if (is_ipaddress(server)) {
1237 struct in_addr to_ip;
1239 /* we shouldn't have 255.255.255.255 forthe IP address of a password server anyways */
1240 if ((to_ip.s_addr=inet_addr(server)) == 0xFFFFFFFF) {
1241 DEBUG (0,("connect_to_domain_password_server: inet_addr(%s) returned 0xFFFFFFFF!\n", server));
1242 cli_shutdown(pcli);
1243 return False;
1246 if (!name_status_find("*", 0, 0x20, to_ip, remote_machine)) {
1247 DEBUG(1, ("connect_to_domain_password_server: Can't " "resolve name for IP %s\n", server));
1248 cli_shutdown(pcli);
1249 return False;
1251 } else {
1252 fstrcpy(remote_machine, server);
1255 standard_sub_basic(remote_machine,sizeof(remote_machine));
1256 strupper(remote_machine);
1258 if(!resolve_name( remote_machine, &dest_ip, 0x20)) {
1259 DEBUG(1,("connect_to_domain_password_server: Can't resolve address for %s\n", remote_machine));
1260 cli_shutdown(pcli);
1261 return False;
1264 if (ismyip(dest_ip)) {
1265 DEBUG(1,("connect_to_domain_password_server: Password server loop - not using password server %s\n",
1266 remote_machine));
1267 cli_shutdown(pcli);
1268 return False;
1271 /* we use a mutex to prevent two connections at once - when a NT PDC gets
1272 two connections where one hasn't completed a negprot yet it will send a
1273 TCP reset to the first connection (tridge) */
1275 if (!grab_server_mutex(server)) {
1276 cli_shutdown(pcli);
1277 return False;
1280 if (!cli_connect(pcli, remote_machine, &dest_ip)) {
1281 DEBUG(0,("connect_to_domain_password_server: unable to connect to SMB server on \
1282 machine %s. Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
1283 cli_shutdown(pcli);
1284 release_server_mutex();
1285 return False;
1288 if (!attempt_netbios_session_request(pcli, global_myname, remote_machine, &dest_ip)) {
1289 DEBUG(0,("connect_to_password_server: machine %s rejected the NetBIOS \
1290 session request. Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
1291 cli_shutdown(pcli);
1292 release_server_mutex();
1293 return False;
1296 pcli->protocol = PROTOCOL_NT1;
1298 if (!cli_negprot(pcli)) {
1299 DEBUG(0,("connect_to_domain_password_server: machine %s rejected the negotiate protocol. \
1300 Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
1301 cli_shutdown(pcli);
1302 release_server_mutex();
1303 return False;
1306 if (pcli->protocol != PROTOCOL_NT1) {
1307 DEBUG(0,("connect_to_domain_password_server: machine %s didn't negotiate NT protocol.\n",
1308 remote_machine));
1309 cli_shutdown(pcli);
1310 release_server_mutex();
1311 return False;
1315 * Do an anonymous session setup.
1318 if (!cli_session_setup(pcli, "", "", 0, "", 0, "")) {
1319 DEBUG(0,("connect_to_domain_password_server: machine %s rejected the session setup. \
1320 Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
1321 cli_shutdown(pcli);
1322 release_server_mutex();
1323 return False;
1326 if (!(pcli->sec_mode & 1)) {
1327 DEBUG(1,("connect_to_domain_password_server: machine %s isn't in user level security mode\n",
1328 remote_machine));
1329 cli_shutdown(pcli);
1330 release_server_mutex();
1331 return False;
1334 if (!cli_send_tconX(pcli, "IPC$", "IPC", "", 1)) {
1335 DEBUG(0,("connect_to_domain_password_server: machine %s rejected the tconX on the IPC$ share. \
1336 Error was : %s.\n", remote_machine, cli_errstr(pcli) ));
1337 cli_shutdown(pcli);
1338 release_server_mutex();
1339 return False;
1343 * We now have an anonymous connection to IPC$ on the domain password server.
1347 * Even if the connect succeeds we need to setup the netlogon
1348 * pipe here. We do this as we may just have changed the domain
1349 * account password on the PDC and yet we may be talking to
1350 * a BDC that doesn't have this replicated yet. In this case
1351 * a successful connect to a DC needs to take the netlogon connect
1352 * into account also. This patch from "Bjart Kvarme" <bjart.kvarme@usit.uio.no>.
1355 if(cli_nt_session_open(pcli, PIPE_NETLOGON) == False) {
1356 DEBUG(0,("connect_to_domain_password_server: unable to open the domain client session to \
1357 machine %s. Error was : %s.\n", remote_machine, cli_errstr(pcli)));
1358 cli_nt_session_close(pcli);
1359 cli_ulogoff(pcli);
1360 cli_shutdown(pcli);
1361 release_server_mutex();
1362 return False;
1365 if (!NT_STATUS_IS_OK(cli_nt_setup_creds(pcli, trust_passwd))) {
1366 DEBUG(0,("connect_to_domain_password_server: unable to setup the PDC credentials to machine \
1367 %s. Error was : %s.\n", remote_machine, cli_errstr(pcli)));
1368 cli_nt_session_close(pcli);
1369 cli_ulogoff(pcli);
1370 cli_shutdown(pcli);
1371 release_server_mutex();
1372 return(False);
1375 *ppcli = pcli;
1377 /* We exit here with the mutex *locked*. JRA */
1378 return True;
1381 /***********************************************************************
1382 Utility function to attempt a connection to an IP address of a DC.
1383 ************************************************************************/
1385 static BOOL attempt_connect_to_dc(struct cli_state **ppcli, struct in_addr *ip, unsigned char *trust_passwd)
1387 fstring dc_name;
1390 * Ignore addresses we have already tried.
1393 if (is_zero_ip(*ip))
1394 return False;
1396 if (!lookup_dc_name(global_myname, lp_workgroup(), ip, dc_name))
1397 return False;
1399 return connect_to_domain_password_server(ppcli, dc_name, trust_passwd);
1402 /***********************************************************************
1403 We have been asked to dynamcially determine the IP addresses of
1404 the PDC and BDC's for this DOMAIN, and query them in turn.
1405 ************************************************************************/
1407 static BOOL find_connect_pdc(struct cli_state **ppcli, unsigned char *trust_passwd, time_t last_change_time)
1409 struct in_addr *ip_list = NULL;
1410 int count = 0;
1411 int i;
1412 BOOL connected_ok = False;
1413 time_t time_now = time(NULL);
1414 BOOL use_pdc_only = False;
1417 * If the time the machine password has changed
1418 * was less than an hour ago then we need to contact
1419 * the PDC only, as we cannot be sure domain replication
1420 * has yet taken place. Bug found by Gerald (way to go
1421 * Gerald !). JRA.
1424 if (time_now - last_change_time < 3600)
1425 use_pdc_only = True;
1427 if (!get_dc_list(use_pdc_only, lp_workgroup(), &ip_list, &count))
1428 return False;
1431 * Firstly try and contact a PDC/BDC who has the same
1432 * network address as any of our interfaces.
1434 for(i = 0; i < count; i++) {
1435 if(!is_local_net(ip_list[i]))
1436 continue;
1438 if((connected_ok = attempt_connect_to_dc(ppcli, &ip_list[i], trust_passwd)))
1439 break;
1441 zero_ip(&ip_list[i]); /* Tried and failed. */
1445 * Secondly try and contact a random PDC/BDC.
1447 if(!connected_ok) {
1448 i = (sys_random() % count);
1450 if (!is_zero_ip(ip_list[i])) {
1451 if (!(connected_ok = attempt_connect_to_dc(ppcli, &ip_list[i], trust_passwd)))
1452 zero_ip(&ip_list[i]); /* Tried and failed. */
1457 * Finally go through the IP list in turn, ignoring any addresses
1458 * we have already tried.
1460 if(!connected_ok) {
1462 * Try and connect to any of the other IP addresses in the PDC/BDC list.
1463 * Note that from a WINS server the #1 IP address is the PDC.
1465 for(i = 0; i < count; i++) {
1466 if (is_zero_ip(ip_list[i]))
1467 continue;
1469 if((connected_ok = attempt_connect_to_dc(ppcli, &ip_list[i], trust_passwd)))
1470 break;
1474 SAFE_FREE(ip_list);
1475 return connected_ok;
1478 /***********************************************************************
1479 Do the same as security=server, but using NT Domain calls and a session
1480 key from the machine password.
1481 ************************************************************************/
1483 BOOL domain_client_validate( char *user, char *domain,
1484 char *smb_apasswd, int smb_apasslen,
1485 char *smb_ntpasswd, int smb_ntpasslen,
1486 BOOL *user_exists, NT_USER_TOKEN **pptoken)
1488 unsigned char local_challenge[8];
1489 unsigned char local_lm_response[24];
1490 unsigned char local_nt_response[24];
1491 unsigned char trust_passwd[16];
1492 fstring remote_machine;
1493 char *p, *pserver;
1494 NET_ID_INFO_CTR ctr;
1495 NET_USER_INFO_3 info3;
1496 struct cli_state *pcli = NULL;
1497 uint32 smb_uid_low;
1498 BOOL connected_ok = False;
1499 time_t last_change_time;
1500 NTSTATUS status;
1502 if (pptoken)
1503 *pptoken = NULL;
1505 if(user_exists != NULL)
1506 *user_exists = True; /* Only set false on a very specific error. */
1509 * Check that the requested domain is not our own machine name.
1510 * If it is, we should never check the PDC here, we use our own local
1511 * password file.
1514 if(strequal( domain, global_myname)) {
1515 DEBUG(3,("domain_client_validate: Requested domain was for this machine.\n"));
1516 return False;
1520 * Next, check that the passwords given were encrypted.
1523 if(((smb_apasslen != 24) && (smb_apasslen != 0)) ||
1524 ((smb_ntpasslen != 24) && (smb_ntpasslen != 0))) {
1527 * Not encrypted - do so.
1530 DEBUG(3,("domain_client_validate: User passwords not in encrypted format.\n"));
1531 generate_random_buffer( local_challenge, 8, False);
1532 SMBencrypt( (uchar *)smb_apasswd, local_challenge, local_lm_response);
1533 SMBNTencrypt((uchar *)smb_ntpasswd, local_challenge, local_nt_response);
1534 smb_apasslen = 24;
1535 smb_ntpasslen = 24;
1536 smb_apasswd = (char *)local_lm_response;
1537 smb_ntpasswd = (char *)local_nt_response;
1538 } else {
1541 * Encrypted - get the challenge we sent for these
1542 * responses.
1545 if (!last_challenge(local_challenge)) {
1546 DEBUG(0,("domain_client_validate: no challenge done - password failed\n"));
1547 return False;
1552 * Get the machine account password for our primary domain
1555 if (!secrets_fetch_trust_account_password(global_myworkgroup, trust_passwd, &last_change_time)) {
1556 DEBUG(0, ("domain_client_validate: could not fetch trust account password for domain %s\n", global_myworkgroup));
1557 return False;
1560 /* Test if machine password is expired and need to be changed */
1561 if (time(NULL) > last_change_time + lp_machine_password_timeout())
1562 global_machine_password_needs_changing = True;
1565 * At this point, smb_apasswd points to the lanman response to
1566 * the challenge in local_challenge, and smb_ntpasswd points to
1567 * the NT response to the challenge in local_challenge. Ship
1568 * these over the secure channel to a domain controller and
1569 * see if they were valid.
1573 * Treat each name in the 'password server =' line as a potential
1574 * PDC/BDC. Contact each in turn and try and authenticate.
1577 pserver = lp_passwordserver();
1578 if (! *pserver)
1579 pserver = "*";
1580 p = pserver;
1582 while (!connected_ok &&
1583 next_token(&p,remote_machine,LIST_SEP,sizeof(remote_machine))) {
1584 if(strequal(remote_machine, "*")) {
1585 connected_ok = find_connect_pdc(&pcli, trust_passwd, last_change_time);
1586 } else {
1587 connected_ok = connect_to_domain_password_server(&pcli, remote_machine, trust_passwd);
1591 if (!connected_ok) {
1592 DEBUG(0,("domain_client_validate: Domain password server not available.\n"));
1593 if (pcli)
1594 cli_shutdown(pcli);
1595 release_server_mutex();
1596 return False;
1599 /* We really don't care what LUID we give the user. */
1600 generate_random_buffer( (unsigned char *)&smb_uid_low, 4, False);
1602 ZERO_STRUCT(info3);
1604 status = cli_nt_login_network(pcli, domain, user, smb_uid_low, (char *)local_challenge,
1605 ((smb_apasslen != 0) ? smb_apasswd : NULL),
1606 ((smb_ntpasslen != 0) ? smb_ntpasswd : NULL),
1607 &ctr, &info3);
1609 if (!NT_STATUS_IS_OK(status)) {
1611 DEBUG(0,("domain_client_validate: unable to validate password for user %s in domain \
1612 %s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, get_nt_error_msg(status) ));
1613 cli_nt_session_close(pcli);
1614 cli_ulogoff(pcli);
1615 cli_shutdown(pcli);
1616 release_server_mutex();
1618 if((NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NO_SUCH_USER)) && (user_exists != NULL))
1619 *user_exists = False;
1621 return False;
1625 * Here, if we really want it, we have lots of info about the user in info3.
1628 /* Return group membership as returned by NT. This contains group
1629 membership in nested groups which doesn't seem to be accessible by any
1630 other means. We merge this into the NT_USER_TOKEN associated with the vuid
1631 later on. */
1633 if (pptoken && (info3.num_groups2 != 0)) {
1634 NT_USER_TOKEN *ptok;
1635 int i;
1637 *pptoken = NULL;
1639 if ((ptok = (NT_USER_TOKEN *)malloc( sizeof(NT_USER_TOKEN) ) ) == NULL) {
1640 DEBUG(0, ("domain_client_validate: Out of memory allocating NT_USER_TOKEN\n"));
1641 release_server_mutex();
1642 return False;
1645 ptok->num_sids = (size_t)info3.num_groups2 + info3.num_other_sids;
1646 if ((ptok->user_sids = (DOM_SID *)malloc( sizeof(DOM_SID) * ptok->num_sids )) == NULL) {
1647 DEBUG(0, ("domain_client_validate: Out of memory allocating group SIDS\n"));
1648 SAFE_FREE(ptok);
1649 release_server_mutex();
1650 return False;
1653 /* Group membership (including nested groups) is
1654 stored here. */
1656 for (i = 0; i < info3.num_groups2; i++) {
1657 sid_copy(&ptok->user_sids[i], &info3.dom_sid.sid);
1658 sid_append_rid(&ptok->user_sids[i], info3.gids[i].g_rid);
1661 /* Universal group memberships for other domains are
1662 stored in the info3.other_sids field. We also need to
1663 do sid filtering here. */
1665 for (i = 0; i < info3.num_other_sids; i++)
1666 sid_copy(&ptok->user_sids[info3.num_groups2 + i],
1667 &info3.other_sids[i].sid);
1669 *pptoken = ptok;
1672 #if 0
1674 * We don't actually need to do this - plus it fails currently with
1675 * NT_STATUS_INVALID_INFO_CLASS - we need to know *exactly* what to
1676 * send here. JRA.
1679 if(cli_nt_logoff(pcli, &ctr) == False) {
1680 DEBUG(0,("domain_client_validate: unable to log off user %s in domain \
1681 %s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(pcli)));
1682 cli_nt_session_close(pcli);
1683 cli_ulogoff(pcli);
1684 cli_shutdown(pcli);
1685 release_server_mutex();
1686 return False;
1688 #endif /* 0 */
1690 /* Note - once the cli stream is shutdown the mem_ctx used
1691 to allocate the other_sids and gids structures has been deleted - so
1692 these pointers are no longer valid..... */
1694 cli_nt_session_close(pcli);
1695 cli_ulogoff(pcli);
1696 cli_shutdown(pcli);
1697 release_server_mutex();
1698 return True;