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