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]="";
39 /* Data to do lanman1/2 password challenge. */
40 static unsigned char saved_challenge
[8];
41 static BOOL challenge_sent
=False
;
43 /*******************************************************************
44 Get the next challenge value - no repeats.
45 ********************************************************************/
46 void generate_next_challenge(char *challenge
)
48 unsigned char buf
[16];
49 static int counter
= 0;
53 /* get a sort-of random number */
55 v1
= (counter
++) + getpid() + tval
.tv_sec
;
56 v2
= (counter
++) * getpid() + tval
.tv_usec
;
57 SIVAL(challenge
,0,v1
);
58 SIVAL(challenge
,4,v2
);
60 /* mash it up with md4 */
61 mdfour(buf
, (unsigned char *)challenge
, 8);
63 memcpy(saved_challenge
, buf
, 8);
64 memcpy(challenge
,buf
,8);
65 challenge_sent
= True
;
68 /*******************************************************************
69 set the last challenge sent, usually from a password server
70 ********************************************************************/
71 BOOL
set_challenge(char *challenge
)
73 memcpy(saved_challenge
,challenge
,8);
74 challenge_sent
= True
;
78 /*******************************************************************
79 get the last challenge sent
80 ********************************************************************/
81 BOOL
last_challenge(char *challenge
)
83 if (!challenge_sent
) return(False
);
84 memcpy(challenge
,saved_challenge
,8);
88 /* this holds info on user ids that are already validated for this VC */
89 static user_struct
*validated_users
= NULL
;
90 static int num_validated_users
= 0;
92 /****************************************************************************
93 check if a uid has been validated, and return an pointer to the user_struct
94 if it has. NULL if not. vuid is biased by an offset. This allows us to
95 tell random client vuid's (normally zero) from valid vuids.
96 ****************************************************************************/
97 user_struct
*get_valid_user_struct(uint16 vuid
)
99 if(vuid
== UID_FIELD_INVALID
)
102 if((vuid
>= (uint16
)num_validated_users
) ||
103 (validated_users
[vuid
].uid
== -1) || (validated_users
[vuid
].gid
== -1))
105 return &validated_users
[vuid
];
108 /****************************************************************************
110 ****************************************************************************/
111 void invalidate_vuid(uint16 vuid
)
113 user_struct
*vuser
= get_valid_user_struct(vuid
);
119 vuser
->user_ngroups
= 0;
120 if(vuser
->user_groups
&&
121 (vuser
->user_groups
!= (gid_t
*)vuser
->user_igroups
))
122 free(vuser
->user_groups
);
123 vuser
->user_groups
= NULL
;
124 if(vuser
->user_igroups
)
125 free(vuser
->user_igroups
);
126 vuser
->user_igroups
= NULL
;
130 /****************************************************************************
131 return a validated username
132 ****************************************************************************/
133 char *validated_username(uint16 vuid
)
135 user_struct
*vuser
= get_valid_user_struct(vuid
);
141 /****************************************************************************
142 register a uid/name pair as being valid and that a valid password
143 has been given. vuid is biased by an offset. This allows us to
144 tell random client vuid's (normally zero) from valid vuids.
145 ****************************************************************************/
146 uint16
register_vuid(int uid
,int gid
, char *name
,BOOL guest
)
150 #if (defined(NETGROUP) && defined (AUTOMOUNT))
151 int nis_error
; /* returned by yp all functions */
152 char *nis_result
; /* yp_match inits this */
153 int nis_result_len
; /* and set this */
154 char *nis_domain
; /* yp_get_default_domain inits this */
155 char *nis_map
= (char *)lp_nis_home_map_name();
158 struct passwd
*pwfile
; /* for getting real name from passwd file */
163 * After observing MS-Exchange services writing to a Samba share
164 * I belive this code is incorrect. Each service does it's own
165 * sessionsetup_and_X for the same user, and as each service shuts
166 * down, it does a user_logoff_and_X. As we are consolidating multiple
167 * sessionsetup_and_X's onto the same vuid here, when the first service
168 * shuts down, it invalidates all the open files for the other services.
169 * Hence I am removing this code and forcing each sessionsetup_and_X
171 * Jeremy Allison. (jallison@whistle.com).
175 for(i
= 0; i
< num_validated_users
; i
++) {
176 vuser
= &validated_users
[i
];
177 if( vuser
->uid
== uid
)
178 return (uint16
)(i
+ VUID_OFFSET
); /* User already validated */
182 validated_users
= (user_struct
*)Realloc(validated_users
,
184 (num_validated_users
+1));
186 if (!validated_users
)
188 DEBUG(0,("Failed to realloc users struct!\n"));
189 num_validated_users
= 0;
190 return UID_FIELD_INVALID
;
193 vuser
= &validated_users
[num_validated_users
];
194 num_validated_users
++;
198 vuser
->guest
= guest
;
199 strcpy(vuser
->name
,name
);
201 vuser
->user_ngroups
= 0;
202 vuser
->user_groups
= NULL
;
203 vuser
->user_igroups
= NULL
;
205 /* Find all the groups this uid is in and store them.
206 Used by become_user() */
207 setup_groups(name
,uid
,gid
,
208 &vuser
->user_ngroups
,
209 &vuser
->user_igroups
,
210 &vuser
->user_groups
);
212 DEBUG(3,("uid %d registered to name %s\n",uid
,name
));
214 #if (defined(NETGROUP) && defined (AUTOMOUNT))
215 vuser
->home_share
= NULL
;
216 DEBUG(3, ("Setting default HOMESHR to: \\\\logon server\\HOMES\n"));
217 vuser
->home_share
= Realloc(vuser
->home_share
, 32);
218 strcpy(vuser
->home_share
,"\\\\%L\\HOMES");
220 if (nis_error
= yp_get_default_domain(&nis_domain
))
221 DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error
)));
222 DEBUG(3, ("NIS Domain: %s\n", nis_domain
));
224 if (nis_error
= yp_match(nis_domain
, nis_map
, vuser
->name
, strlen(vuser
->name
),
225 &nis_result
, &nis_result_len
))
226 DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error
)));
227 if (!nis_error
&& lp_nis_home_map()) {
228 home_server_len
= strcspn(nis_result
,":");
229 DEBUG(3, ("NIS lookup succeeded\n\tHome server length: %d\n",home_server_len
));
230 vuser
->home_share
= (char *)Realloc(vuser
->home_share
, home_server_len
+12);
231 DEBUG(3, ("\tAllocated %d bytes for HOMESHR\n",home_server_len
+12 ));
232 strcpy(vuser
->home_share
,"\\\\");
233 strncat(vuser
->home_share
, nis_result
, home_server_len
);
234 strcat(vuser
->home_share
,"\\homes");
235 DEBUG(2,("\tUser = %s\n\tUID = %d\n\tNIS result = %s\n\tHOMESHR = %s\n",
236 vuser
->name
, vuser
->uid
, nis_result
, vuser
->home_share
));
240 vuser
->real_name
= NULL
;
241 DEBUG(3, ("Clearing default real name\n"));
242 vuser
->real_name
= Realloc(vuser
->real_name
, 15);
243 strcpy(vuser
->real_name
, "<Full Name>\0");
244 if (lp_unix_realname()) {
245 if((pwfile
=getpwnam(vuser
->name
))!= NULL
)
247 DEBUG(3, ("User name: %s\tReal name: %s\n",vuser
->name
,pwfile
->pw_gecos
));
248 real_name_len
= strcspn(pwfile
->pw_gecos
, ",");
249 DEBUG(3, ("Real name length: %d\n", real_name_len
));
250 vuser
->real_name
= (char *)Realloc(vuser
->real_name
, real_name_len
+1);
251 strncpy(vuser
->real_name
, pwfile
->pw_gecos
, real_name_len
);
252 vuser
->real_name
[real_name_len
]='\0';
256 return (uint16
)((num_validated_users
- 1) + VUID_OFFSET
);
260 /****************************************************************************
261 add a name to the session users list
262 ****************************************************************************/
263 void add_session_user(char *user
)
266 StrnCpy(suser
,user
,sizeof(suser
)-1);
268 if (!Get_Pwnam(suser
,True
)) return;
270 if (suser
&& *suser
&& !in_list(suser
,session_users
,False
))
272 if (strlen(suser
) + strlen(session_users
) + 2 >= sizeof(pstring
))
273 DEBUG(1,("Too many session users??\n"));
276 strcat(session_users
," ");
277 strcat(session_users
,suser
);
284 /* a fake shadow password routine which just fills a fake spwd struct
285 * with the sp_pwdp field. (sreiz@aie.nl)
287 static struct spwd
*getspnam(char *username
) /* fake shadow password routine */
292 static struct spwd static_spwd
;
294 static_spwd
.sp_pwdp
=0;
295 if (!(f
=fopen("/etc/master.passwd", "r")))
297 while (fgets(line
, 1024, f
)) {
298 if (!strncmp(line
, username
, strlen(username
)) &&
299 line
[strlen(username
)]==':') { /* found entry */
302 p
=line
+strlen(username
)+1;
303 if ((q
=strchr(p
, ':'))) {
308 static_spwd
.sp_pwdp
=pw
;
314 if (static_spwd
.sp_pwdp
)
322 /****************************************************************************
323 an enhanced crypt for OSF1
324 ****************************************************************************/
325 static char *osf1_bigcrypt(char *password
,char *salt1
)
327 static char result
[AUTH_MAX_PASSWD_LENGTH
] = "";
332 int parts
= strlen(password
) / AUTH_CLEARTEXT_SEG_CHARS
;
333 if (strlen(password
)%AUTH_CLEARTEXT_SEG_CHARS
)
336 StrnCpy(salt
,salt1
,2);
337 StrnCpy(result
,salt1
,2);
339 for (i
=0; i
<parts
;i
++)
343 StrnCpy(salt
,&result
[2+i
*AUTH_CIPHERTEXT_SEG_CHARS
],2);
344 p2
+= AUTH_CLEARTEXT_SEG_CHARS
;
352 /****************************************************************************
353 update the enhanced security database. Only relevant for OSF1 at the moment.
354 ****************************************************************************/
355 static void update_protected_database( char *user
, BOOL result
)
358 struct pr_passwd
*mypasswd
;
361 mypasswd
= getprpwnam (user
);
362 starttime
= time (NULL
);
366 mypasswd
->ufld
.fd_slogin
= starttime
;
367 mypasswd
->ufld
.fd_nlogins
= 0;
369 putprpwnam(user
,mypasswd
);
371 DEBUG(3,("Update protected database for Account %s after succesful connection\n",user
));
375 mypasswd
->ufld
.fd_ulogin
= starttime
;
376 mypasswd
->ufld
.fd_nlogins
= mypasswd
->ufld
.fd_nlogins
+ 1;
377 if ( mypasswd
->ufld
.fd_max_tries
!= 0 && mypasswd
->ufld
.fd_nlogins
> mypasswd
->ufld
.fd_max_tries
)
379 mypasswd
->uflg
.fg_lock
= 0;
380 DEBUG(3,("Account is disabled -- see Account Administrator.\n"));
382 putprpwnam ( user
, mypasswd
);
383 DEBUG(3,("Update protected database for Account %s after refusing connection\n",user
));
386 DEBUG(6,("Updated database with %s %s\n",user
,BOOLSTR(result
)));
392 /*******************************************************************
393 check on PAM authentication
394 ********************************************************************/
396 /* We first need some helper functions */
397 #include <security/pam_appl.h>
398 /* Static variables used to communicate between the conversation function
399 * and the server_login function
401 static char *PAM_username
;
402 static char *PAM_password
;
404 /* PAM conversation function
405 * Here we assume (for now, at least) that echo on means login name, and
406 * echo off means password.
408 static int PAM_conv (int num_msg
,
409 struct pam_message
**msg
,
410 struct pam_response
**resp
,
412 int count
= 0, replies
= 0;
413 struct pam_response
*reply
= NULL
;
414 int size
= sizeof(struct pam_response
);
416 #define GET_MEM if (reply) realloc(reply, size); else reply = malloc(size); \
417 if (!reply) return PAM_CONV_ERR; \
418 size += sizeof(struct pam_response)
419 #define COPY_STRING(s) (s) ? strdup(s) : NULL
421 for (count
= 0; count
< num_msg
; count
++) {
422 switch (msg
[count
]->msg_style
) {
423 case PAM_PROMPT_ECHO_ON
:
425 reply
[replies
].resp_retcode
= PAM_SUCCESS
;
426 reply
[replies
++].resp
= COPY_STRING(PAM_username
);
429 case PAM_PROMPT_ECHO_OFF
:
431 reply
[replies
].resp_retcode
= PAM_SUCCESS
;
432 reply
[replies
++].resp
= COPY_STRING(PAM_password
);
440 /* Must be an error of some sort... */
445 if (reply
) *resp
= reply
;
448 static struct pam_conv PAM_conversation
= {
454 static BOOL
pam_auth(char *this_user
,char *password
)
459 /* Now use PAM to do authentication. For now, we won't worry about
460 * session logging, only authentication. Bail out if there are any
461 * errors. Since this is a limited protocol, and an even more limited
462 * function within a server speaking this protocol, we can't be as
463 * verbose as would otherwise make sense.
464 * Query: should we be using PAM_SILENT to shut PAM up?
466 #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
467 pam_end(pamh, 0); return False; \
469 PAM_password
= password
;
470 PAM_username
= this_user
;
471 pam_error
= pam_start("samba", this_user
, &PAM_conversation
, &pamh
);
473 pam_error
= pam_authenticate(pamh
, 0);
475 /* It is not clear to me that account management is the right thing
476 * to do, but it is not clear that it isn't, either. This can be
477 * removed if no account management should be done. Alternately,
478 * put a pam_allow.so entry in /etc/pam.conf for account handling. */
479 pam_error
= pam_acct_mgmt(pamh
, 0);
481 pam_end(pamh
, PAM_SUCCESS
);
482 /* If this point is reached, the user has been authenticated. */
489 /*******************************************************************
490 check on AFS authentication
491 ********************************************************************/
492 static BOOL
afs_auth(char *this_user
,char *password
)
494 long password_expires
= 0;
497 /* For versions of AFS prior to 3.3, this routine has few arguments, */
498 /* but since I can't find the old documentation... :-) */
500 if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION
+KA_USERAUTH_DOSETPAG
,
502 (char *) 0, /* instance */
503 (char *) 0, /* cell */
505 0, /* lifetime, default */
506 &password_expires
, /*days 'til it expires */
517 sec_login_handle_t my_dce_sec_context
;
518 int dcelogin_atmost_once
= 0;
520 /*******************************************************************
521 check on a DCE/DFS authentication
522 ********************************************************************/
523 static BOOL
dfs_auth(char *this_user
,char *password
)
528 boolean32 password_reset
;
529 sec_passwd_rec_t my_dce_password
;
530 sec_login_auth_src_t auth_src
= sec_login_auth_src_network
;
531 unsigned char dce_errstr
[dce_c_error_string_len
];
534 * We only go for a DCE login context if the given password
535 * matches that stored in the local password file..
536 * Assumes local passwd file is kept in sync w/ DCE RGY!
539 if (!strcmp((char *)crypt(password
,this_salt
),this_crypted
) ||
540 dcelogin_atmost_once
)
543 if (sec_login_setup_identity(
544 (unsigned char *)this_user
,
549 dce_error_inq_text(err
, dce_errstr
, &err2
);
550 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
551 this_user
,dce_errstr
));
555 my_dce_password
.version_number
= sec_passwd_c_version_none
;
556 my_dce_password
.pepper
= NULL
;
557 my_dce_password
.key
.key_type
= sec_passwd_plain
;
558 my_dce_password
.key
.tagged_union
.plain
= (idl_char
*)password
;
560 if (sec_login_valid_and_cert_ident(my_dce_sec_context
,
566 dce_error_inq_text(err
, dce_errstr
, &err2
);
567 DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
568 this_user
,dce_errstr
));
573 sec_login_set_context(my_dce_sec_context
, &err
);
574 if (err
!= error_status_ok
)
576 dce_error_inq_text(err
, dce_errstr
, &err2
);
577 DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
578 this_user
,dce_errstr
));
579 sec_login_purge_context(my_dce_sec_context
, &err
);
584 DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
585 this_user
, getpid()));
588 dcelogin_atmost_once
= 1;
592 void dfs_unlogin(void)
596 unsigned char dce_errstr
[dce_c_error_string_len
];
598 sec_login_purge_context(my_dce_sec_context
, &err
);
599 if (err
!= error_status_ok
)
601 dce_error_inq_text(err
, dce_errstr
, &err2
);
602 DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
603 getpid(), dce_errstr
));
610 /*******************************************************************
611 check on Kerberos authentication
612 ********************************************************************/
613 static BOOL
krb5_auth(char *this_user
,char *password
)
615 krb5_data tgtname
= {
620 krb5_context kcontext
;
621 krb5_principal kprinc
;
622 krb5_principal server
;
625 krb5_address
**addrs
= (krb5_address
**)0;
626 krb5_preauthtype
*preauth
= NULL
;
627 krb5_keytab keytab
= NULL
;
629 krb5_ccache ccache
= NULL
;
633 if ( retval
=krb5_init_context(&kcontext
))
638 if ( retval
= krb5_timeofday(kcontext
, &now
) )
643 if ( retval
= krb5_cc_default(kcontext
, &ccache
) )
648 if ( retval
= krb5_parse_name(kcontext
, this_user
, &kprinc
) )
653 memset((char *)&kcreds
, 0, sizeof(kcreds
));
655 kcreds
.client
= kprinc
;
657 if ((retval
= krb5_build_principal_ext(kcontext
, &server
,
658 krb5_princ_realm(kcontext
, kprinc
)->length
,
659 krb5_princ_realm(kcontext
, kprinc
)->data
,
662 krb5_princ_realm(kcontext
, kprinc
)->length
,
663 krb5_princ_realm(kcontext
, kprinc
)->data
,
669 kcreds
.server
= server
;
671 retval
= krb5_get_in_tkt_with_password(kcontext
,
688 #endif /* KRB5_AUTH */
690 #ifdef LINUX_BIGCRYPT
691 /****************************************************************************
692 an enhanced crypt for Linux to handle password longer than 8 characters
693 ****************************************************************************/
694 static int linux_bigcrypt(char *password
,char *salt1
, char *crypted
)
696 #define LINUX_PASSWORD_SEG_CHARS 8
700 StrnCpy(salt
,salt1
,2);
703 for ( i
=strlen(password
); i
> 0; i
-= LINUX_PASSWORD_SEG_CHARS
) {
704 char * p
= crypt(password
,salt
) + 2;
705 if(strncmp(p
, crypted
, LINUX_PASSWORD_SEG_CHARS
) != 0)
707 password
+= LINUX_PASSWORD_SEG_CHARS
;
708 crypted
+= strlen(p
);
716 /****************************************************************************
717 apply a function to upper/lower case combinations
718 of a string and return true if one of them returns true.
719 try all combinations with N uppercase letters.
720 offset is the first char to try and change (start with 0)
721 it assumes the string starts lowercased
722 ****************************************************************************/
723 static BOOL
string_combinations2(char *s
,int offset
,BOOL (*fn
)(),int N
)
728 #ifdef PASSWORD_LENGTH
729 len
= MIN(len
,PASSWORD_LENGTH
);
732 if (N
<= 0 || offset
>= len
)
735 for (i
=offset
;i
<(len
-(N
-1));i
++)
738 if (!islower(c
)) continue;
740 if (string_combinations2(s
,i
+1,fn
,N
-1))
747 /****************************************************************************
748 apply a function to upper/lower case combinations
749 of a string and return true if one of them returns true.
750 try all combinations with up to N uppercase letters.
751 offset is the first char to try and change (start with 0)
752 it assumes the string starts lowercased
753 ****************************************************************************/
754 static BOOL
string_combinations(char *s
,BOOL (*fn
)(),int N
)
758 if (string_combinations2(s
,0,fn
,n
)) return(True
);
764 /****************************************************************************
765 core of password checking routine
766 ****************************************************************************/
767 BOOL
password_check(char *password
)
771 /* This falls through if the password check fails
772 - if NO_CRYPT is defined this causes an error msg
773 saying Warning - no crypt available
774 - if NO_CRYPT is NOT defined this is a potential security hole
775 as it may authenticate via the crypt call when PAM
776 settings say it should fail.
777 if (pam_auth(this_user,password)) return(True);
778 Hence we make a direct return to avoid a second chance!!!
780 return (pam_auth(this_user
,password
));
784 if (afs_auth(this_user
,password
)) return(True
);
788 if (dfs_auth(this_user
,password
)) return(True
);
792 if (krb5_auth(this_user
,password
)) return(True
);
796 if (pwdauth(this_user
,password
) == 0)
801 return(strcmp(osf1_bigcrypt(password
,this_salt
),this_crypted
) == 0);
805 return (strcmp((char *)crypt16(password
, this_salt
),this_crypted
) == 0);
808 #ifdef LINUX_BIGCRYPT
809 return(linux_bigcrypt(password
,this_salt
,this_crypted
));
813 DEBUG(1,("Warning - no crypt available\n"));
816 return(strcmp((char *)crypt(password
,this_salt
),this_crypted
) == 0);
820 /****************************************************************************
821 core of smb password checking routine.
822 ****************************************************************************/
823 BOOL
smb_password_check(char *password
, unsigned char *part_passwd
, unsigned char *c8
)
825 /* Finish the encryption of part_passwd. */
826 unsigned char p21
[21];
827 unsigned char p24
[24];
829 if(part_passwd
== NULL
)
830 DEBUG(10,("No password set - allowing access\n"));
831 /* No password set - always true ! */
832 if(part_passwd
== NULL
)
836 memcpy(p21
,part_passwd
,16);
841 DEBUG(100,("Part password (P16) was |"));
842 for(i
= 0; i
< 16; i
++)
843 DEBUG(100,("%X ", (unsigned char)part_passwd
[i
]));
845 DEBUG(100,("Password from client was |"));
846 for(i
= 0; i
< 24; i
++)
847 DEBUG(100,("%X ", (unsigned char)password
[i
]));
849 DEBUG(100,("Given challenge was |"));
850 for(i
= 0; i
< 8; i
++)
851 DEBUG(100,("%X ", (unsigned char)c8
[i
]));
853 DEBUG(100,("Value from encryption was |"));
854 for(i
= 0; i
< 24; i
++)
855 DEBUG(100,("%X ", (unsigned char)p24
[i
]));
859 return (memcmp(p24
, password
, 24) == 0);
862 /****************************************************************************
863 check if a username/password is OK
864 ****************************************************************************/
865 BOOL
password_ok(char *user
,char *password
, int pwlen
, struct passwd
*pwd
)
868 int level
= lp_passwordlevel();
871 struct smb_passwd
*smb_pass
;
872 BOOL challenge_done
= False
;
874 if (password
) password
[pwlen
] = 0;
877 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
]));
888 DEBUG(100,("checking user=[%s] pass=[%s]\n",user
,password
));
895 if (((!*password
) || (!pwlen
)) && !lp_null_passwords())
900 pass
= (struct passwd
*) pwd
;
901 user
= pass
->pw_name
;
904 pass
= Get_Pwnam(user
,True
);
906 DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen
, challenge_done
));
908 if((pwlen
== 24) && challenge_done
)
910 DEBUG(4,("Checking SMB password for user %s (l=24)\n",user
));
914 DEBUG(3,("Couldn't find user %s\n",user
));
918 smb_pass
= get_smbpwnam(user
);
921 DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user
));
925 /* Ensure the uid's match */
926 if(smb_pass
->smb_userid
!= pass
->pw_uid
)
928 DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
932 if(Protocol
>= PROTOCOL_NT1
)
934 /* We have the NT MD4 hash challenge available - see if we can
935 use it (ie. does it exist in the smbpasswd file).
937 if(smb_pass
->smb_nt_passwd
!= NULL
)
939 DEBUG(4,("Checking NT MD4 password\n"));
940 if(smb_password_check(password
,
941 smb_pass
->smb_nt_passwd
,
942 (unsigned char *)challenge
))
944 update_protected_database(user
,True
);
947 DEBUG(4,("NT MD4 password check failed\n"));
951 /* Try against the lanman password */
953 if (smb_password_check(password
,
954 smb_pass
->smb_passwd
,
955 (unsigned char *)challenge
)) {
956 update_protected_database(user
,True
);
960 DEBUG(3,("Error smb_password_check failed\n"));
963 DEBUG(4,("Checking password for user %s (l=%d)\n",user
,pwlen
));
967 DEBUG(3,("Couldn't find user %s\n",user
));
975 /* many shadow systems require you to be root to get the password,
976 in most cases this should already be the case when this
977 function is called, except perhaps for IPC password changing
980 spass
= getspnam(pass
->pw_name
);
981 if (spass
&& spass
->sp_pwdp
)
982 pass
->pw_passwd
= spass
->sp_pwdp
;
984 #elif defined(IA_UINFO)
986 /* Need to get password with SVR4.2's ia_ functions instead of
987 get{sp,pw}ent functions. Required by UnixWare 2.x, tested on
988 version 2.1. (tangent@cyberport.com) */
990 if (ia_openinfo(pass
->pw_name
, &uinfo
) != -1)
991 ia_get_logpwd(uinfo
, &(pass
->pw_passwd
));
997 struct pr_passwd
*pr_pw
= getprpwnam(pass
->pw_name
);
998 if (pr_pw
&& pr_pw
->ufld
.fd_encrypt
)
999 pass
->pw_passwd
= pr_pw
->ufld
.fd_encrypt
;
1003 #ifdef HPUX_10_TRUSTED
1005 struct pr_passwd
*pr_pw
= getprpwnam(pass
->pw_name
);
1006 if (pr_pw
&& pr_pw
->ufld
.fd_encrypt
)
1007 pass
->pw_passwd
= pr_pw
->ufld
.fd_encrypt
;
1013 struct pr_passwd
*mypasswd
;
1014 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user
));
1015 mypasswd
= getprpwnam (user
);
1018 strcpy(pass
->pw_name
,mypasswd
->ufld
.fd_name
);
1019 strcpy(pass
->pw_passwd
,mypasswd
->ufld
.fd_encrypt
);
1023 DEBUG(5,("No entry for user %s in protected database !\n",user
));
1031 AUTHORIZATION
*ap
= getauthuid( pass
->pw_uid
);
1034 strcpy( pass
->pw_passwd
, ap
->a_password
);
1040 /* extract relevant info */
1041 strcpy(this_user
,pass
->pw_name
);
1042 strcpy(this_salt
,pass
->pw_passwd
);
1043 strcpy(this_crypted
,pass
->pw_passwd
);
1045 if (!*this_crypted
) {
1046 if (!lp_null_passwords()) {
1047 DEBUG(2,("Disallowing access to %s due to null password\n",this_user
));
1052 DEBUG(3,("Allowing access to %s with null password\n",this_user
));
1058 /* try it as it came to us */
1059 if (password_check(password
))
1061 update_protected_database(user
,True
);
1065 /* if the password was given to us with mixed case then we don't
1066 need to proceed as we know it hasn't been case modified by the
1068 if (strhasupper(password
) && strhaslower(password
))
1071 /* make a copy of it */
1072 StrnCpy(pass2
,password
,sizeof(pstring
)-1);
1074 /* try all lowercase */
1076 if (password_check(password
))
1078 update_protected_database(user
,True
);
1085 update_protected_database(user
,False
);
1088 strcpy(password
,pass2
);
1093 /* last chance - all combinations of up to level chars upper! */
1096 if (string_combinations(password
,password_check
,level
))
1098 update_protected_database(user
,True
);
1102 update_protected_database(user
,False
);
1105 strcpy(password
,pass2
);
1112 /****************************************************************************
1113 check if a username is valid
1114 ****************************************************************************/
1115 BOOL
user_ok(char *user
,int snum
)
1117 pstring valid
, invalid
;
1120 StrnCpy(valid
, lp_valid_users(snum
), sizeof(pstring
));
1121 StrnCpy(invalid
, lp_invalid_users(snum
), sizeof(pstring
));
1123 string_sub(valid
,"%S",lp_servicename(snum
));
1124 string_sub(invalid
,"%S",lp_servicename(snum
));
1126 ret
= !user_in_list(user
,invalid
);
1128 if (ret
&& valid
&& *valid
)
1129 ret
= user_in_list(user
,valid
);
1131 if (ret
&& lp_onlyuser(snum
)) {
1132 char *user_list
= lp_username(snum
);
1133 string_sub(user_list
,"%S",lp_servicename(snum
));
1134 ret
= user_in_list(user
,user_list
);
1143 /****************************************************************************
1144 validate a group username entry. Return the username or NULL
1145 ****************************************************************************/
1146 static char *validate_group(char *group
,char *password
,int pwlen
,int snum
)
1150 char *host
, *user
, *domain
;
1152 while (getnetgrent(&host
, &user
, &domain
)) {
1154 if (user_ok(user
, snum
) &&
1155 password_ok(user
,password
,pwlen
,NULL
)) {
1167 struct group
*gptr
= (struct group
*)getgrnam(group
);
1171 member
= gptr
->gr_mem
;
1172 while (member
&& *member
)
1174 static fstring name
;
1175 strcpy(name
,*member
);
1176 if (user_ok(name
,snum
) &&
1177 password_ok(name
,password
,pwlen
,NULL
))
1181 #ifdef GROUP_CHECK_PWENT
1187 while (pwd
= getpwent ()) {
1188 if (*(pwd
->pw_passwd
) && pwd
->pw_gid
== gptr
->gr_gid
) {
1189 /* This Entry have PASSWORD and same GID then check pwd */
1190 if (password_ok(NULL
, password
, pwlen
, pwd
)) {
1191 strcpy(tm
, pwd
->pw_name
);
1199 #endif /* GROUP_CHECK_PWENT */
1208 /****************************************************************************
1209 check for authority to login to a service with a given username/password
1210 ****************************************************************************/
1211 BOOL
authorise_login(int snum
,char *user
,char *password
, int pwlen
,
1212 BOOL
*guest
,BOOL
*force
,uint16 vuid
)
1219 DEBUG(100,("checking authorisation on user=%s pass=%s\n",user
,password
));
1222 /* there are several possibilities:
1223 1) login as the given user with given password
1224 2) login as a previously registered username with the given password
1225 3) login as a session list username with the given password
1226 4) login as a previously validated user/password pair
1227 5) login as the "user =" user with given password
1228 6) login as the "user =" user with no password (guest connection)
1229 7) login as guest user with no password
1231 if the service is guest_only then steps 1 to 5 are skipped
1234 if (GUEST_ONLY(snum
)) *force
= True
;
1236 if (!(GUEST_ONLY(snum
) && GUEST_OK(snum
)))
1239 user_struct
*vuser
= get_valid_user_struct(vuid
);
1241 /* check the given username and password */
1242 if (!ok
&& (*user
) && user_ok(user
,snum
)) {
1243 ok
= password_ok(user
,password
, pwlen
, NULL
);
1244 if (ok
) DEBUG(3,("ACCEPTED: given username password ok\n"));
1247 /* check for a previously registered guest username */
1248 if (!ok
&& (vuser
!= 0) && vuser
->guest
) {
1249 if (user_ok(vuser
->name
,snum
) &&
1250 password_ok(vuser
->name
, password
, pwlen
, NULL
)) {
1251 strcpy(user
, vuser
->name
);
1252 vuser
->guest
= False
;
1253 DEBUG(3,("ACCEPTED: given password with registered user %s\n", user
));
1259 /* now check the list of session users */
1263 char *user_list
= strdup(session_users
);
1264 if (!user_list
) return(False
);
1266 for (auser
=strtok(user_list
,LIST_SEP
);
1268 auser
= strtok(NULL
,LIST_SEP
))
1271 strcpy(user2
,auser
);
1272 if (!user_ok(user2
,snum
)) continue;
1274 if (password_ok(user2
,password
, pwlen
, NULL
)) {
1277 DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
1283 /* check for a previously validated username/password pair */
1284 if (!ok
&& !lp_revalidate(snum
) &&
1285 (vuser
!= 0) && !vuser
->guest
&&
1286 user_ok(vuser
->name
,snum
)) {
1287 strcpy(user
,vuser
->name
);
1289 DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
1293 /* check for a rhosts entry */
1294 if (!ok
&& user_ok(user
,snum
) && check_hosts_equiv(user
)) {
1296 DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
1299 /* check the user= fields and the given password */
1300 if (!ok
&& lp_username(snum
)) {
1303 StrnCpy(user_list
,lp_username(snum
),sizeof(pstring
));
1305 string_sub(user_list
,"%S",lp_servicename(snum
));
1307 for (auser
=strtok(user_list
,LIST_SEP
);
1309 auser
= strtok(NULL
,LIST_SEP
))
1313 auser
= validate_group(auser
+1,password
,pwlen
,snum
);
1318 DEBUG(3,("ACCEPTED: group username and given password ok\n"));
1324 strcpy(user2
,auser
);
1325 if (user_ok(user2
,snum
) &&
1326 password_ok(user2
,password
,pwlen
,NULL
))
1330 DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
1335 } /* not guest only */
1337 /* check for a normal guest connection */
1338 if (!ok
&& GUEST_OK(snum
))
1341 StrnCpy(guestname
,lp_guestaccount(snum
),sizeof(guestname
)-1);
1342 if (Get_Pwnam(guestname
,True
))
1344 strcpy(user
,guestname
);
1346 DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
1349 DEBUG(0,("Invalid guest account %s??\n",guestname
));
1354 if (ok
&& !user_ok(user
,snum
))
1356 DEBUG(0,("rejected invalid user %s\n",user
));
1364 /****************************************************************************
1365 read the a hosts.equiv or .rhosts file and check if it
1366 allows this user from this machine
1367 ****************************************************************************/
1368 static BOOL
check_user_equiv(char *user
, char *remote
, char *equiv_file
)
1371 int plus_allowed
= 1;
1374 FILE *fp
= fopen(equiv_file
, "r");
1375 DEBUG(5, ("check_user_equiv %s %s %s\n", user
, remote
, equiv_file
));
1376 if (! fp
) return False
;
1377 while(fgets(buf
, sizeof(buf
), fp
))
1379 trim_string(buf
," "," ");
1381 if (buf
[0] != '#' && buf
[0] != '\n')
1383 BOOL is_group
= False
;
1386 if (strcmp(buf
, "NO_PLUS\n") == 0)
1388 DEBUG(6, ("check_user_equiv NO_PLUS\n"));
1395 if (*bp
== '\n' && plus_allowed
)
1397 /* a bare plus means everbody allowed */
1398 DEBUG(6, ("check_user_equiv everybody allowed\n"));
1403 else if (buf
[0] == '-')
1413 file_host
= strtok(bp
, " \t\n");
1414 file_user
= strtok(NULL
, " \t\n");
1415 DEBUG(7, ("check_user_equiv %s %s\n", file_host
? file_host
: "(null)",
1416 file_user
? file_user
: "(null)" ));
1417 if (file_host
&& *file_host
)
1419 BOOL host_ok
= False
;
1424 static char *mydomain
= NULL
;
1426 yp_get_default_domain(&mydomain
);
1427 if (mydomain
&& innetgr(file_host
,remote
,user
,mydomain
))
1433 DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n"));
1438 /* is it this host */
1439 /* the fact that remote has come from a call of gethostbyaddr
1440 * means that it may have the fully qualified domain name
1441 * so we could look up the file version to get it into
1442 * a canonical form, but I would rather just type it
1443 * in full in the equiv file
1445 if (!host_ok
&& !is_group
&& strequal(remote
, file_host
))
1451 /* is it this user */
1452 if (file_user
== 0 || strequal(user
, file_user
))
1455 DEBUG(5, ("check_user_equiv matched %s%s %s\n",
1456 (plus
? "+" : "-"), file_host
,
1457 (file_user
? file_user
: "")));
1458 return (plus
? True
: False
);
1469 /****************************************************************************
1470 check for a possible hosts equiv or rhosts entry for the user
1471 ****************************************************************************/
1472 BOOL
check_hosts_equiv(char *user
)
1476 struct passwd
*pass
= Get_Pwnam(user
,True
);
1481 fname
= lp_hosts_equiv();
1483 /* note: don't allow hosts.equiv on root */
1484 if (fname
&& *fname
&& (pass
->pw_uid
!= 0))
1486 if (check_user_equiv(user
,client_name(),fname
))
1490 if (lp_use_rhosts())
1492 char *home
= get_home_dir(user
);
1495 sprintf(rhostsfile
, "%s/.rhosts", home
);
1496 if (check_user_equiv(user
,client_name(),rhostsfile
))
1505 int password_client
= -1;
1506 static fstring pserver
;
1507 static char *secserver_inbuf
= NULL
;
1509 /****************************************************************************
1510 attempted support for server level security
1511 ****************************************************************************/
1512 BOOL
server_cryptkey(char *buf
)
1515 fstring pass_protocol
;
1516 extern fstring remote_machine
;
1520 struct in_addr dest_ip
;
1521 int port
= SMB_PORT
;
1524 if(secserver_inbuf
== NULL
) {
1525 secserver_inbuf
= (char *)malloc(BUFFER_SIZE
+ SAFETY_MARGIN
);
1526 if(secserver_inbuf
== NULL
) {
1527 DEBUG(0,("server_cryptkey: malloc fail for input buffer.\n"));
1532 if (password_client
>= 0)
1533 close(password_client
);
1534 password_client
= -1;
1536 if (Protocol
< PROTOCOL_NT1
) {
1537 strcpy(pass_protocol
,"LM1.2X002");
1539 strcpy(pass_protocol
,"NT LM 0.12");
1542 bzero(secserver_inbuf
,BUFFER_SIZE
+ SAFETY_MARGIN
);
1543 bzero(outbuf
,sizeof(outbuf
));
1545 for (p
=strtok(lp_passwordserver(),LIST_SEP
); p
; p
= strtok(NULL
,LIST_SEP
)) {
1547 standard_sub_basic(desthost
);
1550 dest_ip
= *interpret_addr2(desthost
);
1551 if (zero_ip(dest_ip
)) {
1552 DEBUG(1,("Can't resolve address for %s\n",p
));
1556 if (ismyip(dest_ip
)) {
1557 DEBUG(1,("Password server loop - disabling password server %s\n",p
));
1561 password_client
= open_socket_out(SOCK_STREAM
, &dest_ip
, port
, SHORT_CONNECT_TIMEOUT
);
1562 if (password_client
>= 0) {
1563 DEBUG(3,("connected to password server %s\n",p
));
1564 StrnCpy(pserver
,p
,sizeof(pserver
)-1);
1569 if (password_client
< 0) {
1570 DEBUG(1,("password server not available\n"));
1575 /* send a session request (RFC 8002) */
1577 /* put in the destination name */
1580 name_mangle(desthost
,p
,' ');
1585 /* Fix from Frank Varnavas <varnavas@ny.ubs.com>.
1586 We cannot use the same name as the client to
1587 the NT password server, as NT will drop client
1588 connections if the same client name connects
1589 twice. Instead, synthesize a name from our pid.
1590 and the remote machine name.
1593 char buf2
[32]; /* create name as PIDname */
1594 sprintf(buf2
,"%d", getpid());
1595 strncpy(&buf2
[strlen(buf2
)], remote_machine
, 31 - strlen(buf2
));
1597 DEBUG(1,("negprot w/password server as %s\n",buf2
));
1598 name_mangle(buf2
,p
,' ');
1602 _smb_setlen(outbuf
,len
);
1603 CVAL(outbuf
,0) = 0x81;
1605 send_smb(password_client
,outbuf
);
1608 if (!receive_smb(password_client
,secserver_inbuf
,5000) ||
1609 CVAL(secserver_inbuf
,0) != 0x82) {
1610 DEBUG(1,("%s rejected the session\n",pserver
));
1611 close(password_client
); password_client
= -1;
1615 DEBUG(3,("got session\n"));
1617 bzero(outbuf
,smb_size
);
1619 /* setup the protocol string */
1620 set_message(outbuf
,0,strlen(pass_protocol
)+2,True
);
1621 p
= smb_buf(outbuf
);
1623 strcpy(p
,pass_protocol
);
1625 CVAL(outbuf
,smb_com
) = SMBnegprot
;
1626 CVAL(outbuf
,smb_flg
) = 0x8;
1627 SSVAL(outbuf
,smb_flg2
,0x1);
1629 send_smb(password_client
,outbuf
);
1630 ret
= receive_smb(password_client
,secserver_inbuf
,5000);
1632 if (!ret
|| CVAL(secserver_inbuf
,smb_rcls
) || SVAL(secserver_inbuf
,smb_vwv0
)) {
1633 DEBUG(1,("%s rejected the protocol\n",pserver
));
1634 close(password_client
); password_client
= -1;
1638 if (!(CVAL(secserver_inbuf
,smb_vwv1
) & 1)) {
1639 DEBUG(1,("%s isn't in user level security mode\n",pserver
));
1640 close(password_client
); password_client
= -1;
1644 memcpy(buf
,secserver_inbuf
,smb_len(secserver_inbuf
)+4);
1646 DEBUG(3,("password server OK\n"));
1651 /****************************************************************************
1652 attempted support for server level security
1653 ****************************************************************************/
1654 BOOL
server_validate(char *buf
)
1659 if(secserver_inbuf
== NULL
) {
1660 secserver_inbuf
= (char *)malloc(BUFFER_SIZE
+ SAFETY_MARGIN
);
1661 if(secserver_inbuf
== NULL
) {
1662 DEBUG(0,("server_validate: malloc fail for input buffer.\n"));
1667 if (password_client
< 0) {
1668 DEBUG(1,("%s not connected\n",pserver
));
1672 bzero(secserver_inbuf
,BUFFER_SIZE
+ SAFETY_MARGIN
);
1673 memcpy(outbuf
,buf
,sizeof(outbuf
));
1675 /* send a session setup command */
1676 CVAL(outbuf
,smb_flg
) = 0x8;
1677 SSVAL(outbuf
,smb_flg2
,0x1);
1678 CVAL(outbuf
,smb_vwv0
) = 0xFF;
1680 set_message(outbuf
,smb_numwords(outbuf
),smb_buflen(outbuf
),False
);
1682 SCVAL(secserver_inbuf
,smb_rcls
,1);
1684 send_smb(password_client
,outbuf
);
1685 ret
= receive_smb(password_client
,secserver_inbuf
,5000);
1687 if (!ret
|| CVAL(secserver_inbuf
,smb_rcls
) != 0) {
1688 DEBUG(1,("password server %s rejected the password\n",pserver
));
1692 /* if logged in as guest then reject */
1693 if ((SVAL(secserver_inbuf
,smb_vwv2
) & 1) != 0) {
1694 DEBUG(1,("password server %s gave us guest only\n",pserver
));
1698 DEBUG(3,("password server %s accepted the password\n",pserver
));
1700 #if !KEEP_PASSWORD_SERVER_OPEN
1701 close(password_client
); password_client
= -1;