2022-06-22 21:53:42 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2001-11-20 11:54:15 +03:00
ads ( active directory ) utility library
Copyright ( C ) Andrew Tridgell 2001
2001-12-20 06:54:52 +03:00
Copyright ( C ) Remus Koos 2001
2003-08-01 19:21:20 +04:00
Copyright ( C ) Jim McDonough < jmcd @ us . ibm . com > 2002
2006-02-04 01:19:41 +03:00
Copyright ( C ) Guenther Deschner 2005
2006-07-11 22:45:22 +04:00
Copyright ( C ) Gerald Carter 2006
2009-05-31 13:14:06 +04:00
2001-11-20 11:54:15 +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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2001-11-20 11:54:15 +03:00
( at your option ) any later version .
2009-05-31 13:14:06 +04:00
2001-11-20 11:54:15 +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 13:14:06 +04:00
2001-11-20 11:54:15 +03: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/>.
2001-11-20 11:54:15 +03:00
*/
# include "includes.h"
2010-07-02 02:32:52 +04:00
# include "ads.h"
2010-02-23 19:11:37 +03:00
# include "libads/sitename_cache.h"
2010-05-18 21:40:31 +04:00
# include "libads/cldap.h"
2022-08-24 17:11:06 +03:00
# include "../lib/tsocket/tsocket.h"
2012-05-05 00:47:27 +04:00
# include "../lib/addns/dnsquery.h"
2010-07-01 01:38:57 +04:00
# include "../libds/common/flags.h"
2010-08-26 16:07:20 +04:00
# include "smbldap.h"
2010-10-12 08:27:50 +04:00
# include "../libcli/security/security.h"
2016-01-22 11:57:04 +03:00
# include "../librpc/gen_ndr/netlogon.h"
2012-07-23 06:47:01 +04:00
# include "lib/param/loadparm.h"
2018-03-10 17:31:11 +03:00
# include "libsmb/namequery.h"
2016-08-17 12:58:02 +03:00
# include "../librpc/gen_ndr/ndr_ads.h"
2022-04-27 14:11:26 +03:00
# include "auth/credentials/credentials.h"
2022-04-28 19:53:03 +03:00
# include "passdb.h"
2001-11-20 11:54:15 +03:00
2002-10-01 22:26:00 +04:00
# ifdef HAVE_LDAP
2001-11-20 11:54:15 +03:00
2002-04-10 17:28:03 +04:00
/**
* @ file ldap . c
* @ brief basic ldap client - side routines for ads server communications
*
* The routines contained here should do the necessary ldap calls for
* ads setups .
2022-06-22 21:53:42 +03:00
*
2002-07-15 14:35:28 +04:00
* Important note : attribute names passed into ads_ routines must
* already be in UTF - 8 format . We do not convert them because in almost
* all cases , they are just ascii ( which is represented with the same
* codepoints in UTF - 8 ) . This may have to change at some point
2002-04-10 17:28:03 +04:00
* */
2005-12-12 21:55:54 +03:00
# define LDAP_SERVER_TREE_DELETE_OID "1.2.840.113556.1.4.805"
2004-07-01 20:35:43 +04:00
static SIG_ATOMIC_T gotalarm ;
2007-12-06 15:51:25 +03:00
2004-07-01 20:35:43 +04:00
/***************************************************************
Signal function to tell us we timed out .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-08-14 16:42:46 +04:00
2010-02-19 17:29:47 +03:00
static void gotalarm_sig ( int signum )
2004-07-01 20:35:43 +04:00
{
gotalarm = 1 ;
}
2006-08-14 16:42:46 +04:00
2011-04-26 07:53:45 +04:00
LDAP * ldap_open_with_timeout ( const char * server ,
struct sockaddr_storage * ss ,
int port , unsigned int to )
2004-07-01 20:35:43 +04:00
{
LDAP * ldp = NULL ;
2013-07-03 16:26:49 +04:00
int ldap_err ;
char * uri ;
2006-08-14 16:42:46 +04:00
2008-01-04 23:54:02 +03:00
DEBUG ( 10 , ( " Opening connection to LDAP server '%s:%d', timeout "
" %u seconds \n " , server , port , to ) ) ;
2011-08-20 05:43:51 +04:00
if ( to ) {
/* Setup timeout */
gotalarm = 0 ;
CatchSignal ( SIGALRM , gotalarm_sig ) ;
alarm ( to ) ;
/* End setup timeout. */
}
2006-08-14 16:42:46 +04:00
2015-05-12 18:09:54 +03:00
if ( strchr_m ( server , ' : ' ) ) {
/* IPv6 URI */
uri = talloc_asprintf ( talloc_tos ( ) , " ldap://[%s]:%u " , server , port ) ;
} else {
/* IPv4 URI */
uri = talloc_asprintf ( talloc_tos ( ) , " ldap://%s:%u " , server , port ) ;
}
2013-07-03 16:26:49 +04:00
if ( uri = = NULL ) {
return NULL ;
}
2006-08-14 16:42:46 +04:00
2020-06-03 20:40:59 +03:00
# ifdef HAVE_LDAP_INIT_FD
{
int fd = - 1 ;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL ;
2020-07-14 23:38:06 +03:00
unsigned timeout_ms = 1000 * to ;
2020-06-03 20:40:59 +03:00
2020-07-14 23:38:06 +03:00
status = open_socket_out ( ss , port , timeout_ms , & fd ) ;
2020-06-03 20:40:59 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2020-07-14 23:38:06 +03:00
DEBUG ( 3 , ( " open_socket_out: failed to open socket \n " ) ) ;
2020-06-03 20:40:59 +03:00
return NULL ;
}
/* define LDAP_PROTO_TCP from openldap.h if required */
# ifndef LDAP_PROTO_TCP
# define LDAP_PROTO_TCP 1
# endif
ldap_err = ldap_init_fd ( fd , LDAP_PROTO_TCP , uri , & ldp ) ;
}
# elif defined(HAVE_LDAP_INITIALIZE)
2013-07-03 16:26:49 +04:00
ldap_err = ldap_initialize ( & ldp , uri ) ;
# else
ldp = ldap_open ( server , port ) ;
if ( ldp ! = NULL ) {
ldap_err = LDAP_SUCCESS ;
} else {
ldap_err = LDAP_OTHER ;
}
# endif
if ( ldap_err ! = LDAP_SUCCESS ) {
DEBUG ( 2 , ( " Could not initialize connection for LDAP server '%s': %s \n " ,
uri , ldap_err2string ( ldap_err ) ) ) ;
2008-01-04 23:54:02 +03:00
} else {
2013-07-03 16:26:49 +04:00
DEBUG ( 10 , ( " Initialized connection for LDAP server '%s' \n " , uri ) ) ;
2006-08-14 16:54:37 +04:00
}
2011-08-20 05:43:51 +04:00
if ( to ) {
/* Teardown timeout. */
alarm ( 0 ) ;
CatchSignal ( SIGALRM , SIG_IGN ) ;
}
2006-08-14 16:42:46 +04:00
2004-07-01 20:35:43 +04:00
return ldp ;
}
2002-08-17 21:00:51 +04:00
2004-11-18 14:43:14 +03:00
static int ldap_search_with_timeout ( LDAP * ld ,
LDAP_CONST char * base ,
int scope ,
LDAP_CONST char * filter ,
char * * attrs ,
int attrsonly ,
LDAPControl * * sctrls ,
LDAPControl * * cctrls ,
int sizelimit ,
LDAPMessage * * res )
{
2011-08-20 05:43:51 +04:00
int to = lp_ldap_timeout ( ) ;
2005-01-11 05:13:03 +03:00
struct timeval timeout ;
2011-08-20 05:43:51 +04:00
struct timeval * timeout_ptr = NULL ;
2004-11-18 14:43:14 +03:00
int result ;
2024-02-26 10:31:24 +03:00
DBG_DEBUG ( " ldap_search: base => [%s], filter => [%s], scope => [%d] \n " ,
base ,
filter ,
scope ) ;
2005-01-11 05:13:03 +03:00
/* Setup timeout for the ldap_search_ext_s call - local and remote. */
2004-11-18 14:43:14 +03:00
gotalarm = 0 ;
2011-08-20 05:43:51 +04:00
if ( to ) {
timeout . tv_sec = to ;
timeout . tv_usec = 0 ;
timeout_ptr = & timeout ;
/* Setup alarm timeout. */
CatchSignal ( SIGALRM , gotalarm_sig ) ;
/* Make the alarm time one second beyond
2023-07-05 12:21:39 +03:00
the timeout we ' re setting for the
2011-08-20 05:43:51 +04:00
remote search timeout , to allow that
to fire in preference . */
alarm ( to + 1 ) ;
/* End setup timeout. */
}
2004-11-18 14:43:14 +03:00
result = ldap_search_ext_s ( ld , base , scope , filter , attrs ,
2011-08-20 05:43:51 +04:00
attrsonly , sctrls , cctrls , timeout_ptr ,
2004-11-18 14:43:14 +03:00
sizelimit , res ) ;
2011-08-20 05:43:51 +04:00
if ( to ) {
/* Teardown alarm timeout. */
CatchSignal ( SIGALRM , SIG_IGN ) ;
alarm ( 0 ) ;
}
2004-11-18 14:43:14 +03:00
if ( gotalarm ! = 0 )
return LDAP_TIMELIMIT_EXCEEDED ;
2009-04-22 14:03:04 +04:00
/*
* A bug in OpenLDAP means ldap_search_ext_s can return
* LDAP_SUCCESS but with a NULL res pointer . Cope with
* this . See bug # 6279 for details . JRA .
*/
2009-04-22 13:54:11 +04:00
if ( * res = = NULL ) {
return LDAP_TIMELIMIT_EXCEEDED ;
}
2004-11-18 14:43:14 +03:00
return result ;
}
2006-08-31 08:14:08 +04:00
/**********************************************
Do client and server sitename match ?
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
bool ads_sitename_match ( ADS_STRUCT * ads )
2006-08-31 08:14:08 +04:00
{
if ( ads - > config . server_site_name = = NULL & &
ads - > config . client_site_name = = NULL ) {
2006-09-02 05:23:08 +04:00
DEBUG ( 10 , ( " ads_sitename_match: both null \n " ) ) ;
2006-08-31 08:14:08 +04:00
return True ;
}
if ( ads - > config . server_site_name & &
ads - > config . client_site_name & &
strequal ( ads - > config . server_site_name ,
ads - > config . client_site_name ) ) {
2006-09-02 05:23:08 +04:00
DEBUG ( 10 , ( " ads_sitename_match: name %s match \n " , ads - > config . server_site_name ) ) ;
2006-08-31 08:14:08 +04:00
return True ;
}
2006-10-13 13:44:54 +04:00
DEBUG ( 10 , ( " ads_sitename_match: no match between server: %s and client: %s \n " ,
2006-09-02 05:23:08 +04:00
ads - > config . server_site_name ? ads - > config . server_site_name : " NULL " ,
ads - > config . client_site_name ? ads - > config . client_site_name : " NULL " ) ) ;
2006-08-31 08:14:08 +04:00
return False ;
}
2006-11-10 15:42:50 +03:00
/**********************************************
Is this the closest DC ?
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
bool ads_closest_dc ( ADS_STRUCT * ads )
2006-11-10 15:42:50 +03:00
{
2008-04-21 21:59:27 +04:00
if ( ads - > config . flags & NBT_SERVER_CLOSEST ) {
DEBUG ( 10 , ( " ads_closest_dc: NBT_SERVER_CLOSEST flag set \n " ) ) ;
2006-11-10 15:42:50 +03:00
return True ;
}
/* not sure if this can ever happen */
if ( ads_sitename_match ( ads ) ) {
2008-04-21 21:59:27 +04:00
DEBUG ( 10 , ( " ads_closest_dc: NBT_SERVER_CLOSEST flag not set but sites match \n " ) ) ;
2006-11-10 15:42:50 +03:00
return True ;
}
2008-10-27 21:38:15 +03:00
if ( ads - > config . client_site_name = = NULL ) {
DEBUG ( 10 , ( " ads_closest_dc: client belongs to no site \n " ) ) ;
return True ;
}
2022-06-22 21:53:42 +03:00
DEBUG ( 10 , ( " ads_closest_dc: %s is not the closest DC \n " ,
2006-11-10 15:42:50 +03:00
ads - > config . ldap_server_name ) ) ;
return False ;
}
2022-08-24 17:36:17 +03:00
static bool ads_fill_cldap_reply ( ADS_STRUCT * ads ,
bool gc ,
const struct sockaddr_storage * ss ,
const struct NETLOGON_SAM_LOGON_RESPONSE_EX * cldap_reply )
2002-08-17 21:00:51 +04:00
{
2009-07-28 22:51:58 +04:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2008-04-21 21:47:13 +04:00
bool ret = false ;
2011-04-26 11:03:32 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
2022-06-15 11:50:22 +03:00
ADS_STATUS status ;
2016-08-17 12:58:02 +03:00
char * dn ;
2002-08-17 21:00:51 +04:00
2014-04-16 18:07:14 +04:00
print_sockaddr ( addr , sizeof ( addr ) , ss ) ;
2008-04-21 21:47:13 +04:00
2006-05-12 19:17:35 +04:00
/* Check the CLDAP reply flags */
2022-08-24 17:36:17 +03:00
if ( ! ( cldap_reply - > server_type & NBT_SERVER_LDAP ) ) {
DBG_WARNING ( " %s's CLDAP reply says it is not an LDAP server! \n " ,
addr ) ;
2008-04-21 21:47:13 +04:00
ret = false ;
goto out ;
2006-05-12 19:17:35 +04:00
}
/* Fill in the ads->config values */
2021-10-15 04:34:11 +03:00
ADS_TALLOC_CONST_FREE ( ads - > config . workgroup ) ;
2016-08-17 12:58:02 +03:00
ADS_TALLOC_CONST_FREE ( ads - > config . realm ) ;
ADS_TALLOC_CONST_FREE ( ads - > config . bind_path ) ;
ADS_TALLOC_CONST_FREE ( ads - > config . ldap_server_name ) ;
ADS_TALLOC_CONST_FREE ( ads - > config . server_site_name ) ;
ADS_TALLOC_CONST_FREE ( ads - > config . client_site_name ) ;
2006-05-12 19:17:35 +04:00
2022-08-24 17:36:17 +03:00
if ( ! check_cldap_reply_required_flags ( cldap_reply - > server_type ,
2017-03-20 05:37:12 +03:00
ads - > config . flags ) ) {
ret = false ;
goto out ;
}
2022-06-15 13:03:56 +03:00
ads - > config . ldap_server_name = talloc_strdup ( ads ,
2022-08-24 17:36:17 +03:00
cldap_reply - > pdc_dns_name ) ;
2022-06-15 13:03:56 +03:00
if ( ads - > config . ldap_server_name = = NULL ) {
DBG_WARNING ( " Out of memory \n " ) ;
ret = false ;
goto out ;
}
2021-10-15 04:34:11 +03:00
ads - > config . workgroup = talloc_strdup ( ads , cldap_reply - > domain_name ) ;
if ( ads - > config . workgroup = = NULL ) {
DBG_WARNING ( " Out of memory \n " ) ;
ret = false ;
goto out ;
}
2022-06-13 18:44:02 +03:00
ads - > config . realm = talloc_asprintf_strupper_m ( ads ,
" %s " ,
2022-08-24 17:36:17 +03:00
cldap_reply - > dns_domain ) ;
2022-06-13 18:44:02 +03:00
if ( ads - > config . realm = = NULL ) {
DBG_WARNING ( " Out of memory \n " ) ;
2012-08-09 02:35:28 +04:00
ret = false ;
goto out ;
}
2016-08-17 12:58:02 +03:00
status = ads_build_dn ( ads - > config . realm , ads , & dn ) ;
2022-06-15 11:50:22 +03:00
if ( ! ADS_ERR_OK ( status ) ) {
DBG_DEBUG ( " Failed to build bind path: %s \n " ,
ads_errstr ( status ) ) ;
ret = false ;
goto out ;
}
2016-08-17 12:58:02 +03:00
ads - > config . bind_path = dn ;
2022-06-15 11:50:22 +03:00
2022-08-24 17:36:17 +03:00
if ( * cldap_reply - > server_site ) {
2006-08-31 08:14:08 +04:00
ads - > config . server_site_name =
2022-08-24 17:36:17 +03:00
talloc_strdup ( ads , cldap_reply - > server_site ) ;
2022-06-15 13:09:21 +03:00
if ( ads - > config . server_site_name = = NULL ) {
DBG_WARNING ( " Out of memory \n " ) ;
ret = false ;
goto out ;
}
2006-08-31 08:14:08 +04:00
}
2022-06-15 13:09:21 +03:00
2022-08-24 17:36:17 +03:00
if ( * cldap_reply - > client_site ) {
2006-09-02 05:23:08 +04:00
ads - > config . client_site_name =
2022-08-24 17:36:17 +03:00
talloc_strdup ( ads , cldap_reply - > client_site ) ;
2022-06-15 13:16:23 +03:00
if ( ads - > config . client_site_name = = NULL ) {
DBG_WARNING ( " Out of memory \n " ) ;
ret = false ;
goto out ;
}
2006-08-31 08:14:08 +04:00
}
2022-06-10 17:09:48 +03:00
2008-06-27 18:22:39 +04:00
ads - > ldap . port = gc ? LDAP_GC_PORT : LDAP_PORT ;
2014-04-16 18:07:14 +04:00
ads - > ldap . ss = * ss ;
2007-10-25 01:16:54 +04:00
2006-08-30 08:40:03 +04:00
/* Store our site name. */
2022-08-24 17:36:17 +03:00
sitename_store ( cldap_reply - > domain_name , cldap_reply - > client_site ) ;
sitename_store ( cldap_reply - > dns_domain , cldap_reply - > client_site ) ;
2006-08-30 08:40:03 +04:00
2017-03-20 05:37:12 +03:00
/* Leave this until last so that the flags are not clobbered */
2022-08-24 17:36:17 +03:00
ads - > config . flags = cldap_reply - > server_type ;
2017-03-20 05:37:12 +03:00
2008-04-21 21:47:13 +04:00
ret = true ;
2009-07-28 22:51:58 +04:00
2008-04-21 21:47:13 +04:00
out :
2009-07-28 22:51:58 +04:00
TALLOC_FREE ( frame ) ;
2008-04-21 21:47:13 +04:00
return ret ;
2002-08-17 21:00:51 +04:00
}
2022-08-24 17:36:17 +03:00
/*
try a connection to a given ldap server , returning True and setting the servers IP
in the ads struct if successful
*/
static bool ads_try_connect ( ADS_STRUCT * ads , bool gc ,
struct sockaddr_storage * ss )
{
struct NETLOGON_SAM_LOGON_RESPONSE_EX cldap_reply = { } ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
bool ok ;
char addr [ INET6_ADDRSTRLEN ] = { 0 , } ;
if ( ss = = NULL ) {
TALLOC_FREE ( frame ) ;
return false ;
}
print_sockaddr ( addr , sizeof ( addr ) , ss ) ;
DBG_INFO ( " ads_try_connect: sending CLDAP request to %s (realm: %s) \n " ,
addr , ads - > server . realm ) ;
ok = ads_cldap_netlogon_5 ( frame , ss , ads - > server . realm , & cldap_reply ) ;
if ( ! ok ) {
DBG_NOTICE ( " ads_cldap_netlogon_5(%s, %s) failed. \n " ,
addr , ads - > server . realm ) ;
TALLOC_FREE ( frame ) ;
return false ;
}
ok = ads_fill_cldap_reply ( ads , gc , ss , & cldap_reply ) ;
if ( ! ok ) {
DBG_NOTICE ( " ads_fill_cldap_reply(%s, %s) failed. \n " ,
addr , ads - > server . realm ) ;
TALLOC_FREE ( frame ) ;
return false ;
}
TALLOC_FREE ( frame ) ;
return true ;
}
2020-09-09 02:33:25 +03:00
/**********************************************************************
send a cldap ping to list of servers , one at a time , until one of
them answers it ' s an ldap server . Record success in the ADS_STRUCT .
Take note of and update negative connection cache .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-09-09 02:38:09 +03:00
static NTSTATUS cldap_ping_list ( ADS_STRUCT * ads ,
2020-09-09 02:33:25 +03:00
const char * domain ,
struct samba_sockaddr * sa_list ,
size_t count )
{
2022-08-24 17:11:06 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct timeval endtime = timeval_current_ofs ( MAX ( 3 , lp_ldap_timeout ( ) / 2 ) , 0 ) ;
uint32_t nt_version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX ;
struct tsocket_address * * ts_list = NULL ;
const struct tsocket_address * const * ts_list_const = NULL ;
struct samba_sockaddr * * req_sa_list = NULL ;
struct netlogon_samlogon_response * * responses = NULL ;
size_t num_requests = 0 ;
NTSTATUS status ;
2020-09-09 02:33:25 +03:00
size_t i ;
2022-08-24 17:11:06 +03:00
bool ok = false ;
bool retry ;
ts_list = talloc_zero_array ( frame ,
struct tsocket_address * ,
count ) ;
if ( ts_list = = NULL ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
req_sa_list = talloc_zero_array ( frame ,
struct samba_sockaddr * ,
count ) ;
if ( req_sa_list = = NULL ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
again :
/*
* The retry loop is bound by the timeout
*/
retry = false ;
2023-07-04 19:07:12 +03:00
num_requests = 0 ;
2020-09-09 02:33:25 +03:00
for ( i = 0 ; i < count ; i + + ) {
char server [ INET6_ADDRSTRLEN ] ;
2022-08-24 17:11:06 +03:00
int ret ;
2020-09-09 02:33:25 +03:00
2022-06-22 21:54:15 +03:00
if ( is_zero_addr ( & sa_list [ i ] . u . ss ) ) {
continue ;
}
2020-09-09 02:33:25 +03:00
print_sockaddr ( server , sizeof ( server ) , & sa_list [ i ] . u . ss ) ;
2022-08-24 17:11:06 +03:00
status = check_negative_conn_cache ( domain , server ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2020-09-09 02:33:25 +03:00
continue ;
2022-08-24 17:11:06 +03:00
}
2020-09-09 02:33:25 +03:00
2022-08-24 17:11:06 +03:00
ret = tsocket_address_inet_from_strings ( ts_list , " ip " ,
server , LDAP_PORT ,
& ts_list [ num_requests ] ) ;
if ( ret ! = 0 ) {
status = map_nt_error_from_unix ( errno ) ;
DBG_WARNING ( " Failed to create tsocket_address for %s - %s \n " ,
server , nt_errstr ( status ) ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
req_sa_list [ num_requests ] = & sa_list [ i ] ;
num_requests + = 1 ;
}
2023-10-18 12:32:57 +03:00
DBG_DEBUG ( " Try to create %zu netlogon connections for domain '%s' "
" (provided count of addresses was %zu). \n " ,
num_requests ,
domain ,
count ) ;
2022-08-24 17:11:06 +03:00
if ( num_requests = = 0 ) {
status = NT_STATUS_NO_LOGON_SERVERS ;
DBG_WARNING ( " domain[%s] num_requests[%zu] for count[%zu] - %s \n " ,
domain , num_requests , count , nt_errstr ( status ) ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
ts_list_const = ( const struct tsocket_address * const * ) ts_list ;
status = cldap_multi_netlogon ( frame ,
ts_list_const , num_requests ,
ads - > server . realm , NULL ,
nt_version ,
1 , endtime , & responses ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " cldap_multi_netlogon(realm=%s, num_requests=%zu) "
" for count[%zu] - %s \n " ,
ads - > server . realm ,
num_requests , count ,
nt_errstr ( status ) ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_LOGON_SERVERS ;
}
2020-09-09 02:33:25 +03:00
2022-08-24 17:11:06 +03:00
for ( i = 0 ; i < num_requests ; i + + ) {
struct NETLOGON_SAM_LOGON_RESPONSE_EX * cldap_reply = NULL ;
char server [ INET6_ADDRSTRLEN ] ;
if ( responses [ i ] = = NULL ) {
continue ;
}
print_sockaddr ( server , sizeof ( server ) , & req_sa_list [ i ] - > u . ss ) ;
if ( responses [ i ] - > ntver ! = NETLOGON_NT_VERSION_5EX ) {
DBG_NOTICE ( " realm=[%s] nt_version mismatch: 0x%08x for %s \n " ,
ads - > server . realm ,
responses [ i ] - > ntver , server ) ;
continue ;
}
cldap_reply = & responses [ i ] - > data . nt5_ex ;
/* Returns ok only if it matches the correct server type */
ok = ads_fill_cldap_reply ( ads ,
false ,
& req_sa_list [ i ] - > u . ss ,
cldap_reply ) ;
2020-09-09 02:33:25 +03:00
if ( ok ) {
2022-08-24 17:11:06 +03:00
DBG_DEBUG ( " realm[%s]: selected %s => %s \n " ,
ads - > server . realm ,
server , cldap_reply - > pdc_dns_name ) ;
if ( CHECK_DEBUGLVL ( DBGLVL_DEBUG ) ) {
NDR_PRINT_DEBUG ( NETLOGON_SAM_LOGON_RESPONSE_EX ,
cldap_reply ) ;
}
TALLOC_FREE ( frame ) ;
2020-09-09 02:33:25 +03:00
return NT_STATUS_OK ;
}
2022-08-24 17:11:06 +03:00
DBG_NOTICE ( " realm[%s] server %s %s - not usable \n " ,
ads - > server . realm ,
server , cldap_reply - > pdc_dns_name ) ;
if ( CHECK_DEBUGLVL ( DBGLVL_NOTICE ) ) {
NDR_PRINT_DEBUG ( NETLOGON_SAM_LOGON_RESPONSE_EX ,
cldap_reply ) ;
}
add_failed_connection_entry ( domain , server ,
NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID ) ;
retry = true ;
}
if ( retry ) {
bool expired ;
expired = timeval_expired ( & endtime ) ;
if ( ! expired ) {
goto again ;
}
}
/* keep track of failures as all were not suitable */
for ( i = 0 ; i < num_requests ; i + + ) {
char server [ INET6_ADDRSTRLEN ] ;
print_sockaddr ( server , sizeof ( server ) , & req_sa_list [ i ] - > u . ss ) ;
2020-09-09 02:33:25 +03:00
add_failed_connection_entry ( domain , server ,
NT_STATUS_UNSUCCESSFUL ) ;
}
2022-08-24 17:11:06 +03:00
status = NT_STATUS_NO_LOGON_SERVERS ;
DBG_WARNING ( " realm[%s] no valid response "
" num_requests[%zu] for count[%zu] - %s \n " ,
ads - > server . realm ,
num_requests , count , nt_errstr ( status ) ) ;
TALLOC_FREE ( frame ) ;
2020-09-09 02:33:25 +03:00
return NT_STATUS_NO_LOGON_SERVERS ;
}
2015-06-11 14:24:36 +03:00
/***************************************************************************
resolve a name and perform an " ldap ping " using NetBIOS and related methods
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS resolve_and_ping_netbios ( ADS_STRUCT * ads ,
const char * domain , const char * realm )
{
2020-09-02 20:05:48 +03:00
size_t i ;
size_t count = 0 ;
2020-09-09 02:35:01 +03:00
struct samba_sockaddr * sa_list = NULL ;
2019-09-17 11:05:28 +03:00
NTSTATUS status ;
2015-06-09 14:30:14 +03:00
2015-06-11 14:24:36 +03:00
DEBUG ( 6 , ( " resolve_and_ping_netbios: (cldap) looking for domain '%s' \n " ,
domain ) ) ;
2015-06-09 14:30:14 +03:00
2020-09-09 04:07:28 +03:00
status = get_sorted_dc_list ( talloc_tos ( ) ,
2020-08-26 21:50:46 +03:00
domain ,
NULL ,
2020-09-09 02:35:01 +03:00
& sa_list ,
2020-08-26 21:50:46 +03:00
& count ,
false ) ;
2015-06-09 14:30:14 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2015-06-11 14:24:36 +03:00
/* remove servers which are known to be dead based on
the corresponding DNS method */
if ( * realm ) {
for ( i = 0 ; i < count ; + + i ) {
char server [ INET6_ADDRSTRLEN ] ;
2015-06-09 14:30:14 +03:00
2020-09-09 02:35:01 +03:00
print_sockaddr ( server , sizeof ( server ) , & sa_list [ i ] . u . ss ) ;
2015-06-09 14:30:14 +03:00
2015-06-11 14:24:36 +03:00
if ( ! NT_STATUS_IS_OK (
2015-06-09 14:30:14 +03:00
check_negative_conn_cache ( realm , server ) ) ) {
/* Ensure we add the workgroup name for this
IP address as negative too . */
add_failed_connection_entry (
2015-06-11 14:24:36 +03:00
domain , server ,
2015-06-09 14:30:14 +03:00
NT_STATUS_UNSUCCESSFUL ) ;
}
}
2015-06-11 14:24:36 +03:00
}
2015-06-09 14:30:14 +03:00
2020-09-09 02:38:09 +03:00
status = cldap_ping_list ( ads , domain , sa_list , count ) ;
2015-06-09 14:30:14 +03:00
2020-09-09 02:35:01 +03:00
TALLOC_FREE ( sa_list ) ;
2015-06-11 14:24:36 +03:00
return status ;
}
/**********************************************************************
resolve a name and perform an " ldap ping " using DNS
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS resolve_and_ping_dns ( ADS_STRUCT * ads , const char * sitename ,
const char * realm )
{
2020-09-02 20:05:48 +03:00
size_t count = 0 ;
2020-09-09 02:36:40 +03:00
struct samba_sockaddr * sa_list = NULL ;
2019-09-17 11:05:28 +03:00
NTSTATUS status ;
2015-06-11 14:24:36 +03:00
DEBUG ( 6 , ( " resolve_and_ping_dns: (cldap) looking for realm '%s' \n " ,
realm ) ) ;
2020-09-09 04:07:28 +03:00
status = get_sorted_dc_list ( talloc_tos ( ) ,
2020-08-26 21:50:46 +03:00
realm ,
sitename ,
2020-09-09 02:36:40 +03:00
& sa_list ,
2020-08-26 21:50:46 +03:00
& count ,
true ) ;
2015-06-11 14:24:36 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2020-09-09 02:36:40 +03:00
TALLOC_FREE ( sa_list ) ;
2015-06-11 14:24:36 +03:00
return status ;
2015-06-09 14:30:14 +03:00
}
2020-09-09 02:38:09 +03:00
status = cldap_ping_list ( ads , realm , sa_list , count ) ;
2015-06-11 14:24:36 +03:00
2020-09-09 02:36:40 +03:00
TALLOC_FREE ( sa_list ) ;
2015-06-09 14:30:14 +03:00
2015-06-11 14:24:36 +03:00
return status ;
2015-06-09 14:30:14 +03:00
}
2003-06-25 21:41:05 +04:00
/**********************************************************************
Try to find an AD dc using our internal name resolution routines
2023-09-01 04:39:18 +03:00
Try the realm first and then the workgroup name if netbios is not
2003-06-25 21:41:05 +04:00
disabled
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-08-17 21:00:51 +04:00
2006-08-28 13:19:30 +04:00
static NTSTATUS ads_find_dc ( ADS_STRUCT * ads )
2002-08-17 21:00:51 +04:00
{
2015-06-09 14:30:14 +03:00
const char * c_domain = " " ;
2002-11-13 02:20:50 +03:00
const char * c_realm ;
2007-10-19 04:40:25 +04:00
bool use_own_domain = False ;
2015-06-09 14:30:14 +03:00
char * sitename = NULL ;
2006-08-28 13:19:30 +04:00
NTSTATUS status = NT_STATUS_UNSUCCESSFUL ;
2014-04-16 18:07:14 +04:00
bool ok = false ;
2003-07-25 20:42:34 +04:00
/* if the realm and workgroup are both empty, assume they are ours */
2002-08-17 21:00:51 +04:00
2003-06-25 21:41:05 +04:00
/* realm */
2002-11-13 02:20:50 +03:00
c_realm = ads - > server . realm ;
2007-11-21 05:55:36 +03:00
2015-06-09 14:30:14 +03:00
if ( c_realm = = NULL )
c_realm = " " ;
if ( ! * c_realm ) {
2003-07-25 20:42:34 +04:00
/* special case where no realm and no workgroup means our own */
if ( ! ads - > server . workgroup | | ! * ads - > server . workgroup ) {
use_own_domain = True ;
c_realm = lp_realm ( ) ;
}
}
2007-11-21 05:55:36 +03:00
2015-06-09 14:30:14 +03:00
if ( ! lp_disable_netbios ( ) ) {
if ( use_own_domain ) {
c_domain = lp_workgroup ( ) ;
} else {
c_domain = ads - > server . workgroup ;
if ( ! * c_realm & & ( ! c_domain | | ! * c_domain ) ) {
c_domain = lp_workgroup ( ) ;
}
}
2007-11-21 05:55:36 +03:00
2015-06-09 14:30:14 +03:00
if ( ! c_domain ) {
c_domain = " " ;
2003-07-25 20:42:34 +04:00
}
2008-11-24 17:04:12 +03:00
}
2007-11-21 05:55:36 +03:00
2015-06-09 14:30:14 +03:00
if ( ! * c_realm & & ! * c_domain ) {
2015-06-27 10:31:21 +03:00
DEBUG ( 0 , ( " ads_find_dc: no realm or workgroup! Don't know "
2011-08-17 13:58:57 +04:00
" what to do \n " ) ) ;
2008-11-24 17:04:12 +03:00
return NT_STATUS_INVALID_PARAMETER ; /* rather need MISSING_PARAMETER ... */
2002-08-17 21:00:51 +04:00
}
2007-11-21 05:55:36 +03:00
2008-10-22 13:14:10 +04:00
/*
* In case of LDAP we use get_dc_name ( ) as that
* creates the custom krb5 . conf file
*/
2024-03-07 11:56:00 +03:00
if ( ads - > auth . flags & ADS_AUTH_GENERATE_KRB5_CONFIG ) {
2008-10-22 13:14:10 +04:00
fstring srv_name ;
struct sockaddr_storage ip_out ;
2015-06-09 14:30:14 +03:00
DEBUG ( 6 , ( " ads_find_dc: (ldap) looking for realm '%s' "
" and falling back to domain '%s' \n " ,
c_realm , c_domain ) ) ;
2008-10-22 13:14:10 +04:00
2015-06-09 14:30:14 +03:00
ok = get_dc_name ( c_domain , c_realm , srv_name , & ip_out ) ;
2014-04-16 18:07:14 +04:00
if ( ok ) {
2022-06-22 21:54:15 +03:00
if ( is_zero_addr ( & ip_out ) ) {
return NT_STATUS_NO_LOGON_SERVERS ;
}
2008-10-22 13:14:10 +04:00
/*
* we call ads_try_connect ( ) to fill in the
* ads - > config details
*/
2014-04-16 18:07:14 +04:00
ok = ads_try_connect ( ads , false , & ip_out ) ;
if ( ok ) {
2008-10-22 13:14:10 +04:00
return NT_STATUS_OK ;
}
}
return NT_STATUS_NO_LOGON_SERVERS ;
}
2015-06-09 14:30:14 +03:00
if ( * c_realm ) {
sitename = sitename_fetch ( talloc_tos ( ) , c_realm ) ;
2015-06-11 14:24:36 +03:00
status = resolve_and_ping_dns ( ads , sitename , c_realm ) ;
2007-01-18 12:58:57 +03:00
2015-06-09 14:30:14 +03:00
if ( NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( sitename ) ;
return status ;
2002-08-17 21:00:51 +04:00
}
2007-11-21 05:55:36 +03:00
2015-06-09 14:30:14 +03:00
/* In case we failed to contact one of our closest DC on our
* site we
* need to try to find another DC , retry with a site - less SRV
* DNS query
* - Guenther */
if ( sitename ) {
2015-06-27 10:31:21 +03:00
DEBUG ( 3 , ( " ads_find_dc: failed to find a valid DC on "
" our site (%s), Trying to find another DC "
" for realm '%s' (domain '%s') \n " ,
sitename , c_realm , c_domain ) ) ;
2015-06-09 14:30:14 +03:00
namecache_delete ( c_realm , 0x1C ) ;
status =
2015-06-11 14:24:36 +03:00
resolve_and_ping_dns ( ads , NULL , c_realm ) ;
2015-06-09 14:30:14 +03:00
if ( NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( sitename ) ;
return status ;
2006-09-03 07:46:07 +04:00
}
}
2007-11-21 05:55:36 +03:00
2015-06-09 14:30:14 +03:00
TALLOC_FREE ( sitename ) ;
2002-08-17 21:00:51 +04:00
}
2015-06-09 14:30:14 +03:00
/* try netbios as fallback - if permitted,
or if configuration specifically requests it */
if ( * c_domain ) {
if ( * c_realm ) {
2015-06-27 10:31:21 +03:00
DEBUG ( 3 , ( " ads_find_dc: falling back to netbios "
" name resolution for domain '%s' (realm '%s') \n " ,
c_domain , c_realm ) ) ;
2015-06-09 14:30:14 +03:00
}
2007-01-17 21:25:35 +03:00
2015-06-11 14:24:36 +03:00
status = resolve_and_ping_netbios ( ads , c_domain , c_realm ) ;
2015-06-27 10:31:21 +03:00
if ( NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2007-01-17 21:25:35 +03:00
}
2015-06-27 10:31:21 +03:00
DEBUG ( 1 , ( " ads_find_dc: "
" name resolution for realm '%s' (domain '%s') failed: %s \n " ,
c_realm , c_domain , nt_errstr ( status ) ) ) ;
2015-06-09 14:30:14 +03:00
return status ;
2002-08-17 21:00:51 +04:00
}
2022-04-27 14:11:26 +03:00
2002-04-10 17:28:03 +04:00
/**
* Connect to the LDAP server
* @ param ads Pointer to an existing ADS_STRUCT
* @ return status of connection
* */
2022-04-27 14:11:26 +03:00
static ADS_STATUS ads_connect_internal ( ADS_STRUCT * ads ,
struct cli_credentials * creds )
2001-11-20 11:54:15 +03:00
{
int version = LDAP_VERSION3 ;
2001-12-19 15:21:12 +03:00
ADS_STATUS status ;
2006-08-28 13:19:30 +04:00
NTSTATUS ntstatus ;
2007-10-25 01:16:54 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
2022-01-28 19:51:10 +03:00
struct sockaddr_storage existing_ss ;
2024-01-30 12:27:58 +03:00
bool tls = false ;
bool start_tls = false ;
2022-01-28 19:51:10 +03:00
zero_sockaddr ( & existing_ss ) ;
2020-07-23 01:35:43 +03:00
2022-04-27 14:11:26 +03:00
if ( ! ( ads - > auth . flags & ADS_AUTH_NO_BIND ) ) {
SMB_ASSERT ( creds ! = NULL ) ;
}
if ( ads - > auth . flags & ADS_AUTH_ANON_BIND ) {
/*
* Simple anonyous binds are only
* allowed for anonymous credentials
*/
SMB_ASSERT ( cli_credentials_is_anonymous ( creds ) ) ;
}
2024-03-07 11:56:00 +03:00
if ( ! ( ads - > auth . flags & ( ADS_AUTH_NO_BIND | ADS_AUTH_ANON_BIND ) ) ) {
2024-03-07 11:56:00 +03:00
ads - > auth . flags | = ADS_AUTH_GENERATE_KRB5_CONFIG ;
}
2020-07-23 01:35:43 +03:00
/*
* ads_connect can be passed in a reused ADS_STRUCT
* with an existing non - zero ads - > ldap . ss IP address
* that was stored by going through ads_find_dc ( )
* if ads - > server . ldap_server was NULL .
*
* If ads - > server . ldap_server is still NULL but
* the target address isn ' t the zero address , then
* store that address off off before zeroing out
* ads - > ldap so we don ' t keep doing multiple calls
* to ads_find_dc ( ) in the reuse case .
*
* If a caller wants a clean ADS_STRUCT they
2022-05-26 18:28:34 +03:00
* will TALLOC_FREE it and allocate a new one
* by calling ads_init ( ) , which ensures
2020-07-23 01:35:43 +03:00
* ads - > ldap . ss is a properly zero ' ed out valid IP
* address .
*/
if ( ads - > server . ldap_server = = NULL & & ! is_zero_addr ( & ads - > ldap . ss ) ) {
/* Save off the address we previously found by ads_find_dc(). */
2022-01-31 14:54:12 +03:00
existing_ss = ads - > ldap . ss ;
2020-07-23 01:35:43 +03:00
}
2001-11-20 11:54:15 +03:00
2020-08-08 06:24:07 +03:00
ads_zero_ldap ( ads ) ;
2024-01-30 12:27:58 +03:00
ZERO_STRUCT ( ads - > ldap_tls_data ) ;
2017-05-05 15:37:20 +03:00
ZERO_STRUCT ( ads - > ldap_wrap_data ) ;
2010-09-07 04:15:09 +04:00
ads - > ldap . last_attempt = time_mono ( NULL ) ;
2017-05-05 15:37:20 +03:00
ads - > ldap_wrap_data . wrap_type = ADS_SASLWRAP_TYPE_PLAIN ;
2002-07-15 14:35:28 +04:00
2002-08-17 21:00:51 +04:00
/* try with a user specified server */
2006-05-12 19:17:35 +04:00
2008-01-31 03:50:49 +03:00
if ( DEBUGLEVEL > = 11 ) {
char * s = NDR_PRINT_STRUCT_STRING ( talloc_tos ( ) , ads_struct , ads ) ;
DEBUG ( 11 , ( " ads_connect: entering \n " ) ) ;
DEBUGADD ( 11 , ( " %s \n " , s ) ) ;
TALLOC_FREE ( s ) ;
}
2014-04-16 18:07:14 +04:00
if ( ads - > server . ldap_server ) {
bool ok = false ;
struct sockaddr_storage ss ;
2023-10-18 12:32:57 +03:00
DBG_DEBUG ( " Resolving name of LDAP server '%s'. \n " ,
ads - > server . ldap_server ) ;
2014-04-16 18:07:14 +04:00
ok = resolve_name ( ads - > server . ldap_server , & ss , 0x20 , true ) ;
if ( ! ok ) {
DEBUG ( 5 , ( " ads_connect: unable to resolve name %s \n " ,
ads - > server . ldap_server ) ) ;
status = ADS_ERROR_NT ( NT_STATUS_NOT_FOUND ) ;
goto out ;
}
2022-06-22 21:54:15 +03:00
if ( is_zero_addr ( & ss ) ) {
status = ADS_ERROR_NT ( NT_STATUS_NOT_FOUND ) ;
goto out ;
}
2014-04-16 18:07:14 +04:00
ok = ads_try_connect ( ads , ads - > server . gc , & ss ) ;
if ( ok ) {
2009-01-16 21:06:49 +03:00
goto got_connection ;
}
/* The choice of which GC use is handled one level up in
ads_connect_gc ( ) . If we continue on from here with
ads_find_dc ( ) we will get GC searches on port 389 which
doesn ' t work . - - jerry */
if ( ads - > server . gc = = true ) {
return ADS_ERROR ( LDAP_OPERATIONS_ERROR ) ;
}
2017-04-04 03:42:17 +03:00
if ( ads - > server . no_fallback ) {
status = ADS_ERROR_NT ( NT_STATUS_NOT_FOUND ) ;
goto out ;
}
2002-07-15 14:35:28 +04:00
}
2022-01-31 14:54:12 +03:00
if ( ! is_zero_addr ( & existing_ss ) ) {
2020-07-23 01:35:43 +03:00
/* We saved off who we should talk to. */
bool ok = ads_try_connect ( ads ,
ads - > server . gc ,
2022-01-31 14:54:12 +03:00
& existing_ss ) ;
2020-07-23 01:35:43 +03:00
if ( ok ) {
goto got_connection ;
}
/*
* Keep trying to find a server and fall through
* into ads_find_dc ( ) again .
*/
2023-10-18 12:32:57 +03:00
DBG_DEBUG ( " Failed to connect to DC via LDAP server IP address, "
" trying to find another DC. \n " ) ;
2020-07-23 01:35:43 +03:00
}
2006-08-28 13:19:30 +04:00
ntstatus = ads_find_dc ( ads ) ;
if ( NT_STATUS_IS_OK ( ntstatus ) ) {
2002-08-17 21:00:51 +04:00
goto got_connection ;
2001-11-20 11:54:15 +03:00
}
2002-07-15 14:35:28 +04:00
2008-01-31 03:50:49 +03:00
status = ADS_ERROR_NT ( ntstatus ) ;
goto out ;
2002-08-17 21:00:51 +04:00
got_connection :
2007-10-25 01:16:54 +04:00
print_sockaddr ( addr , sizeof ( addr ) , & ads - > ldap . ss ) ;
2008-01-04 23:45:28 +03:00
DEBUG ( 3 , ( " Successfully contacted LDAP server %s \n " , addr ) ) ;
2002-07-15 14:35:28 +04:00
2002-08-17 21:00:51 +04:00
if ( ! ads - > auth . kdc_server ) {
2007-10-25 01:16:54 +04:00
print_sockaddr ( addr , sizeof ( addr ) , & ads - > ldap . ss ) ;
2022-06-13 18:03:01 +03:00
ads - > auth . kdc_server = talloc_strdup ( ads , addr ) ;
if ( ads - > auth . kdc_server = = NULL ) {
status = ADS_ERROR_NT ( NT_STATUS_NO_MEMORY ) ;
goto out ;
}
2002-08-17 21:00:51 +04:00
}
2006-05-12 19:17:35 +04:00
/* If the caller() requested no LDAP bind, then we are done */
2009-05-31 13:14:06 +04:00
2002-09-25 19:19:00 +04:00
if ( ads - > auth . flags & ADS_AUTH_NO_BIND ) {
2008-01-31 03:50:49 +03:00
status = ADS_SUCCESS ;
goto out ;
2002-08-17 21:00:51 +04:00
}
2007-07-18 11:45:16 +04:00
2024-01-30 12:27:58 +03:00
ads - > ldap_tls_data . mem_ctx = talloc_init ( " ads LDAP TLS connection memory " ) ;
if ( ! ads - > ldap_tls_data . mem_ctx ) {
status = ADS_ERROR_NT ( NT_STATUS_NO_MEMORY ) ;
goto out ;
}
2017-05-05 15:37:20 +03:00
ads - > ldap_wrap_data . mem_ctx = talloc_init ( " ads LDAP connection memory " ) ;
if ( ! ads - > ldap_wrap_data . mem_ctx ) {
2008-01-31 03:50:49 +03:00
status = ADS_ERROR_NT ( NT_STATUS_NO_MEMORY ) ;
goto out ;
2007-07-18 11:45:16 +04:00
}
2009-05-31 13:14:06 +04:00
2006-05-12 19:17:35 +04:00
/* Otherwise setup the TCP LDAP session */
2024-01-30 12:27:58 +03:00
if ( ads - > auth . flags & ADS_AUTH_SASL_LDAPS ) {
tls = true ;
ads - > ldap . port = 636 ;
} else if ( ads - > auth . flags & ADS_AUTH_SASL_STARTTLS ) {
tls = true ;
start_tls = true ;
ads - > ldap . port = 389 ;
} else {
ads - > ldap . port = 389 ;
}
2020-02-10 21:19:44 +03:00
ads - > ldap . ld = ldap_open_with_timeout ( ads - > config . ldap_server_name ,
2011-04-26 07:53:45 +04:00
& ads - > ldap . ss ,
2008-06-27 18:22:39 +04:00
ads - > ldap . port , lp_ldap_timeout ( ) ) ;
2008-01-04 23:56:57 +03:00
if ( ads - > ldap . ld = = NULL ) {
2008-01-31 03:50:49 +03:00
status = ADS_ERROR ( LDAP_OPERATIONS_ERROR ) ;
goto out ;
2006-05-12 19:17:35 +04:00
}
2008-01-05 00:06:15 +03:00
DEBUG ( 3 , ( " Connected to LDAP server %s \n " , ads - > config . ldap_server_name ) ) ;
2006-08-30 22:48:49 +04:00
2024-01-30 12:27:58 +03:00
ldap_set_option ( ads - > ldap . ld , LDAP_OPT_PROTOCOL_VERSION , & version ) ;
2024-01-30 12:27:58 +03:00
if ( start_tls ) {
unsigned int to = lp_ldap_connection_timeout ( ) ;
struct berval * rspdata = NULL ;
char * rspoid = NULL ;
int rc ;
if ( to ) {
/* Setup timeout */
gotalarm = 0 ;
CatchSignal ( SIGALRM , gotalarm_sig ) ;
alarm ( to ) ;
/* End setup timeout. */
}
rc = ldap_extended_operation_s ( ads - > ldap . ld ,
LDAP_EXOP_START_TLS ,
NULL ,
NULL ,
NULL ,
& rspoid ,
& rspdata ) ;
if ( gotalarm ! = 0 & & rc = = LDAP_SUCCESS ) {
rc = LDAP_TIMEOUT ;
}
if ( to ) {
/* Teardown timeout. */
alarm ( 0 ) ;
CatchSignal ( SIGALRM , SIG_IGN ) ;
}
if ( rspoid ! = NULL ) {
ldap_memfree ( rspoid ) ;
}
if ( rspdata ! = NULL ) {
ber_bvfree ( rspdata ) ;
}
if ( rc ! = LDAP_SUCCESS ) {
status = ADS_ERROR_LDAP ( rc ) ;
goto out ;
}
}
if ( tls ) {
unsigned int to = lp_ldap_connection_timeout ( ) ;
if ( to ) {
/* Setup timeout */
gotalarm = 0 ;
CatchSignal ( SIGALRM , gotalarm_sig ) ;
alarm ( to ) ;
/* End setup timeout. */
}
status = ads_setup_tls_wrapping ( & ads - > ldap_tls_data ,
ads - > ldap . ld ,
ads - > config . ldap_server_name ) ;
if ( to ) {
/* Teardown timeout. */
alarm ( 0 ) ;
CatchSignal ( SIGALRM , SIG_IGN ) ;
}
if ( ! ADS_ERR_OK ( status ) ) {
goto out ;
}
}
2006-09-05 10:32:46 +04:00
/* cache the successful connection for workgroup and realm */
2006-11-10 15:42:50 +03:00
if ( ads_closest_dc ( ads ) ) {
2008-10-27 21:39:30 +03:00
saf_store ( ads - > server . workgroup , ads - > config . ldap_server_name ) ;
saf_store ( ads - > server . realm , ads - > config . ldap_server_name ) ;
2006-09-15 18:18:52 +04:00
}
2006-08-30 22:48:49 +04:00
2006-05-12 19:17:35 +04:00
/* fill in the current time and offsets */
2009-05-31 13:14:06 +04:00
2006-05-12 19:17:35 +04:00
status = ads_current_time ( ads ) ;
if ( ! ADS_ERR_OK ( status ) ) {
2008-01-31 03:50:49 +03:00
goto out ;
2006-05-12 19:17:35 +04:00
}
2002-08-17 21:00:51 +04:00
2006-05-12 19:17:35 +04:00
/* Now do the bind */
2009-05-31 13:14:06 +04:00
2002-10-01 22:26:00 +04:00
if ( ads - > auth . flags & ADS_AUTH_ANON_BIND ) {
2008-01-31 03:50:49 +03:00
status = ADS_ERROR ( ldap_simple_bind_s ( ads - > ldap . ld , NULL , NULL ) ) ;
goto out ;
2002-10-01 22:26:00 +04:00
}
2022-04-27 14:11:26 +03:00
status = ads_sasl_bind ( ads , creds ) ;
2008-01-31 03:50:49 +03:00
out :
if ( DEBUGLEVEL > = 11 ) {
char * s = NDR_PRINT_STRUCT_STRING ( talloc_tos ( ) , ads_struct , ads ) ;
DEBUG ( 11 , ( " ads_connect: leaving with: %s \n " ,
ads_errstr ( status ) ) ) ;
DEBUGADD ( 11 , ( " %s \n " , s ) ) ;
TALLOC_FREE ( s ) ;
2002-10-01 22:26:00 +04:00
}
2008-01-31 03:50:49 +03:00
return status ;
2001-11-20 11:54:15 +03:00
}
2024-03-05 19:45:35 +03:00
/**
* Connect to the LDAP server using without a bind
* and without a tcp connection at all
*
* @ param ads Pointer to an existing ADS_STRUCT
* @ return status of connection
* */
ADS_STATUS ads_connect_cldap_only ( ADS_STRUCT * ads )
{
ads - > auth . flags | = ADS_AUTH_NO_BIND ;
return ads_connect_internal ( ads , NULL ) ;
}
2022-04-27 14:11:26 +03:00
/**
* Connect to the LDAP server
* @ param ads Pointer to an existing ADS_STRUCT
* @ return status of connection
* */
ADS_STATUS ads_connect_creds ( ADS_STRUCT * ads , struct cli_credentials * creds )
{
SMB_ASSERT ( creds ! = NULL ) ;
/*
* We allow upgrades from
* ADS_AUTH_NO_BIND if credentials
* are specified
*/
ads - > auth . flags & = ~ ADS_AUTH_NO_BIND ;
/*
* We allow upgrades from ADS_AUTH_ANON_BIND ,
* as we don ' t want to use simple binds with
* non - anon credentials
*/
if ( ! cli_credentials_is_anonymous ( creds ) ) {
ads - > auth . flags & = ~ ADS_AUTH_ANON_BIND ;
}
return ads_connect_internal ( ads , creds ) ;
}
2022-04-28 19:38:17 +03:00
/**
* Connect to the LDAP server using anonymous credentials
* using a simple bind without username / password
*
* @ param ads Pointer to an existing ADS_STRUCT
* @ return status of connection
* */
ADS_STATUS ads_connect_simple_anon ( ADS_STRUCT * ads )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct cli_credentials * creds = NULL ;
ADS_STATUS status ;
creds = cli_credentials_init_anon ( frame ) ;
if ( creds = = NULL ) {
TALLOC_FREE ( frame ) ;
return ADS_ERROR_SYSTEM ( errno ) ;
}
ads - > auth . flags | = ADS_AUTH_ANON_BIND ;
status = ads_connect_creds ( ads , creds ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
2022-04-28 19:53:03 +03:00
/**
* Connect to the LDAP server using the machine account
* @ param ads Pointer to an existing ADS_STRUCT
* @ return status of connection
* */
ADS_STATUS ads_connect_machine ( ADS_STRUCT * ads )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct cli_credentials * creds = NULL ;
ADS_STATUS status ;
NTSTATUS ntstatus ;
ntstatus = pdb_get_trust_credentials ( ads - > server . workgroup ,
ads - > server . realm ,
frame ,
& creds ) ;
if ( ! NT_STATUS_IS_OK ( ntstatus ) ) {
TALLOC_FREE ( frame ) ;
return ADS_ERROR_NT ( ntstatus ) ;
}
status = ads_connect_creds ( ads , creds ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
2022-04-27 14:11:26 +03:00
/*
2020-08-08 06:18:50 +03:00
* Zero out the internal ads - > ldap struct and initialize the address to zero IP .
* @ param ads Pointer to an existing ADS_STRUCT
*
* Sets the ads - > ldap . ss to a valid
* zero ip address that can be detected by
* our is_zero_addr ( ) function . Otherwise
* it is left as AF_UNSPEC ( 0 ) .
* */
void ads_zero_ldap ( ADS_STRUCT * ads )
{
ZERO_STRUCT ( ads - > ldap ) ;
/*
* Initialize the sockaddr_storage so we can use
* sockaddr test functions against it .
*/
zero_sockaddr ( & ads - > ldap . ss ) ;
}
2007-07-16 13:48:15 +04:00
/**
* Disconnect the LDAP server
* @ param ads Pointer to an existing ADS_STRUCT
* */
void ads_disconnect ( ADS_STRUCT * ads )
{
2007-07-16 15:08:00 +04:00
if ( ads - > ldap . ld ) {
ldap_unbind ( ads - > ldap . ld ) ;
ads - > ldap . ld = NULL ;
2007-07-16 13:48:15 +04:00
}
2024-01-30 12:27:58 +03:00
if ( ads - > ldap_tls_data . mem_ctx ) {
talloc_free ( ads - > ldap_tls_data . mem_ctx ) ;
}
2017-05-05 15:37:20 +03:00
if ( ads - > ldap_wrap_data . wrap_ops & &
ads - > ldap_wrap_data . wrap_ops - > disconnect ) {
ads - > ldap_wrap_data . wrap_ops - > disconnect ( & ads - > ldap_wrap_data ) ;
2007-07-18 11:45:16 +04:00
}
2017-05-05 15:37:20 +03:00
if ( ads - > ldap_wrap_data . mem_ctx ) {
talloc_free ( ads - > ldap_wrap_data . mem_ctx ) ;
2007-07-18 11:45:16 +04:00
}
2020-08-08 06:24:07 +03:00
ads_zero_ldap ( ads ) ;
2024-01-30 12:27:58 +03:00
ZERO_STRUCT ( ads - > ldap_tls_data ) ;
2017-05-05 15:37:20 +03:00
ZERO_STRUCT ( ads - > ldap_wrap_data ) ;
2007-07-16 13:48:15 +04:00
}
2002-07-15 14:35:28 +04:00
/*
Duplicate a struct berval into talloc ' ed memory
*/
static struct berval * dup_berval ( TALLOC_CTX * ctx , const struct berval * in_val )
{
struct berval * value ;
if ( ! in_val ) return NULL ;
2011-06-07 05:44:43 +04:00
value = talloc_zero ( ctx , struct berval ) ;
2002-12-31 02:55:53 +03:00
if ( value = = NULL )
return NULL ;
2002-07-15 14:35:28 +04:00
if ( in_val - > bv_len = = 0 ) return value ;
value - > bv_len = in_val - > bv_len ;
2011-06-07 06:13:26 +04:00
value - > bv_val = ( char * ) talloc_memdup ( ctx , in_val - > bv_val ,
2006-09-04 01:07:16 +04:00
in_val - > bv_len ) ;
2002-07-15 14:35:28 +04:00
return value ;
}
/*
Make a values list out of an array of ( struct berval * )
*/
2022-06-22 21:53:42 +03:00
static struct berval * * ads_dup_values ( TALLOC_CTX * ctx ,
2002-07-15 14:35:28 +04:00
const struct berval * * in_vals )
{
struct berval * * values ;
int i ;
2009-05-31 13:14:06 +04:00
2002-07-15 14:35:28 +04:00
if ( ! in_vals ) return NULL ;
2004-12-07 21:25:53 +03:00
for ( i = 0 ; in_vals [ i ] ; i + + )
; /* count values */
2011-06-07 05:58:39 +04:00
values = talloc_zero_array ( ctx , struct berval * , i + 1 ) ;
2002-07-15 14:35:28 +04:00
if ( ! values ) return NULL ;
for ( i = 0 ; in_vals [ i ] ; i + + ) {
values [ i ] = dup_berval ( ctx , in_vals [ i ] ) ;
}
return values ;
}
/*
UTF8 - encode a values list out of an array of ( char * )
*/
static char * * ads_push_strvals ( TALLOC_CTX * ctx , const char * * in_vals )
{
char * * values ;
int i ;
2008-04-30 01:36:24 +04:00
size_t size ;
2002-07-15 14:35:28 +04:00
if ( ! in_vals ) return NULL ;
2004-12-07 21:25:53 +03:00
for ( i = 0 ; in_vals [ i ] ; i + + )
; /* count values */
2011-06-07 05:58:39 +04:00
values = talloc_zero_array ( ctx , char * , i + 1 ) ;
2002-07-15 14:35:28 +04:00
if ( ! values ) return NULL ;
for ( i = 0 ; in_vals [ i ] ; i + + ) {
2008-04-30 01:36:24 +04:00
if ( ! push_utf8_talloc ( ctx , & values [ i ] , in_vals [ i ] , & size ) ) {
2008-03-15 01:26:28 +03:00
TALLOC_FREE ( values ) ;
return NULL ;
}
2002-07-15 14:35:28 +04:00
}
return values ;
}
/*
Pull a ( char * ) array out of a UTF8 - encoded values list
*/
static char * * ads_pull_strvals ( TALLOC_CTX * ctx , const char * * in_vals )
{
char * * values ;
int i ;
2008-04-30 01:36:24 +04:00
size_t converted_size ;
2009-05-31 13:14:06 +04:00
2002-07-15 14:35:28 +04:00
if ( ! in_vals ) return NULL ;
2004-12-07 21:25:53 +03:00
for ( i = 0 ; in_vals [ i ] ; i + + )
; /* count values */
2011-06-07 05:58:39 +04:00
values = talloc_zero_array ( ctx , char * , i + 1 ) ;
2002-07-15 14:35:28 +04:00
if ( ! values ) return NULL ;
for ( i = 0 ; in_vals [ i ] ; i + + ) {
2008-04-30 01:36:24 +04:00
if ( ! pull_utf8_talloc ( ctx , & values [ i ] , in_vals [ i ] ,
& converted_size ) ) {
DEBUG ( 0 , ( " ads_pull_strvals: pull_utf8_talloc failed: "
2023-08-07 07:36:27 +03:00
" %s \n " , strerror ( errno ) ) ) ;
2008-04-30 01:36:24 +04:00
}
2002-07-15 14:35:28 +04:00
}
return values ;
}
2002-03-19 15:58:38 +03:00
2002-04-10 17:28:03 +04:00
/**
* Do a search with paged results . cookie must be null on the first
* call , and then returned on each subsequent call . It will be null
2022-06-22 21:53:42 +03:00
* again when the entire search is complete
* @ param ads connection to ads server
2002-04-10 17:28:03 +04:00
* @ param bind_path Base dn for the search
2003-07-03 08:12:54 +04:00
* @ param scope Scope of search ( LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE )
2003-04-15 21:06:51 +04:00
* @ param expr Search expression - specified in local charset
2002-07-15 14:35:28 +04:00
* @ param attrs Attributes to retrieve - specified in utf8 or ascii
2002-04-10 17:28:03 +04:00
* @ param res * * which will contain results - free res * with ads_msgfree ( )
* @ param count Number of entries retrieved on this page
* @ param cookie The paged results cookie to be returned on subsequent calls
* @ return status of search
* */
2006-09-04 01:07:16 +04:00
static ADS_STATUS ads_do_paged_search_args ( ADS_STRUCT * ads ,
const char * bind_path ,
int scope , const char * expr ,
const char * * attrs , void * args ,
2022-06-22 21:53:42 +03:00
LDAPMessage * * res ,
2006-09-04 01:07:16 +04:00
int * count , struct berval * * cookie )
2002-03-14 20:48:26 +03:00
{
2002-07-15 14:35:28 +04:00
int rc , i , version ;
2008-10-13 02:40:57 +04:00
char * utf8_expr , * utf8_path , * * search_attrs = NULL ;
2008-04-30 01:36:24 +04:00
size_t converted_size ;
2007-05-11 16:52:48 +04:00
LDAPControl PagedResults , NoReferrals , ExternalCtrl , * controls [ 4 ] , * * rcontrols ;
2002-04-10 17:28:03 +04:00
BerElement * cookie_be = NULL ;
struct berval * cookie_bv = NULL ;
2007-05-11 16:52:48 +04:00
BerElement * ext_be = NULL ;
struct berval * ext_bv = NULL ;
2006-05-18 23:34:25 +04:00
2002-07-15 14:35:28 +04:00
TALLOC_CTX * ctx ;
2006-05-18 23:34:25 +04:00
ads_control * external_control = ( ads_control * ) args ;
2002-03-14 20:48:26 +03:00
* res = NULL ;
2006-05-18 23:34:25 +04:00
if ( ! ( ctx = talloc_init ( " ads_do_paged_search_args " ) ) )
2002-07-15 14:35:28 +04:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
2002-03-14 20:48:26 +03:00
2022-06-22 21:53:42 +03:00
/* 0 means the conversion worked but the result was empty
so we only fail if it ' s - 1. In any case , it always
2002-07-15 14:35:28 +04:00
at least nulls out the dest */
2008-04-30 01:36:24 +04:00
if ( ! push_utf8_talloc ( ctx , & utf8_expr , expr , & converted_size ) | |
! push_utf8_talloc ( ctx , & utf8_path , bind_path , & converted_size ) )
{
2002-07-15 14:35:28 +04:00
rc = LDAP_NO_MEMORY ;
goto done ;
}
if ( ! attrs | | ! ( * attrs ) )
search_attrs = NULL ;
else {
/* This would be the utf8-encoded version...*/
/* if (!(search_attrs = ads_push_strvals(ctx, attrs))) */
2008-10-12 02:56:56 +04:00
if ( ! ( search_attrs = str_list_copy ( talloc_tos ( ) , attrs ) ) ) {
2002-07-15 14:35:28 +04:00
rc = LDAP_NO_MEMORY ;
goto done ;
}
}
2009-05-31 13:14:06 +04:00
2002-07-15 14:35:28 +04:00
/* Paged results only available on ldap v3 or later */
2007-07-16 15:08:00 +04:00
ldap_get_option ( ads - > ldap . ld , LDAP_OPT_PROTOCOL_VERSION , & version ) ;
2002-07-15 14:35:28 +04:00
if ( version < LDAP_VERSION3 ) {
rc = LDAP_NOT_SUPPORTED ;
goto done ;
}
2002-03-14 20:48:26 +03:00
2002-04-05 23:26:52 +04:00
cookie_be = ber_alloc_t ( LBER_USE_DER ) ;
2006-08-29 05:04:25 +04:00
if ( * cookie ) {
2012-05-18 16:01:14 +04:00
ber_printf ( cookie_be , " {iO} " , ( ber_int_t ) ads - > config . ldap_page_size , * cookie ) ;
2002-03-14 20:48:26 +03:00
ber_bvfree ( * cookie ) ; /* don't need it from last time */
2002-03-20 01:14:53 +03:00
* cookie = NULL ;
2002-03-14 20:48:26 +03:00
} else {
2012-05-18 16:01:14 +04:00
ber_printf ( cookie_be , " {io} " , ( ber_int_t ) ads - > config . ldap_page_size , " " , 0 ) ;
2002-03-14 20:48:26 +03:00
}
2002-04-05 23:26:52 +04:00
ber_flatten ( cookie_be , & cookie_bv ) ;
2011-05-06 01:36:55 +04:00
PagedResults . ldctl_oid = discard_const_p ( char , ADS_PAGE_CTL_OID ) ;
2002-03-27 06:09:50 +03:00
PagedResults . ldctl_iscritical = ( char ) 1 ;
2002-04-05 23:26:52 +04:00
PagedResults . ldctl_value . bv_len = cookie_bv - > bv_len ;
PagedResults . ldctl_value . bv_val = cookie_bv - > bv_val ;
2002-03-27 05:58:58 +03:00
2011-05-06 01:36:55 +04:00
NoReferrals . ldctl_oid = discard_const_p ( char , ADS_NO_REFERRALS_OID ) ;
2002-03-27 05:58:58 +03:00
NoReferrals . ldctl_iscritical = ( char ) 0 ;
NoReferrals . ldctl_value . bv_len = 0 ;
2011-05-06 01:36:55 +04:00
NoReferrals . ldctl_value . bv_val = discard_const_p ( char , " " ) ;
2002-03-27 05:58:58 +03:00
2022-06-22 21:53:42 +03:00
if ( external_control & &
( strequal ( external_control - > control , ADS_EXTENDED_DN_OID ) | |
2007-05-11 16:52:48 +04:00
strequal ( external_control - > control , ADS_SD_FLAGS_OID ) ) ) {
2006-05-18 23:34:25 +04:00
2011-05-06 01:36:55 +04:00
ExternalCtrl . ldctl_oid = discard_const_p ( char , external_control - > control ) ;
2007-05-11 16:52:48 +04:00
ExternalCtrl . ldctl_iscritical = ( char ) external_control - > critical ;
2006-05-18 23:34:25 +04:00
2023-07-05 12:21:39 +03:00
/* win2k does not accept a ldctl_value being passed in */
2006-05-18 23:34:25 +04:00
if ( external_control - > val ! = 0 ) {
2007-05-11 16:52:48 +04:00
if ( ( ext_be = ber_alloc_t ( LBER_USE_DER ) ) = = NULL ) {
2006-05-18 23:34:25 +04:00
rc = LDAP_NO_MEMORY ;
goto done ;
}
2007-05-11 16:52:48 +04:00
if ( ( ber_printf ( ext_be , " {i} " , ( ber_int_t ) external_control - > val ) ) = = - 1 ) {
2006-05-18 23:34:25 +04:00
rc = LDAP_NO_MEMORY ;
goto done ;
}
2007-05-11 17:19:49 +04:00
if ( ( ber_flatten ( ext_be , & ext_bv ) ) = = - 1 ) {
2006-05-18 23:34:25 +04:00
rc = LDAP_NO_MEMORY ;
goto done ;
}
2007-05-11 16:52:48 +04:00
ExternalCtrl . ldctl_value . bv_len = ext_bv - > bv_len ;
ExternalCtrl . ldctl_value . bv_val = ext_bv - > bv_val ;
2006-05-18 23:34:25 +04:00
} else {
2007-05-11 16:52:48 +04:00
ExternalCtrl . ldctl_value . bv_len = 0 ;
ExternalCtrl . ldctl_value . bv_val = NULL ;
2006-05-18 23:34:25 +04:00
}
2002-04-05 23:26:52 +04:00
2006-05-18 23:34:25 +04:00
controls [ 0 ] = & NoReferrals ;
controls [ 1 ] = & PagedResults ;
2007-05-11 16:52:48 +04:00
controls [ 2 ] = & ExternalCtrl ;
2006-05-18 23:34:25 +04:00
controls [ 3 ] = NULL ;
} else {
controls [ 0 ] = & NoReferrals ;
controls [ 1 ] = & PagedResults ;
controls [ 2 ] = NULL ;
}
2002-03-14 20:48:26 +03:00
2002-03-19 15:58:38 +03:00
/* we need to disable referrals as the openldap libs don't
2002-07-15 14:35:28 +04:00
handle them and paged results at the same time . Using them
2022-06-22 21:53:42 +03:00
together results in the result record containing the server
page control being removed from the result list ( tridge / jmcd )
2009-05-31 13:14:06 +04:00
2002-03-27 05:58:58 +03:00
leaving this in despite the control that says don ' t generate
referrals , in case the server doesn ' t support it ( jmcd )
*/
2007-07-16 15:08:00 +04:00
ldap_set_option ( ads - > ldap . ld , LDAP_OPT_REFERRALS , LDAP_OPT_OFF ) ;
2002-03-19 15:58:38 +03:00
2022-06-22 21:53:42 +03:00
rc = ldap_search_with_timeout ( ads - > ldap . ld , utf8_path , scope , utf8_expr ,
2004-11-18 14:43:14 +03:00
search_attrs , 0 , controls ,
2005-01-11 05:13:03 +03:00
NULL , LDAP_NO_LIMIT ,
2004-11-18 14:43:14 +03:00
( LDAPMessage * * ) res ) ;
2002-03-19 15:58:38 +03:00
2002-04-05 23:26:52 +04:00
ber_free ( cookie_be , 1 ) ;
ber_bvfree ( cookie_bv ) ;
2002-03-19 15:58:38 +03:00
if ( rc ) {
2006-05-18 23:34:25 +04:00
DEBUG ( 3 , ( " ads_do_paged_search_args: ldap_search_with_timeout(%s) -> %s \n " , expr ,
2004-11-18 14:43:14 +03:00
ldap_err2string ( rc ) ) ) ;
2013-06-12 12:07:22 +04:00
if ( rc = = LDAP_OTHER ) {
char * ldap_errmsg ;
int ret ;
ret = ldap_parse_result ( ads - > ldap . ld ,
* res ,
NULL ,
NULL ,
& ldap_errmsg ,
NULL ,
NULL ,
0 ) ;
if ( ret = = LDAP_SUCCESS ) {
DEBUG ( 3 , ( " ldap_search_with_timeout(%s) "
" error: %s \n " , expr , ldap_errmsg ) ) ;
ldap_memfree ( ldap_errmsg ) ;
}
}
2002-07-15 14:35:28 +04:00
goto done ;
2002-03-19 15:58:38 +03:00
}
2007-07-16 15:08:00 +04:00
rc = ldap_parse_result ( ads - > ldap . ld , * res , NULL , NULL , NULL ,
2002-03-14 20:48:26 +03:00
NULL , & rcontrols , 0 ) ;
2002-03-19 15:58:38 +03:00
if ( ! rcontrols ) {
2002-07-15 14:35:28 +04:00
goto done ;
2002-03-19 15:58:38 +03:00
}
2002-04-05 23:26:52 +04:00
for ( i = 0 ; rcontrols [ i ] ; i + + ) {
if ( strcmp ( ADS_PAGE_CTL_OID , rcontrols [ i ] - > ldctl_oid ) = = 0 ) {
cookie_be = ber_init ( & rcontrols [ i ] - > ldctl_value ) ;
ber_scanf ( cookie_be , " {iO} " , ( ber_int_t * ) count ,
& cookie_bv ) ;
2002-03-14 20:48:26 +03:00
/* the berval is the cookie, but must be freed when
it is all done */
2002-04-05 23:26:52 +04:00
if ( cookie_bv - > bv_len ) /* still more to do */
* cookie = ber_bvdup ( cookie_bv ) ;
2002-03-14 20:48:26 +03:00
else
* cookie = NULL ;
2002-04-05 23:26:52 +04:00
ber_bvfree ( cookie_bv ) ;
ber_free ( cookie_be , 1 ) ;
2002-03-14 20:48:26 +03:00
break ;
}
}
ldap_controls_free ( rcontrols ) ;
2002-07-15 14:35:28 +04:00
done :
talloc_destroy ( ctx ) ;
2006-05-18 23:34:25 +04:00
2007-05-11 16:52:48 +04:00
if ( ext_be ) {
ber_free ( ext_be , 1 ) ;
2006-05-18 23:34:25 +04:00
}
2007-05-11 16:52:48 +04:00
if ( ext_bv ) {
ber_bvfree ( ext_bv ) ;
2006-05-18 23:34:25 +04:00
}
2009-05-31 13:14:06 +04:00
2016-10-05 11:33:26 +03:00
if ( rc ! = LDAP_SUCCESS & & * res ! = NULL ) {
ads_msgfree ( ads , * res ) ;
* res = NULL ;
}
2002-07-15 14:35:28 +04:00
/* if/when we decide to utf8-encode attrs, take out this next line */
2008-02-04 23:05:41 +03:00
TALLOC_FREE ( search_attrs ) ;
2002-07-15 14:35:28 +04:00
2002-03-14 20:48:26 +03:00
return ADS_ERROR ( rc ) ;
}
2006-09-04 01:07:16 +04:00
static ADS_STATUS ads_do_paged_search ( ADS_STRUCT * ads , const char * bind_path ,
int scope , const char * expr ,
2022-06-22 21:53:42 +03:00
const char * * attrs , LDAPMessage * * res ,
2006-09-04 01:07:16 +04:00
int * count , struct berval * * cookie )
2006-05-18 23:34:25 +04:00
{
return ads_do_paged_search_args ( ads , bind_path , scope , expr , attrs , NULL , res , count , cookie ) ;
}
2002-03-20 01:14:53 +03:00
2002-04-10 17:28:03 +04:00
/**
2022-06-22 21:53:42 +03:00
* Get all results for a search . This uses ads_do_paged_search ( ) to return
2002-04-10 17:28:03 +04:00
* all entries in a large search .
2022-06-22 21:53:42 +03:00
* @ param ads connection to ads server
2002-04-10 17:28:03 +04:00
* @ param bind_path Base dn for the search
2003-07-03 08:12:54 +04:00
* @ param scope Scope of search ( LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE )
2003-04-15 21:06:51 +04:00
* @ param expr Search expression
2002-04-10 17:28:03 +04:00
* @ param attrs Attributes to retrieve
* @ param res * * which will contain results - free res * with ads_msgfree ( )
* @ return status of search
* */
2006-09-04 01:07:16 +04:00
ADS_STATUS ads_do_search_all_args ( ADS_STRUCT * ads , const char * bind_path ,
int scope , const char * expr ,
const char * * attrs , void * args ,
LDAPMessage * * res )
2002-03-20 01:14:53 +03:00
{
2006-09-04 01:07:16 +04:00
struct berval * cookie = NULL ;
2002-03-20 01:14:53 +03:00
int count = 0 ;
ADS_STATUS status ;
2004-11-15 21:57:22 +03:00
* res = NULL ;
2006-05-18 23:34:25 +04:00
status = ads_do_paged_search_args ( ads , bind_path , scope , expr , attrs , args , res ,
2002-04-10 17:28:03 +04:00
& count , & cookie ) ;
2002-03-20 01:14:53 +03:00
2022-06-22 21:53:42 +03:00
if ( ! ADS_ERR_OK ( status ) )
2005-11-22 20:15:28 +03:00
return status ;
2002-03-20 01:14:53 +03:00
2005-11-22 20:15:28 +03:00
# ifdef HAVE_LDAP_ADD_RESULT_ENTRY
2002-03-20 01:14:53 +03:00
while ( cookie ) {
2006-09-04 01:07:16 +04:00
LDAPMessage * res2 = NULL ;
2002-03-20 01:14:53 +03:00
LDAPMessage * msg , * next ;
2014-01-22 04:25:41 +04:00
status = ads_do_paged_search_args ( ads , bind_path , scope , expr ,
2006-05-18 23:34:25 +04:00
attrs , args , & res2 , & count , & cookie ) ;
2014-01-22 04:25:41 +04:00
if ( ! ADS_ERR_OK ( status ) ) {
break ;
}
2002-03-20 01:14:53 +03:00
/* this relies on the way that ldap_add_result_entry() works internally. I hope
that this works on all ldap libs , but I have only tested with openldap */
2008-04-26 05:34:46 +04:00
for ( msg = ads_first_message ( ads , res2 ) ; msg ; msg = next ) {
next = ads_next_message ( ads , msg ) ;
2002-03-20 01:14:53 +03:00
ldap_add_result_entry ( ( LDAPMessage * * ) res , msg ) ;
}
/* note that we do not free res2, as the memory is now
part of the main returned list */
}
2005-11-22 20:15:28 +03:00
# else
DEBUG ( 0 , ( " no ldap_add_result_entry() support in LDAP libs! \n " ) ) ;
status = ADS_ERROR_NT ( NT_STATUS_UNSUCCESSFUL ) ;
# endif
2002-03-20 01:14:53 +03:00
return status ;
}
2006-09-04 01:07:16 +04:00
ADS_STATUS ads_do_search_all ( 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_all_args ( ads , bind_path , scope , expr , attrs , NULL , res ) ;
}
2007-05-11 16:52:48 +04:00
ADS_STATUS ads_do_search_all_sd_flags ( ADS_STRUCT * ads , const char * bind_path ,
int scope , const char * expr ,
2022-06-22 21:53:42 +03:00
const char * * attrs , uint32_t sd_flags ,
2007-05-11 16:52:48 +04:00
LDAPMessage * * res )
{
ads_control args ;
args . control = ADS_SD_FLAGS_OID ;
args . val = sd_flags ;
args . critical = True ;
return ads_do_search_all_args ( ads , bind_path , scope , expr , attrs , & args , res ) ;
}
2002-04-10 17:28:03 +04:00
/**
* Run a function on all results for a search . Uses ads_do_paged_search ( ) and
* runs the function as each page is returned , using ads_process_results ( )
* @ param ads connection to ads server
* @ param bind_path Base dn for the search
2003-07-03 08:12:54 +04:00
* @ param scope Scope of search ( LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE )
2003-04-15 21:06:51 +04:00
* @ param expr Search expression - specified in local charset
2002-07-15 14:35:28 +04:00
* @ param attrs Attributes to retrieve - specified in UTF - 8 or ascii
2002-04-10 17:28:03 +04:00
* @ param fn Function which takes attr name , values list , and data_area
* @ param data_area Pointer which is passed to function on each call
* @ return status of search
* */
ADS_STATUS ads_do_search_all_fn ( ADS_STRUCT * ads , const char * bind_path ,
2003-04-15 21:06:51 +04:00
int scope , const char * expr , const char * * attrs ,
2022-06-22 21:53:42 +03:00
bool ( * fn ) ( ADS_STRUCT * , char * , void * * , void * ) ,
2002-04-10 17:28:03 +04:00
void * data_area )
2002-04-05 23:26:52 +04:00
{
2006-09-04 01:07:16 +04:00
struct berval * cookie = NULL ;
2002-04-05 23:26:52 +04:00
int count = 0 ;
ADS_STATUS status ;
2006-09-04 01:07:16 +04:00
LDAPMessage * res ;
2002-04-05 23:26:52 +04:00
2003-04-15 21:06:51 +04:00
status = ads_do_paged_search ( ads , bind_path , scope , expr , attrs , & res ,
2002-04-10 17:28:03 +04:00
& count , & cookie ) ;
2002-04-05 23:26:52 +04:00
if ( ! ADS_ERR_OK ( status ) ) return status ;
ads_process_results ( ads , res , fn , data_area ) ;
ads_msgfree ( ads , res ) ;
while ( cookie ) {
2003-04-15 21:06:51 +04:00
status = ads_do_paged_search ( ads , bind_path , scope , expr , attrs ,
2002-04-10 17:28:03 +04:00
& res , & count , & cookie ) ;
2002-04-05 23:26:52 +04:00
if ( ! ADS_ERR_OK ( status ) ) break ;
2009-05-31 13:14:06 +04:00
2002-04-05 23:26:52 +04:00
ads_process_results ( ads , res , fn , data_area ) ;
ads_msgfree ( ads , res ) ;
}
return status ;
}
2002-04-10 17:28:03 +04:00
/**
* Do a search with a timeout .
* @ param ads connection to ads server
* @ param bind_path Base dn for the search
2003-07-03 08:12:54 +04:00
* @ param scope Scope of search ( LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE )
2003-04-15 21:06:51 +04:00
* @ param expr Search expression
2002-04-10 17:28:03 +04:00
* @ param attrs Attributes to retrieve
* @ param res * * which will contain results - free res * with ads_msgfree ( )
* @ return status of search
* */
2022-06-22 21:53:42 +03:00
ADS_STATUS ads_do_search ( ADS_STRUCT * ads , const char * bind_path , int scope ,
2006-09-04 01:07:16 +04:00
const char * expr ,
const char * * attrs , LDAPMessage * * res )
2001-12-05 12:19:25 +03:00
{
2001-12-19 15:21:12 +03:00
int rc ;
2003-04-15 21:06:51 +04:00
char * utf8_expr , * utf8_path , * * search_attrs = NULL ;
2008-04-30 01:36:24 +04:00
size_t converted_size ;
2002-07-15 14:35:28 +04:00
TALLOC_CTX * ctx ;
2004-11-15 21:57:22 +03:00
* res = NULL ;
2002-12-20 23:21:31 +03:00
if ( ! ( ctx = talloc_init ( " ads_do_search " ) ) ) {
2023-08-07 07:36:27 +03:00
DEBUG ( 1 , ( " ads_do_search: talloc_init() failed! \n " ) ) ;
2002-07-15 14:35:28 +04:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
2002-09-25 19:19:00 +04:00
}
2002-07-15 14:35:28 +04:00
2022-06-22 21:53:42 +03:00
/* 0 means the conversion worked but the result was empty
so we only fail if it ' s negative . In any case , it always
2002-07-15 14:35:28 +04:00
at least nulls out the dest */
2008-04-30 01:36:24 +04:00
if ( ! push_utf8_talloc ( ctx , & utf8_expr , expr , & converted_size ) | |
! push_utf8_talloc ( ctx , & utf8_path , bind_path , & converted_size ) )
{
2023-08-07 07:36:27 +03:00
DEBUG ( 1 , ( " ads_do_search: push_utf8_talloc() failed! \n " ) ) ;
2002-07-15 14:35:28 +04:00
rc = LDAP_NO_MEMORY ;
goto done ;
}
if ( ! attrs | | ! ( * attrs ) )
search_attrs = NULL ;
else {
/* This would be the utf8-encoded version...*/
/* if (!(search_attrs = ads_push_strvals(ctx, attrs))) */
2008-10-12 02:56:56 +04:00
if ( ! ( search_attrs = str_list_copy ( talloc_tos ( ) , attrs ) ) )
2002-07-15 14:35:28 +04:00
{
2023-08-07 07:36:27 +03:00
DEBUG ( 1 , ( " ads_do_search: str_list_copy() failed! \n " ) ) ;
2002-07-15 14:35:28 +04:00
rc = LDAP_NO_MEMORY ;
goto done ;
}
}
2001-12-05 12:19:25 +03:00
2002-07-15 14:35:28 +04:00
/* see the note in ads_do_paged_search - we *must* disable referrals */
2007-07-16 15:08:00 +04:00
ldap_set_option ( ads - > ldap . ld , LDAP_OPT_REFERRALS , LDAP_OPT_OFF ) ;
2002-07-15 14:35:28 +04:00
2007-07-16 15:08:00 +04:00
rc = ldap_search_with_timeout ( ads - > ldap . ld , utf8_path , scope , utf8_expr ,
2022-06-22 21:53:42 +03:00
search_attrs , 0 , NULL , NULL ,
2005-01-11 05:13:03 +03:00
LDAP_NO_LIMIT ,
2004-11-18 14:43:14 +03:00
( LDAPMessage * * ) res ) ;
2002-03-14 20:48:26 +03:00
2002-03-13 09:43:52 +03:00
if ( rc = = LDAP_SIZELIMIT_EXCEEDED ) {
DEBUG ( 3 , ( " Warning! sizelimit exceeded in ldap. Truncating. \n " ) ) ;
rc = 0 ;
}
2002-03-14 20:48:26 +03:00
2002-07-15 14:35:28 +04:00
done :
talloc_destroy ( ctx ) ;
/* if/when we decide to utf8-encode attrs, take out this next line */
2008-02-04 23:05:41 +03:00
TALLOC_FREE ( search_attrs ) ;
2001-12-19 15:21:12 +03:00
return ADS_ERROR ( rc ) ;
2001-12-05 12:19:25 +03:00
}
2002-04-10 17:28:03 +04:00
/**
* Do a general ADS search
* @ param ads connection to ads server
* @ param res * * which will contain results - free res * with ads_msgfree ( )
2003-04-15 21:06:51 +04:00
* @ param expr Search expression
2002-04-10 17:28:03 +04:00
* @ param attrs Attributes to retrieve
* @ return status of search
* */
2022-06-22 21:53:42 +03:00
ADS_STATUS ads_search ( ADS_STRUCT * ads , LDAPMessage * * res ,
2006-09-04 01:07:16 +04:00
const char * expr , const char * * attrs )
2001-11-25 04:31:07 +03:00
{
2022-06-22 21:53:42 +03:00
return ads_do_search ( ads , ads - > config . bind_path , LDAP_SCOPE_SUBTREE ,
2003-04-15 21:06:51 +04:00
expr , attrs , res ) ;
2001-11-25 04:31:07 +03:00
}
2002-04-10 17:28:03 +04:00
/**
* Do a search on a specific DistinguishedName
* @ param ads connection to ads server
* @ param res * * which will contain results - free res * with ads_msgfree ( )
2023-09-01 04:39:18 +03:00
* @ param dn DistinguishedName to search
2002-04-10 17:28:03 +04:00
* @ param attrs Attributes to retrieve
* @ return status of search
* */
2022-06-22 21:53:42 +03:00
ADS_STATUS ads_search_dn ( ADS_STRUCT * ads , LDAPMessage * * res ,
2006-09-04 01:07:16 +04:00
const char * dn , const char * * attrs )
2001-12-04 15:08:16 +03:00
{
2006-09-04 01:07:16 +04:00
return ads_do_search ( ads , dn , LDAP_SCOPE_BASE , " (objectclass=*) " ,
attrs , res ) ;
2001-12-04 15:08:16 +03:00
}
2002-04-10 17:28:03 +04:00
/**
* Free up memory from a ads_search
* @ param ads connection to ads server
* @ param msg Search results to free
* */
2006-09-04 01:07:16 +04:00
void ads_msgfree ( ADS_STRUCT * ads , LDAPMessage * msg )
2001-12-05 09:26:56 +03:00
{
if ( ! msg ) return ;
ldap_msgfree ( msg ) ;
}
2001-11-25 04:31:07 +03:00
2002-04-10 17:28:03 +04:00
/**
* Get a dn from search results
* @ param ads connection to ads server
2003-06-16 06:42:00 +04:00
* @ param msg Search result
2002-04-10 17:28:03 +04:00
* @ return dn string
* */
2009-03-18 09:35:03 +03:00
char * ads_get_dn ( ADS_STRUCT * ads , TALLOC_CTX * mem_ctx , LDAPMessage * msg )
2002-02-02 05:04:01 +03:00
{
2002-07-15 14:35:28 +04:00
char * utf8_dn , * unix_dn ;
2008-04-30 01:36:24 +04:00
size_t converted_size ;
2002-07-15 14:35:28 +04:00
2007-07-16 15:08:00 +04:00
utf8_dn = ldap_get_dn ( ads - > ldap . ld , msg ) ;
2003-06-16 06:42:00 +04:00
2003-09-11 02:33:06 +04:00
if ( ! utf8_dn ) {
DEBUG ( 5 , ( " ads_get_dn: ldap_get_dn failed \n " ) ) ;
return NULL ;
}
2009-03-18 09:35:03 +03:00
if ( ! pull_utf8_talloc ( mem_ctx , & unix_dn , utf8_dn , & converted_size ) ) {
2003-09-11 02:33:06 +04:00
DEBUG ( 0 , ( " ads_get_dn: string conversion failure utf8 [%s] \n " ,
utf8_dn ) ) ;
return NULL ;
}
2002-07-15 14:35:28 +04:00
ldap_memfree ( utf8_dn ) ;
return unix_dn ;
2002-02-02 05:04:01 +03:00
}
2006-02-04 01:19:41 +03:00
/**
* Get the parent from a dn
* @ param dn the dn to return the parent from
* @ return parent dn string
* */
char * ads_parent_dn ( const char * dn )
{
2006-06-18 13:45:18 +04:00
char * p ;
if ( dn = = NULL ) {
return NULL ;
}
p = strchr ( dn , ' , ' ) ;
2006-02-04 01:19:41 +03:00
if ( p = = NULL ) {
return NULL ;
}
return p + 1 ;
}
2002-04-10 17:28:03 +04:00
/**
* Find a machine account given a hostname
* @ param ads connection to ads server
* @ param res * * which will contain results - free res * with ads_msgfree ( )
* @ param host Hostname to search for
* @ return status of search
* */
2006-09-04 01:07:16 +04:00
ADS_STATUS ads_find_machine_acct ( ADS_STRUCT * ads , LDAPMessage * * res ,
const char * machine )
2001-11-20 11:54:15 +03:00
{
2001-12-19 15:21:12 +03:00
ADS_STATUS status ;
2003-04-15 21:06:51 +04:00
char * expr ;
2019-08-14 14:01:19 +03:00
const char * attrs [ ] = {
/* This is how Windows checks for machine accounts */
" objectClass " ,
" SamAccountName " ,
" userAccountControl " ,
" DnsHostName " ,
" ServicePrincipalName " ,
2020-04-03 16:58:28 +03:00
" userPrincipalName " ,
2019-08-14 14:01:19 +03:00
/* Additional attributes Samba checks */
2024-01-23 19:19:30 +03:00
" msDS-KeyVersionNumber " ,
2020-05-27 16:36:28 +03:00
" msDS-AdditionalDnsHostName " ,
2019-08-14 14:01:19 +03:00
" msDS-SupportedEncryptionTypes " ,
" nTSecurityDescriptor " ,
2021-02-13 20:20:53 +03:00
" objectSid " ,
2019-08-14 14:01:19 +03:00
NULL
} ;
2019-08-21 13:22:32 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2001-11-20 11:54:15 +03:00
2004-11-15 21:57:22 +03:00
* res = NULL ;
2001-11-20 11:54:15 +03:00
/* the easiest way to find a machine account anywhere in the tree
is to look for hostname $ */
2019-08-21 13:22:32 +03:00
expr = talloc_asprintf ( frame , " (samAccountName=%s$) " , machine ) ;
if ( expr = = NULL ) {
status = ADS_ERROR_NT ( NT_STATUS_NO_MEMORY ) ;
goto done ;
2002-10-01 22:26:00 +04:00
}
2009-05-31 13:14:06 +04:00
2003-04-15 21:06:51 +04:00
status = ads_search ( ads , res , expr , attrs ) ;
2019-08-14 14:01:19 +03:00
if ( ADS_ERR_OK ( status ) ) {
if ( ads_count_replies ( ads , * res ) ! = 1 ) {
status = ADS_ERROR_LDAP ( LDAP_NO_SUCH_OBJECT ) ;
}
}
2019-08-21 13:22:32 +03:00
done :
TALLOC_FREE ( frame ) ;
2001-12-19 15:21:12 +03:00
return status ;
2001-11-20 11:54:15 +03:00
}
2002-04-10 17:28:03 +04:00
/**
* Initialize a list of mods to be used in a modify request
* @ param ctx An initialized TALLOC_CTX
* @ return allocated ADS_MODLIST
* */
2002-02-12 21:22:33 +03:00
ADS_MODLIST ads_init_mods ( TALLOC_CTX * ctx )
2002-02-01 19:14:33 +03:00
{
2002-02-11 18:47:02 +03:00
# define ADS_MODLIST_ALLOC_SIZE 10
2002-02-01 19:14:33 +03:00
LDAPMod * * mods ;
2009-05-31 13:14:06 +04:00
2011-06-07 05:58:39 +04:00
if ( ( mods = talloc_zero_array ( ctx , LDAPMod * , ADS_MODLIST_ALLOC_SIZE + 1 ) ) )
2002-02-03 01:06:10 +03:00
/* -1 is safety to make sure we don't go over the end.
need to reset it to NULL before doing ldap modify */
2002-02-11 18:47:02 +03:00
mods [ ADS_MODLIST_ALLOC_SIZE ] = ( LDAPMod * ) - 1 ;
2009-05-31 13:14:06 +04:00
2005-03-22 19:39:09 +03:00
return ( ADS_MODLIST ) mods ;
2002-02-01 19:14:33 +03:00
}
2002-07-15 14:35:28 +04:00
2002-02-01 19:14:33 +03:00
/*
add an attribute to the list , with values list already constructed
*/
2022-06-22 21:53:42 +03:00
static ADS_STATUS ads_modlist_add ( TALLOC_CTX * ctx , ADS_MODLIST * mods ,
int mod_op , const char * name ,
2006-07-11 22:01:26 +04:00
const void * _invals )
2002-02-01 19:14:33 +03:00
{
int curmod ;
2002-02-11 18:47:02 +03:00
LDAPMod * * modlist = ( LDAPMod * * ) * mods ;
2003-02-24 06:43:49 +03:00
struct berval * * ber_values = NULL ;
char * * char_values = NULL ;
2002-07-15 14:35:28 +04:00
2014-02-26 23:16:26 +04:00
if ( ! _invals ) {
2002-07-15 14:35:28 +04:00
mod_op = LDAP_MOD_DELETE ;
} else {
2014-02-26 23:16:26 +04:00
if ( mod_op & LDAP_MOD_BVALUES ) {
const struct berval * * b ;
b = discard_const_p ( const struct berval * , _invals ) ;
ber_values = ads_dup_values ( ctx , b ) ;
} else {
const char * * c ;
c = discard_const_p ( const char * , _invals ) ;
char_values = ads_push_strvals ( ctx , c ) ;
}
2002-07-15 14:35:28 +04:00
}
2002-02-01 19:14:33 +03:00
/* find the first empty slot */
2002-02-06 05:28:46 +03:00
for ( curmod = 0 ; modlist [ curmod ] & & modlist [ curmod ] ! = ( LDAPMod * ) - 1 ;
curmod + + ) ;
2002-02-11 18:47:02 +03:00
if ( modlist [ curmod ] = = ( LDAPMod * ) - 1 ) {
2011-06-07 05:10:15 +04:00
if ( ! ( modlist = talloc_realloc ( ctx , modlist , LDAPMod * ,
2004-12-07 21:25:53 +03:00
curmod + ADS_MODLIST_ALLOC_SIZE + 1 ) ) )
2002-02-11 18:47:02 +03:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
2022-06-22 21:53:42 +03:00
memset ( & modlist [ curmod ] , 0 ,
2002-02-11 18:47:02 +03:00
ADS_MODLIST_ALLOC_SIZE * sizeof ( LDAPMod * ) ) ;
modlist [ curmod + ADS_MODLIST_ALLOC_SIZE ] = ( LDAPMod * ) - 1 ;
2005-03-22 19:39:09 +03:00
* mods = ( ADS_MODLIST ) modlist ;
2002-02-11 18:47:02 +03:00
}
2009-05-31 13:14:06 +04:00
2011-06-07 05:44:43 +04:00
if ( ! ( modlist [ curmod ] = talloc_zero ( ctx , LDAPMod ) ) )
2002-02-03 01:06:10 +03:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
2002-07-15 14:35:28 +04:00
modlist [ curmod ] - > mod_type = talloc_strdup ( ctx , name ) ;
2003-02-24 05:55:00 +03:00
if ( mod_op & LDAP_MOD_BVALUES ) {
modlist [ curmod ] - > mod_bvalues = ber_values ;
} else if ( mod_op & LDAP_MOD_DELETE ) {
modlist [ curmod ] - > mod_values = NULL ;
} else {
modlist [ curmod ] - > mod_values = char_values ;
}
2002-02-01 20:13:39 +03:00
modlist [ curmod ] - > mod_op = mod_op ;
2002-02-03 01:06:10 +03:00
return ADS_ERROR ( LDAP_SUCCESS ) ;
2002-02-01 19:14:33 +03:00
}
2002-04-10 17:28:03 +04:00
/**
2002-07-15 14:35:28 +04:00
* Add a single string value to a mod list
2002-04-10 17:28:03 +04:00
* @ param ctx An initialized TALLOC_CTX
* @ param mods An initialized ADS_MODLIST
* @ param name The attribute name to add
2002-07-15 14:35:28 +04:00
* @ param val The value to add - NULL means DELETE
2002-04-10 17:28:03 +04:00
* @ return ADS STATUS indicating success of add
* */
2022-06-22 21:53:42 +03:00
ADS_STATUS ads_mod_str ( TALLOC_CTX * ctx , ADS_MODLIST * mods ,
2002-07-15 14:35:28 +04:00
const char * name , const char * val )
2002-02-01 19:14:33 +03:00
{
2002-09-25 19:19:00 +04:00
const char * values [ 2 ] ;
values [ 0 ] = val ;
values [ 1 ] = NULL ;
2002-07-15 14:35:28 +04:00
if ( ! val )
2002-02-12 21:22:33 +03:00
return ads_modlist_add ( ctx , mods , LDAP_MOD_DELETE , name , NULL ) ;
2006-07-11 22:01:26 +04:00
return ads_modlist_add ( ctx , mods , LDAP_MOD_REPLACE , name , values ) ;
2002-02-01 19:14:33 +03:00
}
2002-04-10 17:28:03 +04:00
/**
2002-07-15 14:35:28 +04:00
* Add an array of string values to a mod list
2002-04-10 17:28:03 +04:00
* @ param ctx An initialized TALLOC_CTX
* @ param mods An initialized ADS_MODLIST
* @ param name The attribute name to add
2002-07-15 14:35:28 +04:00
* @ param vals The array of string values to add - NULL means DELETE
2002-04-10 17:28:03 +04:00
* @ return ADS STATUS indicating success of add
* */
2002-07-15 14:35:28 +04:00
ADS_STATUS ads_mod_strlist ( TALLOC_CTX * ctx , ADS_MODLIST * mods ,
const char * name , const char * * vals )
2002-02-03 01:06:10 +03:00
{
2002-07-15 14:35:28 +04:00
if ( ! vals )
return ads_modlist_add ( ctx , mods , LDAP_MOD_DELETE , name , NULL ) ;
2022-06-22 21:53:42 +03:00
return ads_modlist_add ( ctx , mods , LDAP_MOD_REPLACE ,
2002-07-15 14:35:28 +04:00
name , ( const void * * ) vals ) ;
2002-02-01 19:14:33 +03:00
}
2002-04-10 17:28:03 +04:00
/**
2002-07-15 14:35:28 +04:00
* Add a single ber - encoded value to a mod list
2002-04-10 17:28:03 +04:00
* @ param ctx An initialized TALLOC_CTX
* @ param mods An initialized ADS_MODLIST
* @ param name The attribute name to add
2002-07-15 14:35:28 +04:00
* @ param val The value to add - NULL means DELETE
2002-04-10 17:28:03 +04:00
* @ return ADS STATUS indicating success of add
* */
2022-06-22 21:53:42 +03:00
static ADS_STATUS ads_mod_ber ( TALLOC_CTX * ctx , ADS_MODLIST * mods ,
2002-07-15 14:35:28 +04:00
const char * name , const struct berval * val )
2002-02-12 21:22:33 +03:00
{
2002-09-25 19:19:00 +04:00
const struct berval * values [ 2 ] ;
values [ 0 ] = val ;
values [ 1 ] = NULL ;
2002-02-12 21:22:33 +03:00
if ( ! val )
2002-07-15 14:35:28 +04:00
return ads_modlist_add ( ctx , mods , LDAP_MOD_DELETE , name , NULL ) ;
return ads_modlist_add ( ctx , mods , LDAP_MOD_REPLACE | LDAP_MOD_BVALUES ,
2024-02-26 23:02:08 +03:00
name , ( const void * ) values ) ;
2002-02-01 19:14:33 +03:00
}
2016-03-04 19:42:05 +03:00
static void ads_print_error ( int ret , LDAP * ld )
{
if ( ret ! = 0 ) {
char * ld_error = NULL ;
ldap_get_option ( ld , LDAP_OPT_ERROR_STRING , & ld_error ) ;
2019-03-29 13:34:53 +03:00
DBG_ERR ( " AD LDAP ERROR: %d (%s): %s \n " ,
ret ,
ldap_err2string ( ret ) ,
ld_error ) ;
2016-03-04 19:42:05 +03:00
SAFE_FREE ( ld_error ) ;
}
}
2002-04-10 17:28:03 +04:00
/**
* Perform an ldap modify
* @ param ads connection to ads server
* @ param mod_dn DistinguishedName to modify
* @ param mods list of modifications to perform
* @ return status of modify
* */
2002-02-11 18:47:02 +03:00
ADS_STATUS ads_gen_mod ( ADS_STRUCT * ads , const char * mod_dn , ADS_MODLIST mods )
2002-02-01 19:14:33 +03:00
{
int ret , i ;
2002-07-15 14:35:28 +04:00
char * utf8_dn = NULL ;
2008-04-30 01:36:24 +04:00
size_t converted_size ;
2022-06-22 21:53:42 +03:00
/*
this control is needed to modify that contains a currently
2002-02-06 05:28:46 +03:00
non - existent attribute ( but allowable for the object ) to run
2002-02-03 01:06:10 +03:00
*/
2002-02-06 05:28:46 +03:00
LDAPControl PermitModify = {
2011-05-06 01:36:55 +04:00
discard_const_p ( char , ADS_PERMIT_MODIFY_OID ) ,
2002-02-06 05:28:46 +03:00
{ 0 , NULL } ,
( char ) 1 } ;
2002-03-04 04:07:02 +03:00
LDAPControl * controls [ 2 ] ;
2019-03-29 13:34:53 +03:00
DBG_INFO ( " AD LDAP: Modifying %s \n " , mod_dn ) ;
2002-03-04 04:07:02 +03:00
controls [ 0 ] = & PermitModify ;
controls [ 1 ] = NULL ;
2002-02-03 01:06:10 +03:00
2009-03-19 04:20:11 +03:00
if ( ! push_utf8_talloc ( talloc_tos ( ) , & utf8_dn , mod_dn , & converted_size ) ) {
2002-10-01 22:26:00 +04:00
return ADS_ERROR_NT ( NT_STATUS_NO_MEMORY ) ;
}
2002-07-15 14:35:28 +04:00
2002-02-01 19:14:33 +03:00
/* find the end of the list, marked by NULL or -1 */
2002-02-11 18:47:02 +03:00
for ( i = 0 ; ( mods [ i ] ! = 0 ) & & ( mods [ i ] ! = ( LDAPMod * ) - 1 ) ; i + + ) ;
2002-02-01 19:14:33 +03:00
/* make sure the end of the list is NULL */
mods [ i ] = NULL ;
2007-07-16 15:08:00 +04:00
ret = ldap_modify_ext_s ( ads - > ldap . ld , utf8_dn ,
2002-07-15 14:35:28 +04:00
( LDAPMod * * ) mods , controls , NULL ) ;
2016-03-04 19:42:05 +03:00
ads_print_error ( ret , ads - > ldap . ld ) ;
2009-03-19 04:20:11 +03:00
TALLOC_FREE ( utf8_dn ) ;
2002-02-01 19:14:33 +03:00
return ADS_ERROR ( ret ) ;
}
2001-11-20 11:54:15 +03:00
2002-04-10 17:28:03 +04:00
/**
* Perform an ldap add
* @ param ads connection to ads server
* @ param new_dn DistinguishedName to add
* @ param mods list of attributes and values for DN
* @ return status of add
* */
2002-02-12 21:22:33 +03:00
ADS_STATUS ads_gen_add ( ADS_STRUCT * ads , const char * new_dn , ADS_MODLIST mods )
2001-11-20 11:54:15 +03:00
{
2002-07-15 14:35:28 +04:00
int ret , i ;
char * utf8_dn = NULL ;
2008-04-30 01:36:24 +04:00
size_t converted_size ;
2001-11-20 11:54:15 +03:00
2019-03-29 13:34:53 +03:00
DBG_INFO ( " AD LDAP: Adding %s \n " , new_dn ) ;
2009-03-19 04:20:11 +03:00
if ( ! push_utf8_talloc ( talloc_tos ( ) , & utf8_dn , new_dn , & converted_size ) ) {
2023-08-07 07:36:27 +03:00
DEBUG ( 1 , ( " ads_gen_add: push_utf8_talloc failed! \n " ) ) ;
2002-10-01 22:26:00 +04:00
return ADS_ERROR_NT ( NT_STATUS_NO_MEMORY ) ;
}
2009-05-31 13:14:06 +04:00
2002-02-12 21:22:33 +03:00
/* find the end of the list, marked by NULL or -1 */
for ( i = 0 ; ( mods [ i ] ! = 0 ) & & ( mods [ i ] ! = ( LDAPMod * ) - 1 ) ; i + + ) ;
/* make sure the end of the list is NULL */
2001-11-20 11:54:15 +03:00
mods [ i ] = NULL ;
2019-08-13 18:06:58 +03:00
ret = ldap_add_ext_s ( ads - > ldap . ld , utf8_dn , ( LDAPMod * * ) mods , NULL , NULL ) ;
2016-03-04 19:42:05 +03:00
ads_print_error ( ret , ads - > ldap . ld ) ;
2009-03-19 04:20:11 +03:00
TALLOC_FREE ( utf8_dn ) ;
2002-07-15 14:35:28 +04:00
return ADS_ERROR ( ret ) ;
2001-11-20 11:54:15 +03:00
}
2002-04-10 17:28:03 +04:00
/**
* Delete a DistinguishedName
* @ param ads connection to ads server
* @ param new_dn DistinguishedName to delete
* @ return status of delete
* */
2002-02-02 05:04:01 +03:00
ADS_STATUS ads_del_dn ( ADS_STRUCT * ads , char * del_dn )
{
2002-07-15 14:35:28 +04:00
int ret ;
char * utf8_dn = NULL ;
2008-04-30 01:36:24 +04:00
size_t converted_size ;
2009-03-19 04:20:11 +03:00
if ( ! push_utf8_talloc ( talloc_tos ( ) , & utf8_dn , del_dn , & converted_size ) ) {
2023-08-07 07:36:27 +03:00
DEBUG ( 1 , ( " ads_del_dn: push_utf8_talloc failed! \n " ) ) ;
2002-10-01 22:26:00 +04:00
return ADS_ERROR_NT ( NT_STATUS_NO_MEMORY ) ;
}
2009-05-31 13:14:06 +04:00
2019-03-29 13:34:53 +03:00
DBG_INFO ( " AD LDAP: Deleting %s \n " , del_dn ) ;
2007-07-16 15:08:00 +04:00
ret = ldap_delete_s ( ads - > ldap . ld , utf8_dn ) ;
2016-03-04 19:42:05 +03:00
ads_print_error ( ret , ads - > ldap . ld ) ;
2009-03-19 04:20:11 +03:00
TALLOC_FREE ( utf8_dn ) ;
2002-07-15 14:35:28 +04:00
return ADS_ERROR ( ret ) ;
2002-02-02 05:04:01 +03:00
}
2002-04-10 17:28:03 +04:00
/**
* Build an org unit string
* if org unit is Computers or blank then assume a container , otherwise
2006-04-06 05:46:01 +04:00
* assume a / separated list of organisational units .
* jmcd : ' \ ' is now used for escapes so certain chars can be in the ou ( e . g . # )
2004-10-06 20:21:35 +04:00
* @ param ads connection to ads server
2002-04-10 17:28:03 +04:00
* @ param org_unit Organizational unit
* @ return org unit string - caller must free
* */
2004-10-06 20:21:35 +04:00
char * ads_ou_string ( ADS_STRUCT * ads , const char * org_unit )
{
2022-06-15 11:38:51 +03:00
ADS_STATUS status ;
2004-10-06 20:21:35 +04:00
char * ret = NULL ;
2022-06-15 11:38:51 +03:00
char * dn = NULL ;
2004-10-06 20:21:35 +04:00
if ( ! org_unit | | ! * org_unit ) {
2010-07-01 01:09:05 +04:00
ret = ads_default_ou_string ( ads , DS_GUID_COMPUTERS_CONTAINER ) ;
2004-10-06 20:21:35 +04:00
/* samba4 might not yet respond to a wellknownobject-query */
2004-12-07 21:25:53 +03:00
return ret ? ret : SMB_STRDUP ( " cn=Computers " ) ;
2004-10-06 20:21:35 +04:00
}
2009-05-31 13:14:06 +04:00
2004-10-06 20:21:35 +04:00
if ( strequal ( org_unit , " Computers " ) ) {
2004-12-07 21:25:53 +03:00
return SMB_STRDUP ( " cn=Computers " ) ;
2002-01-16 05:22:30 +03:00
}
2006-04-06 05:46:01 +04:00
/* jmcd: removed "\\" from the separation chars, because it is
needed as an escape for chars like ' # ' which are valid in an
OU name */
2022-06-15 11:38:51 +03:00
status = ads_build_path ( org_unit , " / " , " ou= " , 1 , & dn ) ;
if ( ! ADS_ERR_OK ( status ) ) {
return NULL ;
}
return dn ;
2002-01-16 05:22:30 +03:00
}
2004-10-06 20:21:35 +04:00
/**
* Get a org unit string for a well - known GUID
* @ param ads connection to ads server
* @ param wknguid Well known GUID
* @ return org unit string - caller must free
* */
char * ads_default_ou_string ( ADS_STRUCT * ads , const char * wknguid )
{
ADS_STATUS status ;
2006-11-09 13:16:38 +03:00
LDAPMessage * res = NULL ;
2006-11-13 13:34:59 +03:00
char * base , * wkn_dn = NULL , * ret = NULL , * * wkn_dn_exp = NULL ,
* * bind_dn_exp = NULL ;
2004-10-06 20:21:35 +04:00
const char * attrs [ ] = { " distinguishedName " , NULL } ;
int new_ln , wkn_ln , bind_ln , i ;
if ( wknguid = = NULL ) {
return NULL ;
}
if ( asprintf ( & base , " <WKGUID=%s,%s> " , wknguid , ads - > config . bind_path ) = = - 1 ) {
DEBUG ( 1 , ( " asprintf failed! \n " ) ) ;
return NULL ;
}
status = ads_search_dn ( ads , & res , base , attrs ) ;
if ( ! ADS_ERR_OK ( status ) ) {
DEBUG ( 1 , ( " Failed while searching for: %s \n " , base ) ) ;
2006-11-09 13:16:38 +03:00
goto out ;
2004-10-06 20:21:35 +04:00
}
if ( ads_count_replies ( ads , res ) ! = 1 ) {
2006-11-09 13:16:38 +03:00
goto out ;
2004-10-06 20:21:35 +04:00
}
/* substitute the bind-path from the well-known-guid-search result */
2009-04-07 02:40:46 +04:00
wkn_dn = ads_get_dn ( ads , talloc_tos ( ) , res ) ;
2006-11-09 13:16:38 +03:00
if ( ! wkn_dn ) {
goto out ;
}
2004-10-06 20:21:35 +04:00
wkn_dn_exp = ldap_explode_dn ( wkn_dn , 0 ) ;
2006-11-09 13:16:38 +03:00
if ( ! wkn_dn_exp ) {
goto out ;
}
2004-10-06 20:21:35 +04:00
bind_dn_exp = ldap_explode_dn ( ads - > config . bind_path , 0 ) ;
2006-11-09 13:16:38 +03:00
if ( ! bind_dn_exp ) {
goto out ;
}
2004-10-06 20:21:35 +04:00
for ( wkn_ln = 0 ; wkn_dn_exp [ wkn_ln ] ; wkn_ln + + )
;
for ( bind_ln = 0 ; bind_dn_exp [ bind_ln ] ; bind_ln + + )
;
new_ln = wkn_ln - bind_ln ;
2006-11-01 14:19:33 +03:00
ret = SMB_STRDUP ( wkn_dn_exp [ 0 ] ) ;
2006-11-09 13:16:38 +03:00
if ( ! ret ) {
goto out ;
}
2004-10-06 20:21:35 +04:00
for ( i = 1 ; i < new_ln ; i + + ) {
2006-11-09 13:16:38 +03:00
char * s = NULL ;
2009-05-31 13:14:06 +04:00
2006-11-09 13:16:38 +03:00
if ( asprintf ( & s , " %s,%s " , ret , wkn_dn_exp [ i ] ) = = - 1 ) {
SAFE_FREE ( ret ) ;
goto out ;
}
SAFE_FREE ( ret ) ;
2004-12-07 21:25:53 +03:00
ret = SMB_STRDUP ( s ) ;
2004-10-06 20:21:35 +04:00
free ( s ) ;
2006-11-09 13:16:38 +03:00
if ( ! ret ) {
goto out ;
}
2004-10-06 20:21:35 +04:00
}
2006-11-09 13:16:38 +03:00
out :
SAFE_FREE ( base ) ;
2006-11-01 14:19:33 +03:00
ads_msgfree ( ads , res ) ;
2009-03-18 09:35:03 +03:00
TALLOC_FREE ( wkn_dn ) ;
2006-11-09 13:16:38 +03:00
if ( wkn_dn_exp ) {
ldap_value_free ( wkn_dn_exp ) ;
}
if ( bind_dn_exp ) {
ldap_value_free ( bind_dn_exp ) ;
}
2006-06-13 17:41:04 +04:00
2004-10-06 20:21:35 +04:00
return ret ;
}
2004-06-22 04:48:59 +04:00
/**
* Adds ( appends ) an item to an attribute array , rather then
* replacing the whole list
* @ param ctx An initialized TALLOC_CTX
* @ param mods An initialized ADS_MODLIST
* @ param name name of the ldap attribute to append to
* @ param vals an array of values to add
* @ return status of addition
* */
2002-01-16 05:22:30 +03:00
2004-06-22 04:48:59 +04:00
ADS_STATUS ads_add_strlist ( TALLOC_CTX * ctx , ADS_MODLIST * mods ,
const char * name , const char * * vals )
{
2006-09-04 01:07:16 +04:00
return ads_modlist_add ( ctx , mods , LDAP_MOD_ADD , name ,
( const void * ) vals ) ;
2004-06-22 04:48:59 +04:00
}
2002-01-16 05:22:30 +03:00
2004-06-22 04:48:59 +04:00
/**
* This clears out all registered spn ' s for a given hostname
2023-09-01 04:39:18 +03:00
* @ param ads An initialized ADS_STRUCT
2004-06-22 04:48:59 +04:00
* @ param machine_name the NetBIOS name of the computer .
* @ return 0 upon success , non - zero otherwise .
* */
ADS_STATUS ads_clear_service_principal_names ( ADS_STRUCT * ads , const char * machine_name )
{
TALLOC_CTX * ctx ;
2004-06-23 04:20:31 +04:00
LDAPMessage * res = NULL ;
2004-06-22 04:48:59 +04:00
ADS_MODLIST mods ;
const char * servicePrincipalName [ 1 ] = { NULL } ;
2019-09-17 11:05:28 +03:00
ADS_STATUS ret ;
2004-06-22 04:48:59 +04:00
char * dn_string = NULL ;
2006-09-04 01:07:16 +04:00
ret = ads_find_machine_acct ( ads , & res , machine_name ) ;
2019-08-14 14:01:19 +03:00
if ( ! ADS_ERR_OK ( ret ) ) {
2004-06-22 04:48:59 +04:00
DEBUG ( 5 , ( " ads_clear_service_principal_names: WARNING: Host Account for %s not found... skipping operation. \n " , machine_name ) ) ;
DEBUG ( 5 , ( " ads_clear_service_principal_names: WARNING: Service Principals for %s have NOT been cleared. \n " , machine_name ) ) ;
2004-06-23 04:20:31 +04:00
ads_msgfree ( ads , res ) ;
2019-08-14 14:01:19 +03:00
return ret ;
2004-06-22 04:48:59 +04:00
}
DEBUG ( 5 , ( " ads_clear_service_principal_names: Host account for %s found \n " , machine_name ) ) ;
ctx = talloc_init ( " ads_clear_service_principal_names " ) ;
if ( ! ctx ) {
2004-06-23 04:20:31 +04:00
ads_msgfree ( ads , res ) ;
2004-06-22 04:48:59 +04:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
if ( ! ( mods = ads_init_mods ( ctx ) ) ) {
talloc_destroy ( ctx ) ;
2004-06-23 04:20:31 +04:00
ads_msgfree ( ads , res ) ;
2004-06-22 04:48:59 +04:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
ret = ads_mod_strlist ( ctx , & mods , " servicePrincipalName " , servicePrincipalName ) ;
if ( ! ADS_ERR_OK ( ret ) ) {
DEBUG ( 1 , ( " ads_clear_service_principal_names: Error creating strlist. \n " ) ) ;
2004-06-23 04:20:31 +04:00
ads_msgfree ( ads , res ) ;
2004-06-22 04:48:59 +04:00
talloc_destroy ( ctx ) ;
return ret ;
}
2009-04-07 02:40:46 +04:00
dn_string = ads_get_dn ( ads , talloc_tos ( ) , res ) ;
2004-06-22 04:48:59 +04:00
if ( ! dn_string ) {
talloc_destroy ( ctx ) ;
2004-06-23 04:20:31 +04:00
ads_msgfree ( ads , res ) ;
2004-06-22 04:48:59 +04:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
ret = ads_gen_mod ( ads , dn_string , mods ) ;
2009-03-18 09:35:03 +03:00
TALLOC_FREE ( dn_string ) ;
2004-06-22 04:48:59 +04:00
if ( ! ADS_ERR_OK ( ret ) ) {
DEBUG ( 1 , ( " ads_clear_service_principal_names: Error: Updating Service Principals for machine %s in LDAP \n " ,
machine_name ) ) ;
2004-06-23 04:20:31 +04:00
ads_msgfree ( ads , res ) ;
2004-06-22 04:48:59 +04:00
talloc_destroy ( ctx ) ;
return ret ;
}
2004-06-23 04:20:31 +04:00
ads_msgfree ( ads , res ) ;
2004-06-22 04:48:59 +04:00
talloc_destroy ( ctx ) ;
return ret ;
}
2014-09-24 11:23:58 +04:00
/**
* @ brief Search for an element in a string array .
*
* @ param [ in ] el_array The string array to search .
*
* @ param [ in ] num_el The number of elements in the string array .
*
* @ param [ in ] el The string to search .
*
* @ return True if found , false if not .
*/
bool ads_element_in_array ( const char * * el_array , size_t num_el , const char * el )
{
size_t i ;
if ( el_array = = NULL | | num_el = = 0 | | el = = NULL ) {
return false ;
}
for ( i = 0 ; i < num_el & & el_array [ i ] ! = NULL ; i + + ) {
int cmp ;
cmp = strcasecmp_m ( el_array [ i ] , el ) ;
if ( cmp = = 0 ) {
return true ;
}
}
return false ;
}
2014-09-24 11:22:03 +04:00
/**
* @ brief This gets the service principal names of an existing computer account .
*
* @ param [ in ] mem_ctx The memory context to use to allocate the spn array .
*
* @ param [ in ] ads The ADS context to use .
*
* @ param [ in ] machine_name The NetBIOS name of the computer , which is used to
* identify the computer account .
*
* @ param [ in ] spn_array A pointer to store the array for SPNs .
*
* @ param [ in ] num_spns The number of principals stored in the array .
*
2017-02-17 22:46:28 +03:00
* @ return 0 on success , or a ADS error if a failure occurred .
2014-09-24 11:22:03 +04:00
*/
ADS_STATUS ads_get_service_principal_names ( TALLOC_CTX * mem_ctx ,
ADS_STRUCT * ads ,
const char * machine_name ,
char * * * spn_array ,
size_t * num_spns )
{
ADS_STATUS status ;
LDAPMessage * res = NULL ;
int count ;
status = ads_find_machine_acct ( ads ,
& res ,
machine_name ) ;
if ( ! ADS_ERR_OK ( status ) ) {
DEBUG ( 1 , ( " Host Account for %s not found... skipping operation. \n " ,
machine_name ) ) ;
return status ;
}
count = ads_count_replies ( ads , res ) ;
if ( count ! = 1 ) {
status = ADS_ERROR ( LDAP_NO_SUCH_OBJECT ) ;
goto done ;
}
* spn_array = ads_pull_strings ( ads ,
mem_ctx ,
res ,
" servicePrincipalName " ,
num_spns ) ;
2015-09-23 14:45:47 +03:00
if ( * spn_array = = NULL ) {
DEBUG ( 1 , ( " Host account for %s does not have service principal "
" names. \n " ,
machine_name ) ) ;
status = ADS_ERROR ( LDAP_NO_SUCH_OBJECT ) ;
goto done ;
}
2014-09-24 11:22:03 +04:00
done :
ads_msgfree ( ads , res ) ;
return status ;
}
2004-06-22 04:48:59 +04:00
/**
* This adds a service principal name to an existing computer account
* ( found by hostname ) in AD .
* @ param ads An initialized ADS_STRUCT
* @ param machine_name the NetBIOS name of the computer , which is used to identify the computer account .
2018-02-16 19:52:01 +03:00
* @ param spns An array or strings for the service principals to add ,
* i . e . ' cifs / machine_name ' , ' http / machine . full . domain . com ' etc .
2023-07-05 12:21:39 +03:00
* @ return 0 upon success , or non - zero if a failure occurs
2004-06-22 04:48:59 +04:00
* */
2018-02-16 19:52:01 +03:00
ADS_STATUS ads_add_service_principal_names ( ADS_STRUCT * ads ,
const char * machine_name ,
const char * * spns )
2004-06-22 04:48:59 +04:00
{
ADS_STATUS ret ;
TALLOC_CTX * ctx ;
2004-06-23 04:20:31 +04:00
LDAPMessage * res = NULL ;
2004-06-22 04:48:59 +04:00
ADS_MODLIST mods ;
char * dn_string = NULL ;
2018-02-16 19:52:01 +03:00
const char * * servicePrincipalName = spns ;
2004-06-22 04:48:59 +04:00
2006-09-04 01:07:16 +04:00
ret = ads_find_machine_acct ( ads , & res , machine_name ) ;
2019-08-14 14:01:19 +03:00
if ( ! ADS_ERR_OK ( ret ) ) {
2004-06-22 04:48:59 +04:00
DEBUG ( 1 , ( " ads_add_service_principal_name: WARNING: Host Account for %s not found... skipping operation. \n " ,
machine_name ) ) ;
2018-02-16 19:52:01 +03:00
DEBUG ( 1 , ( " ads_add_service_principal_name: WARNING: Service Principals have NOT been added. \n " ) ) ;
2004-06-23 04:20:31 +04:00
ads_msgfree ( ads , res ) ;
2019-08-14 14:01:19 +03:00
return ret ;
2004-06-22 04:48:59 +04:00
}
DEBUG ( 1 , ( " ads_add_service_principal_name: Host account for %s found \n " , machine_name ) ) ;
if ( ! ( ctx = talloc_init ( " ads_add_service_principal_name " ) ) ) {
2004-06-23 04:20:31 +04:00
ads_msgfree ( ads , res ) ;
2004-06-22 04:48:59 +04:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
2018-02-16 19:52:01 +03:00
DEBUG ( 5 , ( " ads_add_service_principal_name: INFO: "
" Adding %s to host %s \n " ,
spns [ 0 ] ? " N/A " : spns [ 0 ] , machine_name ) ) ;
2009-05-31 13:14:06 +04:00
2004-06-22 04:48:59 +04:00
2018-02-16 19:52:01 +03:00
DEBUG ( 5 , ( " ads_add_service_principal_name: INFO: "
" Adding %s to host %s \n " ,
spns [ 1 ] ? " N/A " : spns [ 1 ] , machine_name ) ) ;
2006-06-17 03:21:36 +04:00
2006-07-11 22:45:22 +04:00
if ( ( mods = ads_init_mods ( ctx ) ) = = NULL ) {
ret = ADS_ERROR ( LDAP_NO_MEMORY ) ;
goto out ;
2004-06-22 04:48:59 +04:00
}
2009-05-31 13:14:06 +04:00
2018-02-16 19:52:01 +03:00
ret = ads_add_strlist ( ctx ,
& mods ,
" servicePrincipalName " ,
servicePrincipalName ) ;
2004-06-22 04:48:59 +04:00
if ( ! ADS_ERR_OK ( ret ) ) {
DEBUG ( 1 , ( " ads_add_service_principal_name: Error: Updating Service Principals in LDAP \n " ) ) ;
2006-07-11 22:45:22 +04:00
goto out ;
2004-06-22 04:48:59 +04:00
}
2009-05-31 13:14:06 +04:00
2009-03-18 09:35:03 +03:00
if ( ( dn_string = ads_get_dn ( ads , ctx , res ) ) = = NULL ) {
2006-07-11 22:45:22 +04:00
ret = ADS_ERROR ( LDAP_NO_MEMORY ) ;
goto out ;
2004-06-22 04:48:59 +04:00
}
2009-05-31 13:14:06 +04:00
2004-06-23 04:20:31 +04:00
ret = ads_gen_mod ( ads , dn_string , mods ) ;
2004-06-22 04:48:59 +04:00
if ( ! ADS_ERR_OK ( ret ) ) {
DEBUG ( 1 , ( " ads_add_service_principal_name: Error: Updating Service Principals in LDAP \n " ) ) ;
2006-07-11 22:45:22 +04:00
goto out ;
2004-06-22 04:48:59 +04:00
}
2006-07-11 22:45:22 +04:00
out :
TALLOC_FREE ( ctx ) ;
2004-06-23 04:20:31 +04:00
ads_msgfree ( ads , res ) ;
2004-06-22 04:48:59 +04:00
return ret ;
}
2019-08-08 15:40:04 +03:00
static uint32_t ads_get_acct_ctrl ( ADS_STRUCT * ads ,
LDAPMessage * msg )
{
uint32_t acct_ctrl = 0 ;
bool ok ;
ok = ads_pull_uint32 ( ads , msg , " userAccountControl " , & acct_ctrl ) ;
if ( ! ok ) {
return 0 ;
}
return acct_ctrl ;
}
static ADS_STATUS ads_change_machine_acct ( ADS_STRUCT * ads ,
LDAPMessage * msg ,
const struct berval * machine_pw_val )
{
ADS_MODLIST mods ;
ADS_STATUS ret ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
uint32_t acct_control ;
char * control_str = NULL ;
const char * attrs [ ] = {
" objectSid " ,
NULL
} ;
LDAPMessage * res = NULL ;
char * dn = NULL ;
dn = ads_get_dn ( ads , frame , msg ) ;
if ( dn = = NULL ) {
ret = ADS_ERROR ( LDAP_NO_MEMORY ) ;
goto done ;
}
acct_control = ads_get_acct_ctrl ( ads , msg ) ;
if ( acct_control = = 0 ) {
ret = ADS_ERROR ( LDAP_NO_RESULTS_RETURNED ) ;
goto done ;
}
/*
* Changing the password , disables the account . So we need to change the
* userAccountControl flags to enable it again .
*/
mods = ads_init_mods ( frame ) ;
if ( mods = = NULL ) {
ret = ADS_ERROR_LDAP ( LDAP_NO_MEMORY ) ;
goto done ;
}
ads_mod_ber ( frame , & mods , " unicodePwd " , machine_pw_val ) ;
ret = ads_gen_mod ( ads , dn , mods ) ;
if ( ! ADS_ERR_OK ( ret ) ) {
goto done ;
}
TALLOC_FREE ( mods ) ;
/*
* To activate the account , we need to disable and enable it .
*/
acct_control | = UF_ACCOUNTDISABLE ;
control_str = talloc_asprintf ( frame , " %u " , acct_control ) ;
if ( control_str = = NULL ) {
ret = ADS_ERROR ( LDAP_NO_MEMORY ) ;
goto done ;
}
mods = ads_init_mods ( frame ) ;
if ( mods = = NULL ) {
ret = ADS_ERROR_LDAP ( LDAP_NO_MEMORY ) ;
goto done ;
}
ads_mod_str ( frame , & mods , " userAccountControl " , control_str ) ;
ret = ads_gen_mod ( ads , dn , mods ) ;
if ( ! ADS_ERR_OK ( ret ) ) {
goto done ;
}
TALLOC_FREE ( mods ) ;
TALLOC_FREE ( control_str ) ;
/*
* Enable the account again .
*/
acct_control & = ~ UF_ACCOUNTDISABLE ;
control_str = talloc_asprintf ( frame , " %u " , acct_control ) ;
if ( control_str = = NULL ) {
ret = ADS_ERROR ( LDAP_NO_MEMORY ) ;
goto done ;
}
mods = ads_init_mods ( frame ) ;
if ( mods = = NULL ) {
ret = ADS_ERROR_LDAP ( LDAP_NO_MEMORY ) ;
goto done ;
}
ads_mod_str ( frame , & mods , " userAccountControl " , control_str ) ;
ret = ads_gen_mod ( ads , dn , mods ) ;
if ( ! ADS_ERR_OK ( ret ) ) {
goto done ;
}
TALLOC_FREE ( mods ) ;
TALLOC_FREE ( control_str ) ;
ret = ads_search_dn ( ads , & res , dn , attrs ) ;
ads_msgfree ( ads , res ) ;
done :
talloc_free ( frame ) ;
return ret ;
}
2004-06-22 04:48:59 +04:00
/**
* adds a machine account to the ADS server
2023-07-05 12:21:39 +03:00
* @ param ads An initialized ADS_STRUCT
2004-06-22 04:48:59 +04:00
* @ param machine_name - the NetBIOS machine name of this account .
* @ param account_type A number indicating the type of account to create
* @ param org_unit The LDAP path in which to place this account
* @ return 0 upon success , or non - zero otherwise
* */
2016-03-11 18:04:52 +03:00
ADS_STATUS ads_create_machine_acct ( ADS_STRUCT * ads ,
const char * machine_name ,
2019-08-13 17:34:34 +03:00
const char * machine_password ,
2016-03-11 18:04:52 +03:00
const char * org_unit ,
2019-08-13 17:34:34 +03:00
uint32_t etype_list ,
const char * dns_domain_name )
2001-11-20 11:54:15 +03:00
{
2006-05-13 08:39:19 +04:00
ADS_STATUS ret ;
2019-08-13 17:30:07 +03:00
char * samAccountName = NULL ;
char * controlstr = NULL ;
TALLOC_CTX * ctx = NULL ;
2002-02-12 21:22:33 +03:00
ADS_MODLIST mods ;
2007-03-01 04:17:36 +03:00
char * machine_escaped = NULL ;
2019-08-13 17:34:34 +03:00
char * dns_hostname = NULL ;
2019-08-13 17:30:07 +03:00
char * new_dn = NULL ;
2019-08-13 17:34:34 +03:00
char * utf8_pw = NULL ;
size_t utf8_pw_len = 0 ;
char * utf16_pw = NULL ;
size_t utf16_pw_len = 0 ;
struct berval machine_pw_val ;
bool ok ;
const char * * spn_array = NULL ;
size_t num_spns = 0 ;
const char * spn_prefix [ ] = {
" HOST " ,
" RestrictedKrbHost " ,
} ;
size_t i ;
2004-06-23 04:20:31 +04:00
LDAPMessage * res = NULL ;
2019-08-13 17:34:34 +03:00
uint32_t acct_control = UF_WORKSTATION_TRUST_ACCOUNT ;
2009-05-31 13:14:06 +04:00
2019-08-13 17:30:07 +03:00
ctx = talloc_init ( " ads_add_machine_acct " ) ;
if ( ctx = = NULL ) {
2004-06-22 04:48:59 +04:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
2019-08-13 17:30:07 +03:00
}
2007-03-01 03:49:28 +03:00
machine_escaped = escape_rdn_val_string_alloc ( machine_name ) ;
2019-08-13 17:30:07 +03:00
if ( machine_escaped = = NULL ) {
ret = ADS_ERROR ( LDAP_NO_MEMORY ) ;
2007-03-01 03:49:28 +03:00
goto done ;
}
2019-08-08 15:40:04 +03:00
utf8_pw = talloc_asprintf ( ctx , " \" %s \" " , machine_password ) ;
if ( utf8_pw = = NULL ) {
ret = ADS_ERROR ( LDAP_NO_MEMORY ) ;
goto done ;
}
utf8_pw_len = strlen ( utf8_pw ) ;
ok = convert_string_talloc ( ctx ,
CH_UTF8 , CH_UTF16MUNGED ,
utf8_pw , utf8_pw_len ,
( void * ) & utf16_pw , & utf16_pw_len ) ;
if ( ! ok ) {
ret = ADS_ERROR ( LDAP_NO_MEMORY ) ;
goto done ;
}
machine_pw_val = ( struct berval ) {
. bv_val = utf16_pw ,
. bv_len = utf16_pw_len ,
} ;
2019-08-13 17:34:34 +03:00
/* Check if the machine account already exists. */
2019-04-01 18:40:03 +03:00
ret = ads_find_machine_acct ( ads , & res , machine_escaped ) ;
2019-08-14 14:01:19 +03:00
if ( ADS_ERR_OK ( ret ) ) {
2019-08-08 15:40:04 +03:00
/* Change the machine account password */
ret = ads_change_machine_acct ( ads , res , & machine_pw_val ) ;
2019-07-31 22:17:20 +03:00
ads_msgfree ( ads , res ) ;
2019-08-08 15:40:04 +03:00
2019-04-01 18:40:03 +03:00
goto done ;
}
2019-07-31 22:17:20 +03:00
ads_msgfree ( ads , res ) ;
2019-04-01 18:40:03 +03:00
2007-03-01 03:49:28 +03:00
new_dn = talloc_asprintf ( ctx , " cn=%s,%s " , machine_escaped , org_unit ) ;
2019-08-13 17:30:07 +03:00
if ( new_dn = = NULL ) {
ret = ADS_ERROR ( LDAP_NO_MEMORY ) ;
goto done ;
}
2004-06-22 04:48:59 +04:00
2019-08-13 17:34:34 +03:00
/* Create machine account */
2019-08-13 17:30:07 +03:00
samAccountName = talloc_asprintf ( ctx , " %s$ " , machine_name ) ;
if ( samAccountName = = NULL ) {
ret = ADS_ERROR ( LDAP_NO_MEMORY ) ;
2002-02-12 21:22:33 +03:00
goto done ;
2004-06-22 04:48:59 +04:00
}
2009-05-31 13:14:06 +04:00
2019-08-13 17:34:34 +03:00
dns_hostname = talloc_asprintf ( ctx ,
" %s.%s " ,
machine_name ,
dns_domain_name ) ;
if ( dns_hostname = = NULL ) {
ret = ADS_ERROR ( LDAP_NO_MEMORY ) ;
goto done ;
}
/* Add dns_hostname SPNs */
for ( i = 0 ; i < ARRAY_SIZE ( spn_prefix ) ; i + + ) {
char * spn = talloc_asprintf ( ctx ,
" %s/%s " ,
spn_prefix [ i ] ,
dns_hostname ) ;
if ( spn = = NULL ) {
ret = ADS_ERROR ( LDAP_NO_MEMORY ) ;
goto done ;
}
2023-10-31 16:04:31 +03:00
ok = add_string_to_array ( ctx ,
2019-08-13 17:34:34 +03:00
spn ,
& spn_array ,
& num_spns ) ;
if ( ! ok ) {
ret = ADS_ERROR ( LDAP_NO_MEMORY ) ;
goto done ;
}
}
/* Add machine_name SPNs */
for ( i = 0 ; i < ARRAY_SIZE ( spn_prefix ) ; i + + ) {
char * spn = talloc_asprintf ( ctx ,
" %s/%s " ,
spn_prefix [ i ] ,
machine_name ) ;
if ( spn = = NULL ) {
ret = ADS_ERROR ( LDAP_NO_MEMORY ) ;
goto done ;
}
2023-10-31 16:04:31 +03:00
ok = add_string_to_array ( ctx ,
2019-08-13 17:34:34 +03:00
spn ,
& spn_array ,
& num_spns ) ;
if ( ! ok ) {
ret = ADS_ERROR ( LDAP_NO_MEMORY ) ;
goto done ;
}
}
/* Make sure to NULL terminate the array */
spn_array = talloc_realloc ( ctx , spn_array , const char * , num_spns + 1 ) ;
if ( spn_array = = NULL ) {
2019-11-01 10:50:29 +03:00
ret = ADS_ERROR ( LDAP_NO_MEMORY ) ;
goto done ;
2019-08-13 17:34:34 +03:00
}
spn_array [ num_spns ] = NULL ;
2019-08-13 17:30:07 +03:00
controlstr = talloc_asprintf ( ctx , " %u " , acct_control ) ;
if ( controlstr = = NULL ) {
ret = ADS_ERROR ( LDAP_NO_MEMORY ) ;
2002-02-12 21:22:33 +03:00
goto done ;
2004-06-22 04:48:59 +04:00
}
2002-02-12 21:22:33 +03:00
2019-08-13 17:30:07 +03:00
mods = ads_init_mods ( ctx ) ;
if ( mods = = NULL ) {
ret = ADS_ERROR ( LDAP_NO_MEMORY ) ;
2002-02-12 21:22:33 +03:00
goto done ;
2004-06-22 04:48:59 +04:00
}
2009-05-31 13:14:06 +04:00
2019-08-13 17:34:34 +03:00
ads_mod_str ( ctx , & mods , " objectClass " , " Computer " ) ;
ads_mod_str ( ctx , & mods , " SamAccountName " , samAccountName ) ;
2006-03-07 19:56:31 +03:00
ads_mod_str ( ctx , & mods , " userAccountControl " , controlstr ) ;
2019-08-13 17:34:34 +03:00
ads_mod_str ( ctx , & mods , " DnsHostName " , dns_hostname ) ;
ads_mod_strlist ( ctx , & mods , " ServicePrincipalName " , spn_array ) ;
ads_mod_ber ( ctx , & mods , " unicodePwd " , & machine_pw_val ) ;
2003-02-19 15:31:16 +03:00
2006-05-13 08:39:19 +04:00
ret = ads_gen_add ( ads , new_dn , mods ) ;
2003-02-19 15:31:16 +03:00
2002-02-12 21:22:33 +03:00
done :
2007-03-01 04:17:36 +03:00
SAFE_FREE ( machine_escaped ) ;
2002-02-12 21:22:33 +03:00
talloc_destroy ( ctx ) ;
2009-05-31 13:14:06 +04:00
2001-11-20 11:54:15 +03:00
return ret ;
}
2007-05-07 01:45:53 +04:00
/**
* move a machine account to another OU on the ADS server
2023-07-05 12:21:39 +03:00
* @ param ads - An initialized ADS_STRUCT
2007-05-07 01:45:53 +04:00
* @ param machine_name - the NetBIOS machine name of this account .
* @ param org_unit - The LDAP path in which to place this account
* @ param moved - whether we moved the machine account ( optional )
* @ return 0 upon success , or non - zero otherwise
* */
2022-06-22 21:53:42 +03:00
ADS_STATUS ads_move_machine_acct ( ADS_STRUCT * ads , const char * machine_name ,
2007-10-19 04:40:25 +04:00
const char * org_unit , bool * moved )
2007-05-07 01:45:53 +04:00
{
ADS_STATUS rc ;
int ldap_status ;
LDAPMessage * res = NULL ;
char * filter = NULL ;
char * computer_dn = NULL ;
char * parent_dn ;
char * computer_rdn = NULL ;
2007-10-19 04:40:25 +04:00
bool need_move = False ;
2007-05-07 01:45:53 +04:00
if ( asprintf ( & filter , " (samAccountName=%s$) " , machine_name ) = = - 1 ) {
rc = ADS_ERROR ( LDAP_NO_MEMORY ) ;
goto done ;
}
/* Find pre-existing machine */
rc = ads_search ( ads , & res , filter , NULL ) ;
if ( ! ADS_ERR_OK ( rc ) ) {
goto done ;
}
2009-04-07 02:40:46 +04:00
computer_dn = ads_get_dn ( ads , talloc_tos ( ) , res ) ;
2007-05-07 01:45:53 +04:00
if ( ! computer_dn ) {
rc = ADS_ERROR ( LDAP_NO_MEMORY ) ;
goto done ;
}
parent_dn = ads_parent_dn ( computer_dn ) ;
if ( strequal ( parent_dn , org_unit ) ) {
goto done ;
}
need_move = True ;
if ( asprintf ( & computer_rdn , " CN=%s " , machine_name ) = = - 1 ) {
rc = ADS_ERROR ( LDAP_NO_MEMORY ) ;
goto done ;
}
2022-06-22 21:53:42 +03:00
ldap_status = ldap_rename_s ( ads - > ldap . ld , computer_dn , computer_rdn ,
2007-05-15 14:47:40 +04:00
org_unit , 1 , NULL , NULL ) ;
2007-05-07 01:45:53 +04:00
rc = ADS_ERROR ( ldap_status ) ;
done :
ads_msgfree ( ads , res ) ;
SAFE_FREE ( filter ) ;
2009-12-04 20:31:53 +03:00
TALLOC_FREE ( computer_dn ) ;
2007-05-07 01:45:53 +04:00
SAFE_FREE ( computer_rdn ) ;
if ( ! ADS_ERR_OK ( rc ) ) {
need_move = False ;
}
if ( moved ) {
* moved = need_move ;
}
return rc ;
}
2001-11-25 04:06:56 +03:00
/*
dump a binary result from ldap
*/
2007-07-11 17:21:32 +04:00
static void dump_binary ( ADS_STRUCT * ads , const char * field , struct berval * * values )
2001-11-25 04:06:56 +03:00
{
2019-01-12 16:59:58 +03:00
size_t i ;
2001-11-25 04:06:56 +03:00
for ( i = 0 ; values [ i ] ; i + + ) {
2019-01-12 16:59:58 +03:00
ber_len_t j ;
2001-11-25 04:06:56 +03:00
printf ( " %s: " , field ) ;
for ( j = 0 ; j < values [ i ] - > bv_len ; j + + ) {
printf ( " %02X " , ( unsigned char ) values [ i ] - > bv_val [ j ] ) ;
}
printf ( " \n " ) ;
}
}
2007-07-11 17:21:32 +04:00
static void dump_guid ( ADS_STRUCT * ads , const char * field , struct berval * * values )
2002-10-29 17:47:11 +03:00
{
int i ;
for ( i = 0 ; values [ i ] ; i + + ) {
2010-09-17 12:04:05 +04:00
NTSTATUS status ;
DATA_BLOB in = data_blob_const ( values [ i ] - > bv_val , values [ i ] - > bv_len ) ;
struct GUID guid ;
2007-11-25 12:10:52 +03:00
2010-09-17 12:04:05 +04:00
status = GUID_from_ndr_blob ( & in , & guid ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
printf ( " %s: %s \n " , field , GUID_string ( talloc_tos ( ) , & guid ) ) ;
} else {
printf ( " %s: INVALID GUID \n " , field ) ;
}
2002-10-29 17:47:11 +03:00
}
}
2001-12-19 11:44:23 +03:00
/*
dump a sid result from ldap
*/
2007-07-11 17:21:32 +04:00
static void dump_sid ( ADS_STRUCT * ads , const char * field , struct berval * * values )
2001-12-19 11:44:23 +03:00
{
int i ;
for ( i = 0 ; values [ i ] ; i + + ) {
2019-03-11 19:11:06 +03:00
ssize_t ret ;
2010-05-21 05:25:01 +04:00
struct dom_sid sid ;
2018-11-09 23:12:51 +03:00
struct dom_sid_buf tmp ;
2019-03-11 18:55:57 +03:00
ret = sid_parse ( ( const uint8_t * ) values [ i ] - > bv_val ,
values [ i ] - > bv_len , & sid ) ;
2019-03-11 19:11:06 +03:00
if ( ret = = - 1 ) {
2010-09-16 02:40:15 +04:00
return ;
}
2018-11-09 23:12:51 +03:00
printf ( " %s: %s \n " , field , dom_sid_str_buf ( & sid , & tmp ) ) ;
2001-12-19 11:44:23 +03:00
}
}
2002-03-10 04:54:44 +03:00
/*
dump ntSecurityDescriptor
*/
2007-07-11 17:21:32 +04:00
static void dump_sd ( ADS_STRUCT * ads , const char * filed , struct berval * * values )
2002-03-10 04:54:44 +03:00
{
2007-12-16 16:15:16 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct security_descriptor * psd ;
NTSTATUS status ;
2002-03-10 04:54:44 +03:00
2015-04-18 18:40:14 +03:00
status = unmarshall_sec_desc ( talloc_tos ( ) , ( uint8_t * ) values [ 0 ] - > bv_val ,
2007-12-16 16:15:16 +03:00
values [ 0 ] - > bv_len , & psd ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " unmarshall_sec_desc failed: %s \n " ,
nt_errstr ( status ) ) ) ;
TALLOC_FREE ( frame ) ;
2002-03-10 04:54:44 +03:00
return ;
}
2007-12-16 16:15:16 +03:00
2007-07-11 17:30:38 +04:00
if ( psd ) {
2007-12-16 16:15:16 +03:00
ads_disp_sd ( ads , talloc_tos ( ) , psd ) ;
2007-07-11 17:30:38 +04:00
}
2002-03-10 04:54:44 +03:00
2007-12-16 16:15:16 +03:00
TALLOC_FREE ( frame ) ;
2002-03-10 04:54:44 +03:00
}
2001-11-25 04:06:56 +03:00
/*
dump a string result from ldap
*/
2002-07-15 14:35:28 +04:00
static void dump_string ( const char * field , char * * values )
2001-11-25 04:06:56 +03:00
{
int i ;
for ( i = 0 ; values [ i ] ; i + + ) {
2002-07-15 14:35:28 +04:00
printf ( " %s: %s \n " , field , values [ i ] ) ;
2001-11-25 04:06:56 +03:00
}
}
2001-11-20 11:54:15 +03:00
/*
2002-03-30 00:06:33 +03:00
dump a field from LDAP on stdout
2001-11-20 11:54:15 +03:00
used for debugging
*/
2002-03-30 00:06:33 +03:00
2007-10-19 04:40:25 +04:00
static bool ads_dump_field ( ADS_STRUCT * ads , char * field , void * * values , void * data_area )
2001-11-20 11:54:15 +03:00
{
2003-01-03 11:28:12 +03:00
const struct {
const char * name ;
2007-10-19 04:40:25 +04:00
bool string ;
2007-07-11 17:21:32 +04:00
void ( * handler ) ( ADS_STRUCT * , const char * , struct berval * * ) ;
2001-11-25 04:06:56 +03:00
} handlers [ ] = {
2002-10-29 17:47:11 +03:00
{ " objectGUID " , False , dump_guid } ,
2006-02-09 13:24:27 +03:00
{ " netbootGUID " , False , dump_guid } ,
2002-07-15 14:35:28 +04:00
{ " nTSecurityDescriptor " , False , dump_sd } ,
2002-08-17 21:00:51 +04:00
{ " dnsRecord " , False , dump_binary } ,
2002-07-15 14:35:28 +04:00
{ " objectSid " , False , dump_sid } ,
2024-04-03 17:00:41 +03:00
{ " securityIdentifier " , False , dump_sid } ,
2003-03-18 01:41:14 +03:00
{ " tokenGroups " , False , dump_sid } ,
2006-04-26 00:13:05 +04:00
{ " tokenGroupsNoGCAcceptable " , False , dump_sid } ,
{ " tokengroupsGlobalandUniversal " , False , dump_sid } ,
2006-09-25 20:55:19 +04:00
{ " mS-DS-CreatorSID " , False , dump_sid } ,
2007-08-06 18:03:11 +04:00
{ " msExchMailboxGuid " , False , dump_guid } ,
2024-04-03 17:00:41 +03:00
{ " msDS-TrustForestTrustInfo " , False , dump_binary } ,
2002-07-15 14:35:28 +04:00
{ NULL , True , NULL }
2001-11-25 04:06:56 +03:00
} ;
2002-03-30 00:06:33 +03:00
int i ;
if ( ! field ) { /* must be end of an entry */
printf ( " \n " ) ;
2002-07-15 14:35:28 +04:00
return False ;
2002-03-30 00:06:33 +03:00
}
for ( i = 0 ; handlers [ i ] . name ; i + + ) {
2011-05-13 22:21:30 +04:00
if ( strcasecmp_m ( handlers [ i ] . name , field ) = = 0 ) {
2002-07-15 14:35:28 +04:00
if ( ! values ) /* first time, indicate string or not */
return handlers [ i ] . string ;
2007-07-11 17:21:32 +04:00
handlers [ i ] . handler ( ads , field , ( struct berval * * ) values ) ;
2002-03-30 00:06:33 +03:00
break ;
}
}
if ( ! handlers [ i ] . name ) {
2002-07-15 14:35:28 +04:00
if ( ! values ) /* first time, indicate string conversion */
return True ;
dump_string ( field , ( char * * ) values ) ;
2002-03-30 00:06:33 +03:00
}
2002-07-15 14:35:28 +04:00
return False ;
2002-03-30 00:06:33 +03:00
}
2002-04-10 17:28:03 +04:00
/**
* Dump a result from LDAP on stdout
* used for debugging
* @ param ads connection to ads server
* @ param res Results to dump
* */
2002-03-30 00:06:33 +03:00
2006-09-04 01:07:16 +04:00
void ads_dump ( ADS_STRUCT * ads , LDAPMessage * res )
2002-03-30 00:06:33 +03:00
{
ads_process_results ( ads , res , ads_dump_field , NULL ) ;
}
2002-04-10 17:28:03 +04:00
/**
* Walk through results , calling a function for each entry found .
* The function receives a field name , a berval * array of values ,
* and a data area passed through from the start . The function is
* called once with null for field and values at the end of each
* entry .
* @ param ads connection to ads server
* @ param res Results to process
* @ param fn Function for processing each result
* @ param data_area user - defined area to pass to function
* */
2006-09-04 01:07:16 +04:00
void ads_process_results ( ADS_STRUCT * ads , LDAPMessage * res ,
2007-10-19 04:40:25 +04:00
bool ( * fn ) ( ADS_STRUCT * , char * , void * * , void * ) ,
2006-09-04 01:07:16 +04:00
void * data_area )
2002-03-30 00:06:33 +03:00
{
2006-09-04 01:07:16 +04:00
LDAPMessage * msg ;
2002-07-15 14:35:28 +04:00
TALLOC_CTX * ctx ;
2008-04-30 01:36:24 +04:00
size_t converted_size ;
2002-07-15 14:35:28 +04:00
2002-12-20 23:21:31 +03:00
if ( ! ( ctx = talloc_init ( " ads_process_results " ) ) )
2002-07-15 14:35:28 +04:00
return ;
2002-03-30 00:06:33 +03:00
2022-06-22 21:53:42 +03:00
for ( msg = ads_first_entry ( ads , res ) ; msg ;
2002-03-30 00:06:33 +03:00
msg = ads_next_entry ( ads , msg ) ) {
2002-07-15 14:35:28 +04:00
char * utf8_field ;
2002-03-30 00:06:33 +03:00
BerElement * b ;
2009-05-31 13:14:06 +04:00
2007-07-16 15:08:00 +04:00
for ( utf8_field = ldap_first_attribute ( ads - > ldap . ld ,
2022-06-22 21:53:42 +03:00
( LDAPMessage * ) msg , & b ) ;
2002-07-15 14:35:28 +04:00
utf8_field ;
2007-07-16 15:08:00 +04:00
utf8_field = ldap_next_attribute ( ads - > ldap . ld ,
2002-07-15 14:35:28 +04:00
( LDAPMessage * ) msg , b ) ) {
struct berval * * ber_vals ;
2014-02-26 23:16:26 +04:00
char * * str_vals ;
char * * utf8_vals ;
2002-07-15 14:35:28 +04:00
char * field ;
2022-06-22 21:53:42 +03:00
bool string ;
2002-07-15 14:35:28 +04:00
2008-04-30 01:36:24 +04:00
if ( ! pull_utf8_talloc ( ctx , & field , utf8_field ,
& converted_size ) )
{
DEBUG ( 0 , ( " ads_process_results: "
2023-08-07 07:36:27 +03:00
" pull_utf8_talloc failed: %s \n " ,
2008-04-30 01:36:24 +04:00
strerror ( errno ) ) ) ;
}
2007-07-11 17:21:32 +04:00
string = fn ( ads , field , NULL , data_area ) ;
2002-07-15 14:35:28 +04:00
if ( string ) {
2014-02-26 23:16:26 +04:00
const char * * p ;
2007-07-16 15:08:00 +04:00
utf8_vals = ldap_get_values ( ads - > ldap . ld ,
2002-07-15 14:35:28 +04:00
( LDAPMessage * ) msg , field ) ;
2014-02-26 23:16:26 +04:00
p = discard_const_p ( const char * , utf8_vals ) ;
str_vals = ads_pull_strvals ( ctx , p ) ;
2007-07-11 17:21:32 +04:00
fn ( ads , field , ( void * * ) str_vals , data_area ) ;
2002-07-15 14:35:28 +04:00
ldap_value_free ( utf8_vals ) ;
} else {
2022-06-22 21:53:42 +03:00
ber_vals = ldap_get_values_len ( ads - > ldap . ld ,
2002-07-15 14:35:28 +04:00
( LDAPMessage * ) msg , field ) ;
2007-07-11 17:21:32 +04:00
fn ( ads , field , ( void * * ) ber_vals , data_area ) ;
2002-07-15 14:35:28 +04:00
ldap_value_free_len ( ber_vals ) ;
}
ldap_memfree ( utf8_field ) ;
2001-11-20 11:54:15 +03:00
}
2002-03-30 00:06:33 +03:00
ber_free ( b , 0 ) ;
2005-05-03 11:33:49 +04:00
talloc_free_children ( ctx ) ;
2007-07-11 17:21:32 +04:00
fn ( ads , NULL , NULL , data_area ) ; /* completed an entry */
2001-11-20 11:54:15 +03:00
}
2002-07-15 14:35:28 +04:00
talloc_destroy ( ctx ) ;
2001-11-20 11:54:15 +03:00
}
2002-04-10 17:28:03 +04:00
/**
* count how many replies are in a LDAPMessage
* @ param ads connection to ads server
* @ param res Results to count
* @ return number of replies
* */
2001-11-20 11:54:15 +03:00
int ads_count_replies ( ADS_STRUCT * ads , void * res )
{
2007-07-16 15:08:00 +04:00
return ldap_count_entries ( ads - > ldap . ld , ( LDAPMessage * ) res ) ;
2001-11-20 11:54:15 +03:00
}
2002-04-10 17:28:03 +04:00
/**
* pull the first entry from a ADS result
* @ param ads connection to ads server
* @ param res Results of search
* @ return first entry from result
* */
2006-09-04 01:07:16 +04:00
LDAPMessage * ads_first_entry ( ADS_STRUCT * ads , LDAPMessage * res )
2001-12-03 09:04:18 +03:00
{
2007-07-16 15:08:00 +04:00
return ldap_first_entry ( ads - > ldap . ld , res ) ;
2001-12-03 09:04:18 +03:00
}
2002-04-10 17:28:03 +04:00
/**
* pull the next entry from a ADS result
* @ param ads connection to ads server
* @ param res Results of search
* @ return next entry from result
* */
2006-09-04 01:07:16 +04:00
LDAPMessage * ads_next_entry ( ADS_STRUCT * ads , LDAPMessage * res )
2001-12-03 09:04:18 +03:00
{
2007-07-16 15:08:00 +04:00
return ldap_next_entry ( ads - > ldap . ld , res ) ;
2001-12-03 09:04:18 +03:00
}
2008-04-26 05:34:46 +04:00
/**
* pull the first message from a ADS result
* @ param ads connection to ads server
* @ param res Results of search
* @ return first message from result
* */
LDAPMessage * ads_first_message ( ADS_STRUCT * ads , LDAPMessage * res )
{
return ldap_first_message ( ads - > ldap . ld , res ) ;
}
/**
* pull the next message from a ADS result
* @ param ads connection to ads server
* @ param res Results of search
* @ return next message from result
* */
LDAPMessage * ads_next_message ( ADS_STRUCT * ads , LDAPMessage * res )
{
return ldap_next_message ( ads - > ldap . ld , res ) ;
}
2002-04-10 17:28:03 +04:00
/**
* pull a single string from a ADS result
* @ param ads connection to ads server
* @ param mem_ctx TALLOC_CTX to use for allocating result string
* @ param msg Results of search
* @ param field Attribute to retrieve
* @ return Result string in talloc context
* */
2006-09-04 01:07:16 +04:00
char * ads_pull_string ( ADS_STRUCT * ads , TALLOC_CTX * mem_ctx , LDAPMessage * msg ,
const char * field )
2001-12-03 09:04:18 +03:00
{
char * * values ;
2001-12-05 10:35:57 +03:00
char * ret = NULL ;
2002-07-15 14:35:28 +04:00
char * ux_string ;
2008-04-30 01:36:24 +04:00
size_t converted_size ;
2001-12-03 09:04:18 +03:00
2007-07-16 15:08:00 +04:00
values = ldap_get_values ( ads - > ldap . ld , msg , field ) ;
2003-02-05 02:44:28 +03:00
if ( ! values )
return NULL ;
2009-05-31 13:14:06 +04:00
2008-04-30 01:36:24 +04:00
if ( values [ 0 ] & & pull_utf8_talloc ( mem_ctx , & ux_string , values [ 0 ] ,
& converted_size ) )
{
ret = ux_string ;
2001-12-05 10:35:57 +03:00
}
2001-12-03 09:04:18 +03:00
ldap_value_free ( values ) ;
return ret ;
}
2002-07-15 14:35:28 +04:00
/**
* pull an array of strings from a ADS result
* @ param ads connection to ads server
* @ param mem_ctx TALLOC_CTX to use for allocating result string
* @ param msg Results of search
* @ param field Attribute to retrieve
* @ return Result strings in talloc context
* */
2006-09-04 01:07:16 +04:00
char * * ads_pull_strings ( ADS_STRUCT * ads , TALLOC_CTX * mem_ctx ,
LDAPMessage * msg , const char * field ,
size_t * num_values )
2002-07-15 14:35:28 +04:00
{
char * * values ;
char * * ret = NULL ;
2019-01-12 16:59:58 +03:00
size_t i , converted_size ;
2002-07-15 14:35:28 +04:00
2007-07-16 15:08:00 +04:00
values = ldap_get_values ( ads - > ldap . ld , msg , field ) ;
2003-02-05 02:44:28 +03:00
if ( ! values )
return NULL ;
2002-07-15 14:35:28 +04:00
2004-01-05 04:48:21 +03:00
* num_values = ldap_count_values ( values ) ;
2002-07-15 14:35:28 +04:00
2011-06-07 05:30:12 +04:00
ret = talloc_array ( mem_ctx , char * , * num_values + 1 ) ;
2003-02-05 02:44:28 +03:00
if ( ! ret ) {
ldap_value_free ( values ) ;
return NULL ;
}
2002-07-15 14:35:28 +04:00
2004-01-05 04:48:21 +03:00
for ( i = 0 ; i < * num_values ; i + + ) {
2008-04-30 01:36:24 +04:00
if ( ! pull_utf8_talloc ( mem_ctx , & ret [ i ] , values [ i ] ,
& converted_size ) )
{
2003-02-05 02:44:28 +03:00
ldap_value_free ( values ) ;
2002-07-15 14:35:28 +04:00
return NULL ;
}
}
ret [ i ] = NULL ;
ldap_value_free ( values ) ;
return ret ;
}
2004-01-05 04:48:21 +03:00
/**
2022-06-22 21:53:42 +03:00
* pull an array of strings from a ADS result
2004-01-05 04:48:21 +03:00
* ( handle large multivalue attributes with range retrieval )
* @ param ads connection to ads server
* @ param mem_ctx TALLOC_CTX to use for allocating result string
* @ param msg Results of search
* @ param field Attribute to retrieve
* @ param current_strings strings returned by a previous call to this function
* @ param next_attribute The next query should ask for this attribute
* @ param num_values How many values did we get this time ?
* @ param more_values Are there more values to get ?
* @ return Result strings in talloc context
* */
2022-06-22 21:53:42 +03:00
char * * ads_pull_strings_range ( ADS_STRUCT * ads ,
2006-09-04 01:07:16 +04:00
TALLOC_CTX * mem_ctx ,
LDAPMessage * msg , const char * field ,
char * * current_strings ,
const char * * next_attribute ,
size_t * num_strings ,
2007-10-19 04:40:25 +04:00
bool * more_strings )
2004-01-05 04:48:21 +03:00
{
char * attr ;
2023-09-28 06:39:47 +03:00
char * expected_range_attrib , * range_attr = NULL ;
2004-01-05 04:48:21 +03:00
BerElement * ptr = NULL ;
char * * strings ;
char * * new_strings ;
size_t num_new_strings ;
unsigned long int range_start ;
unsigned long int range_end ;
2009-05-31 13:14:06 +04:00
2004-01-05 04:48:21 +03:00
/* we might have been given the whole lot anyway */
if ( ( strings = ads_pull_strings ( ads , mem_ctx , msg , field , num_strings ) ) ) {
* more_strings = False ;
return strings ;
}
expected_range_attrib = talloc_asprintf ( mem_ctx , " %s;Range= " , field ) ;
/* look for Range result */
2022-06-22 21:53:42 +03:00
for ( attr = ldap_first_attribute ( ads - > ldap . ld , ( LDAPMessage * ) msg , & ptr ) ;
attr ;
2007-07-16 15:08:00 +04:00
attr = ldap_next_attribute ( ads - > ldap . ld , ( LDAPMessage * ) msg , ptr ) ) {
2004-01-05 04:48:21 +03:00
/* we ignore the fact that this is utf8, as all attributes are ascii... */
if ( strnequal ( attr , expected_range_attrib , strlen ( expected_range_attrib ) ) ) {
range_attr = attr ;
break ;
}
ldap_memfree ( attr ) ;
}
2023-09-28 06:39:47 +03:00
if ( ! range_attr ) {
2004-01-05 04:48:21 +03:00
ber_free ( ptr , 0 ) ;
2004-02-08 03:31:36 +03:00
/* nothing here - this field is just empty */
2004-01-05 04:48:21 +03:00
* more_strings = False ;
return NULL ;
}
2009-05-31 13:14:06 +04:00
2022-06-22 21:53:42 +03:00
if ( sscanf ( & range_attr [ strlen ( expected_range_attrib ) ] , " %lu-%lu " ,
2004-01-05 04:48:21 +03:00
& range_start , & range_end ) = = 2 ) {
* more_strings = True ;
} else {
2022-06-22 21:53:42 +03:00
if ( sscanf ( & range_attr [ strlen ( expected_range_attrib ) ] , " %lu-* " ,
2004-01-05 04:48:21 +03:00
& range_start ) = = 1 ) {
* more_strings = False ;
} else {
2023-09-01 04:39:18 +03:00
DEBUG ( 1 , ( " ads_pull_strings_range: Cannot parse Range attribute (%s) \n " ,
2004-01-05 15:20:15 +03:00
range_attr ) ) ;
2004-01-05 04:48:21 +03:00
ldap_memfree ( range_attr ) ;
* more_strings = False ;
return NULL ;
}
}
if ( ( * num_strings ) ! = range_start ) {
2004-01-05 15:20:15 +03:00
DEBUG ( 1 , ( " ads_pull_strings_range: Range attribute (%s) doesn't start at %u, but at %lu "
2023-07-05 12:21:39 +03:00
" - aborting range retrieval \n " ,
2005-09-30 21:13:37 +04:00
range_attr , ( unsigned int ) ( * num_strings ) + 1 , range_start ) ) ;
2004-01-05 04:48:21 +03:00
ldap_memfree ( range_attr ) ;
* more_strings = False ;
return NULL ;
}
new_strings = ads_pull_strings ( ads , mem_ctx , msg , range_attr , & num_new_strings ) ;
2009-05-31 13:14:06 +04:00
2004-01-05 04:48:21 +03:00
if ( * more_strings & & ( ( * num_strings + num_new_strings ) ! = ( range_end + 1 ) ) ) {
2004-01-05 15:20:15 +03:00
DEBUG ( 1 , ( " ads_pull_strings_range: Range attribute (%s) tells us we have %lu "
2023-07-05 12:21:39 +03:00
" strings in this bunch, but we only got %lu - aborting range retrieval \n " ,
2022-06-22 21:53:42 +03:00
range_attr , ( unsigned long int ) range_end - range_start + 1 ,
2004-01-05 15:20:15 +03:00
( unsigned long int ) num_new_strings ) ) ;
2004-01-05 04:48:21 +03:00
ldap_memfree ( range_attr ) ;
* more_strings = False ;
return NULL ;
}
2011-06-07 05:10:15 +04:00
strings = talloc_realloc ( mem_ctx , current_strings , char * ,
2004-12-07 21:25:53 +03:00
* num_strings + num_new_strings ) ;
2009-05-31 13:14:06 +04:00
2004-01-05 04:48:21 +03:00
if ( strings = = NULL ) {
ldap_memfree ( range_attr ) ;
* more_strings = False ;
return NULL ;
}
2009-05-31 13:14:06 +04:00
2006-06-17 03:14:12 +04:00
if ( new_strings & & num_new_strings ) {
memcpy ( & strings [ * num_strings ] , new_strings ,
sizeof ( * new_strings ) * num_new_strings ) ;
}
2004-01-05 04:48:21 +03:00
( * num_strings ) + = num_new_strings ;
if ( * more_strings ) {
* next_attribute = talloc_asprintf ( mem_ctx ,
2022-06-22 21:53:42 +03:00
" %s;range=%d-* " ,
2004-02-08 03:31:36 +03:00
field ,
2005-09-30 21:13:37 +04:00
( int ) * num_strings ) ;
2009-05-31 13:14:06 +04:00
2004-01-05 04:48:21 +03:00
if ( ! * next_attribute ) {
DEBUG ( 1 , ( " talloc_asprintf for next attribute failed! \n " ) ) ;
ldap_memfree ( range_attr ) ;
* more_strings = False ;
return NULL ;
}
}
ldap_memfree ( range_attr ) ;
return strings ;
}
2002-07-15 14:35:28 +04:00
2002-04-10 17:28:03 +04:00
/**
2015-04-18 18:40:14 +03:00
* pull a single uint32_t from a ADS result
2002-04-10 17:28:03 +04:00
* @ param ads connection to ads server
* @ param msg Results of search
* @ param field Attribute to retrieve
* @ param v Pointer to int to store result
2023-07-05 12:21:39 +03:00
* @ return boolean indicating success
2001-12-03 09:04:18 +03:00
*/
2007-10-19 04:40:25 +04:00
bool ads_pull_uint32 ( ADS_STRUCT * ads , LDAPMessage * msg , const char * field ,
2015-04-18 18:40:14 +03:00
uint32_t * v )
2001-12-03 09:04:18 +03:00
{
char * * values ;
2007-07-16 15:08:00 +04:00
values = ldap_get_values ( ads - > ldap . ld , msg , field ) ;
2003-02-05 02:44:28 +03:00
if ( ! values )
return False ;
2001-12-05 10:35:57 +03:00
if ( ! values [ 0 ] ) {
ldap_value_free ( values ) ;
return False ;
}
2001-12-03 09:04:18 +03:00
* v = atoi ( values [ 0 ] ) ;
ldap_value_free ( values ) ;
return True ;
}
2002-12-13 22:01:27 +03:00
/**
* pull a single objectGUID from an ADS result
* @ param ads connection to ADS server
* @ param msg results of search
* @ param guid 37 - byte area to receive text guid
* @ return boolean indicating success
* */
2007-10-19 04:40:25 +04:00
bool ads_pull_guid ( ADS_STRUCT * ads , LDAPMessage * msg , struct GUID * guid )
2002-12-13 22:01:27 +03:00
{
2010-09-17 12:04:05 +04:00
DATA_BLOB blob ;
NTSTATUS status ;
2009-05-31 13:14:06 +04:00
2010-09-17 12:04:05 +04:00
if ( ! smbldap_talloc_single_blob ( talloc_tos ( ) , ads - > ldap . ld , msg , " objectGUID " ,
& blob ) ) {
return false ;
2002-12-13 22:01:27 +03:00
}
2010-09-17 12:04:05 +04:00
status = GUID_from_ndr_blob ( & blob , guid ) ;
talloc_free ( blob . data ) ;
return NT_STATUS_IS_OK ( status ) ;
2002-12-13 22:01:27 +03:00
}
2002-04-10 17:28:03 +04:00
/**
2010-05-21 05:25:01 +04:00
* pull a single struct dom_sid from a ADS result
2002-04-10 17:28:03 +04:00
* @ param ads connection to ads server
* @ param msg Results of search
* @ param field Attribute to retrieve
* @ param sid Pointer to sid to store result
2023-07-05 12:21:39 +03:00
* @ return boolean indicating success
2001-12-03 09:04:18 +03:00
*/
2007-10-19 04:40:25 +04:00
bool ads_pull_sid ( ADS_STRUCT * ads , LDAPMessage * msg , const char * field ,
2010-05-21 05:25:01 +04:00
struct dom_sid * sid )
2001-12-03 09:04:18 +03:00
{
2009-05-28 03:02:40 +04:00
return smbldap_pull_sid ( ads - > ldap . ld , msg , field , sid ) ;
2001-12-03 09:04:18 +03:00
}
2002-04-10 17:28:03 +04:00
/**
2010-05-21 05:25:01 +04:00
* pull an array of struct dom_sids from a ADS result
2002-04-10 17:28:03 +04:00
* @ param ads connection to ads server
* @ param mem_ctx TALLOC_CTX for allocating sid array
* @ param msg Results of search
* @ param field Attribute to retrieve
* @ param sids pointer to sid array to allocate
* @ return the count of SIDs pulled
* */
2006-09-04 01:07:16 +04:00
int ads_pull_sids ( ADS_STRUCT * ads , TALLOC_CTX * mem_ctx ,
2010-05-21 05:25:01 +04:00
LDAPMessage * msg , const char * field , struct dom_sid * * sids )
2001-12-04 15:08:16 +03:00
{
struct berval * * values ;
int count , i ;
2007-07-16 15:08:00 +04:00
values = ldap_get_values_len ( ads - > ldap . ld , msg , field ) ;
2001-12-04 15:08:16 +03:00
2003-02-05 02:44:28 +03:00
if ( ! values )
return 0 ;
2001-12-04 15:08:16 +03:00
2003-02-05 02:44:28 +03:00
for ( i = 0 ; values [ i ] ; i + + )
/* nop */ ;
2001-12-04 15:08:16 +03:00
2007-04-30 06:39:34 +04:00
if ( i ) {
2011-06-07 05:30:12 +04:00
( * sids ) = talloc_array ( mem_ctx , struct dom_sid , i ) ;
2007-04-30 06:39:34 +04:00
if ( ! ( * sids ) ) {
ldap_value_free_len ( values ) ;
return 0 ;
}
} else {
( * sids ) = NULL ;
2003-02-05 02:44:28 +03:00
}
2001-12-04 15:08:16 +03:00
count = 0 ;
for ( i = 0 ; values [ i ] ; i + + ) {
2019-03-11 19:11:06 +03:00
ssize_t ret ;
2015-08-24 13:33:28 +03:00
ret = sid_parse ( ( const uint8_t * ) values [ i ] - > bv_val ,
values [ i ] - > bv_len , & ( * sids ) [ count ] ) ;
2019-03-11 19:11:06 +03:00
if ( ret ! = - 1 ) {
2018-12-11 09:44:13 +03:00
struct dom_sid_buf buf ;
DBG_DEBUG ( " pulling SID: %s \n " ,
dom_sid_str_buf ( & ( * sids ) [ count ] , & buf ) ) ;
2003-02-05 02:44:28 +03:00
count + + ;
2003-02-24 05:55:00 +03:00
}
2001-12-04 15:08:16 +03:00
}
2009-05-31 13:14:06 +04:00
2001-12-04 15:08:16 +03:00
ldap_value_free_len ( values ) ;
return count ;
}
2002-10-01 22:26:00 +04:00
/**
2010-05-18 12:29:34 +04:00
* pull a struct security_descriptor from a ADS result
2002-10-01 22:26:00 +04:00
* @ param ads connection to ads server
* @ param mem_ctx TALLOC_CTX for allocating sid array
* @ param msg Results of search
* @ param field Attribute to retrieve
2010-05-18 12:29:34 +04:00
* @ param sd Pointer to * struct security_descriptor to store result ( talloc ( ) ed )
2023-07-05 12:21:39 +03:00
* @ return boolean indicating success
2002-10-01 22:26:00 +04:00
*/
2007-10-19 04:40:25 +04:00
bool ads_pull_sd ( ADS_STRUCT * ads , TALLOC_CTX * mem_ctx ,
2010-05-18 12:29:34 +04:00
LDAPMessage * msg , const char * field ,
struct security_descriptor * * sd )
2002-10-01 22:26:00 +04:00
{
struct berval * * values ;
2007-12-30 00:47:03 +03:00
bool ret = true ;
2002-10-01 22:26:00 +04:00
2007-07-16 15:08:00 +04:00
values = ldap_get_values_len ( ads - > ldap . ld , msg , field ) ;
2002-10-01 22:26:00 +04:00
2007-12-30 00:47:03 +03:00
if ( ! values ) return false ;
2002-10-01 22:26:00 +04:00
if ( values [ 0 ] ) {
2007-12-30 00:47:03 +03:00
NTSTATUS status ;
status = unmarshall_sec_desc ( mem_ctx ,
2015-04-18 18:40:14 +03:00
( uint8_t * ) values [ 0 ] - > bv_val ,
2007-12-30 00:47:03 +03:00
values [ 0 ] - > bv_len , sd ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " unmarshall_sec_desc failed: %s \n " ,
nt_errstr ( status ) ) ) ;
ret = false ;
}
2002-10-01 22:26:00 +04:00
}
2009-05-31 13:14:06 +04:00
2002-10-01 22:26:00 +04:00
ldap_value_free_len ( values ) ;
return ret ;
}
2022-06-22 21:53:42 +03:00
/*
* in order to support usernames longer than 21 characters we need to
* use both the sAMAccountName and the userPrincipalName attributes
2002-10-01 22:26:00 +04:00
* It seems that not all users have the userPrincipalName attribute set
*
* @ param ads connection to ads server
* @ param mem_ctx TALLOC_CTX for allocating sid array
* @ param msg Results of search
* @ return the username
*/
2006-09-04 01:07:16 +04:00
char * ads_pull_username ( ADS_STRUCT * ads , TALLOC_CTX * mem_ctx ,
LDAPMessage * msg )
2002-10-01 22:26:00 +04:00
{
2004-08-27 20:15:23 +04:00
#if 0 /* JERRY */
2002-10-01 22:26:00 +04:00
char * ret , * p ;
2022-06-22 21:53:42 +03:00
/* lookup_name() only works on the sAMAccountName to
2004-08-27 20:15:23 +04:00
returning the username portion of userPrincipalName
breaks winbindd_getpwnam ( ) */
2002-10-01 22:26:00 +04:00
ret = ads_pull_string ( ads , mem_ctx , msg , " userPrincipalName " ) ;
2004-10-27 04:41:41 +04:00
if ( ret & & ( p = strchr_m ( ret , ' @ ' ) ) ) {
2002-10-01 22:26:00 +04:00
* p = 0 ;
return ret ;
}
2004-08-27 20:15:23 +04:00
# endif
2002-10-01 22:26:00 +04:00
return ads_pull_string ( ads , mem_ctx , msg , " sAMAccountName " ) ;
}
2001-12-03 09:04:18 +03:00
2002-04-10 17:28:03 +04:00
/**
* find the update serial number - this is the core of the ldap cache
* @ param ads connection to ads server
* @ param ads connection to ADS server
* @ param usn Pointer to retrieved update serial number
* @ return status of search
* */
2015-04-18 18:40:14 +03:00
ADS_STATUS ads_USN ( ADS_STRUCT * ads , uint32_t * usn )
2001-11-28 06:56:30 +03:00
{
const char * attrs [ ] = { " highestCommittedUSN " , NULL } ;
2001-12-19 15:21:12 +03:00
ADS_STATUS status ;
2006-09-04 01:07:16 +04:00
LDAPMessage * res ;
2001-11-28 06:56:30 +03:00
2003-09-06 22:02:19 +04:00
status = ads_do_search_retry ( ads , " " , LDAP_SCOPE_BASE , " (objectclass=*) " , attrs , & res ) ;
2022-06-22 21:53:42 +03:00
if ( ! ADS_ERR_OK ( status ) )
2003-10-04 01:43:09 +04:00
return status ;
2001-12-19 15:21:12 +03:00
if ( ads_count_replies ( ads , res ) ! = 1 ) {
2006-09-06 16:14:58 +04:00
ads_msgfree ( ads , res ) ;
2001-12-19 15:21:12 +03:00
return ADS_ERROR ( LDAP_NO_RESULTS_RETURNED ) ;
}
2006-09-06 16:14:58 +04:00
if ( ! ads_pull_uint32 ( ads , res , " highestCommittedUSN " , usn ) ) {
ads_msgfree ( ads , res ) ;
return ADS_ERROR ( LDAP_NO_SUCH_ATTRIBUTE ) ;
}
2001-12-05 12:19:25 +03:00
ads_msgfree ( ads , res ) ;
2001-12-19 15:21:12 +03:00
return ADS_SUCCESS ;
2001-11-28 06:56:30 +03:00
}
2002-09-25 19:19:00 +04:00
/* parse a ADS timestring - typical string is
' 20020917091222.0 Z0 ' which means 09 : 12.22 17 th September
2002 , timezone 0 */
static time_t ads_parse_time ( const char * str )
{
struct tm tm ;
ZERO_STRUCT ( tm ) ;
2022-06-22 21:53:42 +03:00
if ( sscanf ( str , " %4d%2d%2d%2d%2d%2d " ,
& tm . tm_year , & tm . tm_mon , & tm . tm_mday ,
2002-09-25 19:19:00 +04:00
& tm . tm_hour , & tm . tm_min , & tm . tm_sec ) ! = 6 ) {
return 0 ;
}
tm . tm_year - = 1900 ;
tm . tm_mon - = 1 ;
return timegm ( & tm ) ;
}
2006-07-11 22:45:22 +04:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-05-12 19:17:35 +04:00
ADS_STATUS ads_current_time ( ADS_STRUCT * ads )
2001-12-08 14:18:56 +03:00
{
2006-05-12 19:17:35 +04:00
const char * attrs [ ] = { " currentTime " , NULL } ;
2001-12-19 15:21:12 +03:00
ADS_STATUS status ;
2006-09-04 01:07:16 +04:00
LDAPMessage * res ;
2002-09-25 19:19:00 +04:00
char * timestr ;
2022-05-24 19:02:04 +03:00
TALLOC_CTX * tmp_ctx = talloc_stackframe ( ) ;
2006-05-12 19:17:35 +04:00
ADS_STRUCT * ads_s = ads ;
2002-09-25 19:19:00 +04:00
2006-05-12 19:17:35 +04:00
/* establish a new ldap tcp session if necessary */
2001-12-08 14:18:56 +03:00
2007-07-16 15:08:00 +04:00
if ( ! ads - > ldap . ld ) {
2020-07-23 05:00:52 +03:00
/*
* ADS_STRUCT may be being reused after a
* DC lookup , so ads - > ldap . ss may already have a
* good address . If not , re - initialize the passed - in
* ADS_STRUCT with the given server . XXXX parameters .
*
* Note that this doesn ' t depend on
* ads - > server . ldap_server ! = NULL ,
* as the case where ads - > server . ldap_server = = NULL and
* ads - > ldap . ss ! = zero_address is precisely the DC
* lookup case where ads - > ldap . ss was found by going
* through ads_find_dc ( ) again we want to avoid repeating .
*/
if ( is_zero_addr ( & ads - > ldap . ss ) ) {
2022-05-26 18:28:34 +03:00
ads_s = ads_init ( tmp_ctx ,
ads - > server . realm ,
2020-07-23 05:00:52 +03:00
ads - > server . workgroup ,
ads - > server . ldap_server ,
ADS_SASL_PLAIN ) ;
if ( ads_s = = NULL ) {
status = ADS_ERROR ( LDAP_NO_MEMORY ) ;
goto done ;
}
2006-05-12 19:17:35 +04:00
}
2022-05-23 15:11:24 +03:00
/*
* Reset ads - > config . flags as it can contain the flags
* returned by the previous CLDAP ping when reusing the struct .
*/
ads_s - > config . flags = 0 ;
2022-04-28 19:43:00 +03:00
status = ads_connect_simple_anon ( ads_s ) ;
2006-05-12 19:17:35 +04:00
if ( ! ADS_ERR_OK ( status ) )
goto done ;
2002-09-25 19:19:00 +04:00
}
2006-05-12 19:17:35 +04:00
status = ads_do_search ( ads_s , " " , LDAP_SCOPE_BASE , " (objectclass=*) " , attrs , & res ) ;
if ( ! ADS_ERR_OK ( status ) ) {
goto done ;
2002-09-25 19:19:00 +04:00
}
2022-05-24 19:02:04 +03:00
timestr = ads_pull_string ( ads_s , tmp_ctx , res , " currentTime " ) ;
2006-05-12 19:17:35 +04:00
if ( ! timestr ) {
2006-09-06 16:14:58 +04:00
ads_msgfree ( ads_s , res ) ;
2006-05-12 19:17:35 +04:00
status = ADS_ERROR ( LDAP_NO_RESULTS_RETURNED ) ;
goto done ;
2005-06-29 18:03:53 +04:00
}
2022-06-22 21:53:42 +03:00
/* but save the time and offset in the original ADS_STRUCT */
2009-05-31 13:14:06 +04:00
2006-05-12 19:17:35 +04:00
ads - > config . current_time = ads_parse_time ( timestr ) ;
2001-12-08 14:18:56 +03:00
2006-05-12 19:17:35 +04:00
if ( ads - > config . current_time ! = 0 ) {
2024-02-27 15:49:08 +03:00
ads - > config . time_offset = ads - > config . current_time - time ( NULL ) ;
DBG_INFO ( " server time offset is %d seconds \n " ,
ads - > config . time_offset ) ;
} else {
ads - > config . time_offset = 0 ;
2001-12-08 14:18:56 +03:00
}
2024-02-27 15:49:08 +03:00
DBG_INFO ( " server time offset is %d seconds \n " ,
ads - > config . time_offset ) ;
2006-05-18 19:08:09 +04:00
ads_msgfree ( ads , res ) ;
2006-05-12 19:17:35 +04:00
status = ADS_SUCCESS ;
2001-12-08 14:18:56 +03:00
2006-05-12 19:17:35 +04:00
done :
2022-05-24 19:02:04 +03:00
TALLOC_FREE ( tmp_ctx ) ;
2001-12-08 14:18:56 +03:00
2006-05-12 19:17:35 +04:00
return status ;
}
2001-12-08 14:18:56 +03:00
2006-07-11 22:45:22 +04:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-04-18 18:40:14 +03:00
ADS_STATUS ads_domain_func_level ( ADS_STRUCT * ads , uint32_t * val )
2006-07-11 22:45:22 +04:00
{
2022-05-24 19:05:38 +03:00
TALLOC_CTX * tmp_ctx = talloc_stackframe ( ) ;
2006-07-11 22:45:22 +04:00
const char * attrs [ ] = { " domainFunctionality " , NULL } ;
ADS_STATUS status ;
2006-09-04 01:07:16 +04:00
LDAPMessage * res ;
2006-07-11 22:45:22 +04:00
ADS_STRUCT * ads_s = ads ;
2009-05-31 13:14:06 +04:00
2006-07-11 22:45:22 +04:00
* val = DS_DOMAIN_FUNCTION_2000 ;
/* establish a new ldap tcp session if necessary */
2007-07-16 15:08:00 +04:00
if ( ! ads - > ldap . ld ) {
2020-07-23 05:03:23 +03:00
/*
* ADS_STRUCT may be being reused after a
* DC lookup , so ads - > ldap . ss may already have a
* good address . If not , re - initialize the passed - in
* ADS_STRUCT with the given server . XXXX parameters .
*
* Note that this doesn ' t depend on
* ads - > server . ldap_server ! = NULL ,
* as the case where ads - > server . ldap_server = = NULL and
* ads - > ldap . ss ! = zero_address is precisely the DC
* lookup case where ads - > ldap . ss was found by going
* through ads_find_dc ( ) again we want to avoid repeating .
*/
if ( is_zero_addr ( & ads - > ldap . ss ) ) {
2022-05-26 18:28:34 +03:00
ads_s = ads_init ( tmp_ctx ,
ads - > server . realm ,
2020-07-23 05:03:23 +03:00
ads - > server . workgroup ,
ads - > server . ldap_server ,
ADS_SASL_PLAIN ) ;
if ( ads_s = = NULL ) {
status = ADS_ERROR_NT ( NT_STATUS_NO_MEMORY ) ;
goto done ;
}
2006-07-11 22:45:22 +04:00
}
2022-05-24 19:06:47 +03:00
/*
* Reset ads - > config . flags as it can contain the flags
* returned by the previous CLDAP ping when reusing the struct .
*/
ads_s - > config . flags = 0 ;
2022-04-28 19:43:00 +03:00
status = ads_connect_simple_anon ( ads_s ) ;
2006-07-11 22:45:22 +04:00
if ( ! ADS_ERR_OK ( status ) )
goto done ;
}
2022-06-22 21:53:42 +03:00
/* If the attribute does not exist assume it is a Windows 2000
2006-07-11 22:45:22 +04:00
functional domain */
2009-05-31 13:14:06 +04:00
2006-07-11 22:45:22 +04:00
status = ads_do_search ( ads_s , " " , LDAP_SCOPE_BASE , " (objectclass=*) " , attrs , & res ) ;
if ( ! ADS_ERR_OK ( status ) ) {
if ( status . err . rc = = LDAP_NO_SUCH_ATTRIBUTE ) {
status = ADS_SUCCESS ;
}
goto done ;
}
if ( ! ads_pull_uint32 ( ads_s , res , " domainFunctionality " , val ) ) {
DEBUG ( 5 , ( " ads_domain_func_level: Failed to pull the domainFunctionality attribute. \n " ) ) ;
}
DEBUG ( 3 , ( " ads_domain_func_level: %d \n " , * val ) ) ;
2009-05-31 13:14:06 +04:00
2022-05-24 19:09:02 +03:00
ads_msgfree ( ads_s , res ) ;
2006-07-11 22:45:22 +04:00
done :
2022-05-24 19:05:38 +03:00
TALLOC_FREE ( tmp_ctx ) ;
2006-07-11 22:45:22 +04:00
return status ;
}
2002-04-10 17:28:03 +04:00
/**
* find the domain sid for our domain
* @ param ads connection to ads server
* @ param sid Pointer to domain sid
* @ return status of search
* */
2010-05-21 05:25:01 +04:00
ADS_STATUS ads_domain_sid ( ADS_STRUCT * ads , struct dom_sid * sid )
2001-12-21 02:35:14 +03:00
{
const char * attrs [ ] = { " objectSid " , NULL } ;
2006-09-04 01:07:16 +04:00
LDAPMessage * res ;
2001-12-21 02:35:14 +03:00
ADS_STATUS rc ;
2022-06-22 21:53:42 +03:00
rc = ads_do_search_retry ( ads , ads - > config . bind_path , LDAP_SCOPE_BASE , " (objectclass=*) " ,
2001-12-21 02:35:14 +03:00
attrs , & res ) ;
if ( ! ADS_ERR_OK ( rc ) ) return rc ;
if ( ! ads_pull_sid ( ads , res , " objectSid " , sid ) ) {
2004-05-07 21:58:06 +04:00
ads_msgfree ( ads , res ) ;
2001-12-21 02:35:14 +03:00
return ADS_ERROR_SYSTEM ( ENOENT ) ;
}
ads_msgfree ( ads , res ) ;
2009-05-31 13:14:06 +04:00
2001-12-21 02:35:14 +03:00
return ADS_SUCCESS ;
}
2006-02-04 01:19:41 +03:00
/**
2022-06-22 21:53:42 +03:00
* find our site name
2006-02-04 01:19:41 +03:00
* @ param ads connection to ads server
* @ param mem_ctx Pointer to talloc context
* @ param site_name Pointer to the sitename
* @ return status of search
* */
ADS_STATUS ads_site_dn ( ADS_STRUCT * ads , TALLOC_CTX * mem_ctx , const char * * site_name )
{
ADS_STATUS status ;
2006-09-04 01:07:16 +04:00
LDAPMessage * res ;
2006-02-04 01:19:41 +03:00
const char * dn , * service_name ;
const char * attrs [ ] = { " dsServiceName " , NULL } ;
status = ads_do_search ( ads , " " , LDAP_SCOPE_BASE , " (objectclass=*) " , attrs , & res ) ;
if ( ! ADS_ERR_OK ( status ) ) {
return status ;
}
service_name = ads_pull_string ( ads , mem_ctx , res , " dsServiceName " ) ;
if ( service_name = = NULL ) {
2006-09-26 20:27:18 +04:00
ads_msgfree ( ads , res ) ;
2006-02-04 01:19:41 +03:00
return ADS_ERROR ( LDAP_NO_RESULTS_RETURNED ) ;
}
2006-09-26 20:27:18 +04:00
ads_msgfree ( ads , res ) ;
2006-02-04 01:19:41 +03:00
/* go up three levels */
dn = ads_parent_dn ( ads_parent_dn ( ads_parent_dn ( service_name ) ) ) ;
if ( dn = = NULL ) {
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
* site_name = talloc_strdup ( mem_ctx , dn ) ;
if ( * site_name = = NULL ) {
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
return status ;
/*
dsServiceName : CN = NTDS Settings , CN = W2K3DC , CN = Servers , CN = Default - First - Site - Name , CN = Sites , CN = Configuration , DC = ber , DC = suse , DC = de
2022-06-22 21:53:42 +03:00
*/
2006-02-04 01:19:41 +03:00
}
/**
* find the site dn where a machine resides
* @ param ads connection to ads server
* @ param mem_ctx Pointer to talloc context
* @ param computer_name name of the machine
* @ param site_name Pointer to the sitename
* @ return status of search
* */
ADS_STATUS ads_site_dn_for_machine ( ADS_STRUCT * ads , TALLOC_CTX * mem_ctx , const char * computer_name , const char * * site_dn )
{
ADS_STATUS status ;
2006-09-04 01:07:16 +04:00
LDAPMessage * res ;
2007-07-18 00:28:31 +04:00
const char * parent , * filter ;
char * config_context = NULL ;
2006-02-04 01:19:41 +03:00
char * dn ;
/* shortcut a query */
if ( strequal ( computer_name , ads - > config . ldap_server_name ) ) {
return ads_site_dn ( ads , mem_ctx , site_dn ) ;
}
2007-07-18 00:28:31 +04:00
status = ads_config_path ( ads , mem_ctx , & config_context ) ;
2006-02-04 01:19:41 +03:00
if ( ! ADS_ERR_OK ( status ) ) {
return status ;
}
filter = talloc_asprintf ( mem_ctx , " (cn=%s) " , computer_name ) ;
if ( filter = = NULL ) {
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
2022-06-22 21:53:42 +03:00
status = ads_do_search ( ads , config_context , LDAP_SCOPE_SUBTREE ,
2007-07-18 00:28:31 +04:00
filter , NULL , & res ) ;
2006-02-04 01:19:41 +03:00
if ( ! ADS_ERR_OK ( status ) ) {
return status ;
}
if ( ads_count_replies ( ads , res ) ! = 1 ) {
2006-09-26 20:27:18 +04:00
ads_msgfree ( ads , res ) ;
2006-02-04 01:19:41 +03:00
return ADS_ERROR ( LDAP_NO_SUCH_OBJECT ) ;
}
2009-03-18 09:35:03 +03:00
dn = ads_get_dn ( ads , mem_ctx , res ) ;
2006-02-04 01:19:41 +03:00
if ( dn = = NULL ) {
2006-09-26 20:27:18 +04:00
ads_msgfree ( ads , res ) ;
2006-02-04 01:19:41 +03:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
/* go up three levels */
parent = ads_parent_dn ( ads_parent_dn ( ads_parent_dn ( dn ) ) ) ;
if ( parent = = NULL ) {
2006-09-26 20:27:18 +04:00
ads_msgfree ( ads , res ) ;
2009-03-18 09:35:03 +03:00
TALLOC_FREE ( dn ) ;
2006-02-04 01:19:41 +03:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
* site_dn = talloc_strdup ( mem_ctx , parent ) ;
if ( * site_dn = = NULL ) {
2006-09-26 20:27:18 +04:00
ads_msgfree ( ads , res ) ;
2009-03-18 09:35:03 +03:00
TALLOC_FREE ( dn ) ;
2007-08-04 14:25:27 +04:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
2006-02-04 01:19:41 +03:00
}
2009-03-18 09:35:03 +03:00
TALLOC_FREE ( dn ) ;
2006-02-04 01:19:41 +03:00
ads_msgfree ( ads , res ) ;
return status ;
}
/**
* get the upn suffixes for a domain
* @ param ads connection to ads server
* @ param mem_ctx Pointer to talloc context
* @ param suffixes Pointer to an array of suffixes
2007-02-15 03:03:38 +03:00
* @ param num_suffixes Pointer to the number of suffixes
2006-02-04 01:19:41 +03:00
* @ return status of search
* */
2007-02-15 03:03:38 +03:00
ADS_STATUS ads_upn_suffixes ( ADS_STRUCT * ads , TALLOC_CTX * mem_ctx , char * * * suffixes , size_t * num_suffixes )
2006-02-04 01:19:41 +03:00
{
ADS_STATUS status ;
2006-09-04 01:07:16 +04:00
LDAPMessage * res ;
2007-07-18 00:28:31 +04:00
const char * base ;
char * config_context = NULL ;
const char * attrs [ ] = { " uPNSuffixes " , NULL } ;
2006-02-04 01:19:41 +03:00
2007-07-18 00:28:31 +04:00
status = ads_config_path ( ads , mem_ctx , & config_context ) ;
2006-02-04 01:19:41 +03:00
if ( ! ADS_ERR_OK ( status ) ) {
return status ;
}
base = talloc_asprintf ( mem_ctx , " cn=Partitions,%s " , config_context ) ;
if ( base = = NULL ) {
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
2007-07-18 00:28:31 +04:00
status = ads_search_dn ( ads , & res , base , attrs ) ;
2006-02-04 01:19:41 +03:00
if ( ! ADS_ERR_OK ( status ) ) {
return status ;
}
if ( ads_count_replies ( ads , res ) ! = 1 ) {
2007-07-18 00:28:31 +04:00
ads_msgfree ( ads , res ) ;
2006-02-04 01:19:41 +03:00
return ADS_ERROR ( LDAP_NO_SUCH_OBJECT ) ;
}
2007-02-15 03:03:38 +03:00
( * suffixes ) = ads_pull_strings ( ads , mem_ctx , res , " uPNSuffixes " , num_suffixes ) ;
if ( ( * suffixes ) = = NULL ) {
2006-02-04 01:19:41 +03:00
ads_msgfree ( ads , res ) ;
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
ads_msgfree ( ads , res ) ;
return status ;
}
2008-01-03 19:28:09 +03:00
/**
* get the joinable ous for a domain
* @ param ads connection to ads server
* @ param mem_ctx Pointer to talloc context
* @ param ous Pointer to an array of ous
* @ param num_ous Pointer to the number of ous
* @ return status of search
* */
ADS_STATUS ads_get_joinable_ous ( ADS_STRUCT * ads ,
TALLOC_CTX * mem_ctx ,
char * * * ous ,
size_t * num_ous )
{
ADS_STATUS status ;
LDAPMessage * res = NULL ;
LDAPMessage * msg = NULL ;
const char * attrs [ ] = { " dn " , NULL } ;
int count = 0 ;
status = ads_search ( ads , & res ,
" (|(objectClass=domain)(objectclass=organizationalUnit)) " ,
attrs ) ;
if ( ! ADS_ERR_OK ( status ) ) {
return status ;
}
count = ads_count_replies ( ads , res ) ;
if ( count < 1 ) {
ads_msgfree ( ads , res ) ;
return ADS_ERROR ( LDAP_NO_RESULTS_RETURNED ) ;
}
for ( msg = ads_first_entry ( ads , res ) ; msg ;
msg = ads_next_entry ( ads , msg ) ) {
2014-02-26 23:16:26 +04:00
const char * * p = discard_const_p ( const char * , * ous ) ;
2008-01-03 19:28:09 +03:00
char * dn = NULL ;
2009-04-07 02:40:46 +04:00
dn = ads_get_dn ( ads , talloc_tos ( ) , msg ) ;
2008-01-03 19:28:09 +03:00
if ( ! dn ) {
ads_msgfree ( ads , res ) ;
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
2014-02-26 23:16:26 +04:00
if ( ! add_string_to_array ( mem_ctx , dn , & p , num_ous ) ) {
2009-03-18 09:35:03 +03:00
TALLOC_FREE ( dn ) ;
2008-01-03 19:28:09 +03:00
ads_msgfree ( ads , res ) ;
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
2009-03-18 09:35:03 +03:00
TALLOC_FREE ( dn ) ;
2014-02-26 23:16:26 +04:00
* ous = discard_const_p ( char * , p ) ;
2008-01-03 19:28:09 +03:00
}
ads_msgfree ( ads , res ) ;
return status ;
}
2006-05-18 23:34:25 +04:00
/**
2010-05-21 05:25:01 +04:00
* pull a struct dom_sid from an extended dn string
2008-11-15 06:16:12 +03:00
* @ param mem_ctx TALLOC_CTX
2007-04-22 19:13:50 +04:00
* @ param extended_dn string
2006-05-18 23:34:25 +04:00
* @ param flags string type of extended_dn
2010-05-21 05:25:01 +04:00
* @ param sid pointer to a struct dom_sid
2008-11-16 00:07:15 +03:00
* @ return NT_STATUS_OK on success ,
* NT_INVALID_PARAMETER on error ,
* NT_STATUS_NOT_FOUND if no SID present
2006-05-18 23:34:25 +04:00
* */
2008-11-16 00:07:15 +03:00
ADS_STATUS ads_get_sid_from_extended_dn ( TALLOC_CTX * mem_ctx ,
const char * extended_dn ,
enum ads_extended_dn_flags flags ,
2010-05-21 05:25:01 +04:00
struct dom_sid * sid )
2006-05-18 23:34:25 +04:00
{
2007-04-22 19:13:50 +04:00
char * p , * q , * dn ;
2006-05-18 23:34:25 +04:00
2007-04-22 19:13:50 +04:00
if ( ! extended_dn ) {
2008-11-16 00:07:15 +03:00
return ADS_ERROR_NT ( NT_STATUS_INVALID_PARAMETER ) ;
2006-05-18 23:34:25 +04:00
}
2007-04-22 19:13:50 +04:00
/* otherwise extended_dn gets stripped off */
if ( ( dn = talloc_strdup ( mem_ctx , extended_dn ) ) = = NULL ) {
2008-11-16 00:07:15 +03:00
return ADS_ERROR_NT ( NT_STATUS_INVALID_PARAMETER ) ;
2007-04-22 19:13:50 +04:00
}
2008-11-15 06:16:12 +03:00
/*
2006-05-18 23:34:25 +04:00
* ADS_EXTENDED_DN_HEX_STRING :
* < GUID = 238e1963 cb390f4bb032ba0105525a29 > ; < SID = 010500000000000515000000 bb68c8fd6b61b427572eb04556040000 > ; CN = gd , OU = berlin , OU = suse , DC = ber , DC = suse , DC = de
*
* ADS_EXTENDED_DN_STRING ( only with w2k3 ) :
2008-11-16 00:07:15 +03:00
* < GUID = 63198e23 - 39 cb - 4 b0f - b032 - ba0105525a29 > ; < SID = S - 1 - 5 - 21 - 4257769659 - 666132843 - 1169174103 - 1110 > ; CN = gd , OU = berlin , OU = suse , DC = ber , DC = suse , DC = de
*
* Object with no SID , such as an Exchange Public Folder
* < GUID = 28907f b4bdf6854993e7f0a10b504e7c > ; CN = public , CN = Microsoft Exchange System Objects , DC = sd2k3ms , DC = west , DC = isilon , DC = com
2006-05-18 23:34:25 +04:00
*/
p = strchr ( dn , ' ; ' ) ;
if ( ! p ) {
2008-11-16 00:07:15 +03:00
return ADS_ERROR_NT ( NT_STATUS_INVALID_PARAMETER ) ;
2006-05-18 23:34:25 +04:00
}
if ( strncmp ( p , " ;<SID= " , strlen ( " ;<SID= " ) ) ! = 0 ) {
2008-11-16 00:07:15 +03:00
DEBUG ( 5 , ( " No SID present in extended dn \n " ) ) ;
return ADS_ERROR_NT ( NT_STATUS_NOT_FOUND ) ;
2006-05-18 23:34:25 +04:00
}
p + = strlen ( " ;<SID= " ) ;
q = strchr ( p , ' > ' ) ;
if ( ! q ) {
2008-11-16 00:07:15 +03:00
return ADS_ERROR_NT ( NT_STATUS_INVALID_PARAMETER ) ;
2006-05-18 23:34:25 +04:00
}
2008-11-15 06:16:12 +03:00
2006-05-18 23:34:25 +04:00
* q = ' \0 ' ;
DEBUG ( 100 , ( " ads_get_sid_from_extended_dn: sid string is %s \n " , p ) ) ;
switch ( flags ) {
2008-11-15 06:16:12 +03:00
2006-05-18 23:34:25 +04:00
case ADS_EXTENDED_DN_STRING :
if ( ! string_to_sid ( sid , p ) ) {
2008-11-16 00:07:15 +03:00
return ADS_ERROR_NT ( NT_STATUS_INVALID_PARAMETER ) ;
2006-05-18 23:34:25 +04:00
}
break ;
case ADS_EXTENDED_DN_HEX_STRING : {
2019-03-11 19:11:06 +03:00
ssize_t ret ;
2007-12-04 04:17:05 +03:00
fstring buf ;
2006-05-18 23:34:25 +04:00
size_t buf_len ;
2007-12-04 04:17:05 +03:00
buf_len = strhex_to_str ( buf , sizeof ( buf ) , p , strlen ( p ) ) ;
2006-05-18 23:34:25 +04:00
if ( buf_len = = 0 ) {
2008-11-16 00:07:15 +03:00
return ADS_ERROR_NT ( NT_STATUS_INVALID_PARAMETER ) ;
2006-05-18 23:34:25 +04:00
}
2019-03-11 18:55:57 +03:00
ret = sid_parse ( ( const uint8_t * ) buf , buf_len , sid ) ;
2019-03-11 19:11:06 +03:00
if ( ret = = - 1 ) {
2006-05-18 23:34:25 +04:00
DEBUG ( 10 , ( " failed to parse sid \n " ) ) ;
2008-11-16 00:07:15 +03:00
return ADS_ERROR_NT ( NT_STATUS_INVALID_PARAMETER ) ;
2006-05-18 23:34:25 +04:00
}
break ;
}
default :
DEBUG ( 10 , ( " unknown extended dn format \n " ) ) ;
2008-11-16 00:07:15 +03:00
return ADS_ERROR_NT ( NT_STATUS_INVALID_PARAMETER ) ;
2006-05-18 23:34:25 +04:00
}
2008-11-16 00:07:15 +03:00
return ADS_ERROR_NT ( NT_STATUS_OK ) ;
2006-05-18 23:34:25 +04:00
}
2006-07-11 22:45:22 +04:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * ads_get_upn ( ADS_STRUCT * ads , TALLOC_CTX * ctx , const char * machine_name )
{
LDAPMessage * res = NULL ;
ADS_STATUS status ;
int count = 0 ;
char * name = NULL ;
2008-01-08 15:46:54 +03:00
status = ads_find_machine_acct ( ads , & res , machine_name ) ;
2006-07-11 22:45:22 +04:00
if ( ! ADS_ERR_OK ( status ) ) {
2006-08-24 19:43:32 +04:00
DEBUG ( 0 , ( " ads_get_upn: Failed to find account for %s \n " ,
2011-06-09 09:31:03 +04:00
lp_netbios_name ( ) ) ) ;
2006-07-11 22:45:22 +04:00
goto out ;
}
2008-01-08 15:46:54 +03:00
2006-07-11 22:45:22 +04:00
if ( ( count = ads_count_replies ( ads , res ) ) ! = 1 ) {
2006-08-24 19:43:32 +04:00
DEBUG ( 1 , ( " ads_get_upn: %d entries returned! \n " , count ) ) ;
2006-07-11 22:45:22 +04:00
goto out ;
}
2008-01-08 15:46:54 +03:00
2006-07-11 22:45:22 +04:00
if ( ( name = ads_pull_string ( ads , ctx , res , " userPrincipalName " ) ) = = NULL ) {
2006-08-24 19:43:32 +04:00
DEBUG ( 2 , ( " ads_get_upn: No userPrincipalName attribute! \n " ) ) ;
2006-07-11 22:45:22 +04:00
}
out :
ads_msgfree ( ads , res ) ;
2008-01-08 15:46:54 +03:00
2006-07-11 22:45:22 +04:00
return name ;
}
2006-09-13 13:03:42 +04:00
#if 0
SAVED CODE - we used to join via ldap - remember how we did this . JRA .
/**
* Join a machine to a realm
* Creates the machine account and sets the machine password
* @ param ads connection to ads server
* @ param machine name of host to add
* @ param org_unit Organizational unit to place machine in
* @ return status of join
* */
ADS_STATUS ads_join_realm ( ADS_STRUCT * ads , const char * machine_name ,
2015-04-18 18:40:14 +03:00
uint32_t account_type , const char * org_unit )
2006-09-13 13:03:42 +04:00
{
ADS_STATUS status ;
LDAPMessage * res = NULL ;
char * machine ;
/* machine name must be lowercase */
machine = SMB_STRDUP ( machine_name ) ;
strlower_m ( machine ) ;
/*
status = ads_find_machine_acct ( ads , ( void * * ) & res , machine ) ;
if ( ADS_ERR_OK ( status ) & & ads_count_replies ( ads , res ) = = 1 ) {
DEBUG ( 0 , ( " Host account for %s already exists - deleting old account \n " , machine ) ) ;
status = ads_leave_realm ( ads , machine ) ;
if ( ! ADS_ERR_OK ( status ) ) {
DEBUG ( 0 , ( " Failed to delete host '%s' from the '%s' realm. \n " ,
machine , ads - > config . realm ) ) ;
return status ;
}
}
*/
status = ads_add_machine_acct ( ads , machine , account_type , org_unit ) ;
if ( ! ADS_ERR_OK ( status ) ) {
DEBUG ( 0 , ( " ads_join_realm: ads_add_machine_acct failed (%s): %s \n " , machine , ads_errstr ( status ) ) ) ;
SAFE_FREE ( machine ) ;
return status ;
}
status = ads_find_machine_acct ( ads , ( void * * ) ( void * ) & res , machine ) ;
if ( ! ADS_ERR_OK ( status ) ) {
DEBUG ( 0 , ( " ads_join_realm: Host account test failed for machine %s \n " , machine ) ) ;
SAFE_FREE ( machine ) ;
return status ;
}
SAFE_FREE ( machine ) ;
ads_msgfree ( ads , res ) ;
return status ;
}
# endif
/**
* Delete a machine from the realm
* @ param ads connection to ads server
* @ param hostname Machine to remove
* @ return status of delete
* */
ADS_STATUS ads_leave_realm ( ADS_STRUCT * ads , const char * hostname )
{
ADS_STATUS status ;
void * msg ;
LDAPMessage * res ;
char * hostnameDN , * host ;
int rc ;
LDAPControl ldap_control ;
LDAPControl * pldap_control [ 2 ] = { NULL , NULL } ;
pldap_control [ 0 ] = & ldap_control ;
memset ( & ldap_control , 0 , sizeof ( LDAPControl ) ) ;
2011-05-06 01:36:55 +04:00
ldap_control . ldctl_oid = discard_const_p ( char , LDAP_SERVER_TREE_DELETE_OID ) ;
2006-09-13 13:03:42 +04:00
/* hostname must be lowercase */
host = SMB_STRDUP ( hostname ) ;
2012-08-09 04:01:00 +04:00
if ( ! strlower_m ( host ) ) {
SAFE_FREE ( host ) ;
return ADS_ERROR_SYSTEM ( EINVAL ) ;
}
2006-09-13 13:03:42 +04:00
status = ads_find_machine_acct ( ads , & res , host ) ;
if ( ! ADS_ERR_OK ( status ) ) {
DEBUG ( 0 , ( " Host account for %s does not exist. \n " , host ) ) ;
SAFE_FREE ( host ) ;
return status ;
}
msg = ads_first_entry ( ads , res ) ;
if ( ! msg ) {
SAFE_FREE ( host ) ;
return ADS_ERROR_SYSTEM ( ENOENT ) ;
}
2009-04-07 02:40:46 +04:00
hostnameDN = ads_get_dn ( ads , talloc_tos ( ) , ( LDAPMessage * ) msg ) ;
2011-04-22 11:48:10 +04:00
if ( hostnameDN = = NULL ) {
SAFE_FREE ( host ) ;
return ADS_ERROR_SYSTEM ( ENOENT ) ;
}
2006-09-13 13:03:42 +04:00
2007-07-16 15:08:00 +04:00
rc = ldap_delete_ext_s ( ads - > ldap . ld , hostnameDN , pldap_control , NULL ) ;
2006-09-13 13:03:42 +04:00
if ( rc ) {
DEBUG ( 3 , ( " ldap_delete_ext_s failed with error code %d \n " , rc ) ) ;
} else {
DEBUG ( 3 , ( " ldap_delete_ext_s succeeded with error code %d \n " , rc ) ) ;
}
if ( rc ! = LDAP_SUCCESS ) {
const char * attrs [ ] = { " cn " , NULL } ;
2006-09-13 15:40:21 +04:00
LDAPMessage * msg_sub ;
2006-09-13 13:03:42 +04:00
/* we only search with scope ONE, we do not expect any further
* objects to be created deeper */
2006-09-13 15:40:21 +04:00
status = ads_do_search_retry ( ads , hostnameDN ,
LDAP_SCOPE_ONELEVEL ,
" (objectclass=*) " , attrs , & res ) ;
2006-09-13 13:03:42 +04:00
if ( ! ADS_ERR_OK ( status ) ) {
SAFE_FREE ( host ) ;
2009-03-18 09:35:03 +03:00
TALLOC_FREE ( hostnameDN ) ;
2006-09-13 13:03:42 +04:00
return status ;
}
for ( msg_sub = ads_first_entry ( ads , res ) ; msg_sub ;
msg_sub = ads_next_entry ( ads , msg_sub ) ) {
char * dn = NULL ;
2009-04-07 02:40:46 +04:00
if ( ( dn = ads_get_dn ( ads , talloc_tos ( ) , msg_sub ) ) = = NULL ) {
2006-09-13 13:03:42 +04:00
SAFE_FREE ( host ) ;
2009-03-18 09:35:03 +03:00
TALLOC_FREE ( hostnameDN ) ;
2006-09-13 13:03:42 +04:00
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
status = ads_del_dn ( ads , dn ) ;
if ( ! ADS_ERR_OK ( status ) ) {
DEBUG ( 3 , ( " failed to delete dn %s: %s \n " , dn , ads_errstr ( status ) ) ) ;
SAFE_FREE ( host ) ;
2009-03-18 09:35:03 +03:00
TALLOC_FREE ( dn ) ;
TALLOC_FREE ( hostnameDN ) ;
2006-09-13 13:03:42 +04:00
return status ;
}
2009-03-18 09:35:03 +03:00
TALLOC_FREE ( dn ) ;
2006-09-13 13:03:42 +04:00
}
/* there should be no subordinate objects anymore */
2006-09-13 15:40:21 +04:00
status = ads_do_search_retry ( ads , hostnameDN ,
LDAP_SCOPE_ONELEVEL ,
" (objectclass=*) " , attrs , & res ) ;
2006-09-13 13:03:42 +04:00
if ( ! ADS_ERR_OK ( status ) | | ( ( ads_count_replies ( ads , res ) ) > 0 ) ) {
SAFE_FREE ( host ) ;
2009-03-18 09:35:03 +03:00
TALLOC_FREE ( hostnameDN ) ;
2006-09-13 13:03:42 +04:00
return status ;
}
/* delete hostnameDN now */
status = ads_del_dn ( ads , hostnameDN ) ;
if ( ! ADS_ERR_OK ( status ) ) {
SAFE_FREE ( host ) ;
DEBUG ( 3 , ( " failed to delete dn %s: %s \n " , hostnameDN , ads_errstr ( status ) ) ) ;
2009-03-18 09:35:03 +03:00
TALLOC_FREE ( hostnameDN ) ;
2006-09-13 13:03:42 +04:00
return status ;
}
}
2009-03-18 09:35:03 +03:00
TALLOC_FREE ( hostnameDN ) ;
2006-09-13 13:03:42 +04:00
status = ads_find_machine_acct ( ads , & res , host ) ;
2019-08-14 14:01:19 +03:00
if ( ( status . error_type = = ENUM_ADS_ERROR_LDAP ) & &
( status . err . rc ! = LDAP_NO_SUCH_OBJECT ) ) {
2006-09-13 13:03:42 +04:00
DEBUG ( 3 , ( " Failed to remove host account. \n " ) ) ;
SAFE_FREE ( host ) ;
return status ;
}
SAFE_FREE ( host ) ;
2019-08-14 14:01:19 +03:00
return ADS_SUCCESS ;
2006-09-13 13:03:42 +04:00
}
2006-09-13 14:03:27 +04:00
2007-05-11 17:33:37 +04:00
/**
* pull all token - sids from an LDAP dn
* @ param ads connection to ads server
* @ param mem_ctx TALLOC_CTX for allocating sid array
* @ param dn of LDAP object
2010-05-21 05:25:01 +04:00
* @ param user_sid pointer to struct dom_sid ( objectSid )
* @ param primary_group_sid pointer to struct dom_sid ( self composed )
2007-05-11 17:33:37 +04:00
* @ param sids pointer to sid array to allocate
* @ param num_sids counter of SIDs pulled
* @ return status of token query
* */
ADS_STATUS ads_get_tokensids ( ADS_STRUCT * ads ,
TALLOC_CTX * mem_ctx ,
const char * dn ,
2010-05-21 05:25:01 +04:00
struct dom_sid * user_sid ,
struct dom_sid * primary_group_sid ,
struct dom_sid * * sids ,
2007-05-11 17:33:37 +04:00
size_t * num_sids )
{
ADS_STATUS status ;
LDAPMessage * res = NULL ;
int count = 0 ;
size_t tmp_num_sids ;
2010-05-21 05:25:01 +04:00
struct dom_sid * tmp_sids ;
struct dom_sid tmp_user_sid ;
struct dom_sid tmp_primary_group_sid ;
2015-04-18 18:40:14 +03:00
uint32_t pgid ;
2007-05-11 17:33:37 +04:00
const char * attrs [ ] = {
" objectSid " ,
" tokenGroups " ,
" primaryGroupID " ,
NULL
} ;
status = ads_search_retry_dn ( ads , & res , dn , attrs ) ;
if ( ! ADS_ERR_OK ( status ) ) {
return status ;
}
count = ads_count_replies ( ads , res ) ;
if ( count ! = 1 ) {
ads_msgfree ( ads , res ) ;
return ADS_ERROR_LDAP ( LDAP_NO_SUCH_OBJECT ) ;
}
if ( ! ads_pull_sid ( ads , res , " objectSid " , & tmp_user_sid ) ) {
ads_msgfree ( ads , res ) ;
return ADS_ERROR_LDAP ( LDAP_NO_MEMORY ) ;
}
if ( ! ads_pull_uint32 ( ads , res , " primaryGroupID " , & pgid ) ) {
ads_msgfree ( ads , res ) ;
return ADS_ERROR_LDAP ( LDAP_NO_MEMORY ) ;
}
{
/* hack to compose the primary group sid without knowing the
* domsid */
2010-05-21 05:25:01 +04:00
struct dom_sid domsid ;
2007-05-11 17:33:37 +04:00
sid_copy ( & domsid , & tmp_user_sid ) ;
2011-03-10 18:19:17 +03:00
if ( ! sid_split_rid ( & domsid , NULL ) ) {
2007-05-11 17:33:37 +04:00
ads_msgfree ( ads , res ) ;
return ADS_ERROR_LDAP ( LDAP_NO_MEMORY ) ;
}
if ( ! sid_compose ( & tmp_primary_group_sid , & domsid , pgid ) ) {
ads_msgfree ( ads , res ) ;
return ADS_ERROR_LDAP ( LDAP_NO_MEMORY ) ;
}
}
tmp_num_sids = ads_pull_sids ( ads , mem_ctx , res , " tokenGroups " , & tmp_sids ) ;
if ( tmp_num_sids = = 0 | | ! tmp_sids ) {
ads_msgfree ( ads , res ) ;
return ADS_ERROR_LDAP ( LDAP_NO_MEMORY ) ;
}
if ( num_sids ) {
* num_sids = tmp_num_sids ;
}
if ( sids ) {
* sids = tmp_sids ;
}
if ( user_sid ) {
* user_sid = tmp_user_sid ;
}
if ( primary_group_sid ) {
* primary_group_sid = tmp_primary_group_sid ;
}
DEBUG ( 10 , ( " ads_get_tokensids: returned %d sids \n " , ( int ) tmp_num_sids + 2 ) ) ;
ads_msgfree ( ads , res ) ;
return ADS_ERROR_LDAP ( LDAP_SUCCESS ) ;
}
2007-07-11 17:17:42 +04:00
/**
2023-09-01 04:39:18 +03:00
* Find a sAMAccountName in LDAP
2007-07-11 17:17:42 +04:00
* @ param ads connection to ads server
* @ param mem_ctx TALLOC_CTX for allocating sid array
* @ param samaccountname to search
2015-04-18 18:40:14 +03:00
* @ param uac_ret uint32_t pointer userAccountControl attribute value
2007-07-11 17:17:42 +04:00
* @ param dn_ret pointer to dn
* @ return status of token query
* */
2007-07-09 20:03:00 +04:00
ADS_STATUS ads_find_samaccount ( ADS_STRUCT * ads ,
TALLOC_CTX * mem_ctx ,
const char * samaccountname ,
2015-04-18 18:40:14 +03:00
uint32_t * uac_ret ,
2007-07-09 20:03:00 +04:00
const char * * dn_ret )
{
ADS_STATUS status ;
const char * attrs [ ] = { " userAccountControl " , NULL } ;
const char * filter ;
LDAPMessage * res = NULL ;
char * dn = NULL ;
2015-04-18 18:40:14 +03:00
uint32_t uac = 0 ;
2007-07-09 20:03:00 +04:00
filter = talloc_asprintf ( mem_ctx , " (&(objectclass=user)(sAMAccountName=%s)) " ,
samaccountname ) ;
if ( filter = = NULL ) {
2008-03-23 21:26:35 +03:00
status = ADS_ERROR_NT ( NT_STATUS_NO_MEMORY ) ;
2007-07-09 20:03:00 +04:00
goto out ;
}
status = ads_do_search_all ( ads , ads - > config . bind_path ,
LDAP_SCOPE_SUBTREE ,
filter , attrs , & res ) ;
2009-05-31 13:14:06 +04:00
2007-07-09 20:03:00 +04:00
if ( ! ADS_ERR_OK ( status ) ) {
goto out ;
}
if ( ads_count_replies ( ads , res ) ! = 1 ) {
2007-07-13 13:53:55 +04:00
status = ADS_ERROR ( LDAP_NO_RESULTS_RETURNED ) ;
2007-07-09 20:03:00 +04:00
goto out ;
}
2009-04-07 02:40:46 +04:00
dn = ads_get_dn ( ads , talloc_tos ( ) , res ) ;
2007-07-09 20:03:00 +04:00
if ( dn = = NULL ) {
status = ADS_ERROR ( LDAP_NO_MEMORY ) ;
goto out ;
}
if ( ! ads_pull_uint32 ( ads , res , " userAccountControl " , & uac ) ) {
status = ADS_ERROR ( LDAP_NO_SUCH_ATTRIBUTE ) ;
goto out ;
}
if ( uac_ret ) {
* uac_ret = uac ;
}
if ( dn_ret ) {
* dn_ret = talloc_strdup ( mem_ctx , dn ) ;
if ( ! * dn_ret ) {
status = ADS_ERROR ( LDAP_NO_MEMORY ) ;
goto out ;
}
}
out :
2009-03-18 09:35:03 +03:00
TALLOC_FREE ( dn ) ;
2007-07-09 20:03:00 +04:00
ads_msgfree ( ads , res ) ;
return status ;
}
2007-07-11 17:26:04 +04:00
/**
2022-06-22 21:53:42 +03:00
* find our configuration path
2007-07-11 17:26:04 +04:00
* @ param ads connection to ads server
* @ param mem_ctx Pointer to talloc context
* @ param config_path Pointer to the config path
* @ return status of search
* */
2022-06-22 21:53:42 +03:00
ADS_STATUS ads_config_path ( ADS_STRUCT * ads ,
TALLOC_CTX * mem_ctx ,
2007-07-11 17:26:04 +04:00
char * * config_path )
{
ADS_STATUS status ;
LDAPMessage * res = NULL ;
const char * config_context = NULL ;
const char * attrs [ ] = { " configurationNamingContext " , NULL } ;
2022-06-22 21:53:42 +03:00
status = ads_do_search ( ads , " " , LDAP_SCOPE_BASE ,
2007-07-11 17:26:04 +04:00
" (objectclass=*) " , attrs , & res ) ;
if ( ! ADS_ERR_OK ( status ) ) {
return status ;
}
2022-06-22 21:53:42 +03:00
config_context = ads_pull_string ( ads , mem_ctx , res ,
2007-07-11 17:26:04 +04:00
" configurationNamingContext " ) ;
ads_msgfree ( ads , res ) ;
if ( ! config_context ) {
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
if ( config_path ) {
* config_path = talloc_strdup ( mem_ctx , config_context ) ;
if ( ! * config_path ) {
return ADS_ERROR ( LDAP_NO_MEMORY ) ;
}
}
return ADS_ERROR ( LDAP_SUCCESS ) ;
}
/**
2022-06-22 21:53:42 +03:00
* find the displayName of an extended right
2007-07-11 17:26:04 +04:00
* @ param ads connection to ads server
* @ param config_path The config path
* @ param mem_ctx Pointer to talloc context
* @ param GUID struct of the rightsGUID
* @ return status of search
* */
2022-06-22 21:53:42 +03:00
const char * ads_get_extended_right_name_by_guid ( ADS_STRUCT * ads ,
const char * config_path ,
TALLOC_CTX * mem_ctx ,
2007-07-11 17:26:04 +04:00
const struct GUID * rights_guid )
{
ADS_STATUS rc ;
LDAPMessage * res = NULL ;
char * expr = NULL ;
const char * attrs [ ] = { " displayName " , NULL } ;
const char * result = NULL ;
const char * path ;
if ( ! ads | | ! mem_ctx | | ! rights_guid ) {
goto done ;
}
2022-06-22 21:53:42 +03:00
expr = talloc_asprintf ( mem_ctx , " (rightsGuid=%s) " ,
2008-10-14 04:26:18 +04:00
GUID_string ( mem_ctx , rights_guid ) ) ;
2007-07-11 17:26:04 +04:00
if ( ! expr ) {
goto done ;
}
path = talloc_asprintf ( mem_ctx , " cn=Extended-Rights,%s " , config_path ) ;
if ( ! path ) {
goto done ;
}
2022-06-22 21:53:42 +03:00
rc = ads_do_search_retry ( ads , path , LDAP_SCOPE_SUBTREE ,
2007-07-11 17:26:04 +04:00
expr , attrs , & res ) ;
if ( ! ADS_ERR_OK ( rc ) ) {
goto done ;
}
if ( ads_count_replies ( ads , res ) ! = 1 ) {
goto done ;
}
result = ads_pull_string ( ads , mem_ctx , res , " displayName " ) ;
done :
ads_msgfree ( ads , res ) ;
return result ;
}
2008-03-28 18:33:54 +03:00
/**
* verify or build and verify an account ou
* @ param mem_ctx Pointer to talloc context
* @ param ads connection to ads server
* @ param account_ou
* @ return status of search
* */
ADS_STATUS ads_check_ou_dn ( TALLOC_CTX * mem_ctx ,
ADS_STRUCT * ads ,
2008-05-15 01:50:25 +04:00
const char * * account_ou )
2008-03-28 18:33:54 +03:00
{
2010-03-01 22:50:50 +03:00
char * * exploded_dn ;
const char * name ;
char * ou_string ;
2016-03-11 14:15:14 +03:00
if ( account_ou = = NULL ) {
return ADS_ERROR_NT ( NT_STATUS_INVALID_PARAMETER ) ;
}
if ( * account_ou ! = NULL ) {
exploded_dn = ldap_explode_dn ( * account_ou , 0 ) ;
if ( exploded_dn ) {
ldap_value_free ( exploded_dn ) ;
return ADS_SUCCESS ;
}
2008-03-28 18:33:54 +03:00
}
2008-05-15 01:50:25 +04:00
ou_string = ads_ou_string ( ads , * account_ou ) ;
2008-03-28 18:33:54 +03:00
if ( ! ou_string ) {
return ADS_ERROR_LDAP ( LDAP_INVALID_DN_SYNTAX ) ;
}
2010-03-01 22:50:50 +03:00
name = talloc_asprintf ( mem_ctx , " %s,%s " , ou_string ,
ads - > config . bind_path ) ;
2008-03-28 18:33:54 +03:00
SAFE_FREE ( ou_string ) ;
2010-03-01 22:50:50 +03:00
if ( ! name ) {
return ADS_ERROR_LDAP ( LDAP_NO_MEMORY ) ;
2008-03-28 18:33:54 +03:00
}
2010-03-01 22:50:50 +03:00
exploded_dn = ldap_explode_dn ( name , 0 ) ;
if ( ! exploded_dn ) {
return ADS_ERROR_LDAP ( LDAP_INVALID_DN_SYNTAX ) ;
2008-03-28 18:33:54 +03:00
}
2010-03-01 22:50:50 +03:00
ldap_value_free ( exploded_dn ) ;
2008-03-28 18:33:54 +03:00
2010-03-01 22:50:50 +03:00
* account_ou = name ;
2008-03-28 18:33:54 +03:00
return ADS_SUCCESS ;
}
2006-09-13 14:03:27 +04:00
# endif