2009-06-06 14:30:57 +04:00
/*
Unix SMB / CIFS implementation .
Infrastructure for async ldap client requests
Copyright ( C ) Volker Lendecke 2009
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
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 .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2015-12-21 13:17:28 +03:00
# include "replace.h"
2010-05-18 02:39:43 +04:00
# include "tldap.h"
2015-12-21 13:17:28 +03:00
# include "system/network.h"
# include "system/locale.h"
# include "lib/util/talloc_stack.h"
# include "lib/util/samba_util.h"
2015-12-21 12:50:59 +03:00
# include "lib/util_tsock.h"
2011-02-24 14:27:29 +03:00
# include "../lib/util/asn1.h"
2011-04-28 19:26:40 +04:00
# include "../lib/tsocket/tsocket.h"
2011-04-28 19:38:09 +04:00
# include "../lib/util/tevent_unix.h"
2009-06-06 14:30:57 +04:00
2016-01-24 13:53:48 +03:00
static TLDAPRC tldap_simple_recv ( struct tevent_req * req ) ;
2011-02-13 01:49:26 +03:00
2016-01-24 13:53:48 +03:00
# define TEVENT_TLDAP_RC_MAGIC (0x87bcd26e)
bool tevent_req_ldap_error ( struct tevent_req * req , TLDAPRC rc )
{
uint64_t err ;
if ( TLDAP_RC_IS_SUCCESS ( rc ) ) {
return false ;
}
err = TEVENT_TLDAP_RC_MAGIC ;
err < < = 32 ;
err | = TLDAP_RC_V ( rc ) ;
return tevent_req_error ( req , err ) ;
}
bool tevent_req_is_ldap_error ( struct tevent_req * req , TLDAPRC * perr )
2009-06-06 14:30:57 +04:00
{
enum tevent_req_state state ;
uint64_t err ;
if ( ! tevent_req_is_error ( req , & state , & err ) ) {
return false ;
}
switch ( state ) {
case TEVENT_REQ_TIMED_OUT :
* perr = TLDAP_TIMEOUT ;
break ;
case TEVENT_REQ_NO_MEMORY :
* perr = TLDAP_NO_MEMORY ;
break ;
case TEVENT_REQ_USER_ERROR :
2016-01-24 13:53:48 +03:00
if ( ( err > > 32 ) ! = TEVENT_TLDAP_RC_MAGIC ) {
abort ( ) ;
}
* perr = TLDAP_RC ( err & 0xffffffff ) ;
2009-06-06 14:30:57 +04:00
break ;
default :
* perr = TLDAP_OPERATIONS_ERROR ;
break ;
}
return true ;
}
2009-06-19 13:45:01 +04:00
struct tldap_ctx_attribute {
char * name ;
void * ptr ;
} ;
2009-06-06 14:30:57 +04:00
struct tldap_context {
int ld_version ;
2009-06-27 20:14:25 +04:00
struct tstream_context * conn ;
2009-06-28 17:29:38 +04:00
bool server_down ;
2009-06-06 14:30:57 +04:00
int msgid ;
struct tevent_queue * outgoing ;
struct tevent_req * * pending ;
/* For the sync wrappers we need something like get_last_error... */
2009-06-20 20:42:18 +04:00
struct tldap_message * last_msg ;
2009-06-12 16:50:46 +04:00
/* debug */
void ( * log_fn ) ( void * context , enum tldap_debug_level level ,
const char * fmt , va_list ap ) ;
void * log_private ;
2009-06-19 13:45:01 +04:00
struct tldap_ctx_attribute * ctx_attrs ;
2009-06-06 14:30:57 +04:00
} ;
struct tldap_message {
struct asn1_data * data ;
uint8_t * inbuf ;
int type ;
int id ;
/* RESULT_ENTRY */
char * dn ;
struct tldap_attribute * attribs ;
2009-06-20 20:42:18 +04:00
/* Error data sent by the server */
2016-01-24 13:53:48 +03:00
TLDAPRC lderr ;
2009-06-20 20:42:18 +04:00
char * res_matcheddn ;
char * res_diagnosticmessage ;
char * res_referral ;
2015-12-27 00:40:36 +03:00
DATA_BLOB res_serverSaslCreds ;
2009-06-20 20:42:18 +04:00
struct tldap_control * res_sctrls ;
/* Controls sent by the server */
struct tldap_control * ctrls ;
2009-06-06 14:30:57 +04:00
} ;
2009-06-12 16:50:46 +04:00
void tldap_set_debug ( struct tldap_context * ld ,
void ( * log_fn ) ( void * log_private ,
enum tldap_debug_level level ,
const char * fmt ,
va_list ap ) PRINTF_ATTRIBUTE ( 3 , 0 ) ,
void * log_private )
{
ld - > log_fn = log_fn ;
ld - > log_private = log_private ;
}
static void tldap_debug ( struct tldap_context * ld ,
enum tldap_debug_level level ,
const char * fmt , . . . )
{
va_list ap ;
if ( ! ld ) {
return ;
}
if ( ld - > log_fn = = NULL ) {
return ;
}
va_start ( ap , fmt ) ;
ld - > log_fn ( ld - > log_private , level , fmt , ap ) ;
va_end ( ap ) ;
}
2009-06-06 14:30:57 +04:00
static int tldap_next_msgid ( struct tldap_context * ld )
{
int result ;
result = ld - > msgid + + ;
if ( ld - > msgid = = 2147483647 ) {
ld - > msgid = 1 ;
}
return result ;
}
struct tldap_context * tldap_context_create ( TALLOC_CTX * mem_ctx , int fd )
{
struct tldap_context * ctx ;
2009-06-27 20:14:25 +04:00
int ret ;
2009-06-06 14:30:57 +04:00
ctx = talloc_zero ( mem_ctx , struct tldap_context ) ;
if ( ctx = = NULL ) {
return NULL ;
}
2009-06-27 20:14:25 +04:00
ret = tstream_bsd_existing_socket ( ctx , fd , & ctx - > conn ) ;
if ( ret = = - 1 ) {
TALLOC_FREE ( ctx ) ;
return NULL ;
}
2009-06-06 14:30:57 +04:00
ctx - > msgid = 1 ;
ctx - > ld_version = 3 ;
ctx - > outgoing = tevent_queue_create ( ctx , " tldap_outgoing " ) ;
if ( ctx - > outgoing = = NULL ) {
TALLOC_FREE ( ctx ) ;
return NULL ;
}
return ctx ;
}
2009-06-28 17:29:38 +04:00
bool tldap_connection_ok ( struct tldap_context * ld )
{
if ( ld = = NULL ) {
return false ;
}
return ! ld - > server_down ;
}
2016-01-31 17:15:46 +03:00
static size_t tldap_pending_reqs ( struct tldap_context * ld )
{
return talloc_array_length ( ld - > pending ) ;
}
2015-12-27 14:37:25 +03:00
struct tstream_context * tldap_get_tstream ( struct tldap_context * ld )
{
return ld - > conn ;
}
void tldap_set_tstream ( struct tldap_context * ld ,
struct tstream_context * stream )
{
ld - > conn = stream ;
}
2009-06-19 13:45:01 +04:00
static struct tldap_ctx_attribute * tldap_context_findattr (
struct tldap_context * ld , const char * name )
{
2016-01-10 13:29:40 +03:00
size_t i , num_attrs ;
2009-06-19 13:45:01 +04:00
num_attrs = talloc_array_length ( ld - > ctx_attrs ) ;
for ( i = 0 ; i < num_attrs ; i + + ) {
if ( strcmp ( ld - > ctx_attrs [ i ] . name , name ) = = 0 ) {
return & ld - > ctx_attrs [ i ] ;
}
}
return NULL ;
}
bool tldap_context_setattr ( struct tldap_context * ld ,
const char * name , const void * _pptr )
{
struct tldap_ctx_attribute * tmp , * attr ;
char * tmpname ;
int num_attrs ;
2011-05-05 21:41:59 +04:00
void * * pptr = ( void * * ) discard_const_p ( void , _pptr ) ;
2009-06-19 13:45:01 +04:00
attr = tldap_context_findattr ( ld , name ) ;
if ( attr ! = NULL ) {
/*
* We don ' t actually delete attrs , we don ' t expect tons of
* attributes being shuffled around .
*/
TALLOC_FREE ( attr - > ptr ) ;
if ( * pptr ! = NULL ) {
attr - > ptr = talloc_move ( ld - > ctx_attrs , pptr ) ;
* pptr = NULL ;
}
return true ;
}
tmpname = talloc_strdup ( ld , name ) ;
if ( tmpname = = NULL ) {
return false ;
}
num_attrs = talloc_array_length ( ld - > ctx_attrs ) ;
tmp = talloc_realloc ( ld , ld - > ctx_attrs , struct tldap_ctx_attribute ,
num_attrs + 1 ) ;
if ( tmp = = NULL ) {
TALLOC_FREE ( tmpname ) ;
return false ;
}
tmp [ num_attrs ] . name = talloc_move ( tmp , & tmpname ) ;
if ( * pptr ! = NULL ) {
tmp [ num_attrs ] . ptr = talloc_move ( tmp , pptr ) ;
} else {
tmp [ num_attrs ] . ptr = NULL ;
}
* pptr = NULL ;
ld - > ctx_attrs = tmp ;
return true ;
}
void * tldap_context_getattr ( struct tldap_context * ld , const char * name )
{
struct tldap_ctx_attribute * attr = tldap_context_findattr ( ld , name ) ;
if ( attr = = NULL ) {
return NULL ;
}
return attr - > ptr ;
}
2009-06-06 14:30:57 +04:00
struct read_ldap_state {
uint8_t * buf ;
bool done ;
} ;
2009-06-27 22:03:55 +04:00
static ssize_t read_ldap_more ( uint8_t * buf , size_t buflen , void * private_data ) ;
static void read_ldap_done ( struct tevent_req * subreq ) ;
static struct tevent_req * read_ldap_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tstream_context * conn )
{
struct tevent_req * req , * subreq ;
struct read_ldap_state * state ;
req = tevent_req_create ( mem_ctx , & state , struct read_ldap_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > done = false ;
subreq = tstream_read_packet_send ( state , ev , conn , 2 , read_ldap_more ,
state ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , read_ldap_done , req ) ;
return req ;
}
2009-06-06 14:30:57 +04:00
static ssize_t read_ldap_more ( uint8_t * buf , size_t buflen , void * private_data )
{
struct read_ldap_state * state = talloc_get_type_abort (
private_data , struct read_ldap_state ) ;
size_t len ;
int i , lensize ;
if ( state - > done ) {
/* We've been here, we're done */
return 0 ;
}
/*
* From ldap . h : LDAP_TAG_MESSAGE is 0x30
*/
if ( buf [ 0 ] ! = 0x30 ) {
return - 1 ;
}
len = buf [ 1 ] ;
if ( ( len & 0x80 ) = = 0 ) {
state - > done = true ;
return len ;
}
lensize = ( len & 0x7f ) ;
len = 0 ;
if ( buflen = = 2 ) {
/* Please get us the full length */
return lensize ;
}
if ( buflen > 2 + lensize ) {
state - > done = true ;
return 0 ;
}
if ( buflen ! = 2 + lensize ) {
return - 1 ;
}
for ( i = 0 ; i < lensize ; i + + ) {
len = ( len < < 8 ) | buf [ 2 + i ] ;
}
return len ;
}
static void read_ldap_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct read_ldap_state * state = tevent_req_data (
req , struct read_ldap_state ) ;
ssize_t nread ;
int err ;
2009-06-27 20:14:25 +04:00
nread = tstream_read_packet_recv ( subreq , state , & state - > buf , & err ) ;
2009-06-06 14:30:57 +04:00
TALLOC_FREE ( subreq ) ;
if ( nread = = - 1 ) {
tevent_req_error ( req , err ) ;
return ;
}
tevent_req_done ( req ) ;
}
static ssize_t read_ldap_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
uint8_t * * pbuf , int * perrno )
{
struct read_ldap_state * state = tevent_req_data (
req , struct read_ldap_state ) ;
if ( tevent_req_is_unix_error ( req , perrno ) ) {
return - 1 ;
}
* pbuf = talloc_move ( mem_ctx , & state - > buf ) ;
return talloc_get_size ( * pbuf ) ;
}
struct tldap_msg_state {
struct tldap_context * ld ;
struct tevent_context * ev ;
int id ;
struct iovec iov ;
struct asn1_data * data ;
uint8_t * inbuf ;
} ;
2014-09-20 02:10:46 +04:00
static bool tldap_push_controls ( struct asn1_data * data ,
2009-06-07 01:21:01 +04:00
struct tldap_control * sctrls ,
int num_sctrls )
{
int i ;
if ( ( sctrls = = NULL ) | | ( num_sctrls = = 0 ) ) {
2014-09-20 02:10:46 +04:00
return true ;
2009-06-07 01:21:01 +04:00
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( data , ASN1_CONTEXT ( 0 ) ) ) return false ;
2009-06-07 01:21:01 +04:00
for ( i = 0 ; i < num_sctrls ; i + + ) {
struct tldap_control * c = & sctrls [ i ] ;
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( data , ASN1_SEQUENCE ( 0 ) ) ) return false ;
if ( ! asn1_write_OctetString ( data , c - > oid , strlen ( c - > oid ) ) ) return false ;
2009-06-07 01:21:01 +04:00
if ( c - > critical ) {
2014-09-20 02:10:46 +04:00
if ( ! asn1_write_BOOLEAN ( data , true ) ) return false ;
2009-06-07 01:21:01 +04:00
}
if ( c - > value . data ! = NULL ) {
2014-09-20 02:10:46 +04:00
if ( ! asn1_write_OctetString ( data , c - > value . data ,
c - > value . length ) ) return false ;
2009-06-07 01:21:01 +04:00
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_pop_tag ( data ) ) return false ; /* ASN1_SEQUENCE(0) */
2009-06-07 01:21:01 +04:00
}
2014-09-20 02:10:46 +04:00
return asn1_pop_tag ( data ) ; /* ASN1_CONTEXT(0) */
2009-06-07 01:21:01 +04:00
}
2009-06-06 14:30:57 +04:00
static void tldap_msg_sent ( struct tevent_req * subreq ) ;
static void tldap_msg_received ( struct tevent_req * subreq ) ;
static struct tevent_req * tldap_msg_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tldap_context * ld ,
2009-06-07 01:21:01 +04:00
int id , struct asn1_data * data ,
struct tldap_control * sctrls ,
int num_sctrls )
2009-06-06 14:30:57 +04:00
{
struct tevent_req * req , * subreq ;
struct tldap_msg_state * state ;
DATA_BLOB blob ;
2009-06-12 16:52:35 +04:00
tldap_debug ( ld , TLDAP_DEBUG_TRACE , " tldap_msg_send: sending msg %d \n " ,
id ) ;
2009-06-06 14:30:57 +04:00
req = tevent_req_create ( mem_ctx , & state , struct tldap_msg_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ld = ld ;
state - > ev = ev ;
state - > id = id ;
2009-06-28 17:29:38 +04:00
if ( state - > ld - > server_down ) {
2016-01-24 13:53:48 +03:00
tevent_req_ldap_error ( req , TLDAP_SERVER_DOWN ) ;
2009-06-28 17:29:38 +04:00
return tevent_req_post ( req , ev ) ;
}
2014-09-20 02:10:46 +04:00
if ( ! tldap_push_controls ( data , sctrls , num_sctrls ) ) {
2016-01-24 13:53:48 +03:00
tevent_req_ldap_error ( req , TLDAP_ENCODING_ERROR ) ;
2014-09-20 02:10:46 +04:00
return tevent_req_post ( req , ev ) ;
}
2009-06-07 01:21:01 +04:00
2014-09-20 02:10:46 +04:00
if ( ! asn1_pop_tag ( data ) ) {
2016-01-24 13:53:48 +03:00
tevent_req_ldap_error ( req , TLDAP_ENCODING_ERROR ) ;
2014-09-20 02:10:46 +04:00
return tevent_req_post ( req , ev ) ;
}
2009-06-06 14:30:57 +04:00
if ( ! asn1_blob ( data , & blob ) ) {
2016-01-24 13:53:48 +03:00
tevent_req_ldap_error ( req , TLDAP_ENCODING_ERROR ) ;
2009-06-06 14:30:57 +04:00
return tevent_req_post ( req , ev ) ;
}
2010-06-21 10:47:38 +04:00
state - > iov . iov_base = ( void * ) blob . data ;
2009-06-06 14:30:57 +04:00
state - > iov . iov_len = blob . length ;
2009-06-27 20:14:25 +04:00
subreq = tstream_writev_queue_send ( state , ev , ld - > conn , ld - > outgoing ,
& state - > iov , 1 ) ;
2009-06-06 14:30:57 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , tldap_msg_sent , req ) ;
return req ;
}
static void tldap_msg_unset_pending ( struct tevent_req * req )
{
struct tldap_msg_state * state = tevent_req_data (
req , struct tldap_msg_state ) ;
struct tldap_context * ld = state - > ld ;
2016-01-31 17:15:46 +03:00
int num_pending = tldap_pending_reqs ( ld ) ;
2009-06-06 14:30:57 +04:00
int i ;
2014-01-08 13:31:15 +04:00
tevent_req_set_cleanup_fn ( req , NULL ) ;
2009-06-06 14:30:57 +04:00
if ( num_pending = = 1 ) {
TALLOC_FREE ( ld - > pending ) ;
return ;
}
for ( i = 0 ; i < num_pending ; i + + ) {
if ( req = = ld - > pending [ i ] ) {
break ;
}
}
if ( i = = num_pending ) {
/*
* Something ' s seriously broken . Just returning here is the
* right thing nevertheless , the point of this routine is to
* remove ourselves from cli - > pending .
*/
return ;
}
/*
* Remove ourselves from the cli - > pending array
*/
if ( num_pending > 1 ) {
ld - > pending [ i ] = ld - > pending [ num_pending - 1 ] ;
}
/*
* No NULL check here , we ' re shrinking by sizeof ( void * ) , and
* talloc_realloc just adjusts the size for this .
*/
ld - > pending = talloc_realloc ( NULL , ld - > pending , struct tevent_req * ,
num_pending - 1 ) ;
}
2014-01-08 13:31:15 +04:00
static void tldap_msg_cleanup ( struct tevent_req * req ,
enum tevent_req_state req_state )
2009-06-06 14:30:57 +04:00
{
2014-01-08 13:31:15 +04:00
switch ( req_state ) {
case TEVENT_REQ_USER_ERROR :
case TEVENT_REQ_RECEIVED :
tldap_msg_unset_pending ( req ) ;
return ;
default :
return ;
}
2009-06-06 14:30:57 +04:00
}
static bool tldap_msg_set_pending ( struct tevent_req * req )
{
struct tldap_msg_state * state = tevent_req_data (
req , struct tldap_msg_state ) ;
struct tldap_context * ld ;
struct tevent_req * * pending ;
int num_pending ;
struct tevent_req * subreq ;
ld = state - > ld ;
2016-01-31 17:15:46 +03:00
num_pending = tldap_pending_reqs ( ld ) ;
2009-06-06 14:30:57 +04:00
pending = talloc_realloc ( ld , ld - > pending , struct tevent_req * ,
num_pending + 1 ) ;
if ( pending = = NULL ) {
return false ;
}
pending [ num_pending ] = req ;
ld - > pending = pending ;
2014-01-08 13:31:15 +04:00
tevent_req_set_cleanup_fn ( req , tldap_msg_cleanup ) ;
2009-06-06 14:30:57 +04:00
if ( num_pending > 0 ) {
return true ;
}
/*
2011-02-12 21:54:26 +03:00
* We ' re the first one , add the read_ldap request that waits for the
2009-06-06 14:30:57 +04:00
* answer from the server
*/
2009-06-27 20:14:25 +04:00
subreq = read_ldap_send ( ld - > pending , state - > ev , ld - > conn ) ;
2009-06-06 14:30:57 +04:00
if ( subreq = = NULL ) {
tldap_msg_unset_pending ( req ) ;
return false ;
}
tevent_req_set_callback ( subreq , tldap_msg_received , ld ) ;
return true ;
}
static void tldap_msg_sent ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2009-06-28 17:29:38 +04:00
struct tldap_msg_state * state = tevent_req_data (
req , struct tldap_msg_state ) ;
2009-06-06 14:30:57 +04:00
ssize_t nwritten ;
int err ;
2009-06-27 20:14:25 +04:00
nwritten = tstream_writev_queue_recv ( subreq , & err ) ;
2009-06-06 14:30:57 +04:00
TALLOC_FREE ( subreq ) ;
if ( nwritten = = - 1 ) {
2009-06-28 17:29:38 +04:00
state - > ld - > server_down = true ;
2016-01-24 13:53:48 +03:00
tevent_req_ldap_error ( req , TLDAP_SERVER_DOWN ) ;
2009-06-06 14:30:57 +04:00
return ;
}
if ( ! tldap_msg_set_pending ( req ) ) {
2011-06-19 23:10:01 +04:00
tevent_req_oom ( req ) ;
2009-06-06 14:30:57 +04:00
return ;
}
}
static int tldap_msg_msgid ( struct tevent_req * req )
{
struct tldap_msg_state * state = tevent_req_data (
req , struct tldap_msg_state ) ;
return state - > id ;
}
static void tldap_msg_received ( struct tevent_req * subreq )
{
struct tldap_context * ld = tevent_req_callback_data (
subreq , struct tldap_context ) ;
struct tevent_req * req ;
struct tldap_msg_state * state ;
struct asn1_data * data ;
uint8_t * inbuf ;
ssize_t received ;
size_t num_pending ;
2016-01-24 13:53:48 +03:00
int i , err ;
TLDAPRC status ;
2009-06-06 14:30:57 +04:00
int id ;
2009-06-12 16:52:35 +04:00
uint8_t type ;
2009-06-06 14:30:57 +04:00
bool ok ;
received = read_ldap_recv ( subreq , talloc_tos ( ) , & inbuf , & err ) ;
TALLOC_FREE ( subreq ) ;
if ( received = = - 1 ) {
2015-12-18 18:31:46 +03:00
ld - > server_down = true ;
2009-06-06 14:30:57 +04:00
status = TLDAP_SERVER_DOWN ;
goto fail ;
}
data = asn1_init ( talloc_tos ( ) ) ;
if ( data = = NULL ) {
status = TLDAP_NO_MEMORY ;
goto fail ;
}
asn1_load_nocopy ( data , inbuf , received ) ;
ok = true ;
ok & = asn1_start_tag ( data , ASN1_SEQUENCE ( 0 ) ) ;
ok & = asn1_read_Integer ( data , & id ) ;
2009-06-12 16:52:35 +04:00
ok & = asn1_peek_uint8 ( data , & type ) ;
2009-06-06 14:30:57 +04:00
if ( ! ok ) {
status = TLDAP_PROTOCOL_ERROR ;
goto fail ;
}
2009-06-12 16:52:35 +04:00
tldap_debug ( ld , TLDAP_DEBUG_TRACE , " tldap_msg_received: got msg %d "
" type %d \n " , id , ( int ) type ) ;
2009-06-06 14:30:57 +04:00
num_pending = talloc_array_length ( ld - > pending ) ;
for ( i = 0 ; i < num_pending ; i + + ) {
if ( id = = tldap_msg_msgid ( ld - > pending [ i ] ) ) {
break ;
}
}
if ( i = = num_pending ) {
/* Dump unexpected reply */
2009-06-12 16:52:35 +04:00
tldap_debug ( ld , TLDAP_DEBUG_WARNING , " tldap_msg_received: "
" No request pending for msg %d \n " , id ) ;
2009-06-28 15:03:14 +04:00
TALLOC_FREE ( data ) ;
2009-06-06 14:30:57 +04:00
TALLOC_FREE ( inbuf ) ;
goto done ;
}
req = ld - > pending [ i ] ;
state = tevent_req_data ( req , struct tldap_msg_state ) ;
state - > inbuf = talloc_move ( state , & inbuf ) ;
state - > data = talloc_move ( state , & data ) ;
2009-06-28 00:28:47 +04:00
tldap_msg_unset_pending ( req ) ;
num_pending = talloc_array_length ( ld - > pending ) ;
2009-06-06 14:30:57 +04:00
tevent_req_done ( req ) ;
done :
2009-06-28 00:28:47 +04:00
if ( num_pending = = 0 ) {
return ;
}
if ( talloc_array_length ( ld - > pending ) > num_pending ) {
/*
* The callback functions called from tevent_req_done ( ) above
* have put something on the pending queue . We don ' t have to
* trigger the read_ldap_send ( ) , tldap_msg_set_pending ( ) has
* done it for us already .
*/
return ;
}
2009-06-27 20:14:25 +04:00
state = tevent_req_data ( ld - > pending [ 0 ] , struct tldap_msg_state ) ;
subreq = read_ldap_send ( ld - > pending , state - > ev , ld - > conn ) ;
2009-06-28 00:28:47 +04:00
if ( subreq = = NULL ) {
status = TLDAP_NO_MEMORY ;
goto fail ;
2009-06-06 14:30:57 +04:00
}
2009-06-28 00:28:47 +04:00
tevent_req_set_callback ( subreq , tldap_msg_received , ld ) ;
2009-06-06 14:30:57 +04:00
return ;
fail :
while ( talloc_array_length ( ld - > pending ) > 0 ) {
req = ld - > pending [ 0 ] ;
2014-01-08 22:46:01 +04:00
state = tevent_req_data ( req , struct tldap_msg_state ) ;
tevent_req_defer_callback ( req , state - > ev ) ;
2016-01-24 13:53:48 +03:00
tevent_req_ldap_error ( req , status ) ;
2009-06-06 14:30:57 +04:00
}
}
2016-01-24 13:53:48 +03:00
static TLDAPRC tldap_msg_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
struct tldap_message * * pmsg )
2009-06-06 14:30:57 +04:00
{
struct tldap_msg_state * state = tevent_req_data (
req , struct tldap_msg_state ) ;
struct tldap_message * msg ;
2016-01-24 13:53:48 +03:00
TLDAPRC err ;
2009-06-06 14:30:57 +04:00
uint8_t msgtype ;
if ( tevent_req_is_ldap_error ( req , & err ) ) {
return err ;
}
if ( ! asn1_peek_uint8 ( state - > data , & msgtype ) ) {
return TLDAP_PROTOCOL_ERROR ;
}
if ( pmsg = = NULL ) {
return TLDAP_SUCCESS ;
}
msg = talloc_zero ( mem_ctx , struct tldap_message ) ;
if ( msg = = NULL ) {
return TLDAP_NO_MEMORY ;
}
msg - > id = state - > id ;
msg - > inbuf = talloc_move ( msg , & state - > inbuf ) ;
msg - > data = talloc_move ( msg , & state - > data ) ;
msg - > type = msgtype ;
* pmsg = msg ;
return TLDAP_SUCCESS ;
}
struct tldap_req_state {
int id ;
struct asn1_data * out ;
struct tldap_message * result ;
} ;
static struct tevent_req * tldap_req_create ( TALLOC_CTX * mem_ctx ,
struct tldap_context * ld ,
struct tldap_req_state * * pstate )
{
struct tevent_req * req ;
struct tldap_req_state * state ;
req = tevent_req_create ( mem_ctx , & state , struct tldap_req_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > out = asn1_init ( state ) ;
if ( state - > out = = NULL ) {
2014-09-20 02:10:46 +04:00
goto err ;
2009-06-06 14:30:57 +04:00
}
state - > id = tldap_next_msgid ( ld ) ;
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( state - > out , ASN1_SEQUENCE ( 0 ) ) ) goto err ;
if ( ! asn1_write_Integer ( state - > out , state - > id ) ) goto err ;
2009-06-06 14:30:57 +04:00
* pstate = state ;
return req ;
2014-09-20 02:10:46 +04:00
err :
TALLOC_FREE ( req ) ;
return NULL ;
2009-06-06 14:30:57 +04:00
}
2009-06-20 20:42:18 +04:00
static void tldap_save_msg ( struct tldap_context * ld , struct tevent_req * req )
2009-06-06 14:30:57 +04:00
{
struct tldap_req_state * state = tevent_req_data (
req , struct tldap_req_state ) ;
2009-06-20 20:42:18 +04:00
TALLOC_FREE ( ld - > last_msg ) ;
ld - > last_msg = talloc_move ( ld , & state - > result ) ;
2009-06-06 14:30:57 +04:00
}
static char * blob2string_talloc ( TALLOC_CTX * mem_ctx , DATA_BLOB blob )
{
char * result = talloc_array ( mem_ctx , char , blob . length + 1 ) ;
2011-02-13 01:41:48 +03:00
if ( result = = NULL ) {
return NULL ;
}
2009-06-06 14:30:57 +04:00
memcpy ( result , blob . data , blob . length ) ;
result [ blob . length ] = ' \0 ' ;
return result ;
}
static bool asn1_read_OctetString_talloc ( TALLOC_CTX * mem_ctx ,
struct asn1_data * data ,
2011-02-13 01:41:48 +03:00
char * * presult )
2009-06-06 14:30:57 +04:00
{
DATA_BLOB string ;
2011-02-13 01:41:48 +03:00
char * result ;
2009-06-06 14:30:57 +04:00
if ( ! asn1_read_OctetString ( data , mem_ctx , & string ) )
return false ;
2011-02-13 01:41:48 +03:00
result = blob2string_talloc ( mem_ctx , string ) ;
2009-06-06 14:30:57 +04:00
data_blob_free ( & string ) ;
2011-02-13 01:41:48 +03:00
if ( result = = NULL ) {
return false ;
}
* presult = result ;
2009-06-06 14:30:57 +04:00
return true ;
}
2009-06-20 20:42:18 +04:00
static bool tldap_decode_controls ( struct tldap_req_state * state ) ;
2009-06-06 14:30:57 +04:00
static bool tldap_decode_response ( struct tldap_req_state * state )
{
struct asn1_data * data = state - > result - > data ;
2009-06-20 20:42:18 +04:00
struct tldap_message * msg = state - > result ;
2016-01-24 13:53:48 +03:00
int rc ;
2009-06-06 14:30:57 +04:00
bool ok = true ;
2016-01-24 13:53:48 +03:00
ok & = asn1_read_enumerated ( data , & rc ) ;
if ( ok ) {
msg - > lderr = TLDAP_RC ( rc ) ;
}
2009-06-20 20:42:18 +04:00
ok & = asn1_read_OctetString_talloc ( msg , data , & msg - > res_matcheddn ) ;
ok & = asn1_read_OctetString_talloc ( msg , data ,
& msg - > res_diagnosticmessage ) ;
2014-09-20 02:10:46 +04:00
if ( ! ok ) return ok ;
2009-06-06 14:30:57 +04:00
if ( asn1_peek_tag ( data , ASN1_CONTEXT ( 3 ) ) ) {
ok & = asn1_start_tag ( data , ASN1_CONTEXT ( 3 ) ) ;
2009-06-20 20:42:18 +04:00
ok & = asn1_read_OctetString_talloc ( msg , data ,
& msg - > res_referral ) ;
2009-06-06 14:30:57 +04:00
ok & = asn1_end_tag ( data ) ;
} else {
2009-06-20 20:42:18 +04:00
msg - > res_referral = NULL ;
2009-06-06 14:30:57 +04:00
}
return ok ;
}
static void tldap_sasl_bind_done ( struct tevent_req * subreq ) ;
struct tevent_req * tldap_sasl_bind_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tldap_context * ld ,
const char * dn ,
const char * mechanism ,
DATA_BLOB * creds ,
2009-06-06 23:06:33 +04:00
struct tldap_control * sctrls ,
int num_sctrls ,
struct tldap_control * cctrls ,
int num_cctrls )
2009-06-06 14:30:57 +04:00
{
struct tevent_req * req , * subreq ;
struct tldap_req_state * state ;
req = tldap_req_create ( mem_ctx , ld , & state ) ;
if ( req = = NULL ) {
return NULL ;
}
if ( dn = = NULL ) {
dn = " " ;
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( state - > out , TLDAP_REQ_BIND ) ) goto err ;
if ( ! asn1_write_Integer ( state - > out , ld - > ld_version ) ) goto err ;
if ( ! asn1_write_OctetString ( state - > out , dn , strlen ( dn ) ) ) goto err ;
2009-06-06 14:30:57 +04:00
if ( mechanism = = NULL ) {
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( state - > out , ASN1_CONTEXT_SIMPLE ( 0 ) ) ) goto err ;
if ( ! asn1_write ( state - > out , creds - > data , creds - > length ) ) goto err ;
if ( ! asn1_pop_tag ( state - > out ) ) goto err ;
2009-06-06 14:30:57 +04:00
} else {
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( state - > out , ASN1_CONTEXT ( 3 ) ) ) goto err ;
if ( ! asn1_write_OctetString ( state - > out , mechanism ,
strlen ( mechanism ) ) ) goto err ;
2009-06-06 14:30:57 +04:00
if ( ( creds ! = NULL ) & & ( creds - > data ! = NULL ) ) {
2014-09-20 02:10:46 +04:00
if ( ! asn1_write_OctetString ( state - > out , creds - > data ,
creds - > length ) ) goto err ;
2009-06-06 14:30:57 +04:00
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_pop_tag ( state - > out ) ) goto err ;
2009-06-06 14:30:57 +04:00
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_pop_tag ( state - > out ) ) goto err ;
2009-06-06 14:30:57 +04:00
2009-06-07 01:21:01 +04:00
subreq = tldap_msg_send ( state , ev , ld , state - > id , state - > out ,
sctrls , num_sctrls ) ;
2009-06-06 14:30:57 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , tldap_sasl_bind_done , req ) ;
return req ;
2014-09-20 02:10:46 +04:00
err :
2016-01-24 13:53:48 +03:00
tevent_req_ldap_error ( req , TLDAP_ENCODING_ERROR ) ;
2014-09-20 02:10:46 +04:00
return tevent_req_post ( req , ev ) ;
2009-06-06 14:30:57 +04:00
}
static void tldap_sasl_bind_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct tldap_req_state * state = tevent_req_data (
req , struct tldap_req_state ) ;
2016-01-24 13:53:48 +03:00
TLDAPRC rc ;
2015-12-27 00:40:36 +03:00
bool ok ;
2009-06-06 14:30:57 +04:00
2016-01-24 13:53:48 +03:00
rc = tldap_msg_recv ( subreq , state , & state - > result ) ;
2009-06-06 14:30:57 +04:00
TALLOC_FREE ( subreq ) ;
2016-01-24 13:53:48 +03:00
if ( tevent_req_ldap_error ( req , rc ) ) {
2009-06-06 14:30:57 +04:00
return ;
}
if ( state - > result - > type ! = TLDAP_RES_BIND ) {
2016-01-24 13:53:48 +03:00
tevent_req_ldap_error ( req , TLDAP_PROTOCOL_ERROR ) ;
2009-06-06 14:30:57 +04:00
return ;
}
2015-12-27 00:40:36 +03:00
ok = asn1_start_tag ( state - > result - > data , TLDAP_RES_BIND ) ;
ok & = tldap_decode_response ( state ) ;
if ( asn1_peek_tag ( state - > result - > data , ASN1_CONTEXT_SIMPLE ( 7 ) ) ) {
int len ;
ok & = asn1_start_tag ( state - > result - > data ,
ASN1_CONTEXT_SIMPLE ( 7 ) ) ;
if ( ! ok ) {
goto decode_error ;
}
len = asn1_tag_remaining ( state - > result - > data ) ;
if ( len = = - 1 ) {
goto decode_error ;
}
state - > result - > res_serverSaslCreds =
data_blob_talloc ( state - > result , NULL , len ) ;
if ( state - > result - > res_serverSaslCreds . data = = NULL ) {
goto decode_error ;
}
ok = asn1_read ( state - > result - > data ,
state - > result - > res_serverSaslCreds . data ,
state - > result - > res_serverSaslCreds . length ) ;
ok & = asn1_end_tag ( state - > result - > data ) ;
2009-06-06 14:30:57 +04:00
}
2015-12-27 00:40:36 +03:00
ok & = asn1_end_tag ( state - > result - > data ) ;
if ( ! ok ) {
goto decode_error ;
}
2016-01-24 13:53:48 +03:00
if ( ! TLDAP_RC_IS_SUCCESS ( state - > result - > lderr ) & &
! TLDAP_RC_EQUAL ( state - > result - > lderr ,
TLDAP_SASL_BIND_IN_PROGRESS ) ) {
tevent_req_ldap_error ( req , state - > result - > lderr ) ;
2009-06-06 14:30:57 +04:00
return ;
}
tevent_req_done ( req ) ;
2015-12-27 00:40:36 +03:00
return ;
decode_error :
2016-01-24 13:53:48 +03:00
tevent_req_ldap_error ( req , TLDAP_DECODING_ERROR ) ;
2015-12-27 00:40:36 +03:00
return ;
2009-06-06 14:30:57 +04:00
}
2016-01-24 13:53:48 +03:00
TLDAPRC tldap_sasl_bind_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
DATA_BLOB * serverSaslCreds )
2009-06-06 14:30:57 +04:00
{
2015-12-27 00:40:36 +03:00
struct tldap_req_state * state = tevent_req_data (
req , struct tldap_req_state ) ;
2016-01-24 13:53:48 +03:00
TLDAPRC rc ;
2015-12-27 00:40:36 +03:00
2016-01-24 13:53:48 +03:00
if ( tevent_req_is_ldap_error ( req , & rc ) ) {
return rc ;
2015-12-27 00:40:36 +03:00
}
if ( serverSaslCreds ! = NULL ) {
serverSaslCreds - > data = talloc_move (
mem_ctx , & state - > result - > res_serverSaslCreds . data ) ;
serverSaslCreds - > length =
state - > result - > res_serverSaslCreds . length ;
}
return state - > result - > lderr ;
2009-06-06 14:30:57 +04:00
}
2016-01-24 13:53:48 +03:00
TLDAPRC tldap_sasl_bind ( struct tldap_context * ld ,
const char * dn ,
const char * mechanism ,
DATA_BLOB * creds ,
struct tldap_control * sctrls ,
int num_sctrls ,
struct tldap_control * cctrls ,
int num_cctrls ,
TALLOC_CTX * mem_ctx ,
DATA_BLOB * serverSaslCreds )
2009-06-06 14:30:57 +04:00
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct tevent_context * ev ;
struct tevent_req * req ;
2016-01-24 13:53:48 +03:00
TLDAPRC rc = TLDAP_NO_MEMORY ;
2009-06-06 14:30:57 +04:00
2013-02-18 12:10:34 +04:00
ev = samba_tevent_context_init ( frame ) ;
2009-06-06 14:30:57 +04:00
if ( ev = = NULL ) {
goto fail ;
}
req = tldap_sasl_bind_send ( frame , ev , ld , dn , mechanism , creds ,
2009-06-06 23:06:33 +04:00
sctrls , num_sctrls , cctrls , num_cctrls ) ;
2009-06-06 14:30:57 +04:00
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll ( req , ev ) ) {
2016-01-24 13:53:48 +03:00
rc = TLDAP_OPERATIONS_ERROR ;
2009-06-06 14:30:57 +04:00
goto fail ;
}
2016-01-24 13:53:48 +03:00
rc = tldap_sasl_bind_recv ( req , mem_ctx , serverSaslCreds ) ;
2009-06-20 20:42:18 +04:00
tldap_save_msg ( ld , req ) ;
2009-06-06 14:30:57 +04:00
fail :
TALLOC_FREE ( frame ) ;
2016-01-24 13:53:48 +03:00
return rc ;
2009-06-06 14:30:57 +04:00
}
struct tevent_req * tldap_simple_bind_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tldap_context * ld ,
const char * dn ,
const char * passwd )
{
DATA_BLOB cred ;
if ( passwd ! = NULL ) {
2011-05-05 21:41:59 +04:00
cred . data = discard_const_p ( uint8_t , passwd ) ;
2009-06-06 14:30:57 +04:00
cred . length = strlen ( passwd ) ;
} else {
2011-05-05 21:41:59 +04:00
cred . data = discard_const_p ( uint8_t , " " ) ;
2009-06-06 14:30:57 +04:00
cred . length = 0 ;
}
2009-06-06 23:06:33 +04:00
return tldap_sasl_bind_send ( mem_ctx , ev , ld , dn , NULL , & cred , NULL , 0 ,
NULL , 0 ) ;
2009-06-06 14:30:57 +04:00
}
2016-01-24 13:53:48 +03:00
TLDAPRC tldap_simple_bind_recv ( struct tevent_req * req )
2009-06-06 14:30:57 +04:00
{
2015-12-27 00:40:36 +03:00
return tldap_sasl_bind_recv ( req , NULL , NULL ) ;
2009-06-06 14:30:57 +04:00
}
2016-01-24 13:53:48 +03:00
TLDAPRC tldap_simple_bind ( struct tldap_context * ld , const char * dn ,
const char * passwd )
2009-06-06 14:30:57 +04:00
{
DATA_BLOB cred ;
if ( passwd ! = NULL ) {
2011-05-05 21:41:59 +04:00
cred . data = discard_const_p ( uint8_t , passwd ) ;
2009-06-06 14:30:57 +04:00
cred . length = strlen ( passwd ) ;
} else {
2011-05-05 21:41:59 +04:00
cred . data = discard_const_p ( uint8_t , " " ) ;
2009-06-06 14:30:57 +04:00
cred . length = 0 ;
}
2015-12-27 00:40:36 +03:00
return tldap_sasl_bind ( ld , dn , NULL , & cred , NULL , 0 , NULL , 0 ,
NULL , NULL ) ;
2009-06-06 14:30:57 +04:00
}
/*****************************************************************************/
2010-03-08 04:20:02 +03:00
/* can't use isalpha() as only a strict set is valid for LDAP */
2010-03-08 09:24:03 +03:00
static bool tldap_is_alpha ( char c )
{
return ( ( ( c > = ' a ' ) & & ( c < = ' z ' ) ) | | \
( ( c > = ' A ' ) & & ( c < = ' Z ' ) ) ) ;
}
static bool tldap_is_adh ( char c )
{
return tldap_is_alpha ( c ) | | isdigit ( c ) | | ( c = = ' - ' ) ;
}
2010-03-08 04:20:02 +03:00
# define TLDAP_FILTER_AND ASN1_CONTEXT(0)
# define TLDAP_FILTER_OR ASN1_CONTEXT(1)
# define TLDAP_FILTER_NOT ASN1_CONTEXT(2)
# define TLDAP_FILTER_EQ ASN1_CONTEXT(3)
# define TLDAP_FILTER_SUB ASN1_CONTEXT(4)
# define TLDAP_FILTER_LE ASN1_CONTEXT(5)
# define TLDAP_FILTER_GE ASN1_CONTEXT(6)
# define TLDAP_FILTER_PRES ASN1_CONTEXT_SIMPLE(7)
# define TLDAP_FILTER_APX ASN1_CONTEXT(8)
# define TLDAP_FILTER_EXT ASN1_CONTEXT(9)
# define TLDAP_SUB_INI ASN1_CONTEXT_SIMPLE(0)
# define TLDAP_SUB_ANY ASN1_CONTEXT_SIMPLE(1)
# define TLDAP_SUB_FIN ASN1_CONTEXT_SIMPLE(2)
/* oid's should be numerical only in theory,
* but apparently some broken servers may have alphanum aliases instead .
* Do like openldap libraries and allow alphanum aliases for oids , but
* do not allow Tagging options in that case .
2009-06-06 14:30:57 +04:00
*/
2010-03-08 04:20:02 +03:00
static bool tldap_is_attrdesc ( const char * s , int len , bool no_tagopts )
{
bool is_oid = false ;
bool dot = false ;
int i ;
/* first char has stricter rules */
if ( isdigit ( * s ) ) {
is_oid = true ;
2010-03-08 09:24:03 +03:00
} else if ( ! tldap_is_alpha ( * s ) ) {
2010-03-08 04:20:02 +03:00
/* bad first char */
return false ;
}
2009-06-06 14:30:57 +04:00
2010-03-08 04:20:02 +03:00
for ( i = 1 ; i < len ; i + + ) {
2009-06-06 14:30:57 +04:00
2010-03-08 04:20:02 +03:00
if ( is_oid ) {
if ( isdigit ( s [ i ] ) ) {
dot = false ;
continue ;
}
if ( s [ i ] = = ' . ' ) {
if ( dot ) {
/* malformed */
return false ;
}
dot = true ;
continue ;
}
} else {
2010-03-08 09:24:03 +03:00
if ( tldap_is_adh ( s [ i ] ) ) {
2010-03-08 04:20:02 +03:00
continue ;
}
}
if ( s [ i ] = = ' ; ' ) {
if ( no_tagopts ) {
/* no tagging options */
return false ;
}
if ( dot ) {
/* malformed */
return false ;
}
if ( ( i + 1 ) = = len ) {
/* malformed */
return false ;
}
is_oid = false ;
continue ;
}
}
if ( dot ) {
/* malformed */
return false ;
}
return true ;
}
/* this function copies the value until the closing parenthesis is found. */
static char * tldap_get_val ( TALLOC_CTX * memctx ,
const char * value , const char * * _s )
2009-06-06 14:30:57 +04:00
{
2010-03-08 04:20:02 +03:00
const char * s = value ;
/* find terminator */
while ( * s ) {
s = strchr ( s , ' ) ' ) ;
if ( s & & ( * ( s - 1 ) = = ' \\ ' ) ) {
continue ;
}
break ;
}
if ( ! s | | ! ( * s = = ' ) ' ) ) {
/* malformed filter */
return NULL ;
}
* _s = s ;
return talloc_strndup ( memctx , value , s - value ) ;
}
static int tldap_hex2char ( const char * x )
{
if ( isxdigit ( x [ 0 ] ) & & isxdigit ( x [ 1 ] ) ) {
const char h1 = x [ 0 ] , h2 = x [ 1 ] ;
2010-07-20 23:54:45 +04:00
int c = 0 ;
2010-03-08 04:20:02 +03:00
if ( h1 > = ' a ' ) c = h1 - ( int ) ' a ' + 10 ;
else if ( h1 > = ' A ' ) c = h1 - ( int ) ' A ' + 10 ;
else if ( h1 > = ' 0 ' ) c = h1 - ( int ) ' 0 ' ;
c = c < < 4 ;
if ( h2 > = ' a ' ) c + = h2 - ( int ) ' a ' + 10 ;
2010-03-10 00:41:44 +03:00
else if ( h2 > = ' A ' ) c + = h2 - ( int ) ' A ' + 10 ;
else if ( h2 > = ' 0 ' ) c + = h2 - ( int ) ' 0 ' ;
2010-03-08 04:20:02 +03:00
return c ;
}
return - 1 ;
}
2009-06-06 14:30:57 +04:00
2010-03-08 04:20:02 +03:00
static bool tldap_find_first_star ( const char * val , const char * * star )
{
const char * s ;
for ( s = val ; * s ; s + + ) {
switch ( * s ) {
case ' \\ ' :
if ( isxdigit ( s [ 1 ] ) & & isxdigit ( s [ 2 ] ) ) {
s + = 2 ;
break ;
}
/* not hex based escape, check older syntax */
switch ( s [ 1 ] ) {
case ' ( ' :
case ' ) ' :
case ' * ' :
case ' \\ ' :
s + + ;
break ;
default :
/* invalid escape sequence */
2009-06-06 14:30:57 +04:00
return false ;
}
2010-03-08 04:20:02 +03:00
break ;
case ' ) ' :
/* end of val, nothing found */
* star = s ;
return true ;
case ' * ' :
* star = s ;
return true ;
2009-06-06 14:30:57 +04:00
}
2010-03-08 04:20:02 +03:00
}
/* string ended without closing parenthesis, filter is malformed */
return false ;
}
static bool tldap_unescape_inplace ( char * value , size_t * val_len )
{
int c , i , p ;
for ( i = 0 , p = 0 ; i < * val_len ; i + + ) {
switch ( value [ i ] ) {
case ' ( ' :
case ' ) ' :
case ' * ' :
/* these must be escaped */
return false ;
case ' \\ ' :
if ( ! value [ i + 1 ] ) {
/* invalid EOL */
return false ;
}
i + + ;
c = tldap_hex2char ( & value [ i ] ) ;
if ( c > = 0 & & c < 256 ) {
value [ p ] = c ;
i + + ;
p + + ;
break ;
}
switch ( value [ i ] ) {
case ' ( ' :
case ' ) ' :
case ' * ' :
case ' \\ ' :
value [ p ] = value [ i ] ;
p + + ;
default :
/* invalid */
return false ;
}
break ;
default :
value [ p ] = value [ i ] ;
p + + ;
}
}
value [ p ] = ' \0 ' ;
* val_len = p ;
return true ;
}
static bool tldap_push_filter_basic ( struct tldap_context * ld ,
struct asn1_data * data ,
const char * * _s ) ;
static bool tldap_push_filter_substring ( struct tldap_context * ld ,
struct asn1_data * data ,
const char * val ,
const char * * _s ) ;
static bool tldap_push_filter_int ( struct tldap_context * ld ,
struct asn1_data * data ,
const char * * _s )
{
const char * s = * _s ;
bool ret ;
if ( * s ! = ' ( ' ) {
tldap_debug ( ld , TLDAP_DEBUG_ERROR ,
" Incomplete or malformed filter \n " ) ;
return false ;
}
s + + ;
/* we are right after a parenthesis,
* find out what op we have at hand */
switch ( * s ) {
case ' & ' :
tldap_debug ( ld , TLDAP_DEBUG_TRACE , " Filter op: AND \n " ) ;
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( data , TLDAP_FILTER_AND ) ) return false ;
2010-03-08 04:20:02 +03:00
s + + ;
break ;
case ' | ' :
tldap_debug ( ld , TLDAP_DEBUG_TRACE , " Filter op: OR \n " ) ;
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( data , TLDAP_FILTER_OR ) ) return false ;
2010-03-08 04:20:02 +03:00
s + + ;
2009-06-06 14:30:57 +04:00
break ;
2010-03-08 04:20:02 +03:00
case ' ! ' :
tldap_debug ( ld , TLDAP_DEBUG_TRACE , " Filter op: NOT \n " ) ;
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( data , TLDAP_FILTER_NOT ) ) return false ;
2010-03-08 04:20:02 +03:00
s + + ;
ret = tldap_push_filter_int ( ld , data , & s ) ;
if ( ! ret ) {
2009-06-06 14:30:57 +04:00
return false ;
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_pop_tag ( data ) ) return false ;
2010-03-08 04:20:02 +03:00
goto done ;
case ' ( ' :
case ' ) ' :
tldap_debug ( ld , TLDAP_DEBUG_ERROR ,
" Invalid parenthesis '%c' \n " , * s ) ;
return false ;
case ' \0 ' :
tldap_debug ( ld , TLDAP_DEBUG_ERROR ,
" Invalid filter termination \n " ) ;
return false ;
2009-06-06 14:30:57 +04:00
2010-03-08 04:20:02 +03:00
default :
ret = tldap_push_filter_basic ( ld , data , & s ) ;
if ( ! ret ) {
return false ;
}
goto done ;
}
/* only and/or filters get here.
* go through the list of filters */
if ( * s = = ' ) ' ) {
/* RFC 4526: empty and/or */
2014-09-20 02:10:46 +04:00
if ( ! asn1_pop_tag ( data ) ) return false ;
2010-03-08 04:20:02 +03:00
goto done ;
}
2009-06-06 14:30:57 +04:00
2010-03-08 04:20:02 +03:00
while ( * s ) {
ret = tldap_push_filter_int ( ld , data , & s ) ;
if ( ! ret ) {
return false ;
2009-06-06 14:30:57 +04:00
}
2010-03-08 04:20:02 +03:00
if ( * s = = ' ) ' ) {
/* end of list, return */
2014-09-20 02:10:46 +04:00
if ( ! asn1_pop_tag ( data ) ) return false ;
2010-03-08 04:20:02 +03:00
break ;
2009-06-06 14:30:57 +04:00
}
2010-03-08 04:20:02 +03:00
}
2009-06-06 14:30:57 +04:00
2010-03-08 04:20:02 +03:00
done :
if ( * s ! = ' ) ' ) {
tldap_debug ( ld , TLDAP_DEBUG_ERROR ,
" Incomplete or malformed filter \n " ) ;
return false ;
}
s + + ;
2016-01-02 20:11:00 +03:00
if ( asn1_has_error ( data ) ) {
2010-03-08 04:20:02 +03:00
return false ;
}
* _s = s ;
return true ;
}
static bool tldap_push_filter_basic ( struct tldap_context * ld ,
struct asn1_data * data ,
const char * * _s )
{
TALLOC_CTX * tmpctx = talloc_tos ( ) ;
const char * s = * _s ;
const char * e ;
const char * eq ;
const char * val ;
const char * type ;
const char * dn ;
const char * rule ;
const char * star ;
2010-07-20 23:54:45 +04:00
size_t type_len = 0 ;
2010-03-08 04:20:02 +03:00
char * uval ;
size_t uval_len ;
bool write_octect = true ;
bool ret ;
eq = strchr ( s , ' = ' ) ;
if ( ! eq ) {
tldap_debug ( ld , TLDAP_DEBUG_ERROR ,
" Invalid filter, missing equal sign \n " ) ;
return false ;
}
val = eq + 1 ;
e = eq - 1 ;
switch ( * e ) {
case ' < ' :
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( data , TLDAP_FILTER_LE ) ) return false ;
2009-06-06 14:30:57 +04:00
break ;
2010-03-08 04:20:02 +03:00
case ' > ' :
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( data , TLDAP_FILTER_GE ) ) return false ;
2009-06-06 14:30:57 +04:00
break ;
2010-03-08 04:20:02 +03:00
case ' ~ ' :
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( data , TLDAP_FILTER_APX ) ) return false ;
2009-06-06 14:30:57 +04:00
break ;
2010-03-08 04:20:02 +03:00
case ' : ' :
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( data , TLDAP_FILTER_EXT ) ) return false ;
2010-03-08 04:20:02 +03:00
write_octect = false ;
type = NULL ;
dn = NULL ;
rule = NULL ;
if ( * s = = ' : ' ) { /* [:dn]:rule:= value */
if ( s = = e ) {
/* malformed filter */
return false ;
}
dn = s ;
} else { /* type[:dn][:rule]:= value */
type = s ;
dn = strchr ( s , ' : ' ) ;
type_len = dn - type ;
if ( dn = = e ) { /* type:= value */
dn = NULL ;
}
}
if ( dn ) {
dn + + ;
rule = strchr ( dn , ' : ' ) ;
2013-02-18 20:30:19 +04:00
if ( rule = = NULL ) {
return false ;
}
2010-03-08 04:20:02 +03:00
if ( ( rule = = dn + 1 ) | | rule + 1 = = e ) {
/* malformed filter, contains "::" */
return false ;
}
2011-05-13 22:23:36 +04:00
if ( strncasecmp_m ( dn , " dn: " , 3 ) ! = 0 ) {
2010-03-08 04:20:02 +03:00
if ( rule = = e ) {
rule = dn ;
dn = NULL ;
} else {
/* malformed filter. With two
* optionals , the first must be " dn "
*/
return false ;
}
} else {
if ( rule = = e ) {
rule = NULL ;
} else {
rule + + ;
}
}
}
if ( ! type & & ! dn & & ! rule ) {
/* malformed filter, there must be at least one */
return false ;
}
2009-06-06 14:30:57 +04:00
/*
MatchingRuleAssertion : : = SEQUENCE {
matchingRule [ 1 ] MatchingRuleID OPTIONAL ,
2010-03-08 04:20:02 +03:00
type [ 2 ] AttributeDescription OPTIONAL ,
2009-06-06 14:30:57 +04:00
matchValue [ 3 ] AssertionValue ,
dnAttributes [ 4 ] BOOLEAN DEFAULT FALSE
}
*/
2010-03-08 04:20:02 +03:00
/* check and add rule */
if ( rule ) {
ret = tldap_is_attrdesc ( rule , e - rule , true ) ;
if ( ! ret ) {
return false ;
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( data , ASN1_CONTEXT_SIMPLE ( 1 ) ) ) return false ;
if ( ! asn1_write ( data , rule , e - rule ) ) return false ;
if ( ! asn1_pop_tag ( data ) ) return false ;
2009-06-06 14:30:57 +04:00
}
2010-03-08 04:20:02 +03:00
/* check and add type */
if ( type ) {
ret = tldap_is_attrdesc ( type , type_len , false ) ;
if ( ! ret ) {
return false ;
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( data , ASN1_CONTEXT_SIMPLE ( 2 ) ) ) return false ;
if ( ! asn1_write ( data , type , type_len ) ) return false ;
if ( ! asn1_pop_tag ( data ) ) return false ;
2009-06-06 14:30:57 +04:00
}
2010-03-08 04:20:02 +03:00
uval = tldap_get_val ( tmpctx , val , _s ) ;
if ( ! uval ) {
return false ;
}
uval_len = * _s - val ;
ret = tldap_unescape_inplace ( uval , & uval_len ) ;
if ( ! ret ) {
return false ;
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( data , ASN1_CONTEXT_SIMPLE ( 3 ) ) ) return false ;
if ( ! asn1_write ( data , uval , uval_len ) ) return false ;
if ( ! asn1_pop_tag ( data ) ) return false ;
2010-03-08 04:20:02 +03:00
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( data , ASN1_CONTEXT_SIMPLE ( 4 ) ) ) return false ;
if ( ! asn1_write_uint8 ( data , dn ? 1 : 0 ) ) return false ;
if ( ! asn1_pop_tag ( data ) ) return false ;
2009-06-06 14:30:57 +04:00
break ;
default :
2010-03-08 04:20:02 +03:00
e = eq ;
ret = tldap_is_attrdesc ( s , e - s , false ) ;
if ( ! ret ) {
return false ;
}
if ( strncmp ( val , " *) " , 2 ) = = 0 ) {
/* presence */
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( data , TLDAP_FILTER_PRES ) ) return false ;
if ( ! asn1_write ( data , s , e - s ) ) return false ;
2010-03-08 04:20:02 +03:00
* _s = val + 1 ;
write_octect = false ;
break ;
}
ret = tldap_find_first_star ( val , & star ) ;
if ( ! ret ) {
return false ;
}
if ( * star = = ' * ' ) {
/* substring */
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( data , TLDAP_FILTER_SUB ) ) return false ;
if ( ! asn1_write_OctetString ( data , s , e - s ) ) return false ;
2010-03-08 04:20:02 +03:00
ret = tldap_push_filter_substring ( ld , data , val , & s ) ;
if ( ! ret ) {
return false ;
}
* _s = s ;
write_octect = false ;
break ;
}
/* if nothing else, then it is just equality */
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( data , TLDAP_FILTER_EQ ) ) return false ;
2010-03-08 04:20:02 +03:00
write_octect = true ;
break ;
}
if ( write_octect ) {
uval = tldap_get_val ( tmpctx , val , _s ) ;
if ( ! uval ) {
return false ;
}
uval_len = * _s - val ;
ret = tldap_unescape_inplace ( uval , & uval_len ) ;
if ( ! ret ) {
return false ;
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_write_OctetString ( data , s , e - s ) ) return false ;
if ( ! asn1_write_OctetString ( data , uval , uval_len ) ) return false ;
2010-03-08 04:20:02 +03:00
}
2016-01-02 20:11:00 +03:00
if ( asn1_has_error ( data ) ) {
2009-06-06 14:30:57 +04:00
return false ;
}
2014-09-20 02:10:46 +04:00
return asn1_pop_tag ( data ) ;
2010-03-08 04:20:02 +03:00
}
static bool tldap_push_filter_substring ( struct tldap_context * ld ,
struct asn1_data * data ,
const char * val ,
const char * * _s )
{
TALLOC_CTX * tmpctx = talloc_tos ( ) ;
bool initial = true ;
const char * star ;
char * chunk ;
size_t chunk_len ;
bool ret ;
/*
SubstringFilter : : = SEQUENCE {
type AttributeDescription ,
- - at least one must be present
substrings SEQUENCE OF CHOICE {
initial [ 0 ] LDAPString ,
any [ 1 ] LDAPString ,
final [ 2 ] LDAPString } }
*/
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( data , ASN1_SEQUENCE ( 0 ) ) ) return false ;
2010-03-08 04:20:02 +03:00
do {
ret = tldap_find_first_star ( val , & star ) ;
if ( ! ret ) {
return false ;
}
chunk_len = star - val ;
switch ( * star ) {
case ' * ' :
if ( ! initial & & chunk_len = = 0 ) {
/* found '**', which is illegal */
return false ;
}
break ;
case ' ) ' :
if ( initial ) {
/* no stars ?? */
return false ;
}
/* we are done */
break ;
default :
/* ?? */
return false ;
}
if ( initial & & chunk_len = = 0 ) {
val = star + 1 ;
initial = false ;
continue ;
}
chunk = talloc_strndup ( tmpctx , val , chunk_len ) ;
if ( ! chunk ) {
return false ;
}
ret = tldap_unescape_inplace ( chunk , & chunk_len ) ;
if ( ! ret ) {
return false ;
}
switch ( * star ) {
case ' * ' :
if ( initial ) {
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( data , TLDAP_SUB_INI ) ) return false ;
2010-03-08 04:20:02 +03:00
initial = false ;
} else {
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( data , TLDAP_SUB_ANY ) ) return false ;
2010-03-08 04:20:02 +03:00
}
break ;
case ' ) ' :
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( data , TLDAP_SUB_FIN ) ) return false ;
2010-03-08 04:20:02 +03:00
break ;
default :
/* ?? */
return false ;
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_write ( data , chunk , chunk_len ) ) return false ;
if ( ! asn1_pop_tag ( data ) ) return false ;
2010-03-08 04:20:02 +03:00
val = star + 1 ;
} while ( * star = = ' * ' ) ;
* _s = star ;
/* end of sequence */
2014-09-20 02:10:46 +04:00
return asn1_pop_tag ( data ) ;
2009-06-06 14:30:57 +04:00
}
2010-03-08 04:20:02 +03:00
/* NOTE: although openldap libraries allow for spaces in some places, mosly
* around parenthesis , we do not allow any spaces ( except in values of
* course ) as I couldn ' t fine any place in RFC 4512 or RFC 4515 where
* leading or trailing spaces where allowed .
*/
static bool tldap_push_filter ( struct tldap_context * ld ,
struct asn1_data * data ,
const char * filter )
2009-06-06 14:30:57 +04:00
{
2010-03-08 04:20:02 +03:00
const char * s = filter ;
2009-06-06 14:30:57 +04:00
bool ret ;
2010-03-08 04:20:02 +03:00
ret = tldap_push_filter_int ( ld , data , & s ) ;
if ( ret & & * s ) {
tldap_debug ( ld , TLDAP_DEBUG_ERROR ,
" Incomplete or malformed filter \n " ) ;
2009-06-06 14:30:57 +04:00
return false ;
}
return ret ;
}
/*****************************************************************************/
static void tldap_search_done ( struct tevent_req * subreq ) ;
struct tevent_req * tldap_search_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tldap_context * ld ,
const char * base , int scope ,
const char * filter ,
const char * * attrs ,
int num_attrs ,
int attrsonly ,
2009-06-06 23:06:33 +04:00
struct tldap_control * sctrls ,
int num_sctrls ,
struct tldap_control * cctrls ,
int num_cctrls ,
2009-06-06 14:30:57 +04:00
int timelimit ,
int sizelimit ,
int deref )
{
struct tevent_req * req , * subreq ;
struct tldap_req_state * state ;
int i ;
req = tldap_req_create ( mem_ctx , ld , & state ) ;
if ( req = = NULL ) {
return NULL ;
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( state - > out , TLDAP_REQ_SEARCH ) ) goto encoding_error ;
if ( ! asn1_write_OctetString ( state - > out , base , strlen ( base ) ) ) goto encoding_error ;
if ( ! asn1_write_enumerated ( state - > out , scope ) ) goto encoding_error ;
if ( ! asn1_write_enumerated ( state - > out , deref ) ) goto encoding_error ;
if ( ! asn1_write_Integer ( state - > out , sizelimit ) ) goto encoding_error ;
if ( ! asn1_write_Integer ( state - > out , timelimit ) ) goto encoding_error ;
if ( ! asn1_write_BOOLEAN ( state - > out , attrsonly ) ) goto encoding_error ;
2009-06-06 14:30:57 +04:00
2010-03-08 04:20:02 +03:00
if ( ! tldap_push_filter ( ld , state - > out , filter ) ) {
2009-06-06 14:30:57 +04:00
goto encoding_error ;
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( state - > out , ASN1_SEQUENCE ( 0 ) ) ) goto encoding_error ;
2009-06-06 14:30:57 +04:00
for ( i = 0 ; i < num_attrs ; i + + ) {
2014-09-20 02:10:46 +04:00
if ( ! asn1_write_OctetString ( state - > out , attrs [ i ] , strlen ( attrs [ i ] ) ) ) goto encoding_error ;
2009-06-06 14:30:57 +04:00
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_pop_tag ( state - > out ) ) goto encoding_error ;
if ( ! asn1_pop_tag ( state - > out ) ) goto encoding_error ;
2009-06-06 14:30:57 +04:00
2009-06-07 01:21:01 +04:00
subreq = tldap_msg_send ( state , ev , ld , state - > id , state - > out ,
sctrls , num_sctrls ) ;
2009-06-06 14:30:57 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , tldap_search_done , req ) ;
return req ;
encoding_error :
2016-01-24 13:53:48 +03:00
tevent_req_ldap_error ( req , TLDAP_ENCODING_ERROR ) ;
2009-06-06 14:30:57 +04:00
return tevent_req_post ( req , ev ) ;
}
static void tldap_search_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct tldap_req_state * state = tevent_req_data (
req , struct tldap_req_state ) ;
2016-01-24 13:53:48 +03:00
TLDAPRC rc ;
2009-06-06 14:30:57 +04:00
2016-01-24 13:53:48 +03:00
rc = tldap_msg_recv ( subreq , state , & state - > result ) ;
if ( tevent_req_ldap_error ( req , rc ) ) {
2009-06-06 14:30:57 +04:00
return ;
}
switch ( state - > result - > type ) {
case TLDAP_RES_SEARCH_ENTRY :
case TLDAP_RES_SEARCH_REFERENCE :
if ( ! tldap_msg_set_pending ( subreq ) ) {
2011-06-19 23:10:01 +04:00
tevent_req_oom ( req ) ;
2009-06-06 14:30:57 +04:00
return ;
}
2011-03-20 12:35:18 +03:00
tevent_req_notify_callback ( req ) ;
2009-06-06 14:30:57 +04:00
break ;
case TLDAP_RES_SEARCH_RESULT :
TALLOC_FREE ( subreq ) ;
if ( ! asn1_start_tag ( state - > result - > data ,
state - > result - > type ) | |
! tldap_decode_response ( state ) | |
2009-06-20 20:42:18 +04:00
! asn1_end_tag ( state - > result - > data ) | |
! tldap_decode_controls ( state ) ) {
2016-01-24 13:53:48 +03:00
tevent_req_ldap_error ( req , TLDAP_DECODING_ERROR ) ;
2009-06-06 14:30:57 +04:00
return ;
}
tevent_req_done ( req ) ;
break ;
default :
2016-01-24 13:53:48 +03:00
tevent_req_ldap_error ( req , TLDAP_PROTOCOL_ERROR ) ;
2009-06-06 14:30:57 +04:00
return ;
}
}
2016-01-24 13:53:48 +03:00
TLDAPRC tldap_search_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
struct tldap_message * * pmsg )
2009-06-06 14:30:57 +04:00
{
struct tldap_req_state * state = tevent_req_data (
req , struct tldap_req_state ) ;
2016-01-24 13:53:48 +03:00
TLDAPRC rc ;
2009-06-06 14:30:57 +04:00
if ( ! tevent_req_is_in_progress ( req )
2016-01-24 13:53:48 +03:00
& & tevent_req_is_ldap_error ( req , & rc ) ) {
return rc ;
2009-06-06 14:30:57 +04:00
}
if ( tevent_req_is_in_progress ( req ) ) {
switch ( state - > result - > type ) {
case TLDAP_RES_SEARCH_ENTRY :
case TLDAP_RES_SEARCH_REFERENCE :
break ;
default :
return TLDAP_OPERATIONS_ERROR ;
}
}
2009-06-19 19:36:38 +04:00
* pmsg = talloc_move ( mem_ctx , & state - > result ) ;
2009-06-06 14:30:57 +04:00
return TLDAP_SUCCESS ;
}
2015-12-22 15:32:01 +03:00
struct tldap_search_all_state {
struct tldap_message * * msgs ;
struct tldap_message * result ;
} ;
static void tldap_search_all_done ( struct tevent_req * subreq ) ;
struct tevent_req * tldap_search_all_send (
TALLOC_CTX * mem_ctx , struct tevent_context * ev ,
struct tldap_context * ld , const char * base , int scope ,
const char * filter , const char * * attrs , int num_attrs , int attrsonly ,
struct tldap_control * sctrls , int num_sctrls ,
struct tldap_control * cctrls , int num_cctrls ,
int timelimit , int sizelimit , int deref )
{
struct tevent_req * req , * subreq ;
struct tldap_search_all_state * state ;
req = tevent_req_create ( mem_ctx , & state ,
struct tldap_search_all_state ) ;
if ( req = = NULL ) {
return NULL ;
}
subreq = tldap_search_send ( state , ev , ld , base , scope , filter ,
attrs , num_attrs , attrsonly ,
sctrls , num_sctrls , cctrls , num_cctrls ,
timelimit , sizelimit , deref ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , tldap_search_all_done , req ) ;
return req ;
}
static void tldap_search_all_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct tldap_search_all_state * state = tevent_req_data (
req , struct tldap_search_all_state ) ;
struct tldap_message * msg , * * tmp ;
size_t num_msgs ;
TLDAPRC rc ;
int msgtype ;
rc = tldap_search_recv ( subreq , state , & msg ) ;
/* No TALLOC_FREE(subreq), this is multi-step */
if ( tevent_req_ldap_error ( req , rc ) ) {
TALLOC_FREE ( subreq ) ;
return ;
}
msgtype = tldap_msg_type ( msg ) ;
if ( msgtype = = TLDAP_RES_SEARCH_RESULT ) {
state - > result = msg ;
tevent_req_done ( req ) ;
return ;
}
num_msgs = talloc_array_length ( state - > msgs ) ;
tmp = talloc_realloc ( state , state - > msgs , struct tldap_message * ,
num_msgs + 1 ) ;
if ( tevent_req_nomem ( tmp , req ) ) {
return ;
}
state - > msgs = tmp ;
state - > msgs [ num_msgs ] = talloc_move ( state - > msgs , & msg ) ;
}
TLDAPRC tldap_search_all_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
struct tldap_message * * * msgs ,
struct tldap_message * * result )
{
struct tldap_search_all_state * state = tevent_req_data (
req , struct tldap_search_all_state ) ;
TLDAPRC rc ;
if ( tevent_req_is_ldap_error ( req , & rc ) ) {
return rc ;
}
if ( msgs ! = NULL ) {
* msgs = talloc_move ( mem_ctx , & state - > msgs ) ;
}
if ( result ! = NULL ) {
* result = talloc_move ( mem_ctx , & state - > result ) ;
}
return TLDAP_SUCCESS ;
}
2016-01-24 13:53:48 +03:00
TLDAPRC tldap_search ( struct tldap_context * ld ,
const char * base , int scope , const char * filter ,
const char * * attrs , int num_attrs , int attrsonly ,
struct tldap_control * sctrls , int num_sctrls ,
struct tldap_control * cctrls , int num_cctrls ,
int timelimit , int sizelimit , int deref ,
2016-01-31 17:29:29 +03:00
TALLOC_CTX * mem_ctx , struct tldap_message * * * pmsgs )
2009-06-06 14:30:57 +04:00
{
2016-01-31 17:29:29 +03:00
TALLOC_CTX * frame ;
2009-06-06 14:30:57 +04:00
struct tevent_context * ev ;
struct tevent_req * req ;
2016-01-31 17:29:29 +03:00
TLDAPRC rc = TLDAP_NO_MEMORY ;
struct tldap_message * * msgs ;
struct tldap_message * result ;
if ( tldap_pending_reqs ( ld ) ) {
return TLDAP_BUSY ;
}
frame = talloc_stackframe ( ) ;
2009-06-06 14:30:57 +04:00
2013-02-18 12:10:34 +04:00
ev = samba_tevent_context_init ( frame ) ;
2009-06-06 14:30:57 +04:00
if ( ev = = NULL ) {
goto fail ;
}
2016-01-31 17:29:29 +03:00
req = tldap_search_all_send ( frame , ev , ld , base , scope , filter ,
attrs , num_attrs , attrsonly ,
sctrls , num_sctrls , cctrls , num_cctrls ,
timelimit , sizelimit , deref ) ;
2009-06-06 14:30:57 +04:00
if ( req = = NULL ) {
goto fail ;
}
2016-01-31 17:29:29 +03:00
if ( ! tevent_req_poll ( req , ev ) ) {
rc = TLDAP_OPERATIONS_ERROR ;
goto fail ;
2010-03-08 04:20:02 +03:00
}
2016-01-31 17:29:29 +03:00
rc = tldap_search_all_recv ( req , mem_ctx , & msgs , & result ) ;
TALLOC_FREE ( req ) ;
if ( ! TLDAP_RC_IS_SUCCESS ( rc ) ) {
2016-02-08 16:40:19 +03:00
goto fail ;
2009-06-06 14:30:57 +04:00
}
2016-01-31 17:29:29 +03:00
TALLOC_FREE ( ld - > last_msg ) ;
ld - > last_msg = talloc_move ( ld , & result ) ;
2009-06-06 14:30:57 +04:00
2016-01-31 17:29:29 +03:00
* pmsgs = msgs ;
2009-06-06 14:30:57 +04:00
fail :
TALLOC_FREE ( frame ) ;
2016-01-31 17:29:29 +03:00
return rc ;
2009-06-06 14:30:57 +04:00
}
static bool tldap_parse_search_entry ( struct tldap_message * msg )
{
int num_attribs = 0 ;
2016-02-02 14:15:49 +03:00
if ( msg - > type ! = TLDAP_RES_SEARCH_ENTRY ) {
return false ;
}
if ( ! asn1_start_tag ( msg - > data , TLDAP_RES_SEARCH_ENTRY ) ) {
return false ;
}
2009-06-06 14:30:57 +04:00
/* dn */
2014-09-20 02:10:46 +04:00
if ( ! asn1_read_OctetString_talloc ( msg , msg - > data , & msg - > dn ) ) return false ;
2009-06-06 14:30:57 +04:00
if ( msg - > dn = = NULL ) {
return false ;
}
/*
* Attributes : We overallocate msg - > attribs by one , so that while
* looping over the attributes we can directly parse into the last
* array element . Same for the values in the inner loop .
*/
msg - > attribs = talloc_array ( msg , struct tldap_attribute , 1 ) ;
if ( msg - > attribs = = NULL ) {
return false ;
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_start_tag ( msg - > data , ASN1_SEQUENCE ( 0 ) ) ) return false ;
2009-06-06 14:30:57 +04:00
while ( asn1_peek_tag ( msg - > data , ASN1_SEQUENCE ( 0 ) ) ) {
struct tldap_attribute * attrib ;
int num_values = 0 ;
attrib = & msg - > attribs [ num_attribs ] ;
attrib - > values = talloc_array ( msg - > attribs , DATA_BLOB , 1 ) ;
if ( attrib - > values = = NULL ) {
return false ;
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_start_tag ( msg - > data , ASN1_SEQUENCE ( 0 ) ) ) return false ;
if ( ! asn1_read_OctetString_talloc ( msg - > attribs , msg - > data ,
& attrib - > name ) ) return false ;
if ( ! asn1_start_tag ( msg - > data , ASN1_SET ) ) return false ;
2009-06-06 14:30:57 +04:00
while ( asn1_peek_tag ( msg - > data , ASN1_OCTET_STRING ) ) {
2014-09-20 02:10:46 +04:00
if ( ! asn1_read_OctetString ( msg - > data , msg ,
& attrib - > values [ num_values ] ) ) return false ;
2009-06-06 14:30:57 +04:00
attrib - > values = talloc_realloc (
msg - > attribs , attrib - > values , DATA_BLOB ,
num_values + 2 ) ;
if ( attrib - > values = = NULL ) {
return false ;
}
num_values + = 1 ;
}
attrib - > values = talloc_realloc ( msg - > attribs , attrib - > values ,
DATA_BLOB , num_values ) ;
attrib - > num_values = num_values ;
2014-09-20 02:10:46 +04:00
if ( ! asn1_end_tag ( msg - > data ) ) return false ; /* ASN1_SET */
if ( ! asn1_end_tag ( msg - > data ) ) return false ; /* ASN1_SEQUENCE(0) */
2009-06-06 14:30:57 +04:00
msg - > attribs = talloc_realloc (
msg , msg - > attribs , struct tldap_attribute ,
num_attribs + 2 ) ;
if ( msg - > attribs = = NULL ) {
return false ;
}
num_attribs + = 1 ;
}
msg - > attribs = talloc_realloc (
msg , msg - > attribs , struct tldap_attribute , num_attribs ) ;
2014-09-20 02:10:46 +04:00
return asn1_end_tag ( msg - > data ) ;
2009-06-06 14:30:57 +04:00
}
bool tldap_entry_dn ( struct tldap_message * msg , char * * dn )
{
if ( ( msg - > dn = = NULL ) & & ( ! tldap_parse_search_entry ( msg ) ) ) {
return false ;
}
* dn = msg - > dn ;
return true ;
}
2011-03-14 23:16:23 +03:00
bool tldap_entry_attributes ( struct tldap_message * msg ,
struct tldap_attribute * * attributes ,
int * num_attributes )
2009-06-06 14:30:57 +04:00
{
if ( ( msg - > dn = = NULL ) & & ( ! tldap_parse_search_entry ( msg ) ) ) {
return false ;
}
* attributes = msg - > attribs ;
* num_attributes = talloc_array_length ( msg - > attribs ) ;
return true ;
}
2009-06-07 01:21:01 +04:00
static bool tldap_decode_controls ( struct tldap_req_state * state )
{
2009-06-20 20:42:18 +04:00
struct tldap_message * msg = state - > result ;
struct asn1_data * data = msg - > data ;
2009-06-07 01:21:01 +04:00
struct tldap_control * sctrls = NULL ;
int num_controls = 0 ;
2014-09-20 02:10:46 +04:00
bool ret = false ;
2009-06-07 01:21:01 +04:00
2009-06-20 20:42:18 +04:00
msg - > res_sctrls = NULL ;
2009-06-07 01:21:01 +04:00
if ( ! asn1_peek_tag ( data , ASN1_CONTEXT ( 0 ) ) ) {
return true ;
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_start_tag ( data , ASN1_CONTEXT ( 0 ) ) ) goto out ;
2009-06-07 01:21:01 +04:00
while ( asn1_peek_tag ( data , ASN1_SEQUENCE ( 0 ) ) ) {
struct tldap_control * c ;
char * oid = NULL ;
2009-06-20 20:42:18 +04:00
sctrls = talloc_realloc ( msg , sctrls , struct tldap_control ,
2009-06-07 01:21:01 +04:00
num_controls + 1 ) ;
if ( sctrls = = NULL ) {
2014-09-20 02:10:46 +04:00
goto out ;
2009-06-07 01:21:01 +04:00
}
c = & sctrls [ num_controls ] ;
2014-09-20 02:10:46 +04:00
if ( ! asn1_start_tag ( data , ASN1_SEQUENCE ( 0 ) ) ) goto out ;
if ( ! asn1_read_OctetString_talloc ( msg , data , & oid ) ) goto out ;
2016-01-02 20:11:00 +03:00
if ( asn1_has_error ( data ) | | ( oid = = NULL ) ) {
2014-09-20 02:10:46 +04:00
goto out ;
2009-06-07 01:21:01 +04:00
}
c - > oid = oid ;
if ( asn1_peek_tag ( data , ASN1_BOOLEAN ) ) {
2014-09-20 02:10:46 +04:00
if ( ! asn1_read_BOOLEAN ( data , & c - > critical ) ) goto out ;
2009-06-07 01:21:01 +04:00
} else {
c - > critical = false ;
}
c - > value = data_blob_null ;
if ( asn1_peek_tag ( data , ASN1_OCTET_STRING ) & &
2009-06-20 20:42:18 +04:00
! asn1_read_OctetString ( data , msg , & c - > value ) ) {
2014-09-20 02:10:46 +04:00
goto out ;
2009-06-07 01:21:01 +04:00
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_end_tag ( data ) ) goto out ; /* ASN1_SEQUENCE(0) */
2009-06-07 01:21:01 +04:00
num_controls + = 1 ;
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_end_tag ( data ) ) goto out ; /* ASN1_CONTEXT(0) */
2009-06-07 01:21:01 +04:00
2014-09-20 02:10:46 +04:00
ret = true ;
out :
2016-01-31 14:25:32 +03:00
if ( ret ) {
2014-09-20 02:10:46 +04:00
msg - > res_sctrls = sctrls ;
2016-01-31 14:25:32 +03:00
} else {
TALLOC_FREE ( sctrls ) ;
2009-06-07 01:21:01 +04:00
}
2014-09-20 02:10:46 +04:00
return ret ;
2009-06-07 01:21:01 +04:00
}
2009-06-06 14:30:57 +04:00
static void tldap_simple_done ( struct tevent_req * subreq , int type )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct tldap_req_state * state = tevent_req_data (
req , struct tldap_req_state ) ;
2016-01-24 13:53:48 +03:00
TLDAPRC rc ;
2009-06-06 14:30:57 +04:00
2016-01-24 13:53:48 +03:00
rc = tldap_msg_recv ( subreq , state , & state - > result ) ;
2009-06-06 14:30:57 +04:00
TALLOC_FREE ( subreq ) ;
2016-01-24 13:53:48 +03:00
if ( tevent_req_ldap_error ( req , rc ) ) {
2009-06-06 14:30:57 +04:00
return ;
}
if ( state - > result - > type ! = type ) {
2016-01-24 13:53:48 +03:00
tevent_req_ldap_error ( req , TLDAP_PROTOCOL_ERROR ) ;
2009-06-06 14:30:57 +04:00
return ;
}
if ( ! asn1_start_tag ( state - > result - > data , state - > result - > type ) | |
! tldap_decode_response ( state ) | |
2009-06-07 01:21:01 +04:00
! asn1_end_tag ( state - > result - > data ) | |
! tldap_decode_controls ( state ) ) {
2016-01-24 13:53:48 +03:00
tevent_req_ldap_error ( req , TLDAP_DECODING_ERROR ) ;
2009-06-06 14:30:57 +04:00
return ;
}
2016-01-24 13:53:48 +03:00
if ( ! TLDAP_RC_IS_SUCCESS ( state - > result - > lderr ) ) {
tevent_req_ldap_error ( req , state - > result - > lderr ) ;
2009-06-06 14:30:57 +04:00
return ;
}
tevent_req_done ( req ) ;
}
2016-01-24 13:53:48 +03:00
static TLDAPRC tldap_simple_recv ( struct tevent_req * req )
2009-06-06 14:30:57 +04:00
{
2016-01-24 13:53:48 +03:00
TLDAPRC rc ;
if ( tevent_req_is_ldap_error ( req , & rc ) ) {
return rc ;
2009-06-06 14:30:57 +04:00
}
return TLDAP_SUCCESS ;
}
static void tldap_add_done ( struct tevent_req * subreq ) ;
struct tevent_req * tldap_add_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tldap_context * ld ,
const char * dn ,
struct tldap_mod * attributes ,
2009-06-06 23:06:33 +04:00
int num_attributes ,
struct tldap_control * sctrls ,
int num_sctrls ,
struct tldap_control * cctrls ,
int num_cctrls )
2009-06-06 14:30:57 +04:00
{
struct tevent_req * req , * subreq ;
struct tldap_req_state * state ;
int i , j ;
req = tldap_req_create ( mem_ctx , ld , & state ) ;
if ( req = = NULL ) {
return NULL ;
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( state - > out , TLDAP_REQ_ADD ) ) goto err ;
if ( ! asn1_write_OctetString ( state - > out , dn , strlen ( dn ) ) ) goto err ;
if ( ! asn1_push_tag ( state - > out , ASN1_SEQUENCE ( 0 ) ) ) goto err ;
2009-06-06 14:30:57 +04:00
for ( i = 0 ; i < num_attributes ; i + + ) {
struct tldap_mod * attrib = & attributes [ i ] ;
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( state - > out , ASN1_SEQUENCE ( 0 ) ) ) goto err ;
if ( ! asn1_write_OctetString ( state - > out , attrib - > attribute ,
strlen ( attrib - > attribute ) ) ) goto err ;
if ( ! asn1_push_tag ( state - > out , ASN1_SET ) ) goto err ;
2009-06-06 14:30:57 +04:00
for ( j = 0 ; j < attrib - > num_values ; j + + ) {
2014-09-20 02:10:46 +04:00
if ( ! asn1_write_OctetString ( state - > out ,
2009-06-06 14:30:57 +04:00
attrib - > values [ j ] . data ,
2014-09-20 02:10:46 +04:00
attrib - > values [ j ] . length ) ) goto err ;
2009-06-06 14:30:57 +04:00
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_pop_tag ( state - > out ) ) goto err ;
if ( ! asn1_pop_tag ( state - > out ) ) goto err ;
2009-06-06 14:30:57 +04:00
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_pop_tag ( state - > out ) ) goto err ;
if ( ! asn1_pop_tag ( state - > out ) ) goto err ;
2009-06-06 14:30:57 +04:00
2009-06-07 01:21:01 +04:00
subreq = tldap_msg_send ( state , ev , ld , state - > id , state - > out ,
sctrls , num_sctrls ) ;
2009-06-06 14:30:57 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , tldap_add_done , req ) ;
return req ;
2014-09-20 02:10:46 +04:00
err :
2016-01-24 13:53:48 +03:00
tevent_req_ldap_error ( req , TLDAP_ENCODING_ERROR ) ;
2014-09-20 02:10:46 +04:00
return tevent_req_post ( req , ev ) ;
2009-06-06 14:30:57 +04:00
}
static void tldap_add_done ( struct tevent_req * subreq )
{
2009-07-15 22:54:01 +04:00
tldap_simple_done ( subreq , TLDAP_RES_ADD ) ;
2009-06-06 14:30:57 +04:00
}
2016-01-24 13:53:48 +03:00
TLDAPRC tldap_add_recv ( struct tevent_req * req )
2009-06-06 14:30:57 +04:00
{
return tldap_simple_recv ( req ) ;
}
2016-01-24 13:53:48 +03:00
TLDAPRC tldap_add ( struct tldap_context * ld , const char * dn ,
struct tldap_mod * attributes , int num_attributes ,
struct tldap_control * sctrls , int num_sctrls ,
struct tldap_control * cctrls , int num_cctrls )
2009-06-06 14:30:57 +04:00
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct tevent_context * ev ;
struct tevent_req * req ;
2016-01-24 13:53:48 +03:00
TLDAPRC rc = TLDAP_NO_MEMORY ;
2009-06-06 14:30:57 +04:00
2013-02-18 12:10:34 +04:00
ev = samba_tevent_context_init ( frame ) ;
2009-06-06 14:30:57 +04:00
if ( ev = = NULL ) {
goto fail ;
}
2009-06-06 23:06:33 +04:00
req = tldap_add_send ( frame , ev , ld , dn , attributes , num_attributes ,
sctrls , num_sctrls , cctrls , num_cctrls ) ;
2009-06-06 14:30:57 +04:00
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll ( req , ev ) ) {
2016-01-24 13:53:48 +03:00
rc = TLDAP_OPERATIONS_ERROR ;
2009-06-06 14:30:57 +04:00
goto fail ;
}
2016-01-24 13:53:48 +03:00
rc = tldap_add_recv ( req ) ;
2009-06-20 20:42:18 +04:00
tldap_save_msg ( ld , req ) ;
2009-06-06 14:30:57 +04:00
fail :
TALLOC_FREE ( frame ) ;
2016-01-24 13:53:48 +03:00
return rc ;
2009-06-06 14:30:57 +04:00
}
static void tldap_modify_done ( struct tevent_req * subreq ) ;
struct tevent_req * tldap_modify_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tldap_context * ld ,
const char * dn ,
2011-02-11 00:21:19 +03:00
struct tldap_mod * mods , int num_mods ,
2009-06-06 23:06:33 +04:00
struct tldap_control * sctrls ,
int num_sctrls ,
struct tldap_control * cctrls ,
int num_cctrls )
2009-06-06 14:30:57 +04:00
{
struct tevent_req * req , * subreq ;
struct tldap_req_state * state ;
int i , j ;
req = tldap_req_create ( mem_ctx , ld , & state ) ;
if ( req = = NULL ) {
return NULL ;
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( state - > out , TLDAP_REQ_MODIFY ) ) goto err ;
if ( ! asn1_write_OctetString ( state - > out , dn , strlen ( dn ) ) ) goto err ;
if ( ! asn1_push_tag ( state - > out , ASN1_SEQUENCE ( 0 ) ) ) goto err ;
2009-06-06 14:30:57 +04:00
for ( i = 0 ; i < num_mods ; i + + ) {
struct tldap_mod * mod = & mods [ i ] ;
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( state - > out , ASN1_SEQUENCE ( 0 ) ) ) goto err ;
if ( ! asn1_write_enumerated ( state - > out , mod - > mod_op ) ) goto err ;
if ( ! asn1_push_tag ( state - > out , ASN1_SEQUENCE ( 0 ) ) ) goto err ;
if ( ! asn1_write_OctetString ( state - > out , mod - > attribute ,
strlen ( mod - > attribute ) ) ) goto err ;
if ( ! asn1_push_tag ( state - > out , ASN1_SET ) ) goto err ;
2009-06-06 14:30:57 +04:00
for ( j = 0 ; j < mod - > num_values ; j + + ) {
2014-09-20 02:10:46 +04:00
if ( ! asn1_write_OctetString ( state - > out ,
2009-06-06 14:30:57 +04:00
mod - > values [ j ] . data ,
2014-09-20 02:10:46 +04:00
mod - > values [ j ] . length ) ) goto err ;
2009-06-06 14:30:57 +04:00
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_pop_tag ( state - > out ) ) goto err ;
if ( ! asn1_pop_tag ( state - > out ) ) goto err ;
if ( ! asn1_pop_tag ( state - > out ) ) goto err ;
2009-06-06 14:30:57 +04:00
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_pop_tag ( state - > out ) ) goto err ;
if ( ! asn1_pop_tag ( state - > out ) ) goto err ;
2009-06-06 14:30:57 +04:00
2009-06-07 01:21:01 +04:00
subreq = tldap_msg_send ( state , ev , ld , state - > id , state - > out ,
sctrls , num_sctrls ) ;
2009-06-06 14:30:57 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , tldap_modify_done , req ) ;
return req ;
2014-09-20 02:10:46 +04:00
err :
2016-01-24 13:53:48 +03:00
tevent_req_ldap_error ( req , TLDAP_ENCODING_ERROR ) ;
2014-09-20 02:10:46 +04:00
return tevent_req_post ( req , ev ) ;
2009-06-06 14:30:57 +04:00
}
static void tldap_modify_done ( struct tevent_req * subreq )
{
2009-07-15 22:54:01 +04:00
tldap_simple_done ( subreq , TLDAP_RES_MODIFY ) ;
2009-06-06 14:30:57 +04:00
}
2016-01-24 13:53:48 +03:00
TLDAPRC tldap_modify_recv ( struct tevent_req * req )
2009-06-06 14:30:57 +04:00
{
return tldap_simple_recv ( req ) ;
}
2016-01-24 13:53:48 +03:00
TLDAPRC tldap_modify ( struct tldap_context * ld , const char * dn ,
struct tldap_mod * mods , int num_mods ,
struct tldap_control * sctrls , int num_sctrls ,
struct tldap_control * cctrls , int num_cctrls )
2009-06-06 14:30:57 +04:00
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct tevent_context * ev ;
struct tevent_req * req ;
2016-01-24 13:53:48 +03:00
TLDAPRC rc = TLDAP_NO_MEMORY ;
2009-06-06 14:30:57 +04:00
2013-02-18 12:10:34 +04:00
ev = samba_tevent_context_init ( frame ) ;
2009-06-06 14:30:57 +04:00
if ( ev = = NULL ) {
goto fail ;
}
2011-02-11 00:21:19 +03:00
req = tldap_modify_send ( frame , ev , ld , dn , mods , num_mods ,
2009-06-06 23:06:33 +04:00
sctrls , num_sctrls , cctrls , num_cctrls ) ;
2009-06-06 14:30:57 +04:00
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll ( req , ev ) ) {
2016-01-24 13:53:48 +03:00
rc = TLDAP_OPERATIONS_ERROR ;
2009-06-06 14:30:57 +04:00
goto fail ;
}
2016-01-24 13:53:48 +03:00
rc = tldap_modify_recv ( req ) ;
2009-06-20 20:42:18 +04:00
tldap_save_msg ( ld , req ) ;
2009-06-06 14:30:57 +04:00
fail :
TALLOC_FREE ( frame ) ;
2016-01-24 13:53:48 +03:00
return rc ;
2009-06-06 14:30:57 +04:00
}
static void tldap_delete_done ( struct tevent_req * subreq ) ;
struct tevent_req * tldap_delete_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tldap_context * ld ,
const char * dn ,
2009-06-06 23:06:33 +04:00
struct tldap_control * sctrls ,
int num_sctrls ,
struct tldap_control * cctrls ,
int num_cctrls )
2009-06-06 14:30:57 +04:00
{
struct tevent_req * req , * subreq ;
struct tldap_req_state * state ;
req = tldap_req_create ( mem_ctx , ld , & state ) ;
if ( req = = NULL ) {
return NULL ;
}
2014-09-20 02:10:46 +04:00
if ( ! asn1_push_tag ( state - > out , TLDAP_REQ_DELETE ) ) goto err ;
if ( ! asn1_write ( state - > out , dn , strlen ( dn ) ) ) goto err ;
if ( ! asn1_pop_tag ( state - > out ) ) goto err ;
2009-06-06 14:30:57 +04:00
2009-06-07 01:21:01 +04:00
subreq = tldap_msg_send ( state , ev , ld , state - > id , state - > out ,
sctrls , num_sctrls ) ;
2009-06-06 14:30:57 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , tldap_delete_done , req ) ;
return req ;
2014-09-20 02:10:46 +04:00
err :
2016-01-24 13:53:48 +03:00
tevent_req_ldap_error ( req , TLDAP_ENCODING_ERROR ) ;
2014-09-20 02:10:46 +04:00
return tevent_req_post ( req , ev ) ;
2009-06-06 14:30:57 +04:00
}
static void tldap_delete_done ( struct tevent_req * subreq )
{
2009-07-15 22:54:01 +04:00
tldap_simple_done ( subreq , TLDAP_RES_DELETE ) ;
2009-06-06 14:30:57 +04:00
}
2016-01-24 13:53:48 +03:00
TLDAPRC tldap_delete_recv ( struct tevent_req * req )
2009-06-06 14:30:57 +04:00
{
return tldap_simple_recv ( req ) ;
}
2016-01-24 13:53:48 +03:00
TLDAPRC tldap_delete ( struct tldap_context * ld , const char * dn ,
struct tldap_control * sctrls , int num_sctrls ,
struct tldap_control * cctrls , int num_cctrls )
2009-06-06 14:30:57 +04:00
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct tevent_context * ev ;
struct tevent_req * req ;
2016-01-24 13:53:48 +03:00
TLDAPRC rc = TLDAP_NO_MEMORY ;
2009-06-06 14:30:57 +04:00
2013-02-18 12:10:34 +04:00
ev = samba_tevent_context_init ( frame ) ;
2009-06-06 14:30:57 +04:00
if ( ev = = NULL ) {
goto fail ;
}
2009-06-06 23:06:33 +04:00
req = tldap_delete_send ( frame , ev , ld , dn , sctrls , num_sctrls ,
cctrls , num_cctrls ) ;
2009-06-06 14:30:57 +04:00
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll ( req , ev ) ) {
2016-01-24 13:53:48 +03:00
rc = TLDAP_OPERATIONS_ERROR ;
2009-06-06 14:30:57 +04:00
goto fail ;
}
2016-01-24 13:53:48 +03:00
rc = tldap_delete_recv ( req ) ;
2009-06-20 20:42:18 +04:00
tldap_save_msg ( ld , req ) ;
2009-06-06 14:30:57 +04:00
fail :
TALLOC_FREE ( frame ) ;
2016-01-24 13:53:48 +03:00
return rc ;
2009-06-06 14:30:57 +04:00
}
int tldap_msg_id ( const struct tldap_message * msg )
{
return msg - > id ;
}
int tldap_msg_type ( const struct tldap_message * msg )
{
return msg - > type ;
}
2009-06-20 20:42:18 +04:00
const char * tldap_msg_matcheddn ( struct tldap_message * msg )
2009-06-06 14:30:57 +04:00
{
2009-06-20 20:42:18 +04:00
if ( msg = = NULL ) {
return NULL ;
}
return msg - > res_matcheddn ;
2009-06-06 14:30:57 +04:00
}
2009-06-20 20:42:18 +04:00
const char * tldap_msg_diagnosticmessage ( struct tldap_message * msg )
2009-06-06 14:30:57 +04:00
{
2009-06-20 20:42:18 +04:00
if ( msg = = NULL ) {
return NULL ;
}
return msg - > res_diagnosticmessage ;
2009-06-06 14:30:57 +04:00
}
2009-06-20 20:42:18 +04:00
const char * tldap_msg_referral ( struct tldap_message * msg )
2009-06-06 14:30:57 +04:00
{
2009-06-20 20:42:18 +04:00
if ( msg = = NULL ) {
return NULL ;
}
return msg - > res_referral ;
2009-06-06 14:30:57 +04:00
}
2009-06-20 20:42:18 +04:00
void tldap_msg_sctrls ( struct tldap_message * msg , int * num_sctrls ,
2009-06-07 01:21:01 +04:00
struct tldap_control * * sctrls )
{
2009-06-20 20:42:18 +04:00
if ( msg = = NULL ) {
* sctrls = NULL ;
* num_sctrls = 0 ;
2011-01-20 01:04:13 +03:00
return ;
2009-06-20 20:42:18 +04:00
}
* sctrls = msg - > res_sctrls ;
* num_sctrls = talloc_array_length ( msg - > res_sctrls ) ;
2009-06-06 14:30:57 +04:00
}
2009-06-20 20:42:18 +04:00
struct tldap_message * tldap_ctx_lastmsg ( struct tldap_context * ld )
2009-06-07 01:21:01 +04:00
{
2009-06-20 20:42:18 +04:00
return ld - > last_msg ;
2009-06-07 01:21:01 +04:00
}
2016-01-24 13:53:48 +03:00
static const struct { TLDAPRC rc ; const char * string ; } tldaprc_errmap [ ] =
{
{ TLDAP_SUCCESS ,
" TLDAP_SUCCESS " } ,
{ TLDAP_OPERATIONS_ERROR ,
" TLDAP_OPERATIONS_ERROR " } ,
{ TLDAP_PROTOCOL_ERROR ,
" TLDAP_PROTOCOL_ERROR " } ,
{ TLDAP_TIMELIMIT_EXCEEDED ,
" TLDAP_TIMELIMIT_EXCEEDED " } ,
{ TLDAP_SIZELIMIT_EXCEEDED ,
" TLDAP_SIZELIMIT_EXCEEDED " } ,
{ TLDAP_COMPARE_FALSE ,
" TLDAP_COMPARE_FALSE " } ,
{ TLDAP_COMPARE_TRUE ,
" TLDAP_COMPARE_TRUE " } ,
{ TLDAP_STRONG_AUTH_NOT_SUPPORTED ,
" TLDAP_STRONG_AUTH_NOT_SUPPORTED " } ,
{ TLDAP_STRONG_AUTH_REQUIRED ,
" TLDAP_STRONG_AUTH_REQUIRED " } ,
{ TLDAP_REFERRAL ,
" TLDAP_REFERRAL " } ,
{ TLDAP_ADMINLIMIT_EXCEEDED ,
" TLDAP_ADMINLIMIT_EXCEEDED " } ,
{ TLDAP_UNAVAILABLE_CRITICAL_EXTENSION ,
" TLDAP_UNAVAILABLE_CRITICAL_EXTENSION " } ,
{ TLDAP_CONFIDENTIALITY_REQUIRED ,
" TLDAP_CONFIDENTIALITY_REQUIRED " } ,
{ TLDAP_SASL_BIND_IN_PROGRESS ,
" TLDAP_SASL_BIND_IN_PROGRESS " } ,
{ TLDAP_NO_SUCH_ATTRIBUTE ,
" TLDAP_NO_SUCH_ATTRIBUTE " } ,
{ TLDAP_UNDEFINED_TYPE ,
" TLDAP_UNDEFINED_TYPE " } ,
{ TLDAP_INAPPROPRIATE_MATCHING ,
" TLDAP_INAPPROPRIATE_MATCHING " } ,
{ TLDAP_CONSTRAINT_VIOLATION ,
" TLDAP_CONSTRAINT_VIOLATION " } ,
{ TLDAP_TYPE_OR_VALUE_EXISTS ,
" TLDAP_TYPE_OR_VALUE_EXISTS " } ,
{ TLDAP_INVALID_SYNTAX ,
" TLDAP_INVALID_SYNTAX " } ,
{ TLDAP_NO_SUCH_OBJECT ,
" TLDAP_NO_SUCH_OBJECT " } ,
{ TLDAP_ALIAS_PROBLEM ,
" TLDAP_ALIAS_PROBLEM " } ,
{ TLDAP_INVALID_DN_SYNTAX ,
" TLDAP_INVALID_DN_SYNTAX " } ,
{ TLDAP_IS_LEAF ,
" TLDAP_IS_LEAF " } ,
{ TLDAP_ALIAS_DEREF_PROBLEM ,
" TLDAP_ALIAS_DEREF_PROBLEM " } ,
{ TLDAP_INAPPROPRIATE_AUTH ,
" TLDAP_INAPPROPRIATE_AUTH " } ,
{ TLDAP_INVALID_CREDENTIALS ,
" TLDAP_INVALID_CREDENTIALS " } ,
{ TLDAP_INSUFFICIENT_ACCESS ,
" TLDAP_INSUFFICIENT_ACCESS " } ,
{ TLDAP_BUSY ,
" TLDAP_BUSY " } ,
{ TLDAP_UNAVAILABLE ,
" TLDAP_UNAVAILABLE " } ,
{ TLDAP_UNWILLING_TO_PERFORM ,
" TLDAP_UNWILLING_TO_PERFORM " } ,
{ TLDAP_LOOP_DETECT ,
" TLDAP_LOOP_DETECT " } ,
{ TLDAP_NAMING_VIOLATION ,
" TLDAP_NAMING_VIOLATION " } ,
{ TLDAP_OBJECT_CLASS_VIOLATION ,
" TLDAP_OBJECT_CLASS_VIOLATION " } ,
{ TLDAP_NOT_ALLOWED_ON_NONLEAF ,
" TLDAP_NOT_ALLOWED_ON_NONLEAF " } ,
{ TLDAP_NOT_ALLOWED_ON_RDN ,
" TLDAP_NOT_ALLOWED_ON_RDN " } ,
{ TLDAP_ALREADY_EXISTS ,
" TLDAP_ALREADY_EXISTS " } ,
{ TLDAP_NO_OBJECT_CLASS_MODS ,
" TLDAP_NO_OBJECT_CLASS_MODS " } ,
{ TLDAP_RESULTS_TOO_LARGE ,
" TLDAP_RESULTS_TOO_LARGE " } ,
{ TLDAP_AFFECTS_MULTIPLE_DSAS ,
" TLDAP_AFFECTS_MULTIPLE_DSAS " } ,
{ TLDAP_OTHER ,
" TLDAP_OTHER " } ,
{ TLDAP_SERVER_DOWN ,
" TLDAP_SERVER_DOWN " } ,
{ TLDAP_LOCAL_ERROR ,
" TLDAP_LOCAL_ERROR " } ,
{ TLDAP_ENCODING_ERROR ,
" TLDAP_ENCODING_ERROR " } ,
{ TLDAP_DECODING_ERROR ,
" TLDAP_DECODING_ERROR " } ,
{ TLDAP_TIMEOUT ,
" TLDAP_TIMEOUT " } ,
{ TLDAP_AUTH_UNKNOWN ,
" TLDAP_AUTH_UNKNOWN " } ,
{ TLDAP_FILTER_ERROR ,
" TLDAP_FILTER_ERROR " } ,
{ TLDAP_USER_CANCELLED ,
" TLDAP_USER_CANCELLED " } ,
{ TLDAP_PARAM_ERROR ,
" TLDAP_PARAM_ERROR " } ,
{ TLDAP_NO_MEMORY ,
" TLDAP_NO_MEMORY " } ,
{ TLDAP_CONNECT_ERROR ,
" TLDAP_CONNECT_ERROR " } ,
{ TLDAP_NOT_SUPPORTED ,
" TLDAP_NOT_SUPPORTED " } ,
{ TLDAP_CONTROL_NOT_FOUND ,
" TLDAP_CONTROL_NOT_FOUND " } ,
{ TLDAP_NO_RESULTS_RETURNED ,
" TLDAP_NO_RESULTS_RETURNED " } ,
{ TLDAP_MORE_RESULTS_TO_RETURN ,
" TLDAP_MORE_RESULTS_TO_RETURN " } ,
{ TLDAP_CLIENT_LOOP ,
" TLDAP_CLIENT_LOOP " } ,
{ TLDAP_REFERRAL_LIMIT_EXCEEDED ,
" TLDAP_REFERRAL_LIMIT_EXCEEDED " } ,
} ;
2009-06-06 14:30:57 +04:00
2016-01-24 13:53:48 +03:00
const char * tldap_rc2string ( TLDAPRC rc )
{
size_t i ;
2009-06-06 14:30:57 +04:00
2016-01-24 13:53:48 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( tldaprc_errmap ) ; i + + ) {
if ( TLDAP_RC_EQUAL ( rc , tldaprc_errmap [ i ] . rc ) ) {
return tldaprc_errmap [ i ] . string ;
}
2009-06-06 14:30:57 +04:00
}
2016-01-24 13:53:48 +03:00
return " Unknown LDAP Error " ;
2009-06-06 14:30:57 +04:00
}