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