2007-12-17 06:22:44 +03:00
/*
Unix SMB / CIFS implementation .
Samba utility functions
Copyright ( C ) Andrew Tridgell 2004
Copyright ( C ) Volker Lendecke 2004
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2006
Copyright ( C ) Jelmer Vernooij < jelmer @ samba . org > 2007
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03: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 .
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03: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 .
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
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"
2009-01-21 15:40:18 +03:00
# include "events/events.h"
2007-12-17 06:22:44 +03:00
# include "ldb.h"
2010-07-06 07:21:54 +04:00
# include "ldb_module.h"
2007-12-17 06:22:44 +03:00
# include "ldb_errors.h"
2008-10-11 23:31:42 +04:00
# include "../lib/util/util_ldb.h"
2008-10-16 05:48:16 +04:00
# include "../lib/crypto/crypto.h"
2007-12-17 06:22:44 +03:00
# include "dsdb/samdb/samdb.h"
# include "libcli/security/security.h"
# include "librpc/gen_ndr/ndr_security.h"
2008-04-02 06:53:27 +04:00
# include "librpc/gen_ndr/ndr_misc.h"
2009-06-12 16:27:19 +04:00
# include "../libds/common/flags.h"
2007-12-17 06:22:44 +03:00
# include "dsdb/common/proto.h"
# include "libcli/ldap/ldap_ndr.h"
2008-01-02 07:05:05 +03:00
# include "param/param.h"
2007-12-17 06:22:44 +03:00
# include "libcli/auth/libcli_auth.h"
2009-09-12 05:09:10 +04:00
# include "librpc/gen_ndr/ndr_drsblobs.h"
2009-11-14 22:12:42 +03:00
# include "system/locale.h"
2010-02-13 04:59:43 +03:00
# include "lib/util/tsort.h"
2010-02-16 06:23:21 +03:00
# include "dsdb/common/util.h"
2010-04-13 20:28:53 +04:00
# include "lib/socket/socket.h"
2010-04-26 10:56:59 +04:00
# include "dsdb/samdb/ldb_modules/util.h"
2007-12-17 06:22:44 +03:00
/*
search the sam for the specified attributes in a specific domain , filter on
objectSid being in domain_sid .
*/
int samdb_search_domain ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * basedn ,
struct ldb_message * * * res ,
const char * const * attrs ,
const struct dom_sid * domain_sid ,
const char * format , . . . ) _PRINTF_ATTRIBUTE ( 7 , 8 )
{
va_list ap ;
int i , count ;
va_start ( ap , format ) ;
count = gendb_search_v ( sam_ldb , mem_ctx , basedn ,
res , attrs , format , ap ) ;
va_end ( ap ) ;
i = 0 ;
while ( i < count ) {
struct dom_sid * entry_sid ;
entry_sid = samdb_result_dom_sid ( mem_ctx , ( * res ) [ i ] , " objectSid " ) ;
if ( ( entry_sid = = NULL ) | |
( ! dom_sid_in_domain ( domain_sid , entry_sid ) ) ) {
/* Delete that entry from the result set */
( * res ) [ i ] = ( * res ) [ count - 1 ] ;
count - = 1 ;
talloc_free ( entry_sid ) ;
continue ;
}
talloc_free ( entry_sid ) ;
i + = 1 ;
}
return count ;
}
/*
search the sam for a single string attribute in exactly 1 record
*/
const char * samdb_search_string_v ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * basedn ,
const char * attr_name ,
const char * format , va_list ap ) _PRINTF_ATTRIBUTE ( 5 , 0 )
{
int count ;
const char * attrs [ 2 ] = { NULL , NULL } ;
struct ldb_message * * res = NULL ;
attrs [ 0 ] = attr_name ;
count = gendb_search_v ( sam_ldb , mem_ctx , basedn , & res , attrs , format , ap ) ;
if ( count > 1 ) {
DEBUG ( 1 , ( " samdb: search for %s %s not single valued (count=%d) \n " ,
attr_name , format , count ) ) ;
}
if ( count ! = 1 ) {
talloc_free ( res ) ;
return NULL ;
}
return samdb_result_string ( res [ 0 ] , attr_name , NULL ) ;
}
/*
search the sam for a single string attribute in exactly 1 record
*/
const char * samdb_search_string ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * basedn ,
const char * attr_name ,
const char * format , . . . ) _PRINTF_ATTRIBUTE ( 5 , 6 )
{
va_list ap ;
const char * str ;
va_start ( ap , format ) ;
str = samdb_search_string_v ( sam_ldb , mem_ctx , basedn , attr_name , format , ap ) ;
va_end ( ap ) ;
return str ;
}
struct ldb_dn * samdb_search_dn ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * basedn ,
const char * format , . . . ) _PRINTF_ATTRIBUTE ( 4 , 5 )
{
va_list ap ;
struct ldb_dn * ret ;
struct ldb_message * * res = NULL ;
int count ;
va_start ( ap , format ) ;
count = gendb_search_v ( sam_ldb , mem_ctx , basedn , & res , NULL , format , ap ) ;
va_end ( ap ) ;
if ( count ! = 1 ) return NULL ;
ret = talloc_steal ( mem_ctx , res [ 0 ] - > dn ) ;
talloc_free ( res ) ;
return ret ;
}
/*
search the sam for a dom_sid attribute in exactly 1 record
*/
struct dom_sid * samdb_search_dom_sid ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * basedn ,
const char * attr_name ,
const char * format , . . . ) _PRINTF_ATTRIBUTE ( 5 , 6 )
{
va_list ap ;
int count ;
struct ldb_message * * res ;
const char * attrs [ 2 ] = { NULL , NULL } ;
struct dom_sid * sid ;
attrs [ 0 ] = attr_name ;
va_start ( ap , format ) ;
count = gendb_search_v ( sam_ldb , mem_ctx , basedn , & res , attrs , format , ap ) ;
va_end ( ap ) ;
if ( count > 1 ) {
DEBUG ( 1 , ( " samdb: search for %s %s not single valued (count=%d) \n " ,
attr_name , format , count ) ) ;
}
if ( count ! = 1 ) {
talloc_free ( res ) ;
return NULL ;
}
sid = samdb_result_dom_sid ( mem_ctx , res [ 0 ] , attr_name ) ;
talloc_free ( res ) ;
return sid ;
}
/*
return the count of the number of records in the sam matching the query
*/
int samdb_search_count ( struct ldb_context * sam_ldb ,
struct ldb_dn * basedn ,
2009-12-04 09:45:38 +03:00
const char * format , . . . ) _PRINTF_ATTRIBUTE ( 3 , 4 )
2007-12-17 06:22:44 +03:00
{
va_list ap ;
struct ldb_message * * res ;
2009-12-04 09:45:38 +03:00
const char * attrs [ ] = { NULL } ;
2007-12-17 06:22:44 +03:00
int ret ;
2009-12-04 09:45:38 +03:00
TALLOC_CTX * tmp_ctx = talloc_new ( sam_ldb ) ;
2007-12-17 06:22:44 +03:00
va_start ( ap , format ) ;
2009-12-04 09:45:38 +03:00
ret = gendb_search_v ( sam_ldb , tmp_ctx , basedn , & res , attrs , format , ap ) ;
2007-12-17 06:22:44 +03:00
va_end ( ap ) ;
2009-12-04 09:45:38 +03:00
talloc_free ( tmp_ctx ) ;
2007-12-17 06:22:44 +03:00
return ret ;
}
/*
search the sam for a single integer attribute in exactly 1 record
*/
2010-01-05 20:42:54 +03:00
unsigned int samdb_search_uint ( struct ldb_context * sam_ldb ,
2007-12-17 06:22:44 +03:00
TALLOC_CTX * mem_ctx ,
2010-01-05 20:42:54 +03:00
unsigned int default_value ,
2007-12-17 06:22:44 +03:00
struct ldb_dn * basedn ,
const char * attr_name ,
const char * format , . . . ) _PRINTF_ATTRIBUTE ( 6 , 7 )
{
va_list ap ;
int count ;
struct ldb_message * * res ;
const char * attrs [ 2 ] = { NULL , NULL } ;
attrs [ 0 ] = attr_name ;
va_start ( ap , format ) ;
count = gendb_search_v ( sam_ldb , mem_ctx , basedn , & res , attrs , format , ap ) ;
va_end ( ap ) ;
if ( count ! = 1 ) {
return default_value ;
}
return samdb_result_uint ( res [ 0 ] , attr_name , default_value ) ;
}
/*
search the sam for a single signed 64 bit integer attribute in exactly 1 record
*/
int64_t samdb_search_int64 ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
int64_t default_value ,
struct ldb_dn * basedn ,
const char * attr_name ,
const char * format , . . . ) _PRINTF_ATTRIBUTE ( 6 , 7 )
{
va_list ap ;
int count ;
struct ldb_message * * res ;
const char * attrs [ 2 ] = { NULL , NULL } ;
attrs [ 0 ] = attr_name ;
va_start ( ap , format ) ;
count = gendb_search_v ( sam_ldb , mem_ctx , basedn , & res , attrs , format , ap ) ;
va_end ( ap ) ;
if ( count ! = 1 ) {
return default_value ;
}
return samdb_result_int64 ( res [ 0 ] , attr_name , default_value ) ;
}
/*
search the sam for multipe records each giving a single string attribute
return the number of matches , or - 1 on error
*/
int samdb_search_string_multiple ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * basedn ,
const char * * * strs ,
const char * attr_name ,
const char * format , . . . ) _PRINTF_ATTRIBUTE ( 6 , 7 )
{
va_list ap ;
int count , i ;
const char * attrs [ 2 ] = { NULL , NULL } ;
struct ldb_message * * res = NULL ;
attrs [ 0 ] = attr_name ;
va_start ( ap , format ) ;
count = gendb_search_v ( sam_ldb , mem_ctx , basedn , & res , attrs , format , ap ) ;
va_end ( ap ) ;
if ( count < = 0 ) {
return count ;
}
/* make sure its single valued */
for ( i = 0 ; i < count ; i + + ) {
if ( res [ i ] - > num_elements ! = 1 ) {
DEBUG ( 1 , ( " samdb: search for %s %s not single valued \n " ,
attr_name , format ) ) ;
talloc_free ( res ) ;
return - 1 ;
}
}
* strs = talloc_array ( mem_ctx , const char * , count + 1 ) ;
if ( ! * strs ) {
talloc_free ( res ) ;
return - 1 ;
}
for ( i = 0 ; i < count ; i + + ) {
( * strs ) [ i ] = samdb_result_string ( res [ i ] , attr_name , NULL ) ;
}
( * strs ) [ count ] = NULL ;
return count ;
}
/*
pull a uint from a result set .
*/
2010-01-05 20:42:54 +03:00
unsigned int samdb_result_uint ( const struct ldb_message * msg , const char * attr , unsigned int default_value )
2007-12-17 06:22:44 +03:00
{
return ldb_msg_find_attr_as_uint ( msg , attr , default_value ) ;
}
/*
pull a ( signed ) int64 from a result set .
*/
int64_t samdb_result_int64 ( const struct ldb_message * msg , const char * attr , int64_t default_value )
{
return ldb_msg_find_attr_as_int64 ( msg , attr , default_value ) ;
}
/*
pull a string from a result set .
*/
const char * samdb_result_string ( const struct ldb_message * msg , const char * attr ,
const char * default_value )
{
return ldb_msg_find_attr_as_string ( msg , attr , default_value ) ;
}
struct ldb_dn * samdb_result_dn ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx , const struct ldb_message * msg ,
const char * attr , struct ldb_dn * default_value )
{
struct ldb_dn * ret_dn = ldb_msg_find_attr_as_dn ( ldb , mem_ctx , msg , attr ) ;
if ( ! ret_dn ) {
return default_value ;
}
return ret_dn ;
}
/*
pull a rid from a objectSid in a result set .
*/
uint32_t samdb_result_rid_from_sid ( TALLOC_CTX * mem_ctx , const struct ldb_message * msg ,
const char * attr , uint32_t default_value )
{
struct dom_sid * sid ;
uint32_t rid ;
sid = samdb_result_dom_sid ( mem_ctx , msg , attr ) ;
if ( sid = = NULL ) {
return default_value ;
}
rid = sid - > sub_auths [ sid - > num_auths - 1 ] ;
talloc_free ( sid ) ;
return rid ;
}
/*
pull a dom_sid structure from a objectSid in a result set .
*/
struct dom_sid * samdb_result_dom_sid ( TALLOC_CTX * mem_ctx , const struct ldb_message * msg ,
const char * attr )
{
const struct ldb_val * v ;
struct dom_sid * sid ;
enum ndr_err_code ndr_err ;
v = ldb_msg_find_ldb_val ( msg , attr ) ;
if ( v = = NULL ) {
return NULL ;
}
sid = talloc ( mem_ctx , struct dom_sid ) ;
if ( sid = = NULL ) {
return NULL ;
}
2010-05-09 19:20:01 +04:00
ndr_err = ndr_pull_struct_blob ( v , sid , sid ,
2007-12-17 06:22:44 +03:00
( ndr_pull_flags_fn_t ) ndr_pull_dom_sid ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
talloc_free ( sid ) ;
return NULL ;
}
return sid ;
}
/*
pull a guid structure from a objectGUID in a result set .
*/
struct GUID samdb_result_guid ( const struct ldb_message * msg , const char * attr )
{
const struct ldb_val * v ;
struct GUID guid ;
2009-12-10 03:26:36 +03:00
NTSTATUS status ;
2007-12-17 06:22:44 +03:00
v = ldb_msg_find_ldb_val ( msg , attr ) ;
2009-12-11 09:33:32 +03:00
if ( ! v ) return GUID_zero ( ) ;
2007-12-17 06:22:44 +03:00
2009-12-10 03:26:36 +03:00
status = GUID_from_ndr_blob ( v , & guid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return GUID_zero ( ) ;
2007-12-17 06:22:44 +03:00
}
return guid ;
}
/*
pull a sid prefix from a objectSid in a result set .
this is used to find the domain sid for a user
*/
struct dom_sid * samdb_result_sid_prefix ( TALLOC_CTX * mem_ctx , const struct ldb_message * msg ,
const char * attr )
{
struct dom_sid * sid = samdb_result_dom_sid ( mem_ctx , msg , attr ) ;
if ( ! sid | | sid - > num_auths < 1 ) return NULL ;
sid - > num_auths - - ;
return sid ;
}
/*
pull a NTTIME in a result set .
*/
2009-12-17 14:43:10 +03:00
NTTIME samdb_result_nttime ( const struct ldb_message * msg , const char * attr ,
NTTIME default_value )
2007-12-17 06:22:44 +03:00
{
return ldb_msg_find_attr_as_uint64 ( msg , attr , default_value ) ;
}
2009-08-01 14:02:58 +04:00
/*
* Windows stores 0 for lastLogoff .
* But when a MS DC return the lastLogoff ( as Logoff Time )
* it returns 0x7FFFFFFFFFFFFFFF , not returning this value in this case
* cause windows 2008 and newer version to fail for SMB requests
*/
2009-12-17 14:43:10 +03:00
NTTIME samdb_result_last_logoff ( const struct ldb_message * msg )
2009-08-01 14:02:58 +04:00
{
NTTIME ret = ldb_msg_find_attr_as_uint64 ( msg , " lastLogoff " , 0 ) ;
if ( ret = = 0 )
ret = 0x7FFFFFFFFFFFFFFFULL ;
return ret ;
}
2008-03-06 15:02:46 +03:00
/*
* Windows uses both 0 and 9223372036854775807 ( 0x7FFFFFFFFFFFFFFFULL ) to
* indicate an account doesn ' t expire .
*
* When Windows initially creates an account , it sets
* accountExpires = 9223372036854775807 ( 0x7FFFFFFFFFFFFFFF ) . However ,
* when changing from an account having a specific expiration date to
* that account never expiring , it sets accountExpires = 0.
*
* Consolidate that logic here to allow clearer logic for account expiry in
* the rest of the code .
*/
2009-12-17 14:43:10 +03:00
NTTIME samdb_result_account_expires ( const struct ldb_message * msg )
2008-03-06 15:02:46 +03:00
{
NTTIME ret = ldb_msg_find_attr_as_uint64 ( msg , " accountExpires " ,
2008-03-25 07:25:13 +03:00
0 ) ;
2008-03-06 15:02:46 +03:00
2008-03-25 08:36:13 +03:00
if ( ret = = 0 )
2008-03-06 15:02:46 +03:00
ret = 0x7FFFFFFFFFFFFFFFULL ;
return ret ;
}
2007-12-17 06:22:44 +03:00
/*
pull a uint64_t from a result set .
*/
2009-12-17 14:43:10 +03:00
uint64_t samdb_result_uint64 ( const struct ldb_message * msg , const char * attr ,
uint64_t default_value )
2007-12-17 06:22:44 +03:00
{
return ldb_msg_find_attr_as_uint64 ( msg , attr , default_value ) ;
}
/*
construct the allow_password_change field from the PwdLastSet attribute and the
domain password settings
*/
NTTIME samdb_result_allow_password_change ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * domain_dn ,
struct ldb_message * msg ,
const char * attr )
{
uint64_t attr_time = samdb_result_uint64 ( msg , attr , 0 ) ;
int64_t minPwdAge ;
if ( attr_time = = 0 ) {
return 0 ;
}
minPwdAge = samdb_search_int64 ( sam_ldb , mem_ctx , 0 , domain_dn , " minPwdAge " , NULL ) ;
/* yes, this is a -= not a += as minPwdAge is stored as the negative
of the number of 100 - nano - seconds */
attr_time - = minPwdAge ;
return attr_time ;
}
/*
2008-02-29 00:47:42 +03:00
construct the force_password_change field from the PwdLastSet
attribute , the userAccountControl and the domain password settings
2007-12-17 06:22:44 +03:00
*/
NTTIME samdb_result_force_password_change ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * domain_dn ,
struct ldb_message * msg )
{
2010-07-05 18:55:50 +04:00
int64_t attr_time = samdb_result_int64 ( msg , " pwdLastSet " , 0 ) ;
uint32_t userAccountControl = ldb_msg_find_attr_as_uint ( msg ,
" userAccountControl " ,
0 ) ;
2007-12-17 06:22:44 +03:00
int64_t maxPwdAge ;
2008-02-29 00:47:42 +03:00
/* Machine accounts don't expire, and there is a flag for 'no expiry' */
if ( ! ( userAccountControl & UF_NORMAL_ACCOUNT )
| | ( userAccountControl & UF_DONT_EXPIRE_PASSWD ) ) {
2007-12-17 06:22:44 +03:00
return 0x7FFFFFFFFFFFFFFFULL ;
}
if ( attr_time = = 0 ) {
return 0 ;
}
2010-07-05 18:55:50 +04:00
if ( attr_time = = - 1 ) {
return 0x7FFFFFFFFFFFFFFFULL ;
}
2007-12-17 06:22:44 +03:00
2010-07-05 18:55:50 +04:00
maxPwdAge = samdb_search_int64 ( sam_ldb , mem_ctx , 0 , domain_dn ,
" maxPwdAge " , NULL ) ;
2007-12-17 06:22:44 +03:00
if ( maxPwdAge = = 0 ) {
2008-03-07 14:56:04 +03:00
return 0x7FFFFFFFFFFFFFFFULL ;
2007-12-17 06:22:44 +03:00
} else {
attr_time - = maxPwdAge ;
}
return attr_time ;
}
/*
pull a samr_Password structutre from a result set .
*/
2009-07-09 04:08:02 +04:00
struct samr_Password * samdb_result_hash ( TALLOC_CTX * mem_ctx , const struct ldb_message * msg , const char * attr )
2007-12-17 06:22:44 +03:00
{
struct samr_Password * hash = NULL ;
const struct ldb_val * val = ldb_msg_find_ldb_val ( msg , attr ) ;
if ( val & & ( val - > length > = sizeof ( hash - > hash ) ) ) {
hash = talloc ( mem_ctx , struct samr_Password ) ;
memcpy ( hash - > hash , val - > data , MIN ( val - > length , sizeof ( hash - > hash ) ) ) ;
}
return hash ;
}
/*
2009-11-06 22:14:41 +03:00
pull an array of samr_Password structures from a result set .
2007-12-17 06:22:44 +03:00
*/
2010-01-05 20:42:54 +03:00
unsigned int samdb_result_hashes ( TALLOC_CTX * mem_ctx , const struct ldb_message * msg ,
2007-12-17 06:22:44 +03:00
const char * attr , struct samr_Password * * hashes )
{
2010-01-05 20:42:54 +03:00
unsigned int count , i ;
2007-12-17 06:22:44 +03:00
const struct ldb_val * val = ldb_msg_find_ldb_val ( msg , attr ) ;
* hashes = NULL ;
if ( ! val ) {
return 0 ;
}
count = val - > length / 16 ;
if ( count = = 0 ) {
return 0 ;
}
* hashes = talloc_array ( mem_ctx , struct samr_Password , count ) ;
if ( ! * hashes ) {
return 0 ;
}
for ( i = 0 ; i < count ; i + + ) {
memcpy ( ( * hashes ) [ i ] . hash , ( i * 16 ) + ( char * ) val - > data , 16 ) ;
}
return count ;
}
2010-07-16 08:32:42 +04:00
NTSTATUS samdb_result_passwords ( TALLOC_CTX * mem_ctx , struct loadparm_context * lp_ctx , struct ldb_message * msg ,
2007-12-17 06:22:44 +03:00
struct samr_Password * * lm_pwd , struct samr_Password * * nt_pwd )
{
struct samr_Password * lmPwdHash , * ntPwdHash ;
if ( nt_pwd ) {
2009-11-06 22:14:41 +03:00
unsigned int num_nt ;
2007-12-17 06:22:44 +03:00
num_nt = samdb_result_hashes ( mem_ctx , msg , " unicodePwd " , & ntPwdHash ) ;
if ( num_nt = = 0 ) {
* nt_pwd = NULL ;
} else if ( num_nt > 1 ) {
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
} else {
* nt_pwd = & ntPwdHash [ 0 ] ;
}
}
if ( lm_pwd ) {
2008-10-16 05:48:16 +04:00
/* Ensure that if we have turned off LM
* authentication , that we never use the LM hash , even
* if we store it */
2010-07-16 08:32:42 +04:00
if ( lpcfg_lanman_auth ( lp_ctx ) ) {
2009-11-06 22:14:41 +03:00
unsigned int num_lm ;
2008-10-16 05:48:16 +04:00
num_lm = samdb_result_hashes ( mem_ctx , msg , " dBCSPwd " , & lmPwdHash ) ;
if ( num_lm = = 0 ) {
* lm_pwd = NULL ;
} else if ( num_lm > 1 ) {
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
} else {
* lm_pwd = & lmPwdHash [ 0 ] ;
}
2007-12-17 06:22:44 +03:00
} else {
2008-10-16 05:48:16 +04:00
* lm_pwd = NULL ;
2007-12-17 06:22:44 +03:00
}
}
return NT_STATUS_OK ;
}
/*
pull a samr_LogonHours structutre from a result set .
*/
struct samr_LogonHours samdb_result_logon_hours ( TALLOC_CTX * mem_ctx , struct ldb_message * msg , const char * attr )
{
struct samr_LogonHours hours ;
2010-05-12 19:34:02 +04:00
size_t units_per_week = 168 ;
2007-12-17 06:22:44 +03:00
const struct ldb_val * val = ldb_msg_find_ldb_val ( msg , attr ) ;
2010-05-12 19:34:02 +04:00
2007-12-17 06:22:44 +03:00
ZERO_STRUCT ( hours ) ;
2010-05-12 19:34:02 +04:00
if ( val ) {
units_per_week = val - > length * 8 ;
}
hours . bits = talloc_array ( mem_ctx , uint8_t , units_per_week / 8 ) ;
2007-12-17 06:22:44 +03:00
if ( ! hours . bits ) {
return hours ;
}
hours . units_per_week = units_per_week ;
2010-05-12 19:34:02 +04:00
memset ( hours . bits , 0xFF , units_per_week / 8 ) ;
2007-12-17 06:22:44 +03:00
if ( val ) {
2010-05-12 19:34:02 +04:00
memcpy ( hours . bits , val - > data , val - > length ) ;
2007-12-17 06:22:44 +03:00
}
2010-05-12 19:34:02 +04:00
2007-12-17 06:22:44 +03:00
return hours ;
}
/*
pull a set of account_flags from a result set .
2008-02-28 00:50:00 +03:00
This requires that the attributes :
pwdLastSet
userAccountControl
be included in ' msg '
2007-12-17 06:22:44 +03:00
*/
2008-02-28 00:50:00 +03:00
uint32_t samdb_result_acct_flags ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx ,
struct ldb_message * msg , struct ldb_dn * domain_dn )
2007-12-17 06:22:44 +03:00
{
2008-02-28 00:50:00 +03:00
uint32_t userAccountControl = ldb_msg_find_attr_as_uint ( msg , " userAccountControl " , 0 ) ;
2009-06-12 17:20:48 +04:00
uint32_t acct_flags = ds_uf2acb ( userAccountControl ) ;
2008-02-29 00:47:42 +03:00
NTTIME must_change_time ;
NTTIME now ;
2009-05-31 18:19:11 +04:00
2008-02-29 00:47:42 +03:00
must_change_time = samdb_result_force_password_change ( sam_ctx , mem_ctx ,
domain_dn , msg ) ;
2009-05-31 18:19:11 +04:00
2008-02-29 00:47:42 +03:00
/* Test account expire time */
unix_to_nt_time ( & now , time ( NULL ) ) ;
/* check for expired password */
if ( must_change_time < now ) {
acct_flags | = ACB_PW_EXPIRED ;
2008-02-28 00:50:00 +03:00
}
return acct_flags ;
2007-12-17 06:22:44 +03:00
}
2008-11-10 22:35:32 +03:00
struct lsa_BinaryString samdb_result_parameters ( TALLOC_CTX * mem_ctx ,
struct ldb_message * msg ,
const char * attr )
{
struct lsa_BinaryString s ;
const struct ldb_val * val = ldb_msg_find_ldb_val ( msg , attr ) ;
ZERO_STRUCT ( s ) ;
if ( ! val ) {
return s ;
}
s . array = talloc_array ( mem_ctx , uint16_t , val - > length / 2 ) ;
if ( ! s . array ) {
return s ;
}
2010-01-12 11:59:26 +03:00
s . length = s . size = val - > length ;
2008-11-10 22:35:32 +03:00
memcpy ( s . array , val - > data , val - > length ) ;
return s ;
}
2007-12-17 06:22:44 +03:00
/* Find an attribute, with a particular value */
/* The current callers of this function expect a very specific
* behaviour : In particular , objectClass subclass equivilance is not
* wanted . This means that we should not lookup the schema for the
* comparison function */
struct ldb_message_element * samdb_find_attribute ( struct ldb_context * ldb ,
const struct ldb_message * msg ,
const char * name , const char * value )
{
2009-11-06 22:14:41 +03:00
unsigned int i ;
2007-12-17 06:22:44 +03:00
struct ldb_message_element * el = ldb_msg_find_element ( msg , name ) ;
if ( ! el ) {
return NULL ;
}
for ( i = 0 ; i < el - > num_values ; i + + ) {
if ( ldb_attr_cmp ( value , ( char * ) el - > values [ i ] . data ) = = 0 ) {
return el ;
}
}
return NULL ;
}
2009-10-04 21:30:53 +04:00
/*
* This is intended for use by the " password hash " module since there
* password changes can be specified through one message element with the
* new password ( to set ) and another one with the old password ( to unset ) .
*
* The first which sets a password ( new value ) can have flags
* ( LDB_FLAG_MOD_ADD , LDB_FLAG_MOD_REPLACE ) but also none ( on " add " operations
* for entries ) . The latter ( old value ) has always specified
* LDB_FLAG_MOD_DELETE .
*
* Returns LDB_ERR_NO_SUCH_ATTRIBUTE if the attribute which should be deleted
* doesn ' t contain only one value ( this is the Windows Server behaviour )
* otherwise LDB_SUCCESS .
*/
int samdb_msg_find_old_and_new_ldb_val ( const struct ldb_message * msg ,
const char * name ,
const struct ldb_val * * new_val ,
const struct ldb_val * * old_val )
{
unsigned int i ;
* new_val = NULL ;
* old_val = NULL ;
if ( msg = = NULL ) {
return LDB_SUCCESS ;
}
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
if ( ldb_attr_cmp ( msg - > elements [ i ] . name , name ) = = 0 ) {
if ( msg - > elements [ i ] . flags = = LDB_FLAG_MOD_DELETE ) {
* old_val = & msg - > elements [ i ] . values [ 0 ] ;
} else {
* new_val = & msg - > elements [ i ] . values [ 0 ] ;
}
}
}
return LDB_SUCCESS ;
}
2007-12-17 06:22:44 +03:00
int samdb_find_or_add_value ( struct ldb_context * ldb , struct ldb_message * msg , const char * name , const char * set_value )
{
if ( samdb_find_attribute ( ldb , msg , name , set_value ) = = NULL ) {
return samdb_msg_add_string ( ldb , msg , msg , name , set_value ) ;
}
return LDB_SUCCESS ;
}
int samdb_find_or_add_attribute ( struct ldb_context * ldb , struct ldb_message * msg , const char * name , const char * set_value )
{
struct ldb_message_element * el ;
el = ldb_msg_find_element ( msg , name ) ;
if ( el ) {
return LDB_SUCCESS ;
}
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
return samdb_msg_add_string ( ldb , msg , msg , name , set_value ) ;
}
/*
add a string element to a message
*/
int samdb_msg_add_string ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , const char * str )
{
char * s = talloc_strdup ( mem_ctx , str ) ;
char * a = talloc_strdup ( mem_ctx , attr_name ) ;
if ( s = = NULL | | a = = NULL ) {
2010-07-06 07:21:54 +04:00
return ldb_oom ( sam_ldb ) ;
2007-12-17 06:22:44 +03:00
}
return ldb_msg_add_string ( msg , a , s ) ;
}
/*
add a dom_sid element to a message
*/
int samdb_msg_add_dom_sid ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , struct dom_sid * sid )
{
struct ldb_val v ;
enum ndr_err_code ndr_err ;
2008-01-02 07:05:05 +03:00
ndr_err = ndr_push_struct_blob ( & v , mem_ctx ,
sid ,
2007-12-17 06:22:44 +03:00
( ndr_push_flags_fn_t ) ndr_push_dom_sid ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2010-07-06 07:21:54 +04:00
return ldb_operr ( sam_ldb ) ;
2007-12-17 06:22:44 +03:00
}
return ldb_msg_add_value ( msg , attr_name , & v , NULL ) ;
}
/*
add a delete element operation to a message
*/
int samdb_msg_add_delete ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name )
{
/* we use an empty replace rather than a delete, as it allows for
2010-02-16 06:45:16 +03:00
dsdb_replace ( ) to be used everywhere */
2007-12-17 06:22:44 +03:00
return ldb_msg_add_empty ( msg , attr_name , LDB_FLAG_MOD_REPLACE , NULL ) ;
}
/*
2010-05-31 16:52:46 +04:00
add an add attribute value to a message or enhance an existing attribute
which has the same name and the add flag set .
2007-12-17 06:22:44 +03:00
*/
2010-05-31 16:52:46 +04:00
int samdb_msg_add_addval ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx ,
struct ldb_message * msg , const char * attr_name ,
const char * value )
2007-12-17 06:22:44 +03:00
{
struct ldb_message_element * el ;
2010-05-31 16:52:46 +04:00
struct ldb_val val , * vals ;
char * v ;
unsigned int i ;
bool found = false ;
2007-12-17 06:22:44 +03:00
int ret ;
2010-05-31 16:52:46 +04:00
2007-12-17 06:22:44 +03:00
v = talloc_strdup ( mem_ctx , value ) ;
2010-05-31 16:52:46 +04:00
if ( v = = NULL ) {
2010-07-06 07:21:54 +04:00
return ldb_oom ( sam_ldb ) ;
2010-05-31 16:52:46 +04:00
}
val . data = ( uint8_t * ) v ;
val . length = strlen ( v ) ;
if ( val . length = = 0 ) {
/* allow empty strings as non-existent attributes */
return LDB_SUCCESS ;
}
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
el = & msg - > elements [ i ] ;
if ( ( ldb_attr_cmp ( el - > name , attr_name ) = = 0 ) & &
( el - > flags = = LDB_FLAG_MOD_ADD ) ) {
found = true ;
break ;
}
}
if ( ! found ) {
ret = ldb_msg_add_empty ( msg , attr_name , LDB_FLAG_MOD_ADD ,
& el ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
vals = talloc_realloc ( msg , el - > values , struct ldb_val ,
el - > num_values + 1 ) ;
if ( vals = = NULL ) {
2010-07-06 07:21:54 +04:00
return ldb_oom ( sam_ldb ) ;
2010-05-31 16:52:46 +04:00
}
el - > values = vals ;
el - > values [ el - > num_values ] = val ;
+ + ( el - > num_values ) ;
2010-02-17 20:24:03 +03:00
return LDB_SUCCESS ;
2007-12-17 06:22:44 +03:00
}
/*
2010-05-31 16:52:46 +04:00
add a delete attribute value to a message or enhance an existing attribute
which has the same name and the delete flag set .
2007-12-17 06:22:44 +03:00
*/
2010-05-31 16:52:46 +04:00
int samdb_msg_add_delval ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx ,
struct ldb_message * msg , const char * attr_name ,
const char * value )
2007-12-17 06:22:44 +03:00
{
struct ldb_message_element * el ;
2010-05-31 16:52:46 +04:00
struct ldb_val val , * vals ;
char * v ;
unsigned int i ;
bool found = false ;
2007-12-17 06:22:44 +03:00
int ret ;
2010-05-31 16:52:46 +04:00
2007-12-17 06:22:44 +03:00
v = talloc_strdup ( mem_ctx , value ) ;
2010-05-31 16:52:46 +04:00
if ( v = = NULL ) {
2010-07-06 07:21:54 +04:00
return ldb_oom ( sam_ldb ) ;
2010-05-31 16:52:46 +04:00
}
val . data = ( uint8_t * ) v ;
val . length = strlen ( v ) ;
if ( val . length = = 0 ) {
/* allow empty strings as non-existent attributes */
return LDB_SUCCESS ;
}
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
el = & msg - > elements [ i ] ;
if ( ( ldb_attr_cmp ( el - > name , attr_name ) = = 0 ) & &
( el - > flags = = LDB_FLAG_MOD_DELETE ) ) {
found = true ;
break ;
}
}
if ( ! found ) {
ret = ldb_msg_add_empty ( msg , attr_name , LDB_FLAG_MOD_DELETE ,
& el ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
vals = talloc_realloc ( msg , el - > values , struct ldb_val ,
el - > num_values + 1 ) ;
if ( vals = = NULL ) {
2010-07-06 07:21:54 +04:00
return ldb_oom ( sam_ldb ) ;
2010-05-31 16:52:46 +04:00
}
el - > values = vals ;
el - > values [ el - > num_values ] = val ;
+ + ( el - > num_values ) ;
2010-02-17 20:24:03 +03:00
return LDB_SUCCESS ;
2007-12-17 06:22:44 +03:00
}
/*
add a int element to a message
*/
int samdb_msg_add_int ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , int v )
{
const char * s = talloc_asprintf ( mem_ctx , " %d " , v ) ;
return samdb_msg_add_string ( sam_ldb , mem_ctx , msg , attr_name , s ) ;
}
/*
2010-01-05 20:42:54 +03:00
add a unsigned int element to a message
2007-12-17 06:22:44 +03:00
*/
int samdb_msg_add_uint ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
2010-01-05 20:42:54 +03:00
const char * attr_name , unsigned int v )
2007-12-17 06:22:44 +03:00
{
2010-01-11 22:17:53 +03:00
return samdb_msg_add_int ( sam_ldb , mem_ctx , msg , attr_name , ( int ) v ) ;
2007-12-17 06:22:44 +03:00
}
/*
add a ( signed ) int64_t element to a message
*/
int samdb_msg_add_int64 ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , int64_t v )
{
const char * s = talloc_asprintf ( mem_ctx , " %lld " , ( long long ) v ) ;
return samdb_msg_add_string ( sam_ldb , mem_ctx , msg , attr_name , s ) ;
}
/*
add a uint64_t element to a message
*/
int samdb_msg_add_uint64 ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , uint64_t v )
{
2010-01-11 22:00:43 +03:00
return samdb_msg_add_int64 ( sam_ldb , mem_ctx , msg , attr_name , ( int64_t ) v ) ;
2007-12-17 06:22:44 +03:00
}
/*
add a samr_Password element to a message
*/
int samdb_msg_add_hash ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , struct samr_Password * hash )
{
struct ldb_val val ;
val . data = talloc_memdup ( mem_ctx , hash - > hash , 16 ) ;
if ( ! val . data ) {
2010-07-06 07:21:54 +04:00
return ldb_oom ( sam_ldb ) ;
2007-12-17 06:22:44 +03:00
}
val . length = 16 ;
return ldb_msg_add_value ( msg , attr_name , & val , NULL ) ;
}
/*
add a samr_Password array to a message
*/
2010-07-06 07:21:54 +04:00
int samdb_msg_add_hashes ( struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
2009-11-06 22:14:41 +03:00
const char * attr_name , struct samr_Password * hashes ,
unsigned int count )
2007-12-17 06:22:44 +03:00
{
struct ldb_val val ;
2009-11-06 22:14:41 +03:00
unsigned int i ;
2007-12-17 06:22:44 +03:00
val . data = talloc_array_size ( mem_ctx , 16 , count ) ;
val . length = count * 16 ;
if ( ! val . data ) {
2010-07-06 07:21:54 +04:00
return ldb_oom ( ldb ) ;
2007-12-17 06:22:44 +03:00
}
for ( i = 0 ; i < count ; i + + ) {
memcpy ( i * 16 + ( char * ) val . data , hashes [ i ] . hash , 16 ) ;
}
return ldb_msg_add_value ( msg , attr_name , & val , NULL ) ;
}
/*
add a acct_flags element to a message
*/
int samdb_msg_add_acct_flags ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , uint32_t v )
{
2009-06-12 17:20:48 +04:00
return samdb_msg_add_uint ( sam_ldb , mem_ctx , msg , attr_name , ds_acb2uf ( v ) ) ;
2007-12-17 06:22:44 +03:00
}
/*
add a logon_hours element to a message
*/
int samdb_msg_add_logon_hours ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , struct samr_LogonHours * hours )
{
struct ldb_val val ;
val . length = hours - > units_per_week / 8 ;
val . data = hours - > bits ;
return ldb_msg_add_value ( msg , attr_name , & val , NULL ) ;
}
2008-11-10 22:35:41 +03:00
/*
add a parameters element to a message
*/
int samdb_msg_add_parameters ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , struct lsa_BinaryString * parameters )
{
struct ldb_val val ;
2010-01-12 11:59:26 +03:00
val . length = parameters - > length ;
2008-11-10 22:35:41 +03:00
val . data = ( uint8_t * ) parameters - > array ;
return ldb_msg_add_value ( msg , attr_name , & val , NULL ) ;
}
2007-12-17 06:22:44 +03:00
/*
add a general value element to a message
*/
int samdb_msg_add_value ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , const struct ldb_val * val )
{
return ldb_msg_add_value ( msg , attr_name , val , NULL ) ;
}
/*
sets a general value element to a message
*/
int samdb_msg_set_value ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , const struct ldb_val * val )
{
struct ldb_message_element * el ;
el = ldb_msg_find_element ( msg , attr_name ) ;
if ( el ) {
el - > num_values = 0 ;
}
return ldb_msg_add_value ( msg , attr_name , val , NULL ) ;
}
/*
set a string element in a message
*/
int samdb_msg_set_string ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , const char * str )
{
struct ldb_message_element * el ;
el = ldb_msg_find_element ( msg , attr_name ) ;
if ( el ) {
el - > num_values = 0 ;
}
return samdb_msg_add_string ( sam_ldb , mem_ctx , msg , attr_name , str ) ;
}
2009-12-18 19:11:48 +03:00
/*
* Handle ldb_request in transaction
*/
static int dsdb_autotransaction_request ( struct ldb_context * sam_ldb ,
2010-02-16 06:45:16 +03:00
struct ldb_request * req )
2009-12-18 19:11:48 +03:00
{
int ret ;
ret = ldb_transaction_start ( sam_ldb ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
ret = ldb_request ( sam_ldb , req ) ;
if ( ret = = LDB_SUCCESS ) {
ret = ldb_wait ( req - > handle , LDB_WAIT_ALL ) ;
}
if ( ret = = LDB_SUCCESS ) {
return ldb_transaction_commit ( sam_ldb ) ;
}
ldb_transaction_cancel ( sam_ldb ) ;
return ret ;
}
2007-12-17 06:22:44 +03:00
/*
return a default security descriptor
*/
struct security_descriptor * samdb_default_security_descriptor ( TALLOC_CTX * mem_ctx )
{
struct security_descriptor * sd ;
sd = security_descriptor_initialise ( mem_ctx ) ;
return sd ;
}
2009-11-24 02:16:56 +03:00
struct ldb_dn * samdb_aggregate_schema_dn ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx )
{
struct ldb_dn * schema_dn = ldb_get_schema_basedn ( sam_ctx ) ;
struct ldb_dn * aggregate_dn ;
if ( ! schema_dn ) {
return NULL ;
}
aggregate_dn = ldb_dn_copy ( mem_ctx , schema_dn ) ;
if ( ! aggregate_dn ) {
return NULL ;
}
if ( ! ldb_dn_add_child_fmt ( aggregate_dn , " CN=Aggregate " ) ) {
return NULL ;
}
return aggregate_dn ;
}
2007-12-17 06:22:44 +03:00
struct ldb_dn * samdb_partitions_dn ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx )
{
struct ldb_dn * new_dn ;
2010-04-13 10:41:10 +04:00
new_dn = ldb_dn_copy ( mem_ctx , ldb_get_config_basedn ( sam_ctx ) ) ;
2007-12-17 06:22:44 +03:00
if ( ! ldb_dn_add_child_fmt ( new_dn , " CN=Partitions " ) ) {
talloc_free ( new_dn ) ;
return NULL ;
}
return new_dn ;
}
2010-03-09 15:56:46 +03:00
struct ldb_dn * samdb_infrastructure_dn ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx )
{
struct ldb_dn * new_dn ;
2010-04-13 10:41:10 +04:00
new_dn = ldb_dn_copy ( mem_ctx , ldb_get_default_basedn ( sam_ctx ) ) ;
2010-03-09 15:56:46 +03:00
if ( ! ldb_dn_add_child_fmt ( new_dn , " CN=Infrastructure " ) ) {
talloc_free ( new_dn ) ;
return NULL ;
}
return new_dn ;
}
2007-12-17 06:22:44 +03:00
struct ldb_dn * samdb_sites_dn ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx )
{
struct ldb_dn * new_dn ;
2010-04-13 10:41:10 +04:00
new_dn = ldb_dn_copy ( mem_ctx , ldb_get_config_basedn ( sam_ctx ) ) ;
2007-12-17 06:22:44 +03:00
if ( ! ldb_dn_add_child_fmt ( new_dn , " CN=Sites " ) ) {
talloc_free ( new_dn ) ;
return NULL ;
}
return new_dn ;
}
/*
work out the domain sid for the current open ldb
*/
const struct dom_sid * samdb_domain_sid ( struct ldb_context * ldb )
{
TALLOC_CTX * tmp_ctx ;
2008-03-13 06:11:06 +03:00
const struct dom_sid * domain_sid ;
const char * attrs [ ] = {
" objectSid " ,
NULL
} ;
struct ldb_result * res ;
int ret ;
2007-12-17 06:22:44 +03:00
/* see if we have a cached copy */
domain_sid = ( struct dom_sid * ) ldb_get_opaque ( ldb , " cache.domain_sid " ) ;
if ( domain_sid ) {
return domain_sid ;
}
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
goto failed ;
}
2008-09-23 22:30:06 +04:00
ret = ldb_search ( ldb , tmp_ctx , & res , ldb_get_default_basedn ( ldb ) , LDB_SCOPE_BASE , attrs , " objectSid=* " ) ;
2008-03-13 06:11:06 +03:00
if ( ret ! = LDB_SUCCESS ) {
goto failed ;
}
2009-05-31 18:19:11 +04:00
2008-03-13 06:11:06 +03:00
if ( res - > count ! = 1 ) {
goto failed ;
}
domain_sid = samdb_result_dom_sid ( tmp_ctx , res - > msgs [ 0 ] , " objectSid " ) ;
2007-12-17 06:22:44 +03:00
if ( domain_sid = = NULL ) {
goto failed ;
}
/* cache the domain_sid in the ldb */
2008-06-27 01:30:42 +04:00
if ( ldb_set_opaque ( ldb , " cache.domain_sid " , discard_const_p ( struct dom_sid , domain_sid ) ) ! = LDB_SUCCESS ) {
2007-12-17 06:22:44 +03:00
goto failed ;
}
talloc_steal ( ldb , domain_sid ) ;
talloc_free ( tmp_ctx ) ;
return domain_sid ;
failed :
talloc_free ( tmp_ctx ) ;
return NULL ;
}
2010-01-10 04:52:22 +03:00
/*
get domain sid from cache
*/
const struct dom_sid * samdb_domain_sid_cache_only ( struct ldb_context * ldb )
{
return ( struct dom_sid * ) ldb_get_opaque ( ldb , " cache.domain_sid " ) ;
}
2007-12-17 06:22:44 +03:00
bool samdb_set_domain_sid ( struct ldb_context * ldb , const struct dom_sid * dom_sid_in )
{
TALLOC_CTX * tmp_ctx ;
struct dom_sid * dom_sid_new ;
struct dom_sid * dom_sid_old ;
/* see if we have a cached copy */
dom_sid_old = talloc_get_type ( ldb_get_opaque ( ldb ,
" cache.domain_sid " ) , struct dom_sid ) ;
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
goto failed ;
}
dom_sid_new = dom_sid_dup ( tmp_ctx , dom_sid_in ) ;
if ( ! dom_sid_new ) {
goto failed ;
}
/* cache the domain_sid in the ldb */
if ( ldb_set_opaque ( ldb , " cache.domain_sid " , dom_sid_new ) ! = LDB_SUCCESS ) {
goto failed ;
}
talloc_steal ( ldb , dom_sid_new ) ;
talloc_free ( tmp_ctx ) ;
talloc_free ( dom_sid_old ) ;
return true ;
failed :
DEBUG ( 1 , ( " Failed to set our own cached domain SID in the ldb! \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return false ;
}
2010-04-20 05:48:51 +04:00
bool samdb_set_ntds_settings_dn ( struct ldb_context * ldb , struct ldb_dn * ntds_settings_dn_in )
{
TALLOC_CTX * tmp_ctx ;
struct ldb_dn * ntds_settings_dn_new ;
struct ldb_dn * ntds_settings_dn_old ;
/* see if we have a cached copy */
ntds_settings_dn_old = talloc_get_type ( ldb_get_opaque ( ldb ,
" cache.ntds_settings_dn " ) , struct ldb_dn ) ;
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
goto failed ;
}
ntds_settings_dn_new = ldb_dn_copy ( tmp_ctx , ntds_settings_dn_in ) ;
if ( ! ntds_settings_dn_new ) {
goto failed ;
}
/* cache the domain_sid in the ldb */
if ( ldb_set_opaque ( ldb , " cache.ntds_settings_dn " , ntds_settings_dn_new ) ! = LDB_SUCCESS ) {
goto failed ;
}
talloc_steal ( ldb , ntds_settings_dn_new ) ;
talloc_free ( tmp_ctx ) ;
talloc_free ( ntds_settings_dn_old ) ;
return true ;
failed :
DEBUG ( 1 , ( " Failed to set our NTDS Settings DN in the ldb! \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return false ;
}
2007-12-17 06:22:44 +03:00
/* Obtain the short name of the flexible single master operator
* ( FSMO ) , such as the PDC Emulator */
const char * samdb_result_fsmo_name ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx , const struct ldb_message * msg ,
const char * attr )
{
/* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
struct ldb_dn * fsmo_dn = ldb_msg_find_attr_as_dn ( ldb , mem_ctx , msg , attr ) ;
const struct ldb_val * val = ldb_dn_get_component_val ( fsmo_dn , 1 ) ;
const char * name = ldb_dn_get_component_name ( fsmo_dn , 1 ) ;
if ( ! name | | ( ldb_attr_cmp ( name , " cn " ) ! = 0 ) ) {
/* Ensure this matches the format. This gives us a
* bit more confidence that a ' cn ' value will be a
* ascii string */
return NULL ;
}
if ( val ) {
return ( char * ) val - > data ;
}
return NULL ;
}
/*
work out the ntds settings dn for the current open ldb
*/
struct ldb_dn * samdb_ntds_settings_dn ( struct ldb_context * ldb )
{
TALLOC_CTX * tmp_ctx ;
const char * root_attrs [ ] = { " dsServiceName " , NULL } ;
int ret ;
struct ldb_result * root_res ;
struct ldb_dn * settings_dn ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
/* see if we have a cached copy */
2010-04-20 05:48:51 +04:00
settings_dn = ( struct ldb_dn * ) ldb_get_opaque ( ldb , " cache.ntds_settings_dn " ) ;
2007-12-17 06:22:44 +03:00
if ( settings_dn ) {
return settings_dn ;
}
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
goto failed ;
}
2008-09-23 22:30:06 +04:00
ret = ldb_search ( ldb , tmp_ctx , & root_res , ldb_dn_new ( tmp_ctx , ldb , " " ) , LDB_SCOPE_BASE , root_attrs , NULL ) ;
2007-12-17 06:22:44 +03:00
if ( ret ) {
DEBUG ( 1 , ( " Searching for dsServiceName in rootDSE failed: %s \n " ,
ldb_errstring ( ldb ) ) ) ;
goto failed ;
}
if ( root_res - > count ! = 1 ) {
goto failed ;
}
settings_dn = ldb_msg_find_attr_as_dn ( ldb , tmp_ctx , root_res - > msgs [ 0 ] , " dsServiceName " ) ;
/* cache the domain_sid in the ldb */
if ( ldb_set_opaque ( ldb , " cache.settings_dn " , settings_dn ) ! = LDB_SUCCESS ) {
goto failed ;
}
talloc_steal ( ldb , settings_dn ) ;
talloc_free ( tmp_ctx ) ;
return settings_dn ;
failed :
DEBUG ( 1 , ( " Failed to find our own NTDS Settings DN in the ldb! \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return NULL ;
}
/*
work out the ntds settings invocationId for the current open ldb
*/
const struct GUID * samdb_ntds_invocation_id ( struct ldb_context * ldb )
{
TALLOC_CTX * tmp_ctx ;
const char * attrs [ ] = { " invocationId " , NULL } ;
int ret ;
struct ldb_result * res ;
struct GUID * invocation_id ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
/* see if we have a cached copy */
invocation_id = ( struct GUID * ) ldb_get_opaque ( ldb , " cache.invocation_id " ) ;
if ( invocation_id ) {
return invocation_id ;
}
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
goto failed ;
}
2008-09-23 22:30:06 +04:00
ret = ldb_search ( ldb , tmp_ctx , & res , samdb_ntds_settings_dn ( ldb ) , LDB_SCOPE_BASE , attrs , NULL ) ;
2007-12-17 06:22:44 +03:00
if ( ret ) {
goto failed ;
}
if ( res - > count ! = 1 ) {
goto failed ;
}
invocation_id = talloc ( tmp_ctx , struct GUID ) ;
if ( ! invocation_id ) {
goto failed ;
}
* invocation_id = samdb_result_guid ( res - > msgs [ 0 ] , " invocationId " ) ;
/* cache the domain_sid in the ldb */
if ( ldb_set_opaque ( ldb , " cache.invocation_id " , invocation_id ) ! = LDB_SUCCESS ) {
goto failed ;
}
talloc_steal ( ldb , invocation_id ) ;
talloc_free ( tmp_ctx ) ;
return invocation_id ;
failed :
DEBUG ( 1 , ( " Failed to find our own NTDS Settings invocationId in the ldb! \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return NULL ;
}
bool samdb_set_ntds_invocation_id ( struct ldb_context * ldb , const struct GUID * invocation_id_in )
{
TALLOC_CTX * tmp_ctx ;
struct GUID * invocation_id_new ;
struct GUID * invocation_id_old ;
/* see if we have a cached copy */
invocation_id_old = ( struct GUID * ) ldb_get_opaque ( ldb ,
" cache.invocation_id " ) ;
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
goto failed ;
}
invocation_id_new = talloc ( tmp_ctx , struct GUID ) ;
if ( ! invocation_id_new ) {
goto failed ;
}
* invocation_id_new = * invocation_id_in ;
/* cache the domain_sid in the ldb */
if ( ldb_set_opaque ( ldb , " cache.invocation_id " , invocation_id_new ) ! = LDB_SUCCESS ) {
goto failed ;
}
talloc_steal ( ldb , invocation_id_new ) ;
talloc_free ( tmp_ctx ) ;
talloc_free ( invocation_id_old ) ;
return true ;
failed :
DEBUG ( 1 , ( " Failed to set our own cached invocationId in the ldb! \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return false ;
}
/*
work out the ntds settings objectGUID for the current open ldb
*/
const struct GUID * samdb_ntds_objectGUID ( struct ldb_context * ldb )
{
TALLOC_CTX * tmp_ctx ;
const char * attrs [ ] = { " objectGUID " , NULL } ;
int ret ;
struct ldb_result * res ;
struct GUID * ntds_guid ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
/* see if we have a cached copy */
ntds_guid = ( struct GUID * ) ldb_get_opaque ( ldb , " cache.ntds_guid " ) ;
if ( ntds_guid ) {
return ntds_guid ;
}
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
goto failed ;
}
2008-09-23 22:30:06 +04:00
ret = ldb_search ( ldb , tmp_ctx , & res , samdb_ntds_settings_dn ( ldb ) , LDB_SCOPE_BASE , attrs , NULL ) ;
2007-12-17 06:22:44 +03:00
if ( ret ) {
goto failed ;
}
if ( res - > count ! = 1 ) {
goto failed ;
}
ntds_guid = talloc ( tmp_ctx , struct GUID ) ;
if ( ! ntds_guid ) {
goto failed ;
}
* ntds_guid = samdb_result_guid ( res - > msgs [ 0 ] , " objectGUID " ) ;
/* cache the domain_sid in the ldb */
if ( ldb_set_opaque ( ldb , " cache.ntds_guid " , ntds_guid ) ! = LDB_SUCCESS ) {
goto failed ;
}
talloc_steal ( ldb , ntds_guid ) ;
talloc_free ( tmp_ctx ) ;
return ntds_guid ;
failed :
DEBUG ( 1 , ( " Failed to find our own NTDS Settings objectGUID in the ldb! \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return NULL ;
}
bool samdb_set_ntds_objectGUID ( struct ldb_context * ldb , const struct GUID * ntds_guid_in )
{
TALLOC_CTX * tmp_ctx ;
struct GUID * ntds_guid_new ;
struct GUID * ntds_guid_old ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
/* see if we have a cached copy */
ntds_guid_old = ( struct GUID * ) ldb_get_opaque ( ldb , " cache.ntds_guid " ) ;
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
goto failed ;
}
ntds_guid_new = talloc ( tmp_ctx , struct GUID ) ;
if ( ! ntds_guid_new ) {
goto failed ;
}
* ntds_guid_new = * ntds_guid_in ;
/* cache the domain_sid in the ldb */
if ( ldb_set_opaque ( ldb , " cache.ntds_guid " , ntds_guid_new ) ! = LDB_SUCCESS ) {
goto failed ;
}
talloc_steal ( ldb , ntds_guid_new ) ;
talloc_free ( tmp_ctx ) ;
talloc_free ( ntds_guid_old ) ;
return true ;
failed :
DEBUG ( 1 , ( " Failed to set our own cached invocationId in the ldb! \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return false ;
}
/*
work out the server dn for the current open ldb
*/
struct ldb_dn * samdb_server_dn ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx )
{
return ldb_dn_get_parent ( mem_ctx , samdb_ntds_settings_dn ( ldb ) ) ;
}
/*
work out the server dn for the current open ldb
*/
struct ldb_dn * samdb_server_site_dn ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx )
{
struct ldb_dn * server_dn ;
2010-02-26 04:36:17 +03:00
struct ldb_dn * servers_dn ;
2007-12-17 06:22:44 +03:00
struct ldb_dn * server_site_dn ;
2010-02-26 04:36:17 +03:00
/* TODO: there must be a saner way to do this!! */
2007-12-17 06:22:44 +03:00
server_dn = samdb_server_dn ( ldb , mem_ctx ) ;
if ( ! server_dn ) return NULL ;
2010-02-26 04:36:17 +03:00
servers_dn = ldb_dn_get_parent ( mem_ctx , server_dn ) ;
2010-04-11 14:56:50 +04:00
talloc_free ( server_dn ) ;
2010-02-26 04:36:17 +03:00
if ( ! servers_dn ) return NULL ;
server_site_dn = ldb_dn_get_parent ( mem_ctx , servers_dn ) ;
2010-04-11 14:56:50 +04:00
talloc_free ( servers_dn ) ;
2007-12-17 06:22:44 +03:00
return server_site_dn ;
}
2010-01-04 06:13:21 +03:00
/*
find a ' reference ' DN that points at another object
( eg . serverReference , rIDManagerReference etc )
*/
int samdb_reference_dn ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx , struct ldb_dn * base ,
const char * attribute , struct ldb_dn * * dn )
{
const char * attrs [ 2 ] ;
struct ldb_result * res ;
int ret ;
attrs [ 0 ] = attribute ;
attrs [ 1 ] = NULL ;
ret = ldb_search ( ldb , mem_ctx , & res , base , LDB_SCOPE_BASE , attrs , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
if ( res - > count ! = 1 ) {
talloc_free ( res ) ;
return LDB_ERR_NO_SUCH_OBJECT ;
}
* dn = ldb_msg_find_attr_as_dn ( ldb , mem_ctx , res - > msgs [ 0 ] , attribute ) ;
if ( ! * dn ) {
talloc_free ( res ) ;
return LDB_ERR_NO_SUCH_ATTRIBUTE ;
}
talloc_free ( res ) ;
return LDB_SUCCESS ;
}
/*
find our machine account via the serverReference attribute in the
server DN
*/
int samdb_server_reference_dn ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx , struct ldb_dn * * dn )
{
struct ldb_dn * server_dn ;
int ret ;
server_dn = samdb_server_dn ( ldb , mem_ctx ) ;
if ( server_dn = = NULL ) {
return LDB_ERR_NO_SUCH_OBJECT ;
}
ret = samdb_reference_dn ( ldb , mem_ctx , server_dn , " serverReference " , dn ) ;
talloc_free ( server_dn ) ;
return ret ;
}
/*
find the RID Manager $ DN via the rIDManagerReference attribute in the
base DN
*/
int samdb_rid_manager_dn ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx , struct ldb_dn * * dn )
{
2010-04-13 10:41:10 +04:00
return samdb_reference_dn ( ldb , mem_ctx , ldb_get_default_basedn ( ldb ) ,
" rIDManagerReference " , dn ) ;
2010-01-04 06:13:21 +03:00
}
2010-01-05 09:07:51 +03:00
/*
find the RID Set DN via the rIDSetReferences attribute in our
machine account DN
*/
int samdb_rid_set_dn ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx , struct ldb_dn * * dn )
{
struct ldb_dn * server_ref_dn ;
int ret ;
ret = samdb_server_reference_dn ( ldb , mem_ctx , & server_ref_dn ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
ret = samdb_reference_dn ( ldb , mem_ctx , server_ref_dn , " rIDSetReferences " , dn ) ;
talloc_free ( server_ref_dn ) ;
return ret ;
}
2009-10-18 13:59:11 +04:00
const char * samdb_server_site_name ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx )
{
2010-04-13 17:40:43 +04:00
const struct ldb_val * val = ldb_dn_get_rdn_val ( samdb_server_site_dn ( ldb ,
mem_ctx ) ) ;
2009-10-18 13:59:11 +04:00
2010-04-13 17:40:43 +04:00
if ( val = = NULL ) {
2009-10-18 13:59:11 +04:00
return NULL ;
2010-04-13 17:40:43 +04:00
}
return ( const char * ) val - > data ;
2009-10-18 13:59:11 +04:00
}
2010-04-13 20:28:53 +04:00
/*
* Finds the client site by using the client ' s IP address .
* The " subnet_name " returns the name of the subnet if parameter ! = NULL
*/
const char * samdb_client_site_name ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx ,
const char * ip_address , char * * subnet_name )
{
const char * attrs [ ] = { " cn " , " siteObject " , NULL } ;
struct ldb_dn * sites_container_dn , * subnets_dn , * sites_dn ;
struct ldb_result * res ;
const struct ldb_val * val ;
const char * site_name = NULL , * l_subnet_name = NULL ;
const char * allow_list [ 2 ] = { NULL , NULL } ;
2010-05-07 16:43:36 +04:00
unsigned int i , count ;
2010-04-13 20:28:53 +04:00
int cnt , ret ;
2010-04-27 12:21:28 +04:00
/*
* if we don ' t have a client ip e . g . ncalrpc
* the server site is the client site
*/
if ( ip_address = = NULL ) {
return samdb_server_site_name ( ldb , mem_ctx ) ;
}
2010-04-13 20:28:53 +04:00
sites_container_dn = samdb_sites_dn ( ldb , mem_ctx ) ;
if ( sites_container_dn = = NULL ) {
return NULL ;
}
subnets_dn = ldb_dn_copy ( mem_ctx , sites_container_dn ) ;
if ( ! ldb_dn_add_child_fmt ( subnets_dn , " CN=Subnets " ) ) {
talloc_free ( sites_container_dn ) ;
talloc_free ( subnets_dn ) ;
return NULL ;
}
ret = ldb_search ( ldb , mem_ctx , & res , subnets_dn , LDB_SCOPE_ONELEVEL ,
attrs , NULL ) ;
2010-05-07 16:43:36 +04:00
if ( ret = = LDB_ERR_NO_SUCH_OBJECT ) {
count = 0 ;
} else if ( ret ! = LDB_SUCCESS ) {
2010-04-13 20:28:53 +04:00
talloc_free ( sites_container_dn ) ;
talloc_free ( subnets_dn ) ;
return NULL ;
2010-05-07 16:43:36 +04:00
} else {
count = res - > count ;
2010-04-13 20:28:53 +04:00
}
2010-05-07 16:43:36 +04:00
for ( i = 0 ; i < count ; i + + ) {
2010-04-13 20:28:53 +04:00
l_subnet_name = ldb_msg_find_attr_as_string ( res - > msgs [ i ] , " cn " ,
NULL ) ;
allow_list [ 0 ] = l_subnet_name ;
if ( allow_access ( mem_ctx , NULL , allow_list , " " , ip_address ) ) {
sites_dn = ldb_msg_find_attr_as_dn ( ldb , mem_ctx ,
res - > msgs [ i ] ,
" siteObject " ) ;
if ( sites_dn = = NULL ) {
/* No reference, maybe another subnet matches */
continue ;
}
/* "val" cannot be NULL here since "sites_dn" != NULL */
val = ldb_dn_get_rdn_val ( sites_dn ) ;
site_name = talloc_strdup ( mem_ctx ,
( const char * ) val - > data ) ;
talloc_free ( sites_dn ) ;
break ;
}
}
if ( site_name = = NULL ) {
/* This is the Windows Server fallback rule: when no subnet
* exists and we have only one site available then use it ( it
* is for sure the same as our server site ) . If more sites do
* exist then we don ' t know which one to use and set the site
* name to " " . */
cnt = samdb_search_count ( ldb , sites_container_dn ,
" (objectClass=site) " ) ;
if ( cnt = = 1 ) {
site_name = samdb_server_site_name ( ldb , mem_ctx ) ;
} else {
site_name = talloc_strdup ( mem_ctx , " " ) ;
}
l_subnet_name = NULL ;
}
if ( subnet_name ! = NULL ) {
* subnet_name = talloc_strdup ( mem_ctx , l_subnet_name ) ;
}
talloc_free ( sites_container_dn ) ;
talloc_free ( subnets_dn ) ;
talloc_free ( res ) ;
return site_name ;
}
2007-12-17 06:22:44 +03:00
/*
work out if we are the PDC for the domain of the current open ldb
*/
bool samdb_is_pdc ( struct ldb_context * ldb )
{
const char * dom_attrs [ ] = { " fSMORoleOwner " , NULL } ;
int ret ;
struct ldb_result * dom_res ;
TALLOC_CTX * tmp_ctx ;
bool is_pdc ;
struct ldb_dn * pdc ;
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
DEBUG ( 1 , ( " talloc_new failed in samdb_is_pdc " ) ) ;
return false ;
}
2008-09-23 22:30:06 +04:00
ret = ldb_search ( ldb , tmp_ctx , & dom_res , ldb_get_default_basedn ( ldb ) , LDB_SCOPE_BASE , dom_attrs , NULL ) ;
2010-08-09 21:45:45 +04:00
if ( ret ! = LDB_SUCCESS ) {
2007-12-17 06:22:44 +03:00
DEBUG ( 1 , ( " Searching for fSMORoleOwner in %s failed: %s \n " ,
ldb_dn_get_linearized ( ldb_get_default_basedn ( ldb ) ) ,
ldb_errstring ( ldb ) ) ) ;
goto failed ;
}
if ( dom_res - > count ! = 1 ) {
goto failed ;
}
pdc = ldb_msg_find_attr_as_dn ( ldb , tmp_ctx , dom_res - > msgs [ 0 ] , " fSMORoleOwner " ) ;
if ( ldb_dn_compare ( samdb_ntds_settings_dn ( ldb ) , pdc ) = = 0 ) {
is_pdc = true ;
} else {
is_pdc = false ;
}
talloc_free ( tmp_ctx ) ;
return is_pdc ;
failed :
DEBUG ( 1 , ( " Failed to find if we are the PDC for this ldb \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return false ;
}
2008-01-03 13:40:24 +03:00
/*
work out if we are a Global Catalog server for the domain of the current open ldb
*/
bool samdb_is_gc ( struct ldb_context * ldb )
{
const char * attrs [ ] = { " options " , NULL } ;
int ret , options ;
struct ldb_result * res ;
TALLOC_CTX * tmp_ctx ;
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
DEBUG ( 1 , ( " talloc_new failed in samdb_is_pdc " ) ) ;
return false ;
}
/* Query cn=ntds settings,.... */
2008-09-23 22:30:06 +04:00
ret = ldb_search ( ldb , tmp_ctx , & res , samdb_ntds_settings_dn ( ldb ) , LDB_SCOPE_BASE , attrs , NULL ) ;
2010-08-09 21:45:45 +04:00
if ( ret ! = LDB_SUCCESS ) {
2008-09-23 22:30:06 +04:00
talloc_free ( tmp_ctx ) ;
2008-01-03 13:40:24 +03:00
return false ;
}
if ( res - > count ! = 1 ) {
2008-09-23 22:30:06 +04:00
talloc_free ( tmp_ctx ) ;
2008-01-03 13:40:24 +03:00
return false ;
}
options = ldb_msg_find_attr_as_int ( res - > msgs [ 0 ] , " options " , 0 ) ;
2008-01-07 09:46:39 +03:00
talloc_free ( tmp_ctx ) ;
2008-01-03 13:40:24 +03:00
/* if options attribute has the 0x00000001 flag set, then enable the global catlog */
if ( options & 0x000000001 ) {
return true ;
}
return false ;
}
2007-12-17 06:22:44 +03:00
/* Find a domain object in the parents of a particular DN. */
int samdb_search_for_parent_domain ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx , struct ldb_dn * dn ,
struct ldb_dn * * parent_dn , const char * * errstring )
{
TALLOC_CTX * local_ctx ;
struct ldb_dn * sdn = dn ;
struct ldb_result * res = NULL ;
2010-08-09 21:45:45 +04:00
int ret = LDB_SUCCESS ;
2007-12-17 06:22:44 +03:00
const char * attrs [ ] = { NULL } ;
local_ctx = talloc_new ( mem_ctx ) ;
2010-07-06 07:21:54 +04:00
if ( local_ctx = = NULL ) return ldb_oom ( ldb ) ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
while ( ( sdn = ldb_dn_get_parent ( local_ctx , sdn ) ) ) {
2008-09-23 22:30:06 +04:00
ret = ldb_search ( ldb , local_ctx , & res , sdn , LDB_SCOPE_BASE , attrs ,
2009-10-12 09:44:19 +04:00
" (|(objectClass=domain)(objectClass=builtinDomain)) " ) ;
2007-12-17 06:22:44 +03:00
if ( ret = = LDB_SUCCESS ) {
if ( res - > count = = 1 ) {
break ;
}
} else {
break ;
}
}
if ( ret ! = LDB_SUCCESS ) {
* errstring = talloc_asprintf ( mem_ctx , " Error searching for parent domain of %s, failed searching for %s: %s " ,
ldb_dn_get_linearized ( dn ) ,
ldb_dn_get_linearized ( sdn ) ,
ldb_errstring ( ldb ) ) ;
talloc_free ( local_ctx ) ;
return ret ;
}
if ( res - > count ! = 1 ) {
* errstring = talloc_asprintf ( mem_ctx , " Invalid dn (%s), not child of a domain object " ,
ldb_dn_get_linearized ( dn ) ) ;
2009-09-24 00:52:39 +04:00
DEBUG ( 0 , ( __location__ " : %s \n " , * errstring ) ) ;
2007-12-17 06:22:44 +03:00
talloc_free ( local_ctx ) ;
return LDB_ERR_CONSTRAINT_VIOLATION ;
}
* parent_dn = talloc_steal ( mem_ctx , res - > msgs [ 0 ] - > dn ) ;
talloc_free ( local_ctx ) ;
return ret ;
}
/*
2009-11-06 17:15:53 +03:00
* Performs checks on a user password ( plaintext UNIX format - attribute
2009-10-24 22:21:04 +04:00
* " password " ) . The remaining parameters have to be extracted from the domain
* object in the AD .
*
* Result codes from " enum samr_ValidationStatus " ( consider " samr.idl " )
*/
2009-11-06 17:15:53 +03:00
enum samr_ValidationStatus samdb_check_password ( const DATA_BLOB * password ,
2009-10-24 22:21:04 +04:00
const uint32_t pwdProperties ,
const uint32_t minPwdLength )
{
/* checks if the "minPwdLength" property is satisfied */
2009-11-06 17:15:53 +03:00
if ( minPwdLength > password - > length )
2009-10-24 22:21:04 +04:00
return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT ;
2007-12-17 06:22:44 +03:00
2009-11-06 17:15:53 +03:00
/* checks the password complexity */
if ( ( ( pwdProperties & DOMAIN_PASSWORD_COMPLEX ) ! = 0 )
2009-11-06 17:38:31 +03:00
& & ( password - > data ! = NULL )
2009-11-06 17:15:53 +03:00
& & ( ! check_password_quality ( ( const char * ) password - > data ) ) )
return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH ;
2009-10-24 22:21:04 +04:00
return SAMR_VALIDATION_STATUS_SUCCESS ;
}
2009-09-26 14:09:07 +04:00
/*
* Callback for " samdb_set_password " password change
*/
int samdb_set_password_callback ( struct ldb_request * req , struct ldb_reply * ares )
{
int ret ;
if ( ! ares ) {
return ldb_request_done ( req , LDB_ERR_OPERATIONS_ERROR ) ;
}
if ( ares - > error ! = LDB_SUCCESS ) {
ret = ares - > error ;
req - > context = talloc_steal ( req ,
ldb_reply_get_control ( ares , DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID ) ) ;
talloc_free ( ares ) ;
return ldb_request_done ( req , ret ) ;
}
if ( ares - > type ! = LDB_REPLY_DONE ) {
talloc_free ( ares ) ;
return ldb_request_done ( req , LDB_ERR_OPERATIONS_ERROR ) ;
}
req - > context = talloc_steal ( req ,
ldb_reply_get_control ( ares , DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID ) ) ;
talloc_free ( ares ) ;
return ldb_request_done ( req , LDB_SUCCESS ) ;
}
2009-10-24 22:21:04 +04:00
/*
* Sets the user password using plaintext UTF16 ( attribute " new_password " ) or
* LM ( attribute " lmNewHash " ) or NT ( attribute " ntNewHash " ) hash . Also pass
* as parameter if it ' s a user change or not ( " userChange " ) . The " rejectReason "
* gives some more informations if the changed failed .
*
* Results : NT_STATUS_OK , NT_STATUS_INTERNAL_DB_CORRUPTION ,
* NT_STATUS_INVALID_PARAMETER , NT_STATUS_UNSUCCESSFUL ,
2009-09-26 14:09:07 +04:00
* NT_STATUS_WRONG_PASSWORD , NT_STATUS_PASSWORD_RESTRICTION
2009-10-24 22:21:04 +04:00
*/
2009-09-26 14:09:07 +04:00
NTSTATUS samdb_set_password ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx ,
2009-10-24 21:31:01 +04:00
struct ldb_dn * user_dn , struct ldb_dn * domain_dn ,
2008-10-16 05:48:16 +04:00
const DATA_BLOB * new_password ,
2009-09-26 14:09:07 +04:00
struct samr_Password * lmNewHash ,
struct samr_Password * ntNewHash ,
2007-12-17 06:22:44 +03:00
bool user_change ,
2009-09-26 00:44:00 +04:00
enum samPwdChangeReason * reject_reason ,
2007-12-17 06:22:44 +03:00
struct samr_DomInfo1 * * _dominfo )
{
2009-09-26 14:09:07 +04:00
struct ldb_message * msg ;
struct ldb_message_element * el ;
struct ldb_request * req ;
struct dsdb_control_password_change_status * pwd_stat = NULL ;
int ret ;
2010-08-15 20:05:29 +04:00
NTSTATUS status = NT_STATUS_OK ;
2007-12-17 06:22:44 +03:00
2009-09-26 14:09:07 +04:00
# define CHECK_RET(x) \
if ( x ! = LDB_SUCCESS ) { \
talloc_free ( msg ) ; \
return NT_STATUS_NO_MEMORY ; \
}
2007-12-17 06:22:44 +03:00
2009-09-26 14:09:07 +04:00
msg = ldb_msg_new ( mem_ctx ) ;
if ( msg = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
msg - > dn = user_dn ;
if ( ( new_password ! = NULL )
& & ( ( lmNewHash = = NULL ) & & ( ntNewHash = = NULL ) ) ) {
/* we have the password as plaintext UTF16 */
CHECK_RET ( samdb_msg_add_value ( ldb , mem_ctx , msg ,
" clearTextPassword " , new_password ) ) ;
el = ldb_msg_find_element ( msg , " clearTextPassword " ) ;
el - > flags = LDB_FLAG_MOD_REPLACE ;
} else if ( ( new_password = = NULL )
& & ( ( lmNewHash ! = NULL ) | | ( ntNewHash ! = NULL ) ) ) {
/* we have a password as LM and/or NT hash */
if ( lmNewHash ! = NULL ) {
CHECK_RET ( samdb_msg_add_hash ( ldb , mem_ctx , msg ,
" dBCSPwd " , lmNewHash ) ) ;
el = ldb_msg_find_element ( msg , " dBCSPwd " ) ;
el - > flags = LDB_FLAG_MOD_REPLACE ;
2007-12-17 06:22:44 +03:00
}
2009-09-26 14:09:07 +04:00
if ( ntNewHash ! = NULL ) {
CHECK_RET ( samdb_msg_add_hash ( ldb , mem_ctx , msg ,
" unicodePwd " , ntNewHash ) ) ;
el = ldb_msg_find_element ( msg , " unicodePwd " ) ;
el - > flags = LDB_FLAG_MOD_REPLACE ;
2007-12-17 06:22:44 +03:00
}
2009-09-26 14:09:07 +04:00
} else {
/* the password wasn't specified correctly */
talloc_free ( msg ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
2007-12-17 06:22:44 +03:00
2009-09-26 14:09:07 +04:00
/* build modify request */
ret = ldb_build_mod_req ( & req , ldb , mem_ctx , msg , NULL , NULL ,
samdb_set_password_callback , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( msg ) ;
return NT_STATUS_NO_MEMORY ;
}
2009-12-03 12:48:44 +03:00
if ( user_change ) {
/* a user password change and we've checked already the old
* password somewhere else ( callers responsability ) */
ret = ldb_request_add_control ( req ,
DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID ,
true , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( req ) ;
talloc_free ( msg ) ;
return NT_STATUS_NO_MEMORY ;
}
}
2009-09-26 14:09:07 +04:00
ret = ldb_request_add_control ( req ,
DSDB_CONTROL_PASSWORD_HASH_VALUES_OID ,
true , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( req ) ;
talloc_free ( msg ) ;
return NT_STATUS_NO_MEMORY ;
}
ret = ldb_request_add_control ( req ,
DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID ,
true , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( req ) ;
talloc_free ( msg ) ;
return NT_STATUS_NO_MEMORY ;
2007-12-17 06:22:44 +03:00
}
2009-09-26 14:09:07 +04:00
ret = dsdb_autotransaction_request ( ldb , req ) ;
2007-12-17 06:22:44 +03:00
2009-09-26 14:09:07 +04:00
if ( req - > context ! = NULL ) {
pwd_stat = talloc_steal ( mem_ctx ,
( ( struct ldb_control * ) req - > context ) - > data ) ;
2009-05-25 09:23:54 +04:00
}
2009-09-26 14:09:07 +04:00
talloc_free ( req ) ;
talloc_free ( msg ) ;
/* Sets the domain info (if requested) */
2009-09-23 21:23:17 +04:00
if ( _dominfo ! = NULL ) {
2007-12-17 06:22:44 +03:00
struct samr_DomInfo1 * dominfo ;
2009-09-26 14:09:07 +04:00
dominfo = talloc_zero ( mem_ctx , struct samr_DomInfo1 ) ;
2007-12-17 06:22:44 +03:00
if ( dominfo = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2009-05-31 18:19:11 +04:00
2009-09-26 14:09:07 +04:00
if ( pwd_stat ! = NULL ) {
dominfo - > min_password_length = pwd_stat - > domain_data . minPwdLength ;
dominfo - > password_properties = pwd_stat - > domain_data . pwdProperties ;
dominfo - > password_history_length = pwd_stat - > domain_data . pwdHistoryLength ;
dominfo - > max_password_age = pwd_stat - > domain_data . maxPwdAge ;
dominfo - > min_password_age = pwd_stat - > domain_data . minPwdAge ;
2007-12-17 06:22:44 +03:00
}
2008-10-16 05:48:16 +04:00
2009-09-26 14:09:07 +04:00
* _dominfo = dominfo ;
2007-12-17 06:22:44 +03:00
}
2009-09-26 14:09:07 +04:00
if ( reject_reason ! = NULL ) {
if ( pwd_stat ! = NULL ) {
* reject_reason = pwd_stat - > reject_reason ;
} else {
* reject_reason = SAM_PWD_CHANGE_NO_ERROR ;
2007-12-17 06:22:44 +03:00
}
}
2009-09-26 14:09:07 +04:00
if ( pwd_stat ! = NULL ) {
talloc_free ( pwd_stat ) ;
}
2007-12-17 06:22:44 +03:00
2010-08-15 20:05:29 +04:00
if ( ret = = LDB_ERR_CONSTRAINT_VIOLATION ) {
const char * errmsg = ldb_errstring ( ldb ) ;
char * endptr = NULL ;
WERROR werr = WERR_GENERAL_FAILURE ;
status = NT_STATUS_UNSUCCESSFUL ;
if ( errmsg ! = NULL ) {
werr = W_ERROR ( strtol ( errmsg , & endptr , 16 ) ) ;
}
if ( endptr ! = errmsg ) {
if ( W_ERROR_EQUAL ( werr , WERR_INVALID_PASSWORD ) ) {
status = NT_STATUS_WRONG_PASSWORD ;
}
if ( W_ERROR_EQUAL ( werr , WERR_PASSWORD_RESTRICTION ) ) {
status = NT_STATUS_PASSWORD_RESTRICTION ; }
}
2010-08-14 19:11:40 +04:00
} else if ( ret = = LDB_ERR_NO_SUCH_OBJECT ) {
2010-08-15 20:05:29 +04:00
/* don't let the caller know if an account doesn't exist */
2010-08-14 19:11:40 +04:00
status = NT_STATUS_WRONG_PASSWORD ;
2009-09-26 14:09:07 +04:00
} else if ( ret ! = LDB_SUCCESS ) {
status = NT_STATUS_UNSUCCESSFUL ;
2007-12-17 06:22:44 +03:00
}
2009-09-26 14:09:07 +04:00
return status ;
2007-12-17 06:22:44 +03:00
}
/*
2009-10-24 21:31:01 +04:00
* Sets the user password using plaintext UTF16 ( attribute " new_password " ) or
* LM ( attribute " lmNewHash " ) or NT ( attribute " ntNewHash " ) hash . Also pass
* as parameter if it ' s a user change or not ( " userChange " ) . The " rejectReason "
* gives some more informations if the changed failed .
*
* This wrapper function for " samdb_set_password " takes a SID as input rather
* than a user DN .
*
* This call encapsulates a new LDB transaction for changing the password ;
* therefore the user hasn ' t to start a new one .
*
* Results : NT_STATUS_OK , NT_STATUS_INTERNAL_DB_CORRUPTION ,
* NT_STATUS_INVALID_PARAMETER , NT_STATUS_UNSUCCESSFUL ,
2009-09-26 14:09:07 +04:00
* NT_STATUS_WRONG_PASSWORD , NT_STATUS_PASSWORD_RESTRICTION
2009-10-24 21:31:01 +04:00
*/
NTSTATUS samdb_set_password_sid ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx ,
2007-12-17 06:22:44 +03:00
const struct dom_sid * user_sid ,
2009-10-24 21:31:01 +04:00
const DATA_BLOB * new_password ,
2007-12-17 06:22:44 +03:00
struct samr_Password * lmNewHash ,
struct samr_Password * ntNewHash ,
bool user_change ,
2009-09-26 00:44:00 +04:00
enum samPwdChangeReason * reject_reason ,
2007-12-17 06:22:44 +03:00
struct samr_DomInfo1 * * _dominfo )
{
NTSTATUS nt_status ;
struct ldb_dn * user_dn ;
int ret ;
2009-10-24 21:31:01 +04:00
ret = ldb_transaction_start ( ldb ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 1 , ( " Failed to start transaction: %s \n " , ldb_errstring ( ldb ) ) ) ;
2007-12-17 06:22:44 +03:00
return NT_STATUS_TRANSACTION_ABORTED ;
}
2009-10-24 21:31:01 +04:00
user_dn = samdb_search_dn ( ldb , mem_ctx , NULL ,
2007-12-17 06:22:44 +03:00
" (&(objectSid=%s)(objectClass=user)) " ,
ldap_encode_ndr_dom_sid ( mem_ctx , user_sid ) ) ;
if ( ! user_dn ) {
2009-10-24 21:31:01 +04:00
ldb_transaction_cancel ( ldb ) ;
2007-12-17 06:22:44 +03:00
DEBUG ( 3 , ( " samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER \n " ,
dom_sid_string ( mem_ctx , user_sid ) ) ) ;
return NT_STATUS_NO_SUCH_USER ;
}
2009-10-24 21:31:01 +04:00
nt_status = samdb_set_password ( ldb , mem_ctx ,
2007-12-17 06:22:44 +03:00
user_dn , NULL ,
2009-09-26 14:09:07 +04:00
new_password ,
2007-12-17 06:22:44 +03:00
lmNewHash , ntNewHash ,
2009-12-13 18:13:34 +03:00
user_change ,
2007-12-17 06:22:44 +03:00
reject_reason , _dominfo ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2009-10-24 21:31:01 +04:00
ldb_transaction_cancel ( ldb ) ;
2009-12-13 18:13:34 +03:00
talloc_free ( user_dn ) ;
2007-12-17 06:22:44 +03:00
return nt_status ;
}
2009-05-31 18:19:11 +04:00
2009-10-24 21:31:01 +04:00
ret = ldb_transaction_commit ( ldb ) ;
if ( ret ! = LDB_SUCCESS ) {
2007-12-17 06:22:44 +03:00
DEBUG ( 0 , ( " Failed to commit transaction to change password on %s: %s \n " ,
2009-12-13 18:13:34 +03:00
ldb_dn_get_linearized ( user_dn ) ,
2009-10-24 21:31:01 +04:00
ldb_errstring ( ldb ) ) ) ;
2009-12-13 18:13:34 +03:00
talloc_free ( user_dn ) ;
2007-12-17 06:22:44 +03:00
return NT_STATUS_TRANSACTION_ABORTED ;
}
2009-12-13 18:13:34 +03:00
talloc_free ( user_dn ) ;
2007-12-17 06:22:44 +03:00
return NT_STATUS_OK ;
}
NTSTATUS samdb_create_foreign_security_principal ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx ,
struct dom_sid * sid , struct ldb_dn * * ret_dn )
{
struct ldb_message * msg ;
struct ldb_dn * basedn ;
2009-12-30 13:38:21 +03:00
char * sidstr ;
2007-12-17 06:22:44 +03:00
int ret ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
sidstr = dom_sid_string ( mem_ctx , sid ) ;
NT_STATUS_HAVE_NO_MEMORY ( sidstr ) ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
/* We might have to create a ForeignSecurityPrincipal, even if this user
* is in our own domain */
2009-05-31 18:19:11 +04:00
2009-12-30 13:38:21 +03:00
msg = ldb_msg_new ( sidstr ) ;
2007-12-17 06:22:44 +03:00
if ( msg = = NULL ) {
2009-12-30 13:38:21 +03:00
talloc_free ( sidstr ) ;
2007-12-17 06:22:44 +03:00
return NT_STATUS_NO_MEMORY ;
}
2009-05-31 18:19:11 +04:00
2010-04-13 10:41:10 +04:00
ret = dsdb_wellknown_dn ( sam_ctx , sidstr ,
ldb_get_default_basedn ( sam_ctx ) ,
2009-12-30 13:38:21 +03:00
DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER ,
& basedn ) ;
if ( ret ! = LDB_SUCCESS ) {
2007-12-17 06:22:44 +03:00
DEBUG ( 0 , ( " Failed to find DN for "
2009-12-30 13:38:21 +03:00
" ForeignSecurityPrincipal container - %s \n " , ldb_errstring ( sam_ctx ) ) ) ;
talloc_free ( sidstr ) ;
2007-12-17 06:22:44 +03:00
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
/* add core elements to the ldb_message for the alias */
2009-12-30 13:38:21 +03:00
msg - > dn = basedn ;
if ( ! ldb_dn_add_child_fmt ( msg - > dn , " CN=%s " , sidstr ) ) {
talloc_free ( sidstr ) ;
2007-12-17 06:22:44 +03:00
return NT_STATUS_NO_MEMORY ;
2009-12-30 13:38:21 +03:00
}
2009-05-31 18:19:11 +04:00
2009-12-30 13:38:21 +03:00
samdb_msg_add_string ( sam_ctx , msg , msg ,
2007-12-17 06:22:44 +03:00
" objectClass " ,
" foreignSecurityPrincipal " ) ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
/* create the alias */
ret = ldb_add ( sam_ctx , msg ) ;
2009-12-30 13:38:21 +03:00
if ( ret ! = LDB_SUCCESS ) {
2007-12-17 06:22:44 +03:00
DEBUG ( 0 , ( " Failed to create foreignSecurityPrincipal "
" record %s: %s \n " ,
ldb_dn_get_linearized ( msg - > dn ) ,
ldb_errstring ( sam_ctx ) ) ) ;
2009-12-30 13:38:21 +03:00
talloc_free ( sidstr ) ;
2007-12-17 06:22:44 +03:00
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
2009-12-30 13:38:21 +03:00
* ret_dn = talloc_steal ( mem_ctx , msg - > dn ) ;
talloc_free ( sidstr ) ;
2007-12-17 06:22:44 +03:00
return NT_STATUS_OK ;
}
/*
Find the DN of a domain , assuming it to be a dotted . dns name
*/
struct ldb_dn * samdb_dns_domain_to_dn ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx , const char * dns_domain )
{
2009-11-06 22:14:41 +03:00
unsigned int i ;
2007-12-17 06:22:44 +03:00
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
const char * binary_encoded ;
const char * * split_realm ;
struct ldb_dn * dn ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
if ( ! tmp_ctx ) {
return NULL ;
}
2009-05-31 18:19:11 +04:00
2008-10-12 02:56:56 +04:00
split_realm = ( const char * * ) str_list_make ( tmp_ctx , dns_domain , " . " ) ;
2007-12-17 06:22:44 +03:00
if ( ! split_realm ) {
talloc_free ( tmp_ctx ) ;
return NULL ;
}
dn = ldb_dn_new ( mem_ctx , ldb , NULL ) ;
for ( i = 0 ; split_realm [ i ] ; i + + ) {
binary_encoded = ldb_binary_encode_string ( tmp_ctx , split_realm [ i ] ) ;
if ( ! ldb_dn_add_base_fmt ( dn , " dc=%s " , binary_encoded ) ) {
DEBUG ( 2 , ( " Failed to add dc=%s element to DN %s \n " ,
binary_encoded , ldb_dn_get_linearized ( dn ) ) ) ;
talloc_free ( tmp_ctx ) ;
return NULL ;
}
}
if ( ! ldb_dn_validate ( dn ) ) {
DEBUG ( 2 , ( " Failed to validated DN %s \n " ,
ldb_dn_get_linearized ( dn ) ) ) ;
2009-12-30 13:39:24 +03:00
talloc_free ( tmp_ctx ) ;
2007-12-17 06:22:44 +03:00
return NULL ;
}
2009-12-30 13:39:24 +03:00
talloc_free ( tmp_ctx ) ;
2007-12-17 06:22:44 +03:00
return dn ;
}
2009-12-30 13:39:24 +03:00
2007-12-17 06:22:44 +03:00
/*
Find the DN of a domain , be it the netbios or DNS name
*/
struct ldb_dn * samdb_domain_to_dn ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx ,
const char * domain_name )
{
const char * const domain_ref_attrs [ ] = {
" ncName " , NULL
} ;
const char * const domain_ref2_attrs [ ] = {
NULL
} ;
struct ldb_result * res_domain_ref ;
char * escaped_domain = ldb_binary_encode_string ( mem_ctx , domain_name ) ;
/* find the domain's DN */
2008-09-23 22:30:06 +04:00
int ret_domain = ldb_search ( ldb , mem_ctx ,
2007-12-17 06:22:44 +03:00
& res_domain_ref ,
samdb_partitions_dn ( ldb , mem_ctx ) ,
LDB_SCOPE_ONELEVEL ,
domain_ref_attrs ,
" (&(nETBIOSName=%s)(objectclass=crossRef)) " ,
escaped_domain ) ;
2010-08-09 21:45:45 +04:00
if ( ret_domain ! = LDB_SUCCESS ) {
2007-12-17 06:22:44 +03:00
return NULL ;
}
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
if ( res_domain_ref - > count = = 0 ) {
2008-09-23 22:30:06 +04:00
ret_domain = ldb_search ( ldb , mem_ctx ,
2007-12-17 06:22:44 +03:00
& res_domain_ref ,
samdb_dns_domain_to_dn ( ldb , mem_ctx , domain_name ) ,
LDB_SCOPE_BASE ,
domain_ref2_attrs ,
" (objectclass=domain) " ) ;
2010-08-09 21:45:45 +04:00
if ( ret_domain ! = LDB_SUCCESS ) {
2007-12-17 06:22:44 +03:00
return NULL ;
}
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
if ( res_domain_ref - > count = = 1 ) {
return res_domain_ref - > msgs [ 0 ] - > dn ;
}
return NULL ;
}
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
if ( res_domain_ref - > count > 1 ) {
DEBUG ( 0 , ( " Found %d records matching domain [%s] \n " ,
ret_domain , domain_name ) ) ;
return NULL ;
}
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
return samdb_result_dn ( ldb , mem_ctx , res_domain_ref - > msgs [ 0 ] , " nCName " , NULL ) ;
}
2009-09-03 06:51:22 +04:00
/*
use a GUID to find a DN
*/
int dsdb_find_dn_by_guid ( struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx ,
2010-02-16 07:40:44 +03:00
const struct GUID * guid , struct ldb_dn * * dn )
2009-09-03 06:51:22 +04:00
{
int ret ;
struct ldb_result * res ;
const char * attrs [ ] = { NULL } ;
2010-02-16 07:40:44 +03:00
char * guid_str = GUID_string ( mem_ctx , guid ) ;
if ( ! guid_str ) {
2010-07-06 07:21:54 +04:00
return ldb_operr ( ldb ) ;
2010-02-16 07:40:44 +03:00
}
2009-09-03 06:51:22 +04:00
2010-02-16 07:15:35 +03:00
ret = dsdb_search ( ldb , mem_ctx , & res , NULL , LDB_SCOPE_SUBTREE , attrs ,
DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2010-02-16 07:40:44 +03:00
DSDB_SEARCH_SHOW_EXTENDED_DN |
DSDB_SEARCH_ONE_ONLY ,
2010-02-16 07:15:35 +03:00
" objectGUID=%s " , guid_str ) ;
2010-02-16 07:40:44 +03:00
talloc_free ( guid_str ) ;
2009-09-03 06:51:22 +04:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2009-12-30 13:39:24 +03:00
* dn = talloc_steal ( mem_ctx , res - > msgs [ 0 ] - > dn ) ;
2010-02-16 07:15:35 +03:00
talloc_free ( res ) ;
2009-09-03 06:51:22 +04:00
return LDB_SUCCESS ;
}
2009-09-03 12:27:29 +04:00
/*
2010-01-06 06:50:41 +03:00
use a DN to find a GUID with a given attribute name
2009-09-03 12:27:29 +04:00
*/
2010-01-06 06:50:41 +03:00
int dsdb_find_guid_attr_by_dn ( struct ldb_context * ldb ,
struct ldb_dn * dn , const char * attribute ,
struct GUID * guid )
2009-09-03 12:27:29 +04:00
{
int ret ;
struct ldb_result * res ;
2010-01-06 06:50:41 +03:00
const char * attrs [ 2 ] ;
2009-09-03 12:27:29 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( ldb ) ;
2010-01-06 06:50:41 +03:00
attrs [ 0 ] = attribute ;
attrs [ 1 ] = NULL ;
2010-02-16 06:55:19 +03:00
ret = dsdb_search_dn ( ldb , tmp_ctx , & res , dn , attrs , DSDB_SEARCH_SHOW_DELETED ) ;
2009-09-03 12:27:29 +04:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-09-24 18:05:07 +04:00
if ( res - > count < 1 ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_NO_SUCH_OBJECT ;
}
2010-01-06 06:50:41 +03:00
* guid = samdb_result_guid ( res - > msgs [ 0 ] , attribute ) ;
2009-09-03 12:27:29 +04:00
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2009-09-12 05:09:10 +04:00
2010-01-06 06:50:41 +03:00
/*
use a DN to find a GUID
*/
int dsdb_find_guid_by_dn ( struct ldb_context * ldb ,
struct ldb_dn * dn , struct GUID * guid )
{
return dsdb_find_guid_attr_by_dn ( ldb , dn , " objectGUID " , guid ) ;
}
2009-11-19 21:28:37 +03:00
/*
adds the given GUID to the given ldb_message . This value is added
for the given attr_name ( may be either " objectGUID " or " parentGUID " ) .
*/
int dsdb_msg_add_guid ( struct ldb_message * msg ,
struct GUID * guid ,
const char * attr_name )
{
int ret ;
struct ldb_val v ;
2009-12-10 06:33:13 +03:00
NTSTATUS status ;
2009-11-19 21:28:37 +03:00
TALLOC_CTX * tmp_ctx = talloc_init ( " dsdb_msg_add_guid " ) ;
2009-12-10 06:33:13 +03:00
status = GUID_to_ndr_blob ( guid , tmp_ctx , & v ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-11-19 21:28:37 +03:00
ret = LDB_ERR_OPERATIONS_ERROR ;
goto done ;
}
ret = ldb_msg_add_steal_value ( msg , attr_name , & v ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 4 , ( __location__ " : Failed to add %s to the message \n " ,
attr_name ) ) ;
goto done ;
}
ret = LDB_SUCCESS ;
done :
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-09-24 00:52:39 +04:00
/*
use a DN to find a SID
*/
int dsdb_find_sid_by_dn ( struct ldb_context * ldb ,
struct ldb_dn * dn , struct dom_sid * sid )
{
int ret ;
struct ldb_result * res ;
const char * attrs [ ] = { " objectSID " , NULL } ;
TALLOC_CTX * tmp_ctx = talloc_new ( ldb ) ;
struct dom_sid * s ;
ZERO_STRUCTP ( sid ) ;
2010-02-16 06:55:19 +03:00
ret = dsdb_search_dn ( ldb , tmp_ctx , & res , dn , attrs , DSDB_SEARCH_SHOW_DELETED ) ;
2009-09-24 00:52:39 +04:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-09-24 18:05:07 +04:00
if ( res - > count < 1 ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_NO_SUCH_OBJECT ;
}
2009-09-24 00:52:39 +04:00
s = samdb_result_dom_sid ( tmp_ctx , res - > msgs [ 0 ] , " objectSID " ) ;
if ( s = = NULL ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_NO_SUCH_OBJECT ;
}
* sid = * s ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2010-06-28 11:34:14 +04:00
/*
use a SID to find a DN
*/
int dsdb_find_dn_by_sid ( struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx ,
struct dom_sid * sid , struct ldb_dn * * dn )
{
int ret ;
struct ldb_result * res ;
const char * attrs [ ] = { NULL } ;
char * sid_str = dom_sid_string ( mem_ctx , sid ) ;
if ( ! sid_str ) {
2010-07-06 07:21:54 +04:00
return ldb_operr ( ldb ) ;
2010-06-28 11:34:14 +04:00
}
ret = dsdb_search ( ldb , mem_ctx , & res , NULL , LDB_SCOPE_SUBTREE , attrs ,
DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
DSDB_SEARCH_SHOW_EXTENDED_DN |
DSDB_SEARCH_ONE_ONLY ,
" objectSID=%s " , sid_str ) ;
talloc_free ( sid_str ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
* dn = talloc_steal ( mem_ctx , res - > msgs [ 0 ] - > dn ) ;
talloc_free ( res ) ;
return LDB_SUCCESS ;
}
2009-09-12 05:09:10 +04:00
/*
load a repsFromTo blob list for a given partition GUID
attr must be " repsFrom " or " repsTo "
*/
WERROR dsdb_loadreps ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx , struct ldb_dn * dn ,
const char * attr , struct repsFromToBlob * * r , uint32_t * count )
{
const char * attrs [ ] = { attr , NULL } ;
struct ldb_result * res = NULL ;
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
2009-11-06 22:14:41 +03:00
unsigned int i ;
2009-09-12 05:09:10 +04:00
struct ldb_message_element * el ;
* r = NULL ;
* count = 0 ;
if ( ldb_search ( sam_ctx , tmp_ctx , & res , dn , LDB_SCOPE_BASE , attrs , NULL ) ! = LDB_SUCCESS | |
res - > count < 1 ) {
DEBUG ( 0 , ( " dsdb_loadreps: failed to read partition object \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
el = ldb_msg_find_element ( res - > msgs [ 0 ] , attr ) ;
if ( el = = NULL ) {
/* it's OK to be empty */
talloc_free ( tmp_ctx ) ;
return WERR_OK ;
}
* count = el - > num_values ;
* r = talloc_array ( mem_ctx , struct repsFromToBlob , * count ) ;
if ( * r = = NULL ) {
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
for ( i = 0 ; i < ( * count ) ; i + + ) {
enum ndr_err_code ndr_err ;
ndr_err = ndr_pull_struct_blob ( & el - > values [ i ] ,
2010-05-09 19:20:01 +04:00
mem_ctx ,
2009-09-12 05:09:10 +04:00
& ( * r ) [ i ] ,
( ndr_pull_flags_fn_t ) ndr_pull_repsFromToBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
}
talloc_free ( tmp_ctx ) ;
return WERR_OK ;
}
/*
save the repsFromTo blob list for a given partition GUID
attr must be " repsFrom " or " repsTo "
*/
WERROR dsdb_savereps ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx , struct ldb_dn * dn ,
const char * attr , struct repsFromToBlob * r , uint32_t count )
{
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
struct ldb_message * msg ;
struct ldb_message_element * el ;
2009-11-06 22:14:41 +03:00
unsigned int i ;
2009-09-12 05:09:10 +04:00
msg = ldb_msg_new ( tmp_ctx ) ;
msg - > dn = dn ;
if ( ldb_msg_add_empty ( msg , attr , LDB_FLAG_MOD_REPLACE , & el ) ! = LDB_SUCCESS ) {
goto failed ;
}
el - > values = talloc_array ( msg , struct ldb_val , count ) ;
if ( ! el - > values ) {
goto failed ;
}
for ( i = 0 ; i < count ; i + + ) {
struct ldb_val v ;
enum ndr_err_code ndr_err ;
2010-05-09 19:20:01 +04:00
ndr_err = ndr_push_struct_blob ( & v , tmp_ctx ,
2009-09-12 05:09:10 +04:00
& r [ i ] ,
( ndr_push_flags_fn_t ) ndr_push_repsFromToBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
goto failed ;
}
el - > num_values + + ;
el - > values [ i ] = v ;
}
if ( ldb_modify ( sam_ctx , msg ) ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( " Failed to store %s - %s \n " , attr , ldb_errstring ( sam_ctx ) ) ) ;
goto failed ;
}
talloc_free ( tmp_ctx ) ;
return WERR_OK ;
failed :
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2009-09-13 12:13:17 +04:00
/*
2010-01-07 21:30:05 +03:00
load the uSNHighest and the uSNUrgent attributes from the @ REPLCHANGED
object for a partition
2009-09-13 12:13:17 +04:00
*/
2010-01-07 21:30:05 +03:00
int dsdb_load_partition_usn ( struct ldb_context * ldb , struct ldb_dn * dn ,
uint64_t * uSN , uint64_t * urgent_uSN )
2009-09-13 12:13:17 +04:00
{
struct ldb_request * req ;
int ret ;
TALLOC_CTX * tmp_ctx = talloc_new ( ldb ) ;
struct dsdb_control_current_partition * p_ctrl ;
struct ldb_result * res ;
res = talloc_zero ( tmp_ctx , struct ldb_result ) ;
if ( ! res ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 07:21:54 +04:00
return ldb_oom ( ldb ) ;
2009-09-13 12:13:17 +04:00
}
ret = ldb_build_search_req ( & req , ldb , tmp_ctx ,
ldb_dn_new ( tmp_ctx , ldb , " @REPLCHANGED " ) ,
LDB_SCOPE_BASE ,
NULL , NULL ,
NULL ,
res , ldb_search_default_callback ,
NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
p_ctrl = talloc ( req , struct dsdb_control_current_partition ) ;
if ( p_ctrl = = NULL ) {
2010-06-21 13:02:45 +04:00
talloc_free ( tmp_ctx ) ;
2010-07-06 07:21:54 +04:00
return ldb_oom ( ldb ) ;
2009-09-13 12:13:17 +04:00
}
p_ctrl - > version = DSDB_CONTROL_CURRENT_PARTITION_VERSION ;
p_ctrl - > dn = dn ;
ret = ldb_request_add_control ( req ,
DSDB_CONTROL_CURRENT_PARTITION_OID ,
false , p_ctrl ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
/* Run the new request */
ret = ldb_request ( ldb , req ) ;
if ( ret = = LDB_SUCCESS ) {
ret = ldb_wait ( req - > handle , LDB_WAIT_ALL ) ;
}
2009-09-16 14:43:37 +04:00
if ( ret = = LDB_ERR_NO_SUCH_OBJECT ) {
/* it hasn't been created yet, which means
an implicit value of zero */
* uSN = 0 ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2009-09-13 12:13:17 +04:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
if ( res - > count < 1 ) {
* uSN = 0 ;
2010-01-07 21:30:05 +03:00
if ( urgent_uSN ) {
* urgent_uSN = 0 ;
}
2009-09-13 12:13:17 +04:00
} else {
* uSN = ldb_msg_find_attr_as_uint64 ( res - > msgs [ 0 ] , " uSNHighest " , 0 ) ;
2010-01-07 21:30:05 +03:00
if ( urgent_uSN ) {
* urgent_uSN = ldb_msg_find_attr_as_uint64 ( res - > msgs [ 0 ] , " uSNUrgent " , 0 ) ;
}
2009-09-13 12:13:17 +04:00
}
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2009-09-14 22:46:59 +04:00
int drsuapi_DsReplicaCursor2_compare ( const struct drsuapi_DsReplicaCursor2 * c1 ,
const struct drsuapi_DsReplicaCursor2 * c2 )
{
return GUID_compare ( & c1 - > source_dsa_invocation_id , & c2 - > source_dsa_invocation_id ) ;
}
2009-10-13 12:48:13 +04:00
2010-01-09 05:11:27 +03:00
int drsuapi_DsReplicaCursor_compare ( const struct drsuapi_DsReplicaCursor * c1 ,
const struct drsuapi_DsReplicaCursor * c2 )
{
return GUID_compare ( & c1 - > source_dsa_invocation_id , & c2 - > source_dsa_invocation_id ) ;
}
2010-04-16 00:37:40 +04:00
2009-10-13 12:48:13 +04:00
/*
2010-04-16 00:37:40 +04:00
see if a computer identified by its invocationId is a RODC
2009-10-13 12:48:13 +04:00
*/
2010-04-28 18:02:55 +04:00
int samdb_is_rodc ( struct ldb_context * sam_ctx , const struct GUID * objectGUID , bool * is_rodc )
2010-04-16 00:37:40 +04:00
{
/* 1) find the DN for this servers NTDSDSA object
2 ) search for the msDS - isRODC attribute
3 ) if not present then not a RODC
4 ) if present and TRUE then is a RODC
*/
struct ldb_dn * config_dn ;
const char * attrs [ ] = { " msDS-isRODC " , NULL } ;
int ret ;
struct ldb_result * res ;
TALLOC_CTX * tmp_ctx = talloc_new ( sam_ctx ) ;
2010-03-01 15:16:59 +03:00
2010-04-16 01:54:13 +04:00
config_dn = ldb_get_config_basedn ( sam_ctx ) ;
2010-04-16 00:37:40 +04:00
if ( ! config_dn ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 07:21:54 +04:00
return ldb_operr ( sam_ctx ) ;
2010-03-01 15:16:59 +03:00
}
2010-04-16 00:37:40 +04:00
ret = dsdb_search ( sam_ctx , tmp_ctx , & res , config_dn , LDB_SCOPE_SUBTREE , attrs ,
2010-04-28 18:02:55 +04:00
DSDB_SEARCH_ONE_ONLY , " objectGUID=%s " , GUID_string ( tmp_ctx , objectGUID ) ) ;
if ( ret = = LDB_ERR_NO_SUCH_OBJECT ) {
* is_rodc = false ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2010-04-16 00:37:40 +04:00
if ( ret ! = LDB_SUCCESS ) {
2010-04-28 18:02:55 +04:00
DEBUG ( 1 , ( ( " Failed to find our own NTDS Settings object by objectGUID=%s! \n " ) ,
GUID_string ( tmp_ctx , objectGUID ) ) ) ;
2010-05-04 13:49:18 +04:00
* is_rodc = false ;
2010-04-16 00:37:40 +04:00
talloc_free ( tmp_ctx ) ;
return ret ;
2010-03-01 15:16:59 +03:00
}
2010-04-16 00:37:40 +04:00
ret = ldb_msg_find_attr_as_bool ( res - > msgs [ 0 ] , " msDS-isRODC " , 0 ) ;
* is_rodc = ( ret = = 1 ) ;
2009-10-13 12:48:13 +04:00
2010-04-16 00:37:40 +04:00
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2010-03-01 15:16:59 +03:00
2010-04-16 00:37:40 +04:00
/*
see if we are a RODC
*/
int samdb_rodc ( struct ldb_context * sam_ctx , bool * am_rodc )
{
2010-04-28 18:02:55 +04:00
const struct GUID * objectGUID ;
2010-05-11 12:34:19 +04:00
int ret ;
bool * cached ;
/* see if we have a cached copy */
cached = ( bool * ) ldb_get_opaque ( sam_ctx , " cache.am_rodc " ) ;
if ( cached ) {
* am_rodc = * cached ;
return LDB_SUCCESS ;
}
2010-04-28 18:02:55 +04:00
objectGUID = samdb_ntds_objectGUID ( sam_ctx ) ;
if ( ! objectGUID ) {
2010-07-06 07:21:54 +04:00
return ldb_operr ( sam_ctx ) ;
2010-04-16 00:37:40 +04:00
}
2010-05-11 12:34:19 +04:00
ret = samdb_is_rodc ( sam_ctx , objectGUID , am_rodc ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
cached = talloc ( sam_ctx , bool ) ;
if ( cached = = NULL ) {
2010-07-06 07:21:54 +04:00
return ldb_oom ( sam_ctx ) ;
2010-05-11 12:34:19 +04:00
}
* cached = * am_rodc ;
ret = ldb_set_opaque ( sam_ctx , " cache.am_rodc " , cached ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( cached ) ;
2010-07-06 07:21:54 +04:00
return ldb_operr ( sam_ctx ) ;
2010-05-11 12:34:19 +04:00
}
return LDB_SUCCESS ;
2010-03-01 15:16:59 +03:00
}
2009-10-13 12:48:13 +04:00
2010-05-13 16:07:50 +04:00
bool samdb_set_am_rodc ( struct ldb_context * ldb , bool am_rodc )
{
TALLOC_CTX * tmp_ctx ;
bool * cached ;
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
goto failed ;
}
cached = talloc ( tmp_ctx , bool ) ;
if ( ! cached ) {
goto failed ;
}
* cached = am_rodc ;
if ( ldb_set_opaque ( ldb , " cache.am_rodc " , cached ) ! = LDB_SUCCESS ) {
goto failed ;
}
talloc_steal ( ldb , cached ) ;
talloc_free ( tmp_ctx ) ;
return true ;
failed :
DEBUG ( 1 , ( " Failed to set our own cached am_rodc in the ldb! \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return false ;
}
2010-04-16 00:37:40 +04:00
2009-10-13 12:48:13 +04:00
/*
return NTDS options flags . See MS - ADTS 7.1 .1 .2 .2 .1 .2 .1 .1
flags are DS_NTDS_OPTION_ *
*/
int samdb_ntds_options ( struct ldb_context * ldb , uint32_t * options )
{
TALLOC_CTX * tmp_ctx ;
const char * attrs [ ] = { " options " , NULL } ;
int ret ;
struct ldb_result * res ;
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
goto failed ;
}
ret = ldb_search ( ldb , tmp_ctx , & res , samdb_ntds_settings_dn ( ldb ) , LDB_SCOPE_BASE , attrs , NULL ) ;
2010-08-09 21:45:45 +04:00
if ( ret ! = LDB_SUCCESS ) {
2009-10-13 12:48:13 +04:00
goto failed ;
}
if ( res - > count ! = 1 ) {
goto failed ;
}
* options = samdb_result_uint ( res - > msgs [ 0 ] , " options " , 0 ) ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
failed :
2010-03-01 15:16:59 +03:00
DEBUG ( 1 , ( " Failed to find our own NTDS Settings options in the ldb! \n " ) ) ;
2009-10-13 12:48:13 +04:00
talloc_free ( tmp_ctx ) ;
return LDB_ERR_NO_SUCH_OBJECT ;
}
2009-11-14 22:12:42 +03:00
2010-03-01 15:16:59 +03:00
const char * samdb_ntds_object_category ( TALLOC_CTX * tmp_ctx , struct ldb_context * ldb )
{
const char * attrs [ ] = { " objectCategory " , NULL } ;
int ret ;
struct ldb_result * res ;
ret = ldb_search ( ldb , tmp_ctx , & res , samdb_ntds_settings_dn ( ldb ) , LDB_SCOPE_BASE , attrs , NULL ) ;
2010-08-09 21:45:45 +04:00
if ( ret ! = LDB_SUCCESS ) {
2010-03-01 15:16:59 +03:00
goto failed ;
}
if ( res - > count ! = 1 ) {
goto failed ;
}
return samdb_result_string ( res - > msgs [ 0 ] , " objectCategory " , NULL ) ;
failed :
DEBUG ( 1 , ( " Failed to find our own NTDS Settings objectCategory in the ldb! \n " ) ) ;
return NULL ;
}
2009-11-14 22:12:42 +03:00
/*
* Function which generates a " lDAPDisplayName " attribute from a " CN " one .
* Algorithm implemented according to MS - ADTS 3.1 .1 .2 .3 .4
*/
const char * samdb_cn_to_lDAPDisplayName ( TALLOC_CTX * mem_ctx , const char * cn )
{
char * * tokens , * ret ;
size_t i ;
tokens = str_list_make ( mem_ctx , cn , " -_ " ) ;
if ( tokens = = NULL )
return NULL ;
/* "tolower()" and "toupper()" should also work properly on 0x00 */
tokens [ 0 ] [ 0 ] = tolower ( tokens [ 0 ] [ 0 ] ) ;
for ( i = 1 ; i < str_list_length ( ( const char * * ) tokens ) ; i + + )
tokens [ i ] [ 0 ] = toupper ( tokens [ i ] [ 0 ] ) ;
ret = talloc_strdup ( mem_ctx , tokens [ 0 ] ) ;
for ( i = 1 ; i < str_list_length ( ( const char * * ) tokens ) ; i + + )
ret = talloc_asprintf_append_buffer ( ret , " %s " , tokens [ i ] ) ;
talloc_free ( tokens ) ;
return ret ;
}
2009-12-09 07:18:37 +03:00
/*
2010-08-09 21:52:00 +04:00
* This detects and returns the domain functional level ( DS_DOMAIN_FUNCTION_ * )
2009-12-09 07:18:37 +03:00
*/
int dsdb_functional_level ( struct ldb_context * ldb )
{
int * domainFunctionality =
talloc_get_type ( ldb_get_opaque ( ldb , " domainFunctionality " ) , int ) ;
if ( ! domainFunctionality ) {
DEBUG ( 0 , ( __location__ " : WARNING: domainFunctionality not setup \n " ) ) ;
return DS_DOMAIN_FUNCTION_2000 ;
}
return * domainFunctionality ;
}
2010-08-09 21:52:00 +04:00
/*
* This detects and returns the forest functional level ( DS_DOMAIN_FUNCTION_ * )
*/
int dsdb_forest_functional_level ( struct ldb_context * ldb )
{
int * forestFunctionality =
talloc_get_type ( ldb_get_opaque ( ldb , " forestFunctionality " ) , int ) ;
if ( ! forestFunctionality ) {
DEBUG ( 0 , ( __location__ " : WARNING: forestFunctionality not setup \n " ) ) ;
return DS_DOMAIN_FUNCTION_2000 ;
}
return * forestFunctionality ;
}
2009-12-30 02:52:14 +03:00
/*
set a GUID in an extended DN structure
*/
int dsdb_set_extended_dn_guid ( struct ldb_dn * dn , const struct GUID * guid , const char * component_name )
{
struct ldb_val v ;
NTSTATUS status ;
int ret ;
status = GUID_to_ndr_blob ( guid , dn , & v ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX ;
}
ret = ldb_dn_set_extended_component ( dn , component_name , & v ) ;
data_blob_free ( & v ) ;
return ret ;
}
2009-12-10 03:23:20 +03:00
/*
return a GUID from a extended DN structure
*/
2009-12-18 12:51:37 +03:00
NTSTATUS dsdb_get_extended_dn_guid ( struct ldb_dn * dn , struct GUID * guid , const char * component_name )
2009-12-10 03:23:20 +03:00
{
const struct ldb_val * v ;
2009-12-18 12:51:37 +03:00
v = ldb_dn_get_extended_component ( dn , component_name ) ;
2009-12-10 03:23:20 +03:00
if ( v = = NULL ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
return GUID_from_ndr_blob ( v , guid ) ;
}
2009-12-15 03:00:30 +03:00
2009-12-18 12:54:23 +03:00
/*
2009-12-19 04:23:42 +03:00
return a uint64_t from a extended DN structure
2009-12-18 12:54:23 +03:00
*/
2009-12-19 04:23:42 +03:00
NTSTATUS dsdb_get_extended_dn_uint64 ( struct ldb_dn * dn , uint64_t * val , const char * component_name )
2009-12-18 12:54:23 +03:00
{
const struct ldb_val * v ;
char * s ;
v = ldb_dn_get_extended_component ( dn , component_name ) ;
if ( v = = NULL ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
s = talloc_strndup ( dn , ( const char * ) v - > data , v - > length ) ;
NT_STATUS_HAVE_NO_MEMORY ( s ) ;
2009-12-19 04:23:42 +03:00
* val = strtoull ( s , NULL , 0 ) ;
2009-12-18 12:54:23 +03:00
talloc_free ( s ) ;
return NT_STATUS_OK ;
}
2009-12-19 04:23:42 +03:00
/*
return a NTTIME from a extended DN structure
*/
NTSTATUS dsdb_get_extended_dn_nttime ( struct ldb_dn * dn , NTTIME * nttime , const char * component_name )
{
return dsdb_get_extended_dn_uint64 ( dn , nttime , component_name ) ;
}
2009-12-18 12:54:23 +03:00
/*
return a uint32_t from a extended DN structure
*/
NTSTATUS dsdb_get_extended_dn_uint32 ( struct ldb_dn * dn , uint32_t * val , const char * component_name )
{
const struct ldb_val * v ;
char * s ;
v = ldb_dn_get_extended_component ( dn , component_name ) ;
if ( v = = NULL ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
s = talloc_strndup ( dn , ( const char * ) v - > data , v - > length ) ;
NT_STATUS_HAVE_NO_MEMORY ( s ) ;
* val = strtoul ( s , NULL , 0 ) ;
talloc_free ( s ) ;
return NT_STATUS_OK ;
}
2010-04-22 08:53:53 +04:00
/*
return a dom_sid from a extended DN structure
*/
NTSTATUS dsdb_get_extended_dn_sid ( struct ldb_dn * dn , struct dom_sid * sid , const char * component_name )
{
const struct ldb_val * sid_blob ;
struct TALLOC_CTX * tmp_ctx ;
enum ndr_err_code ndr_err ;
sid_blob = ldb_dn_get_extended_component ( dn , " SID " ) ;
if ( ! sid_blob ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
tmp_ctx = talloc_new ( NULL ) ;
2010-05-09 19:20:01 +04:00
ndr_err = ndr_pull_struct_blob_all ( sid_blob , tmp_ctx , sid ,
2010-04-22 08:53:53 +04:00
( ndr_pull_flags_fn_t ) ndr_pull_dom_sid ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
NTSTATUS status = ndr_map_error2ntstatus ( ndr_err ) ;
talloc_free ( tmp_ctx ) ;
return status ;
}
talloc_free ( tmp_ctx ) ;
return NT_STATUS_OK ;
}
2010-01-02 00:14:52 +03:00
/*
return RMD_FLAGS directly from a ldb_dn
returns 0 if not found
*/
uint32_t dsdb_dn_rmd_flags ( struct ldb_dn * dn )
{
const struct ldb_val * v ;
char buf [ 32 ] ;
v = ldb_dn_get_extended_component ( dn , " RMD_FLAGS " ) ;
if ( ! v | | v - > length > sizeof ( buf ) - 1 ) return 0 ;
strncpy ( buf , ( const char * ) v - > data , v - > length ) ;
buf [ v - > length ] = 0 ;
return strtoul ( buf , NULL , 10 ) ;
}
/*
return RMD_FLAGS directly from a ldb_val for a DN
returns 0 if RMD_FLAGS is not found
*/
2010-06-14 07:27:59 +04:00
uint32_t dsdb_dn_val_rmd_flags ( const struct ldb_val * val )
2010-01-02 00:14:52 +03:00
{
const char * p ;
uint32_t flags ;
char * end ;
if ( val - > length < 13 ) {
return 0 ;
}
p = memmem ( val - > data , val - > length - 2 , " <RMD_FLAGS= " , 11 ) ;
if ( ! p ) {
return 0 ;
}
flags = strtoul ( p + 11 , & end , 10 ) ;
if ( ! end | | * end ! = ' > ' ) {
/* it must end in a > */
return 0 ;
}
return flags ;
}
2009-12-15 03:00:30 +03:00
/*
return true if a ldb_val containing a DN in storage form is deleted
*/
2010-06-14 07:27:59 +04:00
bool dsdb_dn_is_deleted_val ( const struct ldb_val * val )
2009-12-15 03:00:30 +03:00
{
2010-01-02 00:14:52 +03:00
return ( dsdb_dn_val_rmd_flags ( val ) & DSDB_RMD_FLAG_DELETED ) ! = 0 ;
2009-12-15 03:00:30 +03:00
}
2009-12-16 05:18:44 +03:00
2009-12-19 12:55:46 +03:00
/*
return true if a ldb_val containing a DN in storage form is
in the upgraded w2k3 linked attribute format
*/
bool dsdb_dn_is_upgraded_link_val ( struct ldb_val * val )
{
return memmem ( val - > data , val - > length , " <RMD_ADDTIME= " , 13 ) ! = NULL ;
}
2009-12-16 05:18:44 +03:00
/*
return a DN for a wellknown GUID
*/
int dsdb_wellknown_dn ( struct ldb_context * samdb , TALLOC_CTX * mem_ctx ,
struct ldb_dn * nc_root , const char * wk_guid ,
struct ldb_dn * * wkguid_dn )
{
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
const char * attrs [ ] = { NULL } ;
int ret ;
struct ldb_dn * dn ;
struct ldb_result * res ;
/* construct the magic WKGUID DN */
dn = ldb_dn_new_fmt ( tmp_ctx , samdb , " <WKGUID=%s,%s> " ,
wk_guid , ldb_dn_get_linearized ( nc_root ) ) ;
if ( ! wkguid_dn ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 07:21:54 +04:00
return ldb_operr ( samdb ) ;
2009-12-16 05:18:44 +03:00
}
2010-02-16 06:55:19 +03:00
ret = dsdb_search_dn ( samdb , tmp_ctx , & res , dn , attrs , DSDB_SEARCH_SHOW_DELETED ) ;
2009-12-16 05:18:44 +03:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
( * wkguid_dn ) = talloc_steal ( mem_ctx , res - > msgs [ 0 ] - > dn ) ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2009-12-16 05:36:17 +03:00
2009-12-17 15:50:05 +03:00
static int dsdb_dn_compare_ptrs ( struct ldb_dn * * dn1 , struct ldb_dn * * dn2 )
{
return ldb_dn_compare ( * dn1 , * dn2 ) ;
}
2009-12-16 05:36:17 +03:00
/*
find a NC root given a DN within the NC
*/
int dsdb_find_nc_root ( struct ldb_context * samdb , TALLOC_CTX * mem_ctx , struct ldb_dn * dn ,
struct ldb_dn * * nc_root )
{
const char * root_attrs [ ] = { " namingContexts " , NULL } ;
TALLOC_CTX * tmp_ctx ;
int ret ;
struct ldb_message_element * el ;
struct ldb_result * root_res ;
2010-05-30 22:45:56 +04:00
unsigned int i ;
2009-12-16 05:36:17 +03:00
struct ldb_dn * * nc_dns ;
tmp_ctx = talloc_new ( samdb ) ;
if ( tmp_ctx = = NULL ) {
2010-07-06 07:21:54 +04:00
return ldb_oom ( samdb ) ;
2009-12-16 05:36:17 +03:00
}
ret = ldb_search ( samdb , tmp_ctx , & root_res ,
ldb_dn_new ( tmp_ctx , samdb , " " ) , LDB_SCOPE_BASE , root_attrs , NULL ) ;
2010-08-09 21:45:45 +04:00
if ( ret ! = LDB_SUCCESS ) {
2009-12-16 05:36:17 +03:00
DEBUG ( 1 , ( " Searching for namingContexts in rootDSE failed: %s \n " , ldb_errstring ( samdb ) ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
el = ldb_msg_find_element ( root_res - > msgs [ 0 ] , " namingContexts " ) ;
if ( ! el ) {
DEBUG ( 1 , ( " Finding namingContexts element in root_res failed: %s \n " ,
ldb_errstring ( samdb ) ) ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_NO_SUCH_ATTRIBUTE ;
}
nc_dns = talloc_array ( tmp_ctx , struct ldb_dn * , el - > num_values ) ;
if ( ! nc_dns ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 07:21:54 +04:00
return ldb_oom ( samdb ) ;
2009-12-16 05:36:17 +03:00
}
for ( i = 0 ; i < el - > num_values ; i + + ) {
nc_dns [ i ] = ldb_dn_from_ldb_val ( nc_dns , samdb , & el - > values [ i ] ) ;
if ( nc_dns [ i ] = = NULL ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 07:21:54 +04:00
return ldb_operr ( samdb ) ;
2009-12-16 05:36:17 +03:00
}
}
2010-02-13 04:59:43 +03:00
TYPESAFE_QSORT ( nc_dns , el - > num_values , dsdb_dn_compare_ptrs ) ;
2009-12-16 05:36:17 +03:00
for ( i = 0 ; i < el - > num_values ; i + + ) {
if ( ldb_dn_compare_base ( nc_dns [ i ] , dn ) = = 0 ) {
( * nc_root ) = talloc_steal ( mem_ctx , nc_dns [ i ] ) ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
}
talloc_free ( tmp_ctx ) ;
return LDB_ERR_NO_SUCH_OBJECT ;
}
2009-12-16 05:41:21 +03:00
/*
find the deleted objects DN for any object , by looking for the NC
root , then looking up the wellknown GUID
*/
int dsdb_get_deleted_objects_dn ( struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx , struct ldb_dn * obj_dn ,
struct ldb_dn * * do_dn )
{
struct ldb_dn * nc_root ;
int ret ;
ret = dsdb_find_nc_root ( ldb , mem_ctx , obj_dn , & nc_root ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
ret = dsdb_wellknown_dn ( ldb , mem_ctx , nc_root , DS_GUID_DELETED_OBJECTS_CONTAINER , do_dn ) ;
talloc_free ( nc_root ) ;
return ret ;
}
2009-12-30 12:04:17 +03:00
/*
return the tombstoneLifetime , in days
*/
int dsdb_tombstone_lifetime ( struct ldb_context * ldb , uint32_t * lifetime )
{
struct ldb_dn * dn ;
2010-04-13 10:41:10 +04:00
dn = ldb_get_config_basedn ( ldb ) ;
2009-12-30 12:04:17 +03:00
if ( ! dn ) {
return LDB_ERR_NO_SUCH_OBJECT ;
}
dn = ldb_dn_copy ( ldb , dn ) ;
if ( ! dn ) {
2010-07-06 07:21:54 +04:00
return ldb_operr ( ldb ) ;
2009-12-30 12:04:17 +03:00
}
/* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
be a wellknown GUID for this */
2010-02-13 20:20:54 +03:00
if ( ! ldb_dn_add_child_fmt ( dn , " CN=Directory Service,CN=Windows NT,CN=Services " ) ) {
2009-12-30 12:04:17 +03:00
talloc_free ( dn ) ;
2010-07-06 07:21:54 +04:00
return ldb_operr ( ldb ) ;
2009-12-30 12:04:17 +03:00
}
* lifetime = samdb_search_uint ( ldb , dn , 180 , dn , " tombstoneLifetime " , " objectClass=nTDSService " ) ;
talloc_free ( dn ) ;
return LDB_SUCCESS ;
}
2010-01-09 09:42:05 +03:00
/*
compare a ldb_val to a string case insensitively
*/
int samdb_ldb_val_case_cmp ( const char * s , struct ldb_val * v )
{
size_t len = strlen ( s ) ;
int ret ;
if ( len > v - > length ) return 1 ;
ret = strncasecmp ( s , ( const char * ) v - > data , v - > length ) ;
if ( ret ! = 0 ) return ret ;
if ( v - > length > len & & v - > data [ len ] ! = 0 ) {
return - 1 ;
}
return 0 ;
}
2010-01-16 03:08:15 +03:00
/*
load the UDV for a partition in v2 format
2010-01-16 03:48:25 +03:00
The list is returned sorted , and with our local cursor added
2010-01-16 03:08:15 +03:00
*/
int dsdb_load_udv_v2 ( struct ldb_context * samdb , struct ldb_dn * dn , TALLOC_CTX * mem_ctx ,
struct drsuapi_DsReplicaCursor2 * * cursors , uint32_t * count )
{
static const char * attrs [ ] = { " replUpToDateVector " , NULL } ;
struct ldb_result * r ;
const struct ldb_val * ouv_value ;
2009-11-06 22:14:41 +03:00
unsigned int i ;
int ret ;
2010-01-16 03:48:25 +03:00
uint64_t highest_usn ;
const struct GUID * our_invocation_id ;
struct timeval now = timeval_current ( ) ;
2010-01-16 03:08:15 +03:00
ret = ldb_search ( samdb , mem_ctx , & r , dn , LDB_SCOPE_BASE , attrs , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
ouv_value = ldb_msg_find_ldb_val ( r - > msgs [ 0 ] , " replUpToDateVector " ) ;
2010-01-16 03:48:25 +03:00
if ( ouv_value ) {
enum ndr_err_code ndr_err ;
struct replUpToDateVectorBlob ouv ;
2010-05-09 19:20:01 +04:00
ndr_err = ndr_pull_struct_blob ( ouv_value , r , & ouv ,
2010-01-16 03:48:25 +03:00
( ndr_pull_flags_fn_t ) ndr_pull_replUpToDateVectorBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
talloc_free ( r ) ;
return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX ;
}
if ( ouv . version ! = 2 ) {
/* we always store as version 2, and
* replUpToDateVector is not replicated
*/
return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX ;
}
* count = ouv . ctr . ctr2 . count ;
* cursors = talloc_steal ( mem_ctx , ouv . ctr . ctr2 . cursors ) ;
} else {
2010-01-16 03:08:15 +03:00
* count = 0 ;
* cursors = NULL ;
2010-01-16 03:48:25 +03:00
}
talloc_free ( r ) ;
our_invocation_id = samdb_ntds_invocation_id ( samdb ) ;
if ( ! our_invocation_id ) {
DEBUG ( 0 , ( __location__ " : No invocationID on samdb - %s \n " , ldb_errstring ( samdb ) ) ) ;
talloc_free ( * cursors ) ;
2010-07-06 07:21:54 +04:00
return ldb_operr ( samdb ) ;
2010-01-16 03:48:25 +03:00
}
ret = dsdb_load_partition_usn ( samdb , dn , & highest_usn , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
/* nothing to add - this can happen after a vampire */
2010-02-13 04:59:43 +03:00
TYPESAFE_QSORT ( * cursors , * count , drsuapi_DsReplicaCursor2_compare ) ;
2010-01-16 03:08:15 +03:00
return LDB_SUCCESS ;
}
2010-01-16 03:48:25 +03:00
for ( i = 0 ; i < * count ; i + + ) {
if ( GUID_equal ( our_invocation_id , & ( * cursors ) [ i ] . source_dsa_invocation_id ) ) {
( * cursors ) [ i ] . highest_usn = highest_usn ;
( * cursors ) [ i ] . last_sync_success = timeval_to_nttime ( & now ) ;
2010-02-13 04:59:43 +03:00
TYPESAFE_QSORT ( * cursors , * count , drsuapi_DsReplicaCursor2_compare ) ;
2010-01-16 03:48:25 +03:00
return LDB_SUCCESS ;
}
2010-01-16 03:08:15 +03:00
}
2010-01-16 03:48:25 +03:00
( * cursors ) = talloc_realloc ( mem_ctx , * cursors , struct drsuapi_DsReplicaCursor2 , ( * count ) + 1 ) ;
if ( ! * cursors ) {
2010-07-06 07:21:54 +04:00
return ldb_oom ( samdb ) ;
2010-01-16 03:08:15 +03:00
}
2010-01-16 03:48:25 +03:00
( * cursors ) [ * count ] . source_dsa_invocation_id = * our_invocation_id ;
( * cursors ) [ * count ] . highest_usn = highest_usn ;
( * cursors ) [ * count ] . last_sync_success = timeval_to_nttime ( & now ) ;
( * count ) + + ;
2010-02-13 04:59:43 +03:00
TYPESAFE_QSORT ( * cursors , * count , drsuapi_DsReplicaCursor2_compare ) ;
2010-01-16 03:08:15 +03:00
return LDB_SUCCESS ;
}
/*
load the UDV for a partition in version 1 format
2010-01-16 03:48:25 +03:00
The list is returned sorted , and with our local cursor added
2010-01-16 03:08:15 +03:00
*/
int dsdb_load_udv_v1 ( struct ldb_context * samdb , struct ldb_dn * dn , TALLOC_CTX * mem_ctx ,
struct drsuapi_DsReplicaCursor * * cursors , uint32_t * count )
{
struct drsuapi_DsReplicaCursor2 * v2 ;
2010-06-01 00:04:29 +04:00
uint32_t i ;
2009-11-06 22:14:41 +03:00
int ret ;
2010-01-16 03:08:15 +03:00
ret = dsdb_load_udv_v2 ( samdb , dn , mem_ctx , & v2 , count ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
if ( * count = = 0 ) {
talloc_free ( v2 ) ;
* cursors = NULL ;
return LDB_SUCCESS ;
}
* cursors = talloc_array ( mem_ctx , struct drsuapi_DsReplicaCursor , * count ) ;
if ( * cursors = = NULL ) {
talloc_free ( v2 ) ;
2010-07-06 07:21:54 +04:00
return ldb_oom ( samdb ) ;
2010-01-16 03:08:15 +03:00
}
for ( i = 0 ; i < * count ; i + + ) {
( * cursors ) [ i ] . source_dsa_invocation_id = v2 [ i ] . source_dsa_invocation_id ;
( * cursors ) [ i ] . highest_usn = v2 [ i ] . highest_usn ;
}
talloc_free ( v2 ) ;
return LDB_SUCCESS ;
}
2010-02-15 09:38:16 +03:00
2010-02-16 06:23:21 +03:00
/*
add a set of controls to a ldb_request structure based on a set of
flags . See util . h for a list of available flags
*/
int dsdb_request_add_controls ( struct ldb_request * req , uint32_t dsdb_flags )
{
int ret ;
if ( dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS ) {
struct ldb_search_options_control * options ;
/* Using the phantom root control allows us to search all partitions */
options = talloc ( req , struct ldb_search_options_control ) ;
if ( options = = NULL ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
options - > search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT ;
ret = ldb_request_add_control ( req ,
LDB_CONTROL_SEARCH_OPTIONS_OID ,
true , options ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
if ( dsdb_flags & DSDB_SEARCH_SHOW_DELETED ) {
ret = ldb_request_add_control ( req , LDB_CONTROL_SHOW_DELETED_OID , true , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
if ( dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT ) {
ret = ldb_request_add_control ( req , DSDB_CONTROL_DN_STORAGE_FORMAT_OID , true , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
if ( dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN ) {
struct ldb_extended_dn_control * extended_ctrl = talloc ( req , struct ldb_extended_dn_control ) ;
if ( ! extended_ctrl ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
extended_ctrl - > type = 1 ;
ret = ldb_request_add_control ( req , LDB_CONTROL_EXTENDED_DN_OID , true , extended_ctrl ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
if ( dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS ) {
ret = ldb_request_add_control ( req , LDB_CONTROL_REVEAL_INTERNALS , false , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
if ( dsdb_flags & DSDB_MODIFY_RELAX ) {
ret = ldb_request_add_control ( req , LDB_CONTROL_RELAX_OID , false , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2010-02-16 06:29:07 +03:00
if ( dsdb_flags & DSDB_MODIFY_PERMISSIVE ) {
ret = ldb_request_add_control ( req , LDB_CONTROL_PERMISSIVE_MODIFY_OID , false , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2010-02-16 06:45:16 +03:00
if ( dsdb_flags & DSDB_FLAG_AS_SYSTEM ) {
ret = ldb_request_add_control ( req , LDB_CONTROL_AS_SYSTEM_OID , false , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2010-06-20 14:43:49 +04:00
if ( dsdb_flags & DSDB_TREE_DELETE ) {
ret = ldb_request_add_control ( req , LDB_CONTROL_TREE_DELETE_OID , false , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2010-02-16 06:23:21 +03:00
return LDB_SUCCESS ;
}
2010-02-16 06:29:07 +03:00
2010-08-05 23:58:57 +04:00
/*
an add with a set of controls
*/
int dsdb_add ( struct ldb_context * ldb , const struct ldb_message * message ,
uint32_t dsdb_flags )
{
struct ldb_request * req ;
int ret ;
ret = ldb_build_add_req ( & req , ldb , ldb ,
message ,
NULL ,
NULL ,
ldb_op_default_callback ,
NULL ) ;
if ( ret ! = LDB_SUCCESS ) return ret ;
ret = dsdb_request_add_controls ( req , dsdb_flags ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( req ) ;
return ret ;
}
ret = dsdb_autotransaction_request ( ldb , req ) ;
talloc_free ( req ) ;
return ret ;
}
2010-02-16 06:29:07 +03:00
/*
a modify with a set of controls
*/
int dsdb_modify ( struct ldb_context * ldb , const struct ldb_message * message ,
uint32_t dsdb_flags )
{
struct ldb_request * req ;
int ret ;
ret = ldb_build_mod_req ( & req , ldb , ldb ,
message ,
NULL ,
NULL ,
ldb_op_default_callback ,
NULL ) ;
if ( ret ! = LDB_SUCCESS ) return ret ;
ret = dsdb_request_add_controls ( req , dsdb_flags ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( req ) ;
return ret ;
}
2010-02-16 06:45:16 +03:00
ret = dsdb_autotransaction_request ( ldb , req ) ;
2010-02-16 06:29:07 +03:00
talloc_free ( req ) ;
return ret ;
}
2010-02-16 06:45:16 +03:00
/*
like dsdb_modify ( ) but set all the element flags to
LDB_FLAG_MOD_REPLACE
*/
int dsdb_replace ( struct ldb_context * ldb , struct ldb_message * msg , uint32_t dsdb_flags )
{
2009-11-06 22:14:41 +03:00
unsigned int i ;
2010-02-16 06:45:16 +03:00
/* mark all the message elements as LDB_FLAG_MOD_REPLACE */
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
msg - > elements [ i ] . flags = LDB_FLAG_MOD_REPLACE ;
}
return dsdb_modify ( ldb , msg , dsdb_flags ) ;
}
2010-02-16 06:55:19 +03:00
/*
search for attrs on one DN , allowing for dsdb_flags controls
*/
int dsdb_search_dn ( struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_result * * _res ,
struct ldb_dn * basedn ,
const char * const * attrs ,
uint32_t dsdb_flags )
{
int ret ;
struct ldb_request * req ;
struct ldb_result * res ;
res = talloc_zero ( mem_ctx , struct ldb_result ) ;
if ( ! res ) {
2010-07-06 07:21:54 +04:00
return ldb_oom ( ldb ) ;
2010-02-16 06:55:19 +03:00
}
ret = ldb_build_search_req ( & req , ldb , res ,
basedn ,
LDB_SCOPE_BASE ,
NULL ,
attrs ,
NULL ,
res ,
ldb_search_default_callback ,
NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( res ) ;
return ret ;
}
ret = dsdb_request_add_controls ( req , dsdb_flags ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( res ) ;
return ret ;
}
ret = ldb_request ( ldb , req ) ;
if ( ret = = LDB_SUCCESS ) {
ret = ldb_wait ( req - > handle , LDB_WAIT_ALL ) ;
}
talloc_free ( req ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( res ) ;
return ret ;
}
* _res = res ;
return LDB_SUCCESS ;
}
2010-02-16 07:15:35 +03:00
/*
general search with dsdb_flags for controls
*/
int dsdb_search ( struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_result * * _res ,
struct ldb_dn * basedn ,
enum ldb_scope scope ,
const char * const * attrs ,
uint32_t dsdb_flags ,
const char * exp_fmt , . . . ) _PRINTF_ATTRIBUTE ( 8 , 9 )
{
int ret ;
struct ldb_request * req ;
struct ldb_result * res ;
va_list ap ;
char * expression = NULL ;
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
res = talloc_zero ( tmp_ctx , struct ldb_result ) ;
if ( ! res ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 07:21:54 +04:00
return ldb_oom ( ldb ) ;
2010-02-16 07:15:35 +03:00
}
if ( exp_fmt ) {
va_start ( ap , exp_fmt ) ;
expression = talloc_vasprintf ( tmp_ctx , exp_fmt , ap ) ;
va_end ( ap ) ;
if ( ! expression ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 07:21:54 +04:00
return ldb_oom ( ldb ) ;
2010-02-16 07:15:35 +03:00
}
}
ret = ldb_build_search_req ( & req , ldb , tmp_ctx ,
basedn ,
scope ,
expression ,
attrs ,
NULL ,
res ,
ldb_search_default_callback ,
NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
ret = dsdb_request_add_controls ( req , dsdb_flags ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
ret = ldb_request ( ldb , req ) ;
if ( ret = = LDB_SUCCESS ) {
ret = ldb_wait ( req - > handle , LDB_WAIT_ALL ) ;
}
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2010-02-16 07:40:44 +03:00
if ( dsdb_flags & DSDB_SEARCH_ONE_ONLY ) {
if ( res - > count = = 0 ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_NO_SUCH_OBJECT ;
}
if ( res - > count ! = 1 ) {
talloc_free ( tmp_ctx ) ;
2010-02-16 08:39:49 +03:00
return LDB_ERR_CONSTRAINT_VIOLATION ;
2010-02-16 07:40:44 +03:00
}
}
2010-02-16 07:15:35 +03:00
* _res = talloc_steal ( mem_ctx , res ) ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2010-02-16 07:40:44 +03:00
/*
general search with dsdb_flags for controls
returns exactly 1 record or an error
*/
int dsdb_search_one ( struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_message * * msg ,
struct ldb_dn * basedn ,
enum ldb_scope scope ,
const char * const * attrs ,
uint32_t dsdb_flags ,
const char * exp_fmt , . . . ) _PRINTF_ATTRIBUTE ( 8 , 9 )
{
int ret ;
struct ldb_result * res ;
va_list ap ;
char * expression = NULL ;
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
dsdb_flags | = DSDB_SEARCH_ONE_ONLY ;
res = talloc_zero ( tmp_ctx , struct ldb_result ) ;
if ( ! res ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 07:21:54 +04:00
return ldb_oom ( ldb ) ;
2010-02-16 07:40:44 +03:00
}
if ( exp_fmt ) {
va_start ( ap , exp_fmt ) ;
expression = talloc_vasprintf ( tmp_ctx , exp_fmt , ap ) ;
va_end ( ap ) ;
if ( ! expression ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 07:21:54 +04:00
return ldb_oom ( ldb ) ;
2010-02-16 07:40:44 +03:00
}
2010-05-21 02:11:13 +04:00
ret = dsdb_search ( ldb , tmp_ctx , & res , basedn , scope , attrs ,
dsdb_flags , " %s " , expression ) ;
} else {
ret = dsdb_search ( ldb , tmp_ctx , & res , basedn , scope , attrs ,
dsdb_flags , NULL ) ;
2010-02-16 07:40:44 +03:00
}
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
* msg = talloc_steal ( mem_ctx , res - > msgs [ 0 ] ) ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2010-04-12 16:15:34 +04:00
/* returns back the forest DNS name */
const char * samdb_forest_name ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx )
{
const char * forest_name = ldb_dn_canonical_string ( mem_ctx ,
ldb_get_root_basedn ( ldb ) ) ;
char * p ;
if ( forest_name = = NULL ) {
return NULL ;
}
p = strchr ( forest_name , ' / ' ) ;
if ( p ) {
* p = ' \0 ' ;
}
return forest_name ;
}
2010-04-22 08:54:52 +04:00
/*
2010-04-26 01:22:53 +04:00
validate that an DSA GUID belongs to the specified user sid .
2010-04-22 08:54:52 +04:00
The user SID must be a domain controller account ( either RODC or
RWDC )
*/
2010-04-26 01:22:53 +04:00
int dsdb_validate_dsa_guid ( struct ldb_context * ldb ,
const struct GUID * dsa_guid ,
const struct dom_sid * sid )
2010-04-22 08:54:52 +04:00
{
/* strategy:
2010-04-26 01:22:53 +04:00
- find DN of record with the DSA GUID in the
configuration partition ( objectGUID )
- remove " NTDS Settings " component from DN
2010-04-22 08:54:52 +04:00
- do a base search on that DN for serverReference with
extended - dn enabled
- extract objectSID from resulting serverReference
attribute
- check this sid matches the sid argument
*/
struct ldb_dn * config_dn ;
TALLOC_CTX * tmp_ctx = talloc_new ( ldb ) ;
struct ldb_message * msg ;
const char * attrs1 [ ] = { NULL } ;
const char * attrs2 [ ] = { " serverReference " , NULL } ;
int ret ;
struct ldb_dn * dn , * account_dn ;
struct dom_sid sid2 ;
NTSTATUS status ;
config_dn = ldb_get_config_basedn ( ldb ) ;
ret = dsdb_search_one ( ldb , tmp_ctx , & msg , config_dn , LDB_SCOPE_SUBTREE ,
2010-04-26 01:22:53 +04:00
attrs1 , 0 , " (&(objectGUID=%s)(objectClass=nTDSDSA)) " , GUID_string ( tmp_ctx , dsa_guid ) ) ;
2010-04-22 08:54:52 +04:00
if ( ret ! = LDB_SUCCESS ) {
2010-04-26 01:22:53 +04:00
DEBUG ( 1 , ( __location__ " : Failed to find DSA objectGUID %s for sid %s \n " ,
GUID_string ( tmp_ctx , dsa_guid ) , dom_sid_string ( tmp_ctx , sid ) ) ) ;
2010-04-22 08:54:52 +04:00
talloc_free ( tmp_ctx ) ;
2010-07-06 07:21:54 +04:00
return ldb_operr ( ldb ) ;
2010-04-22 08:54:52 +04:00
}
dn = msg - > dn ;
if ( ! ldb_dn_remove_child_components ( dn , 1 ) ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 07:21:54 +04:00
return ldb_operr ( ldb ) ;
2010-04-22 08:54:52 +04:00
}
ret = dsdb_search_one ( ldb , tmp_ctx , & msg , dn , LDB_SCOPE_BASE ,
attrs2 , DSDB_SEARCH_SHOW_EXTENDED_DN ,
" (objectClass=server) " ) ;
if ( ret ! = LDB_SUCCESS ) {
2010-04-26 01:22:53 +04:00
DEBUG ( 1 , ( __location__ " : Failed to find server record for DSA with objectGUID %s, sid %s \n " ,
GUID_string ( tmp_ctx , dsa_guid ) , dom_sid_string ( tmp_ctx , sid ) ) ) ;
2010-04-22 08:54:52 +04:00
talloc_free ( tmp_ctx ) ;
2010-07-06 07:21:54 +04:00
return ldb_operr ( ldb ) ;
2010-04-22 08:54:52 +04:00
}
account_dn = ldb_msg_find_attr_as_dn ( ldb , tmp_ctx , msg , " serverReference " ) ;
if ( account_dn = = NULL ) {
2010-04-26 01:22:53 +04:00
DEBUG ( 1 , ( __location__ " : Failed to find account_dn for DSA with objectGUID %s, sid %s \n " ,
GUID_string ( tmp_ctx , dsa_guid ) , dom_sid_string ( tmp_ctx , sid ) ) ) ;
2010-04-22 08:54:52 +04:00
talloc_free ( tmp_ctx ) ;
2010-07-06 07:21:54 +04:00
return ldb_operr ( ldb ) ;
2010-04-22 08:54:52 +04:00
}
status = dsdb_get_extended_dn_sid ( account_dn , & sid2 , " SID " ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-04-26 01:22:53 +04:00
DEBUG ( 1 , ( __location__ " : Failed to find SID for DSA with objectGUID %s, sid %s \n " ,
GUID_string ( tmp_ctx , dsa_guid ) , dom_sid_string ( tmp_ctx , sid ) ) ) ;
2010-04-22 08:54:52 +04:00
talloc_free ( tmp_ctx ) ;
2010-07-06 07:21:54 +04:00
return ldb_operr ( ldb ) ;
2010-04-22 08:54:52 +04:00
}
if ( ! dom_sid_equal ( sid , & sid2 ) ) {
/* someone is trying to spoof another account */
2010-04-26 01:22:53 +04:00
DEBUG ( 0 , ( __location__ " : Bad DSA objectGUID %s for sid %s - expected sid %s \n " ,
GUID_string ( tmp_ctx , dsa_guid ) ,
2010-04-22 08:54:52 +04:00
dom_sid_string ( tmp_ctx , sid ) ,
dom_sid_string ( tmp_ctx , & sid2 ) ) ) ;
talloc_free ( tmp_ctx ) ;
2010-07-06 07:21:54 +04:00
return ldb_operr ( ldb ) ;
2010-04-22 08:54:52 +04:00
}
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2010-04-26 10:56:59 +04:00
const char * rodc_fas_list [ ] = { " ms-PKI-DPAPIMasterKeys " ,
" ms-PKI-AccountCredentials " ,
" ms-PKI-RoamingTimeStamp " ,
" ms-FVE-KeyPackage " ,
" ms-FVE-RecoveryGuid " ,
" ms-FVE-RecoveryInformation " ,
" ms-FVE-RecoveryPassword " ,
" ms-FVE-VolumeGuid " ,
" ms-TPM-OwnerInformation " ,
NULL } ;
/*
check if the attribute belongs to the RODC filtered attribute set
*/
bool dsdb_attr_in_rodc_fas ( uint32_t replica_flags , const struct dsdb_attribute * sa )
{
int rodc_filtered_flags = SEARCH_FLAG_RODC_ATTRIBUTE | SEARCH_FLAG_CONFIDENTIAL ;
bool drs_write_replica = ( ( replica_flags & DRSUAPI_DRS_WRIT_REP ) = = 0 ) ;
if ( drs_write_replica & & ( sa - > searchFlags & rodc_filtered_flags ) ) {
return true ;
}
if ( drs_write_replica & & is_attr_in_list ( rodc_fas_list , sa - > cn ) ) {
return true ;
}
return false ;
}