2 Unix SMB/Netbios implementation.
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.
24 #if (defined(NETGROUP) && defined (AUTOMOUNT))
25 #include "rpcsvc/ypclnt.h"
28 extern int DEBUGLEVEL
;
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]="";
40 /* Data to do lanman1/2 password challenge. */
41 static unsigned char saved_challenge
[8];
42 static BOOL challenge_sent
=False
;
44 /*******************************************************************
45 Get the next challenge value - no repeats.
46 ********************************************************************/
47 void generate_next_challenge(char *challenge
)
49 static int counter
= 0;
53 v1
= (counter
++) + getpid() + tval
.tv_sec
;
54 v2
= (counter
++) * getpid() + tval
.tv_usec
;
55 SIVAL(challenge
,0,v1
);
56 SIVAL(challenge
,4,v2
);
57 E1(challenge
,"SAMBA",(char *)saved_challenge
);
58 memcpy(challenge
,saved_challenge
,8);
59 challenge_sent
= True
;
62 /*******************************************************************
63 set the last challenge sent, usually from a password server
64 ********************************************************************/
65 BOOL
set_challenge(char *challenge
)
67 memcpy(saved_challenge
,challenge
,8);
68 challenge_sent
= True
;
72 /*******************************************************************
73 get the last challenge sent
74 ********************************************************************/
75 BOOL
last_challenge(char *challenge
)
77 if (!challenge_sent
) return(False
);
78 memcpy(challenge
,saved_challenge
,8);
83 /* this holds info on user ids that are already validated for this VC */
84 static user_struct
*validated_users
= NULL
;
85 static int num_validated_users
= 0;
87 /****************************************************************************
88 check if a uid has been validated, and return an pointer to the user_struct
89 if it has. NULL if not. vuid is biased by an offset. This allows us to
90 tell random client vuid's (normally zero) from valid vuids.
91 ****************************************************************************/
92 user_struct
*get_valid_user_struct(uint16 vuid
)
94 if(vuid
== UID_FIELD_INVALID
)
97 if((vuid
>= (uint16
)num_validated_users
) ||
98 (validated_users
[vuid
].uid
== -1) || (validated_users
[vuid
].gid
== -1))
100 return &validated_users
[vuid
];
103 /****************************************************************************
105 ****************************************************************************/
106 void invalidate_vuid(uint16 vuid
)
108 user_struct
*vuser
= get_valid_user_struct(vuid
);
114 vuser
->user_ngroups
= 0;
115 if(vuser
->user_groups
&&
116 (vuser
->user_groups
!= (gid_t
*)vuser
->user_igroups
))
117 free(vuser
->user_groups
);
118 vuser
->user_groups
= NULL
;
119 if(vuser
->user_igroups
)
120 free(vuser
->user_igroups
);
121 vuser
->user_igroups
= NULL
;
125 /****************************************************************************
126 return a validated username
127 ****************************************************************************/
128 char *validated_username(uint16 vuid
)
130 user_struct
*vuser
= get_valid_user_struct(vuid
);
136 /****************************************************************************
137 register a uid/name pair as being valid and that a valid password
138 has been given. vuid is biased by an offset. This allows us to
139 tell random client vuid's (normally zero) from valid vuids.
140 ****************************************************************************/
141 uint16
register_vuid(int uid
,int gid
, char *name
,BOOL guest
)
145 #if (defined(NETGROUP) && defined (AUTOMOUNT))
146 int nis_error
; /* returned by yp all functions */
147 char *nis_result
; /* yp_match inits this */
148 int nis_result_len
; /* and set this */
149 char *nis_domain
; /* yp_get_default_domain inits this */
150 char *nis_map
= (char *)lp_nis_home_map_name();
153 struct passwd
*pwfile
; /* for getting real name from passwd file */
157 for(i
= 0; i
< num_validated_users
; i
++) {
158 vuser
= &validated_users
[i
];
159 if( vuser
->uid
== uid
)
160 return (uint16
)(i
+ VUID_OFFSET
); /* User already validated */
163 validated_users
= (user_struct
*)Realloc(validated_users
,
165 (num_validated_users
+1));
167 if (!validated_users
)
169 DEBUG(0,("Failed to realloc users struct!\n"));
170 num_validated_users
= 0;
171 return UID_FIELD_INVALID
;
174 vuser
= &validated_users
[num_validated_users
];
175 num_validated_users
++;
179 vuser
->guest
= guest
;
180 strcpy(vuser
->name
,name
);
182 vuser
->user_ngroups
= 0;
183 vuser
->user_groups
= NULL
;
184 vuser
->user_igroups
= NULL
;
186 /* Find all the groups this uid is in and store them.
187 Used by become_user() */
188 setup_groups(name
,uid
,gid
,
189 &vuser
->user_ngroups
,
190 &vuser
->user_igroups
,
191 &vuser
->user_groups
);
193 DEBUG(3,("uid %d registered to name %s\n",uid
,name
));
195 #if (defined(NETGROUP) && defined (AUTOMOUNT))
196 vuser
->home_share
= NULL
;
197 DEBUG(3, ("Setting default HOMESHR to: \\\\logon server\\HOMES\n"));
198 vuser
->home_share
= Realloc(vuser
->home_share
, 32);
199 strcpy(vuser
->home_share
,"\\\\%L\\HOMES");
201 if (nis_error
= yp_get_default_domain(&nis_domain
))
202 DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error
)));
203 DEBUG(3, ("NIS Domain: %s\n", nis_domain
));
205 if (nis_error
= yp_match(nis_domain
, nis_map
, vuser
->name
, strlen(vuser
->name
),
206 &nis_result
, &nis_result_len
))
207 DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error
)));
208 if (!nis_error
&& lp_nis_home_map()) {
209 home_server_len
= strcspn(nis_result
,":");
210 DEBUG(3, ("NIS lookup succeeded\n\tHome server length: %d\n",home_server_len
));
211 vuser
->home_share
= (char *)Realloc(vuser
->home_share
, home_server_len
+12);
212 DEBUG(3, ("\tAllocated %d bytes for HOMESHR\n",home_server_len
+12 ));
213 strcpy(vuser
->home_share
,"\\\\");
214 strncat(vuser
->home_share
, nis_result
, home_server_len
);
215 strcat(vuser
->home_share
,"\\homes");
216 DEBUG(2,("\tUser = %s\n\tUID = %d\n\tNIS result = %s\n\tHOMESHR = %s\n",
217 vuser
->name
, vuser
->uid
, nis_result
, vuser
->home_share
));
221 vuser
->real_name
= NULL
;
222 DEBUG(3, ("Clearing default real name\n"));
223 vuser
->real_name
= Realloc(vuser
->real_name
, 15);
224 strcpy(vuser
->real_name
, "<Full Name>\0");
225 if (lp_unix_realname()) {
226 pwfile
=getpwnam(vuser
->name
);
227 DEBUG(3, ("User name: %s\tReal name: %s\n",vuser
->name
,pwfile
->pw_gecos
));
228 real_name_len
= strcspn(pwfile
->pw_gecos
, ",");
229 DEBUG(3, ("Real name length: %d\n", real_name_len
));
230 vuser
->real_name
= (char *)Realloc(vuser
->real_name
, real_name_len
+1);
231 strncpy(vuser
->real_name
, pwfile
->pw_gecos
, real_name_len
);
232 vuser
->real_name
[real_name_len
]='\0';
235 return (uint16
)((num_validated_users
- 1) + VUID_OFFSET
);
239 /****************************************************************************
240 add a name to the session users list
241 ****************************************************************************/
242 void add_session_user(char *user
)
245 StrnCpy(suser
,user
,sizeof(suser
)-1);
247 if (!Get_Pwnam(suser
,True
)) return;
249 if (suser
&& *suser
&& !in_list(suser
,session_users
,False
))
251 if (strlen(suser
) + strlen(session_users
) + 2 >= sizeof(pstring
))
252 DEBUG(1,("Too many session users??\n"));
255 strcat(session_users
," ");
256 strcat(session_users
,suser
);
263 /* a fake shadow password routine which just fills a fake spwd struct
264 * with the sp_pwdp field. (sreiz@aie.nl)
266 static struct spwd
*getspnam(char *username
) /* fake shadow password routine */
271 static struct spwd static_spwd
;
273 static_spwd
.sp_pwdp
=0;
274 if (!(f
=fopen("/etc/master.passwd", "r")))
276 while (fgets(line
, 1024, f
)) {
277 if (!strncmp(line
, username
, strlen(username
)) &&
278 line
[strlen(username
)]==':') { /* found entry */
281 p
=line
+strlen(username
)+1;
282 if ((q
=strchr(p
, ':'))) {
287 static_spwd
.sp_pwdp
=pw
;
293 if (static_spwd
.sp_pwdp
)
301 /****************************************************************************
302 an enhanced crypt for OSF1
303 ****************************************************************************/
304 static char *osf1_bigcrypt(char *password
,char *salt1
)
306 static char result
[AUTH_MAX_PASSWD_LENGTH
] = "";
311 int parts
= strlen(password
) / AUTH_CLEARTEXT_SEG_CHARS
;
312 if (strlen(password
)%AUTH_CLEARTEXT_SEG_CHARS
)
315 StrnCpy(salt
,salt1
,2);
316 StrnCpy(result
,salt1
,2);
318 for (i
=0; i
<parts
;i
++)
322 StrnCpy(salt
,&result
[2+i
*AUTH_CIPHERTEXT_SEG_CHARS
],2);
323 p2
+= AUTH_CLEARTEXT_SEG_CHARS
;
331 /****************************************************************************
332 update the enhanced security database. Only relevant for OSF1 at the moment.
333 ****************************************************************************/
334 static void update_protected_database( char *user
, BOOL result
)
337 struct pr_passwd
*mypasswd
;
340 mypasswd
= getprpwnam (user
);
341 starttime
= time (NULL
);
345 mypasswd
->ufld
.fd_slogin
= starttime
;
346 mypasswd
->ufld
.fd_nlogins
= 0;
348 putprpwnam(user
,mypasswd
);
350 DEBUG(3,("Update protected database for Account %s after succesful connection\n",user
));
354 mypasswd
->ufld
.fd_ulogin
= starttime
;
355 mypasswd
->ufld
.fd_nlogins
= mypasswd
->ufld
.fd_nlogins
+ 1;
356 if ( mypasswd
->ufld
.fd_max_tries
!= 0 && mypasswd
->ufld
.fd_nlogins
> mypasswd
->ufld
.fd_max_tries
)
358 mypasswd
->uflg
.fg_lock
= 0;
359 DEBUG(3,("Account is disabled -- see Account Administrator.\n"));
361 putprpwnam ( user
, mypasswd
);
362 DEBUG(3,("Update protected database for Account %s after refusing connection\n",user
));
365 DEBUG(6,("Updated database with %s %s\n",user
,BOOLSTR(result
)));
371 /*******************************************************************
372 check on PAM authentication
373 ********************************************************************/
375 /* We first need some helper functions */
376 #include <security/pam_appl.h>
377 /* Static variables used to communicate between the conversation function
378 * and the server_login function
380 static char *PAM_username
;
381 static char *PAM_password
;
383 /* PAM conversation function
384 * Here we assume (for now, at least) that echo on means login name, and
385 * echo off means password.
387 static int PAM_conv (int num_msg
,
388 const struct pam_message
**msg
,
389 struct pam_response
**resp
,
391 int count
= 0, replies
= 0;
392 struct pam_response
*reply
= NULL
;
393 int size
= sizeof(struct pam_response
);
395 #define GET_MEM if (reply) realloc(reply, size); else reply = malloc(size); \
396 if (!reply) return PAM_CONV_ERR; \
397 size += sizeof(struct pam_response)
398 #define COPY_STRING(s) (s) ? strdup(s) : NULL
400 for (count
= 0; count
< num_msg
; count
++) {
401 switch (msg
[count
]->msg_style
) {
402 case PAM_PROMPT_ECHO_ON
:
404 reply
[replies
].resp_retcode
= PAM_SUCCESS
;
405 reply
[replies
++].resp
= COPY_STRING(PAM_username
);
408 case PAM_PROMPT_ECHO_OFF
:
410 reply
[replies
].resp_retcode
= PAM_SUCCESS
;
411 reply
[replies
++].resp
= COPY_STRING(PAM_password
);
419 /* Must be an error of some sort... */
424 if (reply
) *resp
= reply
;
427 static struct pam_conv PAM_conversation
= {
433 static BOOL
pam_auth(char *this_user
,char *password
)
438 /* Now use PAM to do authentication. For now, we won't worry about
439 * session logging, only authentication. Bail out if there are any
440 * errors. Since this is a limited protocol, and an even more limited
441 * function within a server speaking this protocol, we can't be as
442 * verbose as would otherwise make sense.
443 * Query: should we be using PAM_SILENT to shut PAM up?
445 #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
446 pam_end(pamh, 0); return False; \
448 PAM_password
= password
;
449 PAM_username
= this_user
;
450 pam_error
= pam_start("samba", this_user
, &PAM_conversation
, &pamh
);
452 pam_error
= pam_authenticate(pamh
, 0);
454 /* It is not clear to me that account management is the right thing
455 * to do, but it is not clear that it isn't, either. This can be
456 * removed if no account management should be done. Alternately,
457 * put a pam_allow.so entry in /etc/pam.conf for account handling. */
458 pam_error
= pam_acct_mgmt(pamh
, 0);
460 pam_end(pamh
, PAM_SUCCESS
);
461 /* If this point is reached, the user has been authenticated. */
468 /*******************************************************************
469 check on AFS authentication
470 ********************************************************************/
471 static BOOL
afs_auth(char *this_user
,char *password
)
473 long password_expires
= 0;
476 /* For versions of AFS prior to 3.3, this routine has few arguments, */
477 /* but since I can't find the old documentation... :-) */
479 if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION
+KA_USERAUTH_DOSETPAG
,
481 (char *) 0, /* instance */
482 (char *) 0, /* cell */
484 0, /* lifetime, default */
485 &password_expires
, /*days 'til it expires */
496 sec_login_handle_t my_dce_sec_context
;
497 int dcelogin_atmost_once
= 0;
499 /*******************************************************************
500 check on a DCE/DFS authentication
501 ********************************************************************/
502 static BOOL
dfs_auth(char *this_user
,char *password
)
507 boolean32 password_reset
;
508 sec_passwd_rec_t my_dce_password
;
509 sec_login_auth_src_t auth_src
= sec_login_auth_src_network
;
510 unsigned char dce_errstr
[dce_c_error_string_len
];
513 * We only go for a DCE login context if the given password
514 * matches that stored in the local password file..
515 * Assumes local passwd file is kept in sync w/ DCE RGY!
518 if (!strcmp((char *)crypt(password
,this_salt
),this_crypted
) ||
519 dcelogin_atmost_once
)
522 if (sec_login_setup_identity(
523 (unsigned char *)this_user
,
528 dce_error_inq_text(err
, dce_errstr
, &err2
);
529 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
530 this_user
,dce_errstr
));
534 my_dce_password
.version_number
= sec_passwd_c_version_none
;
535 my_dce_password
.pepper
= NULL
;
536 my_dce_password
.key
.key_type
= sec_passwd_plain
;
537 my_dce_password
.key
.tagged_union
.plain
= (idl_char
*)password
;
539 if (sec_login_valid_and_cert_ident(my_dce_sec_context
,
545 dce_error_inq_text(err
, dce_errstr
, &err2
);
546 DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
547 this_user
,dce_errstr
));
552 sec_login_set_context(my_dce_sec_context
, &err
);
553 if (err
!= error_status_ok
)
555 dce_error_inq_text(err
, dce_errstr
, &err2
);
556 DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
557 this_user
,dce_errstr
));
558 sec_login_purge_context(my_dce_sec_context
, &err
);
563 DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
564 this_user
, getpid()));
567 dcelogin_atmost_once
= 1;
571 void dfs_unlogin(void)
575 unsigned char dce_errstr
[dce_c_error_string_len
];
577 sec_login_purge_context(my_dce_sec_context
, &err
);
578 if (err
!= error_status_ok
)
580 dce_error_inq_text(err
, dce_errstr
, &err2
);
581 DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
582 getpid(), dce_errstr
));
589 #ifdef LINUX_BIGCRYPT
590 /****************************************************************************
591 an enhanced crypt for Linux to handle password longer than 8 characters
592 ****************************************************************************/
593 static int linux_bigcrypt(char *password
,char *salt1
, char *crypted
)
595 #define LINUX_PASSWORD_SEG_CHARS 8
599 StrnCpy(salt
,salt1
,2);
602 for ( i
=strlen(password
); i
> 0; i
-= LINUX_PASSWORD_SEG_CHARS
) {
603 char * p
= crypt(password
,salt
) + 2;
604 if(strncmp(p
, crypted
, LINUX_PASSWORD_SEG_CHARS
) != 0)
606 password
+= LINUX_PASSWORD_SEG_CHARS
;
607 crypted
+= strlen(p
);
615 /****************************************************************************
616 apply a function to upper/lower case combinations
617 of a string and return true if one of them returns true.
618 try all combinations with N uppercase letters.
619 offset is the first char to try and change (start with 0)
620 it assumes the string starts lowercased
621 ****************************************************************************/
622 static BOOL
string_combinations2(char *s
,int offset
,BOOL (*fn
)(),int N
)
627 #ifdef PASSWORD_LENGTH
628 len
= MIN(len
,PASSWORD_LENGTH
);
631 if (N
<= 0 || offset
>= len
)
634 for (i
=offset
;i
<(len
-(N
-1));i
++)
637 if (!islower(c
)) continue;
639 if (string_combinations2(s
,i
+1,fn
,N
-1))
646 /****************************************************************************
647 apply a function to upper/lower case combinations
648 of a string and return true if one of them returns true.
649 try all combinations with up to N uppercase letters.
650 offset is the first char to try and change (start with 0)
651 it assumes the string starts lowercased
652 ****************************************************************************/
653 static BOOL
string_combinations(char *s
,BOOL (*fn
)(),int N
)
657 if (string_combinations2(s
,0,fn
,n
)) return(True
);
663 /****************************************************************************
664 core of password checking routine
665 ****************************************************************************/
666 BOOL
password_check(char *password
)
670 /* This falls through if the password check fails
671 - if NO_CRYPT is defined this causes an error msg
672 saying Warning - no crypt available
673 - if NO_CRYPT is NOT defined this is a potential security hole
674 as it may authenticate via the crypt call when PAM
675 settings say it should fail.
676 if (pam_auth(this_user,password)) return(True);
677 Hence we make a direct return to avoid a second chance!!!
679 return (pam_auth(this_user
,password
));
683 if (afs_auth(this_user
,password
)) return(True
);
687 if (dfs_auth(this_user
,password
)) return(True
);
691 if (pwdauth(this_user
,password
) == 0)
696 return(strcmp(osf1_bigcrypt(password
,this_salt
),this_crypted
) == 0);
700 return (strcmp((char *)crypt16(password
, this_salt
),this_crypted
) == 0);
703 #ifdef LINUX_BIGCRYPT
704 return(linux_bigcrypt(password
,this_salt
,this_crypted
));
708 DEBUG(1,("Warning - no crypt available\n"));
711 return(strcmp((char *)crypt(password
,this_salt
),this_crypted
) == 0);
716 /****************************************************************************
717 core of smb password checking routine.
718 ****************************************************************************/
719 BOOL
smb_password_check(char *password
, unsigned char *part_passwd
, unsigned char *c8
)
721 /* Finish the encryption of part_passwd. */
722 unsigned char p21
[21];
723 unsigned char p24
[24];
725 if(part_passwd
== NULL
)
726 DEBUG(10,("No password set - allowing access\n"));
727 /* No password set - always true ! */
728 if(part_passwd
== NULL
)
732 memcpy(p21
,part_passwd
,16);
737 DEBUG(100,("Part password (P16) was |"));
738 for(i
= 0; i
< 16; i
++)
739 DEBUG(100,("%X ", (unsigned char)part_passwd
[i
]));
741 DEBUG(100,("Password from client was |"));
742 for(i
= 0; i
< 24; i
++)
743 DEBUG(100,("%X ", (unsigned char)password
[i
]));
745 DEBUG(100,("Given challenge was |"));
746 for(i
= 0; i
< 8; i
++)
747 DEBUG(100,("%X ", (unsigned char)c8
[i
]));
749 DEBUG(100,("Value from encryption was |"));
750 for(i
= 0; i
< 24; i
++)
751 DEBUG(100,("%X ", (unsigned char)p24
[i
]));
755 return (memcmp(p24
, password
, 24) == 0);
759 /****************************************************************************
760 check if a username/password is OK
761 ****************************************************************************/
762 BOOL
password_ok(char *user
,char *password
, int pwlen
, struct passwd
*pwd
)
765 int level
= lp_passwordlevel();
769 struct smb_passwd
*smb_pass
;
770 BOOL challenge_done
= False
;
773 if (password
) password
[pwlen
] = 0;
777 challenge_done
= last_challenge(challenge
);
785 DEBUG(100,("checking user=[%s] pass=[",user
));
786 for( i
= 0; i
< 24; i
++)
787 DEBUG(100,("%0x ", (unsigned char)password
[i
]));
792 DEBUG(100,("checking user=[%s] pass=[%s]\n",user
,password
));
798 if (((!*password
) || (!pwlen
)) && !lp_null_passwords())
803 pass
= (struct passwd
*) pwd
;
804 user
= pass
->pw_name
;
807 pass
= Get_Pwnam(user
,True
);
811 DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen
, challenge_done
));
813 if((pwlen
== 24) && challenge_done
)
815 DEBUG(4,("Checking SMB password for user %s (l=24)\n",user
));
819 DEBUG(3,("Couldn't find user %s\n",user
));
823 smb_pass
= get_smbpwnam(user
);
826 DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user
));
830 /* Ensure the uid's match */
831 if(smb_pass
->smb_userid
!= pass
->pw_uid
)
833 DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
837 if(Protocol
>= PROTOCOL_NT1
)
839 /* We have the NT MD4 hash challenge available - see if we can
840 use it (ie. does it exist in the smbpasswd file).
842 if(smb_pass
->smb_nt_passwd
!= NULL
)
844 DEBUG(4,("Checking NT MD4 password\n"));
845 if(smb_password_check(password
,
846 smb_pass
->smb_nt_passwd
,
849 update_protected_database(user
,True
);
852 DEBUG(4,("NT MD4 password check failed\n"));
856 /* Try against the lanman password */
858 if (smb_password_check(password
,
859 smb_pass
->smb_passwd
,
860 (char *)challenge
)) {
861 update_protected_database(user
,True
);
865 DEBUG(3,("Error smb_password_check failed\n"));
869 DEBUG(4,("Checking password for user %s (l=%d)\n",user
,pwlen
));
873 DEBUG(3,("Couldn't find user %s\n",user
));
881 /* many shadow systems require you to be root to get the password,
882 in most cases this should already be the case when this
883 function is called, except perhaps for IPC password changing
886 spass
= getspnam(pass
->pw_name
);
887 if (spass
&& spass
->sp_pwdp
)
888 pass
->pw_passwd
= spass
->sp_pwdp
;
894 struct pr_passwd
*pr_pw
= getprpwnam(pass
->pw_name
);
895 if (pr_pw
&& pr_pw
->ufld
.fd_encrypt
)
896 pass
->pw_passwd
= pr_pw
->ufld
.fd_encrypt
;
900 #ifdef HPUX_10_TRUSTED
902 struct pr_passwd
*pr_pw
= getprpwnam(pass
->pw_name
);
903 if (pr_pw
&& pr_pw
->ufld
.fd_encrypt
)
904 pass
->pw_passwd
= pr_pw
->ufld
.fd_encrypt
;
910 struct pr_passwd
*mypasswd
;
911 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user
));
912 mypasswd
= getprpwnam (user
);
915 strcpy(pass
->pw_name
,mypasswd
->ufld
.fd_name
);
916 strcpy(pass
->pw_passwd
,mypasswd
->ufld
.fd_encrypt
);
920 DEBUG(5,("No entry for user %s in protected database !\n",user
));
928 AUTHORIZATION
*ap
= getauthuid( pass
->pw_uid
);
931 strcpy( pass
->pw_passwd
, ap
->a_password
);
937 /* extract relevant info */
938 strcpy(this_user
,pass
->pw_name
);
939 strcpy(this_salt
,pass
->pw_passwd
);
940 strcpy(this_crypted
,pass
->pw_passwd
);
942 if (!*this_crypted
) {
943 if (!lp_null_passwords()) {
944 DEBUG(2,("Disallowing access to %s due to null password\n",this_user
));
949 DEBUG(3,("Allowing access to %s with null password\n",this_user
));
955 /* try it as it came to us */
956 if (password_check(password
))
958 update_protected_database(user
,True
);
962 /* if the password was given to us with mixed case then we don't
963 need to proceed as we know it hasn't been case modified by the
965 if (strhasupper(password
) && strhaslower(password
))
968 /* make a copy of it */
969 StrnCpy(pass2
,password
,sizeof(pstring
)-1);
971 /* try all lowercase */
973 if (password_check(password
))
975 update_protected_database(user
,True
);
982 update_protected_database(user
,False
);
985 strcpy(password
,pass2
);
990 /* last chance - all combinations of up to level chars upper! */
993 if (string_combinations(password
,password_check
,level
))
995 update_protected_database(user
,True
);
999 update_protected_database(user
,False
);
1002 strcpy(password
,pass2
);
1009 /****************************************************************************
1010 check if a username is valid
1011 ****************************************************************************/
1012 BOOL
user_ok(char *user
,int snum
)
1014 pstring valid
, invalid
;
1017 StrnCpy(valid
, lp_valid_users(snum
), sizeof(pstring
));
1018 StrnCpy(invalid
, lp_invalid_users(snum
), sizeof(pstring
));
1020 string_sub(valid
,"%S",lp_servicename(snum
));
1021 string_sub(invalid
,"%S",lp_servicename(snum
));
1023 ret
= !user_in_list(user
,invalid
);
1025 if (ret
&& valid
&& *valid
)
1026 ret
= user_in_list(user
,valid
);
1028 if (ret
&& lp_onlyuser(snum
)) {
1029 char *user_list
= lp_username(snum
);
1030 string_sub(user_list
,"%S",lp_servicename(snum
));
1031 ret
= user_in_list(user
,user_list
);
1040 /****************************************************************************
1041 validate a group username entry. Return the username or NULL
1042 ****************************************************************************/
1043 static char *validate_group(char *group
,char *password
,int pwlen
,int snum
)
1047 char *host
, *user
, *domain
;
1049 while (getnetgrent(&host
, &user
, &domain
)) {
1051 if (user_ok(user
, snum
) &&
1052 password_ok(user
,password
,pwlen
,NULL
)) {
1064 struct group
*gptr
= (struct group
*)getgrnam(group
);
1068 member
= gptr
->gr_mem
;
1069 while (member
&& *member
)
1071 static fstring name
;
1072 strcpy(name
,*member
);
1073 if (user_ok(name
,snum
) &&
1074 password_ok(name
,password
,pwlen
,NULL
))
1078 #ifdef GROUP_CHECK_PWENT
1084 while (pwd
= getpwent ()) {
1085 if (*(pwd
->pw_passwd
) && pwd
->pw_gid
== gptr
->gr_gid
) {
1086 /* This Entry have PASSWORD and same GID then check pwd */
1087 if (password_ok(NULL
, password
, pwlen
, pwd
)) {
1088 strcpy(tm
, pwd
->pw_name
);
1096 #endif /* GROUP_CHECK_PWENT */
1105 /****************************************************************************
1106 check for authority to login to a service with a given username/password
1107 ****************************************************************************/
1108 BOOL
authorise_login(int snum
,char *user
,char *password
, int pwlen
,
1109 BOOL
*guest
,BOOL
*force
,uint16 vuid
)
1116 DEBUG(100,("checking authorisation on user=%s pass=%s\n",user
,password
));
1119 /* there are several possabilities:
1120 1) login as the given user with given password
1121 2) login as a previously registered username with the given password
1122 3) login as a session list username with the given password
1123 4) login as a previously validated user/password pair
1124 5) login as the "user =" user with given password
1125 6) login as the "user =" user with no password (guest connection)
1126 7) login as guest user with no password
1128 if the service is guest_only then steps 1 to 5 are skipped
1131 if (GUEST_ONLY(snum
)) *force
= True
;
1133 if (!(GUEST_ONLY(snum
) && GUEST_OK(snum
)))
1136 user_struct
*vuser
= get_valid_user_struct(vuid
);
1138 /* check the given username and password */
1139 if (!ok
&& (*user
) && user_ok(user
,snum
)) {
1140 ok
= password_ok(user
,password
, pwlen
, NULL
);
1141 if (ok
) DEBUG(3,("ACCEPTED: given username password ok\n"));
1144 /* check for a previously registered guest username */
1145 if (!ok
&& (vuser
!= 0) && vuser
->guest
) {
1146 if (user_ok(vuser
->name
,snum
) &&
1147 password_ok(vuser
->name
, password
, pwlen
, NULL
)) {
1148 strcpy(user
, vuser
->name
);
1149 vuser
->guest
= False
;
1150 DEBUG(3,("ACCEPTED: given password with registered user %s\n", user
));
1156 /* now check the list of session users */
1160 char *user_list
= strdup(session_users
);
1161 if (!user_list
) return(False
);
1163 for (auser
=strtok(user_list
,LIST_SEP
);
1165 auser
= strtok(NULL
,LIST_SEP
))
1168 strcpy(user2
,auser
);
1169 if (!user_ok(user2
,snum
)) continue;
1171 if (password_ok(user2
,password
, pwlen
, NULL
)) {
1174 DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
1180 /* check for a previously validated username/password pair */
1181 if (!ok
&& !lp_revalidate(snum
) &&
1182 (vuser
!= 0) && !vuser
->guest
&&
1183 user_ok(vuser
->name
,snum
)) {
1184 strcpy(user
,vuser
->name
);
1186 DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
1190 /* check for a rhosts entry */
1191 if (!ok
&& user_ok(user
,snum
) && check_hosts_equiv(user
)) {
1193 DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
1196 /* check the user= fields and the given password */
1197 if (!ok
&& lp_username(snum
)) {
1200 StrnCpy(user_list
,lp_username(snum
),sizeof(pstring
));
1202 string_sub(user_list
,"%S",lp_servicename(snum
));
1204 for (auser
=strtok(user_list
,LIST_SEP
);
1206 auser
= strtok(NULL
,LIST_SEP
))
1210 auser
= validate_group(auser
+1,password
,pwlen
,snum
);
1215 DEBUG(3,("ACCEPTED: group username and given password ok\n"));
1221 strcpy(user2
,auser
);
1222 if (user_ok(user2
,snum
) &&
1223 password_ok(user2
,password
,pwlen
,NULL
))
1227 DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
1232 } /* not guest only */
1234 /* check for a normal guest connection */
1235 if (!ok
&& GUEST_OK(snum
))
1238 StrnCpy(guestname
,lp_guestaccount(snum
),sizeof(guestname
)-1);
1239 if (Get_Pwnam(guestname
,True
))
1241 strcpy(user
,guestname
);
1243 DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
1246 DEBUG(0,("Invalid guest account %s??\n",guestname
));
1251 if (ok
&& !user_ok(user
,snum
))
1253 DEBUG(0,("rejected invalid user %s\n",user
));
1261 /****************************************************************************
1262 read the a hosts.equiv or .rhosts file and check if it
1263 allows this user from this machine
1264 ****************************************************************************/
1265 static BOOL
check_user_equiv(char *user
, char *remote
, char *equiv_file
)
1268 int plus_allowed
= 1;
1271 FILE *fp
= fopen(equiv_file
, "r");
1272 DEBUG(5, ("check_user_equiv %s %s %s\n", user
, remote
, equiv_file
));
1273 if (! fp
) return False
;
1274 while(fgets(buf
, sizeof(buf
), fp
))
1276 trim_string(buf
," "," ");
1278 if (buf
[0] != '#' && buf
[0] != '\n')
1280 BOOL is_group
= False
;
1283 if (strcmp(buf
, "NO_PLUS\n") == 0)
1285 DEBUG(6, ("check_user_equiv NO_PLUS\n"));
1292 if (*bp
== '\n' && plus_allowed
)
1294 /* a bare plus means everbody allowed */
1295 DEBUG(6, ("check_user_equiv everybody allowed\n"));
1300 else if (buf
[0] == '-')
1310 file_host
= strtok(bp
, " \t\n");
1311 file_user
= strtok(NULL
, " \t\n");
1312 DEBUG(7, ("check_user_equiv %s %s\n", file_host
, file_user
));
1313 if (file_host
&& *file_host
)
1315 BOOL host_ok
= False
;
1320 static char *mydomain
= NULL
;
1322 yp_get_default_domain(&mydomain
);
1323 if (mydomain
&& innetgr(file_host
,remote
,user
,mydomain
))
1329 DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n"));
1334 /* is it this host */
1335 /* the fact that remote has come from a call of gethostbyaddr
1336 * means that it may have the fully qualified domain name
1337 * so we could look up the file version to get it into
1338 * a canonical form, but I would rather just type it
1339 * in full in the equiv file
1341 if (!host_ok
&& !is_group
&& strequal(remote
, file_host
))
1347 /* is it this user */
1348 if (file_user
== 0 || strequal(user
, file_user
))
1351 DEBUG(5, ("check_user_equiv matched %s%s %s\n",
1352 (plus
? "+" : "-"), file_host
,
1353 (file_user
? file_user
: "")));
1354 return (plus
? True
: False
);
1365 /****************************************************************************
1366 check for a possible hosts equiv or rhosts entry for the user
1367 ****************************************************************************/
1368 BOOL
check_hosts_equiv(char *user
)
1372 struct passwd
*pass
= Get_Pwnam(user
,True
);
1377 fname
= lp_hosts_equiv();
1379 /* note: don't allow hosts.equiv on root */
1380 if (fname
&& *fname
&& (pass
->pw_uid
!= 0))
1382 if (check_user_equiv(user
,client_name(),fname
))
1386 if (lp_use_rhosts())
1388 char *home
= get_home_dir(user
);
1391 sprintf(rhostsfile
, "%s/.rhosts", home
);
1392 if (check_user_equiv(user
,client_name(),rhostsfile
))
1401 int password_client
= -1;
1402 static fstring pserver
;
1404 /****************************************************************************
1405 attempted support for server level security
1406 ****************************************************************************/
1407 BOOL
server_cryptkey(char *buf
)
1409 pstring inbuf
,outbuf
;
1410 fstring pass_protocol
;
1411 extern fstring remote_machine
;
1415 struct in_addr dest_ip
;
1416 int port
= SMB_PORT
;
1419 if (password_client
>= 0)
1420 close(password_client
);
1421 password_client
= -1;
1423 if (Protocol
< PROTOCOL_NT1
) {
1424 strcpy(pass_protocol
,"LM1.2X002");
1426 strcpy(pass_protocol
,"NT LM 0.12");
1429 bzero(inbuf
,sizeof(inbuf
));
1430 bzero(outbuf
,sizeof(outbuf
));
1432 for (p
=strtok(lp_passwordserver(),LIST_SEP
); p
; p
= strtok(NULL
,LIST_SEP
)) {
1434 standard_sub_basic(desthost
);
1437 dest_ip
= *interpret_addr2(desthost
);
1438 if (zero_ip(dest_ip
)) {
1439 DEBUG(1,("Can't resolve address for %s\n",p
));
1443 if (ismyip(dest_ip
)) {
1444 DEBUG(1,("Password server loop - disabling password server %s\n",p
));
1448 password_client
= open_socket_out(SOCK_STREAM
, &dest_ip
, port
, SHORT_CONNECT_TIMEOUT
);
1449 if (password_client
>= 0) {
1450 DEBUG(3,("connected to password server %s\n",p
));
1451 StrnCpy(pserver
,p
,sizeof(pserver
)-1);
1456 if (password_client
< 0) {
1457 DEBUG(1,("password server not available\n"));
1462 /* send a session request (RFC 8002) */
1464 /* put in the destination name */
1467 name_mangle(desthost
,p
,' ');
1472 name_mangle(remote_machine
,p
,' ');
1475 _smb_setlen(outbuf
,len
);
1476 CVAL(outbuf
,0) = 0x81;
1478 send_smb(password_client
,outbuf
);
1481 if (!receive_smb(password_client
,inbuf
,5000) ||
1482 CVAL(inbuf
,0) != 0x82) {
1483 DEBUG(1,("%s rejected the session\n",pserver
));
1484 close(password_client
); password_client
= -1;
1488 DEBUG(3,("got session\n"));
1490 bzero(outbuf
,smb_size
);
1492 /* setup the protocol string */
1493 set_message(outbuf
,0,strlen(pass_protocol
)+2,True
);
1494 p
= smb_buf(outbuf
);
1496 strcpy(p
,pass_protocol
);
1498 CVAL(outbuf
,smb_com
) = SMBnegprot
;
1499 CVAL(outbuf
,smb_flg
) = 0x8;
1500 SSVAL(outbuf
,smb_flg2
,0x1);
1502 send_smb(password_client
,outbuf
);
1503 ret
= receive_smb(password_client
,inbuf
,5000);
1505 if (!ret
|| CVAL(inbuf
,smb_rcls
) || SVAL(inbuf
,smb_vwv0
)) {
1506 DEBUG(1,("%s rejected the protocol\n",pserver
));
1507 close(password_client
); password_client
= -1;
1511 if (!(CVAL(inbuf
,smb_vwv1
) & 1)) {
1512 DEBUG(1,("%s isn't in user level security mode\n",pserver
));
1513 close(password_client
); password_client
= -1;
1517 memcpy(buf
,inbuf
,smb_len(inbuf
)+4);
1519 DEBUG(3,("password server OK\n"));
1524 /****************************************************************************
1525 attempted support for server level security
1526 ****************************************************************************/
1527 BOOL
server_validate(char *buf
)
1529 pstring inbuf
,outbuf
;
1532 if (password_client
< 0) {
1533 DEBUG(1,("%s not connected\n",pserver
));
1537 bzero(inbuf
,sizeof(inbuf
));
1538 memcpy(outbuf
,buf
,sizeof(outbuf
));
1540 /* send a session setup command */
1541 CVAL(outbuf
,smb_flg
) = 0x8;
1542 SSVAL(outbuf
,smb_flg2
,0x1);
1543 CVAL(outbuf
,smb_vwv0
) = 0xFF;
1545 set_message(outbuf
,smb_numwords(outbuf
),smb_buflen(outbuf
),False
);
1547 SCVAL(inbuf
,smb_rcls
,1);
1549 send_smb(password_client
,outbuf
);
1550 ret
= receive_smb(password_client
,inbuf
,5000);
1552 if (!ret
|| CVAL(inbuf
,smb_rcls
) != 0) {
1553 DEBUG(1,("password server %s rejected the password\n",pserver
));
1557 /* if logged in as guest then reject */
1558 if ((SVAL(inbuf
,smb_vwv2
) & 1) != 0) {
1559 DEBUG(1,("password server %s gave us guest only\n",pserver
));
1563 DEBUG(3,("password server %s accepted the password\n",pserver
));
1565 #if !KEEP_PASSWORD_SERVER_OPEN
1566 close(password_client
); password_client
= -1;