diff options
Diffstat (limited to 'plugin/suffix.c')
-rw-r--r-- | plugin/suffix.c | 359 |
1 files changed, 359 insertions, 0 deletions
diff --git a/plugin/suffix.c b/plugin/suffix.c new file mode 100644 index 0000000..6327994 --- /dev/null +++ b/plugin/suffix.c @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2008, Stefan Walter + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#include "config.h" + +#include "plugin.h" + +#include <stdarg.h> +#include <string.h> +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> + +/*---------------------------------------------------------------------------------- + * DECLARATIONS + */ + +static const char *suffix_attribute = NULL; +static const char *suffix_delimiter = NULL; + +/* --------------------------------------------------------------------------------- + * LDAP OPERATIONS + */ + +static char** +entry_values (Slapi_Entry *entry, const char *name) +{ + struct berval **values, **bv; + char **results, *result, **r; + Slapi_Attr *attr; + int rc, num; + + /* The attribute we're after */ + rc = slapi_entry_attr_find (entry, (char*)name, &attr); + if (rc != 0) + return NULL; + return_val_if_fail (attr, NULL); + + /* The values for that attribute */ + rc = slapi_attr_get_values (attr, &values); + return_val_if_fail (rc == 0, NULL); + + /* How many values? */ + for (bv = values, num = 0; values && *bv; ++bv) + ++num; + + /* Allocate memory and copy over all values found */ + r = results = (char**)slapi_ch_calloc (num + 1, sizeof (char*)); + for (bv = values; values && *bv; ++bv) { + + /* Allocate a string for this value */ + result = slapi_ch_calloc ((*bv)->bv_len + 1, sizeof (char)); + if ((*bv)->bv_len) + memcpy (result, (*bv)->bv_val, (*bv)->bv_len); + result[(*bv)->bv_len] = 0; + + /* Add into array */ + *(r++) = result; + } + + /* Null terminate */ + *r = NULL; + + return results; +} + +static char** +lookup_values (const char *dn, const char *attr) +{ + Slapi_Entry **entries, *entry; + Slapi_PBlock *pb; + LDAPControl *ctrl; + char *attrs[2]; + char **results; + int rc, code; + + assert (dn && dn[0]); + + ctrl = NULL; /* No controls */ + attrs[0] = (char*)attr; + attrs[1] = NULL; + + trace ("performing internal lookup"); + + /* Do the actual search */ + pb = slapi_search_internal ((char*)dn, LDAP_SCOPE_BASE, "(objectClass=*)", &ctrl, attrs, 0); + return_val_if_fail (pb, NULL); + + /* Was it successful? */ + code = -1; + rc = slapi_pblock_get (pb, SLAPI_PLUGIN_INTOP_RESULT, &code); + return_val_if_fail (rc >= 0, NULL); + if (code != LDAP_SUCCESS) { + log_plugin ("error loading attribute %s from %s (code %d)", attr, dn, code); + slapi_pblock_destroy (pb); + trace ("failure"); + return NULL; + } + + /* Dig out all the entries */ + entries = NULL; + slapi_pblock_get (pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries); + return_val_if_fail (entries, NULL); + + /* The first entry is what we're after */ + entry = *entries; + return_val_if_fail (entry, NULL); + + results = entry_values (entry, attr); + slapi_pblock_destroy (pb); + trace ("success"); + + return results; +} + +static char** +mods_values (LDAPMod **mods, const char *name) +{ + char **results, *result, **r; + struct berval **bv; + LDAPMod *mod; + int num; + + assert (name); + + /* Count the number of values */ + for (mod = *mods; mod; mod = *(++mods)) { + if (mod->mod_op & LDAP_MOD_DELETE || + strcmp (mod->mod_type, name) != 0) + continue; + for (bv = mod->mod_bvalues; *bv; ++bv) + ++num; + } + + /* Allocate memory and copy over all values found */ + r = results = (char**)slapi_ch_calloc (num + 1, sizeof (char*)); + for (mod = *mods; mod; mod = *(++mods)) { + if (mod->mod_op & LDAP_MOD_DELETE || + strcmp (mod->mod_type, name) != 0) + continue; + for (bv = mod->mod_bvalues; *bv; ++bv) { + + /* Allocate a string for this value */ + result = slapi_ch_calloc ((*bv)->bv_len + 1, sizeof (char)); + if ((*bv)->bv_len) + memcpy (result, (*bv)->bv_val, (*bv)->bv_len); + result[(*bv)->bv_len] = 0; + + /* Add into array */ + *(r++) = result; + + } + } + + /* Null terminate */ + *r = NULL; + + return results; +} + +static int +has_suffix (const char *value, const char *suffix, const char *delim) +{ + size_t n_value, n_suffix, n_delim; + + assert (value); + assert (suffix); + assert (delim); + + n_value = strlen (value); + n_suffix = strlen (suffix); + n_delim =strlen (delim); + + /* Must be long enough */ + if (n_value < n_suffix + n_delim) + return 0; + + /* The delim must be in the right place */ + if (memcmp (value + (n_value - (n_suffix + n_delim)), delim, n_delim) != 0) + return 0; + + /* And the suffix must be in the right place */ + if (memcmp (value + (n_value - n_suffix), suffix, n_suffix) != 0) + return 0; + + return 1; +} + +static int +check_suffix_constraints (Slapi_PBlock *pb, char **suffixes, char **values) +{ + char **val, **suffix; + char msg[512]; + int found; + + assert (pb); + + if (!values || !suffixes) + return 0; + + for (val = values; *val; ++val) { + found = 0; + for (suffix = suffixes; *suffix; ++suffix) { + if (has_suffix (*val, *suffix, suffix_delimiter)) { + found = 1; + break; + } + } + + if (!found) { + snprintf (msg, sizeof (msg), + "The value '%s' for the %s attribute does not have a valid suffix", + *val, suffix_attribute); + slapi_send_ldap_result (pb, LDAP_CONSTRAINT_VIOLATION, NULL, msg, 0, NULL); + return -1; + } + } + + return 0; +} + +int +suffix_pre_add (Slapi_PBlock *pb, const char *dn) +{ + Slapi_Entry *entry; + char **suffixes; + char **values; + char *parent; + int rc = 0; + + if (!suffix_attribute) + return 0; + + parent = slapi_dn_parent (dn); + return_val_if_fail (parent, -1); + + suffixes = lookup_values (parent, suffix_attribute); + slapi_ch_free_string (&parent); + + /* When parent has no suffixes, then any are allowed */ + if (!suffixes || !suffixes[0]) { + slapi_ch_array_free (suffixes); + return 0; + } + + /* The entry itself */ + rc = slapi_pblock_get (pb, SLAPI_ADD_ENTRY, &entry); + return_val_if_fail (rc >= 0 && entry, -1); + + /* Extract the various values from the entry */ + values = entry_values (entry, suffix_attribute); + rc = check_suffix_constraints (pb, suffixes, values); + + slapi_ch_array_free (suffixes); + slapi_ch_array_free (values); + + return rc; +} + +int +suffix_pre_modify (Slapi_PBlock *pb, const char *dn) +{ + char **suffixes; + LDAPMod **mods; + char **values; + char *parent; + int rc = 0; + + if (!suffix_attribute) + return 0; + + parent = slapi_dn_parent (dn); + return_val_if_fail (parent, -1); + + suffixes = lookup_values (parent, suffix_attribute); + slapi_ch_free_string (&parent); + + /* When parent has no suffixes, then any are allowed */ + if (!suffixes || !suffixes[0]) { + slapi_ch_array_free (suffixes); + return 0; + } + + /* The modifications being made */ + rc = slapi_pblock_get (pb, SLAPI_MODIFY_MODS, &mods); + return_val_if_fail (rc >= 0 && mods, -1); + + /* Extract the various values from the entry */ + values = mods_values (mods, suffix_attribute); + rc = check_suffix_constraints (pb, suffixes, values); + + slapi_ch_array_free (suffixes); + slapi_ch_array_free (values); + + return rc; +} + +int +suffix_config (const char *name, const char *value) +{ + return_val_if_fail (name, 0); + + if (strcmp ("suffix-attribute", name) == 0 && value) { + suffix_attribute = value; + return 1; + + } + + return 0; +} + +void +suffix_destroy (void) +{ + +} + +int +suffix_init (void) +{ + if (!suffix_attribute || !suffix_attribute[0]) { + log_plugin ("'attribute' argument not specified"); + return -1; + } + + return 0; +} |