Hi, I found a crash on ldapd while parsing schema file, and wrote a fix for the crash. It's first time for me to send a patch to OpenBSD, so if there's any problem please let me know.
The crash is found on -CURRENT, and the patch is written based on latest CVS version. nis.schema from -CURRENT and additional sshkey.schema file is needed to reproduce the crash. Here's content of sshkey.schema -- attributetype ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) objectclass ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY MUST ( sshPublicKey $ uid ) ) -- Here's first ldapd.conf file which crashes ldapd -- schema "/etc/ldap/nis.schema" schema "sshkey.schema" schema "/etc/ldap/nis.schema" schema "sshkey.schema" -- Here's second ldapd.conf file, similar with the first one but crashed on different point -- schema "/etc/ldap/nis.schema" schema "sshkey.schema" namespace "d=a" schema "sshkey.schema" namespace "d=a" schema "/etc/ldap/nis.schema" -- Finally, here's the patch. Index: usr.sbin/ldapd/schema.c =================================================================== RCS file: /cvs/src/usr.sbin/ldapd/schema.c,v retrieving revision 1.16 diff -u -p -r1.16 schema.c --- usr.sbin/ldapd/schema.c 16 Nov 2014 19:04:40 -0000 1.16 +++ usr.sbin/ldapd/schema.c 18 Jan 2015 12:58:48 -0000 @@ -453,6 +453,18 @@ schema_err(struct schema *schema, const schema->error++; } +static void +schema_unlink_attr_name(struct schema *schema, const char *name, struct attr_type *attr) +{ + struct oidname find, *oidname; + + find.on_name = name; + oidname = RB_FIND(oidname_tree, &schema->attr_names, &find); + if (oidname != NULL) { + RB_REMOVE(oidname_tree, &schema->attr_names, oidname); + } +} + static int schema_link_attr_name(struct schema *schema, const char *name, struct attr_type *attr) { @@ -490,6 +502,16 @@ schema_link_attr_names(struct schema *sc } static int +schema_unlink_attr_names(struct schema *schema, struct attr_type *attr) +{ + struct name *name; + + SLIST_FOREACH(name, attr->names, next) { + schema_unlink_attr_name(schema, name->name, attr); + } +} + +static int schema_link_obj_name(struct schema *schema, const char *name, struct object *obj) { struct oidname *oidname, *prev; @@ -513,6 +535,18 @@ schema_link_obj_name(struct schema *sche return 0; } +static void +schema_unlink_obj_name(struct schema *schema, const char *name, struct object *obj) +{ + struct oidname find, *oidname; + + find.on_name = name; + oidname = RB_FIND(oidname_tree, &schema->object_names, &find); + if(oidname != NULL) { + RB_REMOVE(oidname_tree, &schema->object_names, oidname); + } +} + static int schema_link_obj_names(struct schema *schema, struct object *obj) { @@ -525,6 +559,16 @@ schema_link_obj_names(struct schema *sch return 0; } +static void +schema_unlink_obj_names(struct schema *schema, struct object *obj) +{ + struct name *name; + + SLIST_FOREACH(name, obj->names, next) { + schema_unlink_obj_name(schema, name->name, obj); + } +} + static struct name_list * schema_parse_names(struct schema *schema) { @@ -879,6 +923,9 @@ schema_parse_attributetype(struct schema fail: free(kw); if (attr != NULL) { + if(attr->names != NULL) { + schema_unlink_attr_names(schema, attr); + } if (attr->oid != NULL) { RB_REMOVE(attr_type_tree, &schema->attr_types, attr); free(attr->oid); @@ -1013,6 +1060,9 @@ schema_parse_objectclass(struct schema * fail: free(kw); if (obj != NULL) { + if (obj->names != NULL) { + schema_unlink_obj_names(schema, obj); + } if (obj->oid != NULL) { RB_REMOVE(object_tree, &schema->objects, obj); free(obj->oid);