/* * 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 #include #include #include #include #include #include /*---------------------------------------------------------------------------------- * DECLARATIONS */ static const char *suffix_attribute = NULL; static struct berval suffix_delimiter = { 0, NULL }; /* --------------------------------------------------------------------------------- * LDAP OPERATIONS */ static void bv_to_string (struct berval *bv, char *string, size_t n_string) { assert (bv); assert (string); assert (n_string); /* For null terminator */ --n_string; if (bv->bv_len < n_string) n_string = bv->bv_len; memcpy (string, bv->bv_val, n_string); string[n_string] = 0; } static struct berval** entry_values (Slapi_Entry *entry, const char *name) { struct berval **values; Slapi_Attr *attr; int rc; assert (entry); assert (name); /* 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); return values; } static struct berval** lookup_values (const char *dn, const char *attr, Slapi_PBlock **pb) { Slapi_Entry **entries, *entry; LDAPControl *ctrl; char *attrs[2]; struct berval **results; int rc, code; assert (dn && dn[0]); assert (pb); 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); 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); trace ("success"); return results; } static int has_suffix (struct berval *value, struct berval *suffix, struct berval *delim) { char *ptr; assert (value); assert (suffix); assert (delim); /* Must be long enough */ if (value->bv_len < suffix->bv_len + delim->bv_len) return 0; ptr = value->bv_val; /* The delim must be in the right place */ if (memcmp (ptr + (value->bv_len - (suffix->bv_len + delim->bv_len)), delim->bv_val, delim->bv_len) != 0) return 0; /* And the suffix must be in the right place */ if (memcmp (ptr + (value->bv_len - suffix->bv_len), suffix->bv_val, suffix->bv_len) != 0) return 0; return 1; } static int check_suffix_constraints (Slapi_PBlock *pb, struct berval **suffixes, struct berval **values) { struct berval *value, **suffix; char string[128]; char msg[512]; int found; assert (pb); /* When parent has no suffixes, then any are allowed */ if (!values || !suffixes) return 0; for (value = *values; value; value = *(++values)) { found = 0; for (suffix = suffixes; suffix; ++suffix) { if (has_suffix (value, *suffix, &suffix_delimiter)) { found = 1; break; } } if (!found) { /* Build and return our error message */ bv_to_string (value, string, sizeof (string)); snprintf (msg, sizeof (msg), "The value '%s' for the %s attribute does not have a valid suffix", string, 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) { struct berval **suffixes; struct berval **values; Slapi_PBlock *ipb = NULL; Slapi_Entry *entry; char *parent; int rc = 0; assert (pb); assert (dn); if (!suffix_attribute) return 0; parent = slapi_dn_beparent (pb, dn); if (!parent) return 0; suffixes = lookup_values (parent, suffix_attribute, &ipb); slapi_ch_free_string (&parent); /* 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); return_val_if_fail (ipb, -1); slapi_pblock_destroy (ipb); return rc; } int suffix_pre_modify (Slapi_PBlock *pb, const char *dn) { struct berval **suffixes; Slapi_PBlock *ipb = NULL; LDAPMod **mods, *mod; char *parent; int rc = 0; assert (pb); assert (dn); if (!suffix_attribute) return 0; parent = slapi_dn_beparent (pb, dn); if (!parent) return 0; suffixes = lookup_values (parent, suffix_attribute, &ipb); slapi_ch_free_string (&parent); /* The modifications being made */ rc = slapi_pblock_get (pb, SLAPI_MODIFY_MODS, &mods); return_val_if_fail (rc >= 0 && mods, -1); /* Validate the values */ for (mod = *mods; rc == 0 && mod; mod = *(++mods)) { if (!(mod->mod_op & LDAP_MOD_DELETE) && strcmp (mod->mod_type, suffix_attribute) == 0) rc = check_suffix_constraints (pb, suffixes, mod->mod_bvalues); } return_val_if_fail (ipb, -1); slapi_pblock_destroy (ipb); 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; } else if (strcmp ("suffix-delimiter", name) == 0 && value) { suffix_delimiter.bv_val = (void*)value; suffix_delimiter.bv_len = strlen (value); return 1; } return 0; } void suffix_destroy (void) { } int suffix_init (void) { return 0; }