/* * Copyright (c) 2009, 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 #ifdef WITH_SYSLOG #include #endif #define WHITESPACE " \t\r\n\v" static char **plugin_arguments = NULL; /* --------------------------------------------------------------------- * LOGGING/TRACING */ static void log_msg_va (int level, const char* msg, va_list ap) { size_t len; char buf[1024]; assert (level >= 0); assert (msg != NULL); vsnprintf (buf, sizeof (buf) - 2, msg, ap); len = strlen (buf); buf[len] = '\n'; buf[len + 1] = '\0'; fprintf (stderr, "%s: %s", PLUGIN_NAME, buf); #ifdef WITH_SYSLOG if (level != SLAPI_LOG_TRACE) syslog (LOG_WARNING | LOG_DAEMON, "%s: %s", PLUGIN_NAME, buf); #endif slapi_log_error (level, PLUGIN_NAME, buf); } void log_msg (int level, const char* msg, ...) { va_list ap; va_start (ap, msg); log_msg_va (level, msg, ap); va_end (ap); } #if _DEBUG void log_trace (const char *where, int line, const char *msg) { log_msg (SLAPI_LOG_TRACE, " *** %s:%d %s%s", where, line, msg ? ": " : "", msg ? msg : ""); } #endif void log_plugin (const char* msg, ...) { va_list ap; va_start (ap, msg); log_msg_va (SLAPI_LOG_PLUGIN, msg, ap); va_end (ap); } /* -------------------------------------------------------------------------------- * HELPERS */ const char* ltrim (const char *data) { while (*data && isspace (*data)) ++data; return data; } void rtrim (char *data) { char *t = data + strlen (data); while (t > data && isspace (*(t - 1))) { t--; *t = 0; } } char* trim (char *data) { data = (char*)ltrim (data); rtrim (data); return data; } void lowercase (char *data) { while (*data) { *data = tolower (*data); ++data; } } /* --------------------------------------------------------------------------------- * OPERATIONS */ static char* dn_build_normalize (const char *dn, const char *rdn) { char *result; Slapi_DN *sdn; Slapi_DN *parent; Slapi_RDN *srdn; /* Get the parent of the dn */ sdn = slapi_sdn_new_dn_byval (dn); return_val_if_fail (sdn, NULL); parent = slapi_sdn_new (); slapi_sdn_get_parent (sdn, parent); /* Add the rdn to the parent */ srdn = slapi_rdn_new_dn (rdn); return_val_if_fail (srdn, NULL); slapi_sdn_add_rdn (parent, srdn); /* Get the result out */ result = (char*)slapi_sdn_get_dn (parent); return_val_if_fail (result, NULL); /* Normalize the result */ result = slapi_ch_strdup (result); slapi_dn_normalize_case (result); slapi_sdn_free (&sdn); slapi_rdn_free (&srdn); slapi_sdn_free (&parent); trace (result); return result; } static int pre_modify (Slapi_PBlock *pb) { LDAPMod **mods; char *dn; int rc, code; return_val_if_fail (pb, -1); /* Get out the DN and normalize it */ rc = slapi_pblock_get (pb, SLAPI_MODIFY_TARGET, &dn); return_val_if_fail (rc >= 0 && dn, -1); dn = slapi_ch_strdup (dn); slapi_dn_normalize_case (dn); rc = slapi_pblock_get (pb, SLAPI_MODIFY_MODS, &mods); return_val_if_fail (rc >= 0 && mods, -1); /* Send off to components */ rc = serial_pre_modify (dn, mods); slapi_ch_free_string (&dn); return rc; } static int pre_add (Slapi_PBlock *pb) { char *dn; int rc, code; return_val_if_fail (pb, -1); /* Make sure it was successful, don't process errors */ rc = slapi_pblock_get (pb, SLAPI_RESULT_CODE, &code); return_val_if_fail (rc >= 0, -1); if (code != LDAP_SUCCESS) return 0; /* Get out the DN and normalize it */ rc = slapi_pblock_get (pb, SLAPI_ADD_TARGET, &dn); return_val_if_fail (rc >= 0 && dn, -1); dn = slapi_ch_strdup (dn); slapi_dn_normalize_case (dn); /* Send off to components */ rc = serial_post_add (dn); slapi_ch_free_string (&dn); return rc; } static Slapi_PluginDesc plugin_description = { PLUGIN_NAME, /* plug-in identifier */ "stef@memberwebs.com", /* vendor name */ VERSION, /* plug-in revision number */ "Limit attr values to those that have a suffix which equals parent's attribute" }; static int plugin_destroy (Slapi_PBlock *pb) { suffix_destroy (); slapi_ch_array_free (plugin_arguments); plugin_arguments = NULL; return 0; } int plugin_init (Slapi_PBlock *pb) { char **argv = NULL, *arg, *value; int argc = 0; int rc, i; return_val_if_fail (pb, -1); rc = slapi_pblock_get (pb, SLAPI_PLUGIN_ARGV, &argv); return_val_if_fail (rc >= 0, -1); slapi_pblock_get (pb, SLAPI_PLUGIN_ARGC, &argc); return_val_if_fail (rc >= 0, -1); /* * Copy all the arguments, until we get destroyed, and * send the arguments to the components to configure * themselves. */ plugin_arguments = (char**)slapi_ch_calloc (argc + 1, sizeof (char*)); for (i = 0; i < argc; ++i) { plugin_arguments[i] = slapi_ch_strdup (argv[i]); arg = trim (plugin_arguments[i]); value = arg + strcspn (arg, ":="); if (!*value) { value = NULL; } else { *value = 0; value = trim (value + 1); } lowercase (arg); rc = suffix_config (arg, value); if (!rc) log_plugin ("unrecognized plugin argument: %s", argv[i]); } /* Null terminate */ plugin_arguments[i] = NULL; /* Next we initialize all components */ if (suffix_init () < 0) return -1; if (slapi_pblock_set (pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_03) != 0 || slapi_pblock_set (pb, SLAPI_PLUGIN_DESCRIPTION, &plugin_description) != 0 || slapi_pblock_set (pb, SLAPI_PLUGIN_DESTROY_FN, plugin_destroy)) { log_plugin ("error registring plugin"); return -1; } /* Setup the entry add/mobify functions */ if (slapi_pblock_set (pb, SLAPI_PLUGIN_PRE_ADD_FN, (void*)post_add) != 0 || slapi_pblock_set (pb, SLAPI_PLUGIN_PRE_MODIFY_FN, (void*)post_modify) != 0) { log_plugin ("error registering plugin hooks"); return -1; } #ifdef _DEBUG log_trace ("%s initialized", PLUGIN_NAME); #endif return 0; }