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