2008-06-18 14:52:00 +04:00
/*
Unix SMB / CIFS implementation .
dump the remote SAM using rpc samsync operations
Copyright ( C ) Guenther Deschner 2008.
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 3 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 , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2010-08-10 06:00:29 +04:00
# include "smb_krb5.h"
# include "ads.h"
# include "libnet/libnet_keytab.h"
2010-07-02 02:14:04 +04:00
# include "libnet/libnet_samsync.h"
2010-08-18 20:45:36 +04:00
# include "krb5_env.h"
2008-06-18 14:52:00 +04:00
2010-08-10 02:25:02 +04:00
# if defined(HAVE_ADS)
2008-06-18 14:52:00 +04:00
/****************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS keytab_ad_connect ( TALLOC_CTX * mem_ctx ,
const char * domain_name ,
2010-09-22 07:56:23 +04:00
const char * dc ,
2008-06-18 14:52:00 +04:00
const char * username ,
const char * password ,
2008-06-26 23:48:41 +04:00
struct libnet_keytab_context * ctx )
2008-06-18 14:52:00 +04:00
{
ADS_STATUS ad_status ;
ADS_STRUCT * ads ;
ads = ads_init ( NULL , domain_name , dc ) ;
NT_STATUS_HAVE_NO_MEMORY ( ads ) ;
if ( getenv ( KRB5_ENV_CCNAME ) = = NULL ) {
setenv ( KRB5_ENV_CCNAME , " MEMORY:libnet_samsync_keytab " , 1 ) ;
}
ads - > auth . user_name = SMB_STRDUP ( username ) ;
ads - > auth . password = SMB_STRDUP ( password ) ;
ad_status = ads_connect_user_creds ( ads ) ;
if ( ! ADS_ERR_OK ( ad_status ) ) {
return NT_STATUS_UNSUCCESSFUL ;
}
ctx - > ads = ads ;
ctx - > dns_domain_name = talloc_strdup_upper ( mem_ctx , ads - > config . realm ) ;
NT_STATUS_HAVE_NO_MEMORY ( ctx - > dns_domain_name ) ;
return NT_STATUS_OK ;
}
/****************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS fetch_sam_entry_keytab ( TALLOC_CTX * mem_ctx ,
enum netr_SamDatabaseID database_id ,
uint32_t rid ,
struct netr_DELTA_USER * r ,
2008-06-26 23:48:41 +04:00
struct libnet_keytab_context * ctx )
2008-06-18 14:52:00 +04:00
{
2008-11-18 03:16:53 +03:00
NTSTATUS status ;
uint32_t kvno = 0 ;
DATA_BLOB blob ;
2008-06-18 14:52:00 +04:00
if ( memcmp ( r - > ntpassword . hash , ctx - > zero_buf , 16 ) = = 0 ) {
return NT_STATUS_OK ;
}
2008-11-18 03:16:53 +03:00
kvno = ads_get_kvno ( ctx - > ads , r - > account_name . string ) ;
blob = data_blob_const ( r - > ntpassword . hash , 16 ) ;
2008-06-18 14:52:00 +04:00
2008-11-18 03:16:53 +03:00
status = libnet_keytab_add_to_keytab_entries ( mem_ctx , ctx ,
kvno ,
r - > account_name . string ,
NULL ,
ENCTYPE_ARCFOUR_HMAC ,
blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2008-06-18 14:52:00 +04:00
return NT_STATUS_OK ;
}
/****************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-11-17 21:34:56 +03:00
static NTSTATUS init_keytab ( TALLOC_CTX * mem_ctx ,
struct samsync_context * ctx ,
enum netr_SamDatabaseID database_id ,
uint64_t * sequence_num )
2008-06-18 14:52:00 +04:00
{
krb5_error_code ret = 0 ;
2008-11-17 21:34:56 +03:00
NTSTATUS status ;
2009-02-19 04:35:20 +03:00
struct libnet_keytab_context * keytab_ctx = NULL ;
2008-11-18 11:52:35 +03:00
struct libnet_keytab_entry * entry ;
uint64_t old_sequence_num = 0 ;
const char * principal = NULL ;
2010-09-22 07:56:23 +04:00
struct netr_DsRGetDCNameInfo * info = NULL ;
const char * dc ;
2008-06-18 14:52:00 +04:00
2008-11-17 21:34:56 +03:00
ret = libnet_keytab_init ( mem_ctx , ctx - > output_filename , & keytab_ctx ) ;
if ( ret ) {
return krb5_to_nt_status ( ret ) ;
2008-06-18 14:52:00 +04:00
}
2010-09-22 07:56:23 +04:00
status = dsgetdcname ( mem_ctx , ctx - > msg_ctx ,
ctx - > domain_name , NULL , NULL , 0 , & info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
dc = strip_hostname ( info - > dc_unc ) ;
2008-11-17 21:34:56 +03:00
keytab_ctx - > clean_old_entries = ctx - > clean_old_entries ;
ctx - > private_data = keytab_ctx ;
2008-06-18 14:52:00 +04:00
status = keytab_ad_connect ( mem_ctx ,
ctx - > domain_name ,
2010-09-22 07:56:23 +04:00
dc ,
2008-06-18 14:52:00 +04:00
ctx - > username ,
ctx - > password ,
keytab_ctx ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-11-17 21:34:56 +03:00
TALLOC_FREE ( keytab_ctx ) ;
return status ;
2008-06-18 14:52:00 +04:00
}
2008-11-18 11:52:35 +03:00
principal = talloc_asprintf ( mem_ctx , " SEQUENCE_NUM@%s " ,
keytab_ctx - > dns_domain_name ) ;
NT_STATUS_HAVE_NO_MEMORY ( principal ) ;
entry = libnet_keytab_search ( keytab_ctx , principal , 0 , ENCTYPE_NULL ,
mem_ctx ) ;
if ( entry & & ( entry - > password . length = = 8 ) ) {
old_sequence_num = BVAL ( entry - > password . data , 0 ) ;
}
if ( sequence_num ) {
* sequence_num = old_sequence_num ;
}
2008-11-17 21:34:56 +03:00
return status ;
}
/****************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS fetch_sam_entries_keytab ( TALLOC_CTX * mem_ctx ,
enum netr_SamDatabaseID database_id ,
struct netr_DELTA_ENUM_ARRAY * r ,
2008-11-18 04:01:03 +03:00
uint64_t * sequence_num ,
2008-11-17 21:34:56 +03:00
struct samsync_context * ctx )
{
struct libnet_keytab_context * keytab_ctx =
( struct libnet_keytab_context * ) ctx - > private_data ;
NTSTATUS status = NT_STATUS_OK ;
int i ;
2008-06-18 14:52:00 +04:00
for ( i = 0 ; i < r - > num_deltas ; i + + ) {
2008-11-18 11:42:59 +03:00
switch ( r - > delta_enum [ i ] . delta_type ) {
case NETR_DELTA_USER :
break ;
case NETR_DELTA_DOMAIN :
if ( sequence_num ) {
* sequence_num =
r - > delta_enum [ i ] . delta_union . domain - > sequence_num ;
}
continue ;
case NETR_DELTA_MODIFY_COUNT :
if ( sequence_num ) {
* sequence_num =
* r - > delta_enum [ i ] . delta_union . modified_count ;
}
continue ;
default :
2008-06-18 14:52:00 +04:00
continue ;
}
status = fetch_sam_entry_keytab ( mem_ctx , database_id ,
r - > delta_enum [ i ] . delta_id_union . rid ,
r - > delta_enum [ i ] . delta_union . user ,
keytab_ctx ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto out ;
}
}
2008-11-17 21:34:56 +03:00
out :
return status ;
}
2008-06-18 14:52:00 +04:00
2008-11-17 21:34:56 +03:00
/****************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-06-27 17:54:01 +04:00
2008-11-17 21:34:56 +03:00
static NTSTATUS close_keytab ( TALLOC_CTX * mem_ctx ,
struct samsync_context * ctx ,
enum netr_SamDatabaseID database_id ,
uint64_t sequence_num )
{
struct libnet_keytab_context * keytab_ctx =
( struct libnet_keytab_context * ) ctx - > private_data ;
krb5_error_code ret ;
NTSTATUS status ;
2008-11-18 11:52:35 +03:00
struct libnet_keytab_entry * entry ;
uint64_t old_sequence_num = 0 ;
const char * principal = NULL ;
principal = talloc_asprintf ( mem_ctx , " SEQUENCE_NUM@%s " ,
keytab_ctx - > dns_domain_name ) ;
NT_STATUS_HAVE_NO_MEMORY ( principal ) ;
entry = libnet_keytab_search ( keytab_ctx , principal , 0 , ENCTYPE_NULL ,
mem_ctx ) ;
if ( entry & & ( entry - > password . length = = 8 ) ) {
old_sequence_num = BVAL ( entry - > password . data , 0 ) ;
}
if ( sequence_num > old_sequence_num ) {
DATA_BLOB blob ;
blob = data_blob_talloc_zero ( mem_ctx , 8 ) ;
SBVAL ( blob . data , 0 , sequence_num ) ;
status = libnet_keytab_add_to_keytab_entries ( mem_ctx , keytab_ctx ,
0 ,
" SEQUENCE_NUM " ,
NULL ,
ENCTYPE_NULL ,
blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
}
}
2008-06-27 17:54:01 +04:00
2008-11-17 21:34:56 +03:00
ret = libnet_keytab_add ( keytab_ctx ) ;
if ( ret ) {
status = krb5_to_nt_status ( ret ) ;
ctx - > error_message = talloc_asprintf ( ctx ,
" Failed to add entries to keytab %s: %s " ,
keytab_ctx - > keytab_name , error_message ( ret ) ) ;
2008-06-27 02:46:38 +04:00
TALLOC_FREE ( keytab_ctx ) ;
2008-11-17 21:34:56 +03:00
return status ;
2008-06-27 02:46:38 +04:00
}
2008-11-17 21:34:56 +03:00
ctx - > result_message = talloc_asprintf ( ctx ,
" Vampired %d accounts to keytab %s " ,
keytab_ctx - > count ,
keytab_ctx - > keytab_name ) ;
2008-11-18 11:52:35 +03:00
status = NT_STATUS_OK ;
done :
2008-06-18 14:52:00 +04:00
TALLOC_FREE ( keytab_ctx ) ;
2008-11-18 11:52:35 +03:00
return status ;
2008-06-18 14:52:00 +04:00
}
# else
2008-11-17 21:34:56 +03:00
static NTSTATUS init_keytab ( TALLOC_CTX * mem_ctx ,
struct samsync_context * ctx ,
enum netr_SamDatabaseID database_id ,
uint64_t * sequence_num )
{
return NT_STATUS_NOT_SUPPORTED ;
}
2008-11-17 18:31:59 +03:00
static NTSTATUS fetch_sam_entries_keytab ( TALLOC_CTX * mem_ctx ,
enum netr_SamDatabaseID database_id ,
struct netr_DELTA_ENUM_ARRAY * r ,
2008-11-18 04:01:03 +03:00
uint64_t * sequence_num ,
2008-11-17 18:31:59 +03:00
struct samsync_context * ctx )
2008-06-18 14:52:00 +04:00
{
return NT_STATUS_NOT_SUPPORTED ;
}
2008-11-17 21:34:56 +03:00
static NTSTATUS close_keytab ( TALLOC_CTX * mem_ctx ,
struct samsync_context * ctx ,
enum netr_SamDatabaseID database_id ,
uint64_t sequence_num )
{
return NT_STATUS_NOT_SUPPORTED ;
}
2010-08-10 02:25:02 +04:00
# endif /* defined(HAVE_ADS) */
2008-11-17 18:29:11 +03:00
const struct samsync_ops libnet_samsync_keytab_ops = {
2008-11-17 21:34:56 +03:00
. startup = init_keytab ,
2008-11-17 18:29:11 +03:00
. process_objects = fetch_sam_entries_keytab ,
2008-11-17 21:34:56 +03:00
. finish = close_keytab
2008-11-17 18:29:11 +03:00
} ;