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