summaryrefslogtreecommitdiff
path: root/usr.sbin/ldapd
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/ldapd')
-rw-r--r--usr.sbin/ldapd/Makefile6
-rw-r--r--usr.sbin/ldapd/ldapd.h92
-rw-r--r--usr.sbin/ldapd/modify.c6
-rw-r--r--usr.sbin/ldapd/parse.y539
-rw-r--r--usr.sbin/ldapd/schema.c925
-rw-r--r--usr.sbin/ldapd/schema.h139
-rw-r--r--usr.sbin/ldapd/search.c4
-rw-r--r--usr.sbin/ldapd/validate.c8
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(&current_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(&current_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;
}