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