2000-01-12 09:15:45 +03:00
|
|
|
/* -*- Mode: C; eval: (c-set-style "GNU") -*-
|
2000-01-12 09:27:00 +03:00
|
|
|
******************************************************************************
|
2000-01-15 01:25:29 +03:00
|
|
|
* $Id: rex_filt.c,v 1.3 2000-01-14 22:25:27 leif%netscape.com Exp $
|
2000-01-12 09:27:00 +03:00
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License
|
|
|
|
* Version 1.1 (the "License"); you may not use this file except in
|
|
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS"
|
|
|
|
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
|
|
|
* License for the specific language governing rights and limitations
|
|
|
|
* under the License.
|
|
|
|
*
|
|
|
|
* The Original Code is Netscape DS Plugins. The Initial Developer of the
|
|
|
|
* Original Code is Leif Hedstrom and Netscape Communications Corp.
|
|
|
|
* Portions created by Netscape are Copyright (C) Netscape Communications
|
|
|
|
* Corp. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
*
|
|
|
|
* DESCRIPTION:
|
|
|
|
* Apply regular expressions to MOD/ADD operations, if the rule is a match
|
|
|
|
* deny/allow the modification. You can use this plugin any number of times
|
|
|
|
* from the slapd.conf file, it will extend the filter rules accordingly.
|
|
|
|
*
|
|
|
|
* USAGE:
|
|
|
|
* plugin preoperation rex_filt.so rexPlugInit attr1,2 0/1 regexp1
|
|
|
|
* plugin preoperation rex_filt.so rexPlugInit attr3,4 0/1 regexp2
|
|
|
|
*
|
|
|
|
* TODO:
|
|
|
|
* * Support the /.../i syntax, for case insensitive regexps.
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
2000-01-15 01:25:29 +03:00
|
|
|
|
2000-01-12 09:15:45 +03:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <regex.h>
|
2000-01-15 01:25:29 +03:00
|
|
|
#include "lulu.h"
|
2000-01-12 09:15:45 +03:00
|
|
|
|
2000-01-15 01:25:29 +03:00
|
|
|
/******************************************************************************
|
|
|
|
* Defines, for this particular plugin only.
|
|
|
|
*/
|
2000-01-12 09:15:45 +03:00
|
|
|
#define PLUGIN_NAME "rex_filter"
|
2000-01-15 01:25:29 +03:00
|
|
|
#define PLUGIN_VERS "1.1"
|
2000-01-12 09:15:45 +03:00
|
|
|
|
|
|
|
#define ERR_NOMATCH "An attribute does not match a server regex rule.\n"
|
|
|
|
#define ERR_MATCH "An attribute matches a server regex rule.\n"
|
|
|
|
|
|
|
|
|
2000-01-15 01:25:29 +03:00
|
|
|
/******************************************************************************
|
|
|
|
* Typedefs and structures. Note that some of the members of this structure
|
|
|
|
* are for performance reason, e.g. the "len" fields.
|
|
|
|
*/
|
2000-01-12 09:15:45 +03:00
|
|
|
typedef struct _Rex_Filter
|
|
|
|
{
|
|
|
|
char *string;
|
|
|
|
char *attributes;
|
|
|
|
regex_t *regex;
|
|
|
|
int match;
|
2000-01-15 01:25:29 +03:00
|
|
|
Plugin_Attrs *attrs;
|
2000-01-12 09:15:45 +03:00
|
|
|
struct _Rex_Filter *next;
|
|
|
|
} Rex_Filter;
|
|
|
|
|
2000-01-15 01:25:29 +03:00
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* Globals, "private" to this module.
|
|
|
|
*/
|
2000-01-12 09:15:45 +03:00
|
|
|
static int rex_num_filters = 0;
|
|
|
|
static Rex_Filter *rex_filter_list = NULL;
|
|
|
|
static Slapi_PluginDesc rex_descript = { PLUGIN_NAME,
|
|
|
|
"Leif Hedstrom",
|
2000-01-15 01:25:29 +03:00
|
|
|
PLUGIN_VERS,
|
2000-01-12 09:15:45 +03:00
|
|
|
"Regex filter plugin" };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
create_filter(Rex_Filter *filter, char *attributes, char *string)
|
|
|
|
{
|
|
|
|
if (!filter || filter->attrs || !attributes || !string)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!(filter->string = slapi_ch_strdup(string)))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!(filter->attributes = slapi_ch_strdup(attributes)))
|
|
|
|
{
|
|
|
|
slapi_ch_free((void **)&(filter->attributes));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(filter->attrs = parse_attributes(filter->attributes)))
|
|
|
|
{
|
|
|
|
slapi_ch_free((void **)&(filter->string));
|
|
|
|
slapi_ch_free((void **)&(filter->attributes));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (regcomp(filter->regex, filter->string, REG_EXTENDED|REG_NOSUB))
|
|
|
|
{
|
|
|
|
slapi_ch_free((void **)&(filter->attributes));
|
|
|
|
slapi_ch_free((void **)&(filter->string));
|
|
|
|
free_attributes(filter->attrs);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static INLINE int
|
|
|
|
loop_ber_values(Slapi_PBlock *pb, Rex_Filter *filter, BerVal **bvals,
|
|
|
|
char *type)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
|
|
|
|
while (*bvals)
|
|
|
|
{
|
|
|
|
res = regexec(filter->regex, (*bvals)->bv_val, (size_t) 0, NULL, 0);
|
|
|
|
if ((!res && !filter->match) || (res && filter->match))
|
|
|
|
{
|
|
|
|
slapi_log_error(LOG_FACILITY, PLUGIN_NAME,
|
|
|
|
"Violation: %s /%s/ on '%s: %s'\n",
|
|
|
|
filter->match ? "require" : "refuse",
|
|
|
|
filter->string, type, (*bvals)->bv_val);
|
|
|
|
slapi_send_ldap_result(pb, LDAP_CONSTRAINT_VIOLATION, NULL,
|
|
|
|
filter->match ? ERR_NOMATCH : ERR_MATCH, 0,
|
|
|
|
(BerVal **)NULL);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
bvals++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
eval_add_filter(Slapi_PBlock *pb)
|
|
|
|
{
|
|
|
|
Rex_Filter *filter;
|
2000-01-15 01:25:29 +03:00
|
|
|
Plugin_Attrs *attrs;
|
2000-01-12 09:15:45 +03:00
|
|
|
Slapi_Entry *entry;
|
|
|
|
Slapi_Attr *att;
|
|
|
|
BerVal **bvals;
|
|
|
|
|
|
|
|
if (!entry)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &entry) || !entry)
|
|
|
|
{
|
|
|
|
slapi_log_error(LOG_FACILITY, PLUGIN_NAME, ERR_NOENTRY);
|
|
|
|
slapi_send_ldap_result(pb, LDAP_NO_MEMORY, NULL, ERR_NOENTRY, 0,
|
|
|
|
(BerVal **)NULL);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
filter = rex_filter_list;
|
|
|
|
while (filter)
|
|
|
|
{
|
|
|
|
attrs = filter->attrs;
|
|
|
|
while (attrs)
|
|
|
|
{
|
|
|
|
if (!slapi_entry_attr_find(entry, attrs->type, &att))
|
|
|
|
{
|
|
|
|
slapi_attr_get_values(att, &bvals);
|
|
|
|
if (loop_ber_values(pb, filter, bvals, attrs->type))
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
attrs = attrs->next;
|
|
|
|
}
|
|
|
|
filter = filter->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
eval_mod_filter(Slapi_PBlock *pb)
|
|
|
|
{
|
|
|
|
Rex_Filter *filter;
|
|
|
|
LDAPMod **mods, *mod;
|
|
|
|
|
|
|
|
if (!mods)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods) || !mods)
|
|
|
|
{
|
|
|
|
slapi_log_error(LOG_FACILITY, PLUGIN_NAME, ERR_NOMODS);
|
|
|
|
slapi_send_ldap_result(pb, LDAP_NO_MEMORY, NULL, ERR_NOMODS, 0,
|
|
|
|
(BerVal **)NULL);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((mod = *mods))
|
|
|
|
{
|
|
|
|
if (!(mod->mod_op & LDAP_MOD_DELETE))
|
|
|
|
{
|
|
|
|
filter = rex_filter_list;
|
|
|
|
while (filter)
|
|
|
|
{
|
|
|
|
if (list_has_attribute(filter->attrs, mod->mod_type) &&
|
|
|
|
loop_ber_values(pb, filter, mod->mod_bvalues,
|
|
|
|
mod->mod_type))
|
|
|
|
return (-1);
|
|
|
|
filter = filter->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mods++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rex_filter_init(Slapi_PBlock *pb)
|
|
|
|
{
|
|
|
|
char **argv;
|
|
|
|
int argc;
|
|
|
|
Rex_Filter *new, *last;
|
|
|
|
|
|
|
|
if (slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc) ||
|
|
|
|
slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv) || (argc < 3) || !argv)
|
|
|
|
{
|
|
|
|
slapi_log_error(LOG_FACILITY, PLUGIN_NAME,
|
|
|
|
"Can't locate plugin arguments, please panic!\n");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(new = (Rex_Filter *)slapi_ch_malloc(sizeof(Rex_Filter))))
|
|
|
|
{
|
|
|
|
slapi_log_error(LOG_FACILITY, PLUGIN_NAME, ERR_MALLOC);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(new->regex = (regex_t *)slapi_ch_malloc(sizeof(regex_t))))
|
|
|
|
{
|
|
|
|
slapi_log_error(LOG_FACILITY, PLUGIN_NAME, ERR_MALLOC);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
new->next = (Rex_Filter *)NULL;
|
2000-01-15 01:25:29 +03:00
|
|
|
new->attrs = (Plugin_Attrs *)NULL;
|
2000-01-12 09:15:45 +03:00
|
|
|
new->match = (*(argv[1]) == '0' ? 0 : 1);
|
|
|
|
if (!create_filter(new, argv[0], argv[2]) || !new->attrs)
|
|
|
|
{
|
|
|
|
slapi_ch_free((void **)&(new->regex));
|
|
|
|
slapi_ch_free((void **)&new);
|
|
|
|
slapi_log_error(LOG_FACILITY, PLUGIN_NAME,
|
|
|
|
"Can't make filter out of plugin arguments.\n");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((last = rex_filter_list))
|
|
|
|
{
|
|
|
|
while (last && last->next)
|
|
|
|
last = last->next;
|
|
|
|
last->next = new;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
rex_filter_list = new;
|
|
|
|
|
|
|
|
if (rex_num_filters++)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01) ||
|
|
|
|
slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&rex_descript) ||
|
|
|
|
slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODIFY_FN,
|
|
|
|
(void *)&eval_mod_filter)
|
|
|
|
|| slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_ADD_FN,
|
|
|
|
(void *)&eval_add_filter))
|
|
|
|
{
|
|
|
|
slapi_log_error(LOG_FACILITY, PLUGIN_NAME,
|
|
|
|
"Error registering plugin functions.\n");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
slapi_log_error(LOG_FACILITY, PLUGIN_NAME,
|
|
|
|
"plugin loaded\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|