From 50bb2ee6676e10cdda704982dfa831efa4011037 Mon Sep 17 00:00:00 2001 From: Noriko Hosoi Date: Thu, 15 Jul 2010 13:33:28 -0700 Subject: 612771 - RHDS 8.1/389 v1.2.5 accepts 2 identical entries with different DN formats https://bugzilla.redhat.com/show_bug.cgi?id=612771 Fix Description: This patch fixes the upgradednformat utility to eliminate the duplicated DNs found in the upgrading period. Assuming DN: attr0=value0,attr1=value1,...,attrn=valuen exists in the DB and another identical DN is found, the second DN is renamed to nsuniqueid=+attr0=value0,attr1=value1,...,attrn=valuen , where the is the unique id assigned to the entry when the entry is added to the server. The modification is logged in the error log. In addition, there was a bug to handle multi-valued RDNs in slapi_dn_normalize_ext. In case multi-valued RDN appears with DN value (e.g., nsuniqueid=+cn=uid\=\,o\=,dc=), it was not normalized properly. Introduced second rdn_av_stack (subinitial_rdn_av_stack) for the nested DN value. See also: http://directory.fedoraproject.org/wiki/Upgrade_to_New_DN_Format#Another_Upgrade_Scenario --- ldap/admin/src/scripts/70upgradednformat.pl | 22 +-- ldap/servers/slapd/back-ldbm/ancestorid.c | 3 +- ldap/servers/slapd/back-ldbm/back-ldbm.h | 11 ++ ldap/servers/slapd/back-ldbm/dblayer.c | 2 + ldap/servers/slapd/back-ldbm/import-threads.c | 186 +++++++++++++++++++++----- ldap/servers/slapd/back-ldbm/import.c | 24 +++- ldap/servers/slapd/back-ldbm/import.h | 1 + ldap/servers/slapd/back-ldbm/ldif2ldbm.c | 17 ++- ldap/servers/slapd/dn.c | 61 ++++++--- ldap/servers/slapd/entry.c | 53 +++++--- ldap/servers/slapd/slap.h | 1 + ldap/servers/slapd/slapi-plugin.h | 9 ++ ldap/servers/slapd/slapi-private.h | 1 + 13 files changed, 299 insertions(+), 92 deletions(-) diff --git a/ldap/admin/src/scripts/70upgradednformat.pl b/ldap/admin/src/scripts/70upgradednformat.pl index 894a0887..100a318c 100644 --- a/ldap/admin/src/scripts/70upgradednformat.pl +++ b/ldap/admin/src/scripts/70upgradednformat.pl @@ -15,15 +15,21 @@ use File::Copy; sub runinst { my ($inf, $inst, $dseldif, $conn) = @_; - # First, check if the server is up or down. - if ($conn->isa("Mozilla::LDAP::Conn")) { - # The server is up, we do nothing. - return (); - } - my @errs; my $config = "cn=config"; + my $config_entry = $conn->search($config, "base", "(cn=*)"); + if (!$config_entry) { + return ("error_no_configuration_entry", $!); + } + # First, check if the server is up or down. + my $rundir = $config_entry->getValues('nsslapd-rundir'); + + # Check if the server is up or not + my $pidfile = $rundir . "/" . $inst . ".pid"; + if (-e $pidfile) { + return (); # server is running; do nothing. + } my $mappingtree = "cn=mapping tree,cn=config"; my $ldbmbase = "cn=ldbm database,cn=plugins,cn=config"; @@ -62,10 +68,6 @@ sub runinst { $mtentry = $conn->nextEntry(); } - my $config_entry = $conn->search($config, "base", "(cn=*)", 0, ("nsslapd-instancedir")); - if (!$config_entry) { - return ("error_no_configuration_entry", $!); - } my $instancedir = $config_entry->{"nsslapd-instancedir"}[0]; my $upgradednformat = $instancedir . "/upgradednformat"; diff --git a/ldap/servers/slapd/back-ldbm/ancestorid.c b/ldap/servers/slapd/back-ldbm/ancestorid.c index 59d77223..8f641452 100644 --- a/ldap/servers/slapd/back-ldbm/ancestorid.c +++ b/ldap/servers/slapd/back-ldbm/ancestorid.c @@ -397,7 +397,8 @@ static int ldbm_ancestorid_new_idl_create_index(backend *be) ai_aid->ai_indexmask |= INDEX_OFFLINE; /* Open the ancestorid index file */ - ret = dblayer_get_index_file(be, ai_aid, &db_aid, DBOPEN_CREATE); + ret = dblayer_get_index_file(be, ai_aid, &db_aid, + DBOPEN_CREATE|DBOPEN_TRUNCATE); if (ret != 0) { ldbm_nasty(sourcefile,13050,ret); goto out; diff --git a/ldap/servers/slapd/back-ldbm/back-ldbm.h b/ldap/servers/slapd/back-ldbm/back-ldbm.h index 1bf9a035..efcf03f9 100644 --- a/ldap/servers/slapd/back-ldbm/back-ldbm.h +++ b/ldap/servers/slapd/back-ldbm/back-ldbm.h @@ -755,7 +755,18 @@ typedef struct _back_search_result_set /* flag: open_flag for dblayer_get_index_file -> dblayer_open_file */ #define DBOPEN_CREATE 0x1 /* oprinary mode: create a db file if needed */ +#define DBOPEN_TRUNCATE 0x2 /* oprinary mode: truncate a db file if needed */ /* whether we call fat lock or not [608146] */ #define SERIALLOCK(li) (li->li_fat_lock) + +/* + * 0: SUCCESS + * libdb returns negative error codes + * Linux errno's < 140, for now + * Chose any positive value other than the above values. + * Being used to specify duplicated DN is found in entrydn or entryrdn. + */ +#define LDBM_ERROR_FOUND_DUPDN 9999 + #endif /* _back_ldbm_h_ */ diff --git a/ldap/servers/slapd/back-ldbm/dblayer.c b/ldap/servers/slapd/back-ldbm/dblayer.c index 27a4f6f4..23da61ff 100644 --- a/ldap/servers/slapd/back-ldbm/dblayer.c +++ b/ldap/servers/slapd/back-ldbm/dblayer.c @@ -2792,6 +2792,8 @@ int dblayer_open_file(backend *be, char* indexname, int open_flag, struct attrin open_flags = DB_THREAD; if (open_flag & DBOPEN_CREATE) open_flags |= DB_CREATE; + if (open_flag & DBOPEN_TRUNCATE) + open_flags |= DB_TRUNCATE; if (!ppDB) goto out; diff --git a/ldap/servers/slapd/back-ldbm/import-threads.c b/ldap/servers/slapd/back-ldbm/import-threads.c index 32fcf467..859f6c39 100644 --- a/ldap/servers/slapd/back-ldbm/import-threads.c +++ b/ldap/servers/slapd/back-ldbm/import-threads.c @@ -547,7 +547,7 @@ void import_producer(void *param) curr_lineno, curr_filename); if (e) { slapi_entry_free(e); - } + } job->skipped++; continue; @@ -978,7 +978,7 @@ upgradedn_free_list(struct upgradedn_attr **ud_list) slapi_ch_free((void **)&ptr); ptr = next; } - *ud_list = NULL; + *ud_list = NULL; return; } @@ -1011,8 +1011,8 @@ upgradedn_add_to_list(struct upgradedn_attr **ud_list, * deleted attribute list e_deleted_attrs. * * If FLAG_UPGRADEDNFORMAT is set, worker_threads for indexing DN syntax - * attributes are brought up. Foreman thread updates entrydn index - * as well as the entry itself in the id2entry.db#. + * attributes (+ cn & ou) are brought up. Foreman thread updates entrydn + * index as well as the entry itself in the id2entry.db#. * * Note: QUIT state for info->state is introduced for DRYRUN mode to * distinguish the intentional QUIT (found the dn upgrade candidate) @@ -1142,7 +1142,7 @@ upgradedn_producer(void *param) ecopy = (char *)slapi_ch_malloc(data.dsize + 1); memcpy(ecopy, data.dptr, data.dsize); *(ecopy + data.dsize) = '\0'; - e = slapi_str2entry(data.data, 0); + e = slapi_str2entry(data.data, SLAPI_STR2ENTRY_USE_OBSOLETE_DNFORMAT); if ( NULL == e ) { if (job->task) { slapi_task_log_notice(job->task, @@ -1274,7 +1274,7 @@ upgradedn_producer(void *param) skipit = 0; for (ud_ptr = ud_list; ud_ptr; ud_ptr = ud_ptr->ud_next) { - /* Move the current value to e_deleted_attrs. */ + /* Move the current value to e_aux_attrs. */ ud_attr = attrlist_find(e->e_attrs, ud_ptr->ud_type); if (ud_attr) { if (0 == strcmp(ud_ptr->ud_type, "entrydn")) { @@ -1304,24 +1304,24 @@ upgradedn_producer(void *param) break; } } - attrlist_add(&e->e_deleted_attrs, ud_attr); + attrlist_add(&e->e_aux_attrs, ud_attr); } else { /* We have to normalize the orignal string to generate the key in the index. */ - a = attrlist_find(e->e_deleted_attrs, ud_ptr->ud_type); + a = attrlist_find(e->e_aux_attrs, ud_ptr->ud_type); if (!a) { a = slapi_attr_new(); slapi_attr_init(a, ud_ptr->ud_type); } else { - a = attrlist_remove(&e->e_deleted_attrs, + a = attrlist_remove(&e->e_aux_attrs, ud_ptr->ud_type); } slapi_dn_normalize_case_original(ud_ptr->ud_value); value = slapi_value_new_string(ud_ptr->ud_value); slapi_attr_add_value(a, value); slapi_value_free(&value); - attrlist_add(&e->e_deleted_attrs, a); + attrlist_add(&e->e_aux_attrs, a); } } } @@ -1475,7 +1475,7 @@ import_wait_for_space_in_fifo(ImportJob *job, size_t new_esize) } /* helper function for the foreman: */ -static int foreman_do_parentid(ImportJob *job, struct backentry *entry, +static int foreman_do_parentid(ImportJob *job, FifoItem *fi, struct attrinfo *parentid_ai) { backend *be = job->inst->inst_be; @@ -1483,11 +1483,44 @@ static int foreman_do_parentid(ImportJob *job, struct backentry *entry, Slapi_Attr *attr = NULL; int idl_disposition = 0; int ret = 0; + struct backentry *entry = fi->entry; + + if (job->flags & FLAG_UPGRADEDNFORMAT) { + /* Get the parentid attribute value from deleted attr list */ + Slapi_Value *value = NULL; + Slapi_Attr *pid_to_del = + attrlist_remove(&entry->ep_entry->e_aux_attrs, "parentid"); + if (pid_to_del) { + /* Delete it. */ + ret = slapi_attr_first_value(pid_to_del, &value); + if (ret < 0) { + import_log_notice(job, + "Error: retrieving parentid value (error %d)", + ret); + } else { + const struct berval *bval = + slapi_value_get_berval((const Slapi_Value *)value); + ret = index_addordel_string(be, "parentid", + bval->bv_val, entry->ep_id, + BE_INDEX_DEL|BE_INDEX_EQUALITY|BE_INDEX_NORMALIZED, + NULL); + if (ret) { + import_log_notice(job, + "Error: deleting %s from parentid index " + "(error %d: %s)", + bval->bv_val, ret, dblayer_strerror(ret)); + return ret; + } + } + slapi_attr_free(&pid_to_del); + } + } if (slapi_entry_attr_find(entry->ep_entry, "parentid", &attr) == 0) { svals = attr_get_present_values(attr); - ret = index_addordel_values_ext_sv(be, "parentid", svals, NULL, entry->ep_id, - BE_INDEX_ADD, NULL, &idl_disposition, NULL); + ret = index_addordel_values_ext_sv(be, "parentid", svals, NULL, + entry->ep_id, BE_INDEX_ADD, + NULL, &idl_disposition, NULL); if (idl_disposition != IDL_INSERT_NORMAL) { char *attr_value = slapi_value_get_berval(svals[0])->bv_val; ID parent_id = atol(attr_value); @@ -1510,19 +1543,20 @@ static int foreman_do_parentid(ImportJob *job, struct backentry *entry, } /* helper function for the foreman: */ -static int foreman_do_entrydn(ImportJob *job, FifoItem *fi) +static int +foreman_do_entrydn(ImportJob *job, FifoItem *fi) { backend *be = job->inst->inst_be; struct berval bv; int err = 0, ret = 0; IDList *IDL; + struct backentry *entry = fi->entry; if (job->flags & FLAG_UPGRADEDNFORMAT) { /* Get the entrydn attribute value from deleted attr list */ Slapi_Value *value = NULL; Slapi_Attr *entrydn_to_del = - attrlist_remove(&fi->entry->ep_entry->e_deleted_attrs, "entrydn"); - + attrlist_remove(&entry->ep_entry->e_aux_attrs, "entrydn"); if (entrydn_to_del) { /* Delete it. */ ret = slapi_attr_first_value(entrydn_to_del, &value); @@ -1534,8 +1568,7 @@ static int foreman_do_entrydn(ImportJob *job, FifoItem *fi) const struct berval *bval = slapi_value_get_berval((const Slapi_Value *)value); ret = index_addordel_string(be, "entrydn", - bval->bv_val, - fi->entry->ep_id, + bval->bv_val, entry->ep_id, BE_INDEX_DEL|BE_INDEX_EQUALITY|BE_INDEX_NORMALIZED, NULL); if (ret) { @@ -1551,7 +1584,7 @@ static int foreman_do_entrydn(ImportJob *job, FifoItem *fi) } /* insert into the entrydn index */ - bv.bv_val = (void*)backentry_get_ndn(fi->entry); /* jcm - Had to cast away const */ + bv.bv_val = (void*)backentry_get_ndn(entry); /* jcm - Had to cast away const */ bv.bv_len = strlen(bv.bv_val); /* We need to check here whether the DN is already present in @@ -1565,14 +1598,24 @@ static int foreman_do_entrydn(ImportJob *job, FifoItem *fi) if (job->flags & FLAG_UPGRADEDNFORMAT) { /* * In the UPGRADEDNFORMAT case, if entrydn value exists, - * that means entrydn is not upgraded. And it is normal. - * We could add entrydn only when the value is not found in the db. + * that means either 1) entrydn is not upgraded (ID == entry->ep_id) + * or 2) a duplicated entry is found (ID != entry->ep_id). + * (1) is normal. For (2), need to return a specific error + * LDBM_ERROR_FOUND_DUPDN. + * Otherwise, add entrydn to the entrydn index file. */ if (IDL) { + ID id = idl_firstid(IDL); /* entrydn is a single attr */ idl_free(IDL); + if (id != entry->ep_id) { /* case (2) */ + import_log_notice(job, "Duplicated entrydn detected: \"%s\": " + "Entry ID: (%d, %d)", + bv.bv_val, id, entry->ep_id); + return LDBM_ERROR_FOUND_DUPDN; + } } else { ret = index_addordel_string(be, "entrydn", - bv.bv_val, fi->entry->ep_id, + bv.bv_val, entry->ep_id, BE_INDEX_ADD|BE_INDEX_NORMALIZED, NULL); if (ret) { import_log_notice(job, "Error writing entrydn index " @@ -1587,7 +1630,7 @@ static int foreman_do_entrydn(ImportJob *job, FifoItem *fi) /* IMPOSTER ! Get thee hence... */ import_log_notice(job, "WARNING: Skipping duplicate entry " "\"%s\" found at line %d of file \"%s\"", - slapi_entry_get_dn(fi->entry->ep_entry), + slapi_entry_get_dn(entry->ep_entry), fi->line, fi->filename); idl_free(IDL); /* skip this one */ @@ -1595,7 +1638,7 @@ static int foreman_do_entrydn(ImportJob *job, FifoItem *fi) job->skipped++; return -1; /* skip to next entry */ } - ret = index_addordel_string(be, "entrydn", bv.bv_val, fi->entry->ep_id, + ret = index_addordel_string(be, "entrydn", bv.bv_val, entry->ep_id, BE_INDEX_ADD|BE_INDEX_NORMALIZED, NULL); if (ret) { import_log_notice(job, "Error writing entrydn index " @@ -1678,6 +1721,11 @@ void import_foreman(void *param) /* first, fill in any operational attributes */ /* add_op_attrs wants a pblock for some reason. */ + if (job->flags & FLAG_UPGRADEDNFORMAT) { + /* Upgrade dn format may alter the DIT structure. */ + /* It requires a special treatment for that. */ + parent_status = IMPORT_ADD_OP_ATTRS_SAVE_OLD_PID; + } if (add_op_attrs(pb, inst->inst_li, fi->entry, &parent_status) != 0) { import_log_notice(job, "ERROR: Could not add op attrs to " "entry ending at line %d of file \"%s\"", @@ -1720,10 +1768,85 @@ void import_foreman(void *param) /* insert into the entrydn index */ ret = foreman_do_entrydn(job, fi); - if (ret == -1) + if (ret == -1) { goto cont; /* skip entry */ - if (ret != 0) + } else if ((job->flags & FLAG_UPGRADEDNFORMAT) && + (LDBM_ERROR_FOUND_DUPDN == ret)) { + /* + * Duplicated DN is detected. + * + * Rename to nsuniqueid=+ + * E.g., uid=tuser,dc=example,dc=com ==> + * nsuniqueid=+uid=tuser,dc=example,dc=com + * + * Note: FLAG_UPGRADEDNFORMAT only. + */ + Slapi_Attr *orig_entrydn = NULL; + Slapi_Attr *new_entrydn = slapi_attr_new(); + Slapi_Attr *nsuniqueid = NULL; + char *uuidstr = NULL; + char *new_dn = NULL; + char *orig_dn = + slapi_ch_strdup(slapi_entry_get_dn(fi->entry->ep_entry)); + struct berval *vals[2]; + struct berval val; + int rc = 0; + nsuniqueid = attrlist_find(fi->entry->ep_entry->e_attrs, + "nsuniqueid"); + if (nsuniqueid) { + Slapi_Value *uival = NULL; + rc = slapi_attr_first_value(nsuniqueid, &uival); + uuidstr = slapi_value_get_string(uival); + } else { + import_log_notice(job, "ERROR: Failed to get nsUniqueId " + "of the duplicated entry %s; " + "Entry ID: %d", + orig_dn, fi->entry->ep_id); + goto cont; + } + new_dn = slapi_create_dn_string("nsuniqueid=%s+%s", + uuidstr, orig_dn); + /* releasing original dn */ + slapi_sdn_done(&fi->entry->ep_entry->e_sdn); + /* setting new dn; pass in */ + slapi_sdn_init_dn_passin(&fi->entry->ep_entry->e_sdn, new_dn); + + /* Replacing entrydn attribute value */ + orig_entrydn = attrlist_remove(&fi->entry->ep_entry->e_attrs, + "entrydn"); + /* released in forman_do_entrydn */ + attrlist_add(&fi->entry->ep_entry->e_aux_attrs, orig_entrydn); + + /* Setting new entrydn attribute value */ + slapi_attr_init(new_entrydn, "entrydn"); + valueset_add_string(&new_entrydn->a_present_values, + /* new_dn: duped in valueset_add_string */ + (const char *)new_dn, + CSN_TYPE_UNKNOWN, NULL); + attrlist_add(&fi->entry->ep_entry->e_attrs, new_entrydn); + + /* Try foreman_do_entrydn, again. */ + ret = foreman_do_entrydn(job, fi); + if (ret) { + import_log_notice(job, "ERROR: Failed to rename duplicated " + "DN %s to %s; Entry ID: %d", + orig_dn, new_dn, fi->entry->ep_id); + slapi_ch_free_string(&orig_dn); + if (-1 == ret) { + goto cont; /* skip entry */ + } else { + goto error; + } + } else { + import_log_notice(job, "WARNING: Duplicated entry %s is " + "renamed to %s; Entry ID: %d", + orig_dn, new_dn, fi->entry->ep_id); + slapi_ch_free_string(&orig_dn); + } + + } else if (ret != 0) { goto error; + } } if (job->flags & FLAG_ABORT) { @@ -1764,17 +1887,14 @@ void import_foreman(void *param) goto error; } - if (!(job->flags & FLAG_UPGRADEDNFORMAT) && /* Upgrade dn format mode - does not need to update - parentid index */ - !slapi_entry_flag_is_set(fi->entry->ep_entry, - SLAPI_ENTRY_FLAG_TOMBSTONE)) { + if (!slapi_entry_flag_is_set(fi->entry->ep_entry, + SLAPI_ENTRY_FLAG_TOMBSTONE)) { /* parentid index * (we have to do this here, because the parentID is dependent on * looking up by entrydn.) * Only add to the parent index if the entry is not a tombstone. */ - ret = foreman_do_parentid(job, fi->entry, parentid_ai); + ret = foreman_do_parentid(job, fi, parentid_ai); if (ret != 0) goto error; @@ -1954,7 +2074,7 @@ void import_worker(void *param) Slapi_Value *value = NULL; const struct berval *bval = NULL; Slapi_Attr *key_to_del = - attrlist_remove(&fi->entry->ep_entry->e_deleted_attrs, + attrlist_remove(&fi->entry->ep_entry->e_aux_attrs, info->index_info->name); if (key_to_del) { diff --git a/ldap/servers/slapd/back-ldbm/import.c b/ldap/servers/slapd/back-ldbm/import.c index 8b66705f..dde03db3 100644 --- a/ldap/servers/slapd/back-ldbm/import.c +++ b/ldap/servers/slapd/back-ldbm/import.c @@ -262,11 +262,25 @@ static int import_attr_callback(void *node, void *param) * attribute type. (except entrydn -- taken care below) */ int rc = 0; Slapi_Attr attr = {0}; - slapi_attr_init(&attr, a->ai_type); - rc = slapi_attr_is_dn_syntax_attr(&attr); - attr_done(&attr); - if (0 == rc) { - return 0; + + /* + * Treat cn and ou specially. Bring up the import workers for + * cn and ou even though they are not DN syntax attribute. + * This is done because they have some exceptional case to store + * DN format in the admin entries such as UserPreferences. + */ + if ((0 == PL_strcasecmp("cn", a->ai_type)) || + (0 == PL_strcasecmp("commonname", a->ai_type)) || + (0 == PL_strcasecmp("ou", a->ai_type)) || + (0 == PL_strcasecmp("organizationalUnit", a->ai_type))) { + ; + } else { + slapi_attr_init(&attr, a->ai_type); + rc = slapi_attr_is_dn_syntax_attr(&attr); + attr_done(&attr); + if (0 == rc) { + return 0; + } } } diff --git a/ldap/servers/slapd/back-ldbm/import.h b/ldap/servers/slapd/back-ldbm/import.h index e5569d34..e9843400 100644 --- a/ldap/servers/slapd/back-ldbm/import.h +++ b/ldap/servers/slapd/back-ldbm/import.h @@ -52,6 +52,7 @@ #define IMPORT_ADD_OP_ATTRS_OK 0 #define IMPORT_ADD_OP_ATTRS_NO_PARENT 1 +#define IMPORT_ADD_OP_ATTRS_SAVE_OLD_PID 2 #define IMPORT_COMPLETE_PASS 1 #define IMPORT_INCOMPLETE_PASS 2 diff --git a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c index 0cb90623..4dabd81f 100644 --- a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c +++ b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c @@ -195,6 +195,7 @@ int add_op_attrs(Slapi_PBlock *pb, struct ldbminfo *li, struct backentry *ep, backend *be; char *pdn; ID pid = 0; + int save_old_pid = 0; slapi_pblock_get(pb, SLAPI_BACKEND, &be); @@ -203,6 +204,9 @@ int add_op_attrs(Slapi_PBlock *pb, struct ldbminfo *li, struct backentry *ep, */ if (NULL != status) { + if (IMPORT_ADD_OP_ATTRS_SAVE_OLD_PID == *status) { + save_old_pid = 1; + } *status = IMPORT_ADD_OP_ATTRS_OK; } @@ -248,6 +252,16 @@ int add_op_attrs(Slapi_PBlock *pb, struct ldbminfo *li, struct backentry *ep, /* Get rid of attributes you're not allowed to specify yourself */ slapi_entry_delete_values( ep->ep_entry, hassubordinates, NULL ); slapi_entry_delete_values( ep->ep_entry, numsubordinates, NULL ); + + /* Upgrade DN format only */ + /* Set current parentid to e_aux_attrs to remove it from the index file. */ + if (save_old_pid) { + Slapi_Attr *pid_attr = NULL; + pid_attr = attrlist_remove(&ep->ep_entry->e_attrs, "parentid"); + if (pid_attr) { + attrlist_add(&ep->ep_entry->e_aux_attrs, pid_attr); + } + } /* Add the entryid, parentid and entrydn operational attributes */ /* Note: This function is provided by the Add code */ @@ -1376,11 +1390,12 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb) run_from_cmdline = (task_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE); slapi_pblock_get(pb, SLAPI_BACKEND_TASK, &task); + dblayer_txn_init(li, &txn); + if (run_from_cmdline) { /* No ldbm backend exists until we process the config info. */ li->li_flags |= SLAPI_TASK_RUNNING_FROM_COMMANDLINE; ldbm_config_load_dse_info(li); - txn.back_txn_txn = NULL; /* no transaction */ } inst = ldbm_instance_find_by_name(li, instance_name); diff --git a/ldap/servers/slapd/dn.c b/ldap/servers/slapd/dn.c index 108c1655..e1891de6 100644 --- a/ldap/servers/slapd/dn.c +++ b/ldap/servers/slapd/dn.c @@ -493,13 +493,19 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len) char *d = NULL; /* work pointer for dest */ char *ends = NULL; char *endd = NULL; - char *typestart = NULL; - char *subtypestart = NULL; /* used for the nested DN */ char *lastesc = NULL; + /* rdn avs for the main DN */ + char *typestart = NULL; int rdn_av_count = 0; struct berval *rdn_avs = NULL; struct berval initial_rdn_av_stack[ SLAPI_DNNORM_INITIAL_RDN_AVS ]; + /* rdn avs for the nested DN */ + char *subtypestart = NULL; /* used for nested rdn avs */ + int subrdn_av_count = 0; + struct berval *subrdn_avs = NULL; + struct berval subinitial_rdn_av_stack[ SLAPI_DNNORM_INITIAL_RDN_AVS ]; int chkblank = 0; + int avstat = 0; if (NULL == dest) { goto bail; @@ -649,16 +655,18 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len) * multivalued RDNs. */ if (subtypestart && - (ISPLUS(*(s+1)) || rdn_av_count > 0)) { - add_rdn_av(subtypestart, d, &rdn_av_count, - &rdn_avs, initial_rdn_av_stack); + (ISPLUS(*(s+1)) || subrdn_av_count > 0)) { + add_rdn_av(subtypestart, d, &subrdn_av_count, + &subrdn_avs, subinitial_rdn_av_stack); } if (!ISPLUS(*(s+1))) { /* at end of this RDN */ - if (rdn_av_count > 1) { - sort_rdn_avs( rdn_avs, rdn_av_count, 1 ); + if (subrdn_av_count > 1) { + sort_rdn_avs( subrdn_avs, + subrdn_av_count, 1 ); } if (rdn_av_count > 0) { - reset_rdn_avs( &rdn_avs, &rdn_av_count ); + reset_rdn_avs( &subrdn_avs, + &subrdn_av_count ); subtypestart = NULL; } } @@ -681,7 +689,7 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len) } } else if (((state == INVALUE1ST) && (s+2 < ends) && LEADNEEDSESCAPESTR(s+1)) || - ((state == INVALUE) && + ((state == INVALUE) && (((s+2 < ends) && NEEDSESCAPESTR(s+1)) || (ISEOV(s+3, ends) && ISBLANKSTR(s+1))))) { /* e.g., cn=abc\20 ,... */ @@ -724,16 +732,16 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len) * multivalued RDNs. */ if (subtypestart && - (ISPLUSSTR(s+1) || rdn_av_count > 0)) { - add_rdn_av(subtypestart, d, &rdn_av_count, - &rdn_avs, initial_rdn_av_stack); + (ISPLUSSTR(s+1) || subrdn_av_count > 0)) { + add_rdn_av(subtypestart, d, &subrdn_av_count, + &subrdn_avs, subinitial_rdn_av_stack); } if (!ISPLUSSTR(s+1)) { /* at end of this RDN */ - if (rdn_av_count > 1) { - sort_rdn_avs( rdn_avs, rdn_av_count, 1 ); + if (subrdn_av_count > 1) { + sort_rdn_avs( subrdn_avs, subrdn_av_count, 1 ); } - if (rdn_av_count > 0) { - reset_rdn_avs( &rdn_avs, &rdn_av_count ); + if (subrdn_av_count > 0) { + reset_rdn_avs( &subrdn_avs, &subrdn_av_count ); } } } @@ -856,15 +864,15 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len) * multivalued RDNs. */ if (ISPLUS(*s) || rdn_av_count > 0) { - add_rdn_av(subtypestart, d, &rdn_av_count, - &rdn_avs, initial_rdn_av_stack); + add_rdn_av(subtypestart, d, &subrdn_av_count, + &subrdn_avs, subinitial_rdn_av_stack); } if (!ISPLUS(*s)) { /* at end of this RDN */ - if (rdn_av_count > 1) { - sort_rdn_avs( rdn_avs, rdn_av_count, 1 ); + if (subrdn_av_count > 1) { + sort_rdn_avs( subrdn_avs, subrdn_av_count, 1 ); } if (rdn_av_count > 0) { - reset_rdn_avs( &rdn_avs, &rdn_av_count ); + reset_rdn_avs( &subrdn_avs, &subrdn_av_count ); subtypestart = NULL; } } @@ -1173,6 +1181,17 @@ slapi_dn_normalize( char *dn ) return dn; } +/* Introduced for the upgrade tool. DON'T USE THIS API! */ +char * +slapi_dn_normalize_original( char *dn ) +{ + /* LDAPDebug( LDAP_DEBUG_TRACE, "=> slapi_dn_normalize \"%s\"\n", dn, 0, 0 ); */ + *(substr_dn_normalize_orig( dn, dn + strlen( dn ))) = '\0'; + /* LDAPDebug( LDAP_DEBUG_TRACE, "<= slapi_dn_normalize \"%s\"\n", dn, 0, 0 ); */ + + return( dn ); +} + /* Introduced for the upgrade tool. DON'T USE THIS API! */ char * slapi_dn_normalize_case_original( char *dn ) diff --git a/ldap/servers/slapd/entry.c b/ldap/servers/slapd/entry.c index 17f41990..f2bd3061 100644 --- a/ldap/servers/slapd/entry.c +++ b/ldap/servers/slapd/entry.c @@ -279,14 +279,19 @@ str2entry_fast( char *s, int flags, int read_stateinfo ) if (freetype) slapi_ch_free_string(&type); continue; } - normdn = slapi_create_dn_string("%s", valuecharptr); - if (NULL == normdn) { - LDAPDebug1Arg(LDAP_DEBUG_TRACE, + if (flags & SLAPI_STR2ENTRY_USE_OBSOLETE_DNFORMAT) { + normdn = slapi_ch_strdup( + slapi_dn_normalize_original(valuecharptr)); + } else { + normdn = slapi_create_dn_string("%s", valuecharptr); + if (NULL == normdn) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, "str2entry_fast: Invalid DN: %s\n", valuecharptr); - slapi_entry_free( e ); - if (retmalloc) slapi_ch_free_string(&valuecharptr); - if (freetype) slapi_ch_free_string(&type); - return NULL; + slapi_entry_free( e ); + if (retmalloc) slapi_ch_free_string(&valuecharptr); + if (freetype) slapi_ch_free_string(&type); + return NULL; + } } /* normdn is consumed in e */ slapi_entry_set_dn(e, normdn); @@ -375,21 +380,26 @@ str2entry_fast( char *s, int flags, int read_stateinfo ) return NULL; } } - rc = slapi_dn_normalize_ext(valuecharptr, 0, &dn_aval, &dnlen); - if (rc < 0) { - /* Give up normalizing the attribute value */ - LDAPDebug2Args(LDAP_DEBUG_TRACE, + if (flags & SLAPI_STR2ENTRY_USE_OBSOLETE_DNFORMAT) { + dn_aval = slapi_dn_normalize_original(valuecharptr); + slapi_value_set(value, dn_aval, strlen(dn_aval)); + } else { + rc = + slapi_dn_normalize_ext(valuecharptr, 0, &dn_aval, &dnlen); + if (rc < 0) { + /* Give up normalizing the attribute value */ + LDAPDebug2Args(LDAP_DEBUG_TRACE, "str2entry_fast: Invalid DN value: %s: %s\n", type, valuecharptr); - dn_aval = valuecharptr; - dnlen = valuelen; - } - slapi_value_set(value, dn_aval, dnlen); - if (rc > 0) { /* if rc == 0, valuecharptr is passed in */ - slapi_ch_free_string(&dn_aval); - } else if (rc == 0) { /* rc == 0; valuecharptr is passed in; - not null terminated */ - *(dn_aval + dnlen) = '\0'; + dn_aval = valuecharptr; + dnlen = valuelen; + } + slapi_value_set(value, dn_aval, dnlen); + if (rc > 0) { + /* rc > 0; + dn_aval was allocated in slapi_dn_normalize_ext */ + slapi_ch_free_string(&dn_aval); + } } } else { slapi_value_set(value, valuecharptr, valuelen); @@ -1172,6 +1182,7 @@ free_and_return: ( SLAPI_STR2ENTRY_IGNORE_STATE \ | SLAPI_STR2ENTRY_EXPAND_OBJECTCLASSES \ | SLAPI_STR2ENTRY_TOMBSTONE_CHECK \ + | SLAPI_STR2ENTRY_USE_OBSOLETE_DNFORMAT \ ) #define SLAPI_STRENTRY_FLAGS_HANDLED_BY_STR2ENTRY_FAST \ @@ -1197,7 +1208,7 @@ slapi_str2entry( char *s, int flags ) * slower but more forgiving str2entry_dupcheck() function. */ if ( 0 != ( flags & SLAPI_STR2ENTRY_NOT_WELL_FORMED_LDIF ) || - 0 != ( flags & ~SLAPI_STRENTRY_FLAGS_HANDLED_BY_STR2ENTRY_FAST )) + 0 != ( flags & ~SLAPI_STRENTRY_FLAGS_HANDLED_BY_STR2ENTRY_FAST )) { e= str2entry_dupcheck( s, flags, read_stateinfo ); } diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h index 10da992f..534b6eb5 100644 --- a/ldap/servers/slapd/slap.h +++ b/ldap/servers/slapd/slap.h @@ -615,6 +615,7 @@ struct slapi_entry { PRRWLock *e_virtual_lock; /* for access to cached vattrs */ void *e_extension; /* A list of entry object extensions */ unsigned char e_flags; + Slapi_Attr *e_aux_attrs; /* Attr list used for upgrade */ }; /* diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h index 045f1648..ff141084 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -881,6 +881,15 @@ Slapi_Entry *slapi_str2entry( char *s, int flags ); */ #define SLAPI_STR2ENTRY_NO_SCHEMA_LOCK 256 +/** + * Normalize DN using obsolete DN normalizer. + * + * This marco is used only for the upgrading dn format tool. + * + * \see slapi_str2entry() + */ +#define SLAPI_STR2ENTRY_USE_OBSOLETE_DNFORMAT 512 + /** * Generates a description of an entry as an LDIF string. * diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h index 7c8d9647..485e2940 100644 --- a/ldap/servers/slapd/slapi-private.h +++ b/ldap/servers/slapd/slapi-private.h @@ -375,6 +375,7 @@ Slapi_DN *slapi_sdn_init_dn_passin(Slapi_DN *sdn,const char *dn); Slapi_DN *slapi_sdn_init_ndn_byref(Slapi_DN *sdn,const char *dn); Slapi_DN *slapi_sdn_init_ndn_byval(Slapi_DN *sdn,const char *dn); Slapi_DN *slapi_sdn_init_dn_ndn_byref(Slapi_DN *sdn,const char *dn); +char * slapi_dn_normalize_original( char *dn ); char * slapi_dn_normalize_case_original( char *dn ); /* filter.c */ -- cgit