From: Howard Chu Date: Fri, 19 Jan 2001 21:27:20 +0000 (+0000) Subject: Pierangelo Masarati's bugfixes and enhancements for suffix-massaging. X-Git-Tag: LDBM_PRE_GIANT_RWLOCK~1551 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=4703fe82b20b863b58c573f9dcd123e1fa50e1a2;p=openldap Pierangelo Masarati's bugfixes and enhancements for suffix-massaging. See the Changes file for detailed description. --- diff --git a/servers/slapd/back-ldap/Changes b/servers/slapd/back-ldap/Changes new file mode 100644 index 0000000000..ded43c3156 --- /dev/null +++ b/servers/slapd/back-ldap/Changes @@ -0,0 +1,121 @@ +Copyright 2000, Pierangelo Masarati, All rights reserved. + +The backend back-ldap has been modified as follows: + +* The LDAP handlers have been put under an avl tree, in an attempt + to improve the access to connections in heavy loaded environments + (many clients connecting simultaneously for long times, e.g. + authenticators that make successive searches and binds without + renewing the handler). + This required to change the lcs member of struct ldapinfo into + an (Avlnode *) member called conntree. + The member next in the ldapconn struct has been eliminated because + it is no longer needed. + +* The ldap_back_dobind function has been forced to return the value + of the bound flag instead of void; there is no longer need to test + for the flag outside the function as a test was already in. + Now the function can be called as + + if ( !ldap_back_dobind( lc, op ) ) { + /* handle error */ + } + +* The suffix of the operations can be "massaged", i.e. changed to + a different suffix to implement what has been termed a + "virtual naming context": an incoming request with a certain + base or related to a certain dn is turned into a request to a different + server with the base or the dn changed in its terminal part (the naming + context). The resulting entries, if any, have the real naming context + changed back into the virtual naming context. + + This required to add a suffixMassage configuration line of the form + + suffix "virtual naming context" + suffixMassage "virtual naming context" "real naming context" + + (the name of the configuration parameter will be changed to something + more appropriate as will result from a debate in the -devel mailing + list). + The "virtual naming context" must appear in a suffix configuration line + so the server can select the appropriate backend; then the suffixMassage + configuration line maps the "virtual" and the "real" naming contexts + back and forth. + This allows one to map multiple real naming contexts as branches + of a single naming context, provided these reside on the same server: + + suffix "ou=Branch 1, o=My Org, c=IT" + suffixMassage "ou=Branch 1, o=My Org, c=IT" "o=Org 1, c=IT" + suffix "ou=Branch 2, o=My Org, c=IT" + suffixMassage "ou=Branch 2, o=My Org, c=IT" "dc=host, dc=net" + suffix "o=My Org, c=IT" + suffixMassage "o=My Org, c=IT" "dc=host, dc=it" + + Note that the "same server" limitation can be overcome by using + multiple back-ldap databases, each pointing to the appropriate + server. + + Another choice, which would not allow multiple naming contexts + being served by the same database, is to use the "dn" part of the + "uri" configuration parameter, e.g.: + + suffix "virtual naming context" + uri "ldap://ldap.my.org:port/real naming context" + + This has not been implemented yet. + + A possible future enhancement will allow the ldap backend to handle + multiple servers within a single naming context. + + Two functions, ldap_back_dn_massage and ldap_back_dn_restore, have + been added. The former changes the bind dn or the search base, + in case its terminal portion matches the "virtual naming context" + of a suffixMassage entry, to the corresponding "real naming context" + suffixed value. + The latter turns the entry's dn back to the "virtual naming context" + suffixed form if the real dn terminal portion matches any "real naming + context" part of a suffixMassage configuration line. + The deferred bind required to add the bound_dn member to the ldapconn + struct. + As of the time of this writing, all the backend operations that + require writing (add, delete, modify, modrdn) have been added the + massaging capability; it can be safely turned off by turning on + the readonly mode at the backend level. The massaging is performed + only on the dn of the entry that is modified, and in the modrdn + operation it affects both the old and the newSuperior dn. + +* Cleanup/minor bug fixes/software enhancements: + + - the suffix member (unused) has been eliminated (commented out) + from the ldapinfo struct. + + - bind.c:ldap_back_op_result: a check of the value of "match" and + "msg" variables is added before freeing them (got a NULL "match" + when the server the backend points to was restarted). + + - search.c:ldap_send_entry: the member a_desc in the (Attribute *) + "attr" must be set to NULL before calling slap_str2ad, otherwise + an assertion fails (ITS #919). + + - search.c:ldap_send_entry: the entry's ent.e_dn and ent.e_ndn members + need be freed before returning because they were allocated inside + the routine. + + - modify.c:ldap_back_modify: the Modifications member sml_op needs be + ORed with LDAP_MOD_BVALUES to force the ldap_modify_s routine + handle the modifications as bervals: + + mods[i].mod_op = ml->sml_op | LDAP_MOD_BVALUES; + +* Notes: + - there a possible memory leak in the backend, because the memory + occupation of the slapd processes steadily grows when it is + repeatedly accessed. + + - when writing (add/modify) lastmod must be set to OFF otherwise + the lastmod attributes will be added to the entry mods and the + target server will complain about + + ldap_modify: Constraint violation + ldap_modify: additional info: no user modification allowed + diff --git a/servers/slapd/back-ldap/Copyright b/servers/slapd/back-ldap/Copyright index c70463833d..4b23929e7a 100644 --- a/servers/slapd/back-ldap/Copyright +++ b/servers/slapd/back-ldap/Copyright @@ -21,3 +21,13 @@ to the following restrictions: ever read sources, credits should appear in the documentation. 4. This notice may not be removed or altered. + + + +Copyright 2000, Pierangelo Masarati, All rights reserved. + +This software is being modified by Pierangelo Masarati. +The previously reported conditions apply to the modified code as well. +Changes in the original code are highlighted where required. +Credits for the original code go to the author, Howard Chu. + diff --git a/servers/slapd/back-ldap/Makefile.in b/servers/slapd/back-ldap/Makefile.in index 2f740a1e5d..38f42798c5 100644 --- a/servers/slapd/back-ldap/Makefile.in +++ b/servers/slapd/back-ldap/Makefile.in @@ -1,9 +1,11 @@ # $OpenLDAP$ SRCS = init.c config.c search.c bind.c unbind.c add.c compare.c \ - delete.c modify.c modrdn.c group.c attribute.c + delete.c modify.c modrdn.c group.c attribute.c \ + suffixmassage.c OBJS = init.lo config.lo search.lo bind.lo unbind.lo add.lo compare.lo \ - delete.lo modify.lo modrdn.lo group.lo attribute.lo + delete.lo modify.lo modrdn.lo group.lo attribute.lo \ + suffixmassage.lo LDAP_INCDIR= ../../../include LDAP_LIBDIR= ../../../libraries diff --git a/servers/slapd/back-ldap/TODO.proxy b/servers/slapd/back-ldap/TODO.proxy new file mode 100644 index 0000000000..41ada65624 --- /dev/null +++ b/servers/slapd/back-ldap/TODO.proxy @@ -0,0 +1,101 @@ +back-proxy + +A proxy that handles a pool of URI associated to a unique suffix. +Each request is spread over the different URIs and results are +masqueraded to appear as coming from a unique server. + +Suppose a company has two branches, whose existing DS have URIs + +"ldap://ldap.branch1.com/o=Branch 1, c=US" +"ldap://ldap.branch2.it/o=Branch 2, c=IT" + +and it wants to propose to the outer world as a unique URI + +"ldap://ldap.company.net/dc=company, dc=net" + +It could do some rewriting to map everything that comes in with a base dn +of "o=Branch 1, dc=company, dc=net" as the URI of the Branch 1, and +everything that comes in with a base dn of "o=Branch 2, dc=company, dc=net" +as the URI of Branch 2, and by rewriting all the dns back to the new, uniform +base. Everything that comes in with a base dn of "dc=company, dc=net" should +be handled locally and propagated to the two branch URIs if a subtree +(or at least onelevel) search is required. + +Operations: + +- bind +- unbind +- search +- compare +- add +- modify +- modrdn +- delete +- abandon + +The input of each operation may be related to: + + exact dn exact parent ancestor +------------------------------------------------------------- +bind x +unbind +search x x x +compare x +add x +modify x +modrdn x +delete x +abandon + +The backend must rely on a dn fetching mechanism. Each operation requires +to determine as early as possible which URI will be able to satisfy it. +Apart from searches, which by definition are usually allowed to return +multiple results, and apart from unbind and abandon, which do not return any +result, all the remaining operations require the related entry to be unique. + +A major problem isposed by the uniqueness of the dns. As far as the suffixes +are masqueraded by a common suffix, tyhe dns are no longer guaranteed to be +unique. This backend relies on the assumption that the uniqueness of the +dns is guaranteed. + +Two layers of depth in dn fetching are envisaged. +The first layer is provided by a backend-side cache made of previously +retrieved entries. The cache relates each rdn (i.e. the dn apart from the +common suffix) to the pool of URIs that are expected to contain a subset +of its children. + +The second layer is provided by a fetching function that spawns a search for +each URI in the pool determined by the cache if the correct URI has not been +directly determined. + +Note that, as the remote servers may have been updated by some direct +operation, this mechanism does not guarantee the uniqueness of the result. +So write operations will require to skip the cache search and to perform +the exaustive search of all the URIs unless some hint mechanism is provided +to the backend (e.g. a server is read-only). + +Again, the lag between the fetching of the required dn and the actual +read/write may result in a failure; however, this applies to any LDAP +operation AFAIK. + +- bind +if updates are to be strictly honored, a bind operation is performed against +each URI; otherwise, it is performed against the URIs resulting from a +cache-level dn fetch. + +- unbind +nothing to say; all the open handles related to the connection are reset. + +- search +if updates are to be strictly honored, a search operation is performed agaist +each URI. Note that this needs be performed also when the backend suffix +is used as base. In case the base is stricter, the URI pool may be restricted +by performing a cache dn fetch of the base first. + +- compare +the same applies to the compare dn. + +- add +this operation is delicate. Unless the dn up to the top-level part excluded +can be uniquely associated to a URI, and unless its uniqueness can be trusted, +no add operation should be allowed. diff --git a/servers/slapd/back-ldap/add.c b/servers/slapd/back-ldap/add.c index 656a6e6cbf..f282ee0f90 100644 --- a/servers/slapd/back-ldap/add.c +++ b/servers/slapd/back-ldap/add.c @@ -24,6 +24,15 @@ * ever read sources, credits should appear in the documentation. * * 4. This notice may not be removed or altered. + * + * + * + * Copyright 2000, Pierangelo Masarati, All rights reserved. + * + * This software is being modified by Pierangelo Masarati. + * The previously reported conditions apply to the modified code as well. + * Changes in the original code are highlighted where required. + * Credits for the original code go to the author, Howard Chu. */ #include "portable.h" @@ -50,18 +59,20 @@ ldap_back_add( Attribute *a; LDAPMod **attrs; + char *mdn; + lc = ldap_back_getconn(li, conn, op); - if (!lc) + if ( !lc || !ldap_back_dobind( lc, op ) ) { return( -1 ); + } - if (!lc->bound) { - ldap_back_dobind(lc, op); - if (!lc->bound) - return( -1 ); + mdn = ldap_back_dn_massage( li, ch_strdup( e->e_dn ), 0 ); + if ( mdn == NULL ) { + return( -1 ); } /* Count number of attributes in entry */ - for (i=1, a=e->e_attrs; a; i++, a=a->a_next) + for (i = 1, a = e->e_attrs; a; i++, a = a->a_next) ; /* Create array of LDAPMods for ldap_add() */ @@ -75,9 +86,10 @@ ldap_back_add( attrs[i]->mod_vals.modv_bvals = a->a_vals; } - ldap_add_s(lc->ld, e->e_dn, attrs); + ldap_add_s(lc->ld, mdn, attrs); for (--i; i>= 0; --i) free(attrs[i]); free(attrs); + free( mdn ); return( ldap_back_op_result( lc, op )); } diff --git a/servers/slapd/back-ldap/back-ldap.h b/servers/slapd/back-ldap/back-ldap.h index 0fd098642e..fdbe1a2d9c 100644 --- a/servers/slapd/back-ldap/back-ldap.h +++ b/servers/slapd/back-ldap/back-ldap.h @@ -24,6 +24,15 @@ * ever read sources, credits should appear in the documentation. * * 4. This notice may not be removed or altered. + * + * + * + * Copyright 2000, Pierangelo Masarati, All rights reserved. + * + * This software is being modified by Pierangelo Masarati. + * The previously reported conditions apply to the modified code as well. + * Changes in the original code are highlighted where required. + * Credits for the original code go to the author, Howard Chu. */ #ifndef SLAPD_LDAP_H @@ -37,28 +46,37 @@ struct slap_conn; struct slap_op; struct ldapconn { - struct ldapconn *next; struct slap_conn *conn; LDAP *ld; + char *bound_dn; int bound; }; struct ldapinfo { char *url; +#if 0 /* unused! */ char *suffix; +#endif /* 0 */ + char **suffix_massage; char *binddn; char *bindpw; ldap_pvt_thread_mutex_t conn_mutex; - struct ldapconn *lcs; + Avlnode *conntree; }; struct ldapconn *ldap_back_getconn(struct ldapinfo *li, struct slap_conn *conn, struct slap_op *op); -void ldap_back_dobind(struct ldapconn *lc, Operation *op); +int ldap_back_dobind(struct ldapconn *lc, Operation *op); int ldap_back_map_result(int err); int ldap_back_op_result(struct ldapconn *lc, Operation *op); int back_ldap_LTX_init_module(int argc, char *argv[]); +char *ldap_back_dn_massage(struct ldapinfo *li, char *dn, int normalized); +char *ldap_back_dn_restore(struct ldapinfo *li, char *dn, int normalized); + +int conn_cmp(const void *, const void *); +int conn_dup(void *, void *); + LDAP_END_DECL #endif diff --git a/servers/slapd/back-ldap/bind.c b/servers/slapd/back-ldap/bind.c index 67ce0fc16a..6fa83775b1 100644 --- a/servers/slapd/back-ldap/bind.c +++ b/servers/slapd/back-ldap/bind.c @@ -24,6 +24,15 @@ * ever read sources, credits should appear in the documentation. * * 4. This notice may not be removed or altered. + * + * + * + * Copyright 2000, Pierangelo Masarati, All rights reserved. + * + * This software is being modified by Pierangelo Masarati. + * The previously reported conditions apply to the modified code as well. + * Changes in the original code are highlighted where required. + * Credits for the original code go to the author, Howard Chu. */ #include "portable.h" @@ -33,6 +42,8 @@ #include #include + +#define AVL_INTERNAL #include "slap.h" #include "back-ldap.h" @@ -51,35 +62,116 @@ ldap_back_bind( struct ldapinfo *li = (struct ldapinfo *) be->be_private; struct ldapconn *lc; + char *mdn = NULL; + int rc = 0; + *edn = NULL; lc = ldap_back_getconn(li, conn, op); - if (!lc) + if ( !lc ) { return( -1 ); + } + + mdn = ldap_back_dn_massage( li, ch_strdup( dn ), 0 ); + if ( mdn == NULL ) { + return -1; + } + + if (ldap_bind_s(lc->ld, mdn, cred->bv_val, method) != LDAP_SUCCESS) { + rc = ldap_back_op_result( lc, op ); + } else { + lc->bound = 1; + } + + free( mdn ); + + return( rc ); +} + +/* + * conn_cmp + * + * compares two struct ldapconn based on the value of the conn pointer; + * used by avl stuff + */ +int +conn_cmp( + const void *c1, + const void *c2 + ) +{ + struct ldapconn *lc1 = (struct ldapconn *)c1; + struct ldapconn *lc2 = (struct ldapconn *)c2; + + return ( ( lc1->conn < lc2->conn ) ? -1 : ( ( lc1->conn > lc2-> conn ) ? 1 : 0 ) ); +} + +/* + * conn_dup + * + * returns -1 in case a duplicate struct ldapconn has been inserted; + * used by avl stuff + */ +int +conn_dup( + void *c1, + void *c2 + ) +{ + struct ldapconn *lc1 = (struct ldapconn *)c1; + struct ldapconn *lc2 = (struct ldapconn *)c2; + + return( ( lc1->conn == lc2->conn ) ? -1 : 0 ); +} - if (ldap_bind_s(lc->ld, dn, cred->bv_val, method) != LDAP_SUCCESS) - return( ldap_back_op_result(lc, op) ); +static void ravl_print( Avlnode *root, int depth ) +{ + int i; + + if ( root == 0 ) + return; + + ravl_print( root->avl_right, depth+1 ); + + for ( i = 0; i < depth; i++ ) + printf( " " ); - lc->bound = 1; - return( 0 ); + printf( "c(%d) %d\n", ((struct ldapconn *) root->avl_data)->conn->c_connid, root->avl_bf ); + + ravl_print( root->avl_left, depth+1 ); +} + +static void myprint( Avlnode *root ) +{ + printf( "********\n" ); + + if ( root == 0 ) + printf( "\tNULL\n" ); + + else + ravl_print( root, 0 ); + + printf( "********\n" ); } struct ldapconn * ldap_back_getconn(struct ldapinfo *li, Connection *conn, Operation *op) { - struct ldapconn *lc; + struct ldapconn *lc, lc_curr; LDAP *ld; + /* Searches for a ldapconn in the avl tree */ + lc_curr.conn = conn; ldap_pvt_thread_mutex_lock( &li->conn_mutex ); - for (lc = li->lcs; lc; lc=lc->next) - if (lc->conn == conn) - break; + lc = (struct ldapconn *)avl_find( li->conntree, + (caddr_t)&lc_curr, conn_cmp ); ldap_pvt_thread_mutex_unlock( &li->conn_mutex ); /* Looks like we didn't get a bind. Open a new session... */ if (!lc) { int vers = conn->c_protocol; int err = ldap_initialize(&ld, li->url); + if (err != LDAP_SUCCESS) { err = ldap_back_map_result(err); send_ldap_result( conn, op, err, @@ -94,26 +186,65 @@ ldap_back_getconn(struct ldapinfo *li, Connection *conn, Operation *op) lc = (struct ldapconn *)ch_malloc(sizeof(struct ldapconn)); lc->conn = conn; lc->ld = ld; + if ( lc->conn->c_cdn != NULL && lc->conn->c_cdn[0] != '\0' ) { + lc->bound_dn = ldap_back_dn_massage( li, + ch_strdup( lc->conn->c_cdn ), 0 ); + } else { + lc->bound_dn = NULL; + } lc->bound = 0; + + /* Inserts the newly created ldapconn in the avl tree */ ldap_pvt_thread_mutex_lock( &li->conn_mutex ); - lc->next = li->lcs; - li->lcs = lc; + err = avl_insert( &li->conntree, (caddr_t)lc, + conn_cmp, conn_dup ); + +#if 1 + myprint( li->conntree ); +#endif + ldap_pvt_thread_mutex_unlock( &li->conn_mutex ); + + Debug( LDAP_DEBUG_TRACE, + "=>ldap_back_getconn: conn %d inserted\n", + lc->conn->c_connid, 0, 0 ); + + /* Err could be -1 in case a duplicate ldapconn is inserted */ + if ( err != 0 ) { + send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, + NULL, "internal server error", NULL, NULL ); + /* better destroy the ldapconn struct? */ + return( NULL ); + } + } else { + Debug( LDAP_DEBUG_TRACE, + "=>ldap_back_getconn: conn %d fetched\n", + lc->conn->c_connid, 0, 0 ); } + return( lc ); } -void +/* + * ldap_back_dobind + * + * Note: as the check for the value of lc->bound was already here, I removed + * it from all the callers, and I made the function return the flag, so + * it can be used to simplify the check. + */ +int ldap_back_dobind(struct ldapconn *lc, Operation *op) { - if (lc->bound) - return; + if (lc->bound) { + return( lc->bound ); + } - if (ldap_bind_s(lc->ld, lc->conn->c_cdn, NULL, LDAP_AUTH_SIMPLE) != - LDAP_SUCCESS) + if (ldap_bind_s(lc->ld, lc->bound_dn, NULL, LDAP_AUTH_SIMPLE) != + LDAP_SUCCESS) { ldap_back_op_result(lc, op); - else - lc->bound = 1; + return( 0 ); + } /* else */ + return( lc->bound = 1 ); } /* Map API errors to protocol errors... */ @@ -166,16 +297,17 @@ ldap_back_map_result(int err) int ldap_back_op_result(struct ldapconn *lc, Operation *op) { - int err; - char *msg; - char *match; + int err = LDAP_SUCCESS; + char *msg = NULL; + char *match = NULL; ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &err); ldap_get_option(lc->ld, LDAP_OPT_ERROR_STRING, &msg); ldap_get_option(lc->ld, LDAP_OPT_MATCHED_DN, &match); err = ldap_back_map_result(err); send_ldap_result( lc->conn, op, err, match, msg, NULL, NULL ); - free(match); - free(msg); + /* better test the pointers before freeing? */ + if ( match ) free( match ); + if ( msg ) free( msg ); return( (err==LDAP_SUCCESS) ? 0 : -1 ); } diff --git a/servers/slapd/back-ldap/compare.c b/servers/slapd/back-ldap/compare.c index e342f6ee43..e5db2342a7 100644 --- a/servers/slapd/back-ldap/compare.c +++ b/servers/slapd/back-ldap/compare.c @@ -24,6 +24,15 @@ * ever read sources, credits should appear in the documentation. * * 4. This notice may not be removed or altered. + * + * + * + * Copyright 2000, Pierangelo Masarati, All rights reserved. + * + * This software is being modified by Pierangelo Masarati. + * The previously reported conditions apply to the modified code as well. + * Changes in the original code are highlighted where required. + * Credits for the original code go to the author, Howard Chu. */ #include "portable.h" @@ -48,17 +57,21 @@ ldap_back_compare( { struct ldapinfo *li = (struct ldapinfo *) be->be_private; struct ldapconn *lc; + char *mdn; lc = ldap_back_getconn(li, conn, op); - if (!lc) + if (!lc || !ldap_back_dobind( lc, op ) ) { return( -1 ); - - if (!lc->bound) { - ldap_back_dobind(lc, op); - if (!lc->bound) - return( -1 ); } - ldap_compare_s( lc->ld, dn, ava->aa_desc->ad_cname->bv_val, ava->aa_value->bv_val ); + mdn = ldap_back_dn_massage( li, ch_strdup( dn ), 0 ); + if ( mdn == NULL ) { + return -1; + } + + ldap_compare_s( lc->ld, mdn, ava->aa_desc->ad_cname->bv_val, ava->aa_value->bv_val ); + + free( mdn ); + return( ldap_back_op_result( lc, op ) ); } diff --git a/servers/slapd/back-ldap/config.c b/servers/slapd/back-ldap/config.c index 4b0078f96c..5113ed617d 100644 --- a/servers/slapd/back-ldap/config.c +++ b/servers/slapd/back-ldap/config.c @@ -24,6 +24,15 @@ * ever read sources, credits should appear in the documentation. * * 4. This notice may not be removed or altered. + * + * + * + * Copyright 2000, Pierangelo Masarati, All rights reserved. + * + * This software is being modified by Pierangelo Masarati. + * The previously reported conditions apply to the modified code as well. + * Changes in the original code are highlighted where required. + * Credits for the original code go to the author, Howard Chu. */ #include "portable.h" @@ -101,6 +110,49 @@ ldap_back_db_config( return( 1 ); } li->bindpw = ch_strdup(argv[1]); + + /* dn massaging */ + } else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) { + char *dn, *massaged_dn; + BackendDB *tmp_be; + + if ( argc != 3 ) { + fprintf( stderr, + "%s: line %d: syntax is \"suffixMassage \"\n", + fname, lineno ); + return( 1 ); + } + + tmp_be = select_backend( argv[1], 0 ); + if ( tmp_be != NULL && tmp_be != be ) { + fprintf( stderr, + "%s: line %d: suffix already in use by another backend in" + " \"suffixMassage \"\n", + fname, lineno ); + return( 1 ); + } + + tmp_be = select_backend( argv[2], 0 ); + if ( tmp_be != NULL ) { + fprintf( stderr, + "%s: line %d: massaged suffix already in use by another backend in" + " \"suffixMassage \"\n", + fname, lineno ); + return( 1 ); + } + + dn = ch_strdup( argv[1] ); + charray_add( &li->suffix_massage, dn ); + (void) dn_normalize( dn ); + charray_add( &li->suffix_massage, dn ); + + massaged_dn = ch_strdup( argv[2] ); + charray_add( &li->suffix_massage, massaged_dn ); + (void) dn_normalize( massaged_dn ); + charray_add( &li->suffix_massage, massaged_dn ); + + free( dn ); + free( massaged_dn ); /* anything else */ } else { diff --git a/servers/slapd/back-ldap/delete.c b/servers/slapd/back-ldap/delete.c index 2035493684..4b92412be1 100644 --- a/servers/slapd/back-ldap/delete.c +++ b/servers/slapd/back-ldap/delete.c @@ -24,6 +24,15 @@ * ever read sources, credits should appear in the documentation. * * 4. This notice may not be removed or altered. + * + * + * + * Copyright 2000, Pierangelo Masarati, All rights reserved. + * + * This software is being modified by Pierangelo Masarati. + * The previously reported conditions apply to the modified code as well. + * Changes in the original code are highlighted where required. + * Credits for the original code go to the author, Howard Chu. */ #include "portable.h" @@ -48,16 +57,22 @@ ldap_back_delete( struct ldapinfo *li = (struct ldapinfo *) be->be_private; struct ldapconn *lc; + char *mdn; + lc = ldap_back_getconn( li, conn, op ); - if (!lc) + + if ( !lc || !ldap_back_dobind( lc, op ) ) { return( -1 ); + } - if (!lc->bound) { - ldap_back_dobind(lc, op); - if (!lc->bound) - return( -1 ); + mdn = ldap_back_dn_massage( li, ch_strdup( dn ), 0 ); + if ( mdn == NULL ) { + return( -1 ); } + + ldap_delete_s( lc->ld, mdn ); - ldap_delete_s( lc->ld, dn ); + free( mdn ); + return( ldap_back_op_result( lc, op ) ); } diff --git a/servers/slapd/back-ldap/init.c b/servers/slapd/back-ldap/init.c index 7e4fabca09..9d49b424a0 100644 --- a/servers/slapd/back-ldap/init.c +++ b/servers/slapd/back-ldap/init.c @@ -24,6 +24,15 @@ * ever read sources, credits should appear in the documentation. * * 4. This notice may not be removed or altered. + * + * + * + * Copyright 2000, Pierangelo Masarati, All rights reserved. + * + * This software is being modified by Pierangelo Masarati. + * The previously reported conditions apply to the modified code as well. + * Changes in the original code are highlighted where required. + * Credits for the original code go to the author, Howard Chu. */ #include "portable.h" @@ -103,6 +112,16 @@ ldap_back_db_init( return li == NULL; } +static void +conn_free( + struct ldapconn *lc +) +{ + ldap_unbind(lc->ld); + if ( lc->bound_dn) free( lc->bound_dn ); + free( lc ); +} + int ldap_back_db_destroy( Backend *be @@ -112,6 +131,9 @@ ldap_back_db_destroy( if (be->be_private) { li = (struct ldapinfo *)be->be_private; + + ldap_pvt_thread_mutex_lock( &li->conn_mutex ); + if (li->url) { free(li->url); li->url = NULL; @@ -124,6 +146,15 @@ ldap_back_db_destroy( free(li->bindpw); li->bindpw = NULL; } + if (li->suffix_massage) { + ldap_value_free( li->suffix_massage ); + li->suffix_massage = NULL; + } + if (li->conntree) { + avl_free( li->conntree, (AVL_FREE) conn_free ); + } + + ldap_pvt_thread_mutex_unlock( &li->conn_mutex ); ldap_pvt_thread_mutex_destroy( &li->conn_mutex ); } diff --git a/servers/slapd/back-ldap/modify.c b/servers/slapd/back-ldap/modify.c index ff9ac9f6d8..9b11c27b57 100644 --- a/servers/slapd/back-ldap/modify.c +++ b/servers/slapd/back-ldap/modify.c @@ -24,6 +24,15 @@ * ever read sources, credits should appear in the documentation. * * 4. This notice may not be removed or altered. + * + * + * + * Copyright 2000, Pierangelo Masarati, All rights reserved. + * + * This software is being modified by Pierangelo Masarati. + * The previously reported conditions apply to the modified code as well. + * Changes in the original code are highlighted where required. + * Credits for the original code go to the author, Howard Chu. */ #include "portable.h" @@ -53,14 +62,16 @@ ldap_back_modify( Modifications *ml; int i; + char *mdn; + lc = ldap_back_getconn(li, conn, op); - if (!lc) + if ( !lc || !ldap_back_dobind( lc, op ) ) { return( -1 ); + } - if (!lc->bound) { - ldap_back_dobind(lc, op); - if (!lc->bound) - return( -1 ); + mdn = ldap_back_dn_massage( li, ch_strdup( dn ), 0 ); + if ( mdn == NULL ) { + return( -1 ); } for (i=0, ml=modlist; ml; i++,ml=ml->sml_next) @@ -79,13 +90,16 @@ ldap_back_modify( for (i=0, ml=modlist; ml; i++, ml=ml->sml_next) { modv[i] = &mods[i]; - mods[i].mod_op = ml->sml_op; + mods[i].mod_op = ml->sml_op | LDAP_MOD_BVALUES; mods[i].mod_type = ml->sml_desc->ad_cname->bv_val; mods[i].mod_bvalues = ml->sml_bvalues; } - ldap_modify_s( lc->ld, dn, modv ); - free(mods); - free(modv); + + + ldap_modify_s( lc->ld, mdn, modv ); + free( mdn ); + free(mods); + free(modv); return( ldap_back_op_result( lc, op )); } diff --git a/servers/slapd/back-ldap/modrdn.c b/servers/slapd/back-ldap/modrdn.c index fd54b36aa2..66761c0a73 100644 --- a/servers/slapd/back-ldap/modrdn.c +++ b/servers/slapd/back-ldap/modrdn.c @@ -24,6 +24,15 @@ * ever read sources, credits should appear in the documentation. * * 4. This notice may not be removed or altered. + * + * + * + * Copyright 2000, Pierangelo Masarati, All rights reserved. + * + * This software is being modified by Pierangelo Masarati. + * The previously reported conditions apply to the modified code as well. + * Changes in the original code are highlighted where required. + * Credits for the original code go to the author, Howard Chu. */ #include "portable.h" @@ -51,21 +60,37 @@ ldap_back_modrdn( struct ldapinfo *li = (struct ldapinfo *) be->be_private; struct ldapconn *lc; + char *mdn, *mnewSuperior; + lc = ldap_back_getconn( li, conn, op ); - if (!lc) + if ( !lc ) { return( -1 ); + } if (newSuperior) { int version = LDAP_VERSION3; ldap_set_option( lc->ld, LDAP_OPT_PROTOCOL_VERSION, &version); + + mnewSuperior = ldap_back_dn_massage( li, + ch_strdup( newSuperior ), 0 ); + if ( mnewSuperior == NULL ) { + return( -1 ); + } } - if (!lc->bound) { - ldap_back_dobind(lc, op); - if (!lc->bound) - return( -1 ); + if ( !ldap_back_dobind(lc, op) ) { + return( -1 ); } - ldap_rename2_s( lc->ld, dn, newrdn, newSuperior, deleteoldrdn ); + mdn = ldap_back_dn_massage( li, ch_strdup( dn ), 0 ); + if ( mdn == NULL ) { + return( -1 ); + } + + ldap_rename2_s( lc->ld, mdn, newrdn, mnewSuperior, deleteoldrdn ); + + free( mdn ); + if ( mnewSuperior ) free( mnewSuperior ); + return( ldap_back_op_result( lc, op ) ); } diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c index d188c249c9..240a85736b 100644 --- a/servers/slapd/back-ldap/search.c +++ b/servers/slapd/back-ldap/search.c @@ -24,6 +24,15 @@ * ever read sources, credits should appear in the documentation. * * 4. This notice may not be removed or altered. + * + * + * + * Copyright 2000, Pierangelo Masarati, All rights reserved. + * + * This software is being modified by Pierangelo Masarati. + * The previously reported conditions apply to the modified code as well. + * Changes in the original code are highlighted where required. + * Credits for the original code go to the author, Howard Chu. */ #include "portable.h" @@ -64,9 +73,12 @@ ldap_back_search( int i, rc, msgid, sres = LDAP_SUCCESS; char *match = NULL, *err = NULL; + char *mbase; + lc = ldap_back_getconn(li, conn, op); - if (!lc) + if ( !lc ) { return( -1 ); + } if (deref != -1) ldap_set_option( lc->ld, LDAP_OPT_DEREF, (void *)&deref); @@ -74,13 +86,17 @@ ldap_back_search( ldap_set_option( lc->ld, LDAP_OPT_TIMELIMIT, (void *)&time); if (size != -1) ldap_set_option( lc->ld, LDAP_OPT_SIZELIMIT, (void *)&size); - if (!lc->bound) { - ldap_back_dobind(lc, op); - if (!lc->bound) - return( -1 ); + + if ( !ldap_back_dobind( lc, op ) ) { + return( -1 ); + } + + mbase = ldap_back_dn_massage( li, ch_strdup( base ), 0 ); + if ( mbase == NULL ) { + return -1; } - if ((msgid = ldap_search(lc->ld, base, scope, filterstr, attrs, + if ((msgid = ldap_search(lc->ld, mbase, scope, filterstr, attrs, attrsonly)) == -1) fail: return( ldap_back_op_result(lc, op) ); @@ -132,6 +148,8 @@ fail: return( ldap_back_op_result(lc, op) ); free(match); if (err) free(err); + if (mbase) + free(mbase); return( 0 ); } @@ -145,6 +163,7 @@ ldap_send_entry( int attrsonly ) { + struct ldapinfo *li = (struct ldapinfo *) be->be_private; char *a; Entry ent; BerElement *ber = NULL; @@ -152,8 +171,8 @@ ldap_send_entry( struct berval *dummy = NULL; const char *text; - ent.e_dn = ldap_get_dn(lc->ld, e); - ent.e_ndn = ch_strdup( ent.e_dn); + ent.e_dn = ldap_back_dn_restore( li, ldap_get_dn(lc->ld, e), 0 ); + ent.e_ndn = ch_strdup( ent.e_dn ); (void) dn_normalize( ent.e_ndn ); ent.e_id = 0; ent.e_attrs = 0; @@ -187,4 +206,9 @@ ldap_send_entry( } if (ber) ber_free(ber,0); + + if ( ent.e_dn ) + free( ent.e_dn ); + if ( ent.e_ndn ) + free( ent.e_ndn ); } diff --git a/servers/slapd/back-ldap/suffixmassage.c b/servers/slapd/back-ldap/suffixmassage.c new file mode 100644 index 0000000000..aa49ef21c4 --- /dev/null +++ b/servers/slapd/back-ldap/suffixmassage.c @@ -0,0 +1,157 @@ +/* suffixmassage.c - massages ldap backend dns */ +/* $OpenLDAP$ */ + +/* + * Copyright 1999, Howard Chu, All rights reserved. + * Copyright 2000, Pierangelo Masarati, All rights reserved. + * + * Module back-ldap, originally developed by Howard Chu + * + * has been modified by Pierangelo Masarati. The original copyright + * notice has been maintained. + * + * Permission is granted to anyone to use this software for any purpose + * on any computer system, and to alter it and redistribute it, subject + * to the following restrictions: + * + * 1. The author is not responsible for the consequences of use of this + * software, no matter how awful, even if they arise from flaws in it. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Since few users ever read sources, + * credits should appear in the documentation. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. Since few users + * ever read sources, credits should appear in the documentation. + * + * 4. This notice may not be removed or altered. + */ + +#include "portable.h" + +#include + +#include + +#include "slap.h" +#include "back-ldap.h" + +/* + * ldap_back_dn_massage + * + * Aliases the suffix; based on suffix_alias (servers/slapd/suffixalias.c). + */ +char * +ldap_back_dn_massage( + struct ldapinfo *li, + char *dn, + int normalized +) +{ + int i, dnLength; + + if ( dn == NULL ) { + return NULL; + } + if ( li == NULL ) { + return dn; + } + + dnLength = strlen ( dn ); + + for ( i = 0; + li->suffix_massage != NULL && li->suffix_massage[i] != NULL; + i += 4 ) { + int aliasLength = strlen( li->suffix_massage[i+normalized] ); + int diff = dnLength - aliasLength; + + if ( diff < 0 ) { + /* alias is longer than dn */ + continue; + } else if ( diff > 0 ) { + if ( normalized && ( ! DN_SEPARATOR(dn[diff-1]) ) ) { + /* boundary is not at a DN separator */ + continue; + } + /* At a DN Separator */ + /* XXX or an escaped separator... oh well */ + } + + if ( !strcmp( li->suffix_massage[i+normalized], &dn[diff] ) ) { + char *oldDN = dn; + dn = ch_malloc( diff + strlen( li->suffix_massage[i+2+normalized] ) + 1 ); + strncpy( dn, oldDN, diff ); + strcpy( &dn[diff], li->suffix_massage[i+2+normalized] ); + Debug( LDAP_DEBUG_ARGS, + "ldap_back_dn_massage:" + " converted \"%s\" to \"%s\"\n", + oldDN, dn, 0 ); + free( oldDN ); + break; + } + } + + return dn; +} + +/* + * ldap_back_dn_restore + * + * Restores the original suffix; + * based on suffix_alias (servers/slapd/suffixalias.c). + */ +char * +ldap_back_dn_restore( + struct ldapinfo *li, + char *dn, + int normalized + ) +{ + int i, dnLength; + + if ( dn == NULL ) { + return NULL; + } + if ( li == NULL ) { + return dn; + } + + dnLength = strlen ( dn ); + + for ( i = 0; + li->suffix_massage != NULL && li->suffix_massage[i] != NULL; + i += 4 ) { + int aliasLength = strlen( li->suffix_massage[i+2+normalized] ); + int diff = dnLength - aliasLength; + + if ( diff < 0 ) { + /* alias is longer than dn */ + continue; + + } else if ( diff > 0 ) { + if ( normalized && ( ! DN_SEPARATOR(dn[diff-1]) ) ) { + /* boundary is not at a DN separator */ + continue; + } + /* At a DN Separator */ + /* XXX or an escaped separator... oh well */ + } + + if ( !strcmp( li->suffix_massage[i+2+normalized], &dn[diff] ) ) { + char *oldDN = dn; + dn = ch_malloc( diff + strlen( li->suffix_massage[i+normalized] ) + 1 ); + strncpy( dn, oldDN, diff ); + strcpy( &dn[diff], li->suffix_massage[i+normalized] ); + Debug( LDAP_DEBUG_ARGS, + "ldap_back_dn_restore:" + " converted \"%s\" to \"%s\"\n", + oldDN, dn, 0 ); + free( oldDN ); + break; + } + } + + return dn; +} + diff --git a/servers/slapd/back-ldap/unbind.c b/servers/slapd/back-ldap/unbind.c index 83d5609a42..574ef6ba60 100644 --- a/servers/slapd/back-ldap/unbind.c +++ b/servers/slapd/back-ldap/unbind.c @@ -24,6 +24,15 @@ * ever read sources, credits should appear in the documentation. * * 4. This notice may not be removed or altered. + * + * + * + * Copyright 2000, Pierangelo Masarati, All rights reserved. + * + * This software is being modified by Pierangelo Masarati. + * The previously reported conditions apply to the modified code as well. + * Changes in the original code are highlighted where required. + * Credits for the original code go to the author, Howard Chu. */ #include "portable.h" @@ -43,20 +52,34 @@ ldap_back_conn_destroy( ) { struct ldapinfo *li = (struct ldapinfo *) be->be_private; - struct ldapconn *lc, *lp; + struct ldapconn *lc, lc_curr; + Debug( LDAP_DEBUG_TRACE, + "=>ldap_back_conn_destroy: fetching conn %d\n", + conn->c_connid, 0, 0 ); + + + lc_curr.conn = conn; + ldap_pvt_thread_mutex_lock( &li->conn_mutex ); - for (lc = li->lcs, lp = (struct ldapconn *)&li->lcs; lc; - lp=lc, lc=lc->next) - if (lc->conn == conn) { - lp->next = lc->next; - break; - } + lc = avl_delete( &li->conntree, (caddr_t)&lc_curr, conn_cmp ); ldap_pvt_thread_mutex_unlock( &li->conn_mutex ); if (lc) { + Debug( LDAP_DEBUG_TRACE, + "=>ldap_back_conn_destroy: destroying conn %d\n", + lc->conn->c_connid, 0, 0 ); + + /* + * Needs a test because the handler may be corrupted, + * and calling ldap_unbind on a corrupted header results + * in a segmentation fault + */ ldap_unbind(lc->ld); - free(lc); + if ( lc->bound_dn ) { + free( lc->bound_dn ); + } + free( lc ); } /* no response to unbind */