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