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