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