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