JHT ==> Added extensions for PAM (Pluggable Authentication Module) support
[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 USE_PAM
316 /*******************************************************************
317 check on PAM authentication
318 ********************************************************************/
319
320 /* We first need some helper functions */
321 #include <security/pam_appl.h>
322 /* Static variables used to communicate between the conversation function
323  * and the server_login function
324  */
325 static char *PAM_username;
326 static char *PAM_password;
327
328 /* PAM conversation function
329  * Here we assume (for now, at least) that echo on means login name, and
330  * echo off means password.
331  */
332 static int PAM_conv (int num_msg,
333                      const struct pam_message **msg,
334                      struct pam_response **resp,
335                      void *appdata_ptr) {
336   int count = 0, replies = 0;
337   struct pam_response *reply = NULL;
338   int size = sizeof(struct pam_response);
339
340   #define GET_MEM if (reply) realloc(reply, size); else reply = malloc(size); \
341   if (!reply) return PAM_CONV_ERR; \
342   size += sizeof(struct pam_response)
343   #define COPY_STRING(s) (s) ? strdup(s) : NULL
344
345   for (count = 0; count < num_msg; count++) {
346     switch (msg[count]->msg_style) {
347       case PAM_PROMPT_ECHO_ON:
348         GET_MEM;
349         reply[replies].resp_retcode = PAM_SUCCESS;
350         reply[replies++].resp = COPY_STRING(PAM_username);
351           /* PAM frees resp */
352         break;
353       case PAM_PROMPT_ECHO_OFF:
354         GET_MEM;
355         reply[replies].resp_retcode = PAM_SUCCESS;
356         reply[replies++].resp = COPY_STRING(PAM_password);
357           /* PAM frees resp */
358         break;
359       case PAM_TEXT_INFO:
360         /* ignore it... */
361         break;
362       case PAM_ERROR_MSG:
363       default:
364         /* Must be an error of some sort... */
365         free (reply);
366         return PAM_CONV_ERR;
367     }
368   }
369   if (reply) *resp = reply;
370   return PAM_SUCCESS;
371 }
372 static struct pam_conv PAM_conversation = {
373     &PAM_conv,
374     NULL
375 };
376
377
378 static BOOL pam_auth(char *this_user,char *password)
379 {
380   pam_handle_t *pamh;
381   int pam_error;
382
383   /* Now use PAM to do authentication.  For now, we won't worry about
384    * session logging, only authentication.  Bail out if there are any
385    * errors.  Since this is a limited protocol, and an even more limited
386    * function within a server speaking this protocol, we can't be as
387    * verbose as would otherwise make sense.
388    * Query: should we be using PAM_SILENT to shut PAM up?
389    */
390   #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
391      pam_end(pamh, 0); return False; \
392    }
393   PAM_password = password;
394   PAM_username = this_user;
395   pam_error = pam_start("samba", this_user, &PAM_conversation, &pamh);
396   PAM_BAIL;
397   pam_error = pam_authenticate(pamh, 0);
398   PAM_BAIL;
399   /* It is not clear to me that account management is the right thing
400    * to do, but it is not clear that it isn't, either.  This can be
401    * removed if no account management should be done.  Alternately,
402    * put a pam_allow.so entry in /etc/pam.conf for account handling. */
403   pam_error = pam_acct_mgmt(pamh, 0);
404   PAM_BAIL;
405   pam_end(pamh, PAM_SUCCESS);
406   /* If this point is reached, the user has been authenticated. */
407   return(True);
408 }
409 #endif
410
411
412 #ifdef AFS_AUTH
413 /*******************************************************************
414 check on AFS authentication
415 ********************************************************************/
416 static BOOL afs_auth(char *this_user,char *password)
417 {
418   long password_expires = 0;
419   char *reason;
420     
421   /* For versions of AFS prior to 3.3, this routine has few arguments, */
422   /* but since I can't find the old documentation... :-)               */
423   setpag();
424   if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
425                                  this_user,
426                                  (char *) 0, /* instance */
427                                  (char *) 0, /* cell */
428                                  password,
429                                  0,          /* lifetime, default */
430                                  &password_expires, /*days 'til it expires */
431                                  0,          /* spare 2 */
432                                  &reason) == 0)
433     return(True);
434   return(False);
435 }
436 #endif
437
438
439 #ifdef DFS_AUTH
440
441 sec_login_handle_t my_dce_sec_context;
442 int dcelogin_atmost_once = 0;
443
444 /*******************************************************************
445 check on a DCE/DFS authentication
446 ********************************************************************/
447 static BOOL dfs_auth(char *this_user,char *password)
448 {
449   error_status_t err;
450   int err2;
451   int prterr;
452   boolean32 password_reset;
453   sec_passwd_rec_t my_dce_password;
454   sec_login_auth_src_t auth_src = sec_login_auth_src_network;
455   unsigned char dce_errstr[dce_c_error_string_len];
456
457   /*
458    * We only go for a DCE login context if the given password
459    * matches that stored in the local password file.. 
460    * Assumes local passwd file is kept in sync w/ DCE RGY!
461    */
462
463   if (!strcmp((char *)crypt(password,this_salt),this_crypted) ||
464       dcelogin_atmost_once)
465     return(False);
466
467   if (sec_login_setup_identity(
468                                (unsigned char *)this_user,
469                                sec_login_no_flags,
470                                &my_dce_sec_context,
471                                &err) == 0)
472     {
473       dce_error_inq_text(err, dce_errstr, &err2);
474       DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
475                this_user,dce_errstr));
476       return(False);
477     }
478
479   my_dce_password.version_number = sec_passwd_c_version_none;
480   my_dce_password.pepper = NULL; 
481   my_dce_password.key.key_type = sec_passwd_plain;
482   my_dce_password.key.tagged_union.plain  = (idl_char *)password;
483   
484   if (sec_login_valid_and_cert_ident(my_dce_sec_context,
485                                      &my_dce_password,
486                                      &password_reset,
487                                      &auth_src,
488                                      &err) == 0 )
489     { 
490       dce_error_inq_text(err, dce_errstr, &err2);
491       DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
492                this_user,dce_errstr));
493           
494       return(False);
495     }
496
497   sec_login_set_context(my_dce_sec_context, &err);
498   if (err != error_status_ok )
499     {  
500       dce_error_inq_text(err, dce_errstr, &err2);
501       DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
502                this_user,dce_errstr));
503       sec_login_purge_context(my_dce_sec_context, &err);
504       return(False);
505     }
506   else
507     {
508       DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
509                this_user, getpid()));
510     }
511
512   dcelogin_atmost_once = 1;
513   return (True);
514 }
515
516 void dfs_unlogin(void)
517 {
518   error_status_t err;
519   int err2;
520   unsigned char dce_errstr[dce_c_error_string_len];
521
522   sec_login_purge_context(my_dce_sec_context, &err);
523   if (err != error_status_ok )
524     {  
525       dce_error_inq_text(err, dce_errstr, &err2);
526       DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
527                getpid(), dce_errstr));
528     }
529 }
530
531 #endif
532
533
534 #ifdef LINUX_BIGCRYPT
535 /****************************************************************************
536 an enhanced crypt for Linux to handle password longer than 8 characters
537 ****************************************************************************/
538 static int linux_bigcrypt(char *password,char *salt1, char *crypted)
539 {
540 #define LINUX_PASSWORD_SEG_CHARS 8
541   char salt[3];
542   int i;
543   
544   StrnCpy(salt,salt1,2);
545   crypted +=2;
546   
547   for ( i=strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
548     char * p = crypt(password,salt) + 2;
549     if(strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
550       return(0);
551     password += LINUX_PASSWORD_SEG_CHARS;
552     crypted  += strlen(p);
553   }
554   
555   return(1);
556 }
557 #endif
558
559
560 /****************************************************************************
561 apply a function to upper/lower case combinations
562 of a string and return true if one of them returns true.
563 try all combinations with N uppercase letters.
564 offset is the first char to try and change (start with 0)
565 it assumes the string starts lowercased
566 ****************************************************************************/
567 static BOOL string_combinations2(char *s,int offset,BOOL (*fn)(),int N)
568 {
569   int len = strlen(s);
570   int i;
571
572 #ifdef PASSWORD_LENGTH
573   len = MIN(len,PASSWORD_LENGTH);
574 #endif
575
576   if (N <= 0 || offset >= len)
577     return(fn(s));
578
579   for (i=offset;i<(len-(N-1));i++)
580     {      
581       char c = s[i];
582       if (!islower(c)) continue;
583       s[i] = toupper(c);
584       if (string_combinations2(s,i+1,fn,N-1))
585         return(True);
586       s[i] = c;
587     }
588   return(False);
589 }
590
591 /****************************************************************************
592 apply a function to upper/lower case combinations
593 of a string and return true if one of them returns true.
594 try all combinations with up to N uppercase letters.
595 offset is the first char to try and change (start with 0)
596 it assumes the string starts lowercased
597 ****************************************************************************/
598 static BOOL string_combinations(char *s,BOOL (*fn)(),int N)
599 {
600   int n;
601   for (n=1;n<=N;n++)
602     if (string_combinations2(s,0,fn,n)) return(True);
603   return(False);
604 }
605
606
607
608 /****************************************************************************
609 core of password checking routine
610 ****************************************************************************/
611 BOOL password_check(char *password)
612 {
613
614 #ifdef USE_PAM
615   if (pam_auth(this_user,password)) return(True);
616 #endif
617
618 #ifdef AFS_AUTH
619   if (afs_auth(this_user,password)) return(True);
620 #endif
621
622 #ifdef DFS_AUTH
623   if (dfs_auth(this_user,password)) return(True);
624 #endif 
625
626 #ifdef PWDAUTH
627   if (pwdauth(this_user,password) == 0)
628     return(True);
629 #endif
630
631 #ifdef OSF1_ENH_SEC
632   return(strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0);
633 #endif
634
635 #ifdef ULTRIX_AUTH
636   return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
637 #endif
638
639 #ifdef LINUX_BIGCRYPT
640   return(linux_bigcrypt(password,this_salt,this_crypted));
641 #endif
642
643 #ifdef NO_CRYPT
644   DEBUG(1,("Warning - no crypt available\n"));
645   return(False);
646 #else
647   return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
648 #endif
649 }
650
651 #ifdef SMB_PASSWD
652 /****************************************************************************
653 core of smb password checking routine.
654 ****************************************************************************/
655 BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8)
656 {
657   /* Finish the encryption of part_passwd. */
658   unsigned char p21[21];
659   unsigned char p24[24];
660
661   if(part_passwd == NULL)
662     DEBUG(10,("No password set - allowing access\n"));
663   /* No password set - always true ! */
664   if(part_passwd == NULL)
665     return 1;
666
667   memset(p21,'\0',21);
668   memcpy(p21,part_passwd,16);
669   E_P24(p21, c8, p24);
670 #if DEBUG_PASSWORD
671   {
672     int i;
673     DEBUG(100,("Part password (P16) was |"));
674     for(i = 0; i < 16; i++)
675       DEBUG(100,("%X ", (unsigned char)part_passwd[i]));
676     DEBUG(100,("|\n"));
677     DEBUG(100,("Password from client was |"));
678     for(i = 0; i < 24; i++)
679       DEBUG(100,("%X ", (unsigned char)password[i]));
680     DEBUG(100,("|\n"));
681     DEBUG(100,("Given challenge was |"));
682     for(i = 0; i < 8; i++)
683       DEBUG(100,("%X ", (unsigned char)c8[i]));
684     DEBUG(100,("|\n"));
685     DEBUG(100,("Value from encryption was |"));
686     for(i = 0; i < 24; i++)
687       DEBUG(100,("%X ", (unsigned char)p24[i]));
688     DEBUG(100,("|\n"));
689   }
690 #endif
691   return (memcmp(p24, password, 24) == 0);
692 }
693 #endif
694
695 /****************************************************************************
696 check if a username/password is OK
697 ****************************************************************************/
698 BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd)
699 {
700   pstring pass2;
701   int level = lp_passwordlevel();
702   struct passwd *pass;
703 #ifdef SMB_PASSWD
704   char challenge[8];
705   struct smb_passwd *smb_pass;
706   BOOL challenge_done = False;
707 #endif
708
709   if (password) password[pwlen] = 0;
710
711 #ifdef SMB_PASSWD
712   if (pwlen == 24)
713     challenge_done = last_challenge(challenge);
714 #endif
715
716 #if DEBUG_PASSWORD
717 #ifdef SMB_PASSWD
718   if (challenge_done)
719     {
720       int i;      
721       DEBUG(100,("checking user=[%s] pass=[",user));
722       for( i = 0; i < 24; i++)
723         DEBUG(100,("%0x ", (unsigned char)password[i]));
724       DEBUG(100,("]\n"));
725     }
726   else
727 #endif
728     DEBUG(100,("checking user=[%s] pass=[%s]\n",user,password));
729 #endif
730
731   if (!password)
732     return(False);
733
734   if (((!*password) || (!pwlen)) && !lp_null_passwords())
735     return(False);
736
737   if (pwd && !user) 
738     {
739       pass = (struct passwd *) pwd;
740       user = pass->pw_name;
741     } 
742   else 
743     pass = Get_Pwnam(user,True);
744
745 #ifdef SMB_PASSWD
746
747   DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen, challenge_done));
748
749   if((pwlen == 24) && challenge_done)
750     {
751       DEBUG(4,("Checking SMB password for user %s (l=24)\n",user));
752
753       if (!pass) 
754         {
755           DEBUG(3,("Couldn't find user %s\n",user));
756           return(False);
757         }
758
759       smb_pass = get_smbpwnam(user);
760       if(!smb_pass)
761         {
762           DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
763           return(False);
764         }
765
766       /* Ensure the uid's match */
767       if(smb_pass->smb_userid != pass->pw_uid)
768         {
769           DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
770           return(False);
771         }
772
773         if(Protocol >= PROTOCOL_NT1)
774         {
775                 /* We have the NT MD4 hash challenge available - see if we can
776                    use it (ie. does it exist in the smbpasswd file).
777                 */
778                 if(smb_pass->smb_nt_passwd != NULL)
779                 {
780                   DEBUG(4,("Checking NT MD4 password\n"));
781                   if(smb_password_check(password, 
782                                         smb_pass->smb_nt_passwd, 
783                                         (char *)challenge))
784                   {
785                 update_protected_database(user,True);
786                 return(True);
787           }
788                   DEBUG(4,("NT MD4 password check failed\n"));
789                 }
790         }
791
792         /* Try against the lanman password */
793
794       if (smb_password_check(password, 
795                              smb_pass->smb_passwd,
796                              (char *)challenge)) {
797         update_protected_database(user,True);
798         return(True);
799       }
800
801         DEBUG(3,("Error smb_password_check failed\n"));
802     }
803 #endif 
804
805   DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
806
807   if (!pass) 
808     {
809       DEBUG(3,("Couldn't find user %s\n",user));
810       return(False);
811     }
812
813 #ifdef SHADOW_PWD
814   {
815     struct spwd *spass;
816
817     /* many shadow systems require you to be root to get the password,
818        in most cases this should already be the case when this
819        function is called, except perhaps for IPC password changing
820        requests */
821
822     spass = getspnam(pass->pw_name);
823     if (spass && spass->sp_pwdp)
824       pass->pw_passwd = spass->sp_pwdp;
825   }
826 #endif
827
828 #ifdef SecureWare
829   {
830     struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
831     if (pr_pw && pr_pw->ufld.fd_encrypt)
832       pass->pw_passwd = pr_pw->ufld.fd_encrypt;
833   }
834 #endif
835
836 #ifdef HPUX_10_TRUSTED
837   {
838     struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
839     if (pr_pw && pr_pw->ufld.fd_encrypt)
840       pass->pw_passwd = pr_pw->ufld.fd_encrypt;
841   }
842 #endif
843
844 #ifdef OSF1_ENH_SEC
845   {
846     struct pr_passwd *mypasswd;
847     DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user));
848     mypasswd = getprpwnam (user);
849     if ( mypasswd )
850       { 
851         strcpy(pass->pw_name,mypasswd->ufld.fd_name);
852         strcpy(pass->pw_passwd,mypasswd->ufld.fd_encrypt);
853       }
854     else
855       {
856         DEBUG(5,("No entry for user %s in protected database !\n",user));
857         return(False);
858       }
859   }
860 #endif
861
862 #ifdef ULTRIX_AUTH
863   {
864     AUTHORIZATION *ap = getauthuid( pass->pw_uid );
865     if (ap)
866       {
867         strcpy( pass->pw_passwd, ap->a_password );
868         endauthent();
869       }
870   }
871 #endif
872
873   /* extract relevant info */
874   strcpy(this_user,pass->pw_name);  
875   strcpy(this_salt,pass->pw_passwd);
876   strcpy(this_crypted,pass->pw_passwd);
877  
878   if (!*this_crypted) {
879     if (!lp_null_passwords()) {
880       DEBUG(2,("Disallowing access to %s due to null password\n",this_user));
881       return(False);
882     }
883 #ifndef PWDAUTH
884     if (!*password) {
885       DEBUG(3,("Allowing access to %s with null password\n",this_user));
886       return(True);
887     }
888 #endif    
889   }
890
891   /* try it as it came to us */
892   if (password_check(password))
893     {
894       update_protected_database(user,True);
895       return(True);
896     }
897
898   /* if the password was given to us with mixed case then we don't
899      need to proceed as we know it hasn't been case modified by the
900      client */
901   if (strhasupper(password) && strhaslower(password))
902     return(False);
903
904   /* make a copy of it */
905   StrnCpy(pass2,password,sizeof(pstring)-1);
906   
907   /* try all lowercase */
908   strlower(password);
909   if (password_check(password))
910     {
911       update_protected_database(user,True);
912       return(True);
913     }
914
915   /* give up? */
916   if(level < 1)
917     {
918       update_protected_database(user,False);
919
920       /* restore it */
921       strcpy(password,pass2);
922
923       return(False);
924     }
925
926   /* last chance - all combinations of up to level chars upper! */
927   strlower(password);
928
929   if (string_combinations(password,password_check,level))
930     {
931       update_protected_database(user,True);
932       return(True);
933     }
934
935   update_protected_database(user,False);
936   
937   /* restore it */
938   strcpy(password,pass2);
939   
940   return(False);
941 }
942
943
944
945 /****************************************************************************
946 check if a username is valid
947 ****************************************************************************/
948 BOOL user_ok(char *user,int snum)
949 {
950   pstring valid, invalid;
951   BOOL ret;
952
953   StrnCpy(valid, lp_valid_users(snum), sizeof(pstring));
954   StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring));
955
956   string_sub(valid,"%S",lp_servicename(snum));
957   string_sub(invalid,"%S",lp_servicename(snum));
958
959   ret = !user_in_list(user,invalid);
960
961   if (ret && valid && *valid)
962     ret = user_in_list(user,valid);
963
964   if (ret && lp_onlyuser(snum)) {
965     char *user_list = lp_username(snum);
966     string_sub(user_list,"%S",lp_servicename(snum));
967     ret = user_in_list(user,user_list);
968   }
969
970   return(ret);
971 }
972
973
974
975
976 /****************************************************************************
977 validate a group username entry. Return the username or NULL
978 ****************************************************************************/
979 static char *validate_group(char *group,char *password,int pwlen,int snum)
980 {
981 #ifdef NETGROUP
982   {
983     char *host, *user, *domain;
984     setnetgrent(group);
985     while (getnetgrent(&host, &user, &domain)) {
986       if (user) {
987         if (user_ok(user, snum) && 
988             password_ok(user,password,pwlen,NULL)) {
989           endnetgrent();
990           return(user);
991         }
992       }
993     }
994     endnetgrent();
995   }
996 #endif
997   
998 #if HAVE_GETGRNAM 
999   {
1000     struct group *gptr = (struct group *)getgrnam(group);
1001     char **member;
1002     if (gptr)
1003       {
1004         member = gptr->gr_mem;
1005         while (member && *member)
1006           {
1007             static fstring name;
1008             strcpy(name,*member);
1009             if (user_ok(name,snum) &&
1010                 password_ok(name,password,pwlen,NULL))
1011               return(&name[0]);
1012             member++;
1013           }
1014 #ifdef GROUP_CHECK_PWENT
1015         {
1016           struct passwd *pwd;
1017           static fstring tm;
1018           
1019           setpwent ();
1020           while (pwd = getpwent ()) {
1021             if (*(pwd->pw_passwd) && pwd->pw_gid == gptr->gr_gid) {
1022               /* This Entry have PASSWORD and same GID then check pwd */
1023               if (password_ok(NULL, password, pwlen, pwd)) {
1024                 strcpy(tm, pwd->pw_name);
1025                 endpwent ();
1026                 return tm;
1027               }
1028             }
1029           }
1030           endpwent ();
1031         }
1032 #endif /* GROUP_CHECK_PWENT */
1033       }
1034   }      
1035 #endif
1036   return(NULL);
1037 }
1038
1039
1040
1041 /****************************************************************************
1042 check for authority to login to a service with a given username/password
1043 ****************************************************************************/
1044 BOOL authorise_login(int snum,char *user,char *password, int pwlen, 
1045                      BOOL *guest,BOOL *force,uint16 vuid)
1046 {
1047   BOOL ok = False;
1048   
1049   *guest = False;
1050   
1051 #if DEBUG_PASSWORD
1052   DEBUG(100,("checking authorisation on user=%s pass=%s\n",user,password));
1053 #endif
1054
1055   /* there are several possabilities:
1056      1) login as the given user with given password
1057      2) login as a previously registered username with the given password
1058      3) login as a session list username with the given password
1059      4) login as a previously validated user/password pair
1060      5) login as the "user =" user with given password
1061      6) login as the "user =" user with no password (guest connection)
1062      7) login as guest user with no password
1063
1064      if the service is guest_only then steps 1 to 5 are skipped
1065   */
1066
1067   if (GUEST_ONLY(snum)) *force = True;
1068
1069   if (!(GUEST_ONLY(snum) && GUEST_OK(snum)))
1070     {
1071
1072       user_struct *vuser = get_valid_user_struct(vuid);
1073
1074       /* check the given username and password */
1075       if (!ok && (*user) && user_ok(user,snum)) {
1076         ok = password_ok(user,password, pwlen, NULL);
1077         if (ok) DEBUG(3,("ACCEPTED: given username password ok\n"));
1078       }
1079
1080       /* check for a previously registered guest username */
1081       if (!ok && (vuser != 0) && vuser->guest) {          
1082         if (user_ok(vuser->name,snum) &&
1083             password_ok(vuser->name, password, pwlen, NULL)) {
1084           strcpy(user, vuser->name);
1085           vuser->guest = False;
1086           DEBUG(3,("ACCEPTED: given password with registered user %s\n", user));
1087           ok = True;
1088         }
1089       }
1090
1091
1092       /* now check the list of session users */
1093       if (!ok)
1094         {
1095           char *auser;
1096           char *user_list = strdup(session_users);
1097           if (!user_list) return(False);
1098
1099           for (auser=strtok(user_list,LIST_SEP); 
1100                !ok && auser; 
1101                auser = strtok(NULL,LIST_SEP))
1102             {
1103               fstring user2;
1104               strcpy(user2,auser);
1105               if (!user_ok(user2,snum)) continue;
1106                   
1107               if (password_ok(user2,password, pwlen, NULL)) {
1108                 ok = True;
1109                 strcpy(user,user2);
1110                 DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
1111               }
1112             }
1113           free(user_list);
1114         }
1115
1116       /* check for a previously validated username/password pair */
1117       if (!ok && !lp_revalidate(snum) &&
1118           (vuser != 0) && !vuser->guest &&
1119           user_ok(vuser->name,snum)) {
1120         strcpy(user,vuser->name);
1121         *guest = False;
1122         DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
1123         ok = True;
1124       }
1125
1126       /* check for a rhosts entry */
1127       if (!ok && user_ok(user,snum) && check_hosts_equiv(user)) {
1128         ok = True;
1129         DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
1130       }
1131
1132       /* check the user= fields and the given password */
1133       if (!ok && lp_username(snum)) {
1134         char *auser;
1135         pstring user_list;
1136         StrnCpy(user_list,lp_username(snum),sizeof(pstring));
1137
1138         string_sub(user_list,"%S",lp_servicename(snum));
1139           
1140         for (auser=strtok(user_list,LIST_SEP);
1141              auser && !ok;
1142              auser = strtok(NULL,LIST_SEP))
1143           {
1144             if (*auser == '@')
1145               {
1146                 auser = validate_group(auser+1,password,pwlen,snum);
1147                 if (auser)
1148                   {
1149                     ok = True;
1150                     strcpy(user,auser);
1151                     DEBUG(3,("ACCEPTED: group username and given password ok\n"));
1152                   }
1153               }
1154             else
1155               {
1156                 fstring user2;
1157                 strcpy(user2,auser);
1158                 if (user_ok(user2,snum) && 
1159                     password_ok(user2,password,pwlen,NULL))
1160                   {
1161                     ok = True;
1162                     strcpy(user,user2);
1163                     DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
1164                   }
1165               }
1166           }
1167       }      
1168     } /* not guest only */
1169
1170   /* check for a normal guest connection */
1171   if (!ok && GUEST_OK(snum))
1172     {
1173       fstring guestname;
1174       StrnCpy(guestname,lp_guestaccount(snum),sizeof(guestname)-1);
1175       if (Get_Pwnam(guestname,True))
1176         {
1177           strcpy(user,guestname);
1178           ok = True;
1179           DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
1180         }
1181       else
1182         DEBUG(0,("Invalid guest account %s??\n",guestname));
1183       *guest = True;
1184       *force = True;
1185     }
1186
1187   if (ok && !user_ok(user,snum))
1188     {
1189       DEBUG(0,("rejected invalid user %s\n",user));
1190       ok = False;
1191     }
1192
1193   return(ok);
1194 }
1195
1196
1197 /****************************************************************************
1198 read the a hosts.equiv or .rhosts file and check if it
1199 allows this user from this machine
1200 ****************************************************************************/
1201 static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
1202 {
1203   pstring buf;
1204   int plus_allowed = 1;
1205   char *file_host;
1206   char *file_user;
1207   FILE *fp = fopen(equiv_file, "r");
1208   DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
1209   if (! fp) return False;
1210   while(fgets(buf, sizeof(buf), fp)) 
1211   {
1212     trim_string(buf," "," ");
1213
1214     if (buf[0] != '#' && buf[0] != '\n') 
1215     {
1216       BOOL is_group = False;
1217       int plus = 1;
1218       char *bp = buf;
1219       if (strcmp(buf, "NO_PLUS\n") == 0)
1220       {
1221         DEBUG(6, ("check_user_equiv NO_PLUS\n"));
1222         plus_allowed = 0;
1223       }
1224       else {
1225         if (buf[0] == '+') 
1226         {
1227           bp++;
1228           if (*bp == '\n' && plus_allowed) 
1229           {
1230             /* a bare plus means everbody allowed */
1231             DEBUG(6, ("check_user_equiv everybody allowed\n"));
1232             fclose(fp);
1233             return True;
1234           }
1235         }
1236         else if (buf[0] == '-')
1237         {
1238           bp++;
1239           plus = 0;
1240         }
1241         if (*bp == '@') 
1242         {
1243           is_group = True;
1244           bp++;
1245         }
1246         file_host = strtok(bp, " \t\n");
1247         file_user = strtok(NULL, " \t\n");
1248         DEBUG(7, ("check_user_equiv %s %s\n", file_host, file_user));
1249         if (file_host && *file_host) 
1250         {
1251           BOOL host_ok = False;
1252
1253 #ifdef NETGROUP   
1254           if (is_group)
1255             {
1256               static char *mydomain = NULL;
1257               if (!mydomain)
1258                 yp_get_default_domain(&mydomain);
1259               if (mydomain && innetgr(file_host,remote,user,mydomain))
1260                 host_ok = True;
1261             }
1262 #else
1263           if (is_group)
1264             {
1265               DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n"));
1266               continue;
1267             }
1268 #endif
1269
1270           /* is it this host */
1271           /* the fact that remote has come from a call of gethostbyaddr
1272            * means that it may have the fully qualified domain name
1273            * so we could look up the file version to get it into
1274            * a canonical form, but I would rather just type it
1275            * in full in the equiv file
1276            */
1277           if (!host_ok && !is_group && strequal(remote, file_host))
1278             host_ok = True;
1279
1280           if (!host_ok)
1281             continue;
1282
1283           /* is it this user */
1284           if (file_user == 0 || strequal(user, file_user)) 
1285             {
1286               fclose(fp);
1287               DEBUG(5, ("check_user_equiv matched %s%s %s\n",
1288                         (plus ? "+" : "-"), file_host,
1289                         (file_user ? file_user : "")));
1290               return (plus ? True : False);
1291             }
1292         }
1293       }
1294     }
1295   }
1296   fclose(fp);
1297   return False;
1298 }
1299
1300
1301 /****************************************************************************
1302 check for a possible hosts equiv or rhosts entry for the user
1303 ****************************************************************************/
1304 BOOL check_hosts_equiv(char *user)
1305 {
1306   char *fname = NULL;
1307   pstring rhostsfile;
1308   struct passwd *pass = Get_Pwnam(user,True);
1309
1310   if (!pass) 
1311     return(False);
1312
1313   fname = lp_hosts_equiv();
1314
1315   /* note: don't allow hosts.equiv on root */
1316   if (fname && *fname && (pass->pw_uid != 0))
1317     {
1318       if (check_user_equiv(user,client_name(),fname))
1319         return(True);
1320     }
1321   
1322   if (lp_use_rhosts())
1323     {
1324       char *home = get_home_dir(user);
1325       if (home)
1326         {
1327           sprintf(rhostsfile, "%s/.rhosts", home);
1328           if (check_user_equiv(user,client_name(),rhostsfile))
1329             return(True);
1330         }
1331     }
1332
1333   return(False);
1334 }
1335
1336
1337 int password_client = -1;
1338 static fstring pserver;
1339
1340 /****************************************************************************
1341 attempted support for server level security 
1342 ****************************************************************************/
1343 BOOL server_cryptkey(char *buf)
1344 {
1345   pstring inbuf,outbuf;
1346   fstring pass_protocol;
1347   extern fstring remote_machine;
1348   char *p;
1349   int len;
1350   fstring desthost;
1351   struct in_addr dest_ip;
1352   int port = SMB_PORT;
1353   BOOL ret;
1354
1355   if (password_client >= 0)
1356     close(password_client);
1357   password_client = -1;
1358
1359   if (Protocol < PROTOCOL_NT1) {
1360     strcpy(pass_protocol,"LM1.2X002");
1361   } else {
1362     strcpy(pass_protocol,"NT LM 0.12");
1363   }
1364
1365   bzero(inbuf,sizeof(inbuf));
1366   bzero(outbuf,sizeof(outbuf));
1367
1368   for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) {
1369     strcpy(desthost,p);
1370     standard_sub_basic(desthost);
1371     strupper(desthost);
1372
1373     dest_ip = *interpret_addr2(desthost);
1374     if (zero_ip(dest_ip)) {
1375       DEBUG(1,("Can't resolve address for %s\n",p));
1376       continue;
1377     }
1378
1379     if (ismyip(dest_ip)) {
1380       DEBUG(1,("Password server loop - disabling password server %s\n",p));
1381       continue;
1382     }
1383
1384     password_client = open_socket_out(SOCK_STREAM, &dest_ip, port, SHORT_CONNECT_TIMEOUT);
1385     if (password_client >= 0) {
1386       DEBUG(3,("connected to password server %s\n",p));
1387       StrnCpy(pserver,p,sizeof(pserver)-1);
1388       break;
1389     }
1390   }
1391
1392   if (password_client < 0) {
1393     DEBUG(1,("password server not available\n"));
1394     return(False);
1395   }
1396
1397
1398   /* send a session request (RFC 8002) */
1399
1400   /* put in the destination name */
1401   len = 4;
1402   p = outbuf+len;
1403   name_mangle(desthost,p,' ');
1404   len += name_len(p);
1405
1406   /* and my name */
1407   p = outbuf+len;
1408   name_mangle(remote_machine,p,' ');
1409   len += name_len(p);
1410
1411   _smb_setlen(outbuf,len);
1412   CVAL(outbuf,0) = 0x81;
1413
1414   send_smb(password_client,outbuf);
1415   
1416  
1417   if (!receive_smb(password_client,inbuf,5000) ||
1418       CVAL(inbuf,0) != 0x82) {
1419     DEBUG(1,("%s rejected the session\n",pserver));
1420     close(password_client); password_client = -1;
1421     return(False);
1422   }
1423
1424   DEBUG(3,("got session\n"));
1425
1426   bzero(outbuf,smb_size);
1427
1428   /* setup the protocol string */
1429   set_message(outbuf,0,strlen(pass_protocol)+2,True);
1430   p = smb_buf(outbuf);
1431   *p++ = 2;
1432   strcpy(p,pass_protocol);
1433
1434   CVAL(outbuf,smb_com) = SMBnegprot;
1435   CVAL(outbuf,smb_flg) = 0x8;
1436   SSVAL(outbuf,smb_flg2,0x1);
1437
1438   send_smb(password_client,outbuf);
1439   ret = receive_smb(password_client,inbuf,5000);
1440
1441   if (!ret || CVAL(inbuf,smb_rcls) || SVAL(inbuf,smb_vwv0)) {
1442     DEBUG(1,("%s rejected the protocol\n",pserver));
1443     close(password_client); password_client= -1;
1444     return(False);
1445   }
1446
1447   if (!(CVAL(inbuf,smb_vwv1) & 1)) {
1448     DEBUG(1,("%s isn't in user level security mode\n",pserver));
1449     close(password_client); password_client= -1;
1450     return(False);
1451   }
1452
1453   memcpy(buf,inbuf,smb_len(inbuf)+4);
1454
1455   DEBUG(3,("password server OK\n"));
1456
1457   return(True);
1458 }
1459
1460 /****************************************************************************
1461 attempted support for server level security 
1462 ****************************************************************************/
1463 BOOL server_validate(char *buf)
1464 {
1465   pstring inbuf,outbuf;  
1466   BOOL ret;
1467
1468   if (password_client < 0) {
1469     DEBUG(1,("%s not connected\n",pserver));
1470     return(False);
1471   }  
1472
1473   bzero(inbuf,sizeof(inbuf));
1474   memcpy(outbuf,buf,sizeof(outbuf));
1475
1476   /* send a session setup command */
1477   CVAL(outbuf,smb_flg) = 0x8;
1478   SSVAL(outbuf,smb_flg2,0x1);
1479   CVAL(outbuf,smb_vwv0) = 0xFF;
1480
1481   set_message(outbuf,smb_numwords(outbuf),smb_buflen(outbuf),False);
1482
1483   SCVAL(inbuf,smb_rcls,1);
1484
1485   send_smb(password_client,outbuf);
1486   ret = receive_smb(password_client,inbuf,5000);
1487
1488   if (!ret || CVAL(inbuf,smb_rcls) != 0) {
1489     DEBUG(1,("password server %s rejected the password\n",pserver));
1490     return(False);
1491   }
1492
1493   /* if logged in as guest then reject */
1494   if ((SVAL(inbuf,smb_vwv2) & 1) != 0) {
1495     DEBUG(1,("password server %s gave us guest only\n",pserver));
1496     return(False);
1497   }
1498
1499   DEBUG(3,("password server %s accepted the password\n",pserver));
1500
1501 #if !KEEP_PASSWORD_SERVER_OPEN
1502   close(password_client); password_client= -1;
1503 #endif
1504
1505   return(True);
1506 }
1507
1508