2002-09-27 16:23:47 +04:00
/*
Unix SMB / CIFS implementation .
Some Helpful wrappers on LDAP
Copyright ( C ) Andrew Tridgell 2001
2007-05-11 16:52:48 +04:00
Copyright ( C ) Guenther Deschner 2006 , 2007
2010-11-16 21:17:32 +03:00
2002-09-27 16:23:47 +04: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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2002-09-27 16:23:47 +04:00
( at your option ) any later version .
2010-11-16 21:17:32 +03:00
2002-09-27 16:23:47 +04: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 .
2010-11-16 21:17:32 +03:00
2002-09-27 16:23:47 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2002-09-27 16:23:47 +04:00
*/
# include "includes.h"
2010-07-02 02:32:52 +04:00
# include "ads.h"
2012-07-23 06:47:01 +04:00
# include "lib/param/loadparm.h"
2002-09-28 04:47:06 +04:00
# ifdef HAVE_LDAP
2010-11-16 21:18:56 +03:00
static ADS_STATUS ads_ranged_search_internal ( ADS_STRUCT * ads ,
TALLOC_CTX * mem_ctx ,
int scope ,
const char * base ,
const char * filter ,
const char * * attrs ,
void * args ,
const char * range_attr ,
char * * * strings ,
size_t * num_strings ,
2015-04-18 18:40:14 +03:00
uint32_t * first_usn ,
2010-11-16 21:18:56 +03:00
int * num_retries ,
bool * more_values ) ;
2002-09-27 16:23:47 +04:00
/*
a wrapper around ldap_search_s that retries depending on the error code
this is supposed to catch dropped connections and auto - reconnect
*/
2006-05-18 23:34:25 +04:00
static ADS_STATUS ads_do_search_retry_internal ( ADS_STRUCT * ads , const char * bind_path , int scope ,
const char * expr ,
2006-09-04 01:07:16 +04:00
const char * * attrs , void * args ,
LDAPMessage * * res )
2002-09-27 16:23:47 +04:00
{
2005-11-02 03:19:26 +03:00
ADS_STATUS status = ADS_SUCCESS ;
2002-09-27 16:23:47 +04:00
int count = 3 ;
char * bp ;
2004-01-05 05:12:38 +03:00
* res = NULL ;
2007-07-16 15:08:00 +04:00
if ( ! ads - > ldap . ld & &
2010-09-07 04:15:09 +04:00
time_mono ( NULL ) - ads - > ldap . last_attempt < ADS_RECONNECT_TIME ) {
2002-09-27 16:23:47 +04:00
return ADS_ERROR ( LDAP_SERVER_DOWN ) ;
}
2004-12-07 21:25:53 +03:00
bp = SMB_STRDUP ( bind_path ) ;
2002-09-27 16:23:47 +04:00
2004-01-05 05:12:38 +03:00
if ( ! bp ) {
2007-04-22 19:15:00 +04:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
2004-01-05 05:12:38 +03:00
}
2002-09-28 16:27:04 +04:00
2006-05-07 19:05:32 +04:00
* res = NULL ;
2006-09-18 23:26:09 +04:00
/* when binding anonymously, we cannot use the paged search LDAP
* control - Guenther */
if ( ads - > auth . flags & ADS_AUTH_ANON_BIND ) {
status = ads_do_search ( ads , bp , scope , expr , attrs , res ) ;
} else {
status = ads_do_search_all_args ( ads , bp , scope , expr , attrs , args , res ) ;
}
2006-05-07 19:05:32 +04:00
if ( ADS_ERR_OK ( status ) ) {
2007-10-11 00:34:30 +04:00
DEBUG ( 5 , ( " Search for %s in <%s> gave %d replies \n " ,
expr , bp , ads_count_replies ( ads , * res ) ) ) ;
2006-05-07 19:05:32 +04:00
SAFE_FREE ( bp ) ;
return status ;
}
while ( - - count ) {
2002-09-27 16:23:47 +04:00
2016-01-14 03:25:34 +03:00
if ( NT_STATUS_EQUAL ( ads_ntstatus ( status ) , NT_STATUS_IO_TIMEOUT ) & &
ads - > config . ldap_page_size > = ( lp_ldap_page_size ( ) / 4 ) & &
lp_ldap_page_size ( ) > 4 ) {
2012-05-18 16:01:14 +04:00
int new_page_size = ( ads - > config . ldap_page_size / 2 ) ;
DEBUG ( 1 , ( " Reducing LDAP page size from %d to %d due to IO_TIMEOUT \n " ,
ads - > config . ldap_page_size , new_page_size ) ) ;
ads - > config . ldap_page_size = new_page_size ;
}
2003-10-04 01:43:09 +04:00
if ( * res )
ads_msgfree ( ads , * res ) ;
2002-09-27 16:23:47 +04:00
* res = NULL ;
2010-11-16 21:17:32 +03:00
2002-09-27 16:23:47 +04:00
DEBUG ( 3 , ( " Reopening ads connection to realm '%s' after error %s \n " ,
ads - > config . realm , ads_errstr ( status ) ) ) ;
2010-11-16 21:17:32 +03:00
2007-07-16 13:48:15 +04:00
ads_disconnect ( ads ) ;
2002-09-27 16:23:47 +04:00
status = ads_connect ( ads ) ;
2010-11-16 21:17:32 +03:00
2002-09-27 16:23:47 +04:00
if ( ! ADS_ERR_OK ( status ) ) {
DEBUG ( 1 , ( " ads_search_retry: failed to reconnect (%s) \n " ,
ads_errstr ( status ) ) ) ;
ads_destroy ( & ads ) ;
2004-01-05 05:12:38 +03:00
SAFE_FREE ( bp ) ;
2002-09-27 16:23:47 +04:00
return status ;
}
2006-05-07 19:05:32 +04:00
* res = NULL ;
2006-09-18 23:26:09 +04:00
/* when binding anonymously, we cannot use the paged search LDAP
* control - Guenther */
if ( ads - > auth . flags & ADS_AUTH_ANON_BIND ) {
status = ads_do_search ( ads , bp , scope , expr , attrs , res ) ;
} else {
status = ads_do_search_all_args ( ads , bp , scope , expr , attrs , args , res ) ;
}
2006-05-07 19:05:32 +04:00
if ( ADS_ERR_OK ( status ) ) {
2006-09-06 16:34:00 +04:00
DEBUG ( 5 , ( " Search for filter: %s, base: %s gave %d replies \n " ,
expr , bp , ads_count_replies ( ads , * res ) ) ) ;
2006-05-07 19:05:32 +04:00
SAFE_FREE ( bp ) ;
return status ;
}
2002-09-27 16:23:47 +04:00
}
2004-01-05 05:12:38 +03:00
SAFE_FREE ( bp ) ;
2002-09-27 16:23:47 +04:00
2007-02-08 20:02:39 +03:00
if ( ! ADS_ERR_OK ( status ) ) {
2003-08-16 01:23:25 +04:00
DEBUG ( 1 , ( " ads reopen failed after error %s \n " ,
ads_errstr ( status ) ) ) ;
2007-02-08 20:02:39 +03:00
}
2002-09-27 16:23:47 +04:00
return status ;
}
2006-09-04 01:07:16 +04:00
ADS_STATUS ads_do_search_retry ( ADS_STRUCT * ads , const char * bind_path ,
int scope , const char * expr ,
const char * * attrs , LDAPMessage * * res )
2006-05-18 23:34:25 +04:00
{
return ads_do_search_retry_internal ( ads , bind_path , scope , expr , attrs , NULL , res ) ;
}
2010-11-16 21:10:50 +03:00
static ADS_STATUS ads_do_search_retry_args ( ADS_STRUCT * ads , const char * bind_path ,
int scope , const char * expr ,
const char * * attrs , void * args ,
LDAPMessage * * res )
2006-05-18 23:34:25 +04:00
{
return ads_do_search_retry_internal ( ads , bind_path , scope , expr , attrs , args , res ) ;
}
2002-09-27 16:23:47 +04:00
2006-09-04 01:07:16 +04:00
ADS_STATUS ads_search_retry ( ADS_STRUCT * ads , LDAPMessage * * res ,
const char * expr , const char * * attrs )
2002-09-27 16:23:47 +04:00
{
return ads_do_search_retry ( ads , ads - > config . bind_path , LDAP_SCOPE_SUBTREE ,
2003-04-15 21:06:51 +04:00
expr , attrs , res ) ;
2002-09-27 16:23:47 +04:00
}
2006-09-04 01:07:16 +04:00
ADS_STATUS ads_search_retry_dn ( ADS_STRUCT * ads , LDAPMessage * * res ,
const char * dn ,
const char * * attrs )
2002-09-27 16:23:47 +04:00
{
return ads_do_search_retry ( ads , dn , LDAP_SCOPE_BASE ,
" (objectclass=*) " , attrs , res ) ;
}
2006-04-28 18:44:43 +04:00
2007-10-11 00:34:30 +04:00
ADS_STATUS ads_search_retry_dn_sd_flags ( ADS_STRUCT * ads , LDAPMessage * * res ,
2015-04-18 18:40:14 +03:00
uint32_t sd_flags ,
2007-10-11 00:34:30 +04:00
const char * dn ,
const char * * attrs )
{
ads_control args ;
args . control = ADS_SD_FLAGS_OID ;
args . val = sd_flags ;
args . critical = True ;
return ads_do_search_retry_args ( ads , dn , LDAP_SCOPE_BASE ,
" (objectclass=*) " , attrs , & args , res ) ;
}
2007-04-22 19:15:00 +04:00
ADS_STATUS ads_search_retry_extended_dn_ranged ( ADS_STRUCT * ads , TALLOC_CTX * mem_ctx ,
const char * dn ,
const char * * attrs ,
enum ads_extended_dn_flags flags ,
char * * * strings ,
size_t * num_strings )
{
ads_control args ;
args . control = ADS_EXTENDED_DN_OID ;
args . val = flags ;
args . critical = True ;
/* we can only range process one attribute */
if ( ! attrs | | ! attrs [ 0 ] | | attrs [ 1 ] ) {
return ADS_ERROR_NT ( NT_STATUS_INVALID_PARAMETER ) ;
}
return ads_ranged_search ( ads , mem_ctx , LDAP_SCOPE_BASE , dn ,
" (objectclass=*) " , & args , attrs [ 0 ] ,
strings , num_strings ) ;
2006-05-18 23:34:25 +04:00
}
2006-09-04 01:07:16 +04:00
ADS_STATUS ads_search_retry_sid ( ADS_STRUCT * ads , LDAPMessage * * res ,
2010-05-21 05:25:01 +04:00
const struct dom_sid * sid ,
2006-09-04 01:07:16 +04:00
const char * * attrs )
2006-04-28 18:44:43 +04:00
{
char * dn , * sid_string ;
ADS_STATUS status ;
2010-11-16 21:17:32 +03:00
2015-05-08 13:06:23 +03:00
sid_string = sid_binstring_hex_talloc ( talloc_tos ( ) , sid ) ;
2006-04-28 18:44:43 +04:00
if ( sid_string = = NULL ) {
2006-05-19 02:34:16 +04:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
2006-04-28 18:44:43 +04:00
}
if ( ! asprintf ( & dn , " <SID=%s> " , sid_string ) ) {
2015-05-08 13:06:23 +03:00
TALLOC_FREE ( sid_string ) ;
2006-05-19 02:34:16 +04:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
2006-04-28 18:44:43 +04:00
}
status = ads_do_search_retry ( ads , dn , LDAP_SCOPE_BASE ,
" (objectclass=*) " , attrs , res ) ;
SAFE_FREE ( dn ) ;
2015-05-08 13:06:23 +03:00
TALLOC_FREE ( sid_string ) ;
2006-04-28 18:44:43 +04:00
return status ;
}
2007-04-22 19:15:00 +04:00
ADS_STATUS ads_ranged_search ( ADS_STRUCT * ads ,
TALLOC_CTX * mem_ctx ,
int scope ,
const char * base ,
const char * filter ,
void * args ,
const char * range_attr ,
char * * * strings ,
size_t * num_strings )
{
ADS_STATUS status ;
2015-04-18 18:40:14 +03:00
uint32_t first_usn ;
2007-04-22 19:15:00 +04:00
int num_retries = 0 ;
const char * * attrs ;
2007-10-19 04:40:25 +04:00
bool more_values = False ;
2007-04-22 19:15:00 +04:00
* num_strings = 0 ;
* strings = NULL ;
2011-06-07 05:30:12 +04:00
attrs = talloc_array ( mem_ctx , const char * , 3 ) ;
2007-04-22 19:15:00 +04:00
ADS_ERROR_HAVE_NO_MEMORY ( attrs ) ;
attrs [ 0 ] = talloc_strdup ( mem_ctx , range_attr ) ;
attrs [ 1 ] = talloc_strdup ( mem_ctx , " usnChanged " ) ;
attrs [ 2 ] = NULL ;
ADS_ERROR_HAVE_NO_MEMORY ( attrs [ 0 ] ) ;
ADS_ERROR_HAVE_NO_MEMORY ( attrs [ 1 ] ) ;
do {
status = ads_ranged_search_internal ( ads , mem_ctx ,
scope , base , filter ,
attrs , args , range_attr ,
strings , num_strings ,
& first_usn , & num_retries ,
& more_values ) ;
if ( NT_STATUS_EQUAL ( STATUS_MORE_ENTRIES , ads_ntstatus ( status ) ) ) {
continue ;
}
if ( ! ADS_ERR_OK ( status ) ) {
* num_strings = 0 ;
strings = NULL ;
goto done ;
}
} while ( more_values ) ;
done :
DEBUG ( 10 , ( " returning with %d strings \n " , ( int ) * num_strings ) ) ;
return status ;
}
2010-11-16 21:18:56 +03:00
static ADS_STATUS ads_ranged_search_internal ( ADS_STRUCT * ads ,
2007-04-22 19:15:00 +04:00
TALLOC_CTX * mem_ctx ,
int scope ,
const char * base ,
const char * filter ,
const char * * attrs ,
void * args ,
const char * range_attr ,
char * * * strings ,
size_t * num_strings ,
2015-04-18 18:40:14 +03:00
uint32_t * first_usn ,
2007-04-22 19:15:00 +04:00
int * num_retries ,
2007-10-19 04:40:25 +04:00
bool * more_values )
2007-04-22 19:15:00 +04:00
{
LDAPMessage * res = NULL ;
ADS_STATUS status ;
int count ;
2015-04-18 18:40:14 +03:00
uint32_t current_usn ;
2007-04-22 19:15:00 +04:00
DEBUG ( 10 , ( " Searching for attrs[0] = %s, attrs[1] = %s \n " , attrs [ 0 ] , attrs [ 1 ] ) ) ;
* more_values = False ;
status = ads_do_search_retry_internal ( ads , base , scope , filter , attrs , args , & res ) ;
if ( ! ADS_ERR_OK ( status ) ) {
DEBUG ( 1 , ( " ads_search: %s \n " ,
ads_errstr ( status ) ) ) ;
return status ;
}
2010-11-16 21:17:32 +03:00
2007-04-22 19:15:00 +04:00
if ( ! res ) {
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
count = ads_count_replies ( ads , res ) ;
if ( count = = 0 ) {
ads_msgfree ( ads , res ) ;
return ADS_ERROR ( LDAP_SUCCESS ) ;
}
if ( * num_strings = = 0 ) {
if ( ! ads_pull_uint32 ( ads , res , " usnChanged " , first_usn ) ) {
DEBUG ( 1 , ( " could not pull first usnChanged! \n " ) ) ;
ads_msgfree ( ads , res ) ;
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
}
if ( ! ads_pull_uint32 ( ads , res , " usnChanged " , & current_usn ) ) {
DEBUG ( 1 , ( " could not pull current usnChanged! \n " ) ) ;
ads_msgfree ( ads , res ) ;
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
if ( * first_usn ! = current_usn ) {
DEBUG ( 5 , ( " USN on this record changed "
" - restarting search \n " ) ) ;
if ( * num_retries < 5 ) {
( * num_retries ) + + ;
* num_strings = 0 ;
ads_msgfree ( ads , res ) ;
return ADS_ERROR_NT ( STATUS_MORE_ENTRIES ) ;
} else {
DEBUG ( 5 , ( " USN on this record changed "
" - restarted search too many times, aborting! \n " ) ) ;
ads_msgfree ( ads , res ) ;
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
}
* strings = ads_pull_strings_range ( ads , mem_ctx , res ,
range_attr ,
* strings ,
& attrs [ 0 ] ,
num_strings ,
more_values ) ;
ads_msgfree ( ads , res ) ;
/* paranoia checks */
if ( * strings = = NULL & & * more_values ) {
DEBUG ( 0 , ( " no strings found but more values??? \n " ) ) ;
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
if ( * num_strings = = 0 & & * more_values ) {
DEBUG ( 0 , ( " no strings found but more values??? \n " ) ) ;
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
return ( * more_values ) ? ADS_ERROR_NT ( STATUS_MORE_ENTRIES ) : ADS_ERROR ( LDAP_SUCCESS ) ;
}
2002-09-28 04:47:06 +04:00
# endif