0f2efcc1da9917c70b88f92eda73ef483057f62f
[nivanova/samba-autobuild/.git] / source3 / smbd / password.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Password and authentication handling
5    Copyright (C) Andrew Tridgell 1992-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 #if (defined(NETGROUP) && defined (AUTOMOUNT))
25 #include "rpcsvc/ypclnt.h"
26 #endif
27
28 extern int DEBUGLEVEL;
29 extern int Protocol;
30
31 /* users from session setup */
32 static pstring session_users="";
33
34 extern pstring global_myname;
35 extern fstring global_myworkgroup;
36
37 /* these are kept here to keep the string_combinations function simple */
38 static char this_user[100]="";
39 static char this_salt[100]="";
40 static char this_crypted[100]="";
41
42 /* Data to do lanman1/2 password challenge. */
43 static unsigned char saved_challenge[8];
44 static BOOL challenge_sent=False;
45
46 /*******************************************************************
47 Get the next challenge value - no repeats.
48 ********************************************************************/
49 void generate_next_challenge(char *challenge)
50 {
51 #if 0
52         /* 
53          * Leave this ifdef'd out while we test
54          * the new crypto random number generator.
55          * JRA.
56          */
57         unsigned char buf[16];
58         static int counter = 0;
59         struct timeval tval;
60         int v1,v2;
61
62         /* get a sort-of random number */
63         GetTimeOfDay(&tval);
64         v1 = (counter++) + getpid() + tval.tv_sec;
65         v2 = (counter++) * getpid() + tval.tv_usec;
66         SIVAL(challenge,0,v1);
67         SIVAL(challenge,4,v2);
68
69         /* mash it up with md4 */
70         mdfour(buf, (unsigned char *)challenge, 8);
71 #else
72         unsigned char buf[8];
73
74         generate_random_buffer(buf,8,False);
75 #endif 
76         memcpy(saved_challenge, buf, 8);
77         memcpy(challenge,buf,8);
78         challenge_sent = True;
79 }
80
81 /*******************************************************************
82 set the last challenge sent, usually from a password server
83 ********************************************************************/
84 BOOL set_challenge(char *challenge)
85 {
86   memcpy(saved_challenge,challenge,8);
87   challenge_sent = True;
88   return(True);
89 }
90
91 /*******************************************************************
92 get the last challenge sent
93 ********************************************************************/
94 BOOL last_challenge(unsigned char *challenge)
95 {
96   if (!challenge_sent) return(False);
97   memcpy(challenge,saved_challenge,8);
98   return(True);
99 }
100
101 /* this holds info on user ids that are already validated for this VC */
102 static user_struct *validated_users = NULL;
103 static int num_validated_users = 0;
104
105 /****************************************************************************
106 check if a uid has been validated, and return an pointer to the user_struct
107 if it has. NULL if not. vuid is biased by an offset. This allows us to
108 tell random client vuid's (normally zero) from valid vuids.
109 ****************************************************************************/
110 user_struct *get_valid_user_struct(uint16 vuid)
111 {
112   if (vuid == UID_FIELD_INVALID)
113     return NULL;
114   vuid -= VUID_OFFSET;
115   if ((vuid >= (uint16)num_validated_users) || 
116      (validated_users[vuid].uid == -1) || (validated_users[vuid].gid == -1))
117     return NULL;
118   return &validated_users[vuid];
119 }
120
121 /****************************************************************************
122 invalidate a uid
123 ****************************************************************************/
124 void invalidate_vuid(uint16 vuid)
125 {
126   user_struct *vuser = get_valid_user_struct(vuid);
127
128   if (vuser == NULL) return;
129
130   vuser->uid = -1;
131   vuser->gid = -1;
132
133   vuser->n_sids = 0;
134
135   /* same number of igroups as groups as attrs */
136   vuser->n_groups = 0;
137
138   if (vuser->groups && (vuser->groups != (gid_t *)vuser->igroups))
139        free(vuser->groups);
140
141   if (vuser->igroups) free(vuser->igroups);
142   if (vuser->attrs  ) free(vuser->attrs);
143   if (vuser->sids   ) free(vuser->sids);
144
145   vuser->attrs   = NULL;
146   vuser->sids    = NULL;
147   vuser->igroups = NULL;
148   vuser->groups  = NULL;
149 }
150
151
152 /****************************************************************************
153 return a validated username
154 ****************************************************************************/
155 char *validated_username(uint16 vuid)
156 {
157   user_struct *vuser = get_valid_user_struct(vuid);
158   if (vuser == NULL)
159     return 0;
160   return(vuser->name);
161 }
162
163
164 /****************************************************************************
165 Setup the groups a user belongs to.
166 ****************************************************************************/
167 int setup_groups(char *user, int uid, int gid, int *p_ngroups, 
168                  int **p_igroups, gid_t **p_groups,
169          int **p_attrs)
170 {
171   if (-1 == initgroups(user,gid))
172     {
173       if (getuid() == 0)
174         {
175           DEBUG(0,("Unable to initgroups!\n"));
176           if (gid < 0 || gid > 16000 || uid < 0 || uid > 16000)
177             DEBUG(0,("This is probably a problem with the account %s\n",user));
178         }
179     }
180   else
181     {
182       int i,ngroups;
183       int *igroups;
184       int *attrs;
185       gid_t grp = 0;
186       ngroups = getgroups(0,&grp);
187       if (ngroups <= 0)
188         ngroups = 32;
189       igroups = (int *)malloc(sizeof(int)*ngroups);
190       attrs   = (int *)malloc(sizeof(int)*ngroups);
191       for (i=0;i<ngroups;i++)
192       {
193         attrs  [i] = 0x7; /* XXXX don't know what NT user attributes are yet! */
194         igroups[i] = 0x42424242;
195       }
196       ngroups = getgroups(ngroups,(gid_t *)igroups);
197
198       if (igroups[0] == 0x42424242)
199         ngroups = 0;
200
201       *p_ngroups = ngroups;
202       *p_attrs   = attrs;
203
204       /* The following bit of code is very strange. It is due to the
205          fact that some OSes use int* and some use gid_t* for
206          getgroups, and some (like SunOS) use both, one in prototypes,
207          and one in man pages and the actual code. Thus we detect it
208          dynamically using some very ugly code */
209       if (ngroups > 0)
210         {
211           /* does getgroups return ints or gid_t ?? */
212           static BOOL groups_use_ints = True;
213
214           if (groups_use_ints && 
215               ngroups == 1 && 
216               SVAL(igroups,2) == 0x4242)
217             groups_use_ints = False;
218           
219           for (i=0;groups_use_ints && i<ngroups;i++)
220             if (igroups[i] == 0x42424242)
221               groups_use_ints = False;
222               
223           if (groups_use_ints)
224           {
225               *p_igroups = igroups;
226               *p_groups = (gid_t *)igroups;       
227           }
228           else
229           {
230               gid_t *groups = (gid_t *)igroups;
231               igroups = (int *)malloc(sizeof(int)*ngroups);
232               for (i=0;i<ngroups;i++)
233           {
234                 igroups[i] = groups[i];
235           }
236               *p_igroups = igroups;
237               *p_groups = (gid_t *)groups;
238             }
239         }
240       DEBUG(3,("%s is in %d groups\n",user,ngroups));
241       for (i=0;i<ngroups;i++)
242         DEBUG(3,("%d ",igroups[i]));
243       DEBUG(3,("\n"));
244     }
245   return 0;
246 }
247
248
249 /****************************************************************************
250 register a uid/name pair as being valid and that a valid password
251 has been given. vuid is biased by an offset. This allows us to
252 tell random client vuid's (normally zero) from valid vuids.
253 ****************************************************************************/
254 uint16 register_vuid(int uid,int gid, char *unix_name, char *requested_name, BOOL guest)
255 {
256   user_struct *vuser;
257   struct passwd *pwfile; /* for getting real name from passwd file */
258
259   /* Ensure no vuid gets registered in share level security. */
260   if(lp_security() == SEC_SHARE)
261     return UID_FIELD_INVALID;
262
263 #if 0
264   /*
265    * After observing MS-Exchange services writing to a Samba share
266    * I belive this code is incorrect. Each service does its own
267    * sessionsetup_and_X for the same user, and as each service shuts
268    * down, it does a user_logoff_and_X. As we are consolidating multiple
269    * sessionsetup_and_X's onto the same vuid here, when the first service
270    * shuts down, it invalidates all the open files for the other services.
271    * Hence I am removing this code and forcing each sessionsetup_and_X
272    * to get a new vuid.
273    * Jeremy Allison. (jallison@whistle.com).
274    */
275
276   int i;
277   for(i = 0; i < num_validated_users; i++) {
278     vuser = &validated_users[i];
279     if ( vuser->uid == uid )
280       return (uint16)(i + VUID_OFFSET); /* User already validated */
281   }
282 #endif
283
284   validated_users = (user_struct *)Realloc(validated_users,
285                            sizeof(user_struct)*
286                            (num_validated_users+1));
287   
288   if (!validated_users)
289     {
290       DEBUG(0,("Failed to realloc users struct!\n"));
291       num_validated_users = 0;
292       return UID_FIELD_INVALID;
293     }
294
295   vuser = &validated_users[num_validated_users];
296   num_validated_users++;
297
298   vuser->uid = uid;
299   vuser->gid = gid;
300   vuser->guest = guest;
301   fstrcpy(vuser->name,unix_name);
302   fstrcpy(vuser->requested_name,requested_name);
303
304   vuser->n_sids = 0;
305   vuser->sids   = NULL;
306
307   vuser->n_groups = 0;
308   vuser->groups  = NULL;
309   vuser->igroups = NULL;
310   vuser->attrs    = NULL;
311
312   /* Find all the groups this uid is in and store them. 
313      Used by become_user() */
314   setup_groups(unix_name,uid,gid,
315                &vuser->n_groups,
316                &vuser->igroups,
317                &vuser->groups,
318                &vuser->attrs);
319
320   DEBUG(3,("uid %d registered to name %s\n",uid,unix_name));
321
322   DEBUG(3, ("Clearing default real name\n"));
323   fstrcpy(vuser->real_name, "<Full Name>\0");
324   if (lp_unix_realname()) {
325     if ((pwfile=getpwnam(vuser->name))!= NULL)
326       {
327       DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->name,pwfile->pw_gecos));
328       fstrcpy(vuser->real_name, pwfile->pw_gecos);
329       }
330   }
331
332   return (uint16)((num_validated_users - 1) + VUID_OFFSET);
333 }
334
335
336 /****************************************************************************
337 add a name to the session users list
338 ****************************************************************************/
339 void add_session_user(char *user)
340 {
341   fstring suser;
342   StrnCpy(suser,user,sizeof(suser)-1);
343
344   if (!Get_Pwnam(suser,True)) return;
345
346   if (suser && *suser && !in_list(suser,session_users,False))
347     {
348       if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring))
349         DEBUG(1,("Too many session users??\n"));
350       else
351         {
352           pstrcat(session_users," ");
353           pstrcat(session_users,suser);
354         }
355     }
356 }
357
358
359 #ifdef NO_GETSPNAM
360 /* a fake shadow password routine which just fills a fake spwd struct
361  * with the sp_pwdp field. (sreiz@aie.nl)
362  */
363 static struct spwd *getspnam(char *username) /* fake shadow password routine */
364 {
365        FILE *f;
366        char line[1024];
367        static fstring pw;
368        static struct spwd static_spwd;
369
370        static_spwd.sp_pwdp=0;
371        if (!(f=fopen("/etc/master.passwd", "r")))
372                return 0;
373        while (fgets(line, 1024, f)) {
374                if (!strncmp(line, username, strlen(username)) &&
375                 line[strlen(username)]==':') { /* found entry */
376                        char *p, *q;
377
378                        p=line+strlen(username)+1;
379                        if ((q=strchr(p, ':'))) {
380                                *q=0;
381                                if (q-p+1>20)
382                                        break;
383                                fstrcpy(pw, p);
384                                static_spwd.sp_pwdp=pw;
385                        }
386                        break;
387                }
388        }
389        fclose(f);
390        if (static_spwd.sp_pwdp)
391                return &static_spwd;
392        return 0;
393 }
394 #endif
395
396
397 #ifdef OSF1_ENH_SEC
398 /****************************************************************************
399 an enhanced crypt for OSF1
400 ****************************************************************************/
401 static char *osf1_bigcrypt(char *password,char *salt1)
402 {
403   static char result[AUTH_MAX_PASSWD_LENGTH] = "";
404   char *p1;
405   char *p2=password;
406   char salt[3];
407   int i;
408   int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
409   if (strlen(password)%AUTH_CLEARTEXT_SEG_CHARS)
410     parts++;
411
412   StrnCpy(salt,salt1,2);
413   StrnCpy(result,salt1,2);
414
415   for (i=0; i<parts;i++)
416     {
417       p1 = crypt(p2,salt);
418       strncat(result,p1+2,AUTH_MAX_PASSWD_LENGTH-strlen(p1+2)-1);
419       StrnCpy(salt,&result[2+i*AUTH_CIPHERTEXT_SEG_CHARS],2);
420       p2 += AUTH_CLEARTEXT_SEG_CHARS;
421     }
422
423   return(result);
424 }
425 #endif
426
427 /****************************************************************************
428 update the encrypted smbpasswd file from the plaintext username and password
429 *****************************************************************************/
430 BOOL update_smbpassword_file( char *user, fstring password)
431 {
432   struct smb_passwd *smbpw;
433   BOOL ret;
434
435   become_root(0);
436   smbpw = getsmbpwnam(user);
437   unbecome_root(0);
438
439   if(smbpw == NULL)
440   {
441     DEBUG(0,("update_smbpassword_file: getsmbpwnam returned NULL\n"));
442     return False;
443   }
444  
445   /* Here, the flag is one, because we want to ignore the XXXXXXX'd out password */
446   ret = change_oem_password( smbpw, password, True);
447   if (ret == False)
448     DEBUG(3,("update_smbpasswd_file: change_oem_password returned False\n"));
449
450   return ret;
451 }
452
453 /****************************************************************************
454 update the enhanced security database. Only relevant for OSF1 at the moment.
455 ****************************************************************************/
456 static void update_protected_database( char *user, BOOL result)
457 {
458 #ifdef OSF1_ENH_SEC
459   struct pr_passwd *mypasswd;
460   time_t starttime;
461
462   mypasswd = getprpwnam (user);
463   starttime = time (NULL);
464
465   if (result)
466     {
467       mypasswd->ufld.fd_slogin = starttime;
468       mypasswd->ufld.fd_nlogins = 0;
469       
470       putprpwnam(user,mypasswd);
471       
472       DEBUG(3,("Update protected database for Account %s after succesful connection\n",user));
473     }
474   else
475     {
476       mypasswd->ufld.fd_ulogin = starttime;
477       mypasswd->ufld.fd_nlogins = mypasswd->ufld.fd_nlogins + 1;
478       if ( mypasswd->ufld.fd_max_tries != 0 && mypasswd->ufld.fd_nlogins > mypasswd->ufld.fd_max_tries )
479         {
480           mypasswd->uflg.fg_lock = 0;
481           DEBUG(3,("Account is disabled -- see Account Administrator.\n"));
482         }
483       putprpwnam ( user , mypasswd );
484       DEBUG(3,("Update protected database for Account %s after refusing connection\n",user));
485     }
486 #else
487   DEBUG(6,("Updated database with %s %s\n",user,BOOLSTR(result)));
488 #endif
489 }
490
491
492 #ifdef USE_PAM
493 /*******************************************************************
494 check on PAM authentication
495 ********************************************************************/
496
497 /* We first need some helper functions */
498 #include <security/pam_appl.h>
499 /* Static variables used to communicate between the conversation function
500  * and the server_login function
501  */
502 static char *PAM_username;
503 static char *PAM_password;
504
505 /* PAM conversation function
506  * Here we assume (for now, at least) that echo on means login name, and
507  * echo off means password.
508  */
509 static int PAM_conv (int num_msg,
510                      const struct pam_message **msg,
511                      struct pam_response **resp,
512                      void *appdata_ptr) {
513   int replies = 0;
514   struct pam_response *reply = NULL;
515
516   #define COPY_STRING(s) (s) ? strdup(s) : NULL
517
518   reply = malloc(sizeof(struct pam_response) * num_msg);
519   if (!reply) return PAM_CONV_ERR;
520
521   for (replies = 0; replies < num_msg; replies++) {
522     switch (msg[replies]->msg_style) {
523       case PAM_PROMPT_ECHO_ON:
524         reply[replies].resp_retcode = PAM_SUCCESS;
525         reply[replies].resp = COPY_STRING(PAM_username);
526           /* PAM frees resp */
527         break;
528       case PAM_PROMPT_ECHO_OFF:
529         reply[replies].resp_retcode = PAM_SUCCESS;
530         reply[replies].resp = COPY_STRING(PAM_password);
531           /* PAM frees resp */
532         break;
533       case PAM_TEXT_INFO:
534         /* fall through */
535       case PAM_ERROR_MSG:
536         /* ignore it... */
537         reply[replies].resp_retcode = PAM_SUCCESS;
538         reply[replies].resp = NULL;
539         break;
540       default:
541         /* Must be an error of some sort... */
542         free (reply);
543         return PAM_CONV_ERR;
544     }
545   }
546   if (reply) *resp = reply;
547   return PAM_SUCCESS;
548 }
549 static struct pam_conv PAM_conversation = {
550     &PAM_conv,
551     NULL
552 };
553
554
555 static BOOL pam_auth(char *this_user,char *password)
556 {
557   pam_handle_t *pamh;
558   int pam_error;
559
560   /* Now use PAM to do authentication.  For now, we won't worry about
561    * session logging, only authentication.  Bail out if there are any
562    * errors.  Since this is a limited protocol, and an even more limited
563    * function within a server speaking this protocol, we can't be as
564    * verbose as would otherwise make sense.
565    * Query: should we be using PAM_SILENT to shut PAM up?
566    */
567   #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
568      pam_end(pamh, 0); return False; \
569    }
570   PAM_password = password;
571   PAM_username = this_user;
572   pam_error = pam_start("samba", this_user, &PAM_conversation, &pamh);
573   PAM_BAIL;
574 /* Setting PAM_SILENT stops generation of error messages to syslog
575  * to enable debugging on Red Hat Linux set:
576  * /etc/pam.d/samba:
577  *      auth required /lib/security/pam_pwdb.so nullok shadow audit
578  * _OR_ change PAM_SILENT to 0 to force detailed reporting (logging)
579  */
580   pam_error = pam_authenticate(pamh, PAM_SILENT);
581   PAM_BAIL;
582   /* It is not clear to me that account management is the right thing
583    * to do, but it is not clear that it isn't, either.  This can be
584    * removed if no account management should be done.  Alternately,
585    * put a pam_allow.so entry in /etc/pam.conf for account handling. */
586   pam_error = pam_acct_mgmt(pamh, PAM_SILENT);
587   PAM_BAIL;
588   pam_end(pamh, PAM_SUCCESS);
589   /* If this point is reached, the user has been authenticated. */
590   return(True);
591 }
592 #endif
593
594
595 #ifdef AFS_AUTH
596 /*******************************************************************
597 check on AFS authentication
598 ********************************************************************/
599 static BOOL afs_auth(char *this_user,char *password)
600 {
601   long password_expires = 0;
602   char *reason;
603     
604   /* For versions of AFS prior to 3.3, this routine has few arguments, */
605   /* but since I can't find the old documentation... :-)               */
606   setpag();
607   if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
608                                  this_user,
609                                  (char *) 0, /* instance */
610                                  (char *) 0, /* cell */
611                                  password,
612                                  0,          /* lifetime, default */
613                                  &password_expires, /*days 'til it expires */
614                                  0,          /* spare 2 */
615                                  &reason) == 0)
616     return(True);
617   return(False);
618 }
619 #endif
620
621
622 #ifdef DFS_AUTH
623
624 sec_login_handle_t my_dce_sec_context;
625 int dcelogin_atmost_once = 0;
626
627 /*******************************************************************
628 check on a DCE/DFS authentication
629 ********************************************************************/
630 static BOOL dfs_auth(char *this_user,char *password)
631 {
632   error_status_t err;
633   int err2;
634   int prterr;
635   boolean32 password_reset;
636   sec_passwd_rec_t my_dce_password;
637   sec_login_auth_src_t auth_src = sec_login_auth_src_network;
638   unsigned char dce_errstr[dce_c_error_string_len];
639
640   /*
641    * We only go for a DCE login context if the given password
642    * matches that stored in the local password file.. 
643    * Assumes local passwd file is kept in sync w/ DCE RGY!
644    */
645
646   /* Fix for original (broken) code from Brett Wooldridge <brettw@austin.ibm.com> */
647   if (dcelogin_atmost_once)
648     return (False);
649   /* This can be ifdefed as the DCE check below is stricter... */
650 #ifndef NO_CRYPT
651   if ( strcmp((char *)crypt(password,this_salt),this_crypted) )
652     return (False);
653 #endif
654
655   if (sec_login_setup_identity(
656                                (unsigned char *)this_user,
657                                sec_login_no_flags,
658                                &my_dce_sec_context,
659                                &err) == 0)
660     {
661       dce_error_inq_text(err, dce_errstr, &err2);
662       DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
663                this_user,dce_errstr));
664       return(False);
665     }
666
667   my_dce_password.version_number = sec_passwd_c_version_none;
668   my_dce_password.pepper = NULL; 
669   my_dce_password.key.key_type = sec_passwd_plain;
670   my_dce_password.key.tagged_union.plain  = (idl_char *)password;
671   
672   if (sec_login_valid_and_cert_ident(my_dce_sec_context,
673                                      &my_dce_password,
674                                      &password_reset,
675                                      &auth_src,
676                                      &err) == 0 )
677     { 
678       dce_error_inq_text(err, dce_errstr, &err2);
679       DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
680                this_user,dce_errstr));
681           
682       return(False);
683     }
684
685   sec_login_set_context(my_dce_sec_context, &err);
686   if (err != error_status_ok )
687     {  
688       dce_error_inq_text(err, dce_errstr, &err2);
689       DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
690                this_user,dce_errstr));
691       sec_login_purge_context(my_dce_sec_context, &err);
692       return(False);
693     }
694   else
695     {
696       DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
697                this_user, getpid()));
698     }
699
700   dcelogin_atmost_once = 1;
701   return (True);
702 }
703
704 void dfs_unlogin(void)
705 {
706   error_status_t err;
707   int err2;
708   unsigned char dce_errstr[dce_c_error_string_len];
709
710   sec_login_purge_context(my_dce_sec_context, &err);
711   if (err != error_status_ok )
712     {  
713       dce_error_inq_text(err, dce_errstr, &err2);
714       DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
715                getpid(), dce_errstr));
716     }
717 }
718
719 #endif
720
721 #ifdef KRB5_AUTH
722 /*******************************************************************
723 check on Kerberos authentication
724 ********************************************************************/
725 static BOOL krb5_auth(char *this_user,char *password)
726 {
727         krb5_data tgtname = {
728                 0,
729                 KRB5_TGS_NAME_SIZE,
730                 KRB5_TGS_NAME
731         };
732         krb5_context kcontext;
733         krb5_principal kprinc;
734         krb5_principal server;
735         krb5_creds kcreds;
736         int options = 0;
737         krb5_address **addrs = (krb5_address **)0;
738         krb5_preauthtype *preauth = NULL;
739         krb5_keytab keytab = NULL;
740         krb5_timestamp now;
741         krb5_ccache ccache = NULL;
742         int retval;
743         char *name;
744
745         if ( retval=krb5_init_context(&kcontext))
746         {
747                 return(False);
748         }
749
750         if ( retval = krb5_timeofday(kcontext, &now) )
751         {
752                 return(False);
753         }
754
755         if ( retval = krb5_cc_default(kcontext, &ccache) )
756         {
757                 return(False);
758         }
759         
760         if ( retval = krb5_parse_name(kcontext, this_user, &kprinc) )
761         {
762                 return(False);
763         }
764
765         memset((char *)&kcreds, 0, sizeof(kcreds));
766
767         kcreds.client = kprinc;
768         
769         if ((retval = krb5_build_principal_ext(kcontext, &server,
770                 krb5_princ_realm(kcontext, kprinc)->length,
771                 krb5_princ_realm(kcontext, kprinc)->data,
772                 tgtname.length,
773                 tgtname.data,
774                 krb5_princ_realm(kcontext, kprinc)->length,
775                 krb5_princ_realm(kcontext, kprinc)->data,
776                 0)))
777         {
778                 return(False);
779         }
780
781         kcreds.server = server;
782
783         retval = krb5_get_in_tkt_with_password(kcontext,
784                 options,
785                 addrs,
786                 NULL,
787                 preauth,
788                 password,
789                 0,
790                 &kcreds,
791                 0);
792
793         if ( retval )
794         {
795                 return(False);
796         }
797
798         return(True);
799 }
800 #endif /* KRB5_AUTH */
801
802 #ifdef KRB4_AUTH
803 /*******************************************************************
804 check on Kerberos authentication
805 ********************************************************************/
806 static BOOL krb4_auth(char *this_user,char *password)
807 {
808   char realm[REALM_SZ];
809   char tkfile[MAXPATHLEN];
810   
811   if (krb_get_lrealm(realm, 1) != KSUCCESS)
812     (void) safe_strcpy(realm, KRB_REALM, sizeof (realm) - 1);
813   
814   (void) slprintf(tkfile, sizeof(tkfile) - 1, "/tmp/samba_tkt_%d", getpid());
815   
816   krb_set_tkt_string(tkfile);
817   if (krb_verify_user(this_user, "", realm,
818                      password, 0,
819                      "rmcd") == KSUCCESS) {
820     unlink(tkfile);
821     return 1;
822   }
823   unlink(tkfile);
824   return 0;
825 }
826 #endif /* KRB4_AUTH */
827
828 #ifdef LINUX_BIGCRYPT
829 /****************************************************************************
830 an enhanced crypt for Linux to handle password longer than 8 characters
831 ****************************************************************************/
832 static int linux_bigcrypt(char *password,char *salt1, char *crypted)
833 {
834 #define LINUX_PASSWORD_SEG_CHARS 8
835   char salt[3];
836   int i;
837   
838   StrnCpy(salt,salt1,2);
839   crypted +=2;
840   
841   for ( i=strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
842     char * p = crypt(password,salt) + 2;
843     if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
844       return(0);
845     password += LINUX_PASSWORD_SEG_CHARS;
846     crypted  += strlen(p);
847   }
848   
849   return(1);
850 }
851 #endif
852
853
854 /****************************************************************************
855 apply a function to upper/lower case combinations
856 of a string and return true if one of them returns true.
857 try all combinations with N uppercase letters.
858 offset is the first char to try and change (start with 0)
859 it assumes the string starts lowercased
860 ****************************************************************************/
861 static BOOL string_combinations2(char *s,int offset,BOOL (*fn)(char *),int N)
862 {
863   int len = strlen(s);
864   int i;
865
866 #ifdef PASSWORD_LENGTH
867   len = MIN(len,PASSWORD_LENGTH);
868 #endif
869
870   if (N <= 0 || offset >= len)
871     return(fn(s));
872
873   for (i=offset;i<(len-(N-1));i++)
874     {      
875       char c = s[i];
876       if (!islower(c)) continue;
877       s[i] = toupper(c);
878       if (string_combinations2(s,i+1,fn,N-1))
879         return(True);
880       s[i] = c;
881     }
882   return(False);
883 }
884
885 /****************************************************************************
886 apply a function to upper/lower case combinations
887 of a string and return true if one of them returns true.
888 try all combinations with up to N uppercase letters.
889 offset is the first char to try and change (start with 0)
890 it assumes the string starts lowercased
891 ****************************************************************************/
892 static BOOL string_combinations(char *s,BOOL (*fn)(char *),int N)
893 {
894   int n;
895   for (n=1;n<=N;n++)
896     if (string_combinations2(s,0,fn,n)) return(True);
897   return(False);
898 }
899
900
901
902 /****************************************************************************
903 core of password checking routine
904 ****************************************************************************/
905 BOOL password_check(char *password)
906 {
907
908 #ifdef USE_PAM
909 /* This falls through if the password check fails
910         - if NO_CRYPT is defined this causes an error msg
911                 saying Warning - no crypt available
912         - if NO_CRYPT is NOT defined this is a potential security hole
913                 as it may authenticate via the crypt call when PAM
914                 settings say it should fail.
915   if (pam_auth(this_user,password)) return(True);
916 Hence we make a direct return to avoid a second chance!!!
917 */
918   return (pam_auth(this_user,password));
919 #endif
920
921 #ifdef AFS_AUTH
922   if (afs_auth(this_user,password)) return(True);
923 #endif
924
925 #ifdef DFS_AUTH
926   if (dfs_auth(this_user,password)) return(True);
927 #endif 
928
929 #ifdef KRB5_AUTH
930   if (krb5_auth(this_user,password)) return(True);
931 #endif
932
933 #ifdef KRB4_AUTH
934   if (krb4_auth(this_user,password)) return(True);
935 #endif
936
937 #ifdef PWDAUTH
938   if (pwdauth(this_user,password) == 0)
939     return(True);
940 #endif
941
942 #ifdef OSF1_ENH_SEC
943   {
944     BOOL ret = (strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0);
945     if(!ret) {
946       DEBUG(2,("password_check: OSF1_ENH_SEC failed. Trying normal crypt.\n"));
947       ret = (strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
948     }
949     return ret;
950   }
951 #endif
952
953 #ifdef ULTRIX_AUTH
954   return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
955 #endif
956
957 #ifdef LINUX_BIGCRYPT
958   return(linux_bigcrypt(password,this_salt,this_crypted));
959 #endif
960
961 #ifdef HPUX_10_TRUSTED
962   return(bigcrypt(password,this_salt,this_crypted));
963 #endif
964
965 #ifdef NO_CRYPT
966   DEBUG(1,("Warning - no crypt available\n"));
967   return(False);
968 #else
969   return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
970 #endif
971 }
972
973 /****************************************************************************
974 core of smb password checking routine.
975 ****************************************************************************/
976 BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8)
977 {
978   /* Finish the encryption of part_passwd. */
979   unsigned char p21[21];
980   unsigned char p24[24];
981
982   if (part_passwd == NULL)
983     DEBUG(10,("No password set - allowing access\n"));
984   /* No password set - always true ! */
985   if (part_passwd == NULL)
986     return 1;
987
988   memset(p21,'\0',21);
989   memcpy(p21,part_passwd,16);
990   E_P24(p21, c8, p24);
991 #if DEBUG_PASSWORD
992   {
993     int i;
994     DEBUG(100,("Part password (P16) was |"));
995     for(i = 0; i < 16; i++)
996       DEBUG(100,("%X ", (unsigned char)part_passwd[i]));
997     DEBUG(100,("|\n"));
998     DEBUG(100,("Password from client was |"));
999     for(i = 0; i < 24; i++)
1000       DEBUG(100,("%X ", (unsigned char)password[i]));
1001     DEBUG(100,("|\n"));
1002     DEBUG(100,("Given challenge was |"));
1003     for(i = 0; i < 8; i++)
1004       DEBUG(100,("%X ", (unsigned char)c8[i]));
1005     DEBUG(100,("|\n"));
1006     DEBUG(100,("Value from encryption was |"));
1007     for(i = 0; i < 24; i++)
1008       DEBUG(100,("%X ", (unsigned char)p24[i]));
1009     DEBUG(100,("|\n"));
1010   }
1011 #endif
1012   return (memcmp(p24, password, 24) == 0);
1013 }
1014
1015 /****************************************************************************
1016  Do a specific test for an smb password being correct, given a smb_password and
1017  the lanman and NT responses.
1018 ****************************************************************************/
1019
1020 BOOL smb_password_ok(struct smb_passwd *smb_pass,
1021                      uchar lm_pass[24], uchar nt_pass[24])
1022 {
1023   uchar challenge[8];
1024
1025   if (!lm_pass || !smb_pass) return(False);
1026
1027   if(smb_pass->acct_ctrl & ACB_DISABLED)
1028   {
1029     DEBUG(3,("smb_password_ok: account for user %s was disabled.\n", smb_pass->smb_name));
1030     return(False);
1031   }
1032
1033   if (!last_challenge(challenge))
1034   {
1035     DEBUG(1,("smb_password_ok: no challenge done - password failed\n"));
1036     return False;
1037   }
1038
1039   DEBUG(4,("smb_password_ok: Checking SMB password for user %s\n", smb_pass->smb_name));
1040
1041   if ((Protocol >= PROTOCOL_NT1) && (smb_pass->smb_nt_passwd != NULL))
1042   {
1043     /* We have the NT MD4 hash challenge available - see if we can
1044        use it (ie. does it exist in the smbpasswd file).
1045      */
1046     DEBUG(4,("smb_password_ok: Checking NT MD4 password\n"));
1047     if (smb_password_check((char *)nt_pass, (uchar *)smb_pass->smb_nt_passwd, challenge))
1048     {
1049       DEBUG(4,("smb_password_ok: NT MD4 password check succeeded\n"));
1050       return(True);
1051     }
1052     DEBUG(4,("smb_password_ok: NT MD4 password check failed\n"));
1053   }
1054
1055   /* Try against the lanman password. smb_pass->smb_passwd == NULL means
1056      no password, allow access. */
1057
1058   DEBUG(4,("Checking LM MD4 password\n"));
1059
1060   if((smb_pass->smb_passwd == NULL) && (smb_pass->acct_ctrl & ACB_PWNOTREQ))
1061   {
1062     DEBUG(4,("smb_password_ok: no password required for user %s\n", smb_pass->smb_name));
1063     return True;
1064   }
1065
1066   if((smb_pass->smb_passwd != NULL) && smb_password_check((char *)lm_pass, (uchar *)smb_pass->smb_passwd, challenge))
1067   {
1068     DEBUG(4,("smb_password_ok: LM MD4 password check succeeded\n"));
1069     return(True);
1070   }
1071
1072   DEBUG(4,("smb_password_ok: LM MD4 password check failed\n"));
1073
1074   return False;
1075 }
1076
1077 /****************************************************************************
1078 check if a username/password is OK
1079 ****************************************************************************/
1080 BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd)
1081 {
1082   pstring pass2;
1083   int level = lp_passwordlevel();
1084   struct passwd *pass;
1085   uchar challenge[8];
1086   struct smb_passwd *smb_pass;
1087   BOOL update_encrypted = lp_update_encrypted();
1088   BOOL challenge_done = False;
1089
1090   if (password) password[pwlen] = 0;
1091
1092   if (pwlen == 24)
1093     challenge_done = last_challenge(challenge);
1094
1095 #if DEBUG_PASSWORD
1096   if (challenge_done)
1097     {
1098       int i;      
1099       DEBUG(100,("checking user=[%s] pass=[",user));
1100       for( i = 0; i < 24; i++)
1101         DEBUG(100,("%0x ", (unsigned char)password[i]));
1102       DEBUG(100,("]\n"));
1103     } else {
1104             DEBUG(100,("checking user=[%s] pass=[%s]\n",user,password));
1105     }
1106 #endif
1107
1108   if (!password)
1109     return(False);
1110
1111   if (((!*password) || (!pwlen)) && !lp_null_passwords())
1112     return(False);
1113
1114   if (pwd && !user) 
1115     {
1116       pass = (struct passwd *) pwd;
1117       user = pass->pw_name;
1118     } 
1119   else 
1120     pass = Get_Pwnam(user,True);
1121
1122   DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen, challenge_done));
1123
1124   if ((pwlen == 24) && challenge_done)
1125     {
1126       DEBUG(4,("Checking SMB password for user %s (l=24)\n",user));
1127
1128       if (!pass) 
1129         {
1130           DEBUG(3,("Couldn't find user %s\n",user));
1131           return(False);
1132         }
1133
1134       smb_pass = getsmbpwnam(user);
1135
1136       if (!smb_pass)
1137         {
1138           DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
1139           return(False);
1140         }
1141
1142       /* Quit if the account was disabled. */
1143       if(smb_pass->acct_ctrl & ACB_DISABLED)
1144         {
1145           DEBUG(3,("password_ok: account for user %s was disabled.\n", user));
1146           return(False);
1147         }
1148
1149       /* Ensure the uid's match */
1150       if (smb_pass->smb_userid != pass->pw_uid)
1151         {
1152           DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
1153           return(False);
1154         }
1155
1156       if(smb_password_ok( smb_pass, (unsigned char *)password,(uchar *)password))
1157         {
1158           update_protected_database(user,True);
1159           return(True);
1160         }
1161
1162       DEBUG(3,("Error smb_password_check failed\n"));
1163     }
1164
1165   DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
1166
1167   if (!pass) 
1168     {
1169       DEBUG(3,("Couldn't find user %s\n",user));
1170       return(False);
1171     }
1172
1173 #ifdef SHADOW_PWD
1174   {
1175     struct spwd *spass;
1176
1177     /* many shadow systems require you to be root to get the password,
1178        in most cases this should already be the case when this
1179        function is called, except perhaps for IPC password changing
1180        requests */
1181
1182     spass = getspnam(pass->pw_name);
1183     if (spass && spass->sp_pwdp)
1184       pass->pw_passwd = spass->sp_pwdp;
1185   }
1186 #elif defined(IA_UINFO)
1187   {
1188       /* Need to get password with SVR4.2's ia_ functions instead of
1189          get{sp,pw}ent functions. Required by UnixWare 2.x, tested on 
1190          version 2.1. (tangent@cyberport.com) */
1191       uinfo_t uinfo;
1192       if (ia_openinfo(pass->pw_name, &uinfo) != -1)
1193         ia_get_logpwd(uinfo, &(pass->pw_passwd));
1194   }
1195 #endif
1196
1197 #ifdef SecureWare
1198   {
1199     struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
1200     if (pr_pw && pr_pw->ufld.fd_encrypt)
1201       pass->pw_passwd = pr_pw->ufld.fd_encrypt;
1202   }
1203 #endif
1204
1205 #ifdef HPUX_10_TRUSTED
1206   {
1207     struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
1208     if (pr_pw && pr_pw->ufld.fd_encrypt)
1209       pass->pw_passwd = pr_pw->ufld.fd_encrypt;
1210   }
1211 #endif
1212
1213 #ifdef OSF1_ENH_SEC
1214   {
1215     struct pr_passwd *mypasswd;
1216     DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user));
1217     mypasswd = getprpwnam (user);
1218     if ( mypasswd )
1219       { 
1220         fstrcpy(pass->pw_name,mypasswd->ufld.fd_name);
1221         fstrcpy(pass->pw_passwd,mypasswd->ufld.fd_encrypt);
1222       }
1223     else
1224       {
1225         DEBUG(5,("No entry for user %s in protected database !\n",user));
1226         return(False);
1227       }
1228   }
1229 #endif
1230
1231 #ifdef ULTRIX_AUTH
1232   {
1233     AUTHORIZATION *ap = getauthuid( pass->pw_uid );
1234     if (ap)
1235       {
1236         fstrcpy( pass->pw_passwd, ap->a_password );
1237         endauthent();
1238       }
1239   }
1240 #endif
1241
1242   /* extract relevant info */
1243   fstrcpy(this_user,pass->pw_name);  
1244   fstrcpy(this_salt,pass->pw_passwd);
1245 #ifdef HPUX
1246   /* The crypt on HPUX won't work with more than 2 salt characters. */
1247   this_salt[2] = 0;
1248 #endif /* HPUX */
1249   fstrcpy(this_crypted,pass->pw_passwd);
1250  
1251   if (!*this_crypted) {
1252     if (!lp_null_passwords()) {
1253       DEBUG(2,("Disallowing access to %s due to null password\n",this_user));
1254       return(False);
1255     }
1256 #ifndef PWDAUTH
1257     if (!*password) {
1258       DEBUG(3,("Allowing access to %s with null password\n",this_user));
1259       return(True);
1260     }
1261 #endif    
1262   }
1263
1264   /* try it as it came to us */
1265   if (password_check(password))
1266     {
1267       update_protected_database(user,True);
1268       if (update_encrypted)
1269         update_smbpassword_file(user,password);
1270       return(True);
1271     }
1272
1273   /* if the password was given to us with mixed case then we don't
1274      need to proceed as we know it hasn't been case modified by the
1275      client */
1276   if (strhasupper(password) && strhaslower(password))
1277     return(False);
1278
1279   /* make a copy of it */
1280   StrnCpy(pass2,password,sizeof(pstring)-1);
1281   
1282   /* try all lowercase */
1283   strlower(password);
1284   if (password_check(password))
1285     {
1286       update_protected_database(user,True);
1287       if (update_encrypted)
1288         update_smbpassword_file(user,password);
1289       return(True);
1290     }
1291
1292   /* give up? */
1293   if (level < 1)
1294     {
1295       update_protected_database(user,False);
1296
1297       /* restore it */
1298       fstrcpy(password,pass2);
1299
1300       return(False);
1301     }
1302
1303   /* last chance - all combinations of up to level chars upper! */
1304   strlower(password);
1305
1306   if (string_combinations(password,password_check,level))
1307     {
1308       update_protected_database(user,True);
1309       if (update_encrypted)
1310         update_smbpassword_file(user,password);
1311       return(True);
1312     }
1313
1314   update_protected_database(user,False);
1315   
1316   /* restore it */
1317   fstrcpy(password,pass2);
1318   
1319   return(False);
1320 }
1321
1322
1323
1324 /****************************************************************************
1325 check if a username is valid
1326 ****************************************************************************/
1327 BOOL user_ok(char *user,int snum)
1328 {
1329   pstring valid, invalid;
1330   BOOL ret;
1331
1332   StrnCpy(valid, lp_valid_users(snum), sizeof(pstring));
1333   StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring));
1334
1335   string_sub(valid,"%S",lp_servicename(snum));
1336   string_sub(invalid,"%S",lp_servicename(snum));
1337
1338   ret = !user_in_list(user,invalid);
1339
1340   if (ret && valid && *valid)
1341     ret = user_in_list(user,valid);
1342
1343   if (ret && lp_onlyuser(snum)) {
1344     char *user_list = lp_username(snum);
1345     string_sub(user_list,"%S",lp_servicename(snum));
1346     ret = user_in_list(user,user_list);
1347   }
1348
1349   return(ret);
1350 }
1351
1352
1353
1354
1355 /****************************************************************************
1356 validate a group username entry. Return the username or NULL
1357 ****************************************************************************/
1358 static char *validate_group(char *group,char *password,int pwlen,int snum)
1359 {
1360 #ifdef NETGROUP
1361   {
1362     char *host, *user, *domain;
1363     setnetgrent(group);
1364     while (getnetgrent(&host, &user, &domain)) {
1365       if (user) {
1366         if (user_ok(user, snum) && 
1367             password_ok(user,password,pwlen,NULL)) {
1368           endnetgrent();
1369           return(user);
1370         }
1371       }
1372     }
1373     endnetgrent();
1374   }
1375 #endif
1376   
1377 #if HAVE_GETGRNAM 
1378   {
1379     struct group *gptr = (struct group *)getgrnam(group);
1380     char **member;
1381     if (gptr)
1382       {
1383         member = gptr->gr_mem;
1384         while (member && *member)
1385           {
1386             static fstring name;
1387             fstrcpy(name,*member);
1388             if (user_ok(name,snum) &&
1389                 password_ok(name,password,pwlen,NULL))
1390               return(&name[0]);
1391             member++;
1392           }
1393 #ifdef GROUP_CHECK_PWENT
1394         {
1395           struct passwd *pwd;
1396           static fstring tm;
1397           
1398           setpwent ();
1399           while (pwd = getpwent ()) {
1400             if (*(pwd->pw_passwd) && pwd->pw_gid == gptr->gr_gid) {
1401               /* This Entry have PASSWORD and same GID then check pwd */
1402               if (password_ok(NULL, password, pwlen, pwd)) {
1403                 fstrcpy(tm, pwd->pw_name);
1404                 endpwent ();
1405                 return tm;
1406               }
1407             }
1408           }
1409           endpwent ();
1410         }
1411 #endif /* GROUP_CHECK_PWENT */
1412       }
1413   }      
1414 #endif
1415   return(NULL);
1416 }
1417
1418
1419
1420 /****************************************************************************
1421 check for authority to login to a service with a given username/password
1422 ****************************************************************************/
1423 BOOL authorise_login(int snum,char *user,char *password, int pwlen, 
1424                      BOOL *guest,BOOL *force,uint16 vuid)
1425 {
1426   BOOL ok = False;
1427   
1428   *guest = False;
1429   
1430 #if DEBUG_PASSWORD
1431   DEBUG(100,("checking authorisation on user=%s pass=%s\n",user,password));
1432 #endif
1433
1434   /* there are several possibilities:
1435      1) login as the given user with given password
1436      2) login as a previously registered username with the given password
1437      3) login as a session list username with the given password
1438      4) login as a previously validated user/password pair
1439      5) login as the "user =" user with given password
1440      6) login as the "user =" user with no password (guest connection)
1441      7) login as guest user with no password
1442
1443      if the service is guest_only then steps 1 to 5 are skipped
1444   */
1445
1446   if (GUEST_ONLY(snum)) *force = True;
1447
1448   if (!(GUEST_ONLY(snum) && GUEST_OK(snum)))
1449     {
1450
1451       user_struct *vuser = get_valid_user_struct(vuid);
1452
1453       /* check the given username and password */
1454       if (!ok && (*user) && user_ok(user,snum)) {
1455         ok = password_ok(user,password, pwlen, NULL);
1456         if (ok) DEBUG(3,("ACCEPTED: given username password ok\n"));
1457       }
1458
1459       /* check for a previously registered guest username */
1460       if (!ok && (vuser != 0) && vuser->guest) {          
1461         if (user_ok(vuser->name,snum) &&
1462             password_ok(vuser->name, password, pwlen, NULL)) {
1463           fstrcpy(user, vuser->name);
1464           vuser->guest = False;
1465           DEBUG(3,("ACCEPTED: given password with registered user %s\n", user));
1466           ok = True;
1467         }
1468       }
1469
1470
1471       /* now check the list of session users */
1472     if (!ok)
1473     {
1474       char *auser;
1475       char *user_list = strdup(session_users);
1476       if (!user_list) return(False);
1477
1478       for (auser=strtok(user_list,LIST_SEP); 
1479            !ok && auser; 
1480            auser = strtok(NULL,LIST_SEP))
1481       {
1482         fstring user2;
1483         fstrcpy(user2,auser);
1484         if (!user_ok(user2,snum)) continue;
1485                   
1486         if (password_ok(user2,password, pwlen, NULL)) {
1487           ok = True;
1488           fstrcpy(user,user2);
1489           DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
1490         }
1491       }
1492       free(user_list);
1493     }
1494
1495     /* check for a previously validated username/password pair */
1496     if (!ok && (!lp_revalidate(snum) || lp_security() > SEC_SHARE) &&
1497         (vuser != 0) && !vuser->guest &&
1498         user_ok(vuser->name,snum)) {
1499       fstrcpy(user,vuser->name);
1500       *guest = False;
1501       DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
1502       ok = True;
1503     }
1504
1505       /* check for a rhosts entry */
1506       if (!ok && user_ok(user,snum) && check_hosts_equiv(user)) {
1507         ok = True;
1508         DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
1509       }
1510
1511       /* check the user= fields and the given password */
1512       if (!ok && lp_username(snum)) {
1513         char *auser;
1514         pstring user_list;
1515         StrnCpy(user_list,lp_username(snum),sizeof(pstring));
1516
1517         string_sub(user_list,"%S",lp_servicename(snum));
1518           
1519         for (auser=strtok(user_list,LIST_SEP);
1520              auser && !ok;
1521              auser = strtok(NULL,LIST_SEP))
1522           {
1523             if (*auser == '@')
1524               {
1525                 auser = validate_group(auser+1,password,pwlen,snum);
1526                 if (auser)
1527                   {
1528                     ok = True;
1529                     fstrcpy(user,auser);
1530                     DEBUG(3,("ACCEPTED: group username and given password ok\n"));
1531                   }
1532               }
1533             else
1534               {
1535                 fstring user2;
1536                 fstrcpy(user2,auser);
1537                 if (user_ok(user2,snum) && 
1538                     password_ok(user2,password,pwlen,NULL))
1539                   {
1540                     ok = True;
1541                     fstrcpy(user,user2);
1542                     DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
1543                   }
1544               }
1545           }
1546       }      
1547     } /* not guest only */
1548
1549   /* check for a normal guest connection */
1550   if (!ok && GUEST_OK(snum))
1551     {
1552       fstring guestname;
1553       StrnCpy(guestname,lp_guestaccount(snum),sizeof(guestname)-1);
1554       if (Get_Pwnam(guestname,True))
1555         {
1556           fstrcpy(user,guestname);
1557           ok = True;
1558           DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
1559         }
1560       else
1561         DEBUG(0,("Invalid guest account %s??\n",guestname));
1562       *guest = True;
1563       *force = True;
1564     }
1565
1566   if (ok && !user_ok(user,snum))
1567     {
1568       DEBUG(0,("rejected invalid user %s\n",user));
1569       ok = False;
1570     }
1571
1572   return(ok);
1573 }
1574
1575
1576 /****************************************************************************
1577 read the a hosts.equiv or .rhosts file and check if it
1578 allows this user from this machine
1579 ****************************************************************************/
1580 static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
1581 {
1582   pstring buf;
1583   int plus_allowed = 1;
1584   char *file_host;
1585   char *file_user;
1586   FILE *fp = fopen(equiv_file, "r");
1587   DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
1588   if (! fp) return False;
1589   while(fgets(buf, sizeof(buf), fp)) 
1590   {
1591     trim_string(buf," "," ");
1592
1593     if (buf[0] != '#' && buf[0] != '\n') 
1594     {
1595       BOOL is_group = False;
1596       int plus = 1;
1597       char *bp = buf;
1598       if (strcmp(buf, "NO_PLUS\n") == 0)
1599       {
1600         DEBUG(6, ("check_user_equiv NO_PLUS\n"));
1601         plus_allowed = 0;
1602       }
1603       else {
1604         if (buf[0] == '+') 
1605         {
1606           bp++;
1607           if (*bp == '\n' && plus_allowed) 
1608           {
1609             /* a bare plus means everbody allowed */
1610             DEBUG(6, ("check_user_equiv everybody allowed\n"));
1611             fclose(fp);
1612             return True;
1613           }
1614         }
1615         else if (buf[0] == '-')
1616         {
1617           bp++;
1618           plus = 0;
1619         }
1620         if (*bp == '@') 
1621         {
1622           is_group = True;
1623           bp++;
1624         }
1625         file_host = strtok(bp, " \t\n");
1626         file_user = strtok(NULL, " \t\n");
1627         DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)", 
1628                  file_user ? file_user : "(null)" ));
1629         if (file_host && *file_host) 
1630         {
1631           BOOL host_ok = False;
1632
1633 #ifdef NETGROUP   
1634           if (is_group)
1635             {
1636               static char *mydomain = NULL;
1637               if (!mydomain)
1638                 yp_get_default_domain(&mydomain);
1639               if (mydomain && innetgr(file_host,remote,user,mydomain))
1640                 host_ok = True;
1641             }
1642 #else
1643           if (is_group)
1644             {
1645               DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n"));
1646               continue;
1647             }
1648 #endif
1649
1650           /* is it this host */
1651           /* the fact that remote has come from a call of gethostbyaddr
1652            * means that it may have the fully qualified domain name
1653            * so we could look up the file version to get it into
1654            * a canonical form, but I would rather just type it
1655            * in full in the equiv file
1656            */
1657           if (!host_ok && !is_group && strequal(remote, file_host))
1658             host_ok = True;
1659
1660           if (!host_ok)
1661             continue;
1662
1663           /* is it this user */
1664           if (file_user == 0 || strequal(user, file_user)) 
1665             {
1666               fclose(fp);
1667               DEBUG(5, ("check_user_equiv matched %s%s %s\n",
1668                         (plus ? "+" : "-"), file_host,
1669                         (file_user ? file_user : "")));
1670               return (plus ? True : False);
1671             }
1672         }
1673       }
1674     }
1675   }
1676   fclose(fp);
1677   return False;
1678 }
1679
1680
1681 /****************************************************************************
1682 check for a possible hosts equiv or rhosts entry for the user
1683 ****************************************************************************/
1684 BOOL check_hosts_equiv(char *user)
1685 {
1686   char *fname = NULL;
1687   pstring rhostsfile;
1688   struct passwd *pass = Get_Pwnam(user,True);
1689
1690   if (!pass) 
1691     return(False);
1692
1693   fname = lp_hosts_equiv();
1694
1695   /* note: don't allow hosts.equiv on root */
1696   if (fname && *fname && (pass->pw_uid != 0)) {
1697           extern int Client;
1698           if (check_user_equiv(user,client_name(Client),fname))
1699                   return(True);
1700   }
1701   
1702   if (lp_use_rhosts())
1703     {
1704       char *home = get_home_dir(user);
1705       if (home) {
1706               extern int Client;
1707               slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home);
1708               if (check_user_equiv(user,client_name(Client),rhostsfile))
1709                       return(True);
1710       }
1711     }
1712
1713   return(False);
1714 }
1715
1716
1717 static struct cli_state pw_cli;
1718
1719 /****************************************************************************
1720 return the client state structure
1721 ****************************************************************************/
1722 struct cli_state *server_client(void)
1723 {
1724         return &pw_cli;
1725 }
1726
1727 /****************************************************************************
1728 support for server level security 
1729 ****************************************************************************/
1730 struct cli_state *server_cryptkey(void)
1731 {
1732         fstring desthost;
1733         struct in_addr dest_ip;
1734         extern fstring local_machine;
1735         char *p;
1736         BOOL connected_ok = False;
1737
1738         if (!cli_initialise(&pw_cli))
1739                 return NULL;
1740
1741         p = lp_passwordserver();
1742         while(p && next_token( &p, desthost, LIST_SEP)) {
1743                 standard_sub_basic(desthost);
1744                 strupper(desthost);
1745
1746                 if(!resolve_name( desthost, &dest_ip)) {
1747                         DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost));
1748                         continue;
1749                 }
1750
1751                 if (ismyip(dest_ip)) {
1752                         DEBUG(1,("Password server loop - disabling password server %s\n",desthost));
1753                         continue;
1754                 }
1755
1756                 if (cli_connect(&pw_cli, desthost, &dest_ip)) {
1757                         DEBUG(3,("connected to password server %s\n",desthost));
1758                         connected_ok = True;
1759                         break;
1760                 }
1761         }
1762
1763         if (!connected_ok) {
1764                 DEBUG(0,("password server not available\n"));
1765                 cli_shutdown(&pw_cli);
1766                 return NULL;
1767         }
1768
1769         if (!cli_session_request(&pw_cli, desthost, 0x20, local_machine)) {
1770                 DEBUG(1,("%s rejected the session\n",desthost));
1771                 cli_shutdown(&pw_cli);
1772                 return NULL;
1773         }
1774
1775         DEBUG(3,("got session\n"));
1776
1777         if (!cli_negprot(&pw_cli)) {
1778                 DEBUG(1,("%s rejected the negprot\n",desthost));
1779                 cli_shutdown(&pw_cli);
1780                 return NULL;
1781         }
1782
1783         if (pw_cli.protocol < PROTOCOL_LANMAN2 ||
1784             !(pw_cli.sec_mode & 1)) {
1785                 DEBUG(1,("%s isn't in user level security mode\n",desthost));
1786                 cli_shutdown(&pw_cli);
1787                 return NULL;
1788         }
1789
1790         DEBUG(3,("password server OK\n"));
1791
1792         return &pw_cli;
1793 }
1794
1795 /****************************************************************************
1796 validate a password with the password server
1797 ****************************************************************************/
1798 BOOL server_validate(char *user, char *domain, 
1799                      char *pass, int passlen,
1800                      char *ntpass, int ntpasslen)
1801 {
1802         extern fstring local_machine;
1803         static unsigned char badpass[24];
1804
1805         if (!pw_cli.initialised) {
1806                 DEBUG(1,("password server %s is not connected\n", pw_cli.desthost));
1807                 return(False);
1808         }  
1809
1810         if(badpass[0] == 0) {
1811           memset(badpass, 0x1f, sizeof(badpass));
1812         }
1813
1814         if((passlen == sizeof(badpass)) && !memcmp(badpass, pass, passlen)) {
1815           /* Very unlikely, our random bad password is the same as the users
1816              password. */
1817           memset(badpass, badpass[0]+1, sizeof(badpass));
1818         }
1819
1820         /*
1821          * Attempt a session setup with a totally incorrect password.
1822          * If this succeeds with the guest bit *NOT* set then the password
1823          * server is broken and is not correctly setting the guest bit. We
1824          * need to detect this as some versions of NT4.x are broken. JRA.
1825          */
1826
1827         if (cli_session_setup(&pw_cli, user, (char *)badpass, sizeof(badpass), 
1828                               (char *)badpass, sizeof(badpass), domain)) {
1829           if ((SVAL(pw_cli.inbuf,smb_vwv2) & 1) == 0) {
1830             DEBUG(0,("server_validate: password server %s allows users as non-guest \
1831 with a bad password.\n", pw_cli.desthost));
1832             DEBUG(0,("server_validate: This is broken (and insecure) behaviour. Please do not \
1833 use this machine as the password server.\n"));
1834             cli_ulogoff(&pw_cli);
1835             return False;
1836           }
1837           cli_ulogoff(&pw_cli);
1838         }
1839
1840         /*
1841          * Now we know the password server will correctly set the guest bit, or is
1842          * not guest enabled, we can try with the real password.
1843          */
1844
1845         if (!cli_session_setup(&pw_cli, user, pass, passlen, ntpass, ntpasslen, domain)) {
1846                 DEBUG(1,("password server %s rejected the password\n", pw_cli.desthost));
1847                 return False;
1848         }
1849
1850         /* if logged in as guest then reject */
1851         if ((SVAL(pw_cli.inbuf,smb_vwv2) & 1) != 0) {
1852                 DEBUG(1,("password server %s gave us guest only\n", pw_cli.desthost));
1853                 cli_ulogoff(&pw_cli);
1854                 return(False);
1855         }
1856
1857         /*
1858          * This patch from Rob Nielsen <ran@adc.com> makes doing
1859          * the NetWksaUserLogon a dynamic, rather than compile-time
1860          * parameter, defaulting to on. This is somewhat dangerous
1861          * as it allows people to turn off this neccessary check,
1862          * but so many people have had problems with this that I
1863          * think it is a neccessary change. JRA.
1864          */
1865
1866         if (lp_net_wksta_user_logon()) {
1867                 DEBUG(3,("trying NetWkstaUserLogon with password server %s\n", pw_cli.desthost));
1868
1869                 if (!cli_send_tconX(&pw_cli, "IPC$", "IPC", "", 1)) {
1870                         DEBUG(0,("password server %s refused IPC$ connect\n", pw_cli.desthost));
1871                         cli_ulogoff(&pw_cli);
1872                         return False;
1873                 }
1874
1875                 if (!cli_NetWkstaUserLogon(&pw_cli,user,local_machine)) {
1876                         DEBUG(0,("password server %s failed NetWkstaUserLogon\n", pw_cli.desthost));
1877                         cli_tdis(&pw_cli);
1878                         cli_ulogoff(&pw_cli);
1879                         return False;
1880                 }
1881
1882                 if (pw_cli.privilages == 0) {
1883                         DEBUG(0,("password server %s gave guest privilages\n", pw_cli.desthost));
1884                         cli_tdis(&pw_cli);
1885                         cli_ulogoff(&pw_cli);
1886                         return False;
1887                 }
1888
1889                 if (!strequal(pw_cli.eff_name, user)) {
1890                         DEBUG(0,("password server %s gave different username %s\n", 
1891                                 pw_cli.desthost,
1892                                 pw_cli.eff_name));
1893                         cli_tdis(&pw_cli);
1894                         cli_ulogoff(&pw_cli);
1895                         return False;
1896                 }
1897                 cli_tdis(&pw_cli);
1898         }
1899         else {
1900                 DEBUG(3,("skipping NetWkstaUserLogon with password server %s\n", pw_cli.desthost));
1901         }
1902
1903         DEBUG(3,("password server %s accepted the password\n", pw_cli.desthost));
1904
1905         cli_ulogoff(&pw_cli);
1906
1907         return(True);
1908 }
1909
1910 /***********************************************************************
1911  Do the same as security=server, but using NT Domain calls and a session
1912  key from the machine password.
1913 ************************************************************************/
1914
1915 BOOL domain_client_validate( char *user, char *domain, 
1916                              char *smb_apasswd, int smb_apasslen, 
1917                              char *smb_ntpasswd, int smb_ntpasslen)
1918 {
1919   unsigned char local_challenge[8];
1920   unsigned char local_lm_response[24];
1921   unsigned char local_nt_reponse[24];
1922   unsigned char trust_passwd[16];
1923   time_t lct;
1924   fstring remote_machine;
1925   char *p;
1926   struct in_addr dest_ip;
1927   NET_ID_INFO_CTR ctr;
1928   NET_USER_INFO_3 info3;
1929   struct cli_state cli;
1930   uint32 smb_uid_low;
1931   BOOL connected_ok = False;
1932
1933   /* 
1934    * Check that the requested domain is not our own machine name.
1935    * If it is, we should never check the PDC here, we use our own local
1936    * password file.
1937    */
1938
1939   if(strequal( domain, global_myname)) {
1940     DEBUG(3,("domain_client_validate: Requested domain was for this machine.\n"));
1941     return False;
1942   }
1943
1944   /*
1945    * Next, check that the passwords given were encrypted.
1946    */
1947
1948   if(smb_apasslen != 24 || smb_ntpasslen != 24) {
1949
1950     /*
1951      * Not encrypted - do so.
1952      */
1953
1954     DEBUG(3,("domain_client_validate: User passwords not in encrypted format.\n"));
1955     generate_random_buffer( local_challenge, 8, False);
1956     SMBencrypt( (uchar *)smb_apasswd, local_challenge, local_lm_response);
1957     SMBNTencrypt((uchar *)smb_ntpasswd, local_challenge, local_nt_reponse);
1958     smb_apasslen = 24;
1959     smb_ntpasslen = 24;
1960     smb_apasswd = (char *)local_lm_response;
1961     smb_ntpasswd = (char *)local_nt_reponse;
1962   } else {
1963
1964     /*
1965      * Encrypted - get the challenge we sent for these
1966      * responses.
1967      */
1968
1969     if (!last_challenge(local_challenge)) {
1970       DEBUG(0,("domain_client_validate: no challenge done - password failed\n"));
1971       return False;
1972     }
1973   }
1974
1975   become_root(False);
1976
1977   /*
1978    * Get the machine account password.
1979    */
1980   if(!trust_password_lock( global_myworkgroup, global_myname, False)) {
1981     DEBUG(0,("domain_client_validate: unable to open the machine account password file for \
1982 machine %s in domain %s.\n", global_myname, global_myworkgroup ));
1983     return False;
1984   }
1985
1986   if(get_trust_account_password( trust_passwd, &lct) == False) {
1987     DEBUG(0,("domain_client_validate: unable to read the machine account password for \
1988 machine %s in domain %s.\n", global_myname, global_myworkgroup ));
1989     trust_password_unlock();
1990     return False;
1991   }
1992
1993   trust_password_unlock();
1994
1995   unbecome_root(False);
1996
1997   /* 
1998    * Here we should check the last change time to see if the machine
1999    * password needs changing..... TODO... JRA. 
2000    */
2001
2002   /*
2003    * At this point, smb_apasswd points to the lanman response to
2004    * the challenge in local_challenge, and smb_ntpasswd points to
2005    * the NT response to the challenge in local_challenge. Ship
2006    * these over the secure channel to a domain controller and
2007    * see if they were valid.
2008    */
2009
2010   memset(&cli, '\0', sizeof(struct cli_state));
2011   if(cli_initialise(&cli) == False) {
2012     DEBUG(0,("domain_client_validate: unable to initialize client connection.\n"));
2013     return False;
2014   }
2015
2016   /*
2017    * Treat each name in the 'password server =' line as a potential
2018    * PDC/BDC. Contact each in turn and try and authenticate.
2019    */
2020
2021   p = lp_passwordserver();
2022   while(p && next_token( &p, remote_machine, LIST_SEP)) {                       
2023
2024     standard_sub_basic(remote_machine);
2025     strupper(remote_machine);
2026  
2027     if(!resolve_name( remote_machine, &dest_ip)) {
2028       DEBUG(1,("domain_client_validate: Can't resolve address for %s\n", remote_machine));
2029       continue;
2030     }   
2031     
2032     if (ismyip(dest_ip)) {
2033       DEBUG(1,("domain_client_validate: Password server loop - not using password server %s\n",remote_machine));
2034       continue;
2035     }
2036       
2037     if (!cli_connect(&cli, remote_machine, &dest_ip)) {
2038       DEBUG(0,("domain_client_validate: unable to connect to SMB server on \
2039 machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2040       continue;
2041     }
2042     
2043     if (!cli_session_request(&cli, remote_machine, 0x20, global_myname)) {
2044       DEBUG(0,("domain_client_validate: machine %s rejected the session setup. \
2045 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2046       cli_shutdown(&cli);
2047       continue;
2048     }
2049     
2050     cli.protocol = PROTOCOL_NT1;
2051
2052     if (!cli_negprot(&cli)) {
2053       DEBUG(0,("domain_client_validate: machine %s rejected the negotiate protocol. \
2054 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2055       cli_shutdown(&cli);
2056       continue;
2057     }
2058     
2059     if (cli.protocol != PROTOCOL_NT1) {
2060       DEBUG(0,("domain_client_validate: machine %s didn't negotiate NT protocol.\n",
2061                      remote_machine));
2062       cli_shutdown(&cli);
2063       continue;
2064     }
2065
2066     /* 
2067      * Do an anonymous session setup.
2068      */
2069
2070     if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) {
2071       DEBUG(0,("domain_client_validate: machine %s rejected the session setup. \
2072 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2073       cli_shutdown(&cli);
2074       continue;
2075     }      
2076
2077     if (!(cli.sec_mode & 1)) {
2078       DEBUG(1,("domain_client_validate: machine %s isn't in user level security mode\n",
2079                  remote_machine));
2080       cli_shutdown(&cli);
2081       continue;
2082     }
2083
2084     if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
2085       DEBUG(0,("domain_client_validate: machine %s rejected the tconX on the IPC$ share. \
2086 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2087       cli_shutdown(&cli);
2088       continue;
2089     }
2090
2091     /*
2092      * We have an anonymous connection to IPC$.
2093      */
2094     connected_ok = True;
2095     break;
2096   }
2097
2098   if (!connected_ok) {
2099     DEBUG(0,("domain_client_validate: Domain password server not available.\n"));
2100     cli_shutdown(&cli);
2101     return False;
2102   }
2103
2104   /*
2105    * Ok - we have an anonymous connection to the IPC$ share.
2106    * Now start the NT Domain stuff :-).
2107    */
2108
2109   if(cli_nt_session_open(&cli, PIPE_NETLOGON, False) == False) {
2110     DEBUG(0,("domain_client_validate: unable to open the domain client session to \
2111 machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli)));
2112     cli_nt_session_close(&cli);
2113     cli_ulogoff(&cli);
2114     cli_shutdown(&cli);
2115     return False; 
2116   }
2117
2118   if(cli_nt_setup_creds(&cli, trust_passwd) == False) {
2119     DEBUG(0,("domain_client_validate: unable to setup the PDC credentials to machine \
2120 %s. Error was : %s.\n", remote_machine, cli_errstr(&cli)));
2121     cli_nt_session_close(&cli);
2122     cli_ulogoff(&cli);
2123     cli_shutdown(&cli);
2124     return False;
2125   }
2126
2127   /* We really don't care what LUID we give the user. */
2128   generate_random_buffer( (unsigned char *)&smb_uid_low, 4, False);
2129
2130   if(cli_nt_login_network(&cli, domain, user, smb_uid_low, (char *)local_challenge,
2131                           smb_apasswd, smb_ntpasswd, &ctr, &info3) == False) {
2132     DEBUG(0,("domain_client_validate: unable to validate password for user %s in domain \
2133 %s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli)));
2134     cli_nt_session_close(&cli);
2135     cli_ulogoff(&cli);
2136     cli_shutdown(&cli);
2137     return False;
2138   }
2139
2140   /*
2141    * Here, if we really want it, we have lots of info about the user in info3.
2142    */
2143
2144 #if 0
2145   /* 
2146    * We don't actually need to do this - plus it fails currently with
2147    * NT_STATUS_INVALID_INFO_CLASS - we need to know *exactly* what to
2148    * send here. JRA.
2149    */
2150
2151   if(cli_nt_logoff(&cli, &ctr) == False) {
2152     DEBUG(0,("domain_client_validate: unable to log off user %s in domain \
2153 %s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli)));        
2154     cli_nt_session_close(&cli);
2155     cli_ulogoff(&cli);
2156     cli_shutdown(&cli);
2157     return False;
2158   }
2159 #endif /* 0 */
2160
2161   cli_nt_session_close(&cli);
2162   cli_ulogoff(&cli);
2163   cli_shutdown(&cli);
2164   return True;
2165 }