2008-12-16 09:21:55 +01:00
/*
ldb database library
Copyright ( C ) Simo Sorce 2005 - 2008
2009-11-05 17:04:10 +11:00
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2007 - 2009
2008-12-16 09:21:55 +01: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
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/>.
*/
/*
* Name : ldb
*
* Component : ldb extended dn control module
*
* Description : this module builds a special dn for returned search
* results , and fixes some other aspects of the result ( returned case issues )
* values .
*
* Authors : Simo Sorce
* Andrew Bartlett
*/
# include "includes.h"
2011-02-10 14:12:51 +11:00
# include <ldb.h>
# include <ldb_errors.h>
# include <ldb_module.h>
2010-09-20 17:42:13 +10:00
# include "libcli/security/security.h"
2008-12-16 09:21:55 +01:00
# include "librpc/gen_ndr/ndr_misc.h"
2009-10-23 22:59:48 -05:00
# include "librpc/gen_ndr/ndr_security.h"
2008-12-16 09:21:55 +01:00
# include "librpc/ndr/libndr.h"
# include "dsdb/samdb/samdb.h"
2010-04-26 09:56:59 +03:00
# include "util.h"
2008-12-16 09:21:55 +01:00
struct extended_dn_out_private {
bool dereference ;
bool normalise ;
struct dsdb_openldap_dereference_control * dereference_control ;
2010-10-21 21:08:45 +11:00
const char * * attrs ;
2008-12-16 09:21:55 +01:00
} ;
2010-10-21 21:08:45 +11:00
/* Do the lazy init of the derererence control */
static int extended_dn_out_dereference_setup_control ( struct ldb_context * ldb , struct extended_dn_out_private * p )
{
const struct dsdb_schema * schema ;
struct dsdb_openldap_dereference_control * dereference_control ;
struct dsdb_attribute * cur ;
unsigned int i = 0 ;
if ( p - > dereference_control ) {
return LDB_SUCCESS ;
}
schema = dsdb_get_schema ( ldb , p ) ;
if ( ! schema ) {
/* No schema on this DB (yet) */
return LDB_SUCCESS ;
}
p - > dereference_control = dereference_control
= talloc_zero ( p , struct dsdb_openldap_dereference_control ) ;
if ( ! p - > dereference_control ) {
return ldb_oom ( ldb ) ;
}
for ( cur = schema - > attributes ; cur ; cur = cur - > next ) {
2011-08-05 11:28:12 +10:00
if ( cur - > dn_format ! = DSDB_NORMAL_DN ) {
2010-10-21 21:08:45 +11:00
continue ;
}
dereference_control - > dereference
= talloc_realloc ( p , dereference_control - > dereference ,
struct dsdb_openldap_dereference * , i + 2 ) ;
if ( ! dereference_control ) {
return ldb_oom ( ldb ) ;
}
dereference_control - > dereference [ i ] = talloc ( dereference_control - > dereference ,
struct dsdb_openldap_dereference ) ;
if ( ! dereference_control - > dereference [ i ] ) {
return ldb_oom ( ldb ) ;
}
dereference_control - > dereference [ i ] - > source_attribute = cur - > lDAPDisplayName ;
dereference_control - > dereference [ i ] - > dereference_attribute = p - > attrs ;
i + + ;
dereference_control - > dereference [ i ] = NULL ;
}
return LDB_SUCCESS ;
}
2008-12-16 09:21:55 +01:00
static char * * copy_attrs ( void * mem_ctx , const char * const * attrs )
{
2009-02-02 08:19:11 +01:00
char * * nattrs ;
2010-03-07 19:03:21 +01:00
unsigned int i , num ;
2008-12-16 09:21:55 +01:00
for ( num = 0 ; attrs [ num ] ; num + + ) ;
2009-02-02 08:19:11 +01:00
nattrs = talloc_array ( mem_ctx , char * , num + 1 ) ;
if ( ! nattrs ) return NULL ;
2008-12-16 09:21:55 +01:00
for ( i = 0 ; i < num ; i + + ) {
2009-02-02 08:19:11 +01:00
nattrs [ i ] = talloc_strdup ( nattrs , attrs [ i ] ) ;
if ( ! nattrs [ i ] ) {
talloc_free ( nattrs ) ;
2008-12-16 09:21:55 +01:00
return NULL ;
}
}
2009-02-02 08:19:11 +01:00
nattrs [ i ] = NULL ;
2008-12-16 09:21:55 +01:00
2009-02-02 08:19:11 +01:00
return nattrs ;
2008-12-16 09:21:55 +01:00
}
static bool add_attrs ( void * mem_ctx , char * * * attrs , const char * attr )
{
2009-02-02 08:19:11 +01:00
char * * nattrs ;
2010-03-07 19:03:21 +01:00
unsigned int num ;
2008-12-16 09:21:55 +01:00
for ( num = 0 ; ( * attrs ) [ num ] ; num + + ) ;
2009-02-02 08:19:11 +01:00
nattrs = talloc_realloc ( mem_ctx , * attrs , char * , num + 2 ) ;
if ( ! nattrs ) return false ;
2008-12-16 09:21:55 +01:00
2009-02-02 08:19:11 +01:00
* attrs = nattrs ;
2008-12-16 09:21:55 +01:00
2009-02-02 08:19:11 +01:00
nattrs [ num ] = talloc_strdup ( nattrs , attr ) ;
if ( ! nattrs [ num ] ) return false ;
2008-12-16 09:21:55 +01:00
2009-02-02 08:19:11 +01:00
nattrs [ num + 1 ] = NULL ;
2008-12-16 09:21:55 +01:00
return true ;
}
/* Fix the DN so that the relative attribute names are in upper case so that the DN:
cn = Adminstrator , cn = users , dc = samba , dc = example , dc = com becomes
CN = Adminstrator , CN = users , DC = samba , DC = example , DC = com
*/
2010-07-06 13:21:54 +10:00
static int fix_dn ( struct ldb_context * ldb , struct ldb_dn * dn )
2008-12-16 09:21:55 +01:00
{
int i , ret ;
char * upper_rdn_attr ;
for ( i = 0 ; i < ldb_dn_get_comp_num ( dn ) ; i + + ) {
/* We need the attribute name in upper case */
upper_rdn_attr = strupper_talloc ( dn ,
ldb_dn_get_component_name ( dn , i ) ) ;
if ( ! upper_rdn_attr ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2008-12-16 09:21:55 +01:00
}
/* And replace it with CN=foo (we need the attribute in upper case */
ret = ldb_dn_set_component ( dn , i , upper_rdn_attr ,
* ldb_dn_get_component_val ( dn , i ) ) ;
talloc_free ( upper_rdn_attr ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
return LDB_SUCCESS ;
}
2011-08-01 13:55:58 +10:00
2008-12-16 09:21:55 +01:00
/* Inject the extended DN components, so the DN cn=Adminstrator,cn=users,dc=samba,dc=example,dc=com becomes
< GUID = 541203 ae - f7d6 - 47 ef - 8390 - bfcf019f9583 > ; < SID = S - 1 - 5 - 21 - 4177067393 - 1453636373 - 93818737 - 500 > ; cn = Adminstrator , cn = users , dc = samba , dc = example , dc = com */
static int inject_extended_dn_out ( struct ldb_reply * ares ,
struct ldb_context * ldb ,
int type ,
bool remove_guid ,
bool remove_sid )
{
int ret ;
const DATA_BLOB * guid_blob ;
const DATA_BLOB * sid_blob ;
guid_blob = ldb_msg_find_ldb_val ( ares - > message , " objectGUID " ) ;
2010-09-13 22:39:50 +02:00
sid_blob = ldb_msg_find_ldb_val ( ares - > message , " objectSid " ) ;
2008-12-16 09:21:55 +01:00
if ( ! guid_blob ) {
ldb_set_errstring ( ldb , " Did not find objectGUID to inject into extended DN " ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
ret = ldb_dn_set_extended_component ( ares - > message - > dn , " GUID " , guid_blob ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
if ( sid_blob ) {
ret = ldb_dn_set_extended_component ( ares - > message - > dn , " SID " , sid_blob ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
if ( remove_guid ) {
ldb_msg_remove_attr ( ares - > message , " objectGUID " ) ;
}
if ( sid_blob & & remove_sid ) {
2010-09-13 22:39:50 +02:00
ldb_msg_remove_attr ( ares - > message , " objectSid " ) ;
2008-12-16 09:21:55 +01:00
}
return LDB_SUCCESS ;
}
2009-10-21 16:02:18 -05:00
static int handle_dereference_openldap ( struct ldb_dn * dn ,
2008-12-16 09:21:55 +01:00
struct dsdb_openldap_dereference_result * * dereference_attrs ,
const char * attr , const DATA_BLOB * val )
{
const struct ldb_val * entryUUIDblob , * sid_blob ;
struct ldb_message fake_msg ; /* easier to use routines that expect an ldb_message */
2010-03-07 19:03:21 +01:00
unsigned int j ;
2008-12-16 09:21:55 +01:00
fake_msg . num_elements = 0 ;
/* Look for this attribute in the returned control */
for ( j = 0 ; dereference_attrs & & dereference_attrs [ j ] ; j + + ) {
struct ldb_val source_dn = data_blob_string_const ( dereference_attrs [ j ] - > dereferenced_dn ) ;
if ( ldb_attr_cmp ( dereference_attrs [ j ] - > source_attribute , attr ) = = 0
& & data_blob_cmp ( & source_dn , val ) = = 0 ) {
fake_msg . num_elements = dereference_attrs [ j ] - > num_attributes ;
fake_msg . elements = dereference_attrs [ j ] - > attributes ;
break ;
}
}
if ( ! fake_msg . num_elements ) {
return LDB_SUCCESS ;
}
/* Look for an OpenLDAP entryUUID */
entryUUIDblob = ldb_msg_find_ldb_val ( & fake_msg , " entryUUID " ) ;
if ( entryUUIDblob ) {
NTSTATUS status ;
struct ldb_val guid_blob ;
struct GUID guid ;
status = GUID_from_data_blob ( entryUUIDblob , & guid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return LDB_ERR_INVALID_DN_SYNTAX ;
}
2009-12-10 14:33:13 +11:00
status = GUID_to_ndr_blob ( & guid , dn , & guid_blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-12-16 09:21:55 +01:00
return LDB_ERR_INVALID_DN_SYNTAX ;
}
ldb_dn_set_extended_component ( dn , " GUID " , & guid_blob ) ;
}
2010-09-13 22:39:50 +02:00
sid_blob = ldb_msg_find_ldb_val ( & fake_msg , " objectSid " ) ;
2008-12-16 09:21:55 +01:00
2010-09-13 22:39:50 +02:00
/* Look for the objectSid */
2008-12-16 09:21:55 +01:00
if ( sid_blob ) {
ldb_dn_set_extended_component ( dn , " SID " , sid_blob ) ;
}
return LDB_SUCCESS ;
}
2009-10-21 16:02:18 -05:00
static int handle_dereference_fds ( struct ldb_dn * dn ,
struct dsdb_openldap_dereference_result * * dereference_attrs ,
const char * attr , const DATA_BLOB * val )
{
const struct ldb_val * nsUniqueIdBlob , * sidBlob ;
struct ldb_message fake_msg ; /* easier to use routines that expect an ldb_message */
2010-03-07 19:03:21 +01:00
unsigned int j ;
2009-10-21 16:02:18 -05:00
fake_msg . num_elements = 0 ;
/* Look for this attribute in the returned control */
for ( j = 0 ; dereference_attrs & & dereference_attrs [ j ] ; j + + ) {
struct ldb_val source_dn = data_blob_string_const ( dereference_attrs [ j ] - > dereferenced_dn ) ;
if ( ldb_attr_cmp ( dereference_attrs [ j ] - > source_attribute , attr ) = = 0
& & data_blob_cmp ( & source_dn , val ) = = 0 ) {
fake_msg . num_elements = dereference_attrs [ j ] - > num_attributes ;
fake_msg . elements = dereference_attrs [ j ] - > attributes ;
break ;
}
}
if ( ! fake_msg . num_elements ) {
return LDB_SUCCESS ;
}
/* Look for the nsUniqueId */
nsUniqueIdBlob = ldb_msg_find_ldb_val ( & fake_msg , " nsUniqueId " ) ;
if ( nsUniqueIdBlob ) {
NTSTATUS status ;
struct ldb_val guid_blob ;
struct GUID guid ;
status = NS_GUID_from_string ( ( char * ) nsUniqueIdBlob - > data , & guid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return LDB_ERR_INVALID_DN_SYNTAX ;
}
2009-12-10 14:33:13 +11:00
status = GUID_to_ndr_blob ( & guid , dn , & guid_blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-10-21 16:02:18 -05:00
return LDB_ERR_INVALID_DN_SYNTAX ;
}
ldb_dn_set_extended_component ( dn , " GUID " , & guid_blob ) ;
}
2010-09-13 22:39:50 +02:00
/* Look for the objectSid */
2009-10-21 16:02:18 -05:00
2009-10-23 22:59:48 -05:00
sidBlob = ldb_msg_find_ldb_val ( & fake_msg , " sambaSID " ) ;
2009-10-21 16:02:18 -05:00
if ( sidBlob ) {
2009-10-23 22:59:48 -05:00
enum ndr_err_code ndr_err ;
struct ldb_val sid_blob ;
struct dom_sid * sid ;
sid = dom_sid_parse_length ( NULL , sidBlob ) ;
if ( sid = = NULL ) {
return LDB_ERR_INVALID_DN_SYNTAX ;
}
2010-05-09 17:20:01 +02:00
ndr_err = ndr_push_struct_blob ( & sid_blob , NULL , sid ,
2009-10-23 22:59:48 -05:00
( ndr_push_flags_fn_t ) ndr_push_dom_sid ) ;
talloc_free ( sid ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return LDB_ERR_INVALID_DN_SYNTAX ;
}
ldb_dn_set_extended_component ( dn , " SID " , & sid_blob ) ;
2009-10-21 16:02:18 -05:00
}
return LDB_SUCCESS ;
}
2008-12-16 09:21:55 +01:00
/* search */
struct extended_search_context {
struct ldb_module * module ;
const struct dsdb_schema * schema ;
struct ldb_request * req ;
bool inject ;
bool remove_guid ;
bool remove_sid ;
int extended_type ;
} ;
2011-08-01 13:55:58 +10:00
/*
fix one - way links to have the right string DN , to cope with
renames of the target
*/
static int fix_one_way_link ( struct extended_search_context * ac , struct ldb_dn * dn )
{
struct GUID guid ;
NTSTATUS status ;
int ret ;
struct ldb_dn * real_dn ;
status = dsdb_get_extended_dn_guid ( dn , & guid , " GUID " ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
/* this is a strange DN that doesn't have a GUID! just
return the current DN string ? ? */
return LDB_SUCCESS ;
}
ret = dsdb_module_dn_by_guid ( ac - > module , dn , & guid , & real_dn , ac - > req ) ;
if ( ret ! = LDB_SUCCESS ) {
/* it could be on another server, we need to leave the
string DN alone */
return LDB_SUCCESS ;
}
if ( strcmp ( ldb_dn_get_linearized ( dn ) , ldb_dn_get_linearized ( real_dn ) ) = = 0 ) {
/* its already correct */
talloc_free ( real_dn ) ;
return LDB_SUCCESS ;
}
/* fix the DN by replacing its components with those from the
* real DN
*/
if ( ! ldb_dn_replace_components ( dn , real_dn ) ) {
talloc_free ( real_dn ) ;
return ldb_operr ( ldb_module_get_ctx ( ac - > module ) ) ;
}
talloc_free ( real_dn ) ;
return LDB_SUCCESS ;
}
/*
this is called to post - process the results from the search
*/
2009-10-21 16:02:18 -05:00
static int extended_callback ( struct ldb_request * req , struct ldb_reply * ares ,
int ( * handle_dereference ) ( struct ldb_dn * dn ,
struct dsdb_openldap_dereference_result * * dereference_attrs ,
const char * attr , const DATA_BLOB * val ) )
2008-12-16 09:21:55 +01:00
{
struct extended_search_context * ac ;
struct ldb_control * control ;
struct dsdb_openldap_dereference_result_control * dereference_control = NULL ;
2010-03-07 19:03:21 +01:00
int ret ;
unsigned int i , j ;
2010-09-10 20:15:00 +10:00
struct ldb_message * msg ;
2009-02-02 08:19:11 +01:00
struct extended_dn_out_private * p ;
2009-11-07 12:07:06 +11:00
struct ldb_context * ldb ;
2011-01-08 22:21:13 +01:00
bool have_reveal_control = false , checked_reveal_control = false ;
2009-12-10 23:46:34 +11:00
2008-12-16 09:21:55 +01:00
ac = talloc_get_type ( req - > context , struct extended_search_context ) ;
2009-06-30 15:12:29 +10:00
p = talloc_get_type ( ldb_module_get_private ( ac - > module ) , struct extended_dn_out_private ) ;
2009-11-07 12:07:06 +11:00
ldb = ldb_module_get_ctx ( ac - > module ) ;
2008-12-16 09:21:55 +01: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 ) ;
}
2010-09-10 20:15:00 +10:00
msg = ares - > message ;
2008-12-16 09:21:55 +01:00
switch ( ares - > type ) {
case LDB_REPLY_REFERRAL :
return ldb_module_send_referral ( ac - > req , ares - > referral ) ;
case LDB_REPLY_DONE :
return ldb_module_done ( ac - > req , ares - > controls ,
ares - > response , LDB_SUCCESS ) ;
case LDB_REPLY_ENTRY :
break ;
}
2009-02-02 08:19:11 +01:00
if ( p & & p - > normalise ) {
2010-07-06 13:21:54 +10:00
ret = fix_dn ( ldb , ares - > message - > dn ) ;
2008-12-16 09:21:55 +01:00
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , NULL , NULL , ret ) ;
}
}
if ( ac - > inject ) {
/* for each record returned post-process to add any derived
attributes that have been asked for */
2009-11-07 12:07:06 +11:00
ret = inject_extended_dn_out ( ares , ldb ,
2008-12-16 09:21:55 +01:00
ac - > extended_type , ac - > remove_guid ,
ac - > remove_sid ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , NULL , NULL , ret ) ;
}
}
2009-02-02 08:19:11 +01:00
if ( ( p & & p - > normalise ) | | ac - > inject ) {
2008-12-16 09:21:55 +01:00
const struct ldb_val * val = ldb_msg_find_ldb_val ( ares - > message , " distinguishedName " ) ;
if ( val ) {
ldb_msg_remove_attr ( ares - > message , " distinguishedName " ) ;
if ( ac - > inject ) {
ret = ldb_msg_add_steal_string ( ares - > message , " distinguishedName " ,
ldb_dn_get_extended_linearized ( ares - > message , ares - > message - > dn , ac - > extended_type ) ) ;
} else {
2009-11-23 15:47:51 -02:00
ret = ldb_msg_add_linearized_dn ( ares - > message ,
" distinguishedName " ,
ares - > message - > dn ) ;
2008-12-16 09:21:55 +01:00
}
if ( ret ! = LDB_SUCCESS ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2008-12-16 09:21:55 +01:00
}
}
}
2009-02-02 08:19:11 +01:00
if ( p & & p - > dereference ) {
2008-12-16 09:21:55 +01:00
control = ldb_reply_get_control ( ares , DSDB_OPENLDAP_DEREFERENCE_CONTROL ) ;
if ( control & & control - > data ) {
dereference_control = talloc_get_type ( control - > data , struct dsdb_openldap_dereference_result_control ) ;
}
}
2010-03-07 19:03:21 +01:00
/* Walk the returned elements (but only if we have a schema to
* interpret the list with ) */
2008-12-16 09:21:55 +01:00
for ( i = 0 ; ac - > schema & & i < msg - > num_elements ; i + + ) {
2009-11-22 17:48:32 +02:00
bool make_extended_dn ;
2008-12-16 09:21:55 +01:00
const struct dsdb_attribute * attribute ;
2011-08-01 13:55:58 +10:00
2008-12-16 09:21:55 +01:00
attribute = dsdb_attribute_by_lDAPDisplayName ( ac - > schema , msg - > elements [ i ] . name ) ;
if ( ! attribute ) {
continue ;
}
2009-02-02 08:19:11 +01:00
if ( p - > normalise ) {
2008-12-16 09:21:55 +01:00
/* If we are also in 'normalise' mode, then
* fix the attribute names to be in the
* correct case */
msg - > elements [ i ] . name = talloc_strdup ( msg - > elements , attribute - > lDAPDisplayName ) ;
if ( ! msg - > elements [ i ] . name ) {
2009-11-07 12:07:06 +11:00
ldb_oom ( ldb ) ;
2008-12-16 09:21:55 +01:00
return ldb_module_done ( ac - > req , NULL , NULL , LDB_ERR_OPERATIONS_ERROR ) ;
}
}
/* distinguishedName has been dealt with above */
if ( ldb_attr_cmp ( msg - > elements [ i ] . name , " distinguishedName " ) = = 0 ) {
continue ;
}
/* Look to see if this attributeSyntax is a DN */
2011-08-05 11:28:12 +10:00
if ( attribute - > dn_format = = DSDB_INVALID_DN ) {
2008-12-16 09:21:55 +01:00
continue ;
}
2009-11-22 17:48:32 +02:00
make_extended_dn = ac - > inject ;
/* Always show plain DN in case of Object(OR-Name) syntax */
if ( make_extended_dn ) {
make_extended_dn = ( strcmp ( attribute - > syntax - > ldap_oid , DSDB_SYNTAX_OR_NAME ) ! = 0 ) ;
}
2008-12-16 09:21:55 +01:00
for ( j = 0 ; j < msg - > elements [ i ] . num_values ; j + + ) {
const char * dn_str ;
2009-11-05 17:04:10 +11:00
struct ldb_dn * dn ;
struct dsdb_dn * dsdb_dn = NULL ;
struct ldb_val * plain_dn = & msg - > elements [ i ] . values [ j ] ;
2009-12-15 11:01:18 +11:00
if ( ! checked_reveal_control ) {
have_reveal_control =
ldb_request_get_control ( req , LDB_CONTROL_REVEAL_INTERNALS ) ! = NULL ;
checked_reveal_control = true ;
}
/* this is a fast method for detecting deleted
linked attributes , working on the unparsed
ldb_val */
if ( dsdb_dn_is_deleted_val ( plain_dn ) & & ! have_reveal_control ) {
/* it's a deleted linked attribute,
and we don ' t have the reveal control */
memmove ( & msg - > elements [ i ] . values [ j ] ,
& msg - > elements [ i ] . values [ j + 1 ] ,
( msg - > elements [ i ] . num_values - ( j + 1 ) ) * sizeof ( struct ldb_val ) ) ;
msg - > elements [ i ] . num_values - - ;
j - - ;
continue ;
}
2009-11-07 12:07:06 +11:00
dsdb_dn = dsdb_dn_parse ( msg , ldb , plain_dn , attribute - > syntax - > ldap_oid ) ;
2009-12-10 23:46:34 +11:00
2009-11-05 17:04:10 +11:00
if ( ! dsdb_dn | | ! ldb_dn_validate ( dsdb_dn - > dn ) ) {
2009-11-07 12:07:06 +11:00
ldb_asprintf_errstring ( ldb ,
2009-11-12 15:35:54 +11:00
" could not parse %.*s in %s on %s as a %s DN " ,
( int ) plain_dn - > length , plain_dn - > data ,
msg - > elements [ i ] . name , ldb_dn_get_linearized ( msg - > dn ) ,
2009-11-05 17:04:10 +11:00
attribute - > syntax - > ldap_oid ) ;
talloc_free ( dsdb_dn ) ;
2008-12-16 09:21:55 +01:00
return ldb_module_done ( ac - > req , NULL , NULL , LDB_ERR_INVALID_DN_SYNTAX ) ;
}
2009-11-05 17:04:10 +11:00
dn = dsdb_dn - > dn ;
2008-12-16 09:21:55 +01:00
2009-12-10 23:46:34 +11:00
/* don't let users see the internal extended
GUID components */
if ( ! have_reveal_control ) {
const char * accept [ ] = { " GUID " , " SID " , " WKGUID " , NULL } ;
ldb_dn_extended_filter ( dn , accept ) ;
}
2009-02-02 08:19:11 +01:00
if ( p - > normalise ) {
2010-07-06 13:21:54 +10:00
ret = fix_dn ( ldb , dn ) ;
2008-12-16 09:21:55 +01:00
if ( ret ! = LDB_SUCCESS ) {
2009-11-05 17:04:10 +11:00
talloc_free ( dsdb_dn ) ;
2008-12-16 09:21:55 +01:00
return ldb_module_done ( ac - > req , NULL , NULL , ret ) ;
}
}
/* If we are running in dereference mode (such
* as against OpenLDAP ) then the DN in the msg
* above does not contain the extended values ,
* and we need to look in the dereference
* result */
/* Look for this value in the attribute */
if ( dereference_control ) {
ret = handle_dereference ( dn ,
dereference_control - > attributes ,
msg - > elements [ i ] . name ,
& msg - > elements [ i ] . values [ j ] ) ;
if ( ret ! = LDB_SUCCESS ) {
2011-08-01 13:55:58 +10:00
talloc_free ( dsdb_dn ) ;
return ldb_module_done ( ac - > req , NULL , NULL , ret ) ;
}
}
/* note that we don't fixup objectCategory as
it should not be possible to move
objectCategory elements in the schema */
if ( attribute - > one_way_link & &
strcasecmp ( attribute - > lDAPDisplayName , " objectCategory " ) ! = 0 ) {
ret = fix_one_way_link ( ac , dn ) ;
if ( ret ! = LDB_SUCCESS ) {
2009-11-05 17:04:10 +11:00
talloc_free ( dsdb_dn ) ;
2008-12-16 09:21:55 +01:00
return ldb_module_done ( ac - > req , NULL , NULL , ret ) ;
}
}
2009-11-22 17:48:32 +02:00
if ( make_extended_dn ) {
dn_str = dsdb_dn_get_extended_linearized ( msg - > elements [ i ] . values ,
dsdb_dn , ac - > extended_type ) ;
} else {
2009-11-05 17:04:10 +11:00
dn_str = dsdb_dn_get_linearized ( msg - > elements [ i ] . values ,
dsdb_dn ) ;
2008-12-16 09:21:55 +01:00
}
2009-11-05 17:04:10 +11:00
2008-12-16 09:21:55 +01:00
if ( ! dn_str ) {
2009-11-07 12:07:06 +11:00
ldb_oom ( ldb ) ;
2009-11-05 17:04:10 +11:00
talloc_free ( dsdb_dn ) ;
2008-12-16 09:21:55 +01:00
return ldb_module_done ( ac - > req , NULL , NULL , LDB_ERR_OPERATIONS_ERROR ) ;
}
msg - > elements [ i ] . values [ j ] = data_blob_string_const ( dn_str ) ;
2009-11-05 17:04:10 +11:00
talloc_free ( dsdb_dn ) ;
2008-12-16 09:21:55 +01:00
}
2009-12-10 23:46:34 +11:00
if ( msg - > elements [ i ] . num_values = = 0 ) {
/* we've deleted all of the values from this
* element - remove the element */
memmove ( & msg - > elements [ i ] ,
& msg - > elements [ i + 1 ] ,
( msg - > num_elements - ( i + 1 ) ) * sizeof ( struct ldb_message_element ) ) ;
msg - > num_elements - - ;
i - - ;
}
2008-12-16 09:21:55 +01:00
}
return ldb_module_send_entry ( ac - > req , msg , ares - > controls ) ;
}
2009-11-12 21:31:11 +11:00
static int extended_callback_ldb ( struct ldb_request * req , struct ldb_reply * ares )
{
return extended_callback ( req , ares , NULL ) ;
}
2009-10-21 16:02:18 -05:00
static int extended_callback_openldap ( struct ldb_request * req , struct ldb_reply * ares )
{
return extended_callback ( req , ares , handle_dereference_openldap ) ;
}
2008-12-16 09:21:55 +01:00
2009-10-21 16:02:18 -05:00
static int extended_callback_fds ( struct ldb_request * req , struct ldb_reply * ares )
{
return extended_callback ( req , ares , handle_dereference_fds ) ;
}
static int extended_dn_out_search ( struct ldb_module * module , struct ldb_request * req ,
int ( * callback ) ( struct ldb_request * req , struct ldb_reply * ares ) )
2008-12-16 09:21:55 +01:00
{
struct ldb_control * control ;
struct ldb_control * storage_format_control ;
struct ldb_extended_dn_control * extended_ctrl = NULL ;
struct extended_search_context * ac ;
struct ldb_request * down_req ;
char * * new_attrs ;
const char * const * const_attrs ;
2009-11-07 12:07:06 +11:00
struct ldb_context * ldb = ldb_module_get_ctx ( module ) ;
2008-12-16 09:21:55 +01:00
int ret ;
2010-07-11 23:08:46 +10:00
bool critical ;
2008-12-16 09:21:55 +01:00
2009-06-30 15:12:29 +10:00
struct extended_dn_out_private * p = talloc_get_type ( ldb_module_get_private ( module ) , struct extended_dn_out_private ) ;
2008-12-16 09:21:55 +01:00
2010-03-22 15:17:58 +11:00
/* The schema manipulation does not apply to special DNs */
if ( ldb_dn_is_special ( req - > op . search . base ) ) {
return ldb_next_request ( module , req ) ;
}
2008-12-16 09:21:55 +01:00
/* check if there's an extended dn control */
control = ldb_request_get_control ( req , LDB_CONTROL_EXTENDED_DN_OID ) ;
if ( control & & control - > data ) {
extended_ctrl = talloc_get_type ( control - > data , struct ldb_extended_dn_control ) ;
if ( ! extended_ctrl ) {
return LDB_ERR_PROTOCOL_ERROR ;
}
}
/* Look to see if, as we are in 'store DN+GUID+SID' mode, the
* client is after the storage format ( to fill in linked
* attributes ) */
storage_format_control = ldb_request_get_control ( req , DSDB_CONTROL_DN_STORAGE_FORMAT_OID ) ;
if ( ! control & & storage_format_control & & storage_format_control - > data ) {
extended_ctrl = talloc_get_type ( storage_format_control - > data , struct ldb_extended_dn_control ) ;
if ( ! extended_ctrl ) {
2009-11-07 12:07:06 +11:00
ldb_set_errstring ( ldb , " extended_dn_out: extended_ctrl was of the wrong data type " ) ;
2008-12-16 09:21:55 +01:00
return LDB_ERR_PROTOCOL_ERROR ;
}
}
ac = talloc_zero ( req , struct extended_search_context ) ;
if ( ac = = NULL ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2008-12-16 09:21:55 +01:00
}
ac - > module = module ;
2010-03-16 14:52:39 +11:00
ac - > schema = dsdb_get_schema ( ldb , ac ) ;
2008-12-16 09:21:55 +01:00
ac - > req = req ;
ac - > inject = false ;
ac - > remove_guid = false ;
ac - > remove_sid = false ;
const_attrs = req - > op . search . attrs ;
/* We only need to do special processing if we were asked for
* the extended DN , or we are ' store DN + GUID + SID '
* ( ! dereference ) mode . ( This is the normal mode for LDB on
* tdb ) . */
2009-02-02 08:19:11 +01:00
if ( control | | ( storage_format_control & & p & & ! p - > dereference ) ) {
2008-12-16 09:21:55 +01:00
ac - > inject = true ;
if ( extended_ctrl ) {
ac - > extended_type = extended_ctrl - > type ;
} else {
ac - > extended_type = 0 ;
}
/* check if attrs only is specified, in that case check wether we need to modify them */
if ( req - > op . search . attrs & & ! is_attr_in_list ( req - > op . search . attrs , " * " ) ) {
if ( ! is_attr_in_list ( req - > op . search . attrs , " objectGUID " ) ) {
ac - > remove_guid = true ;
}
2010-09-13 22:39:50 +02:00
if ( ! is_attr_in_list ( req - > op . search . attrs , " objectSid " ) ) {
2008-12-16 09:21:55 +01:00
ac - > remove_sid = true ;
}
if ( ac - > remove_guid | | ac - > remove_sid ) {
new_attrs = copy_attrs ( ac , req - > op . search . attrs ) ;
if ( new_attrs = = NULL ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2008-12-16 09:21:55 +01:00
}
if ( ac - > remove_guid ) {
if ( ! add_attrs ( ac , & new_attrs , " objectGUID " ) )
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2008-12-16 09:21:55 +01:00
}
if ( ac - > remove_sid ) {
2010-09-13 22:39:50 +02:00
if ( ! add_attrs ( ac , & new_attrs , " objectSid " ) )
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2008-12-16 09:21:55 +01:00
}
const_attrs = ( const char * const * ) new_attrs ;
}
}
}
ret = ldb_build_search_req_ex ( & down_req ,
2009-11-07 12:07:06 +11:00
ldb , ac ,
2008-12-16 09:21:55 +01:00
req - > op . search . base ,
req - > op . search . scope ,
req - > op . search . tree ,
const_attrs ,
req - > controls ,
2009-10-21 16:02:18 -05:00
ac , callback ,
2008-12-16 09:21:55 +01:00
req ) ;
2010-09-24 12:09:26 -07:00
LDB_REQ_SET_LOCATION ( down_req ) ;
2008-12-16 09:21:55 +01:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2009-12-16 20:45:02 +11:00
/* mark extended DN and storage format controls as done */
2008-12-16 09:21:55 +01:00
if ( control ) {
2010-07-11 23:08:46 +10:00
critical = control - > critical ;
2009-12-16 20:45:02 +11:00
control - > critical = 0 ;
2008-12-16 09:21:55 +01:00
}
if ( storage_format_control ) {
2009-12-16 20:45:02 +11:00
storage_format_control - > critical = 0 ;
2008-12-16 09:21:55 +01:00
}
/* Add in dereference control, if we were asked to, we are
* using the ' dereference ' mode ( such as with an OpenLDAP
* backend ) and have the control prepared */
2010-10-21 21:08:45 +11:00
if ( control & & p & & p - > dereference ) {
ret = extended_dn_out_dereference_setup_control ( ldb , p ) ;
2008-12-16 09:21:55 +01:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2010-10-21 21:08:45 +11:00
/* We should always have this, but before the schema
* is with us , things get tricky */
if ( p - > dereference_control ) {
/* This control must *not* be critical,
* because if this particular request did not
* return any dereferencable attributes in the
* end , then OpenLDAP will reply with
* unavailableCriticalExtension , rather than
* just an empty return control */
ret = ldb_request_add_control ( down_req ,
DSDB_OPENLDAP_DEREFERENCE_CONTROL ,
false , p - > dereference_control ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2008-12-16 09:21:55 +01:00
}
/* perform the search */
return ldb_next_request ( module , down_req ) ;
}
2009-10-21 16:02:18 -05:00
static int extended_dn_out_ldb_search ( struct ldb_module * module , struct ldb_request * req )
{
2009-11-12 21:31:11 +11:00
return extended_dn_out_search ( module , req , extended_callback_ldb ) ;
2009-10-21 16:02:18 -05:00
}
static int extended_dn_out_openldap_search ( struct ldb_module * module , struct ldb_request * req )
{
return extended_dn_out_search ( module , req , extended_callback_openldap ) ;
}
static int extended_dn_out_fds_search ( struct ldb_module * module , struct ldb_request * req )
{
return extended_dn_out_search ( module , req , extended_callback_fds ) ;
}
2008-12-16 09:21:55 +01:00
static int extended_dn_out_ldb_init ( struct ldb_module * module )
{
int ret ;
2009-02-02 08:19:11 +01:00
struct extended_dn_out_private * p = talloc ( module , struct extended_dn_out_private ) ;
2009-11-16 18:46:28 +11:00
struct dsdb_extended_dn_store_format * dn_format ;
2008-12-16 09:21:55 +01:00
2009-06-30 15:12:29 +10:00
ldb_module_set_private ( module , p ) ;
2008-12-16 09:21:55 +01:00
2009-02-02 08:19:11 +01:00
if ( ! p ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb_module_get_ctx ( module ) ) ;
2008-12-16 09:21:55 +01:00
}
2009-11-16 18:46:28 +11:00
dn_format = talloc ( p , struct dsdb_extended_dn_store_format ) ;
if ( ! dn_format ) {
talloc_free ( p ) ;
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb_module_get_ctx ( module ) ) ;
2009-11-16 18:46:28 +11:00
}
dn_format - > store_extended_dn_in_ldb = true ;
ret = ldb_set_opaque ( ldb_module_get_ctx ( module ) , DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME , dn_format ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( p ) ;
return ret ;
}
2009-02-02 08:19:11 +01:00
p - > dereference = false ;
p - > normalise = false ;
2008-12-16 09:21:55 +01:00
ret = ldb_mod_register_control ( module , LDB_CONTROL_EXTENDED_DN_OID ) ;
if ( ret ! = LDB_SUCCESS ) {
2009-06-30 15:12:29 +10:00
ldb_debug ( ldb_module_get_ctx ( module ) , LDB_DEBUG_ERROR ,
2008-12-16 09:21:55 +01:00
" extended_dn_out: Unable to register control with rootdse! \n " ) ;
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb_module_get_ctx ( module ) ) ;
2008-12-16 09:21:55 +01:00
}
return ldb_next_init ( module ) ;
}
2009-10-21 16:02:18 -05:00
static int extended_dn_out_dereference_init ( struct ldb_module * module , const char * attrs [ ] )
2008-12-16 09:21:55 +01:00
{
2010-03-07 19:03:21 +01:00
int ret ;
2009-06-30 15:12:29 +10:00
struct extended_dn_out_private * p = talloc_zero ( module , struct extended_dn_out_private ) ;
2009-11-16 18:46:28 +11:00
struct dsdb_extended_dn_store_format * dn_format ;
2008-12-16 09:21:55 +01:00
2009-06-30 15:12:29 +10:00
ldb_module_set_private ( module , p ) ;
2008-12-16 09:21:55 +01:00
2009-02-02 08:19:11 +01:00
if ( ! p ) {
2010-10-21 21:08:45 +11:00
return ldb_module_oom ( module ) ;
2008-12-16 09:21:55 +01:00
}
2009-11-16 18:46:28 +11:00
dn_format = talloc ( p , struct dsdb_extended_dn_store_format ) ;
if ( ! dn_format ) {
talloc_free ( p ) ;
2010-10-21 21:08:45 +11:00
return ldb_module_oom ( module ) ;
2009-11-16 18:46:28 +11:00
}
dn_format - > store_extended_dn_in_ldb = false ;
ret = ldb_set_opaque ( ldb_module_get_ctx ( module ) , DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME , dn_format ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( p ) ;
return ret ;
}
2009-02-02 08:19:11 +01:00
p - > dereference = true ;
2008-12-16 09:21:55 +01:00
2010-10-21 21:08:45 +11:00
p - > attrs = attrs ;
2008-12-16 09:21:55 +01:00
/* At the moment, servers that need dereference also need the
* DN and attribute names to be normalised */
2009-02-02 08:19:11 +01:00
p - > normalise = true ;
2008-12-16 09:21:55 +01:00
ret = ldb_mod_register_control ( module , LDB_CONTROL_EXTENDED_DN_OID ) ;
if ( ret ! = LDB_SUCCESS ) {
2010-10-21 21:08:45 +11:00
ldb_debug ( ldb_module_get_ctx ( module ) , LDB_DEBUG_ERROR ,
" extended_dn_out: Unable to register control with rootdse! \n " ) ;
return ldb_operr ( ldb_module_get_ctx ( module ) ) ;
2008-12-16 09:21:55 +01:00
}
2010-10-21 21:08:45 +11:00
return ldb_next_init ( module ) ;
2008-12-16 09:21:55 +01:00
}
2009-10-21 16:02:18 -05:00
static int extended_dn_out_openldap_init ( struct ldb_module * module )
{
static const char * attrs [ ] = {
" entryUUID " ,
2010-09-13 22:39:50 +02:00
" objectSid " ,
2009-10-21 16:02:18 -05:00
NULL
} ;
return extended_dn_out_dereference_init ( module , attrs ) ;
}
static int extended_dn_out_fds_init ( struct ldb_module * module )
{
static const char * attrs [ ] = {
" nsUniqueId " ,
2010-07-11 23:11:09 +10:00
" sambaSID " ,
2009-10-21 16:02:18 -05:00
NULL
} ;
return extended_dn_out_dereference_init ( module , attrs ) ;
}
2010-11-01 12:39:06 +11:00
static const struct ldb_module_ops ldb_extended_dn_out_ldb_module_ops = {
2008-12-16 09:21:55 +01:00
. name = " extended_dn_out_ldb " ,
2009-10-21 16:02:18 -05:00
. search = extended_dn_out_ldb_search ,
2008-12-16 09:21:55 +01:00
. init_context = extended_dn_out_ldb_init ,
} ;
2010-11-01 12:39:06 +11:00
static const struct ldb_module_ops ldb_extended_dn_out_openldap_module_ops = {
2009-10-21 16:02:18 -05:00
. name = " extended_dn_out_openldap " ,
. search = extended_dn_out_openldap_search ,
. init_context = extended_dn_out_openldap_init ,
} ;
2008-12-16 09:21:55 +01:00
2010-11-01 12:39:06 +11:00
static const struct ldb_module_ops ldb_extended_dn_out_fds_module_ops = {
2009-10-21 16:02:18 -05:00
. name = " extended_dn_out_fds " ,
. search = extended_dn_out_fds_search ,
. init_context = extended_dn_out_fds_init ,
2008-12-16 09:21:55 +01:00
} ;
2010-11-01 12:39:06 +11:00
/*
initialise the module
*/
2010-11-01 22:30:45 +11:00
_PUBLIC_ int ldb_extended_dn_out_module_init ( const char * version )
2010-11-01 12:39:06 +11:00
{
int ret ;
2010-11-01 22:30:45 +11:00
LDB_MODULE_CHECK_VERSION ( version ) ;
2010-11-01 12:39:06 +11:00
ret = ldb_register_module ( & ldb_extended_dn_out_ldb_module_ops ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
ret = ldb_register_module ( & ldb_extended_dn_out_openldap_module_ops ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
ret = ldb_register_module ( & ldb_extended_dn_out_fds_module_ops ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
return LDB_SUCCESS ;
}