2007-12-17 04:22:44 +01: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 16:19:11 +02:00
2007-12-17 04:22:44 +01:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
2009-05-31 16:19:11 +02:00
2007-12-17 04:22:44 +01: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 16:19:11 +02:00
2007-12-17 04:22:44 +01: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 13:40:18 +01:00
# include "events/events.h"
2007-12-17 04:22:44 +01:00
# include "ldb.h"
2010-07-06 13:21:54 +10:00
# include "ldb_module.h"
2007-12-17 04:22:44 +01:00
# include "ldb_errors.h"
2010-10-17 14:27:18 +02:00
# include "../lib/util/util_ldb.h"
2008-10-16 12:48:16 +11:00
# include "../lib/crypto/crypto.h"
2007-12-17 04:22:44 +01:00
# include "dsdb/samdb/samdb.h"
# include "libcli/security/security.h"
# include "librpc/gen_ndr/ndr_security.h"
2008-04-02 04:53:27 +02:00
# include "librpc/gen_ndr/ndr_misc.h"
2009-06-12 14:27:19 +02:00
# include "../libds/common/flags.h"
2007-12-17 04:22:44 +01:00
# include "dsdb/common/proto.h"
# include "libcli/ldap/ldap_ndr.h"
2008-01-01 22:05:05 -06:00
# include "param/param.h"
2007-12-17 04:22:44 +01:00
# include "libcli/auth/libcli_auth.h"
2009-09-12 11:09:10 +10:00
# include "librpc/gen_ndr/ndr_drsblobs.h"
2009-11-14 20:12:42 +01:00
# include "system/locale.h"
2016-07-05 10:56:24 +02:00
# include "system/filesys.h"
2010-02-13 12:59:43 +11:00
# include "lib/util/tsort.h"
2010-02-16 14:23:21 +11:00
# include "dsdb/common/util.h"
2010-04-13 18:28:53 +02:00
# include "lib/socket/socket.h"
2010-09-20 09:44:19 -07:00
# include "librpc/gen_ndr/irpc.h"
2011-02-24 11:23:53 +11:00
# include "libds/common/flag_mapping.h"
2016-11-10 20:33:17 -08:00
# include "lib/util/access.h"
2018-03-22 16:49:29 +13:00
# include "lib/util/util_str_hex.h"
# include "libcli/util/ntstatus.h"
2007-12-17 04:22:44 +01:00
2017-06-14 13:12:32 +12:00
/*
* This included to allow us to handle DSDB_FLAG_REPLICATED_UPDATE in
* dsdb_request_add_controls ( )
*/
# include "dsdb/samdb/ldb_modules/util.h"
2018-11-13 13:22:41 +13:00
/* default is 30 minutes: -1e7 * 30 * 60 */
# define DEFAULT_OBSERVATION_WINDOW -18000000000
2007-12-17 04:22:44 +01: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 ;
}
2010-10-14 09:41:42 +02:00
return ldb_msg_find_attr_as_string ( res [ 0 ] , attr_name , NULL ) ;
2007-12-17 04:22:44 +01:00
}
/*
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 ;
}
/*
search the sam for a single integer attribute in exactly 1 record
*/
2010-01-05 09:42:54 -08:00
unsigned int samdb_search_uint ( struct ldb_context * sam_ldb ,
2007-12-17 04:22:44 +01:00
TALLOC_CTX * mem_ctx ,
2010-01-05 09:42:54 -08:00
unsigned int default_value ,
2007-12-17 04:22:44 +01: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 ;
}
2010-10-14 09:41:42 +02:00
return ldb_msg_find_attr_as_uint ( res [ 0 ] , attr_name , default_value ) ;
2007-12-17 04:22:44 +01:00
}
/*
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 ;
}
2010-10-14 09:41:42 +02:00
return ldb_msg_find_attr_as_int64 ( res [ 0 ] , attr_name , default_value ) ;
2007-12-17 04:22:44 +01:00
}
/*
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 + + ) {
2010-10-14 09:41:42 +02:00
( * strs ) [ i ] = ldb_msg_find_attr_as_string ( res [ i ] , attr_name , NULL ) ;
2007-12-17 04:22:44 +01:00
}
( * strs ) [ count ] = NULL ;
return count ;
}
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 )
{
2019-03-11 17:11:06 +01:00
ssize_t ret ;
2007-12-17 04:22:44 +01:00
const struct ldb_val * v ;
struct dom_sid * sid ;
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 ;
}
2019-03-11 16:55:57 +01:00
ret = sid_parse ( v - > data , v - > length , sid ) ;
2019-03-11 17:11:06 +01:00
if ( ret = = - 1 ) {
2007-12-17 04:22:44 +01:00
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 11:26:36 +11:00
NTSTATUS status ;
2007-12-17 04:22:44 +01:00
v = ldb_msg_find_ldb_val ( msg , attr ) ;
2009-12-11 17:33:32 +11:00
if ( ! v ) return GUID_zero ( ) ;
2007-12-17 04:22:44 +01:00
2009-12-10 11:26:36 +11:00
status = GUID_from_ndr_blob ( v , & guid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return GUID_zero ( ) ;
2007-12-17 04:22:44 +01: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 12:43:10 +01:00
NTTIME samdb_result_nttime ( const struct ldb_message * msg , const char * attr ,
NTTIME default_value )
2007-12-17 04:22:44 +01: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 12:43:10 +01: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 06:02:46 -06: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 12:43:10 +01:00
NTTIME samdb_result_account_expires ( const struct ldb_message * msg )
2008-03-06 06:02:46 -06:00
{
NTTIME ret = ldb_msg_find_attr_as_uint64 ( msg , " accountExpires " ,
2008-03-25 15:25:13 +11:00
0 ) ;
2008-03-06 06:02:46 -06:00
2008-03-25 16:36:13 +11:00
if ( ret = = 0 )
2008-03-06 06:02:46 -06:00
ret = 0x7FFFFFFFFFFFFFFFULL ;
return ret ;
}
2007-12-17 04:22:44 +01:00
/*
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 )
{
2010-10-14 09:41:42 +02:00
uint64_t attr_time = ldb_msg_find_attr_as_uint64 ( msg , attr , 0 ) ;
2007-12-17 04:22:44 +01:00
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 ;
}
/*
pull a samr_Password structutre from a result set .
*/
2009-07-09 10:08:02 +10:00
struct samr_Password * samdb_result_hash ( TALLOC_CTX * mem_ctx , const struct ldb_message * msg , const char * attr )
2007-12-17 04:22:44 +01: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 20:14:41 +01:00
pull an array of samr_Password structures from a result set .
2007-12-17 04:22:44 +01:00
*/
2010-01-05 09:42:54 -08:00
unsigned int samdb_result_hashes ( TALLOC_CTX * mem_ctx , const struct ldb_message * msg ,
2007-12-17 04:22:44 +01:00
const char * attr , struct samr_Password * * hashes )
{
2010-01-05 09:42:54 -08:00
unsigned int count , i ;
2007-12-17 04:22:44 +01: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 ;
}
2013-11-11 10:37:38 +13:00
NTSTATUS samdb_result_passwords_from_history ( TALLOC_CTX * mem_ctx ,
struct loadparm_context * lp_ctx ,
struct ldb_message * msg ,
unsigned int idx ,
struct samr_Password * * lm_pwd ,
struct samr_Password * * nt_pwd )
{
struct samr_Password * lmPwdHash , * ntPwdHash ;
if ( nt_pwd ) {
unsigned int num_nt ;
num_nt = samdb_result_hashes ( mem_ctx , msg , " ntPwdHistory " , & ntPwdHash ) ;
2014-09-02 09:48:34 +12:00
if ( num_nt < = idx ) {
2013-11-11 10:37:38 +13:00
* nt_pwd = NULL ;
} else {
* nt_pwd = & ntPwdHash [ idx ] ;
}
}
if ( lm_pwd ) {
/* Ensure that if we have turned off LM
* authentication , that we never use the LM hash , even
* if we store it */
if ( lpcfg_lanman_auth ( lp_ctx ) ) {
unsigned int num_lm ;
num_lm = samdb_result_hashes ( mem_ctx , msg , " lmPwdHistory " , & lmPwdHash ) ;
2014-09-02 09:48:34 +12:00
if ( num_lm < = idx ) {
2013-11-11 10:37:38 +13:00
* lm_pwd = NULL ;
} else {
* lm_pwd = & lmPwdHash [ idx ] ;
}
} else {
* lm_pwd = NULL ;
}
}
return NT_STATUS_OK ;
}
2013-11-04 21:37:17 +13:00
NTSTATUS samdb_result_passwords_no_lockout ( TALLOC_CTX * mem_ctx ,
struct loadparm_context * lp_ctx ,
2016-05-25 16:00:29 +02:00
const struct ldb_message * msg ,
2013-11-04 21:37:17 +13:00
struct samr_Password * * lm_pwd ,
struct samr_Password * * nt_pwd )
2007-12-17 04:22:44 +01:00
{
struct samr_Password * lmPwdHash , * ntPwdHash ;
2013-11-04 21:37:17 +13:00
2007-12-17 04:22:44 +01:00
if ( nt_pwd ) {
2009-11-06 20:14:41 +01:00
unsigned int num_nt ;
2007-12-17 04:22:44 +01: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 12:48:16 +11:00
/* Ensure that if we have turned off LM
* authentication , that we never use the LM hash , even
* if we store it */
2010-07-16 14:32:42 +10:00
if ( lpcfg_lanman_auth ( lp_ctx ) ) {
2009-11-06 20:14:41 +01:00
unsigned int num_lm ;
2008-10-16 12:48:16 +11: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 04:22:44 +01:00
} else {
2008-10-16 12:48:16 +11:00
* lm_pwd = NULL ;
2007-12-17 04:22:44 +01:00
}
}
return NT_STATUS_OK ;
}
2013-11-04 21:37:17 +13:00
NTSTATUS samdb_result_passwords ( TALLOC_CTX * mem_ctx ,
struct loadparm_context * lp_ctx ,
2016-05-25 16:00:29 +02:00
const struct ldb_message * msg ,
2013-11-04 21:37:17 +13:00
struct samr_Password * * lm_pwd ,
struct samr_Password * * nt_pwd )
{
uint16_t acct_flags ;
acct_flags = samdb_result_acct_flags ( msg ,
" msDS-User-Account-Control-Computed " ) ;
/* Quit if the account was locked out. */
if ( acct_flags & ACB_AUTOLOCK ) {
DEBUG ( 3 , ( " samdb_result_passwords: Account for user %s was locked out. \n " ,
ldb_dn_get_linearized ( msg - > dn ) ) ) ;
return NT_STATUS_ACCOUNT_LOCKED_OUT ;
}
return samdb_result_passwords_no_lockout ( mem_ctx , lp_ctx , msg ,
lm_pwd , nt_pwd ) ;
}
2007-12-17 04:22:44 +01:00
/*
pull a samr_LogonHours structutre from a result set .
*/
struct samr_LogonHours samdb_result_logon_hours ( TALLOC_CTX * mem_ctx , struct ldb_message * msg , const char * attr )
{
struct samr_LogonHours hours ;
2010-05-12 17:34:02 +02:00
size_t units_per_week = 168 ;
2007-12-17 04:22:44 +01:00
const struct ldb_val * val = ldb_msg_find_ldb_val ( msg , attr ) ;
2010-05-12 17:34:02 +02:00
2007-12-17 04:22:44 +01:00
ZERO_STRUCT ( hours ) ;
2010-05-12 17:34:02 +02:00
if ( val ) {
units_per_week = val - > length * 8 ;
}
hours . bits = talloc_array ( mem_ctx , uint8_t , units_per_week / 8 ) ;
2007-12-17 04:22:44 +01:00
if ( ! hours . bits ) {
return hours ;
}
hours . units_per_week = units_per_week ;
2010-05-12 17:34:02 +02:00
memset ( hours . bits , 0xFF , units_per_week / 8 ) ;
2007-12-17 04:22:44 +01:00
if ( val ) {
2010-05-12 17:34:02 +02:00
memcpy ( hours . bits , val - > data , val - > length ) ;
2007-12-17 04:22:44 +01:00
}
2010-05-12 17:34:02 +02:00
2007-12-17 04:22:44 +01:00
return hours ;
}
/*
pull a set of account_flags from a result set .
2008-02-28 08:50:00 +11:00
2013-10-29 17:30:18 +13:00
Naturally , this requires that userAccountControl and
( if not null ) the attributes ' attr ' be already
included in msg
2007-12-17 04:22:44 +01:00
*/
2016-05-25 16:00:29 +02:00
uint32_t samdb_result_acct_flags ( const struct ldb_message * msg , const char * attr )
2007-12-17 04:22:44 +01:00
{
2008-02-28 08:50:00 +11:00
uint32_t userAccountControl = ldb_msg_find_attr_as_uint ( msg , " userAccountControl " , 0 ) ;
2013-10-29 17:30:18 +13:00
uint32_t attr_flags = 0 ;
2009-06-12 15:20:48 +02:00
uint32_t acct_flags = ds_uf2acb ( userAccountControl ) ;
2013-10-29 17:30:18 +13:00
if ( attr ) {
attr_flags = ldb_msg_find_attr_as_uint ( msg , attr , UF_ACCOUNTDISABLE ) ;
if ( attr_flags = = UF_ACCOUNTDISABLE ) {
DEBUG ( 0 , ( " Attribute %s not found, disabling account %s! \n " , attr ,
ldb_dn_get_linearized ( msg - > dn ) ) ) ;
}
acct_flags | = ds_uf2acb ( attr_flags ) ;
2008-02-28 08:50:00 +11:00
}
2013-10-29 17:30:18 +13:00
2008-02-28 08:50:00 +11:00
return acct_flags ;
2007-12-17 04:22:44 +01:00
}
2014-06-17 16:03:22 +12:00
NTSTATUS samdb_result_parameters ( TALLOC_CTX * mem_ctx ,
struct ldb_message * msg ,
const char * attr ,
struct lsa_BinaryString * s )
2008-11-10 20:35:32 +01:00
{
2014-06-17 16:03:22 +12:00
int i ;
2008-11-10 20:35:32 +01:00
const struct ldb_val * val = ldb_msg_find_ldb_val ( msg , attr ) ;
2014-06-17 16:03:22 +12:00
ZERO_STRUCTP ( s ) ;
2008-11-10 20:35:32 +01:00
if ( ! val ) {
2014-06-17 16:03:22 +12:00
return NT_STATUS_OK ;
2008-11-10 20:35:32 +01:00
}
2014-06-17 16:03:22 +12:00
if ( ( val - > length % 2 ) ! = 0 ) {
/*
* If the on - disk data is not even in length , we know
* it is corrupt , and can not be safely pushed . We
* would either truncate , send either a un - initilaised
* byte or send a forced zero byte
*/
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
2008-11-10 20:35:32 +01:00
}
2014-06-17 16:03:22 +12:00
s - > array = talloc_array ( mem_ctx , uint16_t , val - > length / 2 ) ;
if ( ! s - > array ) {
return NT_STATUS_NO_MEMORY ;
}
s - > length = s - > size = val - > length ;
/* The on-disk format is the 'network' format, being UTF16LE (sort of) */
for ( i = 0 ; i < s - > length / 2 ; i + + ) {
s - > array [ i ] = SVAL ( val - > data , i * 2 ) ;
}
return NT_STATUS_OK ;
2008-11-10 20:35:32 +01:00
}
2007-12-17 04:22:44 +01:00
/* Find an attribute, with a particular value */
/* The current callers of this function expect a very specific
2019-04-07 22:59:24 +12:00
* behaviour : In particular , objectClass subclass equivalence is not
2007-12-17 04:22:44 +01:00
* 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 20:14:41 +01:00
unsigned int i ;
2007-12-17 04:22:44 +01: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 ;
}
2016-02-11 08:31:46 +01:00
static int samdb_find_or_add_attribute_ex ( struct ldb_context * ldb ,
struct ldb_message * msg ,
const char * name ,
const char * set_value ,
2016-07-07 15:44:47 +02:00
unsigned attr_flags ,
2016-02-11 08:31:46 +01:00
bool * added )
2007-12-17 04:22:44 +01:00
{
2014-11-07 07:02:51 +01:00
int ret ;
2007-12-17 04:22:44 +01:00
struct ldb_message_element * el ;
2016-07-08 10:43:19 +02:00
SMB_ASSERT ( attr_flags ! = 0 ) ;
2007-12-17 04:22:44 +01:00
el = ldb_msg_find_element ( msg , name ) ;
if ( el ) {
2016-02-11 08:31:46 +01:00
if ( added ! = NULL ) {
* added = false ;
}
2007-12-17 04:22:44 +01:00
return LDB_SUCCESS ;
}
2009-05-31 16:19:11 +02:00
2016-07-07 15:44:47 +02:00
ret = ldb_msg_add_empty ( msg , name ,
2016-07-08 10:43:19 +02:00
attr_flags ,
2016-07-07 15:44:47 +02:00
& el ) ;
2014-11-07 07:02:51 +01:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2016-07-07 15:44:47 +02:00
if ( set_value ! = NULL ) {
ret = ldb_msg_add_string ( msg , name , set_value ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2016-02-11 08:31:46 +01:00
if ( added ! = NULL ) {
* added = true ;
}
2014-11-07 07:02:51 +01:00
return LDB_SUCCESS ;
2007-12-17 04:22:44 +01:00
}
2016-02-11 08:31:46 +01:00
int samdb_find_or_add_attribute ( struct ldb_context * ldb , struct ldb_message * msg , const char * name , const char * set_value )
{
2016-07-08 10:43:19 +02:00
return samdb_find_or_add_attribute_ex ( ldb , msg , name , set_value , LDB_FLAG_MOD_ADD , NULL ) ;
2016-02-11 08:31:46 +01:00
}
2007-12-17 04:22:44 +01:00
/*
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 ,
2011-09-05 17:07:22 +10:00
const char * attr_name , const struct dom_sid * sid )
2007-12-17 04:22:44 +01:00
{
struct ldb_val v ;
enum ndr_err_code ndr_err ;
2008-01-01 22:05:05 -06:00
ndr_err = ndr_push_struct_blob ( & v , mem_ctx ,
sid ,
2007-12-17 04:22:44 +01:00
( ndr_push_flags_fn_t ) ndr_push_dom_sid ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2010-07-06 13:21:54 +10:00
return ldb_operr ( sam_ldb ) ;
2007-12-17 04:22:44 +01: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 14:45:16 +11:00
dsdb_replace ( ) to be used everywhere */
2007-12-17 04:22:44 +01:00
return ldb_msg_add_empty ( msg , attr_name , LDB_FLAG_MOD_REPLACE , NULL ) ;
}
/*
2010-05-31 14:52:46 +02:00
add an add attribute value to a message or enhance an existing attribute
which has the same name and the add flag set .
2007-12-17 04:22:44 +01:00
*/
2010-05-31 14:52:46 +02:00
int samdb_msg_add_addval ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx ,
struct ldb_message * msg , const char * attr_name ,
const char * value )
2007-12-17 04:22:44 +01:00
{
struct ldb_message_element * el ;
2010-05-31 14:52:46 +02:00
struct ldb_val val , * vals ;
char * v ;
unsigned int i ;
bool found = false ;
2007-12-17 04:22:44 +01:00
int ret ;
2010-05-31 14:52:46 +02:00
2007-12-17 04:22:44 +01:00
v = talloc_strdup ( mem_ctx , value ) ;
2010-05-31 14:52:46 +02:00
if ( v = = NULL ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( sam_ldb ) ;
2010-05-31 14:52:46 +02:00
}
val . data = ( uint8_t * ) v ;
val . length = strlen ( v ) ;
if ( val . length = = 0 ) {
/* allow empty strings as non-existent attributes */
return LDB_SUCCESS ;
}
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
el = & msg - > elements [ i ] ;
if ( ( ldb_attr_cmp ( el - > name , attr_name ) = = 0 ) & &
2010-08-17 11:21:11 +10:00
( LDB_FLAG_MOD_TYPE ( el - > flags ) = = LDB_FLAG_MOD_ADD ) ) {
2010-05-31 14:52:46 +02:00
found = true ;
break ;
}
}
if ( ! found ) {
ret = ldb_msg_add_empty ( msg , attr_name , LDB_FLAG_MOD_ADD ,
& el ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2010-12-01 16:22:15 +01:00
vals = talloc_realloc ( msg - > elements , el - > values , struct ldb_val ,
2010-05-31 14:52:46 +02:00
el - > num_values + 1 ) ;
if ( vals = = NULL ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( sam_ldb ) ;
2010-05-31 14:52:46 +02:00
}
el - > values = vals ;
el - > values [ el - > num_values ] = val ;
+ + ( el - > num_values ) ;
2010-02-17 18:24:03 +01:00
return LDB_SUCCESS ;
2007-12-17 04:22:44 +01:00
}
/*
2010-05-31 14:52:46 +02:00
add a delete attribute value to a message or enhance an existing attribute
which has the same name and the delete flag set .
2007-12-17 04:22:44 +01:00
*/
2010-05-31 14:52:46 +02:00
int samdb_msg_add_delval ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx ,
struct ldb_message * msg , const char * attr_name ,
const char * value )
2007-12-17 04:22:44 +01:00
{
struct ldb_message_element * el ;
2010-05-31 14:52:46 +02:00
struct ldb_val val , * vals ;
char * v ;
unsigned int i ;
bool found = false ;
2007-12-17 04:22:44 +01:00
int ret ;
2010-05-31 14:52:46 +02:00
2007-12-17 04:22:44 +01:00
v = talloc_strdup ( mem_ctx , value ) ;
2010-05-31 14:52:46 +02:00
if ( v = = NULL ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( sam_ldb ) ;
2010-05-31 14:52:46 +02:00
}
val . data = ( uint8_t * ) v ;
val . length = strlen ( v ) ;
if ( val . length = = 0 ) {
/* allow empty strings as non-existent attributes */
return LDB_SUCCESS ;
}
for ( i = 0 ; i < msg - > num_elements ; i + + ) {
el = & msg - > elements [ i ] ;
if ( ( ldb_attr_cmp ( el - > name , attr_name ) = = 0 ) & &
2010-08-17 11:21:11 +10:00
( LDB_FLAG_MOD_TYPE ( el - > flags ) = = LDB_FLAG_MOD_DELETE ) ) {
2010-05-31 14:52:46 +02:00
found = true ;
break ;
}
}
if ( ! found ) {
ret = ldb_msg_add_empty ( msg , attr_name , LDB_FLAG_MOD_DELETE ,
& el ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2010-12-01 16:22:15 +01:00
vals = talloc_realloc ( msg - > elements , el - > values , struct ldb_val ,
2010-05-31 14:52:46 +02:00
el - > num_values + 1 ) ;
if ( vals = = NULL ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( sam_ldb ) ;
2010-05-31 14:52:46 +02:00
}
el - > values = vals ;
el - > values [ el - > num_values ] = val ;
+ + ( el - > num_values ) ;
2010-02-17 18:24:03 +01:00
return LDB_SUCCESS ;
2007-12-17 04:22:44 +01: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 ) ;
2010-10-14 22:43:33 +02:00
if ( s = = NULL ) {
return ldb_oom ( sam_ldb ) ;
}
2010-10-15 10:27:51 +02:00
return ldb_msg_add_string ( msg , attr_name , s ) ;
2007-12-17 04:22:44 +01:00
}
/*
2010-10-16 10:36:32 +02:00
* Add an unsigned int element to a message
*
* The issue here is that we have not yet first cast to int32_t explicitly ,
* before we cast to an signed int to printf ( ) into the % d or cast to a
* int64_t before we then cast to a long long to printf into a % lld .
*
* There are * no * unsigned integers in Active Directory LDAP , even the RID
* allocations and ms - DS - Secondary - KrbTgt - Number are * signed * quantities .
* ( See the schema , and the syntax definitions in schema_syntax . c ) .
*
*/
2007-12-17 04:22:44 +01:00
int samdb_msg_add_uint ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
2010-01-05 09:42:54 -08:00
const char * attr_name , unsigned int v )
2007-12-17 04:22:44 +01:00
{
2010-01-11 20:17:53 +01:00
return samdb_msg_add_int ( sam_ldb , mem_ctx , msg , attr_name , ( int ) v ) ;
2007-12-17 04:22:44 +01: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 ) ;
2010-10-14 22:43:33 +02:00
if ( s = = NULL ) {
return ldb_oom ( sam_ldb ) ;
}
2010-10-15 10:27:51 +02:00
return ldb_msg_add_string ( msg , attr_name , s ) ;
2007-12-17 04:22:44 +01:00
}
/*
2010-10-16 10:36:32 +02:00
* Add an unsigned int64_t ( uint64_t ) element to a message
*
* The issue here is that we have not yet first cast to int32_t explicitly ,
* before we cast to an signed int to printf ( ) into the % d or cast to a
* int64_t before we then cast to a long long to printf into a % lld .
*
* There are * no * unsigned integers in Active Directory LDAP , even the RID
* allocations and ms - DS - Secondary - KrbTgt - Number are * signed * quantities .
* ( See the schema , and the syntax definitions in schema_syntax . c ) .
*
*/
2007-12-17 04:22:44 +01:00
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 20:00:43 +01:00
return samdb_msg_add_int64 ( sam_ldb , mem_ctx , msg , attr_name , ( int64_t ) v ) ;
2007-12-17 04:22:44 +01: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 ,
2010-08-15 21:26:07 +02:00
const char * attr_name , const struct samr_Password * hash )
2007-12-17 04:22:44 +01:00
{
struct ldb_val val ;
val . data = talloc_memdup ( mem_ctx , hash - > hash , 16 ) ;
if ( ! val . data ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( sam_ldb ) ;
2007-12-17 04:22:44 +01:00
}
val . length = 16 ;
return ldb_msg_add_value ( msg , attr_name , & val , NULL ) ;
}
/*
add a samr_Password array to a message
*/
2010-07-06 13:21:54 +10:00
int samdb_msg_add_hashes ( struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
2009-11-06 20:14:41 +01:00
const char * attr_name , struct samr_Password * hashes ,
unsigned int count )
2007-12-17 04:22:44 +01:00
{
struct ldb_val val ;
2009-11-06 20:14:41 +01:00
unsigned int i ;
2007-12-17 04:22:44 +01:00
val . data = talloc_array_size ( mem_ctx , 16 , count ) ;
val . length = count * 16 ;
if ( ! val . data ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2007-12-17 04:22:44 +01: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 15:20:48 +02:00
return samdb_msg_add_uint ( sam_ldb , mem_ctx , msg , attr_name , ds_acb2uf ( v ) ) ;
2007-12-17 04:22:44 +01: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 20:35:41 +01: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 )
{
2014-06-17 16:03:22 +12:00
int i ;
2008-11-10 20:35:41 +01:00
struct ldb_val val ;
2014-06-17 16:03:22 +12:00
if ( ( parameters - > length % 2 ) ! = 0 ) {
return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX ;
}
val . data = talloc_array ( mem_ctx , uint8_t , parameters - > length ) ;
if ( val . data = = NULL ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
2010-01-12 09:59:26 +01:00
val . length = parameters - > length ;
2014-06-17 16:03:22 +12:00
for ( i = 0 ; i < parameters - > length / 2 ; i + + ) {
/*
* The on - disk format needs to be in the ' network '
* format , parmeters - > array is a uint16_t array of
* length parameters - > length / 2
*/
SSVAL ( val . data , i * 2 , parameters - > array [ i ] ) ;
}
return ldb_msg_add_steal_value ( msg , attr_name , & val ) ;
2008-11-10 20:35:41 +01:00
}
2007-12-17 04:22:44 +01:00
2010-10-06 19:11:58 +02:00
/*
2010-10-16 10:36:32 +02:00
* Sets an unsigned int element in a message
*
* The issue here is that we have not yet first cast to int32_t explicitly ,
* before we cast to an signed int to printf ( ) into the % d or cast to a
* int64_t before we then cast to a long long to printf into a % lld .
*
* There are * no * unsigned integers in Active Directory LDAP , even the RID
* allocations and ms - DS - Secondary - KrbTgt - Number are * signed * quantities .
* ( See the schema , and the syntax definitions in schema_syntax . c ) .
*
2010-10-06 19:11:58 +02:00
*/
int samdb_msg_set_uint ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx ,
struct ldb_message * msg , const char * attr_name ,
unsigned int v )
{
struct ldb_message_element * el ;
el = ldb_msg_find_element ( msg , attr_name ) ;
if ( el ) {
el - > num_values = 0 ;
}
return samdb_msg_add_uint ( sam_ldb , mem_ctx , msg , attr_name , v ) ;
}
2009-12-18 18:11:48 +02:00
/*
* Handle ldb_request in transaction
*/
2014-12-08 14:20:21 +13:00
int dsdb_autotransaction_request ( struct ldb_context * sam_ldb ,
struct ldb_request * req )
2009-12-18 18:11:48 +02: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 04:22:44 +01: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 10:16:56 +11: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 04:22:44 +01:00
struct ldb_dn * samdb_partitions_dn ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx )
{
struct ldb_dn * new_dn ;
2010-04-13 08:41:10 +02:00
new_dn = ldb_dn_copy ( mem_ctx , ldb_get_config_basedn ( sam_ctx ) ) ;
2007-12-17 04:22:44 +01:00
if ( ! ldb_dn_add_child_fmt ( new_dn , " CN=Partitions " ) ) {
talloc_free ( new_dn ) ;
return NULL ;
}
return new_dn ;
}
2010-03-09 14:56:46 +02:00
struct ldb_dn * samdb_infrastructure_dn ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx )
{
struct ldb_dn * new_dn ;
2010-04-13 08:41:10 +02:00
new_dn = ldb_dn_copy ( mem_ctx , ldb_get_default_basedn ( sam_ctx ) ) ;
2010-03-09 14:56:46 +02:00
if ( ! ldb_dn_add_child_fmt ( new_dn , " CN=Infrastructure " ) ) {
talloc_free ( new_dn ) ;
return NULL ;
}
return new_dn ;
}
2007-12-17 04:22:44 +01:00
struct ldb_dn * samdb_sites_dn ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx )
{
struct ldb_dn * new_dn ;
2010-04-13 08:41:10 +02:00
new_dn = ldb_dn_copy ( mem_ctx , ldb_get_config_basedn ( sam_ctx ) ) ;
2007-12-17 04:22:44 +01: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 14:11:06 +11:00
const struct dom_sid * domain_sid ;
const char * attrs [ ] = {
" objectSid " ,
NULL
} ;
struct ldb_result * res ;
int ret ;
2007-12-17 04:22:44 +01: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 14:30:06 -04:00
ret = ldb_search ( ldb , tmp_ctx , & res , ldb_get_default_basedn ( ldb ) , LDB_SCOPE_BASE , attrs , " objectSid=* " ) ;
2008-03-13 14:11:06 +11:00
if ( ret ! = LDB_SUCCESS ) {
goto failed ;
}
2009-05-31 16:19:11 +02:00
2008-03-13 14:11:06 +11:00
if ( res - > count ! = 1 ) {
goto failed ;
}
domain_sid = samdb_result_dom_sid ( tmp_ctx , res - > msgs [ 0 ] , " objectSid " ) ;
2007-12-17 04:22:44 +01:00
if ( domain_sid = = NULL ) {
goto failed ;
}
/* cache the domain_sid in the ldb */
2008-06-26 23:30:42 +02:00
if ( ldb_set_opaque ( ldb , " cache.domain_sid " , discard_const_p ( struct dom_sid , domain_sid ) ) ! = LDB_SUCCESS ) {
2007-12-17 04:22:44 +01: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 12:52:22 +11: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 04:22:44 +01: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 ;
}
2018-08-28 11:52:27 +02:00
/*
work out the domain guid for the current open ldb
*/
const struct GUID * samdb_domain_guid ( struct ldb_context * ldb )
{
TALLOC_CTX * tmp_ctx = NULL ;
struct GUID * domain_guid = NULL ;
const char * attrs [ ] = {
" objectGUID " ,
NULL
} ;
struct ldb_result * res = NULL ;
int ret ;
/* see if we have a cached copy */
domain_guid = ( struct GUID * ) ldb_get_opaque ( ldb , " cache.domain_guid " ) ;
if ( domain_guid ) {
return domain_guid ;
}
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
goto failed ;
}
ret = ldb_search ( ldb , tmp_ctx , & res , ldb_get_default_basedn ( ldb ) , LDB_SCOPE_BASE , attrs , " objectGUID=* " ) ;
if ( ret ! = LDB_SUCCESS ) {
goto failed ;
}
if ( res - > count ! = 1 ) {
goto failed ;
}
domain_guid = talloc ( tmp_ctx , struct GUID ) ;
if ( domain_guid = = NULL ) {
goto failed ;
}
* domain_guid = samdb_result_guid ( res - > msgs [ 0 ] , " objectGUID " ) ;
/* cache the domain_sid in the ldb */
if ( ldb_set_opaque ( ldb , " cache.domain_guid " , domain_guid ) ! = LDB_SUCCESS ) {
goto failed ;
}
talloc_steal ( ldb , domain_guid ) ;
talloc_free ( tmp_ctx ) ;
return domain_guid ;
failed :
talloc_free ( tmp_ctx ) ;
return NULL ;
}
2010-04-20 11:48:51 +10: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 ;
2011-08-11 16:29:24 +10:00
/* see if we have a forced copy from provision */
2010-04-20 11:48:51 +10:00
ntds_settings_dn_old = talloc_get_type ( ldb_get_opaque ( ldb ,
2011-08-11 16:29:24 +10:00
" forced.ntds_settings_dn " ) , struct ldb_dn ) ;
2010-04-20 11:48:51 +10:00
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 ;
}
2011-08-11 16:29:24 +10:00
/* set the DN in the ldb to avoid lookups during provision */
if ( ldb_set_opaque ( ldb , " forced.ntds_settings_dn " , ntds_settings_dn_new ) ! = LDB_SUCCESS ) {
2010-04-20 11:48:51 +10:00
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 04:22:44 +01:00
/*
work out the ntds settings dn for the current open ldb
*/
2012-08-14 16:08:47 +10:00
struct ldb_dn * samdb_ntds_settings_dn ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx )
2007-12-17 04:22:44 +01:00
{
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 16:19:11 +02:00
2007-12-17 04:22:44 +01:00
/* see if we have a cached copy */
2011-08-11 16:29:24 +10:00
settings_dn = ( struct ldb_dn * ) ldb_get_opaque ( ldb , " forced.ntds_settings_dn " ) ;
2007-12-17 04:22:44 +01:00
if ( settings_dn ) {
2012-08-14 17:49:12 +10:00
return ldb_dn_copy ( mem_ctx , settings_dn ) ;
2007-12-17 04:22:44 +01:00
}
2012-08-14 16:08:47 +10:00
tmp_ctx = talloc_new ( mem_ctx ) ;
2007-12-17 04:22:44 +01:00
if ( tmp_ctx = = NULL ) {
goto failed ;
}
2008-09-23 14:30:06 -04:00
ret = ldb_search ( ldb , tmp_ctx , & root_res , ldb_dn_new ( tmp_ctx , ldb , " " ) , LDB_SCOPE_BASE , root_attrs , NULL ) ;
2011-12-01 09:33:10 +01:00
if ( ret ! = LDB_SUCCESS ) {
2007-12-17 04:22:44 +01:00
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 " ) ;
2011-08-11 16:29:24 +10:00
/* note that we do not cache the DN here, as that would mean
* we could not handle server renames at runtime . Only
* provision sets up forced . ntds_settings_dn */
2007-12-17 04:22:44 +01:00
2012-08-14 16:08:47 +10:00
talloc_steal ( mem_ctx , settings_dn ) ;
2007-12-17 04:22:44 +01:00
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 ;
}
/*
2019-03-04 15:13:55 +13:00
work out the ntds settings invocationID / objectGUID for the current open ldb
2007-12-17 04:22:44 +01:00
*/
2019-03-04 15:13:55 +13:00
static const struct GUID * samdb_ntds_GUID ( struct ldb_context * ldb ,
const char * attribute ,
const char * cache_name )
2007-12-17 04:22:44 +01:00
{
TALLOC_CTX * tmp_ctx ;
2019-03-04 15:13:55 +13:00
const char * attrs [ ] = { attribute , NULL } ;
2007-12-17 04:22:44 +01:00
int ret ;
struct ldb_result * res ;
2019-03-04 15:13:55 +13:00
struct GUID * ntds_guid ;
struct ldb_dn * ntds_settings_dn = NULL ;
const char * errstr = NULL ;
2009-05-31 16:19:11 +02:00
2007-12-17 04:22:44 +01:00
/* see if we have a cached copy */
2019-03-04 15:13:55 +13:00
ntds_guid = ( struct GUID * ) ldb_get_opaque ( ldb , cache_name ) ;
if ( ntds_guid ! = NULL ) {
return ntds_guid ;
2007-12-17 04:22:44 +01:00
}
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
goto failed ;
}
2019-03-04 15:13:55 +13:00
ntds_settings_dn = samdb_ntds_settings_dn ( ldb , tmp_ctx ) ;
if ( ntds_settings_dn = = NULL ) {
errstr = " samdb_ntds_settings_dn() returned NULL " ;
goto failed ;
}
ret = ldb_search ( ldb , tmp_ctx , & res , ntds_settings_dn ,
LDB_SCOPE_BASE , attrs , NULL ) ;
2007-12-17 04:22:44 +01:00
if ( ret ) {
2019-03-04 15:13:55 +13:00
errstr = ldb_errstring ( ldb ) ;
2007-12-17 04:22:44 +01:00
goto failed ;
}
if ( res - > count ! = 1 ) {
2019-03-04 15:13:55 +13:00
errstr = " incorrect number of results from base search " ;
2007-12-17 04:22:44 +01:00
goto failed ;
}
2019-03-04 15:13:55 +13:00
ntds_guid = talloc ( tmp_ctx , struct GUID ) ;
if ( ntds_guid = = NULL ) {
2007-12-17 04:22:44 +01:00
goto failed ;
}
2019-03-04 15:13:55 +13:00
* ntds_guid = samdb_result_guid ( res - > msgs [ 0 ] , attribute ) ;
if ( GUID_all_zero ( ntds_guid ) ) {
if ( ldb_msg_find_ldb_val ( res - > msgs [ 0 ] , attribute ) ) {
errstr = " failed to find the GUID attribute " ;
2013-09-17 15:20:48 -07:00
} else {
2019-03-04 15:13:55 +13:00
errstr = " failed to parse the GUID " ;
2013-09-17 15:20:48 -07:00
}
goto failed ;
}
2007-12-17 04:22:44 +01:00
/* cache the domain_sid in the ldb */
2019-03-04 15:13:55 +13:00
if ( ldb_set_opaque ( ldb , cache_name , ntds_guid ) ! = LDB_SUCCESS ) {
errstr = " ldb_set_opaque() failed " ;
2007-12-17 04:22:44 +01:00
goto failed ;
}
2019-03-04 15:13:55 +13:00
talloc_steal ( ldb , ntds_guid ) ;
2007-12-17 04:22:44 +01:00
talloc_free ( tmp_ctx ) ;
2019-03-04 15:13:55 +13:00
return ntds_guid ;
2007-12-17 04:22:44 +01:00
failed :
2019-03-04 15:13:55 +13:00
DBG_WARNING ( " Failed to find our own NTDS Settings %s in the ldb: %s! \n " ,
attribute , errstr ) ;
2007-12-17 04:22:44 +01:00
talloc_free ( tmp_ctx ) ;
return NULL ;
}
/*
work out the ntds settings objectGUID for the current open ldb
*/
const struct GUID * samdb_ntds_objectGUID ( struct ldb_context * ldb )
{
2019-03-04 15:13:55 +13:00
return samdb_ntds_GUID ( ldb , " objectGUID " , " cache.ntds_guid " ) ;
}
2007-12-17 04:22:44 +01:00
2019-03-04 15:13:55 +13:00
/*
work out the ntds settings invocationId for the current open ldb
*/
const struct GUID * samdb_ntds_invocation_id ( struct ldb_context * ldb )
{
return samdb_ntds_GUID ( ldb , " invocationId " , " cache.invocation_id " ) ;
2007-12-17 04:22:44 +01:00
}
2019-03-04 15:13:55 +13:00
static bool samdb_set_ntds_GUID ( struct ldb_context * ldb ,
const struct GUID * ntds_guid_in ,
const char * attribute ,
const char * cache_name )
2007-12-17 04:22:44 +01:00
{
TALLOC_CTX * tmp_ctx ;
struct GUID * ntds_guid_new ;
struct GUID * ntds_guid_old ;
2009-05-31 16:19:11 +02:00
2007-12-17 04:22:44 +01:00
/* see if we have a cached copy */
2019-03-04 15:13:55 +13:00
ntds_guid_old = ( struct GUID * ) ldb_get_opaque ( ldb , cache_name ) ;
2007-12-17 04:22:44 +01:00
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 */
2019-03-04 15:13:55 +13:00
if ( ldb_set_opaque ( ldb , cache_name , ntds_guid_new ) ! = LDB_SUCCESS ) {
2007-12-17 04:22:44 +01:00
goto failed ;
}
talloc_steal ( ldb , ntds_guid_new ) ;
talloc_free ( tmp_ctx ) ;
talloc_free ( ntds_guid_old ) ;
return true ;
failed :
2019-03-04 15:13:55 +13:00
DBG_WARNING ( " Failed to set our own cached %s in the ldb! \n " ,
attribute ) ;
2007-12-17 04:22:44 +01:00
talloc_free ( tmp_ctx ) ;
return false ;
}
2019-03-04 15:13:55 +13:00
bool samdb_set_ntds_objectGUID ( struct ldb_context * ldb , const struct GUID * ntds_guid_in )
{
return samdb_set_ntds_GUID ( ldb ,
ntds_guid_in ,
" objectGUID " ,
" cache.ntds_guid " ) ;
}
bool samdb_set_ntds_invocation_id ( struct ldb_context * ldb , const struct GUID * invocation_id_in )
{
return samdb_set_ntds_GUID ( ldb ,
invocation_id_in ,
" invocationId " ,
" cache.invocation_id " ) ;
}
2007-12-17 04:22:44 +01:00
/*
work out the server dn for the current open ldb
*/
struct ldb_dn * samdb_server_dn ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx )
{
2012-08-14 16:08:47 +10:00
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
struct ldb_dn * dn ;
if ( ! tmp_ctx ) {
return NULL ;
}
dn = ldb_dn_get_parent ( mem_ctx , samdb_ntds_settings_dn ( ldb , tmp_ctx ) ) ;
talloc_free ( tmp_ctx ) ;
return dn ;
2007-12-17 04:22:44 +01:00
}
/*
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 12:36:17 +11:00
struct ldb_dn * servers_dn ;
2007-12-17 04:22:44 +01:00
struct ldb_dn * server_site_dn ;
2010-02-26 12:36:17 +11:00
/* TODO: there must be a saner way to do this!! */
2007-12-17 04:22:44 +01:00
server_dn = samdb_server_dn ( ldb , mem_ctx ) ;
if ( ! server_dn ) return NULL ;
2010-02-26 12:36:17 +11:00
servers_dn = ldb_dn_get_parent ( mem_ctx , server_dn ) ;
2010-04-11 12:56:50 +02:00
talloc_free ( server_dn ) ;
2010-02-26 12:36:17 +11:00
if ( ! servers_dn ) return NULL ;
server_site_dn = ldb_dn_get_parent ( mem_ctx , servers_dn ) ;
2010-04-11 12:56:50 +02:00
talloc_free ( servers_dn ) ;
2007-12-17 04:22:44 +01:00
return server_site_dn ;
}
2010-09-27 19:46:37 -07:00
/*
find the site name from a computers DN record
*/
int samdb_find_site_for_computer ( struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx , struct ldb_dn * computer_dn ,
const char * * site_name )
{
int ret ;
struct ldb_dn * dn ;
const struct ldb_val * rdn_val ;
* site_name = NULL ;
ret = samdb_reference_dn ( ldb , mem_ctx , computer_dn , " serverReferenceBL " , & dn ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
if ( ! ldb_dn_remove_child_components ( dn , 2 ) ) {
talloc_free ( dn ) ;
return LDB_ERR_INVALID_DN_SYNTAX ;
}
2010-11-10 16:05:16 +01:00
2010-09-27 19:46:37 -07:00
rdn_val = ldb_dn_get_rdn_val ( dn ) ;
2010-11-10 16:05:16 +01:00
if ( rdn_val = = NULL ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
2010-09-27 19:46:37 -07:00
( * site_name ) = talloc_strndup ( mem_ctx , ( const char * ) rdn_val - > data , rdn_val - > length ) ;
talloc_free ( dn ) ;
if ( ! * site_name ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
return LDB_SUCCESS ;
}
/*
find the NTDS GUID from a computers DN record
*/
int samdb_find_ntdsguid_for_computer ( struct ldb_context * ldb , struct ldb_dn * computer_dn ,
struct GUID * ntds_guid )
{
int ret ;
struct ldb_dn * dn ;
* ntds_guid = GUID_zero ( ) ;
ret = samdb_reference_dn ( ldb , ldb , computer_dn , " serverReferenceBL " , & dn ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
if ( ! ldb_dn_add_child_fmt ( dn , " CN=NTDS Settings " ) ) {
talloc_free ( dn ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
ret = dsdb_find_guid_by_dn ( ldb , dn , ntds_guid ) ;
talloc_free ( dn ) ;
return ret ;
}
2010-01-04 14:13:21 +11: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 ;
2012-08-14 18:46:47 +10:00
ret = dsdb_search ( ldb , mem_ctx , & res , base , LDB_SCOPE_BASE , attrs , DSDB_SEARCH_ONE_ONLY | DSDB_SEARCH_SHOW_EXTENDED_DN , NULL ) ;
2010-01-04 14:13:21 +11:00
if ( ret ! = LDB_SUCCESS ) {
2012-08-14 22:53:35 +10:00
ldb_asprintf_errstring ( ldb , " Cannot find DN %s to get attribute %s for reference dn: %s " ,
ldb_dn_get_linearized ( base ) , attribute , ldb_errstring ( ldb ) ) ;
2010-01-04 14:13:21 +11:00
return ret ;
}
* dn = ldb_msg_find_attr_as_dn ( ldb , mem_ctx , res - > msgs [ 0 ] , attribute ) ;
if ( ! * dn ) {
2010-09-28 12:55:48 +10:00
if ( ! ldb_msg_find_element ( res - > msgs [ 0 ] , attribute ) ) {
ldb_asprintf_errstring ( ldb , " Cannot find attribute %s of %s to calculate reference dn " , attribute ,
ldb_dn_get_linearized ( base ) ) ;
} else {
ldb_asprintf_errstring ( ldb , " Cannot interpret attribute %s of %s as a dn " , attribute ,
ldb_dn_get_linearized ( base ) ) ;
}
2010-01-04 14:13:21 +11:00
talloc_free ( res ) ;
return LDB_ERR_NO_SUCH_ATTRIBUTE ;
}
talloc_free ( res ) ;
return LDB_SUCCESS ;
}
2012-08-14 19:44:18 +10:00
/*
find if a DN ( must have GUID component ! ) is our ntdsDsa
*/
int samdb_dn_is_our_ntdsa ( struct ldb_context * ldb , struct ldb_dn * dn , bool * is_ntdsa )
{
NTSTATUS status ;
struct GUID dn_guid ;
const struct GUID * our_ntds_guid ;
status = dsdb_get_extended_dn_guid ( dn , & dn_guid , " GUID " ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
our_ntds_guid = samdb_ntds_objectGUID ( ldb ) ;
if ( ! our_ntds_guid ) {
DEBUG ( 0 , ( " Failed to find our NTDS Settings GUID for comparison with %s - %s \n " , ldb_dn_get_linearized ( dn ) , ldb_errstring ( ldb ) ) ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
* is_ntdsa = GUID_equal ( & dn_guid , our_ntds_guid ) ;
return LDB_SUCCESS ;
}
2012-08-14 18:46:47 +10:00
/*
find a ' reference ' DN that points at another object and indicate if it is our ntdsDsa
*/
int samdb_reference_dn_is_our_ntdsa ( struct ldb_context * ldb , struct ldb_dn * base ,
const char * attribute , bool * is_ntdsa )
{
int ret ;
struct ldb_dn * referenced_dn ;
TALLOC_CTX * tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
ret = samdb_reference_dn ( ldb , tmp_ctx , base , attribute , & referenced_dn ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( " Failed to find object %s for attribute %s - %s \n " , ldb_dn_get_linearized ( base ) , attribute , ldb_errstring ( ldb ) ) ) ;
return ret ;
}
2012-08-14 19:48:32 +10:00
ret = samdb_dn_is_our_ntdsa ( ldb , referenced_dn , is_ntdsa ) ;
2012-08-14 18:46:47 +10:00
talloc_free ( tmp_ctx ) ;
2012-08-14 19:48:32 +10:00
return ret ;
2012-08-14 18:46:47 +10:00
}
2010-01-04 14:13:21 +11:00
/*
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 ) {
2016-01-14 11:50:56 +01:00
return ldb_error ( ldb , LDB_ERR_NO_SUCH_OBJECT , __func__ ) ;
2010-01-04 14:13:21 +11:00
}
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 08:41:10 +02:00
return samdb_reference_dn ( ldb , mem_ctx , ldb_get_default_basedn ( ldb ) ,
" rIDManagerReference " , dn ) ;
2010-01-04 14:13:21 +11:00
}
2010-01-05 17:07:51 +11: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 11:59:11 +02:00
const char * samdb_server_site_name ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx )
{
2010-04-13 15:40:43 +02:00
const struct ldb_val * val = ldb_dn_get_rdn_val ( samdb_server_site_dn ( ldb ,
mem_ctx ) ) ;
2009-10-18 11:59:11 +02:00
2010-04-13 15:40:43 +02:00
if ( val = = NULL ) {
2009-10-18 11:59:11 +02:00
return NULL ;
2010-04-13 15:40:43 +02:00
}
return ( const char * ) val - > data ;
2009-10-18 11:59:11 +02:00
}
2010-04-13 18:28:53 +02:00
/*
* Finds the client site by using the client ' s IP address .
* The " subnet_name " returns the name of the subnet if parameter ! = NULL
2018-03-26 14:25:45 +13:00
*
* Has a Windows - based fallback to provide the only site available , or an empty
* string if there are multiple sites .
2010-04-13 18:28:53 +02:00
*/
const char * samdb_client_site_name ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx ,
2018-03-26 14:25:45 +13:00
const char * ip_address , char * * subnet_name ,
bool fallback )
2010-04-13 18:28:53 +02:00
{
const char * attrs [ ] = { " cn " , " siteObject " , NULL } ;
2019-02-14 10:53:37 +13:00
struct ldb_dn * sites_container_dn = NULL ;
struct ldb_dn * subnets_dn = NULL ;
struct ldb_dn * sites_dn = NULL ;
struct ldb_result * res = NULL ;
const struct ldb_val * val = NULL ;
const char * site_name = NULL ;
const char * l_subnet_name = NULL ;
2010-04-13 18:28:53 +02:00
const char * allow_list [ 2 ] = { NULL , NULL } ;
2010-05-07 22:43:36 +10:00
unsigned int i , count ;
2019-02-14 09:18:20 +13:00
int ret ;
2010-04-13 18:28:53 +02:00
2010-04-27 10:21:28 +02:00
/*
* if we don ' t have a client ip e . g . ncalrpc
* the server site is the client site
*/
if ( ip_address = = NULL ) {
return samdb_server_site_name ( ldb , mem_ctx ) ;
}
2010-04-13 18:28:53 +02:00
sites_container_dn = samdb_sites_dn ( ldb , mem_ctx ) ;
if ( sites_container_dn = = NULL ) {
2019-02-14 10:53:37 +13:00
goto exit ;
2010-04-13 18:28:53 +02:00
}
subnets_dn = ldb_dn_copy ( mem_ctx , sites_container_dn ) ;
if ( ! ldb_dn_add_child_fmt ( subnets_dn , " CN=Subnets " ) ) {
2019-02-14 10:53:37 +13:00
goto exit ;
2010-04-13 18:28:53 +02:00
}
ret = ldb_search ( ldb , mem_ctx , & res , subnets_dn , LDB_SCOPE_ONELEVEL ,
attrs , NULL ) ;
2010-05-07 22:43:36 +10:00
if ( ret = = LDB_ERR_NO_SUCH_OBJECT ) {
count = 0 ;
} else if ( ret ! = LDB_SUCCESS ) {
2019-02-14 10:53:37 +13:00
goto exit ;
2010-05-07 22:43:36 +10:00
} else {
count = res - > count ;
2010-04-13 18:28:53 +02:00
}
2010-05-07 22:43:36 +10:00
for ( i = 0 ; i < count ; i + + ) {
2010-04-13 18:28:53 +02:00
l_subnet_name = ldb_msg_find_attr_as_string ( res - > msgs [ i ] , " cn " ,
NULL ) ;
allow_list [ 0 ] = l_subnet_name ;
2016-11-10 20:33:17 -08:00
if ( allow_access_nolog ( NULL , allow_list , " " , ip_address ) ) {
2010-04-13 18:28:53 +02:00
sites_dn = ldb_msg_find_attr_as_dn ( ldb , mem_ctx ,
res - > msgs [ i ] ,
" siteObject " ) ;
if ( sites_dn = = NULL ) {
/* No reference, maybe another subnet matches */
continue ;
}
/* "val" cannot be NULL here since "sites_dn" != NULL */
val = ldb_dn_get_rdn_val ( sites_dn ) ;
site_name = talloc_strdup ( mem_ctx ,
( const char * ) val - > data ) ;
2019-02-14 10:53:37 +13:00
TALLOC_FREE ( sites_dn ) ;
2010-04-13 18:28:53 +02:00
break ;
}
}
2018-03-26 14:25:45 +13:00
if ( site_name = = NULL & & fallback ) {
2010-04-13 18:28:53 +02:00
/* This is the Windows Server fallback rule: when no subnet
* exists and we have only one site available then use it ( it
* is for sure the same as our server site ) . If more sites do
* exist then we don ' t know which one to use and set the site
* name to " " . */
2019-02-14 09:18:20 +13:00
size_t cnt = 0 ;
ret = dsdb_domain_count (
ldb ,
& cnt ,
sites_container_dn ,
NULL ,
LDB_SCOPE_SUBTREE ,
" (objectClass=site) " ) ;
if ( ret ! = LDB_SUCCESS ) {
goto exit ;
}
2010-04-13 18:28:53 +02:00
if ( cnt = = 1 ) {
site_name = samdb_server_site_name ( ldb , mem_ctx ) ;
} else {
site_name = talloc_strdup ( mem_ctx , " " ) ;
}
l_subnet_name = NULL ;
}
if ( subnet_name ! = NULL ) {
* subnet_name = talloc_strdup ( mem_ctx , l_subnet_name ) ;
}
2019-02-14 09:18:20 +13:00
exit :
2019-02-14 10:53:37 +13:00
TALLOC_FREE ( sites_container_dn ) ;
TALLOC_FREE ( subnets_dn ) ;
TALLOC_FREE ( res ) ;
2010-04-13 18:28:53 +02:00
return site_name ;
}
2007-12-17 04:22:44 +01:00
/*
work out if we are the PDC for the domain of the current open ldb
*/
bool samdb_is_pdc ( struct ldb_context * ldb )
{
int ret ;
bool is_pdc ;
2012-08-14 18:48:24 +10:00
ret = samdb_reference_dn_is_our_ntdsa ( ldb , ldb_get_default_basedn ( ldb ) , " fsmoRoleOwner " ,
& is_pdc ) ;
2010-08-09 19:45:45 +02:00
if ( ret ! = LDB_SUCCESS ) {
2012-08-14 18:48:24 +10:00
DEBUG ( 1 , ( " Failed to find if we are the PDC for this ldb: Searching for fSMORoleOwner in %s failed: %s \n " ,
2007-12-17 04:22:44 +01:00
ldb_dn_get_linearized ( ldb_get_default_basedn ( ldb ) ) ,
ldb_errstring ( ldb ) ) ) ;
2012-08-14 18:48:24 +10:00
return false ;
2007-12-17 04:22:44 +01:00
}
return is_pdc ;
}
2008-01-03 04:40:24 -06: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 )
{
2011-03-01 11:40:23 +01:00
uint32_t options ;
2011-09-28 14:36:00 +10:00
if ( samdb_ntds_options ( ldb , & options ) ! = LDB_SUCCESS ) {
2008-01-03 04:40:24 -06:00
return false ;
}
2011-09-28 14:36:00 +10:00
return ( options & DS_NTDSDSA_OPT_IS_GC ) ! = 0 ;
2008-01-03 04:40:24 -06:00
}
2007-12-17 04:22:44 +01:00
/* Find a domain object in the parents of a particular DN. */
int samdb_search_for_parent_domain ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx , struct ldb_dn * dn ,
struct ldb_dn * * parent_dn , const char * * errstring )
{
TALLOC_CTX * local_ctx ;
struct ldb_dn * sdn = dn ;
struct ldb_result * res = NULL ;
2010-08-09 19:45:45 +02:00
int ret = LDB_SUCCESS ;
2007-12-17 04:22:44 +01:00
const char * attrs [ ] = { NULL } ;
local_ctx = talloc_new ( mem_ctx ) ;
2010-07-06 13:21:54 +10:00
if ( local_ctx = = NULL ) return ldb_oom ( ldb ) ;
2009-05-31 16:19:11 +02:00
2007-12-17 04:22:44 +01:00
while ( ( sdn = ldb_dn_get_parent ( local_ctx , sdn ) ) ) {
2008-09-23 14:30:06 -04:00
ret = ldb_search ( ldb , local_ctx , & res , sdn , LDB_SCOPE_BASE , attrs ,
2009-10-12 16:44:19 +11:00
" (|(objectClass=domain)(objectClass=builtinDomain)) " ) ;
2007-12-17 04:22:44 +01: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-23 13:52:39 -07:00
DEBUG ( 0 , ( __location__ " : %s \n " , * errstring ) ) ;
2007-12-17 04:22:44 +01: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 ;
}
2016-06-28 10:33:24 +12:00
static void pwd_timeout_debug ( struct tevent_context * unused1 ,
struct tevent_timer * unused2 ,
struct timeval unused3 ,
void * unused4 )
{
DEBUG ( 0 , ( " WARNING: check_password_complexity: password script "
" took more than 1 second to run \n " ) ) ;
}
2007-12-17 04:22:44 +01:00
/*
2009-11-06 15:15:53 +01:00
* Performs checks on a user password ( plaintext UNIX format - attribute
2009-10-24 20:21:04 +02: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 " )
*/
2016-04-01 10:10:57 +13:00
enum samr_ValidationStatus samdb_check_password ( TALLOC_CTX * mem_ctx ,
struct loadparm_context * lp_ctx ,
2019-01-22 11:33:23 +01:00
const char * account_name ,
const char * user_principal_name ,
const char * full_name ,
2016-04-01 10:10:57 +13:00
const DATA_BLOB * utf8_blob ,
2009-10-24 20:21:04 +02:00
const uint32_t pwdProperties ,
const uint32_t minPwdLength )
{
2013-02-04 09:19:54 +01:00
const char * utf8_pw = ( const char * ) utf8_blob - > data ;
size_t utf8_len = strlen_m ( utf8_pw ) ;
2016-04-01 10:10:57 +13:00
char * password_script = NULL ;
2013-02-04 09:19:54 +01:00
2009-10-24 20:21:04 +02:00
/* checks if the "minPwdLength" property is satisfied */
2013-02-04 09:19:54 +01:00
if ( minPwdLength > utf8_len ) {
2009-10-24 20:21:04 +02:00
return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT ;
2013-02-04 09:19:54 +01:00
}
2007-12-17 04:22:44 +01:00
2009-11-06 15:15:53 +01:00
/* checks the password complexity */
2013-02-04 09:19:54 +01:00
if ( ! ( pwdProperties & DOMAIN_PASSWORD_COMPLEX ) ) {
return SAMR_VALIDATION_STATUS_SUCCESS ;
}
if ( utf8_len = = 0 ) {
2009-11-06 15:15:53 +01:00
return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH ;
2013-02-04 09:19:54 +01:00
}
2016-04-01 10:10:57 +13:00
password_script = lpcfg_check_password_script ( lp_ctx , mem_ctx ) ;
if ( password_script ! = NULL & & * password_script ! = ' \0 ' ) {
int check_ret = 0 ;
int error = 0 ;
struct tevent_context * event_ctx = NULL ;
struct tevent_req * req = NULL ;
2019-02-02 13:00:13 +01:00
int cps_stdin = - 1 ;
2016-04-01 10:10:57 +13:00
const char * const cmd [ 4 ] = {
" /bin/sh " , " -c " ,
password_script ,
NULL
} ;
event_ctx = tevent_context_init ( mem_ctx ) ;
if ( event_ctx = = NULL ) {
TALLOC_FREE ( password_script ) ;
return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR ;
}
2016-06-28 10:33:24 +12:00
/* Gives a warning after 1 second, terminates after 10 */
tevent_add_timer ( event_ctx , event_ctx ,
tevent_timeval_current_ofs ( 1 , 0 ) ,
pwd_timeout_debug , NULL ) ;
2019-01-22 11:33:23 +01:00
check_ret = setenv ( " SAMBA_CPS_ACCOUNT_NAME " , account_name , 1 ) ;
if ( check_ret ! = 0 ) {
TALLOC_FREE ( password_script ) ;
TALLOC_FREE ( event_ctx ) ;
return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR ;
}
if ( user_principal_name ! = NULL ) {
check_ret = setenv ( " SAMBA_CPS_USER_PRINCIPAL_NAME " ,
user_principal_name , 1 ) ;
} else {
unsetenv ( " SAMBA_CPS_USER_PRINCIPAL_NAME " ) ;
}
if ( check_ret ! = 0 ) {
TALLOC_FREE ( password_script ) ;
TALLOC_FREE ( event_ctx ) ;
return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR ;
}
if ( full_name ! = NULL ) {
check_ret = setenv ( " SAMBA_CPS_FULL_NAME " , full_name , 1 ) ;
} else {
unsetenv ( " SAMBA_CPS_FULL_NAME " ) ;
}
if ( check_ret ! = 0 ) {
TALLOC_FREE ( password_script ) ;
TALLOC_FREE ( event_ctx ) ;
return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR ;
}
2016-06-28 10:33:24 +12:00
req = samba_runcmd_send ( event_ctx , event_ctx ,
tevent_timeval_current_ofs ( 10 , 0 ) ,
2016-04-01 10:10:57 +13:00
100 , 100 , cmd , NULL ) ;
2019-01-22 11:33:23 +01:00
unsetenv ( " SAMBA_CPS_ACCOUNT_NAME " ) ;
unsetenv ( " SAMBA_CPS_USER_PRINCIPAL_NAME " ) ;
unsetenv ( " SAMBA_CPS_FULL_NAME " ) ;
2019-02-02 13:00:13 +01:00
if ( req = = NULL ) {
2016-04-01 10:10:57 +13:00
TALLOC_FREE ( password_script ) ;
2016-06-28 10:33:24 +12:00
TALLOC_FREE ( event_ctx ) ;
2016-04-01 10:10:57 +13:00
return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR ;
}
2019-02-02 13:00:13 +01:00
cps_stdin = samba_runcmd_export_stdin ( req ) ;
if ( write ( cps_stdin , utf8_pw , utf8_len ) ! = utf8_len ) {
close ( cps_stdin ) ;
cps_stdin = - 1 ;
TALLOC_FREE ( password_script ) ;
TALLOC_FREE ( event_ctx ) ;
return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR ;
}
close ( cps_stdin ) ;
cps_stdin = - 1 ;
2016-04-01 10:10:57 +13:00
if ( ! tevent_req_poll ( req , event_ctx ) ) {
TALLOC_FREE ( password_script ) ;
2016-06-28 10:33:24 +12:00
TALLOC_FREE ( event_ctx ) ;
2016-04-01 10:10:57 +13:00
return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR ;
}
check_ret = samba_runcmd_recv ( req , & error ) ;
2016-06-28 10:33:24 +12:00
TALLOC_FREE ( event_ctx ) ;
2016-04-01 10:10:57 +13:00
2016-06-28 10:33:24 +12:00
if ( error = = ETIMEDOUT ) {
DEBUG ( 0 , ( " check_password_complexity: check password script took too long! \n " ) ) ;
TALLOC_FREE ( password_script ) ;
return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR ;
2018-11-15 10:40:50 +01:00
}
DEBUG ( 5 , ( " check_password_complexity: check password script (%s) "
" returned [%d] \n " , password_script , check_ret ) ) ;
if ( check_ret ! = 0 ) {
DEBUG ( 1 , ( " check_password_complexity: "
" check password script said new password is not good "
" enough! \n " ) ) ;
TALLOC_FREE ( password_script ) ;
return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH ;
2016-04-01 10:10:57 +13:00
}
2016-06-28 10:33:24 +12:00
TALLOC_FREE ( password_script ) ;
2016-04-01 10:10:57 +13:00
return SAMR_VALIDATION_STATUS_SUCCESS ;
}
TALLOC_FREE ( password_script ) ;
2017-08-10 10:13:24 +12:00
/*
* Here are the standard AD password quality rules , which we
* run after the script .
*/
2013-02-04 09:19:54 +01:00
if ( ! check_password_quality ( utf8_pw ) ) {
return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH ;
}
2009-10-24 20:21:04 +02:00
return SAMR_VALIDATION_STATUS_SUCCESS ;
}
2009-09-26 12:09:07 +02:00
/*
* Callback for " samdb_set_password " password change
*/
int samdb_set_password_callback ( struct ldb_request * req , struct ldb_reply * ares )
{
int ret ;
if ( ! ares ) {
return ldb_request_done ( req , LDB_ERR_OPERATIONS_ERROR ) ;
}
if ( ares - > error ! = LDB_SUCCESS ) {
ret = ares - > error ;
req - > context = talloc_steal ( req ,
ldb_reply_get_control ( ares , DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID ) ) ;
talloc_free ( ares ) ;
return ldb_request_done ( req , ret ) ;
}
if ( ares - > type ! = LDB_REPLY_DONE ) {
talloc_free ( ares ) ;
return ldb_request_done ( req , LDB_ERR_OPERATIONS_ERROR ) ;
}
req - > context = talloc_steal ( req ,
ldb_reply_get_control ( ares , DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID ) ) ;
talloc_free ( ares ) ;
return ldb_request_done ( req , LDB_SUCCESS ) ;
}
2009-10-24 20:21:04 +02:00
/*
* Sets the user password using plaintext UTF16 ( attribute " new_password " ) or
* LM ( attribute " lmNewHash " ) or NT ( attribute " ntNewHash " ) hash . Also pass
2010-08-15 20:44:28 +02:00
* the old LM and / or NT hash ( attributes " lmOldHash " / " ntOldHash " ) if it is a
2011-02-28 22:04:29 +01:00
* user change or not . The " rejectReason " gives some more information if the
2010-08-15 20:44:28 +02:00
* change failed .
2009-10-24 20:21:04 +02:00
*
2010-08-15 20:44:28 +02:00
* Results : NT_STATUS_OK , NT_STATUS_INVALID_PARAMETER , NT_STATUS_UNSUCCESSFUL ,
2009-09-26 12:09:07 +02:00
* NT_STATUS_WRONG_PASSWORD , NT_STATUS_PASSWORD_RESTRICTION
2009-10-24 20:21:04 +02:00
*/
2015-02-05 10:42:08 +00:00
static NTSTATUS samdb_set_password_internal ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx ,
2009-10-24 19:31:01 +02:00
struct ldb_dn * user_dn , struct ldb_dn * domain_dn ,
2008-10-16 12:48:16 +11:00
const DATA_BLOB * new_password ,
2010-08-15 21:26:07 +02:00
const struct samr_Password * lmNewHash ,
const struct samr_Password * ntNewHash ,
2010-08-15 20:44:28 +02:00
const struct samr_Password * lmOldHash ,
const struct samr_Password * ntOldHash ,
2009-09-25 22:44:00 +02:00
enum samPwdChangeReason * reject_reason ,
2015-02-05 10:42:08 +00:00
struct samr_DomInfo1 * * _dominfo ,
bool permit_interdomain_trust )
2007-12-17 04:22:44 +01:00
{
2009-09-26 12:09:07 +02:00
struct ldb_message * msg ;
struct ldb_message_element * el ;
struct ldb_request * req ;
struct dsdb_control_password_change_status * pwd_stat = NULL ;
int ret ;
2012-12-10 23:56:47 +01:00
bool hash_values = false ;
2010-08-15 18:05:29 +02:00
NTSTATUS status = NT_STATUS_OK ;
2007-12-17 04:22:44 +01:00
2009-09-26 12:09:07 +02:00
# define CHECK_RET(x) \
if ( x ! = LDB_SUCCESS ) { \
talloc_free ( msg ) ; \
return NT_STATUS_NO_MEMORY ; \
}
2007-12-17 04:22:44 +01:00
2009-09-26 12:09:07 +02:00
msg = ldb_msg_new ( mem_ctx ) ;
if ( msg = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
msg - > dn = user_dn ;
if ( ( new_password ! = NULL )
& & ( ( lmNewHash = = NULL ) & & ( ntNewHash = = NULL ) ) ) {
/* we have the password as plaintext UTF16 */
2010-10-14 21:54:51 +02:00
CHECK_RET ( ldb_msg_add_value ( msg , " clearTextPassword " ,
new_password , NULL ) ) ;
2009-09-26 12:09:07 +02:00
el = ldb_msg_find_element ( msg , " clearTextPassword " ) ;
el - > flags = LDB_FLAG_MOD_REPLACE ;
} else if ( ( new_password = = NULL )
& & ( ( lmNewHash ! = NULL ) | | ( ntNewHash ! = NULL ) ) ) {
/* we have a password as LM and/or NT hash */
if ( lmNewHash ! = NULL ) {
CHECK_RET ( samdb_msg_add_hash ( ldb , mem_ctx , msg ,
" dBCSPwd " , lmNewHash ) ) ;
el = ldb_msg_find_element ( msg , " dBCSPwd " ) ;
el - > flags = LDB_FLAG_MOD_REPLACE ;
2007-12-17 04:22:44 +01:00
}
2009-09-26 12:09:07 +02:00
if ( ntNewHash ! = NULL ) {
CHECK_RET ( samdb_msg_add_hash ( ldb , mem_ctx , msg ,
" unicodePwd " , ntNewHash ) ) ;
el = ldb_msg_find_element ( msg , " unicodePwd " ) ;
el - > flags = LDB_FLAG_MOD_REPLACE ;
2007-12-17 04:22:44 +01:00
}
2012-12-10 23:56:47 +01:00
hash_values = true ;
2009-09-26 12:09:07 +02:00
} else {
/* the password wasn't specified correctly */
talloc_free ( msg ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
2007-12-17 04:22:44 +01:00
2009-09-26 12:09:07 +02:00
/* build modify request */
ret = ldb_build_mod_req ( & req , ldb , mem_ctx , msg , NULL , NULL ,
samdb_set_password_callback , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( msg ) ;
return NT_STATUS_NO_MEMORY ;
}
2010-08-15 20:44:28 +02:00
/* A password change operation */
if ( ( ntOldHash ! = NULL ) | | ( lmOldHash ! = NULL ) ) {
struct dsdb_control_password_change * change ;
change = talloc ( req , struct dsdb_control_password_change ) ;
if ( change = = NULL ) {
talloc_free ( req ) ;
talloc_free ( msg ) ;
return NT_STATUS_NO_MEMORY ;
}
change - > old_nt_pwd_hash = ntOldHash ;
change - > old_lm_pwd_hash = lmOldHash ;
2009-12-03 10:48:44 +01:00
ret = ldb_request_add_control ( req ,
2010-08-15 19:52:18 +02:00
DSDB_CONTROL_PASSWORD_CHANGE_OID ,
2010-08-15 20:44:28 +02:00
true , change ) ;
2009-12-03 10:48:44 +01:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( req ) ;
talloc_free ( msg ) ;
return NT_STATUS_NO_MEMORY ;
}
}
2012-12-10 23:56:47 +01:00
if ( hash_values ) {
ret = ldb_request_add_control ( req ,
DSDB_CONTROL_PASSWORD_HASH_VALUES_OID ,
true , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( req ) ;
talloc_free ( msg ) ;
return NT_STATUS_NO_MEMORY ;
}
2009-09-26 12:09:07 +02:00
}
2015-02-05 10:42:08 +00:00
if ( permit_interdomain_trust ) {
ret = ldb_request_add_control ( req ,
DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID ,
false , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( req ) ;
talloc_free ( msg ) ;
return NT_STATUS_NO_MEMORY ;
}
}
2009-09-26 12:09:07 +02:00
ret = ldb_request_add_control ( req ,
DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID ,
true , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( req ) ;
talloc_free ( msg ) ;
return NT_STATUS_NO_MEMORY ;
2007-12-17 04:22:44 +01:00
}
2009-09-26 12:09:07 +02:00
ret = dsdb_autotransaction_request ( ldb , req ) ;
2007-12-17 04:22:44 +01:00
2009-09-26 12:09:07 +02:00
if ( req - > context ! = NULL ) {
2013-12-02 15:44:37 +13:00
struct ldb_control * control = talloc_get_type_abort ( req - > context ,
struct ldb_control ) ;
pwd_stat = talloc_get_type_abort ( control - > data ,
struct dsdb_control_password_change_status ) ;
talloc_steal ( mem_ctx , pwd_stat ) ;
2009-05-25 15:23:54 +10:00
}
2009-09-26 12:09:07 +02:00
talloc_free ( req ) ;
talloc_free ( msg ) ;
/* Sets the domain info (if requested) */
2009-09-23 19:23:17 +02:00
if ( _dominfo ! = NULL ) {
2007-12-17 04:22:44 +01:00
struct samr_DomInfo1 * dominfo ;
2009-09-26 12:09:07 +02:00
dominfo = talloc_zero ( mem_ctx , struct samr_DomInfo1 ) ;
2007-12-17 04:22:44 +01:00
if ( dominfo = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2009-05-31 16:19:11 +02:00
2009-09-26 12:09:07 +02:00
if ( pwd_stat ! = NULL ) {
dominfo - > min_password_length = pwd_stat - > domain_data . minPwdLength ;
dominfo - > password_properties = pwd_stat - > domain_data . pwdProperties ;
dominfo - > password_history_length = pwd_stat - > domain_data . pwdHistoryLength ;
dominfo - > max_password_age = pwd_stat - > domain_data . maxPwdAge ;
dominfo - > min_password_age = pwd_stat - > domain_data . minPwdAge ;
2007-12-17 04:22:44 +01:00
}
2008-10-16 12:48:16 +11:00
2009-09-26 12:09:07 +02:00
* _dominfo = dominfo ;
2007-12-17 04:22:44 +01:00
}
2009-09-26 12:09:07 +02:00
if ( reject_reason ! = NULL ) {
if ( pwd_stat ! = NULL ) {
* reject_reason = pwd_stat - > reject_reason ;
} else {
* reject_reason = SAM_PWD_CHANGE_NO_ERROR ;
2007-12-17 04:22:44 +01:00
}
}
2009-09-26 12:09:07 +02:00
if ( pwd_stat ! = NULL ) {
talloc_free ( pwd_stat ) ;
}
2007-12-17 04:22:44 +01:00
2010-08-15 18:05:29 +02:00
if ( ret = = LDB_ERR_CONSTRAINT_VIOLATION ) {
const char * errmsg = ldb_errstring ( ldb ) ;
char * endptr = NULL ;
2015-12-03 15:24:21 +01:00
WERROR werr = WERR_GEN_FAILURE ;
2010-08-15 18:05:29 +02:00
status = NT_STATUS_UNSUCCESSFUL ;
if ( errmsg ! = NULL ) {
werr = W_ERROR ( strtol ( errmsg , & endptr , 16 ) ) ;
2016-01-25 16:39:59 +01:00
DBG_WARNING ( " %s \n " , errmsg ) ;
2010-08-15 18:05:29 +02:00
}
if ( endptr ! = errmsg ) {
if ( W_ERROR_EQUAL ( werr , WERR_INVALID_PASSWORD ) ) {
status = NT_STATUS_WRONG_PASSWORD ;
}
if ( W_ERROR_EQUAL ( werr , WERR_PASSWORD_RESTRICTION ) ) {
2010-08-15 19:45:29 +02:00
status = NT_STATUS_PASSWORD_RESTRICTION ;
}
2010-08-15 18:05:29 +02:00
}
2010-08-14 17:11:40 +02:00
} else if ( ret = = LDB_ERR_NO_SUCH_OBJECT ) {
2010-08-15 18:05:29 +02:00
/* don't let the caller know if an account doesn't exist */
2010-08-14 17:11:40 +02:00
status = NT_STATUS_WRONG_PASSWORD ;
2013-11-06 15:54:17 +13:00
} else if ( ret = = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS ) {
status = NT_STATUS_ACCESS_DENIED ;
2009-09-26 12:09:07 +02:00
} else if ( ret ! = LDB_SUCCESS ) {
2013-11-06 15:54:17 +13:00
DEBUG ( 1 , ( " Failed to set password on %s: %s \n " ,
2016-09-06 11:08:04 +02:00
ldb_dn_get_linearized ( user_dn ) ,
2013-11-06 15:54:17 +13:00
ldb_errstring ( ldb ) ) ) ;
2009-09-26 12:09:07 +02:00
status = NT_STATUS_UNSUCCESSFUL ;
2007-12-17 04:22:44 +01:00
}
2009-09-26 12:09:07 +02:00
return status ;
2007-12-17 04:22:44 +01:00
}
2015-02-05 10:42:08 +00:00
NTSTATUS samdb_set_password ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx ,
struct ldb_dn * user_dn , struct ldb_dn * domain_dn ,
const DATA_BLOB * new_password ,
const struct samr_Password * lmNewHash ,
const struct samr_Password * ntNewHash ,
const struct samr_Password * lmOldHash ,
const struct samr_Password * ntOldHash ,
enum samPwdChangeReason * reject_reason ,
struct samr_DomInfo1 * * _dominfo )
{
return samdb_set_password_internal ( ldb , mem_ctx ,
user_dn , domain_dn ,
new_password ,
lmNewHash , ntNewHash ,
lmOldHash , ntOldHash ,
reject_reason , _dominfo ,
false ) ; /* reject trusts */
}
2007-12-17 04:22:44 +01:00
/*
2009-10-24 19:31:01 +02:00
* Sets the user password using plaintext UTF16 ( attribute " new_password " ) or
* LM ( attribute " lmNewHash " ) or NT ( attribute " ntNewHash " ) hash . Also pass
2010-08-15 20:44:28 +02:00
* the old LM and / or NT hash ( attributes " lmOldHash " / " ntOldHash " ) if it is a
2011-02-28 22:04:29 +01:00
* user change or not . The " rejectReason " gives some more information if the
2010-08-15 20:44:28 +02:00
* change failed .
2009-10-24 19:31:01 +02:00
*
* 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 ,
2010-08-16 18:45:26 +02:00
* NT_STATUS_WRONG_PASSWORD , NT_STATUS_PASSWORD_RESTRICTION ,
* NT_STATUS_TRANSACTION_ABORTED , NT_STATUS_NO_SUCH_USER
2009-10-24 19:31:01 +02:00
*/
NTSTATUS samdb_set_password_sid ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx ,
2007-12-17 04:22:44 +01:00
const struct dom_sid * user_sid ,
2015-02-05 12:09:34 +01:00
const uint32_t * new_version , /* optional for trusts */
2009-10-24 19:31:01 +02:00
const DATA_BLOB * new_password ,
2010-08-15 21:26:07 +02:00
const struct samr_Password * lmNewHash ,
const struct samr_Password * ntNewHash ,
2010-08-15 20:44:28 +02:00
const struct samr_Password * lmOldHash ,
const struct samr_Password * ntOldHash ,
2009-09-25 22:44:00 +02:00
enum samPwdChangeReason * reject_reason ,
2007-12-17 04:22:44 +01:00
struct samr_DomInfo1 * * _dominfo )
{
2015-02-05 10:42:08 +00:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2007-12-17 04:22:44 +01:00
NTSTATUS nt_status ;
2015-02-05 10:42:08 +00:00
const char * const user_attrs [ ] = {
2015-02-05 10:42:08 +00:00
" userAccountControl " ,
" sAMAccountName " ,
2015-02-05 10:42:08 +00:00
NULL
} ;
struct ldb_message * user_msg = NULL ;
2007-12-17 04:22:44 +01:00
int ret ;
2015-02-05 10:42:08 +00:00
uint32_t uac = 0 ;
2007-12-17 04:22:44 +01:00
2009-10-24 19:31:01 +02:00
ret = ldb_transaction_start ( ldb ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 1 , ( " Failed to start transaction: %s \n " , ldb_errstring ( ldb ) ) ) ;
2015-02-05 10:42:08 +00:00
TALLOC_FREE ( frame ) ;
2007-12-17 04:22:44 +01:00
return NT_STATUS_TRANSACTION_ABORTED ;
}
2015-02-05 10:42:08 +00:00
ret = dsdb_search_one ( ldb , frame , & user_msg , ldb_get_default_basedn ( ldb ) ,
LDB_SCOPE_SUBTREE , user_attrs , 0 ,
" (&(objectSid=%s)(objectClass=user)) " ,
ldap_encode_ndr_dom_sid ( frame , user_sid ) ) ;
if ( ret ! = LDB_SUCCESS ) {
2009-10-24 19:31:01 +02:00
ldb_transaction_cancel ( ldb ) ;
2015-02-05 10:42:08 +00:00
DEBUG ( 3 , ( " samdb_set_password_sid: SID[%s] not found in samdb %s - %s, "
" returning NO_SUCH_USER \n " ,
dom_sid_string ( frame , user_sid ) ,
ldb_strerror ( ret ) , ldb_errstring ( ldb ) ) ) ;
TALLOC_FREE ( frame ) ;
2007-12-17 04:22:44 +01:00
return NT_STATUS_NO_SUCH_USER ;
}
2015-02-05 10:42:08 +00:00
uac = ldb_msg_find_attr_as_uint ( user_msg , " userAccountControl " , 0 ) ;
if ( ! ( uac & UF_ACCOUNT_TYPE_MASK ) ) {
ldb_transaction_cancel ( ldb ) ;
DEBUG ( 1 , ( " samdb_set_password_sid: invalid "
" userAccountControl[0x%08X] for SID[%s] DN[%s], "
" returning NO_SUCH_USER \n " ,
( unsigned ) uac , dom_sid_string ( frame , user_sid ) ,
ldb_dn_get_linearized ( user_msg - > dn ) ) ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_SUCH_USER ;
}
if ( uac & UF_INTERDOMAIN_TRUST_ACCOUNT ) {
const char * const tdo_attrs [ ] = {
" trustAuthIncoming " ,
" trustDirection " ,
NULL
} ;
struct ldb_message * tdo_msg = NULL ;
const char * account_name = NULL ;
uint32_t trust_direction ;
uint32_t i ;
const struct ldb_val * old_val = NULL ;
2019-01-14 13:13:09 +01:00
struct trustAuthInOutBlob old_blob = {
. count = 0 ,
} ;
2015-02-05 10:42:08 +00:00
uint32_t old_version = 0 ;
struct AuthenticationInformation * old_version_a = NULL ;
uint32_t _new_version = 0 ;
2019-01-14 13:13:09 +01:00
struct trustAuthInOutBlob new_blob = {
. count = 0 ,
} ;
struct ldb_val new_val = {
. length = 0 ,
} ;
2015-02-05 10:42:08 +00:00
struct timeval tv = timeval_current ( ) ;
NTTIME now = timeval_to_nttime ( & tv ) ;
enum ndr_err_code ndr_err ;
if ( new_password = = NULL & & ntNewHash = = NULL ) {
ldb_transaction_cancel ( ldb ) ;
DEBUG ( 1 , ( " samdb_set_password_sid: "
" no new password provided "
" sAMAccountName for SID[%s] DN[%s], "
" returning INVALID_PARAMETER \n " ,
dom_sid_string ( frame , user_sid ) ,
ldb_dn_get_linearized ( user_msg - > dn ) ) ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
if ( new_password ! = NULL & & ntNewHash ! = NULL ) {
ldb_transaction_cancel ( ldb ) ;
DEBUG ( 1 , ( " samdb_set_password_sid: "
" two new passwords provided "
" sAMAccountName for SID[%s] DN[%s], "
" returning INVALID_PARAMETER \n " ,
dom_sid_string ( frame , user_sid ) ,
ldb_dn_get_linearized ( user_msg - > dn ) ) ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
if ( new_password ! = NULL & & ( new_password - > length % 2 ) ) {
ldb_transaction_cancel ( ldb ) ;
DEBUG ( 2 , ( " samdb_set_password_sid: "
" invalid utf16 length (%zu) "
" sAMAccountName for SID[%s] DN[%s], "
" returning WRONG_PASSWORD \n " ,
new_password - > length ,
dom_sid_string ( frame , user_sid ) ,
ldb_dn_get_linearized ( user_msg - > dn ) ) ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_WRONG_PASSWORD ;
}
if ( new_password ! = NULL & & new_password - > length > = 500 ) {
ldb_transaction_cancel ( ldb ) ;
DEBUG ( 2 , ( " samdb_set_password_sid: "
" utf16 password too long (%zu) "
" sAMAccountName for SID[%s] DN[%s], "
" returning WRONG_PASSWORD \n " ,
new_password - > length ,
dom_sid_string ( frame , user_sid ) ,
ldb_dn_get_linearized ( user_msg - > dn ) ) ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_WRONG_PASSWORD ;
}
account_name = ldb_msg_find_attr_as_string ( user_msg ,
" sAMAccountName " , NULL ) ;
if ( account_name = = NULL ) {
ldb_transaction_cancel ( ldb ) ;
DEBUG ( 1 , ( " samdb_set_password_sid: missing "
" sAMAccountName for SID[%s] DN[%s], "
" returning NO_SUCH_USER \n " ,
dom_sid_string ( frame , user_sid ) ,
ldb_dn_get_linearized ( user_msg - > dn ) ) ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_SUCH_USER ;
}
nt_status = dsdb_trust_search_tdo_by_type ( ldb ,
SEC_CHAN_DOMAIN ,
account_name ,
tdo_attrs ,
frame , & tdo_msg ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
ldb_transaction_cancel ( ldb ) ;
DEBUG ( 1 , ( " samdb_set_password_sid: dsdb_trust_search_tdo "
" failed(%s) for sAMAccountName[%s] SID[%s] DN[%s], "
" returning INTERNAL_DB_CORRUPTION \n " ,
nt_errstr ( nt_status ) , account_name ,
dom_sid_string ( frame , user_sid ) ,
ldb_dn_get_linearized ( user_msg - > dn ) ) ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
trust_direction = ldb_msg_find_attr_as_int ( tdo_msg ,
" trustDirection " , 0 ) ;
if ( ! ( trust_direction & LSA_TRUST_DIRECTION_INBOUND ) ) {
ldb_transaction_cancel ( ldb ) ;
DEBUG ( 1 , ( " samdb_set_password_sid: direction[0x%08X] is "
" not inbound for sAMAccountName[%s] "
" DN[%s] TDO[%s], "
" returning INTERNAL_DB_CORRUPTION \n " ,
( unsigned ) trust_direction ,
account_name ,
ldb_dn_get_linearized ( user_msg - > dn ) ,
ldb_dn_get_linearized ( tdo_msg - > dn ) ) ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
old_val = ldb_msg_find_ldb_val ( tdo_msg , " trustAuthIncoming " ) ;
if ( old_val ! = NULL ) {
ndr_err = ndr_pull_struct_blob ( old_val , frame , & old_blob ,
( ndr_pull_flags_fn_t ) ndr_pull_trustAuthInOutBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
ldb_transaction_cancel ( ldb ) ;
DEBUG ( 1 , ( " samdb_set_password_sid: "
" failed(%s) to parse "
" trustAuthOutgoing sAMAccountName[%s] "
" DN[%s] TDO[%s], "
" returning INTERNAL_DB_CORRUPTION \n " ,
ndr_map_error2string ( ndr_err ) ,
account_name ,
ldb_dn_get_linearized ( user_msg - > dn ) ,
ldb_dn_get_linearized ( tdo_msg - > dn ) ) ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
}
for ( i = old_blob . current . count ; i > 0 ; i - - ) {
struct AuthenticationInformation * a =
& old_blob . current . array [ i - 1 ] ;
switch ( a - > AuthType ) {
case TRUST_AUTH_TYPE_NONE :
if ( i = = old_blob . current . count ) {
/*
* remove TRUST_AUTH_TYPE_NONE at the
* end
*/
old_blob . current . count - - ;
}
break ;
case TRUST_AUTH_TYPE_VERSION :
old_version_a = a ;
old_version = a - > AuthInfo . version . version ;
break ;
case TRUST_AUTH_TYPE_CLEAR :
break ;
case TRUST_AUTH_TYPE_NT4OWF :
break ;
}
}
if ( new_version = = NULL ) {
_new_version = 0 ;
new_version = & _new_version ;
}
if ( old_version_a ! = NULL & & * new_version ! = ( old_version + 1 ) ) {
old_version_a - > LastUpdateTime = now ;
old_version_a - > AuthType = TRUST_AUTH_TYPE_NONE ;
}
new_blob . count = MAX ( old_blob . current . count , 2 ) ;
new_blob . current . array = talloc_zero_array ( frame ,
struct AuthenticationInformation ,
new_blob . count ) ;
if ( new_blob . current . array = = NULL ) {
ldb_transaction_cancel ( ldb ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
new_blob . previous . array = talloc_zero_array ( frame ,
struct AuthenticationInformation ,
new_blob . count ) ;
if ( new_blob . current . array = = NULL ) {
ldb_transaction_cancel ( ldb ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
for ( i = 0 ; i < old_blob . current . count ; i + + ) {
struct AuthenticationInformation * o =
& old_blob . current . array [ i ] ;
struct AuthenticationInformation * p =
& new_blob . previous . array [ i ] ;
* p = * o ;
new_blob . previous . count + + ;
}
for ( ; i < new_blob . count ; i + + ) {
struct AuthenticationInformation * pi =
& new_blob . previous . array [ i ] ;
if ( i = = 0 ) {
/*
* new_blob . previous is still empty so
* we ' ll do new_blob . previous = new_blob . current
* below .
*/
break ;
}
pi - > LastUpdateTime = now ;
pi - > AuthType = TRUST_AUTH_TYPE_NONE ;
new_blob . previous . count + + ;
}
for ( i = 0 ; i < new_blob . count ; i + + ) {
struct AuthenticationInformation * ci =
& new_blob . current . array [ i ] ;
ci - > LastUpdateTime = now ;
switch ( i ) {
case 0 :
if ( ntNewHash ! = NULL ) {
ci - > AuthType = TRUST_AUTH_TYPE_NT4OWF ;
ci - > AuthInfo . nt4owf . password = * ntNewHash ;
break ;
}
ci - > AuthType = TRUST_AUTH_TYPE_CLEAR ;
ci - > AuthInfo . clear . size = new_password - > length ;
ci - > AuthInfo . clear . password = new_password - > data ;
break ;
case 1 :
ci - > AuthType = TRUST_AUTH_TYPE_VERSION ;
ci - > AuthInfo . version . version = * new_version ;
break ;
default :
ci - > AuthType = TRUST_AUTH_TYPE_NONE ;
break ;
}
new_blob . current . count + + ;
}
if ( new_blob . previous . count = = 0 ) {
TALLOC_FREE ( new_blob . previous . array ) ;
new_blob . previous = new_blob . current ;
}
ndr_err = ndr_push_struct_blob ( & new_val , frame , & new_blob ,
( ndr_push_flags_fn_t ) ndr_push_trustAuthInOutBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
ldb_transaction_cancel ( ldb ) ;
DEBUG ( 1 , ( " samdb_set_password_sid: "
" failed(%s) to generate "
" trustAuthOutgoing sAMAccountName[%s] "
" DN[%s] TDO[%s], "
" returning UNSUCCESSFUL \n " ,
ndr_map_error2string ( ndr_err ) ,
account_name ,
ldb_dn_get_linearized ( user_msg - > dn ) ,
ldb_dn_get_linearized ( tdo_msg - > dn ) ) ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_UNSUCCESSFUL ;
}
tdo_msg - > num_elements = 0 ;
TALLOC_FREE ( tdo_msg - > elements ) ;
ret = ldb_msg_add_empty ( tdo_msg , " trustAuthIncoming " ,
LDB_FLAG_MOD_REPLACE , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_transaction_cancel ( ldb ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
ret = ldb_msg_add_value ( tdo_msg , " trustAuthIncoming " ,
& new_val , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_transaction_cancel ( ldb ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
ret = ldb_modify ( ldb , tdo_msg ) ;
if ( ret ! = LDB_SUCCESS ) {
nt_status = dsdb_ldb_err_to_ntstatus ( ret ) ;
ldb_transaction_cancel ( ldb ) ;
DEBUG ( 1 , ( " samdb_set_password_sid: "
" failed to replace "
" trustAuthOutgoing sAMAccountName[%s] "
" DN[%s] TDO[%s], "
" %s - %s \n " ,
account_name ,
ldb_dn_get_linearized ( user_msg - > dn ) ,
ldb_dn_get_linearized ( tdo_msg - > dn ) ,
nt_errstr ( nt_status ) , ldb_errstring ( ldb ) ) ) ;
TALLOC_FREE ( frame ) ;
return nt_status ;
}
}
nt_status = samdb_set_password_internal ( ldb , mem_ctx ,
user_msg - > dn , NULL ,
new_password ,
lmNewHash , ntNewHash ,
lmOldHash , ntOldHash ,
reject_reason , _dominfo ,
true ) ; /* permit trusts */
2007-12-17 04:22:44 +01:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2009-10-24 19:31:01 +02:00
ldb_transaction_cancel ( ldb ) ;
2015-02-05 10:42:08 +00:00
TALLOC_FREE ( frame ) ;
2007-12-17 04:22:44 +01:00
return nt_status ;
}
2009-05-31 16:19:11 +02:00
2009-10-24 19:31:01 +02:00
ret = ldb_transaction_commit ( ldb ) ;
if ( ret ! = LDB_SUCCESS ) {
2007-12-17 04:22:44 +01:00
DEBUG ( 0 , ( " Failed to commit transaction to change password on %s: %s \n " ,
2015-02-05 10:42:08 +00:00
ldb_dn_get_linearized ( user_msg - > dn ) ,
2009-10-24 19:31:01 +02:00
ldb_errstring ( ldb ) ) ) ;
2015-02-05 10:42:08 +00:00
TALLOC_FREE ( frame ) ;
2007-12-17 04:22:44 +01:00
return NT_STATUS_TRANSACTION_ABORTED ;
}
2009-12-13 16:13:34 +01:00
2015-02-05 10:42:08 +00:00
TALLOC_FREE ( frame ) ;
2007-12-17 04:22:44 +01: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 21:38:21 +11:00
char * sidstr ;
2007-12-17 04:22:44 +01:00
int ret ;
2009-05-31 16:19:11 +02:00
2007-12-17 04:22:44 +01:00
sidstr = dom_sid_string ( mem_ctx , sid ) ;
NT_STATUS_HAVE_NO_MEMORY ( sidstr ) ;
2009-05-31 16:19:11 +02:00
2007-12-17 04:22:44 +01:00
/* We might have to create a ForeignSecurityPrincipal, even if this user
* is in our own domain */
2009-05-31 16:19:11 +02:00
2009-12-30 21:38:21 +11:00
msg = ldb_msg_new ( sidstr ) ;
2007-12-17 04:22:44 +01:00
if ( msg = = NULL ) {
2009-12-30 21:38:21 +11:00
talloc_free ( sidstr ) ;
2007-12-17 04:22:44 +01:00
return NT_STATUS_NO_MEMORY ;
}
2009-05-31 16:19:11 +02:00
2010-04-13 08:41:10 +02:00
ret = dsdb_wellknown_dn ( sam_ctx , sidstr ,
ldb_get_default_basedn ( sam_ctx ) ,
2009-12-30 21:38:21 +11:00
DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER ,
& basedn ) ;
if ( ret ! = LDB_SUCCESS ) {
2007-12-17 04:22:44 +01:00
DEBUG ( 0 , ( " Failed to find DN for "
2009-12-30 21:38:21 +11:00
" ForeignSecurityPrincipal container - %s \n " , ldb_errstring ( sam_ctx ) ) ) ;
talloc_free ( sidstr ) ;
2007-12-17 04:22:44 +01:00
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
2009-05-31 16:19:11 +02:00
2007-12-17 04:22:44 +01:00
/* add core elements to the ldb_message for the alias */
2009-12-30 21:38:21 +11:00
msg - > dn = basedn ;
if ( ! ldb_dn_add_child_fmt ( msg - > dn , " CN=%s " , sidstr ) ) {
talloc_free ( sidstr ) ;
2007-12-17 04:22:44 +01:00
return NT_STATUS_NO_MEMORY ;
2009-12-30 21:38:21 +11:00
}
2009-05-31 16:19:11 +02:00
2010-10-14 22:26:44 +02:00
ret = ldb_msg_add_string ( msg , " objectClass " ,
" foreignSecurityPrincipal " ) ;
2010-10-14 22:36:07 +02:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( sidstr ) ;
return NT_STATUS_NO_MEMORY ;
}
2009-05-31 16:19:11 +02:00
2007-12-17 04:22:44 +01:00
/* create the alias */
ret = ldb_add ( sam_ctx , msg ) ;
2009-12-30 21:38:21 +11:00
if ( ret ! = LDB_SUCCESS ) {
2007-12-17 04:22:44 +01:00
DEBUG ( 0 , ( " Failed to create foreignSecurityPrincipal "
" record %s: %s \n " ,
ldb_dn_get_linearized ( msg - > dn ) ,
ldb_errstring ( sam_ctx ) ) ) ;
2009-12-30 21:38:21 +11:00
talloc_free ( sidstr ) ;
2007-12-17 04:22:44 +01:00
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
2009-12-30 21:38:21 +11:00
* ret_dn = talloc_steal ( mem_ctx , msg - > dn ) ;
talloc_free ( sidstr ) ;
2007-12-17 04:22:44 +01: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 20:14:41 +01:00
unsigned int i ;
2007-12-17 04:22:44 +01:00
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
const char * binary_encoded ;
2012-08-14 15:54:26 +10:00
const char * const * split_realm ;
2007-12-17 04:22:44 +01:00
struct ldb_dn * dn ;
2009-05-31 16:19:11 +02:00
2007-12-17 04:22:44 +01:00
if ( ! tmp_ctx ) {
return NULL ;
}
2009-05-31 16:19:11 +02:00
2012-08-14 15:54:26 +10:00
split_realm = ( const char * const * ) str_list_make ( tmp_ctx , dns_domain , " . " ) ;
2007-12-17 04:22:44 +01: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 21:39:24 +11:00
talloc_free ( tmp_ctx ) ;
2007-12-17 04:22:44 +01:00
return NULL ;
}
2009-12-30 21:39:24 +11:00
talloc_free ( tmp_ctx ) ;
2007-12-17 04:22:44 +01:00
return dn ;
}
2009-12-30 21:39:24 +11:00
2011-08-22 17:00:54 +10:00
/*
Find the DNS equivalent of a DN , in dotted DNS form
*/
char * samdb_dn_to_dns_domain ( TALLOC_CTX * mem_ctx , struct ldb_dn * dn )
{
int i , num_components = ldb_dn_get_comp_num ( dn ) ;
char * dns_name = talloc_strdup ( mem_ctx , " " ) ;
if ( dns_name = = NULL ) {
return NULL ;
}
for ( i = 0 ; i < num_components ; i + + ) {
2011-08-22 17:29:08 +10:00
const struct ldb_val * v = ldb_dn_get_component_val ( dn , i ) ;
2011-08-22 17:00:54 +10:00
char * s ;
if ( v = = NULL ) {
talloc_free ( dns_name ) ;
return NULL ;
}
2011-08-22 17:29:08 +10:00
s = talloc_asprintf_append_buffer ( dns_name , " %*.*s. " ,
( int ) v - > length , ( int ) v - > length , ( char * ) v - > data ) ;
2011-08-22 17:00:54 +10:00
if ( s = = NULL ) {
talloc_free ( dns_name ) ;
return NULL ;
}
dns_name = s ;
}
/* remove the last '.' */
if ( dns_name [ 0 ] ! = 0 ) {
dns_name [ strlen ( dns_name ) - 1 ] = 0 ;
}
return dns_name ;
}
2011-08-22 17:29:08 +10:00
/*
Find the DNS _msdcs name for a given NTDS GUID . The resulting DNS
name is based on the forest DNS name
*/
char * samdb_ntds_msdcs_dns_name ( struct ldb_context * samdb ,
TALLOC_CTX * mem_ctx ,
const struct GUID * ntds_guid )
{
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
const char * guid_str ;
struct ldb_dn * forest_dn ;
const char * dnsforest ;
char * ret ;
guid_str = GUID_string ( tmp_ctx , ntds_guid ) ;
if ( guid_str = = NULL ) {
talloc_free ( tmp_ctx ) ;
return NULL ;
}
forest_dn = ldb_get_root_basedn ( samdb ) ;
if ( forest_dn = = NULL ) {
talloc_free ( tmp_ctx ) ;
return NULL ;
}
dnsforest = samdb_dn_to_dns_domain ( tmp_ctx , forest_dn ) ;
if ( dnsforest = = NULL ) {
talloc_free ( tmp_ctx ) ;
return NULL ;
}
ret = talloc_asprintf ( mem_ctx , " %s._msdcs.%s " , guid_str , dnsforest ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
}
2011-08-22 17:00:54 +10:00
2007-12-17 04:22:44 +01: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 14:30:06 -04:00
int ret_domain = ldb_search ( ldb , mem_ctx ,
2007-12-17 04:22:44 +01:00
& res_domain_ref ,
samdb_partitions_dn ( ldb , mem_ctx ) ,
LDB_SCOPE_ONELEVEL ,
domain_ref_attrs ,
" (&(nETBIOSName=%s)(objectclass=crossRef)) " ,
escaped_domain ) ;
2010-08-09 19:45:45 +02:00
if ( ret_domain ! = LDB_SUCCESS ) {
2007-12-17 04:22:44 +01:00
return NULL ;
}
2009-05-31 16:19:11 +02:00
2007-12-17 04:22:44 +01:00
if ( res_domain_ref - > count = = 0 ) {
2008-09-23 14:30:06 -04:00
ret_domain = ldb_search ( ldb , mem_ctx ,
2007-12-17 04:22:44 +01:00
& res_domain_ref ,
samdb_dns_domain_to_dn ( ldb , mem_ctx , domain_name ) ,
LDB_SCOPE_BASE ,
domain_ref2_attrs ,
" (objectclass=domain) " ) ;
2010-08-09 19:45:45 +02:00
if ( ret_domain ! = LDB_SUCCESS ) {
2007-12-17 04:22:44 +01:00
return NULL ;
}
2009-05-31 16:19:11 +02:00
2007-12-17 04:22:44 +01:00
if ( res_domain_ref - > count = = 1 ) {
return res_domain_ref - > msgs [ 0 ] - > dn ;
}
return NULL ;
}
2009-05-31 16:19:11 +02:00
2007-12-17 04:22:44 +01: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 16:19:11 +02:00
2007-12-17 04:22:44 +01:00
return samdb_result_dn ( ldb , mem_ctx , res_domain_ref - > msgs [ 0 ] , " nCName " , NULL ) ;
}
2009-09-03 12:51:22 +10:00
/*
use a GUID to find a DN
*/
int dsdb_find_dn_by_guid ( struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx ,
2013-06-10 12:22:40 +10:00
const struct GUID * guid ,
uint32_t dsdb_flags ,
struct ldb_dn * * dn )
2009-09-03 12:51:22 +10:00
{
int ret ;
struct ldb_result * res ;
const char * attrs [ ] = { NULL } ;
2010-02-16 15:40:44 +11:00
char * guid_str = GUID_string ( mem_ctx , guid ) ;
if ( ! guid_str ) {
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2010-02-16 15:40:44 +11:00
}
2009-09-03 12:51:22 +10:00
2010-02-16 15:15:35 +11:00
ret = dsdb_search ( ldb , mem_ctx , & res , NULL , LDB_SCOPE_SUBTREE , attrs ,
DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
2010-02-16 15:40:44 +11:00
DSDB_SEARCH_SHOW_EXTENDED_DN |
2013-06-10 12:22:40 +10:00
DSDB_SEARCH_ONE_ONLY | dsdb_flags ,
2010-02-16 15:15:35 +11:00
" objectGUID=%s " , guid_str ) ;
2010-02-16 15:40:44 +11:00
talloc_free ( guid_str ) ;
2009-09-03 12:51:22 +10:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2009-12-30 21:39:24 +11:00
* dn = talloc_steal ( mem_ctx , res - > msgs [ 0 ] - > dn ) ;
2010-02-16 15:15:35 +11:00
talloc_free ( res ) ;
2009-09-03 12:51:22 +10:00
return LDB_SUCCESS ;
}
2009-09-03 18:27:29 +10:00
/*
2010-01-06 14:50:41 +11:00
use a DN to find a GUID with a given attribute name
2009-09-03 18:27:29 +10:00
*/
2010-01-06 14:50:41 +11: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 18:27:29 +10:00
{
int ret ;
struct ldb_result * res ;
2010-01-06 14:50:41 +11:00
const char * attrs [ 2 ] ;
2009-09-03 18:27:29 +10:00
TALLOC_CTX * tmp_ctx = talloc_new ( ldb ) ;
2010-01-06 14:50:41 +11:00
attrs [ 0 ] = attribute ;
attrs [ 1 ] = NULL ;
2010-09-19 22:20:08 +02:00
ret = dsdb_search_dn ( ldb , tmp_ctx , & res , dn , attrs ,
2010-10-04 17:18:19 +02:00
DSDB_SEARCH_SHOW_DELETED |
2010-09-19 22:20:08 +02:00
DSDB_SEARCH_SHOW_RECYCLED ) ;
2009-09-03 18:27:29 +10:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-09-24 07:05:07 -07:00
if ( res - > count < 1 ) {
talloc_free ( tmp_ctx ) ;
2016-01-14 11:50:56 +01:00
return ldb_error ( ldb , LDB_ERR_NO_SUCH_OBJECT , __func__ ) ;
2009-09-24 07:05:07 -07:00
}
2010-01-06 14:50:41 +11:00
* guid = samdb_result_guid ( res - > msgs [ 0 ] , attribute ) ;
2009-09-03 18:27:29 +10:00
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2009-09-12 11:09:10 +10:00
2010-01-06 14:50:41 +11: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 15: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 14:33:13 +11:00
NTSTATUS status ;
2009-11-19 15:28:37 -03:00
TALLOC_CTX * tmp_ctx = talloc_init ( " dsdb_msg_add_guid " ) ;
2009-12-10 14:33:13 +11:00
status = GUID_to_ndr_blob ( guid , tmp_ctx , & v ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-11-19 15: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-23 13:52:39 -07: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 ;
2010-09-13 22:39:50 +02:00
const char * attrs [ ] = { " objectSid " , NULL } ;
2009-09-23 13:52:39 -07:00
TALLOC_CTX * tmp_ctx = talloc_new ( ldb ) ;
struct dom_sid * s ;
ZERO_STRUCTP ( sid ) ;
2010-09-19 22:20:08 +02:00
ret = dsdb_search_dn ( ldb , tmp_ctx , & res , dn , attrs ,
2010-10-04 17:18:19 +02:00
DSDB_SEARCH_SHOW_DELETED |
2010-09-19 22:20:08 +02:00
DSDB_SEARCH_SHOW_RECYCLED ) ;
2009-09-23 13:52:39 -07:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-09-24 07:05:07 -07:00
if ( res - > count < 1 ) {
talloc_free ( tmp_ctx ) ;
2016-01-14 11:50:56 +01:00
return ldb_error ( ldb , LDB_ERR_NO_SUCH_OBJECT , __func__ ) ;
2009-09-24 07:05:07 -07:00
}
2010-09-13 22:39:50 +02:00
s = samdb_result_dom_sid ( tmp_ctx , res - > msgs [ 0 ] , " objectSid " ) ;
2009-09-23 13:52:39 -07:00
if ( s = = NULL ) {
talloc_free ( tmp_ctx ) ;
2016-01-14 11:50:56 +01:00
return ldb_error ( ldb , LDB_ERR_NO_SUCH_OBJECT , __func__ ) ;
2009-09-23 13:52:39 -07:00
}
* sid = * s ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2010-06-28 10:34:14 +03:00
/*
use a SID to find a DN
*/
int dsdb_find_dn_by_sid ( struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx ,
struct dom_sid * sid , struct ldb_dn * * dn )
{
int ret ;
struct ldb_result * res ;
const char * attrs [ ] = { NULL } ;
2010-09-13 22:41:06 +02:00
char * sid_str = ldap_encode_ndr_dom_sid ( mem_ctx , sid ) ;
2010-06-28 10:34:14 +03:00
if ( ! sid_str ) {
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2010-06-28 10:34:14 +03:00
}
ret = dsdb_search ( ldb , mem_ctx , & res , NULL , LDB_SCOPE_SUBTREE , attrs ,
DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
DSDB_SEARCH_SHOW_EXTENDED_DN |
DSDB_SEARCH_ONE_ONLY ,
2010-09-13 22:39:50 +02:00
" objectSid=%s " , sid_str ) ;
2010-06-28 10:34:14 +03:00
talloc_free ( sid_str ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
* dn = talloc_steal ( mem_ctx , res - > msgs [ 0 ] - > dn ) ;
talloc_free ( res ) ;
return LDB_SUCCESS ;
}
2009-09-12 11:09:10 +10: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 20:14:41 +01:00
unsigned int i ;
2009-09-12 11:09:10 +10:00
struct ldb_message_element * el ;
2011-09-21 08:51:20 +10:00
int ret ;
2009-09-12 11:09:10 +10:00
* r = NULL ;
* count = 0 ;
2011-09-21 08:51:20 +10:00
ret = dsdb_search_dn ( sam_ctx , tmp_ctx , & res , dn , attrs , 0 ) ;
if ( ret = = LDB_ERR_NO_SUCH_OBJECT ) {
/* partition hasn't been replicated yet */
return WERR_OK ;
}
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( " dsdb_loadreps: failed to read partition object: %s \n " , ldb_errstring ( sam_ctx ) ) ) ;
2009-09-12 11:09:10 +10:00
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
el = ldb_msg_find_element ( res - > msgs [ 0 ] , attr ) ;
if ( el = = NULL ) {
/* it's OK to be empty */
talloc_free ( tmp_ctx ) ;
return WERR_OK ;
}
* count = el - > num_values ;
* r = talloc_array ( mem_ctx , struct repsFromToBlob , * count ) ;
if ( * r = = NULL ) {
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
for ( i = 0 ; i < ( * count ) ; i + + ) {
enum ndr_err_code ndr_err ;
ndr_err = ndr_pull_struct_blob ( & el - > values [ i ] ,
2010-05-09 17:20:01 +02:00
mem_ctx ,
2009-09-12 11:09:10 +10:00
& ( * r ) [ i ] ,
( ndr_pull_flags_fn_t ) ndr_pull_repsFromToBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
}
talloc_free ( tmp_ctx ) ;
return WERR_OK ;
}
/*
save the repsFromTo blob list for a given partition GUID
attr must be " repsFrom " or " repsTo "
*/
WERROR dsdb_savereps ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx , struct ldb_dn * dn ,
const char * attr , struct repsFromToBlob * r , uint32_t count )
{
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
struct ldb_message * msg ;
struct ldb_message_element * el ;
2009-11-06 20:14:41 +01:00
unsigned int i ;
2009-09-12 11:09:10 +10:00
msg = ldb_msg_new ( tmp_ctx ) ;
msg - > dn = dn ;
if ( ldb_msg_add_empty ( msg , attr , LDB_FLAG_MOD_REPLACE , & el ) ! = LDB_SUCCESS ) {
goto failed ;
}
el - > values = talloc_array ( msg , struct ldb_val , count ) ;
if ( ! el - > values ) {
goto failed ;
}
for ( i = 0 ; i < count ; i + + ) {
struct ldb_val v ;
enum ndr_err_code ndr_err ;
2010-05-09 17:20:01 +02:00
ndr_err = ndr_push_struct_blob ( & v , tmp_ctx ,
2009-09-12 11:09:10 +10:00
& r [ i ] ,
( ndr_push_flags_fn_t ) ndr_push_repsFromToBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
goto failed ;
}
el - > num_values + + ;
el - > values [ i ] = v ;
}
2011-09-22 09:48:17 +10:00
if ( dsdb_modify ( sam_ctx , msg , 0 ) ! = LDB_SUCCESS ) {
2009-09-12 11:09:10 +10:00
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 18:13:17 +10:00
/*
2010-01-07 16:30:05 -02:00
load the uSNHighest and the uSNUrgent attributes from the @ REPLCHANGED
object for a partition
2009-09-13 18:13:17 +10:00
*/
2010-01-07 16:30:05 -02:00
int dsdb_load_partition_usn ( struct ldb_context * ldb , struct ldb_dn * dn ,
uint64_t * uSN , uint64_t * urgent_uSN )
2009-09-13 18:13:17 +10:00
{
struct ldb_request * req ;
int ret ;
TALLOC_CTX * tmp_ctx = talloc_new ( ldb ) ;
struct dsdb_control_current_partition * p_ctrl ;
struct ldb_result * res ;
res = talloc_zero ( tmp_ctx , struct ldb_result ) ;
if ( ! res ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2009-09-13 18:13:17 +10:00
}
ret = ldb_build_search_req ( & req , ldb , tmp_ctx ,
ldb_dn_new ( tmp_ctx , ldb , " @REPLCHANGED " ) ,
LDB_SCOPE_BASE ,
NULL , NULL ,
NULL ,
res , ldb_search_default_callback ,
NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
p_ctrl = talloc ( req , struct dsdb_control_current_partition ) ;
if ( p_ctrl = = NULL ) {
2010-06-21 11:02:45 +02:00
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2009-09-13 18:13:17 +10:00
}
p_ctrl - > version = DSDB_CONTROL_CURRENT_PARTITION_VERSION ;
p_ctrl - > dn = dn ;
ret = ldb_request_add_control ( req ,
DSDB_CONTROL_CURRENT_PARTITION_OID ,
false , p_ctrl ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
/* Run the new request */
ret = ldb_request ( ldb , req ) ;
if ( ret = = LDB_SUCCESS ) {
ret = ldb_wait ( req - > handle , LDB_WAIT_ALL ) ;
}
2010-10-19 22:27:54 +11:00
if ( ret = = LDB_ERR_NO_SUCH_OBJECT | | ret = = LDB_ERR_INVALID_DN_SYNTAX ) {
2009-09-16 03:43:37 -07:00
/* 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 18:13:17 +10:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
if ( res - > count < 1 ) {
* uSN = 0 ;
2010-01-07 16:30:05 -02:00
if ( urgent_uSN ) {
* urgent_uSN = 0 ;
}
2009-09-13 18:13:17 +10:00
} else {
* uSN = ldb_msg_find_attr_as_uint64 ( res - > msgs [ 0 ] , " uSNHighest " , 0 ) ;
2010-01-07 16:30:05 -02:00
if ( urgent_uSN ) {
* urgent_uSN = ldb_msg_find_attr_as_uint64 ( res - > msgs [ 0 ] , " uSNUrgent " , 0 ) ;
}
2009-09-13 18:13:17 +10:00
}
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2009-09-14 11:46:59 -07: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 19:48:13 +11:00
2010-01-09 13:11:27 +11: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-15 17:37:40 -03:00
2009-10-13 19:48:13 +11:00
/*
2010-04-15 17:37:40 -03:00
see if a computer identified by its invocationId is a RODC
2009-10-13 19:48:13 +11:00
*/
2010-04-28 17:02:55 +03:00
int samdb_is_rodc ( struct ldb_context * sam_ctx , const struct GUID * objectGUID , bool * is_rodc )
2010-04-15 17:37:40 -03:00
{
/* 1) find the DN for this servers NTDSDSA object
2 ) search for the msDS - isRODC attribute
3 ) if not present then not a RODC
4 ) if present and TRUE then is a RODC
*/
struct ldb_dn * config_dn ;
const char * attrs [ ] = { " msDS-isRODC " , NULL } ;
int ret ;
struct ldb_result * res ;
TALLOC_CTX * tmp_ctx = talloc_new ( sam_ctx ) ;
2010-03-01 14:16:59 +02:00
2010-04-15 18:54:13 -03:00
config_dn = ldb_get_config_basedn ( sam_ctx ) ;
2010-04-15 17:37:40 -03:00
if ( ! config_dn ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_operr ( sam_ctx ) ;
2010-03-01 14:16:59 +02:00
}
2010-04-15 17:37:40 -03:00
ret = dsdb_search ( sam_ctx , tmp_ctx , & res , config_dn , LDB_SCOPE_SUBTREE , attrs ,
2010-04-28 17:02:55 +03:00
DSDB_SEARCH_ONE_ONLY , " objectGUID=%s " , GUID_string ( tmp_ctx , objectGUID ) ) ;
if ( ret = = LDB_ERR_NO_SUCH_OBJECT ) {
* is_rodc = false ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2010-04-15 17:37:40 -03:00
if ( ret ! = LDB_SUCCESS ) {
2010-04-28 17:02:55 +03:00
DEBUG ( 1 , ( ( " Failed to find our own NTDS Settings object by objectGUID=%s! \n " ) ,
GUID_string ( tmp_ctx , objectGUID ) ) ) ;
2010-05-04 11:49:18 +02:00
* is_rodc = false ;
2010-04-15 17:37:40 -03:00
talloc_free ( tmp_ctx ) ;
return ret ;
2010-03-01 14:16:59 +02:00
}
2010-04-15 17:37:40 -03:00
ret = ldb_msg_find_attr_as_bool ( res - > msgs [ 0 ] , " msDS-isRODC " , 0 ) ;
* is_rodc = ( ret = = 1 ) ;
2009-10-13 19:48:13 +11:00
2010-04-15 17:37:40 -03:00
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2010-03-01 14:16:59 +02:00
2010-04-15 17:37:40 -03:00
/*
see if we are a RODC
*/
int samdb_rodc ( struct ldb_context * sam_ctx , bool * am_rodc )
{
2010-04-28 17:02:55 +03:00
const struct GUID * objectGUID ;
2010-05-11 10:34:19 +02:00
int ret ;
bool * cached ;
/* see if we have a cached copy */
cached = ( bool * ) ldb_get_opaque ( sam_ctx , " cache.am_rodc " ) ;
if ( cached ) {
* am_rodc = * cached ;
return LDB_SUCCESS ;
}
2010-04-28 17:02:55 +03:00
objectGUID = samdb_ntds_objectGUID ( sam_ctx ) ;
if ( ! objectGUID ) {
2010-07-06 13:21:54 +10:00
return ldb_operr ( sam_ctx ) ;
2010-04-15 17:37:40 -03:00
}
2010-05-11 10:34:19 +02:00
ret = samdb_is_rodc ( sam_ctx , objectGUID , am_rodc ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
cached = talloc ( sam_ctx , bool ) ;
if ( cached = = NULL ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( sam_ctx ) ;
2010-05-11 10:34:19 +02:00
}
* cached = * am_rodc ;
ret = ldb_set_opaque ( sam_ctx , " cache.am_rodc " , cached ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( cached ) ;
2010-07-06 13:21:54 +10:00
return ldb_operr ( sam_ctx ) ;
2010-05-11 10:34:19 +02:00
}
return LDB_SUCCESS ;
2010-03-01 14:16:59 +02:00
}
2009-10-13 19:48:13 +11:00
2017-06-19 14:49:55 +12:00
int samdb_dns_host_name ( struct ldb_context * sam_ctx , const char * * host_name )
{
const char * _host_name = NULL ;
const char * attrs [ ] = { " dnsHostName " , NULL } ;
TALLOC_CTX * tmp_ctx = NULL ;
int ret ;
struct ldb_result * res = NULL ;
_host_name = ( const char * ) ldb_get_opaque ( sam_ctx , " cache.dns_host_name " ) ;
if ( _host_name ! = NULL ) {
* host_name = _host_name ;
return LDB_SUCCESS ;
}
tmp_ctx = talloc_new ( sam_ctx ) ;
ret = dsdb_search_dn ( sam_ctx , tmp_ctx , & res , NULL , attrs , 0 ) ;
if ( res - > count ! = 1 | | ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( " Failed to get rootDSE for dnsHostName: %s " ,
ldb_errstring ( sam_ctx ) ) ) ;
TALLOC_FREE ( tmp_ctx ) ;
return ret ;
}
_host_name = ldb_msg_find_attr_as_string ( res - > msgs [ 0 ] ,
" dnsHostName " ,
NULL ) ;
if ( _host_name = = NULL ) {
DEBUG ( 0 , ( " Failed to get dnsHostName from rootDSE " ) ) ;
TALLOC_FREE ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
ret = ldb_set_opaque ( sam_ctx , " cache.dns_host_name " ,
discard_const_p ( char * , _host_name ) ) ;
if ( ret ! = LDB_SUCCESS ) {
TALLOC_FREE ( tmp_ctx ) ;
return ldb_operr ( sam_ctx ) ;
}
* host_name = talloc_steal ( sam_ctx , _host_name ) ;
TALLOC_FREE ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2010-05-13 15:07:50 +03:00
bool samdb_set_am_rodc ( struct ldb_context * ldb , bool am_rodc )
{
TALLOC_CTX * tmp_ctx ;
bool * cached ;
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
goto failed ;
}
cached = talloc ( tmp_ctx , bool ) ;
if ( ! cached ) {
goto failed ;
}
* cached = am_rodc ;
if ( ldb_set_opaque ( ldb , " cache.am_rodc " , cached ) ! = LDB_SUCCESS ) {
goto failed ;
}
talloc_steal ( ldb , cached ) ;
talloc_free ( tmp_ctx ) ;
return true ;
failed :
DEBUG ( 1 , ( " Failed to set our own cached am_rodc in the ldb! \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return false ;
}
2010-04-15 17:37:40 -03:00
2011-07-05 21:19:54 -05:00
/*
* return NTDSSiteSettings options . See MS - ADTS 7.1 .1 .2 .2 .1 .1
* flags are DS_NTDSSETTINGS_OPT_ *
*/
int samdb_ntds_site_settings_options ( struct ldb_context * ldb_ctx ,
uint32_t * options )
{
int rc ;
TALLOC_CTX * tmp_ctx ;
struct ldb_result * res ;
struct ldb_dn * site_dn ;
const char * attrs [ ] = { " options " , NULL } ;
tmp_ctx = talloc_new ( ldb_ctx ) ;
if ( tmp_ctx = = NULL )
goto failed ;
/* Retrieve the site dn for the ldb that we
* have open . This is our local site .
*/
site_dn = samdb_server_site_dn ( ldb_ctx , tmp_ctx ) ;
if ( site_dn = = NULL )
goto failed ;
/* Perform a one level (child) search from the local
* site distinguided name . We ' re looking for the
* " options " attribute within the nTDSSiteSettings
* object
*/
rc = ldb_search ( ldb_ctx , tmp_ctx , & res , site_dn ,
LDB_SCOPE_ONELEVEL , attrs ,
" objectClass=nTDSSiteSettings " ) ;
if ( rc ! = LDB_SUCCESS | | res - > count ! = 1 )
goto failed ;
* options = ldb_msg_find_attr_as_uint ( res - > msgs [ 0 ] , " options " , 0 ) ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
failed :
DEBUG ( 1 , ( " Failed to find our NTDS Site Settings options in ldb! \n " ) ) ;
talloc_free ( tmp_ctx ) ;
2016-01-14 11:50:56 +01:00
return ldb_error ( ldb_ctx , LDB_ERR_NO_SUCH_OBJECT , __func__ ) ;
2011-07-05 21:19:54 -05:00
}
2009-10-13 19:48:13 +11: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 ;
}
2012-08-14 16:08:47 +10:00
ret = ldb_search ( ldb , tmp_ctx , & res , samdb_ntds_settings_dn ( ldb , tmp_ctx ) , LDB_SCOPE_BASE , attrs , NULL ) ;
2010-08-09 19:45:45 +02:00
if ( ret ! = LDB_SUCCESS ) {
2009-10-13 19:48:13 +11:00
goto failed ;
}
if ( res - > count ! = 1 ) {
goto failed ;
}
2010-10-14 09:41:42 +02:00
* options = ldb_msg_find_attr_as_uint ( res - > msgs [ 0 ] , " options " , 0 ) ;
2009-10-13 19:48:13 +11:00
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
failed :
2010-03-01 14:16:59 +02:00
DEBUG ( 1 , ( " Failed to find our own NTDS Settings options in the ldb! \n " ) ) ;
2009-10-13 19:48:13 +11:00
talloc_free ( tmp_ctx ) ;
2016-01-14 11:50:56 +01:00
return ldb_error ( ldb , LDB_ERR_NO_SUCH_OBJECT , __func__ ) ;
2009-10-13 19:48:13 +11:00
}
2009-11-14 20:12:42 +01:00
2010-03-01 14:16:59 +02: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 ;
2012-08-14 16:08:47 +10:00
ret = ldb_search ( ldb , tmp_ctx , & res , samdb_ntds_settings_dn ( ldb , tmp_ctx ) , LDB_SCOPE_BASE , attrs , NULL ) ;
2010-08-09 19:45:45 +02:00
if ( ret ! = LDB_SUCCESS ) {
2010-03-01 14:16:59 +02:00
goto failed ;
}
if ( res - > count ! = 1 ) {
goto failed ;
}
2010-10-14 09:41:42 +02:00
return ldb_msg_find_attr_as_string ( res - > msgs [ 0 ] , " objectCategory " , NULL ) ;
2010-03-01 14:16:59 +02:00
failed :
DEBUG ( 1 , ( " Failed to find our own NTDS Settings objectCategory in the ldb! \n " ) ) ;
return NULL ;
}
2009-11-14 20:12:42 +01: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 , " -_ " ) ;
2016-05-06 15:25:54 +12:00
if ( tokens = = NULL | | tokens [ 0 ] = = NULL ) {
2009-11-14 20:12:42 +01:00
return NULL ;
2016-05-06 15:25:54 +12:00
}
2009-11-14 20:12:42 +01:00
/* "tolower()" and "toupper()" should also work properly on 0x00 */
tokens [ 0 ] [ 0 ] = tolower ( tokens [ 0 ] [ 0 ] ) ;
2016-05-06 15:22:35 +12:00
for ( i = 1 ; tokens [ i ] ! = NULL ; i + + )
2009-11-14 20:12:42 +01:00
tokens [ i ] [ 0 ] = toupper ( tokens [ i ] [ 0 ] ) ;
ret = talloc_strdup ( mem_ctx , tokens [ 0 ] ) ;
2016-05-06 15:22:35 +12:00
for ( i = 1 ; tokens [ i ] ! = NULL ; i + + )
2009-11-14 20:12:42 +01:00
ret = talloc_asprintf_append_buffer ( ret , " %s " , tokens [ i ] ) ;
talloc_free ( tokens ) ;
return ret ;
}
2009-12-09 15:18:37 +11:00
/*
2010-08-09 19:52:00 +02:00
* This detects and returns the domain functional level ( DS_DOMAIN_FUNCTION_ * )
2009-12-09 15:18:37 +11:00
*/
int dsdb_functional_level ( struct ldb_context * ldb )
{
int * domainFunctionality =
talloc_get_type ( ldb_get_opaque ( ldb , " domainFunctionality " ) , int ) ;
if ( ! domainFunctionality ) {
2010-09-30 12:42:35 -07:00
/* this is expected during initial provision */
DEBUG ( 4 , ( __location__ " : WARNING: domainFunctionality not setup \n " ) ) ;
2009-12-09 15:18:37 +11:00
return DS_DOMAIN_FUNCTION_2000 ;
}
return * domainFunctionality ;
}
2010-08-09 19:52:00 +02:00
/*
* This detects and returns the forest functional level ( DS_DOMAIN_FUNCTION_ * )
*/
int dsdb_forest_functional_level ( struct ldb_context * ldb )
{
int * forestFunctionality =
talloc_get_type ( ldb_get_opaque ( ldb , " forestFunctionality " ) , int ) ;
if ( ! forestFunctionality ) {
DEBUG ( 0 , ( __location__ " : WARNING: forestFunctionality not setup \n " ) ) ;
return DS_DOMAIN_FUNCTION_2000 ;
}
return * forestFunctionality ;
}
2009-12-30 10:52:14 +11: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 11:23:20 +11:00
/*
return a GUID from a extended DN structure
*/
2009-12-18 20:51:37 +11:00
NTSTATUS dsdb_get_extended_dn_guid ( struct ldb_dn * dn , struct GUID * guid , const char * component_name )
2009-12-10 11:23:20 +11:00
{
const struct ldb_val * v ;
2009-12-18 20:51:37 +11:00
v = ldb_dn_get_extended_component ( dn , component_name ) ;
2009-12-10 11:23:20 +11:00
if ( v = = NULL ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
return GUID_from_ndr_blob ( v , guid ) ;
}
2009-12-15 11:00:30 +11:00
2009-12-18 20:54:23 +11:00
/*
2009-12-19 12:23:42 +11:00
return a uint64_t from a extended DN structure
2009-12-18 20:54:23 +11:00
*/
2009-12-19 12:23:42 +11:00
NTSTATUS dsdb_get_extended_dn_uint64 ( struct ldb_dn * dn , uint64_t * val , const char * component_name )
2009-12-18 20:54:23 +11:00
{
const struct ldb_val * v ;
2019-01-30 09:31:34 +01:00
int error = 0 ;
2009-12-18 20:54:23 +11:00
v = ldb_dn_get_extended_component ( dn , component_name ) ;
if ( v = = NULL ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2016-06-27 12:35:24 +12:00
/* Just check we don't allow the caller to fill our stack */
if ( v - > length > = 64 ) {
return NT_STATUS_INVALID_PARAMETER ;
} else {
2016-06-16 14:04:44 +12:00
char s [ v - > length + 1 ] ;
memcpy ( s , v - > data , v - > length ) ;
s [ v - > length ] = 0 ;
2009-12-18 20:54:23 +11:00
2019-01-30 09:31:34 +01:00
* val = strtoull_err ( s , NULL , 0 , & error ) ;
if ( error ! = 0 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2016-06-16 14:04:44 +12:00
}
2009-12-18 20:54:23 +11:00
return NT_STATUS_OK ;
}
2009-12-19 12:23:42 +11: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 20:54:23 +11: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 ;
2019-01-30 09:31:34 +01:00
int error = 0 ;
2009-12-18 20:54:23 +11:00
v = ldb_dn_get_extended_component ( dn , component_name ) ;
if ( v = = NULL ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2016-06-27 12:35:24 +12:00
/* Just check we don't allow the caller to fill our stack */
if ( v - > length > = 32 ) {
return NT_STATUS_INVALID_PARAMETER ;
} else {
2016-06-16 14:04:44 +12:00
char s [ v - > length + 1 ] ;
memcpy ( s , v - > data , v - > length ) ;
s [ v - > length ] = 0 ;
2019-01-30 09:31:34 +01:00
* val = strtoul_err ( s , NULL , 0 , & error ) ;
if ( error ! = 0 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2016-06-16 14:04:44 +12:00
}
2009-12-18 20:54:23 +11:00
return NT_STATUS_OK ;
}
2010-04-22 14:53:53 +10: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 ;
enum ndr_err_code ndr_err ;
2010-08-18 18:36:12 +10:00
sid_blob = ldb_dn_get_extended_component ( dn , component_name ) ;
2010-04-22 14:53:53 +10:00
if ( ! sid_blob ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2016-06-16 14:04:44 +12:00
ndr_err = ndr_pull_struct_blob_all_noalloc ( sid_blob , sid ,
( ndr_pull_flags_fn_t ) ndr_pull_dom_sid ) ;
2010-04-22 14:53:53 +10:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
NTSTATUS status = ndr_map_error2ntstatus ( ndr_err ) ;
return status ;
}
return NT_STATUS_OK ;
}
2010-01-02 08:14:52 +11:00
/*
return RMD_FLAGS directly from a ldb_dn
returns 0 if not found
*/
uint32_t dsdb_dn_rmd_flags ( struct ldb_dn * dn )
{
2016-06-27 12:35:24 +12:00
uint32_t rmd_flags = 0 ;
NTSTATUS status = dsdb_get_extended_dn_uint32 ( dn , & rmd_flags ,
" RMD_FLAGS " ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
return rmd_flags ;
}
return 0 ;
2010-01-02 08:14:52 +11:00
}
/*
return RMD_FLAGS directly from a ldb_val for a DN
returns 0 if RMD_FLAGS is not found
*/
2010-06-14 13:27:59 +10:00
uint32_t dsdb_dn_val_rmd_flags ( const struct ldb_val * val )
2010-01-02 08:14:52 +11:00
{
const char * p ;
uint32_t flags ;
char * end ;
2019-01-30 09:31:34 +01:00
int error = 0 ;
2010-01-02 08:14:52 +11:00
if ( val - > length < 13 ) {
return 0 ;
}
2010-10-02 13:45:22 +02:00
p = memmem ( val - > data , val - > length , " <RMD_FLAGS= " , 11 ) ;
2010-01-02 08:14:52 +11:00
if ( ! p ) {
return 0 ;
}
2019-01-30 09:31:34 +01:00
flags = strtoul_err ( p + 11 , & end , 10 , & error ) ;
if ( ! end | | * end ! = ' > ' | | error ! = 0 ) {
2010-01-02 08:14:52 +11:00
/* it must end in a > */
return 0 ;
}
return flags ;
}
2009-12-15 11:00:30 +11:00
/*
return true if a ldb_val containing a DN in storage form is deleted
*/
2010-06-14 13:27:59 +10:00
bool dsdb_dn_is_deleted_val ( const struct ldb_val * val )
2009-12-15 11:00:30 +11:00
{
2010-01-02 08:14:52 +11:00
return ( dsdb_dn_val_rmd_flags ( val ) & DSDB_RMD_FLAG_DELETED ) ! = 0 ;
2009-12-15 11:00:30 +11:00
}
2009-12-16 13:18:44 +11:00
2009-12-19 20:55:46 +11:00
/*
return true if a ldb_val containing a DN in storage form is
in the upgraded w2k3 linked attribute format
*/
2016-01-28 14:11:52 +01:00
bool dsdb_dn_is_upgraded_link_val ( const struct ldb_val * val )
2009-12-19 20:55:46 +11:00
{
2011-06-10 09:10:09 +10:00
return memmem ( val - > data , val - > length , " <RMD_VERSION= " , 13 ) ! = NULL ;
2009-12-19 20:55:46 +11:00
}
2009-12-16 13:18:44 +11:00
/*
return a DN for a wellknown GUID
*/
int dsdb_wellknown_dn ( struct ldb_context * samdb , TALLOC_CTX * mem_ctx ,
struct ldb_dn * nc_root , const char * wk_guid ,
struct ldb_dn * * wkguid_dn )
{
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
const char * attrs [ ] = { NULL } ;
int ret ;
struct ldb_dn * dn ;
struct ldb_result * res ;
/* construct the magic WKGUID DN */
dn = ldb_dn_new_fmt ( tmp_ctx , samdb , " <WKGUID=%s,%s> " ,
wk_guid , ldb_dn_get_linearized ( nc_root ) ) ;
if ( ! wkguid_dn ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_operr ( samdb ) ;
2009-12-16 13:18:44 +11:00
}
2010-09-19 22:20:08 +02:00
ret = dsdb_search_dn ( samdb , tmp_ctx , & res , dn , attrs ,
2010-10-04 17:18:19 +02:00
DSDB_SEARCH_SHOW_DELETED |
2010-09-19 22:20:08 +02:00
DSDB_SEARCH_SHOW_RECYCLED ) ;
2009-12-16 13:18:44 +11: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 13:36:17 +11:00
2009-12-17 23:50:05 +11:00
static int dsdb_dn_compare_ptrs ( struct ldb_dn * * dn1 , struct ldb_dn * * dn2 )
{
return ldb_dn_compare ( * dn1 , * dn2 ) ;
}
2009-12-16 13:36:17 +11:00
/*
find a NC root given a DN within the NC
*/
int dsdb_find_nc_root ( struct ldb_context * samdb , TALLOC_CTX * mem_ctx , struct ldb_dn * dn ,
struct ldb_dn * * nc_root )
{
const char * root_attrs [ ] = { " namingContexts " , NULL } ;
TALLOC_CTX * tmp_ctx ;
int ret ;
struct ldb_message_element * el ;
struct ldb_result * root_res ;
2010-05-30 20:45:56 +02:00
unsigned int i ;
2009-12-16 13:36:17 +11:00
struct ldb_dn * * nc_dns ;
tmp_ctx = talloc_new ( samdb ) ;
if ( tmp_ctx = = NULL ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( samdb ) ;
2009-12-16 13:36:17 +11:00
}
ret = ldb_search ( samdb , tmp_ctx , & root_res ,
ldb_dn_new ( tmp_ctx , samdb , " " ) , LDB_SCOPE_BASE , root_attrs , NULL ) ;
2015-05-23 00:02:42 -07:00
if ( ret ! = LDB_SUCCESS | | root_res - > count = = 0 ) {
2009-12-16 13:36:17 +11:00
DEBUG ( 1 , ( " Searching for namingContexts in rootDSE failed: %s \n " , ldb_errstring ( samdb ) ) ) ;
talloc_free ( tmp_ctx ) ;
return ret ;
2010-11-16 15:20:04 +01:00
}
2009-12-16 13:36:17 +11:00
2010-11-16 15:20:04 +01:00
el = ldb_msg_find_element ( root_res - > msgs [ 0 ] , " namingContexts " ) ;
2011-01-15 18:12:09 +01:00
if ( ( el = = NULL ) | | ( el - > num_values < 3 ) ) {
2010-11-16 15:20:04 +01:00
struct ldb_message * tmp_msg ;
2017-09-07 11:13:17 +12:00
DEBUG ( 5 , ( " dsdb_find_nc_root: Finding a valid 'namingContexts' element in the RootDSE failed. Using a temporary list. \n " ) ) ;
2010-11-16 15:20:04 +01:00
/* This generates a temporary list of NCs in order to let the
* provisioning work . */
tmp_msg = ldb_msg_new ( tmp_ctx ) ;
if ( tmp_msg = = NULL ) {
talloc_free ( tmp_ctx ) ;
return ldb_oom ( samdb ) ;
}
ret = ldb_msg_add_steal_string ( tmp_msg , " namingContexts " ,
ldb_dn_alloc_linearized ( tmp_msg , ldb_get_schema_basedn ( samdb ) ) ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
ret = ldb_msg_add_steal_string ( tmp_msg , " namingContexts " ,
ldb_dn_alloc_linearized ( tmp_msg , ldb_get_config_basedn ( samdb ) ) ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
ret = ldb_msg_add_steal_string ( tmp_msg , " namingContexts " ,
ldb_dn_alloc_linearized ( tmp_msg , ldb_get_default_basedn ( samdb ) ) ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
el = & tmp_msg - > elements [ 0 ] ;
}
2009-12-16 13:36:17 +11:00
nc_dns = talloc_array ( tmp_ctx , struct ldb_dn * , el - > num_values ) ;
if ( ! nc_dns ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_oom ( samdb ) ;
2009-12-16 13:36:17 +11:00
}
for ( i = 0 ; i < el - > num_values ; i + + ) {
nc_dns [ i ] = ldb_dn_from_ldb_val ( nc_dns , samdb , & el - > values [ i ] ) ;
if ( nc_dns [ i ] = = NULL ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_operr ( samdb ) ;
2009-12-16 13:36:17 +11:00
}
}
2010-02-13 12:59:43 +11:00
TYPESAFE_QSORT ( nc_dns , el - > num_values , dsdb_dn_compare_ptrs ) ;
2009-12-16 13:36:17 +11: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 ) ;
2016-01-14 11:50:56 +01:00
return ldb_error ( samdb , LDB_ERR_NO_SUCH_OBJECT , __func__ ) ;
2009-12-16 13:36:17 +11:00
}
2009-12-16 13:41:21 +11: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 20:04:17 +11:00
/*
return the tombstoneLifetime , in days
*/
int dsdb_tombstone_lifetime ( struct ldb_context * ldb , uint32_t * lifetime )
{
struct ldb_dn * dn ;
2010-04-13 08:41:10 +02:00
dn = ldb_get_config_basedn ( ldb ) ;
2009-12-30 20:04:17 +11:00
if ( ! dn ) {
2016-01-14 11:50:56 +01:00
return ldb_error ( ldb , LDB_ERR_NO_SUCH_OBJECT , __func__ ) ;
2009-12-30 20:04:17 +11:00
}
dn = ldb_dn_copy ( ldb , dn ) ;
if ( ! dn ) {
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2009-12-30 20:04:17 +11:00
}
/* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
be a wellknown GUID for this */
2010-02-13 18:20:54 +01:00
if ( ! ldb_dn_add_child_fmt ( dn , " CN=Directory Service,CN=Windows NT,CN=Services " ) ) {
2009-12-30 20:04:17 +11:00
talloc_free ( dn ) ;
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2009-12-30 20:04:17 +11:00
}
* lifetime = samdb_search_uint ( ldb , dn , 180 , dn , " tombstoneLifetime " , " objectClass=nTDSService " ) ;
talloc_free ( dn ) ;
return LDB_SUCCESS ;
}
2010-01-09 17:42:05 +11: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 11:08:15 +11:00
/*
load the UDV for a partition in v2 format
2010-01-16 11:48:25 +11:00
The list is returned sorted , and with our local cursor added
2010-01-16 11:08:15 +11: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 20:14:41 +01:00
unsigned int i ;
int ret ;
2012-12-19 12:47:43 +01:00
uint64_t highest_usn = 0 ;
2010-01-16 11:48:25 +11:00
const struct GUID * our_invocation_id ;
2012-12-19 17:33:13 +01:00
static const struct timeval tv1970 ;
NTTIME nt1970 = timeval_to_nttime ( & tv1970 ) ;
2010-01-16 11:08:15 +11:00
2016-05-25 12:36:59 +12:00
ret = dsdb_search_dn ( samdb , mem_ctx , & r , dn , attrs , DSDB_SEARCH_SHOW_RECYCLED | DSDB_SEARCH_SHOW_DELETED ) ;
2010-01-16 11:08:15 +11:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
ouv_value = ldb_msg_find_ldb_val ( r - > msgs [ 0 ] , " replUpToDateVector " ) ;
2010-01-16 11:48:25 +11:00
if ( ouv_value ) {
enum ndr_err_code ndr_err ;
struct replUpToDateVectorBlob ouv ;
2010-05-09 17:20:01 +02:00
ndr_err = ndr_pull_struct_blob ( ouv_value , r , & ouv ,
2010-01-16 11:48:25 +11:00
( ndr_pull_flags_fn_t ) ndr_pull_replUpToDateVectorBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
talloc_free ( r ) ;
return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX ;
}
if ( ouv . version ! = 2 ) {
/* we always store as version 2, and
* replUpToDateVector is not replicated
*/
return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX ;
}
* count = ouv . ctr . ctr2 . count ;
* cursors = talloc_steal ( mem_ctx , ouv . ctr . ctr2 . cursors ) ;
} else {
2010-01-16 11:08:15 +11:00
* count = 0 ;
* cursors = NULL ;
2010-01-16 11:48:25 +11:00
}
talloc_free ( r ) ;
our_invocation_id = samdb_ntds_invocation_id ( samdb ) ;
if ( ! our_invocation_id ) {
DEBUG ( 0 , ( __location__ " : No invocationID on samdb - %s \n " , ldb_errstring ( samdb ) ) ) ;
talloc_free ( * cursors ) ;
2010-07-06 13:21:54 +10:00
return ldb_operr ( samdb ) ;
2010-01-16 11:48:25 +11:00
}
2012-12-19 12:47:43 +01:00
ret = ldb_sequence_number ( samdb , LDB_SEQ_HIGHEST_SEQ , & highest_usn ) ;
2010-01-16 11:48:25 +11:00
if ( ret ! = LDB_SUCCESS ) {
/* nothing to add - this can happen after a vampire */
2010-02-13 12:59:43 +11:00
TYPESAFE_QSORT ( * cursors , * count , drsuapi_DsReplicaCursor2_compare ) ;
2010-01-16 11:08:15 +11:00
return LDB_SUCCESS ;
}
2010-01-16 11:48:25 +11: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 ;
2012-12-19 17:33:13 +01:00
( * cursors ) [ i ] . last_sync_success = nt1970 ;
2010-02-13 12:59:43 +11:00
TYPESAFE_QSORT ( * cursors , * count , drsuapi_DsReplicaCursor2_compare ) ;
2010-01-16 11:48:25 +11:00
return LDB_SUCCESS ;
}
2010-01-16 11:08:15 +11:00
}
2010-01-16 11:48:25 +11:00
( * cursors ) = talloc_realloc ( mem_ctx , * cursors , struct drsuapi_DsReplicaCursor2 , ( * count ) + 1 ) ;
if ( ! * cursors ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( samdb ) ;
2010-01-16 11:08:15 +11:00
}
2010-01-16 11:48:25 +11:00
( * cursors ) [ * count ] . source_dsa_invocation_id = * our_invocation_id ;
( * cursors ) [ * count ] . highest_usn = highest_usn ;
2012-12-19 17:33:13 +01:00
( * cursors ) [ * count ] . last_sync_success = nt1970 ;
2010-01-16 11:48:25 +11:00
( * count ) + + ;
2010-02-13 12:59:43 +11:00
TYPESAFE_QSORT ( * cursors , * count , drsuapi_DsReplicaCursor2_compare ) ;
2010-01-16 11:08:15 +11:00
return LDB_SUCCESS ;
}
/*
load the UDV for a partition in version 1 format
2010-01-16 11:48:25 +11:00
The list is returned sorted , and with our local cursor added
2010-01-16 11:08:15 +11:00
*/
int dsdb_load_udv_v1 ( struct ldb_context * samdb , struct ldb_dn * dn , TALLOC_CTX * mem_ctx ,
struct drsuapi_DsReplicaCursor * * cursors , uint32_t * count )
{
struct drsuapi_DsReplicaCursor2 * v2 ;
2010-05-31 22:04:29 +02:00
uint32_t i ;
2009-11-06 20:14:41 +01:00
int ret ;
2010-01-16 11:08:15 +11:00
ret = dsdb_load_udv_v2 ( samdb , dn , mem_ctx , & v2 , count ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
if ( * count = = 0 ) {
talloc_free ( v2 ) ;
* cursors = NULL ;
return LDB_SUCCESS ;
}
* cursors = talloc_array ( mem_ctx , struct drsuapi_DsReplicaCursor , * count ) ;
if ( * cursors = = NULL ) {
talloc_free ( v2 ) ;
2010-07-06 13:21:54 +10:00
return ldb_oom ( samdb ) ;
2010-01-16 11:08:15 +11:00
}
for ( i = 0 ; i < * count ; i + + ) {
( * cursors ) [ i ] . source_dsa_invocation_id = v2 [ i ] . source_dsa_invocation_id ;
( * cursors ) [ i ] . highest_usn = v2 [ i ] . highest_usn ;
}
talloc_free ( v2 ) ;
return LDB_SUCCESS ;
}
2010-02-15 17:38:16 +11:00
2010-02-16 14:23:21 +11: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 ;
}
}
2011-09-22 09:48:17 +10:00
if ( dsdb_flags & DSDB_SEARCH_NO_GLOBAL_CATALOG ) {
ret = ldb_request_add_control ( req ,
DSDB_CONTROL_NO_GLOBAL_CATALOG ,
false , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2010-02-16 14:23:21 +11:00
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 ;
}
}
2010-09-19 22:12:23 +02:00
if ( dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED ) {
2010-10-04 17:18:19 +02:00
ret = ldb_request_add_control ( req , LDB_CONTROL_SHOW_RECYCLED_OID , false , NULL ) ;
2010-09-19 22:12:23 +02:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2010-02-16 14:23:21 +11:00
if ( dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT ) {
2011-08-01 12:25:11 +10:00
ret = ldb_request_add_control ( req , DSDB_CONTROL_DN_STORAGE_FORMAT_OID , false , NULL ) ;
2010-02-16 14:23:21 +11:00
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 14:29:07 +11: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 14:45:16 +11:00
if ( dsdb_flags & DSDB_FLAG_AS_SYSTEM ) {
ret = ldb_request_add_control ( req , LDB_CONTROL_AS_SYSTEM_OID , false , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2010-06-20 12:43:49 +02:00
if ( dsdb_flags & DSDB_TREE_DELETE ) {
ret = ldb_request_add_control ( req , LDB_CONTROL_TREE_DELETE_OID , false , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2010-10-23 16:15:51 +02:00
if ( dsdb_flags & DSDB_PROVISION ) {
ret = ldb_request_add_control ( req , LDB_CONTROL_PROVISION_OID , false , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2011-08-11 16:14:36 +10:00
/* This is a special control to bypass the password_hash module for use in pdb_samba4 for Samba3 upgrades */
if ( dsdb_flags & DSDB_BYPASS_PASSWORD_HASH ) {
ret = ldb_request_add_control ( req , DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID , true , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2012-01-24 18:36:49 +11:00
if ( dsdb_flags & DSDB_PASSWORD_BYPASS_LAST_SET ) {
2012-06-27 12:45:37 +10:00
/*
* This must not be critical , as it will only be
* handled ( and need to be handled ) if the other
* attributes in the request bring password_hash into
* action
*/
ret = ldb_request_add_control ( req , DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID , false , NULL ) ;
2012-01-24 18:36:49 +11:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2016-07-06 11:54:25 +12:00
if ( dsdb_flags & DSDB_REPLMD_VANISH_LINKS ) {
ret = ldb_request_add_control ( req , DSDB_CONTROL_REPLMD_VANISH_LINKS , true , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2011-09-28 11:04:29 +10:00
if ( dsdb_flags & DSDB_MODIFY_PARTIAL_REPLICA ) {
ret = ldb_request_add_control ( req , DSDB_CONTROL_PARTIAL_REPLICA , false , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2017-06-14 13:12:32 +12:00
if ( dsdb_flags & DSDB_FLAG_REPLICATED_UPDATE ) {
ret = ldb_request_add_control ( req , DSDB_CONTROL_REPLICATED_UPDATE_OID , false , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2010-02-16 14:23:21 +11:00
return LDB_SUCCESS ;
}
2010-02-16 14:29:07 +11:00
2018-10-11 17:50:52 +13:00
/*
returns true if a control with the specified " oid " exists
*/
bool dsdb_request_has_control ( struct ldb_request * req , const char * oid )
{
return ( ldb_request_get_control ( req , oid ) ! = NULL ) ;
}
2010-08-05 21:58:57 +02:00
/*
an add with a set of controls
*/
int dsdb_add ( struct ldb_context * ldb , const struct ldb_message * message ,
uint32_t dsdb_flags )
{
struct ldb_request * req ;
int ret ;
ret = ldb_build_add_req ( & req , ldb , ldb ,
message ,
NULL ,
NULL ,
ldb_op_default_callback ,
NULL ) ;
if ( ret ! = LDB_SUCCESS ) return ret ;
ret = dsdb_request_add_controls ( req , dsdb_flags ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( req ) ;
return ret ;
}
ret = dsdb_autotransaction_request ( ldb , req ) ;
talloc_free ( req ) ;
return ret ;
}
2010-02-16 14:29:07 +11: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 14:45:16 +11:00
ret = dsdb_autotransaction_request ( ldb , req ) ;
2010-02-16 14:29:07 +11:00
talloc_free ( req ) ;
return ret ;
}
2010-02-16 14:45:16 +11:00
2011-07-14 13:18:17 +10:00
/*
a delete with a set of flags
*/
2011-08-01 12:40:24 +10:00
int dsdb_delete ( struct ldb_context * ldb , struct ldb_dn * dn ,
2011-07-14 13:18:17 +10:00
uint32_t dsdb_flags )
{
struct ldb_request * req ;
int ret ;
ret = ldb_build_del_req ( & req , ldb , ldb ,
dn ,
NULL ,
NULL ,
ldb_op_default_callback ,
NULL ) ;
if ( ret ! = LDB_SUCCESS ) return ret ;
ret = dsdb_request_add_controls ( req , dsdb_flags ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( req ) ;
return ret ;
}
ret = dsdb_autotransaction_request ( ldb , req ) ;
talloc_free ( req ) ;
return ret ;
}
2010-02-16 14:45:16 +11: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 20:14:41 +01:00
unsigned int i ;
2010-02-16 14:45:16 +11: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 14:55:19 +11:00
/*
search for attrs on one DN , allowing for dsdb_flags controls
*/
int dsdb_search_dn ( struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx ,
2012-11-06 01:24:59 +01:00
struct ldb_result * * _result ,
2010-02-16 14:55:19 +11:00
struct ldb_dn * basedn ,
const char * const * attrs ,
uint32_t dsdb_flags )
{
int ret ;
struct ldb_request * req ;
struct ldb_result * res ;
res = talloc_zero ( mem_ctx , struct ldb_result ) ;
if ( ! res ) {
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2010-02-16 14:55:19 +11:00
}
ret = ldb_build_search_req ( & req , ldb , res ,
basedn ,
LDB_SCOPE_BASE ,
NULL ,
attrs ,
NULL ,
res ,
ldb_search_default_callback ,
NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( res ) ;
return ret ;
}
ret = dsdb_request_add_controls ( req , dsdb_flags ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( res ) ;
return ret ;
}
ret = ldb_request ( ldb , req ) ;
if ( ret = = LDB_SUCCESS ) {
ret = ldb_wait ( req - > handle , LDB_WAIT_ALL ) ;
}
talloc_free ( req ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( res ) ;
return ret ;
}
2012-11-06 01:24:59 +01:00
* _result = res ;
2010-02-16 14:55:19 +11:00
return LDB_SUCCESS ;
}
2010-02-16 15:15:35 +11:00
2010-10-01 19:04:44 -07:00
/*
search for attrs on one DN , by the GUID of the DN , allowing for
dsdb_flags controls
*/
int dsdb_search_by_dn_guid ( struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx ,
2012-11-06 01:24:59 +01:00
struct ldb_result * * _result ,
2010-10-01 19:04:44 -07:00
const struct GUID * guid ,
const char * const * attrs ,
uint32_t dsdb_flags )
{
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
struct ldb_dn * dn ;
int ret ;
dn = ldb_dn_new_fmt ( tmp_ctx , ldb , " <GUID=%s> " , GUID_string ( tmp_ctx , guid ) ) ;
2011-03-04 10:49:47 +01:00
if ( dn = = NULL ) {
2010-10-01 19:04:44 -07:00
talloc_free ( tmp_ctx ) ;
2011-03-04 10:49:47 +01:00
return ldb_oom ( ldb ) ;
2010-10-01 19:04:44 -07:00
}
2012-11-06 01:24:59 +01:00
ret = dsdb_search_dn ( ldb , mem_ctx , _result , dn , attrs , dsdb_flags ) ;
2010-10-01 19:04:44 -07:00
talloc_free ( tmp_ctx ) ;
return ret ;
}
2010-02-16 15:15:35 +11:00
/*
general search with dsdb_flags for controls
*/
int dsdb_search ( struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx ,
2012-11-06 01:24:59 +01:00
struct ldb_result * * _result ,
2010-02-16 15:15:35 +11:00
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 ) ;
2011-08-19 17:36:22 +10:00
/* cross-partitions searches with a basedn break multi-domain support */
SMB_ASSERT ( basedn = = NULL | | ( dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS ) = = 0 ) ;
2010-02-16 15:15:35 +11:00
res = talloc_zero ( tmp_ctx , struct ldb_result ) ;
if ( ! res ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2010-02-16 15:15:35 +11:00
}
if ( exp_fmt ) {
va_start ( ap , exp_fmt ) ;
expression = talloc_vasprintf ( tmp_ctx , exp_fmt , ap ) ;
va_end ( ap ) ;
if ( ! expression ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2010-02-16 15:15:35 +11:00
}
}
ret = ldb_build_search_req ( & req , ldb , tmp_ctx ,
basedn ,
scope ,
expression ,
attrs ,
NULL ,
res ,
ldb_search_default_callback ,
NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
ret = dsdb_request_add_controls ( req , dsdb_flags ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
2010-09-28 12:57:15 +10:00
ldb_reset_err_string ( ldb ) ;
2010-02-16 15:15:35 +11:00
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 15:40:44 +11:00
if ( dsdb_flags & DSDB_SEARCH_ONE_ONLY ) {
if ( res - > count = = 0 ) {
talloc_free ( tmp_ctx ) ;
2010-09-28 12:57:15 +10:00
ldb_reset_err_string ( ldb ) ;
2016-01-14 11:50:56 +01:00
return ldb_error ( ldb , LDB_ERR_NO_SUCH_OBJECT , __func__ ) ;
2010-02-16 15:40:44 +11:00
}
if ( res - > count ! = 1 ) {
talloc_free ( tmp_ctx ) ;
2010-09-28 12:57:15 +10:00
ldb_reset_err_string ( ldb ) ;
2010-02-16 16:39:49 +11:00
return LDB_ERR_CONSTRAINT_VIOLATION ;
2010-02-16 15:40:44 +11:00
}
}
2012-11-06 01:24:59 +01:00
* _result = talloc_steal ( mem_ctx , res ) ;
2010-02-16 15:15:35 +11:00
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2010-02-16 15:40:44 +11:00
/*
general search with dsdb_flags for controls
returns exactly 1 record or an error
*/
int dsdb_search_one ( struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_message * * msg ,
struct ldb_dn * basedn ,
enum ldb_scope scope ,
const char * const * attrs ,
uint32_t dsdb_flags ,
const char * exp_fmt , . . . ) _PRINTF_ATTRIBUTE ( 8 , 9 )
{
int ret ;
struct ldb_result * res ;
va_list ap ;
char * expression = NULL ;
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
dsdb_flags | = DSDB_SEARCH_ONE_ONLY ;
res = talloc_zero ( tmp_ctx , struct ldb_result ) ;
if ( ! res ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2010-02-16 15:40:44 +11:00
}
if ( exp_fmt ) {
va_start ( ap , exp_fmt ) ;
expression = talloc_vasprintf ( tmp_ctx , exp_fmt , ap ) ;
va_end ( ap ) ;
if ( ! expression ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_oom ( ldb ) ;
2010-02-16 15:40:44 +11:00
}
2010-05-21 08:11:13 +10:00
ret = dsdb_search ( ldb , tmp_ctx , & res , basedn , scope , attrs ,
dsdb_flags , " %s " , expression ) ;
} else {
ret = dsdb_search ( ldb , tmp_ctx , & res , basedn , scope , attrs ,
dsdb_flags , NULL ) ;
2010-02-16 15:40:44 +11:00
}
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
* msg = talloc_steal ( mem_ctx , res - > msgs [ 0 ] ) ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2010-04-12 14:15:34 +02:00
/* returns back the forest DNS name */
const char * samdb_forest_name ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx )
{
const char * forest_name = ldb_dn_canonical_string ( mem_ctx ,
ldb_get_root_basedn ( ldb ) ) ;
char * p ;
if ( forest_name = = NULL ) {
return NULL ;
}
p = strchr ( forest_name , ' / ' ) ;
if ( p ) {
* p = ' \0 ' ;
}
return forest_name ;
}
2010-04-22 14:54:52 +10:00
2010-12-22 12:19:46 +02:00
/* returns back the default domain DNS name */
const char * samdb_default_domain_name ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx )
{
const char * domain_name = ldb_dn_canonical_string ( mem_ctx ,
ldb_get_default_basedn ( ldb ) ) ;
char * p ;
if ( domain_name = = NULL ) {
return NULL ;
}
p = strchr ( domain_name , ' / ' ) ;
if ( p ) {
* p = ' \0 ' ;
}
return domain_name ;
}
2010-04-22 14:54:52 +10:00
/*
2010-04-26 00:22:53 +03:00
validate that an DSA GUID belongs to the specified user sid .
2010-04-22 14:54:52 +10:00
The user SID must be a domain controller account ( either RODC or
RWDC )
*/
2010-04-26 00:22:53 +03:00
int dsdb_validate_dsa_guid ( struct ldb_context * ldb ,
const struct GUID * dsa_guid ,
const struct dom_sid * sid )
2010-04-22 14:54:52 +10:00
{
/* strategy:
2010-04-26 00:22:53 +03:00
- find DN of record with the DSA GUID in the
configuration partition ( objectGUID )
- remove " NTDS Settings " component from DN
2010-04-22 14:54:52 +10:00
- do a base search on that DN for serverReference with
extended - dn enabled
2010-09-13 22:39:50 +02:00
- extract objectSid from resulting serverReference
2010-04-22 14:54:52 +10:00
attribute
- check this sid matches the sid argument
*/
struct ldb_dn * config_dn ;
TALLOC_CTX * tmp_ctx = talloc_new ( ldb ) ;
struct ldb_message * msg ;
const char * attrs1 [ ] = { NULL } ;
const char * attrs2 [ ] = { " serverReference " , NULL } ;
int ret ;
struct ldb_dn * dn , * account_dn ;
struct dom_sid sid2 ;
NTSTATUS status ;
config_dn = ldb_get_config_basedn ( ldb ) ;
ret = dsdb_search_one ( ldb , tmp_ctx , & msg , config_dn , LDB_SCOPE_SUBTREE ,
2010-04-26 00:22:53 +03:00
attrs1 , 0 , " (&(objectGUID=%s)(objectClass=nTDSDSA)) " , GUID_string ( tmp_ctx , dsa_guid ) ) ;
2010-04-22 14:54:52 +10:00
if ( ret ! = LDB_SUCCESS ) {
2010-04-26 00:22:53 +03:00
DEBUG ( 1 , ( __location__ " : Failed to find DSA objectGUID %s for sid %s \n " ,
GUID_string ( tmp_ctx , dsa_guid ) , dom_sid_string ( tmp_ctx , sid ) ) ) ;
2010-04-22 14:54:52 +10:00
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2010-04-22 14:54:52 +10:00
}
dn = msg - > dn ;
if ( ! ldb_dn_remove_child_components ( dn , 1 ) ) {
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2010-04-22 14:54:52 +10:00
}
ret = dsdb_search_one ( ldb , tmp_ctx , & msg , dn , LDB_SCOPE_BASE ,
attrs2 , DSDB_SEARCH_SHOW_EXTENDED_DN ,
" (objectClass=server) " ) ;
if ( ret ! = LDB_SUCCESS ) {
2010-04-26 00:22:53 +03:00
DEBUG ( 1 , ( __location__ " : Failed to find server record for DSA with objectGUID %s, sid %s \n " ,
GUID_string ( tmp_ctx , dsa_guid ) , dom_sid_string ( tmp_ctx , sid ) ) ) ;
2010-04-22 14:54:52 +10:00
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2010-04-22 14:54:52 +10:00
}
account_dn = ldb_msg_find_attr_as_dn ( ldb , tmp_ctx , msg , " serverReference " ) ;
if ( account_dn = = NULL ) {
2014-08-11 15:53:44 +12:00
DEBUG ( 1 , ( __location__ " : Failed to find account dn "
" (serverReference) for %s, parent of DSA with "
" objectGUID %s, sid %s \n " ,
ldb_dn_get_linearized ( msg - > dn ) ,
GUID_string ( tmp_ctx , dsa_guid ) ,
dom_sid_string ( tmp_ctx , sid ) ) ) ;
2010-04-22 14:54:52 +10:00
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2010-04-22 14:54:52 +10:00
}
status = dsdb_get_extended_dn_sid ( account_dn , & sid2 , " SID " ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-04-26 00:22:53 +03:00
DEBUG ( 1 , ( __location__ " : Failed to find SID for DSA with objectGUID %s, sid %s \n " ,
GUID_string ( tmp_ctx , dsa_guid ) , dom_sid_string ( tmp_ctx , sid ) ) ) ;
2010-04-22 14:54:52 +10:00
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2010-04-22 14:54:52 +10:00
}
if ( ! dom_sid_equal ( sid , & sid2 ) ) {
/* someone is trying to spoof another account */
2010-04-26 00:22:53 +03:00
DEBUG ( 0 , ( __location__ " : Bad DSA objectGUID %s for sid %s - expected sid %s \n " ,
GUID_string ( tmp_ctx , dsa_guid ) ,
2010-04-22 14:54:52 +10:00
dom_sid_string ( tmp_ctx , sid ) ,
dom_sid_string ( tmp_ctx , & sid2 ) ) ) ;
talloc_free ( tmp_ctx ) ;
2010-07-06 13:21:54 +10:00
return ldb_operr ( ldb ) ;
2010-04-22 14:54:52 +10:00
}
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2010-04-26 09:56:59 +03:00
2010-11-09 19:44:12 +01:00
static const char * const secret_attributes [ ] = {
DSDB_SECRET_ATTRIBUTES ,
2010-08-18 14:31:05 +10:00
NULL
} ;
2010-04-26 09:56:59 +03:00
/*
check if the attribute belongs to the RODC filtered attribute set
2010-08-18 14:31:05 +10:00
Note that attributes that are in the filtered attribute set are the
ones that _are_ always sent to a RODC
2010-04-26 09:56:59 +03:00
*/
2010-08-18 14:31:05 +10:00
bool dsdb_attr_in_rodc_fas ( const struct dsdb_attribute * sa )
2010-04-26 09:56:59 +03:00
{
2010-08-18 14:31:05 +10:00
/* they never get secret attributes */
if ( is_attr_in_list ( secret_attributes , sa - > lDAPDisplayName ) ) {
return false ;
}
2010-04-26 09:56:59 +03:00
2010-08-18 14:31:05 +10:00
/* they do get non-secret critical attributes */
if ( sa - > schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL ) {
2010-04-26 09:56:59 +03:00
return true ;
}
2010-08-18 14:31:05 +10:00
/* they do get non-secret attributes marked as being in the FAS */
if ( sa - > searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE ) {
2010-04-26 09:56:59 +03:00
return true ;
}
2010-08-18 14:31:05 +10:00
/* other attributes are denied */
2010-04-26 09:56:59 +03:00
return false ;
}
2010-09-20 09:44:19 -07:00
/* return fsmo role dn and role owner dn for a particular role*/
WERROR dsdb_get_fsmo_role_info ( TALLOC_CTX * tmp_ctx ,
struct ldb_context * ldb ,
uint32_t role ,
struct ldb_dn * * fsmo_role_dn ,
struct ldb_dn * * role_owner_dn )
{
int ret ;
switch ( role ) {
case DREPL_NAMING_MASTER :
* fsmo_role_dn = samdb_partitions_dn ( ldb , tmp_ctx ) ;
ret = samdb_reference_dn ( ldb , tmp_ctx , * fsmo_role_dn , " fSMORoleOwner " , role_owner_dn ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to find fSMORoleOwner in Naming Master object - %s " ,
ldb_errstring ( ldb ) ) ) ;
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
break ;
case DREPL_INFRASTRUCTURE_MASTER :
* fsmo_role_dn = samdb_infrastructure_dn ( ldb , tmp_ctx ) ;
ret = samdb_reference_dn ( ldb , tmp_ctx , * fsmo_role_dn , " fSMORoleOwner " , role_owner_dn ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to find fSMORoleOwner in Schema Master object - %s " ,
ldb_errstring ( ldb ) ) ) ;
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
break ;
case DREPL_RID_MASTER :
ret = samdb_rid_manager_dn ( ldb , tmp_ctx , fsmo_role_dn ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to find RID Manager object - %s " , ldb_errstring ( ldb ) ) ) ;
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
ret = samdb_reference_dn ( ldb , tmp_ctx , * fsmo_role_dn , " fSMORoleOwner " , role_owner_dn ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to find fSMORoleOwner in RID Manager object - %s " ,
ldb_errstring ( ldb ) ) ) ;
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
break ;
case DREPL_SCHEMA_MASTER :
* fsmo_role_dn = ldb_get_schema_basedn ( ldb ) ;
ret = samdb_reference_dn ( ldb , tmp_ctx , * fsmo_role_dn , " fSMORoleOwner " , role_owner_dn ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to find fSMORoleOwner in Schema Master object - %s " ,
ldb_errstring ( ldb ) ) ) ;
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
break ;
case DREPL_PDC_MASTER :
* fsmo_role_dn = ldb_get_default_basedn ( ldb ) ;
ret = samdb_reference_dn ( ldb , tmp_ctx , * fsmo_role_dn , " fSMORoleOwner " , role_owner_dn ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( __location__ " : Failed to find fSMORoleOwner in Pd Master object - %s " ,
ldb_errstring ( ldb ) ) ) ;
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
break ;
default :
return WERR_DS_DRA_INTERNAL_ERROR ;
}
return WERR_OK ;
}
2010-09-20 09:46:10 -07:00
const char * samdb_dn_to_dnshostname ( struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * server_dn )
{
int ldb_ret ;
struct ldb_result * res = NULL ;
const char * const attrs [ ] = { " dNSHostName " , NULL } ;
ldb_ret = ldb_search ( ldb , mem_ctx , & res ,
server_dn ,
LDB_SCOPE_BASE ,
attrs , NULL ) ;
if ( ldb_ret ! = LDB_SUCCESS ) {
DEBUG ( 4 , ( " Failed to find dNSHostName for dn %s, ldb error: %s " ,
ldb_dn_get_linearized ( server_dn ) , ldb_errstring ( ldb ) ) ) ;
return NULL ;
}
2010-10-14 09:41:42 +02:00
return ldb_msg_find_attr_as_string ( res - > msgs [ 0 ] , " dNSHostName " , NULL ) ;
2010-09-20 09:46:10 -07:00
}
2010-09-22 12:50:51 -07:00
/*
returns true if an attribute is in the filter ,
false otherwise , provided that attribute value is provided with the expression
*/
bool dsdb_attr_in_parse_tree ( struct ldb_parse_tree * tree ,
const char * attr )
{
unsigned int i ;
switch ( tree - > operation ) {
case LDB_OP_AND :
case LDB_OP_OR :
for ( i = 0 ; i < tree - > u . list . num_elements ; i + + ) {
if ( dsdb_attr_in_parse_tree ( tree - > u . list . elements [ i ] ,
attr ) )
return true ;
}
return false ;
case LDB_OP_NOT :
return dsdb_attr_in_parse_tree ( tree - > u . isnot . child , attr ) ;
case LDB_OP_EQUALITY :
case LDB_OP_GREATER :
case LDB_OP_LESS :
case LDB_OP_APPROX :
if ( ldb_attr_cmp ( tree - > u . equality . attr , attr ) = = 0 ) {
return true ;
}
return false ;
case LDB_OP_SUBSTRING :
if ( ldb_attr_cmp ( tree - > u . substring . attr , attr ) = = 0 ) {
return true ;
}
return false ;
case LDB_OP_PRESENT :
/* (attrname=*) is not filtered out */
return false ;
case LDB_OP_EXTENDED :
if ( tree - > u . extended . attr & &
ldb_attr_cmp ( tree - > u . extended . attr , attr ) = = 0 ) {
return true ;
}
return false ;
}
return false ;
}
2010-10-10 17:02:10 +02:00
bool is_attr_in_list ( const char * const * attrs , const char * attr )
{
unsigned int i ;
for ( i = 0 ; attrs [ i ] ; i + + ) {
if ( ldb_attr_cmp ( attrs [ i ] , attr ) = = 0 )
return true ;
}
return false ;
}
2016-01-12 15:51:01 +01:00
int dsdb_werror_at ( struct ldb_context * ldb , int ldb_ecode , WERROR werr ,
const char * location , const char * func ,
const char * reason )
{
if ( reason = = NULL ) {
reason = win_errstr ( werr ) ;
}
ldb_asprintf_errstring ( ldb , " %08X: %s at %s:%s " ,
W_ERROR_V ( werr ) , reason , location , func ) ;
return ldb_ecode ;
}
2011-04-01 15:58:21 +11:00
/*
map an ldb error code to an approximate NTSTATUS code
*/
NTSTATUS dsdb_ldb_err_to_ntstatus ( int err )
{
switch ( err ) {
case LDB_SUCCESS :
return NT_STATUS_OK ;
case LDB_ERR_PROTOCOL_ERROR :
return NT_STATUS_DEVICE_PROTOCOL_ERROR ;
case LDB_ERR_TIME_LIMIT_EXCEEDED :
return NT_STATUS_IO_TIMEOUT ;
case LDB_ERR_SIZE_LIMIT_EXCEEDED :
return NT_STATUS_BUFFER_TOO_SMALL ;
case LDB_ERR_COMPARE_FALSE :
case LDB_ERR_COMPARE_TRUE :
return NT_STATUS_REVISION_MISMATCH ;
case LDB_ERR_AUTH_METHOD_NOT_SUPPORTED :
return NT_STATUS_NOT_SUPPORTED ;
case LDB_ERR_STRONG_AUTH_REQUIRED :
case LDB_ERR_CONFIDENTIALITY_REQUIRED :
case LDB_ERR_SASL_BIND_IN_PROGRESS :
case LDB_ERR_INAPPROPRIATE_AUTHENTICATION :
case LDB_ERR_INVALID_CREDENTIALS :
case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS :
case LDB_ERR_UNWILLING_TO_PERFORM :
return NT_STATUS_ACCESS_DENIED ;
case LDB_ERR_NO_SUCH_OBJECT :
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
case LDB_ERR_REFERRAL :
case LDB_ERR_NO_SUCH_ATTRIBUTE :
return NT_STATUS_NOT_FOUND ;
case LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION :
return NT_STATUS_NOT_SUPPORTED ;
case LDB_ERR_ADMIN_LIMIT_EXCEEDED :
return NT_STATUS_BUFFER_TOO_SMALL ;
case LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE :
case LDB_ERR_INAPPROPRIATE_MATCHING :
case LDB_ERR_CONSTRAINT_VIOLATION :
case LDB_ERR_INVALID_ATTRIBUTE_SYNTAX :
case LDB_ERR_INVALID_DN_SYNTAX :
case LDB_ERR_NAMING_VIOLATION :
case LDB_ERR_OBJECT_CLASS_VIOLATION :
case LDB_ERR_NOT_ALLOWED_ON_NON_LEAF :
case LDB_ERR_NOT_ALLOWED_ON_RDN :
return NT_STATUS_INVALID_PARAMETER ;
case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS :
case LDB_ERR_ENTRY_ALREADY_EXISTS :
return NT_STATUS_ERROR_DS_OBJ_STRING_NAME_EXISTS ;
case LDB_ERR_BUSY :
return NT_STATUS_NETWORK_BUSY ;
case LDB_ERR_ALIAS_PROBLEM :
case LDB_ERR_ALIAS_DEREFERENCING_PROBLEM :
case LDB_ERR_UNAVAILABLE :
case LDB_ERR_LOOP_DETECT :
case LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED :
case LDB_ERR_AFFECTS_MULTIPLE_DSAS :
case LDB_ERR_OTHER :
case LDB_ERR_OPERATIONS_ERROR :
break ;
}
return NT_STATUS_UNSUCCESSFUL ;
}
2011-09-28 11:04:29 +10:00
/*
create a new naming context that will hold a partial replica
*/
int dsdb_create_partial_replica_NC ( struct ldb_context * ldb , struct ldb_dn * dn )
{
TALLOC_CTX * tmp_ctx = talloc_new ( ldb ) ;
struct ldb_message * msg ;
int ret ;
msg = ldb_msg_new ( tmp_ctx ) ;
if ( msg = = NULL ) {
talloc_free ( tmp_ctx ) ;
return ldb_oom ( ldb ) ;
}
msg - > dn = dn ;
ret = ldb_msg_add_string ( msg , " objectClass " , " top " ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ldb_oom ( ldb ) ;
}
/* [MS-DRSR] implies that we should only add the 'top'
* objectclass , but that would cause lots of problems with our
* objectclass code as top is not structural , so we add
* ' domainDNS ' as well to keep things sane . We ' re expecting
* this new NC to be of objectclass domainDNS after
* replication anyway
*/
ret = ldb_msg_add_string ( msg , " objectClass " , " domainDNS " ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ldb_oom ( ldb ) ;
}
ret = ldb_msg_add_fmt ( msg , " instanceType " , " %u " ,
INSTANCE_TYPE_IS_NC_HEAD |
INSTANCE_TYPE_NC_ABOVE |
INSTANCE_TYPE_UNINSTANT ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ldb_oom ( ldb ) ;
}
ret = dsdb_add ( ldb , msg , DSDB_MODIFY_PARTIAL_REPLICA ) ;
2011-10-01 10:57:14 +10:00
if ( ret ! = LDB_SUCCESS & & ret ! = LDB_ERR_ENTRY_ALREADY_EXISTS ) {
DEBUG ( 0 , ( " Failed to create new NC for %s - %s (%s) \n " ,
ldb_dn_get_linearized ( dn ) ,
ldb_errstring ( ldb ) , ldb_strerror ( ret ) ) ) ;
2011-09-28 11:04:29 +10:00
talloc_free ( tmp_ctx ) ;
return ret ;
}
DEBUG ( 1 , ( " Created new NC for %s \n " , ldb_dn_get_linearized ( dn ) ) ) ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2012-03-18 18:46:18 +01:00
/**
build a GUID from a string
*/
_PUBLIC_ NTSTATUS NS_GUID_from_string ( const char * s , struct GUID * guid )
{
NTSTATUS status = NT_STATUS_INVALID_PARAMETER ;
uint32_t time_low ;
uint32_t time_mid , time_hi_and_version ;
uint32_t clock_seq [ 2 ] ;
uint32_t node [ 6 ] ;
int i ;
if ( s = = NULL ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2018-03-22 16:49:29 +13:00
status = parse_guid_string ( s ,
& time_low ,
& time_mid ,
& time_hi_and_version ,
clock_seq ,
node ) ;
2012-03-18 18:46:18 +01:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
guid - > time_low = time_low ;
guid - > time_mid = time_mid ;
guid - > time_hi_and_version = time_hi_and_version ;
guid - > clock_seq [ 0 ] = clock_seq [ 0 ] ;
guid - > clock_seq [ 1 ] = clock_seq [ 1 ] ;
for ( i = 0 ; i < 6 ; i + + ) {
guid - > node [ i ] = node [ i ] ;
}
return NT_STATUS_OK ;
}
_PUBLIC_ char * NS_GUID_string ( TALLOC_CTX * mem_ctx , const struct GUID * guid )
{
return talloc_asprintf ( mem_ctx ,
" %08x-%04x%04x-%02x%02x%02x%02x-%02x%02x%02x%02x " ,
guid - > time_low , guid - > time_mid ,
guid - > time_hi_and_version ,
guid - > clock_seq [ 0 ] ,
guid - > clock_seq [ 1 ] ,
guid - > node [ 0 ] , guid - > node [ 1 ] ,
guid - > node [ 2 ] , guid - > node [ 3 ] ,
guid - > node [ 4 ] , guid - > node [ 5 ] ) ;
}
2013-11-28 16:18:31 +13:00
2014-03-26 11:32:05 +13:00
/*
* Return the effective badPwdCount
*
* This requires that the user_msg have ( if present ) :
* - badPasswordTime
* - badPwdCount
*
* This also requires that the domain_msg have ( if present ) :
* - lockOutObservationWindow
*/
2016-04-29 13:20:12 +02:00
static int dsdb_effective_badPwdCount ( const struct ldb_message * user_msg ,
2014-03-26 11:32:05 +13:00
int64_t lockOutObservationWindow ,
NTTIME now )
{
int64_t badPasswordTime ;
badPasswordTime = ldb_msg_find_attr_as_int64 ( user_msg , " badPasswordTime " , 0 ) ;
if ( badPasswordTime - lockOutObservationWindow > = now ) {
return ldb_msg_find_attr_as_int ( user_msg , " badPwdCount " , 0 ) ;
} else {
return 0 ;
}
}
2018-04-11 10:33:21 +12:00
/*
* Returns a user ' s PSO , or NULL if none was found
*/
static struct ldb_result * lookup_user_pso ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
const struct ldb_message * user_msg ,
const char * const * attrs )
{
struct ldb_result * res = NULL ;
struct ldb_dn * pso_dn = NULL ;
int ret ;
/* if the user has a PSO that applies, then use the PSO's setting */
pso_dn = ldb_msg_find_attr_as_dn ( sam_ldb , mem_ctx , user_msg ,
" msDS-ResultantPSO " ) ;
if ( pso_dn ! = NULL ) {
ret = dsdb_search_dn ( sam_ldb , mem_ctx , & res , pso_dn , attrs , 0 ) ;
if ( ret ! = LDB_SUCCESS ) {
/*
* log the error . The caller should fallback to using
* the default domain password settings
*/
DBG_ERR ( " Error retrieving msDS-ResultantPSO %s for %s " ,
ldb_dn_get_linearized ( pso_dn ) ,
ldb_dn_get_linearized ( user_msg - > dn ) ) ;
}
talloc_free ( pso_dn ) ;
}
return res ;
}
2014-03-26 11:32:05 +13:00
/*
* Return the effective badPwdCount
*
* This requires that the user_msg have ( if present ) :
* - badPasswordTime
* - badPwdCount
2018-04-11 10:33:21 +12:00
* - msDS - ResultantPSO
2014-03-26 11:32:05 +13:00
*/
int samdb_result_effective_badPwdCount ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * domain_dn ,
2016-04-29 13:20:12 +02:00
const struct ldb_message * user_msg )
2014-03-26 11:32:05 +13:00
{
struct timeval tv_now = timeval_current ( ) ;
NTTIME now = timeval_to_nttime ( & tv_now ) ;
2018-04-11 10:33:21 +12:00
int64_t lockOutObservationWindow ;
struct ldb_result * res = NULL ;
const char * attrs [ ] = { " msDS-LockoutObservationWindow " ,
NULL } ;
res = lookup_user_pso ( sam_ldb , mem_ctx , user_msg , attrs ) ;
if ( res ! = NULL ) {
lockOutObservationWindow =
2018-11-13 13:19:04 +13:00
ldb_msg_find_attr_as_int64 ( res - > msgs [ 0 ] ,
" msDS-LockoutObservationWindow " ,
2018-11-13 13:22:41 +13:00
DEFAULT_OBSERVATION_WINDOW ) ;
2018-04-11 10:33:21 +12:00
talloc_free ( res ) ;
} else {
/* no PSO was found, lookup the default domain setting */
lockOutObservationWindow =
samdb_search_int64 ( sam_ldb , mem_ctx , 0 , domain_dn ,
" lockOutObservationWindow " , NULL ) ;
}
2014-03-26 11:32:05 +13:00
return dsdb_effective_badPwdCount ( user_msg , lockOutObservationWindow , now ) ;
}
2018-04-06 16:42:50 +12:00
/*
* Returns the lockoutThreshold that applies . If a PSO is specified , then that
* setting is used over the domain defaults
*/
static int64_t get_lockout_threshold ( struct ldb_message * domain_msg ,
struct ldb_message * pso_msg )
{
if ( pso_msg ! = NULL ) {
return ldb_msg_find_attr_as_int ( pso_msg ,
" msDS-LockoutThreshold " , 0 ) ;
} else {
return ldb_msg_find_attr_as_int ( domain_msg ,
" lockoutThreshold " , 0 ) ;
}
}
/*
* Returns the lockOutObservationWindow that applies . If a PSO is specified ,
* then that setting is used over the domain defaults
*/
static int64_t get_lockout_observation_window ( struct ldb_message * domain_msg ,
struct ldb_message * pso_msg )
{
if ( pso_msg ! = NULL ) {
2018-11-13 12:24:16 +13:00
return ldb_msg_find_attr_as_int64 ( pso_msg ,
" msDS-LockoutObservationWindow " ,
2018-11-13 13:22:41 +13:00
DEFAULT_OBSERVATION_WINDOW ) ;
2018-04-06 16:42:50 +12:00
} else {
2018-11-13 12:24:16 +13:00
return ldb_msg_find_attr_as_int64 ( domain_msg ,
2018-11-13 13:22:41 +13:00
" lockOutObservationWindow " ,
DEFAULT_OBSERVATION_WINDOW ) ;
2018-04-06 16:42:50 +12:00
}
}
2013-11-28 16:18:31 +13:00
/*
* Prepare an update to the badPwdCount and associated attributes .
*
* This requires that the user_msg have ( if present ) :
* - objectSid
* - badPasswordTime
* - badPwdCount
*
* This also requires that the domain_msg have ( if present ) :
* - pwdProperties
* - lockoutThreshold
* - lockOutObservationWindow
2018-04-06 16:42:50 +12:00
*
* This also requires that the pso_msg have ( if present ) :
* - msDS - LockoutThreshold
* - msDS - LockoutObservationWindow
2013-11-28 16:18:31 +13:00
*/
NTSTATUS dsdb_update_bad_pwd_count ( TALLOC_CTX * mem_ctx ,
struct ldb_context * sam_ctx ,
struct ldb_message * user_msg ,
struct ldb_message * domain_msg ,
2018-04-06 16:42:50 +12:00
struct ldb_message * pso_msg ,
2013-11-28 16:18:31 +13:00
struct ldb_message * * _mod_msg )
{
int i , ret , badPwdCount ;
2014-03-26 11:32:05 +13:00
int64_t lockoutThreshold , lockOutObservationWindow ;
2013-11-28 16:18:31 +13:00
struct dom_sid * sid ;
struct timeval tv_now = timeval_current ( ) ;
NTTIME now = timeval_to_nttime ( & tv_now ) ;
NTSTATUS status ;
uint32_t pwdProperties , rid = 0 ;
struct ldb_message * mod_msg ;
sid = samdb_result_dom_sid ( mem_ctx , user_msg , " objectSid " ) ;
pwdProperties = ldb_msg_find_attr_as_uint ( domain_msg ,
" pwdProperties " , - 1 ) ;
if ( sid & & ! ( pwdProperties & DOMAIN_PASSWORD_LOCKOUT_ADMINS ) ) {
status = dom_sid_split_rid ( NULL , sid , NULL , & rid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
/*
* This can ' t happen anyway , but always try
* and update the badPwdCount on failure
*/
rid = 0 ;
}
}
TALLOC_FREE ( sid ) ;
/*
* Work out if we are doing password lockout on the domain .
* Also , the built in administrator account is exempt :
* http : //msdn.microsoft.com/en-us/library/windows/desktop/aa375371%28v=vs.85%29.aspx
*/
2018-04-06 16:42:50 +12:00
lockoutThreshold = get_lockout_threshold ( domain_msg , pso_msg ) ;
2013-11-28 16:18:31 +13:00
if ( lockoutThreshold = = 0 | | ( rid = = DOMAIN_RID_ADMINISTRATOR ) ) {
DEBUG ( 5 , ( " Not updating badPwdCount on %s after wrong password \n " ,
ldb_dn_get_linearized ( user_msg - > dn ) ) ) ;
return NT_STATUS_OK ;
}
mod_msg = ldb_msg_new ( mem_ctx ) ;
if ( mod_msg = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
mod_msg - > dn = ldb_dn_copy ( mod_msg , user_msg - > dn ) ;
if ( mod_msg - > dn = = NULL ) {
TALLOC_FREE ( mod_msg ) ;
return NT_STATUS_NO_MEMORY ;
}
2018-04-06 16:42:50 +12:00
lockOutObservationWindow = get_lockout_observation_window ( domain_msg ,
pso_msg ) ;
2014-03-26 11:32:05 +13:00
badPwdCount = dsdb_effective_badPwdCount ( user_msg , lockOutObservationWindow , now ) ;
2013-11-28 16:18:31 +13:00
badPwdCount + + ;
ret = samdb_msg_add_int ( sam_ctx , mod_msg , mod_msg , " badPwdCount " , badPwdCount ) ;
if ( ret ! = LDB_SUCCESS ) {
TALLOC_FREE ( mod_msg ) ;
return NT_STATUS_NO_MEMORY ;
}
ret = samdb_msg_add_int64 ( sam_ctx , mod_msg , mod_msg , " badPasswordTime " , now ) ;
if ( ret ! = LDB_SUCCESS ) {
TALLOC_FREE ( mod_msg ) ;
return NT_STATUS_NO_MEMORY ;
}
if ( badPwdCount > = lockoutThreshold ) {
ret = samdb_msg_add_int64 ( sam_ctx , mod_msg , mod_msg , " lockoutTime " , now ) ;
if ( ret ! = LDB_SUCCESS ) {
TALLOC_FREE ( mod_msg ) ;
return NT_STATUS_NO_MEMORY ;
}
2017-12-18 20:14:31 +01:00
DEBUGC ( DBGC_AUTH , 1 , ( " Locked out user %s after %d wrong passwords \n " ,
2013-11-28 16:18:31 +13:00
ldb_dn_get_linearized ( user_msg - > dn ) , badPwdCount ) ) ;
} else {
2017-12-18 20:14:31 +01:00
DEBUGC ( DBGC_AUTH , 5 , ( " Updated badPwdCount on %s after %d wrong passwords \n " ,
2013-11-28 16:18:31 +13:00
ldb_dn_get_linearized ( user_msg - > dn ) , badPwdCount ) ) ;
}
/* mark all the message elements as LDB_FLAG_MOD_REPLACE */
for ( i = 0 ; i < mod_msg - > num_elements ; i + + ) {
mod_msg - > elements [ i ] . flags = LDB_FLAG_MOD_REPLACE ;
}
* _mod_msg = mod_msg ;
return NT_STATUS_OK ;
}
2015-01-12 03:30:17 +02:00
/**
* Sets defaults for a User object
* List of default attributes set :
* accountExpires , badPasswordTime , badPwdCount ,
* codePage , countryCode , lastLogoff , lastLogon
* logonCount , pwdLastSet
*/
2016-02-11 08:31:46 +01:00
int dsdb_user_obj_set_defaults ( struct ldb_context * ldb ,
struct ldb_message * usr_obj ,
struct ldb_request * req )
2015-01-12 03:30:17 +02:00
{
2015-01-28 01:43:10 +02:00
int i , ret ;
const struct attribute_values {
const char * name ;
const char * value ;
2016-07-08 10:43:19 +02:00
const char * add_value ;
const char * mod_value ;
const char * control ;
unsigned add_flags ;
unsigned mod_flags ;
2015-01-28 01:43:10 +02:00
} map [ ] = {
{
. name = " accountExpires " ,
2016-07-08 10:43:19 +02:00
. add_value = " 9223372036854775807 " ,
. mod_value = " 0 " ,
2015-01-28 01:43:10 +02:00
} ,
{
. name = " badPasswordTime " ,
. value = " 0 "
} ,
{
. name = " badPwdCount " ,
. value = " 0 "
} ,
{
. name = " codePage " ,
. value = " 0 "
} ,
{
. name = " countryCode " ,
. value = " 0 "
} ,
{
. name = " lastLogoff " ,
. value = " 0 "
} ,
{
. name = " lastLogon " ,
. value = " 0 "
} ,
{
. name = " logonCount " ,
. value = " 0 "
} ,
2016-07-07 15:44:47 +02:00
{
. name = " logonHours " ,
2016-07-08 10:43:19 +02:00
. add_flags = DSDB_FLAG_INTERNAL_FORCE_META_DATA ,
2016-07-07 15:44:47 +02:00
} ,
2015-01-28 01:43:10 +02:00
{
. name = " pwdLastSet " ,
2016-02-11 08:31:46 +01:00
. value = " 0 " ,
2016-07-08 10:43:19 +02:00
. control = DSDB_CONTROL_PASSWORD_DEFAULT_LAST_SET_OID ,
} ,
{
. name = " adminCount " ,
. mod_value = " 0 " ,
} ,
{
. name = " operatorCount " ,
. mod_value = " 0 " ,
} ,
2015-01-28 01:43:10 +02:00
} ;
2015-01-12 03:30:17 +02:00
2015-01-28 01:43:10 +02:00
for ( i = 0 ; i < ARRAY_SIZE ( map ) ; i + + ) {
2016-02-11 08:31:46 +01:00
bool added = false ;
2016-07-08 10:43:19 +02:00
const char * value = NULL ;
unsigned flags = 0 ;
if ( req ! = NULL & & req - > operation = = LDB_ADD ) {
value = map [ i ] . add_value ;
flags = map [ i ] . add_flags ;
} else {
value = map [ i ] . mod_value ;
flags = map [ i ] . mod_flags ;
}
if ( value = = NULL ) {
value = map [ i ] . value ;
}
if ( value ! = NULL ) {
flags | = LDB_FLAG_MOD_ADD ;
}
if ( flags = = 0 ) {
continue ;
}
2016-02-11 08:31:46 +01:00
ret = samdb_find_or_add_attribute_ex ( ldb , usr_obj ,
map [ i ] . name ,
2016-07-08 10:43:19 +02:00
value , flags ,
2016-02-11 08:31:46 +01:00
& added ) ;
2015-01-28 01:43:10 +02:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2016-02-11 08:31:46 +01:00
2016-07-08 10:43:19 +02:00
if ( req ! = NULL & & added & & map [ i ] . control ! = NULL ) {
2016-02-11 08:31:46 +01:00
ret = ldb_request_add_control ( req ,
2016-07-08 10:43:19 +02:00
map [ i ] . control ,
2016-02-11 08:31:46 +01:00
false , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
2015-01-28 01:43:10 +02:00
}
2015-01-12 03:30:17 +02:00
return LDB_SUCCESS ;
}
2015-01-12 04:46:38 +02:00
/**
* Sets ' sAMAccountType on user object based on userAccountControl
* @ param ldb Current ldb_context
* @ param usr_obj ldb_message representing User object
* @ param user_account_control Value for userAccountControl flags
* @ param account_type_p Optional pointer to account_type to return
* @ return LDB_SUCCESS or LDB_ERR * code on failure
*/
int dsdb_user_obj_set_account_type ( struct ldb_context * ldb , struct ldb_message * usr_obj ,
uint32_t user_account_control , uint32_t * account_type_p )
{
int ret ;
uint32_t account_type ;
struct ldb_message_element * el ;
account_type = ds_uf2atype ( user_account_control ) ;
if ( account_type = = 0 ) {
ldb_set_errstring ( ldb , " dsdb: Unrecognized account type! " ) ;
return LDB_ERR_UNWILLING_TO_PERFORM ;
}
ret = samdb_msg_add_uint ( ldb , usr_obj , usr_obj ,
" sAMAccountType " ,
account_type ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
el = ldb_msg_find_element ( usr_obj , " sAMAccountType " ) ;
el - > flags = LDB_FLAG_MOD_REPLACE ;
if ( account_type_p ) {
* account_type_p = account_type ;
}
return LDB_SUCCESS ;
}
2015-01-18 23:58:13 +02:00
/**
* Determine and set primaryGroupID based on userAccountControl value
* @ param ldb Current ldb_context
* @ param usr_obj ldb_message representing User object
* @ param user_account_control Value for userAccountControl flags
* @ param group_rid_p Optional pointer to group RID to return
* @ return LDB_SUCCESS or LDB_ERR * code on failure
*/
int dsdb_user_obj_set_primary_group_id ( struct ldb_context * ldb , struct ldb_message * usr_obj ,
uint32_t user_account_control , uint32_t * group_rid_p )
{
int ret ;
uint32_t rid ;
struct ldb_message_element * el ;
rid = ds_uf2prim_group_rid ( user_account_control ) ;
ret = samdb_msg_add_uint ( ldb , usr_obj , usr_obj ,
" primaryGroupID " , rid ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
el = ldb_msg_find_element ( usr_obj , " primaryGroupID " ) ;
el - > flags = LDB_FLAG_MOD_REPLACE ;
if ( group_rid_p ) {
* group_rid_p = rid ;
}
return LDB_SUCCESS ;
}
2017-08-23 10:23:10 +12:00
/**
* Returns True if the source and target DNs both have the same naming context ,
* i . e . they ' re both in the same partition .
*/
bool dsdb_objects_have_same_nc ( struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * source_dn ,
struct ldb_dn * target_dn )
{
TALLOC_CTX * tmp_ctx ;
struct ldb_dn * source_nc ;
struct ldb_dn * target_nc ;
int ret ;
bool same_nc = true ;
tmp_ctx = talloc_new ( mem_ctx ) ;
ret = dsdb_find_nc_root ( ldb , tmp_ctx , source_dn , & source_nc ) ;
if ( ret ! = LDB_SUCCESS ) {
DBG_ERR ( " Failed to find base DN for source %s \n " ,
ldb_dn_get_linearized ( source_dn ) ) ;
talloc_free ( tmp_ctx ) ;
return true ;
}
ret = dsdb_find_nc_root ( ldb , tmp_ctx , target_dn , & target_nc ) ;
if ( ret ! = LDB_SUCCESS ) {
DBG_ERR ( " Failed to find base DN for target %s \n " ,
ldb_dn_get_linearized ( target_dn ) ) ;
talloc_free ( tmp_ctx ) ;
return true ;
}
same_nc = ( ldb_dn_compare ( source_nc , target_nc ) = = 0 ) ;
talloc_free ( tmp_ctx ) ;
return same_nc ;
}
2019-02-13 14:36:33 +13:00
/*
* Context for dsdb_count_domain_callback
*/
struct dsdb_count_domain_context {
/*
* Number of matching records
*/
size_t count ;
/*
* sid of the domain that the records must belong to .
* if NULL records can belong to any domain .
*/
struct dom_sid * dom_sid ;
} ;
/*
* @ brief ldb aysnc callback for dsdb_domain_count .
*
* count the number of records in the database matching an LDAP query ,
* optionally filtering for domain membership .
*
* @ param [ in , out ] req the ldb request being processed
* req - > context contains :
* count The number of matching records
* dom_sid The domain sid , if present records must belong
* to the domain to be counted .
* @ param [ in , out ] ares The query result .
*
* @ return an LDB error code
*
*/
static int dsdb_count_domain_callback (
struct ldb_request * req ,
struct ldb_reply * ares )
{
if ( ares = = NULL ) {
return ldb_request_done ( req , LDB_ERR_OPERATIONS_ERROR ) ;
}
if ( ares - > error ! = LDB_SUCCESS ) {
int error = ares - > error ;
TALLOC_FREE ( ares ) ;
return ldb_request_done ( req , error ) ;
}
switch ( ares - > type ) {
case LDB_REPLY_ENTRY :
{
struct dsdb_count_domain_context * context = NULL ;
2019-03-11 17:11:06 +01:00
ssize_t ret ;
2019-03-11 16:55:57 +01:00
bool in_domain ;
2019-02-13 14:36:33 +13:00
struct dom_sid sid ;
const struct ldb_val * v ;
context = req - > context ;
if ( context - > dom_sid = = NULL ) {
context - > count + + ;
break ;
}
v = ldb_msg_find_ldb_val ( ares - > message , " objectSid " ) ;
if ( v = = NULL ) {
break ;
}
2019-03-11 16:55:57 +01:00
ret = sid_parse ( v - > data , v - > length , & sid ) ;
2019-03-11 17:11:06 +01:00
if ( ret = = - 1 ) {
2019-02-13 14:36:33 +13:00
break ;
}
in_domain = dom_sid_in_domain ( context - > dom_sid , & sid ) ;
if ( ! in_domain ) {
break ;
}
context - > count + + ;
break ;
}
case LDB_REPLY_REFERRAL :
break ;
case LDB_REPLY_DONE :
TALLOC_FREE ( ares ) ;
return ldb_request_done ( req , LDB_SUCCESS ) ;
}
TALLOC_FREE ( ares ) ;
return LDB_SUCCESS ;
}
/*
* @ brief Count the number of records matching a query .
*
* Count the number of entries in the database matching the supplied query ,
* optionally filtering only those entries belonging to the supplied domain .
*
* @ param ldb [ in ] Current ldb context
* @ param count [ out ] Pointer to the count
* @ param base [ in ] The base dn for the quey
* @ param dom_sid [ in ] The domain sid , if non NULL records that are not a member
* of the domain are ignored .
* @ param scope [ in ] Search scope .
* @ param exp_fmt [ in ] format string for the query .
*
* @ return LDB_STATUS code .
*/
int dsdb_domain_count (
struct ldb_context * ldb ,
size_t * count ,
struct ldb_dn * base ,
struct dom_sid * dom_sid ,
enum ldb_scope scope ,
const char * exp_fmt , . . . )
{
TALLOC_CTX * tmp_ctx = NULL ;
struct ldb_request * req = NULL ;
struct dsdb_count_domain_context * context = NULL ;
char * expression = NULL ;
const char * object_sid [ ] = { " objectSid " , NULL } ;
const char * none [ ] = { NULL } ;
va_list ap ;
int ret ;
* count = 0 ;
tmp_ctx = talloc_new ( ldb ) ;
context = talloc_zero ( tmp_ctx , struct dsdb_count_domain_context ) ;
if ( context = = NULL ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
context - > dom_sid = dom_sid ;
if ( exp_fmt ) {
va_start ( ap , exp_fmt ) ;
expression = talloc_vasprintf ( tmp_ctx , exp_fmt , ap ) ;
va_end ( ap ) ;
if ( expression = = NULL ) {
TALLOC_FREE ( context ) ;
TALLOC_FREE ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
}
ret = ldb_build_search_req (
& req ,
ldb ,
tmp_ctx ,
base ,
scope ,
expression ,
( dom_sid = = NULL ) ? none : object_sid ,
NULL ,
context ,
dsdb_count_domain_callback ,
NULL ) ;
ldb_req_set_location ( req , " dsdb_domain_count " ) ;
if ( ret ! = LDB_SUCCESS ) goto done ;
ret = ldb_request ( ldb , req ) ;
if ( ret = = LDB_SUCCESS ) {
ret = ldb_wait ( req - > handle , LDB_WAIT_ALL ) ;
if ( ret = = LDB_SUCCESS ) {
* count = context - > count ;
}
}
done :
TALLOC_FREE ( expression ) ;
TALLOC_FREE ( req ) ;
TALLOC_FREE ( context ) ;
TALLOC_FREE ( tmp_ctx ) ;
return ret ;
}