1998-08-10 11:04:53 +04:00
/*
Unix SMB / Netbios implementation .
Version 1.9 .
Password checking
Copyright ( C ) Andrew Tridgell 1992 - 1998
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
/* this module is for checking a username/password against a system
password database . The SMB encrypted password support is elsewhere */
# include "includes.h"
extern int DEBUGLEVEL ;
/* these are kept here to keep the string_combinations function simple */
2001-08-31 00:09:49 +04:00
static fstring this_user ;
static fstring this_salt ;
static fstring this_crypted ;
1998-08-10 11:04:53 +04:00
# ifdef WITH_AFS
1999-12-13 16:27:58 +03:00
# include <afs/stds.h>
# include <afs/kautils.h>
1998-08-10 11:04:53 +04:00
/*******************************************************************
check on AFS authentication
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-03-22 00:08:07 +03:00
static BOOL afs_auth ( char * user , char * password )
1998-08-10 11:04:53 +04:00
{
long password_expires = 0 ;
char * reason ;
2000-03-22 00:08:07 +03:00
1998-08-10 11:04:53 +04:00
/* For versions of AFS prior to 3.3, this routine has few arguments, */
/* but since I can't find the old documentation... :-) */
setpag ( ) ;
2000-03-22 00:08:07 +03:00
if ( ka_UserAuthenticateGeneral
( KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG , user , ( char * ) 0 , /* instance */
( char * ) 0 , /* cell */
password , 0 , /* lifetime, default */
& password_expires , /*days 'til it expires */
0 , /* spare 2 */
& reason ) = = 0 )
{
return ( True ) ;
}
DEBUG ( 1 ,
( " AFS authentication for \" %s \" failed (%s) \n " , user , reason ) ) ;
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
# endif
# ifdef WITH_DFS
1999-12-13 16:27:58 +03:00
# include <dce/dce_error.h>
# include <dce/sec_login.h>
1998-08-10 11:04:53 +04:00
/*****************************************************************
This new version of the DFS_AUTH code was donated by Karsten Muuss
< muuss @ or . uni - bonn . de > . It fixes the following problems with the
old code :
- Server credentials may expire
- Client credential cache files have wrong owner
- purge_context ( ) function is called with invalid argument
This new code was modified to ensure that on exit the uid / gid is
still root , and the original directory is restored . JRA .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
sec_login_handle_t my_dce_sec_context ;
int dcelogin_atmost_once = 0 ;
/*******************************************************************
check on a DCE / DFS authentication
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-03-22 00:08:07 +03:00
static BOOL dfs_auth ( char * user , char * password )
1998-08-10 11:04:53 +04:00
{
error_status_t err ;
int err2 ;
int prterr ;
signed32 expire_time , current_time ;
boolean32 password_reset ;
struct passwd * pw ;
sec_passwd_rec_t passwd_rec ;
sec_login_auth_src_t auth_src = sec_login_auth_src_network ;
unsigned char dce_errstr [ dce_c_error_string_len ] ;
1999-12-13 16:27:58 +03:00
gid_t egid ;
1998-08-10 11:04:53 +04:00
2000-03-22 00:08:07 +03:00
if ( dcelogin_atmost_once )
return ( False ) ;
1998-08-10 11:04:53 +04:00
# ifdef HAVE_CRYPT
/*
* We only go for a DCE login context if the given password
* matches that stored in the local password file . .
* Assumes local passwd file is kept in sync w / DCE RGY !
*/
2000-03-22 00:08:07 +03:00
if ( strcmp ( ( char * ) crypt ( password , this_salt ) , this_crypted ) )
{
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
# endif
sec_login_get_current_context ( & my_dce_sec_context , & err ) ;
2000-03-22 00:08:07 +03:00
if ( err ! = error_status_ok )
{
1998-08-10 11:04:53 +04:00
dce_error_inq_text ( err , dce_errstr , & err2 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 0 , ( " DCE can't get current context. %s \n " , dce_errstr ) ) ;
1998-08-10 11:04:53 +04:00
2000-03-22 00:08:07 +03:00
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
sec_login_certify_identity ( my_dce_sec_context , & err ) ;
2000-03-22 00:08:07 +03:00
if ( err ! = error_status_ok )
{
1998-08-10 11:04:53 +04:00
dce_error_inq_text ( err , dce_errstr , & err2 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 0 , ( " DCE can't get current context. %s \n " , dce_errstr ) ) ;
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
sec_login_get_expiration ( my_dce_sec_context , & expire_time , & err ) ;
2000-03-22 00:08:07 +03:00
if ( err ! = error_status_ok )
{
1998-08-10 11:04:53 +04:00
dce_error_inq_text ( err , dce_errstr , & err2 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 0 , ( " DCE can't get expiration. %s \n " , dce_errstr ) ) ;
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
2000-03-22 00:08:07 +03:00
1998-08-10 11:04:53 +04:00
time ( & current_time ) ;
2000-03-22 00:08:07 +03:00
if ( expire_time < ( current_time + 60 ) )
{
struct passwd * pw ;
1998-08-10 11:04:53 +04:00
sec_passwd_rec_t * key ;
2000-03-22 00:08:07 +03:00
sec_login_get_pwent ( my_dce_sec_context ,
( sec_login_passwd_t * ) & pw , & err ) ;
if ( err ! = error_status_ok )
{
1998-08-10 11:04:53 +04:00
dce_error_inq_text ( err , dce_errstr , & err2 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 0 , ( " DCE can't get pwent. %s \n " , dce_errstr ) ) ;
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
2000-03-22 00:08:07 +03:00
1998-08-10 11:04:53 +04:00
sec_login_refresh_identity ( my_dce_sec_context , & err ) ;
2000-03-22 00:08:07 +03:00
if ( err ! = error_status_ok )
{
1998-08-10 11:04:53 +04:00
dce_error_inq_text ( err , dce_errstr , & err2 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 0 , ( " DCE can't refresh identity. %s \n " ,
dce_errstr ) ) ;
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
2000-03-22 00:08:07 +03:00
1998-08-10 11:04:53 +04:00
sec_key_mgmt_get_key ( rpc_c_authn_dce_secret , NULL ,
( unsigned char * ) pw - > pw_name ,
sec_c_key_version_none ,
2000-03-22 00:08:07 +03:00
( void * * ) & key , & err ) ;
if ( err ! = error_status_ok )
{
1998-08-10 11:04:53 +04:00
dce_error_inq_text ( err , dce_errstr , & err2 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 0 , ( " DCE can't get key for %s. %s \n " ,
pw - > pw_name , dce_errstr ) ) ;
1998-08-10 11:04:53 +04:00
2000-03-22 00:08:07 +03:00
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
2000-03-22 00:08:07 +03:00
1998-08-10 11:04:53 +04:00
sec_login_valid_and_cert_ident ( my_dce_sec_context , key ,
2000-03-22 00:08:07 +03:00
& password_reset , & auth_src ,
1998-08-10 11:04:53 +04:00
& err ) ;
2000-03-22 00:08:07 +03:00
if ( err ! = error_status_ok )
{
1998-08-10 11:04:53 +04:00
dce_error_inq_text ( err , dce_errstr , & err2 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 0 ,
( " DCE can't validate and certify identity for %s. %s \n " ,
pw - > pw_name , dce_errstr ) ) ;
1998-08-10 11:04:53 +04:00
}
2000-03-22 00:08:07 +03:00
1998-08-10 11:04:53 +04:00
sec_key_mgmt_free_key ( key , & err ) ;
2000-03-22 00:08:07 +03:00
if ( err ! = error_status_ok )
{
1998-08-10 11:04:53 +04:00
dce_error_inq_text ( err , dce_errstr , & err2 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 0 , ( " DCE can't free key. \n " , dce_errstr ) ) ;
1998-08-10 11:04:53 +04:00
}
}
1998-08-15 07:31:57 +04:00
if ( sec_login_setup_identity ( ( unsigned char * ) user ,
1998-08-10 11:04:53 +04:00
sec_login_no_flags ,
2000-03-22 00:08:07 +03:00
& my_dce_sec_context , & err ) = = 0 )
{
1998-08-10 11:04:53 +04:00
dce_error_inq_text ( err , dce_errstr , & err2 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 0 , ( " DCE Setup Identity for %s failed: %s \n " ,
user , dce_errstr ) ) ;
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
2000-03-22 00:08:07 +03:00
sec_login_get_pwent ( my_dce_sec_context ,
( sec_login_passwd_t * ) & pw , & err ) ;
if ( err ! = error_status_ok )
{
1998-08-10 11:04:53 +04:00
dce_error_inq_text ( err , dce_errstr , & err2 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 0 , ( " DCE can't get pwent. %s \n " , dce_errstr ) ) ;
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
sec_login_purge_context ( & my_dce_sec_context , & err ) ;
2000-03-22 00:08:07 +03:00
if ( err ! = error_status_ok )
{
1998-08-10 11:04:53 +04:00
dce_error_inq_text ( err , dce_errstr , & err2 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 0 , ( " DCE can't purge context. %s \n " , dce_errstr ) ) ;
1998-08-10 11:04:53 +04:00
2000-03-22 00:08:07 +03:00
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
/*
* NB . I ' d like to change these to call something like become_user ( )
* instead but currently we don ' t have a connection
* context to become the correct user . This is already
* fairly platform specific code however , so I think
* this should be ok . I have added code to go
* back to being root on error though . JRA .
*/
2000-03-22 00:08:07 +03:00
1999-12-13 16:27:58 +03:00
egid = getegid ( ) ;
2000-06-01 21:01:34 +04:00
set_effective_gid ( pw - > pw_gid ) ;
set_effective_uid ( pw - > pw_uid ) ;
2000-03-22 00:08:07 +03:00
1998-08-15 07:31:57 +04:00
if ( sec_login_setup_identity ( ( unsigned char * ) user ,
1998-08-10 11:04:53 +04:00
sec_login_no_flags ,
2000-03-22 00:08:07 +03:00
& my_dce_sec_context , & err ) = = 0 )
{
1998-08-10 11:04:53 +04:00
dce_error_inq_text ( err , dce_errstr , & err2 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 0 , ( " DCE Setup Identity for %s failed: %s \n " ,
user , dce_errstr ) ) ;
1999-12-13 16:27:58 +03:00
goto err ;
1998-08-10 11:04:53 +04:00
}
2000-03-22 00:08:07 +03:00
sec_login_get_pwent ( my_dce_sec_context ,
( sec_login_passwd_t * ) & pw , & err ) ;
if ( err ! = error_status_ok )
{
1998-08-10 11:04:53 +04:00
dce_error_inq_text ( err , dce_errstr , & err2 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 0 , ( " DCE can't get pwent. %s \n " , dce_errstr ) ) ;
1999-12-13 16:27:58 +03:00
goto err ;
1998-08-10 11:04:53 +04:00
}
passwd_rec . version_number = sec_passwd_c_version_none ;
passwd_rec . pepper = NULL ;
passwd_rec . key . key_type = sec_passwd_plain ;
2000-03-22 00:08:07 +03:00
passwd_rec . key . tagged_union . plain = ( idl_char * ) password ;
1998-08-10 11:04:53 +04:00
sec_login_validate_identity ( my_dce_sec_context ,
& passwd_rec , & password_reset ,
& auth_src , & err ) ;
2000-03-22 00:08:07 +03:00
if ( err ! = error_status_ok )
{
1998-08-10 11:04:53 +04:00
dce_error_inq_text ( err , dce_errstr , & err2 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 0 ,
( " DCE Identity Validation failed for principal %s: %s \n " ,
user , dce_errstr ) ) ;
1999-12-13 16:27:58 +03:00
goto err ;
1998-08-10 11:04:53 +04:00
}
sec_login_certify_identity ( my_dce_sec_context , & err ) ;
2000-03-22 00:08:07 +03:00
if ( err ! = error_status_ok )
{
1998-08-10 11:04:53 +04:00
dce_error_inq_text ( err , dce_errstr , & err2 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 0 , ( " DCE certify identity failed: %s \n " , dce_errstr ) ) ;
1999-12-13 16:27:58 +03:00
goto err ;
1998-08-10 11:04:53 +04:00
}
2000-03-22 00:08:07 +03:00
if ( auth_src ! = sec_login_auth_src_network )
{
DEBUG ( 0 , ( " DCE context has no network credentials. \n " ) ) ;
1998-08-10 11:04:53 +04:00
}
sec_login_set_context ( my_dce_sec_context , & err ) ;
2000-03-22 00:08:07 +03:00
if ( err ! = error_status_ok )
{
1998-08-10 11:04:53 +04:00
dce_error_inq_text ( err , dce_errstr , & err2 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 0 ,
( " DCE login failed for principal %s, cant set context: %s \n " ,
user , dce_errstr ) ) ;
1998-08-10 11:04:53 +04:00
sec_login_purge_context ( & my_dce_sec_context , & err ) ;
1999-12-13 16:27:58 +03:00
goto err ;
1998-08-10 11:04:53 +04:00
}
2000-03-22 00:08:07 +03:00
sec_login_get_pwent ( my_dce_sec_context ,
( sec_login_passwd_t * ) & pw , & err ) ;
if ( err ! = error_status_ok )
{
1998-08-10 11:04:53 +04:00
dce_error_inq_text ( err , dce_errstr , & err2 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 0 , ( " DCE can't get pwent. %s \n " , dce_errstr ) ) ;
1999-12-13 16:27:58 +03:00
goto err ;
1998-08-10 11:04:53 +04:00
}
2000-03-22 00:08:07 +03:00
DEBUG ( 0 , ( " DCE login succeeded for principal %s on pid %d \n " ,
2000-05-02 06:23:41 +04:00
user , sys_getpid ( ) ) ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 3 , ( " DCE principal: %s \n "
" uid: %d \n "
" gid: %d \n " ,
pw - > pw_name , pw - > pw_uid , pw - > pw_gid ) ) ;
DEBUG ( 3 , ( " info: %s \n "
" dir: %s \n "
" shell: %s \n " ,
pw - > pw_gecos , pw - > pw_dir , pw - > pw_shell ) ) ;
1998-08-10 11:04:53 +04:00
sec_login_get_expiration ( my_dce_sec_context , & expire_time , & err ) ;
2000-03-22 00:08:07 +03:00
if ( err ! = error_status_ok )
{
1998-08-10 11:04:53 +04:00
dce_error_inq_text ( err , dce_errstr , & err2 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 0 , ( " DCE can't get expiration. %s \n " , dce_errstr ) ) ;
1999-12-13 16:27:58 +03:00
goto err ;
1998-08-10 11:04:53 +04:00
}
2000-03-22 00:08:07 +03:00
1999-12-13 16:27:58 +03:00
set_effective_uid ( 0 ) ;
set_effective_gid ( 0 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 0 ,
( " DCE context expires: %s " , asctime ( localtime ( & expire_time ) ) ) ) ;
1998-08-10 11:04:53 +04:00
dcelogin_atmost_once = 1 ;
return ( True ) ;
1999-12-13 16:27:58 +03:00
2000-03-22 00:08:07 +03:00
err :
1999-12-13 16:27:58 +03:00
/* Go back to root, JRA. */
set_effective_uid ( 0 ) ;
set_effective_gid ( egid ) ;
2000-03-22 00:08:07 +03:00
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
void dfs_unlogin ( void )
{
error_status_t err ;
int err2 ;
unsigned char dce_errstr [ dce_c_error_string_len ] ;
2000-03-22 00:08:07 +03:00
1998-08-10 11:04:53 +04:00
sec_login_purge_context ( & my_dce_sec_context , & err ) ;
2000-03-22 00:08:07 +03:00
if ( err ! = error_status_ok )
{
1998-08-10 11:04:53 +04:00
dce_error_inq_text ( err , dce_errstr , & err2 ) ;
2000-03-22 00:08:07 +03:00
DEBUG ( 0 ,
( " DCE purge login context failed for server instance %d: %s \n " ,
2000-05-02 06:23:41 +04:00
sys_getpid ( ) , dce_errstr ) ) ;
1998-08-10 11:04:53 +04:00
}
}
# endif
# ifdef KRB5_AUTH
1999-12-13 16:27:58 +03:00
# include <krb5.h>
1998-08-10 11:04:53 +04:00
/*******************************************************************
check on Kerberos authentication
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-03-22 00:08:07 +03:00
static BOOL krb5_auth ( char * user , char * password )
1998-08-10 11:04:53 +04:00
{
krb5_data tgtname = {
0 ,
KRB5_TGS_NAME_SIZE ,
2000-03-22 00:08:07 +03:00
KRB5_TGS_NAME
} ;
1998-08-10 11:04:53 +04:00
krb5_context kcontext ;
krb5_principal kprinc ;
krb5_principal server ;
krb5_creds kcreds ;
int options = 0 ;
2000-03-22 00:08:07 +03:00
krb5_address * * addrs = ( krb5_address * * ) 0 ;
1998-08-10 11:04:53 +04:00
krb5_preauthtype * preauth = NULL ;
krb5_keytab keytab = NULL ;
krb5_timestamp now ;
krb5_ccache ccache = NULL ;
int retval ;
char * name ;
2000-03-22 00:08:07 +03:00
if ( retval = krb5_init_context ( & kcontext ) )
{
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
2000-03-22 00:08:07 +03:00
if ( retval = krb5_timeofday ( kcontext , & now ) )
{
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
2000-03-22 00:08:07 +03:00
if ( retval = krb5_cc_default ( kcontext , & ccache ) )
{
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
2000-03-22 00:08:07 +03:00
if ( retval = krb5_parse_name ( kcontext , user , & kprinc ) )
{
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
1998-09-05 17:24:20 +04:00
ZERO_STRUCT ( kcreds ) ;
1998-08-10 11:04:53 +04:00
kcreds . client = kprinc ;
2000-03-22 00:08:07 +03:00
1998-08-10 11:04:53 +04:00
if ( ( retval = krb5_build_principal_ext ( kcontext , & server ,
2000-03-22 00:08:07 +03:00
krb5_princ_realm ( kcontext ,
kprinc ) - >
length ,
krb5_princ_realm ( kcontext ,
kprinc ) - > data ,
tgtname . length , tgtname . data ,
krb5_princ_realm ( kcontext ,
kprinc ) - >
length ,
krb5_princ_realm ( kcontext ,
kprinc ) - > data ,
0 ) ) )
{
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
kcreds . server = server ;
retval = krb5_get_in_tkt_with_password ( kcontext ,
options ,
addrs ,
NULL ,
preauth ,
2000-03-22 00:08:07 +03:00
password , 0 , & kcreds , 0 ) ;
1998-08-10 11:04:53 +04:00
2000-03-22 00:08:07 +03:00
if ( retval )
{
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
2000-03-22 00:08:07 +03:00
return ( True ) ;
1998-08-10 11:04:53 +04:00
}
# endif /* KRB5_AUTH */
# ifdef KRB4_AUTH
1998-09-26 07:30:15 +04:00
# include <krb.h>
1998-08-10 11:04:53 +04:00
/*******************************************************************
check on Kerberos authentication
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-03-22 00:08:07 +03:00
static BOOL krb4_auth ( char * user , char * password )
1998-08-10 11:04:53 +04:00
{
char realm [ REALM_SZ ] ;
char tkfile [ MAXPATHLEN ] ;
2000-03-22 00:08:07 +03:00
if ( krb_get_lrealm ( realm , 1 ) ! = KSUCCESS )
{
( void ) safe_strcpy ( realm , KRB_REALM , sizeof ( realm ) - 1 ) ;
1998-08-10 11:04:53 +04:00
}
2000-03-22 00:08:07 +03:00
( void ) slprintf ( tkfile , sizeof ( tkfile ) - 1 , " /tmp/samba_tkt_%d " ,
2000-05-02 06:23:41 +04:00
( int ) sys_getpid ( ) ) ;
2000-03-22 00:08:07 +03:00
1998-08-10 11:04:53 +04:00
krb_set_tkt_string ( tkfile ) ;
2000-03-22 00:08:07 +03:00
if ( krb_verify_user ( user , " " , realm , password , 0 , " rmcd " ) = = KSUCCESS )
{
1998-08-10 11:04:53 +04:00
unlink ( tkfile ) ;
return 1 ;
}
unlink ( tkfile ) ;
return 0 ;
}
# endif /* KRB4_AUTH */
# ifdef LINUX_BIGCRYPT
/****************************************************************************
an enhanced crypt for Linux to handle password longer than 8 characters
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-03-22 00:08:07 +03:00
static int linux_bigcrypt ( char * password , char * salt1 , char * crypted )
1998-08-10 11:04:53 +04:00
{
# define LINUX_PASSWORD_SEG_CHARS 8
char salt [ 3 ] ;
int i ;
2000-03-22 00:08:07 +03:00
StrnCpy ( salt , salt1 , 2 ) ;
crypted + = 2 ;
2001-04-10 23:43:14 +04:00
for ( i = strlen ( password ) ; i > 0 ; i - = LINUX_PASSWORD_SEG_CHARS ) {
2000-03-22 00:08:07 +03:00
char * p = crypt ( password , salt ) + 2 ;
1998-08-10 11:04:53 +04:00
if ( strncmp ( p , crypted , LINUX_PASSWORD_SEG_CHARS ) ! = 0 )
2000-03-22 00:08:07 +03:00
return ( 0 ) ;
1998-08-10 11:04:53 +04:00
password + = LINUX_PASSWORD_SEG_CHARS ;
2000-03-22 00:08:07 +03:00
crypted + = strlen ( p ) ;
1998-08-10 11:04:53 +04:00
}
2000-03-22 00:08:07 +03:00
return ( 1 ) ;
1998-08-10 11:04:53 +04:00
}
# endif
# ifdef OSF1_ENH_SEC
/****************************************************************************
an enhanced crypt for OSF1
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-03-22 00:08:07 +03:00
static char * osf1_bigcrypt ( char * password , char * salt1 )
1998-08-10 11:04:53 +04:00
{
static char result [ AUTH_MAX_PASSWD_LENGTH ] = " " ;
char * p1 ;
2000-03-22 00:08:07 +03:00
char * p2 = password ;
1998-08-10 11:04:53 +04:00
char salt [ 3 ] ;
int i ;
int parts = strlen ( password ) / AUTH_CLEARTEXT_SEG_CHARS ;
2000-03-22 00:08:07 +03:00
if ( strlen ( password ) % AUTH_CLEARTEXT_SEG_CHARS )
1998-08-10 11:04:53 +04:00
parts + + ;
2000-03-22 00:08:07 +03:00
StrnCpy ( salt , salt1 , 2 ) ;
StrnCpy ( result , salt1 , 2 ) ;
result [ 2 ] = ' \0 ' ;
2001-04-10 23:43:14 +04:00
for ( i = 0 ; i < parts ; i + + ) {
2000-03-22 00:08:07 +03:00
p1 = crypt ( p2 , salt ) ;
strncat ( result , p1 + 2 ,
AUTH_MAX_PASSWD_LENGTH - strlen ( p1 + 2 ) - 1 ) ;
StrnCpy ( salt , & result [ 2 + i * AUTH_CIPHERTEXT_SEG_CHARS ] , 2 ) ;
1998-08-10 11:04:53 +04:00
p2 + = AUTH_CLEARTEXT_SEG_CHARS ;
}
2000-03-22 00:08:07 +03:00
return ( result ) ;
1998-08-10 11:04:53 +04:00
}
# endif
/****************************************************************************
apply a function to upper / lower case combinations
of a string and return true if one of them returns true .
try all combinations with N uppercase letters .
offset is the first char to try and change ( start with 0 )
it assumes the string starts lowercased
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-03-22 00:08:07 +03:00
static BOOL string_combinations2 ( char * s , int offset , BOOL ( * fn ) ( char * ) ,
int N )
1998-08-10 11:04:53 +04:00
{
int len = strlen ( s ) ;
int i ;
# ifdef PASSWORD_LENGTH
2000-03-22 00:08:07 +03:00
len = MIN ( len , PASSWORD_LENGTH ) ;
1998-08-10 11:04:53 +04:00
# endif
2000-03-22 00:08:07 +03:00
if ( N < = 0 | | offset > = len )
return ( fn ( s ) ) ;
1998-08-10 11:04:53 +04:00
2001-04-10 23:43:14 +04:00
for ( i = offset ; i < ( len - ( N - 1 ) ) ; i + + ) {
1998-08-10 11:04:53 +04:00
char c = s [ i ] ;
2000-03-22 00:08:07 +03:00
if ( ! islower ( c ) )
continue ;
1998-08-10 11:04:53 +04:00
s [ i ] = toupper ( c ) ;
2000-03-22 00:08:07 +03:00
if ( string_combinations2 ( s , i + 1 , fn , N - 1 ) )
return ( True ) ;
1998-08-10 11:04:53 +04:00
s [ i ] = c ;
}
2000-03-22 00:08:07 +03:00
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
/****************************************************************************
apply a function to upper / lower case combinations
of a string and return true if one of them returns true .
try all combinations with up to N uppercase letters .
offset is the first char to try and change ( start with 0 )
it assumes the string starts lowercased
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-03-22 00:08:07 +03:00
static BOOL string_combinations ( char * s , BOOL ( * fn ) ( char * ) , int N )
1998-08-10 11:04:53 +04:00
{
int n ;
2000-03-22 00:08:07 +03:00
for ( n = 1 ; n < = N ; n + + )
if ( string_combinations2 ( s , 0 , fn , n ) )
return ( True ) ;
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
/****************************************************************************
core of password checking routine
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL password_check ( char * password )
{
1999-12-13 16:27:58 +03:00
# ifdef WITH_PAM
2001-09-04 11:13:01 +04:00
return NT_STATUS_IS_OK ( smb_pam_passcheck ( this_user , password ) ) ;
1999-12-13 16:27:58 +03:00
# endif /* WITH_PAM */
2000-03-22 00:08:07 +03:00
1998-08-10 11:04:53 +04:00
# ifdef WITH_AFS
2000-03-22 00:08:07 +03:00
if ( afs_auth ( this_user , password ) )
return ( True ) ;
1999-12-13 16:27:58 +03:00
# endif /* WITH_AFS */
2000-03-22 00:08:07 +03:00
1998-08-10 11:04:53 +04:00
# ifdef WITH_DFS
2000-03-22 00:08:07 +03:00
if ( dfs_auth ( this_user , password ) )
return ( True ) ;
1999-12-13 16:27:58 +03:00
# endif /* WITH_DFS */
1998-08-10 11:04:53 +04:00
# ifdef KRB5_AUTH
2000-03-22 00:08:07 +03:00
if ( krb5_auth ( this_user , password ) )
return ( True ) ;
1999-12-13 16:27:58 +03:00
# endif /* KRB5_AUTH */
1998-08-10 11:04:53 +04:00
# ifdef KRB4_AUTH
2000-03-22 00:08:07 +03:00
if ( krb4_auth ( this_user , password ) )
return ( True ) ;
1999-12-13 16:27:58 +03:00
# endif /* KRB4_AUTH */
1998-08-10 11:04:53 +04:00
# ifdef OSF1_ENH_SEC
{
2000-03-22 00:08:07 +03:00
BOOL ret =
( strcmp
( osf1_bigcrypt ( password , this_salt ) ,
this_crypted ) = = 0 ) ;
2001-04-10 23:43:14 +04:00
if ( ! ret ) {
2000-03-22 00:08:07 +03:00
DEBUG ( 2 ,
( " OSF1_ENH_SEC failed. Trying normal crypt. \n " ) ) ;
2001-04-10 23:43:14 +04:00
ret = ( strcmp ( ( char * ) crypt ( password , this_salt ) , this_crypted ) = = 0 ) ;
2000-03-22 00:08:07 +03:00
}
return ret ;
1998-08-10 11:04:53 +04:00
}
1999-12-13 16:27:58 +03:00
# endif /* OSF1_ENH_SEC */
1998-08-10 11:04:53 +04:00
# ifdef ULTRIX_AUTH
2001-04-10 23:43:14 +04:00
return ( strcmp ( ( char * ) crypt16 ( password , this_salt ) , this_crypted ) = = 0 ) ;
1999-12-13 16:27:58 +03:00
# endif /* ULTRIX_AUTH */
1998-08-10 11:04:53 +04:00
# ifdef LINUX_BIGCRYPT
2000-03-22 00:08:07 +03:00
return ( linux_bigcrypt ( password , this_salt , this_crypted ) ) ;
1999-12-13 16:27:58 +03:00
# endif /* LINUX_BIGCRYPT */
# if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
/*
* Some systems have bigcrypt in the C library but might not
* actually use it for the password hashes ( HPUX 10.20 ) is
* a noteable example . So we try bigcrypt first , followed
* by crypt .
*/
2000-03-22 00:08:07 +03:00
if ( strcmp ( bigcrypt ( password , this_salt ) , this_crypted ) = = 0 )
1999-12-13 16:27:58 +03:00
return True ;
2000-03-22 00:08:07 +03:00
else
2001-04-10 23:43:14 +04:00
return ( strcmp ( ( char * ) crypt ( password , this_salt ) , this_crypted ) = = 0 ) ;
1999-12-13 16:27:58 +03:00
# else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
1998-08-10 11:04:53 +04:00
# ifdef HAVE_BIGCRYPT
2000-03-22 00:08:07 +03:00
return ( strcmp ( bigcrypt ( password , this_salt ) , this_crypted ) = = 0 ) ;
1999-12-13 16:27:58 +03:00
# endif /* HAVE_BIGCRYPT */
1998-08-10 11:04:53 +04:00
# ifndef HAVE_CRYPT
2000-03-22 00:08:07 +03:00
DEBUG ( 1 , ( " Warning - no crypt available \n " ) ) ;
return ( False ) ;
1999-12-13 16:27:58 +03:00
# else /* HAVE_CRYPT */
2001-04-10 23:43:14 +04:00
return ( strcmp ( ( char * ) crypt ( password , this_salt ) , this_crypted ) = = 0 ) ;
1999-12-13 16:27:58 +03:00
# endif /* HAVE_CRYPT */
# endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
1998-08-10 11:04:53 +04:00
}
/****************************************************************************
check if a username / password is OK
the function pointer fn ( ) points to a function to call when a successful
match is found and is used to update the encrypted password file
return True on correct match , False otherwise
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-04-22 11:20:24 +04:00
2001-07-08 18:10:30 +04:00
BOOL pass_check ( char * user , char * password , int pwlen ,
2000-03-22 00:08:07 +03:00
BOOL ( * fn ) ( char * , char * ) )
1998-08-10 11:04:53 +04:00
{
pstring pass2 ;
int level = lp_passwordlevel ( ) ;
2001-04-22 11:20:24 +04:00
struct passwd * pass = NULL ;
1998-08-10 11:04:53 +04:00
2000-03-22 00:08:07 +03:00
if ( password )
password [ pwlen ] = 0 ;
1998-08-10 11:04:53 +04:00
# if DEBUG_PASSWORD
2000-03-22 00:08:07 +03:00
DEBUG ( 100 , ( " checking user=[%s] pass=[%s] \n " , user , password ) ) ;
1998-08-10 11:04:53 +04:00
# endif
2000-03-22 00:08:07 +03:00
if ( ! password )
return ( False ) ;
1998-08-10 11:04:53 +04:00
2000-03-22 00:08:07 +03:00
if ( ( ( ! * password ) | | ( ! pwlen ) ) & & ! lp_null_passwords ( ) )
return ( False ) ;
1998-08-10 11:04:53 +04:00
2001-07-08 18:10:30 +04:00
pass = Get_Pwnam ( user , True ) ;
1998-08-10 11:04:53 +04:00
2001-04-22 11:20:24 +04:00
# ifdef WITH_PAM
/*
* If we ' re using PAM we want to short - circuit all the
* checks below and dive straight into the PAM code .
*/
fstrcpy ( this_user , user ) ;
DEBUG ( 4 , ( " pass_check: Checking (PAM) password for user %s (l=%d) \n " , user , pwlen ) ) ;
# else /* Not using PAM */
1998-08-10 11:04:53 +04:00
2001-04-22 11:20:24 +04:00
DEBUG ( 4 , ( " pass_check: Checking password for user %s (l=%d) \n " , user , pwlen ) ) ;
1998-08-10 11:04:53 +04:00
2001-04-10 23:43:14 +04:00
if ( ! pass ) {
2000-03-22 00:08:07 +03:00
DEBUG ( 3 , ( " Couldn't find user %s \n " , user ) ) ;
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
1999-12-13 16:27:58 +03:00
# ifdef HAVE_GETSPNAM
{
struct spwd * spass ;
/* many shadow systems require you to be root to get
the password , in most cases this should already be
the case when this function is called , except
perhaps for IPC password changing requests */
spass = getspnam ( pass - > pw_name ) ;
2000-03-22 00:08:07 +03:00
if ( spass & & spass - > sp_pwdp )
pstrcpy ( pass - > pw_passwd , spass - > sp_pwdp ) ;
1999-12-13 16:27:58 +03:00
}
# elif defined(IA_UINFO)
{
/* Need to get password with SVR4.2's ia_ functions
instead of get { sp , pw } ent functions . Required by
UnixWare 2. x , tested on version
2.1 . ( tangent @ cyberport . com ) */
uinfo_t uinfo ;
2000-03-22 00:08:07 +03:00
if ( ia_openinfo ( pass - > pw_name , & uinfo ) ! = - 1 )
1999-12-13 16:27:58 +03:00
ia_get_logpwd ( uinfo , & ( pass - > pw_passwd ) ) ;
}
# endif
# ifdef HAVE_GETPRPWNAM
{
struct pr_passwd * pr_pw = getprpwnam ( pass - > pw_name ) ;
if ( pr_pw & & pr_pw - > ufld . fd_encrypt )
2000-03-22 00:08:07 +03:00
pstrcpy ( pass - > pw_passwd , pr_pw - > ufld . fd_encrypt ) ;
1999-12-13 16:27:58 +03:00
}
# endif
# ifdef OSF1_ENH_SEC
{
struct pr_passwd * mypasswd ;
2000-03-22 00:08:07 +03:00
DEBUG ( 5 , ( " Checking password for user %s in OSF1_ENH_SEC \n " ,
user ) ) ;
mypasswd = getprpwnam ( user ) ;
2001-04-10 23:43:14 +04:00
if ( mypasswd ) {
2000-03-22 00:08:07 +03:00
fstrcpy ( pass - > pw_name , mypasswd - > ufld . fd_name ) ;
fstrcpy ( pass - > pw_passwd , mypasswd - > ufld . fd_encrypt ) ;
2001-04-10 23:43:14 +04:00
} else {
2000-03-22 00:08:07 +03:00
DEBUG ( 5 ,
( " OSF1_ENH_SEC: No entry for user %s in protected database ! \n " ,
user ) ) ;
1999-12-13 16:27:58 +03:00
}
}
# endif
# ifdef ULTRIX_AUTH
{
AUTHORIZATION * ap = getauthuid ( pass - > pw_uid ) ;
2001-04-10 23:43:14 +04:00
if ( ap ) {
1999-12-13 16:27:58 +03:00
fstrcpy ( pass - > pw_passwd , ap - > a_password ) ;
endauthent ( ) ;
}
}
# endif
1998-08-10 11:04:53 +04:00
/* extract relevant info */
2000-03-22 00:08:07 +03:00
fstrcpy ( this_user , pass - > pw_name ) ;
fstrcpy ( this_salt , pass - > pw_passwd ) ;
1999-12-13 16:27:58 +03:00
# if defined(HAVE_TRUNCATED_SALT)
1998-08-10 11:04:53 +04:00
/* crypt on some platforms (HPUX in particular)
won ' t work with more than 2 salt characters . */
this_salt [ 2 ] = 0 ;
1999-12-13 16:27:58 +03:00
# endif
2000-03-22 00:08:07 +03:00
fstrcpy ( this_crypted , pass - > pw_passwd ) ;
2001-04-10 22:10:38 +04:00
if ( ! * this_crypted ) {
if ( ! lp_null_passwords ( ) ) {
2000-03-22 00:08:07 +03:00
DEBUG ( 2 , ( " Disallowing %s with null password \n " ,
this_user ) ) ;
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
2001-04-10 22:10:38 +04:00
if ( ! * password ) {
2000-03-22 00:08:07 +03:00
DEBUG ( 3 ,
( " Allowing access to %s with null password \n " ,
this_user ) ) ;
return ( True ) ;
1998-08-10 11:04:53 +04:00
}
}
2001-04-22 11:20:24 +04:00
# endif /* WITH_PAM */
1998-08-10 11:04:53 +04:00
/* try it as it came to us */
2001-04-10 23:43:14 +04:00
if ( password_check ( password ) ) {
2000-03-22 00:08:07 +03:00
if ( fn )
fn ( user , password ) ;
return ( True ) ;
1998-08-10 11:04:53 +04:00
}
/* if the password was given to us with mixed case then we don't
need to proceed as we know it hasn ' t been case modified by the
client */
2001-04-10 23:43:14 +04:00
if ( strhasupper ( password ) & & strhaslower ( password ) ) {
2000-03-22 00:08:07 +03:00
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
/* make a copy of it */
2000-03-22 00:08:07 +03:00
StrnCpy ( pass2 , password , sizeof ( pstring ) - 1 ) ;
2001-04-10 23:43:14 +04:00
/* try all lowercase if it's currently all uppercase */
if ( strhasupper ( password ) ) {
strlower ( password ) ;
if ( password_check ( password ) ) {
if ( fn )
fn ( user , password ) ;
return ( True ) ;
}
1998-08-10 11:04:53 +04:00
}
/* give up? */
2001-04-10 23:43:14 +04:00
if ( level < 1 ) {
1998-08-10 11:04:53 +04:00
/* restore it */
2000-03-22 00:08:07 +03:00
fstrcpy ( password , pass2 ) ;
return ( False ) ;
1998-08-10 11:04:53 +04:00
}
/* last chance - all combinations of up to level chars upper! */
strlower ( password ) ;
2001-04-10 23:43:14 +04:00
if ( string_combinations ( password , password_check , level ) ) {
2000-03-22 00:08:07 +03:00
if ( fn )
fn ( user , password ) ;
return ( True ) ;
1998-08-10 11:04:53 +04:00
}
/* restore it */
2000-03-22 00:08:07 +03:00
fstrcpy ( password , pass2 ) ;
return ( False ) ;
1998-08-10 11:04:53 +04:00
}