2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1992-1998
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.
22 /* this module is for checking a username/password against a system
23 password database. The SMB encrypted password support is elsewhere */
27 extern int DEBUGLEVEL
;
29 /* these are kept here to keep the string_combinations function simple */
30 static char this_user
[100]="";
31 static char this_salt
[100]="";
32 static char this_crypted
[100]="";
36 /*******************************************************************
37 check on PAM authentication
38 ********************************************************************/
40 /* We first need some helper functions */
41 #include <security/pam_appl.h>
42 /* Static variables used to communicate between the conversation function
43 * and the server_login function
45 static char *PAM_username
;
46 static char *PAM_password
;
48 /* PAM conversation function
49 * Here we assume (for now, at least) that echo on means login name, and
50 * echo off means password.
52 static int PAM_conv (int num_msg
,
53 const struct pam_message
**msg
,
54 struct pam_response
**resp
,
57 struct pam_response
*reply
= NULL
;
59 #define COPY_STRING(s) (s) ? strdup(s) : NULL
61 reply
= malloc(sizeof(struct pam_response
) * num_msg
);
62 if (!reply
) return PAM_CONV_ERR
;
64 for (replies
= 0; replies
< num_msg
; replies
++) {
65 switch (msg
[replies
]->msg_style
) {
66 case PAM_PROMPT_ECHO_ON
:
67 reply
[replies
].resp_retcode
= PAM_SUCCESS
;
68 reply
[replies
].resp
= COPY_STRING(PAM_username
);
71 case PAM_PROMPT_ECHO_OFF
:
72 reply
[replies
].resp_retcode
= PAM_SUCCESS
;
73 reply
[replies
].resp
= COPY_STRING(PAM_password
);
80 reply
[replies
].resp_retcode
= PAM_SUCCESS
;
81 reply
[replies
].resp
= NULL
;
84 /* Must be an error of some sort... */
89 if (reply
) *resp
= reply
;
92 static struct pam_conv PAM_conversation
= {
98 static BOOL
pam_auth(char *user
,char *password
)
103 /* Now use PAM to do authentication. For now, we won't worry about
104 * session logging, only authentication. Bail out if there are any
105 * errors. Since this is a limited protocol, and an even more limited
106 * function within a server speaking this protocol, we can't be as
107 * verbose as would otherwise make sense.
108 * Query: should we be using PAM_SILENT to shut PAM up?
110 #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
111 pam_end(pamh, 0); return False; \
113 PAM_password
= password
;
115 pam_error
= pam_start("samba", user
, &PAM_conversation
, &pamh
);
117 /* Setting PAM_SILENT stops generation of error messages to syslog
118 * to enable debugging on Red Hat Linux set:
120 * auth required /lib/security/pam_pwdb.so nullok shadow audit
121 * _OR_ change PAM_SILENT to 0 to force detailed reporting (logging)
123 pam_error
= pam_authenticate(pamh
, PAM_SILENT
);
125 /* It is not clear to me that account management is the right thing
126 * to do, but it is not clear that it isn't, either. This can be
127 * removed if no account management should be done. Alternately,
128 * put a pam_allow.so entry in /etc/pam.conf for account handling. */
129 pam_error
= pam_acct_mgmt(pamh
, PAM_SILENT
);
131 pam_end(pamh
, PAM_SUCCESS
);
132 /* If this point is reached, the user has been authenticated. */
139 /*******************************************************************
140 check on AFS authentication
141 ********************************************************************/
142 static BOOL
afs_auth(char *user
,char *password
)
144 long password_expires
= 0;
147 /* For versions of AFS prior to 3.3, this routine has few arguments, */
148 /* but since I can't find the old documentation... :-) */
150 if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION
+KA_USERAUTH_DOSETPAG
,
152 (char *) 0, /* instance */
153 (char *) 0, /* cell */
155 0, /* lifetime, default */
156 &password_expires
, /*days 'til it expires */
168 /*****************************************************************
169 This new version of the DFS_AUTH code was donated by Karsten Muuss
170 <muuss@or.uni-bonn.de>. It fixes the following problems with the
173 - Server credentials may expire
174 - Client credential cache files have wrong owner
175 - purge_context() function is called with invalid argument
177 This new code was modified to ensure that on exit the uid/gid is
178 still root, and the original directory is restored. JRA.
179 ******************************************************************/
181 sec_login_handle_t my_dce_sec_context
;
182 int dcelogin_atmost_once
= 0;
184 /*******************************************************************
185 check on a DCE/DFS authentication
186 ********************************************************************/
187 static BOOL
dfs_auth(char *user
,char *password
)
192 signed32 expire_time
, current_time
;
193 boolean32 password_reset
;
195 sec_passwd_rec_t passwd_rec
;
196 sec_login_auth_src_t auth_src
= sec_login_auth_src_network
;
197 unsigned char dce_errstr
[dce_c_error_string_len
];
199 if (dcelogin_atmost_once
) return(False
);
203 * We only go for a DCE login context if the given password
204 * matches that stored in the local password file..
205 * Assumes local passwd file is kept in sync w/ DCE RGY!
208 if (strcmp((char *)crypt(password
,this_salt
),this_crypted
)) {
213 sec_login_get_current_context(&my_dce_sec_context
, &err
);
214 if (err
!= error_status_ok
) {
215 dce_error_inq_text(err
, dce_errstr
, &err2
);
216 DEBUG(0,("DCE can't get current context. %s\n", dce_errstr
));
221 sec_login_certify_identity(my_dce_sec_context
, &err
);
222 if (err
!= error_status_ok
) {
223 dce_error_inq_text(err
, dce_errstr
, &err2
);
224 DEBUG(0,("DCE can't get current context. %s\n", dce_errstr
));
229 sec_login_get_expiration(my_dce_sec_context
, &expire_time
, &err
);
230 if (err
!= error_status_ok
) {
231 dce_error_inq_text(err
, dce_errstr
, &err2
);
232 DEBUG(0,("DCE can't get expiration. %s\n", dce_errstr
));
239 if (expire_time
< (current_time
+ 60)) {
241 sec_passwd_rec_t
*key
;
243 sec_login_get_pwent(my_dce_sec_context
,
244 (sec_login_passwd_t
*)&pw
, &err
);
245 if (err
!= error_status_ok
) {
246 dce_error_inq_text(err
, dce_errstr
, &err2
);
247 DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr
));
252 sec_login_refresh_identity(my_dce_sec_context
, &err
);
253 if (err
!= error_status_ok
) {
254 dce_error_inq_text(err
, dce_errstr
, &err2
);
255 DEBUG(0,("DCE can't refresh identity. %s\n",
261 sec_key_mgmt_get_key(rpc_c_authn_dce_secret
, NULL
,
262 (unsigned char *)pw
->pw_name
,
263 sec_c_key_version_none
,
265 if (err
!= error_status_ok
) {
266 dce_error_inq_text(err
, dce_errstr
, &err2
);
267 DEBUG(0,("DCE can't get key for %s. %s\n",
268 pw
->pw_name
, dce_errstr
));
273 sec_login_valid_and_cert_ident(my_dce_sec_context
, key
,
274 &password_reset
, &auth_src
,
276 if (err
!= error_status_ok
) {
277 dce_error_inq_text(err
, dce_errstr
, &err2
);
278 DEBUG(0,("DCE can't validate and certify identity for %s. %s\n",
279 pw
->pw_name
, dce_errstr
));
282 sec_key_mgmt_free_key(key
, &err
);
283 if (err
!= error_status_ok
) {
284 dce_error_inq_text(err
, dce_errstr
, &err2
);
285 DEBUG(0,("DCE can't free key.\n", dce_errstr
));
289 if (sec_login_setup_identity((unsigned char *)user
,
293 dce_error_inq_text(err
, dce_errstr
, &err2
);
294 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
299 sec_login_get_pwent(my_dce_sec_context
,
300 (sec_login_passwd_t
*)&pw
, &err
);
301 if (err
!= error_status_ok
) {
302 dce_error_inq_text(err
, dce_errstr
, &err2
);
303 DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr
));
308 sec_login_purge_context(&my_dce_sec_context
, &err
);
309 if (err
!= error_status_ok
) {
310 dce_error_inq_text(err
, dce_errstr
, &err2
);
311 DEBUG(0,("DCE can't purge context. %s\n", dce_errstr
));
317 * NB. I'd like to change these to call something like become_user()
318 * instead but currently we don't have a connection
319 * context to become the correct user. This is already
320 * fairly platform specific code however, so I think
321 * this should be ok. I have added code to go
322 * back to being root on error though. JRA.
325 if (setregid(-1, pw
->pw_gid
) != 0) {
326 DEBUG(0,("Can't set egid to %d (%s)\n",
327 pw
->pw_gid
, strerror(errno
)));
331 if (setreuid(-1, pw
->pw_uid
) != 0) {
333 DEBUG(0,("Can't set euid to %d (%s)\n",
334 pw
->pw_uid
, strerror(errno
)));
338 if (sec_login_setup_identity((unsigned char *)user
,
342 dce_error_inq_text(err
, dce_errstr
, &err2
);
343 /* Go back to root, JRA. */
346 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
351 sec_login_get_pwent(my_dce_sec_context
,
352 (sec_login_passwd_t
*)&pw
, &err
);
353 if (err
!= error_status_ok
) {
354 dce_error_inq_text(err
, dce_errstr
, &err2
);
355 /* Go back to root, JRA. */
358 DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr
));
363 passwd_rec
.version_number
= sec_passwd_c_version_none
;
364 passwd_rec
.pepper
= NULL
;
365 passwd_rec
.key
.key_type
= sec_passwd_plain
;
366 passwd_rec
.key
.tagged_union
.plain
= (idl_char
*)password
;
368 sec_login_validate_identity(my_dce_sec_context
,
369 &passwd_rec
, &password_reset
,
371 if (err
!= error_status_ok
) {
372 dce_error_inq_text(err
, dce_errstr
, &err2
);
373 /* Go back to root, JRA. */
376 DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
382 sec_login_certify_identity(my_dce_sec_context
, &err
);
383 if (err
!= error_status_ok
) {
384 dce_error_inq_text(err
, dce_errstr
, &err2
);
385 /* Go back to root, JRA. */
388 DEBUG(0,("DCE certify identity failed: %s\n", dce_errstr
));
393 if (auth_src
!= sec_login_auth_src_network
) {
394 DEBUG(0,("DCE context has no network credentials.\n"));
397 sec_login_set_context(my_dce_sec_context
, &err
);
398 if (err
!= error_status_ok
) {
399 dce_error_inq_text(err
, dce_errstr
, &err2
);
400 DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
403 sec_login_purge_context(&my_dce_sec_context
, &err
);
404 /* Go back to root, JRA. */
410 sec_login_get_pwent(my_dce_sec_context
,
411 (sec_login_passwd_t
*)&pw
, &err
);
412 if (err
!= error_status_ok
) {
413 dce_error_inq_text(err
, dce_errstr
, &err2
);
414 DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr
));
416 /* Go back to root, JRA. */
422 DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
425 DEBUG(3,("DCE principal: %s\n"
428 pw
->pw_name
, pw
->pw_uid
, pw
->pw_gid
));
429 DEBUG(3,(" info: %s\n"
432 pw
->pw_gecos
, pw
->pw_dir
, pw
->pw_shell
));
434 sec_login_get_expiration(my_dce_sec_context
, &expire_time
, &err
);
435 if (err
!= error_status_ok
) {
436 dce_error_inq_text(err
, dce_errstr
, &err2
);
437 /* Go back to root, JRA. */
440 DEBUG(0,("DCE can't get expiration. %s\n", dce_errstr
));
448 DEBUG(0,("DCE context expires: %s",asctime(localtime(&expire_time
))));
450 dcelogin_atmost_once
= 1;
454 void dfs_unlogin(void)
458 unsigned char dce_errstr
[dce_c_error_string_len
];
460 sec_login_purge_context(&my_dce_sec_context
, &err
);
461 if (err
!= error_status_ok
) {
462 dce_error_inq_text(err
, dce_errstr
, &err2
);
463 DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
464 getpid(), dce_errstr
));
470 /*******************************************************************
471 check on Kerberos authentication
472 ********************************************************************/
473 static BOOL
krb5_auth(char *user
,char *password
)
475 krb5_data tgtname
= {
480 krb5_context kcontext
;
481 krb5_principal kprinc
;
482 krb5_principal server
;
485 krb5_address
**addrs
= (krb5_address
**)0;
486 krb5_preauthtype
*preauth
= NULL
;
487 krb5_keytab keytab
= NULL
;
489 krb5_ccache ccache
= NULL
;
493 if (retval
=krb5_init_context(&kcontext
)) {
497 if (retval
= krb5_timeofday(kcontext
, &now
)) {
501 if (retval
= krb5_cc_default(kcontext
, &ccache
)) {
505 if (retval
= krb5_parse_name(kcontext
, user
, &kprinc
)) {
511 kcreds
.client
= kprinc
;
513 if ((retval
= krb5_build_principal_ext(kcontext
, &server
,
514 krb5_princ_realm(kcontext
, kprinc
)->length
,
515 krb5_princ_realm(kcontext
, kprinc
)->data
,
518 krb5_princ_realm(kcontext
, kprinc
)->length
,
519 krb5_princ_realm(kcontext
, kprinc
)->data
,
524 kcreds
.server
= server
;
526 retval
= krb5_get_in_tkt_with_password(kcontext
,
542 #endif /* KRB5_AUTH */
547 /*******************************************************************
548 check on Kerberos authentication
549 ********************************************************************/
550 static BOOL
krb4_auth(char *user
,char *password
)
552 char realm
[REALM_SZ
];
553 char tkfile
[MAXPATHLEN
];
555 if (krb_get_lrealm(realm
, 1) != KSUCCESS
) {
556 (void) safe_strcpy(realm
, KRB_REALM
, sizeof (realm
) - 1);
559 (void) slprintf(tkfile
, sizeof(tkfile
) - 1, "/tmp/samba_tkt_%d",
562 krb_set_tkt_string(tkfile
);
563 if (krb_verify_user(user
, "", realm
,
565 "rmcd") == KSUCCESS
) {
572 #endif /* KRB4_AUTH */
574 #ifdef LINUX_BIGCRYPT
575 /****************************************************************************
576 an enhanced crypt for Linux to handle password longer than 8 characters
577 ****************************************************************************/
578 static int linux_bigcrypt(char *password
,char *salt1
, char *crypted
)
580 #define LINUX_PASSWORD_SEG_CHARS 8
584 StrnCpy(salt
,salt1
,2);
587 for ( i
=strlen(password
); i
> 0; i
-= LINUX_PASSWORD_SEG_CHARS
) {
588 char * p
= crypt(password
,salt
) + 2;
589 if (strncmp(p
, crypted
, LINUX_PASSWORD_SEG_CHARS
) != 0)
591 password
+= LINUX_PASSWORD_SEG_CHARS
;
592 crypted
+= strlen(p
);
600 /****************************************************************************
601 an enhanced crypt for OSF1
602 ****************************************************************************/
603 static char *osf1_bigcrypt(char *password
,char *salt1
)
605 static char result
[AUTH_MAX_PASSWD_LENGTH
] = "";
610 int parts
= strlen(password
) / AUTH_CLEARTEXT_SEG_CHARS
;
611 if (strlen(password
)%AUTH_CLEARTEXT_SEG_CHARS
) {
615 StrnCpy(salt
,salt1
,2);
616 StrnCpy(result
,salt1
,2);
619 for (i
=0; i
<parts
;i
++) {
621 strncat(result
,p1
+2,AUTH_MAX_PASSWD_LENGTH
-strlen(p1
+2)-1);
622 StrnCpy(salt
,&result
[2+i
*AUTH_CIPHERTEXT_SEG_CHARS
],2);
623 p2
+= AUTH_CLEARTEXT_SEG_CHARS
;
631 /****************************************************************************
632 apply a function to upper/lower case combinations
633 of a string and return true if one of them returns true.
634 try all combinations with N uppercase letters.
635 offset is the first char to try and change (start with 0)
636 it assumes the string starts lowercased
637 ****************************************************************************/
638 static BOOL
string_combinations2(char *s
,int offset
,BOOL (*fn
)(char *),int N
)
643 #ifdef PASSWORD_LENGTH
644 len
= MIN(len
,PASSWORD_LENGTH
);
647 if (N
<= 0 || offset
>= len
) {
651 for (i
=offset
;i
<(len
-(N
-1));i
++) {
653 if (!islower(c
)) continue;
655 if (string_combinations2(s
,i
+1,fn
,N
-1))
662 /****************************************************************************
663 apply a function to upper/lower case combinations
664 of a string and return true if one of them returns true.
665 try all combinations with up to N uppercase letters.
666 offset is the first char to try and change (start with 0)
667 it assumes the string starts lowercased
668 ****************************************************************************/
669 static BOOL
string_combinations(char *s
,BOOL (*fn
)(char *),int N
)
673 if (string_combinations2(s
,0,fn
,n
)) return(True
);
678 /****************************************************************************
679 core of password checking routine
680 ****************************************************************************/
681 static BOOL
password_check(char *password
)
685 /* This falls through if the password check fails
686 - if HAVE_CRYPT is not defined this causes an error msg
687 saying Warning - no crypt available
688 - if HAVE_CRYPT is defined this is a potential security hole
689 as it may authenticate via the crypt call when PAM
690 settings say it should fail.
691 if (pam_auth(user,password)) return(True);
692 Hence we make a direct return to avoid a second chance!!!
694 return (pam_auth(this_user
,password
));
698 if (afs_auth(this_user
,password
)) return(True
);
702 if (dfs_auth(this_user
,password
)) return(True
);
706 if (krb5_auth(this_user
,password
)) return(True
);
710 if (krb4_auth(this_user
,password
)) return(True
);
715 BOOL ret
= (strcmp(osf1_bigcrypt(password
,this_salt
),this_crypted
) == 0);
717 DEBUG(2,("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
718 ret
= (strcmp((char *)crypt(password
,this_salt
),this_crypted
) == 0);
725 return (strcmp((char *)crypt16(password
, this_salt
),this_crypted
) == 0);
728 #ifdef LINUX_BIGCRYPT
729 return(linux_bigcrypt(password
,this_salt
,this_crypted
));
733 return(strcmp(bigcrypt(password
,this_salt
),this_crypted
) == 0);
737 DEBUG(1,("Warning - no crypt available\n"));
740 return(strcmp((char *)crypt(password
,this_salt
),this_crypted
) == 0);
746 /****************************************************************************
747 check if a username/password is OK
748 the function pointer fn() points to a function to call when a successful
749 match is found and is used to update the encrypted password file
750 return True on correct match, False otherwise
751 ****************************************************************************/
752 BOOL
pass_check(char *user
,char *password
, int pwlen
, struct passwd
*pwd
,
753 BOOL (*fn
)(char *, char *))
756 int level
= lp_passwordlevel();
759 if (password
) password
[pwlen
] = 0;
762 DEBUG(100,("checking user=[%s] pass=[%s]\n",user
,password
));
769 if (((!*password
) || (!pwlen
)) && !lp_null_passwords()) {
774 pass
= (struct passwd
*) pwd
;
775 user
= pass
->pw_name
;
777 pass
= Get_Pwnam(user
,True
);
781 DEBUG(4,("Checking password for user %s (l=%d)\n",user
,pwlen
));
784 DEBUG(3,("Couldn't find user %s\n",user
));
792 /* many shadow systems require you to be root to get
793 the password, in most cases this should already be
794 the case when this function is called, except
795 perhaps for IPC password changing requests */
797 spass
= getspnam(pass
->pw_name
);
798 if (spass
&& spass
->sp_pwdp
) {
799 pass
->pw_passwd
= spass
->sp_pwdp
;
802 #elif defined(IA_UINFO)
804 /* Need to get password with SVR4.2's ia_ functions
805 instead of get{sp,pw}ent functions. Required by
806 UnixWare 2.x, tested on version
807 2.1. (tangent@cyberport.com) */
809 if (ia_openinfo(pass
->pw_name
, &uinfo
) != -1) {
810 ia_get_logpwd(uinfo
, &(pass
->pw_passwd
));
815 #ifdef HAVE_GETPRPWNAM
817 struct pr_passwd
*pr_pw
= getprpwnam(pass
->pw_name
);
818 if (pr_pw
&& pr_pw
->ufld
.fd_encrypt
)
819 pass
->pw_passwd
= pr_pw
->ufld
.fd_encrypt
;
825 struct pr_passwd
*mypasswd
;
826 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",
828 mypasswd
= getprpwnam (user
);
830 fstrcpy(pass
->pw_name
,mypasswd
->ufld
.fd_name
);
831 fstrcpy(pass
->pw_passwd
,mypasswd
->ufld
.fd_encrypt
);
833 DEBUG(5,("No entry for user %s in protected database !\n",
842 AUTHORIZATION
*ap
= getauthuid(pass
->pw_uid
);
844 fstrcpy(pass
->pw_passwd
, ap
->a_password
);
850 /* extract relevant info */
851 fstrcpy(this_user
,pass
->pw_name
);
852 fstrcpy(this_salt
,pass
->pw_passwd
);
853 /* crypt on some platforms (HPUX in particular)
854 won't work with more than 2 salt characters. */
857 fstrcpy(this_crypted
,pass
->pw_passwd
);
859 if (!*this_crypted
) {
860 if (!lp_null_passwords()) {
861 DEBUG(2,("Disallowing %s with null password\n",
866 DEBUG(3,("Allowing access to %s with null password\n",
872 /* try it as it came to us */
873 if (password_check(password
)) {
874 if (fn
) fn(user
,password
);
878 /* if the password was given to us with mixed case then we don't
879 need to proceed as we know it hasn't been case modified by the
881 if (strhasupper(password
) && strhaslower(password
)) {
885 /* make a copy of it */
886 StrnCpy(pass2
,password
,sizeof(pstring
)-1);
888 /* try all lowercase */
890 if (password_check(password
)) {
891 if (fn
) fn(user
,password
);
899 fstrcpy(password
,pass2
);
904 /* last chance - all combinations of up to level chars upper! */
907 if (string_combinations(password
,password_check
,level
)) {
908 if (fn
) fn(user
,password
);
913 fstrcpy(password
,pass2
);