2008-06-26 23:48:41 +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"
# include "libnet/libnet.h"
# ifdef HAVE_KRB5
/****************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int keytab_close ( struct libnet_keytab_context * ctx )
{
if ( ! ctx ) {
return 0 ;
}
if ( ctx - > keytab & & ctx - > context ) {
krb5_kt_close ( ctx - > context , ctx - > keytab ) ;
}
if ( ctx - > context ) {
krb5_free_context ( ctx - > context ) ;
}
if ( ctx - > ads ) {
ads_destroy ( & ctx - > ads ) ;
}
TALLOC_FREE ( ctx ) ;
return 0 ;
}
/****************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
krb5_error_code libnet_keytab_init ( TALLOC_CTX * mem_ctx ,
const char * keytab_name ,
struct libnet_keytab_context * * ctx )
{
krb5_error_code ret = 0 ;
krb5_context context = NULL ;
krb5_keytab keytab = NULL ;
const char * keytab_string = NULL ;
struct libnet_keytab_context * r ;
r = TALLOC_ZERO_P ( mem_ctx , struct libnet_keytab_context ) ;
if ( ! r ) {
return ENOMEM ;
}
talloc_set_destructor ( r , keytab_close ) ;
initialize_krb5_error_table ( ) ;
ret = krb5_init_context ( & context ) ;
if ( ret ) {
DEBUG ( 1 , ( " keytab_init: could not krb5_init_context: %s \n " ,
error_message ( ret ) ) ) ;
return ret ;
}
ret = smb_krb5_open_keytab ( context , keytab_name , true , & keytab ) ;
if ( ret ) {
DEBUG ( 1 , ( " keytab_init: smb_krb5_open_keytab failed (%s) \n " ,
error_message ( ret ) ) ) ;
krb5_free_context ( context ) ;
return ret ;
}
ret = smb_krb5_keytab_name ( mem_ctx , context , keytab , & keytab_string ) ;
if ( ret ) {
krb5_kt_close ( context , keytab ) ;
krb5_free_context ( context ) ;
return ret ;
}
r - > context = context ;
r - > keytab = keytab ;
r - > keytab_name = keytab_string ;
* ctx = r ;
return 0 ;
}
/****************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-29 20:05:13 +04:00
/**
* Remove all entries that have the given principal , kvno and enctype .
*/
static krb5_error_code libnet_keytab_remove_entries ( krb5_context context ,
krb5_keytab keytab ,
const char * principal ,
int kvno ,
const krb5_enctype enctype )
{
krb5_error_code ret ;
krb5_kt_cursor cursor ;
krb5_keytab_entry kt_entry ;
ZERO_STRUCT ( kt_entry ) ;
ZERO_STRUCT ( cursor ) ;
ret = krb5_kt_start_seq_get ( context , keytab , & cursor ) ;
if ( ret ) {
return 0 ;
}
while ( krb5_kt_next_entry ( context , keytab , & kt_entry , & cursor ) = = 0 )
{
char * princ_s = NULL ;
if ( kt_entry . vno ! = kvno ) {
goto cont ;
}
if ( kt_entry . key . enctype ! = enctype ) {
goto cont ;
}
ret = smb_krb5_unparse_name ( context , kt_entry . principal ,
& princ_s ) ;
if ( ret ) {
DEBUG ( 5 , ( " smb_krb5_unparse_name failed (%s) \n " ,
error_message ( ret ) ) ) ;
goto cont ;
}
if ( strcmp ( principal , princ_s ) ! = 0 ) {
goto cont ;
}
/* match found - remove */
DEBUG ( 10 , ( " found entry for principal %s, kvno %d, "
" enctype %d - trying to remove it \n " ,
princ_s , kt_entry . vno , kt_entry . key . enctype ) ) ;
ret = krb5_kt_end_seq_get ( context , keytab , & cursor ) ;
ZERO_STRUCT ( cursor ) ;
if ( ret ) {
DEBUG ( 5 , ( " krb5_kt_end_seq_get failed (%s) \n " ,
error_message ( ret ) ) ) ;
goto cont ;
}
ret = krb5_kt_remove_entry ( context , keytab ,
& kt_entry ) ;
if ( ret ) {
DEBUG ( 5 , ( " krb5_kt_remove_entry failed (%s) \n " ,
error_message ( ret ) ) ) ;
goto cont ;
}
DEBUG ( 10 , ( " removed entry for principal %s, kvno %d, "
" enctype %d \n " , princ_s , kt_entry . vno ,
kt_entry . key . enctype ) ) ;
ret = krb5_kt_start_seq_get ( context , keytab , & cursor ) ;
if ( ret ) {
DEBUG ( 5 , ( " krb5_kt_start_seq_get failed (%s) \n " ,
error_message ( ret ) ) ) ;
goto cont ;
}
cont :
smb_krb5_kt_free_entry ( context , & kt_entry ) ;
SAFE_FREE ( princ_s ) ;
}
ret = krb5_kt_end_seq_get ( context , keytab , & cursor ) ;
if ( ret ) {
DEBUG ( 5 , ( " krb5_kt_end_seq_get failed (%s) \n " ,
error_message ( ret ) ) ) ;
}
return ret ;
}
2008-07-29 17:19:18 +04:00
static krb5_error_code libnet_keytab_add_entry ( krb5_context context ,
krb5_keytab keytab ,
krb5_kvno kvno ,
const char * princ_s ,
krb5_enctype enctype ,
krb5_data password )
{
krb5_keyblock * keyp ;
krb5_keytab_entry kt_entry ;
krb5_error_code ret ;
2008-07-29 20:05:13 +04:00
/* remove duplicates first ... */
ret = libnet_keytab_remove_entries ( context , keytab , princ_s , kvno ,
enctype ) ;
if ( ret ) {
DEBUG ( 1 , ( " libnet_keytab_remove_entries failed: %s \n " ,
error_message ( ret ) ) ) ;
}
2008-07-29 17:19:18 +04:00
ZERO_STRUCT ( kt_entry ) ;
kt_entry . vno = kvno ;
ret = smb_krb5_parse_name ( context , princ_s , & kt_entry . principal ) ;
if ( ret ) {
DEBUG ( 1 , ( " smb_krb5_parse_name(%s) failed (%s) \n " ,
princ_s , error_message ( ret ) ) ) ;
return ret ;
}
# if !defined(HAVE_KRB5_KEYTAB_ENTRY_KEY) && !defined(HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK)
# error krb5_keytab_entry has no key or keyblock member
# endif
# ifdef HAVE_KRB5_KEYTAB_ENTRY_KEY /* MIT */
keyp = & kt_entry . key ;
# endif
# ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK /* Heimdal */
keyp = & kt_entry . keyblock ;
# endif
if ( create_kerberos_key_from_string ( context , kt_entry . principal ,
& password , keyp , enctype , true ) )
{
ret = KRB5KRB_ERR_GENERIC ;
goto done ;
}
ret = krb5_kt_add_entry ( context , keytab , & kt_entry ) ;
if ( ret ) {
DEBUG ( 1 , ( " adding entry to keytab failed (%s) \n " ,
error_message ( ret ) ) ) ;
}
done :
krb5_free_keyblock_contents ( context , keyp ) ;
krb5_free_principal ( context , kt_entry . principal ) ;
ZERO_STRUCT ( kt_entry ) ;
smb_krb5_kt_free_entry ( context , & kt_entry ) ;
return ret ;
}
2008-06-26 23:48:41 +04:00
krb5_error_code libnet_keytab_add ( struct libnet_keytab_context * ctx )
{
krb5_error_code ret = 0 ;
2008-08-01 01:15:35 +04:00
uint32_t i ;
2008-06-26 23:48:41 +04:00
for ( i = 0 ; i < ctx - > count ; i + + ) {
struct libnet_keytab_entry * entry = & ctx - > entries [ i ] ;
krb5_data password ;
password . data = ( char * ) entry - > password . data ;
password . length = entry - > password . length ;
2008-07-29 17:21:30 +04:00
ret = libnet_keytab_add_entry ( ctx - > context ,
ctx - > keytab ,
entry - > kvno ,
entry - > principal ,
entry - > enctype ,
password ) ;
2008-06-26 23:48:41 +04:00
if ( ret ) {
DEBUG ( 1 , ( " libnet_keytab_add: "
" Failed to add entry to keytab file \n " ) ) ;
return ret ;
}
}
return ret ;
}
2008-07-17 02:53:13 +04:00
struct libnet_keytab_entry * libnet_keytab_search ( struct libnet_keytab_context * ctx ,
2008-07-29 16:39:40 +04:00
const char * principal ,
int kvno ,
2008-07-29 12:16:37 +04:00
const krb5_enctype enctype ,
2008-07-17 02:53:13 +04:00
TALLOC_CTX * mem_ctx )
{
krb5_error_code ret = 0 ;
krb5_kt_cursor cursor ;
krb5_keytab_entry kt_entry ;
struct libnet_keytab_entry * entry = NULL ;
ZERO_STRUCT ( kt_entry ) ;
ZERO_STRUCT ( cursor ) ;
ret = krb5_kt_start_seq_get ( ctx - > context , ctx - > keytab , & cursor ) ;
if ( ret ) {
2008-07-29 19:54:01 +04:00
DEBUG ( 10 , ( " krb5_kt_start_seq_get failed: %s " ,
error_message ( ret ) ) ) ;
2008-07-17 02:53:13 +04:00
return NULL ;
}
2008-07-29 16:39:40 +04:00
while ( krb5_kt_next_entry ( ctx - > context , ctx - > keytab , & kt_entry , & cursor ) = = 0 )
{
2008-07-17 02:53:13 +04:00
char * princ_s = NULL ;
if ( kt_entry . vno ! = kvno ) {
2008-07-29 16:39:40 +04:00
goto cont ;
2008-07-17 02:53:13 +04:00
}
2008-07-29 15:32:17 +04:00
if ( kt_entry . key . enctype ! = enctype ) {
2008-07-29 16:39:40 +04:00
goto cont ;
2008-07-29 15:32:17 +04:00
}
2008-07-29 16:39:40 +04:00
ret = smb_krb5_unparse_name ( ctx - > context , kt_entry . principal ,
& princ_s ) ;
2008-07-17 02:53:13 +04:00
if ( ret ) {
2008-07-29 16:39:40 +04:00
goto cont ;
2008-07-17 02:53:13 +04:00
}
if ( strcmp ( principal , princ_s ) ! = 0 ) {
2008-07-29 16:39:40 +04:00
goto cont ;
2008-07-17 02:53:13 +04:00
}
entry = talloc_zero ( mem_ctx , struct libnet_keytab_entry ) ;
if ( ! entry ) {
2008-07-29 19:54:01 +04:00
DEBUG ( 3 , ( " talloc failed \n " ) ) ;
2008-07-29 16:39:40 +04:00
goto fail ;
2008-07-17 02:53:13 +04:00
}
entry - > name = talloc_strdup ( entry , princ_s ) ;
if ( ! entry - > name ) {
2008-07-29 19:54:01 +04:00
DEBUG ( 3 , ( " talloc_strdup_failed \n " ) ) ;
2008-07-29 16:39:40 +04:00
goto fail ;
2008-07-17 02:53:13 +04:00
}
entry - > principal = talloc_strdup ( entry , princ_s ) ;
if ( ! entry - > principal ) {
2008-07-29 19:54:01 +04:00
DEBUG ( 3 , ( " talloc_strdup_failed \n " ) ) ;
2008-07-29 16:39:40 +04:00
goto fail ;
2008-07-17 02:53:13 +04:00
}
2008-07-29 16:39:40 +04:00
entry - > password = data_blob_talloc ( entry , kt_entry . key . contents ,
kt_entry . key . length ) ;
2008-07-17 02:53:13 +04:00
if ( ! entry - > password . data ) {
2008-07-29 19:54:01 +04:00
DEBUG ( 3 , ( " data_blob_talloc failed \n " ) ) ;
2008-07-29 16:39:40 +04:00
goto fail ;
2008-07-17 02:53:13 +04:00
}
2008-07-29 19:54:01 +04:00
DEBUG ( 10 , ( " found entry \n " ) ) ;
2008-07-17 02:53:13 +04:00
smb_krb5_kt_free_entry ( ctx - > context , & kt_entry ) ;
SAFE_FREE ( princ_s ) ;
break ;
2008-07-29 16:39:40 +04:00
fail :
smb_krb5_kt_free_entry ( ctx - > context , & kt_entry ) ;
SAFE_FREE ( princ_s ) ;
TALLOC_FREE ( entry ) ;
break ;
cont :
smb_krb5_kt_free_entry ( ctx - > context , & kt_entry ) ;
SAFE_FREE ( princ_s ) ;
continue ;
2008-07-17 02:53:13 +04:00
}
krb5_kt_end_seq_get ( ctx - > context , ctx - > keytab , & cursor ) ;
return entry ;
}
2008-06-26 23:48:41 +04:00
# endif /* HAVE_KRB5 */