summaryrefslogtreecommitdiffstats
path: root/ldap/servers/plugins/syntaxes
diff options
context:
space:
mode:
authorNathan Kinder <nkinder@redhat.com>2009-05-08 09:14:42 -0700
committerNathan Kinder <nkinder@redhat.com>2009-05-08 09:14:42 -0700
commitd19eafcd211d89cffdac1b2c3432087443e7d122 (patch)
tree26d2b7f956c2ceaa3f605a42552a113e156b5b30 /ldap/servers/plugins/syntaxes
parent5d3d883251dd15cf719181e33fb6954454869822 (diff)
downloadds-d19eafcd211d89cffdac1b2c3432087443e7d122.tar.gz
ds-d19eafcd211d89cffdac1b2c3432087443e7d122.tar.xz
ds-d19eafcd211d89cffdac1b2c3432087443e7d122.zip
Added capability to validate syntax of values being added to the database. Also added numericstring syntax support.
For more details, see the design doc at http://directory.fedoraproject.org/wiki/Syntax_Validation_Design
Diffstat (limited to 'ldap/servers/plugins/syntaxes')
-rw-r--r--ldap/servers/plugins/syntaxes/bin.c6
-rw-r--r--ldap/servers/plugins/syntaxes/ces.c43
-rw-r--r--ldap/servers/plugins/syntaxes/cis.c482
-rw-r--r--ldap/servers/plugins/syntaxes/dn.c215
-rw-r--r--ldap/servers/plugins/syntaxes/int.c56
-rw-r--r--ldap/servers/plugins/syntaxes/numericstring.c188
-rw-r--r--ldap/servers/plugins/syntaxes/sicis.c3
-rw-r--r--ldap/servers/plugins/syntaxes/syntax.h45
-rw-r--r--ldap/servers/plugins/syntaxes/tel.c35
-rw-r--r--ldap/servers/plugins/syntaxes/validate.c352
-rw-r--r--ldap/servers/plugins/syntaxes/validate_task.c303
11 files changed, 1709 insertions, 19 deletions
diff --git a/ldap/servers/plugins/syntaxes/bin.c b/ldap/servers/plugins/syntaxes/bin.c
index 6d6c7632..b7be0d1a 100644
--- a/ldap/servers/plugins/syntaxes/bin.c
+++ b/ldap/servers/plugins/syntaxes/bin.c
@@ -43,8 +43,7 @@
/* bin.c - bin syntax routines */
/*
- * This file actually implements two syntax plugins: OctetString and Binary.
- * We treat them identically for now. XXXmcs: check if that is correct.
+ * This file actually implements three syntax plugins: OctetString, JPEG, and Binary.
*/
#include <stdio.h>
@@ -73,6 +72,9 @@ static char *octetstring_names[] = { "OctetString", OCTETSTRING_SYNTAX_OID, 0 };
static char *jpeg_names[] = { "JPEG", JPEG_SYNTAX_OID, 0 };
+/* This syntax has "gone away" in RFC 4517, however we still use it for
+ * a number of attributes in our default schema. We should try to eliminate
+ * it's use and remove support for it. */
static Slapi_PluginDesc bin_pdesc = {
"bin-syntax", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
"binary attribute syntax plugin"
diff --git a/ldap/servers/plugins/syntaxes/ces.c b/ldap/servers/plugins/syntaxes/ces.c
index a7ffee5a..68b642f0 100644
--- a/ldap/servers/plugins/syntaxes/ces.c
+++ b/ldap/servers/plugins/syntaxes/ces.c
@@ -40,7 +40,9 @@
# include <config.h>
#endif
-/* ces.c - caseexactstring syntax routines */
+/* ces.c - caseexactstring syntax routines. Implements support for:
+ * - IA5String
+ * - URI (DEPRECATED - This is non-standard and isn't used in the default schema.) */
#include <stdio.h>
#include <string.h>
@@ -58,6 +60,7 @@ static int ces_assertion2keys_ava( Slapi_PBlock *pb, Slapi_Value *val,
static int ces_assertion2keys_sub( Slapi_PBlock *pb, char *initial, char **any,
char *final, Slapi_Value ***ivals );
static int ces_compare(struct berval *v1, struct berval *v2);
+static int ia5_validate(struct berval *val);
/* the first name is the official one from RFC 2252 */
static char *ia5_names[] = { "IA5String", "ces", "caseexactstring",
@@ -78,7 +81,7 @@ static Slapi_PluginDesc uri_pdesc = { "uri-syntax", PLUGIN_MAGIC_VENDOR_STR,
*/
static int
register_ces_like_plugin( Slapi_PBlock *pb, Slapi_PluginDesc *pdescp,
- char **names, char *oid )
+ char **names, char *oid, void *validate_fn )
{
int rc, flags;
@@ -105,6 +108,10 @@ register_ces_like_plugin( Slapi_PBlock *pb, Slapi_PluginDesc *pdescp,
(void *) oid );
rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_COMPARE,
(void *) ces_compare );
+ if (validate_fn != NULL) {
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALIDATE,
+ (void *)validate_fn );
+ }
return( rc );
}
@@ -116,7 +123,7 @@ ces_init( Slapi_PBlock *pb )
LDAPDebug( LDAP_DEBUG_PLUGIN, "=> ces_init\n", 0, 0, 0 );
- rc = register_ces_like_plugin(pb,&ia5_pdesc,ia5_names,IA5STRING_SYNTAX_OID);
+ rc = register_ces_like_plugin(pb,&ia5_pdesc,ia5_names,IA5STRING_SYNTAX_OID, ia5_validate);
LDAPDebug( LDAP_DEBUG_PLUGIN, "<= ces_init %d\n", rc, 0, 0 );
return( rc );
@@ -130,7 +137,7 @@ uri_init( Slapi_PBlock *pb )
LDAPDebug( LDAP_DEBUG_PLUGIN, "=> uri_init\n", 0, 0, 0 );
rc = register_ces_like_plugin(pb,&uri_pdesc,uri_names,
- "1.3.6.1.4.1.4401.1.1.1");
+ "1.3.6.1.4.1.4401.1.1.1", NULL);
LDAPDebug( LDAP_DEBUG_PLUGIN, "<= uri_init %d\n", rc, 0, 0 );
return( rc );
@@ -203,3 +210,31 @@ static int ces_compare(
{
return value_cmp(v1,v2,SYNTAX_CES,3 /* Normalise both values */);
}
+
+static int
+ia5_validate(
+ struct berval *val
+)
+{
+ int rc = 0; /* assume the value is valid */
+ int i = 0;
+
+ if (val == NULL) {
+ rc = 1;
+ goto exit;
+ }
+
+ /* Per RFC 4517:
+ *
+ * IA5String = *(%x00-7F)
+ */
+ for (i=0; i < val->bv_len; i++) {
+ if (!IS_UTF1(val->bv_val[i])) {
+ rc = 1;
+ goto exit;
+ }
+ }
+
+exit:
+ return rc;
+}
diff --git a/ldap/servers/plugins/syntaxes/cis.c b/ldap/servers/plugins/syntaxes/cis.c
index 20b990dc..f20ae5eb 100644
--- a/ldap/servers/plugins/syntaxes/cis.c
+++ b/ldap/servers/plugins/syntaxes/cis.c
@@ -43,13 +43,15 @@
/* cis.c - caseignorestring syntax routines */
/*
- * This file actually implements three syntax plugins:
- * DirectoryString
+ * This file actually implements numerous syntax plugins:
+ *
* Boolean
+ * CountryString
+ * DirectoryString
* GeneralizedTime
+ * OID
+ * PostalAddress
*
- * We treat them identically for now. XXXmcs: we could do some validation on
- * Boolean and GeneralizedTime values (someday, maybe).
*/
#include <stdio.h>
@@ -68,6 +70,12 @@ static int cis_assertion2keys_ava( Slapi_PBlock *pb, Slapi_Value *val,
static int cis_assertion2keys_sub( Slapi_PBlock *pb, char *initial, char **any,
char *final, Slapi_Value ***ivals );
static int cis_compare(struct berval *v1, struct berval *v2);
+static int dirstring_validate(struct berval *val);
+static int boolean_validate(struct berval *val);
+static int time_validate(struct berval *val);
+static int country_validate(struct berval *val);
+static int postal_validate(struct berval *val);
+static int oid_validate(struct berval *val);
/*
* Attribute syntaxes. We treat all of these the same for now, even though
@@ -170,7 +178,7 @@ static Slapi_PluginDesc oid_pdesc = { "oid-syntax",
*/
static int
register_cis_like_plugin( Slapi_PBlock *pb, Slapi_PluginDesc *pdescp,
- char **names, char *oid )
+ char **names, char *oid, void *validate_fn )
{
int rc, flags;
@@ -197,11 +205,14 @@ register_cis_like_plugin( Slapi_PBlock *pb, Slapi_PluginDesc *pdescp,
(void *) oid );
rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_COMPARE,
(void *) cis_compare );
+ if (validate_fn != NULL) {
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALIDATE,
+ (void *)validate_fn );
+ }
return( rc );
}
-
int
cis_init( Slapi_PBlock *pb )
{
@@ -209,7 +220,7 @@ cis_init( Slapi_PBlock *pb )
LDAPDebug( LDAP_DEBUG_PLUGIN, "=> cis_init\n", 0, 0, 0 );
rc = register_cis_like_plugin( pb, &dirstring_pdesc, dirstring_names,
- DIRSTRING_SYNTAX_OID );
+ DIRSTRING_SYNTAX_OID, dirstring_validate );
LDAPDebug( LDAP_DEBUG_PLUGIN, "<= cis_init %d\n", rc, 0, 0 );
return( rc );
}
@@ -222,12 +233,11 @@ boolean_init( Slapi_PBlock *pb )
LDAPDebug( LDAP_DEBUG_PLUGIN, "=> boolean_init\n", 0, 0, 0 );
rc = register_cis_like_plugin( pb, &boolean_pdesc, boolean_names,
- BOOLEAN_SYNTAX_OID );
+ BOOLEAN_SYNTAX_OID, boolean_validate );
LDAPDebug( LDAP_DEBUG_PLUGIN, "<= boolean_init %d\n", rc, 0, 0 );
return( rc );
}
-
int
time_init( Slapi_PBlock *pb )
{
@@ -235,7 +245,7 @@ time_init( Slapi_PBlock *pb )
LDAPDebug( LDAP_DEBUG_PLUGIN, "=> time_init\n", 0, 0, 0 );
rc = register_cis_like_plugin( pb, &time_pdesc, time_names,
- GENERALIZEDTIME_SYNTAX_OID );
+ GENERALIZEDTIME_SYNTAX_OID, time_validate );
/* also register this plugin for matching rules */
rc |= slapi_matchingrule_register(&generalizedTimeMatch);
rc |= slapi_matchingrule_register(&generalizedTimeOrderingMatch);
@@ -250,7 +260,7 @@ country_init( Slapi_PBlock *pb )
LDAPDebug( LDAP_DEBUG_PLUGIN, "=> country_init\n", 0, 0, 0 );
rc = register_cis_like_plugin( pb, &country_pdesc, country_names,
- COUNTRYSTRING_SYNTAX_OID );
+ COUNTRYSTRING_SYNTAX_OID, country_validate );
LDAPDebug( LDAP_DEBUG_PLUGIN, "<= country_init %d\n", rc, 0, 0 );
return( rc );
}
@@ -262,7 +272,7 @@ postal_init( Slapi_PBlock *pb )
LDAPDebug( LDAP_DEBUG_PLUGIN, "=> postal_init\n", 0, 0, 0 );
rc = register_cis_like_plugin( pb, &postal_pdesc, postal_names,
- POSTALADDRESS_SYNTAX_OID );
+ POSTALADDRESS_SYNTAX_OID, postal_validate );
LDAPDebug( LDAP_DEBUG_PLUGIN, "<= postal_init %d\n", rc, 0, 0 );
return( rc );
}
@@ -274,7 +284,7 @@ oid_init( Slapi_PBlock *pb )
int rc;
LDAPDebug( LDAP_DEBUG_PLUGIN, "=> oid_init\n", 0, 0, 0 );
- rc = register_cis_like_plugin( pb, &oid_pdesc, oid_names, OID_SYNTAX_OID );
+ rc = register_cis_like_plugin( pb, &oid_pdesc, oid_names, OID_SYNTAX_OID, oid_validate );
LDAPDebug( LDAP_DEBUG_PLUGIN, "<= oid_init %d\n", rc, 0, 0 );
return( rc );
}
@@ -349,3 +359,449 @@ static int cis_compare(
{
return value_cmp(v1,v2,SYNTAX_CIS,3 /* Normalise both values */);
}
+
+static int dirstring_validate(
+ struct berval *val
+)
+{
+ int rc = 0; /* assume the value is valid */
+ char *p = NULL;
+ char *end = NULL;
+
+ /* Per RFC4517:
+ *
+ * DirectoryString = 1*UTF8
+ */
+ if ((val != NULL) && (val->bv_len > 0)) {
+ p = val->bv_val;
+ end = &(val->bv_val[val->bv_len - 1]);
+ rc = utf8string_validate(p, end, NULL);
+ } else {
+ rc = 1;
+ goto exit;
+ }
+
+exit:
+ return( rc );
+}
+
+static int boolean_validate(
+ struct berval *val
+)
+{
+ int rc = 0; /* assume the value is valid */
+
+ /* Per RFC4517:
+ *
+ * Boolean = "TRUE" / "FALSE"
+ */
+ if (val != NULL) {
+ if (val->bv_len == 4) {
+ if (strncmp(val->bv_val, "TRUE", 4) != 0) {
+ rc = 1;
+ goto exit;
+ }
+ } else if (val->bv_len == 5) {
+ if (strncmp(val->bv_val, "FALSE", 5) != 0) {
+ rc = 1;
+ goto exit;
+ }
+ } else {
+ rc = 1;
+ goto exit;
+ }
+ } else {
+ rc = 1;
+ }
+
+exit:
+ return(rc);
+}
+
+static int time_validate(
+ struct berval *val
+)
+{
+ int rc = 0; /* assume the value is valid */
+ int i = 0;
+ const char *p = NULL;
+ char *end = NULL;
+
+ /* Per RFC4517:
+ *
+ * GeneralizedTime = century year month day hour
+ * [ minute [ second / leap-second ] ]
+ * [ fraction ]
+ * g-time-zone
+ *
+ * century = 2(%x30-39) ; "00" to "99"
+ * year = 2(%x30-39) ; "00" to "99"
+ * month = ( %x30 %x31-39 ) ; "01" (January) to "09"
+ * / ( %x31 %x30-32 ) ; "10 to "12"
+ * day = ( %x30 %x31-39 ) ; "01" to "09"
+ * / ( %x31-x32 %x30-39 ) ; "10" to "29"
+ * / ( %x33 %x30-31 ) ; "30" to "31"
+ * hour = ( %x30-31 %x30-39 ) / ( %x32 %x30-33 ) ; "00" to "23"
+ * minute = %x30-35 %x30-39 ; "00" to "59"
+ *
+ * second = ( %x30-35 - %x30-39 ) ; "00" to "59"
+ * leap-second = ( %x36 %x30 ) ; "60"
+ *
+ * fraction = ( DOT / COMMA ) 1*(%x30-39)
+ * g-time-zone = %x5A ; "Z"
+ * / g-differential
+ * g-differential = ( MINUS / PLUS ) hour [ minute ]
+ */
+ if (val != NULL) {
+ /* A valid GeneralizedTime should be at least 11 characters. There
+ * is no upper bound due to the variable length of "fraction". */
+ if (val->bv_len < 11) {
+ rc = 1;
+ goto exit;
+ }
+
+ /* We're guaranteed that the value is at least 11 characters, so we
+ * don't need to bother checking if we're at the end of the value
+ * until we start processing the "minute" part of the value. */
+ p = val->bv_val;
+ end = &(val->bv_val[val->bv_len - 1]);
+
+ /* Process "century year". First 4 characters can be any valid digit. */
+ for (i=0; i<4; i++) {
+ if (!isdigit(*p)) {
+ rc = 1;
+ goto exit;
+ }
+ p++;
+ }
+
+ /* Process "month". Next character can be "0" or "1". */
+ if (*p == '0') {
+ p++;
+ /* any LDIGIT is valid now */
+ if (!IS_LDIGIT(*p)) {
+ rc = 1;
+ goto exit;
+ }
+ p++;
+ } else if (*p == '1') {
+ p++;
+ /* only "0"-"2" are valid now */
+ if ((*p < '0') || (*p > '2')) {
+ rc = 1;
+ goto exit;
+ }
+ p++;
+ } else {
+ rc = 1;
+ goto exit;
+ }
+
+ /* Process "day". Next character can be "0"-"3". */
+ if (*p == '0') {
+ p++;
+ /* any LDIGIT is valid now */
+ if (!IS_LDIGIT(*p)) {
+ rc = 1;
+ goto exit;
+ }
+ p++;
+ } else if ((*p == '1') || (*p == '2')) {
+ p++;
+ /* any digit is valid now */
+ if (!isdigit(*p)) {
+ rc = 1;
+ goto exit;
+ }
+ p++;
+ } else if (*p == '3') {
+ p++;
+ /* only "0"-"1" are valid now */
+ if ((*p != '0') && (*p != '1')) {
+ rc = 1;
+ goto exit;
+ }
+ p++;
+ } else {
+ rc = 1;
+ goto exit;
+ }
+
+ /* Process "hour". Next character can be "0"-"2". */
+ if ((*p == '0') || (*p == '1')) {
+ p++;
+ /* any digit is valid now */
+ if (!isdigit(*p)) {
+ rc = 1;
+ goto exit;
+ }
+ p++;
+ } else if (*p == '2') {
+ p++;
+ /* only "0"-"3" are valid now */
+ if ((*p < '0') || (*p > '3')) {
+ rc = 1;
+ goto exit;
+ }
+ p++;
+ } else {
+ rc = 1;
+ goto exit;
+ }
+
+ /* Time for the optional stuff. We know we have at least one character here, but
+ * we need to start checking for the end of the string afterwards.
+ *
+ * See if a "minute" was specified. */
+ if ((*p >= '0') && (*p <= '5')) {
+ p++;
+ /* any digit is valid for the second char of a minute */
+ if ((p > end) || (!isdigit(*p))) {
+ rc = 1;
+ goto exit;
+ }
+ p++;
+
+ /* At this point, there has to at least be a "g-time-zone" left.
+ * Make sure we're not at the end of the string. */
+ if (p > end) {
+ rc = 1;
+ goto exit;
+ }
+
+ /* See if a "second" or "leap-second" was specified. */
+ if ((*p >= '0') && (*p <= '5')) {
+ p++;
+ /* any digit is valid now */
+ if ((p > end) || (!isdigit(*p))) {
+ rc = 1;
+ goto exit;
+ }
+ p++;
+ } else if (*p == '6') {
+ p++;
+ /* only a '0' is valid now */
+ if ((p > end) || (*p != '0')) {
+ rc = 1;
+ goto exit;
+ }
+ p++;
+ }
+
+ /* At this point, there has to at least be a "g-time-zone" left.
+ * Make sure we're not at the end of the string. */
+ if (p > end) {
+ rc = 1;
+ goto exit;
+ }
+ }
+
+ /* See if a fraction was specified. */
+ if ((*p == '.') || (*p == ',')) {
+ p++;
+ /* An arbitrary length string of digit chars is allowed here.
+ * Ensure we have at least one digit character. */
+ if ((p >= end) || (!isdigit(*p))) {
+ rc = 1;
+ goto exit;
+ }
+
+ /* Just loop through the rest of the fraction until we encounter a non-digit */
+ p++;
+ while ((p < end) && (isdigit(*p))) {
+ p++;
+ }
+ }
+
+ /* Process "g-time-zone". We either end with 'Z', or have a differential. */
+ if (p == end) {
+ if (*p != 'Z') {
+ rc = 1;
+ goto exit;
+ }
+ } else if (p < end) {
+ if ((*p != '-') && (*p != '+')) {
+ rc = 1;
+ goto exit;
+ } else {
+ /* A "g-differential" was specified. An "hour" must be present now. */
+ p++;
+ if ((*p == '0') || (*p == '1')) {
+ p++;
+ /* any digit is valid now */
+ if ((p > end) || !isdigit(*p)) {
+ rc = 1;
+ goto exit;
+ }
+ p++;
+ } else if (*p == '2') {
+ p++;
+ /* only "0"-"3" are valid now */
+ if ((p > end) || (*p < '0') || (*p > '3')) {
+ rc = 1;
+ goto exit;
+ }
+ p++;
+ } else {
+ rc = 1;
+ goto exit;
+ }
+
+ /* See if an optional minute is present ("00"-"59"). */
+ if (p <= end) {
+ /* "0"-"5" are valid now */
+ if ((*p < '0') || (*p > '5')) {
+ rc = 1;
+ goto exit;
+ }
+ p++;
+
+ /* We should be at the last character of the string
+ * now, which must be a valid digit. */
+ if ((p != end) || !isdigit(*p)) {
+ rc = 1;
+ goto exit;
+ }
+ }
+ }
+ } else {
+ /* Premature end of string */
+ rc = 1;
+ goto exit;
+ }
+ } else {
+ rc = 1;
+ goto exit;
+ }
+
+exit:
+ return( rc );
+}
+
+static int country_validate(
+ struct berval *val
+)
+{
+ int rc = 0; /* assume the value is valid */
+
+ /* Per RFC4517:
+ *
+ * CountryString = 2(PrintableCharacter)
+ */
+ if (val != NULL) {
+ if ((val->bv_len != 2) || !IS_PRINTABLE(val->bv_val[0]) || !IS_PRINTABLE(val->bv_val[1])) {
+ rc = 1;
+ goto exit;
+ }
+
+
+ } else {
+ rc = 1;
+ }
+
+exit:
+ return(rc);
+}
+
+static int postal_validate(
+ struct berval *val
+)
+{
+ int rc = 0; /* assume the value is valid */
+ const char *p = NULL;
+ const char *start = NULL;
+ char *end = NULL;
+
+ /* Per RFC4517:
+ * PostalAddress = line *( DOLLAR line )
+ * line = 1*line-char
+ * line-char = %x00-23
+ * / (%x5C "24") ; escaped "$"
+ * / %x25-5B
+ * / (%x5C "5C") ; escaped "\"
+ * / %x5D-7F
+ * / UTFMB
+ */
+ if (val != NULL) {
+ start = val->bv_val;
+ end = &(val->bv_val[val->bv_len - 1]);
+ for (p = start; p <= end; p++) {
+ /* look for a '\' and make sure it's only used to escape a '$' or a '\' */
+ if (*p == '\\') {
+ p++;
+ /* ensure that we're not at the end of the value */
+ if ((p > end) || (strncmp(p, "24", 2) != 0) && (strncasecmp(p, "5C", 2) != 0)) {
+ rc = 1;
+ goto exit;
+ } else {
+ /* advance the pointer to point to the end
+ * of the hex code for the escaped character */
+ p++;
+ }
+ } else if (*p == '$') {
+ /* This signifies the end of a line. We need
+ * to ensure that the line is not empty. */
+ if (p == start) {
+ rc = 1;
+ goto exit;
+ }
+
+ /* make sure the value doesn't end with a '$' */
+ if (p == end) {
+ rc = 1;
+ goto exit;
+ }
+
+ /* Make sure the line (start to p) is valid UTF-8. */
+ if ((rc = utf8string_validate(start, p, NULL)) != 0) {
+ goto exit;
+ }
+
+ /* make the start pointer point to the
+ * beginning of the next line */
+ start = p + 1;
+ }
+ }
+ } else {
+ rc = 1;
+ }
+
+exit:
+ return(rc);
+}
+
+static int oid_validate(
+ struct berval *val
+)
+{
+ int rc = 0; /* assume the value is valid */
+ const char *p = NULL;
+ char *end = NULL;
+
+ /* Per RFC4512:
+ *
+ * oid = descr / numericoid
+ * descr = keystring
+ */
+ if ((val != NULL) && (val->bv_len > 0)) {
+ p = val->bv_val;
+ end = &(val->bv_val[val->bv_len - 1]);
+
+ /* check if the value matches the descr form */
+ if (IS_LEADKEYCHAR(*p)) {
+ rc = keystring_validate(p, end);
+ /* check if the value matches the numericoid form */
+ } else if (isdigit(*p)) {
+ rc = numericoid_validate(p, end);
+ } else {
+ rc = 1;
+ goto exit;
+ }
+ } else {
+ rc = 1;
+ }
+
+exit:
+ return( rc );
+}
+
diff --git a/ldap/servers/plugins/syntaxes/dn.c b/ldap/servers/plugins/syntaxes/dn.c
index c7d34758..a6dcceda 100644
--- a/ldap/servers/plugins/syntaxes/dn.c
+++ b/ldap/servers/plugins/syntaxes/dn.c
@@ -57,6 +57,8 @@ static int dn_assertion2keys_ava( Slapi_PBlock *pb, Slapi_Value *val,
Slapi_Value ***ivals, int ftype );
static int dn_assertion2keys_sub( Slapi_PBlock *pb, char *initial, char **any,
char *final, Slapi_Value ***ivals );
+static int dn_validate( struct berval *val );
+static int rdn_validate( char *begin, char *end, char **last );
/* the first name is the official one from RFC 2252 */
static char *names[] = { "DN", DN_SYNTAX_OID, 0 };
@@ -89,6 +91,8 @@ dn_init( Slapi_PBlock *pb )
(void *) names );
rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_OID,
(void *) DN_SYNTAX_OID );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALIDATE,
+ (void *) dn_validate );
LDAPDebug( LDAP_DEBUG_PLUGIN, "<= dn_init %d\n", rc, 0, 0 );
return( rc );
@@ -133,3 +137,214 @@ dn_assertion2keys_sub( Slapi_PBlock *pb, char *initial, char **any, char *final,
return( string_assertion2keys_sub( pb, initial, any, final, ivals,
SYNTAX_CIS | SYNTAX_DN ) );
}
+
+static int dn_validate( struct berval *val )
+{
+ int rc = 0; /* Assume value is valid */
+
+ if (val != NULL) {
+ /* Per RFC 4514:
+ *
+ * distinguishedName = [ relativeDistinguishedName
+ * *( COMMA relativeDistinguishedName ) ]
+ * relativeDistinguishedName = attributeTypeAndValue
+ * *( PLUS attributeTypeAndValue )
+ * attributeTypeAndValue = attribyteType EQUALS attributeValue
+ * attributeType = descr / numericoid
+ * attributeValue = string / hexstring
+ */
+ if (val->bv_len > 0) {
+ char *p = val->bv_val;
+ char *end = &(val->bv_val[val->bv_len - 1]);
+ char *last = NULL;
+
+ /* Validate one RDN at a time in a loop. */
+ while (p <= end) {
+ if ((rc = rdn_validate(p, end, &last)) != 0) {
+ goto exit;
+ }
+ p = last + 1;
+
+ /* p should be pointing at a comma, or one past
+ * the end of the entire dn value. If we have
+ * not reached the end, ensure that the next
+ * character is a comma and that there is at
+ * least another character after the comma. */
+ if ((p <= end) && ((p == end) || (*p != ','))) {
+ rc = 1;
+ goto exit;
+ }
+
+ /* Advance the pointer past the comma so it
+ * points at the beginning of the next RDN
+ * (if there is one). */
+ p++;
+ }
+ }
+ } else {
+ rc = 1;
+ goto exit;
+ }
+exit:
+ return rc;
+}
+
+/*
+ * Helper function for validating a DN. This function will validate
+ * a single RDN. If the RDN is valid, 0 will be returned, otherwise
+ * non-zero will be returned. A pointer to the last character processed
+ * will be set in the "last parameter. This will be the end of the RDN
+ * in the valid case, and the illegal character in the invalid case.
+ */
+static int rdn_validate( char *begin, char *end, char **last )
+{
+ int rc = 0; /* Assume RDN is valid */
+ int numericform = 0;
+ char *separator = NULL;
+ char *p = begin;
+
+ /* Find the '=', then use the helpers for descr and numericoid */
+ if ((separator = PL_strnchr(p, '=', end - begin + 1)) == NULL) {
+ rc = 1;
+ goto exit;
+ }
+
+ /* Process an attribute type. The 'descr'
+ * form must start with a 'leadkeychar'. */
+ if (IS_LEADKEYCHAR(*p)) {
+ if (rc = keystring_validate(p, separator - 1)) {
+ goto exit;
+ }
+ /* See if the 'numericoid' form is being used */
+ } else if (isdigit(*p)) {
+ numericform = 1;
+ if (rc = numericoid_validate(p, separator - 1)) {
+ goto exit;
+ }
+ } else {
+ rc = 1;
+ goto exit;
+ }
+
+ /* Advance the pointer past the '=' and make sure
+ * we're not past the end of the string. */
+ p = separator + 1;
+ if (p > end) {
+ rc = 1;
+ goto exit;
+ }
+
+ /* The value must be a 'hexstring' if the 'numericoid'
+ * form of 'attributeType' is used. Per RFC 4514:
+ *
+ * hexstring = SHARP 1*hexpair
+ * hexpair = HEX HEX
+ */
+ if (numericform) {
+ if ((p == end) || !IS_SHARP(*p)) {
+ rc = 1;
+ goto exit;
+ }
+ p++;
+ /* The value must be a 'string' when the 'descr' form
+ * of 'attributeType' is used. Per RFC 4514:
+ *
+ * string = [ ( leadchar / pair ) [ *( stringchar / pair )
+ * ( trailchar / pair ) ] ]
+ *
+ * leadchar = LUTF1 / UTFMB
+ * trailchar = TUTF1 / UTFMB
+ * stringchar = SUTF1 / UTFMB
+ *
+ * pair = ESC (ESC / special / hexpair )
+ * special = escaped / SPACE / SHARP / EQUALS
+ * escaped = DQUOTE / PLUS / COMMA / SEMI / LANGLE / RANGLE
+ * hexpair = HEX HEX
+ */
+ } else {
+ /* Check the leadchar to see if anything illegal
+ * is there. We need to allow a 'pair' to get
+ * through, so we'll assume that a '\' is the
+ * start of a 'pair' for now. */
+ if (IS_UTF1(*p) && !IS_ESC(*p) && !IS_LUTF1(*p)) {
+ rc = 1;
+ goto exit;
+ }
+ }
+
+ /* Loop through string until we find the ',' separator, a '+'
+ * char indicating a multi-value RDN, or we reach the end. */
+ while ((p <= end) && (*p != ',') && (*p != '+')) {
+ if (numericform) {
+ /* Process a single 'hexpair' */
+ if ((p == end) || !isxdigit(*p) || !isxdigit(*p + 1)) {
+ rc = 1;
+ goto exit;
+ }
+ p = p + 2;
+ } else {
+ /* Check for a valid 'stringchar'. We handle
+ * multi-byte characters separately. */
+ if (IS_UTF1(*p)) {
+ /* If we're at the end, check if we have
+ * a valid 'trailchar'. */
+ if ((p == end) && !IS_TUTF1(*p)) {
+ rc = 1;
+ goto exit;
+ /* Check for a 'pair'. */
+ } else if (IS_ESC(*p)) {
+ /* We're guaranteed to still have at
+ * least one more character, so lets
+ * take a look at it. */
+ p++;
+ if (!IS_ESC(*p) && !IS_SPECIAL(*p)) {
+ /* The only thing valid now
+ * is a 'hexpair'. */
+ if ((p == end) || !isxdigit(*p) ||!isxdigit(*p + 1)) {
+ rc = 1;
+ goto exit;
+ }
+ p++;
+ }
+ p++;
+ /* Only allow 'SUTF1' chars now. */
+ } else if (!IS_SUTF1(*p)) {
+ rc = 1;
+ goto exit;
+ }
+
+ p++;
+ } else {
+ /* Validate a single 'UTFMB' (multi-byte) character. */
+ if (utf8char_validate(p, end, &p ) != 0) {
+ rc = 1;
+ goto exit;
+ }
+
+ /* Advance the pointer past the multi-byte char. */
+ p++;
+ }
+ }
+ }
+
+ /* We'll end up either at the comma, a '+', or one past end.
+ * If we are processing a multi-valued RDN, we recurse to
+ * process the next 'attributeTypeAndValue'. */
+ if ((p <= end) && (*p == '+')) {
+ /* Make sure that there is something after the '+'. */
+ if (p == end) {
+ rc = 1;
+ goto exit;
+ }
+ p++;
+
+ /* Recurse to process the next value. We need to reset p to
+ * ensure that last is set correctly for the original caller. */
+ rc = rdn_validate( p, end, last );
+ p = *last + 1;
+ }
+
+exit:
+ *last = p - 1;
+ return rc;
+}
diff --git a/ldap/servers/plugins/syntaxes/int.c b/ldap/servers/plugins/syntaxes/int.c
index 73c879a7..0372d3a6 100644
--- a/ldap/servers/plugins/syntaxes/int.c
+++ b/ldap/servers/plugins/syntaxes/int.c
@@ -54,6 +54,7 @@ static int int_values2keys( Slapi_PBlock *pb, Slapi_Value **val,
static int int_assertion2keys( Slapi_PBlock *pb, Slapi_Value *val,
Slapi_Value ***ivals, int ftype );
static int int_compare(struct berval *v1, struct berval *v2);
+static int int_validate(struct berval *val);
/* the first name is the official one from RFC 2252 */
static char *names[] = { "INTEGER", "int", INTEGER_SYNTAX_OID, 0 };
@@ -101,6 +102,8 @@ int_init( Slapi_PBlock *pb )
(void *) INTEGER_SYNTAX_OID );
rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_COMPARE,
(void *) int_compare );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALIDATE,
+ (void *) int_validate );
/* also register this plugin for matching rules */
rc |= slapi_matchingrule_register(&integerMatch);
@@ -139,3 +142,56 @@ static int int_compare(
{
return value_cmp(v1, v2, SYNTAX_INT|SYNTAX_CES, 3 /* Normalise both values */);
}
+
+/* return 0 if valid, non-0 if invalid */
+static int int_validate(
+ struct berval *val
+)
+{
+ int rc = 0; /* assume the value is valid */
+ char *p = NULL;
+ char *end = NULL;
+
+ /* Per RFC4517:
+ *
+ * Integer = (HYPHEN LDIGIT *DIGIT) / number
+ * number = DIGIT / (LDIGIT 1*DIGIT)
+ */
+ if ((val != NULL) && (val->bv_len > 0)) {
+ p = val->bv_val;
+ end = &(val->bv_val[val->bv_len - 1]);
+
+ /* If the first character is HYPHEN, we need
+ * to make sure the next char is a LDIGIT. */
+ if (*p == '-') {
+ p++;
+ if ((p > end) || !IS_LDIGIT(*p)) {
+ rc = 1;
+ goto exit;
+ }
+ p++;
+ } else if (*p == '0') {
+ /* 0 is allowed by itself, but not as
+ * a leading 0 before other digits */
+ if (p != end) {
+ rc = 1;
+ }
+
+ /* We're done here */
+ goto exit;
+ }
+
+ /* Now we can simply allow the rest to be DIGIT */
+ for (; p <= end; p++) {
+ if (!isdigit(*p)) {
+ rc = 1;
+ goto exit;
+ }
+ }
+ } else {
+ rc = 1;
+ }
+
+exit:
+ return(rc);
+}
diff --git a/ldap/servers/plugins/syntaxes/numericstring.c b/ldap/servers/plugins/syntaxes/numericstring.c
new file mode 100644
index 00000000..180f8f7d
--- /dev/null
+++ b/ldap/servers/plugins/syntaxes/numericstring.c
@@ -0,0 +1,188 @@
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2009 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* numericstring.c - Numeric String syntax routines */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "syntax.h"
+
+static int numstr_filter_ava( Slapi_PBlock *pb, struct berval *bvfilter,
+ Slapi_Value **bvals, int ftype, Slapi_Value **retVal );
+static int numstr_values2keys( Slapi_PBlock *pb, Slapi_Value **val,
+ Slapi_Value ***ivals, int ftype );
+static int numstr_assertion2keys( Slapi_PBlock *pb, Slapi_Value *val,
+ Slapi_Value ***ivals, int ftype );
+static int numstr_compare(struct berval *v1, struct berval *v2);
+static int numstr_validate(struct berval *val);
+
+/* the first name is the official one from RFC 4517 */
+static char *names[] = { "Numeric String", "numstr", NUMERICSTRING_SYNTAX_OID, 0 };
+
+#define NUMERICSTRINGMATCH_OID "2.5.13.8"
+#define NUMERICSTRINGORDERINGMATCH_OID "2.5.13.9"
+#define NUMERICSTRINGSUBSTRINGMATCH_OID "2.5.13.10"
+
+static Slapi_PluginDesc pdesc = { "numstr-syntax", PLUGIN_MAGIC_VENDOR_STR,
+ PRODUCTTEXT, "numeric string attribute syntax plugin" };
+
+static Slapi_MatchingRuleEntry
+numericStringMatch = { NUMERICSTRINGMATCH_OID, NULL /* no alias? */,
+ "numericStringMatch", "The rule evaluates to TRUE if and only if the prepared "
+ "attribute value character string and the prepared assertion value character "
+ "string have the same number of characters and corresponding characters have "
+ "the same code point.",
+ NUMERICSTRING_SYNTAX_OID, 0 /* not obsolete */ };
+
+static Slapi_MatchingRuleEntry
+numericStringOrderingMatch = { NUMERICSTRINGORDERINGMATCH_OID, NULL /* no alias? */,
+ "numericStringOrderingMatch", "The rule evaluates to TRUE if and only if, "
+ "in the code point collation order, the prepared attribute value character "
+ "string appears earlier than the prepared assertion value character string; "
+ "i.e., the attribute value is less than the assertion value.",
+ NUMERICSTRING_SYNTAX_OID, 0 /* not obsolete */ };
+
+static Slapi_MatchingRuleEntry
+numericStringSubstringMatch = { NUMERICSTRINGSUBSTRINGMATCH_OID, NULL /* no alias? */,
+ "numericStringSubstringMatch", "The rule evaluates to TRUE if and only if (1) "
+ "the prepared substrings of the assertion value match disjoint portions of "
+ "the prepared attribute value, (2) an initial substring, if present, matches "
+ "the beginning of the prepared attribute value character string, and (3) a "
+ "final substring, if present, matches the end of the prepared attribute value "
+ "character string.",
+ NUMERICSTRING_SYNTAX_OID, 0 /* not obsolete */ };
+
+int
+numstr_init( Slapi_PBlock *pb )
+{
+ int rc, flags;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "=> numstr_init\n", 0, 0, 0 );
+
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ (void *) SLAPI_PLUGIN_VERSION_01 );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&pdesc );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FILTER_AVA,
+ (void *) numstr_filter_ava );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALUES2KEYS,
+ (void *) numstr_values2keys );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_AVA,
+ (void *) numstr_assertion2keys );
+ flags = SLAPI_PLUGIN_SYNTAX_FLAG_ORDERING;
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FLAGS,
+ (void *) &flags );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_NAMES,
+ (void *) names );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_OID,
+ (void *) INTEGER_SYNTAX_OID );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_COMPARE,
+ (void *) numstr_compare );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALIDATE,
+ (void *) numstr_validate );
+
+ /* also register this plugin for matching rules */
+ rc |= slapi_matchingrule_register(&numericStringMatch);
+ rc |= slapi_matchingrule_register(&numericStringOrderingMatch);
+ rc |= slapi_matchingrule_register(&numericStringSubstringMatch);
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<= numstr_init %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+static int
+numstr_filter_ava( Slapi_PBlock *pb, struct berval *bvfilter,
+ Slapi_Value **bvals, int ftype, Slapi_Value **retVal )
+{
+ return( string_filter_ava( bvfilter, bvals, SYNTAX_SI | SYNTAX_CES,
+ ftype, retVal ) );
+}
+
+static int
+numstr_values2keys( Slapi_PBlock *pb, Slapi_Value **vals, Slapi_Value ***ivals, int ftype )
+{
+ return( string_values2keys( pb, vals, ivals, SYNTAX_SI | SYNTAX_CES,
+ ftype ) );
+}
+
+static int
+numstr_assertion2keys( Slapi_PBlock *pb, Slapi_Value *val, Slapi_Value ***ivals, int ftype )
+{
+ return(string_assertion2keys_ava( pb, val, ivals,
+ SYNTAX_SI | SYNTAX_CES, ftype ));
+}
+
+static int numstr_compare(
+ struct berval *v1,
+ struct berval *v2
+)
+{
+ return value_cmp(v1, v2, SYNTAX_SI | SYNTAX_CES, 3 /* Normalise both values */);
+}
+
+/* return 0 if valid, non-0 if invalid */
+static int numstr_validate(
+ struct berval *val
+)
+{
+ int rc = 0; /* assume the value is valid */
+ const char *p = NULL;
+
+ /* Per RFC4517:
+ *
+ * NumericString = 1*(DIGIT / SPACE)
+ */
+ if (val != NULL) {
+ for (p = val->bv_val; p < &(val->bv_val[val->bv_len]); p++) {
+ if (!isdigit(*p) && !IS_SPACE(*p)) {
+ rc = 1;
+ goto exit;
+ }
+ }
+ } else {
+ rc = 1;
+ }
+
+exit:
+ return(rc);
+}
diff --git a/ldap/servers/plugins/syntaxes/sicis.c b/ldap/servers/plugins/syntaxes/sicis.c
index fe7188cd..07fee069 100644
--- a/ldap/servers/plugins/syntaxes/sicis.c
+++ b/ldap/servers/plugins/syntaxes/sicis.c
@@ -43,6 +43,9 @@
/*
* sicis.c - space insensitive string syntax routines.
* these strings are also case insensitive.
+ *
+ * This is a non-standard syntax. It is only used by the presence plug-in.
+ * It will be disabled by default unless the presence plug-in is compiled.
*/
#include <stdio.h>
#include <string.h>
diff --git a/ldap/servers/plugins/syntaxes/syntax.h b/ldap/servers/plugins/syntaxes/syntax.h
index fc7a2db9..b9a01370 100644
--- a/ldap/servers/plugins/syntaxes/syntax.h
+++ b/ldap/servers/plugins/syntaxes/syntax.h
@@ -66,6 +66,46 @@
#define MIN( a, b ) (a < b ? a : b )
#endif
+#define SYNTAX_PLUGIN_SUBSYSTEM "syntax-plugin"
+
+/* The following are derived from RFC 4512, section 1.4. */
+#define IS_LEADKEYCHAR(c) ( isalpha(c) )
+#define IS_KEYCHAR(c) ( isalnum(c) || (c == '-') )
+#define IS_SPACE(c) ( (c == ' ') )
+#define IS_LDIGIT(c) ( (c != '0') && isdigit(c) )
+#define IS_SHARP(c) ( (c == '#') )
+#define IS_ESC(c) ( (c == '\\') )
+#define IS_UTF0(c) ( (c >= '\x80') && (c <= '\xBF') )
+#define IS_UTF1(c) ( !(c & 128) )
+/* These are only checking the first byte of the multibyte character. They
+ * do not verify that the entire multibyte character is correct. */
+#define IS_UTF2(c) ( (c >= '\xC2') && (c <= '\xDF') )
+#define IS_UTF3(c) ( (c >= '\xE0') && (c <= '\xEF') )
+#define IS_UTF4(c) ( (c >= '\xF0') && (c <= '\xF4') )
+#define IS_UTFMB(c) ( IS_UTF2(c) || IS_UTF3(c) || IS_UTF4(c) )
+#define IS_UTF8(c) ( IS_UTF1(c) || IS_UTFMB(c) )
+
+/* The following are derived from RFC 4514, section 3. */
+#define IS_ESCAPED(c) ( (c == '"') || (c == '+') || (c == ',') || \
+ (c == ';') || (c == '<') || (c == '>') )
+#define IS_SPECIAL(c) ( IS_ESCAPED(c) || IS_SPACE(c) || \
+ IS_SHARP(c) || (c == '=') )
+#define IS_LUTF1(c) ( IS_UTF1(c) && !IS_ESCAPED(c) && !IS_SPACE(c) && \
+ !IS_SHARP(c) && !IS_ESC(c) )
+#define IS_TUTF1(c) ( IS_UTF1(c) && !IS_ESCAPED(c) && !IS_SPACE(c) && \
+ !IS_ESC(c) )
+#define IS_SUTF1(c) ( IS_UTF1(c) && !IS_ESCAPED(c) && !IS_ESC(c) )
+
+/* Per RFC 4517:
+ *
+ * PrintableCharacter = ALPHA / DIGIT / SQUOTE / LPAREN / RPAREN /
+ * PLUS / COMMA / HYPHEN / DOT / EQUALS /
+ * SLASH / COLON / QUESTION / SPACE
+ */
+#define IS_PRINTABLE(c) ( isalnum(c) || (c == '\'') || (c == '(') || \
+ (c == ')') || (c == '+') || (c == ',') || (c == '-') || (c == '.') || \
+ (c == '=') || (c == '/') || (c == ':') || (c == '?') || IS_SPACE(c) )
+
int string_filter_sub( Slapi_PBlock *pb, char *initial, char **any, char *final,Slapi_Value **bvals, int syntax );
int string_filter_ava( struct berval *bvfilter, Slapi_Value **bvals, int syntax,int ftype, Slapi_Value **retVal );
int string_values2keys( Slapi_PBlock *pb, Slapi_Value **bvals,Slapi_Value ***ivals, int syntax, int ftype );
@@ -78,5 +118,10 @@ char *first_word( char *s );
char *next_word( char *s );
char *phonetic( char *s );
+/* Validation helper functions */
+int keystring_validate( char *begin, char *end );
+int numericoid_validate( char *begin, char *end );
+int utf8char_validate( char *begin, char *end, char **last );
+int utf8string_validate( char *begin, char *end, char **last );
#endif
diff --git a/ldap/servers/plugins/syntaxes/tel.c b/ldap/servers/plugins/syntaxes/tel.c
index b67fb78b..3a2edd68 100644
--- a/ldap/servers/plugins/syntaxes/tel.c
+++ b/ldap/servers/plugins/syntaxes/tel.c
@@ -58,6 +58,7 @@ static int tel_assertion2keys_ava( Slapi_PBlock *pb, Slapi_Value *val,
static int tel_assertion2keys_sub( Slapi_PBlock *pb, char *initial, char **any,
char *final, Slapi_Value ***ivals );
static int tel_compare(struct berval *v1, struct berval *v2);
+static int tel_validate(struct berval *val);
/* the first name is the official one from RFC 2252 */
static char *names[] = { "TelephoneNumber", "tel", TELEPHONE_SYNTAX_OID, 0 };
@@ -95,6 +96,8 @@ tel_init( Slapi_PBlock *pb )
(void *) TELEPHONE_SYNTAX_OID );
rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_COMPARE,
(void *) tel_compare );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALIDATE,
+ (void *) tel_validate );
LDAPDebug( LDAP_DEBUG_PLUGIN, "<= tel_init %d\n", rc, 0, 0 );
return( rc );
@@ -170,3 +173,35 @@ static int tel_compare(
{
return value_cmp(v1, v2, SYNTAX_TEL|SYNTAX_CIS, 3 /* Normalise both values */);
}
+
+static int
+tel_validate(
+ struct berval *val
+)
+{
+ int rc = 0; /* assume the value is valid */
+ int i = 0;
+
+ /* Per RFC4517:
+ *
+ * TelephoneNumber = PrintableString
+ * PrintableString = 1*PrintableCharacter
+ */
+
+ /* Don't allow a 0 length string */
+ if ((val == NULL) || (val->bv_len == 0)) {
+ rc = 1;
+ goto exit;
+ }
+
+ /* Make sure all chars are a PrintableCharacter */
+ for (i=0; i < val->bv_len; i++) {
+ if (!IS_PRINTABLE(val->bv_val[i])) {
+ rc = 1;
+ goto exit;
+ }
+ }
+
+exit:
+ return rc;
+}
diff --git a/ldap/servers/plugins/syntaxes/validate.c b/ldap/servers/plugins/syntaxes/validate.c
new file mode 100644
index 00000000..8367e083
--- /dev/null
+++ b/ldap/servers/plugins/syntaxes/validate.c
@@ -0,0 +1,352 @@
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* validate.c - syntax validation helper functions */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "syntax.h"
+
+/* Helper function for processing a 'keystring'.
+ *
+ * Returns 0 is the value between begin and end is a valid 'keystring'.
+ * Returns non-zero if the value is not a valide 'keystring'.
+ */
+int keystring_validate(
+ char *begin,
+ char *end
+)
+{
+ int rc = 0; /* assume the value is valid */
+ const char *p = begin;
+
+ if ((begin == NULL) || (end == NULL)) {
+ rc = 1;
+ goto exit;
+ }
+
+ /* Per RFC4512:
+ *
+ * keystring = leadkeychar *keychar
+ */
+ if (IS_LEADKEYCHAR(*p)) {
+ for (p++; p <= end; p++) {
+ if (!IS_KEYCHAR(*p)) {
+ rc = 1;
+ goto exit;
+ }
+ }
+ } else {
+ rc = 1;
+ goto exit;
+ }
+
+exit:
+ return( rc );
+}
+
+/* Helper function for processing a 'numericoid'.
+ *
+ * Returns 0 is the value between begin and end is a valid 'numericoid'.
+ * Returns non-zero if the value is not a valide 'numericoid'.
+ */
+int numericoid_validate(
+ char *begin,
+ char *end
+)
+{
+ int rc = 0; /* assume the value is valid */
+ int found_separator = 0;
+ char *p = NULL;
+
+ if ((begin == NULL) || (end == NULL)) {
+ rc = 1;
+ goto exit;
+ }
+
+ /* Per RFC 4512:
+ *
+ * numericoid = number 1*( DOT number )
+ */
+
+ /* one pass of this loop should process one element of the oid (number DOT) */
+ for (p = begin; p <= end; p++) {
+ if (IS_LDIGIT(*p)) {
+ /* loop until we get to a separator char */
+ while(*p != '.') {
+ p++;
+ if (p > end) {
+ /* ensure we got at least 2 elements */
+ if (!found_separator) {
+ rc = 1;
+ goto exit;
+ } else {
+ /* looks like a valid numericoid */
+ goto exit;
+ }
+ } else if (*p == '.') {
+ /* we can not end with a '.' */
+ if (p == end) {
+ rc = 1;
+ goto exit;
+ } else {
+ found_separator = 1;
+ }
+ } else if (!isdigit(*p)) {
+ rc = 1;
+ goto exit;
+ }
+ }
+ } else if (*p == '0') {
+ p++;
+ if (p > end) {
+ /* ensure we got at least 2 elements */
+ if (!found_separator) {
+ rc = 1;
+ goto exit;
+ } else {
+ /* looks like a valid numericoid */
+ goto exit;
+ }
+ } else if (*p != '.') {
+ /* a leading 0 is not allowed unless the entire element is simply 0 */
+ rc = 1;
+ goto exit;
+ }
+
+ /* At this point, *p is '.'. We can not end with a '.' */
+ if (p == end) {
+ rc = 1;
+ goto exit;
+ } else {
+ found_separator = 1;
+ }
+ } else {
+ rc = 1;
+ goto exit;
+ }
+ }
+
+exit:
+ return(rc);
+}
+
+/* Helper to validate a single UTF-8 character.
+ * It is assumed that the first byte of the character
+ * is pointed to by begin. This function will not read
+ * past the byte pointed to by the end parameter. The
+ * last pointer will be filled in the the address of
+ * the last byte of the validated character if the
+ * character is valid, or the last byte processed
+ * in the invalid case.
+ *
+ * Returns 0 if it is valid and non-zero otherwise. */
+int utf8char_validate(
+ char *begin,
+ char *end,
+ char **last
+)
+{
+ int rc = 0; /* Assume char is valid */
+ char *p = begin;
+
+ if ((begin == NULL) || (end == NULL)) {
+ rc = 1;
+ goto exit;
+ }
+
+ /* Per RFC 4512:
+ *
+ * UTF8 = UTF1 / UTFMB
+ * UTFMB = UTF2 / UTF3 / UTF4
+ * UTF0 = %x80-BF
+ * UTF1 = %x00-7F
+ * UTF2 = %xC2-DF UTF0
+ * UTF3 = %xE0 %xA0-BF UTF0 / %xE1-EC 2(UTF0) /
+ * %xED %x80-9F UTF0 / %xEE-EF 2(UTF0)
+ * UTF4 = %xF0 %x90-BF 2(UTF0) / %xF1-F3 3(UTF0) /
+ * %xF4 %x80-8F 2(UTF0)
+ */
+
+ /* If we have a single byte (ASCII) character, we
+ * don't really have any work to do. */
+ if (IS_UTF1(*p)) {
+ goto exit;
+ } else if (IS_UTF2(*p)) {
+ /* Ensure that there is another byte
+ * and that is is 'UTF0'. */
+ if ((p == end) || !IS_UTF0(*(p + 1))) {
+ rc = 1;
+ goto exit;
+ }
+
+ /* Advance p so last is set correctly */
+ p++;
+ } else if (IS_UTF3(*p)) {
+ /* Ensure that there are at least 2 more bytes. */
+ if (end - p < 2) {
+ rc = 1;
+ goto exit;
+ }
+
+ /* The first byte determines what is legal for
+ * the second byte. */
+ if (*p == '\xE0') {
+ /* The next byte must be %xA0-BF. */
+ p++;
+ if ((*p < '\xA0') || (*p > '\xBF')) {
+ rc = 1;
+ goto exit;
+ }
+ } else if (*p == '\xED') {
+ /* The next byte must be %x80-9F. */
+ p++;
+ if ((*p < '\x80') || (*p > '\x9F')) {
+ rc = 1;
+ goto exit;
+ }
+ } else {
+ /* The next byte must each be 'UTF0'. */
+ p++;
+ if (!IS_UTF0(*p)) {
+ rc = 1;
+ goto exit;
+ }
+ }
+
+ /* The last byte must be 'UTF0'. */
+ p++;
+ if (!IS_UTF0(*p)) {
+ rc = 1;
+ goto exit;
+ }
+ } else if (IS_UTF4(*p)) {
+ /* Ensure that there are at least 3 more bytes. */
+ if (end - p < 3) {
+ rc = 1;
+ goto exit;
+ }
+
+ /* The first byte determines what is legal for
+ * the second byte. */
+ if (*p == '\xF0') {
+ /* The next byte must be %x90-BF. */
+ if ((*p < '\x90') || (*p > '\xBF')) {
+ rc = 1;
+ goto exit;
+ }
+ } else if (*p == '\xF4') {
+ /* The next byte must be %x80-BF. */
+ if ((*p < '\x80') || (*p > '\xBF')) {
+ rc = 1;
+ goto exit;
+ }
+ } else {
+ /* The next byte must each be 'UTF0'. */
+ p++;
+ if (!IS_UTF0(*p)) {
+ rc = 1;
+ goto exit;
+ }
+ }
+
+ /* The last 2 bytes must be 'UTF0'. */
+ p++;
+ if (!IS_UTF0(*p) || !IS_UTF0(*(p + 1))) {
+ rc = 1;
+ goto exit;
+ }
+
+ /* Advance the pointer so last is set correctly
+ * when we return. */
+ p++;
+ } else {
+ /* We found an illegal first byte. */
+ rc = 1;
+ goto exit;
+ }
+
+exit:
+ if (last) {
+ *last = p;
+ }
+ return(rc);
+}
+
+/* Validates that a non '\0' terminated string is UTF8. This
+ * function will not read past the byte pointed to by the end
+ * parameter. The last pointer will be filled in to point to
+ * the address of the last byte of the last validated character
+ * if the string is valid, or the last byte processed in the
+ * invalid case.
+ *
+ * Returns 0 if it is valid and non-zero otherwise. */
+int utf8string_validate(
+ char *begin,
+ char *end,
+ char **last
+)
+{
+ int rc = 0; /* Assume string is valid */
+ char *p = NULL;
+
+ if ((begin == NULL) || (end == NULL)) {
+ rc = 1;
+ goto exit;
+ }
+
+ for (p = begin; p <= end; p++) {
+ if ((rc = utf8char_validate(p, end, &p)) != 0) {
+ goto exit;
+ }
+ }
+
+ /* Adjust the pointer so last is set correctly for caller. */
+ p--;
+
+exit:
+ if (last) {
+ *last = p;
+ }
+ return(rc);
+}
+
diff --git a/ldap/servers/plugins/syntaxes/validate_task.c b/ldap/servers/plugins/syntaxes/validate_task.c
new file mode 100644
index 00000000..d469ccd6
--- /dev/null
+++ b/ldap/servers/plugins/syntaxes/validate_task.c
@@ -0,0 +1,303 @@
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* validate_task.c - syntax validation task */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "syntax.h"
+
+/*
+ * Globals
+ */
+static Slapi_PluginDesc pdesc = { "syntax-validate-task", PLUGIN_MAGIC_VENDOR_STR,
+ PRODUCTTEXT, "syntax validation task plugin" };
+static void* _PluginID = NULL;
+
+
+/*
+ * Data Structures
+ */
+typedef struct _task_data
+{
+ char *dn;
+ char *filter_str;
+ Slapi_Counter *invalid_entries;
+} task_data;
+
+
+/*
+ * Function Prototypes
+ */
+int syntax_validate_task_init(Slapi_PBlock *pb);
+static int syntax_validate_task_start(Slapi_PBlock *pb);
+static int syntax_validate_task_add(Slapi_PBlock *pb, Slapi_Entry *e,
+ Slapi_Entry *eAfter, int *returncode,
+ char *returntext, void *arg);
+static void syntax_validate_task_destructor(Slapi_Task *task);
+static void syntax_validate_task_thread(void *arg);
+static int syntax_validate_task_callback(Slapi_Entry *e, void *callback_data);
+static const char *fetch_attr(Slapi_Entry *e, const char *attrname,
+ const char *default_val);
+static void syntax_validate_set_plugin_id(void * plugin_id);
+static void *syntax_validate_get_plugin_id();
+
+
+/*
+ * Function Implementations
+ */
+int
+syntax_validate_task_init(Slapi_PBlock *pb)
+{
+ int rc = 0;
+ char *syntax_validate_plugin_identity = NULL;
+
+ /* Save plugin ID. */
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &syntax_validate_plugin_identity);
+ PR_ASSERT (syntax_validate_plugin_identity);
+ syntax_validate_set_plugin_id(syntax_validate_plugin_identity);
+
+ /* Register task callback. */
+ rc = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
+ (void *) SLAPI_PLUGIN_VERSION_03 );
+ rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
+ (void *) syntax_validate_task_start );
+
+ return rc;
+}
+
+static int
+syntax_validate_task_start(Slapi_PBlock *pb)
+{
+ int rc = slapi_task_register_handler("syntax validate", syntax_validate_task_add);
+ return rc;
+}
+
+static int
+syntax_validate_task_add(Slapi_PBlock *pb, Slapi_Entry *e,
+ Slapi_Entry *eAfter, int *returncode,
+ char *returntext, void *arg)
+{
+ PRThread *thread = NULL;
+ int rv = SLAPI_DSE_CALLBACK_OK;
+ task_data *mytaskdata = NULL;
+ Slapi_Task *task = NULL;
+ const char *filter;
+ const char *dn = 0;
+
+ *returncode = LDAP_SUCCESS;
+ /* get arg(s) */
+ if ((dn = fetch_attr(e, "basedn", 0)) == NULL) {
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+
+ if ((filter = fetch_attr(e, "filter", "(objectclass=*)")) == NULL) {
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+
+ /* setup our task data */
+ mytaskdata = (task_data*)slapi_ch_malloc(sizeof(task_data));
+ if (mytaskdata == NULL) {
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+ mytaskdata->dn = slapi_ch_strdup(dn);
+ mytaskdata->filter_str = slapi_ch_strdup(filter);
+ mytaskdata->invalid_entries = slapi_counter_new();
+
+ /* allocate new task now */
+ task = slapi_new_task(slapi_entry_get_ndn(e));
+
+ /* register our destructor for cleaning up our private data */
+ slapi_task_set_destructor_fn(task, syntax_validate_task_destructor);
+
+ /* Stash a pointer to our data in the task */
+ slapi_task_set_data(task, mytaskdata);
+
+ /* start the sample task as a separate thread */
+ thread = PR_CreateThread(PR_USER_THREAD, syntax_validate_task_thread,
+ (void *)task, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
+ if (thread == NULL) {
+ slapi_log_error( SLAPI_LOG_FATAL, SYNTAX_PLUGIN_SUBSYSTEM,
+ "unable to create task thread!\n");
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ slapi_task_finish(task, *returncode);
+ } else {
+ rv = SLAPI_DSE_CALLBACK_OK;
+ }
+
+out:
+ return rv;
+}
+
+static void
+syntax_validate_task_destructor(Slapi_Task *task)
+{
+ if (task) {
+ task_data *mydata = (task_data *)slapi_task_get_data(task);
+ if (mydata) {
+ slapi_ch_free_string(&mydata->dn);
+ slapi_ch_free_string(&mydata->filter_str);
+ slapi_counter_destroy(&mydata->invalid_entries);
+ /* Need to cast to avoid a compiler warning */
+ slapi_ch_free((void **)&mydata);
+ }
+ }
+}
+
+static void
+syntax_validate_task_thread(void *arg)
+{
+ int rc = 0;
+ Slapi_Task *task = (Slapi_Task *)arg;
+ task_data *td = NULL;
+ Slapi_PBlock *search_pb = slapi_pblock_new();
+
+ /* Fetch our task data from the task */
+ td = (task_data *)slapi_task_get_data(task);
+
+ /* Log started message. */
+ slapi_task_begin(task, 1);
+ slapi_task_log_notice(task, "Syntax validation task starting (arg: %s) ...\n",
+ td->filter_str);
+ slapi_log_error(SLAPI_LOG_FATAL, SYNTAX_PLUGIN_SUBSYSTEM,
+ "Syntax validate task starting (base: \"%s\", filter: \"%s\") ...\n",
+ td->dn, td->filter_str);
+
+ /* Perform the search and use a callback
+ * to validate each matching entry. */
+ slapi_search_internal_set_pb(search_pb, td->dn,
+ LDAP_SCOPE_SUBTREE, td->filter_str, 0, 0,
+ 0, 0, syntax_validate_get_plugin_id(), 0);
+
+ rc = slapi_search_internal_callback_pb(search_pb,
+ td, 0, syntax_validate_task_callback, 0);
+
+ slapi_pblock_destroy(search_pb);
+
+ /* Log finished message. */
+ slapi_task_log_notice(task, "Syntax validate task complete. Found %" NSPRIu64
+ " invalid entries.\n", slapi_counter_get_value(td->invalid_entries));
+ slapi_task_log_status(task, "Syntax validate task complete. Found %" NSPRIu64
+ " invalid entries.\n", slapi_counter_get_value(td->invalid_entries));
+ slapi_log_error(SLAPI_LOG_FATAL, SYNTAX_PLUGIN_SUBSYSTEM, "Syntax validate task complete."
+ " Found %" NSPRIu64 " invalid entries.\n",
+ slapi_counter_get_value(td->invalid_entries));
+ slapi_task_inc_progress(task);
+
+ /* this will queue the destruction of the task */
+ slapi_task_finish(task, rc);
+}
+
+static int
+syntax_validate_task_callback(Slapi_Entry *e, void *callback_data)
+{
+ int rc = 0;
+ char *dn = slapi_entry_get_dn(e);
+ task_data *td = (task_data *)callback_data;
+ Slapi_PBlock *pb = NULL;
+
+ /* Override the syntax checking config to force syntax checking. */
+ if (slapi_entry_syntax_check(NULL, e, 1) != 0) {
+ char *error_text = NULL;
+
+ /* We need a pblock to get more details on the syntax violation,
+ * but we don't want to allocate a pblock unless we need it for
+ * performance reasons. This means that we will actually call
+ * slapi_entry_syntax_check() twice for entries that have a
+ * syntax violation. */
+ pb = slapi_pblock_new();
+ slapi_entry_syntax_check(pb, e, 1);
+ slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &error_text);
+ slapi_log_error(SLAPI_LOG_FATAL, SYNTAX_PLUGIN_SUBSYSTEM,
+ "Entry \"%s\" violates syntax.\n%s",
+ dn, error_text);
+ slapi_pblock_destroy(pb);
+
+ /* Keep a tally of the number of invalid entries found. */
+ slapi_counter_increment(td->invalid_entries);
+ }
+
+ return rc;
+}
+
+/* extract a single value from the entry (as a string) -- if it's not in the
+ * entry, the default will be returned (which can be NULL).
+ * you do not need to free anything returned by this.
+ */
+static const char *
+fetch_attr(Slapi_Entry *e, const char *attrname,
+ const char *default_val)
+{
+Slapi_Attr *attr;
+Slapi_Value *val = NULL;
+
+ if (slapi_entry_attr_find(e, attrname, &attr) != 0) {
+ return default_val;
+ }
+
+ slapi_attr_first_value(attr, &val);
+
+ return slapi_value_get_string(val);
+}
+
+/*
+ * Plug-in identity management helper functions
+ */
+static void
+syntax_validate_set_plugin_id(void * plugin_id)
+{
+ _PluginID=plugin_id;
+}
+
+static void *
+syntax_validate_get_plugin_id()
+{
+ return _PluginID;
+}