2007-12-17 06:22:44 +03:00
/*
Unix SMB / CIFS implementation .
Samba utility functions
Copyright ( C ) Andrew Tridgell 2004
Copyright ( C ) Volker Lendecke 2004
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2006
Copyright ( C ) Jelmer Vernooij < jelmer @ samba . org > 2007
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2009-01-21 15:40:18 +03:00
# include "events/events.h"
2007-12-17 06:22:44 +03:00
# include "ldb.h"
# include "ldb_errors.h"
2008-10-11 23:31:42 +04:00
# include "../lib/util/util_ldb.h"
2008-10-16 05:48:16 +04:00
# include "../lib/crypto/crypto.h"
2007-12-17 06:22:44 +03:00
# include "dsdb/samdb/samdb.h"
# include "libcli/security/security.h"
# include "librpc/gen_ndr/ndr_security.h"
2008-04-02 06:53:27 +04:00
# include "librpc/gen_ndr/ndr_misc.h"
2009-06-12 16:27:19 +04:00
# include "../libds/common/flags.h"
2007-12-17 06:22:44 +03:00
# include "dsdb/common/proto.h"
# include "libcli/ldap/ldap_ndr.h"
2008-01-02 07:05:05 +03:00
# include "param/param.h"
2007-12-17 06:22:44 +03:00
# include "libcli/auth/libcli_auth.h"
2009-09-12 05:09:10 +04:00
# include "librpc/gen_ndr/ndr_drsblobs.h"
2009-11-14 22:12:42 +03:00
# include "system/locale.h"
2007-12-17 06:22:44 +03:00
/*
search the sam for the specified attributes in a specific domain , filter on
objectSid being in domain_sid .
*/
int samdb_search_domain ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * basedn ,
struct ldb_message * * * res ,
const char * const * attrs ,
const struct dom_sid * domain_sid ,
const char * format , . . . ) _PRINTF_ATTRIBUTE ( 7 , 8 )
{
va_list ap ;
int i , count ;
va_start ( ap , format ) ;
count = gendb_search_v ( sam_ldb , mem_ctx , basedn ,
res , attrs , format , ap ) ;
va_end ( ap ) ;
i = 0 ;
while ( i < count ) {
struct dom_sid * entry_sid ;
entry_sid = samdb_result_dom_sid ( mem_ctx , ( * res ) [ i ] , " objectSid " ) ;
if ( ( entry_sid = = NULL ) | |
( ! dom_sid_in_domain ( domain_sid , entry_sid ) ) ) {
/* Delete that entry from the result set */
( * res ) [ i ] = ( * res ) [ count - 1 ] ;
count - = 1 ;
talloc_free ( entry_sid ) ;
continue ;
}
talloc_free ( entry_sid ) ;
i + = 1 ;
}
return count ;
}
/*
search the sam for a single string attribute in exactly 1 record
*/
const char * samdb_search_string_v ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * basedn ,
const char * attr_name ,
const char * format , va_list ap ) _PRINTF_ATTRIBUTE ( 5 , 0 )
{
int count ;
const char * attrs [ 2 ] = { NULL , NULL } ;
struct ldb_message * * res = NULL ;
attrs [ 0 ] = attr_name ;
count = gendb_search_v ( sam_ldb , mem_ctx , basedn , & res , attrs , format , ap ) ;
if ( count > 1 ) {
DEBUG ( 1 , ( " samdb: search for %s %s not single valued (count=%d) \n " ,
attr_name , format , count ) ) ;
}
if ( count ! = 1 ) {
talloc_free ( res ) ;
return NULL ;
}
return samdb_result_string ( res [ 0 ] , attr_name , NULL ) ;
}
/*
search the sam for a single string attribute in exactly 1 record
*/
const char * samdb_search_string ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * basedn ,
const char * attr_name ,
const char * format , . . . ) _PRINTF_ATTRIBUTE ( 5 , 6 )
{
va_list ap ;
const char * str ;
va_start ( ap , format ) ;
str = samdb_search_string_v ( sam_ldb , mem_ctx , basedn , attr_name , format , ap ) ;
va_end ( ap ) ;
return str ;
}
struct ldb_dn * samdb_search_dn ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * basedn ,
const char * format , . . . ) _PRINTF_ATTRIBUTE ( 4 , 5 )
{
va_list ap ;
struct ldb_dn * ret ;
struct ldb_message * * res = NULL ;
int count ;
va_start ( ap , format ) ;
count = gendb_search_v ( sam_ldb , mem_ctx , basedn , & res , NULL , format , ap ) ;
va_end ( ap ) ;
if ( count ! = 1 ) return NULL ;
ret = talloc_steal ( mem_ctx , res [ 0 ] - > dn ) ;
talloc_free ( res ) ;
return ret ;
}
/*
search the sam for a dom_sid attribute in exactly 1 record
*/
struct dom_sid * samdb_search_dom_sid ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * basedn ,
const char * attr_name ,
const char * format , . . . ) _PRINTF_ATTRIBUTE ( 5 , 6 )
{
va_list ap ;
int count ;
struct ldb_message * * res ;
const char * attrs [ 2 ] = { NULL , NULL } ;
struct dom_sid * sid ;
attrs [ 0 ] = attr_name ;
va_start ( ap , format ) ;
count = gendb_search_v ( sam_ldb , mem_ctx , basedn , & res , attrs , format , ap ) ;
va_end ( ap ) ;
if ( count > 1 ) {
DEBUG ( 1 , ( " samdb: search for %s %s not single valued (count=%d) \n " ,
attr_name , format , count ) ) ;
}
if ( count ! = 1 ) {
talloc_free ( res ) ;
return NULL ;
}
sid = samdb_result_dom_sid ( mem_ctx , res [ 0 ] , attr_name ) ;
talloc_free ( res ) ;
return sid ;
}
/*
return the count of the number of records in the sam matching the query
*/
int samdb_search_count ( struct ldb_context * sam_ldb ,
struct ldb_dn * basedn ,
2009-12-04 09:45:38 +03:00
const char * format , . . . ) _PRINTF_ATTRIBUTE ( 3 , 4 )
2007-12-17 06:22:44 +03:00
{
va_list ap ;
struct ldb_message * * res ;
2009-12-04 09:45:38 +03:00
const char * attrs [ ] = { NULL } ;
2007-12-17 06:22:44 +03:00
int ret ;
2009-12-04 09:45:38 +03:00
TALLOC_CTX * tmp_ctx = talloc_new ( sam_ldb ) ;
2007-12-17 06:22:44 +03:00
va_start ( ap , format ) ;
2009-12-04 09:45:38 +03:00
ret = gendb_search_v ( sam_ldb , tmp_ctx , basedn , & res , attrs , format , ap ) ;
2007-12-17 06:22:44 +03:00
va_end ( ap ) ;
2009-12-04 09:45:38 +03:00
talloc_free ( tmp_ctx ) ;
2007-12-17 06:22:44 +03:00
return ret ;
}
/*
search the sam for a single integer attribute in exactly 1 record
*/
uint_t samdb_search_uint ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
uint_t default_value ,
struct ldb_dn * basedn ,
const char * attr_name ,
const char * format , . . . ) _PRINTF_ATTRIBUTE ( 6 , 7 )
{
va_list ap ;
int count ;
struct ldb_message * * res ;
const char * attrs [ 2 ] = { NULL , NULL } ;
attrs [ 0 ] = attr_name ;
va_start ( ap , format ) ;
count = gendb_search_v ( sam_ldb , mem_ctx , basedn , & res , attrs , format , ap ) ;
va_end ( ap ) ;
if ( count ! = 1 ) {
return default_value ;
}
return samdb_result_uint ( res [ 0 ] , attr_name , default_value ) ;
}
/*
search the sam for a single signed 64 bit integer attribute in exactly 1 record
*/
int64_t samdb_search_int64 ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
int64_t default_value ,
struct ldb_dn * basedn ,
const char * attr_name ,
const char * format , . . . ) _PRINTF_ATTRIBUTE ( 6 , 7 )
{
va_list ap ;
int count ;
struct ldb_message * * res ;
const char * attrs [ 2 ] = { NULL , NULL } ;
attrs [ 0 ] = attr_name ;
va_start ( ap , format ) ;
count = gendb_search_v ( sam_ldb , mem_ctx , basedn , & res , attrs , format , ap ) ;
va_end ( ap ) ;
if ( count ! = 1 ) {
return default_value ;
}
return samdb_result_int64 ( res [ 0 ] , attr_name , default_value ) ;
}
/*
search the sam for multipe records each giving a single string attribute
return the number of matches , or - 1 on error
*/
int samdb_search_string_multiple ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * basedn ,
const char * * * strs ,
const char * attr_name ,
const char * format , . . . ) _PRINTF_ATTRIBUTE ( 6 , 7 )
{
va_list ap ;
int count , i ;
const char * attrs [ 2 ] = { NULL , NULL } ;
struct ldb_message * * res = NULL ;
attrs [ 0 ] = attr_name ;
va_start ( ap , format ) ;
count = gendb_search_v ( sam_ldb , mem_ctx , basedn , & res , attrs , format , ap ) ;
va_end ( ap ) ;
if ( count < = 0 ) {
return count ;
}
/* make sure its single valued */
for ( i = 0 ; i < count ; i + + ) {
if ( res [ i ] - > num_elements ! = 1 ) {
DEBUG ( 1 , ( " samdb: search for %s %s not single valued \n " ,
attr_name , format ) ) ;
talloc_free ( res ) ;
return - 1 ;
}
}
* strs = talloc_array ( mem_ctx , const char * , count + 1 ) ;
if ( ! * strs ) {
talloc_free ( res ) ;
return - 1 ;
}
for ( i = 0 ; i < count ; i + + ) {
( * strs ) [ i ] = samdb_result_string ( res [ i ] , attr_name , NULL ) ;
}
( * strs ) [ count ] = NULL ;
return count ;
}
/*
pull a uint from a result set .
*/
uint_t samdb_result_uint ( const struct ldb_message * msg , const char * attr , uint_t default_value )
{
return ldb_msg_find_attr_as_uint ( msg , attr , default_value ) ;
}
/*
pull a ( signed ) int64 from a result set .
*/
int64_t samdb_result_int64 ( const struct ldb_message * msg , const char * attr , int64_t default_value )
{
return ldb_msg_find_attr_as_int64 ( msg , attr , default_value ) ;
}
/*
pull a string from a result set .
*/
const char * samdb_result_string ( const struct ldb_message * msg , const char * attr ,
const char * default_value )
{
return ldb_msg_find_attr_as_string ( msg , attr , default_value ) ;
}
struct ldb_dn * samdb_result_dn ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx , const struct ldb_message * msg ,
const char * attr , struct ldb_dn * default_value )
{
struct ldb_dn * ret_dn = ldb_msg_find_attr_as_dn ( ldb , mem_ctx , msg , attr ) ;
if ( ! ret_dn ) {
return default_value ;
}
return ret_dn ;
}
/*
pull a rid from a objectSid in a result set .
*/
uint32_t samdb_result_rid_from_sid ( TALLOC_CTX * mem_ctx , const struct ldb_message * msg ,
const char * attr , uint32_t default_value )
{
struct dom_sid * sid ;
uint32_t rid ;
sid = samdb_result_dom_sid ( mem_ctx , msg , attr ) ;
if ( sid = = NULL ) {
return default_value ;
}
rid = sid - > sub_auths [ sid - > num_auths - 1 ] ;
talloc_free ( sid ) ;
return rid ;
}
/*
pull a dom_sid structure from a objectSid in a result set .
*/
struct dom_sid * samdb_result_dom_sid ( TALLOC_CTX * mem_ctx , const struct ldb_message * msg ,
const char * attr )
{
const struct ldb_val * v ;
struct dom_sid * sid ;
enum ndr_err_code ndr_err ;
v = ldb_msg_find_ldb_val ( msg , attr ) ;
if ( v = = NULL ) {
return NULL ;
}
sid = talloc ( mem_ctx , struct dom_sid ) ;
if ( sid = = NULL ) {
return NULL ;
}
2008-01-02 07:05:13 +03:00
ndr_err = ndr_pull_struct_blob ( v , sid , NULL , sid ,
2007-12-17 06:22:44 +03:00
( ndr_pull_flags_fn_t ) ndr_pull_dom_sid ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
talloc_free ( sid ) ;
return NULL ;
}
return sid ;
}
/*
pull a guid structure from a objectGUID in a result set .
*/
struct GUID samdb_result_guid ( const struct ldb_message * msg , const char * attr )
{
const struct ldb_val * v ;
struct GUID guid ;
2009-12-10 03:26:36 +03:00
NTSTATUS status ;
2007-12-17 06:22:44 +03:00
v = ldb_msg_find_ldb_val ( msg , attr ) ;
2009-12-11 09:33:32 +03:00
if ( ! v ) return GUID_zero ( ) ;
2007-12-17 06:22:44 +03:00
2009-12-10 03:26:36 +03:00
status = GUID_from_ndr_blob ( v , & guid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return GUID_zero ( ) ;
2007-12-17 06:22:44 +03:00
}
return guid ;
}
/*
pull a sid prefix from a objectSid in a result set .
this is used to find the domain sid for a user
*/
struct dom_sid * samdb_result_sid_prefix ( TALLOC_CTX * mem_ctx , const struct ldb_message * msg ,
const char * attr )
{
struct dom_sid * sid = samdb_result_dom_sid ( mem_ctx , msg , attr ) ;
if ( ! sid | | sid - > num_auths < 1 ) return NULL ;
sid - > num_auths - - ;
return sid ;
}
/*
pull a NTTIME in a result set .
*/
NTTIME samdb_result_nttime ( struct ldb_message * msg , const char * attr , NTTIME default_value )
{
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
*/
NTTIME samdb_result_last_logoff ( struct ldb_message * msg )
{
NTTIME ret = ldb_msg_find_attr_as_uint64 ( msg , " lastLogoff " , 0 ) ;
if ( ret = = 0 )
ret = 0x7FFFFFFFFFFFFFFFULL ;
return ret ;
}
2008-03-06 15:02:46 +03:00
/*
* Windows uses both 0 and 9223372036854775807 ( 0x7FFFFFFFFFFFFFFFULL ) to
* indicate an account doesn ' t expire .
*
* When Windows initially creates an account , it sets
* accountExpires = 9223372036854775807 ( 0x7FFFFFFFFFFFFFFF ) . However ,
* when changing from an account having a specific expiration date to
* that account never expiring , it sets accountExpires = 0.
*
* Consolidate that logic here to allow clearer logic for account expiry in
* the rest of the code .
*/
2008-03-25 07:25:13 +03:00
NTTIME samdb_result_account_expires ( struct ldb_message * msg )
2008-03-06 15:02:46 +03:00
{
NTTIME ret = ldb_msg_find_attr_as_uint64 ( msg , " accountExpires " ,
2008-03-25 07:25:13 +03:00
0 ) ;
2008-03-06 15:02:46 +03:00
2008-03-25 08:36:13 +03:00
if ( ret = = 0 )
2008-03-06 15:02:46 +03:00
ret = 0x7FFFFFFFFFFFFFFFULL ;
return ret ;
}
2007-12-17 06:22:44 +03:00
/*
pull a uint64_t from a result set .
*/
uint64_t samdb_result_uint64 ( struct ldb_message * msg , const char * attr , uint64_t default_value )
{
return ldb_msg_find_attr_as_uint64 ( msg , attr , default_value ) ;
}
/*
construct the allow_password_change field from the PwdLastSet attribute and the
domain password settings
*/
NTTIME samdb_result_allow_password_change ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * domain_dn ,
struct ldb_message * msg ,
const char * attr )
{
uint64_t attr_time = samdb_result_uint64 ( msg , attr , 0 ) ;
int64_t minPwdAge ;
if ( attr_time = = 0 ) {
return 0 ;
}
minPwdAge = samdb_search_int64 ( sam_ldb , mem_ctx , 0 , domain_dn , " minPwdAge " , NULL ) ;
/* yes, this is a -= not a += as minPwdAge is stored as the negative
of the number of 100 - nano - seconds */
attr_time - = minPwdAge ;
return attr_time ;
}
/*
2008-02-29 00:47:42 +03:00
construct the force_password_change field from the PwdLastSet
attribute , the userAccountControl and the domain password settings
2007-12-17 06:22:44 +03:00
*/
NTTIME samdb_result_force_password_change ( struct ldb_context * sam_ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_dn * domain_dn ,
struct ldb_message * msg )
{
uint64_t attr_time = samdb_result_uint64 ( msg , " pwdLastSet " , 0 ) ;
2008-02-29 03:03:31 +03:00
uint32_t userAccountControl = samdb_result_uint64 ( msg , " userAccountControl " , 0 ) ;
2007-12-17 06:22:44 +03:00
int64_t maxPwdAge ;
2008-02-29 00:47:42 +03:00
/* Machine accounts don't expire, and there is a flag for 'no expiry' */
if ( ! ( userAccountControl & UF_NORMAL_ACCOUNT )
| | ( userAccountControl & UF_DONT_EXPIRE_PASSWD ) ) {
2007-12-17 06:22:44 +03:00
return 0x7FFFFFFFFFFFFFFFULL ;
}
if ( attr_time = = 0 ) {
return 0 ;
}
maxPwdAge = samdb_search_int64 ( sam_ldb , mem_ctx , 0 , domain_dn , " maxPwdAge " , NULL ) ;
if ( maxPwdAge = = 0 ) {
2008-03-07 14:56:04 +03:00
return 0x7FFFFFFFFFFFFFFFULL ;
2007-12-17 06:22:44 +03:00
} else {
attr_time - = maxPwdAge ;
}
return attr_time ;
}
/*
pull a samr_Password structutre from a result set .
*/
2009-07-09 04:08:02 +04:00
struct samr_Password * samdb_result_hash ( TALLOC_CTX * mem_ctx , const struct ldb_message * msg , const char * attr )
2007-12-17 06:22:44 +03:00
{
struct samr_Password * hash = NULL ;
const struct ldb_val * val = ldb_msg_find_ldb_val ( msg , attr ) ;
if ( val & & ( val - > length > = sizeof ( hash - > hash ) ) ) {
hash = talloc ( mem_ctx , struct samr_Password ) ;
memcpy ( hash - > hash , val - > data , MIN ( val - > length , sizeof ( hash - > hash ) ) ) ;
}
return hash ;
}
/*
pull an array of samr_Password structutres from a result set .
*/
2009-07-09 04:08:02 +04:00
uint_t samdb_result_hashes ( TALLOC_CTX * mem_ctx , const struct ldb_message * msg ,
2007-12-17 06:22:44 +03:00
const char * attr , struct samr_Password * * hashes )
{
2009-11-07 14:15:38 +03:00
uint_t count , i ;
2007-12-17 06:22:44 +03:00
const struct ldb_val * val = ldb_msg_find_ldb_val ( msg , attr ) ;
* hashes = NULL ;
if ( ! val ) {
return 0 ;
}
count = val - > length / 16 ;
if ( count = = 0 ) {
return 0 ;
}
* hashes = talloc_array ( mem_ctx , struct samr_Password , count ) ;
if ( ! * hashes ) {
return 0 ;
}
for ( i = 0 ; i < count ; i + + ) {
memcpy ( ( * hashes ) [ i ] . hash , ( i * 16 ) + ( char * ) val - > data , 16 ) ;
}
return count ;
}
2008-10-16 05:48:16 +04:00
NTSTATUS samdb_result_passwords ( TALLOC_CTX * mem_ctx , struct loadparm_context * lp_ctx , struct ldb_message * msg ,
2007-12-17 06:22:44 +03:00
struct samr_Password * * lm_pwd , struct samr_Password * * nt_pwd )
{
struct samr_Password * lmPwdHash , * ntPwdHash ;
if ( nt_pwd ) {
int num_nt ;
num_nt = samdb_result_hashes ( mem_ctx , msg , " unicodePwd " , & ntPwdHash ) ;
if ( num_nt = = 0 ) {
* nt_pwd = NULL ;
} else if ( num_nt > 1 ) {
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
} else {
* nt_pwd = & ntPwdHash [ 0 ] ;
}
}
if ( lm_pwd ) {
2008-10-16 05:48:16 +04:00
/* Ensure that if we have turned off LM
* authentication , that we never use the LM hash , even
* if we store it */
if ( lp_lanman_auth ( lp_ctx ) ) {
int num_lm ;
num_lm = samdb_result_hashes ( mem_ctx , msg , " dBCSPwd " , & lmPwdHash ) ;
if ( num_lm = = 0 ) {
* lm_pwd = NULL ;
} else if ( num_lm > 1 ) {
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
} else {
* lm_pwd = & lmPwdHash [ 0 ] ;
}
2007-12-17 06:22:44 +03:00
} else {
2008-10-16 05:48:16 +04:00
* lm_pwd = NULL ;
2007-12-17 06:22:44 +03:00
}
}
return NT_STATUS_OK ;
}
/*
pull a samr_LogonHours structutre from a result set .
*/
struct samr_LogonHours samdb_result_logon_hours ( TALLOC_CTX * mem_ctx , struct ldb_message * msg , const char * attr )
{
struct samr_LogonHours hours ;
const int units_per_week = 168 ;
const struct ldb_val * val = ldb_msg_find_ldb_val ( msg , attr ) ;
ZERO_STRUCT ( hours ) ;
hours . bits = talloc_array ( mem_ctx , uint8_t , units_per_week ) ;
if ( ! hours . bits ) {
return hours ;
}
hours . units_per_week = units_per_week ;
memset ( hours . bits , 0xFF , units_per_week ) ;
if ( val ) {
memcpy ( hours . bits , val - > data , MIN ( val - > length , units_per_week ) ) ;
}
return hours ;
}
/*
pull a set of account_flags from a result set .
2008-02-28 00:50:00 +03:00
This requires that the attributes :
pwdLastSet
userAccountControl
be included in ' msg '
2007-12-17 06:22:44 +03:00
*/
2008-02-28 00:50:00 +03:00
uint32_t samdb_result_acct_flags ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx ,
struct ldb_message * msg , struct ldb_dn * domain_dn )
2007-12-17 06:22:44 +03:00
{
2008-02-28 00:50:00 +03:00
uint32_t userAccountControl = ldb_msg_find_attr_as_uint ( msg , " userAccountControl " , 0 ) ;
2009-06-12 17:20:48 +04:00
uint32_t acct_flags = ds_uf2acb ( userAccountControl ) ;
2008-02-29 00:47:42 +03:00
NTTIME must_change_time ;
NTTIME now ;
2009-05-31 18:19:11 +04:00
2008-02-29 00:47:42 +03:00
must_change_time = samdb_result_force_password_change ( sam_ctx , mem_ctx ,
domain_dn , msg ) ;
2009-05-31 18:19:11 +04:00
2008-02-29 00:47:42 +03:00
/* Test account expire time */
unix_to_nt_time ( & now , time ( NULL ) ) ;
/* check for expired password */
if ( must_change_time < now ) {
acct_flags | = ACB_PW_EXPIRED ;
2008-02-28 00:50:00 +03:00
}
return acct_flags ;
2007-12-17 06:22:44 +03:00
}
2008-11-10 22:35:32 +03:00
struct lsa_BinaryString samdb_result_parameters ( TALLOC_CTX * mem_ctx ,
struct ldb_message * msg ,
const char * attr )
{
struct lsa_BinaryString s ;
const struct ldb_val * val = ldb_msg_find_ldb_val ( msg , attr ) ;
ZERO_STRUCT ( s ) ;
if ( ! val ) {
return s ;
}
s . array = talloc_array ( mem_ctx , uint16_t , val - > length / 2 ) ;
if ( ! s . array ) {
return s ;
}
s . length = s . size = val - > length / 2 ;
memcpy ( s . array , val - > data , val - > length ) ;
return s ;
}
2007-12-17 06:22:44 +03:00
/* Find an attribute, with a particular value */
/* The current callers of this function expect a very specific
* behaviour : In particular , objectClass subclass equivilance is not
* wanted . This means that we should not lookup the schema for the
* comparison function */
struct ldb_message_element * samdb_find_attribute ( struct ldb_context * ldb ,
const struct ldb_message * msg ,
const char * name , const char * value )
{
int i ;
struct ldb_message_element * el = ldb_msg_find_element ( msg , name ) ;
if ( ! el ) {
return NULL ;
}
for ( i = 0 ; i < el - > num_values ; i + + ) {
if ( ldb_attr_cmp ( value , ( char * ) el - > values [ i ] . data ) = = 0 ) {
return el ;
}
}
return NULL ;
}
int samdb_find_or_add_value ( struct ldb_context * ldb , struct ldb_message * msg , const char * name , const char * set_value )
{
if ( samdb_find_attribute ( ldb , msg , name , set_value ) = = NULL ) {
return samdb_msg_add_string ( ldb , msg , msg , name , set_value ) ;
}
return LDB_SUCCESS ;
}
int samdb_find_or_add_attribute ( struct ldb_context * ldb , struct ldb_message * msg , const char * name , const char * set_value )
{
struct ldb_message_element * el ;
el = ldb_msg_find_element ( msg , name ) ;
if ( el ) {
return LDB_SUCCESS ;
}
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
return samdb_msg_add_string ( ldb , msg , msg , name , set_value ) ;
}
/*
add a string element to a message
*/
int samdb_msg_add_string ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , const char * str )
{
char * s = talloc_strdup ( mem_ctx , str ) ;
char * a = talloc_strdup ( mem_ctx , attr_name ) ;
if ( s = = NULL | | a = = NULL ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
return ldb_msg_add_string ( msg , a , s ) ;
}
/*
add a dom_sid element to a message
*/
int samdb_msg_add_dom_sid ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , struct dom_sid * sid )
{
struct ldb_val v ;
enum ndr_err_code ndr_err ;
2008-01-02 07:05:05 +03:00
ndr_err = ndr_push_struct_blob ( & v , mem_ctx ,
lp_iconv_convenience ( ldb_get_opaque ( sam_ldb , " loadparm " ) ) ,
sid ,
2007-12-17 06:22:44 +03:00
( ndr_push_flags_fn_t ) ndr_push_dom_sid ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return - 1 ;
}
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
samdb_replace ( ) to be used everywhere */
return ldb_msg_add_empty ( msg , attr_name , LDB_FLAG_MOD_REPLACE , NULL ) ;
}
/*
add a add attribute value to a message
*/
int samdb_msg_add_addval ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , const char * value )
{
struct ldb_message_element * el ;
char * a , * v ;
int ret ;
a = talloc_strdup ( mem_ctx , attr_name ) ;
if ( a = = NULL )
return - 1 ;
v = talloc_strdup ( mem_ctx , value ) ;
if ( v = = NULL )
return - 1 ;
ret = ldb_msg_add_string ( msg , a , v ) ;
if ( ret ! = 0 )
return ret ;
el = ldb_msg_find_element ( msg , a ) ;
if ( el = = NULL )
return - 1 ;
el - > flags = LDB_FLAG_MOD_ADD ;
return 0 ;
}
/*
add a delete attribute value to a message
*/
int samdb_msg_add_delval ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , const char * value )
{
struct ldb_message_element * el ;
char * a , * v ;
int ret ;
a = talloc_strdup ( mem_ctx , attr_name ) ;
if ( a = = NULL )
return - 1 ;
v = talloc_strdup ( mem_ctx , value ) ;
if ( v = = NULL )
return - 1 ;
ret = ldb_msg_add_string ( msg , a , v ) ;
if ( ret ! = 0 )
return ret ;
el = ldb_msg_find_element ( msg , a ) ;
if ( el = = NULL )
return - 1 ;
el - > flags = LDB_FLAG_MOD_DELETE ;
return 0 ;
}
/*
add a int element to a message
*/
int samdb_msg_add_int ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , int v )
{
const char * s = talloc_asprintf ( mem_ctx , " %d " , v ) ;
return samdb_msg_add_string ( sam_ldb , mem_ctx , msg , attr_name , s ) ;
}
/*
add a uint_t element to a message
*/
int samdb_msg_add_uint ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , uint_t v )
{
const char * s = talloc_asprintf ( mem_ctx , " %u " , v ) ;
return samdb_msg_add_string ( sam_ldb , mem_ctx , msg , attr_name , s ) ;
}
/*
add a ( signed ) int64_t element to a message
*/
int samdb_msg_add_int64 ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , int64_t v )
{
const char * s = talloc_asprintf ( mem_ctx , " %lld " , ( long long ) v ) ;
return samdb_msg_add_string ( sam_ldb , mem_ctx , msg , attr_name , s ) ;
}
/*
add a uint64_t element to a message
*/
int samdb_msg_add_uint64 ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , uint64_t v )
{
const char * s = talloc_asprintf ( mem_ctx , " %llu " , ( unsigned long long ) v ) ;
return samdb_msg_add_string ( sam_ldb , mem_ctx , msg , attr_name , s ) ;
}
/*
add a samr_Password element to a message
*/
int samdb_msg_add_hash ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , struct samr_Password * hash )
{
struct ldb_val val ;
val . data = talloc_memdup ( mem_ctx , hash - > hash , 16 ) ;
if ( ! val . data ) {
return - 1 ;
}
val . length = 16 ;
return ldb_msg_add_value ( msg , attr_name , & val , NULL ) ;
}
/*
add a samr_Password array to a message
*/
int samdb_msg_add_hashes ( TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , struct samr_Password * hashes , uint_t count )
{
struct ldb_val val ;
int i ;
val . data = talloc_array_size ( mem_ctx , 16 , count ) ;
val . length = count * 16 ;
if ( ! val . data ) {
return - 1 ;
}
for ( i = 0 ; i < count ; i + + ) {
memcpy ( i * 16 + ( char * ) val . data , hashes [ i ] . hash , 16 ) ;
}
return ldb_msg_add_value ( msg , attr_name , & val , NULL ) ;
}
/*
add a acct_flags element to a message
*/
int samdb_msg_add_acct_flags ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , uint32_t v )
{
2009-06-12 17:20:48 +04:00
return samdb_msg_add_uint ( sam_ldb , mem_ctx , msg , attr_name , ds_acb2uf ( v ) ) ;
2007-12-17 06:22:44 +03:00
}
/*
add a logon_hours element to a message
*/
int samdb_msg_add_logon_hours ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , struct samr_LogonHours * hours )
{
struct ldb_val val ;
val . length = hours - > units_per_week / 8 ;
val . data = hours - > bits ;
return ldb_msg_add_value ( msg , attr_name , & val , NULL ) ;
}
2008-11-10 22:35:41 +03:00
/*
add a parameters element to a message
*/
int samdb_msg_add_parameters ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , struct lsa_BinaryString * parameters )
{
struct ldb_val val ;
val . length = parameters - > length * 2 ;
val . data = ( uint8_t * ) parameters - > array ;
return ldb_msg_add_value ( msg , attr_name , & val , NULL ) ;
}
2007-12-17 06:22:44 +03:00
/*
add a general value element to a message
*/
int samdb_msg_add_value ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , const struct ldb_val * val )
{
return ldb_msg_add_value ( msg , attr_name , val , NULL ) ;
}
/*
sets a general value element to a message
*/
int samdb_msg_set_value ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , const struct ldb_val * val )
{
struct ldb_message_element * el ;
el = ldb_msg_find_element ( msg , attr_name ) ;
if ( el ) {
el - > num_values = 0 ;
}
return ldb_msg_add_value ( msg , attr_name , val , NULL ) ;
}
/*
set a string element in a message
*/
int samdb_msg_set_string ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg ,
const char * attr_name , const char * str )
{
struct ldb_message_element * el ;
el = ldb_msg_find_element ( msg , attr_name ) ;
if ( el ) {
el - > num_values = 0 ;
}
return samdb_msg_add_string ( sam_ldb , mem_ctx , msg , attr_name , str ) ;
}
/*
replace elements in a record
*/
int samdb_replace ( struct ldb_context * sam_ldb , TALLOC_CTX * mem_ctx , struct ldb_message * msg )
{
int i ;
/* 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 ;
}
/* modify the samdb record */
return ldb_modify ( sam_ldb , msg ) ;
}
/*
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 ;
}
struct ldb_dn * samdb_base_dn ( struct ldb_context * sam_ctx )
{
return ldb_get_default_basedn ( sam_ctx ) ;
}
struct ldb_dn * samdb_config_dn ( struct ldb_context * sam_ctx )
{
return ldb_get_config_basedn ( sam_ctx ) ;
}
struct ldb_dn * samdb_schema_dn ( struct ldb_context * sam_ctx )
{
return ldb_get_schema_basedn ( sam_ctx ) ;
}
2009-11-24 02:16:56 +03:00
struct ldb_dn * samdb_aggregate_schema_dn ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx )
{
struct ldb_dn * schema_dn = ldb_get_schema_basedn ( sam_ctx ) ;
struct ldb_dn * aggregate_dn ;
if ( ! schema_dn ) {
return NULL ;
}
aggregate_dn = ldb_dn_copy ( mem_ctx , schema_dn ) ;
if ( ! aggregate_dn ) {
return NULL ;
}
if ( ! ldb_dn_add_child_fmt ( aggregate_dn , " CN=Aggregate " ) ) {
return NULL ;
}
return aggregate_dn ;
}
2007-12-17 06:22:44 +03:00
struct ldb_dn * samdb_root_dn ( struct ldb_context * sam_ctx )
{
return ldb_get_root_basedn ( sam_ctx ) ;
}
struct ldb_dn * samdb_partitions_dn ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx )
{
struct ldb_dn * new_dn ;
new_dn = ldb_dn_copy ( mem_ctx , samdb_config_dn ( sam_ctx ) ) ;
if ( ! ldb_dn_add_child_fmt ( new_dn , " CN=Partitions " ) ) {
talloc_free ( new_dn ) ;
return NULL ;
}
return new_dn ;
}
struct ldb_dn * samdb_sites_dn ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx )
{
struct ldb_dn * new_dn ;
new_dn = ldb_dn_copy ( mem_ctx , samdb_config_dn ( sam_ctx ) ) ;
if ( ! ldb_dn_add_child_fmt ( new_dn , " CN=Sites " ) ) {
talloc_free ( new_dn ) ;
return NULL ;
}
return new_dn ;
}
/*
work out the domain sid for the current open ldb
*/
const struct dom_sid * samdb_domain_sid ( struct ldb_context * ldb )
{
TALLOC_CTX * tmp_ctx ;
2008-03-13 06:11:06 +03:00
const struct dom_sid * domain_sid ;
const char * attrs [ ] = {
" objectSid " ,
NULL
} ;
struct ldb_result * res ;
int ret ;
2007-12-17 06:22:44 +03:00
/* see if we have a cached copy */
domain_sid = ( struct dom_sid * ) ldb_get_opaque ( ldb , " cache.domain_sid " ) ;
if ( domain_sid ) {
return domain_sid ;
}
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
goto failed ;
}
2008-09-23 22:30:06 +04:00
ret = ldb_search ( ldb , tmp_ctx , & res , ldb_get_default_basedn ( ldb ) , LDB_SCOPE_BASE , attrs , " objectSid=* " ) ;
2008-03-13 06:11:06 +03:00
if ( ret ! = LDB_SUCCESS ) {
goto failed ;
}
2009-05-31 18:19:11 +04:00
2008-03-13 06:11:06 +03:00
if ( res - > count ! = 1 ) {
goto failed ;
}
domain_sid = samdb_result_dom_sid ( tmp_ctx , res - > msgs [ 0 ] , " objectSid " ) ;
2007-12-17 06:22:44 +03:00
if ( domain_sid = = NULL ) {
goto failed ;
}
/* cache the domain_sid in the ldb */
2008-06-27 01:30:42 +04:00
if ( ldb_set_opaque ( ldb , " cache.domain_sid " , discard_const_p ( struct dom_sid , domain_sid ) ) ! = LDB_SUCCESS ) {
2007-12-17 06:22:44 +03:00
goto failed ;
}
talloc_steal ( ldb , domain_sid ) ;
talloc_free ( tmp_ctx ) ;
return domain_sid ;
failed :
DEBUG ( 1 , ( " Failed to find domain_sid for open ldb \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return NULL ;
}
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 ;
}
/* Obtain the short name of the flexible single master operator
* ( FSMO ) , such as the PDC Emulator */
const char * samdb_result_fsmo_name ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx , const struct ldb_message * msg ,
const char * attr )
{
/* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
struct ldb_dn * fsmo_dn = ldb_msg_find_attr_as_dn ( ldb , mem_ctx , msg , attr ) ;
const struct ldb_val * val = ldb_dn_get_component_val ( fsmo_dn , 1 ) ;
const char * name = ldb_dn_get_component_name ( fsmo_dn , 1 ) ;
if ( ! name | | ( ldb_attr_cmp ( name , " cn " ) ! = 0 ) ) {
/* Ensure this matches the format. This gives us a
* bit more confidence that a ' cn ' value will be a
* ascii string */
return NULL ;
}
if ( val ) {
return ( char * ) val - > data ;
}
return NULL ;
}
/*
work out the ntds settings dn for the current open ldb
*/
struct ldb_dn * samdb_ntds_settings_dn ( struct ldb_context * ldb )
{
TALLOC_CTX * tmp_ctx ;
const char * root_attrs [ ] = { " dsServiceName " , NULL } ;
int ret ;
struct ldb_result * root_res ;
struct ldb_dn * settings_dn ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
/* see if we have a cached copy */
settings_dn = ( struct ldb_dn * ) ldb_get_opaque ( ldb , " cache.settings_dn " ) ;
if ( settings_dn ) {
return settings_dn ;
}
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
goto failed ;
}
2008-09-23 22:30:06 +04:00
ret = ldb_search ( ldb , tmp_ctx , & root_res , ldb_dn_new ( tmp_ctx , ldb , " " ) , LDB_SCOPE_BASE , root_attrs , NULL ) ;
2007-12-17 06:22:44 +03:00
if ( ret ) {
DEBUG ( 1 , ( " Searching for dsServiceName in rootDSE failed: %s \n " ,
ldb_errstring ( ldb ) ) ) ;
goto failed ;
}
if ( root_res - > count ! = 1 ) {
goto failed ;
}
settings_dn = ldb_msg_find_attr_as_dn ( ldb , tmp_ctx , root_res - > msgs [ 0 ] , " dsServiceName " ) ;
/* cache the domain_sid in the ldb */
if ( ldb_set_opaque ( ldb , " cache.settings_dn " , settings_dn ) ! = LDB_SUCCESS ) {
goto failed ;
}
talloc_steal ( ldb , settings_dn ) ;
talloc_free ( tmp_ctx ) ;
return settings_dn ;
failed :
DEBUG ( 1 , ( " Failed to find our own NTDS Settings DN in the ldb! \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return NULL ;
}
/*
work out the ntds settings invocationId for the current open ldb
*/
const struct GUID * samdb_ntds_invocation_id ( struct ldb_context * ldb )
{
TALLOC_CTX * tmp_ctx ;
const char * attrs [ ] = { " invocationId " , NULL } ;
int ret ;
struct ldb_result * res ;
struct GUID * invocation_id ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
/* see if we have a cached copy */
invocation_id = ( struct GUID * ) ldb_get_opaque ( ldb , " cache.invocation_id " ) ;
if ( invocation_id ) {
return invocation_id ;
}
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
goto failed ;
}
2008-09-23 22:30:06 +04:00
ret = ldb_search ( ldb , tmp_ctx , & res , samdb_ntds_settings_dn ( ldb ) , LDB_SCOPE_BASE , attrs , NULL ) ;
2007-12-17 06:22:44 +03:00
if ( ret ) {
goto failed ;
}
if ( res - > count ! = 1 ) {
goto failed ;
}
invocation_id = talloc ( tmp_ctx , struct GUID ) ;
if ( ! invocation_id ) {
goto failed ;
}
* invocation_id = samdb_result_guid ( res - > msgs [ 0 ] , " invocationId " ) ;
/* cache the domain_sid in the ldb */
if ( ldb_set_opaque ( ldb , " cache.invocation_id " , invocation_id ) ! = LDB_SUCCESS ) {
goto failed ;
}
talloc_steal ( ldb , invocation_id ) ;
talloc_free ( tmp_ctx ) ;
return invocation_id ;
failed :
DEBUG ( 1 , ( " Failed to find our own NTDS Settings invocationId in the ldb! \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return NULL ;
}
bool samdb_set_ntds_invocation_id ( struct ldb_context * ldb , const struct GUID * invocation_id_in )
{
TALLOC_CTX * tmp_ctx ;
struct GUID * invocation_id_new ;
struct GUID * invocation_id_old ;
/* see if we have a cached copy */
invocation_id_old = ( struct GUID * ) ldb_get_opaque ( ldb ,
" cache.invocation_id " ) ;
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
goto failed ;
}
invocation_id_new = talloc ( tmp_ctx , struct GUID ) ;
if ( ! invocation_id_new ) {
goto failed ;
}
* invocation_id_new = * invocation_id_in ;
/* cache the domain_sid in the ldb */
if ( ldb_set_opaque ( ldb , " cache.invocation_id " , invocation_id_new ) ! = LDB_SUCCESS ) {
goto failed ;
}
talloc_steal ( ldb , invocation_id_new ) ;
talloc_free ( tmp_ctx ) ;
talloc_free ( invocation_id_old ) ;
return true ;
failed :
DEBUG ( 1 , ( " Failed to set our own cached invocationId in the ldb! \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return false ;
}
/*
work out the ntds settings objectGUID for the current open ldb
*/
const struct GUID * samdb_ntds_objectGUID ( struct ldb_context * ldb )
{
TALLOC_CTX * tmp_ctx ;
const char * attrs [ ] = { " objectGUID " , NULL } ;
int ret ;
struct ldb_result * res ;
struct GUID * ntds_guid ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
/* see if we have a cached copy */
ntds_guid = ( struct GUID * ) ldb_get_opaque ( ldb , " cache.ntds_guid " ) ;
if ( ntds_guid ) {
return ntds_guid ;
}
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
goto failed ;
}
2008-09-23 22:30:06 +04:00
ret = ldb_search ( ldb , tmp_ctx , & res , samdb_ntds_settings_dn ( ldb ) , LDB_SCOPE_BASE , attrs , NULL ) ;
2007-12-17 06:22:44 +03:00
if ( ret ) {
goto failed ;
}
if ( res - > count ! = 1 ) {
goto failed ;
}
ntds_guid = talloc ( tmp_ctx , struct GUID ) ;
if ( ! ntds_guid ) {
goto failed ;
}
* ntds_guid = samdb_result_guid ( res - > msgs [ 0 ] , " objectGUID " ) ;
/* cache the domain_sid in the ldb */
if ( ldb_set_opaque ( ldb , " cache.ntds_guid " , ntds_guid ) ! = LDB_SUCCESS ) {
goto failed ;
}
talloc_steal ( ldb , ntds_guid ) ;
talloc_free ( tmp_ctx ) ;
return ntds_guid ;
failed :
DEBUG ( 1 , ( " Failed to find our own NTDS Settings objectGUID in the ldb! \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return NULL ;
}
bool samdb_set_ntds_objectGUID ( struct ldb_context * ldb , const struct GUID * ntds_guid_in )
{
TALLOC_CTX * tmp_ctx ;
struct GUID * ntds_guid_new ;
struct GUID * ntds_guid_old ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
/* see if we have a cached copy */
ntds_guid_old = ( struct GUID * ) ldb_get_opaque ( ldb , " cache.ntds_guid " ) ;
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
goto failed ;
}
ntds_guid_new = talloc ( tmp_ctx , struct GUID ) ;
if ( ! ntds_guid_new ) {
goto failed ;
}
* ntds_guid_new = * ntds_guid_in ;
/* cache the domain_sid in the ldb */
if ( ldb_set_opaque ( ldb , " cache.ntds_guid " , ntds_guid_new ) ! = LDB_SUCCESS ) {
goto failed ;
}
talloc_steal ( ldb , ntds_guid_new ) ;
talloc_free ( tmp_ctx ) ;
talloc_free ( ntds_guid_old ) ;
return true ;
failed :
DEBUG ( 1 , ( " Failed to set our own cached invocationId in the ldb! \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return false ;
}
/*
work out the server dn for the current open ldb
*/
struct ldb_dn * samdb_server_dn ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx )
{
return ldb_dn_get_parent ( mem_ctx , samdb_ntds_settings_dn ( ldb ) ) ;
}
/*
work out the server dn for the current open ldb
*/
struct ldb_dn * samdb_server_site_dn ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx )
{
struct ldb_dn * server_dn ;
struct ldb_dn * server_site_dn ;
server_dn = samdb_server_dn ( ldb , mem_ctx ) ;
if ( ! server_dn ) return NULL ;
server_site_dn = ldb_dn_get_parent ( mem_ctx , server_dn ) ;
talloc_free ( server_dn ) ;
return server_site_dn ;
}
2009-10-18 13:59:11 +04:00
const char * samdb_server_site_name ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx )
{
const struct ldb_val * val = ldb_dn_get_rdn_val ( samdb_server_site_dn ( ldb , mem_ctx ) ) ;
if ( val ! = NULL )
return ( const char * ) val - > data ;
else
return NULL ;
}
2007-12-17 06:22:44 +03:00
/*
work out if we are the PDC for the domain of the current open ldb
*/
bool samdb_is_pdc ( struct ldb_context * ldb )
{
const char * dom_attrs [ ] = { " fSMORoleOwner " , NULL } ;
int ret ;
struct ldb_result * dom_res ;
TALLOC_CTX * tmp_ctx ;
bool is_pdc ;
struct ldb_dn * pdc ;
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
DEBUG ( 1 , ( " talloc_new failed in samdb_is_pdc " ) ) ;
return false ;
}
2008-09-23 22:30:06 +04:00
ret = ldb_search ( ldb , tmp_ctx , & dom_res , ldb_get_default_basedn ( ldb ) , LDB_SCOPE_BASE , dom_attrs , NULL ) ;
2007-12-17 06:22:44 +03:00
if ( ret ) {
DEBUG ( 1 , ( " Searching for fSMORoleOwner in %s failed: %s \n " ,
ldb_dn_get_linearized ( ldb_get_default_basedn ( ldb ) ) ,
ldb_errstring ( ldb ) ) ) ;
goto failed ;
}
if ( dom_res - > count ! = 1 ) {
goto failed ;
}
pdc = ldb_msg_find_attr_as_dn ( ldb , tmp_ctx , dom_res - > msgs [ 0 ] , " fSMORoleOwner " ) ;
if ( ldb_dn_compare ( samdb_ntds_settings_dn ( ldb ) , pdc ) = = 0 ) {
is_pdc = true ;
} else {
is_pdc = false ;
}
talloc_free ( tmp_ctx ) ;
return is_pdc ;
failed :
DEBUG ( 1 , ( " Failed to find if we are the PDC for this ldb \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return false ;
}
2008-01-03 13:40:24 +03:00
/*
work out if we are a Global Catalog server for the domain of the current open ldb
*/
bool samdb_is_gc ( struct ldb_context * ldb )
{
const char * attrs [ ] = { " options " , NULL } ;
int ret , options ;
struct ldb_result * res ;
TALLOC_CTX * tmp_ctx ;
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
DEBUG ( 1 , ( " talloc_new failed in samdb_is_pdc " ) ) ;
return false ;
}
/* Query cn=ntds settings,.... */
2008-09-23 22:30:06 +04:00
ret = ldb_search ( ldb , tmp_ctx , & res , samdb_ntds_settings_dn ( ldb ) , LDB_SCOPE_BASE , attrs , NULL ) ;
2008-01-03 13:40:24 +03:00
if ( ret ) {
2008-09-23 22:30:06 +04:00
talloc_free ( tmp_ctx ) ;
2008-01-03 13:40:24 +03:00
return false ;
}
if ( res - > count ! = 1 ) {
2008-09-23 22:30:06 +04:00
talloc_free ( tmp_ctx ) ;
2008-01-03 13:40:24 +03:00
return false ;
}
options = ldb_msg_find_attr_as_int ( res - > msgs [ 0 ] , " options " , 0 ) ;
2008-01-07 09:46:39 +03:00
talloc_free ( tmp_ctx ) ;
2008-01-03 13:40:24 +03:00
/* if options attribute has the 0x00000001 flag set, then enable the global catlog */
if ( options & 0x000000001 ) {
return true ;
}
return false ;
}
2007-12-17 06:22:44 +03:00
/* Find a domain object in the parents of a particular DN. */
int samdb_search_for_parent_domain ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx , struct ldb_dn * dn ,
struct ldb_dn * * parent_dn , const char * * errstring )
{
TALLOC_CTX * local_ctx ;
struct ldb_dn * sdn = dn ;
struct ldb_result * res = NULL ;
int ret = 0 ;
const char * attrs [ ] = { NULL } ;
local_ctx = talloc_new ( mem_ctx ) ;
if ( local_ctx = = NULL ) return LDB_ERR_OPERATIONS_ERROR ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
while ( ( sdn = ldb_dn_get_parent ( local_ctx , sdn ) ) ) {
2008-09-23 22:30:06 +04:00
ret = ldb_search ( ldb , local_ctx , & res , sdn , LDB_SCOPE_BASE , attrs ,
2009-10-12 09:44:19 +04:00
" (|(objectClass=domain)(objectClass=builtinDomain)) " ) ;
2007-12-17 06:22:44 +03:00
if ( ret = = LDB_SUCCESS ) {
if ( res - > count = = 1 ) {
break ;
}
} else {
break ;
}
}
if ( ret ! = LDB_SUCCESS ) {
* errstring = talloc_asprintf ( mem_ctx , " Error searching for parent domain of %s, failed searching for %s: %s " ,
ldb_dn_get_linearized ( dn ) ,
ldb_dn_get_linearized ( sdn ) ,
ldb_errstring ( ldb ) ) ;
talloc_free ( local_ctx ) ;
return ret ;
}
if ( res - > count ! = 1 ) {
* errstring = talloc_asprintf ( mem_ctx , " Invalid dn (%s), not child of a domain object " ,
ldb_dn_get_linearized ( dn ) ) ;
2009-09-24 00:52:39 +04:00
DEBUG ( 0 , ( __location__ " : %s \n " , * errstring ) ) ;
2007-12-17 06:22:44 +03:00
talloc_free ( local_ctx ) ;
return LDB_ERR_CONSTRAINT_VIOLATION ;
}
* parent_dn = talloc_steal ( mem_ctx , res - > msgs [ 0 ] - > dn ) ;
talloc_free ( local_ctx ) ;
return ret ;
}
/*
2009-11-06 17:15:53 +03:00
* Performs checks on a user password ( plaintext UNIX format - attribute
2009-10-24 22:21:04 +04:00
* " password " ) . The remaining parameters have to be extracted from the domain
* object in the AD .
*
* Result codes from " enum samr_ValidationStatus " ( consider " samr.idl " )
*/
2009-11-06 17:15:53 +03:00
enum samr_ValidationStatus samdb_check_password ( const DATA_BLOB * password ,
2009-10-24 22:21:04 +04:00
const uint32_t pwdProperties ,
const uint32_t minPwdLength )
{
/* checks if the "minPwdLength" property is satisfied */
2009-11-06 17:15:53 +03:00
if ( minPwdLength > password - > length )
2009-10-24 22:21:04 +04:00
return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT ;
2007-12-17 06:22:44 +03:00
2009-11-06 17:15:53 +03:00
/* checks the password complexity */
if ( ( ( pwdProperties & DOMAIN_PASSWORD_COMPLEX ) ! = 0 )
2009-11-06 17:38:31 +03:00
& & ( password - > data ! = NULL )
2009-11-06 17:15:53 +03:00
& & ( ! check_password_quality ( ( const char * ) password - > data ) ) )
return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH ;
2009-10-24 22:21:04 +04:00
return SAMR_VALIDATION_STATUS_SUCCESS ;
}
/*
* Sets the user password using plaintext UTF16 ( attribute " new_password " ) or
* LM ( attribute " lmNewHash " ) or NT ( attribute " ntNewHash " ) hash . Also pass
* as parameter if it ' s a user change or not ( " userChange " ) . The " rejectReason "
* gives some more informations if the changed failed .
*
* The caller should have a LDB transaction wrapping this .
*
* Results : NT_STATUS_OK , NT_STATUS_INTERNAL_DB_CORRUPTION ,
* NT_STATUS_INVALID_PARAMETER , NT_STATUS_UNSUCCESSFUL ,
* NT_STATUS_PASSWORD_RESTRICTION
*/
2008-04-02 06:53:27 +04:00
NTSTATUS samdb_set_password ( struct ldb_context * ctx , TALLOC_CTX * mem_ctx ,
2009-10-24 21:31:01 +04:00
struct ldb_dn * user_dn , struct ldb_dn * domain_dn ,
2007-12-17 06:22:44 +03:00
struct ldb_message * mod ,
2008-10-16 05:48:16 +04:00
const DATA_BLOB * new_password ,
2009-08-19 13:58:42 +04:00
struct samr_Password * param_lmNewHash ,
struct samr_Password * param_ntNewHash ,
2007-12-17 06:22:44 +03:00
bool user_change ,
2009-09-26 00:44:00 +04:00
enum samPwdChangeReason * reject_reason ,
2007-12-17 06:22:44 +03:00
struct samr_DomInfo1 * * _dominfo )
{
2009-09-23 21:23:17 +04:00
const char * const user_attrs [ ] = { " userAccountControl " ,
" lmPwdHistory " ,
2007-12-17 06:22:44 +03:00
" ntPwdHistory " ,
" dBCSPwd " , " unicodePwd " ,
" objectSid " ,
" pwdLastSet " , NULL } ;
2009-09-23 21:23:17 +04:00
const char * const domain_attrs [ ] = { " minPwdLength " , " pwdProperties " ,
" pwdHistoryLength " ,
" maxPwdAge " , " minPwdAge " , NULL } ;
2007-12-17 06:22:44 +03:00
NTTIME pwdLastSet ;
2009-09-23 21:23:17 +04:00
uint32_t minPwdLength , pwdProperties , pwdHistoryLength ;
2009-09-25 20:03:31 +04:00
int64_t maxPwdAge , minPwdAge ;
2009-09-23 21:23:17 +04:00
uint32_t userAccountControl ;
2009-08-19 13:58:42 +04:00
struct samr_Password * sambaLMPwdHistory , * sambaNTPwdHistory ,
* lmPwdHash , * ntPwdHash , * lmNewHash , * ntNewHash ;
2007-12-17 06:22:44 +03:00
struct samr_Password local_lmNewHash , local_ntNewHash ;
int sambaLMPwdHistory_len , sambaNTPwdHistory_len ;
struct dom_sid * domain_sid ;
struct ldb_message * * res ;
bool restrictions ;
int count ;
time_t now = time ( NULL ) ;
NTTIME now_nt ;
int i ;
/* we need to know the time to compute password age */
unix_to_nt_time ( & now_nt , now ) ;
/* pull all the user parameters */
count = gendb_search_dn ( ctx , mem_ctx , user_dn , & res , user_attrs ) ;
if ( count ! = 1 ) {
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
2009-09-23 21:23:17 +04:00
userAccountControl = samdb_result_uint ( res [ 0 ] , " userAccountControl " , 0 ) ;
sambaLMPwdHistory_len = samdb_result_hashes ( mem_ctx , res [ 0 ] ,
" lmPwdHistory " , & sambaLMPwdHistory ) ;
sambaNTPwdHistory_len = samdb_result_hashes ( mem_ctx , res [ 0 ] ,
" ntPwdHistory " , & sambaNTPwdHistory ) ;
lmPwdHash = samdb_result_hash ( mem_ctx , res [ 0 ] , " dBCSPwd " ) ;
ntPwdHash = samdb_result_hash ( mem_ctx , res [ 0 ] , " unicodePwd " ) ;
pwdLastSet = samdb_result_uint64 ( res [ 0 ] , " pwdLastSet " , 0 ) ;
2007-12-17 06:22:44 +03:00
2009-08-19 13:58:42 +04:00
/* Copy parameters */
lmNewHash = param_lmNewHash ;
ntNewHash = param_ntNewHash ;
2007-12-17 06:22:44 +03:00
/* Only non-trust accounts have restrictions (possibly this
* test is the wrong way around , but I like to be restrictive
* if possible */
restrictions = ! ( userAccountControl & ( UF_INTERDOMAIN_TRUST_ACCOUNT
| UF_WORKSTATION_TRUST_ACCOUNT
| UF_SERVER_TRUST_ACCOUNT ) ) ;
2009-09-23 21:23:17 +04:00
if ( domain_dn ! = NULL ) {
2007-12-17 06:22:44 +03:00
/* pull the domain parameters */
2009-09-23 21:23:17 +04:00
count = gendb_search_dn ( ctx , mem_ctx , domain_dn , & res ,
domain_attrs ) ;
2007-12-17 06:22:44 +03:00
if ( count ! = 1 ) {
DEBUG ( 2 , ( " samdb_set_password: Domain DN %s is invalid, for user %s \n " ,
ldb_dn_get_linearized ( domain_dn ) ,
ldb_dn_get_linearized ( user_dn ) ) ) ;
return NT_STATUS_NO_SUCH_DOMAIN ;
}
} else {
/* work out the domain sid, and pull the domain from there */
2009-09-23 21:23:17 +04:00
domain_sid = samdb_result_sid_prefix ( mem_ctx , res [ 0 ] ,
" objectSid " ) ;
2007-12-17 06:22:44 +03:00
if ( domain_sid = = NULL ) {
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
count = gendb_search ( ctx , mem_ctx , NULL , & res , domain_attrs ,
2009-09-23 21:23:17 +04:00
" (objectSid=%s) " ,
ldap_encode_ndr_dom_sid ( mem_ctx , domain_sid ) ) ;
2007-12-17 06:22:44 +03:00
if ( count ! = 1 ) {
DEBUG ( 2 , ( " samdb_set_password: Could not find domain to match SID: %s, for user %s \n " ,
dom_sid_string ( mem_ctx , domain_sid ) ,
ldb_dn_get_linearized ( user_dn ) ) ) ;
return NT_STATUS_NO_SUCH_DOMAIN ;
}
}
2009-09-23 21:23:17 +04:00
minPwdLength = samdb_result_uint ( res [ 0 ] , " minPwdLength " , 0 ) ;
pwdProperties = samdb_result_uint ( res [ 0 ] , " pwdProperties " , 0 ) ;
pwdHistoryLength = samdb_result_uint ( res [ 0 ] , " pwdHistoryLength " , 0 ) ;
2009-09-25 20:03:31 +04:00
maxPwdAge = samdb_result_int64 ( res [ 0 ] , " maxPwdAge " , 0 ) ;
2009-09-23 21:23:17 +04:00
minPwdAge = samdb_result_int64 ( res [ 0 ] , " minPwdAge " , 0 ) ;
2007-12-17 06:22:44 +03:00
2009-09-23 21:23:17 +04:00
if ( ( userAccountControl & UF_PASSWD_NOTREQD ) ! = 0 ) {
2009-05-25 09:23:54 +04:00
/* see [MS-ADTS] 2.2.15 */
minPwdLength = 0 ;
}
2009-09-23 21:23:17 +04:00
if ( _dominfo ! = NULL ) {
2007-12-17 06:22:44 +03:00
struct samr_DomInfo1 * dominfo ;
/* on failure we need to fill in the reject reasons */
dominfo = talloc ( mem_ctx , struct samr_DomInfo1 ) ;
if ( dominfo = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
dominfo - > min_password_length = minPwdLength ;
dominfo - > password_properties = pwdProperties ;
dominfo - > password_history_length = pwdHistoryLength ;
2009-09-25 20:03:31 +04:00
dominfo - > max_password_age = maxPwdAge ;
2007-12-17 06:22:44 +03:00
dominfo - > min_password_age = minPwdAge ;
* _dominfo = dominfo ;
}
2009-09-23 21:23:17 +04:00
if ( ( restrictions ! = 0 ) & & ( new_password ! = 0 ) ) {
2008-10-16 05:48:16 +04:00
char * new_pass ;
2009-05-31 18:19:11 +04:00
2009-09-23 21:23:17 +04:00
/* checks if the "minPwdLength" property is satisfied */
if ( ( restrictions ! = 0 )
& & ( minPwdLength > utf16_len_n (
new_password - > data , new_password - > length ) / 2 ) ) {
2007-12-17 06:22:44 +03:00
if ( reject_reason ) {
2009-09-26 00:44:00 +04:00
* reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT ;
2007-12-17 06:22:44 +03:00
}
return NT_STATUS_PASSWORD_RESTRICTION ;
}
2008-10-16 05:48:16 +04:00
/* Create the NT hash */
2009-09-23 21:23:17 +04:00
mdfour ( local_ntNewHash . hash , new_password - > data ,
new_password - > length ) ;
2009-05-31 18:19:11 +04:00
2008-10-16 05:48:16 +04:00
ntNewHash = & local_ntNewHash ;
/* Only check complexity if we can convert it at all. Assuming unconvertable passwords are 'strong' */
2009-08-19 10:59:58 +04:00
if ( convert_string_talloc_convenience ( mem_ctx ,
lp_iconv_convenience ( ldb_get_opaque ( ctx , " loadparm " ) ) ,
CH_UTF16 , CH_UNIX ,
new_password - > data , new_password - > length ,
( void * * ) & new_pass , NULL , false ) ) {
2009-05-31 18:19:11 +04:00
2009-09-23 21:23:17 +04:00
/* checks the password complexity */
if ( ( restrictions ! = 0 )
& & ( ( pwdProperties
& DOMAIN_PASSWORD_COMPLEX ) ! = 0 )
& & ( ! check_password_quality ( new_pass ) ) ) {
2008-10-16 05:48:16 +04:00
if ( reject_reason ) {
2009-09-26 00:44:00 +04:00
* reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX ;
2008-10-16 05:48:16 +04:00
}
return NT_STATUS_PASSWORD_RESTRICTION ;
2007-12-17 06:22:44 +03:00
}
2009-05-31 18:19:11 +04:00
2008-10-16 05:48:16 +04:00
/* compute the new lm hashes (for checking history - case insenitivly!) */
if ( E_deshash ( new_pass , local_lmNewHash . hash ) ) {
lmNewHash = & local_lmNewHash ;
2007-12-17 06:22:44 +03:00
}
}
}
2009-09-23 21:23:17 +04:00
if ( ( restrictions ! = 0 ) & & user_change ) {
2007-12-17 06:22:44 +03:00
/* are all password changes disallowed? */
2009-09-23 21:23:17 +04:00
if ( ( pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE ) ! = 0 ) {
2007-12-17 06:22:44 +03:00
if ( reject_reason ) {
2009-09-26 00:44:00 +04:00
* reject_reason = SAM_PWD_CHANGE_NO_ERROR ;
2007-12-17 06:22:44 +03:00
}
return NT_STATUS_PASSWORD_RESTRICTION ;
}
2009-05-31 18:19:11 +04:00
2009-09-23 21:23:17 +04:00
/* can this user change the password? */
if ( ( userAccountControl & UF_PASSWD_CANT_CHANGE ) ! = 0 ) {
2007-12-17 06:22:44 +03:00
if ( reject_reason ) {
2009-09-26 00:44:00 +04:00
* reject_reason = SAM_PWD_CHANGE_NO_ERROR ;
2007-12-17 06:22:44 +03:00
}
return NT_STATUS_PASSWORD_RESTRICTION ;
}
2009-05-31 18:19:11 +04:00
2009-09-23 21:23:17 +04:00
/* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
2007-12-17 06:22:44 +03:00
if ( pwdLastSet - minPwdAge > now_nt ) {
if ( reject_reason ) {
2009-09-26 00:44:00 +04:00
* reject_reason = SAM_PWD_CHANGE_NO_ERROR ;
2007-12-17 06:22:44 +03:00
}
return NT_STATUS_PASSWORD_RESTRICTION ;
}
/* check the immediately past password */
if ( pwdHistoryLength > 0 ) {
2009-09-23 21:23:17 +04:00
if ( lmNewHash & & lmPwdHash & & memcmp ( lmNewHash - > hash ,
lmPwdHash - > hash , 16 ) = = 0 ) {
2007-12-17 06:22:44 +03:00
if ( reject_reason ) {
2009-09-26 00:44:00 +04:00
* reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY ;
2007-12-17 06:22:44 +03:00
}
return NT_STATUS_PASSWORD_RESTRICTION ;
}
2009-09-23 21:23:17 +04:00
if ( ntNewHash & & ntPwdHash & & memcmp ( ntNewHash - > hash ,
ntPwdHash - > hash , 16 ) = = 0 ) {
2007-12-17 06:22:44 +03:00
if ( reject_reason ) {
2009-09-26 00:44:00 +04:00
* reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY ;
2007-12-17 06:22:44 +03:00
}
return NT_STATUS_PASSWORD_RESTRICTION ;
}
}
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
/* check the password history */
2009-09-23 21:23:17 +04:00
sambaLMPwdHistory_len = MIN ( sambaLMPwdHistory_len ,
pwdHistoryLength ) ;
sambaNTPwdHistory_len = MIN ( sambaNTPwdHistory_len ,
pwdHistoryLength ) ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
for ( i = 0 ; lmNewHash & & i < sambaLMPwdHistory_len ; i + + ) {
2009-09-23 21:23:17 +04:00
if ( memcmp ( lmNewHash - > hash , sambaLMPwdHistory [ i ] . hash ,
16 ) = = 0 ) {
2007-12-17 06:22:44 +03:00
if ( reject_reason ) {
2009-09-26 00:44:00 +04:00
* reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY ;
2007-12-17 06:22:44 +03:00
}
return NT_STATUS_PASSWORD_RESTRICTION ;
}
}
for ( i = 0 ; ntNewHash & & i < sambaNTPwdHistory_len ; i + + ) {
2009-09-23 21:23:17 +04:00
if ( memcmp ( ntNewHash - > hash , sambaNTPwdHistory [ i ] . hash ,
16 ) = = 0 ) {
2007-12-17 06:22:44 +03:00
if ( reject_reason ) {
2009-09-26 00:44:00 +04:00
* reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY ;
2007-12-17 06:22:44 +03:00
}
return NT_STATUS_PASSWORD_RESTRICTION ;
}
}
}
# define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
/* the password is acceptable. Start forming the new fields */
2009-09-23 21:23:17 +04:00
if ( new_password ! = NULL ) {
2008-10-16 05:48:16 +04:00
/* if we know the cleartext UTF16 password, then set it.
2007-12-17 06:22:44 +03:00
* Modules in ldb will set all the appropriate
* hashes */
2008-10-16 05:48:16 +04:00
CHECK_RET ( ldb_msg_add_value ( mod , " clearTextPassword " , new_password , NULL ) ) ;
2007-12-17 06:22:44 +03:00
} else {
/* We don't have the cleartext, so delete the old one
* and set what we have of the hashes */
2008-10-16 05:48:16 +04:00
CHECK_RET ( samdb_msg_add_delete ( ctx , mem_ctx , mod , " clearTextPassword " ) ) ;
2007-12-17 06:22:44 +03:00
if ( lmNewHash ) {
CHECK_RET ( samdb_msg_add_hash ( ctx , mem_ctx , mod , " dBCSPwd " , lmNewHash ) ) ;
} else {
CHECK_RET ( samdb_msg_add_delete ( ctx , mem_ctx , mod , " dBCSPwd " ) ) ;
}
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
if ( ntNewHash ) {
CHECK_RET ( samdb_msg_add_hash ( ctx , mem_ctx , mod , " unicodePwd " , ntNewHash ) ) ;
} else {
CHECK_RET ( samdb_msg_add_delete ( ctx , mem_ctx , mod , " unicodePwd " ) ) ;
}
}
2009-09-26 00:44:00 +04:00
if ( reject_reason ) {
* reject_reason = SAM_PWD_CHANGE_NO_ERROR ;
}
2007-12-17 06:22:44 +03:00
return NT_STATUS_OK ;
}
/*
2009-10-24 21:31:01 +04:00
* Sets the user password using plaintext UTF16 ( attribute " new_password " ) or
* LM ( attribute " lmNewHash " ) or NT ( attribute " ntNewHash " ) hash . Also pass
* as parameter if it ' s a user change or not ( " userChange " ) . The " rejectReason "
* gives some more informations if the changed failed .
*
* This wrapper function for " samdb_set_password " takes a SID as input rather
* than a user DN .
*
* This call encapsulates a new LDB transaction for changing the password ;
* therefore the user hasn ' t to start a new one .
*
* Results : NT_STATUS_OK , NT_STATUS_INTERNAL_DB_CORRUPTION ,
* NT_STATUS_INVALID_PARAMETER , NT_STATUS_UNSUCCESSFUL ,
* NT_STATUS_PASSWORD_RESTRICTION
*/
NTSTATUS samdb_set_password_sid ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx ,
2007-12-17 06:22:44 +03:00
const struct dom_sid * user_sid ,
2009-10-24 21:31:01 +04:00
const DATA_BLOB * new_password ,
2007-12-17 06:22:44 +03:00
struct samr_Password * lmNewHash ,
struct samr_Password * ntNewHash ,
bool user_change ,
2009-09-26 00:44:00 +04:00
enum samPwdChangeReason * reject_reason ,
2007-12-17 06:22:44 +03:00
struct samr_DomInfo1 * * _dominfo )
{
NTSTATUS nt_status ;
struct ldb_dn * user_dn ;
struct ldb_message * msg ;
int ret ;
2009-10-24 21:31:01 +04:00
ret = ldb_transaction_start ( ldb ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 1 , ( " Failed to start transaction: %s \n " , ldb_errstring ( ldb ) ) ) ;
2007-12-17 06:22:44 +03:00
return NT_STATUS_TRANSACTION_ABORTED ;
}
2009-10-24 21:31:01 +04:00
user_dn = samdb_search_dn ( ldb , mem_ctx , NULL ,
2007-12-17 06:22:44 +03:00
" (&(objectSid=%s)(objectClass=user)) " ,
ldap_encode_ndr_dom_sid ( mem_ctx , user_sid ) ) ;
if ( ! user_dn ) {
2009-10-24 21:31:01 +04:00
ldb_transaction_cancel ( ldb ) ;
2007-12-17 06:22:44 +03:00
DEBUG ( 3 , ( " samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER \n " ,
dom_sid_string ( mem_ctx , user_sid ) ) ) ;
return NT_STATUS_NO_SUCH_USER ;
}
msg = ldb_msg_new ( mem_ctx ) ;
if ( msg = = NULL ) {
2009-10-24 21:31:01 +04:00
ldb_transaction_cancel ( ldb ) ;
2009-12-13 18:13:34 +03:00
talloc_free ( user_dn ) ;
2007-12-17 06:22:44 +03:00
return NT_STATUS_NO_MEMORY ;
}
msg - > dn = ldb_dn_copy ( msg , user_dn ) ;
if ( ! msg - > dn ) {
2009-10-24 21:31:01 +04:00
ldb_transaction_cancel ( ldb ) ;
2009-12-13 18:13:34 +03:00
talloc_free ( user_dn ) ;
talloc_free ( msg ) ;
2007-12-17 06:22:44 +03:00
return NT_STATUS_NO_MEMORY ;
}
2009-10-24 21:31:01 +04:00
nt_status = samdb_set_password ( ldb , mem_ctx ,
2007-12-17 06:22:44 +03:00
user_dn , NULL ,
2009-10-24 21:31:01 +04:00
msg , new_password ,
2007-12-17 06:22:44 +03:00
lmNewHash , ntNewHash ,
2009-12-13 18:13:34 +03:00
user_change ,
2007-12-17 06:22:44 +03:00
reject_reason , _dominfo ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2009-10-24 21:31:01 +04:00
ldb_transaction_cancel ( ldb ) ;
2009-12-13 18:13:34 +03:00
talloc_free ( user_dn ) ;
talloc_free ( msg ) ;
2007-12-17 06:22:44 +03:00
return nt_status ;
}
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
/* modify the samdb record */
2009-10-24 21:31:01 +04:00
ret = samdb_replace ( ldb , mem_ctx , msg ) ;
if ( ret ! = LDB_SUCCESS ) {
ldb_transaction_cancel ( ldb ) ;
2009-12-13 18:13:34 +03:00
talloc_free ( user_dn ) ;
talloc_free ( msg ) ;
2007-12-17 06:22:44 +03:00
return NT_STATUS_ACCESS_DENIED ;
}
2009-12-13 18:13:34 +03:00
talloc_free ( msg ) ;
2009-10-24 21:31:01 +04:00
ret = ldb_transaction_commit ( ldb ) ;
if ( ret ! = LDB_SUCCESS ) {
2007-12-17 06:22:44 +03:00
DEBUG ( 0 , ( " Failed to commit transaction to change password on %s: %s \n " ,
2009-12-13 18:13:34 +03:00
ldb_dn_get_linearized ( user_dn ) ,
2009-10-24 21:31:01 +04:00
ldb_errstring ( ldb ) ) ) ;
2009-12-13 18:13:34 +03:00
talloc_free ( user_dn ) ;
2007-12-17 06:22:44 +03:00
return NT_STATUS_TRANSACTION_ABORTED ;
}
2009-12-13 18:13:34 +03:00
talloc_free ( user_dn ) ;
2007-12-17 06:22:44 +03:00
return NT_STATUS_OK ;
}
NTSTATUS samdb_create_foreign_security_principal ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx ,
struct dom_sid * sid , struct ldb_dn * * ret_dn )
{
struct ldb_message * msg ;
struct ldb_dn * basedn ;
const char * sidstr ;
int ret ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
sidstr = dom_sid_string ( mem_ctx , sid ) ;
NT_STATUS_HAVE_NO_MEMORY ( sidstr ) ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
/* We might have to create a ForeignSecurityPrincipal, even if this user
* is in our own domain */
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
msg = ldb_msg_new ( mem_ctx ) ;
if ( msg = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
/* TODO: Hmmm. This feels wrong. How do I find the base dn to
* put the ForeignSecurityPrincipals ? d_state - > domain_dn does
* not work , this is wrong for the Builtin domain , there ' s no
* cn = For . . . , cn = Builtin , dc = { BASEDN } . - - vl
*/
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
basedn = samdb_search_dn ( sam_ctx , mem_ctx , NULL ,
" (&(objectClass=container)(cn=ForeignSecurityPrincipals)) " ) ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
if ( basedn = = NULL ) {
DEBUG ( 0 , ( " Failed to find DN for "
" ForeignSecurityPrincipal container \n " ) ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
/* add core elements to the ldb_message for the alias */
msg - > dn = ldb_dn_copy ( mem_ctx , basedn ) ;
if ( ! ldb_dn_add_child_fmt ( msg - > dn , " CN=%s " , sidstr ) )
return NT_STATUS_NO_MEMORY ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
samdb_msg_add_string ( sam_ctx , mem_ctx , msg ,
" objectClass " ,
" foreignSecurityPrincipal " ) ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
/* create the alias */
ret = ldb_add ( sam_ctx , msg ) ;
if ( ret ! = 0 ) {
DEBUG ( 0 , ( " Failed to create foreignSecurityPrincipal "
" record %s: %s \n " ,
ldb_dn_get_linearized ( msg - > dn ) ,
ldb_errstring ( sam_ctx ) ) ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
* ret_dn = msg - > dn ;
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 )
{
int i ;
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
const char * binary_encoded ;
const char * * split_realm ;
struct ldb_dn * dn ;
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
if ( ! tmp_ctx ) {
return NULL ;
}
2009-05-31 18:19:11 +04:00
2008-10-12 02:56:56 +04:00
split_realm = ( const char * * ) str_list_make ( tmp_ctx , dns_domain , " . " ) ;
2007-12-17 06:22:44 +03:00
if ( ! split_realm ) {
talloc_free ( tmp_ctx ) ;
return NULL ;
}
dn = ldb_dn_new ( mem_ctx , ldb , NULL ) ;
for ( i = 0 ; split_realm [ i ] ; i + + ) {
binary_encoded = ldb_binary_encode_string ( tmp_ctx , split_realm [ i ] ) ;
if ( ! ldb_dn_add_base_fmt ( dn , " dc=%s " , binary_encoded ) ) {
DEBUG ( 2 , ( " Failed to add dc=%s element to DN %s \n " ,
binary_encoded , ldb_dn_get_linearized ( dn ) ) ) ;
talloc_free ( tmp_ctx ) ;
return NULL ;
}
}
if ( ! ldb_dn_validate ( dn ) ) {
DEBUG ( 2 , ( " Failed to validated DN %s \n " ,
ldb_dn_get_linearized ( dn ) ) ) ;
return NULL ;
}
return dn ;
}
/*
Find the DN of a domain , be it the netbios or DNS name
*/
struct ldb_dn * samdb_domain_to_dn ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx ,
const char * domain_name )
{
const char * const domain_ref_attrs [ ] = {
" ncName " , NULL
} ;
const char * const domain_ref2_attrs [ ] = {
NULL
} ;
struct ldb_result * res_domain_ref ;
char * escaped_domain = ldb_binary_encode_string ( mem_ctx , domain_name ) ;
/* find the domain's DN */
2008-09-23 22:30:06 +04:00
int ret_domain = ldb_search ( ldb , mem_ctx ,
2007-12-17 06:22:44 +03:00
& res_domain_ref ,
samdb_partitions_dn ( ldb , mem_ctx ) ,
LDB_SCOPE_ONELEVEL ,
domain_ref_attrs ,
" (&(nETBIOSName=%s)(objectclass=crossRef)) " ,
escaped_domain ) ;
if ( ret_domain ! = 0 ) {
return NULL ;
}
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
if ( res_domain_ref - > count = = 0 ) {
2008-09-23 22:30:06 +04:00
ret_domain = ldb_search ( ldb , mem_ctx ,
2007-12-17 06:22:44 +03:00
& res_domain_ref ,
samdb_dns_domain_to_dn ( ldb , mem_ctx , domain_name ) ,
LDB_SCOPE_BASE ,
domain_ref2_attrs ,
" (objectclass=domain) " ) ;
if ( ret_domain ! = 0 ) {
return NULL ;
}
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
if ( res_domain_ref - > count = = 1 ) {
return res_domain_ref - > msgs [ 0 ] - > dn ;
}
return NULL ;
}
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
if ( res_domain_ref - > count > 1 ) {
DEBUG ( 0 , ( " Found %d records matching domain [%s] \n " ,
ret_domain , domain_name ) ) ;
return NULL ;
}
2009-05-31 18:19:11 +04:00
2007-12-17 06:22:44 +03:00
return samdb_result_dn ( ldb , mem_ctx , res_domain_ref - > msgs [ 0 ] , " nCName " , NULL ) ;
}
2009-09-03 06:51:22 +04:00
/*
use a GUID to find a DN
*/
int dsdb_find_dn_by_guid ( struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx ,
const char * guid_str , struct ldb_dn * * dn )
{
int ret ;
struct ldb_result * res ;
const char * attrs [ ] = { NULL } ;
struct ldb_request * search_req ;
char * expression ;
struct ldb_search_options_control * options ;
expression = talloc_asprintf ( mem_ctx , " objectGUID=%s " , guid_str ) ;
if ( ! expression ) {
DEBUG ( 0 , ( __location__ " : out of memory \n " ) ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
res = talloc_zero ( mem_ctx , struct ldb_result ) ;
if ( ! res ) {
DEBUG ( 0 , ( __location__ " : out of memory \n " ) ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
ret = ldb_build_search_req ( & search_req , ldb , mem_ctx ,
ldb_get_default_basedn ( ldb ) ,
LDB_SCOPE_SUBTREE ,
expression , attrs ,
NULL ,
res , ldb_search_default_callback ,
NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
/* we need to cope with cross-partition links, so search for
the GUID over all partitions */
options = talloc ( search_req , struct ldb_search_options_control ) ;
if ( options = = NULL ) {
DEBUG ( 0 , ( __location__ " : out of memory \n " ) ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
options - > search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT ;
2009-09-25 07:13:22 +04:00
ret = ldb_request_add_control ( search_req , LDB_CONTROL_EXTENDED_DN_OID , true , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2009-09-03 06:51:22 +04:00
ret = ldb_request_add_control ( search_req ,
LDB_CONTROL_SEARCH_OPTIONS_OID ,
true , options ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
ret = ldb_request ( ldb , search_req ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
ret = ldb_wait ( search_req - > handle , LDB_WAIT_ALL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
/* this really should be exactly 1, but there is a bug in the
partitions module that can return two here with the
search_options control set */
if ( res - > count < 1 ) {
2009-09-03 12:27:29 +04:00
return LDB_ERR_NO_SUCH_OBJECT ;
2009-09-03 06:51:22 +04:00
}
* dn = res - > msgs [ 0 ] - > dn ;
return LDB_SUCCESS ;
}
2009-09-24 18:05:07 +04:00
/*
search for attrs on one DN , allowing for deleted objects
*/
2009-09-25 04:20:34 +04:00
int dsdb_search_dn_with_deleted ( struct ldb_context * ldb ,
TALLOC_CTX * mem_ctx ,
struct ldb_result * * _res ,
struct ldb_dn * basedn ,
const char * const * attrs )
2009-09-24 18:05:07 +04:00
{
int ret ;
struct ldb_request * req ;
TALLOC_CTX * tmp_ctx ;
struct ldb_result * res ;
tmp_ctx = talloc_new ( mem_ctx ) ;
res = talloc_zero ( tmp_ctx , struct ldb_result ) ;
if ( ! res ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
ret = ldb_build_search_req ( & req , ldb , tmp_ctx ,
basedn ,
LDB_SCOPE_BASE ,
NULL ,
attrs ,
NULL ,
res ,
ldb_search_default_callback ,
NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
ret = ldb_request_add_control ( req , LDB_CONTROL_SHOW_DELETED_OID , true , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
ret = ldb_request ( ldb , req ) ;
if ( ret = = LDB_SUCCESS ) {
ret = ldb_wait ( req - > handle , LDB_WAIT_ALL ) ;
}
talloc_free ( req ) ;
* _res = talloc_steal ( mem_ctx , res ) ;
return ret ;
}
2009-09-03 06:51:22 +04:00
2009-09-03 12:27:29 +04: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 )
{
int ret ;
struct ldb_result * res ;
2009-09-04 07:58:17 +04:00
const char * attrs [ ] = { " objectGUID " , NULL } ;
2009-09-03 12:27:29 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( ldb ) ;
2009-09-24 18:05:07 +04:00
ret = dsdb_search_dn_with_deleted ( ldb , tmp_ctx , & res , dn , attrs ) ;
2009-09-03 12:27:29 +04:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-09-24 18:05:07 +04:00
if ( res - > count < 1 ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_NO_SUCH_OBJECT ;
}
2009-09-03 12:27:29 +04:00
* guid = samdb_result_guid ( res - > msgs [ 0 ] , " objectGUID " ) ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2009-09-12 05:09:10 +04:00
2009-11-19 21:28:37 +03:00
/*
adds the given GUID to the given ldb_message . This value is added
for the given attr_name ( may be either " objectGUID " or " parentGUID " ) .
*/
int dsdb_msg_add_guid ( struct ldb_message * msg ,
struct GUID * guid ,
const char * attr_name )
{
int ret ;
struct ldb_val v ;
2009-12-10 06:33:13 +03:00
NTSTATUS status ;
2009-11-19 21:28:37 +03:00
TALLOC_CTX * tmp_ctx = talloc_init ( " dsdb_msg_add_guid " ) ;
2009-12-10 06:33:13 +03:00
status = GUID_to_ndr_blob ( guid , tmp_ctx , & v ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-11-19 21:28:37 +03:00
ret = LDB_ERR_OPERATIONS_ERROR ;
goto done ;
}
ret = ldb_msg_add_steal_value ( msg , attr_name , & v ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 4 , ( __location__ " : Failed to add %s to the message \n " ,
attr_name ) ) ;
goto done ;
}
ret = LDB_SUCCESS ;
done :
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-09-24 00:52:39 +04:00
/*
use a DN to find a SID
*/
int dsdb_find_sid_by_dn ( struct ldb_context * ldb ,
struct ldb_dn * dn , struct dom_sid * sid )
{
int ret ;
struct ldb_result * res ;
const char * attrs [ ] = { " objectSID " , NULL } ;
TALLOC_CTX * tmp_ctx = talloc_new ( ldb ) ;
struct dom_sid * s ;
ZERO_STRUCTP ( sid ) ;
2009-09-24 18:05:07 +04:00
ret = dsdb_search_dn_with_deleted ( ldb , tmp_ctx , & res , dn , attrs ) ;
2009-09-24 00:52:39 +04:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
2009-09-24 18:05:07 +04:00
if ( res - > count < 1 ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_NO_SUCH_OBJECT ;
}
2009-09-24 00:52:39 +04:00
s = samdb_result_dom_sid ( tmp_ctx , res - > msgs [ 0 ] , " objectSID " ) ;
if ( s = = NULL ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_NO_SUCH_OBJECT ;
}
* sid = * s ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2009-09-12 05:09:10 +04:00
/*
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 ) ;
int i ;
struct ldb_message_element * el ;
* r = NULL ;
* count = 0 ;
if ( ldb_search ( sam_ctx , tmp_ctx , & res , dn , LDB_SCOPE_BASE , attrs , NULL ) ! = LDB_SUCCESS | |
res - > count < 1 ) {
DEBUG ( 0 , ( " dsdb_loadreps: failed to read partition object \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
el = ldb_msg_find_element ( res - > msgs [ 0 ] , attr ) ;
if ( el = = NULL ) {
/* it's OK to be empty */
talloc_free ( tmp_ctx ) ;
return WERR_OK ;
}
* count = el - > num_values ;
* r = talloc_array ( mem_ctx , struct repsFromToBlob , * count ) ;
if ( * r = = NULL ) {
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
for ( i = 0 ; i < ( * count ) ; i + + ) {
enum ndr_err_code ndr_err ;
ndr_err = ndr_pull_struct_blob ( & el - > values [ i ] ,
mem_ctx , lp_iconv_convenience ( ldb_get_opaque ( sam_ctx , " loadparm " ) ) ,
& ( * r ) [ i ] ,
( ndr_pull_flags_fn_t ) ndr_pull_repsFromToBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
}
talloc_free ( tmp_ctx ) ;
return WERR_OK ;
}
/*
save the repsFromTo blob list for a given partition GUID
attr must be " repsFrom " or " repsTo "
*/
WERROR dsdb_savereps ( struct ldb_context * sam_ctx , TALLOC_CTX * mem_ctx , struct ldb_dn * dn ,
const char * attr , struct repsFromToBlob * r , uint32_t count )
{
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
struct ldb_message * msg ;
struct ldb_message_element * el ;
int i ;
msg = ldb_msg_new ( tmp_ctx ) ;
msg - > dn = dn ;
if ( ldb_msg_add_empty ( msg , attr , LDB_FLAG_MOD_REPLACE , & el ) ! = LDB_SUCCESS ) {
goto failed ;
}
el - > values = talloc_array ( msg , struct ldb_val , count ) ;
if ( ! el - > values ) {
goto failed ;
}
for ( i = 0 ; i < count ; i + + ) {
struct ldb_val v ;
enum ndr_err_code ndr_err ;
ndr_err = ndr_push_struct_blob ( & v , tmp_ctx , lp_iconv_convenience ( ldb_get_opaque ( sam_ctx , " loadparm " ) ) ,
& r [ i ] ,
( ndr_push_flags_fn_t ) ndr_push_repsFromToBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
goto failed ;
}
el - > num_values + + ;
el - > values [ i ] = v ;
}
if ( ldb_modify ( sam_ctx , msg ) ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( " Failed to store %s - %s \n " , attr , ldb_errstring ( sam_ctx ) ) ) ;
goto failed ;
}
talloc_free ( tmp_ctx ) ;
return WERR_OK ;
failed :
talloc_free ( tmp_ctx ) ;
return WERR_DS_DRA_INTERNAL_ERROR ;
}
2009-09-13 12:13:17 +04:00
/*
load the uSNHighest attribute from the @ REPLCHANGED object for a
partition
*/
int dsdb_load_partition_usn ( struct ldb_context * ldb , struct ldb_dn * dn , uint64_t * uSN )
{
struct ldb_request * req ;
int ret ;
TALLOC_CTX * tmp_ctx = talloc_new ( ldb ) ;
struct dsdb_control_current_partition * p_ctrl ;
struct ldb_result * res ;
res = talloc_zero ( tmp_ctx , struct ldb_result ) ;
if ( ! res ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
ret = ldb_build_search_req ( & req , ldb , tmp_ctx ,
ldb_dn_new ( tmp_ctx , ldb , " @REPLCHANGED " ) ,
LDB_SCOPE_BASE ,
NULL , NULL ,
NULL ,
res , ldb_search_default_callback ,
NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
p_ctrl = talloc ( req , struct dsdb_control_current_partition ) ;
if ( p_ctrl = = NULL ) {
talloc_free ( res ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
p_ctrl - > version = DSDB_CONTROL_CURRENT_PARTITION_VERSION ;
p_ctrl - > dn = dn ;
ret = ldb_request_add_control ( req ,
DSDB_CONTROL_CURRENT_PARTITION_OID ,
false , p_ctrl ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
/* Run the new request */
ret = ldb_request ( ldb , req ) ;
if ( ret = = LDB_SUCCESS ) {
ret = ldb_wait ( req - > handle , LDB_WAIT_ALL ) ;
}
2009-09-16 14:43:37 +04:00
if ( ret = = LDB_ERR_NO_SUCH_OBJECT ) {
/* it hasn't been created yet, which means
an implicit value of zero */
* uSN = 0 ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
2009-09-13 12:13:17 +04:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return ret ;
}
if ( res - > count < 1 ) {
* uSN = 0 ;
} else {
* uSN = ldb_msg_find_attr_as_uint64 ( res - > msgs [ 0 ] , " uSNHighest " , 0 ) ;
}
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
}
/*
save the uSNHighest attribute in the @ REPLCHANGED object for a
partition
*/
int dsdb_save_partition_usn ( struct ldb_context * ldb , struct ldb_dn * dn , uint64_t uSN )
{
struct ldb_request * req ;
struct ldb_message * msg ;
struct dsdb_control_current_partition * p_ctrl ;
int ret ;
msg = ldb_msg_new ( ldb ) ;
if ( msg = = NULL ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
msg - > dn = ldb_dn_new ( msg , ldb , " @REPLCHANGED " ) ;
if ( msg - > dn = = NULL ) {
talloc_free ( msg ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
ret = ldb_msg_add_fmt ( msg , " uSNHighest " , " %llu " , ( unsigned long long ) uSN ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( msg ) ;
return ret ;
}
msg - > elements [ 0 ] . flags = LDB_FLAG_MOD_REPLACE ;
p_ctrl = talloc ( msg , struct dsdb_control_current_partition ) ;
if ( p_ctrl = = NULL ) {
talloc_free ( msg ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
p_ctrl - > version = DSDB_CONTROL_CURRENT_PARTITION_VERSION ;
p_ctrl - > dn = dn ;
ret = ldb_build_mod_req ( & req , ldb , msg ,
msg ,
NULL ,
NULL , ldb_op_default_callback ,
NULL ) ;
again :
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( msg ) ;
return ret ;
}
ret = ldb_request_add_control ( req ,
DSDB_CONTROL_CURRENT_PARTITION_OID ,
false , p_ctrl ) ;
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( msg ) ;
return ret ;
}
/* Run the new request */
ret = ldb_request ( ldb , req ) ;
if ( ret = = LDB_SUCCESS ) {
ret = ldb_wait ( req - > handle , LDB_WAIT_ALL ) ;
}
if ( ret = = LDB_ERR_NO_SUCH_OBJECT ) {
ret = ldb_build_add_req ( & req , ldb , msg ,
msg ,
NULL ,
NULL , ldb_op_default_callback ,
NULL ) ;
goto again ;
}
talloc_free ( msg ) ;
return ret ;
}
2009-09-14 22:46:59 +04:00
int drsuapi_DsReplicaCursor2_compare ( const struct drsuapi_DsReplicaCursor2 * c1 ,
const struct drsuapi_DsReplicaCursor2 * c2 )
{
return GUID_compare ( & c1 - > source_dsa_invocation_id , & c2 - > source_dsa_invocation_id ) ;
}
2009-10-13 12:48:13 +04:00
/*
see if we are a RODC
TODO : This should take a sam_ctx , and lookup the right object ( with
a cache )
*/
bool samdb_rodc ( struct loadparm_context * lp_ctx )
{
return lp_parm_bool ( lp_ctx , NULL , " repl " , " RODC " , false ) ;
}
/*
return NTDS options flags . See MS - ADTS 7.1 .1 .2 .2 .1 .2 .1 .1
flags are DS_NTDS_OPTION_ *
*/
int samdb_ntds_options ( struct ldb_context * ldb , uint32_t * options )
{
TALLOC_CTX * tmp_ctx ;
const char * attrs [ ] = { " options " , NULL } ;
int ret ;
struct ldb_result * res ;
tmp_ctx = talloc_new ( ldb ) ;
if ( tmp_ctx = = NULL ) {
goto failed ;
}
ret = ldb_search ( ldb , tmp_ctx , & res , samdb_ntds_settings_dn ( ldb ) , LDB_SCOPE_BASE , attrs , NULL ) ;
if ( ret ) {
goto failed ;
}
if ( res - > count ! = 1 ) {
goto failed ;
}
* options = samdb_result_uint ( res - > msgs [ 0 ] , " options " , 0 ) ;
talloc_free ( tmp_ctx ) ;
return LDB_SUCCESS ;
failed :
DEBUG ( 1 , ( " Failed to find our own NTDS Settings objectGUID in the ldb! \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return LDB_ERR_NO_SUCH_OBJECT ;
}
2009-11-14 22:12:42 +03:00
/*
* Function which generates a " lDAPDisplayName " attribute from a " CN " one .
* Algorithm implemented according to MS - ADTS 3.1 .1 .2 .3 .4
*/
const char * samdb_cn_to_lDAPDisplayName ( TALLOC_CTX * mem_ctx , const char * cn )
{
char * * tokens , * ret ;
size_t i ;
tokens = str_list_make ( mem_ctx , cn , " -_ " ) ;
if ( tokens = = NULL )
return NULL ;
/* "tolower()" and "toupper()" should also work properly on 0x00 */
tokens [ 0 ] [ 0 ] = tolower ( tokens [ 0 ] [ 0 ] ) ;
for ( i = 1 ; i < str_list_length ( ( const char * * ) tokens ) ; i + + )
tokens [ i ] [ 0 ] = toupper ( tokens [ i ] [ 0 ] ) ;
ret = talloc_strdup ( mem_ctx , tokens [ 0 ] ) ;
for ( i = 1 ; i < str_list_length ( ( const char * * ) tokens ) ; i + + )
ret = talloc_asprintf_append_buffer ( ret , " %s " , tokens [ i ] ) ;
talloc_free ( tokens ) ;
return ret ;
}
2009-12-09 07:18:37 +03:00
/*
return domain functional level
returns DS_DOMAIN_FUNCTION_ *
*/
int dsdb_functional_level ( struct ldb_context * ldb )
{
int * domainFunctionality =
talloc_get_type ( ldb_get_opaque ( ldb , " domainFunctionality " ) , int ) ;
if ( ! domainFunctionality ) {
DEBUG ( 0 , ( __location__ " : WARNING: domainFunctionality not setup \n " ) ) ;
return DS_DOMAIN_FUNCTION_2000 ;
}
return * domainFunctionality ;
}
2009-12-10 03:23:20 +03:00
/*
return a GUID from a extended DN structure
*/
NTSTATUS dsdb_get_extended_dn_guid ( struct ldb_dn * dn , struct GUID * guid )
{
const struct ldb_val * v ;
v = ldb_dn_get_extended_component ( dn , " GUID " ) ;
if ( v = = NULL ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
return GUID_from_ndr_blob ( v , guid ) ;
}
2009-12-15 03:00:30 +03:00
/*
return true if a ldb_val containing a DN in storage form is deleted
*/
bool dsdb_dn_is_deleted_val ( struct ldb_val * val )
{
/* this relies on the sort order and exact format of
linearized extended DNs */
if ( val - > length > = 12 & &
strncmp ( ( const char * ) val - > data , " <DELETED=1>; " , 12 ) = = 0 ) {
return true ;
}
return false ;
}
2009-12-16 05:18:44 +03:00
/*
return a DN for a wellknown GUID
*/
int dsdb_wellknown_dn ( struct ldb_context * samdb , TALLOC_CTX * mem_ctx ,
struct ldb_dn * nc_root , const char * wk_guid ,
struct ldb_dn * * wkguid_dn )
{
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
const char * attrs [ ] = { NULL } ;
int ret ;
struct ldb_dn * dn ;
struct ldb_result * res ;
/* construct the magic WKGUID DN */
dn = ldb_dn_new_fmt ( tmp_ctx , samdb , " <WKGUID=%s,%s> " ,
wk_guid , ldb_dn_get_linearized ( nc_root ) ) ;
if ( ! wkguid_dn ) {
talloc_free ( tmp_ctx ) ;
return LDB_ERR_OPERATIONS_ERROR ;
}
ret = dsdb_search_dn_with_deleted ( samdb , tmp_ctx , & res , dn , attrs ) ;
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 ;
}