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.
25 extern int DEBUGLEVEL
;
28 /* users from session setup */
29 static pstring session_users
="";
31 /* these are kept here to keep the string_combinations function simple */
32 static char this_user
[100]="";
33 static char this_salt
[100]="";
34 static char this_crypted
[100]="";
37 /* Data to do lanman1/2 password challenge. */
38 static unsigned char saved_challenge
[8];
39 static BOOL challenge_sent
=False
;
41 /*******************************************************************
42 Get the next challenge value - no repeats.
43 ********************************************************************/
44 void generate_next_challenge(char *challenge
)
46 extern void E1(char *,char *,char *);
47 static int counter
= 0;
51 v1
= (counter
++) + getpid() + tval
.tv_sec
;
52 v2
= (counter
++) * getpid() + tval
.tv_usec
;
53 SIVAL(challenge
,0,v1
);
54 SIVAL(challenge
,4,v2
);
55 E1(challenge
,"SAMBA",saved_challenge
);
56 memcpy(challenge
,saved_challenge
,8);
57 challenge_sent
= True
;
60 /*******************************************************************
61 set the last challenge sent, usually from a password server
62 ********************************************************************/
63 BOOL
set_challenge(char *challenge
)
65 memcpy(saved_challenge
,challenge
,8);
66 challenge_sent
= True
;
70 /*******************************************************************
71 get the last challenge sent
72 ********************************************************************/
73 BOOL
last_challenge(char *challenge
)
75 if (!challenge_sent
) return(False
);
76 memcpy(challenge
,saved_challenge
,8);
81 /* this holds info on user ids that are already validated for this VC */
82 static user_struct
*validated_users
= NULL
;
83 static int num_validated_users
= 0;
85 /****************************************************************************
86 check if a uid has been validated, and return an index if it has. -1 if not
87 ****************************************************************************/
88 int valid_uid(int uid
)
91 if (uid
== -1) return(-1);
93 for (i
=0;i
<num_validated_users
;i
++)
94 if (validated_users
[i
].uid
== uid
)
96 DEBUG(3,("valid uid %d mapped to vuid %d (user=%s)\n",
97 uid
,i
,validated_users
[i
].name
));
103 /****************************************************************************
104 check if a uid has been validated, and return an pointer to the user_struct
105 if it has. NULL if not
106 ****************************************************************************/
107 user_struct
*get_valid_user_struct(int uid
)
109 int vuid
= valid_uid(uid
);
110 if(vuid
== -1 || validated_users
[vuid
].guest
)
112 return &validated_users
[vuid
];
115 /****************************************************************************
117 ****************************************************************************/
118 void invalidate_uid(int uid
)
121 for (i
=0;i
<num_validated_users
;i
++)
122 if (validated_users
[i
].uid
== uid
)
124 user_struct
*vuser
= &validated_users
[i
];
127 vuser
->user_ngroups
= 0;
128 if(vuser
->user_groups
&&
129 (vuser
->user_groups
!= (gid_t
*)vuser
->user_igroups
))
130 free(vuser
->user_groups
);
131 vuser
->user_groups
= NULL
;
132 if(vuser
->user_igroups
)
133 free(vuser
->user_igroups
);
134 vuser
->user_igroups
= NULL
;
139 /****************************************************************************
140 return a validated username
141 ****************************************************************************/
142 char *validated_username(int vuid
)
144 return(validated_users
[vuid
].name
);
147 /****************************************************************************
148 register a uid/name pair as being valid and that a valid password
150 ****************************************************************************/
151 void register_uid(int uid
,int gid
, char *name
,BOOL guest
)
155 if (valid_uid(uid
) >= 0)
157 validated_users
= (user_struct
*)Realloc(validated_users
,
159 (num_validated_users
+1));
161 if (!validated_users
)
163 DEBUG(0,("Failed to realloc users struct!\n"));
167 vuser
= &validated_users
[num_validated_users
];
170 vuser
->guest
= guest
;
171 strcpy(vuser
->name
,name
);
173 vuser
->user_ngroups
= 0;
174 vuser
->user_groups
= NULL
;
175 vuser
->user_igroups
= NULL
;
177 /* Find all the groups this uid is in and store them.
178 Used by become_user() */
179 setup_groups(name
,uid
,gid
,
180 &vuser
->user_ngroups
,
181 &vuser
->user_igroups
,
182 &vuser
->user_groups
);
184 DEBUG(3,("uid %d registered to name %s\n",uid
,name
));
186 num_validated_users
++;
190 /****************************************************************************
191 add a name to the session users list
192 ****************************************************************************/
193 void add_session_user(char *user
)
196 StrnCpy(suser
,user
,sizeof(suser
)-1);
198 if (!Get_Pwnam(suser
,True
)) return;
200 if (suser
&& *suser
&& !in_list(suser
,session_users
,False
))
202 if (strlen(suser
) + strlen(session_users
) + 2 >= sizeof(pstring
))
203 DEBUG(1,("Too many session users??\n"));
206 strcat(session_users
," ");
207 strcat(session_users
,suser
);
214 /* a fake shadow password routine which just fills a fake spwd struct
215 * with the sp_pwdp field. (sreiz@aie.nl)
217 static struct spwd
*getspnam(char *username
) /* fake shadow password routine */
222 static struct spwd static_spwd
;
224 static_spwd
.sp_pwdp
=0;
225 if (!(f
=fopen("/etc/master.passwd", "r")))
227 while (fgets(line
, 1024, f
)) {
228 if (!strncmp(line
, username
, strlen(username
)) &&
229 line
[strlen(username
)]==':') { /* found entry */
232 p
=line
+strlen(username
)+1;
233 if ((q
=strchr(p
, ':'))) {
238 static_spwd
.sp_pwdp
=pw
;
244 if (static_spwd
.sp_pwdp
)
252 /****************************************************************************
253 an enhanced crypt for OSF1
254 ****************************************************************************/
255 static char *osf1_bigcrypt(char *password
,char *salt1
)
257 static char result
[AUTH_MAX_PASSWD_LENGTH
] = "";
262 int parts
= strlen(password
) / AUTH_CLEARTEXT_SEG_CHARS
;
263 if (strlen(password
)%AUTH_CLEARTEXT_SEG_CHARS
)
266 StrnCpy(salt
,salt1
,2);
267 StrnCpy(result
,salt1
,2);
269 for (i
=0; i
<parts
;i
++)
273 StrnCpy(salt
,&result
[2+i
*AUTH_CIPHERTEXT_SEG_CHARS
],2);
274 p2
+= AUTH_CLEARTEXT_SEG_CHARS
;
282 /****************************************************************************
283 update the enhanced security database. Only relevant for OSF1 at the moment.
284 ****************************************************************************/
285 static void update_protected_database( char *user
, BOOL result
)
288 struct pr_passwd
*mypasswd
;
292 mypasswd
= getprpwnam (user
);
293 starttime
= time (NULL
);
294 tz
= mktime ( localtime ( &starttime
) );
298 mypasswd
->ufld
.fd_slogin
= tz
;
299 mypasswd
->ufld
.fd_nlogins
= 0;
301 putprpwnam(user
,mypasswd
);
303 DEBUG(3,("Update protected database for Account %s after succesful connection\n",user
));
307 mypasswd
->ufld
.fd_ulogin
= tz
;
308 mypasswd
->ufld
.fd_nlogins
= mypasswd
->ufld
.fd_nlogins
+ 1;
309 if ( mypasswd
->ufld
.fd_max_tries
!= 0 && mypasswd
->ufld
.fd_nlogins
> mypasswd
->ufld
.fd_max_tries
)
311 mypasswd
->uflg
.fg_lock
= 0;
312 DEBUG(3,("Account is disabled -- see Account Administrator.\n"));
314 putprpwnam ( user
, mypasswd
);
315 DEBUG(3,("Update protected database for Account %s after refusing connection\n",user
));
318 DEBUG(6,("Updated database with %s %s\n",user
,BOOLSTR(result
)));
324 /*******************************************************************
325 check on AFS authentication
326 ********************************************************************/
327 static BOOL
afs_auth(char *this_user
,char *password
)
329 long password_expires
= 0;
332 /* For versions of AFS prior to 3.3, this routine has few arguments, */
333 /* but since I can't find the old documentation... :-) */
335 if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION
+KA_USERAUTH_DOSETPAG
,
337 (char *) 0, /* instance */
338 (char *) 0, /* cell */
340 0, /* lifetime, default */
341 &password_expires
, /*days 'til it expires */
352 sec_login_handle_t my_dce_sec_context
;
353 int dcelogin_atmost_once
= 0;
355 /*******************************************************************
356 check on a DCE/DFS authentication
357 ********************************************************************/
358 static BOOL
dfs_auth(char *this_user
,char *password
)
363 boolean32 password_reset
;
364 sec_passwd_rec_t my_dce_password
;
365 sec_login_auth_src_t auth_src
= sec_login_auth_src_network
;
366 unsigned char dce_errstr
[dce_c_error_string_len
];
369 * We only go for a DCE login context if the given password
370 * matches that stored in the local password file..
371 * Assumes local passwd file is kept in sync w/ DCE RGY!
374 if (!strcmp((char *)crypt(password
,this_salt
),this_crypted
) ||
375 dcelogin_atmost_once
)
378 if (sec_login_setup_identity(
379 (unsigned char *)this_user
,
384 dce_error_inq_text(err
, dce_errstr
, &err2
);
385 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
386 this_user
,dce_errstr
));
390 my_dce_password
.version_number
= sec_passwd_c_version_none
;
391 my_dce_password
.pepper
= NULL
;
392 my_dce_password
.key
.key_type
= sec_passwd_plain
;
393 my_dce_password
.key
.tagged_union
.plain
= (idl_char
*)password
;
395 if (sec_login_valid_and_cert_ident(my_dce_sec_context
,
401 dce_error_inq_text(err
, dce_errstr
, &err2
);
402 DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
403 this_user
,dce_errstr
));
408 sec_login_set_context(my_dce_sec_context
, &err
);
409 if (err
!= error_status_ok
)
411 dce_error_inq_text(err
, dce_errstr
, &err2
);
412 DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
413 this_user
,dce_errstr
));
414 sec_login_purge_context(my_dce_sec_context
, &err
);
419 DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
420 this_user
, getpid()));
423 dcelogin_atmost_once
= 1;
427 void dfs_unlogin(void)
431 unsigned char dce_errstr
[dce_c_error_string_len
];
433 sec_login_purge_context(my_dce_sec_context
, &err
);
434 if (err
!= error_status_ok
)
436 dce_error_inq_text(err
, dce_errstr
, &err2
);
437 DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
438 getpid(), dce_errstr
));
445 #ifdef LINUX_BIGCRYPT
446 /****************************************************************************
447 an enhanced crypt for Linux to handle password longer than 8 characters
448 ****************************************************************************/
449 static int linux_bigcrypt(char *password
,char *salt1
, char *crypted
)
451 #define LINUX_PASSWORD_SEG_CHARS 8
455 StrnCpy(salt
,salt1
,2);
458 for ( i
=strlen(password
); i
> 0; i
-= LINUX_PASSWORD_SEG_CHARS
) {
459 char * p
= crypt(password
,salt
) + 2;
460 if(strncmp(p
, crypted
, LINUX_PASSWORD_SEG_CHARS
) != 0)
462 password
+= LINUX_PASSWORD_SEG_CHARS
;
463 crypted
+= strlen(p
);
471 /****************************************************************************
472 apply a function to upper/lower case combinations
473 of a string and return true if one of them returns true.
474 try all combinations with N uppercase letters.
475 offset is the first char to try and change (start with 0)
476 it assumes the string starts lowercased
477 ****************************************************************************/
478 static BOOL
string_combinations2(char *s
,int offset
,BOOL (*fn
)(),int N
)
483 #ifdef PASSWORD_LENGTH
484 len
= MIN(len
,PASSWORD_LENGTH
);
487 if (N
<= 0 || offset
>= len
)
490 for (i
=offset
;i
<(len
-(N
-1));i
++)
493 if (!islower(c
)) continue;
495 if (string_combinations2(s
,i
+1,fn
,N
-1))
502 /****************************************************************************
503 apply a function to upper/lower case combinations
504 of a string and return true if one of them returns true.
505 try all combinations with up to N uppercase letters.
506 offset is the first char to try and change (start with 0)
507 it assumes the string starts lowercased
508 ****************************************************************************/
509 static BOOL
string_combinations(char *s
,BOOL (*fn
)(),int N
)
513 if (string_combinations2(s
,0,fn
,n
)) return(True
);
519 /****************************************************************************
520 core of password checking routine
521 ****************************************************************************/
522 BOOL
password_check(char *password
)
525 if (afs_auth(this_user
,password
)) return(True
);
529 if (dfs_auth(this_user
,password
)) return(True
);
533 if (pwdauth(this_user
,password
) == 0)
538 return(strcmp(osf1_bigcrypt(password
,this_salt
),this_crypted
) == 0);
542 return (strcmp((char *)crypt16(password
, this_salt
),this_crypted
) == 0);
545 #ifdef LINUX_BIGCRYPT
546 return(linux_bigcrypt(password
,this_salt
,this_crypted
));
550 DEBUG(1,("Warning - no crypt available\n"));
553 return(strcmp((char *)crypt(password
,this_salt
),this_crypted
) == 0);
558 /****************************************************************************
559 core of smb password checking routine.
560 ****************************************************************************/
561 BOOL
smb_password_check(char *password
, unsigned char *part_passwd
, unsigned char *c8
)
563 /* Finish the encryption of part_passwd. */
564 unsigned char p21
[21];
565 unsigned char p24
[24];
567 if(part_passwd
== NULL
)
568 DEBUG(10,("No password set - allowing access\n"));
569 /* No password set - always true ! */
570 if(part_passwd
== NULL
)
574 memcpy(p21
,part_passwd
,16);
579 DEBUG(100,("Part password (P16) was |"));
580 for(i
= 0; i
< 16; i
++)
581 DEBUG(100,("%X ", (unsigned char)part_passwd
[i
]));
583 DEBUG(100,("Password from client was |"));
584 for(i
= 0; i
< 24; i
++)
585 DEBUG(100,("%X ", (unsigned char)password
[i
]));
587 DEBUG(100,("Given challenge was |"));
588 for(i
= 0; i
< 8; i
++)
589 DEBUG(100,("%X ", (unsigned char)c8
[i
]));
591 DEBUG(100,("Value from encryption was |"));
592 for(i
= 0; i
< 24; i
++)
593 DEBUG(100,("%X ", (unsigned char)p24
[i
]));
597 return (memcmp(p24
, password
, 24) == 0);
601 /****************************************************************************
602 check if a username/password is OK
603 ****************************************************************************/
604 BOOL
password_ok(char *user
,char *password
, int pwlen
, struct passwd
*pwd
, BOOL is_nt_password
)
607 int level
= lp_passwordlevel();
611 struct smb_passwd
*smb_pass
;
612 BOOL challenge_done
= False
;
615 if (password
) password
[pwlen
] = 0;
619 challenge_done
= last_challenge(challenge
);
627 DEBUG(100,("checking user=[%s] pass=[",user
));
628 for( i
= 0; i
< 24; i
++)
629 DEBUG(100,("%0x ", (unsigned char)password
[i
]));
634 DEBUG(100,("checking user=[%s] pass=[%s]\n",user
,password
));
640 if (((!*password
) || (!pwlen
)) && !lp_null_passwords())
645 pass
= (struct passwd
*) pwd
;
646 user
= pass
->pw_name
;
649 pass
= Get_Pwnam(user
,True
);
653 DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen
, challenge_done
));
655 if((pwlen
== 24) && challenge_done
)
657 DEBUG(4,("Checking SMB password for user %s (l=24)\n",user
));
661 DEBUG(3,("Couldn't find user %s\n",user
));
665 smb_pass
= get_smbpwnam(user
);
668 DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user
));
672 /* Ensure the uid's match */
673 if(smb_pass
->smb_userid
!= pass
->pw_uid
)
675 DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
679 if(Protocol
>= PROTOCOL_NT1
&& is_nt_password
)
681 /* We have the NT MD4 hash challenge available - see if we can
682 use it (ie. does it exist in the smbpasswd file).
684 if(smb_pass
->smb_nt_passwd
!= NULL
)
686 DEBUG(4,("Checking NT MD4 password\n"));
687 if(smb_password_check(password
, smb_pass
->smb_nt_passwd
, challenge
))
689 update_protected_database(user
,True
);
692 DEBUG(4,("NT MD4 password check failed\n"));
697 /* Try against the lanman password */
699 if(smb_password_check(password
, smb_pass
->smb_passwd
, challenge
))
701 update_protected_database(user
,True
);
705 DEBUG(3,("Error smb_password_check failed\n"));
709 DEBUG(4,("Checking password for user %s (l=%d)\n",user
,pwlen
));
713 DEBUG(3,("Couldn't find user %s\n",user
));
721 /* many shadow systems require you to be root to get the password,
722 in most cases this should already be the case when this
723 function is called, except perhaps for IPC password changing
726 spass
= getspnam(pass
->pw_name
);
727 if (spass
&& spass
->sp_pwdp
)
728 pass
->pw_passwd
= spass
->sp_pwdp
;
734 struct pr_passwd
*pr_pw
= getprpwnam(pass
->pw_name
);
735 if (pr_pw
&& pr_pw
->ufld
.fd_encrypt
)
736 pass
->pw_passwd
= pr_pw
->ufld
.fd_encrypt
;
740 #ifdef HPUX_10_TRUSTED
742 struct pr_passwd
*pr_pw
= getprpwnam(pass
->pw_name
);
743 if (pr_pw
&& pr_pw
->ufld
.fd_encrypt
)
744 pass
->pw_passwd
= pr_pw
->ufld
.fd_encrypt
;
750 struct pr_passwd
*mypasswd
;
751 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user
));
752 mypasswd
= getprpwnam (user
);
755 strcpy(pass
->pw_name
,mypasswd
->ufld
.fd_name
);
756 strcpy(pass
->pw_passwd
,mypasswd
->ufld
.fd_encrypt
);
760 DEBUG(5,("No entry for user %s in protected database !\n",user
));
768 AUTHORIZATION
*ap
= getauthuid( pass
->pw_uid
);
771 strcpy( pass
->pw_passwd
, ap
->a_password
);
777 /* extract relevant info */
778 strcpy(this_user
,pass
->pw_name
);
779 strcpy(this_salt
,pass
->pw_passwd
);
780 strcpy(this_crypted
,pass
->pw_passwd
);
782 if (!*this_crypted
) {
783 if (!lp_null_passwords()) {
784 DEBUG(2,("Disallowing access to %s due to null password\n",this_user
));
789 DEBUG(3,("Allowing access to %s with null password\n",this_user
));
795 /* try it as it came to us */
796 if (password_check(password
))
798 update_protected_database(user
,True
);
802 /* if the password was given to us with mixed case then we don't
803 need to proceed as we know it hasn't been case modified by the
805 if (strhasupper(password
) && strhaslower(password
))
808 /* make a copy of it */
809 StrnCpy(pass2
,password
,sizeof(pstring
)-1);
811 /* try all lowercase */
813 if (password_check(password
))
815 update_protected_database(user
,True
);
822 update_protected_database(user
,False
);
825 strcpy(password
,pass2
);
830 /* last chance - all combinations of up to level chars upper! */
833 if (string_combinations(password
,password_check
,level
))
835 update_protected_database(user
,True
);
839 update_protected_database(user
,False
);
842 strcpy(password
,pass2
);
849 /****************************************************************************
850 check if a username is valid
851 ****************************************************************************/
852 BOOL
user_ok(char *user
,int snum
)
854 pstring valid
, invalid
;
857 StrnCpy(valid
, lp_valid_users(snum
), sizeof(pstring
));
858 StrnCpy(invalid
, lp_invalid_users(snum
), sizeof(pstring
));
860 string_sub(valid
,"%S",lp_servicename(snum
));
861 string_sub(invalid
,"%S",lp_servicename(snum
));
863 ret
= !user_in_list(user
,invalid
);
865 if (ret
&& valid
&& *valid
)
866 ret
= user_in_list(user
,valid
);
868 if (ret
&& lp_onlyuser(snum
)) {
869 char *user_list
= lp_username(snum
);
870 string_sub(user_list
,"%S",lp_servicename(snum
));
871 ret
= user_in_list(user
,user_list
);
880 /****************************************************************************
881 validate a group username entry. Return the username or NULL
882 ****************************************************************************/
883 static char *validate_group(char *group
,char *password
,int pwlen
,int snum
)
887 char *host
, *user
, *domain
;
889 while (getnetgrent(&host
, &user
, &domain
)) {
891 if (user_ok(user
, snum
) &&
892 password_ok(user
,password
,pwlen
,NULL
,False
)) {
904 struct group
*gptr
= (struct group
*)getgrnam(group
);
908 member
= gptr
->gr_mem
;
909 while (member
&& *member
)
912 strcpy(name
,*member
);
913 if (user_ok(name
,snum
) &&
914 password_ok(name
,password
,pwlen
,NULL
,False
))
918 #ifdef GROUP_CHECK_PWENT
924 while (pwd
= getpwent ()) {
925 if (*(pwd
->pw_passwd
) && pwd
->pw_gid
== gptr
->gr_gid
) {
926 /* This Entry have PASSWORD and same GID then check pwd */
927 if (password_ok(NULL
, password
, pwlen
, pwd
,False
)) {
928 strcpy(tm
, pwd
->pw_name
);
936 #endif /* GROUP_CHECK_PWENT */
945 /****************************************************************************
946 check for authority to login to a service with a given username/password
947 ****************************************************************************/
948 BOOL
authorise_login(int snum
,char *user
,char *password
, int pwlen
,
949 BOOL
*guest
,BOOL
*force
,int vuid
)
956 DEBUG(100,("checking authorisation on user=%s pass=%s\n",user
,password
));
959 /* there are several possabilities:
960 1) login as the given user with given password
961 2) login as a previously registered username with the given password
962 3) login as a session list username with the given password
963 4) login as a previously validated user/password pair
964 5) login as the "user =" user with given password
965 6) login as the "user =" user with no password (guest connection)
966 7) login as guest user with no password
968 if the service is guest_only then steps 1 to 5 are skipped
971 if (GUEST_ONLY(snum
)) *force
= True
;
973 if (!(GUEST_ONLY(snum
) && GUEST_OK(snum
)))
976 /* check the given username and password */
977 if (!ok
&& (*user
) && user_ok(user
,snum
)) {
978 ok
= password_ok(user
,password
, pwlen
, NULL
, False
);
979 if (ok
) DEBUG(3,("ACCEPTED: given username password ok\n"));
982 /* check for a previously registered guest username */
983 if (!ok
&& (vuid
>= 0) && validated_users
[vuid
].guest
) {
984 if (user_ok(validated_users
[vuid
].name
,snum
) &&
985 password_ok(validated_users
[vuid
].name
, password
, pwlen
, NULL
, False
)) {
986 strcpy(user
, validated_users
[vuid
].name
);
987 validated_users
[vuid
].guest
= False
;
988 DEBUG(3,("ACCEPTED: given password with registered user %s\n", user
));
994 /* now check the list of session users */
998 char *user_list
= strdup(session_users
);
999 if (!user_list
) return(False
);
1001 for (auser
=strtok(user_list
,LIST_SEP
);
1003 auser
= strtok(NULL
,LIST_SEP
))
1006 strcpy(user2
,auser
);
1007 if (!user_ok(user2
,snum
)) continue;
1009 if (password_ok(user2
,password
, pwlen
, NULL
, False
)) {
1012 DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
1018 /* check for a previously validated username/password pair */
1019 if (!ok
&& !lp_revalidate(snum
) &&
1020 (vuid
>= 0) && !validated_users
[vuid
].guest
&&
1021 user_ok(validated_users
[vuid
].name
,snum
)) {
1022 strcpy(user
,validated_users
[vuid
].name
);
1024 DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
1028 /* check for a rhosts entry */
1029 if (!ok
&& user_ok(user
,snum
) && check_hosts_equiv(user
)) {
1031 DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
1034 /* check the user= fields and the given password */
1035 if (!ok
&& lp_username(snum
)) {
1038 StrnCpy(user_list
,lp_username(snum
),sizeof(pstring
));
1040 string_sub(user_list
,"%S",lp_servicename(snum
));
1042 for (auser
=strtok(user_list
,LIST_SEP
);
1044 auser
= strtok(NULL
,LIST_SEP
))
1048 auser
= validate_group(auser
+1,password
,pwlen
,snum
);
1053 DEBUG(3,("ACCEPTED: group username and given password ok\n"));
1059 strcpy(user2
,auser
);
1060 if (user_ok(user2
,snum
) &&
1061 password_ok(user2
,password
,pwlen
,NULL
, False
))
1065 DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
1070 } /* not guest only */
1072 /* check for a normal guest connection */
1073 if (!ok
&& GUEST_OK(snum
))
1076 StrnCpy(guestname
,lp_guestaccount(snum
),sizeof(guestname
)-1);
1077 if (Get_Pwnam(guestname
,True
))
1079 strcpy(user
,guestname
);
1081 DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
1084 DEBUG(0,("Invalid guest account %s??\n",guestname
));
1089 if (ok
&& !user_ok(user
,snum
))
1091 DEBUG(0,("rejected invalid user %s\n",user
));
1099 /****************************************************************************
1100 read the a hosts.equiv or .rhosts file and check if it
1101 allows this user from this machine
1102 ****************************************************************************/
1103 static BOOL
check_user_equiv(char *user
, char *remote
, char *equiv_file
)
1106 int plus_allowed
= 1;
1109 FILE *fp
= fopen(equiv_file
, "r");
1110 DEBUG(5, ("check_user_equiv %s %s %s\n", user
, remote
, equiv_file
));
1111 if (! fp
) return False
;
1112 while(fgets(buf
, sizeof(buf
), fp
))
1114 trim_string(buf
," "," ");
1116 if (buf
[0] != '#' && buf
[0] != '\n')
1118 BOOL is_group
= False
;
1121 if (strcmp(buf
, "NO_PLUS\n") == 0)
1123 DEBUG(6, ("check_user_equiv NO_PLUS\n"));
1130 if (*bp
== '\n' && plus_allowed
)
1132 /* a bare plus means everbody allowed */
1133 DEBUG(6, ("check_user_equiv everybody allowed\n"));
1138 else if (buf
[0] == '-')
1148 file_host
= strtok(bp
, " \t\n");
1149 file_user
= strtok(NULL
, " \t\n");
1150 DEBUG(7, ("check_user_equiv %s %s\n", file_host
, file_user
));
1151 if (file_host
&& *file_host
)
1153 BOOL host_ok
= False
;
1156 /* THIS IS UNTESTED!! */
1159 static char *mydomain
= NULL
;
1161 yp_get_default_domain(&mydomain
);
1162 if (mydomain
&& innetgr(remote
,file_host
,user
,mydomain
))
1168 DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n"));
1173 /* is it this host */
1174 /* the fact that remote has come from a call of gethostbyaddr
1175 * means that it may have the fully qualified domain name
1176 * so we could look up the file version to get it into
1177 * a canonical form, but I would rather just type it
1178 * in full in the equiv file
1180 if (!host_ok
&& !is_group
&& strequal(remote
, file_host
))
1186 /* is it this user */
1187 if (file_user
== 0 || strequal(user
, file_user
))
1190 DEBUG(5, ("check_user_equiv matched %s%s %s\n",
1191 (plus
? "+" : "-"), file_host
,
1192 (file_user
? file_user
: "")));
1193 return (plus
? True
: False
);
1204 /****************************************************************************
1205 check for a possible hosts equiv or rhosts entry for the user
1206 ****************************************************************************/
1207 BOOL
check_hosts_equiv(char *user
)
1211 struct passwd
*pass
= Get_Pwnam(user
,True
);
1213 extern struct from_host Client_info
;
1219 fromhost(Client
,&Client_info
);
1221 fname
= lp_hosts_equiv();
1223 /* note: don't allow hosts.equiv on root */
1224 if (fname
&& *fname
&& (pass
->pw_uid
!= 0))
1226 if (check_user_equiv(user
,Client_info
.name
,fname
))
1230 if (lp_use_rhosts())
1232 char *home
= get_home_dir(user
);
1235 sprintf(rhostsfile
, "%s/.rhosts", home
);
1236 if (check_user_equiv(user
,Client_info
.name
,rhostsfile
))
1245 static int password_client
= -1;
1246 static fstring pserver
;
1248 /****************************************************************************
1249 attempted support for server level security
1250 ****************************************************************************/
1251 BOOL
server_cryptkey(char *buf
)
1253 pstring inbuf
,outbuf
;
1254 fstring pass_protocol
;
1255 extern fstring remote_machine
;
1259 struct in_addr dest_ip
;
1260 extern struct in_addr myip
;
1264 if (password_client
>= 0)
1265 close(password_client
);
1266 password_client
= -1;
1268 if (Protocol
< PROTOCOL_NT1
) {
1269 strcpy(pass_protocol
,"LM1.2X002");
1271 strcpy(pass_protocol
,"NT LM 0.12");
1274 bzero(inbuf
,sizeof(inbuf
));
1275 bzero(outbuf
,sizeof(outbuf
));
1277 for (p
=strtok(lp_passwordserver(),LIST_SEP
); p
; p
= strtok(NULL
,LIST_SEP
)) {
1279 standard_sub_basic(desthost
);
1282 dest_ip
= *interpret_addr2(desthost
);
1283 if (zero_ip(dest_ip
)) {
1284 DEBUG(1,("Can't resolve address for %s\n",p
));
1288 if (memcmp(&dest_ip
,&myip
,sizeof(dest_ip
)) == 0) {
1289 DEBUG(1,("Password server loop - disabling password server %s\n",p
));
1293 password_client
= open_socket_out(SOCK_STREAM
, &dest_ip
, port
);
1294 if (password_client
>= 0) {
1295 DEBUG(3,("connected to password server %s\n",p
));
1296 StrnCpy(pserver
,p
,sizeof(pserver
)-1);
1301 if (password_client
< 0) {
1302 DEBUG(1,("password server not available\n"));
1307 /* send a session request (RFC 8002) */
1309 /* put in the destination name */
1312 name_mangle(desthost
,p
,' ');
1317 name_mangle(remote_machine
,p
,' ');
1320 _smb_setlen(outbuf
,len
);
1321 CVAL(outbuf
,0) = 0x81;
1323 send_smb(password_client
,outbuf
);
1324 receive_smb(password_client
,inbuf
,5000);
1326 if (CVAL(inbuf
,0) != 0x82) {
1327 DEBUG(1,("%s rejected the session\n",pserver
));
1328 close(password_client
); password_client
= -1;
1332 DEBUG(3,("got session\n"));
1334 bzero(outbuf
,smb_size
);
1336 /* setup the protocol string */
1337 set_message(outbuf
,0,strlen(pass_protocol
)+2,True
);
1338 p
= smb_buf(outbuf
);
1340 strcpy(p
,pass_protocol
);
1342 CVAL(outbuf
,smb_com
) = SMBnegprot
;
1343 CVAL(outbuf
,smb_flg
) = 0x8;
1344 SSVAL(outbuf
,smb_flg2
,0x1);
1346 send_smb(password_client
,outbuf
);
1347 ret
= receive_smb(password_client
,inbuf
,5000);
1349 if (!ret
|| CVAL(inbuf
,smb_rcls
) || SVAL(inbuf
,smb_vwv0
)) {
1350 DEBUG(1,("%s rejected the protocol\n",pserver
));
1351 close(password_client
); password_client
= -1;
1355 if (!(CVAL(inbuf
,smb_vwv1
) & 1)) {
1356 DEBUG(1,("%s isn't in user level security mode\n",pserver
));
1357 close(password_client
); password_client
= -1;
1361 memcpy(buf
,inbuf
,smb_len(inbuf
)+4);
1363 DEBUG(3,("password server OK\n"));
1368 /****************************************************************************
1369 attempted support for server level security
1370 ****************************************************************************/
1371 BOOL
server_validate(char *buf
)
1373 pstring inbuf
,outbuf
;
1376 if (password_client
< 0) {
1377 DEBUG(1,("%s not connected\n",pserver
));
1381 bzero(inbuf
,sizeof(inbuf
));
1382 memcpy(outbuf
,buf
,sizeof(outbuf
));
1384 /* send a session setup command */
1385 CVAL(outbuf
,smb_flg
) = 0x8;
1386 SSVAL(outbuf
,smb_flg2
,0x1);
1387 CVAL(outbuf
,smb_vwv0
) = 0xFF;
1389 set_message(outbuf
,smb_numwords(outbuf
),smb_buflen(outbuf
),False
);
1391 SCVAL(inbuf
,smb_rcls
,1);
1393 send_smb(password_client
,outbuf
);
1394 ret
= receive_smb(password_client
,inbuf
,5000);
1396 if (!ret
|| CVAL(inbuf
,smb_rcls
) != 0) {
1397 DEBUG(1,("password server %s rejected the password\n",pserver
));
1401 /* if logged in as guest then reject */
1402 if ((SVAL(inbuf
,smb_vwv2
) & 1) != 0) {
1403 DEBUG(1,("password server %s gave us guest only\n",pserver
));
1407 DEBUG(3,("password server %s accepted the password\n",pserver
));
1409 #ifndef KEEP_PASSWORD_SERVER_OPEN
1410 close(password_client
); password_client
= -1;