2007-02-04 07:17:03 +00:00
/*
ldb database library
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2007
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 02:07:03 +00:00
the Free Software Foundation ; either version 3 of the License , or
2007-02-04 07:17:03 +00:00
( 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
2007-07-10 02:07:03 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2007-02-04 07:17:03 +00:00
*/
/*
* Name : ldb
*
* Component : ldb update_keytabs module
*
* Description : Update keytabs whenever their matching secret record changes
*
* Author : Andrew Bartlett
*/
# include "includes.h"
2009-01-29 18:39:30 -05:00
# include "ldb_module.h"
2009-06-18 03:09:14 +02:00
# include "lib/util/dlinklist.h"
2007-02-04 07:17:03 +00:00
# include "auth/credentials/credentials.h"
# include "auth/credentials/credentials_krb5.h"
# include "system/kerberos.h"
2010-09-23 17:01:44 +10:00
# include "auth/kerberos/kerberos.h"
2012-03-30 19:33:53 -04:00
# include "auth/kerberos/kerberos_srv_keytab.h"
2011-09-20 14:26:36 -07:00
# include "dsdb/samdb/ldb_modules/util.h"
2012-03-31 01:27:02 -04:00
# include "param/secrets.h"
2007-02-04 07:17:03 +00:00
struct dn_list {
2010-09-23 17:01:44 +10:00
struct ldb_message * msg ;
bool do_delete ;
2007-02-04 07:17:03 +00:00
struct dn_list * prev , * next ;
} ;
struct update_kt_private {
struct dn_list * changed_dns ;
} ;
2008-09-11 18:36:28 -04:00
struct update_kt_ctx {
struct ldb_module * module ;
struct ldb_request * req ;
struct ldb_dn * dn ;
2009-02-02 11:10:15 +01:00
bool do_delete ;
2008-09-11 18:36:28 -04:00
struct ldb_reply * op_reply ;
bool found ;
} ;
2008-10-20 18:59:51 +02:00
static struct update_kt_ctx * update_kt_ctx_init ( struct ldb_module * module ,
struct ldb_request * req )
2008-09-11 18:36:28 -04:00
{
struct update_kt_ctx * ac ;
ac = talloc_zero ( req , struct update_kt_ctx ) ;
if ( ac = = NULL ) {
2009-01-29 18:39:30 -05:00
ldb_oom ( ldb_module_get_ctx ( module ) ) ;
2008-09-11 18:36:28 -04:00
return NULL ;
}
ac - > module = module ;
ac - > req = req ;
return ac ;
}
/* FIXME: too many semi-async searches here for my taste, direct and indirect as
* cli_credentials_set_secrets ( ) performs a sync ldb search .
* Just hope we are lucky and nothing breaks ( using the tdb backend masks a lot
* of async issues ) . - SSS
*/
2011-01-17 13:39:46 +11:00
static int add_modified ( struct ldb_module * module , struct ldb_dn * dn , bool do_delete ,
struct ldb_request * parent )
{
2009-01-29 18:39:30 -05:00
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
struct update_kt_private * data = talloc_get_type ( ldb_module_get_private ( module ) , struct update_kt_private ) ;
2007-02-13 13:43:23 +00:00
struct dn_list * item ;
2007-02-04 07:17:03 +00:00
char * filter ;
2007-02-13 13:43:23 +00:00
struct ldb_result * res ;
int ret ;
2011-10-25 20:06:45 +02:00
filter = talloc_asprintf ( data ,
" (&(objectClass=kerberosSecret)(privateKeytab=*)) " ) ;
2007-02-13 13:43:23 +00:00
if ( ! filter ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2007-02-13 13:43:23 +00:00
}
2011-01-17 13:39:46 +11:00
ret = dsdb_module_search ( module , data , & res ,
dn , LDB_SCOPE_BASE , NULL ,
DSDB_FLAG_NEXT_MODULE , parent ,
" %s " , filter ) ;
2010-09-23 17:01:44 +10:00
talloc_free ( filter ) ;
2007-02-13 13:43:23 +00:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
if ( res - > count ! = 1 ) {
/* if it's not a kerberosSecret then we don't have anything to update */
talloc_free ( res ) ;
return LDB_SUCCESS ;
}
item = talloc ( data - > changed_dns ? ( void * ) data - > changed_dns : ( void * ) data , struct dn_list ) ;
2007-02-04 07:17:03 +00:00
if ( ! item ) {
2010-09-23 17:01:44 +10:00
talloc_free ( res ) ;
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2007-02-04 07:17:03 +00:00
}
2008-09-11 18:36:28 -04:00
2010-09-23 17:01:44 +10:00
item - > msg = talloc_steal ( item , res - > msgs [ 0 ] ) ;
item - > do_delete = do_delete ;
talloc_free ( res ) ;
2007-02-04 07:17:03 +00:00
2016-02-05 11:32:18 +01:00
DLIST_ADD_END ( data - > changed_dns , item ) ;
2007-02-04 07:17:03 +00:00
return LDB_SUCCESS ;
}
2008-09-11 18:36:28 -04:00
static int ukt_search_modified ( struct update_kt_ctx * ac ) ;
static int update_kt_op_callback ( struct ldb_request * req ,
struct ldb_reply * ares )
{
2009-01-29 18:39:30 -05:00
struct ldb_context * ldb ;
2008-09-11 18:36:28 -04:00
struct update_kt_ctx * ac ;
int ret ;
ac = talloc_get_type ( req - > context , struct update_kt_ctx ) ;
2009-01-29 18:39:30 -05:00
ldb = ldb_module_get_ctx ( ac - > module ) ;
2008-09-11 18:36:28 -04:00
if ( ! ares ) {
return ldb_module_done ( ac - > req , NULL , NULL ,
LDB_ERR_OPERATIONS_ERROR ) ;
}
if ( ares - > error ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , ares - > controls ,
ares - > response , ares - > error ) ;
}
if ( ares - > type ! = LDB_REPLY_DONE ) {
2009-01-29 18:39:30 -05:00
ldb_set_errstring ( ldb , " Invalid request type! \n " ) ;
2008-09-11 18:36:28 -04:00
return ldb_module_done ( ac - > req , NULL , NULL ,
LDB_ERR_OPERATIONS_ERROR ) ;
}
2009-02-02 11:10:15 +01:00
if ( ac - > do_delete ) {
2008-09-11 18:36:28 -04:00
return ldb_module_done ( ac - > req , ares - > controls ,
ares - > response , LDB_SUCCESS ) ;
}
ac - > op_reply = talloc_steal ( ac , ares ) ;
ret = ukt_search_modified ( ac ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , NULL , NULL , ret ) ;
}
return LDB_SUCCESS ;
}
static int ukt_del_op ( struct update_kt_ctx * ac )
{
2009-01-29 18:39:30 -05:00
struct ldb_context * ldb ;
2008-09-11 18:36:28 -04:00
struct ldb_request * down_req ;
int ret ;
2009-01-29 18:39:30 -05:00
ldb = ldb_module_get_ctx ( ac - > module ) ;
ret = ldb_build_del_req ( & down_req , ldb , ac ,
2008-09-11 18:36:28 -04:00
ac - > dn ,
ac - > req - > controls ,
ac , update_kt_op_callback ,
ac - > req ) ;
2010-09-24 12:50:13 -07:00
LDB_REQ_SET_LOCATION ( down_req ) ;
2008-09-11 18:36:28 -04:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
return ldb_next_request ( ac - > module , down_req ) ;
}
static int ukt_search_modified_callback ( struct ldb_request * req ,
struct ldb_reply * ares )
{
struct update_kt_ctx * ac ;
int ret ;
ac = talloc_get_type ( req - > context , struct update_kt_ctx ) ;
if ( ! ares ) {
return ldb_module_done ( ac - > req , NULL , NULL ,
LDB_ERR_OPERATIONS_ERROR ) ;
}
if ( ares - > error ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , ares - > controls ,
ares - > response , ares - > error ) ;
}
switch ( ares - > type ) {
case LDB_REPLY_ENTRY :
ac - > found = true ;
break ;
case LDB_REPLY_REFERRAL :
/* ignore */
break ;
case LDB_REPLY_DONE :
if ( ac - > found ) {
/* do the dirty sync job here :/ */
2011-01-17 13:39:46 +11:00
ret = add_modified ( ac - > module , ac - > dn , ac - > do_delete , ac - > req ) ;
2008-09-11 18:36:28 -04:00
}
2009-02-02 11:10:15 +01:00
if ( ac - > do_delete ) {
2008-09-11 18:36:28 -04:00
ret = ukt_del_op ( ac ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req ,
NULL , NULL , ret ) ;
}
break ;
}
return ldb_module_done ( ac - > req , ac - > op_reply - > controls ,
ac - > op_reply - > response , LDB_SUCCESS ) ;
}
talloc_free ( ares ) ;
return LDB_SUCCESS ;
}
static int ukt_search_modified ( struct update_kt_ctx * ac )
{
2009-01-29 18:39:30 -05:00
struct ldb_context * ldb ;
2010-11-06 20:23:35 +01:00
static const char * const no_attrs [ ] = { NULL } ;
2008-09-11 18:36:28 -04:00
struct ldb_request * search_req ;
int ret ;
2009-01-29 18:39:30 -05:00
ldb = ldb_module_get_ctx ( ac - > module ) ;
ret = ldb_build_search_req ( & search_req , ldb , ac ,
2008-09-11 18:36:28 -04:00
ac - > dn , LDB_SCOPE_BASE ,
" (&(objectClass=kerberosSecret) "
2010-11-06 20:23:35 +01:00
" (privateKeytab=*)) " , no_attrs ,
2008-09-11 18:36:28 -04:00
NULL ,
ac , ukt_search_modified_callback ,
ac - > req ) ;
2010-09-24 12:50:13 -07:00
LDB_REQ_SET_LOCATION ( search_req ) ;
2008-09-11 18:36:28 -04:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
return ldb_next_request ( ac - > module , search_req ) ;
}
2007-02-04 07:17:03 +00:00
/* add */
static int update_kt_add ( struct ldb_module * module , struct ldb_request * req )
{
2009-01-29 18:39:30 -05:00
struct ldb_context * ldb ;
2008-09-11 18:36:28 -04:00
struct update_kt_ctx * ac ;
struct ldb_request * down_req ;
2007-02-04 07:17:03 +00:00
int ret ;
2008-09-11 18:36:28 -04:00
2009-01-29 18:39:30 -05:00
ldb = ldb_module_get_ctx ( module ) ;
2008-09-11 18:36:28 -04:00
ac = update_kt_ctx_init ( module , req ) ;
if ( ac = = NULL ) {
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2008-09-11 18:36:28 -04:00
}
ac - > dn = req - > op . add . message - > dn ;
2009-01-29 18:39:30 -05:00
ret = ldb_build_add_req ( & down_req , ldb , ac ,
2008-09-11 18:36:28 -04:00
req - > op . add . message ,
req - > controls ,
ac , update_kt_op_callback ,
req ) ;
2010-09-24 12:50:13 -07:00
LDB_REQ_SET_LOCATION ( down_req ) ;
2007-02-04 07:17:03 +00:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2008-09-11 18:36:28 -04:00
return ldb_next_request ( module , down_req ) ;
2007-02-04 07:17:03 +00:00
}
/* modify */
static int update_kt_modify ( struct ldb_module * module , struct ldb_request * req )
{
2009-01-29 18:39:30 -05:00
struct ldb_context * ldb ;
2008-09-11 18:36:28 -04:00
struct update_kt_ctx * ac ;
struct ldb_request * down_req ;
2007-02-04 07:17:03 +00:00
int ret ;
2008-09-11 18:36:28 -04:00
2009-01-29 18:39:30 -05:00
ldb = ldb_module_get_ctx ( module ) ;
2008-09-11 18:36:28 -04:00
ac = update_kt_ctx_init ( module , req ) ;
if ( ac = = NULL ) {
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2008-09-11 18:36:28 -04:00
}
ac - > dn = req - > op . mod . message - > dn ;
2009-01-29 18:39:30 -05:00
ret = ldb_build_mod_req ( & down_req , ldb , ac ,
2008-09-11 18:36:28 -04:00
req - > op . mod . message ,
req - > controls ,
ac , update_kt_op_callback ,
req ) ;
2010-09-24 12:50:13 -07:00
LDB_REQ_SET_LOCATION ( down_req ) ;
2007-02-04 07:17:03 +00:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2008-09-11 18:36:28 -04:00
return ldb_next_request ( module , down_req ) ;
2007-02-04 07:17:03 +00:00
}
/* delete */
static int update_kt_delete ( struct ldb_module * module , struct ldb_request * req )
{
2008-09-11 18:36:28 -04:00
struct update_kt_ctx * ac ;
ac = update_kt_ctx_init ( module , req ) ;
if ( ac = = NULL ) {
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb_module_get_ctx ( module ) ) ;
2007-02-04 07:17:03 +00:00
}
2008-09-11 18:36:28 -04:00
ac - > dn = req - > op . del . dn ;
2009-02-02 11:10:15 +01:00
ac - > do_delete = true ;
2008-09-11 18:36:28 -04:00
return ukt_search_modified ( ac ) ;
2007-02-04 07:17:03 +00:00
}
/* rename */
static int update_kt_rename ( struct ldb_module * module , struct ldb_request * req )
{
2009-01-29 18:39:30 -05:00
struct ldb_context * ldb ;
2008-09-11 18:36:28 -04:00
struct update_kt_ctx * ac ;
struct ldb_request * down_req ;
2007-02-04 07:17:03 +00:00
int ret ;
2008-09-11 18:36:28 -04:00
2009-01-29 18:39:30 -05:00
ldb = ldb_module_get_ctx ( module ) ;
2008-09-11 18:36:28 -04:00
ac = update_kt_ctx_init ( module , req ) ;
if ( ac = = NULL ) {
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2008-09-11 18:36:28 -04:00
}
ac - > dn = req - > op . rename . newdn ;
2009-01-29 18:39:30 -05:00
ret = ldb_build_rename_req ( & down_req , ldb , ac ,
2008-09-11 18:36:28 -04:00
req - > op . rename . olddn ,
req - > op . rename . newdn ,
req - > controls ,
ac , update_kt_op_callback ,
req ) ;
2010-09-24 12:50:13 -07:00
LDB_REQ_SET_LOCATION ( down_req ) ;
2007-02-04 07:17:03 +00:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2008-09-11 18:36:28 -04:00
return ldb_next_request ( module , down_req ) ;
2007-02-04 07:17:03 +00:00
}
2009-09-03 18:33:17 +10:00
/* prepare for a commit */
static int update_kt_prepare_commit ( struct ldb_module * module )
2007-02-04 07:17:03 +00:00
{
2010-09-23 17:01:44 +10:00
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
2009-01-29 18:39:30 -05:00
struct update_kt_private * data = talloc_get_type ( ldb_module_get_private ( module ) , struct update_kt_private ) ;
2007-02-04 07:17:03 +00:00
struct dn_list * p ;
2010-09-23 17:01:44 +10:00
struct smb_krb5_context * smb_krb5_context ;
2014-04-17 21:48:30 +12:00
int krb5_ret = smb_krb5_init_context ( data ,
ldb_get_opaque ( ldb , " loadparm " ) ,
2010-09-23 17:01:44 +10:00
& smb_krb5_context ) ;
2013-12-10 17:52:30 +01:00
TALLOC_CTX * tmp_ctx = NULL ;
2012-03-31 01:27:02 -04:00
2010-09-23 17:01:44 +10:00
if ( krb5_ret ! = 0 ) {
ldb_asprintf_errstring ( ldb , " Failed to setup krb5_context: %s " , error_message ( krb5_ret ) ) ;
2012-03-31 01:27:02 -04:00
goto fail ;
2010-09-23 17:01:44 +10:00
}
2008-09-11 18:36:28 -04:00
2012-03-31 01:27:02 -04:00
tmp_ctx = talloc_new ( data ) ;
if ( ! tmp_ctx ) {
ldb_oom ( ldb ) ;
goto fail ;
}
2009-01-29 18:39:30 -05:00
2007-02-04 07:17:03 +00:00
for ( p = data - > changed_dns ; p ; p = p - > next ) {
2010-09-24 14:17:58 +10:00
const char * error_string ;
2012-03-31 01:27:02 -04:00
const char * realm ;
char * upper_realm ;
struct ldb_message_element * spn_el = ldb_msg_find_element ( p - > msg , " servicePrincipalName " ) ;
2014-02-27 09:29:36 +01:00
const char * * SPNs = NULL ;
2012-03-31 01:27:02 -04:00
int num_SPNs = 0 ;
int i ;
realm = ldb_msg_find_attr_as_string ( p - > msg , " realm " , NULL ) ;
if ( spn_el ) {
upper_realm = strupper_talloc ( tmp_ctx , realm ) ;
if ( ! upper_realm ) {
ldb_oom ( ldb ) ;
goto fail ;
}
num_SPNs = spn_el - > num_values ;
2014-02-27 09:29:36 +01:00
SPNs = talloc_array ( tmp_ctx , const char * , num_SPNs ) ;
2012-03-31 01:27:02 -04:00
if ( ! SPNs ) {
ldb_oom ( ldb ) ;
goto fail ;
}
for ( i = 0 ; i < num_SPNs ; i + + ) {
2014-02-27 09:29:36 +01:00
SPNs [ i ] = talloc_asprintf ( SPNs , " %*.*s@%s " ,
2012-03-31 01:27:02 -04:00
( int ) spn_el - > values [ i ] . length ,
( int ) spn_el - > values [ i ] . length ,
( const char * ) spn_el - > values [ i ] . data ,
upper_realm ) ;
if ( ! SPNs [ i ] ) {
ldb_oom ( ldb ) ;
goto fail ;
}
}
}
2012-04-01 19:08:15 -04:00
krb5_ret = smb_krb5_update_keytab ( tmp_ctx , smb_krb5_context - > krb5_context ,
2012-03-31 01:27:02 -04:00
keytab_name_from_msg ( tmp_ctx , ldb , p - > msg ) ,
ldb_msg_find_attr_as_string ( p - > msg , " samAccountName " , NULL ) ,
2014-02-27 09:29:36 +01:00
realm , SPNs , num_SPNs ,
2012-03-31 01:27:02 -04:00
ldb_msg_find_attr_as_string ( p - > msg , " saltPrincipal " , NULL ) ,
ldb_msg_find_attr_as_string ( p - > msg , " secret " , NULL ) ,
ldb_msg_find_attr_as_string ( p - > msg , " priorSecret " , NULL ) ,
ldb_msg_find_attr_as_int ( p - > msg , " msDS-KeyVersionNumber " , 0 ) ,
( uint32_t ) ldb_msg_find_attr_as_int ( p - > msg , " msDS-SupportedEncryptionTypes " , ENC_ALL_TYPES ) ,
2012-03-31 03:23:19 -04:00
p - > do_delete , NULL , & error_string ) ;
2010-09-23 17:01:44 +10:00
if ( krb5_ret ! = 0 ) {
2010-09-24 14:17:58 +10:00
ldb_asprintf_errstring ( ldb , " Failed to update keytab from entry %s in %s: %s " ,
ldb_dn_get_linearized ( p - > msg - > dn ) ,
( const char * ) ldb_get_opaque ( ldb , " ldb_url " ) ,
error_string ) ;
2012-03-31 01:27:02 -04:00
goto fail ;
2007-02-04 07:17:03 +00:00
}
}
talloc_free ( data - > changed_dns ) ;
data - > changed_dns = NULL ;
2012-03-31 01:27:02 -04:00
talloc_free ( tmp_ctx ) ;
2008-09-11 18:36:28 -04:00
2009-09-03 18:33:17 +10:00
return ldb_next_prepare_commit ( module ) ;
2012-03-31 01:27:02 -04:00
fail :
talloc_free ( data - > changed_dns ) ;
data - > changed_dns = NULL ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
2007-02-04 07:17:03 +00:00
}
/* end a transaction */
static int update_kt_del_trans ( struct ldb_module * module )
{
2009-01-29 18:39:30 -05:00
struct update_kt_private * data = talloc_get_type ( ldb_module_get_private ( module ) , struct update_kt_private ) ;
2008-09-11 18:36:28 -04:00
2007-02-04 07:17:03 +00:00
talloc_free ( data - > changed_dns ) ;
data - > changed_dns = NULL ;
2007-09-20 07:51:08 +00:00
return ldb_next_del_trans ( module ) ;
2007-02-04 07:17:03 +00:00
}
static int update_kt_init ( struct ldb_module * module )
{
2009-01-29 18:39:30 -05:00
struct ldb_context * ldb ;
2007-02-04 07:17:03 +00:00
struct update_kt_private * data ;
2009-01-29 18:39:30 -05:00
ldb = ldb_module_get_ctx ( module ) ;
2007-02-04 07:17:03 +00:00
data = talloc ( module , struct update_kt_private ) ;
if ( data = = NULL ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2007-02-04 07:17:03 +00:00
}
data - > changed_dns = NULL ;
2009-01-29 18:39:30 -05:00
ldb_module_set_private ( module , data ) ;
2007-02-04 07:17:03 +00:00
return ldb_next_init ( module ) ;
}
2010-11-01 15:28:02 +11:00
static const struct ldb_module_ops ldb_update_keytab_module_ops = {
2007-02-04 07:17:03 +00:00
. name = " update_keytab " ,
. init_context = update_kt_init ,
. add = update_kt_add ,
. modify = update_kt_modify ,
. rename = update_kt_rename ,
. del = update_kt_delete ,
2009-09-03 18:33:17 +10:00
. prepare_commit = update_kt_prepare_commit ,
2007-02-04 07:17:03 +00:00
. del_transaction = update_kt_del_trans ,
} ;
2010-11-01 15:28:02 +11:00
int ldb_update_keytab_module_init ( const char * version )
{
2010-11-01 22:30:45 +11:00
LDB_MODULE_CHECK_VERSION ( version ) ;
2010-11-01 15:28:02 +11:00
return ldb_register_module ( & ldb_update_keytab_module_ops ) ;
}