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"
# 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"
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 ;
}
2008-01-02 07:05:13 +03:00
ndr_err = ndr_pull_struct_blob ( v , sid , NULL , 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 )
{
uint64_t attr_time = samdb_result_uint64 ( msg , " pwdLastSet " , 0 ) ;
2008-02-29 03:03:31 +03:00
uint32_t userAccountControl = samdb_result_uint64 ( 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 ;
}
maxPwdAge = samdb_search_int64 ( sam_ldb , mem_ctx , 0 , domain_dn , " maxPwdAge " , NULL ) ;
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 ;
}
2008-10-16 05:48:16 +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 */
if ( lp_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 ;
const int units_per_week = 168 ;
const struct ldb_val * val = ldb_msg_find_ldb_val ( msg , attr ) ;
ZERO_STRUCT ( hours ) ;
hours . bits = talloc_array ( mem_ctx , uint8_t , units_per_week ) ;
if ( ! hours . bits ) {
return hours ;
}
hours . units_per_week = units_per_week ;
memset ( hours . bits , 0xFF , units_per_week ) ;
if ( val ) {
memcpy ( hours . bits , val - > data , MIN ( val - > length , units_per_week ) ) ;
}
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 ;
}
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 ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
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 ,
lp_iconv_convenience ( ldb_get_opaque ( sam_ldb , " loadparm " ) ) ,
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-02-17 20:24:03 +03:00
return LDB_ERR_OPERATIONS_ERROR ;
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 ) ;
}
/*
add a add attribute value to a message
*/
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 )
{
struct ldb_message_element * el ;
char * a , * v ;
int ret ;
a = talloc_strdup ( mem_ctx , attr_name ) ;
if ( a = = NULL )
2010-02-17 20:24:03 +03:00
return LDB_ERR_OPERATIONS_ERROR ;
2007-12-17 06:22:44 +03:00
v = talloc_strdup ( mem_ctx , value ) ;
if ( v = = NULL )
2010-02-17 20:24:03 +03:00
return LDB_ERR_OPERATIONS_ERROR ;
2007-12-17 06:22:44 +03:00
ret = ldb_msg_add_string ( msg , a , v ) ;
if ( ret ! = 0 )
return ret ;
el = ldb_msg_find_element ( msg , a ) ;
if ( el = = NULL )
2010-02-17 20:24:03 +03:00
return LDB_ERR_OPERATIONS_ERROR ;
2007-12-17 06:22:44 +03:00
el - > flags = LDB_FLAG_MOD_ADD ;
2010-02-17 20:24:03 +03:00
return LDB_SUCCESS ;
2007-12-17 06:22:44 +03:00
}
/*
add a delete attribute value to a message
*/
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 )
{
struct ldb_message_element * el ;
char * a , * v ;
int ret ;
a = talloc_strdup ( mem_ctx , attr_name ) ;
if ( a = = NULL )
2010-02-17 20:24:03 +03:00
return LDB_ERR_OPERATIONS_ERROR ;
2007-12-17 06:22:44 +03:00
v = talloc_strdup ( mem_ctx , value ) ;
if ( v = = NULL )
2010-02-17 20:24:03 +03:00
return LDB_ERR_OPERATIONS_ERROR ;
2007-12-17 06:22:44 +03:00
ret = ldb_msg_add_string ( msg , a , v ) ;
if ( ret ! = 0 )
return ret ;
el = ldb_msg_find_element ( msg , a ) ;
if ( el = = NULL )
2010-02-17 20:24:03 +03:00
return LDB_ERR_OPERATIONS_ERROR ;
2007-12-17 06:22:44 +03:00
el - > flags = LDB_FLAG_MOD_DELETE ;
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-02-17 20:24:03 +03:00
return LDB_ERR_OPERATIONS_ERROR ;
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
*/
int samdb_msg_add_hashes ( 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-02-17 20:24:03 +03:00
return LDB_ERR_OPERATIONS_ERROR ;
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
}
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 ) ;
2007-12-17 06:22:44 +03:00
if ( ret ) {
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 ) ;
2008-01-03 13:40:24 +03:00
if ( ret ) {
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 ;
int ret = 0 ;
const char * attrs [ ] = { NULL } ;
local_ctx = talloc_new ( mem_ctx ) ;
if ( local_ctx = = NULL ) return LDB_ERR_OPERATIONS_ERROR ;
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 ;
}
/*
* 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 .
*
* The caller should have a LDB transaction wrapping this .
*
* Results : NT_STATUS_OK , NT_STATUS_INTERNAL_DB_CORRUPTION ,
* NT_STATUS_INVALID_PARAMETER , NT_STATUS_UNSUCCESSFUL ,
* NT_STATUS_PASSWORD_RESTRICTION
*/
2008-04-02 06:53:27 +04:00
NTSTATUS samdb_set_password ( struct ldb_context * ctx , TALLOC_CTX * mem_ctx ,
2009-10-24 21:31:01 +04:00
struct ldb_dn * user_dn , struct ldb_dn * domain_dn ,
2007-12-17 06:22:44 +03:00
struct ldb_message * mod ,
2008-10-16 05:48:16 +04:00
const DATA_BLOB * new_password ,
2009-08-19 13:58:42 +04:00
struct samr_Password * param_lmNewHash ,
struct samr_Password * param_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-23 21:23:17 +04:00
const char * const user_attrs [ ] = { " userAccountControl " ,
" lmPwdHistory " ,
2007-12-17 06:22:44 +03:00
" ntPwdHistory " ,
" dBCSPwd " , " unicodePwd " ,
" objectSid " ,
" pwdLastSet " , NULL } ;
2009-09-23 21:23:17 +04:00
const char * const domain_attrs [ ] = { " minPwdLength " , " pwdProperties " ,
" pwdHistoryLength " ,
" maxPwdAge " , " minPwdAge " , NULL } ;
2007-12-17 06:22:44 +03:00
NTTIME pwdLastSet ;
2009-09-23 21:23:17 +04:00
uint32_t minPwdLength , pwdProperties , pwdHistoryLength ;
2009-09-25 20:03:31 +04:00
int64_t maxPwdAge , minPwdAge ;
2009-09-23 21:23:17 +04:00
uint32_t userAccountControl ;
2009-08-19 13:58:42 +04:00
struct samr_Password * sambaLMPwdHistory , * sambaNTPwdHistory ,
* lmPwdHash , * ntPwdHash , * lmNewHash , * ntNewHash ;
2007-12-17 06:22:44 +03:00
struct samr_Password local_lmNewHash , local_ntNewHash ;
int sambaLMPwdHistory_len , sambaNTPwdHistory_len ;
struct dom_sid * domain_sid ;
struct ldb_message * * res ;
bool restrictions ;
int count ;
time_t now = time ( NULL ) ;
NTTIME now_nt ;
2009-11-06 22:14:41 +03:00
unsigned int i ;
2007-12-17 06:22:44 +03:00
/* we need to know the time to compute password age */
unix_to_nt_time ( & now_nt , now ) ;
/* pull all the user parameters */
count = gendb_search_dn ( ctx , mem_ctx , user_dn , & res , user_attrs ) ;
if ( count ! = 1 ) {
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
2009-09-23 21:23:17 +04:00
userAccountControl = samdb_result_uint ( res [ 0 ] , " userAccountControl " , 0 ) ;
sambaLMPwdHistory_len = samdb_result_hashes ( mem_ctx , res [ 0 ] ,
" lmPwdHistory " , & sambaLMPwdHistory ) ;
sambaNTPwdHistory_len = samdb_result_hashes ( mem_ctx , res [ 0 ] ,
" ntPwdHistory " , & sambaNTPwdHistory ) ;
lmPwdHash = samdb_result_hash ( mem_ctx , res [ 0 ] , " dBCSPwd " ) ;
ntPwdHash = samdb_result_hash ( mem_ctx , res [ 0 ] , " unicodePwd " ) ;
pwdLastSet = samdb_result_uint64 ( res [ 0 ] , " pwdLastSet " , 0 ) ;
2007-12-17 06:22:44 +03:00
2009-08-19 13:58:42 +04:00
/* Copy parameters */
lmNewHash = param_lmNewHash ;
ntNewHash = param_ntNewHash ;
2007-12-17 06:22:44 +03:00
/* Only non-trust accounts have restrictions (possibly this
* test is the wrong way around , but I like to be restrictive
* if possible */
restrictions = ! ( userAccountControl & ( UF_INTERDOMAIN_TRUST_ACCOUNT
| UF_WORKSTATION_TRUST_ACCOUNT
| UF_SERVER_TRUST_ACCOUNT ) ) ;
2009-09-23 21:23:17 +04:00
if ( domain_dn ! = NULL ) {
2007-12-17 06:22:44 +03:00
/* pull the domain parameters */
2009-09-23 21:23:17 +04:00
count = gendb_search_dn ( ctx , mem_ctx , domain_dn , & res ,
domain_attrs ) ;
2007-12-17 06:22:44 +03:00
if ( count ! = 1 ) {
DEBUG ( 2 , ( " samdb_set_password: Domain DN %s is invalid, for user %s \n " ,
ldb_dn_get_linearized ( domain_dn ) ,
ldb_dn_get_linearized ( user_dn ) ) ) ;
return NT_STATUS_NO_SUCH_DOMAIN ;
}
} else {
/* work out the domain sid, and pull the domain from there */
2009-09-23 21:23:17 +04:00
domain_sid = samdb_result_sid_prefix ( mem_ctx , res [ 0 ] ,
" objectSid " ) ;
2007-12-17 06:22:44 +03:00
if ( domain_sid = = NULL ) {
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
count = gendb_search ( ctx , mem_ctx , NULL , & res , domain_attrs ,
2009-09-23 21:23:17 +04:00
" (objectSid=%s) " ,
ldap_encode_ndr_dom_sid ( mem_ctx , domain_sid ) ) ;
2007-12-17 06:22:44 +03:00
if ( count ! = 1 ) {
DEBUG ( 2 , ( " samdb_set_password: Could not find domain to match SID: %s, for user %s \n " ,
dom_sid_string ( mem_ctx , domain_sid ) ,
ldb_dn_get_linearized ( user_dn ) ) ) ;
return NT_STATUS_NO_SUCH_DOMAIN ;
}
}
2009-09-23 21:23:17 +04:00
minPwdLength = samdb_result_uint ( res [ 0 ] , " minPwdLength " , 0 ) ;
pwdProperties = samdb_result_uint ( res [ 0 ] , " pwdProperties " , 0 ) ;
pwdHistoryLength = samdb_result_uint ( res [ 0 ] , " pwdHistoryLength " , 0 ) ;
2009-09-25 20:03:31 +04:00
maxPwdAge = samdb_result_int64 ( res [ 0 ] , " maxPwdAge " , 0 ) ;
2009-09-23 21:23:17 +04:00
minPwdAge = samdb_result_int64 ( res [ 0 ] , " minPwdAge " , 0 ) ;
2007-12-17 06:22:44 +03:00
2009-09-23 21:23:17 +04:00
if ( ( userAccountControl & UF_PASSWD_NOTREQD ) ! = 0 ) {
2009-05-25 09:23:54 +04:00
/* see [MS-ADTS] 2.2.15 */
minPwdLength = 0 ;
}
2009-09-23 21:23:17 +04:00
if ( _dominfo ! = NULL ) {
2007-12-17 06:22:44 +03:00
struct samr_DomInfo1 * dominfo ;
/* on failure we need to fill in the reject reasons */
dominfo = talloc ( mem_ctx , struct samr_DomInfo1 ) ;
if ( dominfo = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
dominfo - > min_password_length = minPwdLength ;
dominfo - > password_properties = pwdProperties ;
dominfo - > password_history_length = pwdHistoryLength ;
2009-09-25 20:03:31 +04:00
dominfo - > max_password_age = maxPwdAge ;
2007-12-17 06:22:44 +03:00
dominfo - > min_password_age = minPwdAge ;
* _dominfo = dominfo ;
}
2009-09-23 21:23:17 +04:00
if ( ( restrictions ! = 0 ) & & ( new_password ! = 0 ) ) {
2008-10-16 05:48:16 +04:00
char * new_pass ;
2009-05-31 18:19:11 +04:00
2009-09-23 21:23:17 +04:00
/* checks if the "minPwdLength" property is satisfied */
if ( ( restrictions ! = 0 )
& & ( minPwdLength > utf16_len_n (
new_password - > data , new_password - > length ) / 2 ) ) {
2007-12-17 06:22:44 +03:00
if ( reject_reason ) {
2009-09-26 00:44:00 +04:00
* reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT ;
2007-12-17 06:22:44 +03:00
}
return NT_STATUS_PASSWORD_RESTRICTION ;
}
2008-10-16 05:48:16 +04:00
/* Create the NT hash */
2009-09-23 21:23:17 +04:00
mdfour ( local_ntNewHash . hash , new_password - > data ,
new_password - > length ) ;
2009-05-31 18:19:11 +04:00
2008-10-16 05:48:16 +04:00
ntNewHash = & local_ntNewHash ;
/* Only check complexity if we can convert it at all. Assuming unconvertable passwords are 'strong' */
2009-08-19 10:59:58 +04:00
if ( convert_string_talloc_convenience ( mem_ctx ,
lp_iconv_convenience ( ldb_get_opaque ( ctx , " loadparm " ) ) ,
CH_UTF16 , CH_UNIX ,
new_password - > data , new_password - > length ,
( void * * ) & new_pass , NULL , false ) ) {
2009-05-31 18:19:11 +04:00
2009-09-23 21:23:17 +04:00
/* checks the password complexity */
if ( ( restrictions ! = 0 )
& & ( ( pwdProperties
& DOMAIN_PASSWORD_COMPLEX ) ! = 0 )
& & ( ! check_password_quality ( new_pass ) ) ) {
2008-10-16 05:48:16 +04:00
if ( reject_reason ) {
2009-09-26 00:44:00 +04:00
* reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX ;
2008-10-16 05:48:16 +04:00
}
return NT_STATUS_PASSWORD_RESTRICTION ;
2007-12-17 06:22:44 +03:00
}
2009-05-31 18:19:11 +04:00
2008-10-16 05:48:16 +04:00
/* compute the new lm hashes (for checking history - case insenitivly!) */
if ( E_deshash ( new_pass , local_lmNewHash . hash ) ) {
lmNewHash = & local_lmNewHash ;
2007-12-17 06:22:44 +03:00
}
}
}
2009-09-23 21:23:17 +04:00
if ( ( restrictions ! = 0 ) & & user_change ) {
2007-12-17 06:22:44 +03:00
/* are all password changes disallowed? */
2009-09-23 21:23:17 +04:00
if ( ( pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE ) ! = 0 ) {
2007-12-17 06:22:44 +03:00
if ( reject_reason ) {
2009-09-26 00:44:00 +04:00
* reject_reason = SAM_PWD_CHANGE_NO_ERROR ;
2007-12-17 06:22:44 +03:00
}
return NT_STATUS_PASSWORD_RESTRICTION ;
}
2009-05-31 18:19:11 +04:00
2009-09-23 21:23:17 +04:00
/* can this user change the password? */
if ( ( userAccountControl & UF_PASSWD_CANT_CHANGE ) ! = 0 ) {
2007-12-17 06:22:44 +03:00
if ( reject_reason ) {
2009-09-26 00:44:00 +04:00
* reject_reason = SAM_PWD_CHANGE_NO_ERROR ;
2007-12-17 06:22:44 +03:00
}
return NT_STATUS_PASSWORD_RESTRICTION ;
}
2009-05-31 18:19:11 +04:00
2009-09-23 21:23:17 +04:00
/* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
2007-12-17 06:22:44 +03:00
if ( pwdLastSet - minPwdAge > now_nt ) {
if ( reject_reason ) {
2009-09-26 00:44:00 +04:00
* reject_reason = SAM_PWD_CHANGE_NO_ERROR ;
2007-12-17 06:22:44 +03:00
}
return NT_STATUS_PASSWORD_RESTRICTION ;
}
/* check the immediately past password */
if ( pwdHistoryLength > 0 ) {
2009-09-23 21:23:17 +04:00
if ( lmNewHash & & lmPwdHash & & memcmp ( lmNewHash - > hash ,
lmPwdHash - > hash , 16 ) = = 0 ) {
2007-12-17 06:22:44 +03:00
if ( reject_reason ) {
2009-09-26 00:44:00 +04:00
* reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY ;
2007-12-17 06:22:44 +03:00
}
return NT_STATUS_PASSWORD_RESTRICTION ;
}
2009-09-23 21:23:17 +04:00
if ( ntNewHash & & ntPwdHash & & memcmp ( ntNewHash - > hash ,
ntPwdHash - > hash , 16 ) = = 0 ) {
2007-12-17 06:22:44 +03:00
if ( reject_reason ) {
2009-09-26 00:44:00 +04:00
* reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY ;
2007-12-17 06:22:44 +03:00
}
return NT_STATUS_PASSWORD_RESTRICTION ;
}
}
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
/* check the password history */
2009-09-23 21:23:17 +04:00
sambaLMPwdHistory_len = MIN ( sambaLMPwdHistory_len ,
pwdHistoryLength ) ;
sambaNTPwdHistory_len = MIN ( sambaNTPwdHistory_len ,
pwdHistoryLength ) ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
for ( i = 0 ; lmNewHash & & i < sambaLMPwdHistory_len ; i + + ) {
2009-09-23 21:23:17 +04:00
if ( memcmp ( lmNewHash - > hash , sambaLMPwdHistory [ i ] . hash ,
16 ) = = 0 ) {
2007-12-17 06:22:44 +03:00
if ( reject_reason ) {
2009-09-26 00:44:00 +04:00
* reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY ;
2007-12-17 06:22:44 +03:00
}
return NT_STATUS_PASSWORD_RESTRICTION ;
}
}
for ( i = 0 ; ntNewHash & & i < sambaNTPwdHistory_len ; i + + ) {
2009-09-23 21:23:17 +04:00
if ( memcmp ( ntNewHash - > hash , sambaNTPwdHistory [ i ] . hash ,
16 ) = = 0 ) {
2007-12-17 06:22:44 +03:00
if ( reject_reason ) {
2009-09-26 00:44:00 +04:00
* reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY ;
2007-12-17 06:22:44 +03:00
}
return NT_STATUS_PASSWORD_RESTRICTION ;
}
}
}
# define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
/* the password is acceptable. Start forming the new fields */
2009-09-23 21:23:17 +04:00
if ( new_password ! = NULL ) {
2008-10-16 05:48:16 +04:00
/* if we know the cleartext UTF16 password, then set it.
2007-12-17 06:22:44 +03:00
* Modules in ldb will set all the appropriate
* hashes */
2008-10-16 05:48:16 +04:00
CHECK_RET ( ldb_msg_add_value ( mod , " clearTextPassword " , new_password , NULL ) ) ;
2007-12-17 06:22:44 +03:00
} else {
2009-12-17 21:41:11 +03:00
/* we don't have the cleartext, so set what we have of the
* hashes */
2007-12-17 06:22:44 +03:00
if ( lmNewHash ) {
CHECK_RET ( samdb_msg_add_hash ( ctx , mem_ctx , mod , " dBCSPwd " , lmNewHash ) ) ;
}
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
if ( ntNewHash ) {
CHECK_RET ( samdb_msg_add_hash ( ctx , mem_ctx , mod , " unicodePwd " , ntNewHash ) ) ;
}
}
2009-09-26 00:44:00 +04:00
if ( reject_reason ) {
* reject_reason = SAM_PWD_CHANGE_NO_ERROR ;
}
2007-12-17 06:22:44 +03:00
return NT_STATUS_OK ;
}
/*
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 ,
* NT_STATUS_PASSWORD_RESTRICTION
*/
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 ;
struct ldb_message * msg ;
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 ;
}
msg = ldb_msg_new ( mem_ctx ) ;
if ( msg = = NULL ) {
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_NO_MEMORY ;
}
msg - > dn = ldb_dn_copy ( msg , user_dn ) ;
if ( ! msg - > dn ) {
2009-10-24 21:31:01 +04:00
ldb_transaction_cancel ( ldb ) ;
2009-12-13 18:13:34 +03:00
talloc_free ( user_dn ) ;
talloc_free ( msg ) ;
2007-12-17 06:22:44 +03:00
return NT_STATUS_NO_MEMORY ;
}
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-10-24 21:31:01 +04:00
msg , 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 ) ;
talloc_free ( msg ) ;
2007-12-17 06:22:44 +03:00
return nt_status ;
}
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
/* modify the samdb record */
2010-02-16 06:45:16 +03:00
ret = dsdb_replace ( ldb , msg , 0 ) ;
2009-10-24 21:31:01 +04:00
if ( ret ! = LDB_SUCCESS ) {
ldb_transaction_cancel ( ldb ) ;
2009-12-13 18:13:34 +03:00
talloc_free ( user_dn ) ;
talloc_free ( msg ) ;
2007-12-17 06:22:44 +03:00
return NT_STATUS_ACCESS_DENIED ;
}
2009-12-13 18:13:34 +03:00
talloc_free ( msg ) ;
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 ) ;
if ( ret_domain ! = 0 ) {
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) " ) ;
if ( ret_domain ! = 0 ) {
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 ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
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 ;
}
2009-09-12 05:09:10 +04:00
2010-04-16 00:38:47 +04:00
int dsdb_validate_client_flags ( struct ldb_context * ldb ,
const struct repsFromTo1 * client_rf )
{
int ret ;
TALLOC_CTX * tmp_ctx = talloc_new ( ldb ) ;
if ( client_rf - > replica_flags & DRSUAPI_DRS_WRIT_REP ) {
bool is_rodc ;
ret = samdb_is_rodc ( ldb , & client_rf - > source_dsa_invocation_id , & is_rodc ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
if ( is_rodc ) {
DEBUG ( 0 , ( " Client %s claimed to be WRIT_REP, but is RODC \n " ,
GUID_string ( tmp_ctx , & client_rf - > source_dsa_invocation_id ) ) ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
}
/* TODO: we may need to validate more client flags here, if they
are security sensitive */
talloc_free ( tmp_ctx ) ;
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 ] ,
mem_ctx , lp_iconv_convenience ( ldb_get_opaque ( sam_ctx , " loadparm " ) ) ,
& ( * 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 ;
ndr_err = ndr_push_struct_blob ( & v , tmp_ctx , lp_iconv_convenience ( ldb_get_opaque ( sam_ctx , " loadparm " ) ) ,
& 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 ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
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 ) {
talloc_free ( res ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
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-16 00:37:40 +04:00
int samdb_is_rodc ( struct ldb_context * sam_ctx , const struct GUID * invocationId , bool * is_rodc )
{
/* 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 ) ;
return LDB_ERR_OPERATIONS_ERROR ;
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 ,
DSDB_SEARCH_ONE_ONLY , " invocationID=%s " , GUID_string ( tmp_ctx , invocationId ) ) ;
if ( ret ! = LDB_SUCCESS ) {
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 )
{
const struct GUID * invocationId ;
invocationId = samdb_ntds_invocation_id ( sam_ctx ) ;
if ( ! invocationId ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
return samdb_is_rodc ( sam_ctx , invocationId , am_rodc ) ;
2010-03-01 15:16:59 +03:00
}
2009-10-13 12:48:13 +04:00
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 ) ;
if ( ret ) {
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 ) ;
if ( ret ) {
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
/*
return domain functional level
returns DS_DOMAIN_FUNCTION_ *
*/
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 ;
}
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 ) ;
ndr_err = ndr_pull_struct_blob_all ( sid_blob , tmp_ctx , NULL , sid ,
( 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
*/
uint32_t dsdb_dn_val_rmd_flags ( struct ldb_val * val )
{
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
*/
bool dsdb_dn_is_deleted_val ( struct ldb_val * val )
{
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 ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
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 ;
int i ;
struct ldb_dn * * nc_dns ;
tmp_ctx = talloc_new ( samdb ) ;
if ( tmp_ctx = = NULL ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
ret = ldb_search ( samdb , tmp_ctx , & root_res ,
ldb_dn_new ( tmp_ctx , samdb , " " ) , LDB_SCOPE_BASE , root_attrs , NULL ) ;
if ( ret ) {
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 ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
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 ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
}
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 ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
/* 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 ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
* 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 ;
ndr_err = ndr_pull_struct_blob ( ouv_value , r ,
lp_iconv_convenience ( ldb_get_opaque ( samdb , " loadparm " ) ) , & ouv ,
( 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 ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
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 ) {
return LDB_ERR_OPERATIONS_ERROR ;
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 ;
2009-11-06 22:14:41 +03:00
unsigned int i ;
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 ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
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-02-16 06:23:21 +03:00
return LDB_SUCCESS ;
}
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 ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
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 ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
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 ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
}
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 ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
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 ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
}
ret = dsdb_search ( ldb , tmp_ctx , & res , basedn , scope , attrs ,
dsdb_flags , " %s " , expression ) ;
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 ;
}