This is the ubiqx binary tree and linked list library.
[Samba.git] / source / smbd / password.c
blobf4d94791cf37876d037e9c904d9bcb786a0b0287
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 Password and authentication handling
5 Copyright (C) Andrew Tridgell 1992-1997
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.
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.
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.
22 #include "includes.h"
24 #if (defined(NETGROUP) && defined (AUTOMOUNT))
25 #include "rpcsvc/ypclnt.h"
26 #endif
28 extern int DEBUGLEVEL;
29 extern int Protocol;
31 /* users from session setup */
32 static pstring session_users="";
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]="";
39 /* Data to do lanman1/2 password challenge. */
40 static unsigned char saved_challenge[8];
41 static BOOL challenge_sent=False;
43 /*******************************************************************
44 Get the next challenge value - no repeats.
45 ********************************************************************/
46 void generate_next_challenge(char *challenge)
48 unsigned char buf[16];
49 static int counter = 0;
50 struct timeval tval;
51 int v1,v2;
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);
60 /* mash it up with md4 */
61 mdfour(buf, (unsigned char *)challenge, 8);
63 memcpy(saved_challenge, buf, 8);
64 memcpy(challenge,buf,8);
65 challenge_sent = True;
68 /*******************************************************************
69 set the last challenge sent, usually from a password server
70 ********************************************************************/
71 BOOL set_challenge(char *challenge)
73 memcpy(saved_challenge,challenge,8);
74 challenge_sent = True;
75 return(True);
78 /*******************************************************************
79 get the last challenge sent
80 ********************************************************************/
81 BOOL last_challenge(char *challenge)
83 if (!challenge_sent) return(False);
84 memcpy(challenge,saved_challenge,8);
85 return(True);
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;
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)
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];
108 /****************************************************************************
109 invalidate a uid
110 ****************************************************************************/
111 void invalidate_vuid(uint16 vuid)
113 user_struct *vuser = get_valid_user_struct(vuid);
114 if(vuser == 0)
115 return;
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;
130 /****************************************************************************
131 return a validated username
132 ****************************************************************************/
133 char *validated_username(uint16 vuid)
135 user_struct *vuser = get_valid_user_struct(vuid);
136 if(vuser == 0)
137 return 0;
138 return(vuser->name);
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)
148 user_struct *vuser;
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;
161 #if 0
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).
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 */
180 #endif
182 validated_users = (user_struct *)Realloc(validated_users,
183 sizeof(user_struct)*
184 (num_validated_users+1));
186 if (!validated_users)
188 DEBUG(0,("Failed to realloc users struct!\n"));
189 num_validated_users = 0;
190 return UID_FIELD_INVALID;
193 vuser = &validated_users[num_validated_users];
194 num_validated_users++;
196 vuser->uid = uid;
197 vuser->gid = gid;
198 vuser->guest = guest;
199 strcpy(vuser->name,name);
201 vuser->user_ngroups = 0;
202 vuser->user_groups = NULL;
203 vuser->user_igroups = NULL;
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);
212 DEBUG(3,("uid %d registered to name %s\n",uid,name));
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");
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));
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));
238 #endif
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)
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';
256 return (uint16)((num_validated_users - 1) + VUID_OFFSET);
260 /****************************************************************************
261 add a name to the session users list
262 ****************************************************************************/
263 void add_session_user(char *user)
265 fstring suser;
266 StrnCpy(suser,user,sizeof(suser)-1);
268 if (!Get_Pwnam(suser,True)) return;
270 if (suser && *suser && !in_list(suser,session_users,False))
272 if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring))
273 DEBUG(1,("Too many session users??\n"));
274 else
276 strcat(session_users," ");
277 strcat(session_users,suser);
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)
287 static struct spwd *getspnam(char *username) /* fake shadow password routine */
289 FILE *f;
290 char line[1024];
291 static char pw[20];
292 static struct spwd static_spwd;
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;
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;
310 break;
313 fclose(f);
314 if (static_spwd.sp_pwdp)
315 return &static_spwd;
316 return 0;
318 #endif
321 #ifdef OSF1_ENH_SEC
322 /****************************************************************************
323 an enhanced crypt for OSF1
324 ****************************************************************************/
325 static char *osf1_bigcrypt(char *password,char *salt1)
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++;
336 StrnCpy(salt,salt1,2);
337 StrnCpy(result,salt1,2);
339 for (i=0; i<parts;i++)
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;
347 return(result);
349 #endif
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)
357 #ifdef OSF1_ENH_SEC
358 struct pr_passwd *mypasswd;
359 time_t starttime;
361 mypasswd = getprpwnam (user);
362 starttime = time (NULL);
364 if (result)
366 mypasswd->ufld.fd_slogin = starttime;
367 mypasswd->ufld.fd_nlogins = 0;
369 putprpwnam(user,mypasswd);
371 DEBUG(3,("Update protected database for Account %s after succesful connection\n",user));
373 else
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 )
379 mypasswd->uflg.fg_lock = 0;
380 DEBUG(3,("Account is disabled -- see Account Administrator.\n"));
382 putprpwnam ( user , mypasswd );
383 DEBUG(3,("Update protected database for Account %s after refusing connection\n",user));
385 #else
386 DEBUG(6,("Updated database with %s %s\n",user,BOOLSTR(result)));
387 #endif
391 #ifdef USE_PAM
392 /*******************************************************************
393 check on PAM authentication
394 ********************************************************************/
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
401 static char *PAM_username;
402 static char *PAM_password;
404 /* PAM conversation function
405 * Here we assume (for now, at least) that echo on means login name, and
406 * echo off means password.
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);
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
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;
445 if (reply) *resp = reply;
446 return PAM_SUCCESS;
448 static struct pam_conv PAM_conversation = {
449 &PAM_conv,
450 NULL
454 static BOOL pam_auth(char *this_user,char *password)
456 pam_handle_t *pamh;
457 int pam_error;
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?
466 #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
467 pam_end(pamh, 0); return False; \
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);
485 #endif
488 #ifdef AFS_AUTH
489 /*******************************************************************
490 check on AFS authentication
491 ********************************************************************/
492 static BOOL afs_auth(char *this_user,char *password)
494 long password_expires = 0;
495 char *reason;
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);
512 #endif
515 #ifdef DFS_AUTH
517 sec_login_handle_t my_dce_sec_context;
518 int dcelogin_atmost_once = 0;
520 /*******************************************************************
521 check on a DCE/DFS authentication
522 ********************************************************************/
523 static BOOL dfs_auth(char *this_user,char *password)
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];
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!
539 if (!strcmp((char *)crypt(password,this_salt),this_crypted) ||
540 dcelogin_atmost_once)
541 return(False);
543 if (sec_login_setup_identity(
544 (unsigned char *)this_user,
545 sec_login_no_flags,
546 &my_dce_sec_context,
547 &err) == 0)
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);
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;
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 )
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));
570 return(False);
573 sec_login_set_context(my_dce_sec_context, &err);
574 if (err != error_status_ok )
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);
582 else
584 DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
585 this_user, getpid()));
588 dcelogin_atmost_once = 1;
589 return (True);
592 void dfs_unlogin(void)
594 error_status_t err;
595 int err2;
596 unsigned char dce_errstr[dce_c_error_string_len];
598 sec_login_purge_context(my_dce_sec_context, &err);
599 if (err != error_status_ok )
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));
607 #endif
609 #ifdef KRB5_AUTH
610 /*******************************************************************
611 check on Kerberos authentication
612 ********************************************************************/
613 static BOOL krb5_auth(char *this_user,char *password)
615 krb5_data tgtname = {
617 KRB5_TGS_NAME_SIZE,
618 KRB5_TGS_NAME
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;
633 if ( retval=krb5_init_context(&kcontext))
635 return(False);
638 if ( retval = krb5_timeofday(kcontext, &now) )
640 return(False);
643 if ( retval = krb5_cc_default(kcontext, &ccache) )
645 return(False);
648 if ( retval = krb5_parse_name(kcontext, this_user, &kprinc) )
650 return(False);
653 memset((char *)&kcreds, 0, sizeof(kcreds));
655 kcreds.client = kprinc;
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)))
666 return(False);
669 kcreds.server = server;
671 retval = krb5_get_in_tkt_with_password(kcontext,
672 options,
673 addrs,
674 NULL,
675 preauth,
676 password,
678 &kcreds,
681 if ( retval )
683 return(False);
686 return(True);
688 #endif /* KRB5_AUTH */
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)
696 #define LINUX_PASSWORD_SEG_CHARS 8
697 char salt[3];
698 int i;
700 StrnCpy(salt,salt1,2);
701 crypted +=2;
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);
711 return(1);
713 #endif
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)
725 int len = strlen(s);
726 int i;
728 #ifdef PASSWORD_LENGTH
729 len = MIN(len,PASSWORD_LENGTH);
730 #endif
732 if (N <= 0 || offset >= len)
733 return(fn(s));
735 for (i=offset;i<(len-(N-1));i++)
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;
744 return(False);
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)
756 int n;
757 for (n=1;n<=N;n++)
758 if (string_combinations2(s,0,fn,n)) return(True);
759 return(False);
764 /****************************************************************************
765 core of password checking routine
766 ****************************************************************************/
767 BOOL password_check(char *password)
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!!!
780 return (pam_auth(this_user,password));
781 #endif
783 #ifdef AFS_AUTH
784 if (afs_auth(this_user,password)) return(True);
785 #endif
787 #ifdef DFS_AUTH
788 if (dfs_auth(this_user,password)) return(True);
789 #endif
791 #ifdef KRB5_AUTH
792 if (krb5_auth(this_user,password)) return(True);
793 #endif
795 #ifdef PWDAUTH
796 if (pwdauth(this_user,password) == 0)
797 return(True);
798 #endif
800 #ifdef OSF1_ENH_SEC
801 return(strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0);
802 #endif
804 #ifdef ULTRIX_AUTH
805 return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
806 #endif
808 #ifdef LINUX_BIGCRYPT
809 return(linux_bigcrypt(password,this_salt,this_crypted));
810 #endif
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
820 /****************************************************************************
821 core of smb password checking routine.
822 ****************************************************************************/
823 BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8)
825 /* Finish the encryption of part_passwd. */
826 unsigned char p21[21];
827 unsigned char p24[24];
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;
835 memset(p21,'\0',21);
836 memcpy(p21,part_passwd,16);
837 E_P24(p21, c8, p24);
838 #if DEBUG_PASSWORD
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"));
858 #endif
859 return (memcmp(p24, password, 24) == 0);
862 /****************************************************************************
863 check if a username/password is OK
864 ****************************************************************************/
865 BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd)
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;
874 if (password) password[pwlen] = 0;
876 if (pwlen == 24)
877 challenge_done = last_challenge(challenge);
879 #if DEBUG_PASSWORD
880 if (challenge_done)
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));
890 #endif
892 if (!password)
893 return(False);
895 if (((!*password) || (!pwlen)) && !lp_null_passwords())
896 return(False);
898 if (pwd && !user)
900 pass = (struct passwd *) pwd;
901 user = pass->pw_name;
903 else
904 pass = Get_Pwnam(user,True);
906 DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen, challenge_done));
908 if((pwlen == 24) && challenge_done)
910 DEBUG(4,("Checking SMB password for user %s (l=24)\n",user));
912 if (!pass)
914 DEBUG(3,("Couldn't find user %s\n",user));
915 return(False);
918 smb_pass = get_smbpwnam(user);
919 if(!smb_pass)
921 DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
922 return(False);
925 /* Ensure the uid's match */
926 if(smb_pass->smb_userid != pass->pw_uid)
928 DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
929 return(False);
932 if(Protocol >= PROTOCOL_NT1)
934 /* We have the NT MD4 hash challenge available - see if we can
935 use it (ie. does it exist in the smbpasswd file).
937 if(smb_pass->smb_nt_passwd != NULL)
939 DEBUG(4,("Checking NT MD4 password\n"));
940 if(smb_password_check(password,
941 smb_pass->smb_nt_passwd,
942 (unsigned char *)challenge))
944 update_protected_database(user,True);
945 return(True);
947 DEBUG(4,("NT MD4 password check failed\n"));
951 /* Try against the lanman password */
953 if (smb_password_check(password,
954 smb_pass->smb_passwd,
955 (unsigned char *)challenge)) {
956 update_protected_database(user,True);
957 return(True);
960 DEBUG(3,("Error smb_password_check failed\n"));
963 DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
965 if (!pass)
967 DEBUG(3,("Couldn't find user %s\n",user));
968 return(False);
971 #ifdef SHADOW_PWD
973 struct spwd *spass;
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 */
980 spass = getspnam(pass->pw_name);
981 if (spass && spass->sp_pwdp)
982 pass->pw_passwd = spass->sp_pwdp;
984 #elif defined(IA_UINFO)
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));
993 #endif
995 #ifdef SecureWare
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;
1001 #endif
1003 #ifdef HPUX_10_TRUSTED
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;
1009 #endif
1011 #ifdef OSF1_ENH_SEC
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 )
1018 strcpy(pass->pw_name,mypasswd->ufld.fd_name);
1019 strcpy(pass->pw_passwd,mypasswd->ufld.fd_encrypt);
1021 else
1023 DEBUG(5,("No entry for user %s in protected database !\n",user));
1024 return(False);
1027 #endif
1029 #ifdef ULTRIX_AUTH
1031 AUTHORIZATION *ap = getauthuid( pass->pw_uid );
1032 if (ap)
1034 strcpy( pass->pw_passwd, ap->a_password );
1035 endauthent();
1038 #endif
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);
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);
1050 #ifndef PWDAUTH
1051 if (!*password) {
1052 DEBUG(3,("Allowing access to %s with null password\n",this_user));
1053 return(True);
1055 #endif
1058 /* try it as it came to us */
1059 if (password_check(password))
1061 update_protected_database(user,True);
1062 return(True);
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);
1071 /* make a copy of it */
1072 StrnCpy(pass2,password,sizeof(pstring)-1);
1074 /* try all lowercase */
1075 strlower(password);
1076 if (password_check(password))
1078 update_protected_database(user,True);
1079 return(True);
1082 /* give up? */
1083 if(level < 1)
1085 update_protected_database(user,False);
1087 /* restore it */
1088 strcpy(password,pass2);
1090 return(False);
1093 /* last chance - all combinations of up to level chars upper! */
1094 strlower(password);
1096 if (string_combinations(password,password_check,level))
1098 update_protected_database(user,True);
1099 return(True);
1102 update_protected_database(user,False);
1104 /* restore it */
1105 strcpy(password,pass2);
1107 return(False);
1112 /****************************************************************************
1113 check if a username is valid
1114 ****************************************************************************/
1115 BOOL user_ok(char *user,int snum)
1117 pstring valid, invalid;
1118 BOOL ret;
1120 StrnCpy(valid, lp_valid_users(snum), sizeof(pstring));
1121 StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring));
1123 string_sub(valid,"%S",lp_servicename(snum));
1124 string_sub(invalid,"%S",lp_servicename(snum));
1126 ret = !user_in_list(user,invalid);
1128 if (ret && valid && *valid)
1129 ret = user_in_list(user,valid);
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);
1137 return(ret);
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)
1148 #ifdef NETGROUP
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);
1161 endnetgrent();
1163 #endif
1165 #if HAVE_GETGRNAM
1167 struct group *gptr = (struct group *)getgrnam(group);
1168 char **member;
1169 if (gptr)
1171 member = gptr->gr_mem;
1172 while (member && *member)
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++;
1181 #ifdef GROUP_CHECK_PWENT
1183 struct passwd *pwd;
1184 static fstring tm;
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;
1197 endpwent ();
1199 #endif /* GROUP_CHECK_PWENT */
1202 #endif
1203 return(NULL);
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)
1214 BOOL ok = False;
1216 *guest = False;
1218 #if DEBUG_PASSWORD
1219 DEBUG(100,("checking authorisation on user=%s pass=%s\n",user,password));
1220 #endif
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
1231 if the service is guest_only then steps 1 to 5 are skipped
1234 if (GUEST_ONLY(snum)) *force = True;
1236 if (!(GUEST_ONLY(snum) && GUEST_OK(snum)))
1239 user_struct *vuser = get_valid_user_struct(vuid);
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"));
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;
1259 /* now check the list of session users */
1260 if (!ok)
1262 char *auser;
1263 char *user_list = strdup(session_users);
1264 if (!user_list) return(False);
1266 for (auser=strtok(user_list,LIST_SEP);
1267 !ok && auser;
1268 auser = strtok(NULL,LIST_SEP))
1270 fstring user2;
1271 strcpy(user2,auser);
1272 if (!user_ok(user2,snum)) continue;
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"));
1280 free(user_list);
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;
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"));
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));
1305 string_sub(user_list,"%S",lp_servicename(snum));
1307 for (auser=strtok(user_list,LIST_SEP);
1308 auser && !ok;
1309 auser = strtok(NULL,LIST_SEP))
1311 if (*auser == '@')
1313 auser = validate_group(auser+1,password,pwlen,snum);
1314 if (auser)
1316 ok = True;
1317 strcpy(user,auser);
1318 DEBUG(3,("ACCEPTED: group username and given password ok\n"));
1321 else
1323 fstring user2;
1324 strcpy(user2,auser);
1325 if (user_ok(user2,snum) &&
1326 password_ok(user2,password,pwlen,NULL))
1328 ok = True;
1329 strcpy(user,user2);
1330 DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
1335 } /* not guest only */
1337 /* check for a normal guest connection */
1338 if (!ok && GUEST_OK(snum))
1340 fstring guestname;
1341 StrnCpy(guestname,lp_guestaccount(snum),sizeof(guestname)-1);
1342 if (Get_Pwnam(guestname,True))
1344 strcpy(user,guestname);
1345 ok = True;
1346 DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
1348 else
1349 DEBUG(0,("Invalid guest account %s??\n",guestname));
1350 *guest = True;
1351 *force = True;
1354 if (ok && !user_ok(user,snum))
1356 DEBUG(0,("rejected invalid user %s\n",user));
1357 ok = False;
1360 return(ok);
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)
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))
1379 trim_string(buf," "," ");
1381 if (buf[0] != '#' && buf[0] != '\n')
1383 BOOL is_group = False;
1384 int plus = 1;
1385 char *bp = buf;
1386 if (strcmp(buf, "NO_PLUS\n") == 0)
1388 DEBUG(6, ("check_user_equiv NO_PLUS\n"));
1389 plus_allowed = 0;
1391 else {
1392 if (buf[0] == '+')
1394 bp++;
1395 if (*bp == '\n' && plus_allowed)
1397 /* a bare plus means everbody allowed */
1398 DEBUG(6, ("check_user_equiv everybody allowed\n"));
1399 fclose(fp);
1400 return True;
1403 else if (buf[0] == '-')
1405 bp++;
1406 plus = 0;
1408 if (*bp == '@')
1410 is_group = True;
1411 bp++;
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)
1419 BOOL host_ok = False;
1421 #ifdef NETGROUP
1422 if (is_group)
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;
1430 #else
1431 if (is_group)
1433 DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n"));
1434 continue;
1436 #endif
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
1445 if (!host_ok && !is_group && strequal(remote, file_host))
1446 host_ok = True;
1448 if (!host_ok)
1449 continue;
1451 /* is it this user */
1452 if (file_user == 0 || strequal(user, file_user))
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);
1464 fclose(fp);
1465 return False;
1469 /****************************************************************************
1470 check for a possible hosts equiv or rhosts entry for the user
1471 ****************************************************************************/
1472 BOOL check_hosts_equiv(char *user)
1474 char *fname = NULL;
1475 pstring rhostsfile;
1476 struct passwd *pass = Get_Pwnam(user,True);
1478 if (!pass)
1479 return(False);
1481 fname = lp_hosts_equiv();
1483 /* note: don't allow hosts.equiv on root */
1484 if (fname && *fname && (pass->pw_uid != 0))
1486 if (check_user_equiv(user,client_name(),fname))
1487 return(True);
1490 if (lp_use_rhosts())
1492 char *home = get_home_dir(user);
1493 if (home)
1495 sprintf(rhostsfile, "%s/.rhosts", home);
1496 if (check_user_equiv(user,client_name(),rhostsfile))
1497 return(True);
1501 return(False);
1505 int password_client = -1;
1506 static fstring pserver;
1507 static char *secserver_inbuf = NULL;
1509 /****************************************************************************
1510 attempted support for server level security
1511 ****************************************************************************/
1512 BOOL server_cryptkey(char *buf)
1514 pstring outbuf;
1515 fstring pass_protocol;
1516 extern fstring remote_machine;
1517 char *p;
1518 int len;
1519 fstring desthost;
1520 struct in_addr dest_ip;
1521 int port = SMB_PORT;
1522 BOOL ret;
1524 if(secserver_inbuf == NULL) {
1525 secserver_inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1526 if(secserver_inbuf == NULL) {
1527 DEBUG(0,("server_cryptkey: malloc fail for input buffer.\n"));
1528 return False;
1532 if (password_client >= 0)
1533 close(password_client);
1534 password_client = -1;
1536 if (Protocol < PROTOCOL_NT1) {
1537 strcpy(pass_protocol,"LM1.2X002");
1538 } else {
1539 strcpy(pass_protocol,"NT LM 0.12");
1542 bzero(secserver_inbuf,BUFFER_SIZE + SAFETY_MARGIN);
1543 bzero(outbuf,sizeof(outbuf));
1545 for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) {
1546 strcpy(desthost,p);
1547 standard_sub_basic(desthost);
1548 strupper(desthost);
1550 dest_ip = *interpret_addr2(desthost);
1551 if (zero_ip(dest_ip)) {
1552 DEBUG(1,("Can't resolve address for %s\n",p));
1553 continue;
1556 if (ismyip(dest_ip)) {
1557 DEBUG(1,("Password server loop - disabling password server %s\n",p));
1558 continue;
1561 password_client = open_socket_out(SOCK_STREAM, &dest_ip, port, SHORT_CONNECT_TIMEOUT);
1562 if (password_client >= 0) {
1563 DEBUG(3,("connected to password server %s\n",p));
1564 StrnCpy(pserver,p,sizeof(pserver)-1);
1565 break;
1569 if (password_client < 0) {
1570 DEBUG(1,("password server not available\n"));
1571 return(False);
1575 /* send a session request (RFC 8002) */
1577 /* put in the destination name */
1578 len = 4;
1579 p = outbuf+len;
1580 name_mangle(desthost,p,' ');
1581 len += name_len(p);
1582 p = outbuf+len;
1584 /* and my name */
1585 /* Fix from Frank Varnavas <varnavas@ny.ubs.com>.
1586 We cannot use the same name as the client to
1587 the NT password server, as NT will drop client
1588 connections if the same client name connects
1589 twice. Instead, synthesize a name from our pid.
1590 and the remote machine name.
1593 char buf2[32]; /* create name as PIDname */
1594 sprintf(buf2,"%d", getpid());
1595 strncpy(&buf2[strlen(buf2)], remote_machine, 31 - strlen(buf2));
1596 buf2[31] = '\0';
1597 DEBUG(1,("negprot w/password server as %s\n",buf2));
1598 name_mangle(buf2,p,' ');
1599 len += name_len(p);
1602 _smb_setlen(outbuf,len);
1603 CVAL(outbuf,0) = 0x81;
1605 send_smb(password_client,outbuf);
1608 if (!receive_smb(password_client,secserver_inbuf,5000) ||
1609 CVAL(secserver_inbuf,0) != 0x82) {
1610 DEBUG(1,("%s rejected the session\n",pserver));
1611 close(password_client); password_client = -1;
1612 return(False);
1615 DEBUG(3,("got session\n"));
1617 bzero(outbuf,smb_size);
1619 /* setup the protocol string */
1620 set_message(outbuf,0,strlen(pass_protocol)+2,True);
1621 p = smb_buf(outbuf);
1622 *p++ = 2;
1623 strcpy(p,pass_protocol);
1625 CVAL(outbuf,smb_com) = SMBnegprot;
1626 CVAL(outbuf,smb_flg) = 0x8;
1627 SSVAL(outbuf,smb_flg2,0x1);
1629 send_smb(password_client,outbuf);
1630 ret = receive_smb(password_client,secserver_inbuf,5000);
1632 if (!ret || CVAL(secserver_inbuf,smb_rcls) || SVAL(secserver_inbuf,smb_vwv0)) {
1633 DEBUG(1,("%s rejected the protocol\n",pserver));
1634 close(password_client); password_client= -1;
1635 return(False);
1638 if (!(CVAL(secserver_inbuf,smb_vwv1) & 1)) {
1639 DEBUG(1,("%s isn't in user level security mode\n",pserver));
1640 close(password_client); password_client= -1;
1641 return(False);
1644 memcpy(buf,secserver_inbuf,smb_len(secserver_inbuf)+4);
1646 DEBUG(3,("password server OK\n"));
1648 return(True);
1651 /****************************************************************************
1652 attempted support for server level security
1653 ****************************************************************************/
1654 BOOL server_validate(char *buf)
1656 pstring outbuf;
1657 BOOL ret;
1659 if(secserver_inbuf == NULL) {
1660 secserver_inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1661 if(secserver_inbuf == NULL) {
1662 DEBUG(0,("server_validate: malloc fail for input buffer.\n"));
1663 return False;
1667 if (password_client < 0) {
1668 DEBUG(1,("%s not connected\n",pserver));
1669 return(False);
1672 bzero(secserver_inbuf,BUFFER_SIZE + SAFETY_MARGIN);
1673 memcpy(outbuf,buf,sizeof(outbuf));
1675 /* send a session setup command */
1676 CVAL(outbuf,smb_flg) = 0x8;
1677 SSVAL(outbuf,smb_flg2,0x1);
1678 CVAL(outbuf,smb_vwv0) = 0xFF;
1680 set_message(outbuf,smb_numwords(outbuf),smb_buflen(outbuf),False);
1682 SCVAL(secserver_inbuf,smb_rcls,1);
1684 send_smb(password_client,outbuf);
1685 ret = receive_smb(password_client,secserver_inbuf,5000);
1687 if (!ret || CVAL(secserver_inbuf,smb_rcls) != 0) {
1688 DEBUG(1,("password server %s rejected the password\n",pserver));
1689 return(False);
1692 /* if logged in as guest then reject */
1693 if ((SVAL(secserver_inbuf,smb_vwv2) & 1) != 0) {
1694 DEBUG(1,("password server %s gave us guest only\n",pserver));
1695 return(False);
1698 DEBUG(3,("password server %s accepted the password\n",pserver));
1700 #if !KEEP_PASSWORD_SERVER_OPEN
1701 close(password_client); password_client= -1;
1702 #endif
1704 return(True);