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 */
158 * After observing MS-Exchange services writing to a Samba share
159 * I belive this code is incorrect. Each service does it's own
160 * sessionsetup_and_X for the same user, and as each service shuts
161 * down, it does a user_logoff_and_X. As we are consolidating multiple
162 * sessionsetup_and_X's onto the same vuid here, when the first service
163 * shuts down, it invalidates all the open files for the other services.
164 * Hence I am removing this code and forcing each sessionsetup_and_X
166 * Jeremy Allison. (jallison@whistle.com).
170 for(i
= 0; i
< num_validated_users
; i
++) {
171 vuser
= &validated_users
[i
];
172 if( vuser
->uid
== uid
)
173 return (uint16
)(i
+ VUID_OFFSET
); /* User already validated */
177 validated_users
= (user_struct
*)Realloc(validated_users
,
179 (num_validated_users
+1));
181 if (!validated_users
)
183 DEBUG(0,("Failed to realloc users struct!\n"));
184 num_validated_users
= 0;
185 return UID_FIELD_INVALID
;
188 vuser
= &validated_users
[num_validated_users
];
189 num_validated_users
++;
193 vuser
->guest
= guest
;
194 strcpy(vuser
->name
,name
);
196 vuser
->user_ngroups
= 0;
197 vuser
->user_groups
= NULL
;
198 vuser
->user_igroups
= NULL
;
200 /* Find all the groups this uid is in and store them.
201 Used by become_user() */
202 setup_groups(name
,uid
,gid
,
203 &vuser
->user_ngroups
,
204 &vuser
->user_igroups
,
205 &vuser
->user_groups
);
207 DEBUG(3,("uid %d registered to name %s\n",uid
,name
));
209 #if (defined(NETGROUP) && defined (AUTOMOUNT))
210 vuser
->home_share
= NULL
;
211 DEBUG(3, ("Setting default HOMESHR to: \\\\logon server\\HOMES\n"));
212 vuser
->home_share
= Realloc(vuser
->home_share
, 32);
213 strcpy(vuser
->home_share
,"\\\\%L\\HOMES");
215 if (nis_error
= yp_get_default_domain(&nis_domain
))
216 DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error
)));
217 DEBUG(3, ("NIS Domain: %s\n", nis_domain
));
219 if (nis_error
= yp_match(nis_domain
, nis_map
, vuser
->name
, strlen(vuser
->name
),
220 &nis_result
, &nis_result_len
))
221 DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error
)));
222 if (!nis_error
&& lp_nis_home_map()) {
223 home_server_len
= strcspn(nis_result
,":");
224 DEBUG(3, ("NIS lookup succeeded\n\tHome server length: %d\n",home_server_len
));
225 vuser
->home_share
= (char *)Realloc(vuser
->home_share
, home_server_len
+12);
226 DEBUG(3, ("\tAllocated %d bytes for HOMESHR\n",home_server_len
+12 ));
227 strcpy(vuser
->home_share
,"\\\\");
228 strncat(vuser
->home_share
, nis_result
, home_server_len
);
229 strcat(vuser
->home_share
,"\\homes");
230 DEBUG(2,("\tUser = %s\n\tUID = %d\n\tNIS result = %s\n\tHOMESHR = %s\n",
231 vuser
->name
, vuser
->uid
, nis_result
, vuser
->home_share
));
235 vuser
->real_name
= NULL
;
236 DEBUG(3, ("Clearing default real name\n"));
237 vuser
->real_name
= Realloc(vuser
->real_name
, 15);
238 strcpy(vuser
->real_name
, "<Full Name>\0");
239 if (lp_unix_realname()) {
240 pwfile
=getpwnam(vuser
->name
);
241 DEBUG(3, ("User name: %s\tReal name: %s\n",vuser
->name
,pwfile
->pw_gecos
));
242 real_name_len
= strcspn(pwfile
->pw_gecos
, ",");
243 DEBUG(3, ("Real name length: %d\n", real_name_len
));
244 vuser
->real_name
= (char *)Realloc(vuser
->real_name
, real_name_len
+1);
245 strncpy(vuser
->real_name
, pwfile
->pw_gecos
, real_name_len
);
246 vuser
->real_name
[real_name_len
]='\0';
249 return (uint16
)((num_validated_users
- 1) + VUID_OFFSET
);
253 /****************************************************************************
254 add a name to the session users list
255 ****************************************************************************/
256 void add_session_user(char *user
)
259 StrnCpy(suser
,user
,sizeof(suser
)-1);
261 if (!Get_Pwnam(suser
,True
)) return;
263 if (suser
&& *suser
&& !in_list(suser
,session_users
,False
))
265 if (strlen(suser
) + strlen(session_users
) + 2 >= sizeof(pstring
))
266 DEBUG(1,("Too many session users??\n"));
269 strcat(session_users
," ");
270 strcat(session_users
,suser
);
277 /* a fake shadow password routine which just fills a fake spwd struct
278 * with the sp_pwdp field. (sreiz@aie.nl)
280 static struct spwd
*getspnam(char *username
) /* fake shadow password routine */
285 static struct spwd static_spwd
;
287 static_spwd
.sp_pwdp
=0;
288 if (!(f
=fopen("/etc/master.passwd", "r")))
290 while (fgets(line
, 1024, f
)) {
291 if (!strncmp(line
, username
, strlen(username
)) &&
292 line
[strlen(username
)]==':') { /* found entry */
295 p
=line
+strlen(username
)+1;
296 if ((q
=strchr(p
, ':'))) {
301 static_spwd
.sp_pwdp
=pw
;
307 if (static_spwd
.sp_pwdp
)
315 /****************************************************************************
316 an enhanced crypt for OSF1
317 ****************************************************************************/
318 static char *osf1_bigcrypt(char *password
,char *salt1
)
320 static char result
[AUTH_MAX_PASSWD_LENGTH
] = "";
325 int parts
= strlen(password
) / AUTH_CLEARTEXT_SEG_CHARS
;
326 if (strlen(password
)%AUTH_CLEARTEXT_SEG_CHARS
)
329 StrnCpy(salt
,salt1
,2);
330 StrnCpy(result
,salt1
,2);
332 for (i
=0; i
<parts
;i
++)
336 StrnCpy(salt
,&result
[2+i
*AUTH_CIPHERTEXT_SEG_CHARS
],2);
337 p2
+= AUTH_CLEARTEXT_SEG_CHARS
;
345 /****************************************************************************
346 update the enhanced security database. Only relevant for OSF1 at the moment.
347 ****************************************************************************/
348 static void update_protected_database( char *user
, BOOL result
)
351 struct pr_passwd
*mypasswd
;
354 mypasswd
= getprpwnam (user
);
355 starttime
= time (NULL
);
359 mypasswd
->ufld
.fd_slogin
= starttime
;
360 mypasswd
->ufld
.fd_nlogins
= 0;
362 putprpwnam(user
,mypasswd
);
364 DEBUG(3,("Update protected database for Account %s after succesful connection\n",user
));
368 mypasswd
->ufld
.fd_ulogin
= starttime
;
369 mypasswd
->ufld
.fd_nlogins
= mypasswd
->ufld
.fd_nlogins
+ 1;
370 if ( mypasswd
->ufld
.fd_max_tries
!= 0 && mypasswd
->ufld
.fd_nlogins
> mypasswd
->ufld
.fd_max_tries
)
372 mypasswd
->uflg
.fg_lock
= 0;
373 DEBUG(3,("Account is disabled -- see Account Administrator.\n"));
375 putprpwnam ( user
, mypasswd
);
376 DEBUG(3,("Update protected database for Account %s after refusing connection\n",user
));
379 DEBUG(6,("Updated database with %s %s\n",user
,BOOLSTR(result
)));
385 /*******************************************************************
386 check on PAM authentication
387 ********************************************************************/
389 /* We first need some helper functions */
390 #include <security/pam_appl.h>
391 /* Static variables used to communicate between the conversation function
392 * and the server_login function
394 static char *PAM_username
;
395 static char *PAM_password
;
397 /* PAM conversation function
398 * Here we assume (for now, at least) that echo on means login name, and
399 * echo off means password.
401 static int PAM_conv (int num_msg
,
402 const struct pam_message
**msg
,
403 struct pam_response
**resp
,
405 int count
= 0, replies
= 0;
406 struct pam_response
*reply
= NULL
;
407 int size
= sizeof(struct pam_response
);
409 #define GET_MEM if (reply) realloc(reply, size); else reply = malloc(size); \
410 if (!reply) return PAM_CONV_ERR; \
411 size += sizeof(struct pam_response)
412 #define COPY_STRING(s) (s) ? strdup(s) : NULL
414 for (count
= 0; count
< num_msg
; count
++) {
415 switch (msg
[count
]->msg_style
) {
416 case PAM_PROMPT_ECHO_ON
:
418 reply
[replies
].resp_retcode
= PAM_SUCCESS
;
419 reply
[replies
++].resp
= COPY_STRING(PAM_username
);
422 case PAM_PROMPT_ECHO_OFF
:
424 reply
[replies
].resp_retcode
= PAM_SUCCESS
;
425 reply
[replies
++].resp
= COPY_STRING(PAM_password
);
433 /* Must be an error of some sort... */
438 if (reply
) *resp
= reply
;
441 static struct pam_conv PAM_conversation
= {
447 static BOOL
pam_auth(char *this_user
,char *password
)
452 /* Now use PAM to do authentication. For now, we won't worry about
453 * session logging, only authentication. Bail out if there are any
454 * errors. Since this is a limited protocol, and an even more limited
455 * function within a server speaking this protocol, we can't be as
456 * verbose as would otherwise make sense.
457 * Query: should we be using PAM_SILENT to shut PAM up?
459 #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
460 pam_end(pamh, 0); return False; \
462 PAM_password
= password
;
463 PAM_username
= this_user
;
464 pam_error
= pam_start("samba", this_user
, &PAM_conversation
, &pamh
);
466 pam_error
= pam_authenticate(pamh
, 0);
468 /* It is not clear to me that account management is the right thing
469 * to do, but it is not clear that it isn't, either. This can be
470 * removed if no account management should be done. Alternately,
471 * put a pam_allow.so entry in /etc/pam.conf for account handling. */
472 pam_error
= pam_acct_mgmt(pamh
, 0);
474 pam_end(pamh
, PAM_SUCCESS
);
475 /* If this point is reached, the user has been authenticated. */
482 /*******************************************************************
483 check on AFS authentication
484 ********************************************************************/
485 static BOOL
afs_auth(char *this_user
,char *password
)
487 long password_expires
= 0;
490 /* For versions of AFS prior to 3.3, this routine has few arguments, */
491 /* but since I can't find the old documentation... :-) */
493 if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION
+KA_USERAUTH_DOSETPAG
,
495 (char *) 0, /* instance */
496 (char *) 0, /* cell */
498 0, /* lifetime, default */
499 &password_expires
, /*days 'til it expires */
510 sec_login_handle_t my_dce_sec_context
;
511 int dcelogin_atmost_once
= 0;
513 /*******************************************************************
514 check on a DCE/DFS authentication
515 ********************************************************************/
516 static BOOL
dfs_auth(char *this_user
,char *password
)
521 boolean32 password_reset
;
522 sec_passwd_rec_t my_dce_password
;
523 sec_login_auth_src_t auth_src
= sec_login_auth_src_network
;
524 unsigned char dce_errstr
[dce_c_error_string_len
];
527 * We only go for a DCE login context if the given password
528 * matches that stored in the local password file..
529 * Assumes local passwd file is kept in sync w/ DCE RGY!
532 if (!strcmp((char *)crypt(password
,this_salt
),this_crypted
) ||
533 dcelogin_atmost_once
)
536 if (sec_login_setup_identity(
537 (unsigned char *)this_user
,
542 dce_error_inq_text(err
, dce_errstr
, &err2
);
543 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
544 this_user
,dce_errstr
));
548 my_dce_password
.version_number
= sec_passwd_c_version_none
;
549 my_dce_password
.pepper
= NULL
;
550 my_dce_password
.key
.key_type
= sec_passwd_plain
;
551 my_dce_password
.key
.tagged_union
.plain
= (idl_char
*)password
;
553 if (sec_login_valid_and_cert_ident(my_dce_sec_context
,
559 dce_error_inq_text(err
, dce_errstr
, &err2
);
560 DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
561 this_user
,dce_errstr
));
566 sec_login_set_context(my_dce_sec_context
, &err
);
567 if (err
!= error_status_ok
)
569 dce_error_inq_text(err
, dce_errstr
, &err2
);
570 DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
571 this_user
,dce_errstr
));
572 sec_login_purge_context(my_dce_sec_context
, &err
);
577 DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
578 this_user
, getpid()));
581 dcelogin_atmost_once
= 1;
585 void dfs_unlogin(void)
589 unsigned char dce_errstr
[dce_c_error_string_len
];
591 sec_login_purge_context(my_dce_sec_context
, &err
);
592 if (err
!= error_status_ok
)
594 dce_error_inq_text(err
, dce_errstr
, &err2
);
595 DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
596 getpid(), dce_errstr
));
603 /*******************************************************************
604 check on Kerberos authentication
605 ********************************************************************/
606 static BOOL
krb5_auth(char *this_user
,char *password
)
608 krb5_data tgtname
= {
613 krb5_context kcontext
;
614 krb5_principal kprinc
;
615 krb5_principal server
;
618 krb5_address
**addrs
= (krb5_address
**)0;
619 krb5_preauthtype
*preauth
= NULL
;
620 krb5_keytab keytab
= NULL
;
622 krb5_ccache ccache
= NULL
;
626 if ( retval
=krb5_init_context(&kcontext
))
631 if ( retval
= krb5_timeofday(kcontext
, &now
) )
636 if ( retval
= krb5_cc_default(kcontext
, &ccache
) )
641 if ( retval
= krb5_parse_name(kcontext
, this_user
, &kprinc
) )
646 memset((char *)&kcreds
, 0, sizeof(kcreds
));
648 kcreds
.client
= kprinc
;
650 if ((retval
= krb5_build_principal_ext(kcontext
, &server
,
651 krb5_princ_realm(kcontext
, kprinc
)->length
,
652 krb5_princ_realm(kcontext
, kprinc
)->data
,
655 krb5_princ_realm(kcontext
, kprinc
)->length
,
656 krb5_princ_realm(kcontext
, kprinc
)->data
,
662 kcreds
.server
= server
;
664 retval
= krb5_get_in_tkt_with_password(kcontext
,
681 #endif /* KRB5_AUTH */
683 #ifdef LINUX_BIGCRYPT
684 /****************************************************************************
685 an enhanced crypt for Linux to handle password longer than 8 characters
686 ****************************************************************************/
687 static int linux_bigcrypt(char *password
,char *salt1
, char *crypted
)
689 #define LINUX_PASSWORD_SEG_CHARS 8
693 StrnCpy(salt
,salt1
,2);
696 for ( i
=strlen(password
); i
> 0; i
-= LINUX_PASSWORD_SEG_CHARS
) {
697 char * p
= crypt(password
,salt
) + 2;
698 if(strncmp(p
, crypted
, LINUX_PASSWORD_SEG_CHARS
) != 0)
700 password
+= LINUX_PASSWORD_SEG_CHARS
;
701 crypted
+= strlen(p
);
709 /****************************************************************************
710 apply a function to upper/lower case combinations
711 of a string and return true if one of them returns true.
712 try all combinations with N uppercase letters.
713 offset is the first char to try and change (start with 0)
714 it assumes the string starts lowercased
715 ****************************************************************************/
716 static BOOL
string_combinations2(char *s
,int offset
,BOOL (*fn
)(),int N
)
721 #ifdef PASSWORD_LENGTH
722 len
= MIN(len
,PASSWORD_LENGTH
);
725 if (N
<= 0 || offset
>= len
)
728 for (i
=offset
;i
<(len
-(N
-1));i
++)
731 if (!islower(c
)) continue;
733 if (string_combinations2(s
,i
+1,fn
,N
-1))
740 /****************************************************************************
741 apply a function to upper/lower case combinations
742 of a string and return true if one of them returns true.
743 try all combinations with up to N uppercase letters.
744 offset is the first char to try and change (start with 0)
745 it assumes the string starts lowercased
746 ****************************************************************************/
747 static BOOL
string_combinations(char *s
,BOOL (*fn
)(),int N
)
751 if (string_combinations2(s
,0,fn
,n
)) return(True
);
757 /****************************************************************************
758 core of password checking routine
759 ****************************************************************************/
760 BOOL
password_check(char *password
)
764 /* This falls through if the password check fails
765 - if NO_CRYPT is defined this causes an error msg
766 saying Warning - no crypt available
767 - if NO_CRYPT is NOT defined this is a potential security hole
768 as it may authenticate via the crypt call when PAM
769 settings say it should fail.
770 if (pam_auth(this_user,password)) return(True);
771 Hence we make a direct return to avoid a second chance!!!
773 return (pam_auth(this_user
,password
));
777 if (afs_auth(this_user
,password
)) return(True
);
781 if (dfs_auth(this_user
,password
)) return(True
);
785 if (krb5_auth(this_user
,password
)) return(True
);
789 if (pwdauth(this_user
,password
) == 0)
794 return(strcmp(osf1_bigcrypt(password
,this_salt
),this_crypted
) == 0);
798 return (strcmp((char *)crypt16(password
, this_salt
),this_crypted
) == 0);
801 #ifdef LINUX_BIGCRYPT
802 return(linux_bigcrypt(password
,this_salt
,this_crypted
));
806 DEBUG(1,("Warning - no crypt available\n"));
809 return(strcmp((char *)crypt(password
,this_salt
),this_crypted
) == 0);
814 /****************************************************************************
815 core of smb password checking routine.
816 ****************************************************************************/
817 BOOL
smb_password_check(char *password
, unsigned char *part_passwd
, unsigned char *c8
)
819 /* Finish the encryption of part_passwd. */
820 unsigned char p21
[21];
821 unsigned char p24
[24];
823 if(part_passwd
== NULL
)
824 DEBUG(10,("No password set - allowing access\n"));
825 /* No password set - always true ! */
826 if(part_passwd
== NULL
)
830 memcpy(p21
,part_passwd
,16);
835 DEBUG(100,("Part password (P16) was |"));
836 for(i
= 0; i
< 16; i
++)
837 DEBUG(100,("%X ", (unsigned char)part_passwd
[i
]));
839 DEBUG(100,("Password from client was |"));
840 for(i
= 0; i
< 24; i
++)
841 DEBUG(100,("%X ", (unsigned char)password
[i
]));
843 DEBUG(100,("Given challenge was |"));
844 for(i
= 0; i
< 8; i
++)
845 DEBUG(100,("%X ", (unsigned char)c8
[i
]));
847 DEBUG(100,("Value from encryption was |"));
848 for(i
= 0; i
< 24; i
++)
849 DEBUG(100,("%X ", (unsigned char)p24
[i
]));
853 return (memcmp(p24
, password
, 24) == 0);
857 /****************************************************************************
858 check if a username/password is OK
859 ****************************************************************************/
860 BOOL
password_ok(char *user
,char *password
, int pwlen
, struct passwd
*pwd
)
863 int level
= lp_passwordlevel();
867 struct smb_passwd
*smb_pass
;
868 BOOL challenge_done
= False
;
871 if (password
) password
[pwlen
] = 0;
875 challenge_done
= last_challenge(challenge
);
883 DEBUG(100,("checking user=[%s] pass=[",user
));
884 for( i
= 0; i
< 24; i
++)
885 DEBUG(100,("%0x ", (unsigned char)password
[i
]));
890 DEBUG(100,("checking user=[%s] pass=[%s]\n",user
,password
));
896 if (((!*password
) || (!pwlen
)) && !lp_null_passwords())
901 pass
= (struct passwd
*) pwd
;
902 user
= pass
->pw_name
;
905 pass
= Get_Pwnam(user
,True
);
909 DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen
, challenge_done
));
911 if((pwlen
== 24) && challenge_done
)
913 DEBUG(4,("Checking SMB password for user %s (l=24)\n",user
));
917 DEBUG(3,("Couldn't find user %s\n",user
));
921 smb_pass
= get_smbpwnam(user
);
924 DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user
));
928 /* Ensure the uid's match */
929 if(smb_pass
->smb_userid
!= pass
->pw_uid
)
931 DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
935 if(Protocol
>= PROTOCOL_NT1
)
937 /* We have the NT MD4 hash challenge available - see if we can
938 use it (ie. does it exist in the smbpasswd file).
940 if(smb_pass
->smb_nt_passwd
!= NULL
)
942 DEBUG(4,("Checking NT MD4 password\n"));
943 if(smb_password_check(password
,
944 smb_pass
->smb_nt_passwd
,
947 update_protected_database(user
,True
);
950 DEBUG(4,("NT MD4 password check failed\n"));
954 /* Try against the lanman password */
956 if (smb_password_check(password
,
957 smb_pass
->smb_passwd
,
958 (char *)challenge
)) {
959 update_protected_database(user
,True
);
963 DEBUG(3,("Error smb_password_check failed\n"));
967 DEBUG(4,("Checking password for user %s (l=%d)\n",user
,pwlen
));
971 DEBUG(3,("Couldn't find user %s\n",user
));
979 /* many shadow systems require you to be root to get the password,
980 in most cases this should already be the case when this
981 function is called, except perhaps for IPC password changing
984 spass
= getspnam(pass
->pw_name
);
985 if (spass
&& spass
->sp_pwdp
)
986 pass
->pw_passwd
= spass
->sp_pwdp
;
988 #elif defined(IA_UINFO)
990 /* Need to get password with SVR4.2's ia_ functions instead of
991 get{sp,pw}ent functions. Required by UnixWare 2.x, tested on
992 version 2.1. (tangent@cyberport.com) */
994 if (ia_openinfo(pass
->pw_name
, &uinfo
) != -1)
995 ia_get_logpwd(uinfo
, &(pass
->pw_passwd
));
1001 struct pr_passwd
*pr_pw
= getprpwnam(pass
->pw_name
);
1002 if (pr_pw
&& pr_pw
->ufld
.fd_encrypt
)
1003 pass
->pw_passwd
= pr_pw
->ufld
.fd_encrypt
;
1007 #ifdef HPUX_10_TRUSTED
1009 struct pr_passwd
*pr_pw
= getprpwnam(pass
->pw_name
);
1010 if (pr_pw
&& pr_pw
->ufld
.fd_encrypt
)
1011 pass
->pw_passwd
= pr_pw
->ufld
.fd_encrypt
;
1017 struct pr_passwd
*mypasswd
;
1018 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user
));
1019 mypasswd
= getprpwnam (user
);
1022 strcpy(pass
->pw_name
,mypasswd
->ufld
.fd_name
);
1023 strcpy(pass
->pw_passwd
,mypasswd
->ufld
.fd_encrypt
);
1027 DEBUG(5,("No entry for user %s in protected database !\n",user
));
1035 AUTHORIZATION
*ap
= getauthuid( pass
->pw_uid
);
1038 strcpy( pass
->pw_passwd
, ap
->a_password
);
1044 /* extract relevant info */
1045 strcpy(this_user
,pass
->pw_name
);
1046 strcpy(this_salt
,pass
->pw_passwd
);
1047 strcpy(this_crypted
,pass
->pw_passwd
);
1049 if (!*this_crypted
) {
1050 if (!lp_null_passwords()) {
1051 DEBUG(2,("Disallowing access to %s due to null password\n",this_user
));
1056 DEBUG(3,("Allowing access to %s with null password\n",this_user
));
1062 /* try it as it came to us */
1063 if (password_check(password
))
1065 update_protected_database(user
,True
);
1069 /* if the password was given to us with mixed case then we don't
1070 need to proceed as we know it hasn't been case modified by the
1072 if (strhasupper(password
) && strhaslower(password
))
1075 /* make a copy of it */
1076 StrnCpy(pass2
,password
,sizeof(pstring
)-1);
1078 /* try all lowercase */
1080 if (password_check(password
))
1082 update_protected_database(user
,True
);
1089 update_protected_database(user
,False
);
1092 strcpy(password
,pass2
);
1097 /* last chance - all combinations of up to level chars upper! */
1100 if (string_combinations(password
,password_check
,level
))
1102 update_protected_database(user
,True
);
1106 update_protected_database(user
,False
);
1109 strcpy(password
,pass2
);
1116 /****************************************************************************
1117 check if a username is valid
1118 ****************************************************************************/
1119 BOOL
user_ok(char *user
,int snum
)
1121 pstring valid
, invalid
;
1124 StrnCpy(valid
, lp_valid_users(snum
), sizeof(pstring
));
1125 StrnCpy(invalid
, lp_invalid_users(snum
), sizeof(pstring
));
1127 string_sub(valid
,"%S",lp_servicename(snum
));
1128 string_sub(invalid
,"%S",lp_servicename(snum
));
1130 ret
= !user_in_list(user
,invalid
);
1132 if (ret
&& valid
&& *valid
)
1133 ret
= user_in_list(user
,valid
);
1135 if (ret
&& lp_onlyuser(snum
)) {
1136 char *user_list
= lp_username(snum
);
1137 string_sub(user_list
,"%S",lp_servicename(snum
));
1138 ret
= user_in_list(user
,user_list
);
1147 /****************************************************************************
1148 validate a group username entry. Return the username or NULL
1149 ****************************************************************************/
1150 static char *validate_group(char *group
,char *password
,int pwlen
,int snum
)
1154 char *host
, *user
, *domain
;
1156 while (getnetgrent(&host
, &user
, &domain
)) {
1158 if (user_ok(user
, snum
) &&
1159 password_ok(user
,password
,pwlen
,NULL
)) {
1171 struct group
*gptr
= (struct group
*)getgrnam(group
);
1175 member
= gptr
->gr_mem
;
1176 while (member
&& *member
)
1178 static fstring name
;
1179 strcpy(name
,*member
);
1180 if (user_ok(name
,snum
) &&
1181 password_ok(name
,password
,pwlen
,NULL
))
1185 #ifdef GROUP_CHECK_PWENT
1191 while (pwd
= getpwent ()) {
1192 if (*(pwd
->pw_passwd
) && pwd
->pw_gid
== gptr
->gr_gid
) {
1193 /* This Entry have PASSWORD and same GID then check pwd */
1194 if (password_ok(NULL
, password
, pwlen
, pwd
)) {
1195 strcpy(tm
, pwd
->pw_name
);
1203 #endif /* GROUP_CHECK_PWENT */
1212 /****************************************************************************
1213 check for authority to login to a service with a given username/password
1214 ****************************************************************************/
1215 BOOL
authorise_login(int snum
,char *user
,char *password
, int pwlen
,
1216 BOOL
*guest
,BOOL
*force
,uint16 vuid
)
1223 DEBUG(100,("checking authorisation on user=%s pass=%s\n",user
,password
));
1226 /* there are several possabilities:
1227 1) login as the given user with given password
1228 2) login as a previously registered username with the given password
1229 3) login as a session list username with the given password
1230 4) login as a previously validated user/password pair
1231 5) login as the "user =" user with given password
1232 6) login as the "user =" user with no password (guest connection)
1233 7) login as guest user with no password
1235 if the service is guest_only then steps 1 to 5 are skipped
1238 if (GUEST_ONLY(snum
)) *force
= True
;
1240 if (!(GUEST_ONLY(snum
) && GUEST_OK(snum
)))
1243 user_struct
*vuser
= get_valid_user_struct(vuid
);
1245 /* check the given username and password */
1246 if (!ok
&& (*user
) && user_ok(user
,snum
)) {
1247 ok
= password_ok(user
,password
, pwlen
, NULL
);
1248 if (ok
) DEBUG(3,("ACCEPTED: given username password ok\n"));
1251 /* check for a previously registered guest username */
1252 if (!ok
&& (vuser
!= 0) && vuser
->guest
) {
1253 if (user_ok(vuser
->name
,snum
) &&
1254 password_ok(vuser
->name
, password
, pwlen
, NULL
)) {
1255 strcpy(user
, vuser
->name
);
1256 vuser
->guest
= False
;
1257 DEBUG(3,("ACCEPTED: given password with registered user %s\n", user
));
1263 /* now check the list of session users */
1267 char *user_list
= strdup(session_users
);
1268 if (!user_list
) return(False
);
1270 for (auser
=strtok(user_list
,LIST_SEP
);
1272 auser
= strtok(NULL
,LIST_SEP
))
1275 strcpy(user2
,auser
);
1276 if (!user_ok(user2
,snum
)) continue;
1278 if (password_ok(user2
,password
, pwlen
, NULL
)) {
1281 DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
1287 /* check for a previously validated username/password pair */
1288 if (!ok
&& !lp_revalidate(snum
) &&
1289 (vuser
!= 0) && !vuser
->guest
&&
1290 user_ok(vuser
->name
,snum
)) {
1291 strcpy(user
,vuser
->name
);
1293 DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
1297 /* check for a rhosts entry */
1298 if (!ok
&& user_ok(user
,snum
) && check_hosts_equiv(user
)) {
1300 DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
1303 /* check the user= fields and the given password */
1304 if (!ok
&& lp_username(snum
)) {
1307 StrnCpy(user_list
,lp_username(snum
),sizeof(pstring
));
1309 string_sub(user_list
,"%S",lp_servicename(snum
));
1311 for (auser
=strtok(user_list
,LIST_SEP
);
1313 auser
= strtok(NULL
,LIST_SEP
))
1317 auser
= validate_group(auser
+1,password
,pwlen
,snum
);
1322 DEBUG(3,("ACCEPTED: group username and given password ok\n"));
1328 strcpy(user2
,auser
);
1329 if (user_ok(user2
,snum
) &&
1330 password_ok(user2
,password
,pwlen
,NULL
))
1334 DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
1339 } /* not guest only */
1341 /* check for a normal guest connection */
1342 if (!ok
&& GUEST_OK(snum
))
1345 StrnCpy(guestname
,lp_guestaccount(snum
),sizeof(guestname
)-1);
1346 if (Get_Pwnam(guestname
,True
))
1348 strcpy(user
,guestname
);
1350 DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
1353 DEBUG(0,("Invalid guest account %s??\n",guestname
));
1358 if (ok
&& !user_ok(user
,snum
))
1360 DEBUG(0,("rejected invalid user %s\n",user
));
1368 /****************************************************************************
1369 read the a hosts.equiv or .rhosts file and check if it
1370 allows this user from this machine
1371 ****************************************************************************/
1372 static BOOL
check_user_equiv(char *user
, char *remote
, char *equiv_file
)
1375 int plus_allowed
= 1;
1378 FILE *fp
= fopen(equiv_file
, "r");
1379 DEBUG(5, ("check_user_equiv %s %s %s\n", user
, remote
, equiv_file
));
1380 if (! fp
) return False
;
1381 while(fgets(buf
, sizeof(buf
), fp
))
1383 trim_string(buf
," "," ");
1385 if (buf
[0] != '#' && buf
[0] != '\n')
1387 BOOL is_group
= False
;
1390 if (strcmp(buf
, "NO_PLUS\n") == 0)
1392 DEBUG(6, ("check_user_equiv NO_PLUS\n"));
1399 if (*bp
== '\n' && plus_allowed
)
1401 /* a bare plus means everbody allowed */
1402 DEBUG(6, ("check_user_equiv everybody allowed\n"));
1407 else if (buf
[0] == '-')
1417 file_host
= strtok(bp
, " \t\n");
1418 file_user
= strtok(NULL
, " \t\n");
1419 DEBUG(7, ("check_user_equiv %s %s\n", file_host
? file_host
: "(null)",
1420 file_user
? file_user
: "(null)" ));
1421 if (file_host
&& *file_host
)
1423 BOOL host_ok
= False
;
1428 static char *mydomain
= NULL
;
1430 yp_get_default_domain(&mydomain
);
1431 if (mydomain
&& innetgr(file_host
,remote
,user
,mydomain
))
1437 DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n"));
1442 /* is it this host */
1443 /* the fact that remote has come from a call of gethostbyaddr
1444 * means that it may have the fully qualified domain name
1445 * so we could look up the file version to get it into
1446 * a canonical form, but I would rather just type it
1447 * in full in the equiv file
1449 if (!host_ok
&& !is_group
&& strequal(remote
, file_host
))
1455 /* is it this user */
1456 if (file_user
== 0 || strequal(user
, file_user
))
1459 DEBUG(5, ("check_user_equiv matched %s%s %s\n",
1460 (plus
? "+" : "-"), file_host
,
1461 (file_user
? file_user
: "")));
1462 return (plus
? True
: False
);
1473 /****************************************************************************
1474 check for a possible hosts equiv or rhosts entry for the user
1475 ****************************************************************************/
1476 BOOL
check_hosts_equiv(char *user
)
1480 struct passwd
*pass
= Get_Pwnam(user
,True
);
1485 fname
= lp_hosts_equiv();
1487 /* note: don't allow hosts.equiv on root */
1488 if (fname
&& *fname
&& (pass
->pw_uid
!= 0))
1490 if (check_user_equiv(user
,client_name(),fname
))
1494 if (lp_use_rhosts())
1496 char *home
= get_home_dir(user
);
1499 sprintf(rhostsfile
, "%s/.rhosts", home
);
1500 if (check_user_equiv(user
,client_name(),rhostsfile
))
1509 int password_client
= -1;
1510 static fstring pserver
;
1512 /****************************************************************************
1513 attempted support for server level security
1514 ****************************************************************************/
1515 BOOL
server_cryptkey(char *buf
)
1517 pstring inbuf
,outbuf
;
1518 fstring pass_protocol
;
1519 extern fstring remote_machine
;
1523 struct in_addr dest_ip
;
1524 int port
= SMB_PORT
;
1527 if (password_client
>= 0)
1528 close(password_client
);
1529 password_client
= -1;
1531 if (Protocol
< PROTOCOL_NT1
) {
1532 strcpy(pass_protocol
,"LM1.2X002");
1534 strcpy(pass_protocol
,"NT LM 0.12");
1537 bzero(inbuf
,sizeof(inbuf
));
1538 bzero(outbuf
,sizeof(outbuf
));
1540 for (p
=strtok(lp_passwordserver(),LIST_SEP
); p
; p
= strtok(NULL
,LIST_SEP
)) {
1542 standard_sub_basic(desthost
);
1545 dest_ip
= *interpret_addr2(desthost
);
1546 if (zero_ip(dest_ip
)) {
1547 DEBUG(1,("Can't resolve address for %s\n",p
));
1551 if (ismyip(dest_ip
)) {
1552 DEBUG(1,("Password server loop - disabling password server %s\n",p
));
1556 password_client
= open_socket_out(SOCK_STREAM
, &dest_ip
, port
, SHORT_CONNECT_TIMEOUT
);
1557 if (password_client
>= 0) {
1558 DEBUG(3,("connected to password server %s\n",p
));
1559 StrnCpy(pserver
,p
,sizeof(pserver
)-1);
1564 if (password_client
< 0) {
1565 DEBUG(1,("password server not available\n"));
1570 /* send a session request (RFC 8002) */
1572 /* put in the destination name */
1575 name_mangle(desthost
,p
,' ');
1580 name_mangle(remote_machine
,p
,' ');
1583 _smb_setlen(outbuf
,len
);
1584 CVAL(outbuf
,0) = 0x81;
1586 send_smb(password_client
,outbuf
);
1589 if (!receive_smb(password_client
,inbuf
,5000) ||
1590 CVAL(inbuf
,0) != 0x82) {
1591 DEBUG(1,("%s rejected the session\n",pserver
));
1592 close(password_client
); password_client
= -1;
1596 DEBUG(3,("got session\n"));
1598 bzero(outbuf
,smb_size
);
1600 /* setup the protocol string */
1601 set_message(outbuf
,0,strlen(pass_protocol
)+2,True
);
1602 p
= smb_buf(outbuf
);
1604 strcpy(p
,pass_protocol
);
1606 CVAL(outbuf
,smb_com
) = SMBnegprot
;
1607 CVAL(outbuf
,smb_flg
) = 0x8;
1608 SSVAL(outbuf
,smb_flg2
,0x1);
1610 send_smb(password_client
,outbuf
);
1611 ret
= receive_smb(password_client
,inbuf
,5000);
1613 if (!ret
|| CVAL(inbuf
,smb_rcls
) || SVAL(inbuf
,smb_vwv0
)) {
1614 DEBUG(1,("%s rejected the protocol\n",pserver
));
1615 close(password_client
); password_client
= -1;
1619 if (!(CVAL(inbuf
,smb_vwv1
) & 1)) {
1620 DEBUG(1,("%s isn't in user level security mode\n",pserver
));
1621 close(password_client
); password_client
= -1;
1625 memcpy(buf
,inbuf
,smb_len(inbuf
)+4);
1627 DEBUG(3,("password server OK\n"));
1632 /****************************************************************************
1633 attempted support for server level security
1634 ****************************************************************************/
1635 BOOL
server_validate(char *buf
)
1637 pstring inbuf
,outbuf
;
1640 if (password_client
< 0) {
1641 DEBUG(1,("%s not connected\n",pserver
));
1645 bzero(inbuf
,sizeof(inbuf
));
1646 memcpy(outbuf
,buf
,sizeof(outbuf
));
1648 /* send a session setup command */
1649 CVAL(outbuf
,smb_flg
) = 0x8;
1650 SSVAL(outbuf
,smb_flg2
,0x1);
1651 CVAL(outbuf
,smb_vwv0
) = 0xFF;
1653 set_message(outbuf
,smb_numwords(outbuf
),smb_buflen(outbuf
),False
);
1655 SCVAL(inbuf
,smb_rcls
,1);
1657 send_smb(password_client
,outbuf
);
1658 ret
= receive_smb(password_client
,inbuf
,5000);
1660 if (!ret
|| CVAL(inbuf
,smb_rcls
) != 0) {
1661 DEBUG(1,("password server %s rejected the password\n",pserver
));
1665 /* if logged in as guest then reject */
1666 if ((SVAL(inbuf
,smb_vwv2
) & 1) != 0) {
1667 DEBUG(1,("password server %s gave us guest only\n",pserver
));
1671 DEBUG(3,("password server %s accepted the password\n",pserver
));
1673 #if !KEEP_PASSWORD_SERVER_OPEN
1674 close(password_client
); password_client
= -1;