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