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