2010-08-21 16:42:24 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1998-08-10 11:04:53 +04:00
Password checking
Copyright ( C ) Andrew Tridgell 1992 - 1998
2010-08-21 16:42:24 +04:00
1998-08-10 11:04:53 +04:00
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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
1998-08-10 11:04:53 +04:00
( at your option ) any later version .
2010-08-21 16:42:24 +04:00
1998-08-10 11:04:53 +04:00
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 .
2010-08-21 16:42:24 +04:00
1998-08-10 11:04:53 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1998-08-10 11:04:53 +04:00
*/
/* this module is for checking a username/password against a system
password database . The SMB encrypted password support is elsewhere */
# include "includes.h"
2002-07-15 14:35:28 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_AUTH
1998-08-10 11:04:53 +04:00
/* these are kept here to keep the string_combinations function simple */
2007-12-18 04:02:48 +03:00
static char * ths_user ;
2007-12-18 04:13:31 +03:00
static const char * get_this_user ( void )
2007-12-18 04:02:48 +03:00
{
if ( ! ths_user ) {
return " " ;
}
return ths_user ;
}
# if defined(WITH_PAM) || defined(OSF1_ENH_SEC)
static const char * set_this_user ( const char * newuser )
{
char * orig_user = ths_user ;
ths_user = SMB_STRDUP ( newuser ) ;
SAFE_FREE ( orig_user ) ;
return ths_user ;
}
# endif
# if !defined(WITH_PAM)
static char * ths_salt ;
/* This must be writable. */
2007-12-18 04:13:31 +03:00
static char * get_this_salt ( void )
2007-12-18 04:02:48 +03:00
{
return ths_salt ;
}
/* We may be setting a modified version of the same
* string , so don ' t free before use . */
static const char * set_this_salt ( const char * newsalt )
{
char * orig_salt = ths_salt ;
ths_salt = SMB_STRDUP ( newsalt ) ;
SAFE_FREE ( orig_salt ) ;
return ths_salt ;
}
static char * ths_crypted ;
2007-12-18 04:13:31 +03:00
static const char * get_this_crypted ( void )
2007-12-18 04:02:48 +03:00
{
if ( ! ths_crypted ) {
return " " ;
}
return ths_crypted ;
}
static const char * set_this_crypted ( const char * newcrypted )
{
char * orig_crypted = ths_crypted ;
ths_crypted = SMB_STRDUP ( newcrypted ) ;
SAFE_FREE ( orig_crypted ) ;
return ths_crypted ;
}
2001-09-20 17:15:35 +04:00
# endif
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04: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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool dfs_auth ( char * user , char * password )
1998-08-10 11:04:53 +04:00
{
2006-06-15 01:36:49 +04:00
struct tm * t ;
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 !
*/
2007-12-18 04:02:48 +03:00
if ( strcmp ( ( char * ) crypt ( password , get_this_salt ( ) ) , get_this_crypted ( ) ) )
2000-03-22 00:08:07 +03:00
{
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
}
/*
2001-10-19 00:15:12 +04:00
* NB . I ' d like to change these to call something like change_to_user ( )
1998-08-10 11:04:53 +04:00
* 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
2006-06-15 01:36:49 +04:00
t = localtime ( & expire_time ) ;
if ( t ) {
const char * asct = asctime ( t ) ;
if ( asct ) {
DEBUG ( 0 , ( " DCE context expires: %s " , asct ) ) ;
}
}
2000-03-22 00:08:07 +03:00
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 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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-08-21 16:48:28 +04:00
static NTSTATUS string_combinations2 ( char * s , int offset ,
NTSTATUS ( * fn ) ( const char * s ,
void * private_data ) ,
int N , void * private_data )
1998-08-10 11:04:53 +04:00
{
int len = strlen ( s ) ;
int i ;
2001-09-20 17:15:35 +04:00
NTSTATUS nt_status ;
1998-08-10 11:04:53 +04:00
# 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 )
2010-08-21 16:48:28 +04:00
return ( fn ( s , private_data ) ) ;
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 ] ;
2005-12-27 23:52:36 +03:00
if ( ! islower_ascii ( c ) )
2000-03-22 00:08:07 +03:00
continue ;
2005-12-27 23:52:36 +03:00
s [ i ] = toupper_ascii ( c ) ;
2010-08-21 16:48:28 +04:00
nt_status = string_combinations2 ( s , i + 1 , fn , N - 1 ,
private_data ) ;
if ( ! NT_STATUS_EQUAL ( nt_status , NT_STATUS_WRONG_PASSWORD ) ) {
return nt_status ;
2001-09-20 17:15:35 +04:00
}
1998-08-10 11:04:53 +04:00
s [ i ] = c ;
}
2001-09-20 17:15:35 +04:00
return ( NT_STATUS_WRONG_PASSWORD ) ;
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-08-21 16:48:28 +04:00
static NTSTATUS string_combinations ( char * s ,
NTSTATUS ( * fn ) ( const char * s ,
void * private_data ) ,
int N , void * private_data )
1998-08-10 11:04:53 +04:00
{
int n ;
2001-09-20 17:15:35 +04:00
NTSTATUS nt_status ;
2010-08-21 16:48:28 +04:00
for ( n = 1 ; n < = N ; n + + ) {
nt_status = string_combinations2 ( s , 0 , fn , n , private_data ) ;
if ( ! NT_STATUS_EQUAL ( nt_status , NT_STATUS_WRONG_PASSWORD ) ) {
2001-09-20 17:15:35 +04:00
return nt_status ;
2010-08-21 16:48:28 +04:00
}
}
2001-09-20 17:15:35 +04:00
return NT_STATUS_WRONG_PASSWORD ;
1998-08-10 11:04:53 +04:00
}
/****************************************************************************
core of password checking routine
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-08-21 16:48:28 +04:00
static NTSTATUS password_check ( const char * password , void * private_data )
1998-08-10 11:04:53 +04:00
{
1999-12-13 16:27:58 +03:00
# ifdef WITH_PAM
2010-08-21 16:52:16 +04:00
const char * rhost = ( const char * ) private_data ;
2010-08-21 16:41:01 +04:00
return smb_pam_passcheck ( get_this_user ( ) , rhost , password ) ;
2001-09-20 17:15:35 +04:00
# else
2007-10-19 04:40:25 +04:00
bool ret ;
2000-03-22 00:08:07 +03:00
1998-08-10 11:04:53 +04:00
# ifdef WITH_AFS
2007-12-18 04:02:48 +03:00
if ( afs_auth ( get_this_user ( ) , password ) )
2001-09-20 17:15:35 +04:00
return NT_STATUS_OK ;
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
2007-12-18 04:02:48 +03:00
if ( dfs_auth ( get_this_user ( ) , password ) )
2001-09-20 17:15:35 +04:00
return NT_STATUS_OK ;
1999-12-13 16:27:58 +03:00
# endif /* WITH_DFS */
1998-08-10 11:04:53 +04:00
# ifdef OSF1_ENH_SEC
2010-08-21 16:42:24 +04:00
2007-12-18 04:02:48 +03:00
ret = ( strcmp ( osf1_bigcrypt ( password , get_this_salt ( ) ) ,
get_this_crypted ( ) ) = = 0 ) ;
2001-09-20 17:15:35 +04:00
if ( ! ret ) {
DEBUG ( 2 ,
( " OSF1_ENH_SEC failed. Trying normal crypt. \n " ) ) ;
2007-12-18 04:02:48 +03:00
ret = ( strcmp ( ( char * ) crypt ( password , get_this_salt ( ) ) , get_this_crypted ( ) ) = = 0 ) ;
2001-09-20 17:15:35 +04:00
}
if ( ret ) {
return NT_STATUS_OK ;
} else {
return NT_STATUS_WRONG_PASSWORD ;
}
2010-08-21 16:42:24 +04:00
1999-12-13 16:27:58 +03:00
# endif /* OSF1_ENH_SEC */
2010-08-21 16:42:24 +04:00
1998-08-10 11:04:53 +04:00
# ifdef ULTRIX_AUTH
2007-12-18 04:02:48 +03:00
ret = ( strcmp ( ( char * ) crypt16 ( password , get_this_salt ( ) ) , get_this_crypted ( ) ) = = 0 ) ;
2001-09-20 17:15:35 +04:00
if ( ret ) {
return NT_STATUS_OK ;
} else {
return NT_STATUS_WRONG_PASSWORD ;
}
2010-08-21 16:42:24 +04:00
1999-12-13 16:27:58 +03:00
# endif /* ULTRIX_AUTH */
2010-08-21 16:42:24 +04:00
1998-08-10 11:04:53 +04:00
# ifdef LINUX_BIGCRYPT
2007-12-18 04:02:48 +03:00
ret = ( linux_bigcrypt ( password , get_this_salt ( ) , get_this_crypted ( ) ) ) ;
2001-09-20 17:15:35 +04:00
if ( ret ) {
return NT_STATUS_OK ;
} else {
return NT_STATUS_WRONG_PASSWORD ;
}
1999-12-13 16:27:58 +03:00
# endif /* LINUX_BIGCRYPT */
2010-08-21 16:42:24 +04:00
1999-12-13 16:27:58 +03:00
# if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
2010-08-21 16:42:24 +04:00
1999-12-13 16:27:58 +03:00
/*
* 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 .
*/
2007-12-18 04:02:48 +03:00
if ( strcmp ( bigcrypt ( password , get_this_salt ( ) ) , get_this_crypted ( ) ) = = 0 )
2001-09-20 17:15:35 +04:00
return NT_STATUS_OK ;
2000-03-22 00:08:07 +03:00
else
2007-12-18 04:02:48 +03:00
ret = ( strcmp ( ( char * ) crypt ( password , get_this_salt ( ) ) , get_this_crypted ( ) ) = = 0 ) ;
2001-09-20 17:15:35 +04:00
if ( ret ) {
return NT_STATUS_OK ;
} else {
return NT_STATUS_WRONG_PASSWORD ;
}
1999-12-13 16:27:58 +03:00
# else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
2010-08-21 16:42:24 +04:00
1998-08-10 11:04:53 +04:00
# ifdef HAVE_BIGCRYPT
2007-12-18 04:02:48 +03:00
ret = ( strcmp ( bigcrypt ( password , get_this_salt ( ) ) , get_this_crypted ( ) ) = = 0 ) ;
2001-09-20 17:15:35 +04:00
if ( ret ) {
return NT_STATUS_OK ;
} else {
return NT_STATUS_WRONG_PASSWORD ;
}
1999-12-13 16:27:58 +03:00
# endif /* HAVE_BIGCRYPT */
2010-08-21 16:42:24 +04:00
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 " ) ) ;
2001-09-20 17:15:35 +04:00
return NT_STATUS_LOGON_FAILURE ;
1999-12-13 16:27:58 +03:00
# else /* HAVE_CRYPT */
2007-12-18 04:02:48 +03:00
ret = ( strcmp ( ( char * ) crypt ( password , get_this_salt ( ) ) , get_this_crypted ( ) ) = = 0 ) ;
2001-09-20 17:15:35 +04:00
if ( ret ) {
return NT_STATUS_OK ;
} else {
return NT_STATUS_WRONG_PASSWORD ;
}
1999-12-13 16:27:58 +03:00
# endif /* HAVE_CRYPT */
# endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
2003-02-10 14:47:21 +03:00
# endif /* WITH_PAM */
1998-08-10 11:04:53 +04:00
}
/****************************************************************************
2001-09-20 17:15:35 +04:00
CHECK if a username / password is OK
1998-08-10 11:04:53 +04:00
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
2001-09-20 17:15:35 +04:00
return NT_STATUS_OK on correct match , appropriate error otherwise
1998-08-10 11:04:53 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-04-22 11:20:24 +04:00
2010-07-29 15:16:09 +04:00
NTSTATUS pass_check ( const struct passwd * pass ,
const char * user ,
2010-08-21 16:57:16 +04:00
const char * rhost ,
2010-07-29 15:16:09 +04:00
const char * password ,
bool run_cracker )
1998-08-10 11:04:53 +04:00
{
2007-11-14 21:37:18 +03:00
char * pass2 = NULL ;
1998-08-10 11:04:53 +04:00
int level = lp_passwordlevel ( ) ;
2001-09-20 17:15:35 +04:00
NTSTATUS nt_status ;
1998-08-10 11:04:53 +04:00
2004-10-11 04:32:31 +04:00
# ifdef 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 )
2001-09-20 17:15:35 +04:00
return NT_STATUS_LOGON_FAILURE ;
1998-08-10 11:04:53 +04:00
2010-06-01 15:52:01 +04:00
if ( ( ! * password ) & & ! lp_null_passwords ( ) )
2001-09-20 17:15:35 +04:00
return NT_STATUS_LOGON_FAILURE ;
1998-08-10 11:04:53 +04:00
2001-11-11 13:42:07 +03:00
# if defined(WITH_PAM)
2001-04-22 11:20:24 +04:00
/*
* If we ' re using PAM we want to short - circuit all the
* checks below and dive straight into the PAM code .
*/
2007-12-18 04:02:48 +03:00
if ( set_this_user ( user ) = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2001-04-22 11:20:24 +04:00
2010-06-01 15:52:01 +04:00
DEBUG ( 4 , ( " pass_check: Checking (PAM) password for user %s \n " , user ) ) ;
2001-04-22 11:20:24 +04:00
2002-01-17 11:45:58 +03:00
# else /* Not using PAM */
1998-08-10 11:04:53 +04:00
2010-06-01 15:52:01 +04:00
DEBUG ( 4 , ( " pass_check: Checking password for user %s \n " , user ) ) ;
1998-08-10 11:04:53 +04:00
2002-07-15 14:35:28 +04:00
if ( ! pass ) {
2000-03-22 00:08:07 +03:00
DEBUG ( 3 , ( " Couldn't find user %s \n " , user ) ) ;
2001-09-20 17:15:35 +04:00
return NT_STATUS_NO_SUCH_USER ;
1998-08-10 11:04:53 +04:00
}
2002-07-15 14:35:28 +04:00
/* Copy into global for the convenience of looping code */
/* Also the place to keep the 'password' no matter what
crazy struct it started in . . . */
2007-12-18 04:02:48 +03:00
if ( set_this_crypted ( pass - > pw_passwd ) = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
if ( set_this_salt ( pass - > pw_passwd ) = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2002-01-17 11:45:58 +03: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 ) ;
2002-10-01 17:10:57 +04:00
if ( spass & & spass - > sp_pwdp ) {
2007-12-18 04:02:48 +03:00
if ( set_this_crypted ( spass - > sp_pwdp ) = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
if ( set_this_salt ( spass - > sp_pwdp ) = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2002-10-01 17:10:57 +04:00
}
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 ) ;
2007-12-18 04:02:48 +03:00
if ( pr_pw & & pr_pw - > ufld . fd_encrypt ) {
if ( set_this_crypted ( pr_pw - > ufld . fd_encrypt ) = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
}
1999-12-13 16:27:58 +03:00
}
# endif
2002-01-17 11:45:58 +03:00
# ifdef HAVE_GETPWANAM
{
struct passwd_adjunct * pwret ;
pwret = getpwanam ( s ) ;
2007-12-18 04:02:48 +03:00
if ( pwret & & pwret - > pwa_passwd ) {
if ( set_this_crypted ( pwret - > pwa_passwd ) = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
}
2002-01-17 11:45:58 +03:00
}
# endif
1999-12-13 16:27:58 +03:00
# 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 ) {
2007-12-18 04:02:48 +03:00
if ( set_this_user ( mypasswd - > ufld . fd_name ) = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
if ( set_this_crypted ( mypasswd - > ufld . fd_encrypt ) = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
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 ) {
2007-12-18 04:02:48 +03:00
if ( set_this_crypted ( ap - > a_password ) = = NULL ) {
endauthent ( ) ;
return NT_STATUS_NO_MEMORY ;
}
1999-12-13 16:27:58 +03:00
endauthent ( ) ;
}
}
# endif
# 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 . */
2007-12-18 04:02:48 +03:00
{
char * trunc_salt = get_this_salt ( ) ;
if ( ! trunc_salt | | strlen ( trunc_salt ) < 2 ) {
return NT_STATUS_LOGON_FAILURE ;
}
trunc_salt [ 2 ] = 0 ;
if ( set_this_salt ( trunc_salt ) = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
}
1999-12-13 16:27:58 +03:00
# endif
2000-03-22 00:08:07 +03:00
2007-12-18 04:02:48 +03:00
if ( ! get_this_crypted ( ) | | ! * get_this_crypted ( ) ) {
2001-04-10 22:10:38 +04:00
if ( ! lp_null_passwords ( ) ) {
2000-03-22 00:08:07 +03:00
DEBUG ( 2 , ( " Disallowing %s with null password \n " ,
2007-12-18 04:02:48 +03:00
get_this_user ( ) ) ) ;
2001-09-20 17:15:35 +04:00
return NT_STATUS_LOGON_FAILURE ;
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 " ,
2007-12-18 04:02:48 +03:00
get_this_user ( ) ) ) ;
2001-09-20 17:15:35 +04:00
return NT_STATUS_OK ;
1998-08-10 11:04:53 +04:00
}
}
2001-11-11 13:42:07 +03:00
# endif /* defined(WITH_PAM) */
2001-04-22 11:20:24 +04:00
1998-08-10 11:04:53 +04:00
/* try it as it came to us */
2010-08-21 16:52:16 +04:00
nt_status = password_check ( password , ( void * ) rhost ) ;
2001-09-20 17:15:35 +04:00
if NT_STATUS_IS_OK ( nt_status ) {
return ( nt_status ) ;
} else if ( ! NT_STATUS_EQUAL ( nt_status , NT_STATUS_WRONG_PASSWORD ) ) {
/* No point continuing if its not the password thats to blame (ie PAM disabled). */
return ( nt_status ) ;
}
1998-08-10 11:04:53 +04:00
2001-09-19 09:26:11 +04:00
if ( ! run_cracker ) {
2001-09-20 17:15:35 +04:00
return ( nt_status ) ;
2001-09-19 09:26:11 +04:00
}
1998-08-10 11:04:53 +04:00
/* if the password was given to us with mixed case then we don't
2001-09-20 17:15:35 +04:00
* 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 ) ) {
2001-09-20 17:15:35 +04:00
return nt_status ;
1998-08-10 11:04:53 +04:00
}
/* make a copy of it */
2007-11-14 21:37:18 +03:00
pass2 = talloc_strdup ( talloc_tos ( ) , password ) ;
if ( ! pass2 ) {
return NT_STATUS_NO_MEMORY ;
}
2000-03-22 00:08:07 +03:00
2001-04-10 23:43:14 +04:00
/* try all lowercase if it's currently all uppercase */
2002-07-15 14:35:28 +04:00
if ( strhasupper ( pass2 ) ) {
2003-07-03 23:11:31 +04:00
strlower_m ( pass2 ) ;
2010-08-21 16:52:16 +04:00
nt_status = password_check ( pass2 , ( void * ) rhost ) ;
if ( NT_STATUS_IS_OK ( nt_status ) ) {
2001-09-20 17:15:35 +04:00
return ( nt_status ) ;
2001-04-10 23:43:14 +04:00
}
1998-08-10 11:04:53 +04:00
}
/* give up? */
2001-04-10 23:43:14 +04:00
if ( level < 1 ) {
2001-09-20 17:15:35 +04:00
return NT_STATUS_WRONG_PASSWORD ;
1998-08-10 11:04:53 +04:00
}
/* last chance - all combinations of up to level chars upper! */
2003-07-03 23:11:31 +04:00
strlower_m ( pass2 ) ;
2010-08-21 16:42:24 +04:00
2010-08-21 16:52:16 +04:00
nt_status = string_combinations ( pass2 , password_check , level ,
( void * ) rhost ) ;
2010-08-21 16:48:28 +04:00
if ( NT_STATUS_IS_OK ( nt_status ) ) {
2001-09-20 17:15:35 +04:00
return nt_status ;
1998-08-10 11:04:53 +04:00
}
2010-08-21 16:42:24 +04:00
2001-09-20 17:15:35 +04:00
return NT_STATUS_WRONG_PASSWORD ;
1998-08-10 11:04:53 +04:00
}