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