config: Fix crypt prototype on RedHat Linux.
[vlendec/samba-autobuild/.git] / source3 / smbd / password.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Password and authentication handling
5    Copyright (C) Andrew Tridgell 1992-1998
6    
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.
11    
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.
16    
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.
20 */
21
22 #include "includes.h"
23
24 extern int DEBUGLEVEL;
25 extern int Protocol;
26
27 BOOL global_machine_pasword_needs_changing;
28
29 /* users from session setup */
30 static pstring session_users="";
31
32 extern pstring scope;
33 extern pstring global_myname;
34 extern fstring global_myworkgroup;
35
36 /* Data to do lanman1/2 password challenge. */
37 static unsigned char saved_challenge[8];
38 static BOOL challenge_sent=False;
39
40 /*******************************************************************
41 Get the next challenge value - no repeats.
42 ********************************************************************/
43 void generate_next_challenge(char *challenge)
44 {
45 #if 0
46         /* 
47          * Leave this ifdef'd out while we test
48          * the new crypto random number generator.
49          * JRA.
50          */
51         unsigned char buf[16];
52         static int counter = 0;
53         struct timeval tval;
54         int v1,v2;
55
56         /* get a sort-of random number */
57         GetTimeOfDay(&tval);
58         v1 = (counter++) + getpid() + tval.tv_sec;
59         v2 = (counter++) * getpid() + tval.tv_usec;
60         SIVAL(challenge,0,v1);
61         SIVAL(challenge,4,v2);
62
63         /* mash it up with md4 */
64         mdfour(buf, (unsigned char *)challenge, 8);
65 #else
66         unsigned char buf[8];
67
68         generate_random_buffer(buf,8,False);
69 #endif 
70         memcpy(saved_challenge, buf, 8);
71         memcpy(challenge,buf,8);
72         challenge_sent = True;
73 }
74
75 /*******************************************************************
76 set the last challenge sent, usually from a password server
77 ********************************************************************/
78 BOOL set_challenge(unsigned char *challenge)
79 {
80   memcpy(saved_challenge,challenge,8);
81   challenge_sent = True;
82   return(True);
83 }
84
85 /*******************************************************************
86 get the last challenge sent
87 ********************************************************************/
88 static BOOL last_challenge(unsigned char *challenge)
89 {
90   if (!challenge_sent) return(False);
91   memcpy(challenge,saved_challenge,8);
92   return(True);
93 }
94
95 /* this holds info on user ids that are already validated for this VC */
96 static user_struct *validated_users = NULL;
97 static int num_validated_users = 0;
98
99 /****************************************************************************
100 check if a uid has been validated, and return an pointer to the user_struct
101 if it has. NULL if not. vuid is biased by an offset. This allows us to
102 tell random client vuid's (normally zero) from valid vuids.
103 ****************************************************************************/
104 user_struct *get_valid_user_struct(uint16 vuid)
105 {
106   if (vuid == UID_FIELD_INVALID)
107     return NULL;
108   vuid -= VUID_OFFSET;
109   if ((vuid >= (uint16)num_validated_users) || 
110      (validated_users[vuid].uid == (uid_t)-1) || (validated_users[vuid].gid == (gid_t)-1))
111     return NULL;
112   return &validated_users[vuid];
113 }
114
115 /****************************************************************************
116 invalidate a uid
117 ****************************************************************************/
118 void invalidate_vuid(uint16 vuid)
119 {
120   user_struct *vuser = get_valid_user_struct(vuid);
121
122   if (vuser == NULL) return;
123
124   vuser->uid = (uid_t)-1;
125   vuser->gid = (gid_t)-1;
126
127   vuser->n_sids = 0;
128
129   /* same number of igroups as groups */
130   vuser->n_groups = 0;
131
132   if (vuser->groups)
133     free((char *)vuser->groups);
134
135   if (vuser->sids)
136     free((char *)vuser->sids);
137
138   vuser->sids    = NULL;
139   vuser->groups  = NULL;
140 }
141
142
143 /****************************************************************************
144 return a validated username
145 ****************************************************************************/
146 char *validated_username(uint16 vuid)
147 {
148   user_struct *vuser = get_valid_user_struct(vuid);
149   if (vuser == NULL)
150     return 0;
151   return(vuser->name);
152 }
153
154
155 /****************************************************************************
156 Setup the groups a user belongs to.
157 ****************************************************************************/
158 int setup_groups(char *user, uid_t uid, gid_t gid, int *p_ngroups, gid_t **p_groups)
159 {
160         int i,ngroups;
161         gid_t grp = 0;
162     gid_t *groups = NULL;
163
164         if (-1 == initgroups(user,gid)) {
165                 if (getuid() == 0) {
166                         DEBUG(0,("Unable to initgroups!\n"));
167                         if (gid < 0 || gid > 16000 || uid < 0 || uid > 16000) {
168                                 DEBUG(0,("This is probably a problem with the account %s\n",
169                                          user));
170                         }
171                 }
172                 return -1;
173         }
174
175         ngroups = sys_getgroups(0,&grp);
176         if (ngroups <= 0)
177       ngroups = 32;
178
179     if((groups = (gid_t *)malloc(sizeof(gid_t)*ngroups)) == NULL) {
180       DEBUG(0,("setup_groups malloc fail !\n"));
181       return -1;
182     }
183
184     ngroups = sys_getgroups(ngroups,groups);
185
186         (*p_ngroups) = ngroups;
187         (*p_groups) = groups;
188
189         DEBUG( 3, ( "%s is in %d groups: ", user, ngroups ) );
190         for (i = 0; i < ngroups; i++ ) {
191                 DEBUG( 3, ( "%s%d", (i ? ", " : ""), (int)groups[i] ) );
192         }
193         DEBUG( 3, ( "\n" ) );
194
195         return 0;
196 }
197
198
199 /****************************************************************************
200 register a uid/name pair as being valid and that a valid password
201 has been given. vuid is biased by an offset. This allows us to
202 tell random client vuid's (normally zero) from valid vuids.
203 ****************************************************************************/
204 uint16 register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name, BOOL guest)
205 {
206   user_struct *vuser;
207   struct passwd *pwfile; /* for getting real name from passwd file */
208
209   /* Ensure no vuid gets registered in share level security. */
210   if(lp_security() == SEC_SHARE)
211     return UID_FIELD_INVALID;
212
213 #if 0
214   /*
215    * After observing MS-Exchange services writing to a Samba share
216    * I belive this code is incorrect. Each service does its own
217    * sessionsetup_and_X for the same user, and as each service shuts
218    * down, it does a user_logoff_and_X. As we are consolidating multiple
219    * sessionsetup_and_X's onto the same vuid here, when the first service
220    * shuts down, it invalidates all the open files for the other services.
221    * Hence I am removing this code and forcing each sessionsetup_and_X
222    * to get a new vuid.
223    * Jeremy Allison. (jallison@whistle.com).
224    */
225
226   int i;
227   for(i = 0; i < num_validated_users; i++) {
228     vuser = &validated_users[i];
229     if ( vuser->uid == uid )
230       return (uint16)(i + VUID_OFFSET); /* User already validated */
231   }
232 #endif
233
234   validated_users = (user_struct *)Realloc(validated_users,
235                            sizeof(user_struct)*
236                            (num_validated_users+1));
237   
238   if (!validated_users)
239     {
240       DEBUG(0,("Failed to realloc users struct!\n"));
241       num_validated_users = 0;
242       return UID_FIELD_INVALID;
243     }
244
245   vuser = &validated_users[num_validated_users];
246   num_validated_users++;
247
248   vuser->uid = uid;
249   vuser->gid = gid;
250   vuser->guest = guest;
251   fstrcpy(vuser->name,unix_name);
252   fstrcpy(vuser->requested_name,requested_name);
253
254   vuser->n_sids = 0;
255   vuser->sids   = NULL;
256
257   vuser->n_groups = 0;
258   vuser->groups  = NULL;
259
260   /* Find all the groups this uid is in and store them. 
261      Used by become_user() */
262   setup_groups(unix_name,uid,gid,
263                &vuser->n_groups,
264                &vuser->groups);
265
266   DEBUG(3,("uid %d registered to name %s\n",(int)uid,unix_name));
267
268   DEBUG(3, ("Clearing default real name\n"));
269   fstrcpy(vuser->real_name, "<Full Name>\0");
270   if (lp_unix_realname()) {
271     if ((pwfile=getpwnam(vuser->name))!= NULL)
272       {
273       DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->name,pwfile->pw_gecos));
274       fstrcpy(vuser->real_name, pwfile->pw_gecos);
275       }
276   }
277
278   return (uint16)((num_validated_users - 1) + VUID_OFFSET);
279 }
280
281
282 /****************************************************************************
283 add a name to the session users list
284 ****************************************************************************/
285 void add_session_user(char *user)
286 {
287   fstring suser;
288   StrnCpy(suser,user,sizeof(suser)-1);
289
290   if (!Get_Pwnam(suser,True)) return;
291
292   if (suser && *suser && !in_list(suser,session_users,False))
293     {
294       if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring))
295         DEBUG(1,("Too many session users??\n"));
296       else
297         {
298           pstrcat(session_users," ");
299           pstrcat(session_users,suser);
300         }
301     }
302 }
303
304
305 /****************************************************************************
306 update the encrypted smbpasswd file from the plaintext username and password
307 *****************************************************************************/
308 static BOOL update_smbpassword_file(char *user, char *password)
309 {
310         struct smb_passwd *smbpw;
311         BOOL ret;
312         
313         become_root(0);
314         smbpw = getsmbpwnam(user);
315         unbecome_root(0);
316         
317         if(smbpw == NULL) {
318                 DEBUG(0,("getsmbpwnam returned NULL\n"));
319                 return False;
320         }
321  
322         /* Here, the flag is one, because we want to ignore the
323            XXXXXXX'd out password */
324         ret = change_oem_password( smbpw, password, True);
325         if (ret == False) {
326                 DEBUG(3,("change_oem_password returned False\n"));
327         }
328
329         return ret;
330 }
331
332
333
334
335
336 /****************************************************************************
337 core of smb password checking routine.
338 ****************************************************************************/
339 BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8)
340 {
341   /* Finish the encryption of part_passwd. */
342   unsigned char p21[21];
343   unsigned char p24[24];
344
345   if (part_passwd == NULL)
346     DEBUG(10,("No password set - allowing access\n"));
347   /* No password set - always true ! */
348   if (part_passwd == NULL)
349     return 1;
350
351   memset(p21,'\0',21);
352   memcpy(p21,part_passwd,16);
353   E_P24(p21, c8, p24);
354 #if DEBUG_PASSWORD
355   {
356     int i;
357     DEBUG(100,("Part password (P16) was |"));
358     for(i = 0; i < 16; i++)
359       DEBUG(100,("%X ", (unsigned char)part_passwd[i]));
360     DEBUG(100,("|\n"));
361     DEBUG(100,("Password from client was |"));
362     for(i = 0; i < 24; i++)
363       DEBUG(100,("%X ", (unsigned char)password[i]));
364     DEBUG(100,("|\n"));
365     DEBUG(100,("Given challenge was |"));
366     for(i = 0; i < 8; i++)
367       DEBUG(100,("%X ", (unsigned char)c8[i]));
368     DEBUG(100,("|\n"));
369     DEBUG(100,("Value from encryption was |"));
370     for(i = 0; i < 24; i++)
371       DEBUG(100,("%X ", (unsigned char)p24[i]));
372     DEBUG(100,("|\n"));
373   }
374 #endif
375   return (memcmp(p24, password, 24) == 0);
376 }
377
378 /****************************************************************************
379  Do a specific test for an smb password being correct, given a smb_password and
380  the lanman and NT responses.
381 ****************************************************************************/
382
383 BOOL smb_password_ok(struct smb_passwd *smb_pass,
384                      uchar lm_pass[24], uchar nt_pass[24])
385 {
386         uchar challenge[8];
387
388         if (!lm_pass || !smb_pass) return(False);
389
390         DEBUG(4,("Checking SMB password for user %s\n", 
391                  smb_pass->smb_name));
392
393         if(smb_pass->acct_ctrl & ACB_DISABLED) {
394                 DEBUG(3,("account for user %s was disabled.\n", 
395                          smb_pass->smb_name));
396                 return(False);
397         }
398
399         if (!last_challenge(challenge)) {
400                 DEBUG(1,("no challenge done - password failed\n"));
401                 return False;
402         }
403
404         if ((Protocol >= PROTOCOL_NT1) && (smb_pass->smb_nt_passwd != NULL)) {
405                 /* We have the NT MD4 hash challenge available - see if we can
406                    use it (ie. does it exist in the smbpasswd file).
407                 */
408                 DEBUG(4,("smb_password_ok: Checking NT MD4 password\n"));
409                 if (smb_password_check((char *)nt_pass, 
410                                        (uchar *)smb_pass->smb_nt_passwd, 
411                                        challenge)) {
412                         DEBUG(4,("NT MD4 password check succeeded\n"));
413                         return(True);
414                 }
415                 DEBUG(4,("NT MD4 password check failed\n"));
416         }
417
418         /* Try against the lanman password. smb_pass->smb_passwd == NULL means
419            no password, allow access. */
420
421         DEBUG(4,("Checking LM MD4 password\n"));
422
423         if((smb_pass->smb_passwd == NULL) && 
424            (smb_pass->acct_ctrl & ACB_PWNOTREQ)) {
425                 DEBUG(4,("no password required for user %s\n",
426                          smb_pass->smb_name));
427                 return True;
428         }
429
430         if((smb_pass->smb_passwd != NULL) && 
431            smb_password_check((char *)lm_pass, 
432                               (uchar *)smb_pass->smb_passwd, challenge)) {
433                 DEBUG(4,("LM MD4 password check succeeded\n"));
434                 return(True);
435         }
436
437         DEBUG(4,("LM MD4 password check failed\n"));
438
439         return False;
440 }
441
442
443 /****************************************************************************
444 check if a username/password is OK assuming the password is a 24 byte
445 SMB hash
446 return True if the password is correct, False otherwise
447 ****************************************************************************/
448 static BOOL pass_check_smb(char *user,char *password, struct passwd *pwd)
449 {
450         struct passwd *pass;
451         uchar challenge[8];
452         struct smb_passwd *smb_pass;
453         BOOL challenge_done;
454
455         if (!password) {
456                 return(False);
457         }
458
459         challenge_done = last_challenge(challenge);
460
461         if (!challenge_done) {
462                 DEBUG(0,("Error: challenge not done for user=%s\n", user));
463                 return False;
464         }
465
466         if (pwd && !user) {
467                 pass = (struct passwd *) pwd;
468                 user = pass->pw_name;
469         } else {
470                 pass = Get_Pwnam(user,True);
471         }
472
473         if (!pass) {
474                 DEBUG(3,("Couldn't find user %s\n",user));
475                 return(False);
476         }
477
478         smb_pass = getsmbpwnam(user);
479
480         if (!smb_pass) {
481                 DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
482                 return(False);
483         }
484
485         /* Quit if the account was disabled. */
486         if(smb_pass->acct_ctrl & ACB_DISABLED) {
487                 DEBUG(3,("account for user %s was disabled.\n", user));
488                 return(False);
489         }
490
491         /* Ensure the uid's match */
492         if (smb_pass->smb_userid != pass->pw_uid)       {
493                 DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
494                 return(False);
495         }
496
497         if(password[0] == '\0' && smb_pass->acct_ctrl & ACB_PWNOTREQ && lp_null_passwords()) {
498                 DEBUG(3,("account for user %s has no password and null passwords are allowed.\n", smb_pass->smb_name));
499                 return(True);
500         }
501
502         if (smb_password_ok(smb_pass, 
503                             (unsigned char *)password,
504                             (uchar *)password)) {
505                 return(True);
506         }
507         
508         DEBUG(3,("Error smb_password_check failed\n"));
509         return False;
510 }
511
512 /****************************************************************************
513 check if a username/password pair is OK either via the system password
514 database or the encrypted SMB password database
515 return True if the password is correct, False otherwise
516 ****************************************************************************/
517 BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd)
518 {
519         if (pwlen == 24 || (lp_encrypted_passwords() && (pwlen == 0) && lp_null_passwords())) {
520                 /* if it is 24 bytes long then assume it is an encrypted
521                    password */
522                 return pass_check_smb(user, password, pwd);
523         } 
524
525         return pass_check(user, password, pwlen, pwd, 
526                           lp_update_encrypted() ? 
527                           update_smbpassword_file : NULL);
528 }
529
530 /****************************************************************************
531 check if a username is valid
532 ****************************************************************************/
533 BOOL user_ok(char *user,int snum)
534 {
535         pstring valid, invalid;
536         BOOL ret;
537
538         StrnCpy(valid, lp_valid_users(snum), sizeof(pstring));
539         StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring));
540
541         string_sub(valid,"%S",lp_servicename(snum));
542         string_sub(invalid,"%S",lp_servicename(snum));
543         
544         ret = !user_in_list(user,invalid);
545         
546         if (ret && valid && *valid) {
547                 ret = user_in_list(user,valid);
548         }
549
550         if (ret && lp_onlyuser(snum)) {
551                 char *user_list = lp_username(snum);
552                 string_sub(user_list,"%S",lp_servicename(snum));
553                 ret = user_in_list(user,user_list);
554         }
555
556         return(ret);
557 }
558
559
560
561
562 /****************************************************************************
563 validate a group username entry. Return the username or NULL
564 ****************************************************************************/
565 static char *validate_group(char *group,char *password,int pwlen,int snum)
566 {
567 #ifdef HAVE_NETGROUP
568   {
569     char *host, *user, *domain;
570     setnetgrent(group);
571     while (getnetgrent(&host, &user, &domain)) {
572       if (user) {
573         if (user_ok(user, snum) && 
574             password_ok(user,password,pwlen,NULL)) {
575           endnetgrent();
576           return(user);
577         }
578       }
579     }
580     endnetgrent();
581   }
582 #endif
583   
584 #ifdef HAVE_GETGRNAM 
585   {
586     struct group *gptr = (struct group *)getgrnam(group);
587     char **member;
588     if (gptr)
589       {
590         member = gptr->gr_mem;
591         while (member && *member)
592           {
593             static fstring name;
594             fstrcpy(name,*member);
595             if (user_ok(name,snum) &&
596                 password_ok(name,password,pwlen,NULL))
597               return(&name[0]);
598             member++;
599           }
600 #ifdef GROUP_CHECK_PWENT
601         {
602           struct passwd *pwd;
603           static fstring tm;
604           
605           setpwent ();
606           while (pwd = getpwent ()) {
607             if (*(pwd->pw_passwd) && pwd->pw_gid == gptr->gr_gid) {
608               /* This Entry have PASSWORD and same GID then check pwd */
609               if (password_ok(NULL, password, pwlen, pwd)) {
610                 fstrcpy(tm, pwd->pw_name);
611                 endpwent ();
612                 return tm;
613               }
614             }
615           }
616           endpwent ();
617         }
618 #endif /* GROUP_CHECK_PWENT */
619       }
620   }      
621 #endif
622   return(NULL);
623 }
624
625
626
627 /****************************************************************************
628 check for authority to login to a service with a given username/password
629 ****************************************************************************/
630 BOOL authorise_login(int snum,char *user,char *password, int pwlen, 
631                      BOOL *guest,BOOL *force,uint16 vuid)
632 {
633   BOOL ok = False;
634   
635   *guest = False;
636   
637 #if DEBUG_PASSWORD
638   DEBUG(100,("checking authorisation on user=%s pass=%s\n",user,password));
639 #endif
640
641   /* there are several possibilities:
642      1) login as the given user with given password
643      2) login as a previously registered username with the given password
644      3) login as a session list username with the given password
645      4) login as a previously validated user/password pair
646      5) login as the "user =" user with given password
647      6) login as the "user =" user with no password (guest connection)
648      7) login as guest user with no password
649
650      if the service is guest_only then steps 1 to 5 are skipped
651   */
652
653   if (GUEST_ONLY(snum)) *force = True;
654
655   if (!(GUEST_ONLY(snum) && GUEST_OK(snum)))
656     {
657
658       user_struct *vuser = get_valid_user_struct(vuid);
659
660       /* check the given username and password */
661       if (!ok && (*user) && user_ok(user,snum)) {
662         ok = password_ok(user,password, pwlen, NULL);
663         if (ok) DEBUG(3,("ACCEPTED: given username password ok\n"));
664       }
665
666       /* check for a previously registered guest username */
667       if (!ok && (vuser != 0) && vuser->guest) {          
668         if (user_ok(vuser->name,snum) &&
669             password_ok(vuser->name, password, pwlen, NULL)) {
670           fstrcpy(user, vuser->name);
671           vuser->guest = False;
672           DEBUG(3,("ACCEPTED: given password with registered user %s\n", user));
673           ok = True;
674         }
675       }
676
677
678       /* now check the list of session users */
679     if (!ok)
680     {
681       char *auser;
682       char *user_list = strdup(session_users);
683       if (!user_list) return(False);
684
685       for (auser=strtok(user_list,LIST_SEP); 
686            !ok && auser; 
687            auser = strtok(NULL,LIST_SEP))
688       {
689         fstring user2;
690         fstrcpy(user2,auser);
691         if (!user_ok(user2,snum)) continue;
692                   
693         if (password_ok(user2,password, pwlen, NULL)) {
694           ok = True;
695           fstrcpy(user,user2);
696           DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
697         }
698       }
699       free(user_list);
700     }
701
702     /* check for a previously validated username/password pair */
703     if (!ok && (!lp_revalidate(snum) || lp_security() > SEC_SHARE) &&
704         (vuser != 0) && !vuser->guest &&
705         user_ok(vuser->name,snum)) {
706       fstrcpy(user,vuser->name);
707       *guest = False;
708       DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
709       ok = True;
710     }
711
712       /* check for a rhosts entry */
713       if (!ok && user_ok(user,snum) && check_hosts_equiv(user)) {
714         ok = True;
715         DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
716       }
717
718       /* check the user= fields and the given password */
719       if (!ok && lp_username(snum)) {
720         char *auser;
721         pstring user_list;
722         StrnCpy(user_list,lp_username(snum),sizeof(pstring));
723
724         string_sub(user_list,"%S",lp_servicename(snum));
725           
726         for (auser=strtok(user_list,LIST_SEP);
727              auser && !ok;
728              auser = strtok(NULL,LIST_SEP))
729           {
730             if (*auser == '@')
731               {
732                 auser = validate_group(auser+1,password,pwlen,snum);
733                 if (auser)
734                   {
735                     ok = True;
736                     fstrcpy(user,auser);
737                     DEBUG(3,("ACCEPTED: group username and given password ok\n"));
738                   }
739               }
740             else
741               {
742                 fstring user2;
743                 fstrcpy(user2,auser);
744                 if (user_ok(user2,snum) && 
745                     password_ok(user2,password,pwlen,NULL))
746                   {
747                     ok = True;
748                     fstrcpy(user,user2);
749                     DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
750                   }
751               }
752           }
753       }      
754     } /* not guest only */
755
756   /* check for a normal guest connection */
757   if (!ok && GUEST_OK(snum))
758     {
759       fstring guestname;
760       StrnCpy(guestname,lp_guestaccount(snum),sizeof(guestname)-1);
761       if (Get_Pwnam(guestname,True))
762         {
763           fstrcpy(user,guestname);
764           ok = True;
765           DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
766         }
767       else
768         DEBUG(0,("Invalid guest account %s??\n",guestname));
769       *guest = True;
770       *force = True;
771     }
772
773   if (ok && !user_ok(user,snum))
774     {
775       DEBUG(0,("rejected invalid user %s\n",user));
776       ok = False;
777     }
778
779   return(ok);
780 }
781
782
783 /****************************************************************************
784 read the a hosts.equiv or .rhosts file and check if it
785 allows this user from this machine
786 ****************************************************************************/
787 static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
788 {
789   pstring buf;
790   int plus_allowed = 1;
791   char *file_host;
792   char *file_user;
793   FILE *fp = fopen(equiv_file, "r");
794   DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
795   if (! fp) return False;
796   while(fgets(buf, sizeof(buf), fp)) 
797   {
798     trim_string(buf," "," ");
799
800     if (buf[0] != '#' && buf[0] != '\n') 
801     {
802       BOOL is_group = False;
803       int plus = 1;
804       char *bp = buf;
805       if (strcmp(buf, "NO_PLUS\n") == 0)
806       {
807         DEBUG(6, ("check_user_equiv NO_PLUS\n"));
808         plus_allowed = 0;
809       }
810       else {
811         if (buf[0] == '+') 
812         {
813           bp++;
814           if (*bp == '\n' && plus_allowed) 
815           {
816             /* a bare plus means everbody allowed */
817             DEBUG(6, ("check_user_equiv everybody allowed\n"));
818             fclose(fp);
819             return True;
820           }
821         }
822         else if (buf[0] == '-')
823         {
824           bp++;
825           plus = 0;
826         }
827         if (*bp == '@') 
828         {
829           is_group = True;
830           bp++;
831         }
832         file_host = strtok(bp, " \t\n");
833         file_user = strtok(NULL, " \t\n");
834         DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)", 
835                  file_user ? file_user : "(null)" ));
836         if (file_host && *file_host) 
837         {
838           BOOL host_ok = False;
839
840 #if defined(HAVE_NETGROUP) && defined(HAVE_YP_GET_DEFAULT_DOMAIN)
841           if (is_group)
842             {
843               static char *mydomain = NULL;
844               if (!mydomain)
845                 yp_get_default_domain(&mydomain);
846               if (mydomain && innetgr(file_host,remote,user,mydomain))
847                 host_ok = True;
848             }
849 #else
850           if (is_group)
851             {
852               DEBUG(1,("Netgroups not configured\n"));
853               continue;
854             }
855 #endif
856
857           /* is it this host */
858           /* the fact that remote has come from a call of gethostbyaddr
859            * means that it may have the fully qualified domain name
860            * so we could look up the file version to get it into
861            * a canonical form, but I would rather just type it
862            * in full in the equiv file
863            */
864           if (!host_ok && !is_group && strequal(remote, file_host))
865             host_ok = True;
866
867           if (!host_ok)
868             continue;
869
870           /* is it this user */
871           if (file_user == 0 || strequal(user, file_user)) 
872             {
873               fclose(fp);
874               DEBUG(5, ("check_user_equiv matched %s%s %s\n",
875                         (plus ? "+" : "-"), file_host,
876                         (file_user ? file_user : "")));
877               return (plus ? True : False);
878             }
879         }
880       }
881     }
882   }
883   fclose(fp);
884   return False;
885 }
886
887
888 /****************************************************************************
889 check for a possible hosts equiv or rhosts entry for the user
890 ****************************************************************************/
891 BOOL check_hosts_equiv(char *user)
892 {
893   char *fname = NULL;
894   pstring rhostsfile;
895   struct passwd *pass = Get_Pwnam(user,True);
896
897   if (!pass) 
898     return(False);
899
900   fname = lp_hosts_equiv();
901
902   /* note: don't allow hosts.equiv on root */
903   if (fname && *fname && (pass->pw_uid != 0)) {
904           extern int Client;
905           if (check_user_equiv(user,client_name(Client),fname))
906                   return(True);
907   }
908   
909   if (lp_use_rhosts())
910     {
911       char *home = get_home_dir(user);
912       if (home) {
913               extern int Client;
914               slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home);
915               if (check_user_equiv(user,client_name(Client),rhostsfile))
916                       return(True);
917       }
918     }
919
920   return(False);
921 }
922
923
924 /****************************************************************************
925 return the client state structure
926 ****************************************************************************/
927 struct cli_state *server_client(void)
928 {
929         static struct cli_state pw_cli;
930         return &pw_cli;
931 }
932
933 /****************************************************************************
934 support for server level security 
935 ****************************************************************************/
936 struct cli_state *server_cryptkey(void)
937 {
938         struct cli_state *cli;
939         fstring desthost;
940         struct in_addr dest_ip;
941         extern fstring local_machine;
942         char *p;
943         BOOL connected_ok = False;
944         struct nmb_name calling, called;
945
946         cli = server_client();
947
948         if (!cli_initialise(cli))
949                 return NULL;
950
951         p = lp_passwordserver();
952         while(p && next_token( &p, desthost, LIST_SEP, sizeof(desthost))) {
953                 standard_sub_basic(desthost);
954                 strupper(desthost);
955
956                 if(!resolve_name( desthost, &dest_ip, 0x20)) {
957                         DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost));
958                         continue;
959                 }
960
961                 if (ismyip(dest_ip)) {
962                         DEBUG(1,("Password server loop - disabling password server %s\n",desthost));
963                         continue;
964                 }
965
966                 if (cli_connect(cli, desthost, &dest_ip)) {
967                         DEBUG(3,("connected to password server %s\n",desthost));
968                         connected_ok = True;
969                         break;
970                 }
971         }
972
973         if (!connected_ok) {
974                 DEBUG(0,("password server not available\n"));
975                 cli_shutdown(cli);
976                 return NULL;
977         }
978
979         make_nmb_name(&calling, local_machine, 0x0 , scope);
980         make_nmb_name(&called , desthost     , 0x20, scope);
981
982         if (!cli_session_request(cli, &calling, &called))
983         {
984                 DEBUG(1,("%s rejected the session\n",desthost));
985                 cli_shutdown(cli);
986                 return NULL;
987         }
988
989         DEBUG(3,("got session\n"));
990
991         if (!cli_negprot(cli)) {
992                 DEBUG(1,("%s rejected the negprot\n",desthost));
993                 cli_shutdown(cli);
994                 return NULL;
995         }
996
997         if (cli->protocol < PROTOCOL_LANMAN2 ||
998             !(cli->sec_mode & 1)) {
999                 DEBUG(1,("%s isn't in user level security mode\n",desthost));
1000                 cli_shutdown(cli);
1001                 return NULL;
1002         }
1003
1004         DEBUG(3,("password server OK\n"));
1005
1006         return cli;
1007 }
1008
1009 /****************************************************************************
1010 validate a password with the password server
1011 ****************************************************************************/
1012 BOOL server_validate(char *user, char *domain, 
1013                      char *pass, int passlen,
1014                      char *ntpass, int ntpasslen)
1015 {
1016         struct cli_state *cli;
1017         extern fstring local_machine;
1018         static unsigned char badpass[24];
1019         cli = server_client();
1020
1021         if (!cli->initialised) {
1022                 DEBUG(1,("password server %s is not connected\n", cli->desthost));
1023                 return(False);
1024         }  
1025
1026         if(badpass[0] == 0) {
1027           memset(badpass, 0x1f, sizeof(badpass));
1028         }
1029
1030         if((passlen == sizeof(badpass)) && !memcmp(badpass, pass, passlen)) {
1031           /* Very unlikely, our random bad password is the same as the users
1032              password. */
1033           memset(badpass, badpass[0]+1, sizeof(badpass));
1034         }
1035
1036         /*
1037          * Attempt a session setup with a totally incorrect password.
1038          * If this succeeds with the guest bit *NOT* set then the password
1039          * server is broken and is not correctly setting the guest bit. We
1040          * need to detect this as some versions of NT4.x are broken. JRA.
1041          */
1042
1043         if (cli_session_setup(cli, user, (char *)badpass, sizeof(badpass), 
1044                               (char *)badpass, sizeof(badpass), domain)) {
1045           if ((SVAL(cli->inbuf,smb_vwv2) & 1) == 0) {
1046             DEBUG(0,("server_validate: password server %s allows users as non-guest \
1047 with a bad password.\n", cli->desthost));
1048             DEBUG(0,("server_validate: This is broken (and insecure) behaviour. Please do not \
1049 use this machine as the password server.\n"));
1050             cli_ulogoff(cli);
1051             return False;
1052           }
1053           cli_ulogoff(cli);
1054         }
1055
1056         /*
1057          * Now we know the password server will correctly set the guest bit, or is
1058          * not guest enabled, we can try with the real password.
1059          */
1060
1061         if (!cli_session_setup(cli, user, pass, passlen, ntpass, ntpasslen, domain)) {
1062                 DEBUG(1,("password server %s rejected the password\n", cli->desthost));
1063                 return False;
1064         }
1065
1066         /* if logged in as guest then reject */
1067         if ((SVAL(cli->inbuf,smb_vwv2) & 1) != 0) {
1068                 DEBUG(1,("password server %s gave us guest only\n", cli->desthost));
1069                 cli_ulogoff(cli);
1070                 return(False);
1071         }
1072
1073         /*
1074          * This patch from Rob Nielsen <ran@adc.com> makes doing
1075          * the NetWksaUserLogon a dynamic, rather than compile-time
1076          * parameter, defaulting to on. This is somewhat dangerous
1077          * as it allows people to turn off this neccessary check,
1078          * but so many people have had problems with this that I
1079          * think it is a neccessary change. JRA.
1080          */
1081
1082         if (lp_net_wksta_user_logon()) {
1083                 DEBUG(3,("trying NetWkstaUserLogon with password server %s\n", cli->desthost));
1084
1085                 if (!cli_send_tconX(cli, "IPC$", "IPC", "", 1)) {
1086                         DEBUG(0,("password server %s refused IPC$ connect\n", cli->desthost));
1087                         cli_ulogoff(cli);
1088                         return False;
1089                 }
1090
1091                 if (!cli_NetWkstaUserLogon(cli,user,local_machine)) {
1092                         DEBUG(0,("password server %s failed NetWkstaUserLogon\n", cli->desthost));
1093                         cli_tdis(cli);
1094                         cli_ulogoff(cli);
1095                         return False;
1096                 }
1097
1098                 if (cli->privilages == 0) {
1099                         DEBUG(0,("password server %s gave guest privilages\n", cli->desthost));
1100                         cli_tdis(cli);
1101                         cli_ulogoff(cli);
1102                         return False;
1103                 }
1104
1105                 if (!strequal(cli->eff_name, user)) {
1106                         DEBUG(0,("password server %s gave different username %s\n", 
1107                                 cli->desthost,
1108                                 cli->eff_name));
1109                         cli_tdis(cli);
1110                         cli_ulogoff(cli);
1111                         return False;
1112                 }
1113                 cli_tdis(cli);
1114         }
1115         else {
1116                 DEBUG(3,("skipping NetWkstaUserLogon with password server %s\n", cli->desthost));
1117         }
1118
1119         DEBUG(3,("password server %s accepted the password\n", cli->desthost));
1120
1121         cli_ulogoff(cli);
1122
1123         return(True);
1124 }
1125
1126 /***********************************************************************
1127  Do the same as security=server, but using NT Domain calls and a session
1128  key from the machine password.
1129 ************************************************************************/
1130
1131 BOOL domain_client_validate( char *user, char *domain, 
1132                              char *smb_apasswd, int smb_apasslen, 
1133                              char *smb_ntpasswd, int smb_ntpasslen)
1134 {
1135   unsigned char local_challenge[8];
1136   unsigned char local_lm_response[24];
1137   unsigned char local_nt_reponse[24];
1138   unsigned char trust_passwd[16];
1139   time_t lct;
1140   fstring remote_machine;
1141   char *p;
1142   struct in_addr dest_ip;
1143   NET_ID_INFO_CTR ctr;
1144   NET_USER_INFO_3 info3;
1145   struct cli_state cli;
1146   uint32 smb_uid_low;
1147   BOOL connected_ok = False;
1148   struct nmb_name calling, called;
1149
1150   /* 
1151    * Check that the requested domain is not our own machine name.
1152    * If it is, we should never check the PDC here, we use our own local
1153    * password file.
1154    */
1155
1156   if(strequal( domain, global_myname)) {
1157     DEBUG(3,("domain_client_validate: Requested domain was for this machine.\n"));
1158     return False;
1159   }
1160
1161   /*
1162    * Next, check that the passwords given were encrypted.
1163    */
1164
1165   if(((smb_apasslen != 24) && (smb_apasslen != 0)) || 
1166      ((smb_ntpasslen != 24) && (smb_ntpasslen != 0))) {
1167
1168     /*
1169      * Not encrypted - do so.
1170      */
1171
1172     DEBUG(3,("domain_client_validate: User passwords not in encrypted format.\n"));
1173     generate_random_buffer( local_challenge, 8, False);
1174     SMBencrypt( (uchar *)smb_apasswd, local_challenge, local_lm_response);
1175     SMBNTencrypt((uchar *)smb_ntpasswd, local_challenge, local_nt_reponse);
1176     smb_apasslen = 24;
1177     smb_ntpasslen = 24;
1178     smb_apasswd = (char *)local_lm_response;
1179     smb_ntpasswd = (char *)local_nt_reponse;
1180   } else {
1181
1182     /*
1183      * Encrypted - get the challenge we sent for these
1184      * responses.
1185      */
1186
1187     if (!last_challenge(local_challenge)) {
1188       DEBUG(0,("domain_client_validate: no challenge done - password failed\n"));
1189       return False;
1190     }
1191   }
1192
1193   /*
1194    * Get the machine account password.
1195    */
1196   if(!trust_password_lock( global_myworkgroup, global_myname, False)) {
1197     DEBUG(0,("domain_client_validate: unable to open the machine account password file for \
1198 machine %s in domain %s.\n", global_myname, global_myworkgroup ));
1199     return False;
1200   }
1201
1202   if(get_trust_account_password( trust_passwd, &lct) == False) {
1203     DEBUG(0,("domain_client_validate: unable to read the machine account password for \
1204 machine %s in domain %s.\n", global_myname, global_myworkgroup ));
1205     trust_password_unlock();
1206     return False;
1207   }
1208
1209   trust_password_unlock();
1210
1211   /* 
1212    * Here we check the last change time to see if the machine
1213    * password needs changing. JRA. 
1214    */
1215
1216   if(time(NULL) > lct + lp_machine_password_timeout())
1217     global_machine_pasword_needs_changing = True;
1218
1219   /*
1220    * At this point, smb_apasswd points to the lanman response to
1221    * the challenge in local_challenge, and smb_ntpasswd points to
1222    * the NT response to the challenge in local_challenge. Ship
1223    * these over the secure channel to a domain controller and
1224    * see if they were valid.
1225    */
1226
1227   ZERO_STRUCT(cli);
1228
1229   if(cli_initialise(&cli) == False) {
1230     DEBUG(0,("domain_client_validate: unable to initialize client connection.\n"));
1231     return False;
1232   }
1233
1234   /*
1235    * Treat each name in the 'password server =' line as a potential
1236    * PDC/BDC. Contact each in turn and try and authenticate.
1237    */
1238
1239   p = lp_passwordserver();
1240   while(p && next_token(&p,remote_machine,LIST_SEP,sizeof(remote_machine))) {
1241
1242     standard_sub_basic(remote_machine);
1243     strupper(remote_machine);
1244  
1245     if(!resolve_name( remote_machine, &dest_ip, 0x20)) {
1246       DEBUG(1,("domain_client_validate: Can't resolve address for %s\n", remote_machine));
1247       continue;
1248     }   
1249     
1250     if (ismyip(dest_ip)) {
1251       DEBUG(1,("domain_client_validate: Password server loop - not using password server %s\n",remote_machine));
1252       continue;
1253     }
1254       
1255     if (!cli_connect(&cli, remote_machine, &dest_ip)) {
1256       DEBUG(0,("domain_client_validate: unable to connect to SMB server on \
1257 machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
1258       continue;
1259     }
1260     
1261         make_nmb_name(&calling, global_myname , 0x0 , scope);
1262         make_nmb_name(&called , remote_machine, 0x20, scope);
1263
1264         if (!cli_session_request(&cli, &calling, &called))
1265         {
1266       DEBUG(0,("domain_client_validate: machine %s rejected the session setup. \
1267 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
1268       cli_shutdown(&cli);
1269       continue;
1270     }
1271     
1272     cli.protocol = PROTOCOL_NT1;
1273
1274     if (!cli_negprot(&cli)) {
1275       DEBUG(0,("domain_client_validate: machine %s rejected the negotiate protocol. \
1276 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
1277       cli_shutdown(&cli);
1278       continue;
1279     }
1280     
1281     if (cli.protocol != PROTOCOL_NT1) {
1282       DEBUG(0,("domain_client_validate: machine %s didn't negotiate NT protocol.\n",
1283                      remote_machine));
1284       cli_shutdown(&cli);
1285       continue;
1286     }
1287
1288     /* 
1289      * Do an anonymous session setup.
1290      */
1291
1292     if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) {
1293       DEBUG(0,("domain_client_validate: machine %s rejected the session setup. \
1294 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
1295       cli_shutdown(&cli);
1296       continue;
1297     }      
1298
1299     if (!(cli.sec_mode & 1)) {
1300       DEBUG(1,("domain_client_validate: machine %s isn't in user level security mode\n",
1301                  remote_machine));
1302       cli_shutdown(&cli);
1303       continue;
1304     }
1305
1306     if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
1307       DEBUG(0,("domain_client_validate: machine %s rejected the tconX on the IPC$ share. \
1308 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
1309       cli_shutdown(&cli);
1310       continue;
1311     }
1312
1313     /*
1314      * We have an anonymous connection to IPC$.
1315      */
1316     connected_ok = True;
1317     break;
1318   }
1319
1320   if (!connected_ok) {
1321     DEBUG(0,("domain_client_validate: Domain password server not available.\n"));
1322     cli_shutdown(&cli);
1323     return False;
1324   }
1325
1326   /*
1327    * Ok - we have an anonymous connection to the IPC$ share.
1328    * Now start the NT Domain stuff :-).
1329    */
1330
1331   if(cli_nt_session_open(&cli, PIPE_NETLOGON, False) == False) {
1332     DEBUG(0,("domain_client_validate: unable to open the domain client session to \
1333 machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli)));
1334     cli_nt_session_close(&cli);
1335     cli_ulogoff(&cli);
1336     cli_shutdown(&cli);
1337     return False; 
1338   }
1339
1340   if(cli_nt_setup_creds(&cli, trust_passwd) == False) {
1341     DEBUG(0,("domain_client_validate: unable to setup the PDC credentials to machine \
1342 %s. Error was : %s.\n", remote_machine, cli_errstr(&cli)));
1343     cli_nt_session_close(&cli);
1344     cli_ulogoff(&cli);
1345     cli_shutdown(&cli);
1346     return False;
1347   }
1348
1349   /* We really don't care what LUID we give the user. */
1350   generate_random_buffer( (unsigned char *)&smb_uid_low, 4, False);
1351
1352   if(cli_nt_login_network(&cli, domain, user, smb_uid_low, (char *)local_challenge,
1353                           ((smb_apasslen != 0) ? smb_apasswd : NULL),
1354                           ((smb_ntpasslen != 0) ? smb_ntpasswd : NULL),
1355                           &ctr, &info3) == False) {
1356     DEBUG(0,("domain_client_validate: unable to validate password for user %s in domain \
1357 %s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli)));
1358     cli_nt_session_close(&cli);
1359     cli_ulogoff(&cli);
1360     cli_shutdown(&cli);
1361     return False;
1362   }
1363
1364   /*
1365    * Here, if we really want it, we have lots of info about the user in info3.
1366    */
1367
1368 #if 0
1369   /* 
1370    * We don't actually need to do this - plus it fails currently with
1371    * NT_STATUS_INVALID_INFO_CLASS - we need to know *exactly* what to
1372    * send here. JRA.
1373    */
1374
1375   if(cli_nt_logoff(&cli, &ctr) == False) {
1376     DEBUG(0,("domain_client_validate: unable to log off user %s in domain \
1377 %s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli)));        
1378     cli_nt_session_close(&cli);
1379     cli_ulogoff(&cli);
1380     cli_shutdown(&cli);
1381     return False;
1382   }
1383 #endif /* 0 */
1384
1385   cli_nt_session_close(&cli);
1386   cli_ulogoff(&cli);
1387   cli_shutdown(&cli);
1388   return True;
1389 }