From 0267573cb8f516ef10c12b2d73c34892f1f3a757 Mon Sep 17 00:00:00 2001 From: Kurt Zeilenga Date: Mon, 18 Feb 2002 19:49:56 +0000 Subject: [PATCH] Import control ifdefs from HEAD --- servers/slapd/back-bdb/init.c | 511 ++++++++++++++++++++++++++++++++++ servers/slapd/controls.c | 444 +++++++++++++++++++++++++++++ 2 files changed, 955 insertions(+) create mode 100644 servers/slapd/back-bdb/init.c create mode 100644 servers/slapd/controls.c diff --git a/servers/slapd/back-bdb/init.c b/servers/slapd/back-bdb/init.c new file mode 100644 index 0000000000..ccd08dc62b --- /dev/null +++ b/servers/slapd/back-bdb/init.c @@ -0,0 +1,511 @@ +/* init.c - initialize bdb backend */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include +#include +#include +#include + +#include + +#include "back-bdb.h" +#include "external.h" + +static struct bdbi_database { + char *file; + char *name; + int type; + int flags; +} bdbi_databases[] = { + { "id2entry" BDB_SUFFIX, "id2entry", DB_BTREE, 0 }, +#ifdef BDB_HIER + { "id2parent" BDB_SUFFIX, "id2parent", DB_BTREE, 0 }, +#else + { "dn2id" BDB_SUFFIX, "dn2id", DB_BTREE, 0 }, +#endif + { NULL, NULL, 0, 0 } +}; + +struct berval bdb_uuid = { 0, NULL }; + +static int +bdb_open( BackendInfo *bi ) +{ + return 0; +} + +#if 0 +static int +bdb_destroy( BackendInfo *bi ) +{ + return 0; +} + +static int +bdb_close( BackendInfo *bi ) +{ + /* terminate the underlying database system */ + return 0; +} +#endif + +static int +bdb_db_init( BackendDB *be ) +{ + struct bdb_info *bdb; + + Debug( LDAP_DEBUG_ANY, + "bdb_db_init: Initializing BDB database\n", + 0, 0, 0 ); + + /* indicate system schema supported */ + be->be_flags |= +#ifdef BDB_SUBENTRIES + SLAP_BFLAG_SUBENTRIES | +#endif +#ifdef BDB_ALIASES + SLAP_BFLAG_ALIASES | +#endif + SLAP_BFLAG_REFERRALS; + + /* allocate backend-database-specific stuff */ + bdb = (struct bdb_info *) ch_calloc( 1, sizeof(struct bdb_info) ); + + /* DBEnv parameters */ + bdb->bi_dbenv_home = ch_strdup( SLAPD_DEFAULT_DB_DIR ); + bdb->bi_dbenv_xflags = 0; + bdb->bi_dbenv_mode = SLAPD_DEFAULT_DB_MODE; + + bdb->bi_cache.c_maxsize = DEFAULT_CACHE_SIZE; + +#ifndef NO_THREADS +#if 0 + bdb->bi_lock_detect = DB_LOCK_NORUN; +#else + bdb->bi_lock_detect = DB_LOCK_DEFAULT; +#endif +#endif + + ldap_pvt_thread_mutex_init( &bdb->bi_database_mutex ); + ldap_pvt_thread_mutex_init( &bdb->bi_lastid_mutex ); + ldap_pvt_thread_mutex_init( &bdb->bi_cache.c_mutex ); +#ifdef BDB_HIER + ldap_pvt_thread_rdwr_init( &bdb->bi_tree_rdwr ); +#endif + + be->be_private = bdb; + return 0; +} + +#if 0 /* ifndef NO_THREADS */ +static void *lock_detect_task( void *arg ) +{ + struct bdb_info *bdb = (struct bdb_info *) arg; + + while( bdb->bi_dbenv != NULL ) { + int rc; + int aborted; + sleep( bdb->bi_lock_detect_seconds ); + + rc = LOCK_DETECT( bdb->bi_dbenv, 0, + bdb->bi_lock_detect, &aborted ); + + if( rc != 0 ) { + break; + } + + Debug( LDAP_DEBUG_ANY, + "bdb_lock_detect: aborted %d locks\n", + aborted, 0, 0 ); + } + + return NULL; +} +#endif + +int +bdb_bt_compare( + DB *db, + const DBT *usrkey, + const DBT *curkey +) +{ + unsigned char *u, *c; + int i; + + u = usrkey->data; + c = curkey->data; + +#ifdef WORDS_BIGENDIAN + for( i = 0; i < sizeof(ID); i++) +#else + for( i = sizeof(ID)-1; i >= 0; i--) +#endif + { + if( u[i] - c[i] ) + return u[i] - c[i]; + } + return 0; +} + +static int +bdb_db_open( BackendDB *be ) +{ + int rc, i; + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + u_int32_t flags; + + Debug( LDAP_DEBUG_ARGS, + "bdb_db_open: %s\n", + be->be_suffix[0]->bv_val, 0, 0 ); + + /* we should check existance of dbenv_home and db_directory */ + + rc = db_env_create( &bdb->bi_dbenv, 0 ); + if( rc != 0 ) { + Debug( LDAP_DEBUG_ANY, + "bdb_db_open: db_env_create failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); + return rc; + } + + flags = DB_INIT_MPOOL | DB_THREAD | DB_CREATE + | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN | DB_RECOVER; + + bdb->bi_dbenv->set_errpfx( bdb->bi_dbenv, be->be_suffix[0]->bv_val ); + bdb->bi_dbenv->set_errcall( bdb->bi_dbenv, bdb_errcall ); +#ifndef NO_THREADS + bdb->bi_dbenv->set_lk_detect( bdb->bi_dbenv, bdb->bi_lock_detect ); +#endif + +#ifdef BDB_SUBDIRS + { + char dir[MAXPATHLEN]; + size_t len = strlen( bdb->bi_dbenv_home ); + + strcpy( dir, bdb->bi_dbenv_home ); + strcat( &dir[len], BDB_TMP_SUBDIR ); + + rc = bdb->bi_dbenv->set_tmp_dir( bdb->bi_dbenv, dir ); + if( rc != 0 ) { + Debug( LDAP_DEBUG_ANY, + "bdb_db_open: set_tmp_dir(%s) failed: %s (%d)\n", + dir, db_strerror(rc), rc ); + return rc; + } + + strcat( &dir[len], BDB_LG_SUBDIR ); + + rc = bdb->bi_dbenv->set_lg_dir( bdb->bi_dbenv, dir ); + if( rc != 0 ) { + Debug( LDAP_DEBUG_ANY, + "bdb_db_open: set_lg_dir(%s) failed: %s (%d)\n", + dir, db_strerror(rc), rc ); + return rc; + } + + strcat( &dir[len], BDB_DATA_SUBDIR ); + + rc = bdb->bi_dbenv->set_data_dir( bdb->bi_dbenv, dir ); + if( rc != 0 ) { + Debug( LDAP_DEBUG_ANY, + "bdb_db_open: set_data_dir(%s) failed: %s (%d)\n", + dir, db_strerror(rc), rc ); + return rc; + } + } +#endif + + Debug( LDAP_DEBUG_TRACE, + "bdb_db_open: dbenv_open(%s)\n", + bdb->bi_dbenv_home, 0, 0); + + rc = bdb->bi_dbenv->open( bdb->bi_dbenv, + bdb->bi_dbenv_home, + flags, + bdb->bi_dbenv_mode ); + if( rc != 0 ) { + Debug( LDAP_DEBUG_ANY, + "bdb_db_open: dbenv_open failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); + return rc; + } + + if( bdb->bi_dbenv_xflags != 0 ) { + rc = bdb->bi_dbenv->set_flags( bdb->bi_dbenv, + bdb->bi_dbenv_xflags, 1); + if( rc != 0 ) { + Debug( LDAP_DEBUG_ANY, + "bdb_db_open: dbenv_set_flags failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); + return rc; + } + } + + flags = DB_THREAD | DB_CREATE | bdb->bi_db_opflags; + + bdb->bi_databases = (struct bdb_db_info **) ch_malloc( + BDB_INDICES * sizeof(struct bdb_db_info *) ); + + /* open (and create) main database */ + for( i = 0; bdbi_databases[i].name; i++ ) { + struct bdb_db_info *db; + + db = (struct bdb_db_info *) ch_calloc(1, sizeof(struct bdb_db_info)); + + rc = db_create( &db->bdi_db, bdb->bi_dbenv, 0 ); + if( rc != 0 ) { + Debug( LDAP_DEBUG_ANY, + "bdb_db_open: db_create(%s) failed: %s (%d)\n", + bdb->bi_dbenv_home, db_strerror(rc), rc ); + return rc; + } + + if( i == BDB_ID2ENTRY ) { + rc = db->bdi_db->set_bt_compare( db->bdi_db, + bdb_bt_compare ); + rc = db->bdi_db->set_pagesize( db->bdi_db, + BDB_ID2ENTRY_PAGESIZE ); + } else { +#ifdef BDB_HIER + rc = db->bdi_db->set_bt_compare( db->bdi_db, + bdb_bt_compare ); +#elif defined(BDB_IDL_MULTI) + rc = db->bdi_db->set_flags( db->bdi_db, + DB_DUP | DB_DUPSORT ); + rc = db->bdi_db->set_dup_compare( db->bdi_db, + bdb_bt_compare ); +#endif + rc = db->bdi_db->set_pagesize( db->bdi_db, + BDB_PAGESIZE ); + } + + rc = db->bdi_db->open( db->bdi_db, + bdbi_databases[i].file, + /* bdbi_databases[i].name, */ NULL, + bdbi_databases[i].type, + bdbi_databases[i].flags | flags, + bdb->bi_dbenv_mode ); + + if( rc != 0 ) { + Debug( LDAP_DEBUG_ANY, + "bdb_db_open: db_open(%s) failed: %s (%d)\n", + bdb->bi_dbenv_home, db_strerror(rc), rc ); + return rc; + } + + db->bdi_name = bdbi_databases[i].name; + bdb->bi_databases[i] = db; + } + + bdb->bi_databases[i] = NULL; + bdb->bi_ndatabases = i; + + /* get nextid */ + rc = bdb_last_id( be, NULL ); + if( rc != 0 ) { + Debug( LDAP_DEBUG_ANY, + "bdb_db_open: last_id(%s) failed: %s (%d)\n", + bdb->bi_dbenv_home, db_strerror(rc), rc ); + return rc; + } + + /* open (and create) index databases */ +#ifdef BDB_HIER + rc = bdb_build_tree( be ); +#endif + +#if 0 /* ifndef NO_THREADS */ + if( bdb->bi_lock_detect != DB_LOCK_NORUN ) { + /* listener as a separate THREAD */ + rc = ldap_pvt_thread_create( &bdb->bi_lock_detect_tid, + 1, lock_detect_task, bdb ); + } +#endif + return 0; +} + +static int +bdb_db_close( BackendDB *be ) +{ + int rc; + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + struct bdb_db_info *db; + + while( bdb->bi_ndatabases-- ) { + db = bdb->bi_databases[bdb->bi_ndatabases]; + rc = db->bdi_db->close( db->bdi_db, 0 ); + /* Lower numbered names are not strdup'd */ + if( bdb->bi_ndatabases >= BDB_NDB ) + free( db->bdi_name ); + free( db ); + } + free( bdb->bi_databases ); + bdb_attr_index_destroy( bdb->bi_attrs ); + + bdb_cache_release_all (&bdb->bi_cache); + + return 0; +} + +static int +bdb_db_destroy( BackendDB *be ) +{ + int rc; + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + + /* close db environment */ + if( bdb->bi_dbenv ) { + /* force a checkpoint */ + rc = TXN_CHECKPOINT( bdb->bi_dbenv, 0, 0, DB_FORCE ); + if( rc != 0 ) { + Debug( LDAP_DEBUG_ANY, + "bdb_db_destroy: txn_checkpoint failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); + } + + bdb_cache_release_all (&bdb->bi_cache); + + rc = bdb->bi_dbenv->close( bdb->bi_dbenv, 0 ); + bdb->bi_dbenv = NULL; + if( rc != 0 ) { + Debug( LDAP_DEBUG_ANY, + "bdb_db_destroy: close failed: %s (%d)\n", + db_strerror(rc), rc, 0 ); + return rc; + } + } + + return 0; +} + +#ifdef SLAPD_BDB_DYNAMIC +int back_bdb_LTX_init_module( int argc, char *argv[] ) { + BackendInfo bi; + + memset( &bi, '\0', sizeof(bi) ); + bi.bi_type = "bdb"; + bi.bi_init = bdb_initialize; + + backend_add( &bi ); + return 0; +} +#endif /* SLAPD_BDB_DYNAMIC */ + +int +bdb_initialize( + BackendInfo *bi +) +{ + static char *controls[] = { + LDAP_CONTROL_MANAGEDSAIT, +#ifdef LDAP_CONTROL_SUBENTRIES + LDAP_CONTROL_SUBENTRIES, +#endif +#ifdef LDAP_CONTROL_NOOP + LDAP_CONTROL_NOOP, +#endif + NULL + }; + + bi->bi_controls = controls; + + /* initialize the underlying database system */ + Debug( LDAP_DEBUG_TRACE, "bdb_open: initialize BDB backend\n", + 0, 0, 0 ); + + { /* version check */ + int major, minor, patch; + char *version = db_version( &major, &minor, &patch ); + + if( major != DB_VERSION_MAJOR || + minor != DB_VERSION_MINOR || + patch < DB_VERSION_PATCH ) + { + Debug( LDAP_DEBUG_ANY, + "bdb_open: version mismatch\n" + "\texpected: " DB_VERSION_STRING "\n" + "\tgot: %s \n", version, 0, 0 ); + } + + Debug( LDAP_DEBUG_ANY, "bdb_open: %s\n", + version, 0, 0 ); + } + +#if 0 + db_env_set_func_malloc( ch_malloc ); + db_env_set_func_realloc( ch_realloc ); + db_env_set_func_free( ch_free ); +#endif + + db_env_set_func_yield( ldap_pvt_thread_yield ); + + { + static char uuidbuf[40]; + + bdb_uuid.bv_len = lutil_uuidstr( uuidbuf, sizeof( uuidbuf )); + bdb_uuid.bv_val = uuidbuf; + } + + bi->bi_open = 0; + bi->bi_close = 0; + bi->bi_config = 0; + bi->bi_destroy = 0; + + bi->bi_db_init = bdb_db_init; + bi->bi_db_config = bdb_db_config; + bi->bi_db_open = bdb_db_open; + bi->bi_db_close = bdb_db_close; + bi->bi_db_destroy = bdb_db_destroy; + + bi->bi_op_add = bdb_add; + bi->bi_op_bind = bdb_bind; + bi->bi_op_compare = bdb_compare; + bi->bi_op_delete = bdb_delete; + bi->bi_op_modify = bdb_modify; + bi->bi_op_modrdn = bdb_modrdn; + bi->bi_op_search = bdb_search; + + bi->bi_op_unbind = 0; + bi->bi_op_abandon = 0; + + bi->bi_extended = bdb_extended; + +#if 0 + /* + * these routines (and their callers) are not yet designed + * to work with transaction. Using them may cause deadlock. + */ + bi->bi_acl_group = bdb_group; + bi->bi_acl_attribute = bdb_attribute; +#else + bi->bi_acl_group = 0; + bi->bi_acl_attribute = 0; +#endif + + bi->bi_chk_referrals = bdb_referrals; + bi->bi_entry_release_rw = bdb_entry_release; + + /* + * hooks for slap tools + */ + bi->bi_tool_entry_open = bdb_tool_entry_open; + bi->bi_tool_entry_close = bdb_tool_entry_close; + bi->bi_tool_entry_first = bdb_tool_entry_next; + bi->bi_tool_entry_next = bdb_tool_entry_next; + bi->bi_tool_entry_get = bdb_tool_entry_get; + bi->bi_tool_entry_put = bdb_tool_entry_put; + bi->bi_tool_entry_reindex = bdb_tool_entry_reindex; + bi->bi_tool_sync = 0; + + bi->bi_connection_init = 0; + bi->bi_connection_destroy = 0; + + return 0; +} diff --git a/servers/slapd/controls.c b/servers/slapd/controls.c new file mode 100644 index 0000000000..7c3bf61b6b --- /dev/null +++ b/servers/slapd/controls.c @@ -0,0 +1,444 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1999-2002 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted only + * as authorized by the OpenLDAP Public License. A copy of this + * license is available at http://www.OpenLDAP.org/license.html or + * in file LICENSE in the top-level directory of the distribution. + */ +#include "portable.h" + +#include + +#include +#include + +#include "slap.h" + +#include "../../libraries/liblber/lber-int.h" + +#define SLAP_CTRL_FRONTEND 0x80000000U + +#define SLAP_CTRL_OPFLAGS 0x0000FFFFU +#define SLAP_CTRL_ABANDON 0x00000001U +#define SLAP_CTRL_ADD 0x00002002U +#define SLAP_CTRL_BIND 0x00000004U +#define SLAP_CTRL_COMPARE 0x00001008U +#define SLAP_CTRL_DELETE 0x00002010U +#define SLAP_CTRL_MODIFY 0x00002020U +#define SLAP_CTRL_RENAME 0x00002040U +#define SLAP_CTRL_SEARCH 0x00001080U +#define SLAP_CTRL_UNBIND 0x00000100U + +#define SLAP_CTRL_INTROGATE (SLAP_CTRL_COMPARE|SLAP_CTRL_SEARCH) +#define SLAP_CTRL_UPDATE \ + (SLAP_CTRL_ADD|SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME) +#define SLAP_CTRL_ACCESS (SLAP_CTRL_INTROGATE|SLAP_CTRL_UPDATE) + +typedef int (SLAP_CTRL_PARSE_FN) LDAP_P(( + Connection *conn, + Operation *op, + LDAPControl *ctrl, + const char **text )); + +static SLAP_CTRL_PARSE_FN parseManageDSAit; +static SLAP_CTRL_PARSE_FN parseSubentries; +static SLAP_CTRL_PARSE_FN parseNoOp; + +static struct slap_control { + char *sc_oid; + slap_mask_t sc_mask; + char **sc_extendedops; + SLAP_CTRL_PARSE_FN *sc_parse; + +} supportedControls[] = { + { LDAP_CONTROL_MANAGEDSAIT, + SLAP_CTRL_ACCESS, NULL, + parseManageDSAit }, +#ifdef LDAP_CONTROL_SUBENTRIES + { LDAP_CONTROL_SUBENTRIES, + SLAP_CTRL_SEARCH, NULL, + parseSubentries }, +#endif +#ifdef LDAP_CONTROL_NOOP + { LDAP_CONTROL_NOOP, + SLAP_CTRL_UPDATE, NULL, + parseNoOp }, +#endif + { NULL } +}; + +char * +get_supported_ctrl(int index) +{ + return supportedControls[index].sc_oid; +} + +static struct slap_control * +find_ctrl( const char *oid ) +{ + int i; + for( i=0; supportedControls[i].sc_oid; i++ ) { + if( strcmp( oid, supportedControls[i].sc_oid ) == 0 ) { + return &supportedControls[i]; + } + } + return NULL; +} + +int get_ctrls( + Connection *conn, + Operation *op, + int sendres ) +{ + int nctrls; + ber_tag_t tag; + ber_len_t len; + char *opaque; + BerElement *ber = op->o_ber; + struct slap_control *sc; + int rc = LDAP_SUCCESS; + const char *errmsg = NULL; + + len = ber_pvt_ber_remaining(ber); + + if( len == 0) { + /* no controls */ + rc = LDAP_SUCCESS; + return rc; + } + + if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) { + if( tag == LBER_ERROR ) { + rc = SLAPD_DISCONNECT; + errmsg = "unexpected data in PDU"; + } + + goto return_results; + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, + "get_ctrls: conn %d\n", conn->c_connid )); +#else + Debug( LDAP_DEBUG_TRACE, "=> get_ctrls\n", 0, 0, 0 ); +#endif + if( op->o_protocol < LDAP_VERSION3 ) { + rc = SLAPD_DISCONNECT; + errmsg = "controls require LDAPv3"; + goto return_results; + } + + /* one for first control, one for termination */ + op->o_ctrls = ch_malloc( 2 * sizeof(LDAPControl *) ); + +#if 0 + if( op->ctrls == NULL ) { + rc = LDAP_NO_MEMORY; + errmsg = "no memory"; + goto return_results; + } +#endif + + op->o_ctrls[nctrls=0] = NULL; + + /* step through each element */ + for( tag = ber_first_element( ber, &len, &opaque ); + tag != LBER_ERROR; + tag = ber_next_element( ber, &len, opaque ) ) + { + LDAPControl *c; + LDAPControl **tctrls; + + c = ch_calloc( 1, sizeof(LDAPControl) ); + +#if 0 + if( c == NULL ) { + ldap_controls_free(op->o_ctrls); + op->o_ctrls = NULL; + + rc = LDAP_NO_MEMORY; + errmsg = "no memory"; + goto return_results; + } +#endif + + /* allocate pointer space for current controls (nctrls) + * + this control + extra NULL + */ + tctrls = ch_realloc( op->o_ctrls, + (nctrls+2) * sizeof(LDAPControl *)); + +#if 0 + if( tctrls == NULL ) { + ch_free( c ); + ldap_controls_free(op->o_ctrls); + op->o_ctrls = NULL; + + rc = LDAP_NO_MEMORY; + errmsg = "no memory"; + goto return_results; + } +#endif + op->o_ctrls = tctrls; + + op->o_ctrls[nctrls++] = c; + op->o_ctrls[nctrls] = NULL; + + tag = ber_scanf( ber, "{a" /*}*/, &c->ldctl_oid ); + + if( tag == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "get_ctrls: conn %d get OID failed.\n", + conn->c_connid )); +#else + Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get oid failed.\n", + 0, 0, 0 ); +#endif + ldap_controls_free( op->o_ctrls ); + op->o_ctrls = NULL; + rc = SLAPD_DISCONNECT; + errmsg = "decoding controls error"; + goto return_results; + } + + tag = ber_peek_tag( ber, &len ); + + if( tag == LBER_BOOLEAN ) { + ber_int_t crit; + tag = ber_scanf( ber, "b", &crit ); + + if( tag == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "get_ctrls: conn %d get crit failed.\n", + conn->c_connid )); +#else + Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get crit failed.\n", + 0, 0, 0 ); +#endif + ldap_controls_free( op->o_ctrls ); + op->o_ctrls = NULL; + rc = SLAPD_DISCONNECT; + errmsg = "decoding controls error"; + goto return_results; + } + + c->ldctl_iscritical = (crit != 0); + tag = ber_peek_tag( ber, &len ); + } + + if( tag == LBER_OCTETSTRING ) { + tag = ber_scanf( ber, "o", &c->ldctl_value ); + + if( tag == LBER_ERROR ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, "get_ctrls: conn %d: " + "%s (%scritical): get value failed.\n", + conn->c_connid, + c->ldctl_oid ? c->ldctl_oid : "(NULL)", + c->ldctl_iscritical ? "" : "non" )); +#else + Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: conn %d: " + "%s (%scritical): get value failed.\n", + conn->c_connid, + c->ldctl_oid ? c->ldctl_oid : "(NULL)", + c->ldctl_iscritical ? "" : "non" ); +#endif + ldap_controls_free( op->o_ctrls ); + op->o_ctrls = NULL; + rc = SLAPD_DISCONNECT; + errmsg = "decoding controls error"; + goto return_results; + } + } + +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_INFO, + "get_ctrls: conn %d oid=\"%s\" (%scritical)\n", + conn->c_connid, + c->ldctl_oid ? c->ldctl_oid : "(NULL)", + c->ldctl_iscritical ? "" : "non" )); +#else + Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: oid=\"%s\" (%scritical)\n", + c->ldctl_oid ? c->ldctl_oid : "(NULL)", + c->ldctl_iscritical ? "" : "non", + 0 ); +#endif + + sc = find_ctrl( c->ldctl_oid ); + if( sc != NULL ) { + /* recognized control */ + slap_mask_t tagmask; + switch( op->o_tag ) { + case LDAP_REQ_ADD: + tagmask = SLAP_CTRL_ADD; + break; + case LDAP_REQ_BIND: + tagmask = SLAP_CTRL_BIND; + break; + case LDAP_REQ_COMPARE: + tagmask = SLAP_CTRL_COMPARE; + break; + case LDAP_REQ_DELETE: + tagmask = SLAP_CTRL_DELETE; + break; + case LDAP_REQ_MODIFY: + tagmask = SLAP_CTRL_MODIFY; + break; + case LDAP_REQ_RENAME: + tagmask = SLAP_CTRL_RENAME; + break; + case LDAP_REQ_SEARCH: + tagmask = SLAP_CTRL_SEARCH; + break; + case LDAP_REQ_UNBIND: + tagmask = SLAP_CTRL_UNBIND; + break; + case LDAP_REQ_EXTENDED: + /* FIXME: check list of extended operations */ + tagmask = ~0U; + break; + default: + rc = LDAP_OTHER; + errmsg = "controls internal error"; + goto return_results; + } + + if (( sc->sc_mask & tagmask ) == tagmask ) { + /* available extension */ + + if( !sc->sc_parse ) { + rc = LDAP_OTHER; + errmsg = "not yet implemented"; + goto return_results; + } + + rc = sc->sc_parse( conn, op, c, &errmsg ); + + if( rc != LDAP_SUCCESS ) goto return_results; + + if( sc->sc_mask & SLAP_CTRL_FRONTEND ) { + /* kludge to disable backend_control() check */ + c->ldctl_iscritical = 0; + } + + } else if( c->ldctl_iscritical ) { + /* unavailable CRITICAL control */ + rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; + errmsg = "critical extension is unavailable"; + goto return_results; + } + + } else if( c->ldctl_iscritical ) { + /* unrecognized CRITICAL control */ + rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; + errmsg = "critical extension is not recognized"; + goto return_results; + } + } + +return_results: +#ifdef NEW_LOGGING + LDAP_LOG(( "operation", LDAP_LEVEL_RESULTS, + "get_ctrls: conn=%d n=%d rc=%d err=%s\n", + conn->c_connid, nctrls, rc, errmsg ? errmsg : "" )); +#else + Debug( LDAP_DEBUG_TRACE, "<= get_ctrls: n=%d rc=%d err=%s\n", + nctrls, rc, errmsg ? errmsg : ""); +#endif + + if( sendres && rc != LDAP_SUCCESS ) { + if( rc == SLAPD_DISCONNECT ) { + send_ldap_disconnect( conn, op, LDAP_PROTOCOL_ERROR, errmsg ); + } else { + send_ldap_result( conn, op, rc, + NULL, errmsg, NULL, NULL ); + } + } + + return rc; +} + +static int parseManageDSAit ( + Connection *conn, + Operation *op, + LDAPControl *ctrl, + const char **text ) +{ + if ( op->o_managedsait != SLAP_NO_CONTROL ) { + *text = "manageDSAit control specified multiple times"; + return LDAP_PROTOCOL_ERROR; + } + + if ( ctrl->ldctl_value.bv_len ) { + *text = "manageDSAit control value not empty"; + return LDAP_PROTOCOL_ERROR; + } + + op->o_managedsait = ctrl->ldctl_iscritical + ? SLAP_CRITICAL_CONTROL + : SLAP_NONCRITICAL_CONTROL; + + return LDAP_SUCCESS; +} + +#ifdef LDAP_CONTROL_SUBENTRIES +static int parseSubentries ( + Connection *conn, + Operation *op, + LDAPControl *ctrl, + const char **text ) +{ + if ( op->o_subentries != SLAP_NO_CONTROL ) { + *text = "subentries control specified multiple times"; + return LDAP_PROTOCOL_ERROR; + } + + /* FIXME: should use BER library */ + if( ( ctrl->ldctl_value.bv_len != 3 ) + && ( ctrl->ldctl_value.bv_val[0] != 0x01 ) + && ( ctrl->ldctl_value.bv_val[1] != 0x01 )) + { + *text = "subentries control value encoding is bogus"; + return LDAP_PROTOCOL_ERROR; + } + + op->o_subentries = ctrl->ldctl_iscritical + ? SLAP_CRITICAL_CONTROL + : SLAP_NONCRITICAL_CONTROL; + + op->o_subentries_visibility = (ctrl->ldctl_value.bv_val[2] != 0x00); + + return LDAP_SUCCESS; +} +#endif + +#ifdef LDAP_CONTROL_NOOP +static int parseNoOp ( + Connection *conn, + Operation *op, + LDAPControl *ctrl, + const char **text ) +{ + if ( op->o_noop != SLAP_NO_CONTROL ) { + *text = "noop control specified multiple times"; + return LDAP_PROTOCOL_ERROR; + } + + if ( ctrl->ldctl_value.bv_len ) { + *text = "noop control value not empty"; + return LDAP_PROTOCOL_ERROR; + } + + op->o_noop = ctrl->ldctl_iscritical + ? SLAP_CRITICAL_CONTROL + : SLAP_NONCRITICAL_CONTROL; + + return LDAP_SUCCESS; +} +#endif + -- 2.39.5