diff options
Diffstat (limited to 'usr.sbin/ldapd')
-rw-r--r-- | usr.sbin/ldapd/Makefile | 6 | ||||
-rw-r--r-- | usr.sbin/ldapd/ldapd.h | 92 | ||||
-rw-r--r-- | usr.sbin/ldapd/modify.c | 6 | ||||
-rw-r--r-- | usr.sbin/ldapd/parse.y | 539 | ||||
-rw-r--r-- | usr.sbin/ldapd/schema.c | 925 | ||||
-rw-r--r-- | usr.sbin/ldapd/schema.h | 139 | ||||
-rw-r--r-- | usr.sbin/ldapd/search.c | 4 | ||||
-rw-r--r-- | usr.sbin/ldapd/validate.c | 8 |
8 files changed, 1141 insertions, 578 deletions
diff --git a/usr.sbin/ldapd/Makefile b/usr.sbin/ldapd/Makefile index 661d911b637..7a51c9e066d 100644 --- a/usr.sbin/ldapd/Makefile +++ b/usr.sbin/ldapd/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.5 2010/06/23 12:40:19 martinh Exp $ +# $OpenBSD: Makefile,v 1.6 2010/06/29 02:45:46 martinh Exp $ PROG= ldapd MAN= ldapd.8 ldapd.conf.5 @@ -6,11 +6,11 @@ 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 + validate.c uuid.c schema.c LDADD= -levent -lssl -lcrypto -lz -lutil DPADD= ${LIBEVENT} ${LIBCRYPTO} ${LIBSSL} ${LIBZ} ${LIBUTIL} -CFLAGS+= -I${.CURDIR} +CFLAGS+= -I${.CURDIR} -g CFLAGS+= -Wall -Wstrict-prototypes -Wmissing-prototypes CFLAGS+= -Wmissing-declarations CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual diff --git a/usr.sbin/ldapd/ldapd.h b/usr.sbin/ldapd/ldapd.h index 4b12b67f46d..29cf70ce06e 100644 --- a/usr.sbin/ldapd/ldapd.h +++ b/usr.sbin/ldapd/ldapd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ldapd.h,v 1.11 2010/06/27 18:31:12 martinh Exp $ */ +/* $OpenBSD: ldapd.h,v 1.12 2010/06/29 02:45:46 martinh Exp $ */ /* * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se> @@ -33,6 +33,7 @@ #include <stdarg.h> #include "aldap.h" +#include "schema.h" #include "btree.h" #define CONFFILE "/etc/ldapd.conf" @@ -214,84 +215,6 @@ struct conn }; TAILQ_HEAD(conn_list, conn) conn_list; -enum usage { - USAGE_USER_APP, - USAGE_DIR_OP, /* operational attribute */ - USAGE_DIST_OP, /* operational attribute */ - USAGE_DSA_OP /* operational attribute */ -}; - -struct name { - SLIST_ENTRY(name) next; - const char *name; -}; -SLIST_HEAD(name_list, name); - -struct attr_type { - RB_ENTRY(attr_type) link; - const char *oid; - struct name_list *names; - char *desc; - int obsolete; - struct attr_type *sup; - char *equality; - char *ordering; - char *substr; - char *syntax; - int single; - int collective; - int immutable; /* no-user-modification */ - enum usage usage; -}; -RB_HEAD(attr_type_tree, attr_type); -RB_PROTOTYPE(attr_type_tree, attr_type, link, attr_oid_cmp); - -struct attr_ptr { - SLIST_ENTRY(attr_ptr) next; - struct attr_type *attr_type; -}; -SLIST_HEAD(attr_list, attr_ptr); - -enum object_kind { - KIND_ABSTRACT, - KIND_STRUCTURAL, - KIND_AUXILIARY -}; - -struct object; -struct obj_ptr { - SLIST_ENTRY(obj_ptr) next; - struct object *object; -}; -SLIST_HEAD(obj_list, obj_ptr); - -struct object { - RB_ENTRY(object) link; - const char *oid; - struct name_list *names; - char *desc; - int obsolete; - struct obj_list *sup; - enum object_kind kind; - struct attr_list *must; - struct attr_list *may; -}; -RB_HEAD(object_tree, object); -RB_PROTOTYPE(object_tree, object, link, obj_oid_cmp); - -struct oidname { - RB_ENTRY(oidname) link; - const char *on_name; -#define on_attr_type on_ptr.ou_attr_type -#define on_object on_ptr.ou_object - union { - struct attr_type *ou_attr_type; - struct object *ou_object; - } on_ptr; -}; -RB_HEAD(oidname_tree, oidname); -RB_PROTOTYPE(oidname_tree, oidname, link, oidname_cmp); - struct ssl { SPLAY_ENTRY(ssl) ssl_nodes; char ssl_name[PATH_MAX]; @@ -305,13 +228,10 @@ struct ssl { struct ldapd_config { struct namespace_list namespaces; - struct attr_type_tree attr_types; - struct oidname_tree attr_names; - struct object_tree objects; - struct oidname_tree object_names; struct listenerlist listeners; SPLAY_HEAD(ssltree, ssl) *sc_ssl; struct acl acl; + struct schema *schema; }; struct ldapd_stats @@ -516,12 +436,6 @@ int authorized(struct conn *conn, struct namespace *ns, /* parse.y */ int parse_config(char *filename); -struct attr_type *lookup_attribute_by_oid(const char *oid); -struct attr_type *lookup_attribute_by_name(const char *name); -struct attr_type *lookup_attribute(const char *oid_or_name); -struct object *lookup_object_by_oid(const char *oid); -struct object *lookup_object_by_name(const char *name); -struct object *lookup_object(const char *oid_or_name); int cmdline_symset(char *s); /* log.c */ diff --git a/usr.sbin/ldapd/modify.c b/usr.sbin/ldapd/modify.c index b2a25d8ff1a..79921dd14c2 100644 --- a/usr.sbin/ldapd/modify.c +++ b/usr.sbin/ldapd/modify.c @@ -1,4 +1,4 @@ -/* $OpenBSD: modify.c,v 1.3 2010/06/23 13:10:14 martinh Exp $ */ +/* $OpenBSD: modify.c,v 1.4 2010/06/29 02:45:46 martinh Exp $ */ /* * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se> @@ -139,7 +139,7 @@ ldap_modify(struct request *req) int rc; char *dn; long long op; - const char *attr; + char *attr; struct ber_element *mods, *entry, *mod, *vals, *a, *set; struct namespace *ns; struct attr_type *at; @@ -181,7 +181,7 @@ ldap_modify(struct request *req) goto done; } - if ((at = lookup_attribute(attr)) == NULL && !ns->relax) { + if ((at = lookup_attribute(conf->schema, attr)) == NULL && !ns->relax) { log_debug("unknown attribute type %s", attr); rc = LDAP_NO_SUCH_ATTRIBUTE; goto done; diff --git a/usr.sbin/ldapd/parse.y b/usr.sbin/ldapd/parse.y index 480b4d4be2f..09b8d87c3d4 100644 --- a/usr.sbin/ldapd/parse.y +++ b/usr.sbin/ldapd/parse.y @@ -1,7 +1,7 @@ -/* $OpenBSD: parse.y,v 1.4 2010/06/15 19:30:26 martinh Exp $ */ +/* $OpenBSD: parse.y,v 1.5 2010/06/29 02:45:46 martinh Exp $ */ /* - * Copyright (c) 2009 Martin Hedenfalk <martin@bzero.se> + * Copyright (c) 2009, 2010 Martin Hedenfalk <martinh@openbsd.org> * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -46,28 +46,6 @@ #include "ldapd.h" -static int -attr_oid_cmp(struct attr_type *a, struct attr_type *b) -{ - return strcasecmp(a->oid, b->oid); -} - -static int -obj_oid_cmp(struct object *a, struct object *b) -{ - return strcasecmp(a->oid, b->oid); -} - -static int -oidname_cmp(struct oidname *a, struct oidname *b) -{ - return strcasecmp(a->on_name, b->on_name); -} - -RB_GENERATE(attr_type_tree, attr_type, link, attr_oid_cmp); -RB_GENERATE(object_tree, object, link, obj_oid_cmp); -RB_GENERATE(oidname_tree, oidname, link, oidname_cmp); - TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); static struct file { TAILQ_ENTRY(file) entry; @@ -111,77 +89,48 @@ char *symget(const char *); struct ldapd_config *conf; -static struct attr_list *append_attr(struct attr_list *alist, - struct attr_type *a); -static struct obj_list *append_obj(struct obj_list *olist, struct object *obj); -int is_oidstr(const char *oidstr); -static struct name_list *append_name(struct name_list *nl, const char *name); static struct aci *mk_aci(int type, int rights, enum scope scope, char *target, char *subject); typedef struct { union { - int64_t number; - char *string; - struct attr_type *attr; - struct attr_list *attrlist; - struct object *obj; - struct obj_list *objlist; - struct name_list *namelist; - struct { - int type; - void *data; - long long value; - } data; - struct aci *aci; + int64_t number; + char *string; + struct aci *aci; } v; int lineno; } YYSTYPE; -static struct attr_type *cattr = NULL; -static struct object *cobj = NULL; -static struct namespace *cns = NULL; +static struct namespace *current_ns = NULL; %} %token ERROR LISTEN ON TLS LDAPS PORT NAMESPACE ROOTDN ROOTPW INDEX -%token SUP SYNTAX EQUALITY ORDERING SUBSTR OBSOLETE NAME SINGLE_VALUE -%token DESC USAGE ATTRIBUTETYPE NO_USER_MOD COLLECTIVE +%token SECURE RELAX STRICT SCHEMA USE COMPRESSION LEVEL %token INCLUDE CERTIFICATE FSYNC CACHE_SIZE INDEX_CACHE_SIZE -%token OBJECTCLASS MUST MAY SECURE RELAX STRICT SCHEMA -%token ABSTRACT AUXILIARY STRUCTURAL USE COMPRESSION LEVEL -%token USER_APPLICATIONS DIRECTORY_OPERATION %token DISTRIBUTED_OPERATION DSA_OPERATION %token DENY ALLOW READ WRITE BIND ACCESS TO ROOT %token ANY CHILDREN OF ATTRIBUTE IN SUBTREE BY SELF %token <v.string> STRING %token <v.number> NUMBER -%type <v.string> numericoid oidlen -%type <v.string> qdescr certname -%type <v.number> usage kind port ssl boolean -%type <v.attrlist> attrptrs attrlist -%type <v.attr> attrptr -%type <v.objlist> objptrs objlist -%type <v.obj> objptr -%type <v.namelist> qdescrs qdescrlist +%type <v.number> port ssl boolean comp_level %type <v.number> aci_type aci_access aci_rights aci_right aci_scope -%type <v.string> aci_target aci_subject +%type <v.string> aci_target aci_subject certname %type <v.aci> aci -%type <v.number> comp_level %% grammar : /* empty */ - | grammar include - | grammar attr_type - | grammar object - | grammar varset - | grammar conf_main - | grammar database - | grammar aci { + | grammar '\n' + | grammar include '\n' + | grammar varset '\n' + | grammar conf_main '\n' + | grammar error '\n' { file->errors++; } + | grammar namespace '\n' + | grammar aci '\n' { SIMPLEQ_INSERT_TAIL(&conf->acl, $2, entry); } - | grammar error { file->errors++; } + | grammar schema '\n' ; ssl : /* empty */ { $$ = 0; } @@ -253,13 +202,12 @@ conf_main : LISTEN ON STRING port ssl certname { } ; -database : NAMESPACE STRING '{' { - cns = namespace_new($2); +namespace : NAMESPACE STRING '{' '\n' { + log_debug("parsing namespace %s", $2); + current_ns = namespace_new($2); free($2); - TAILQ_INSERT_TAIL(&conf->namespaces, cns, next); - } ns_opts '}' { - cns = NULL; - } + TAILQ_INSERT_TAIL(&conf->namespaces, current_ns, next); + } ns_opts '}' { current_ns = NULL; } ; boolean : STRING { @@ -281,43 +229,35 @@ boolean : STRING { ; ns_opts : /* empty */ - | ns_opts ROOTDN STRING { - cns->rootdn = $3; - normalize_dn(cns->rootdn); + | ns_opts '\n' + | ns_opts ns_opt '\n' + ; + +ns_opt : ROOTDN STRING { + current_ns->rootdn = $2; + normalize_dn(current_ns->rootdn); } - | ns_opts ROOTPW STRING { cns->rootpw = $3; } - | ns_opts INDEX STRING { + | ROOTPW STRING { current_ns->rootpw = $2; } + | INDEX STRING { struct attr_index *ai; if ((ai = calloc(1, sizeof(*ai))) == NULL) { yyerror("calloc"); - free($3); + free($2); YYERROR; } - ai->attr = $3; + ai->attr = $2; ai->type = INDEX_EQUAL; - TAILQ_INSERT_TAIL(&cns->indices, ai, next); - } - | ns_opts CACHE_SIZE NUMBER { - cns->cache_size = $3; - } - | ns_opts INDEX_CACHE_SIZE NUMBER { - cns->index_cache_size = $3; - } - | ns_opts FSYNC boolean { - cns->sync = $3; - } - | ns_opts aci { - SIMPLEQ_INSERT_TAIL(&cns->acl, $2, entry); - } - | ns_opts RELAX SCHEMA { - cns->relax = 1; + TAILQ_INSERT_TAIL(¤t_ns->indices, ai, next); } - | ns_opts STRICT SCHEMA { - cns->relax = 0; - } - | ns_opts USE COMPRESSION comp_level { - cns->compression_level = $4; + | CACHE_SIZE NUMBER { current_ns->cache_size = $2; } + | INDEX_CACHE_SIZE NUMBER { current_ns->index_cache_size = $2; } + | FSYNC boolean { current_ns->sync = $2; } + | aci { + SIMPLEQ_INSERT_TAIL(¤t_ns->acl, $1, entry); } + | RELAX SCHEMA { current_ns->relax = 1; } + | STRICT SCHEMA { current_ns->relax = 0; } + | USE COMPRESSION comp_level { current_ns->compression_level = $3; } ; comp_level : /* empty */ { $$ = 6; } @@ -374,209 +314,6 @@ aci_subject : /* empty */ { $$ = NULL; } | BY SELF { $$ = strdup("@"); } ; -attr_type : ATTRIBUTETYPE '(' numericoid { - struct attr_type *p; - - if ((cattr = calloc(1, sizeof(*cattr))) == NULL) { - yyerror("calloc"); - free($3); - YYERROR; - } - cattr->oid = $3; - p = RB_INSERT(attr_type_tree, &conf->attr_types, cattr); - if (p != NULL) { - yyerror("attribute '%s' already defined", $3); - free($3); - free(cattr); - cattr = NULL; - YYERROR; - } - } attr_data ')' { - cattr = NULL; - } - ; - -attr_data : /* empty */ - | attr_data NAME qdescrs { cattr->names = $3; } - | attr_data DESC STRING { cattr->desc = $3; } - | attr_data OBSOLETE { cattr->obsolete = 1; } - | attr_data SUP STRING { - cattr->sup = lookup_attribute($3); - if (cattr->sup == NULL) - yyerror("%s: no such attribute", $3); - free($3); - if (cattr->sup == NULL) - YYERROR; - } - | attr_data EQUALITY STRING { cattr->equality = $3; } - | attr_data ORDERING STRING { cattr->ordering = $3; } - | attr_data SUBSTR STRING { cattr->substr = $3; } - | attr_data SYNTAX oidlen { cattr->syntax = $3; } - | attr_data SINGLE_VALUE { cattr->single = 1; } - | attr_data COLLECTIVE { cattr->collective = 1; } - | attr_data NO_USER_MOD { cattr->immutable = 1; } - | attr_data USAGE usage { cattr->usage = $3; } - ; - -usage : USER_APPLICATIONS { $$ = USAGE_USER_APP; } - | DIRECTORY_OPERATION { $$ = USAGE_DIR_OP; } - | DISTRIBUTED_OPERATION { $$ = USAGE_DIST_OP; } - | DSA_OPERATION { $$ = USAGE_DSA_OP; } - ; - -object : OBJECTCLASS '(' numericoid { - struct object *p; - - if ((cobj = calloc(1, sizeof(*cobj))) == NULL) { - yyerror("calloc"); - free($3); - YYERROR; - } - cobj->oid = $3; - p = RB_INSERT(object_tree, &conf->objects, cobj); - if (p != NULL) { - yyerror("object '%s' already defined", $3); - free($3); - free(cobj); - cobj = NULL; - YYERROR; - } - } obj_data ')' { - cobj = NULL; - } - ; - -obj_data : /* empty */ - | obj_data NAME qdescrs { cobj->names = $3; } - | obj_data DESC STRING { cobj->desc = $3; } - | obj_data OBSOLETE { cobj->obsolete = 1; } - | obj_data SUP objlist { cobj->sup = $3; } - | obj_data kind { cobj->kind = $2; } - | obj_data MUST attrlist { cobj->must = $3; } - | obj_data MAY attrlist { cobj->may = $3; } - ; - -attrptr : STRING { - $$ = lookup_attribute($1); - if ($$ == NULL) { - yyerror("undeclared attribute '%s'", $1); - free($1); - YYERROR; - } - free($1); - } - ; - -attrptrs : attrptr { - if (($$ = append_attr(NULL, $1)) == NULL) - YYERROR; - } - | attrptrs '$' attrptr { - if (($$ = append_attr($1, $3)) == NULL) - YYERROR; - } - ; - -attrlist : attrptr { - if (($$ = append_attr(NULL, $1)) == NULL) - YYERROR; - } - | '(' attrptrs ')' { $$ = $2; } - ; - -objptr : STRING { - $$ = lookup_object($1); - if ($$ == NULL) { - yyerror("undeclared object class '%s'", $1); - free($1); - YYERROR; - } - free($1); - } - ; - -objptrs : objptr { - if (($$ = append_obj(NULL, $1)) == NULL) - YYERROR; - } - | objptrs '$' objptr { - if (($$ = append_obj($1, $3)) == NULL) - YYERROR; - } - ; - -objlist : objptr { - if (($$ = append_obj(NULL, $1)) == NULL) - YYERROR; - } - | '(' objptrs ')' { $$ = $2; } - ; - -kind : ABSTRACT { $$ = KIND_ABSTRACT; } - | STRUCTURAL { $$ = KIND_STRUCTURAL; } - | AUXILIARY { $$ = KIND_AUXILIARY; } - ; - -qdescr : STRING { - struct oidname *on, *old; - - if ((on = calloc(1, sizeof(*on))) == NULL) { - yyerror("calloc"); - free($1); - YYERROR; - } - on->on_name = $1; - if (cattr) { - on->on_attr_type = cattr; - old = RB_INSERT(oidname_tree, &conf->attr_names, - on); - if (old != NULL) { - yyerror("attribute name '%s' already" - " defined for oid %s", - $1, old->on_attr_type->oid); - free($1); - free(on); - YYERROR; - } - } else { - on->on_object = cobj; - old = RB_INSERT(oidname_tree, - &conf->object_names, on); - if (old != NULL) { - yyerror("object name '%s' already" - " defined for oid %s", - $1, old->on_object->oid); - free($1); - free(on); - YYERROR; - } - } - } - ; - -qdescrs : qdescr { $$ = append_name(NULL, $1); } - | '(' qdescrlist ')' { $$ = $2; } - ; - -qdescrlist : /* empty */ { $$ = NULL; } - | qdescrlist qdescr { $$ = append_name($1, $2); } - ; - -numericoid : STRING { - if (!is_oidstr($1)) { - yyerror("invalid OID: %s", $1); - free($1); - YYERROR; - } - $$ = $1; - } - ; - -oidlen : STRING { $$ = $1; } - | numericoid '{' NUMBER '}' { - $$ = $1; - } - include : INCLUDE STRING { struct file *nfile; @@ -588,18 +325,29 @@ include : INCLUDE STRING { free($2); file = nfile; + lungetc('\n'); } ; varset : STRING '=' STRING { - /*if (conf->opts & BGPD_OPT_VERBOSE)*/ - printf("%s = \"%s\"\n", $1, $3); if (symset($1, $3, 0) == -1) fatal("cannot store variable"); free($1); free($3); } ; + +schema : SCHEMA STRING { + int ret; + + ret = schema_parse(conf->schema, $2); + free($2); + if (ret != 0) { + YYERROR; + } + } + ; + %% struct keywords { @@ -634,37 +382,16 @@ lookup(char *s) { /* this has to be sorted always */ static const struct keywords keywords[] = { - { "ABSTRACT", ABSTRACT }, - { "AUXILIARY", AUXILIARY }, - { "COLLECTIVE", COLLECTIVE }, - { "DESC", DESC }, - { "EQUALITY", EQUALITY }, - { "MAY", MAY }, - { "MUST", MUST }, - { "NAME", NAME }, - { "NO-USER-MODIFICATION", NO_USER_MOD}, - { "ORDERING", ORDERING }, - { "SINGLE-VALUE", SINGLE_VALUE }, - { "STRUCTURAL", STRUCTURAL }, - { "SUBSTR", SUBSTR }, - { "SUP", SUP }, - { "SYNTAX", SYNTAX }, - { "USAGE", USAGE }, { "access", ACCESS }, { "allow", ALLOW }, { "any", ANY }, - { "attribute", ATTRIBUTE }, - { "attributetype", ATTRIBUTETYPE }, { "bind", BIND }, { "by", BY }, { "cache-size", CACHE_SIZE }, { "certificate", CERTIFICATE }, { "children", CHILDREN }, { "compression", COMPRESSION }, - { "dSAOperation", DSA_OPERATION }, { "deny", DENY }, - { "directoryOperation", DIRECTORY_OPERATION }, - { "distributedOperation", DISTRIBUTED_OPERATION }, { "fsync", FSYNC }, { "in", IN }, { "include", INCLUDE }, @@ -674,7 +401,6 @@ lookup(char *s) { "level", LEVEL }, { "listen", LISTEN }, { "namespace", NAMESPACE }, - { "objectclass", OBJECTCLASS }, { "of", OF }, { "on", ON }, { "port", PORT }, @@ -691,7 +417,6 @@ lookup(char *s) { "tls", TLS }, { "to", TO }, { "use", USE }, - { "userApplications", USER_APPLICATIONS }, { "write", WRITE }, }; @@ -803,7 +528,7 @@ findeol(void) int yylex(void) { - char buf[8096]; + char buf[4096]; char *p, *val; int quotec, next, c; int token; @@ -834,8 +559,6 @@ top: lungetc(c); break; } - if (*buf == '\0') - return ('$'); val = symget(buf); if (val == NULL) { yyerror("macro '%s' not defined", buf); @@ -870,7 +593,7 @@ top: break; } if (p + 1 >= buf + sizeof(buf) - 1) { - yyerror("string too long"); + log_warnx("string too long"); return (findeol()); } *p++ = (char)c; @@ -941,7 +664,6 @@ nodigits: if (c == '\n') { yylval.lineno = file->lineno; file->lineno++; - goto top; } if (c == EOF) return (0); @@ -990,7 +712,6 @@ pushfile(const char *name, int secret) free(nfile); return (NULL); } -#if 0 if (secret && check_file_secrecy(fileno(nfile->stream), nfile->name)) { fclose(nfile->stream); @@ -998,7 +719,6 @@ pushfile(const char *name, int secret) free(nfile); return (NULL); } -#endif nfile->lineno = 1; TAILQ_INSERT_TAIL(&files, nfile, entry); return (nfile); @@ -1029,8 +749,10 @@ parse_config(char *filename) if ((conf = calloc(1, sizeof(struct ldapd_config))) == NULL) fatal(NULL); - RB_INIT(&conf->attr_types); - RB_INIT(&conf->objects); + conf->schema = schema_new(); + if (conf->schema == NULL) + fatal("schema_new"); + TAILQ_INIT(&conf->namespaces); TAILQ_INIT(&conf->listeners); if ((conf->sc_ssl = calloc(1, sizeof(*conf->sc_ssl))) == NULL) @@ -1051,9 +773,7 @@ parse_config(char *filename) /* Free macros and check which have not been used. */ for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) { next = TAILQ_NEXT(sym, entry); - if (/*(conf->opts & BGPD_OPT_VERBOSE2) &&*/ !sym->used) - fprintf(stderr, "warning: macro \"%s\" not " - "used\n", sym->nam); + log_debug("warning: macro \"%s\" not used", sym->nam); if (!sym->persist) { free(sym->nam); free(sym->val); @@ -1139,141 +859,6 @@ symget(const char *nam) return (NULL); } -struct attr_type * -lookup_attribute_by_name(const char *name) -{ - struct oidname *on, find; - - find.on_name = name; - on = RB_FIND(oidname_tree, &conf->attr_names, &find); - - if (on) - return on->on_attr_type; - return NULL; -} - -struct attr_type * -lookup_attribute_by_oid(const char *oid) -{ - struct attr_type find; - - find.oid = oid; - return RB_FIND(attr_type_tree, &conf->attr_types, &find); -} - -struct attr_type * -lookup_attribute(const char *oid_or_name) -{ - if (is_oidstr(oid_or_name)) - return lookup_attribute_by_oid(oid_or_name); - return lookup_attribute_by_name(oid_or_name); -} - -struct object * -lookup_object_by_oid(const char *oid) -{ - struct object find; - - find.oid = oid; - return RB_FIND(object_tree, &conf->objects, &find); -} - -struct object * -lookup_object_by_name(const char *name) -{ - struct oidname *on, find; - - find.on_name = name; - on = RB_FIND(oidname_tree, &conf->object_names, &find); - - if (on) - return on->on_object; - return NULL; -} - -struct object * -lookup_object(const char *oid_or_name) -{ - if (is_oidstr(oid_or_name)) - return lookup_object_by_oid(oid_or_name); - return lookup_object_by_name(oid_or_name); -} - -static struct attr_list * -append_attr(struct attr_list *alist, struct attr_type *a) -{ - struct attr_ptr *aptr; - - if (alist == NULL) { - if ((alist = calloc(1, sizeof(*alist))) == NULL) { - yyerror("calloc"); - return NULL; - } - SLIST_INIT(alist); - } - - if ((aptr = calloc(1, sizeof(*aptr))) == NULL) { - yyerror("calloc"); - return NULL; - } - aptr->attr_type = a; - SLIST_INSERT_HEAD(alist, aptr, next); - - return alist; -} - -static struct obj_list * -append_obj(struct obj_list *olist, struct object *obj) -{ - struct obj_ptr *optr; - - if (olist == NULL) { - if ((olist = calloc(1, sizeof(*olist))) == NULL) { - yyerror("calloc"); - return NULL; - } - SLIST_INIT(olist); - } - - if ((optr = calloc(1, sizeof(*optr))) == NULL) { - yyerror("calloc"); - return NULL; - } - optr->object = obj; - SLIST_INSERT_HEAD(olist, optr, next); - - return olist; -} - -int -is_oidstr(const char *oidstr) -{ - struct ber_oid oid; - return (ber_string2oid(oidstr, &oid) == 0); -} - -static struct name_list * -append_name(struct name_list *nl, const char *name) -{ - struct name *n; - - if (nl == NULL) { - if ((nl = calloc(1, sizeof(*nl))) == NULL) { - yyerror("calloc"); - return NULL; - } - SLIST_INIT(nl); - } - if ((n = calloc(1, sizeof(*n))) == NULL) { - yyerror("calloc"); - return NULL; - } - n->name = name; - SLIST_INSERT_HEAD(nl, n, next); - - return nl; -} - struct listener * host_unix(const char *path) { diff --git a/usr.sbin/ldapd/schema.c b/usr.sbin/ldapd/schema.c new file mode 100644 index 00000000000..4d2d79a249a --- /dev/null +++ b/usr.sbin/ldapd/schema.c @@ -0,0 +1,925 @@ +/* $OpenBSD: schema.c,v 1.1 2010/06/29 02:45:46 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 <ctype.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> + +#include "ldapd.h" + +#define ERROR -1 +#define STRING 1 + +static int +attr_oid_cmp(struct attr_type *a, struct attr_type *b) +{ + return strcasecmp(a->oid, b->oid); +} + +static int +obj_oid_cmp(struct object *a, struct object *b) +{ + return strcasecmp(a->oid, b->oid); +} + +static int +oidname_cmp(struct oidname *a, struct oidname *b) +{ + return strcasecmp(a->on_name, b->on_name); +} + +static int +symoid_cmp(struct symoid *a, struct symoid *b) +{ + return strcasecmp(a->name, b->name); +} + +RB_GENERATE(attr_type_tree, attr_type, link, attr_oid_cmp); +RB_GENERATE(object_tree, object, link, obj_oid_cmp); +RB_GENERATE(oidname_tree, oidname, link, oidname_cmp); +RB_GENERATE(symoid_tree, symoid, link, symoid_cmp); + +static struct attr_list *push_attr(struct attr_list *alist, struct attr_type *a); +static struct obj_list *push_obj(struct obj_list *olist, struct object *obj); +static struct name_list *push_name(struct name_list *nl, const char *name); +int is_oidstr(const char *oidstr); + +struct attr_type * +lookup_attribute_by_name(struct schema *schema, char *name) +{ + struct oidname *on, find; + + find.on_name = name; + on = RB_FIND(oidname_tree, &schema->attr_names, &find); + + if (on) + return on->on_attr_type; + return NULL; +} + +struct attr_type * +lookup_attribute_by_oid(struct schema *schema, char *oid) +{ + struct attr_type find; + + find.oid = oid; + return RB_FIND(attr_type_tree, &schema->attr_types, &find); +} + +struct attr_type * +lookup_attribute(struct schema *schema, char *oid_or_name) +{ + if (is_oidstr(oid_or_name)) + return lookup_attribute_by_oid(schema, oid_or_name); + return lookup_attribute_by_name(schema, oid_or_name); +} + +struct object * +lookup_object_by_oid(struct schema *schema, char *oid) +{ + struct object find; + + find.oid = oid; + return RB_FIND(object_tree, &schema->objects, &find); +} + +struct object * +lookup_object_by_name(struct schema *schema, char *name) +{ + struct oidname *on, find; + + find.on_name = name; + on = RB_FIND(oidname_tree, &schema->object_names, &find); + + if (on) + return on->on_object; + return NULL; +} + +struct object * +lookup_object(struct schema *schema, char *oid_or_name) +{ + if (is_oidstr(oid_or_name)) + return lookup_object_by_oid(schema, oid_or_name); + return lookup_object_by_name(schema, oid_or_name); +} + +/* Looks up a symbolic OID, optionally with a suffix OID, so if + * SYMBOL = 1.2.3.4 + * then + * SYMBOL:5.6 = 1.2.3.4.5.6 + * + * Returned string must be freed by the caller. + * Modifies the name argument. + */ +static char * +lookup_symbolic_oid(struct schema *schema, char *name) +{ + struct symoid *symoid, find; + char *colon, *oid; + size_t sz; + + colon = strchr(name, ':'); + if (colon != NULL) { + if (!is_oidstr(colon + 1)) { + log_warnx("invalid OID after colon: %s", colon + 1); + return NULL; + } + *colon = '\0'; + } + + find.name = name; + symoid = RB_FIND(symoid_tree, &schema->symbolic_oids, &find); + if (symoid == NULL) + return NULL; + + if (colon == NULL) + return strdup(symoid->oid); + + /* Expand SYMBOL:OID. + */ + sz = strlen(symoid->oid) + 1 + strlen(colon + 1) + 1; + if ((oid = malloc(sz)) == NULL) { + log_warnx("malloc"); + return NULL; + } + + strlcpy(oid, symoid->oid, sz); + strlcat(oid, ".", sz); + strlcat(oid, colon + 1, sz); + + return oid; +} + +/* Push a symbol-OID pair on the tree. Name and OID must be valid pointers + * during the lifetime of the tree. + */ +static struct symoid * +push_symbolic_oid(struct schema *schema, char *name, char *oid) +{ + struct symoid *symoid, find; + + find.name = name; + symoid = RB_FIND(symoid_tree, &schema->symbolic_oids, &find); + + if (symoid == NULL) { + symoid = calloc(1, sizeof(*symoid)); + if (symoid == NULL) { + log_warnx("calloc"); + return NULL; + } + + symoid->name = name; + RB_INSERT(symoid_tree, &schema->symbolic_oids, symoid); + } + + free(symoid->oid); + symoid->oid = oid; + + return symoid; +} + +static struct attr_list * +push_attr(struct attr_list *alist, struct attr_type *a) +{ + struct attr_ptr *aptr; + + if (alist == NULL) { + if ((alist = calloc(1, sizeof(*alist))) == NULL) { + log_warn("calloc"); + return NULL; + } + SLIST_INIT(alist); + } + + if ((aptr = calloc(1, sizeof(*aptr))) == NULL) { + log_warn("calloc"); + return NULL; + } + aptr->attr_type = a; + SLIST_INSERT_HEAD(alist, aptr, next); + + return alist; +} + +static struct obj_list * +push_obj(struct obj_list *olist, struct object *obj) +{ + struct obj_ptr *optr; + + if (olist == NULL) { + if ((olist = calloc(1, sizeof(*olist))) == NULL) { + log_warn("calloc"); + return NULL; + } + SLIST_INIT(olist); + } + + if ((optr = calloc(1, sizeof(*optr))) == NULL) { + log_warn("calloc"); + return NULL; + } + optr->object = obj; + SLIST_INSERT_HEAD(olist, optr, next); + + return olist; +} + +int +is_oidstr(const char *oidstr) +{ + struct ber_oid oid; + return (ber_string2oid(oidstr, &oid) == 0); +} + +static struct name_list * +push_name(struct name_list *nl, const char *name) +{ + struct name *n; + + if (nl == NULL) { + if ((nl = calloc(1, sizeof(*nl))) == NULL) { + log_warn("calloc"); + return NULL; + } + SLIST_INIT(nl); + } + if ((n = calloc(1, sizeof(*n))) == NULL) { + log_warn("calloc"); + return NULL; + } + n->name = name; + SLIST_INSERT_HEAD(nl, n, next); + + return nl; +} + +static int +schema_getc(struct schema *schema, int quotec) +{ + int c, next; + + if (schema->pushback_index) + return (schema->pushback_buffer[--schema->pushback_index]); + + if (quotec) { + if ((c = getc(schema->fp)) == EOF) { + log_warnx("reached end of file while parsing " + "quoted string"); + return EOF; + } + return (c); + } + + while ((c = getc(schema->fp)) == '\\') { + next = getc(schema->fp); + if (next != '\n') { + c = next; + break; + } + schema->lineno++; + } + + return (c); +} + +static int +schema_ungetc(struct schema *schema, int c) +{ + if (c == EOF) + return EOF; + + if (schema->pushback_index < SCHEMA_MAXPUSHBACK-1) + return (schema->pushback_buffer[schema->pushback_index++] = c); + else + return (EOF); +} + +static int +findeol(struct schema *schema) +{ + int c; + + /* skip to either EOF or the first real EOL */ + while (1) { + if (schema->pushback_index) + c = schema->pushback_buffer[--schema->pushback_index]; + else + c = schema_getc(schema, 0); + if (c == '\n') { + schema->lineno++; + break; + } + if (c == EOF) + break; + } + return (ERROR); +} + +static int +schema_lex(struct schema *schema, char **kw) +{ + char buf[8096]; + char *p; + int quotec, next, c; + + if (kw) + *kw = NULL; + +top: + p = buf; + while ((c = schema_getc(schema, 0)) == ' ' || c == '\t') + ; /* nothing */ + + if (c == '#') + while ((c = schema_getc(schema, 0)) != '\n' && c != EOF) + ; /* nothing */ + + switch (c) { + case '\'': + case '"': + quotec = c; + while (1) { + if ((c = schema_getc(schema, quotec)) == EOF) + return (0); + if (c == '\n') { + schema->lineno++; + continue; + } else if (c == '\\') { + if ((next = schema_getc(schema, quotec)) == EOF) + return (0); + if (next == quotec || c == ' ' || c == '\t') + c = next; + else if (next == '\n') + continue; + else + schema_ungetc(schema, next); + } else if (c == quotec) { + *p = '\0'; + break; + } + if (p + 1 >= buf + sizeof(buf) - 1) { + log_warnx("string too long"); + return (findeol(schema)); + } + *p++ = (char)c; + } + if (kw != NULL && (*kw = strdup(buf)) == NULL) + fatal("schema_lex: strdup"); + return (STRING); + } + +#define allowed_in_string(x) \ + (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ + x != '{' && x != '}' && x != '<' && x != '>' && \ + x != '!' && x != '=' && x != '/' && x != '#' && \ + x != ',')) + + if (isalnum(c) || c == ':' || c == '_' || c == '*') { + do { + *p++ = c; + if ((unsigned)(p-buf) >= sizeof(buf)) { + log_warnx("string too long"); + return (findeol(schema)); + } + } while ((c = schema_getc(schema, 0)) != EOF && (allowed_in_string(c))); + schema_ungetc(schema, c); + *p = '\0'; + if (kw != NULL && (*kw = strdup(buf)) == NULL) + fatal("schema_lex: strdup"); + return STRING; + } + if (c == '\n') { + schema->lineno++; + goto top; + } + if (c == EOF) + return (0); + return (c); +} + +struct schema * +schema_new(void) +{ + struct schema *schema; + + if ((schema = calloc(1, sizeof(*schema))) == NULL) + return NULL; + + RB_INIT(&schema->attr_types); + RB_INIT(&schema->attr_names); + RB_INIT(&schema->objects); + RB_INIT(&schema->object_names); + RB_INIT(&schema->symbolic_oids); + + return schema; +} + +static void +schema_err(struct schema *schema, const char *fmt, ...) +{ + va_list ap; + char *nfmt; + + va_start(ap, fmt); + if (asprintf(&nfmt, "%s:%d: %s", schema->filename, schema->lineno, + fmt) == -1) + fatal("asprintf"); + vlog(LOG_CRIT, nfmt, ap); + va_end(ap); + free(nfmt); + + schema->error++; +} + +static int +schema_link_attr_name(struct schema *schema, const char *name, struct attr_type *attr) +{ + struct oidname *oidname, *prev; + + if ((oidname = calloc(1, sizeof(*oidname))) == NULL) { + log_warn("calloc"); + return -1; + } + + oidname->on_name = name; + oidname->on_attr_type = attr; + prev = RB_INSERT(oidname_tree, &schema->attr_names, oidname); + if (prev != NULL) { + schema_err(schema, "attribute type name '%s'" + " already defined for oid %s", + name, prev->on_attr_type->oid); + free(oidname); + return -1; + } + + return 0; +} + +static int +schema_link_attr_names(struct schema *schema, struct attr_type *attr) +{ + struct name *name; + + SLIST_FOREACH(name, attr->names, next) { + if (schema_link_attr_name(schema, name->name, attr) != 0) + return -1; + } + return 0; +} + +static int +schema_link_obj_name(struct schema *schema, const char *name, struct object *obj) +{ + struct oidname *oidname, *prev; + + if ((oidname = calloc(1, sizeof(*oidname))) == NULL) { + log_warn("calloc"); + return -1; + } + + oidname->on_name = name; + oidname->on_object = obj; + prev = RB_INSERT(oidname_tree, &schema->object_names, oidname); + if (prev != NULL) { + schema_err(schema, "object class name '%s'" + " already defined for oid %s", + name, prev->on_object->oid); + free(oidname); + return -1; + } + + return 0; +} + +static int +schema_link_obj_names(struct schema *schema, struct object *obj) +{ + struct name *name; + + SLIST_FOREACH(name, obj->names, next) { + if (schema_link_obj_name(schema, name->name, obj) != 0) + return -1; + } + return 0; +} + +static struct name_list * +schema_parse_names(struct schema *schema) +{ + struct name_list *nlist = NULL; + char *kw; + int token; + + token = schema_lex(schema, &kw); + if (token == STRING) + return push_name(NULL, kw); + + if (token != '(') + goto fail; + + for (;;) { + token = schema_lex(schema, &kw); + if (token == ')') + break; + if (token != STRING) + goto fail; + nlist = push_name(nlist, kw); + } + + return nlist; + +fail: + free(kw); + /* FIXME: leaks nlist here */ + return NULL; +} + +static struct attr_list * +schema_parse_attrlist(struct schema *schema) +{ + struct attr_list *alist = NULL; + struct attr_type *attr; + char *kw; + int token, want_dollar = 0; + + token = schema_lex(schema, &kw); + if (token == STRING) { + if ((attr = lookup_attribute(schema, kw)) == NULL) { + schema_err(schema, "undeclared attribute type '%s'", kw); + goto fail; + } + free(kw); + return push_attr(NULL, attr); + } + + if (token != '(') + goto fail; + + for (;;) { + token = schema_lex(schema, &kw); + if (token == ')') + break; + if (token == '$') { + if (!want_dollar) + goto fail; + want_dollar = 0; + continue; + } + if (token != STRING) + goto fail; + if ((attr = lookup_attribute(schema, kw)) == NULL) + goto fail; + alist = push_attr(alist, attr); + want_dollar = 1; + } + + return alist; + +fail: + free(kw); + /* FIXME: leaks alist here */ + return NULL; +} + +static struct obj_list * +schema_parse_objlist(struct schema *schema) +{ + struct obj_list *olist = NULL; + struct object *obj; + char *kw; + int token, want_dollar = 0; + + token = schema_lex(schema, &kw); + if (token == STRING) { + if ((obj = lookup_object(schema, kw)) == NULL) { + schema_err(schema, "undeclared object class '%s'", kw); + goto fail; + } + free(kw); + return push_obj(NULL, obj); + } + + if (token != '(') + goto fail; + + for (;;) { + token = schema_lex(schema, &kw); + if (token == ')') + break; + if (token == '$') { + if (!want_dollar) + goto fail; + want_dollar = 0; + continue; + } + if (token != STRING) + goto fail; + if ((obj = lookup_object(schema, kw)) == NULL) + goto fail; + olist = push_obj(olist, obj); + want_dollar = 1; + } + + return olist; + +fail: + free(kw); + /* FIXME: leaks olist here */ + return NULL; +} + +static int +schema_parse_attributetype(struct schema *schema) +{ + struct attr_type *attr = NULL, *prev; + char *kw, *arg = NULL; + int token, ret = 0, c; + + if (schema_lex(schema, NULL) != '(') + goto fail; + + if (schema_lex(schema, &kw) != STRING) + goto fail; + + if ((attr = calloc(1, sizeof(*attr))) == NULL) { + log_warn("calloc"); + goto fail; + } + + if (is_oidstr(kw)) + attr->oid = kw; + else { + attr->oid = lookup_symbolic_oid(schema, kw); + if (attr->oid == NULL) + goto fail; + free(kw); + } + kw = NULL; + + prev = RB_INSERT(attr_type_tree, &schema->attr_types, attr); + if (prev != NULL) { + schema_err(schema, "attribute type %s already defined", attr->oid); + goto fail; + } + + while (ret == 0) { + token = schema_lex(schema, &kw); + if (token == ')') + break; + else if (token != STRING) + goto fail; + if (strcasecmp(kw, "NAME") == 0) { + attr->names = schema_parse_names(schema); + if (attr->names == NULL) + goto fail; + schema_link_attr_names(schema, attr); + } else if (strcasecmp(kw, "DESC") == 0) { + if (schema_lex(schema, &attr->desc) != STRING) + goto fail; + } else if (strcasecmp(kw, "OBSOLETE") == 0) { + attr->obsolete = 1; + } else if (strcasecmp(kw, "SUP") == 0) { + if (schema_lex(schema, &arg) != STRING) + goto fail; + if ((attr->sup = lookup_attribute(schema, arg)) == NULL) { + schema_err(schema, "%s: no such attribute", arg); + goto fail; + } + } else if (strcasecmp(kw, "EQUALITY") == 0) { + if (schema_lex(schema, &attr->equality) != STRING) + goto fail; + } else if (strcasecmp(kw, "ORDERING") == 0) { + if (schema_lex(schema, &attr->ordering) != STRING) + goto fail; + } else if (strcasecmp(kw, "SUBSTR") == 0) { + if (schema_lex(schema, &attr->substr) != STRING) + goto fail; + } else if (strcasecmp(kw, "SYNTAX") == 0) { + if (schema_lex(schema, &attr->syntax) != STRING || + !is_oidstr(attr->syntax)) + goto fail; + if ((c = schema_getc(schema, 0)) == '{') { + if (schema_lex(schema, NULL) != STRING || + schema_lex(schema, NULL) != '}') + goto fail; + } else + schema_ungetc(schema, c); + } else if (strcasecmp(kw, "SINGLE-VALUE") == 0) { + attr->single = 1; + } else if (strcasecmp(kw, "COLLECTIVE") == 0) { + attr->collective = 1; + } else if (strcasecmp(kw, "NO-USER-MODIFICATION") == 0) { + attr->immutable = 1; + } else if (strcasecmp(kw, "USAGE") == 0) { + if (schema_lex(schema, &arg) != STRING) + goto fail; + if (strcasecmp(arg, "dSAOperation") == 0) + attr->usage = USAGE_DSA_OP; + else if (strcasecmp(arg, "directoryOperation") == 0) + attr->usage = USAGE_DIR_OP; + else if (strcasecmp(arg, "distributedOperation") == 0) + attr->usage = USAGE_DIST_OP; + else if (strcasecmp(arg, "userApplications") == 0) + attr->usage = USAGE_USER_APP; + else { + schema_err(schema, "invalid usage '%s'", arg); + goto fail; + } + } + } + + return 0; + +fail: + free(kw); + free(arg); + if (attr != NULL) { + if (attr->oid != NULL) { + RB_REMOVE(attr_type_tree, &schema->attr_types, attr); + free(attr->oid); + } + free(attr->desc); + free(attr); + } + return -1; +} + +static int +schema_parse_objectclass(struct schema *schema) +{ + struct object *obj = NULL, *prev; + char *kw; + int token, ret = 0; + + if (schema_lex(schema, NULL) != '(') + goto fail; + + if (schema_lex(schema, &kw) != STRING) + goto fail; + + if ((obj = calloc(1, sizeof(*obj))) == NULL) { + log_warn("calloc"); + goto fail; + } + + if (is_oidstr(kw)) + obj->oid = kw; + else { + obj->oid = lookup_symbolic_oid(schema, kw); + if (obj->oid == NULL) + goto fail; + free(kw); + } + kw = NULL; + + prev = RB_INSERT(object_tree, &schema->objects, obj); + if (prev != NULL) { + schema_err(schema, "object class %s already defined", obj->oid); + goto fail; + } + + while (ret == 0) { + token = schema_lex(schema, &kw); + if (token == ')') + break; + else if (token != STRING) + goto fail; + if (strcasecmp(kw, "NAME") == 0) { + obj->names = schema_parse_names(schema); + if (obj->names == NULL) + goto fail; + schema_link_obj_names(schema, obj); + } else if (strcasecmp(kw, "DESC") == 0) { + if (schema_lex(schema, &obj->desc) != STRING) + goto fail; + } else if (strcasecmp(kw, "OBSOLETE") == 0) { + obj->obsolete = 1; + } else if (strcasecmp(kw, "SUP") == 0) { + obj->sup = schema_parse_objlist(schema); + if (obj->sup == NULL) + goto fail; + } else if (strcasecmp(kw, "ABSTRACT") == 0) { + obj->kind = KIND_ABSTRACT; + } else if (strcasecmp(kw, "STRUCTURAL") == 0) { + obj->kind = KIND_STRUCTURAL; + } else if (strcasecmp(kw, "AUXILIARY") == 0) { + obj->kind = KIND_AUXILIARY; + } else if (strcasecmp(kw, "MUST") == 0) { + obj->must = schema_parse_attrlist(schema); + if (obj->must == NULL) + goto fail; + } else if (strcasecmp(kw, "MAY") == 0) { + obj->may = schema_parse_attrlist(schema); + if (obj->may == NULL) + goto fail; + } + } + + return 0; + +fail: + free(kw); + if (obj != NULL) { + if (obj->oid != NULL) { + RB_REMOVE(object_tree, &schema->objects, obj); + free(obj->oid); + } + free(obj->desc); + free(obj); + } + return -1; +} + +static int +schema_parse_objectidentifier(struct schema *schema) +{ + char *symname = NULL, *symoid = NULL; + char *oid = NULL; + + if (schema_lex(schema, &symname) != STRING) + goto fail; + if (schema_lex(schema, &symoid) != STRING) + goto fail; + + if (is_oidstr(symoid)) { + oid = symoid; + symoid = NULL; + } else if ((oid = lookup_symbolic_oid(schema, symoid)) == NULL) + goto fail; + + if (push_symbolic_oid(schema, symname, oid) == NULL) + goto fail; + + free(symoid); + return 0; + +fail: + free(symname); + free(symoid); + free(oid); + return -1; +} + +int +schema_parse(struct schema *schema, const char *filename) +{ + char *kw; + int token, ret = 0; + + log_debug("parsing schema file '%s'", filename); + + if ((schema->fp = fopen(filename, "r")) == NULL) + return -1; + schema->filename = filename; + schema->lineno = 1; + + while (ret == 0) { + token = schema_lex(schema, &kw); + if (token == STRING) { + if (strcasecmp(kw, "attributetype") == 0) + ret = schema_parse_attributetype(schema); + else if (strcasecmp(kw, "objectclass") == 0) + ret = schema_parse_objectclass(schema); + else if (strcasecmp(kw, "objectidentifier") == 0) + ret = schema_parse_objectidentifier(schema); + else { + schema_err(schema, "syntax error at '%s'", kw); + ret = -1; + } + if (ret == -1 && schema->error == 0) + schema_err(schema, "syntax error"); + free(kw); + } else if (token == 0) { /* EOF */ + break; + } else { + schema_err(schema, "syntax error"); + ret = -1; + } + } + + fclose(schema->fp); + schema->fp = NULL; + schema->filename = NULL; + + return ret; +} + diff --git a/usr.sbin/ldapd/schema.h b/usr.sbin/ldapd/schema.h new file mode 100644 index 00000000000..271a1038d4e --- /dev/null +++ b/usr.sbin/ldapd/schema.h @@ -0,0 +1,139 @@ +/* $OpenBSD: schema.h,v 1.1 2010/06/29 02:45:46 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. + */ + +#ifndef _schema_h_ +#define _schema_h_ + +enum usage { + USAGE_USER_APP, + USAGE_DIR_OP, /* operational attribute */ + USAGE_DIST_OP, /* operational attribute */ + USAGE_DSA_OP /* operational attribute */ +}; + +struct name { + SLIST_ENTRY(name) next; + const char *name; +}; +SLIST_HEAD(name_list, name); + +struct attr_type { + RB_ENTRY(attr_type) link; + char *oid; + struct name_list *names; + char *desc; + int obsolete; + struct attr_type *sup; + char *equality; + char *ordering; + char *substr; + char *syntax; + int single; + int collective; + int immutable; /* no-user-modification */ + enum usage usage; +}; +RB_HEAD(attr_type_tree, attr_type); +RB_PROTOTYPE(attr_type_tree, attr_type, link, attr_oid_cmp); + +struct attr_ptr { + SLIST_ENTRY(attr_ptr) next; + struct attr_type *attr_type; +}; +SLIST_HEAD(attr_list, attr_ptr); + +enum object_kind { + KIND_ABSTRACT, + KIND_STRUCTURAL, + KIND_AUXILIARY +}; + +struct object; +struct obj_ptr { + SLIST_ENTRY(obj_ptr) next; + struct object *object; +}; +SLIST_HEAD(obj_list, obj_ptr); + +struct object { + RB_ENTRY(object) link; + char *oid; + struct name_list *names; + char *desc; + int obsolete; + struct obj_list *sup; + enum object_kind kind; + struct attr_list *must; + struct attr_list *may; +}; +RB_HEAD(object_tree, object); +RB_PROTOTYPE(object_tree, object, link, obj_oid_cmp); + +struct oidname { + RB_ENTRY(oidname) link; + const char *on_name; +#define on_attr_type on_ptr.ou_attr_type +#define on_object on_ptr.ou_object + union { + struct attr_type *ou_attr_type; + struct object *ou_object; + } on_ptr; +}; +RB_HEAD(oidname_tree, oidname); +RB_PROTOTYPE(oidname_tree, oidname, link, oidname_cmp); + +struct symoid { + RB_ENTRY(symoid) link; + char *name; /* symbolic name */ + char *oid; +}; +RB_HEAD(symoid_tree, symoid); +RB_PROTOTYPE(symoid_tree, symoid, link, symoid_cmp); + +#define SCHEMA_MAXPUSHBACK 128 + +struct schema +{ + struct attr_type_tree attr_types; + struct oidname_tree attr_names; + struct object_tree objects; + struct oidname_tree object_names; + struct symoid_tree symbolic_oids; + + FILE *fp; + const char *filename; + char pushback_buffer[SCHEMA_MAXPUSHBACK]; + int pushback_index; + int lineno; + int error; +}; + +struct schema *schema_new(void); +int schema_parse(struct schema *schema, + const char *filename); + +struct attr_type *lookup_attribute_by_oid(struct schema *schema, char *oid); +struct attr_type *lookup_attribute_by_name(struct schema *schema, char *name); +struct attr_type *lookup_attribute(struct schema *schema, char *oid_or_name); +struct object *lookup_object_by_oid(struct schema *schema, char *oid); +struct object *lookup_object_by_name(struct schema *schema, char *name); +struct object *lookup_object(struct schema *schema, char *oid_or_name); +int is_oidstr(const char *oidstr); + +#endif + diff --git a/usr.sbin/ldapd/search.c b/usr.sbin/ldapd/search.c index 37446d527c1..f60ce2f09de 100644 --- a/usr.sbin/ldapd/search.c +++ b/usr.sbin/ldapd/search.c @@ -1,4 +1,4 @@ -/* $OpenBSD: search.c,v 1.6 2010/06/23 13:10:14 martinh Exp $ */ +/* $OpenBSD: search.c,v 1.7 2010/06/29 02:45:46 martinh Exp $ */ /* * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se> @@ -55,7 +55,7 @@ is_operational(char *adesc) { struct attr_type *at; - at = lookup_attribute(adesc); + at = lookup_attribute(conf->schema, adesc); if (at) return at->usage != USAGE_USER_APP; diff --git a/usr.sbin/ldapd/validate.c b/usr.sbin/ldapd/validate.c index b7a3358aadd..6b7a01cc0df 100644 --- a/usr.sbin/ldapd/validate.c +++ b/usr.sbin/ldapd/validate.c @@ -1,4 +1,4 @@ -/* $OpenBSD: validate.c,v 1.1 2010/05/31 17:36:31 martinh Exp $ */ +/* $OpenBSD: validate.c,v 1.2 2010/06/29 02:45:46 martinh Exp $ */ /* * Copyright (c) 2010 Martin Hedenfalk <martin@bzero.se> @@ -140,7 +140,7 @@ validate_dn(const char *dn, struct ber_element *entry) log_debug("got naming attribute %s", na); log_debug("got distinguished value %s", dv); - if ((at = lookup_attribute(na)) == NULL) { + if ((at = lookup_attribute(conf->schema, na)) == NULL) { log_debug("attribute %s not defined in schema", na); goto fail; } @@ -240,7 +240,7 @@ validate_entry(const char *dn, struct ber_element *entry, int relax) for (a = objclass->be_sub; a != NULL; a = a->be_next) { if (ber_get_string(a, &s) != 0) return LDAP_INVALID_SYNTAX; - if ((obj = lookup_object(s)) == NULL) { + if ((obj = lookup_object(conf->schema, s)) == NULL) { log_debug("objectClass %s not defined in schema", s); return LDAP_NAMING_VIOLATION; } @@ -265,7 +265,7 @@ validate_entry(const char *dn, struct ber_element *entry, int relax) for (a = entry->be_sub; a != NULL; a = a->be_next) { if (ber_scanf_elements(a, "{se{", &s, &vals) != 0) return LDAP_INVALID_SYNTAX; - if ((at = lookup_attribute(s)) == NULL) { + if ((at = lookup_attribute(conf->schema, s)) == NULL) { log_debug("attribute %s not defined in schema", s); return LDAP_NAMING_VIOLATION; } |