2 Unix SMB/Netbios implementation.
4 Password and authentication handling
5 Copyright (C) Andrew Tridgell 1992-1995
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.
24 extern int DEBUGLEVEL;
27 /* users from session setup */
28 static pstring session_users="";
30 /* these are kept here to keep the string_combinations function simple */
31 static char this_user[100]="";
32 static char this_salt[100]="";
33 static char this_crypted[100]="";
36 /* Data to do lanman1/2 password challenge. */
37 static unsigned char saved_challenge[8];
38 static BOOL challenge_sent=False;
40 /*******************************************************************
41 Get the next challenge value - no repeats.
42 ********************************************************************/
43 void generate_next_challenge(char *challenge)
45 static int counter = 0;
49 v1 = (counter++) + getpid() + tval.tv_sec;
50 v2 = (counter++) * getpid() + tval.tv_usec;
51 SIVAL(challenge,0,v1);
52 SIVAL(challenge,4,v2);
53 E1(challenge,"SAMBA",(char *)saved_challenge);
54 memcpy(challenge,saved_challenge,8);
55 challenge_sent = True;
58 /*******************************************************************
59 set the last challenge sent, usually from a password server
60 ********************************************************************/
61 BOOL set_challenge(char *challenge)
63 memcpy(saved_challenge,challenge,8);
64 challenge_sent = True;
68 /*******************************************************************
69 get the last challenge sent
70 ********************************************************************/
71 BOOL last_challenge(char *challenge)
73 if (!challenge_sent) return(False);
74 memcpy(challenge,saved_challenge,8);
79 /* this holds info on user ids that are already validated for this VC */
80 static user_struct *validated_users = NULL;
81 static int num_validated_users = 0;
83 /****************************************************************************
84 check if a uid has been validated, and return an pointer to the user_struct
85 if it has. NULL if not. vuid is biased by an offset. This allows us to
86 tell random client vuid's (normally zero) from valid vuids.
87 ****************************************************************************/
88 user_struct *get_valid_user_struct(uint16 vuid)
90 if(vuid == UID_FIELD_INVALID)
93 if((vuid >= (uint16)num_validated_users) ||
94 (validated_users[vuid].uid == -1) || (validated_users[vuid].gid == -1))
96 return &validated_users[vuid];
99 /****************************************************************************
101 ****************************************************************************/
102 void invalidate_vuid(uint16 vuid)
104 user_struct *vuser = get_valid_user_struct(vuid);
110 vuser->user_ngroups = 0;
111 if(vuser->user_groups &&
112 (vuser->user_groups != (gid_t *)vuser->user_igroups))
113 free(vuser->user_groups);
114 vuser->user_groups = NULL;
115 if(vuser->user_igroups)
116 free(vuser->user_igroups);
117 vuser->user_igroups = NULL;
121 /****************************************************************************
122 return a validated username
123 ****************************************************************************/
124 char *validated_username(uint16 vuid)
126 user_struct *vuser = get_valid_user_struct(vuid);
132 /****************************************************************************
133 register a uid/name pair as being valid and that a valid password
134 has been given. vuid is biased by an offset. This allows us to
135 tell random client vuid's (normally zero) from valid vuids.
136 ****************************************************************************/
137 uint16 register_vuid(int uid,int gid, char *name,BOOL guest)
142 for(i = 0; i < num_validated_users; i++) {
143 vuser = &validated_users[i];
144 if( vuser->uid == uid )
145 return i; /* User already validated */
148 validated_users = (user_struct *)Realloc(validated_users,
150 (num_validated_users+1));
152 if (!validated_users)
154 DEBUG(0,("Failed to realloc users struct!\n"));
155 num_validated_users = 0;
156 return UID_FIELD_INVALID;
159 vuser = &validated_users[num_validated_users];
160 num_validated_users++;
164 vuser->guest = guest;
165 strcpy(vuser->name,name);
167 vuser->user_ngroups = 0;
168 vuser->user_groups = NULL;
169 vuser->user_igroups = NULL;
171 /* Find all the groups this uid is in and store them.
172 Used by become_user() */
173 setup_groups(name,uid,gid,
174 &vuser->user_ngroups,
175 &vuser->user_igroups,
176 &vuser->user_groups);
178 DEBUG(3,("uid %d registered to name %s\n",uid,name));
180 return (uint16)((num_validated_users - 1) + VUID_OFFSET);
184 /****************************************************************************
185 add a name to the session users list
186 ****************************************************************************/
187 void add_session_user(char *user)
190 StrnCpy(suser,user,sizeof(suser)-1);
192 if (!Get_Pwnam(suser,True)) return;
194 if (suser && *suser && !in_list(suser,session_users,False))
196 if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring))
197 DEBUG(1,("Too many session users??\n"));
200 strcat(session_users," ");
201 strcat(session_users,suser);
208 /* a fake shadow password routine which just fills a fake spwd struct
209 * with the sp_pwdp field. (sreiz@aie.nl)
211 static struct spwd *getspnam(char *username) /* fake shadow password routine */
216 static struct spwd static_spwd;
218 static_spwd.sp_pwdp=0;
219 if (!(f=fopen("/etc/master.passwd", "r")))
221 while (fgets(line, 1024, f)) {
222 if (!strncmp(line, username, strlen(username)) &&
223 line[strlen(username)]==':') { /* found entry */
226 p=line+strlen(username)+1;
227 if ((q=strchr(p, ':'))) {
232 static_spwd.sp_pwdp=pw;
238 if (static_spwd.sp_pwdp)
246 /****************************************************************************
247 an enhanced crypt for OSF1
248 ****************************************************************************/
249 static char *osf1_bigcrypt(char *password,char *salt1)
251 static char result[AUTH_MAX_PASSWD_LENGTH] = "";
256 int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
257 if (strlen(password)%AUTH_CLEARTEXT_SEG_CHARS)
260 StrnCpy(salt,salt1,2);
261 StrnCpy(result,salt1,2);
263 for (i=0; i<parts;i++)
267 StrnCpy(salt,&result[2+i*AUTH_CIPHERTEXT_SEG_CHARS],2);
268 p2 += AUTH_CLEARTEXT_SEG_CHARS;
276 /****************************************************************************
277 update the enhanced security database. Only relevant for OSF1 at the moment.
278 ****************************************************************************/
279 static void update_protected_database( char *user, BOOL result)
282 struct pr_passwd *mypasswd;
285 mypasswd = getprpwnam (user);
286 starttime = time (NULL);
290 mypasswd->ufld.fd_slogin = starttime;
291 mypasswd->ufld.fd_nlogins = 0;
293 putprpwnam(user,mypasswd);
295 DEBUG(3,("Update protected database for Account %s after succesful connection\n",user));
299 mypasswd->ufld.fd_ulogin = starttime;
300 mypasswd->ufld.fd_nlogins = mypasswd->ufld.fd_nlogins + 1;
301 if ( mypasswd->ufld.fd_max_tries != 0 && mypasswd->ufld.fd_nlogins > mypasswd->ufld.fd_max_tries )
303 mypasswd->uflg.fg_lock = 0;
304 DEBUG(3,("Account is disabled -- see Account Administrator.\n"));
306 putprpwnam ( user , mypasswd );
307 DEBUG(3,("Update protected database for Account %s after refusing connection\n",user));
310 DEBUG(6,("Updated database with %s %s\n",user,BOOLSTR(result)));
316 /*******************************************************************
317 check on PAM authentication
318 ********************************************************************/
320 /* We first need some helper functions */
321 #include <security/pam_appl.h>
322 /* Static variables used to communicate between the conversation function
323 * and the server_login function
325 static char *PAM_username;
326 static char *PAM_password;
328 /* PAM conversation function
329 * Here we assume (for now, at least) that echo on means login name, and
330 * echo off means password.
332 static int PAM_conv (int num_msg,
333 const struct pam_message **msg,
334 struct pam_response **resp,
336 int count = 0, replies = 0;
337 struct pam_response *reply = NULL;
338 int size = sizeof(struct pam_response);
340 #define GET_MEM if (reply) realloc(reply, size); else reply = malloc(size); \
341 if (!reply) return PAM_CONV_ERR; \
342 size += sizeof(struct pam_response)
343 #define COPY_STRING(s) (s) ? strdup(s) : NULL
345 for (count = 0; count < num_msg; count++) {
346 switch (msg[count]->msg_style) {
347 case PAM_PROMPT_ECHO_ON:
349 reply[replies].resp_retcode = PAM_SUCCESS;
350 reply[replies++].resp = COPY_STRING(PAM_username);
353 case PAM_PROMPT_ECHO_OFF:
355 reply[replies].resp_retcode = PAM_SUCCESS;
356 reply[replies++].resp = COPY_STRING(PAM_password);
364 /* Must be an error of some sort... */
369 if (reply) *resp = reply;
372 static struct pam_conv PAM_conversation = {
378 static BOOL pam_auth(char *this_user,char *password)
383 /* Now use PAM to do authentication. For now, we won't worry about
384 * session logging, only authentication. Bail out if there are any
385 * errors. Since this is a limited protocol, and an even more limited
386 * function within a server speaking this protocol, we can't be as
387 * verbose as would otherwise make sense.
388 * Query: should we be using PAM_SILENT to shut PAM up?
390 #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
391 pam_end(pamh, 0); return False; \
393 PAM_password = password;
394 PAM_username = this_user;
395 pam_error = pam_start("samba", this_user, &PAM_conversation, &pamh);
397 pam_error = pam_authenticate(pamh, 0);
399 /* It is not clear to me that account management is the right thing
400 * to do, but it is not clear that it isn't, either. This can be
401 * removed if no account management should be done. Alternately,
402 * put a pam_allow.so entry in /etc/pam.conf for account handling. */
403 pam_error = pam_acct_mgmt(pamh, 0);
405 pam_end(pamh, PAM_SUCCESS);
406 /* If this point is reached, the user has been authenticated. */
413 /*******************************************************************
414 check on AFS authentication
415 ********************************************************************/
416 static BOOL afs_auth(char *this_user,char *password)
418 long password_expires = 0;
421 /* For versions of AFS prior to 3.3, this routine has few arguments, */
422 /* but since I can't find the old documentation... :-) */
424 if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
426 (char *) 0, /* instance */
427 (char *) 0, /* cell */
429 0, /* lifetime, default */
430 &password_expires, /*days 'til it expires */
441 sec_login_handle_t my_dce_sec_context;
442 int dcelogin_atmost_once = 0;
444 /*******************************************************************
445 check on a DCE/DFS authentication
446 ********************************************************************/
447 static BOOL dfs_auth(char *this_user,char *password)
452 boolean32 password_reset;
453 sec_passwd_rec_t my_dce_password;
454 sec_login_auth_src_t auth_src = sec_login_auth_src_network;
455 unsigned char dce_errstr[dce_c_error_string_len];
458 * We only go for a DCE login context if the given password
459 * matches that stored in the local password file..
460 * Assumes local passwd file is kept in sync w/ DCE RGY!
463 if (!strcmp((char *)crypt(password,this_salt),this_crypted) ||
464 dcelogin_atmost_once)
467 if (sec_login_setup_identity(
468 (unsigned char *)this_user,
473 dce_error_inq_text(err, dce_errstr, &err2);
474 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
475 this_user,dce_errstr));
479 my_dce_password.version_number = sec_passwd_c_version_none;
480 my_dce_password.pepper = NULL;
481 my_dce_password.key.key_type = sec_passwd_plain;
482 my_dce_password.key.tagged_union.plain = (idl_char *)password;
484 if (sec_login_valid_and_cert_ident(my_dce_sec_context,
490 dce_error_inq_text(err, dce_errstr, &err2);
491 DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
492 this_user,dce_errstr));
497 sec_login_set_context(my_dce_sec_context, &err);
498 if (err != error_status_ok )
500 dce_error_inq_text(err, dce_errstr, &err2);
501 DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
502 this_user,dce_errstr));
503 sec_login_purge_context(my_dce_sec_context, &err);
508 DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
509 this_user, getpid()));
512 dcelogin_atmost_once = 1;
516 void dfs_unlogin(void)
520 unsigned char dce_errstr[dce_c_error_string_len];
522 sec_login_purge_context(my_dce_sec_context, &err);
523 if (err != error_status_ok )
525 dce_error_inq_text(err, dce_errstr, &err2);
526 DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
527 getpid(), dce_errstr));
534 #ifdef LINUX_BIGCRYPT
535 /****************************************************************************
536 an enhanced crypt for Linux to handle password longer than 8 characters
537 ****************************************************************************/
538 static int linux_bigcrypt(char *password,char *salt1, char *crypted)
540 #define LINUX_PASSWORD_SEG_CHARS 8
544 StrnCpy(salt,salt1,2);
547 for ( i=strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
548 char * p = crypt(password,salt) + 2;
549 if(strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
551 password += LINUX_PASSWORD_SEG_CHARS;
552 crypted += strlen(p);
560 /****************************************************************************
561 apply a function to upper/lower case combinations
562 of a string and return true if one of them returns true.
563 try all combinations with N uppercase letters.
564 offset is the first char to try and change (start with 0)
565 it assumes the string starts lowercased
566 ****************************************************************************/
567 static BOOL string_combinations2(char *s,int offset,BOOL (*fn)(),int N)
572 #ifdef PASSWORD_LENGTH
573 len = MIN(len,PASSWORD_LENGTH);
576 if (N <= 0 || offset >= len)
579 for (i=offset;i<(len-(N-1));i++)
582 if (!islower(c)) continue;
584 if (string_combinations2(s,i+1,fn,N-1))
591 /****************************************************************************
592 apply a function to upper/lower case combinations
593 of a string and return true if one of them returns true.
594 try all combinations with up to N uppercase letters.
595 offset is the first char to try and change (start with 0)
596 it assumes the string starts lowercased
597 ****************************************************************************/
598 static BOOL string_combinations(char *s,BOOL (*fn)(),int N)
602 if (string_combinations2(s,0,fn,n)) return(True);
608 /****************************************************************************
609 core of password checking routine
610 ****************************************************************************/
611 BOOL password_check(char *password)
615 if (pam_auth(this_user,password)) return(True);
619 if (afs_auth(this_user,password)) return(True);
623 if (dfs_auth(this_user,password)) return(True);
627 if (pwdauth(this_user,password) == 0)
632 return(strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0);
636 return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
639 #ifdef LINUX_BIGCRYPT
640 return(linux_bigcrypt(password,this_salt,this_crypted));
644 DEBUG(1,("Warning - no crypt available\n"));
647 return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
652 /****************************************************************************
653 core of smb password checking routine.
654 ****************************************************************************/
655 BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8)
657 /* Finish the encryption of part_passwd. */
658 unsigned char p21[21];
659 unsigned char p24[24];
661 if(part_passwd == NULL)
662 DEBUG(10,("No password set - allowing access\n"));
663 /* No password set - always true ! */
664 if(part_passwd == NULL)
668 memcpy(p21,part_passwd,16);
673 DEBUG(100,("Part password (P16) was |"));
674 for(i = 0; i < 16; i++)
675 DEBUG(100,("%X ", (unsigned char)part_passwd[i]));
677 DEBUG(100,("Password from client was |"));
678 for(i = 0; i < 24; i++)
679 DEBUG(100,("%X ", (unsigned char)password[i]));
681 DEBUG(100,("Given challenge was |"));
682 for(i = 0; i < 8; i++)
683 DEBUG(100,("%X ", (unsigned char)c8[i]));
685 DEBUG(100,("Value from encryption was |"));
686 for(i = 0; i < 24; i++)
687 DEBUG(100,("%X ", (unsigned char)p24[i]));
691 return (memcmp(p24, password, 24) == 0);
695 /****************************************************************************
696 check if a username/password is OK
697 ****************************************************************************/
698 BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd)
701 int level = lp_passwordlevel();
705 struct smb_passwd *smb_pass;
706 BOOL challenge_done = False;
709 if (password) password[pwlen] = 0;
713 challenge_done = last_challenge(challenge);
721 DEBUG(100,("checking user=[%s] pass=[",user));
722 for( i = 0; i < 24; i++)
723 DEBUG(100,("%0x ", (unsigned char)password[i]));
728 DEBUG(100,("checking user=[%s] pass=[%s]\n",user,password));
734 if (((!*password) || (!pwlen)) && !lp_null_passwords())
739 pass = (struct passwd *) pwd;
740 user = pass->pw_name;
743 pass = Get_Pwnam(user,True);
747 DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen, challenge_done));
749 if((pwlen == 24) && challenge_done)
751 DEBUG(4,("Checking SMB password for user %s (l=24)\n",user));
755 DEBUG(3,("Couldn't find user %s\n",user));
759 smb_pass = get_smbpwnam(user);
762 DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
766 /* Ensure the uid's match */
767 if(smb_pass->smb_userid != pass->pw_uid)
769 DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
773 if(Protocol >= PROTOCOL_NT1)
775 /* We have the NT MD4 hash challenge available - see if we can
776 use it (ie. does it exist in the smbpasswd file).
778 if(smb_pass->smb_nt_passwd != NULL)
780 DEBUG(4,("Checking NT MD4 password\n"));
781 if(smb_password_check(password,
782 smb_pass->smb_nt_passwd,
785 update_protected_database(user,True);
788 DEBUG(4,("NT MD4 password check failed\n"));
792 /* Try against the lanman password */
794 if (smb_password_check(password,
795 smb_pass->smb_passwd,
796 (char *)challenge)) {
797 update_protected_database(user,True);
801 DEBUG(3,("Error smb_password_check failed\n"));
805 DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
809 DEBUG(3,("Couldn't find user %s\n",user));
817 /* many shadow systems require you to be root to get the password,
818 in most cases this should already be the case when this
819 function is called, except perhaps for IPC password changing
822 spass = getspnam(pass->pw_name);
823 if (spass && spass->sp_pwdp)
824 pass->pw_passwd = spass->sp_pwdp;
830 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
831 if (pr_pw && pr_pw->ufld.fd_encrypt)
832 pass->pw_passwd = pr_pw->ufld.fd_encrypt;
836 #ifdef HPUX_10_TRUSTED
838 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
839 if (pr_pw && pr_pw->ufld.fd_encrypt)
840 pass->pw_passwd = pr_pw->ufld.fd_encrypt;
846 struct pr_passwd *mypasswd;
847 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user));
848 mypasswd = getprpwnam (user);
851 strcpy(pass->pw_name,mypasswd->ufld.fd_name);
852 strcpy(pass->pw_passwd,mypasswd->ufld.fd_encrypt);
856 DEBUG(5,("No entry for user %s in protected database !\n",user));
864 AUTHORIZATION *ap = getauthuid( pass->pw_uid );
867 strcpy( pass->pw_passwd, ap->a_password );
873 /* extract relevant info */
874 strcpy(this_user,pass->pw_name);
875 strcpy(this_salt,pass->pw_passwd);
876 strcpy(this_crypted,pass->pw_passwd);
878 if (!*this_crypted) {
879 if (!lp_null_passwords()) {
880 DEBUG(2,("Disallowing access to %s due to null password\n",this_user));
885 DEBUG(3,("Allowing access to %s with null password\n",this_user));
891 /* try it as it came to us */
892 if (password_check(password))
894 update_protected_database(user,True);
898 /* if the password was given to us with mixed case then we don't
899 need to proceed as we know it hasn't been case modified by the
901 if (strhasupper(password) && strhaslower(password))
904 /* make a copy of it */
905 StrnCpy(pass2,password,sizeof(pstring)-1);
907 /* try all lowercase */
909 if (password_check(password))
911 update_protected_database(user,True);
918 update_protected_database(user,False);
921 strcpy(password,pass2);
926 /* last chance - all combinations of up to level chars upper! */
929 if (string_combinations(password,password_check,level))
931 update_protected_database(user,True);
935 update_protected_database(user,False);
938 strcpy(password,pass2);
945 /****************************************************************************
946 check if a username is valid
947 ****************************************************************************/
948 BOOL user_ok(char *user,int snum)
950 pstring valid, invalid;
953 StrnCpy(valid, lp_valid_users(snum), sizeof(pstring));
954 StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring));
956 string_sub(valid,"%S",lp_servicename(snum));
957 string_sub(invalid,"%S",lp_servicename(snum));
959 ret = !user_in_list(user,invalid);
961 if (ret && valid && *valid)
962 ret = user_in_list(user,valid);
964 if (ret && lp_onlyuser(snum)) {
965 char *user_list = lp_username(snum);
966 string_sub(user_list,"%S",lp_servicename(snum));
967 ret = user_in_list(user,user_list);
976 /****************************************************************************
977 validate a group username entry. Return the username or NULL
978 ****************************************************************************/
979 static char *validate_group(char *group,char *password,int pwlen,int snum)
983 char *host, *user, *domain;
985 while (getnetgrent(&host, &user, &domain)) {
987 if (user_ok(user, snum) &&
988 password_ok(user,password,pwlen,NULL)) {
1000 struct group *gptr = (struct group *)getgrnam(group);
1004 member = gptr->gr_mem;
1005 while (member && *member)
1007 static fstring name;
1008 strcpy(name,*member);
1009 if (user_ok(name,snum) &&
1010 password_ok(name,password,pwlen,NULL))
1014 #ifdef GROUP_CHECK_PWENT
1020 while (pwd = getpwent ()) {
1021 if (*(pwd->pw_passwd) && pwd->pw_gid == gptr->gr_gid) {
1022 /* This Entry have PASSWORD and same GID then check pwd */
1023 if (password_ok(NULL, password, pwlen, pwd)) {
1024 strcpy(tm, pwd->pw_name);
1032 #endif /* GROUP_CHECK_PWENT */
1041 /****************************************************************************
1042 check for authority to login to a service with a given username/password
1043 ****************************************************************************/
1044 BOOL authorise_login(int snum,char *user,char *password, int pwlen,
1045 BOOL *guest,BOOL *force,uint16 vuid)
1052 DEBUG(100,("checking authorisation on user=%s pass=%s\n",user,password));
1055 /* there are several possabilities:
1056 1) login as the given user with given password
1057 2) login as a previously registered username with the given password
1058 3) login as a session list username with the given password
1059 4) login as a previously validated user/password pair
1060 5) login as the "user =" user with given password
1061 6) login as the "user =" user with no password (guest connection)
1062 7) login as guest user with no password
1064 if the service is guest_only then steps 1 to 5 are skipped
1067 if (GUEST_ONLY(snum)) *force = True;
1069 if (!(GUEST_ONLY(snum) && GUEST_OK(snum)))
1072 user_struct *vuser = get_valid_user_struct(vuid);
1074 /* check the given username and password */
1075 if (!ok && (*user) && user_ok(user,snum)) {
1076 ok = password_ok(user,password, pwlen, NULL);
1077 if (ok) DEBUG(3,("ACCEPTED: given username password ok\n"));
1080 /* check for a previously registered guest username */
1081 if (!ok && (vuser != 0) && vuser->guest) {
1082 if (user_ok(vuser->name,snum) &&
1083 password_ok(vuser->name, password, pwlen, NULL)) {
1084 strcpy(user, vuser->name);
1085 vuser->guest = False;
1086 DEBUG(3,("ACCEPTED: given password with registered user %s\n", user));
1092 /* now check the list of session users */
1096 char *user_list = strdup(session_users);
1097 if (!user_list) return(False);
1099 for (auser=strtok(user_list,LIST_SEP);
1101 auser = strtok(NULL,LIST_SEP))
1104 strcpy(user2,auser);
1105 if (!user_ok(user2,snum)) continue;
1107 if (password_ok(user2,password, pwlen, NULL)) {
1110 DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
1116 /* check for a previously validated username/password pair */
1117 if (!ok && !lp_revalidate(snum) &&
1118 (vuser != 0) && !vuser->guest &&
1119 user_ok(vuser->name,snum)) {
1120 strcpy(user,vuser->name);
1122 DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
1126 /* check for a rhosts entry */
1127 if (!ok && user_ok(user,snum) && check_hosts_equiv(user)) {
1129 DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
1132 /* check the user= fields and the given password */
1133 if (!ok && lp_username(snum)) {
1136 StrnCpy(user_list,lp_username(snum),sizeof(pstring));
1138 string_sub(user_list,"%S",lp_servicename(snum));
1140 for (auser=strtok(user_list,LIST_SEP);
1142 auser = strtok(NULL,LIST_SEP))
1146 auser = validate_group(auser+1,password,pwlen,snum);
1151 DEBUG(3,("ACCEPTED: group username and given password ok\n"));
1157 strcpy(user2,auser);
1158 if (user_ok(user2,snum) &&
1159 password_ok(user2,password,pwlen,NULL))
1163 DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
1168 } /* not guest only */
1170 /* check for a normal guest connection */
1171 if (!ok && GUEST_OK(snum))
1174 StrnCpy(guestname,lp_guestaccount(snum),sizeof(guestname)-1);
1175 if (Get_Pwnam(guestname,True))
1177 strcpy(user,guestname);
1179 DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
1182 DEBUG(0,("Invalid guest account %s??\n",guestname));
1187 if (ok && !user_ok(user,snum))
1189 DEBUG(0,("rejected invalid user %s\n",user));
1197 /****************************************************************************
1198 read the a hosts.equiv or .rhosts file and check if it
1199 allows this user from this machine
1200 ****************************************************************************/
1201 static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
1204 int plus_allowed = 1;
1207 FILE *fp = fopen(equiv_file, "r");
1208 DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
1209 if (! fp) return False;
1210 while(fgets(buf, sizeof(buf), fp))
1212 trim_string(buf," "," ");
1214 if (buf[0] != '#' && buf[0] != '\n')
1216 BOOL is_group = False;
1219 if (strcmp(buf, "NO_PLUS\n") == 0)
1221 DEBUG(6, ("check_user_equiv NO_PLUS\n"));
1228 if (*bp == '\n' && plus_allowed)
1230 /* a bare plus means everbody allowed */
1231 DEBUG(6, ("check_user_equiv everybody allowed\n"));
1236 else if (buf[0] == '-')
1246 file_host = strtok(bp, " \t\n");
1247 file_user = strtok(NULL, " \t\n");
1248 DEBUG(7, ("check_user_equiv %s %s\n", file_host, file_user));
1249 if (file_host && *file_host)
1251 BOOL host_ok = False;
1256 static char *mydomain = NULL;
1258 yp_get_default_domain(&mydomain);
1259 if (mydomain && innetgr(file_host,remote,user,mydomain))
1265 DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n"));
1270 /* is it this host */
1271 /* the fact that remote has come from a call of gethostbyaddr
1272 * means that it may have the fully qualified domain name
1273 * so we could look up the file version to get it into
1274 * a canonical form, but I would rather just type it
1275 * in full in the equiv file
1277 if (!host_ok && !is_group && strequal(remote, file_host))
1283 /* is it this user */
1284 if (file_user == 0 || strequal(user, file_user))
1287 DEBUG(5, ("check_user_equiv matched %s%s %s\n",
1288 (plus ? "+" : "-"), file_host,
1289 (file_user ? file_user : "")));
1290 return (plus ? True : False);
1301 /****************************************************************************
1302 check for a possible hosts equiv or rhosts entry for the user
1303 ****************************************************************************/
1304 BOOL check_hosts_equiv(char *user)
1308 struct passwd *pass = Get_Pwnam(user,True);
1313 fname = lp_hosts_equiv();
1315 /* note: don't allow hosts.equiv on root */
1316 if (fname && *fname && (pass->pw_uid != 0))
1318 if (check_user_equiv(user,client_name(),fname))
1322 if (lp_use_rhosts())
1324 char *home = get_home_dir(user);
1327 sprintf(rhostsfile, "%s/.rhosts", home);
1328 if (check_user_equiv(user,client_name(),rhostsfile))
1337 int password_client = -1;
1338 static fstring pserver;
1340 /****************************************************************************
1341 attempted support for server level security
1342 ****************************************************************************/
1343 BOOL server_cryptkey(char *buf)
1345 pstring inbuf,outbuf;
1346 fstring pass_protocol;
1347 extern fstring remote_machine;
1351 struct in_addr dest_ip;
1352 int port = SMB_PORT;
1355 if (password_client >= 0)
1356 close(password_client);
1357 password_client = -1;
1359 if (Protocol < PROTOCOL_NT1) {
1360 strcpy(pass_protocol,"LM1.2X002");
1362 strcpy(pass_protocol,"NT LM 0.12");
1365 bzero(inbuf,sizeof(inbuf));
1366 bzero(outbuf,sizeof(outbuf));
1368 for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) {
1370 standard_sub_basic(desthost);
1373 dest_ip = *interpret_addr2(desthost);
1374 if (zero_ip(dest_ip)) {
1375 DEBUG(1,("Can't resolve address for %s\n",p));
1379 if (ismyip(dest_ip)) {
1380 DEBUG(1,("Password server loop - disabling password server %s\n",p));
1384 password_client = open_socket_out(SOCK_STREAM, &dest_ip, port, SHORT_CONNECT_TIMEOUT);
1385 if (password_client >= 0) {
1386 DEBUG(3,("connected to password server %s\n",p));
1387 StrnCpy(pserver,p,sizeof(pserver)-1);
1392 if (password_client < 0) {
1393 DEBUG(1,("password server not available\n"));
1398 /* send a session request (RFC 8002) */
1400 /* put in the destination name */
1403 name_mangle(desthost,p,' ');
1408 name_mangle(remote_machine,p,' ');
1411 _smb_setlen(outbuf,len);
1412 CVAL(outbuf,0) = 0x81;
1414 send_smb(password_client,outbuf);
1417 if (!receive_smb(password_client,inbuf,5000) ||
1418 CVAL(inbuf,0) != 0x82) {
1419 DEBUG(1,("%s rejected the session\n",pserver));
1420 close(password_client); password_client = -1;
1424 DEBUG(3,("got session\n"));
1426 bzero(outbuf,smb_size);
1428 /* setup the protocol string */
1429 set_message(outbuf,0,strlen(pass_protocol)+2,True);
1430 p = smb_buf(outbuf);
1432 strcpy(p,pass_protocol);
1434 CVAL(outbuf,smb_com) = SMBnegprot;
1435 CVAL(outbuf,smb_flg) = 0x8;
1436 SSVAL(outbuf,smb_flg2,0x1);
1438 send_smb(password_client,outbuf);
1439 ret = receive_smb(password_client,inbuf,5000);
1441 if (!ret || CVAL(inbuf,smb_rcls) || SVAL(inbuf,smb_vwv0)) {
1442 DEBUG(1,("%s rejected the protocol\n",pserver));
1443 close(password_client); password_client= -1;
1447 if (!(CVAL(inbuf,smb_vwv1) & 1)) {
1448 DEBUG(1,("%s isn't in user level security mode\n",pserver));
1449 close(password_client); password_client= -1;
1453 memcpy(buf,inbuf,smb_len(inbuf)+4);
1455 DEBUG(3,("password server OK\n"));
1460 /****************************************************************************
1461 attempted support for server level security
1462 ****************************************************************************/
1463 BOOL server_validate(char *buf)
1465 pstring inbuf,outbuf;
1468 if (password_client < 0) {
1469 DEBUG(1,("%s not connected\n",pserver));
1473 bzero(inbuf,sizeof(inbuf));
1474 memcpy(outbuf,buf,sizeof(outbuf));
1476 /* send a session setup command */
1477 CVAL(outbuf,smb_flg) = 0x8;
1478 SSVAL(outbuf,smb_flg2,0x1);
1479 CVAL(outbuf,smb_vwv0) = 0xFF;
1481 set_message(outbuf,smb_numwords(outbuf),smb_buflen(outbuf),False);
1483 SCVAL(inbuf,smb_rcls,1);
1485 send_smb(password_client,outbuf);
1486 ret = receive_smb(password_client,inbuf,5000);
1488 if (!ret || CVAL(inbuf,smb_rcls) != 0) {
1489 DEBUG(1,("password server %s rejected the password\n",pserver));
1493 /* if logged in as guest then reject */
1494 if ((SVAL(inbuf,smb_vwv2) & 1) != 0) {
1495 DEBUG(1,("password server %s gave us guest only\n",pserver));
1499 DEBUG(3,("password server %s accepted the password\n",pserver));
1501 #if !KEEP_PASSWORD_SERVER_OPEN
1502 close(password_client); password_client= -1;