Slapi_PBlock * slapi_rename_internal(const char *iodn, const char *inewrdn, const char *inewsuperior, int deloldrdn, LDAPControl **controls, int dummy) { Slapi_PBlock pb; Slapi_PBlock *result_pb = NULL; int opresult= 0; Slapi_DN sdn; Slapi_DN newsuperiorsdn; pblock_init (&pb); slapi_sdn_init_dn_byref(&sdn, iodn); slapi_sdn_init_dn_byref(&newsuperiorsdn, inewsuperior); slapi_rename_internal_set_pb_ext(&pb, &sdn, inewrdn, &newsuperiorsdn, deloldrdn, controls, NULL, plugin_get_default_component_id(), 0); rename_internal_pb (&pb); result_pb = slapi_pblock_new(); if (result_pb) { slapi_pblock_get(&pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult); slapi_pblock_set(result_pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult); } slapi_sdn_done(&sdn); slapi_sdn_done(&newsuperiorsdn); pblock_done(&pb); return result_pb; }
/* Handles the parsing of the config entry for an ldbm instance. Returns 0 * on success. */ static int parse_ldbm_instance_config_entry(ldbm_instance *inst, Slapi_Entry *e, config_info *config_array) { Slapi_Attr *attr = NULL; for (slapi_entry_first_attr(e, &attr); attr; slapi_entry_next_attr(e, attr, &attr)) { char *attr_name = NULL; Slapi_Value *sval = NULL; struct berval *bval; char err_buf[BUFSIZ]; slapi_attr_get_type(attr, &attr_name); /* There are some attributes that we don't care about, * like objectclass. */ if (ldbm_config_ignored_attr(attr_name)) { continue; } /* We have to handle suffix attributes a little differently */ if (strcasecmp(attr_name, CONFIG_INSTANCE_SUFFIX) == 0) { Slapi_DN suffix; slapi_attr_first_value(attr, &sval); bval = (struct berval *) slapi_value_get_berval(sval); slapi_sdn_init_dn_byref(&suffix, bval->bv_val); if (!slapi_be_issuffix(inst->inst_be, &suffix)) { be_addsuffix(inst->inst_be, &suffix); } slapi_sdn_done(&suffix); continue; } /* We are assuming that each of these attributes are to have * only one value. If they have more than one value, like * the nsslapd-suffix attribute, then they need to be * handled differently. */ slapi_attr_first_value(attr, &sval); bval = (struct berval *) slapi_value_get_berval(sval); if (ldbm_config_set((void *) inst, attr_name, config_array, bval, err_buf, CONFIG_PHASE_STARTUP, 1 /* apply */, LDAP_MOD_REPLACE) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "Error with config attribute %s : %s\n", attr_name, err_buf, 0); return 1; } } /* Read the index entries */ read_instance_index_entries(inst); /* Read the attribute encryption entries */ read_instance_attrcrypt_entries(inst); return 0; }
/* * snmp_update_cache_stats() * * Reads the backend cache stats from the backend monitor entry and * updates the global counter used by the SNMP sub-agent as well as * the SNMP monitor entry. */ static void snmp_update_cache_stats(void) { Slapi_Backend *be, *be_next; char *cookie = NULL; Slapi_PBlock *search_result_pb = NULL; Slapi_Entry **search_entries; int search_result; /* set the cache hits/cache entries info */ be = slapi_get_first_backend(&cookie); if (!be){ slapi_ch_free ((void **) &cookie); return; } be_next = slapi_get_next_backend(cookie); slapi_ch_free ((void **) &cookie); /* for now, only do it if there is only 1 backend, otherwise don't know * which backend to pick */ if(be_next == NULL) { Slapi_DN monitordn; slapi_sdn_init(&monitordn); be_getmonitordn(be,&monitordn); /* do a search on the monitor dn to get info */ search_result_pb = slapi_search_internal( slapi_sdn_get_dn(&monitordn), LDAP_SCOPE_BASE, "objectclass=*", NULL, NULL, 0); slapi_sdn_done(&monitordn); slapi_pblock_get( search_result_pb, SLAPI_PLUGIN_INTOP_RESULT, &search_result); if(search_result == 0) { slapi_pblock_get( search_result_pb,SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &search_entries); /* set the entrycachehits */ slapi_counter_set_value(g_get_global_snmp_vars()->entries_tbl.dsCacheHits, slapi_entry_attr_get_ulonglong(search_entries[0], "entrycachehits")); /* set the currententrycachesize */ slapi_counter_set_value(g_get_global_snmp_vars()->entries_tbl.dsCacheEntries, slapi_entry_attr_get_ulonglong(search_entries[0], "currententrycachesize")); } slapi_free_search_results_internal(search_result_pb); slapi_pblock_destroy(search_result_pb); } }
/** * Get a particular entry */ static Slapi_Entry * getConfigEntry( const char *dn, Slapi_Entry **e2 ) { Slapi_DN sdn; slapi_sdn_init_dn_byref( &sdn, dn ); slapi_search_internal_get_entry( &sdn, NULL, e2, plugin_get_default_component_id()); slapi_sdn_done( &sdn ); return *e2; }
Slapi_DN *slapi_sdn_add_rdn( Slapi_DN *sdn, const Slapi_RDN *rdn ) { struct berval bv; build_new_dn( &bv, &sdn->dn, (struct berval *)&rdn->bv, NULL ); slapi_sdn_done( sdn ); sdn->dn = bv; return sdn; }
static Slapi_Entry * getConfigEntry( Slapi_Entry **e ) { Slapi_DN sdn; /* SNMP_CONFIG_DN: no need to be normalized */ slapi_sdn_init_normdn_byref( &sdn, SNMP_CONFIG_DN ); slapi_search_internal_get_entry( &sdn, NULL, e, plugin_get_default_component_id()); slapi_sdn_done( &sdn ); return *e; }
Slapi_DN *slapi_sdn_set_ndn_byref( Slapi_DN *sdn, const char *ndn ) { if ( sdn == NULL ) return NULL; slapi_sdn_done( sdn ); if ( ndn != NULL ) { sdn->ndn.bv_val = (char *)ndn; sdn->ndn.bv_len = strlen( ndn ); } return sdn; }
Slapi_DN *slapi_sdn_set_ndn_byval( Slapi_DN *sdn, const char *ndn ) { if ( sdn == NULL ) { return NULL; } slapi_sdn_done( sdn ); if ( ndn != NULL ) { sdn->ndn.bv_val = slapi_ch_strdup( ndn ); sdn->ndn.bv_len = strlen( ndn ); } sdn->flag |= FLAG_NDN; return sdn; }
/* This function is used by the instance modify callback to add a new * suffix. It return LDAP_SUCCESS on success. */ int add_suffix(ldbm_instance *inst, struct berval **bvals, int apply_mod, char *returntext) { Slapi_DN suffix; int x; returntext[0] = '\0'; for (x = 0; bvals[x]; x++) { slapi_sdn_init_dn_byref(&suffix, bvals[x]->bv_val); if (!slapi_be_issuffix(inst->inst_be, &suffix) && apply_mod) { be_addsuffix(inst->inst_be, &suffix); } slapi_sdn_done(&suffix); } return LDAP_SUCCESS; }
/* * If "dn" is passed, get_entry returns an entry which dn is "dn". * If "dn" is not passed, it returns an entry which dn is set in * SLAPI_TARGET_SDN in pblock. * Note: pblock is not mandatory for get_entry (e.g., new_passwdPolicy). */ Slapi_Entry *get_entry ( Slapi_PBlock *pb, const char *dn) { int search_result = 0; Slapi_Entry *retentry = NULL; Slapi_DN *target_sdn = NULL; const char *target_dn = dn; Slapi_DN sdn; if (pb) { slapi_pblock_get( pb, SLAPI_TARGET_SDN, &target_sdn ); if (target_dn == NULL) { target_dn = slapi_sdn_get_dn(target_sdn); } } if (target_dn == NULL) { LDAPDebug0Args(LDAP_DEBUG_TRACE, "WARNING: 'get_entry' - no dn specified.\n"); goto bail; } if (target_dn == dn) { /* target_dn is NOT from target_sdn */ slapi_sdn_init_dn_byref(&sdn, target_dn); target_sdn = &sdn; } search_result = slapi_search_internal_get_entry(target_sdn, NULL, &retentry, pw_get_componentID()); if (search_result != LDAP_SUCCESS) { LDAPDebug2Args(LDAP_DEBUG_TRACE, "WARNING: 'get_entry' can't find entry '%s', err %d\n", target_dn, search_result); } if (target_dn == dn) { /* target_dn is NOT from target_sdn */ slapi_sdn_done(&sdn); } bail: return retentry; }
void do_compare( Slapi_PBlock *pb ) { BerElement *ber = pb->pb_op->o_ber; char *rawdn = NULL; const char *dn = NULL; struct ava ava = {0}; Slapi_Backend *be = NULL; int err; Slapi_DN sdn; Slapi_Entry *referral = NULL; char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE]; slapi_log_err(SLAPI_LOG_TRACE, "do_compare", "=>\n"); /* count the compare request */ slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsCompareOps); /* have to init this here so we can "done" it below if we short circuit */ slapi_sdn_init(&sdn); /* * Parse the compare request. It looks like this: * * CompareRequest := [APPLICATION 14] SEQUENCE { * entry DistinguishedName, * ava SEQUENCE { * type AttributeType, * value AttributeValue * } * } */ if ( ber_scanf( ber, "{a{ao}}", &rawdn, &ava.ava_type, &ava.ava_value ) == LBER_ERROR ) { slapi_log_err(SLAPI_LOG_ERR, "do_compare", "ber_scanf failed (op=Compare; params=DN,Type,Value)\n"); send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0, NULL ); goto free_and_return; } /* Check if we should be performing strict validation. */ if (config_get_dn_validate_strict()) { /* check that the dn is formatted correctly */ err = slapi_dn_syntax_check(pb, rawdn, 1); if (err) { /* syntax check failed */ op_shared_log_error_access(pb, "CMP", rawdn?rawdn:"", "strict: invalid dn"); send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL, "invalid dn", 0, NULL); slapi_ch_free((void **) &rawdn); return; } } slapi_sdn_init_dn_passin(&sdn, rawdn); dn = slapi_sdn_get_dn(&sdn); if (rawdn && (strlen(rawdn) > 0) && (NULL == dn)) { /* normalization failed */ op_shared_log_error_access(pb, "CMP", rawdn, "invalid dn"); send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL, "invalid dn", 0, NULL); slapi_sdn_done(&sdn); return; } /* * in LDAPv3 there can be optional control extensions on * the end of an LDAPMessage. we need to read them in and * pass them to the backend. */ if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 ) { send_ldap_result( pb, err, NULL, NULL, 0, NULL ); goto free_and_return; } /* target spec is used to decide which plugins are applicable for the operation */ operation_set_target_spec (pb->pb_op, &sdn); slapi_log_err(SLAPI_LOG_ARGS, "do_compare: dn (%s) attr (%s)\n", rawdn, ava.ava_type, 0 ); slapi_log_access( LDAP_DEBUG_STATS, "conn=%" NSPRIu64 " op=%d CMP dn=\"%s\" attr=\"%s\"\n", pb->pb_conn->c_connid, pb->pb_op->o_opid, dn, ava.ava_type ); /* * We could be serving multiple database backends. Select the * appropriate one. */ if ((err = slapi_mapping_tree_select(pb, &be, &referral, errorbuf, sizeof(errorbuf))) != LDAP_SUCCESS) { send_ldap_result(pb, err, NULL, errorbuf, 0, NULL); be = NULL; goto free_and_return; } if (referral) { int managedsait; slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait); if (managedsait) { send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "cannot compare referral", 0, NULL); slapi_entry_free(referral); goto free_and_return; } send_referrals_from_entry(pb,referral); slapi_entry_free(referral); goto free_and_return; } if ( be->be_compare != NULL ) { int isroot; slapi_pblock_set( pb, SLAPI_BACKEND, be ); isroot = pb->pb_op->o_isroot; slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &isroot ); /* EXCEPTION: compare target does not allocate memory. */ /* target never be modified by plugins. */ slapi_pblock_set( pb, SLAPI_COMPARE_TARGET_SDN, (void*)&sdn ); slapi_pblock_set( pb, SLAPI_COMPARE_TYPE, ava.ava_type); slapi_pblock_set( pb, SLAPI_COMPARE_VALUE, &ava.ava_value ); /* * call the pre-compare plugins. if they succeed, call * the backend compare function. then call the * post-compare plugins. */ if ( plugin_call_plugins( pb, SLAPI_PLUGIN_PRE_COMPARE_FN ) == 0 ) { int rc; slapi_pblock_set( pb, SLAPI_PLUGIN, be->be_database ); set_db_default_result_handlers(pb); rc = (*be->be_compare)( pb ); slapi_pblock_set( pb, SLAPI_PLUGIN_OPRETURN, &rc ); plugin_call_plugins( pb, SLAPI_PLUGIN_POST_COMPARE_FN ); } } else { send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Function not implemented", 0, NULL ); } free_and_return:; if (be) slapi_be_Unlock(be); slapi_sdn_done(&sdn); ava_done( &ava ); }
void slapi_sdn_free( Slapi_DN **sdn ) { slapi_sdn_done( *sdn ); slapi_ch_free( (void **)sdn ); }
/* This function is called to process operation that come over external connections */ void do_modrdn( Slapi_PBlock *pb ) { Slapi_Operation *operation; BerElement *ber; char *rawdn = NULL, *rawnewsuperior = NULL; const char *dn = NULL, *newsuperior = NULL; char *newrdn = NULL; int err = 0, deloldrdn = 0; ber_len_t len = 0; char *newdn = NULL; char *parent = NULL; Slapi_DN sdn; Slapi_DN snewdn; Slapi_DN *snewsuperior = NULL; LDAPDebug( LDAP_DEBUG_TRACE, "do_modrdn\n", 0, 0, 0 ); /* count the modrdn request */ slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsModifyRDNOps); slapi_pblock_get( pb, SLAPI_OPERATION, &operation); ber = operation->o_ber; slapi_sdn_init(&sdn); slapi_sdn_init(&snewdn); /* * Parse the modrdn request. It looks like this: * * ModifyRDNRequest := SEQUENCE { * entry DistinguishedName, * newrdn RelativeDistinguishedName, * deleteoldrdn BOOLEAN, * newSuperior [0] LDAPDN OPTIONAL -- v3 only * } */ if (ber_scanf(ber, "{aab", &rawdn, &newrdn, &deloldrdn) == LBER_ERROR) { LDAPDebug( LDAP_DEBUG_ANY, "ber_scanf failed (op=ModRDN; params=DN,newRDN,deleteOldRDN)\n", 0, 0, 0 ); op_shared_log_error_access (pb, "MODRDN", "???", "decoding error"); send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "unable to decode DN, newRDN, or deleteOldRDN parameters", 0, NULL ); goto free_and_return; } if ( ber_peek_tag( ber, &len ) == LDAP_TAG_NEWSUPERIOR ) { /* This "len" is not used... */ if ( pb->pb_conn->c_ldapversion < LDAP_VERSION3 ) { LDAPDebug( LDAP_DEBUG_ANY, "got newSuperior in LDAPv2 modrdn op\n", 0, 0, 0 ); op_shared_log_error_access (pb, "MODRDN", rawdn?rawdn:"", "decoding error"); send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "received newSuperior in LDAPv2 modrdn", 0, NULL ); slapi_ch_free_string( &rawdn ); slapi_ch_free_string( &newrdn ); goto free_and_return; } if ( ber_scanf( ber, "a", &rawnewsuperior ) == LBER_ERROR ) { LDAPDebug( LDAP_DEBUG_ANY, "ber_scanf failed (op=ModRDN; params=newSuperior)\n", 0, 0, 0 ); op_shared_log_error_access (pb, "MODRDN", rawdn, "decoding error"); send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "unable to decode newSuperior parameter", 0, NULL ); slapi_ch_free_string( &rawdn ); slapi_ch_free_string( &newrdn ); goto free_and_return; } } /* Check if we should be performing strict validation. */ if (config_get_dn_validate_strict()) { /* check that the dn is formatted correctly */ err = slapi_dn_syntax_check(pb, rawdn, 1); if (err) { /* syntax check failed */ op_shared_log_error_access(pb, "MODRDN", rawdn?rawdn:"", "strict: invalid dn"); send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL, "invalid dn", 0, NULL); slapi_ch_free_string( &rawdn ); slapi_ch_free_string( &newrdn ); slapi_ch_free_string( &rawnewsuperior ); goto free_and_return; } /* check that the new rdn is formatted correctly */ err = slapi_dn_syntax_check(pb, newrdn, 1); if (err) { /* syntax check failed */ op_shared_log_error_access(pb, "MODRDN", newrdn?newrdn:"", "strict: invalid new rdn"); send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL, "invalid new rdn", 0, NULL); slapi_ch_free_string( &rawdn ); slapi_ch_free_string( &newrdn ); slapi_ch_free_string( &rawnewsuperior ); goto free_and_return; } } slapi_sdn_init_dn_passin(&sdn, rawdn); dn = slapi_sdn_get_dn(&sdn); if (rawdn && (strlen(rawdn) > 0) && (NULL == dn)) { /* normalization failed */ op_shared_log_error_access(pb, "MODRDN", rawdn, "invalid dn"); send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL, "invalid dn", 0, NULL); slapi_ch_free_string( &newrdn ); slapi_ch_free_string( &rawnewsuperior ); goto free_and_return; } if (rawnewsuperior) { if (config_get_dn_validate_strict()) { /* check that the dn is formatted correctly */ err = slapi_dn_syntax_check(pb, rawnewsuperior, 1); if (err) { /* syntax check failed */ op_shared_log_error_access(pb, "MODRDN", rawnewsuperior, "strict: invalid new superior"); send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL, "invalid new superior", 0, NULL); slapi_ch_free_string( &rawnewsuperior ); goto free_and_return; } } snewsuperior = slapi_sdn_new_dn_passin(rawnewsuperior); newsuperior = slapi_sdn_get_dn(snewsuperior); } /* * If newsuperior is myself or my descendent, the modrdn should fail. * Note: need to check the case newrdn is given, and newsuperior * uses the newrdn, as well. */ parent = slapi_dn_parent(slapi_sdn_get_ndn(&sdn)); newdn = slapi_ch_smprintf("%s,%s", newrdn, parent); /* slapi_sdn_init_normdn_passin expects normalized but NOT * decapitalized dn */ slapi_sdn_init_dn_passin(&snewdn, newdn); if (0 == slapi_sdn_compare(&sdn, snewsuperior) || 0 == slapi_sdn_compare(&snewdn, snewsuperior)) { op_shared_log_error_access(pb, "MODRDN", newsuperior, "new superior is identical to the entry dn"); send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "new superior is identical to the entry dn", 0, NULL); goto free_and_return; } if (slapi_sdn_issuffix(snewsuperior, &sdn) || slapi_sdn_issuffix(snewsuperior, &snewdn)) { /* E.g., * newsuperior: ou=sub,ou=people,dc=example,dc=com * dn: ou=people,dc=example,dc=com */ op_shared_log_error_access(pb, "MODRDN", newsuperior, "new superior is descendent of the entry"); send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "new superior is descendent of the entry", 0, NULL); goto free_and_return; } /* * in LDAPv3 there can be optional control extensions on * the end of an LDAPMessage. we need to read them in and * pass them to the backend. */ if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 ) { op_shared_log_error_access (pb, "MODRDN", dn, "failed to decode LDAP controls"); send_ldap_result( pb, err, NULL, NULL, 0, NULL ); goto free_and_return; } LDAPDebug( LDAP_DEBUG_ARGS, "do_modrdn: dn (%s) newrdn (%s) deloldrdn (%d)\n", dn, newrdn, deloldrdn ); slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &pb->pb_op->o_isroot ); /* dn, newrdn and newsuperior are all normalized */ slapi_pblock_set( pb, SLAPI_ORIGINAL_TARGET, (void *)slapi_sdn_get_udn(&sdn) ); slapi_pblock_set( pb, SLAPI_MODRDN_TARGET_SDN, &sdn ); slapi_pblock_set( pb, SLAPI_MODRDN_NEWRDN, (void *)newrdn ); slapi_pblock_set( pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, (void *)snewsuperior ); slapi_pblock_set( pb, SLAPI_MODRDN_DELOLDRDN, &deloldrdn ); op_shared_rename(pb, 0 /* do not pass in ownership of string arguments */ ); free_and_return: slapi_sdn_done(&sdn); slapi_ch_free_string(&newrdn); slapi_sdn_free(&snewsuperior); slapi_sdn_done(&snewdn); slapi_ch_free_string(&parent); return; }
/* This function is called to process operation that come over external connections */ void do_add( Slapi_PBlock *pb ) { Slapi_Operation *operation; BerElement *ber; char *last; ber_len_t len = LBER_ERROR; ber_tag_t tag; Slapi_Entry *e = NULL; int err; int rc; PRBool searchsubentry=PR_TRUE; slapi_log_err(SLAPI_LOG_TRACE, "do_add", "==>\n"); slapi_pblock_get( pb, SLAPI_OPERATION, &operation); ber = operation->o_ber; /* count the add request */ slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsAddEntryOps); /* * Parse the add request. It looks like this: * * AddRequest := [APPLICATION 14] SEQUENCE { * name DistinguishedName, * attrs SEQUENCE OF SEQUENCE { * type AttributeType, * values SET OF AttributeValue * } * } */ /* get the name */ { char *rawdn = NULL; Slapi_DN mysdn; if ( ber_scanf( ber, "{a", &rawdn ) == LBER_ERROR ) { slapi_ch_free_string(&rawdn); slapi_log_err(SLAPI_LOG_ERR, "do_add", "ber_scanf failed (op=Add; params=DN)\n"); op_shared_log_error_access (pb, "ADD", "???", "decoding error"); send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "decoding error", 0, NULL ); return; } /* Check if we should be performing strict validation. */ if (config_get_dn_validate_strict()) { /* check that the dn is formatted correctly */ rc = slapi_dn_syntax_check(pb, rawdn, 1); if (rc) { /* syntax check failed */ op_shared_log_error_access(pb, "ADD", rawdn?rawdn:"", "strict: invalid dn"); send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL, "invalid dn", 0, NULL); slapi_ch_free_string(&rawdn); return; } } slapi_sdn_init_dn_passin(&mysdn, rawdn); if (rawdn && (strlen(rawdn) > 0) && (NULL == slapi_sdn_get_dn(&mysdn))) { /* normalization failed */ op_shared_log_error_access(pb, "ADD", rawdn, "invalid dn"); send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL, "invalid dn", 0, NULL); slapi_sdn_done(&mysdn); return; } e = slapi_entry_alloc(); /* Responsibility for DN is passed to the Entry. */ slapi_entry_init_ext(e, &mysdn, NULL); slapi_sdn_done(&mysdn); } slapi_log_err(SLAPI_LOG_ARGS, "do_add", "dn (%s)\n", (char *)slapi_entry_get_dn_const(e)); /* get the attrs */ for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT && tag != LBER_END_OF_SEQORSET; tag = ber_next_element( ber, &len, last ) ) { char *type = NULL, *normtype = NULL; struct berval **vals = NULL; len = -1; /* reset - not used in loop */ if ( ber_scanf( ber, "{a{V}}", &type, &vals ) == LBER_ERROR ) { op_shared_log_error_access (pb, "ADD", slapi_sdn_get_dn (slapi_entry_get_sdn_const(e)), "decoding error"); send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "decoding error", 0, NULL ); slapi_ch_free_string(&type); ber_bvecfree( vals ); goto free_and_return; } if ( vals == NULL ) { slapi_log_err(SLAPI_LOG_ERR, "do_add - no values for type %s\n", type, 0, 0 ); op_shared_log_error_access (pb, "ADD", slapi_sdn_get_dn (slapi_entry_get_sdn_const(e)), "null value"); send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0, NULL ); slapi_ch_free_string(&type); goto free_and_return; } normtype = slapi_attr_syntax_normalize(type); if ( !normtype || !*normtype ) { char ebuf[SLAPI_DSE_RETURNTEXT_SIZE]; rc = LDAP_INVALID_SYNTAX; slapi_create_errormsg(ebuf, sizeof(ebuf), "invalid type '%s'", type); op_shared_log_error_access (pb, "ADD", slapi_sdn_get_dn (slapi_entry_get_sdn_const(e)), ebuf); send_ldap_result( pb, rc, NULL, ebuf, 0, NULL ); slapi_ch_free_string(&type); slapi_ch_free( (void**)&normtype ); ber_bvecfree( vals ); goto free_and_return; } slapi_ch_free_string(&type); /* for now we just ignore attributes that client is not allowed to modify so not to break existing clients */ if (op_shared_is_allowed_attr (normtype, pb->pb_conn->c_isreplication_session)){ if (( rc = slapi_entry_add_values( e, normtype, vals )) != LDAP_SUCCESS ) { slapi_log_access( LDAP_DEBUG_STATS, "conn=%" NSPRIu64 " op=%d ADD dn=\"%s\", add values for type %s failed\n", pb->pb_conn->c_connid, operation->o_opid, slapi_entry_get_dn_const(e), normtype ); send_ldap_result( pb, rc, NULL, NULL, 0, NULL ); slapi_ch_free( (void**)&normtype ); ber_bvecfree( vals ); goto free_and_return; } /* if this is uniqueid attribute, set uniqueid field of the entry */ if (strcasecmp (normtype, SLAPI_ATTR_UNIQUEID) == 0) { e->e_uniqueid = slapi_ch_strdup (vals[0]->bv_val); } if(searchsubentry) searchsubentry=check_oc_subentry(e,vals,normtype); } slapi_ch_free( (void**)&normtype ); ber_bvecfree( vals ); } /* Ensure that created attributes are not used in the RDN. */ if (check_rdn_for_created_attrs(e)) { op_shared_log_error_access (pb, "ADD", slapi_sdn_get_dn(slapi_entry_get_sdn_const(e)), "invalid DN"); send_ldap_result( pb, LDAP_INVALID_DN_SYNTAX, NULL, "illegal attribute in RDN", 0, NULL ); goto free_and_return; } /* len, is ber_len_t, which is uint. Can't be -1. May be better to remove (len != 0) check */ if ( (tag != LBER_END_OF_SEQORSET) && (len != -1) ) { op_shared_log_error_access (pb, "ADD", slapi_sdn_get_dn (slapi_entry_get_sdn_const(e)), "decoding error"); send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "decoding error", 0, NULL ); goto free_and_return; } /* * in LDAPv3 there can be optional control extensions on * the end of an LDAPMessage. we need to read them in and * pass them to the backend. */ if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 ) { op_shared_log_error_access (pb, "ADD", slapi_sdn_get_dn (slapi_entry_get_sdn_const(e)), "failed to decode LDAP controls"); send_ldap_result( pb, err, NULL, NULL, 0, NULL ); goto free_and_return; } slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &operation->o_isroot ); slapi_pblock_set( pb, SLAPI_ADD_ENTRY, e ); if (pb->pb_conn->c_flags & CONN_FLAG_IMPORT) { /* this add is actually part of a bulk import -- punt */ handle_fast_add(pb, e); } else { op_shared_add ( pb ); } /* make sure that we don't free entry if it is successfully added */ e = NULL; free_and_return:; if (e) slapi_entry_free (e); }
/* Extract just the configuration information we need for bootstrapping purposes 1) set up error logging 2) disable syntax checking 3) load the syntax plugins etc. */ int slapd_bootstrap_config(const char *configdir) { char configfile[MAXPATHLEN+1]; PRFileInfo prfinfo; int rc = 0; /* Fail */ int done = 0; PRInt32 nr = 0; PRFileDesc *prfd = 0; char *buf = 0; char *lastp = 0; char *entrystr = 0; if (NULL == configdir) { slapi_log_error(SLAPI_LOG_FATAL, "startup", "Passed null config directory\n"); return rc; /* Fail */ } PR_snprintf(configfile, sizeof(configfile), "%s/%s", configdir, CONFIG_FILENAME); if ( (rc = PR_GetFileInfo( configfile, &prfinfo )) != PR_SUCCESS ) { /* the "real" file does not exist; see if there is a tmpfile */ char tmpfile[MAXPATHLEN+1]; slapi_log_error(SLAPI_LOG_FATAL, "config", "The configuration file %s does not exist\n", configfile); PR_snprintf(tmpfile, sizeof(tmpfile), "%s/%s.tmp", configdir, CONFIG_FILENAME); if ( PR_GetFileInfo( tmpfile, &prfinfo ) == PR_SUCCESS ) { rc = PR_Rename(tmpfile, configfile); if (rc == PR_SUCCESS) { slapi_log_error(SLAPI_LOG_FATAL, "config", "The configuration file %s was restored from backup %s\n", configfile, tmpfile); } else { slapi_log_error(SLAPI_LOG_FATAL, "config", "The configuration file %s was not restored from backup %s, error %d\n", configfile, tmpfile, rc); return rc; /* Fail */ } } else { slapi_log_error(SLAPI_LOG_FATAL, "config", "The backup configuration file %s does not exist, either.\n", tmpfile); return rc; /* Fail */ } } if ( (rc = PR_GetFileInfo( configfile, &prfinfo )) != PR_SUCCESS ) { PRErrorCode prerr = PR_GetError(); slapi_log_error(SLAPI_LOG_FATAL, "config", "The given config file %s could not be accessed, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n", configfile, prerr, slapd_pr_strerror(prerr)); return rc; } else if (( prfd = PR_Open( configfile, PR_RDONLY, SLAPD_DEFAULT_FILE_MODE )) == NULL ) { PRErrorCode prerr = PR_GetError(); slapi_log_error(SLAPI_LOG_FATAL, "config", "The given config file %s could not be opened for reading, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n", configfile, prerr, slapd_pr_strerror(prerr)); return rc; /* Fail */ } else { /* read the entire file into core */ buf = slapi_ch_malloc( prfinfo.size + 1 ); if (( nr = slapi_read_buffer( prfd, buf, prfinfo.size )) < 0 ) { slapi_log_error(SLAPI_LOG_FATAL, "config", "Could only read %d of %d bytes from config file %s\n", nr, prfinfo.size, configfile); rc = 0; /* Fail */ done= 1; } (void)PR_Close(prfd); buf[ nr ] = '\0'; if(!done) { char workpath[MAXPATHLEN+1]; char loglevel[BUFSIZ]; char maxdescriptors[BUFSIZ]; char val[BUFSIZ]; char _localuser[BUFSIZ]; char logenabled[BUFSIZ]; char schemacheck[BUFSIZ]; char syntaxcheck[BUFSIZ]; char syntaxlogging[BUFSIZ]; char plugintracking[BUFSIZ]; char dn_validate_strict[BUFSIZ]; Slapi_DN plug_dn; workpath[0] = loglevel[0] = maxdescriptors[0] = '\0'; val[0] = logenabled[0] = schemacheck[0] = syntaxcheck[0] = '\0'; syntaxlogging[0] = _localuser[0] = '\0'; plugintracking [0] = dn_validate_strict[0] = '\0'; /* Convert LDIF to entry structures */ slapi_sdn_init_ndn_byref(&plug_dn, PLUGIN_BASE_DN); while ((entrystr = dse_read_next_entry(buf, &lastp)) != NULL) { char errorbuf[BUFSIZ]; /* * XXXmcs: it would be better to also pass * SLAPI_STR2ENTRY_REMOVEDUPVALS in the flags, but * duplicate value checking requires that the syntax * and schema subsystems be initialized... and they * are not yet. */ Slapi_Entry *e = slapi_str2entry(entrystr, SLAPI_STR2ENTRY_NOT_WELL_FORMED_LDIF); if (e == NULL) { LDAPDebug(LDAP_DEBUG_ANY, "The entry [%s] in the configfile %s was empty or could not be parsed\n", entrystr, configfile, 0); continue; } /* increase file descriptors */ #if !defined(_WIN32) && !defined(AIX) if (!maxdescriptors[0] && entry_has_attr_and_value(e, CONFIG_MAXDESCRIPTORS_ATTRIBUTE, maxdescriptors, sizeof(maxdescriptors))) { if (config_set_maxdescriptors( CONFIG_MAXDESCRIPTORS_ATTRIBUTE, maxdescriptors, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile, CONFIG_MAXDESCRIPTORS_ATTRIBUTE, errorbuf); } } #endif /* !defined(_WIN32) && !defined(AIX) */ /* see if we need to enable error logging */ if (!logenabled[0] && entry_has_attr_and_value(e, CONFIG_ERRORLOG_LOGGING_ENABLED_ATTRIBUTE, logenabled, sizeof(logenabled))) { if (log_set_logging( CONFIG_ERRORLOG_LOGGING_ENABLED_ATTRIBUTE, logenabled, SLAPD_ERROR_LOG, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile, CONFIG_ERRORLOG_LOGGING_ENABLED_ATTRIBUTE, errorbuf); } } #ifndef _WIN32 /* set the local user name; needed to set up error log */ if (!_localuser[0] && entry_has_attr_and_value(e, CONFIG_LOCALUSER_ATTRIBUTE, _localuser, sizeof(_localuser))) { if (config_set_localuser(CONFIG_LOCALUSER_ATTRIBUTE, _localuser, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s. \n", configfile, CONFIG_LOCALUSER_ATTRIBUTE, errorbuf); } } #endif /* set the log file name */ workpath[0] = '\0'; if (!workpath[0] && entry_has_attr_and_value(e, CONFIG_ERRORLOG_ATTRIBUTE, workpath, sizeof(workpath))) { if (config_set_errorlog(CONFIG_ERRORLOG_ATTRIBUTE, workpath, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s. \n", configfile, CONFIG_ERRORLOG_ATTRIBUTE, errorbuf); } } /* set the error log level */ if (!loglevel[0] && entry_has_attr_and_value(e, CONFIG_LOGLEVEL_ATTRIBUTE, loglevel, sizeof(loglevel))) { if (should_detach || !config_get_errorlog_level()) { /* -d wasn't on command line */ if (config_set_errorlog_level(CONFIG_LOGLEVEL_ATTRIBUTE, loglevel, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s. \n", configfile, CONFIG_LOGLEVEL_ATTRIBUTE, errorbuf); } } else { LDAPDebug(LDAP_DEBUG_ANY, "%s: ignoring %s (since -d %d was given on " "the command line)\n", CONFIG_LOGLEVEL_ATTRIBUTE, loglevel, config_get_errorlog_level()); } } /* set the cert dir; needed in slapd_nss_init */ workpath[0] = '\0'; if (entry_has_attr_and_value(e, CONFIG_CERTDIR_ATTRIBUTE, workpath, sizeof(workpath))) { if (config_set_certdir(CONFIG_CERTDIR_ATTRIBUTE, workpath, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s. \n", configfile, CONFIG_CERTDIR_ATTRIBUTE, errorbuf); } } /* set the sasl path; needed in main */ workpath[0] = '\0'; if (entry_has_attr_and_value(e, CONFIG_SASLPATH_ATTRIBUTE, workpath, sizeof(workpath))) { if (config_set_saslpath(CONFIG_SASLPATH_ATTRIBUTE, workpath, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s. \n", configfile, CONFIG_SASLPATH_ATTRIBUTE, errorbuf); } } #if defined(ENABLE_LDAPI) /* set the ldapi file path; needed in main */ workpath[0] = '\0'; if (entry_has_attr_and_value(e, CONFIG_LDAPI_FILENAME_ATTRIBUTE, workpath, sizeof(workpath))) { if (config_set_ldapi_filename(CONFIG_LDAPI_FILENAME_ATTRIBUTE, workpath, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s. \n", configfile, CONFIG_LDAPI_FILENAME_ATTRIBUTE, errorbuf); } } /* set the ldapi switch; needed in main */ workpath[0] = '\0'; if (entry_has_attr_and_value(e, CONFIG_LDAPI_SWITCH_ATTRIBUTE, workpath, sizeof(workpath))) { if (config_set_ldapi_switch(CONFIG_LDAPI_SWITCH_ATTRIBUTE, workpath, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s. \n", configfile, CONFIG_LDAPI_SWITCH_ATTRIBUTE, errorbuf); } } #endif /* see if the entry is a child of the plugin base dn */ if (slapi_sdn_isparent(&plug_dn, slapi_entry_get_sdn_const(e))) { if (entry_has_attr_and_value(e, "objectclass", "nsSlapdPlugin", 0) && (entry_has_attr_and_value(e, ATTR_PLUGIN_TYPE, "syntax", 0) || entry_has_attr_and_value(e, ATTR_PLUGIN_TYPE, "matchingrule", 0))) { /* add the syntax/matching scheme rule plugin */ if (plugin_setup(e, 0, 0, 1)) { LDAPDebug(LDAP_DEBUG_ANY, "The plugin entry [%s] in the configfile %s was invalid\n", slapi_entry_get_dn(e), configfile, 0); rc = 0; slapi_sdn_done(&plug_dn); goto bail; } } } /* see if the entry is a grand child of the plugin base dn */ if (slapi_sdn_isgrandparent(&plug_dn, slapi_entry_get_sdn_const(e))) { if (entry_has_attr_and_value(e, "objectclass", "nsSlapdPlugin", 0) && ( entry_has_attr_and_value(e, ATTR_PLUGIN_TYPE, "pwdstoragescheme", 0) || entry_has_attr_and_value(e, ATTR_PLUGIN_TYPE, "reverpwdstoragescheme", 0) ) ) { /* add the pwd storage scheme rule plugin */ if (plugin_setup(e, 0, 0, 1)) { LDAPDebug(LDAP_DEBUG_ANY, "The plugin entry [%s] in the configfile %s was invalid\n", slapi_entry_get_dn(e), configfile, 0); rc = 0; slapi_sdn_done(&plug_dn); goto bail; } } } /* see if we need to disable schema checking */ if (!schemacheck[0] && entry_has_attr_and_value(e, CONFIG_SCHEMACHECK_ATTRIBUTE, schemacheck, sizeof(schemacheck))) { if (config_set_schemacheck(CONFIG_SCHEMACHECK_ATTRIBUTE, schemacheck, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile, CONFIG_SCHEMACHECK_ATTRIBUTE, errorbuf); } } /* see if we need to enable plugin binddn tracking */ if (!plugintracking[0] && entry_has_attr_and_value(e, CONFIG_PLUGIN_BINDDN_TRACKING_ATTRIBUTE, plugintracking, sizeof(plugintracking))) { if (config_set_plugin_tracking(CONFIG_PLUGIN_BINDDN_TRACKING_ATTRIBUTE, plugintracking, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile, CONFIG_PLUGIN_BINDDN_TRACKING_ATTRIBUTE, errorbuf); } } /* see if we need to enable syntax checking */ if (!syntaxcheck[0] && entry_has_attr_and_value(e, CONFIG_SYNTAXCHECK_ATTRIBUTE, syntaxcheck, sizeof(syntaxcheck))) { if (config_set_syntaxcheck(CONFIG_SYNTAXCHECK_ATTRIBUTE, syntaxcheck, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile, CONFIG_SYNTAXCHECK_ATTRIBUTE, errorbuf); } } /* see if we need to enable syntax warnings */ if (!syntaxlogging[0] && entry_has_attr_and_value(e, CONFIG_SYNTAXLOGGING_ATTRIBUTE, syntaxlogging, sizeof(syntaxlogging))) { if (config_set_syntaxlogging(CONFIG_SYNTAXLOGGING_ATTRIBUTE, syntaxlogging, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile, CONFIG_SYNTAXLOGGING_ATTRIBUTE, errorbuf); } } /* see if we need to enable strict dn validation */ if (!dn_validate_strict[0] && entry_has_attr_and_value(e, CONFIG_DN_VALIDATE_STRICT_ATTRIBUTE, dn_validate_strict, sizeof(dn_validate_strict))) { if (config_set_dn_validate_strict(CONFIG_DN_VALIDATE_STRICT_ATTRIBUTE, dn_validate_strict, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile, CONFIG_DN_VALIDATE_STRICT_ATTRIBUTE, errorbuf); } } /* see if we need to expect quoted schema values */ if (entry_has_attr_and_value(e, CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE, val, sizeof(val))) { if (config_set_enquote_sup_oc( CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE, val, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile, CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE, errorbuf); } val[0] = 0; } /* see if we need to maintain case in AT and OC names */ if (entry_has_attr_and_value(e, CONFIG_RETURN_EXACT_CASE_ATTRIBUTE, val, sizeof(val))) { if (config_set_return_exact_case( CONFIG_RETURN_EXACT_CASE_ATTRIBUTE, val, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile, CONFIG_RETURN_EXACT_CASE_ATTRIBUTE, errorbuf); } val[0] = 0; } /* see if we should allow attr. name exceptions, e.g. '_'s */ if (entry_has_attr_and_value(e, CONFIG_ATTRIBUTE_NAME_EXCEPTION_ATTRIBUTE, val, sizeof(val))) { if (config_set_attrname_exceptions( CONFIG_ATTRIBUTE_NAME_EXCEPTION_ATTRIBUTE, val, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile, CONFIG_ATTRIBUTE_NAME_EXCEPTION_ATTRIBUTE, errorbuf); } val[0] = 0; } /* see if we need to maintain schema compatibility with 4.x */ if (entry_has_attr_and_value(e, CONFIG_DS4_COMPATIBLE_SCHEMA_ATTRIBUTE, val, sizeof(val))) { if (config_set_ds4_compatible_schema( CONFIG_DS4_COMPATIBLE_SCHEMA_ATTRIBUTE, val, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile, CONFIG_DS4_COMPATIBLE_SCHEMA_ATTRIBUTE, errorbuf); } val[0] = 0; } /* see if we need to allow trailing spaces in OC and AT names */ if (entry_has_attr_and_value(e, CONFIG_SCHEMA_IGNORE_TRAILING_SPACES, val, sizeof(val))) { if (config_set_schema_ignore_trailing_spaces( CONFIG_SCHEMA_IGNORE_TRAILING_SPACES, val, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile, CONFIG_SCHEMA_IGNORE_TRAILING_SPACES, errorbuf); } val[0] = 0; } /* rfc1274-rewrite */ if (entry_has_attr_and_value(e, CONFIG_REWRITE_RFC1274_ATTRIBUTE, val, sizeof(val))) { if (config_set_rewrite_rfc1274( CONFIG_REWRITE_RFC1274_ATTRIBUTE, val, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile, CONFIG_REWRITE_RFC1274_ATTRIBUTE, errorbuf); } val[0] = 0; } /* what is our localhost name */ if (entry_has_attr_and_value(e, CONFIG_LOCALHOST_ATTRIBUTE, val, sizeof(val))) { if (config_set_localhost( CONFIG_LOCALHOST_ATTRIBUTE, val, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) { LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile, CONFIG_LOCALHOST_ATTRIBUTE, errorbuf); } val[0] = 0; } if (e) slapi_entry_free(e); } /* kexcoff: initialize rootpwstoragescheme and pw_storagescheme * if not explicilty set in the config file */ if ( config_set_storagescheme() ) { /* default scheme plugin not loaded */ slapi_log_error(SLAPI_LOG_FATAL, "startup", "The default password storage scheme SSHA could not be read or was not found in the file %s. It is mandatory.\n", configfile); exit (1); } else { slapi_sdn_done(&plug_dn); rc= 1; /* OK */ } } slapi_ch_free_string(&buf); } bail: slapi_ch_free_string(&buf); return rc; }