diff options
author | Martin Hedenfal <martinh@cvs.openbsd.org> | 2010-11-03 14:17:02 +0000 |
---|---|---|
committer | Martin Hedenfal <martinh@cvs.openbsd.org> | 2010-11-03 14:17:02 +0000 |
commit | 0e45dd2311703ce1d77c9129358ac7bd6724fd31 (patch) | |
tree | 52c46d74a50fe1c5297e22a0776e157a4bd14c57 | |
parent | 04bce8357ba512d76a70e072606f6fae4370e22e (diff) |
Validate matching rules against attribute syntaxes. All matching rules from
RFC 4517 are recognized, except the optional wordMatch and keywordMatch.
Requires a current core.schema file.
-rw-r--r-- | usr.sbin/ldapctl/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/ldapd/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/ldapd/matching.c | 144 | ||||
-rw-r--r-- | usr.sbin/ldapd/schema.c | 66 | ||||
-rw-r--r-- | usr.sbin/ldapd/schema.h | 27 |
5 files changed, 230 insertions, 15 deletions
diff --git a/usr.sbin/ldapctl/Makefile b/usr.sbin/ldapctl/Makefile index fcb5c7e9dc5..5807416f72b 100644 --- a/usr.sbin/ldapctl/Makefile +++ b/usr.sbin/ldapctl/Makefile @@ -1,11 +1,11 @@ -# $OpenBSD: Makefile,v 1.4 2010/09/03 14:34:02 martinh Exp $ +# $OpenBSD: Makefile,v 1.5 2010/11/03 14:17:01 martinh Exp $ .PATH: ${.CURDIR}/../ldapd PROG= ldapctl MAN= ldapctl.8 SRCS= ldapctl.c parse.y btree.c log.c ber.c util.c \ - index.c attributes.c schema.c syntax.c + index.c attributes.c schema.c syntax.c matching.c LDADD= -levent -lcrypto -lz -lutil DPADD= ${LIBEVENT} ${LIBCRYPTO} ${LIBZ} ${LIBUTIL} diff --git a/usr.sbin/ldapd/Makefile b/usr.sbin/ldapd/Makefile index f3ee37b6df2..f89a57e244e 100644 --- a/usr.sbin/ldapd/Makefile +++ b/usr.sbin/ldapd/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.8 2010/09/03 09:39:17 martinh Exp $ +# $OpenBSD: Makefile,v 1.9 2010/11/03 14:17:01 martinh Exp $ PROG= ldapd MAN= ldapd.8 ldapd.conf.5 @@ -6,7 +6,7 @@ SRCS= ber.c log.c control.c \ util.c ldapd.c ldape.c conn.c attributes.c namespace.c \ btree.c filter.c search.c parse.y \ auth.c modify.c index.c ssl.c ssl_privsep.c \ - validate.c uuid.c schema.c imsgev.c syntax.c + validate.c uuid.c schema.c imsgev.c syntax.c matching.c LDADD= -levent -lssl -lcrypto -lz -lutil DPADD= ${LIBEVENT} ${LIBCRYPTO} ${LIBSSL} ${LIBZ} ${LIBUTIL} diff --git a/usr.sbin/ldapd/matching.c b/usr.sbin/ldapd/matching.c new file mode 100644 index 00000000000..eb8f4fbf4e9 --- /dev/null +++ b/usr.sbin/ldapd/matching.c @@ -0,0 +1,144 @@ +/* $OpenBSD: matching.c,v 1.1 2010/11/03 14:17:01 martinh Exp $ */ + +/* + * Copyright (c) 2010 Martin Hedenfalk <martinh@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/tree.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "schema.h" + +#ifndef nitems +# define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) +#endif + +static const char *ia5string_syntaxes[] = { + "1.3.6.1.4.1.1466.115.121.1.26", + NULL +}; + +static const char *dir_string_syntaxes[] = { + "1.3.6.1.4.1.1466.115.121.1.15", + "1.3.6.1.4.1.1466.115.121.1.44", + "1.3.6.1.4.1.1466.115.121.1.11", + "1.3.6.1.4.1.1466.115.121.1.50", + "1.3.6.1.4.1.1466.115.121.1.26", + NULL +}; + +static const char *num_string_syntaxes[] = { + "1.3.6.1.4.1.1466.115.121.1.36", + NULL +}; + +static const char *telephone_syntaxes[] = { + "1.3.6.1.4.1.1466.115.121.1.50", + NULL +}; + +static const char *dir_string_sequence_syntaxes[] = { + "1.3.6.1.4.1.1466.115.121.1.41", + NULL +}; + +static const char *int_first_component_syntaxes[] = { + "1.3.6.1.4.1.1466.115.121.1.17", + NULL +}; + +static const char *oid_first_component_syntaxes[] = { + "1.3.6.1.4.1.1466.115.121.1.3", + "1.3.6.1.4.1.1466.115.121.1.16", + "1.3.6.1.4.1.1466.115.121.1.54", + "1.3.6.1.4.1.1466.115.121.1.30", + "1.3.6.1.4.1.1466.115.121.1.31", + "1.3.6.1.4.1.1466.115.121.1.35", + "1.3.6.1.4.1.1466.115.121.1.37", + NULL +}; + +static struct match_rule match_rules[] = { + + { "1.3.6.1.1.16.2", "uuidMatch", MATCH_EQUALITY, NULL, "1.3.6.1.1.16.1", NULL }, + { "1.3.6.1.1.16.3", "uuidOrderingMatch", MATCH_ORDERING, NULL, "1.3.6.1.1.16.1", NULL }, + { "1.3.6.1.4.1.1466.109.114.1", "caseExactIA5Match", MATCH_EQUALITY, NULL, "1.3.6.1.4.1.1466.115.121.1.26", ia5string_syntaxes }, + { "1.3.6.1.4.1.1466.109.114.2", "caseIgnoreIA5Match", MATCH_EQUALITY, NULL, "1.3.6.1.4.1.1466.115.121.1.26", ia5string_syntaxes }, + { "1.3.6.1.4.1.1466.109.114.3", "caseIgnoreIA5SubstringsMatch", MATCH_SUBSTR, NULL, "1.3.6.1.4.1.1466.115.121.1.58", ia5string_syntaxes }, + { "2.5.13.0", "objectIdentifierMatch", MATCH_EQUALITY, NULL, "1.3.6.1.4.1.1466.115.121.1.38", NULL }, + { "2.5.13.1", "distinguishedNameMatch", MATCH_EQUALITY, NULL, "1.3.6.1.4.1.1466.115.121.1.12", NULL }, + { "2.5.13.10", "numericStringSubstringsMatch", MATCH_SUBSTR, NULL, "1.3.6.1.4.1.1466.115.121.1.58", num_string_syntaxes }, + { "2.5.13.11", "caseIgnoreListMatch", MATCH_EQUALITY, NULL, "1.3.6.1.4.1.1466.115.121.1.41", NULL }, + { "2.5.13.12", "caseIgnoreListSubstringsMatch", MATCH_SUBSTR, NULL, "1.3.6.1.4.1.1466.115.121.1.58", dir_string_sequence_syntaxes }, + { "2.5.13.13", "booleanMatch", MATCH_EQUALITY, NULL, "1.3.6.1.4.1.1466.115.121.1.7", NULL }, + { "2.5.13.14", "integerMatch", MATCH_EQUALITY, NULL, "1.3.6.1.4.1.1466.115.121.1.27", NULL }, + { "2.5.13.15", "integerOrderingMatch", MATCH_ORDERING, NULL, "1.3.6.1.4.1.1466.115.121.1.27", NULL }, + { "2.5.13.16", "bitStringMatch", MATCH_EQUALITY, NULL, "1.3.6.1.4.1.1466.115.121.1.6", NULL }, + { "2.5.13.17", "octetStringMatch", MATCH_EQUALITY, NULL, "1.3.6.1.4.1.1466.115.121.1.40", NULL }, + { "2.5.13.18", "octetStringOrderingMatch", MATCH_ORDERING, NULL, "1.3.6.1.4.1.1466.115.121.1.40", NULL }, + { "2.5.13.2", "caseIgnoreMatch", MATCH_EQUALITY, NULL, "1.3.6.1.4.1.1466.115.121.1.15", dir_string_syntaxes }, + { "2.5.13.20", "telephoneNumberMatch", MATCH_EQUALITY, NULL, "1.3.6.1.4.1.1466.115.121.1.50", NULL }, + { "2.5.13.21", "telephoneNumberSubstringsMatch", MATCH_SUBSTR, NULL, "1.3.6.1.4.1.1466.115.121.1.58", telephone_syntaxes }, + { "2.5.13.23", "uniqueMemberMatch", MATCH_EQUALITY, NULL, "1.3.6.1.4.1.1466.115.121.1.34", NULL }, + { "2.5.13.27", "generalizedTimeMatch", MATCH_EQUALITY, NULL, "1.3.6.1.4.1.1466.115.121.1.24", NULL }, + { "2.5.13.28", "generalizedTimeOrderingMatch", MATCH_ORDERING, NULL, "1.3.6.1.4.1.1466.115.121.1.24", NULL }, + { "2.5.13.29", "integerFirstComponentMatch", MATCH_EQUALITY, NULL, "1.3.6.1.4.1.1466.115.121.1.27", int_first_component_syntaxes }, + { "2.5.13.3", "caseIgnoreOrderingMatch", MATCH_ORDERING, NULL, "1.3.6.1.4.1.1466.115.121.1.15", dir_string_syntaxes }, + { "2.5.13.30", "objectIdentifierFirstComponentMatch", MATCH_EQUALITY, NULL, "1.3.6.1.4.1.1466.115.121.1.38", oid_first_component_syntaxes }, + { "2.5.13.31", "directoryStringFirstComponentMatch", MATCH_EQUALITY, NULL, "1.3.6.1.4.1.1466.115.121.1.15", NULL }, + { "2.5.13.4", "caseIgnoreSubstringsMatch", MATCH_SUBSTR, NULL, "1.3.6.1.4.1.1466.115.121.1.58", dir_string_syntaxes }, + { "2.5.13.5", "caseExactMatch", MATCH_EQUALITY, NULL, "1.3.6.1.4.1.1466.115.121.1.15", NULL }, + { "2.5.13.6", "caseExactOrderingMatch", MATCH_ORDERING, NULL, "1.3.6.1.4.1.1466.115.121.1.15", NULL }, + { "2.5.13.7", "caseExactSubstringsMatch", MATCH_SUBSTR, NULL, "1.3.6.1.4.1.1466.115.121.1.58", dir_string_syntaxes }, + { "2.5.13.8", "numericStringMatch", MATCH_EQUALITY, NULL, "1.3.6.1.4.1.1466.115.121.1.36", NULL }, + { "2.5.13.9", "numericStringOrderingMatch", MATCH_ORDERING, NULL, "1.3.6.1.4.1.1466.115.121.1.36", NULL }, + +#if 0 + { "2.5.13.32", "wordMatch", "1.3.6.1.4.1.1466.115.121.1.15", MATCH_EQUALITY, NULL }, + { "2.5.13.33", "keywordMatch", "1.3.6.1.4.1.1466.115.121.1.15", MATCH_EQUALITY, NULL }, +#endif +}; + +static struct match_rule_alias { + char *name; + char *oid; +} aliases[] = { + { "caseExactIA5SubstringsMatch", "caseExactSubstringsMatch" }, +}; + +const struct match_rule * +match_rule_lookup(const char *oid_or_name) +{ + unsigned int i; + + for (i = 0; i < nitems(match_rules); i++) { + if (strcasecmp(oid_or_name, match_rules[i].name) == 0 || + strcmp(oid_or_name, match_rules[i].oid) == 0) + return &match_rules[i]; + } + + for (i = 0; i < nitems(aliases); i++) { + if (strcasecmp(oid_or_name, aliases[i].name) == 0) + return match_rule_lookup(aliases[i].oid); + } + + return NULL; +} + diff --git a/usr.sbin/ldapd/schema.c b/usr.sbin/ldapd/schema.c index 0fdedf5519f..57548b59478 100644 --- a/usr.sbin/ldapd/schema.c +++ b/usr.sbin/ldapd/schema.c @@ -1,4 +1,4 @@ -/* $OpenBSD: schema.c,v 1.12 2010/09/21 10:41:32 martinh Exp $ */ +/* $OpenBSD: schema.c,v 1.13 2010/11/03 14:17:01 martinh Exp $ */ /* * Copyright (c) 2010 Martin Hedenfalk <martinh@openbsd.org> @@ -665,6 +665,35 @@ fail: } static int +schema_validate_match_rule(struct schema *schema, struct attr_type *at, + const struct match_rule *mrule, enum match_rule_type type) +{ + int i; + + if (mrule == NULL) + return 0; + + if ((mrule->type & type) != type) { + schema_err(schema, "%s: bad matching rule '%s'", + ATTR_NAME(at), mrule->name); + return -1; + } + + /* Is this matching rule compatible with the attribute syntax? */ + if (strcmp(mrule->syntax_oid, at->syntax->oid) == 0) + return 0; + + /* Check any alternative syntaxes for compatibility. */ + for (i = 0; mrule->alt_syntax_oids && mrule->alt_syntax_oids[i]; i++) + if (strcmp(mrule->alt_syntax_oids[i], at->syntax->oid) == 0) + return 0; + + schema_err(schema, "%s: inappropriate matching rule '%s' for syntax [%s]", + ATTR_NAME(at), mrule->name, at->syntax->oid); + return -1; +} + +static int schema_parse_attributetype(struct schema *schema) { struct attr_type *attr = NULL, *prev, *sup; @@ -725,14 +754,32 @@ schema_parse_attributetype(struct schema *schema) } free(arg); } else if (strcasecmp(kw, "EQUALITY") == 0) { - if (schema_lex(schema, &attr->equality) != STRING) + if (schema_lex(schema, &arg) != STRING) goto fail; + if ((attr->equality = match_rule_lookup(arg)) == NULL) { + schema_err(schema, "%s: unknown matching rule", + arg); + goto fail; + } + free(arg); } else if (strcasecmp(kw, "ORDERING") == 0) { - if (schema_lex(schema, &attr->ordering) != STRING) + if (schema_lex(schema, &arg) != STRING) goto fail; + if ((attr->ordering = match_rule_lookup(arg)) == NULL) { + schema_err(schema, "%s: unknown matching rule", + arg); + goto fail; + } + free(arg); } else if (strcasecmp(kw, "SUBSTR") == 0) { - if (schema_lex(schema, &attr->substr) != STRING) + if (schema_lex(schema, &arg) != STRING) + goto fail; + if ((attr->substr = match_rule_lookup(arg)) == NULL) { + schema_err(schema, "%s: unknown matching rule", + arg); goto fail; + } + free(arg); } else if (strcasecmp(kw, "SYNTAX") == 0) { if (schema_lex(schema, &arg) != STRING || !is_oidstr(arg)) @@ -820,6 +867,11 @@ schema_parse_attributetype(struct schema *schema) sup = sup->sup; } + if (schema_validate_match_rule(schema, attr, attr->equality, MATCH_EQUALITY) != 0 || + schema_validate_match_rule(schema, attr, attr->ordering, MATCH_ORDERING) != 0 || + schema_validate_match_rule(schema, attr, attr->substr, MATCH_SUBSTR) != 0) + goto fail; + return 0; fail: @@ -1230,17 +1282,17 @@ schema_dump_attribute(struct attr_type *at, char *buf, size_t size) if (at->equality != NULL) if (strlcat(buf, " EQUALITY ", size) >= size || - strlcat(buf, at->equality, size) >= size) + strlcat(buf, at->equality->name, size) >= size) return -1; if (at->ordering != NULL) if (strlcat(buf, " ORDERING ", size) >= size || - strlcat(buf, at->ordering, size) >= size) + strlcat(buf, at->ordering->name, size) >= size) return -1; if (at->substr != NULL) if (strlcat(buf, " SUBSTR ", size) >= size || - strlcat(buf, at->substr, size) >= size) + strlcat(buf, at->substr->name, size) >= size) return -1; if (at->syntax != NULL) diff --git a/usr.sbin/ldapd/schema.h b/usr.sbin/ldapd/schema.h index e5c305d0dcd..750c5eb3abf 100644 --- a/usr.sbin/ldapd/schema.h +++ b/usr.sbin/ldapd/schema.h @@ -1,4 +1,4 @@ -/* $OpenBSD: schema.h,v 1.5 2010/09/03 09:39:17 martinh Exp $ */ +/* $OpenBSD: schema.h,v 1.6 2010/11/03 14:17:01 martinh Exp $ */ /* * Copyright (c) 2010 Martin Hedenfalk <martinh@openbsd.org> @@ -30,6 +30,12 @@ enum usage { USAGE_DSA_OP /* operational attribute */ }; +enum match_rule_type { + MATCH_EQUALITY, + MATCH_ORDERING, + MATCH_SUBSTR, +}; + struct name { SLIST_ENTRY(name) next; char *name; @@ -44,6 +50,16 @@ struct syntax { size_t len); }; +struct match_rule +{ + char *oid; + char *name; + enum match_rule_type type; + int (*prepare)(char *value, size_t len); + const char *syntax_oid; + const char **alt_syntax_oids; +}; + struct attr_type { RB_ENTRY(attr_type) link; char *oid; @@ -51,9 +67,9 @@ struct attr_type { char *desc; int obsolete; struct attr_type *sup; - char *equality; - char *ordering; - char *substr; + const struct match_rule *equality; + const struct match_rule *ordering; + const struct match_rule *substr; const struct syntax *syntax; int single; int collective; @@ -155,5 +171,8 @@ int is_oidstr(const char *oidstr); /* syntax.c */ const struct syntax *syntax_lookup(const char *oid); +/* matching.c */ +const struct match_rule *match_rule_lookup(const char *oid); + #endif |