diff options
Diffstat (limited to 'ldap/servers/plugins/uiduniq/7bit.c')
-rw-r--r-- | ldap/servers/plugins/uiduniq/7bit.c | 722 |
1 files changed, 722 insertions, 0 deletions
diff --git a/ldap/servers/plugins/uiduniq/7bit.c b/ldap/servers/plugins/uiduniq/7bit.c new file mode 100644 index 00000000..535dbe9c --- /dev/null +++ b/ldap/servers/plugins/uiduniq/7bit.c @@ -0,0 +1,722 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * 7bit.c + * + * Implements a directory server pre-operation plugin to test + * attributes for 7 bit clean within a defined subtree in the + * directory. + * + */ +#include <stdio.h> +#include <slapi-plugin.h> +#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */ +#include <string.h> +#include "dirver.h" + +/* DBDB this should be pulled from a common header file */ +#ifdef _WIN32 +#ifndef strcasecmp +#define strcasecmp(x,y) strcmpi(x,y) +#endif +#endif + +#if defined( LDAP_DEBUG ) && !defined( DEBUG ) +#define DEBUG +#endif + +/* + * 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 = "NS7bitAttr"; +static Slapi_PluginDesc +pluginDesc = { "NS7bitAttr", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, + "Enforce 7-bit clean attribute values" }; + + +/* + * More information about constraint failure + */ +static char *moreInfo = + "The value is not 7-bit clean: "; + +/* ------------------------------------------------------------ */ +/* + * op_error - Record (and report) an operational error. + */ +static int +op_error(int internal_error) +{ + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "Internal error: %d\n", internal_error); + + return LDAP_OPERATIONS_ERROR; +} + +static void +issue_error(Slapi_PBlock *pb, int result, char *type, char *value) +{ + char *moreinfop; + int sz; + + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "%s result %d\n", type, result); + + if (value == NULL) { + value = "unknown"; + } + sz = strlen(moreInfo) + strlen(value) + 1; + moreinfop = (char *)slapi_ch_malloc(sz); + sprintf(moreinfop, "%s%s", moreInfo, value); + + /* Send failure to the client */ + slapi_send_ldap_result(pb, result, 0, moreinfop, 0, 0); + slapi_ch_free((void **)&moreinfop); + + return; +} + + +/* + * Check 'value' for 7-bit cleanliness. + */ +static int +bit_check_one_berval(const struct berval *value, char **violated) +{ + int result; + char *ch; + int i; + +#ifdef DEBUG + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "7-bit checking begin\n"); +#endif + + result = LDAP_SUCCESS; + /* If no value, can't possibly be a conflict */ + if ( (struct berval *)NULL == value ) + return result; + + for(i=0, ch=value->bv_val; ch && i < (int)(value->bv_len) ; + ch++, i++) + { + + if (( 0x80 & *ch ) != 0 ) + { + result = LDAP_CONSTRAINT_VIOLATION; + *violated = value->bv_val; + break; + } + } + + return result; +} + + +/* + * Check a set of values for 7-bit cleanliness. + * + * If 'attr' is NULL, the values are taken from 'values'. + * If 'attr' is non-NULL, the values are taken from 'attr'. + */ +static int +bit_check(Slapi_Attr *attr, struct berval **values, char **violated) +{ + int result = LDAP_SUCCESS; + *violated = NULL; + + /* If no values, can't possibly be a conflict */ + if ( (Slapi_Attr *)NULL == attr && (struct berval **)NULL == values ) + return result; + + 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 = bit_check_one_berval(slapi_value_get_berval(v), violated); + } + } + else + { + for (;*values != NULL && LDAP_SUCCESS == result; values++) + { + result = bit_check_one_berval(*values, violated); + } + } + +#ifdef DEBUG + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "7 bit check result = %d\n", result); +#endif + + return result; +} + + +/* ------------------------------------------------------------ */ +/* + * preop_add - pre-operation plug-in for add + */ +static int +preop_add(Slapi_PBlock *pb) +{ + int result; + char *violated; + +#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; + int argc; + char **argv; + char **attrName; + char *dn; + Slapi_Entry *e; + Slapi_Attr *attr; + char **firstSubtree; + char **subtreeDN; + int subtreeCnt; + int is_replicated_operation; + + /* + * Get the arguments + */ + err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc); + if (err) { result = op_error(53); break; } + + err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv); + if (err) { result = op_error(54); break; } + + /* + * If this is a replication update, just be a noop. + */ + err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation); + if (err) { result = op_error(56); break; } + if (is_replicated_operation) + { + break; + } + + /* + * Get the target DN for this add operation + */ + err = slapi_pblock_get(pb, SLAPI_ADD_TARGET, &dn); + if (err) { result = op_error(50); 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 = op_error(51); break; } + + for ( firstSubtree = argv; strcmp(*firstSubtree, ",") != 0; + firstSubtree++, argc--) {} + firstSubtree++; + argc--; + + for (attrName = argv; strcmp(*attrName, ",") != 0; attrName++ ) + { + /* + * if the attribute is userpassword, check unhashed#user#password + * instead. "userpassword" is encoded; it will always pass the 7bit + * check. + */ + char *attr_name; + if ( strcasecmp(*attrName, "userpassword") == 0 ) + { + attr_name = "unhashed#user#password"; + } else { + attr_name = *attrName; + } + err = slapi_entry_attr_find(e, attr_name, &attr); + if (err) continue; /* break;*/ /* no 7-bit attribute */ + + /* + * For each DN in the managed list, do 7-bit checking if + * the target DN is a subnode in the tree. + */ + for( subtreeDN=firstSubtree, subtreeCnt=argc ;subtreeCnt > 0; + subtreeCnt--,subtreeDN++) + { + /* + * issuffix determines whether the target is under the + * subtree *subtreeDN + */ + if (slapi_dn_issuffix(dn, *subtreeDN)) + { +#ifdef DEBUG + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "ADD subtree=%s\n", *subtreeDN); +#endif + + /* + * Check if the value is 7-bit clean + */ + result = bit_check(attr, NULL, &violated); + if (result) break; + } + } + /* don't have to go on if there is a value not 7-bit clean */ + if (result) break; + } + END + + if (result) { + issue_error(pb, result, "ADD", violated); + } + + 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; + char *violated; + LDAPMod **checkmods = NULL; /* holds mods to check */ + int checkmodsCapacity = 0; /* max capacity of checkmods */ + +#ifdef DEBUG + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "MODIFY begin\n"); +#endif + + result = LDAP_SUCCESS; + + BEGIN + int err; + int argc; + char **argv; + char **attrName; + LDAPMod **mods; + LDAPMod **firstMods; + LDAPMod *mod; + char *target; + char **firstSubtree; + char **subtreeDN; + int subtreeCnt; + int is_replicated_operation; + + /* + * Get the arguments + */ + err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc); + if (err) { result = op_error(13); break; } + + err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv); + if (err) { result = op_error(14); break; } + + /* + * If this is a replication update, just be a noop. + */ + err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation); + if (err) { result = op_error(16); break; } + if (is_replicated_operation) + { + break; + } + + err = slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &firstMods); + if (err) { result = op_error(10); break; } + + /* Get the target DN */ + err = slapi_pblock_get(pb, SLAPI_MODIFY_TARGET, &target); + if (err) { result = op_error(11); break; } + + /* + * Look for managed trees that include the target + * Arguments before "," are the 7-bit clean attribute names. Arguemnts + * after "," are subtreeDN's. + */ + for ( firstSubtree = argv; strcmp(*firstSubtree, ",") != 0; + firstSubtree++, argc--) {} + firstSubtree++; + argc--; + + for (attrName = argv; strcmp(*attrName, ",") != 0; attrName++ ) + { + int modcount = 0; + int ii = 0; + + /* + * if the attribute is userpassword, check unhashed#user#password + * instead. "userpassword" is encoded; it will always pass the 7bit + * check. + */ + char *attr_name; + if ( strcasecmp(*attrName, "userpassword") == 0 ) + { + attr_name = "unhashed#user#password"; + } else { + attr_name = *attrName; + } + + /* 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=firstMods;*mods;mods++) + { + mod = *mods; + if ((slapi_attr_type_cmp(mod->mod_type, attr_name, 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) { + continue; /* no mods to check, go to next attr */ + } + + /* + * stop checking at first mod that fails the check + */ + for (ii = 0; (result == 0) && (ii < modcount); ++ii) + { + mod = checkmods[ii]; + /* + * For each DN in the managed list, do 7-bit checking if + * the target DN is a subnode in the tree. + */ + for( subtreeDN=firstSubtree, subtreeCnt=argc ;subtreeCnt > 0; + subtreeCnt--,subtreeDN++) + { + /* + * issuffix determines whether the target is under the + * subtree *subtreeDN + */ + if (slapi_dn_issuffix(target, *subtreeDN)) + { +#ifdef DEBUG + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "MODIFY subtree=%s\n", *subtreeDN); +#endif + /* + * Check if the value is 7-bit clean + */ + result = bit_check(NULL, mod->mod_bvalues, &violated); + if (result) break; + } + } + } + /* don't have to go on if there is a value not 7-bit clean */ + if (result) break; + } + END + + slapi_ch_free((void **)&checkmods); + if (result) { + issue_error(pb, result, "MODIFY", violated); + } + + 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; + char *violated; + +#ifdef DEBUG + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "MODRDN begin\n"); +#endif + + /* Init */ + result = LDAP_SUCCESS; + e = 0; + + BEGIN + int err; + int argc; + char **argv; + char **attrName; + char *target; + char *superior; + char *rdn; + Slapi_Attr *attr; + char **firstSubtree; + char **subtreeDN; + int subtreeCnt; + int is_replicated_operation; + + /* + * Get the arguments + */ + err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc); + if (err) { result = op_error(30); break; } + + err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv); + if (err) { result = op_error(31); break; } + + /* + * If this is a replication update, just be a noop. + */ + err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation); + if (err) { result = op_error(16); break; } + if (is_replicated_operation) + { + break; + } + + /* Get the DN of the entry being renamed */ + err = slapi_pblock_get(pb, SLAPI_MODRDN_TARGET, &target); + if (err) { result = op_error(22); break; } + + /* Get superior value - unimplemented in 3.0 DS */ + err = slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR, &superior); + if (err) { result = op_error(20); 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 = target; + + /* Get the new RDN - this has the attribute values */ + err = slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &rdn); + if (err) { result = 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 = op_error(32); 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 */ + } + + /* + * arguments before "," are the 7-bit clean attribute names. Arguemnts + * after "," are subtreeDN's. + */ + for ( firstSubtree = argv; strcmp(*firstSubtree, ",") != 0; + firstSubtree++, argc--) {} + firstSubtree++; + argc--; + + /* + * Find out if the node is being moved into one of + * the managed subtrees + */ + for (attrName = argv; strcmp(*attrName, ",") != 0; attrName++ ) + { + /* + * If the attribut type is userpassword, do not replace it by + * unhashed#user#password because unhashed#user#password does not exist + * in this case. + */ + /* + * Find any 7-bit attribute data in the new RDN + */ + err = slapi_entry_attr_find(e, *attrName, &attr); + if (err) continue; /* break;*/ /* no 7-bit attribute */ + + /* + * For each DN in the managed list, do 7-bit checking if + * the target DN is a subnode in the tree. + */ + for( subtreeDN=firstSubtree, subtreeCnt=argc ;subtreeCnt > 0; + subtreeCnt--,subtreeDN++) + { + /* + * issuffix determines whether the target is under the + * subtree *subtreeDN + */ + if (slapi_dn_issuffix(superior, *subtreeDN)) + { +#ifdef DEBUG + slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, + "MODRDN subtree=%s\n", *subtreeDN); +#endif + + /* + * Check if the value is 7-bit clean + */ + result = bit_check(attr, NULL, &violated); + if (result) break; + } + } + /* don't have to go on if there is a value not 7-bit clean */ + if (result) break; + } + END + + /* Clean-up */ + if (e) slapi_entry_free(e); + + if (result) { + issue_error(pb, result, "MODRDN", violated); + } + + return (result==LDAP_SUCCESS)?0:-1; +} + +/* ------------------------------------------------------------ */ +/* + * Initialize the plugin + * + */ +int +NS7bitAttr_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 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; + + /* + * Arguments before "," are the 7-bit attribute names. Arguments after + * "," are the subtree DN's. + */ + if (argc < 1) { err = -1; break; } + for(;strcmp(*argv, ",") != 0 && argc > 0; argc--, argv++) + {}; + if (argc == 0) { 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, "NS7bitAttr_Init", + "Error: %d\n", err); + err = -1; + } + else + slapi_log_error(SLAPI_LOG_PLUGIN, "NS7bitAttr_Init", + "plugin loaded\n"); + + return err; +} + |