/* expandUrl.c : overlay to expand uri attributes */ /* Copyright 2005 INRIA Sophia Antipolis */ /* All rights reserved. */ /* Authors : Sebastien Georget . */ /* ACKNOWLEDGEMENTS: * This work is based on the 'collect.c - Demonstration of overlay code' * part of OpenLDAP Software . * * This work was initially developed by the Howard Chu for inclusion * in OpenLDAP Software. */ /* SYNTAX * In slapd.conf : * moduleload expandUrl * overlay expandUrl * expandUrl dn attr1 attr2 * * The 3 parameters are : * - dn : the overlay will only operate on this dn * - attr1 : the overlay will look for URIs in this attribute * only the dn part of the uri is used * - attr2 : if target URIs contain this attribute the * values are merged in dn */ /* EXAMPLE * *** * # test.ldif * dn: cn=test,ou=Group,dc=test * memberURL: ldap:///cn=test,ou=Group,o=org1,dc=test * memberURL: ldap:///cn=test,ou=Group,o=org2,dc=test * * dn: cn=test,ou=Group,o=org1,dc=test * memberUid: bob * * dn: cn=test,ou=Group,o=org2,dc=test * memberUid: alice * *** * * ldapsearch -x -b "ou=Group,dc=test" will return * dn: cn=test,ou=Group,dc=test * memberURL: ldap:///cn=test,ou=Group,o=org1,dc=test * memberURL: ldap:///cn=test,ou=Group,o=org2,dc=test * memberUid: bob * memberUid: alice */ /* CHANGELOG v 0.2 : if no entry is found, check if filters contain the expanded attribute and redo the search on expanded entry if necessary v 0.1 : correctly expand attributes if the entry is found */ #include "portable.h" // #ifdef SLAPD_OVER_EXPANDURL #include #include #include #include "slap.h" typedef struct expandUrl_info { struct expandUrl_info *eui_next; struct berval eui_dn; AttributeDescription *eui_aduri; AttributeDescription *eui_adattr; int expanded; } expandUrl_info; int expand_entry (Operation * op, expandUrl_info * eui, Entry * e) { BerVarray vals = NULL; int rc, n; int cache = op->o_do_not_cache; op->o_do_not_cache = 1; Debug(LDAP_DEBUG_CONFIG, "expandUrl: expanding %s\n", \ e->e_name.bv_val, 0, 0); rc = backend_attribute( op, NULL, &eui->eui_dn, eui->eui_aduri, &vals, ACL_READ ); if (vals) { for (n = 0; !BER_BVISNULL( &(vals)[n] ); n++ ) { BerVarray target_vals = NULL; int target_rc; struct berval target_bv, target_dn; LDAPURLDesc *ludp; if ( ldap_url_parse( vals[n].bv_val, &ludp ) != LDAP_URL_SUCCESS ) { Debug(LDAP_DEBUG_CONFIG, "expandUrl: invalid uri (%s)\n", vals[n].bv_val, 0, 0); continue; } ber_str2bv( ludp->lud_dn, 0, 0, &target_bv ); if ( dnNormalize( 0, NULL, NULL, &target_bv, &target_dn, NULL ) ) { Debug(LDAP_DEBUG_CONFIG, "expandUrl: couldn't normalize uri \n", 0, 0, 0); continue; } Debug(LDAP_DEBUG_CONFIG, "expandUrl: search %s in %s\n", \ eui->eui_adattr->ad_cname.bv_val, target_dn.bv_val, 0); target_rc = backend_attribute( op, NULL, &target_dn, eui->eui_adattr, &target_vals, ACL_READ ); if (target_rc != LDAP_SUCCESS) continue; /* If there are any values, merge them into the * current entry */ if ( target_vals ) { attr_merge( e, eui->eui_adattr, target_vals, NULL ); ber_bvarray_free_x( vals, op->o_tmpmemctx ); } } } op->o_do_not_cache = cache; } static int expandUrl_response( Operation *op, SlapReply *rs ) { slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; expandUrl_info *eui = on->on_bi.bi_private; /* If we've been configured and the current response is * a search entry */ if ( eui && rs->sr_type == REP_SEARCH ) { Entry *new = NULL; op->o_bd->bd_info = (BackendInfo *)on->on_info; for (; eui; eui=eui->eui_next ) { /* have we been called already ? */ if (eui->expanded) { eui->expanded = 0; return SLAP_CB_CONTINUE; } /* If this entry match the configured one */ if ( strcmp(rs->sr_entry->e_nname.bv_val, eui->eui_dn.bv_val) ) continue; /* Extract the values of the uri attribute from * the configured entry */ new = entry_dup( rs->sr_entry ); expand_entry (op, eui, new); } if ( new ) { rs->sr_entry = new; rs->sr_flags |= REP_ENTRY_MUSTBEFREED; } } /* is this the result of a search ? */ /* and does it contains our attribute ? */ if ( eui && op->o_tag == LDAP_REQ_SEARCH && \ rs->sr_type == REP_RESULT && \ strstr(op->ors_filterstr.bv_val, eui->eui_adattr->ad_cname.bv_val) != NULL) { /* have we been called already ? */ if (eui->expanded) return SLAP_CB_CONTINUE; Debug(LDAP_DEBUG_CONFIG, "expandUrl: filters contain %s\n", eui->eui_adattr->ad_cname.bv_val, 0, 0); Entry * new = NULL; op->o_bd = select_backend( &(eui->eui_dn), 0, 0 ); int rc = be_entry_get_rw(op, &(eui->eui_dn), NULL, NULL, 0, &new); new = entry_dup( new ); expand_entry (op, eui, new); int err = test_filter( op, new, op->ors_filter ); if( err == LDAP_COMPARE_TRUE ) { rs->sr_entry = new; rs->sr_flags |= REP_ENTRY_MUSTBEFREED; eui->expanded = 1; send_search_entry(op, rs); } } /* Default is to just fall through to the normal processing */ return SLAP_CB_CONTINUE; } static int expandUrl_config( BackendDB *be, const char *fname, int lineno, int argc, char **argv ) { slap_overinst *on = (slap_overinst *) be->bd_info; AttributeDescription *ad_uri = NULL, *ad_attr = NULL; /* The config syntax is "expandUrl " * and only one directive may be speeuified per overlay instance. */ if ( strcasecmp( argv[0], "expandUrl" ) == 0 ) { expandUrl_info *eui; struct berval bv, dn; const char *text; if ( argc != 4 ) { Debug( LDAP_DEBUG_ANY, "%s: line %d: argument missing in \"expandUrl on_bi.bi_private pointer can be used for * anything this instance of the overlay needs. */ eui = ch_malloc( sizeof( expandUrl_info )); eui->eui_aduri = ad_uri; eui->eui_adattr = ad_attr; eui->eui_dn = dn; eui->expanded = 0; eui->eui_next = on->on_bi.bi_private; on->on_bi.bi_private = eui; return 0; } return SLAP_CONF_UNKNOWN; } static slap_overinst expandUrl; int expandUrl_init() { expandUrl.on_bi.bi_type = "expandUrl"; expandUrl.on_bi.bi_db_config = expandUrl_config; expandUrl.on_response = expandUrl_response; return overlay_register( &expandUrl ); } // #if SLAPD_OVER_EXPANDURL == SLAPD_MOD_DYNAMIC int init_module(int argc, char *argv[]) { return expandUrl_init(); } // #endif // #endif /* SLAPD_OVER_EXPANDURL */