fix a netgroup bug (innetgr() was being called with the args in the
[samba.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-1995
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 #include "loadparm.h"
24
25 extern int DEBUGLEVEL;
26 extern int Protocol;
27
28 /* users from session setup */
29 static pstring session_users="";
30
31 /* these are kept here to keep the string_combinations function simple */
32 static char this_user[100]="";
33 static char this_salt[100]="";
34 static char this_crypted[100]="";
35
36 #ifdef SMB_PASSWD
37 /* Data to do lanman1/2 password challenge. */
38 static unsigned char saved_challenge[8];
39 static BOOL challenge_sent=False;
40
41 /*******************************************************************
42 Get the next challenge value - no repeats.
43 ********************************************************************/
44 void generate_next_challenge(char *challenge)
45 {
46   extern void E1(char *,char *,char *);
47   static int counter = 0;
48   struct timeval tval;
49   int v1,v2;
50   GetTimeOfDay(&tval);
51   v1 = (counter++) + getpid() + tval.tv_sec;
52   v2 = (counter++) * getpid() + tval.tv_usec;
53   SIVAL(challenge,0,v1);
54   SIVAL(challenge,4,v2);
55   E1(challenge,"SAMBA",saved_challenge);
56   memcpy(challenge,saved_challenge,8);
57   challenge_sent = True;
58 }
59
60 /*******************************************************************
61 set the last challenge sent, usually from a password server
62 ********************************************************************/
63 BOOL set_challenge(char *challenge)
64 {
65   memcpy(saved_challenge,challenge,8);
66   challenge_sent = True;
67   return(True);
68 }
69
70 /*******************************************************************
71 get the last challenge sent
72 ********************************************************************/
73 BOOL last_challenge(char *challenge)
74 {
75   if (!challenge_sent) return(False);
76   memcpy(challenge,saved_challenge,8);
77   return(True);
78 }
79 #endif
80
81 /* this holds info on user ids that are already validated for this VC */
82 static user_struct *validated_users = NULL;
83 static int num_validated_users = 0;
84
85 /****************************************************************************
86 check if a uid has been validated, and return an index if it has. -1 if not
87 ****************************************************************************/
88 int valid_uid(int uid)
89 {
90   int i;
91   if (uid == -1) return(-1);
92
93   for (i=0;i<num_validated_users;i++)
94     if (validated_users[i].uid == uid)
95       {
96         DEBUG(3,("valid uid %d mapped to vuid %d (user=%s)\n",
97                  uid,i,validated_users[i].name));
98         return(i);
99       }
100   return(-1);
101 }
102
103 /****************************************************************************
104 check if a uid has been validated, and return an pointer to the user_struct
105 if it has. NULL if not
106 ****************************************************************************/
107 user_struct *get_valid_user_struct(int uid)
108 {
109   int vuid = valid_uid(uid);
110   if(vuid == -1 || validated_users[vuid].guest)
111     return NULL;
112   return &validated_users[vuid];
113 }
114
115 /****************************************************************************
116 invalidate a uid
117 ****************************************************************************/
118 void invalidate_uid(int uid)
119 {
120   int i;
121   for (i=0;i<num_validated_users;i++)
122     if (validated_users[i].uid == uid)
123       {
124         user_struct *vuser = &validated_users[i];
125         vuser->uid = -1;
126         vuser->gid = -1;
127         vuser->user_ngroups = 0;
128         if(vuser->user_groups && 
129            (vuser->user_groups != (gid_t *)vuser->user_igroups))
130           free(vuser->user_groups);
131         vuser->user_groups = NULL;
132         if(vuser->user_igroups)
133           free(vuser->user_igroups);
134         vuser->user_igroups = NULL;
135       }
136 }
137
138
139 /****************************************************************************
140 return a validated username
141 ****************************************************************************/
142 char *validated_username(int vuid)
143 {
144   return(validated_users[vuid].name);
145 }
146
147 /****************************************************************************
148 register a uid/name pair as being valid and that a valid password
149 has been given.
150 ****************************************************************************/
151 void register_uid(int uid,int gid, char *name,BOOL guest)
152 {
153   user_struct *vuser;
154
155   if (valid_uid(uid) >= 0)
156     return;
157   validated_users = (user_struct *)Realloc(validated_users,
158                                            sizeof(user_struct)*
159                                            (num_validated_users+1));
160
161   if (!validated_users)
162     {
163       DEBUG(0,("Failed to realloc users struct!\n"));
164       return;
165     }
166
167   vuser = &validated_users[num_validated_users];
168   vuser->uid = uid;
169   vuser->gid = gid;
170   vuser->guest = guest;
171   strcpy(vuser->name,name);
172
173   vuser->user_ngroups = 0;
174   vuser->user_groups = NULL;
175   vuser->user_igroups = NULL;
176
177   /* Find all the groups this uid is in and store them. 
178      Used by become_user() */
179   setup_groups(name,uid,gid,
180                &vuser->user_ngroups,
181                &vuser->user_igroups,
182                &vuser->user_groups);
183
184   DEBUG(3,("uid %d registered to name %s\n",uid,name));
185   
186   num_validated_users++;
187 }
188
189
190 /****************************************************************************
191 add a name to the session users list
192 ****************************************************************************/
193 void add_session_user(char *user)
194 {
195   fstring suser;
196   StrnCpy(suser,user,sizeof(suser)-1);
197
198   if (!Get_Pwnam(suser,True)) return;
199
200   if (suser && *suser && !in_list(suser,session_users,False))
201     {
202       if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring))
203         DEBUG(1,("Too many session users??\n"));
204       else
205         {
206           strcat(session_users," ");
207           strcat(session_users,suser);
208         }
209     }
210 }
211
212
213 #ifdef NO_GETSPNAM
214 /* a fake shadow password routine which just fills a fake spwd struct
215  * with the sp_pwdp field. (sreiz@aie.nl)
216  */
217 static struct spwd *getspnam(char *username) /* fake shadow password routine */
218 {
219        FILE *f;
220        char line[1024];
221        static char pw[20];
222        static struct spwd static_spwd;
223
224        static_spwd.sp_pwdp=0;
225        if (!(f=fopen("/etc/master.passwd", "r")))
226                return 0;
227        while (fgets(line, 1024, f)) {
228                if (!strncmp(line, username, strlen(username)) &&
229                 line[strlen(username)]==':') { /* found entry */
230                        char *p, *q;
231
232                        p=line+strlen(username)+1;
233                        if ((q=strchr(p, ':'))) {
234                                *q=0;
235                                if (q-p+1>20)
236                                        break;
237                                strcpy(pw, p);
238                                static_spwd.sp_pwdp=pw;
239                        }
240                        break;
241                }
242        }
243        fclose(f);
244        if (static_spwd.sp_pwdp)
245                return &static_spwd;
246        return 0;
247 }
248 #endif
249
250
251 #ifdef OSF1_ENH_SEC
252 /****************************************************************************
253 an enhanced crypt for OSF1
254 ****************************************************************************/
255 static char *osf1_bigcrypt(char *password,char *salt1)
256 {
257   static char result[AUTH_MAX_PASSWD_LENGTH] = "";
258   char *p1;
259   char *p2=password;
260   char salt[3];
261   int i;
262   int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
263   if (strlen(password)%AUTH_CLEARTEXT_SEG_CHARS)
264     parts++;
265
266   StrnCpy(salt,salt1,2);
267   StrnCpy(result,salt1,2);
268
269   for (i=0; i<parts;i++)
270     {
271       p1 = crypt(p2,salt);
272       strcat(result,p1+2);
273       StrnCpy(salt,&result[2+i*AUTH_CIPHERTEXT_SEG_CHARS],2);
274       p2 += AUTH_CLEARTEXT_SEG_CHARS;
275     }
276
277   return(result);
278 }
279 #endif
280
281
282 /****************************************************************************
283 update the enhanced security database. Only relevant for OSF1 at the moment.
284 ****************************************************************************/
285 static void update_protected_database( char *user, BOOL result)
286 {
287 #ifdef OSF1_ENH_SEC
288   struct pr_passwd *mypasswd;
289   time_t starttime;
290   long tz;
291
292   mypasswd = getprpwnam (user);
293   starttime = time (NULL);
294   tz = mktime ( localtime ( &starttime ) );
295
296   if (result)
297     {
298       mypasswd->ufld.fd_slogin = tz;
299       mypasswd->ufld.fd_nlogins = 0;
300       
301       putprpwnam(user,mypasswd);
302       
303       DEBUG(3,("Update protected database for Account %s after succesful connection\n",user));
304     }
305   else
306     {
307       mypasswd->ufld.fd_ulogin = tz;
308       mypasswd->ufld.fd_nlogins = mypasswd->ufld.fd_nlogins + 1;
309       if ( mypasswd->ufld.fd_max_tries != 0 && mypasswd->ufld.fd_nlogins > mypasswd->ufld.fd_max_tries )
310         {
311           mypasswd->uflg.fg_lock = 0;
312           DEBUG(3,("Account is disabled -- see Account Administrator.\n"));
313         }
314       putprpwnam ( user , mypasswd );
315       DEBUG(3,("Update protected database for Account %s after refusing connection\n",user));
316     }
317 #else
318   DEBUG(6,("Updated database with %s %s\n",user,BOOLSTR(result)));
319 #endif
320 }
321
322
323 #ifdef AFS_AUTH
324 /*******************************************************************
325 check on AFS authentication
326 ********************************************************************/
327 static BOOL afs_auth(char *this_user,char *password)
328 {
329   long password_expires = 0;
330   char *reason;
331     
332   /* For versions of AFS prior to 3.3, this routine has few arguments, */
333   /* but since I can't find the old documentation... :-)               */
334   setpag();
335   if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
336                                  this_user,
337                                  (char *) 0, /* instance */
338                                  (char *) 0, /* cell */
339                                  password,
340                                  0,          /* lifetime, default */
341                                  &password_expires, /*days 'til it expires */
342                                  0,          /* spare 2 */
343                                  &reason) == 0)
344     return(True);
345   return(False);
346 }
347 #endif
348
349
350 #ifdef DFS_AUTH
351
352 sec_login_handle_t my_dce_sec_context;
353 int dcelogin_atmost_once = 0;
354
355 /*******************************************************************
356 check on a DCE/DFS authentication
357 ********************************************************************/
358 static BOOL dfs_auth(char *this_user,char *password)
359 {
360   error_status_t err;
361   int err2;
362   int prterr;
363   boolean32 password_reset;
364   sec_passwd_rec_t my_dce_password;
365   sec_login_auth_src_t auth_src = sec_login_auth_src_network;
366   unsigned char dce_errstr[dce_c_error_string_len];
367
368   /*
369    * We only go for a DCE login context if the given password
370    * matches that stored in the local password file.. 
371    * Assumes local passwd file is kept in sync w/ DCE RGY!
372    */
373
374   if (!strcmp((char *)crypt(password,this_salt),this_crypted) ||
375       dcelogin_atmost_once)
376     return(False);
377
378   if (sec_login_setup_identity(
379                                (unsigned char *)this_user,
380                                sec_login_no_flags,
381                                &my_dce_sec_context,
382                                &err) == 0)
383     {
384       dce_error_inq_text(err, dce_errstr, &err2);
385       DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
386                this_user,dce_errstr));
387       return(False);
388     }
389
390   my_dce_password.version_number = sec_passwd_c_version_none;
391   my_dce_password.pepper = NULL; 
392   my_dce_password.key.key_type = sec_passwd_plain;
393   my_dce_password.key.tagged_union.plain  = (idl_char *)password;
394   
395   if (sec_login_valid_and_cert_ident(my_dce_sec_context,
396                                      &my_dce_password,
397                                      &password_reset,
398                                      &auth_src,
399                                      &err) == 0 )
400     { 
401       dce_error_inq_text(err, dce_errstr, &err2);
402       DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
403                this_user,dce_errstr));
404           
405       return(False);
406     }
407
408   sec_login_set_context(my_dce_sec_context, &err);
409   if (err != error_status_ok )
410     {  
411       dce_error_inq_text(err, dce_errstr, &err2);
412       DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
413                this_user,dce_errstr));
414       sec_login_purge_context(my_dce_sec_context, &err);
415       return(False);
416     }
417   else
418     {
419       DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
420                this_user, getpid()));
421     }
422
423   dcelogin_atmost_once = 1;
424   return (True);
425 }
426
427 void dfs_unlogin(void)
428 {
429   error_status_t err;
430   int err2;
431   unsigned char dce_errstr[dce_c_error_string_len];
432
433   sec_login_purge_context(my_dce_sec_context, &err);
434   if (err != error_status_ok )
435     {  
436       dce_error_inq_text(err, dce_errstr, &err2);
437       DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
438                getpid(), dce_errstr));
439     }
440 }
441
442 #endif
443
444
445 #ifdef LINUX_BIGCRYPT
446 /****************************************************************************
447 an enhanced crypt for Linux to handle password longer than 8 characters
448 ****************************************************************************/
449 static int linux_bigcrypt(char *password,char *salt1, char *crypted)
450 {
451 #define LINUX_PASSWORD_SEG_CHARS 8
452   char salt[3];
453   int i;
454   
455   StrnCpy(salt,salt1,2);
456   crypted +=2;
457   
458   for ( i=strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
459     char * p = crypt(password,salt) + 2;
460     if(strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
461       return(0);
462     password += LINUX_PASSWORD_SEG_CHARS;
463     crypted  += strlen(p);
464   }
465   
466   return(1);
467 }
468 #endif
469
470
471 /****************************************************************************
472 apply a function to upper/lower case combinations
473 of a string and return true if one of them returns true.
474 try all combinations with N uppercase letters.
475 offset is the first char to try and change (start with 0)
476 it assumes the string starts lowercased
477 ****************************************************************************/
478 static BOOL string_combinations2(char *s,int offset,BOOL (*fn)(),int N)
479 {
480   int len = strlen(s);
481   int i;
482
483 #ifdef PASSWORD_LENGTH
484   len = MIN(len,PASSWORD_LENGTH);
485 #endif
486
487   if (N <= 0 || offset >= len)
488     return(fn(s));
489
490   for (i=offset;i<(len-(N-1));i++)
491     {      
492       char c = s[i];
493       if (!islower(c)) continue;
494       s[i] = toupper(c);
495       if (string_combinations2(s,i+1,fn,N-1))
496         return(True);
497       s[i] = c;
498     }
499   return(False);
500 }
501
502 /****************************************************************************
503 apply a function to upper/lower case combinations
504 of a string and return true if one of them returns true.
505 try all combinations with up to N uppercase letters.
506 offset is the first char to try and change (start with 0)
507 it assumes the string starts lowercased
508 ****************************************************************************/
509 static BOOL string_combinations(char *s,BOOL (*fn)(),int N)
510 {
511   int n;
512   for (n=1;n<=N;n++)
513     if (string_combinations2(s,0,fn,n)) return(True);
514   return(False);
515 }
516
517
518
519 /****************************************************************************
520 core of password checking routine
521 ****************************************************************************/
522 BOOL password_check(char *password)
523 {
524 #ifdef AFS_AUTH
525   if (afs_auth(this_user,password)) return(True);
526 #endif
527
528 #ifdef DFS_AUTH
529   if (dfs_auth(this_user,password)) return(True);
530 #endif 
531
532 #ifdef PWDAUTH
533   if (pwdauth(this_user,password) == 0)
534     return(True);
535 #endif
536
537 #ifdef OSF1_ENH_SEC
538   return(strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0);
539 #endif
540
541 #ifdef ULTRIX_AUTH
542   return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
543 #endif
544
545 #ifdef LINUX_BIGCRYPT
546   return(linux_bigcrypt(password,this_salt,this_crypted));
547 #endif
548
549 #ifdef NO_CRYPT
550   DEBUG(1,("Warning - no crypt available\n"));
551   return(False);
552 #else
553   return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
554 #endif
555 }
556
557 #ifdef SMB_PASSWD
558 /****************************************************************************
559 core of smb password checking routine.
560 ****************************************************************************/
561 BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8)
562 {
563   /* Finish the encryption of part_passwd. */
564   unsigned char p21[21];
565   unsigned char p24[24];
566
567   if(part_passwd == NULL)
568     DEBUG(10,("No password set - allowing access\n"));
569   /* No password set - always true ! */
570   if(part_passwd == NULL)
571     return 1;
572
573   memset(p21,'\0',21);
574   memcpy(p21,part_passwd,16);
575   E_P24(p21, c8, p24);
576 #if DEBUG_PASSWORD
577   {
578     int i;
579     DEBUG(100,("Part password (P16) was |"));
580     for(i = 0; i < 16; i++)
581       DEBUG(100,("%X ", (unsigned char)part_passwd[i]));
582     DEBUG(100,("|\n"));
583     DEBUG(100,("Password from client was |"));
584     for(i = 0; i < 24; i++)
585       DEBUG(100,("%X ", (unsigned char)password[i]));
586     DEBUG(100,("|\n"));
587     DEBUG(100,("Given challenge was |"));
588     for(i = 0; i < 8; i++)
589       DEBUG(100,("%X ", (unsigned char)c8[i]));
590     DEBUG(100,("|\n"));
591     DEBUG(100,("Value from encryption was |"));
592     for(i = 0; i < 24; i++)
593       DEBUG(100,("%X ", (unsigned char)p24[i]));
594     DEBUG(100,("|\n"));
595   }
596 #endif
597   return (memcmp(p24, password, 24) == 0);
598 }
599 #endif
600
601 /****************************************************************************
602 check if a username/password is OK
603 ****************************************************************************/
604 BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd, BOOL is_nt_password)
605 {
606   pstring pass2;
607   int level = lp_passwordlevel();
608   struct passwd *pass;
609 #ifdef SMB_PASSWD
610   char challenge[8];
611   struct smb_passwd *smb_pass;
612   BOOL challenge_done = False;
613 #endif
614
615   if (password) password[pwlen] = 0;
616
617 #ifdef SMB_PASSWD
618   if (pwlen == 24)
619     challenge_done = last_challenge(challenge);
620 #endif
621
622 #if DEBUG_PASSWORD
623 #ifdef SMB_PASSWD
624   if (challenge_done)
625     {
626       int i;      
627       DEBUG(100,("checking user=[%s] pass=[",user));
628       for( i = 0; i < 24; i++)
629         DEBUG(100,("%0x ", (unsigned char)password[i]));
630       DEBUG(100,("]\n"));
631     }
632   else
633 #endif
634     DEBUG(100,("checking user=[%s] pass=[%s]\n",user,password));
635 #endif
636
637   if (!password)
638     return(False);
639
640   if (((!*password) || (!pwlen)) && !lp_null_passwords())
641     return(False);
642
643   if (pwd && !user) 
644     {
645       pass = (struct passwd *) pwd;
646       user = pass->pw_name;
647     } 
648   else 
649     pass = Get_Pwnam(user,True);
650
651 #ifdef SMB_PASSWD
652
653   DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen, challenge_done));
654
655   if((pwlen == 24) && challenge_done)
656     {
657       DEBUG(4,("Checking SMB password for user %s (l=24)\n",user));
658
659       if (!pass) 
660         {
661           DEBUG(3,("Couldn't find user %s\n",user));
662           return(False);
663         }
664
665       smb_pass = get_smbpwnam(user);
666       if(!smb_pass)
667         {
668           DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
669           return(False);
670         }
671
672       /* Ensure the uid's match */
673       if(smb_pass->smb_userid != pass->pw_uid)
674         {
675           DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
676           return(False);
677         }
678
679         if(Protocol >= PROTOCOL_NT1 && is_nt_password)
680         {
681                 /* We have the NT MD4 hash challenge available - see if we can
682                    use it (ie. does it exist in the smbpasswd file).
683                 */
684                 if(smb_pass->smb_nt_passwd != NULL)
685                 {
686                   DEBUG(4,("Checking NT MD4 password\n"));
687               if(smb_password_check(password, smb_pass->smb_nt_passwd, challenge))
688                   {
689                 update_protected_database(user,True);
690                 return(True);
691           }
692                   DEBUG(4,("NT MD4 password check failed\n"));
693                   return (False);
694                 }
695         }
696
697         /* Try against the lanman password */
698
699       if(smb_password_check(password, smb_pass->smb_passwd, challenge))
700         {
701           update_protected_database(user,True);
702           return(True);
703         }
704
705         DEBUG(3,("Error smb_password_check failed\n"));
706     }
707 #endif 
708
709   DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
710
711   if (!pass) 
712     {
713       DEBUG(3,("Couldn't find user %s\n",user));
714       return(False);
715     }
716
717 #ifdef SHADOW_PWD
718   {
719     struct spwd *spass;
720
721     /* many shadow systems require you to be root to get the password,
722        in most cases this should already be the case when this
723        function is called, except perhaps for IPC password changing
724        requests */
725
726     spass = getspnam(pass->pw_name);
727     if (spass && spass->sp_pwdp)
728       pass->pw_passwd = spass->sp_pwdp;
729   }
730 #endif
731
732 #ifdef SecureWare
733   {
734     struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
735     if (pr_pw && pr_pw->ufld.fd_encrypt)
736       pass->pw_passwd = pr_pw->ufld.fd_encrypt;
737   }
738 #endif
739
740 #ifdef HPUX_10_TRUSTED
741   {
742     struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
743     if (pr_pw && pr_pw->ufld.fd_encrypt)
744       pass->pw_passwd = pr_pw->ufld.fd_encrypt;
745   }
746 #endif
747
748 #ifdef OSF1_ENH_SEC
749   {
750     struct pr_passwd *mypasswd;
751     DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user));
752     mypasswd = getprpwnam (user);
753     if ( mypasswd )
754       { 
755         strcpy(pass->pw_name,mypasswd->ufld.fd_name);
756         strcpy(pass->pw_passwd,mypasswd->ufld.fd_encrypt);
757       }
758     else
759       {
760         DEBUG(5,("No entry for user %s in protected database !\n",user));
761         return(False);
762       }
763   }
764 #endif
765
766 #ifdef ULTRIX_AUTH
767   {
768     AUTHORIZATION *ap = getauthuid( pass->pw_uid );
769     if (ap)
770       {
771         strcpy( pass->pw_passwd, ap->a_password );
772         endauthent();
773       }
774   }
775 #endif
776
777   /* extract relevant info */
778   strcpy(this_user,pass->pw_name);  
779   strcpy(this_salt,pass->pw_passwd);
780   strcpy(this_crypted,pass->pw_passwd);
781  
782   if (!*this_crypted) {
783     if (!lp_null_passwords()) {
784       DEBUG(2,("Disallowing access to %s due to null password\n",this_user));
785       return(False);
786     }
787 #ifndef PWDAUTH
788     if (!*password) {
789       DEBUG(3,("Allowing access to %s with null password\n",this_user));
790       return(True);
791     }
792 #endif    
793   }
794
795   /* try it as it came to us */
796   if (password_check(password))
797     {
798       update_protected_database(user,True);
799       return(True);
800     }
801
802   /* if the password was given to us with mixed case then we don't
803      need to proceed as we know it hasn't been case modified by the
804      client */
805   if (strhasupper(password) && strhaslower(password))
806     return(False);
807
808   /* make a copy of it */
809   StrnCpy(pass2,password,sizeof(pstring)-1);
810   
811   /* try all lowercase */
812   strlower(password);
813   if (password_check(password))
814     {
815       update_protected_database(user,True);
816       return(True);
817     }
818
819   /* give up? */
820   if(level < 1)
821     {
822       update_protected_database(user,False);
823
824       /* restore it */
825       strcpy(password,pass2);
826
827       return(False);
828     }
829
830   /* last chance - all combinations of up to level chars upper! */
831   strlower(password);
832
833   if (string_combinations(password,password_check,level))
834     {
835       update_protected_database(user,True);
836       return(True);
837     }
838
839   update_protected_database(user,False);
840   
841   /* restore it */
842   strcpy(password,pass2);
843   
844   return(False);
845 }
846
847
848
849 /****************************************************************************
850 check if a username is valid
851 ****************************************************************************/
852 BOOL user_ok(char *user,int snum)
853 {
854   pstring valid, invalid;
855   BOOL ret;
856
857   StrnCpy(valid, lp_valid_users(snum), sizeof(pstring));
858   StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring));
859
860   string_sub(valid,"%S",lp_servicename(snum));
861   string_sub(invalid,"%S",lp_servicename(snum));
862
863   ret = !user_in_list(user,invalid);
864
865   if (ret && valid && *valid)
866     ret = user_in_list(user,valid);
867
868   if (ret && lp_onlyuser(snum)) {
869     char *user_list = lp_username(snum);
870     string_sub(user_list,"%S",lp_servicename(snum));
871     ret = user_in_list(user,user_list);
872   }
873
874   return(ret);
875 }
876
877
878
879
880 /****************************************************************************
881 validate a group username entry. Return the username or NULL
882 ****************************************************************************/
883 static char *validate_group(char *group,char *password,int pwlen,int snum)
884 {
885 #ifdef NETGROUP
886   {
887     char *host, *user, *domain;
888     setnetgrent(group);
889     while (getnetgrent(&host, &user, &domain)) {
890       if (user) {
891         if (user_ok(user, snum) && 
892             password_ok(user,password,pwlen,NULL,False)) {
893           endnetgrent();
894           return(user);
895         }
896       }
897     }
898     endnetgrent();
899   }
900 #endif
901   
902 #if HAVE_GETGRNAM 
903   {
904     struct group *gptr = (struct group *)getgrnam(group);
905     char **member;
906     if (gptr)
907       {
908         member = gptr->gr_mem;
909         while (member && *member)
910           {
911             static fstring name;
912             strcpy(name,*member);
913             if (user_ok(name,snum) &&
914                 password_ok(name,password,pwlen,NULL,False))
915               return(&name[0]);
916             member++;
917           }
918 #ifdef GROUP_CHECK_PWENT
919         {
920           struct passwd *pwd;
921           static fstring tm;
922           
923           setpwent ();
924           while (pwd = getpwent ()) {
925             if (*(pwd->pw_passwd) && pwd->pw_gid == gptr->gr_gid) {
926               /* This Entry have PASSWORD and same GID then check pwd */
927               if (password_ok(NULL, password, pwlen, pwd,False)) {
928                 strcpy(tm, pwd->pw_name);
929                 endpwent ();
930                 return tm;
931               }
932             }
933           }
934           endpwent ();
935         }
936 #endif /* GROUP_CHECK_PWENT */
937       }
938   }      
939 #endif
940   return(NULL);
941 }
942
943
944
945 /****************************************************************************
946 check for authority to login to a service with a given username/password
947 ****************************************************************************/
948 BOOL authorise_login(int snum,char *user,char *password, int pwlen, 
949                      BOOL *guest,BOOL *force,int vuid)
950 {
951   BOOL ok = False;
952   
953   *guest = False;
954   
955 #if DEBUG_PASSWORD
956   DEBUG(100,("checking authorisation on user=%s pass=%s\n",user,password));
957 #endif
958
959   /* there are several possabilities:
960      1) login as the given user with given password
961      2) login as a previously registered username with the given password
962      3) login as a session list username with the given password
963      4) login as a previously validated user/password pair
964      5) login as the "user =" user with given password
965      6) login as the "user =" user with no password (guest connection)
966      7) login as guest user with no password
967
968      if the service is guest_only then steps 1 to 5 are skipped
969   */
970
971   if (GUEST_ONLY(snum)) *force = True;
972
973   if (!(GUEST_ONLY(snum) && GUEST_OK(snum)))
974     {
975
976       /* check the given username and password */
977       if (!ok && (*user) && user_ok(user,snum)) {
978         ok = password_ok(user,password, pwlen, NULL, False);
979         if (ok) DEBUG(3,("ACCEPTED: given username password ok\n"));
980       }
981
982       /* check for a previously registered guest username */
983       if (!ok && (vuid >= 0) && validated_users[vuid].guest) {    
984         if (user_ok(validated_users[vuid].name,snum) &&
985             password_ok(validated_users[vuid].name, password, pwlen, NULL, False)) {
986           strcpy(user, validated_users[vuid].name);
987           validated_users[vuid].guest = False;
988           DEBUG(3,("ACCEPTED: given password with registered user %s\n", user));
989           ok = True;
990         }
991       }
992
993
994       /* now check the list of session users */
995       if (!ok)
996         {
997           char *auser;
998           char *user_list = strdup(session_users);
999           if (!user_list) return(False);
1000
1001           for (auser=strtok(user_list,LIST_SEP); 
1002                !ok && auser; 
1003                auser = strtok(NULL,LIST_SEP))
1004             {
1005               fstring user2;
1006               strcpy(user2,auser);
1007               if (!user_ok(user2,snum)) continue;
1008                   
1009               if (password_ok(user2,password, pwlen, NULL, False)) {
1010                 ok = True;
1011                 strcpy(user,user2);
1012                 DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
1013               }
1014             }
1015           free(user_list);
1016         }
1017
1018       /* check for a previously validated username/password pair */
1019       if (!ok && !lp_revalidate(snum) &&
1020           (vuid >= 0) && !validated_users[vuid].guest &&
1021           user_ok(validated_users[vuid].name,snum)) {
1022         strcpy(user,validated_users[vuid].name);
1023         *guest = False;
1024         DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
1025         ok = True;
1026       }
1027
1028       /* check for a rhosts entry */
1029       if (!ok && user_ok(user,snum) && check_hosts_equiv(user)) {
1030         ok = True;
1031         DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
1032       }
1033
1034       /* check the user= fields and the given password */
1035       if (!ok && lp_username(snum)) {
1036         char *auser;
1037         pstring user_list;
1038         StrnCpy(user_list,lp_username(snum),sizeof(pstring));
1039
1040         string_sub(user_list,"%S",lp_servicename(snum));
1041           
1042         for (auser=strtok(user_list,LIST_SEP);
1043              auser && !ok;
1044              auser = strtok(NULL,LIST_SEP))
1045           {
1046             if (*auser == '@')
1047               {
1048                 auser = validate_group(auser+1,password,pwlen,snum);
1049                 if (auser)
1050                   {
1051                     ok = True;
1052                     strcpy(user,auser);
1053                     DEBUG(3,("ACCEPTED: group username and given password ok\n"));
1054                   }
1055               }
1056             else
1057               {
1058                 fstring user2;
1059                 strcpy(user2,auser);
1060                 if (user_ok(user2,snum) && 
1061                     password_ok(user2,password,pwlen,NULL, False))
1062                   {
1063                     ok = True;
1064                     strcpy(user,user2);
1065                     DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
1066                   }
1067               }
1068           }
1069       }      
1070     } /* not guest only */
1071
1072   /* check for a normal guest connection */
1073   if (!ok && GUEST_OK(snum))
1074     {
1075       fstring guestname;
1076       StrnCpy(guestname,lp_guestaccount(snum),sizeof(guestname)-1);
1077       if (Get_Pwnam(guestname,True))
1078         {
1079           strcpy(user,guestname);
1080           ok = True;
1081           DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
1082         }
1083       else
1084         DEBUG(0,("Invalid guest account %s??\n",guestname));
1085       *guest = True;
1086       *force = True;
1087     }
1088
1089   if (ok && !user_ok(user,snum))
1090     {
1091       DEBUG(0,("rejected invalid user %s\n",user));
1092       ok = False;
1093     }
1094
1095   return(ok);
1096 }
1097
1098
1099 /****************************************************************************
1100 read the a hosts.equiv or .rhosts file and check if it
1101 allows this user from this machine
1102 ****************************************************************************/
1103 static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
1104 {
1105   pstring buf;
1106   int plus_allowed = 1;
1107   char *file_host;
1108   char *file_user;
1109   FILE *fp = fopen(equiv_file, "r");
1110   DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
1111   if (! fp) return False;
1112   while(fgets(buf, sizeof(buf), fp)) 
1113   {
1114     trim_string(buf," "," ");
1115
1116     if (buf[0] != '#' && buf[0] != '\n') 
1117     {
1118       BOOL is_group = False;
1119       int plus = 1;
1120       char *bp = buf;
1121       if (strcmp(buf, "NO_PLUS\n") == 0)
1122       {
1123         DEBUG(6, ("check_user_equiv NO_PLUS\n"));
1124         plus_allowed = 0;
1125       }
1126       else {
1127         if (buf[0] == '+') 
1128         {
1129           bp++;
1130           if (*bp == '\n' && plus_allowed) 
1131           {
1132             /* a bare plus means everbody allowed */
1133             DEBUG(6, ("check_user_equiv everybody allowed\n"));
1134             fclose(fp);
1135             return True;
1136           }
1137         }
1138         else if (buf[0] == '-')
1139         {
1140           bp++;
1141           plus = 0;
1142         }
1143         if (*bp == '@') 
1144         {
1145           is_group = True;
1146           bp++;
1147         }
1148         file_host = strtok(bp, " \t\n");
1149         file_user = strtok(NULL, " \t\n");
1150         DEBUG(7, ("check_user_equiv %s %s\n", file_host, file_user));
1151         if (file_host && *file_host) 
1152         {
1153           BOOL host_ok = False;
1154
1155 #ifdef NETGROUP   
1156           if (is_group)
1157             {
1158               static char *mydomain = NULL;
1159               if (!mydomain)
1160                 yp_get_default_domain(&mydomain);
1161               if (mydomain && innetgr(file_host,remote,user,mydomain))
1162                 host_ok = True;
1163             }
1164 #else
1165           if (is_group)
1166             {
1167               DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n"));
1168               continue;
1169             }
1170 #endif
1171
1172           /* is it this host */
1173           /* the fact that remote has come from a call of gethostbyaddr
1174            * means that it may have the fully qualified domain name
1175            * so we could look up the file version to get it into
1176            * a canonical form, but I would rather just type it
1177            * in full in the equiv file
1178            */
1179           if (!host_ok && !is_group && strequal(remote, file_host))
1180             host_ok = True;
1181
1182           if (!host_ok)
1183             continue;
1184
1185           /* is it this user */
1186           if (file_user == 0 || strequal(user, file_user)) 
1187             {
1188               fclose(fp);
1189               DEBUG(5, ("check_user_equiv matched %s%s %s\n",
1190                         (plus ? "+" : "-"), file_host,
1191                         (file_user ? file_user : "")));
1192               return (plus ? True : False);
1193             }
1194         }
1195       }
1196     }
1197   }
1198   fclose(fp);
1199   return False;
1200 }
1201
1202
1203 /****************************************************************************
1204 check for a possible hosts equiv or rhosts entry for the user
1205 ****************************************************************************/
1206 BOOL check_hosts_equiv(char *user)
1207 {
1208   char *fname = NULL;
1209   pstring rhostsfile;
1210   struct passwd *pass = Get_Pwnam(user,True);
1211
1212   extern struct from_host Client_info;
1213   extern int Client;
1214
1215   if (!pass) 
1216     return(False);
1217
1218   fromhost(Client,&Client_info);
1219
1220   fname = lp_hosts_equiv();
1221
1222   /* note: don't allow hosts.equiv on root */
1223   if (fname && *fname && (pass->pw_uid != 0))
1224     {
1225       if (check_user_equiv(user,Client_info.name,fname))
1226         return(True);
1227     }
1228   
1229   if (lp_use_rhosts())
1230     {
1231       char *home = get_home_dir(user);
1232       if (home)
1233         {
1234           sprintf(rhostsfile, "%s/.rhosts", home);
1235           if (check_user_equiv(user,Client_info.name,rhostsfile))
1236             return(True);
1237         }
1238     }
1239
1240   return(False);
1241 }
1242
1243
1244 static int password_client = -1;
1245 static fstring pserver;
1246
1247 /****************************************************************************
1248 attempted support for server level security 
1249 ****************************************************************************/
1250 BOOL server_cryptkey(char *buf)
1251 {
1252   pstring inbuf,outbuf;
1253   fstring pass_protocol;
1254   extern fstring remote_machine;
1255   char *p;
1256   int len;
1257   fstring desthost;
1258   struct in_addr dest_ip;
1259   extern struct in_addr myip;
1260   int port = 139;
1261   BOOL ret;
1262
1263   if (password_client >= 0)
1264     close(password_client);
1265   password_client = -1;
1266
1267   if (Protocol < PROTOCOL_NT1) {
1268     strcpy(pass_protocol,"LM1.2X002");
1269   } else {
1270     strcpy(pass_protocol,"NT LM 0.12");
1271   }
1272
1273   bzero(inbuf,sizeof(inbuf));
1274   bzero(outbuf,sizeof(outbuf));
1275
1276   for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) {
1277     strcpy(desthost,p);
1278     standard_sub_basic(desthost);
1279     strupper(desthost);
1280
1281     dest_ip = *interpret_addr2(desthost);
1282     if (zero_ip(dest_ip)) {
1283       DEBUG(1,("Can't resolve address for %s\n",p));
1284       continue;
1285     }
1286
1287     if (memcmp(&dest_ip,&myip,sizeof(dest_ip)) == 0) {
1288       DEBUG(1,("Password server loop - disabling password server %s\n",p));
1289       continue;
1290     }
1291
1292     password_client = open_socket_out(SOCK_STREAM, &dest_ip, port);
1293     if (password_client >= 0) {
1294       DEBUG(3,("connected to password server %s\n",p));
1295       StrnCpy(pserver,p,sizeof(pserver)-1);
1296       break;
1297     }
1298   }
1299
1300   if (password_client < 0) {
1301     DEBUG(1,("password server not available\n"));
1302     return(False);
1303   }
1304
1305
1306   /* send a session request (RFC 8002) */
1307
1308   /* put in the destination name */
1309   len = 4;
1310   p = outbuf+len;
1311   name_mangle(desthost,p,' ');
1312   len += name_len(p);
1313
1314   /* and my name */
1315   p = outbuf+len;
1316   name_mangle(remote_machine,p,' ');
1317   len += name_len(p);
1318
1319   _smb_setlen(outbuf,len);
1320   CVAL(outbuf,0) = 0x81;
1321
1322   send_smb(password_client,outbuf);
1323   receive_smb(password_client,inbuf,5000);
1324  
1325   if (CVAL(inbuf,0) != 0x82) {
1326     DEBUG(1,("%s rejected the session\n",pserver));
1327     close(password_client); password_client = -1;
1328     return(False);
1329   }
1330
1331   DEBUG(3,("got session\n"));
1332
1333   bzero(outbuf,smb_size);
1334
1335   /* setup the protocol string */
1336   set_message(outbuf,0,strlen(pass_protocol)+2,True);
1337   p = smb_buf(outbuf);
1338   *p++ = 2;
1339   strcpy(p,pass_protocol);
1340
1341   CVAL(outbuf,smb_com) = SMBnegprot;
1342   CVAL(outbuf,smb_flg) = 0x8;
1343   SSVAL(outbuf,smb_flg2,0x1);
1344
1345   send_smb(password_client,outbuf);
1346   ret = receive_smb(password_client,inbuf,5000);
1347
1348   if (!ret || CVAL(inbuf,smb_rcls) || SVAL(inbuf,smb_vwv0)) {
1349     DEBUG(1,("%s rejected the protocol\n",pserver));
1350     close(password_client); password_client= -1;
1351     return(False);
1352   }
1353
1354   if (!(CVAL(inbuf,smb_vwv1) & 1)) {
1355     DEBUG(1,("%s isn't in user level security mode\n",pserver));
1356     close(password_client); password_client= -1;
1357     return(False);
1358   }
1359
1360   memcpy(buf,inbuf,smb_len(inbuf)+4);
1361
1362   DEBUG(3,("password server OK\n"));
1363
1364   return(True);
1365 }
1366
1367 /****************************************************************************
1368 attempted support for server level security 
1369 ****************************************************************************/
1370 BOOL server_validate(char *buf)
1371 {
1372   pstring inbuf,outbuf;  
1373   BOOL ret;
1374
1375   if (password_client < 0) {
1376     DEBUG(1,("%s not connected\n",pserver));
1377     return(False);
1378   }  
1379
1380   bzero(inbuf,sizeof(inbuf));
1381   memcpy(outbuf,buf,sizeof(outbuf));
1382
1383   /* send a session setup command */
1384   CVAL(outbuf,smb_flg) = 0x8;
1385   SSVAL(outbuf,smb_flg2,0x1);
1386   CVAL(outbuf,smb_vwv0) = 0xFF;
1387
1388   set_message(outbuf,smb_numwords(outbuf),smb_buflen(outbuf),False);
1389
1390   SCVAL(inbuf,smb_rcls,1);
1391
1392   send_smb(password_client,outbuf);
1393   ret = receive_smb(password_client,inbuf,5000);
1394
1395   if (!ret || CVAL(inbuf,smb_rcls) != 0) {
1396     DEBUG(1,("password server %s rejected the password\n",pserver));
1397     return(False);
1398   }
1399
1400   /* if logged in as guest then reject */
1401   if ((SVAL(inbuf,smb_vwv2) & 1) != 0) {
1402     DEBUG(1,("password server %s gave us guest only\n",pserver));
1403     return(False);
1404   }
1405
1406   DEBUG(3,("password server %s accepted the password\n",pserver));
1407
1408 #ifndef KEEP_PASSWORD_SERVER_OPEN
1409   close(password_client); password_client= -1;
1410 #endif
1411
1412   return(True);
1413 }
1414
1415