From 991042b89f8a5c6e0f9d220418dc020b9b27983c Mon Sep 17 00:00:00 2001 From: Juan Gomez Date: Wed, 19 May 1999 01:36:03 +0000 Subject: [PATCH] Modrdn fix to support deleteoldrdn (LDAP v2). --- servers/slapd/back-ldbm/modify.c | 159 ++++++++++++--- servers/slapd/back-ldbm/modrdn.c | 218 +++++++++++++++++---- servers/slapd/back-ldbm/proto-back-ldbm.h | 12 ++ servers/slapd/dn.c | 224 ++++++++++++++++++++++ servers/slapd/modify.c | 79 +------- servers/slapd/proto-slap.h | 6 +- tests/scripts/defines.sh | 2 + tests/scripts/test005-modrdn | 95 ++++++++- 8 files changed, 655 insertions(+), 140 deletions(-) diff --git a/servers/slapd/back-ldbm/modify.c b/servers/slapd/back-ldbm/modify.c index 1ef124d554..3772d42384 100644 --- a/servers/slapd/back-ldbm/modify.c +++ b/servers/slapd/back-ldbm/modify.c @@ -14,37 +14,114 @@ static int add_values(Entry *e, LDAPMod *mod, char *dn); static int delete_values(Entry *e, LDAPMod *mod, char *dn); static int replace_values(Entry *e, LDAPMod *mod, char *dn); +static void add_lastmods(Operation *op, LDAPMod **mods); -int -ldbm_back_modify( + +static void +add_lastmods( Operation *op, LDAPMod **mods ) +{ + char buf[22]; + struct berval bv; + struct berval *bvals[2]; + LDAPMod **m; + LDAPMod *tmp; + struct tm *ltm; + + Debug( LDAP_DEBUG_TRACE, "add_lastmods\n", 0, 0, 0 ); + + bvals[0] = &bv; + bvals[1] = NULL; + + /* remove any attempts by the user to modify these attrs */ + for ( m = mods; *m != NULL; m = &(*m)->mod_next ) { + if ( strcasecmp( (*m)->mod_type, "modifytimestamp" ) == 0 || + strcasecmp( (*m)->mod_type, "modifiersname" ) == 0 || + strcasecmp( (*m)->mod_type, "createtimestamp" ) == 0 || + strcasecmp( (*m)->mod_type, "creatorsname" ) == 0 ) { + + Debug( LDAP_DEBUG_TRACE, + "add_lastmods: found lastmod attr: %s\n", + (*m)->mod_type, 0, 0 ); + tmp = *m; + *m = (*m)->mod_next; + free( tmp->mod_type ); + if ( tmp->mod_bvalues != NULL ) { + ber_bvecfree( tmp->mod_bvalues ); + } + free( tmp ); + if (!*m) + break; + } + } + + if ( op->o_dn == NULL || op->o_dn[0] == '\0' ) { + bv.bv_val = "NULLDN"; + bv.bv_len = strlen( bv.bv_val ); + } else { + bv.bv_val = op->o_dn; + bv.bv_len = strlen( bv.bv_val ); + } + tmp = (LDAPMod *) ch_calloc( 1, sizeof(LDAPMod) ); + tmp->mod_type = ch_strdup( "modifiersname" ); + tmp->mod_op = LDAP_MOD_REPLACE; + tmp->mod_bvalues = (struct berval **) ch_calloc( 1, + 2 * sizeof(struct berval *) ); + tmp->mod_bvalues[0] = ber_bvdup( &bv ); + tmp->mod_next = *mods; + *mods = tmp; + + ldap_pvt_thread_mutex_lock( ¤ttime_mutex ); +#ifndef LDAP_LOCALTIME + ltm = gmtime( ¤ttime ); + strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", ltm ); +#else + ltm = localtime( ¤ttime ); + strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm ); +#endif + ldap_pvt_thread_mutex_unlock( ¤ttime_mutex ); + bv.bv_val = buf; + bv.bv_len = strlen( bv.bv_val ); + tmp = (LDAPMod *) ch_calloc( 1, sizeof(LDAPMod) ); + tmp->mod_type = ch_strdup( "modifytimestamp" ); + tmp->mod_op = LDAP_MOD_REPLACE; + tmp->mod_bvalues = (struct berval **) ch_calloc( 1, 2 * sizeof(struct berval *) ); + tmp->mod_bvalues[0] = ber_bvdup( &bv ); + tmp->mod_next = *mods; + *mods = tmp; +} + +/* We need this function because of LDAP modrdn. If we do not + * add this there would be a bunch of code replication here + * and there and of course the likelihood of bugs increases. + * Juan C. Gomez (gomez@engr.sgi.com) 05/18/99 + */ + +int ldbm_internal_modify( Backend *be, Connection *conn, Operation *op, char *dn, - LDAPMod *mods + LDAPMod *mods, + Entry *e ) { - struct ldbminfo *li = (struct ldbminfo *) be->be_private; - char *matched; - Entry *e; int i, err; LDAPMod *mod; - Debug(LDAP_DEBUG_ARGS, "ldbm_back_modify:\n", 0, 0, 0); + if ( ((be->be_lastmod == ON) + || ((be->be_lastmod == UNDEFINED)&&(global_lastmod == ON))) + && (be->be_update_ndn == NULL)) { + + /* XXX: It may be wrong, it changes mod time even if + * mod fails! + */ + add_lastmods( op, &mods ); - /* acquire and lock entry */ - if ( (e = dn2entry_w( be, dn, &matched )) == NULL ) { - send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, - NULL ); - if ( matched != NULL ) { - free( matched ); - } - return( -1 ); } if ( (err = acl_check_mods( be, conn, op, e, mods )) != LDAP_SUCCESS ) { send_ldap_result( conn, op, err, NULL, NULL ); - goto error_return; + return -1; } for ( mod = mods; mod != NULL; mod = mod->mod_next ) { @@ -65,7 +142,7 @@ ldbm_back_modify( if ( err != LDAP_SUCCESS ) { /* unlock entry, delete from cache */ send_ldap_result( conn, op, err, NULL, NULL ); - goto error_return; + return -1; } } @@ -73,35 +150,73 @@ ldbm_back_modify( if ( global_schemacheck && oc_schema_check( e ) != 0 ) { Debug( LDAP_DEBUG_ANY, "entry failed schema check\n", 0, 0, 0 ); send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, NULL, NULL ); - goto error_return; + return -1; } /* check for abandon */ ldap_pvt_thread_mutex_lock( &op->o_abandonmutex ); if ( op->o_abandon ) { ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); - goto error_return; + return -1; } ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); /* modify indexes */ if ( index_add_mods( be, mods, e->e_id ) != 0 ) { send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL ); - goto error_return; + return -1; } /* check for abandon */ ldap_pvt_thread_mutex_lock( &op->o_abandonmutex ); if ( op->o_abandon ) { ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); - goto error_return; + return -1; } ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex ); + return 0; + +}/* int ldbm_internal_modify() */ + + +int +ldbm_back_modify( + Backend *be, + Connection *conn, + Operation *op, + char *dn, + LDAPMod *mods +) +{ + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + char *matched; + Entry *e; + + Debug(LDAP_DEBUG_ARGS, "ldbm_back_modify:\n", 0, 0, 0); + + /* acquire and lock entry */ + if ( (e = dn2entry_w( be, dn, &matched )) == NULL ) { + send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, + NULL ); + if ( matched != NULL ) { + free( matched ); + } + return( -1 ); + } + + /* Modify the entry */ + if ( ldbm_internal_modify( be, conn, op, dn, mods, e ) != 0 ) { + + goto error_return; + + } + /* change the entry itself */ if ( id2entry_add( be, e ) != 0 ) { + entry_free( e ); send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL ); - goto error_return; + return -1; } send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); diff --git a/servers/slapd/back-ldbm/modrdn.c b/servers/slapd/back-ldbm/modrdn.c index 35b7f1eae8..fb38b64118 100644 --- a/servers/slapd/back-ldbm/modrdn.c +++ b/servers/slapd/back-ldbm/modrdn.c @@ -27,8 +27,23 @@ ldbm_back_modrdn( char *new_dn = NULL, *new_ndn = NULL; char sep[2]; Entry *e, *p = NULL; - int rootlock = 0; - int rc = -1; + int rootlock = 0; + int rc = -1; + + char *new_rdn_val = NULL; /* Val of new rdn */ + char *new_rdn_type = NULL; /* Type of new rdn */ + char *old_rdn; /* Old rdn's attr type & val */ + char *old_rdn_type = NULL; /* Type of old rdn attr. */ + char *old_rdn_val = NULL; /* Old rdn attribute value */ + struct berval add_bv; /* Stores new rdn att */ + struct berval *add_bvals[2]; /* Stores new rdn att */ + struct berval del_bv; /* Stores old rdn att */ + struct berval *del_bvals[2]; /* Stores old rdn att */ + LDAPMod mod[2]; /* Used to delete old rdn */ + + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn:()==>\n", + 0, 0, 0 ); /* get entry with writer lock */ if ( (e = dn2entry_w( be, dn, &matched )) == NULL ) { @@ -76,26 +91,7 @@ ldbm_back_modrdn( #endif p_dn = dn_parent( be, e->e_dn ); - new_dn = (char *) ch_malloc( strlen( p_dn ) + strlen( newrdn ) - + 3 ); - if ( dn_type( e->e_dn ) == DN_X500 ) { - strcpy( new_dn, newrdn ); - strcat( new_dn, "," ); - strcat( new_dn, p_dn ); - } else { - char *s; - strcpy( new_dn, newrdn ); - s = strchr( newrdn, '\0' ); - s--; - if ( *s != '.' && *s != '@' ) { - if ( (s = strpbrk( dn, ".@" )) != NULL ) { - sep[0] = *s; - sep[1] = '\0'; - strcat( new_dn, sep ); - } - } - strcat( new_dn, p_dn ); - } + } else { /* no parent, modrdn entry directly under root */ @@ -110,11 +106,154 @@ ldbm_back_modrdn( ldap_pvt_thread_mutex_lock(&li->li_root_mutex); rootlock = 1; - new_dn = ch_strdup( newrdn ); + } + build_new_dn( &new_dn, e->e_dn, p_dn, newrdn ); new_ndn = dn_normalize_case( ch_strdup( new_dn ) ); + /* Get attribute type and attribute value of our new rdn, we will + * need to add that to our new entry + */ + + if ( (new_rdn_type = rdn_attr_type( newrdn )) == NULL ) { + + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: can't figure out type of newrdn\n", + 0, 0, 0 ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + goto return_results; + + } + + if ( (new_rdn_val = rdn_attr_value( newrdn )) == NULL ) { + + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: can't figure out val of newrdn\n", + 0, 0, 0 ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + goto return_results; + + } + + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: new_rdn_val=\"%s\", new_rdn_type=\"%s\"\n", + new_rdn_val, new_rdn_type, 0 ); + + /* Retrieve the old rdn from the entry's dn */ + + if ( (old_rdn = dn_rdn( be, dn )) == NULL ) { + + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: can't figure out old_rdn from dn\n", + 0, 0, 0 ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + goto return_results; + + } + + if ( (old_rdn_type = rdn_attr_type( old_rdn )) == NULL ) { + + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: can't figure out the old_rdn type\n", + 0, 0, 0 ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); + goto return_results; + + } + + if ( strcasecmp( old_rdn_type, new_rdn_type ) != 0 ) { + + /* Not a big deal but we may say something */ + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: old_rdn_type=%s, new_rdn_type=%s!\n", + old_rdn_type, new_rdn_type, 0 ); + + } + + if ( dn_type( old_rdn ) == DN_X500 ) { + + Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: DN_X500\n", + 0, 0, 0 ); + + /* Add new attribute value to the entry. + */ + + add_bvals[0] = &add_bv; /* Array of bervals */ + add_bvals[1] = NULL; + + add_bv.bv_val = new_rdn_val; + add_bv.bv_len = strlen(new_rdn_val); + + mod[0].mod_type = old_rdn_type; + mod[0].mod_bvalues = add_bvals; + mod[0].mod_op = LDAP_MOD_ADD; + mod[0].mod_next = NULL; + + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: adding new rdn attr val =\"%s\"\n", + new_rdn_val, 0, 0 ); + + /* Remove old rdn value if required */ + + if (deleteoldrdn) { + + del_bvals[0] = &del_bv; /* Array of bervals */ + del_bvals[1] = NULL; + /* Get value of old rdn */ + + if ((old_rdn_val = rdn_attr_value( old_rdn )) + == NULL) { + + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: can't figure out old_rdn_val from old_rdn\n", + 0, 0, 0 ); + send_ldap_result( conn, op, + LDAP_OPERATIONS_ERROR, + "", "" ); + goto return_results; + + + } + + /* Remove old value of rdn as an attribute. */ + + del_bv.bv_val = old_rdn_val; + del_bv.bv_len = strlen(old_rdn_val); + + /* No need to normalize old_rdn_type, delete_values() + * does that for us + */ + mod[0].mod_next = &mod[1]; + mod[1].mod_type = old_rdn_type; + mod[1].mod_bvalues = del_bvals; + mod[1].mod_op = LDAP_MOD_DELETE; + mod[1].mod_next = NULL; + + }/* if (deleteoldrdn) */ + + /* modify memory copy of entry */ + if ( ldbm_internal_modify( be, conn, op, dn, &mod[0], e ) + != 0 ) { + + goto return_results; + + } + + } else { + + + Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: DNS DN\n", + 0, 0, 0 ); + /* XXXV3: not sure of what to do here */ + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn: not fully implemented...\n", + 0, 0, 0 ); + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL ); + goto return_results; + + } + if ( (dn2id ( be, new_ndn ) ) != NOID ) { send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL ); goto return_results; @@ -140,6 +279,7 @@ ldbm_back_modrdn( goto return_results; } + (void) cache_delete_entry( &li->li_cache, e ); free( e->e_dn ); free( e->e_ndn ); @@ -147,33 +287,41 @@ ldbm_back_modrdn( e->e_ndn = new_ndn; (void) cache_update_entry( &li->li_cache, e ); - /* XXX - * At some point here we need to update the attribute values in - * the entry itself that were effected by this RDN change - * (respecting the value of the deleteoldrdn parameter). - * - * Since the code to do this has not yet been written, treat this - * omission as a (documented) bug. - */ - - /* id2entry index */ + /* id2entry index: commit */ if ( id2entry_add( be, e ) != 0 ) { entry_free( e ); send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" ); - goto return_results; + goto return_results_new; } send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL ); rc = 0; -return_results: + Debug( LDAP_DEBUG_TRACE, + "ldbm_back_modrdn:()<==\n", + 0, 0, 0 ); + goto return_results_new; + +return_results: if( new_dn != NULL ) free( new_dn ); if( new_ndn != NULL ) free( new_ndn ); +return_results_new: + /* NOTE: + * new_dn and new_ndn are not deallocated because they are used by + * the cache entry at this point. + */ if( p_dn != NULL ) free( p_dn ); if( p_ndn != NULL ) free( p_ndn ); if( matched != NULL ) free( matched ); + /* LDAP v2 supporting correct attribute handling. */ + if( new_rdn_type != NULL ) free(new_rdn_type); + if( new_rdn_val != NULL ) free(new_rdn_val); + if( old_rdn != NULL ) free(old_rdn); + if( old_rdn_type != NULL ) free(old_rdn_type); + if( old_rdn_val != NULL ) free(old_rdn_val); + if( p != NULL ) { /* free parent and writer lock */ cache_return_entry_w( &li->li_cache, p ); diff --git a/servers/slapd/back-ldbm/proto-back-ldbm.h b/servers/slapd/back-ldbm/proto-back-ldbm.h index 603325d27d..33c7edea66 100644 --- a/servers/slapd/back-ldbm/proto-back-ldbm.h +++ b/servers/slapd/back-ldbm/proto-back-ldbm.h @@ -122,6 +122,18 @@ int index_add_values LDAP_P(( Backend *be, char *type, struct berval **vals, ID /* krbv4_ldap_auth LDAP_P(( Backend *be, struct berval *cred, AUTH_DAT *ad )); */ #endif +/* + * modify.c + */ + +/* We need this function because of LDAP modrdn. If we do not + * add this there would be a bunch of code replication here + * and there and of course the likelihood of bugs increases. + * Juan C. Gomez (gomez@engr.sgi.com) 05/18/99 + */ +int ldbm_internal_modify LDAP_P((Backend *be, Connection *conn, Operation *op, + char *dn, LDAPMod *mods, Entry *e)); + /* * nextid.c */ diff --git a/servers/slapd/dn.c b/servers/slapd/dn.c index 70863dc6d9..8b0c5cb187 100644 --- a/servers/slapd/dn.c +++ b/servers/slapd/dn.c @@ -220,6 +220,77 @@ dn_parent( return( ch_strdup( "" ) ); } +char * dn_rdn( + Backend *be, + char *dn ) +{ + char *s; + int inquote; + + if( dn == NULL ) { + return NULL; + } + + while(*dn && SPACE(*dn)) { + dn++; + } + + if( *dn == '\0' ) { + return( NULL ); + } + + if ( be != NULL && be_issuffix( be, dn ) ) { + return( NULL ); + } + + dn = ch_strdup( dn ); + + /* + * no =, assume it is a dns name, like blah@some.domain.name + * if the blah@ part is there, return some.domain.name. if + * it's just some.domain.name, return domain.name. + */ + if ( strchr( dn, '=' ) == NULL ) { + if ( (s = strchr( dn, '@' )) == NULL ) { + if ( (s = strchr( dn, '.' )) == NULL ) { + return( dn ); + } + } + *s = '\0'; + return( dn ); + } + + /* + * else assume it is an X.500-style name, which looks like + * foo=bar,sha=baz,... + */ + + inquote = 0; + + for ( s = dn; *s; s++ ) { + if ( *s == '\\' ) { + if ( *(s + 1) ) { + s++; + } + continue; + } + if ( inquote ) { + if ( *s == '"' ) { + inquote = 0; + } + } else { + if ( *s == '"' ) { + inquote = 1; + } else if ( DNSEPARATOR( *s ) ) { + *s = '\0'; + return( dn ); + } + } + } + + return( dn ); +} + /* * dn_issuffix - tells whether suffix is a suffix of dn. both dn * and suffix must be normalized. @@ -271,3 +342,156 @@ dn_upcase( char *dn ) return( dn ); } + +/* + * get_next_substring(), rdn_attr_type(), rdn_attr_value(), and + * build_new_dn(). + * + * Copyright 1999, Juan C. Gomez, All rights reserved. + * This software is not subject to any license of Silicon Graphics + * Inc. or Purdue University. + * + * Redistribution and use in source and binary forms are permitted + * without restriction or fee of any kind as long as this notice + * is preserved. + * + */ + +/* get_next_substring: + * + * Gets next substring in s, using d (or the end of the string '\0') as a + * string delimiter, and places it in a duplicated memory space. Leading + * spaces are ignored. String s **must** be null-terminated. + */ + +static char * +get_next_substring( char * s, char d ) +{ + + char *str, *r; + + r = str = ch_malloc( strlen(s) + 1 ); + + /* Skip leading spaces */ + + while ( *s && SPACE(*s) ) { + + s++; + + }/* while ( *s && SPACE(*s) ) */ + + /* Copy word */ + + while ( *s && (*s != d) ) { + + /* Don't stop when you see trailing spaces may be a multi-word + * string, i.e. name=John Doe! + */ + + *str++ = *s++; + + }/* while ( *s && (*s != d) ) */ + + *str = '\0'; + + return r; + +}/* char * get_word() */ + + +/* rdn_attr_type: + * + * Given a string (i.e. an rdn) of the form: + * "attribute_type = attribute_value" + * this function returns the type of an attribute, that is the + * string "attribute_type" which is placed in newly allocated + * memory. The returned string will be null-terminated. + */ + +char * rdn_attr_type( char * s ) +{ + + return get_next_substring( s, '=' ); + +}/* char * rdn_attr_type() */ + + +/* rdn_attr_value: + * + * Given a string (i.e. an rdn) of the form: + * "attribute_type = attribute_value" + * this function returns "attribute_type" which is placed in newly allocated + * memory. The returned string will be null-terminated and may contain + * spaces (i.e. "John Doe\0"). + */ + +char * +rdn_attr_value( char * rdn ) +{ + + char *str; + + if ( (str = strchr( rdn, '=' )) != NULL ) { + + return get_next_substring(++str, '\0'); + + }/* if ( (str = strpbrk( rdn, "=" )) != NULL ) */ + + return NULL; + +}/* char * rdn_attr_value() */ + + +/* build_new_dn: + * + * Used by ldbm/bdb2_back_modrdn to create the new dn of entries being + * renamed. + * + * new_dn = parent (p_dn) + separator(s) + rdn (newrdn) + null. + */ + +void +build_new_dn( char ** new_dn, char *e_dn, char * p_dn, char * newrdn ) +{ + + if ( p_dn == NULL ) { + + *new_dn = ch_strdup( newrdn ); + return; + + } + + *new_dn = (char *) ch_malloc( strlen( p_dn ) + strlen( newrdn ) + 3 ); + + if ( dn_type( e_dn ) == DN_X500 ) { + + strcpy( *new_dn, newrdn ); + strcat( *new_dn, "," ); + strcat( *new_dn, p_dn ); + + } else { + + char *s; + char sep[2]; + + strcpy( *new_dn, newrdn ); + s = strchr( newrdn, '\0' ); + s--; + + if ( (*s != '.') && (*s != '@') ) { + + if ( (s = strpbrk( e_dn, ".@" )) != NULL ) { + + sep[0] = *s; + sep[1] = '\0'; + strcat( *new_dn, sep ); + + }/* if ( (s = strpbrk( dn, ".@" )) != NULL ) */ + + }/* if ( *s != '.' && *s != '@' ) */ + + strcat( *new_dn, p_dn ); + + }/* if ( dn_type( e_dn ) == DN_X500 ) {}else */ + +}/* void build_new_dn() */ diff --git a/servers/slapd/modify.c b/servers/slapd/modify.c index c1ddd3faf4..44982c11dd 100644 --- a/servers/slapd/modify.c +++ b/servers/slapd/modify.c @@ -21,7 +21,6 @@ #include "slap.h" static void modlist_free(LDAPMod *mods); -static void add_lastmods(Operation *op, LDAPMod **mods); void @@ -154,10 +153,7 @@ do_modify( if ( be->be_update_ndn == NULL || strcmp( be->be_update_ndn, op->o_ndn ) == 0 ) { - if ( (be->be_lastmod == ON || ( be->be_lastmod == UNDEFINED && - global_lastmod == ON ) ) && be->be_update_ndn == NULL ) { - add_lastmods( op, &mods ); - } + if ( (*be->be_modify)( be, conn, op, ndn, mods ) == 0 ) { replog( be, LDAP_REQ_MODIFY, ndn, mods, 0 ); } @@ -191,76 +187,3 @@ modlist_free( free( mods ); } } - -static void -add_lastmods( Operation *op, LDAPMod **mods ) -{ - char buf[22]; - struct berval bv; - struct berval *bvals[2]; - LDAPMod **m; - LDAPMod *tmp; - struct tm *ltm; - - Debug( LDAP_DEBUG_TRACE, "add_lastmods\n", 0, 0, 0 ); - - bvals[0] = &bv; - bvals[1] = NULL; - - /* remove any attempts by the user to modify these attrs */ - for ( m = mods; *m != NULL; m = &(*m)->mod_next ) { - if ( strcasecmp( (*m)->mod_type, "modifytimestamp" ) == 0 || - strcasecmp( (*m)->mod_type, "modifiersname" ) == 0 || - strcasecmp( (*m)->mod_type, "createtimestamp" ) == 0 || - strcasecmp( (*m)->mod_type, "creatorsname" ) == 0 ) { - - Debug( LDAP_DEBUG_TRACE, - "add_lastmods: found lastmod attr: %s\n", - (*m)->mod_type, 0, 0 ); - tmp = *m; - *m = (*m)->mod_next; - free( tmp->mod_type ); - if ( tmp->mod_bvalues != NULL ) { - ber_bvecfree( tmp->mod_bvalues ); - } - free( tmp ); - if (!*m) - break; - } - } - - if ( op->o_dn == NULL || op->o_dn[0] == '\0' ) { - bv.bv_val = "NULLDN"; - bv.bv_len = strlen( bv.bv_val ); - } else { - bv.bv_val = op->o_dn; - bv.bv_len = strlen( bv.bv_val ); - } - tmp = (LDAPMod *) ch_calloc( 1, sizeof(LDAPMod) ); - tmp->mod_type = ch_strdup( "modifiersname" ); - tmp->mod_op = LDAP_MOD_REPLACE; - tmp->mod_bvalues = (struct berval **) ch_calloc( 1, - 2 * sizeof(struct berval *) ); - tmp->mod_bvalues[0] = ber_bvdup( &bv ); - tmp->mod_next = *mods; - *mods = tmp; - - ldap_pvt_thread_mutex_lock( ¤ttime_mutex ); -#ifndef LDAP_LOCALTIME - ltm = gmtime( ¤ttime ); - strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", ltm ); -#else - ltm = localtime( ¤ttime ); - strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm ); -#endif - ldap_pvt_thread_mutex_unlock( ¤ttime_mutex ); - bv.bv_val = buf; - bv.bv_len = strlen( bv.bv_val ); - tmp = (LDAPMod *) ch_calloc( 1, sizeof(LDAPMod) ); - tmp->mod_type = ch_strdup( "modifytimestamp" ); - tmp->mod_op = LDAP_MOD_REPLACE; - tmp->mod_bvalues = (struct berval **) ch_calloc( 1, 2 * sizeof(struct berval *) ); - tmp->mod_bvalues[0] = ber_bvdup( &bv ); - tmp->mod_next = *mods; - *mods = tmp; -} diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 7a766f78c9..52372983ae 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -102,10 +102,14 @@ void connection_activity LDAP_P(( Connection *conn )); char * dn_normalize LDAP_P(( char *dn )); char * dn_normalize_case LDAP_P(( char *dn )); char * dn_parent LDAP_P(( Backend *be, char *dn )); +char * dn_rdn LDAP_P(( Backend *be, char *dn )); int dn_issuffix LDAP_P(( char *dn, char *suffix )); int dn_type LDAP_P(( char *dn )); char * dn_upcase LDAP_P(( char *dn )); - +char * rdn_attr_value LDAP_P(( char * rdn )); +char * rdn_attr_type LDAP_P(( char * rdn )); +void build_new_dn LDAP_P(( char ** new_dn, char *e_dn, char * p_dn, + char * newrdn )); /* * entry.c */ diff --git a/tests/scripts/defines.sh b/tests/scripts/defines.sh index 49a6656fb7..03337899e2 100755 --- a/tests/scripts/defines.sh +++ b/tests/scripts/defines.sh @@ -5,6 +5,7 @@ SLAPD=../servers/slapd/slapd SLURPD=../servers/slurpd/slurpd LDAPSEARCH=../clients/tools/ldapsearch LDAPMODIFY=../clients/tools/ldapmodify +LDAPMODRDN=../clients/tools/ldapmodrdn LDAPADD=../clients/tools/ldapadd LVL=5 PORT=9009 @@ -32,6 +33,7 @@ LDIFFLT=$DBDIR/ldif.flt MASTEROUT=$DBDIR/master.out SLAVEOUT=$DBDIR/slave.out TESTOUT=$DBDIR/ldapsearch.out +TESTOUT_MODRDN=$DBDIR/ldapmodrdn.out SEARCHOUTMASTER=$DATADIR/search.out.master MODIFYOUTMASTER=$DATADIR/modify.out.master ADDDELOUTMASTER=$DATADIR/adddel.out.master diff --git a/tests/scripts/test005-modrdn b/tests/scripts/test005-modrdn index 510f898554..e6069758f6 100755 --- a/tests/scripts/test005-modrdn +++ b/tests/scripts/test005-modrdn @@ -1,12 +1,99 @@ -#!/bin/sh +#! /bin/sh -if [ $# -eq 0 ]; then +if test $# -eq 0 ; then SRCDIR="." else SRCDIR=$1; shift fi +if test $# -eq 1 ; then + BACKEND=$1; shift +fi -. $SRCDIR/scripts/defines.sh $SRCDIR +echo "running defines.sh $SRCDIR $BACKEND" +. $SRCDIR/scripts/defines.sh + +echo "Cleaning up in $DBDIR..." + +rm -f $DBDIR/[!C]* + +echo "Running ldif2ldbm to build slapd database..." +$LDIF2LDBM -f $CONF -i $LDIF -e ../servers/slapd/tools +RC=$? +if test $RC != 0 ; then + echo "ldif2ldbm failed!" + exit $RC +fi + +echo "Starting slapd on TCP/IP port $PORT..." +$SLAPD -f $CONF -p $PORT -d $LVL $TIMING > $MASTERLOG 2>&1 & +PID=$! +echo "Testing slapd modrdn operations..." + +# Make sure we can search the database +for i in 0 1 2 3 4 5; do + $LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \ + 'cn=Manager' > /dev/null 2>&1 + RC=$? + if test $RC = 1 ; then + echo "Waiting 5 seconds for slapd to start..." + sleep 5 + fi +done + +if test $RC != 0 ; then + echo "ldapsearch failed!" + kill -HUP $PID + exit $RC +fi + +cat /dev/null > $TESTOUT_MODRDN + +# -r used to do remove of old rdn + +echo "Testing modrdn(deleteoldrdn=0)..." +$LDAPMODRDN -v -D "$MANAGERDN" -h localhost -p $PORT -w $PASSWD > \ + /dev/null 2>&1 'cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of Michigan, c=US' 'cn=James A Jones III' + +RC=$? +if test $RC != 0 ; then + echo "ldapmodrdn failed!" + kill -HUP $PID + exit $RC +fi + +echo "Testing modrdn(deleteoldrdn=1)..." +$LDAPMODRDN -v -D "$MANAGERDN" -r -h localhost -p $PORT -w $PASSWD > \ + /dev/null 2>&1 'cn=James A Jones 2, ou=Information Technology Division, ou=People, o=University of Michigan, c=US' 'cn=James A Jones II' + +RC=$? +if test $RC != 0 ; then + echo "ldapmodrdn failed!" + kill -HUP $PID + exit $RC +fi + +echo "Using ldapsearch to retrieve all the entries..." +$LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \ + 'objectClass=*' | egrep -iv '^createtimestamp:|^modifytimestamp:' \ + > $SEARCHOUT 2>&1 +RC=$? +kill -HUP $PID +if test $RC != 0 ; then + echo "ldapsearch failed!" + exit $RC +fi + +echo "Comparing database to reference file" +cmp $SEARCHOUT $MODRDNOUTMASTER +if test $? != 0 ; then + echo "comparison failed - modrdn operations did not complete correctly" + exit 1 +fi + +echo ">>>>> Test succeeded" + + + +# echo "modrdn test not yet written" -echo "modrdn test not yet written" exit 0