2010-10-29 12:55:07 +04:00
/*
2004-05-24 09:35:59 +04:00
Unix SMB / CIFS implementation .
samr server password set / change handling
Copyright ( C ) Andrew Tridgell 2004
2005-12-27 11:02:35 +03:00
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2005
2010-10-29 12:55:07 +04:00
2004-05-24 09:35:59 +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-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2004-05-24 09:35:59 +04:00
( at your option ) any later version .
2010-10-29 12:55:07 +04:00
2004-05-24 09:35:59 +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-10-29 12:55:07 +04:00
2004-05-24 09:35:59 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2004-05-24 09:35:59 +04:00
*/
# include "includes.h"
2004-11-02 10:42:47 +03:00
# include "rpc_server/dcerpc_server.h"
2004-05-24 09:35:59 +04:00
# include "rpc_server/samr/dcesrv_samr.h"
2004-11-02 03:24:21 +03:00
# include "system/time.h"
2008-09-24 17:30:23 +04:00
# include "../lib/crypto/crypto.h"
2005-12-28 18:38:36 +03:00
# include "dsdb/samdb/samdb.h"
# include "auth/auth.h"
2006-03-14 18:03:25 +03:00
# include "libcli/auth/libcli_auth.h"
2010-10-17 16:27:18 +04:00
# include "../lib/util/util_ldb.h"
2011-03-19 02:43:34 +03:00
# include "rpc_server/samr/proto.h"
2004-05-24 09:35:59 +04:00
2010-10-29 12:55:07 +04:00
/*
samr_ChangePasswordUser
2004-05-24 09:35:59 +04:00
*/
2010-10-29 12:55:07 +04:00
NTSTATUS dcesrv_samr_ChangePasswordUser ( struct dcesrv_call_state * dce_call ,
2007-12-04 01:33:22 +03:00
TALLOC_CTX * mem_ctx ,
struct samr_ChangePasswordUser * r )
2004-05-24 09:35:59 +04:00
{
struct dcesrv_handle * h ;
struct samr_account_state * a_state ;
2005-10-07 15:31:45 +04:00
struct ldb_context * sam_ctx ;
2009-09-26 14:09:07 +04:00
struct ldb_message * * res ;
2004-05-24 09:35:59 +04:00
int ret ;
2004-06-04 15:58:46 +04:00
struct samr_Password new_lmPwdHash , new_ntPwdHash , checkHash ;
struct samr_Password * lm_pwd , * nt_pwd ;
2004-05-24 09:35:59 +04:00
NTSTATUS status = NT_STATUS_OK ;
2007-02-15 15:54:58 +03:00
const char * const attrs [ ] = { " dBCSPwd " , " unicodePwd " , NULL } ;
2004-05-24 09:35:59 +04:00
2004-09-21 07:51:38 +04:00
DCESRV_PULL_HANDLE ( h , r - > in . user_handle , SAMR_HANDLE_USER ) ;
2004-05-24 09:35:59 +04:00
a_state = h - > data ;
2005-12-27 10:49:34 +03:00
/* basic sanity checking on parameters. Do this before any database ops */
2004-05-24 09:35:59 +04:00
if ( ! r - > in . lm_present | | ! r - > in . nt_present | |
! r - > in . old_lm_crypted | | ! r - > in . new_lm_crypted | |
! r - > in . old_nt_crypted | | ! r - > in . new_nt_crypted ) {
/* we should really handle a change with lm not
present */
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
2010-07-06 20:07:31 +04:00
/* Connect to a SAMDB with system privileges for fetching the old pw
* hashes . */
sam_ctx = samdb_connect ( mem_ctx , dce_call - > event_ctx ,
dce_call - > conn - > dce_ctx - > lp_ctx ,
2010-10-10 19:00:45 +04:00
system_session ( dce_call - > conn - > dce_ctx - > lp_ctx ) , 0 ) ;
2005-12-27 10:49:34 +03:00
if ( sam_ctx = = NULL ) {
return NT_STATUS_INVALID_SYSTEM_SERVICE ;
}
/* fetch the old hashes */
ret = gendb_search_dn ( sam_ctx , mem_ctx ,
a_state - > account_dn , & res , attrs ) ;
if ( ret ! = 1 ) {
return NT_STATUS_WRONG_PASSWORD ;
}
2009-09-26 14:09:07 +04:00
status = samdb_result_passwords ( mem_ctx ,
dce_call - > conn - > dce_ctx - > lp_ctx ,
res [ 0 ] , & lm_pwd , & nt_pwd ) ;
2009-05-25 07:39:56 +04:00
if ( ! NT_STATUS_IS_OK ( status ) | | ! nt_pwd ) {
2004-05-24 09:35:59 +04:00
return NT_STATUS_WRONG_PASSWORD ;
}
/* decrypt and check the new lm hash */
2009-05-25 07:39:56 +04:00
if ( lm_pwd ) {
D_P16 ( lm_pwd - > hash , r - > in . new_lm_crypted - > hash , new_lmPwdHash . hash ) ;
D_P16 ( new_lmPwdHash . hash , r - > in . old_lm_crypted - > hash , checkHash . hash ) ;
if ( memcmp ( checkHash . hash , lm_pwd , 16 ) ! = 0 ) {
return NT_STATUS_WRONG_PASSWORD ;
}
2004-05-24 09:35:59 +04:00
}
/* decrypt and check the new nt hash */
2004-06-04 15:58:46 +04:00
D_P16 ( nt_pwd - > hash , r - > in . new_nt_crypted - > hash , new_ntPwdHash . hash ) ;
2004-05-24 09:35:59 +04:00
D_P16 ( new_ntPwdHash . hash , r - > in . old_nt_crypted - > hash , checkHash . hash ) ;
2004-05-26 05:16:30 +04:00
if ( memcmp ( checkHash . hash , nt_pwd , 16 ) ! = 0 ) {
2004-05-24 09:35:59 +04:00
return NT_STATUS_WRONG_PASSWORD ;
}
2010-10-29 12:55:07 +04:00
2007-08-22 08:28:15 +04:00
/* The NT Cross is not required by Win2k3 R2, but if present
check the nt cross hash */
2009-05-25 07:39:56 +04:00
if ( r - > in . cross1_present & & r - > in . nt_cross & & lm_pwd ) {
2007-08-22 08:28:15 +04:00
D_P16 ( lm_pwd - > hash , r - > in . nt_cross - > hash , checkHash . hash ) ;
if ( memcmp ( checkHash . hash , new_ntPwdHash . hash , 16 ) ! = 0 ) {
return NT_STATUS_WRONG_PASSWORD ;
}
2004-05-24 09:35:59 +04:00
}
2007-08-22 08:28:15 +04:00
/* The LM Cross is not required by Win2k3 R2, but if present
check the lm cross hash */
2009-05-25 07:39:56 +04:00
if ( r - > in . cross2_present & & r - > in . lm_cross & & lm_pwd ) {
2007-08-22 08:28:15 +04:00
D_P16 ( nt_pwd - > hash , r - > in . lm_cross - > hash , checkHash . hash ) ;
if ( memcmp ( checkHash . hash , new_lmPwdHash . hash , 16 ) ! = 0 ) {
return NT_STATUS_WRONG_PASSWORD ;
}
2004-05-24 09:35:59 +04:00
}
2010-07-06 20:07:31 +04:00
/* Start a SAM with user privileges for the password change */
sam_ctx = samdb_connect ( mem_ctx , dce_call - > event_ctx ,
dce_call - > conn - > dce_ctx - > lp_ctx ,
2010-10-10 19:00:45 +04:00
dce_call - > conn - > auth_state . session_info , 0 ) ;
2010-07-06 20:07:31 +04:00
if ( sam_ctx = = NULL ) {
return NT_STATUS_INVALID_SYSTEM_SERVICE ;
}
/* Start transaction */
ret = ldb_transaction_start ( sam_ctx ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 1 , ( " Failed to start transaction: %s \n " , ldb_errstring ( sam_ctx ) ) ) ;
return NT_STATUS_TRANSACTION_ABORTED ;
}
/* Performs the password modification. We pass the old hashes read out
* from the database since they were already checked against the user -
* provided ones . */
2005-10-07 15:31:45 +04:00
status = samdb_set_password ( sam_ctx , mem_ctx ,
2009-09-26 14:09:07 +04:00
a_state - > account_dn ,
a_state - > domain_state - > domain_dn ,
NULL , & new_lmPwdHash , & new_ntPwdHash ,
2010-07-06 20:07:31 +04:00
lm_pwd , nt_pwd , /* this is a user password change */
2005-10-20 07:17:42 +04:00
NULL ,
2005-01-12 13:49:52 +03:00
NULL ) ;
2004-05-24 09:35:59 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2005-12-27 10:49:34 +03:00
ldb_transaction_cancel ( sam_ctx ) ;
2004-05-24 09:35:59 +04:00
return status ;
}
2005-12-27 10:49:34 +03:00
/* And this confirms it in a transaction commit */
ret = ldb_transaction_commit ( sam_ctx ) ;
2009-11-21 21:25:42 +03:00
if ( ret ! = LDB_SUCCESS ) {
2005-12-30 11:40:16 +03:00
DEBUG ( 1 , ( " Failed to commit transaction to change password on %s: %s \n " ,
2006-11-22 05:05:19 +03:00
ldb_dn_get_linearized ( a_state - > account_dn ) ,
2005-12-27 10:49:34 +03:00
ldb_errstring ( sam_ctx ) ) ) ;
2006-01-03 01:50:12 +03:00
return NT_STATUS_TRANSACTION_ABORTED ;
2005-12-27 10:49:34 +03:00
}
2004-05-24 09:35:59 +04:00
return NT_STATUS_OK ;
}
2010-10-29 12:55:07 +04:00
/*
samr_OemChangePasswordUser2
2004-05-24 09:35:59 +04:00
*/
2009-09-26 00:44:00 +04:00
NTSTATUS dcesrv_samr_OemChangePasswordUser2 ( struct dcesrv_call_state * dce_call ,
TALLOC_CTX * mem_ctx ,
struct samr_OemChangePasswordUser2 * r )
2004-05-24 09:35:59 +04:00
{
NTSTATUS status ;
2008-10-17 05:41:02 +04:00
DATA_BLOB new_password , new_unicode_password ;
2008-10-16 05:48:16 +04:00
char * new_pass ;
2004-05-24 09:35:59 +04:00
struct samr_CryptPassword * pwbuf = r - > in . password ;
2005-10-07 15:31:45 +04:00
struct ldb_context * sam_ctx ;
2006-11-22 03:59:34 +03:00
struct ldb_dn * user_dn ;
2004-05-24 09:35:59 +04:00
int ret ;
2009-09-26 14:09:07 +04:00
struct ldb_message * * res ;
2007-02-15 15:54:58 +03:00
const char * const attrs [ ] = { " objectSid " , " dBCSPwd " , NULL } ;
2004-06-04 15:58:46 +04:00
struct samr_Password * lm_pwd ;
DATA_BLOB lm_pwd_blob ;
2004-11-25 04:13:44 +03:00
uint8_t new_lm_hash [ 16 ] ;
struct samr_Password lm_verifier ;
2009-03-01 21:55:46 +03:00
size_t unicode_pw_len ;
2011-03-29 22:16:26 +04:00
size_t converted_size = 0 ;
2004-05-24 09:35:59 +04:00
if ( pwbuf = = NULL ) {
2007-08-22 08:28:15 +04:00
return NT_STATUS_INVALID_PARAMETER ;
}
if ( r - > in . hash = = NULL ) {
return NT_STATUS_INVALID_PARAMETER ;
2004-05-24 09:35:59 +04:00
}
2009-05-25 07:39:56 +04:00
/* this call can only work with lanman auth */
2010-07-16 08:32:42 +04:00
if ( ! lpcfg_lanman_auth ( dce_call - > conn - > dce_ctx - > lp_ctx ) ) {
2010-06-22 00:59:11 +04:00
return NT_STATUS_WRONG_PASSWORD ;
2009-05-25 07:39:56 +04:00
}
2010-07-06 20:07:31 +04:00
/* Connect to a SAMDB with system privileges for fetching the old pw
* hashes . */
sam_ctx = samdb_connect ( mem_ctx , dce_call - > event_ctx ,
dce_call - > conn - > dce_ctx - > lp_ctx ,
2010-10-10 19:00:45 +04:00
system_session ( dce_call - > conn - > dce_ctx - > lp_ctx ) , 0 ) ;
2004-05-24 09:35:59 +04:00
if ( sam_ctx = = NULL ) {
return NT_STATUS_INVALID_SYSTEM_SERVICE ;
}
/* we need the users dn and the domain dn (derived from the
user SID ) . We also need the current lm password hash in
order to decrypt the incoming password */
2010-10-29 12:55:07 +04:00
ret = gendb_search ( sam_ctx ,
2006-08-25 11:08:06 +04:00
mem_ctx , NULL , & res , attrs ,
2004-05-24 09:35:59 +04:00
" (&(sAMAccountName=%s)(objectclass=user)) " ,
2004-11-13 16:45:41 +03:00
r - > in . account - > string ) ;
2004-05-24 09:35:59 +04:00
if ( ret ! = 1 ) {
2005-12-27 10:49:34 +03:00
/* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */
return NT_STATUS_WRONG_PASSWORD ;
2004-05-24 09:35:59 +04:00
}
user_dn = res [ 0 ] - > dn ;
2008-10-16 05:48:16 +04:00
status = samdb_result_passwords ( mem_ctx , dce_call - > conn - > dce_ctx - > lp_ctx ,
res [ 0 ] , & lm_pwd , NULL ) ;
2004-05-26 05:16:30 +04:00
if ( ! NT_STATUS_IS_OK ( status ) | | ! lm_pwd ) {
2004-05-24 09:35:59 +04:00
return NT_STATUS_WRONG_PASSWORD ;
}
/* decrypt the password we have been given */
2010-10-29 12:55:07 +04:00
lm_pwd_blob = data_blob ( lm_pwd - > hash , sizeof ( lm_pwd - > hash ) ) ;
2004-06-04 15:58:46 +04:00
arcfour_crypt_blob ( pwbuf - > data , 516 , & lm_pwd_blob ) ;
data_blob_free ( & lm_pwd_blob ) ;
2010-10-29 12:55:07 +04:00
2008-10-16 05:48:16 +04:00
if ( ! extract_pw_from_buffer ( mem_ctx , pwbuf - > data , & new_password ) ) {
2004-05-24 09:35:59 +04:00
DEBUG ( 3 , ( " samr: failed to decode password buffer \n " ) ) ;
return NT_STATUS_WRONG_PASSWORD ;
}
2010-10-29 12:55:07 +04:00
2011-03-25 00:37:00 +03:00
if ( ! convert_string_talloc_handle ( mem_ctx , lpcfg_iconv_handle ( dce_call - > conn - > dce_ctx - > lp_ctx ) ,
2010-10-29 12:55:07 +04:00
CH_DOS , CH_UNIX ,
( const char * ) new_password . data ,
2008-10-16 05:48:16 +04:00
new_password . length ,
2011-03-29 22:16:26 +04:00
( void * * ) & new_pass , & converted_size ) ) {
2008-10-16 05:48:16 +04:00
DEBUG ( 3 , ( " samr: failed to convert incoming password buffer to unix charset \n " ) ) ;
2004-11-25 04:13:44 +03:00
return NT_STATUS_WRONG_PASSWORD ;
}
2011-03-25 00:37:00 +03:00
if ( ! convert_string_talloc_handle ( mem_ctx , lpcfg_iconv_handle ( dce_call - > conn - > dce_ctx - > lp_ctx ) ,
2010-10-29 12:55:07 +04:00
CH_DOS , CH_UTF16 ,
( const char * ) new_password . data ,
2008-10-17 05:41:02 +04:00
new_password . length ,
2011-03-24 02:59:41 +03:00
( void * * ) & new_unicode_password . data , & unicode_pw_len ) ) {
2008-10-17 05:41:02 +04:00
DEBUG ( 3 , ( " samr: failed to convert incoming password buffer to UTF16 charset \n " ) ) ;
return NT_STATUS_WRONG_PASSWORD ;
}
new_unicode_password . length = unicode_pw_len ;
2004-11-25 04:13:44 +03:00
E_deshash ( new_pass , new_lm_hash ) ;
E_old_pw_hash ( new_lm_hash , lm_pwd - > hash , lm_verifier . hash ) ;
if ( memcmp ( lm_verifier . hash , r - > in . hash - > hash , 16 ) ! = 0 ) {
return NT_STATUS_WRONG_PASSWORD ;
}
2010-07-06 20:07:31 +04:00
/* Connect to a SAMDB with user privileges for the password change */
sam_ctx = samdb_connect ( mem_ctx , dce_call - > event_ctx ,
dce_call - > conn - > dce_ctx - > lp_ctx ,
2010-10-10 19:00:45 +04:00
dce_call - > conn - > auth_state . session_info , 0 ) ;
2010-07-06 20:07:31 +04:00
if ( sam_ctx = = NULL ) {
return NT_STATUS_INVALID_SYSTEM_SERVICE ;
}
/* Start transaction */
ret = ldb_transaction_start ( sam_ctx ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 1 , ( " Failed to start transaction: %s \n " , ldb_errstring ( sam_ctx ) ) ) ;
return NT_STATUS_TRANSACTION_ABORTED ;
}
/* Performs the password modification. We pass the old hashes read out
* from the database since they were already checked against the user -
* provided ones . */
2004-05-24 09:35:59 +04:00
status = samdb_set_password ( sam_ctx , mem_ctx ,
2010-10-29 12:55:07 +04:00
user_dn , NULL ,
2009-09-26 14:09:07 +04:00
& new_unicode_password ,
2004-05-24 09:35:59 +04:00
NULL , NULL ,
2010-07-06 20:07:31 +04:00
lm_pwd , NULL , /* this is a user password change */
2010-10-29 12:55:07 +04:00
NULL ,
2005-01-12 13:49:52 +03:00
NULL ) ;
2004-05-24 09:35:59 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2005-12-27 10:49:34 +03:00
ldb_transaction_cancel ( sam_ctx ) ;
2004-05-24 09:35:59 +04:00
return status ;
}
2005-12-27 10:49:34 +03:00
/* And this confirms it in a transaction commit */
ret = ldb_transaction_commit ( sam_ctx ) ;
2009-11-21 21:25:42 +03:00
if ( ret ! = LDB_SUCCESS ) {
2006-01-03 01:50:12 +03:00
DEBUG ( 1 , ( " Failed to commit transaction to change password on %s: %s \n " ,
2006-11-22 05:05:19 +03:00
ldb_dn_get_linearized ( user_dn ) ,
2005-12-27 10:49:34 +03:00
ldb_errstring ( sam_ctx ) ) ) ;
2006-01-03 01:50:12 +03:00
return NT_STATUS_TRANSACTION_ABORTED ;
2005-12-27 10:49:34 +03:00
}
2004-05-24 09:35:59 +04:00
return NT_STATUS_OK ;
}
2010-10-29 12:55:07 +04:00
/*
samr_ChangePasswordUser3
2004-05-24 09:35:59 +04:00
*/
2010-10-29 12:55:07 +04:00
NTSTATUS dcesrv_samr_ChangePasswordUser3 ( struct dcesrv_call_state * dce_call ,
2009-09-26 00:44:00 +04:00
TALLOC_CTX * mem_ctx ,
struct samr_ChangePasswordUser3 * r )
2010-10-29 12:55:07 +04:00
{
2004-05-25 17:57:39 +04:00
NTSTATUS status ;
2008-10-16 05:48:16 +04:00
DATA_BLOB new_password ;
2005-12-27 10:49:34 +03:00
struct ldb_context * sam_ctx = NULL ;
2006-11-22 03:59:34 +03:00
struct ldb_dn * user_dn ;
2004-05-25 17:57:39 +04:00
int ret ;
2009-09-26 14:09:07 +04:00
struct ldb_message * * res ;
2007-02-15 15:54:58 +03:00
const char * const attrs [ ] = { " unicodePwd " , " dBCSPwd " , NULL } ;
2004-11-25 04:13:44 +03:00
struct samr_Password * nt_pwd , * lm_pwd ;
2004-06-04 15:58:46 +04:00
DATA_BLOB nt_pwd_blob ;
2005-12-27 10:49:34 +03:00
struct samr_DomInfo1 * dominfo = NULL ;
2009-09-26 00:44:00 +04:00
struct userPwdChangeFailureInformation * reject = NULL ;
enum samPwdChangeReason reason = SAM_PWD_CHANGE_NO_ERROR ;
2004-11-25 04:13:44 +03:00
uint8_t new_nt_hash [ 16 ] , new_lm_hash [ 16 ] ;
struct samr_Password nt_verifier , lm_verifier ;
2004-05-25 17:57:39 +04:00
2008-11-04 21:40:24 +03:00
* r - > out . dominfo = NULL ;
* r - > out . reject = NULL ;
2004-05-25 17:57:39 +04:00
if ( r - > in . nt_password = = NULL | |
r - > in . nt_verifier = = NULL ) {
2005-12-27 10:49:34 +03:00
return NT_STATUS_INVALID_PARAMETER ;
2004-05-25 17:57:39 +04:00
}
2010-07-06 20:07:31 +04:00
/* Connect to a SAMDB with system privileges for fetching the old pw
* hashes . */
sam_ctx = samdb_connect ( mem_ctx , dce_call - > event_ctx ,
dce_call - > conn - > dce_ctx - > lp_ctx ,
2010-10-10 19:00:45 +04:00
system_session ( dce_call - > conn - > dce_ctx - > lp_ctx ) , 0 ) ;
2004-05-25 17:57:39 +04:00
if ( sam_ctx = = NULL ) {
2005-10-07 15:31:45 +04:00
return NT_STATUS_INVALID_SYSTEM_SERVICE ;
2005-12-27 10:49:34 +03:00
}
2004-05-25 17:57:39 +04:00
/* we need the users dn and the domain dn (derived from the
user SID ) . We also need the current lm and nt password hashes
in order to decrypt the incoming passwords */
2010-10-29 12:55:07 +04:00
ret = gendb_search ( sam_ctx ,
2006-08-25 11:08:06 +04:00
mem_ctx , NULL , & res , attrs ,
2004-05-25 17:57:39 +04:00
" (&(sAMAccountName=%s)(objectclass=user)) " ,
2004-11-13 16:45:41 +03:00
r - > in . account - > string ) ;
2004-05-25 17:57:39 +04:00
if ( ret ! = 1 ) {
2005-12-27 10:49:34 +03:00
/* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */
status = NT_STATUS_WRONG_PASSWORD ;
2004-05-25 17:57:39 +04:00
goto failed ;
}
user_dn = res [ 0 ] - > dn ;
2010-07-16 08:32:42 +04:00
status = samdb_result_passwords ( mem_ctx , dce_call - > conn - > dce_ctx - > lp_ctx ,
2008-10-16 05:48:16 +04:00
res [ 0 ] , & lm_pwd , & nt_pwd ) ;
2004-06-04 15:58:46 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto failed ;
}
if ( ! nt_pwd ) {
status = NT_STATUS_WRONG_PASSWORD ;
2004-05-25 17:57:39 +04:00
goto failed ;
}
/* decrypt the password we have been given */
2004-06-04 15:58:46 +04:00
nt_pwd_blob = data_blob ( nt_pwd - > hash , sizeof ( nt_pwd - > hash ) ) ;
arcfour_crypt_blob ( r - > in . nt_password - > data , 516 , & nt_pwd_blob ) ;
data_blob_free ( & nt_pwd_blob ) ;
2004-05-25 17:57:39 +04:00
2008-10-16 05:48:16 +04:00
if ( ! extract_pw_from_buffer ( mem_ctx , r - > in . nt_password - > data , & new_password ) ) {
2004-05-25 17:57:39 +04:00
DEBUG ( 3 , ( " samr: failed to decode password buffer \n " ) ) ;
2010-07-06 20:07:31 +04:00
status = NT_STATUS_WRONG_PASSWORD ;
goto failed ;
2004-05-25 17:57:39 +04:00
}
2010-10-29 12:55:07 +04:00
2004-11-25 04:13:44 +03:00
if ( r - > in . nt_verifier = = NULL ) {
status = NT_STATUS_WRONG_PASSWORD ;
goto failed ;
}
/* check NT verifier */
2008-10-16 05:48:16 +04:00
mdfour ( new_nt_hash , new_password . data , new_password . length ) ;
2004-11-25 04:13:44 +03:00
E_old_pw_hash ( new_nt_hash , nt_pwd - > hash , nt_verifier . hash ) ;
if ( memcmp ( nt_verifier . hash , r - > in . nt_verifier - > hash , 16 ) ! = 0 ) {
status = NT_STATUS_WRONG_PASSWORD ;
goto failed ;
}
2008-10-16 05:48:16 +04:00
/* check LM verifier (really not needed as we just checked the
* much stronger NT hash , but the RPC - SAMR test checks for
* this ) */
2004-11-25 04:13:44 +03:00
if ( lm_pwd & & r - > in . lm_verifier ! = NULL ) {
2008-10-16 05:48:16 +04:00
char * new_pass ;
2011-03-29 22:16:26 +04:00
size_t converted_size = 0 ;
2011-03-25 00:37:00 +03:00
if ( ! convert_string_talloc_handle ( mem_ctx , lpcfg_iconv_handle ( dce_call - > conn - > dce_ctx - > lp_ctx ) ,
2010-10-29 12:55:07 +04:00
CH_UTF16 , CH_UNIX ,
( const char * ) new_password . data ,
2008-10-16 05:48:16 +04:00
new_password . length ,
2011-03-29 22:16:26 +04:00
( void * * ) & new_pass , & converted_size ) ) {
2008-10-16 05:48:16 +04:00
E_deshash ( new_pass , new_lm_hash ) ;
E_old_pw_hash ( new_nt_hash , lm_pwd - > hash , lm_verifier . hash ) ;
if ( memcmp ( lm_verifier . hash , r - > in . lm_verifier - > hash , 16 ) ! = 0 ) {
status = NT_STATUS_WRONG_PASSWORD ;
goto failed ;
}
2004-11-25 04:13:44 +03:00
}
}
2010-07-06 20:07:31 +04:00
/* Connect to a SAMDB with user privileges for the password change */
sam_ctx = samdb_connect ( mem_ctx , dce_call - > event_ctx ,
dce_call - > conn - > dce_ctx - > lp_ctx ,
2010-10-10 19:00:45 +04:00
dce_call - > conn - > auth_state . session_info , 0 ) ;
2010-07-06 20:07:31 +04:00
if ( sam_ctx = = NULL ) {
return NT_STATUS_INVALID_SYSTEM_SERVICE ;
}
ret = ldb_transaction_start ( sam_ctx ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 1 , ( " Failed to start transaction: %s \n " , ldb_errstring ( sam_ctx ) ) ) ;
return NT_STATUS_TRANSACTION_ABORTED ;
}
/* Performs the password modification. We pass the old hashes read out
* from the database since they were already checked against the user -
* provided ones . */
2004-05-25 17:57:39 +04:00
status = samdb_set_password ( sam_ctx , mem_ctx ,
2010-10-29 12:55:07 +04:00
user_dn , NULL ,
2009-09-26 14:09:07 +04:00
& new_password ,
2004-05-25 17:57:39 +04:00
NULL , NULL ,
2010-07-06 20:07:31 +04:00
lm_pwd , nt_pwd , /* this is a user password change */
2010-10-29 12:55:07 +04:00
& reason ,
2005-10-20 07:17:42 +04:00
& dominfo ) ;
2009-09-26 00:44:00 +04:00
2004-05-25 17:57:39 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-07-06 20:07:31 +04:00
ldb_transaction_cancel ( sam_ctx ) ;
2004-05-25 17:57:39 +04:00
goto failed ;
}
2005-12-27 10:49:34 +03:00
/* And this confirms it in a transaction commit */
ret = ldb_transaction_commit ( sam_ctx ) ;
2009-11-21 21:25:42 +03:00
if ( ret ! = LDB_SUCCESS ) {
2006-01-03 01:50:12 +03:00
DEBUG ( 1 , ( " Failed to commit transaction to change password on %s: %s \n " ,
2006-11-22 05:05:19 +03:00
ldb_dn_get_linearized ( user_dn ) ,
2005-12-27 10:49:34 +03:00
ldb_errstring ( sam_ctx ) ) ) ;
2006-01-03 01:50:12 +03:00
status = NT_STATUS_TRANSACTION_ABORTED ;
2005-12-27 10:49:34 +03:00
goto failed ;
}
2004-05-25 17:57:39 +04:00
return NT_STATUS_OK ;
failed :
2009-09-26 14:09:07 +04:00
reject = talloc_zero ( mem_ctx , struct userPwdChangeFailureInformation ) ;
2009-09-26 00:44:00 +04:00
if ( reject ! = NULL ) {
reject - > extendedFailureReason = reason ;
2005-12-27 10:49:34 +03:00
2009-09-26 00:44:00 +04:00
* r - > out . reject = reject ;
2004-05-25 17:57:39 +04:00
}
2009-09-26 00:44:00 +04:00
* r - > out . dominfo = dominfo ;
2004-05-25 17:57:39 +04:00
return status ;
2004-05-24 09:35:59 +04:00
}
2010-10-29 12:55:07 +04:00
/*
samr_ChangePasswordUser2
2004-05-26 05:16:30 +04:00
easy - just a subset of samr_ChangePasswordUser3
*/
2009-09-26 00:44:00 +04:00
NTSTATUS dcesrv_samr_ChangePasswordUser2 ( struct dcesrv_call_state * dce_call ,
TALLOC_CTX * mem_ctx ,
struct samr_ChangePasswordUser2 * r )
2004-05-26 05:16:30 +04:00
{
struct samr_ChangePasswordUser3 r2 ;
2008-11-04 21:40:24 +03:00
struct samr_DomInfo1 * dominfo = NULL ;
2009-09-26 00:44:00 +04:00
struct userPwdChangeFailureInformation * reject = NULL ;
2004-05-26 05:16:30 +04:00
r2 . in . server = r - > in . server ;
r2 . in . account = r - > in . account ;
r2 . in . nt_password = r - > in . nt_password ;
r2 . in . nt_verifier = r - > in . nt_verifier ;
r2 . in . lm_change = r - > in . lm_change ;
r2 . in . lm_password = r - > in . lm_password ;
r2 . in . lm_verifier = r - > in . lm_verifier ;
r2 . in . password3 = NULL ;
2008-11-04 21:40:24 +03:00
r2 . out . dominfo = & dominfo ;
r2 . out . reject = & reject ;
2004-05-26 05:16:30 +04:00
2007-01-17 17:49:36 +03:00
return dcesrv_samr_ChangePasswordUser3 ( dce_call , mem_ctx , & r2 ) ;
2004-05-26 05:16:30 +04:00
}
2004-05-24 09:35:59 +04:00
/*
set password via a samr_CryptPassword buffer
*/
NTSTATUS samr_set_password ( struct dcesrv_call_state * dce_call ,
2009-09-26 14:09:07 +04:00
struct ldb_context * sam_ctx ,
2006-11-22 03:59:34 +03:00
struct ldb_dn * account_dn , struct ldb_dn * domain_dn ,
2004-05-24 09:35:59 +04:00
TALLOC_CTX * mem_ctx ,
struct samr_CryptPassword * pwbuf )
{
2004-09-12 07:18:24 +04:00
NTSTATUS nt_status ;
2008-10-16 05:48:16 +04:00
DATA_BLOB new_password ;
r1294: A nice, large, commit...
This implements gensec for Samba's server side, and brings gensec up
to the standards of a full subsystem.
This means that use of the subsystem is by gensec_* functions, not
function pointers in structures (this is internal). This causes
changes in all the existing gensec users.
Our RPC server no longer contains it's own generalised security
scheme, and now calls gensec directly.
Gensec has also taken over the role of auth/auth_ntlmssp.c
An important part of gensec, is the output of the 'session_info'
struct. This is now reference counted, so that we can correctly free
it when a pipe is closed, no matter if it was inherited, or created by
per-pipe authentication.
The schannel code is reworked, to be in the same file for client and
server.
ntlm_auth is reworked to use gensec.
The major problem with this code is the way it relies on subsystem
auto-initialisation. The primary reason for this commit now.is to
allow these problems to be looked at, and fixed.
There are problems with the new code:
- I've tested it with smbtorture, but currently don't have VMware and
valgrind working (this I'll fix soon).
- The SPNEGO code is client-only at this point.
- We still do not do kerberos.
Andrew Bartlett
(This used to be commit 07fd885fd488fd1051eacc905a2d4962f8a018ec)
2004-06-29 13:40:10 +04:00
DATA_BLOB session_key = data_blob ( NULL , 0 ) ;
2004-06-08 01:34:32 +04:00
2004-09-12 07:18:24 +04:00
nt_status = dcesrv_fetch_session_key ( dce_call - > conn , & session_key ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
return nt_status ;
2004-06-07 12:50:21 +04:00
}
2004-06-04 03:15:16 +04:00
arcfour_crypt_blob ( pwbuf - > data , 516 , & session_key ) ;
2004-05-24 09:35:59 +04:00
2008-10-16 05:48:16 +04:00
if ( ! extract_pw_from_buffer ( mem_ctx , pwbuf - > data , & new_password ) ) {
2004-05-24 09:35:59 +04:00
DEBUG ( 3 , ( " samr: failed to decode password buffer \n " ) ) ;
return NT_STATUS_WRONG_PASSWORD ;
}
2010-10-29 12:55:07 +04:00
2004-05-24 09:35:59 +04:00
/* set the password - samdb needs to know both the domain and user DNs,
so the domain password policy can be used */
return samdb_set_password ( sam_ctx , mem_ctx ,
2010-10-29 12:55:07 +04:00
account_dn , domain_dn ,
2009-09-26 14:09:07 +04:00
& new_password ,
2004-05-24 09:35:59 +04:00
NULL , NULL ,
2010-08-15 23:06:11 +04:00
NULL , NULL , /* This is a password set, not change */
2005-10-20 07:17:42 +04:00
NULL , NULL ) ;
2004-05-24 09:35:59 +04:00
}
2004-05-26 08:20:17 +04:00
/*
set password via a samr_CryptPasswordEx buffer
*/
NTSTATUS samr_set_password_ex ( struct dcesrv_call_state * dce_call ,
2005-10-20 07:17:42 +04:00
struct ldb_context * sam_ctx ,
2009-09-26 00:44:00 +04:00
struct ldb_dn * account_dn ,
struct ldb_dn * domain_dn ,
2004-05-26 08:20:17 +04:00
TALLOC_CTX * mem_ctx ,
struct samr_CryptPasswordEx * pwbuf )
{
2004-09-12 07:18:24 +04:00
NTSTATUS nt_status ;
2008-10-16 05:48:16 +04:00
DATA_BLOB new_password ;
2004-05-26 08:20:17 +04:00
DATA_BLOB co_session_key ;
r1294: A nice, large, commit...
This implements gensec for Samba's server side, and brings gensec up
to the standards of a full subsystem.
This means that use of the subsystem is by gensec_* functions, not
function pointers in structures (this is internal). This causes
changes in all the existing gensec users.
Our RPC server no longer contains it's own generalised security
scheme, and now calls gensec directly.
Gensec has also taken over the role of auth/auth_ntlmssp.c
An important part of gensec, is the output of the 'session_info'
struct. This is now reference counted, so that we can correctly free
it when a pipe is closed, no matter if it was inherited, or created by
per-pipe authentication.
The schannel code is reworked, to be in the same file for client and
server.
ntlm_auth is reworked to use gensec.
The major problem with this code is the way it relies on subsystem
auto-initialisation. The primary reason for this commit now.is to
allow these problems to be looked at, and fixed.
There are problems with the new code:
- I've tested it with smbtorture, but currently don't have VMware and
valgrind working (this I'll fix soon).
- The SPNEGO code is client-only at this point.
- We still do not do kerberos.
Andrew Bartlett
(This used to be commit 07fd885fd488fd1051eacc905a2d4962f8a018ec)
2004-06-29 13:40:10 +04:00
DATA_BLOB session_key = data_blob ( NULL , 0 ) ;
2004-05-26 08:20:17 +04:00
struct MD5Context ctx ;
2004-09-12 07:18:24 +04:00
nt_status = dcesrv_fetch_session_key ( dce_call - > conn , & session_key ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
return nt_status ;
r1294: A nice, large, commit...
This implements gensec for Samba's server side, and brings gensec up
to the standards of a full subsystem.
This means that use of the subsystem is by gensec_* functions, not
function pointers in structures (this is internal). This causes
changes in all the existing gensec users.
Our RPC server no longer contains it's own generalised security
scheme, and now calls gensec directly.
Gensec has also taken over the role of auth/auth_ntlmssp.c
An important part of gensec, is the output of the 'session_info'
struct. This is now reference counted, so that we can correctly free
it when a pipe is closed, no matter if it was inherited, or created by
per-pipe authentication.
The schannel code is reworked, to be in the same file for client and
server.
ntlm_auth is reworked to use gensec.
The major problem with this code is the way it relies on subsystem
auto-initialisation. The primary reason for this commit now.is to
allow these problems to be looked at, and fixed.
There are problems with the new code:
- I've tested it with smbtorture, but currently don't have VMware and
valgrind working (this I'll fix soon).
- The SPNEGO code is client-only at this point.
- We still do not do kerberos.
Andrew Bartlett
(This used to be commit 07fd885fd488fd1051eacc905a2d4962f8a018ec)
2004-06-29 13:40:10 +04:00
}
2004-05-26 08:20:17 +04:00
co_session_key = data_blob_talloc ( mem_ctx , NULL , 16 ) ;
if ( ! co_session_key . data ) {
return NT_STATUS_NO_MEMORY ;
}
MD5Init ( & ctx ) ;
MD5Update ( & ctx , & pwbuf - > data [ 516 ] , 16 ) ;
MD5Update ( & ctx , session_key . data , session_key . length ) ;
MD5Final ( co_session_key . data , & ctx ) ;
2010-10-29 12:55:07 +04:00
2004-06-04 03:15:16 +04:00
arcfour_crypt_blob ( pwbuf - > data , 516 , & co_session_key ) ;
2004-05-26 08:20:17 +04:00
2008-10-16 05:48:16 +04:00
if ( ! extract_pw_from_buffer ( mem_ctx , pwbuf - > data , & new_password ) ) {
2004-05-26 08:20:17 +04:00
DEBUG ( 3 , ( " samr: failed to decode password buffer \n " ) ) ;
return NT_STATUS_WRONG_PASSWORD ;
}
2010-10-29 12:55:07 +04:00
2004-05-26 08:20:17 +04:00
/* set the password - samdb needs to know both the domain and user DNs,
so the domain password policy can be used */
return samdb_set_password ( sam_ctx , mem_ctx ,
2010-10-29 12:55:07 +04:00
account_dn , domain_dn ,
2009-09-26 14:09:07 +04:00
& new_password ,
2004-05-26 08:20:17 +04:00
NULL , NULL ,
2010-08-15 23:06:11 +04:00
NULL , NULL , /* This is a password set, not change */
2005-10-20 07:17:42 +04:00
NULL , NULL ) ;
2004-05-26 08:20:17 +04:00
}
2010-06-21 23:16:20 +04:00
/*
set password via encrypted NT and LM hash buffers
*/
NTSTATUS samr_set_password_buffers ( struct dcesrv_call_state * dce_call ,
struct ldb_context * sam_ctx ,
struct ldb_dn * account_dn ,
struct ldb_dn * domain_dn ,
TALLOC_CTX * mem_ctx ,
const uint8_t * lm_pwd_hash ,
const uint8_t * nt_pwd_hash )
{
struct samr_Password * d_lm_pwd_hash = NULL , * d_nt_pwd_hash = NULL ;
DATA_BLOB session_key = data_blob ( NULL , 0 ) ;
DATA_BLOB in , out ;
NTSTATUS nt_status = NT_STATUS_OK ;
nt_status = dcesrv_fetch_session_key ( dce_call - > conn , & session_key ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
return nt_status ;
}
if ( lm_pwd_hash ! = NULL ) {
in = data_blob_const ( lm_pwd_hash , 16 ) ;
out = data_blob_talloc_zero ( mem_ctx , 16 ) ;
sess_crypt_blob ( & out , & in , & session_key , false ) ;
d_lm_pwd_hash = ( struct samr_Password * ) out . data ;
}
if ( nt_pwd_hash ! = NULL ) {
in = data_blob_const ( nt_pwd_hash , 16 ) ;
out = data_blob_talloc_zero ( mem_ctx , 16 ) ;
sess_crypt_blob ( & out , & in , & session_key , false ) ;
d_nt_pwd_hash = ( struct samr_Password * ) out . data ;
}
if ( ( d_lm_pwd_hash ! = NULL ) | | ( d_nt_pwd_hash ! = NULL ) ) {
nt_status = samdb_set_password ( sam_ctx , mem_ctx , account_dn ,
domain_dn , NULL ,
d_lm_pwd_hash , d_nt_pwd_hash ,
2010-08-15 23:06:11 +04:00
NULL , NULL , /* this is a password set */
2010-06-21 23:16:20 +04:00
NULL , NULL ) ;
}
return nt_status ;
}