diff options
Diffstat (limited to 'ldap/servers/plugins/uiduniq/uid.c')
-rw-r--r-- | ldap/servers/plugins/uiduniq/uid.c | 1073 |
1 files changed, 1073 insertions, 0 deletions
diff --git a/ldap/servers/plugins/uiduniq/uid.c b/ldap/servers/plugins/uiduniq/uid.c new file mode 100644 index 00000000..f32e63ac --- /dev/null +++ b/ldap/servers/plugins/uiduniq/uid.c @@ -0,0 +1,1073 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * uid.c + * + * Implements a directory server pre-operation plugin to test + * attributes for uniqueness within a defined subtree in the + * directory. + * + * Called uid.c since the original purpose of the plugin was to + * check the uid attribute in user entries. + */ +#include <slapi-plugin.h> +#include <portable.h> +#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */ +#include <string.h> +#include "dirver.h" +#include "plugin-utils.h" + +#if defined( LDAP_DEBUG ) && !defined( DEBUG ) +#define DEBUG +#endif + +#define UNTAGGED_PARAMETER 12 + +/* Quoting routine - this should be in a library somewhere (slapi?) */ +int ldap_quote_filter_value( + char *value, int len, + char *out, int maxLen, + int *outLen); + + +static int search_one_berval(const char *baseDN, const char *attrName, + const struct berval *value, const char *target); + +/* + * ISSUES: + * How should this plugin handle ACL issues? It seems wrong to reject + * adds and modifies because there is already a conflicting UID, when + * the request would have failed because of an ACL check anyway. + * + * This code currently defines a maximum filter string size of 512. Is + * this large enough? + * + * This code currently does not quote the value portion of the filter as + * it is created. This is a bug. + */ + +/* */ +#define BEGIN do { +#define END } while(0); + +/* + * Slapi plugin descriptor + */ +static char *plugin_name = "NSUniqueAttr"; +static Slapi_PluginDesc +pluginDesc = { + "NSUniqueAttr", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, + "Enforce unique attribute values" +}; +static void* plugin_identity = NULL; + + +/* + * More information about constraint failure + */ +static char *moreInfo = + "Another entry with the same attribute value already exists"; + +static void +freePblock( Slapi_PBlock *spb ) { + if ( spb ) + { + slapi_free_search_results_internal( spb ); + slapi_pblock_destroy( spb ); + } +} + +/* ------------------------------------------------------------ */ +/* + * op_error - Record (and report) an operational error. + * name changed to uid_op_error so as not to conflict with the external function + * of the same name thereby preventing compiler warnings. + */ +static int +uid_op_error(int internal_error) +{ + slapi_log_error( + SLAPI_LOG_PLUGIN, + plugin_name, + "Internal error: %d\n", + internal_error); + + return LDAP_OPERATIONS_ERROR; +} + +/* ------------------------------------------------------------ */ +/* + * Create an LDAP search filter from the attribute + * name and value supplied. + */ + +static char * +create_filter(const char *attribute, const struct berval *value) +{ + char *filter; + char *fp; + char *max; + int attrLen; + int valueLen; + int filterLen; + + /* Compute the length of the required buffer */ + attrLen = strlen(attribute); + + if (ldap_quote_filter_value(value->bv_val, + value->bv_len, 0, 0, &valueLen)) + return 0; + + filterLen = attrLen + 1 + valueLen + 1; + + /* Allocate the buffer */ + filter = slapi_ch_malloc(filterLen); + fp = filter; + max = &filter[filterLen]; + + /* Place attribute name in filter */ + strcpy(fp, attribute); + fp += attrLen; + + /* Place comparison operator */ + *fp++ = '='; + + /* Place value in filter */ + if (ldap_quote_filter_value(value->bv_val, value->bv_len, + fp, max-fp, &valueLen)) { slapi_ch_free((void**)&filter); return 0; } + fp += valueLen; + + /* Terminate */ + *fp = 0; + + return filter; +} + +/* ------------------------------------------------------------ */ +/* + * search - search a subtree for entries with a named attribute matching + * the list of values. An entry matching the 'target' DN is + * not considered in the search. + * + * If 'attr' is NULL, the values are taken from 'values'. + * If 'attr' is non-NULL, the values are taken from 'attr'. + * + * Return: + * LDAP_SUCCESS - no matches, or the attribute matches the + * target dn. + * LDAP_CONSTRAINT_VIOLATION - an entry was found that already + * contains the attribute value. + * LDAP_OPERATIONS_ERROR - a server failure. + */ +static int +search(const char *baseDN, const char *attrName, Slapi_Attr *attr, + struct berval **values, const char *target) +{ + int result; + +#ifdef DEBUG + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "SEARCH baseDN=%s attr=%s target=%s\n", baseDN, attrName, + target?target:"None"); +#endif + + result = LDAP_SUCCESS; + + /* If no values, can't possibly be a conflict */ + if ( (Slapi_Attr *)NULL == attr && (struct berval **)NULL == values ) + return result; + + /* + * Perform the search for each value provided + * + * Another possibility would be to search for all the values at once. + * However, this is more complex (for filter creation) and unique + * attributes values are probably only changed one at a time anyway. + */ + if ( (Slapi_Attr *)NULL != attr ) + { + Slapi_Value *v = NULL; + int vhint = -1; + + for ( vhint = slapi_attr_first_value( attr, &v ); + vhint != -1 && LDAP_SUCCESS == result; + vhint = slapi_attr_next_value( attr, vhint, &v )) + { + result = search_one_berval(baseDN,attrName, + slapi_value_get_berval(v),target); + } + } + else + { + for (;*values != NULL && LDAP_SUCCESS == result; values++) + { + result = search_one_berval(baseDN,attrName,*values,target); + } + } + +#ifdef DEBUG + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "SEARCH result = %d\n", result); +#endif + + return( result ); +} + + +static int +search_one_berval(const char *baseDN, const char *attrName, + const struct berval *value, const char *target) +{ + int result; + char *filter; + Slapi_PBlock *spb; + + result = LDAP_SUCCESS; + + /* If no value, can't possibly be a conflict */ + if ( (struct berval *)NULL == value ) + return result; + + filter = 0; + spb = 0; + + BEGIN + int err; + int sres; + Slapi_Entry **entries; + static char *attrs[] = { "1.1", 0 }; + + /* Create the filter - this needs to be freed */ + filter = create_filter(attrName, value); + +#ifdef DEBUG + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "SEARCH filter=%s\n", filter); +#endif + + /* Perform the search using the new internal API */ + spb = slapi_pblock_new(); + if (!spb) { result = uid_op_error(2); break; } + + slapi_search_internal_set_pb(spb, baseDN, LDAP_SCOPE_SUBTREE, + filter, attrs, 0 /* attrs only */, NULL, NULL, plugin_identity, 0 /* actions */); + slapi_search_internal_pb(spb); + + err = slapi_pblock_get(spb, SLAPI_PLUGIN_INTOP_RESULT, &sres); + if (err) { result = uid_op_error(3); break; } + + /* Allow search to report that there is nothing in the subtree */ + if (sres == LDAP_NO_SUCH_OBJECT) break; + + /* Other errors are bad */ + if (sres) { result = uid_op_error(3); break; } + + err = slapi_pblock_get(spb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, + &entries); + if (err) { result = uid_op_error(4); break; } + + /* + * Look at entries returned. Any entry found must be the + * target entry or the constraint fails. + */ + for(;*entries;entries++) + { + char *dn = slapi_entry_get_dn(*entries); + + /* + * DNs are returned in the original value used to insert + * the entry. This must be "normalized" for comparison. + * + * This normalization is done "in-place" (modifying the value + * in the entry). This is OK, since this is the only user + * of this copy of the entry. + */ + slapi_dn_normalize_case(dn); + +#ifdef DEBUG + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "SEARCH entry dn=%s\n", dn); +#endif + + /* + * It is a Constraint Violation if any entry is found, unless + * the entry is the target entry (if any). + */ + if (!target || strcmp(dn, target) != 0) + { + result = LDAP_CONSTRAINT_VIOLATION; + break; + } + } + +#ifdef DEBUG + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "SEARCH complete result=%d\n", result); +#endif + END + + /* Clean-up */ + if (spb) { + slapi_free_search_results_internal(spb); + slapi_pblock_destroy(spb); + } + + slapi_ch_free((void**)&filter); + + return result; +} + +/* ------------------------------------------------------------ */ +/* + * searchAllSubtrees - search all subtrees in argv for entries + * with a named attribute matching the list of values, by + * calling search for each one. + * + * If 'attr' is NULL, the values are taken from 'values'. + * If 'attr' is non-NULL, the values are taken from 'attr'. + * + * Return: + * LDAP_SUCCESS - no matches, or the attribute matches the + * target dn. + * LDAP_CONSTRAINT_VIOLATION - an entry was found that already + * contains the attribute value. + * LDAP_OPERATIONS_ERROR - a server failure. + */ +static int +searchAllSubtrees(int argc, char *argv[], const char *attrName, + Slapi_Attr *attr, struct berval **values, const char *dn) +{ + int result = LDAP_SUCCESS; + + /* + * For each DN in the managed list, do uniqueness checking if + * the target DN is a subnode in the tree. + */ + for(;argc > 0;argc--,argv++) + { + result = search(*argv, attrName, attr, values, dn); + if (result) break; + } + return result; +} + +/* ------------------------------------------------------------ */ +/* + * getArguments - parse invocation parameters + * Return: + * 0 - success + * >0 - error parsing parameters + */ +static int +getArguments(Slapi_PBlock *pb, char **attrName, char **markerObjectClass, + char **requiredObjectClass) +{ + int argc; + char **argv; + + /* + * Get the arguments + */ + if (slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc)) + { + return uid_op_error(10); + } + + if (slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv)) + { + return uid_op_error(11); + } + + /* + * Required arguments: attribute and markerObjectClass + * Optional argument: requiredObjectClass + */ + for(;argc > 0;argc--,argv++) + { + char *param = *argv; + char *delimiter = strchr(param, '='); + if (NULL == delimiter) + { + /* Old style untagged parameter */ + *attrName = *argv; + return UNTAGGED_PARAMETER; + } + if (strncasecmp(param, "attribute", delimiter-param) == 0) + { + /* It's OK to set a pointer here, because ultimately it points + * inside the argv array of the pblock, which will be staying + * arround. + */ + *attrName = delimiter+1; + } else if (strncasecmp(param, "markerobjectclass", delimiter-param) == 0) + { + *markerObjectClass = delimiter+1; + } else if (strncasecmp(param, "requiredobjectclass", delimiter-param) == 0) + { + *requiredObjectClass = delimiter+1; + } + } + if (!*attrName || !*markerObjectClass) + { + return uid_op_error(13); + } + + return 0; +} + +/* ------------------------------------------------------------ */ +/* + * findSubtreeAndSearch - walk up the tree to find an entry with + * the marker object class; if found, call search from there and + * return the result it returns + * + * If 'attr' is NULL, the values are taken from 'values'. + * If 'attr' is non-NULL, the values are taken from 'attr'. + * + * Return: + * LDAP_SUCCESS - no matches, or the attribute matches the + * target dn. + * LDAP_CONSTRAINT_VIOLATION - an entry was found that already + * contains the attribute value. + * LDAP_OPERATIONS_ERROR - a server failure. + */ +static int +findSubtreeAndSearch(char *parentDN, const char *attrName, Slapi_Attr *attr, + struct berval **values, const char *target, const char *markerObjectClass) +{ + int result = LDAP_SUCCESS; + Slapi_PBlock *spb = NULL; + + while (NULL != (parentDN = slapi_dn_parent(parentDN))) + { + if (spb = dnHasObjectClass(parentDN, markerObjectClass)) + { + freePblock(spb); + /* + * Do the search. There is no entry that is allowed + * to have the attribute already. + */ + result = search(parentDN, attrName, attr, values, target); + break; + } + } + return result; +} + + +/* ------------------------------------------------------------ */ +/* + * preop_add - pre-operation plug-in for add + */ +static int +preop_add(Slapi_PBlock *pb) +{ + int result; + +#ifdef DEBUG + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "ADD begin\n"); +#endif + + result = LDAP_SUCCESS; + + /* + * Do constraint check on the added entry. Set result. + */ + + BEGIN + int err; + char *attrName = NULL; + char *markerObjectClass = NULL; + char *requiredObjectClass = NULL; + char *dn; + int isupdatedn; + Slapi_Entry *e; + Slapi_Attr *attr; + int argc; + char **argv = NULL; + + /* + * If this is a replication update, just be a noop. + */ + err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &isupdatedn); + if (err) { result = uid_op_error(50); break; } + if (isupdatedn) + { + break; + } + + /* + * Get the arguments + */ + result = getArguments(pb, &attrName, &markerObjectClass, + &requiredObjectClass); + if (UNTAGGED_PARAMETER == result) + { + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "ADD parameter untagged: %s\n", attrName); + result = LDAP_SUCCESS; + /* Statically defined subtrees to monitor */ + err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc); + if (err) { result = uid_op_error(53); break; } + + err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv); + if (err) { result = uid_op_error(54); break; } + argc--; argv++; /* First argument was attribute name */ + } else if (0 != result) + { + break; + } + + /* + * Get the target DN for this add operation + */ + err = slapi_pblock_get(pb, SLAPI_ADD_TARGET, &dn); + if (err) { result = uid_op_error(51); break; } + +#ifdef DEBUG + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "ADD target=%s\n", dn); +#endif + + /* + * Get the entry data for this add. Check whether it + * contains a value for the unique attribute + */ + err = slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e); + if (err) { result = uid_op_error(52); break; } + + err = slapi_entry_attr_find(e, attrName, &attr); + if (err) break; /* no unique attribute */ + + /* + * Check if it contains the required object class + */ + if (NULL != requiredObjectClass) + { + if (!entryHasObjectClass(pb, e, requiredObjectClass)) + { + /* No, so we don't have to do anything */ + break; + } + } + + /* + * Passed all the requirements - this is an operation we + * need to enforce uniqueness on. Now find all parent entries + * with the marker object class, and do a search for each one. + */ + if (NULL != markerObjectClass) + { + /* Subtree defined by location of marker object class */ + result = findSubtreeAndSearch(dn, attrName, attr, NULL, + dn, markerObjectClass); + } else + { + /* Subtrees listed on invocation line */ + result = searchAllSubtrees(argc, argv, attrName, attr, NULL, dn); + } + END + + if (result) + { + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "ADD result %d\n", result); + + /* Send failure to the client */ + slapi_send_ldap_result(pb, result, 0, moreInfo, 0, 0); + } + + return (result==LDAP_SUCCESS)?0:-1; +} + +static void +addMod(LDAPMod ***modary, int *capacity, int *nmods, LDAPMod *toadd) +{ + if (*nmods == *capacity) { + *capacity += 4; + if (*modary) { + *modary = (LDAPMod **)slapi_ch_realloc((char *)*modary, *capacity * sizeof(LDAPMod *)); + } else { + *modary = (LDAPMod **)slapi_ch_malloc(*capacity * sizeof(LDAPMod *)); + } + } + *modary[*nmods] = toadd; + (*nmods)++; +} + +/* ------------------------------------------------------------ */ +/* + * preop_modify - pre-operation plug-in for modify + */ +static int +preop_modify(Slapi_PBlock *pb) +{ + + int result = LDAP_SUCCESS; + Slapi_PBlock *spb = NULL; + LDAPMod **checkmods = NULL; + int checkmodsCapacity = 0; + +#ifdef DEBUG + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "MODIFY begin\n"); +#endif + + BEGIN + int err; + char *attrName; + char *markerObjectClass=NULL; + char *requiredObjectClass=NULL; + LDAPMod **mods; + int modcount = 0; + int ii; + LDAPMod *mod; + char *dn; + int isupdatedn; + int argc; + char **argv = NULL; + + /* + * If this is a replication update, just be a noop. + */ + err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &isupdatedn); + if (err) { result = uid_op_error(60); break; } + if (isupdatedn) + { + break; + } + + /* + * Get the arguments + */ + result = getArguments(pb, &attrName, &markerObjectClass, + &requiredObjectClass); + if (UNTAGGED_PARAMETER == result) + { + result = LDAP_SUCCESS; + /* Statically defined subtrees to monitor */ + err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc); + if (err) { result = uid_op_error(53); break; } + + err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv); + if (err) { result = uid_op_error(54); break; } + argc--; /* First argument was attribute name */ + argv++; + } else if (0 != result) + { + break; + } + + err = slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods); + if (err) { result = uid_op_error(61); break; } + + /* There may be more than one mod that matches e.g. + changetype: modify + delete: uid + uid: balster1950 + - + add: uid + uid: scottg + + So, we need to first find all mods that contain the attribute + which are add or replace ops and are bvalue encoded + */ + /* find out how many mods meet this criteria */ + for(;*mods;mods++) + { + mod = *mods; + if ((slapi_attr_type_cmp(mod->mod_type, attrName, 1) == 0) && /* mod contains target attr */ + (mod->mod_op & LDAP_MOD_BVALUES) && /* mod is bval encoded (not string val) */ + (mod->mod_bvalues && mod->mod_bvalues[0]) && /* mod actually contains some values */ + (((mod->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD) || /* mod is add */ + (mod->mod_op & LDAP_MOD_REPLACE))) /* mod is replace */ + { + addMod(&checkmods, &checkmodsCapacity, &modcount, mod); + } + } + if (modcount == 0) { + break; /* no mods to check, we are done */ + } + + /* Get the target DN */ + err = slapi_pblock_get(pb, SLAPI_MODIFY_TARGET, &dn); + if (err) { result = uid_op_error(11); break; } + + if (requiredObjectClass && + !(spb = dnHasObjectClass(dn, requiredObjectClass))) { break; } + + /* + * Passed all the requirements - this is an operation we + * need to enforce uniqueness on. Now find all parent entries + * with the marker object class, and do a search for each one. + */ + /* + * stop checking at first mod that fails the check + */ + for (ii = 0; (result == 0) && (ii < modcount); ++ii) + { + mod = checkmods[ii]; + if (NULL != markerObjectClass) + { + /* Subtree defined by location of marker object class */ + result = findSubtreeAndSearch(dn, attrName, NULL, + mod->mod_bvalues, dn, + markerObjectClass); + } else + { + /* Subtrees listed on invocation line */ + result = searchAllSubtrees(argc, argv, attrName, NULL, + mod->mod_bvalues, dn); + } + } + END + + slapi_ch_free((void **)&checkmods); + freePblock(spb); + if (result) + { + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "MODIFY result %d\n", result); + + slapi_send_ldap_result(pb, result, 0, moreInfo, 0, 0); + } + + return (result==LDAP_SUCCESS)?0:-1; + +} + +/* ------------------------------------------------------------ */ +/* + * preop_modrdn - Pre-operation call for modify RDN + * + * Check that the new RDN does not include attributes that + * cause a constraint violation + */ +static int +preop_modrdn(Slapi_PBlock *pb) +{ + int result; + Slapi_Entry *e; + +#ifdef DEBUG + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "MODRDN begin\n"); +#endif + + /* Init */ + result = LDAP_SUCCESS; + e = 0; + + BEGIN + int err; + char *attrName; + char *markerObjectClass=NULL; + char *requiredObjectClass=NULL; + char *dn; + char *superior; + char *rdn; + int isupdatedn; + Slapi_Attr *attr; + int argc; + char **argv = NULL; + + /* + * If this is a replication update, just be a noop. + */ + err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &isupdatedn); + if (err) { result = uid_op_error(30); break; } + if (isupdatedn) + { + break; + } + + /* + * Get the arguments + */ + result = getArguments(pb, &attrName, &markerObjectClass, + &requiredObjectClass); + if (UNTAGGED_PARAMETER == result) + { + result = LDAP_SUCCESS; + /* Statically defined subtrees to monitor */ + err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc); + if (err) { result = uid_op_error(53); break; } + + err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv); + if (err) { result = uid_op_error(54); break; } + argc--; /* First argument was attribute name */ + argv++; + } else if (0 != result) + { + break; + } + + /* Get the DN of the entry being renamed */ + err = slapi_pblock_get(pb, SLAPI_MODRDN_TARGET, &dn); + if (err) { result = uid_op_error(31); break; } + + /* Get superior value - unimplemented in 3.0/4.0/5.0 DS */ + err = slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR, &superior); + if (err) { result = uid_op_error(32); break; } + + /* + * No superior means the entry is just renamed at + * its current level in the tree. Use the target DN for + * determining which managed tree this belongs to + */ + if (!superior) superior = dn; + + /* Get the new RDN - this has the attribute values */ + err = slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &rdn); + if (err) { result = uid_op_error(33); break; } +#ifdef DEBUG + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "MODRDN newrdn=%s\n", rdn); +#endif + + /* + * Parse the RDN into attributes by creating a "dummy" entry + * and setting the attributes from the RDN. + * + * The new entry must be freed. + */ + e = slapi_entry_alloc(); + if (!e) { result = uid_op_error(34); break; } + + /* NOTE: strdup on the rdn, since it will be freed when + * the entry is freed */ + + slapi_entry_set_dn(e, slapi_ch_strdup(rdn)); + + err = slapi_entry_add_rdn_values(e); + if (err) + { + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "MODRDN bad rdn value=%s\n", rdn); + break; /* Bad DN */ + } + + /* + * Find any unique attribute data in the new RDN + */ + err = slapi_entry_attr_find(e, attrName, &attr); + if (err) break; /* no UID attribute */ + + /* + * Passed all the requirements - this is an operation we + * need to enforce uniqueness on. Now find all parent entries + * with the marker object class, and do a search for each one. + */ + if (NULL != markerObjectClass) + { + /* Subtree defined by location of marker object class */ + result = findSubtreeAndSearch(dn, attrName, attr, NULL, dn, + markerObjectClass); + } else + { + /* Subtrees listed on invocation line */ + result = searchAllSubtrees(argc, argv, attrName, attr, NULL, dn); + } + END + /* Clean-up */ + if (e) slapi_entry_free(e); + + if (result) + { + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "MODRDN result %d\n", result); + + slapi_send_ldap_result(pb, result, 0, moreInfo, 0, 0); + } + + return (result==LDAP_SUCCESS)?0:-1; + +} + +/* ------------------------------------------------------------ */ +/* + * Initialize the plugin + * + * uidunique_init (the old name) is deprecated + */ +int +NSUniqueAttr_Init(Slapi_PBlock *pb) +{ + int err = 0; + + BEGIN + int err; + int argc; + char **argv; + + /* Declare plugin version */ + err = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, + SLAPI_PLUGIN_VERSION_01); + if (err) break; + + /* + * Get plugin identity and store it for later use + * Used for internal operations + */ + + slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &plugin_identity); + /* PR_ASSERT (plugin_identity); */ + + /* + * Get and normalize arguments + */ + err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc); + if (err) break; + + err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv); + if (err) break; + + /* First argument is the unique attribute name */ + if (argc < 1) { err = -1; break; } + argv++; argc--; + + for(;argc > 0;argc--, argv++) + slapi_dn_normalize_case(*argv); + + /* Provide descriptive information */ + err = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, + (void*)&pluginDesc); + if (err) break; + + /* Register functions */ + err = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_ADD_FN, + (void*)preop_add); + if (err) break; + + err = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODIFY_FN, + (void*)preop_modify); + if (err) break; + + err = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODRDN_FN, + (void*)preop_modrdn); + if (err) break; + + END + + if (err) { + slapi_log_error(SLAPI_LOG_PLUGIN, "NSUniqueAttr_Init", + "Error: %d\n", err); + err = -1; + } + else + slapi_log_error(SLAPI_LOG_PLUGIN, "NSUniqueAttr_Init", + "plugin loaded\n"); + + return err; +} + +int +uidunique_init(Slapi_PBlock *pb) +{ + return NSUniqueAttr_Init(pb); +} + + +/* ------------------------------------------------------------ */ +/* + * ldap_quote_filter_value + * + * Quote the filter value according to RFC 2254 (Dec 1997) + * + * value - a UTF8 string containing the value. It may contain + * any of the chars needing quotes ( '(' ')' '*' '/' and NUL ). + * len - the length of the UTF8 value + * out - a buffer to recieve the converted value. May be NULL, in + * which case, only the length of the output is computed (and placed in + * outLen). + * maxLen - the size of the output buffer. It is an error if this length + * is exceeded. Ignored if out is NULL. + * outLen - recieves the size of the output. If an error occurs, this + * result is not available. + * + * Returns + * 0 - success + * -1 - failure (usually a buffer overflow) + */ +int /* Error value */ +ldap_quote_filter_value( + char *value, int len, + char *out, int maxLen, + int *outLen) +{ + int err; + char *eValue; + int resLen; +#ifdef SLAPI_SUPPORTS_V3_ESCAPING + static char hexchars[16] = "0123456789abcdef"; +#endif + + err = 0; + eValue = &value[len]; + resLen = 0; + + /* + * Convert each character in the input string + */ + while(value < eValue) + { + switch(*value) + { + case '(': + case ')': + case '*': + case '\\': +#ifdef SLAPI_SUPPORTS_V3_ESCAPING + case 0: +#endif + /* Handle characters needing special escape sequences */ + + /* Compute size of output */ +#ifdef SLAPI_SUPPORTS_V3_ESCAPING + resLen += 3; +#else + resLen += 2; +#endif + + /* Generate output if requested */ + if (out) + { + /* Check for overflow */ + if (resLen > maxLen) { err = -1; break; } + + *out++ = '\\'; +#ifdef SLAPI_SUPPORTS_V3_ESCAPING + *out++ = hexchars[(*value >> 4) & 0xF]; + *out++ = hexchars[*value & 0xF]; +#else + *out++ = *value; +#endif + } + + break; + + default: + /* Compute size of output */ + resLen += 1; + + /* Generate output if requested */ + if (out) + { + if (resLen > maxLen) { err = -1; break; } + *out++ = *value; + } + + break; + } + + if (err) break; + + value++; + } + + if (!err) *outLen = resLen; + + return err; +} |