This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Description: add schema check functionality
*
* Author: Simo Sorce
- *
- * License: GNU GPL v2 or Later
*/
#include "includes.h"
#include "libcli/ldap/ldap.h"
#include "ldb/include/ldb_errors.h"
#include "ldb/include/ldb_private.h"
-#include "include/dlinklist.h"
+#include "lib/util/dlinklist.h"
+#include "schema_syntax.h"
/* Syntax-Table
see ldap_server/devdocs/AD-syntaxes.txt
*/
-enum schema_int_attr_id {
- SCHEMA_AS_BOOLEAN,
- SCHEMA_AS_INTEGER,
- SCHEMA_AS_OCTET_STRING,
- SCHEMA_AS_SID,
- SCHEMA_AS_OID,
- SCHEMA_AS_ENUMERATION,
- SCHEMA_AS_NUMERIC_STRING,
- SCHEMA_AS_PRINTABLE_STRING,
- SCHEMA_AS_CASE_IGNORE_STRING,
- SCHEMA_AS_IA5_STRING,
- SCHEMA_AS_UTC_TIME,
- SCHEMA_AS_GENERALIZED_TIME,
- SCHEMA_AS_CASE_SENSITIVE_STRING,
- SCHEMA_AS_DIRECTORY_STRING,
- SCHEMA_AS_LARGE_INTEGER,
- SCHEMA_AS_OBJECT_SECURITY_DESCRIPTOR,
- SCHEMA_AS_DN,
- SCHEMA_AS_DN_BINARY,
- SCHEMA_AS_OR_NAME,
- SCHEMA_AS_REPLICA_LINK,
- SCHEMA_AS_PRESENTATION_ADDRESS,
- SCHEMA_AS_ACCESS_POINT,
- SCHEMA_AS_DN_STRING
-};
-
enum schema_class_type {
SCHEMA_CT_88 = 0,
SCHEMA_CT_STRUCTURAL = 1,
struct schema_attribute {
char *OID; /* attributeID */
char *name; /* lDAPDisplayName */
- enum schema_int_attr_id syntax; /* generated from attributeSyntax, oMSyntax, oMObjectClass */
+ enum schema_internal_syntax syntax; /* generated from attributeSyntax, oMSyntax, oMObjectClass */
bool single; /* isSingleValued */
int min; /* rangeLower */
int max; /* rangeUpper */
+ int systemflag; /* systemFlag */
+ int searchflag; /* searchFlag */
+ bool isdefunct; /* isDefunct */
};
struct schema_class {
- char *OID; /* governsID */
- char *name; /* lDAPDisplayName */
- enum schema_class_type type; /* objectClassCategory */
- bool systemOnly; /* systemOnly */
- struct schema_class *parent; /* subClassOf */
- struct schema_class **sysaux; /* systemAuxiliaryClass */
- struct schema_class **aux; /* auxiliaryClass */
- struct schema_class **sysposssup; /* systemPossSuperiors */
- struct schema_class **posssup; /* possSuperiors */
- struct schema_class **possinf; /* possibleInferiors */
- struct schema_attribute **sysmust; /* systemMustContain */
- struct schema_attribute **must; /* MustContain */
- struct schema_attribute **sysmay; /* systemMayContain */
- struct schema_attribute **may; /* MayContain */
+ char *OID; /* governsID */
+ char *name; /* lDAPDisplayName */
+ enum schema_class_type type; /* objectClassCategory */
+ bool systemOnly; /* systemOnly */
+ bool isdefunct; /* isDefunct */
+ int systemflag; /* systemFlag */
+ char *defobjcat; /* defaultObjectCategory */
+ struct schema_class *parent; /* subClassOf */
+ struct schema_class **sysaux; /* systemAuxiliaryClass */
+ struct schema_class **aux; /* auxiliaryClass */
+ struct schema_class **sysposssup; /* systemPossSuperiors */
+ struct schema_class **posssup; /* possSuperiors */
+ struct schema_class **possinf; /* possibleInferiors */
+ struct schema_attribute **sysmust; /* systemMustContain */
+ struct schema_attribute **must; /* MustContain */
+ struct schema_attribute **sysmay; /* systemMayContain */
+ struct schema_attribute **may; /* MayContain */
};
/* TODO: ditcontentrules */
return list;
}
-static int map_schema_syntax(uint32_t om_syntax, const char *attr_syntax, const struct ldb_val *om_class, enum schema_int_attr_id *syntax)
-{
- int ret;
-
- ret = LDB_SUCCESS;
-
- switch(om_syntax) {
- case 1:
- *syntax = SCHEMA_AS_BOOLEAN;
- break;
- case 2:
- *syntax = SCHEMA_AS_INTEGER;
- break;
- case 4:
- if (strcmp(attr_syntax, "2.5.5.10") == 0) {
- *syntax = SCHEMA_AS_OCTET_STRING;
- break;
- }
- if (strcmp(attr_syntax, "2.5.5.17") == 0) {
- *syntax = SCHEMA_AS_SID;
- break;
- }
- ret = LDB_ERR_OPERATIONS_ERROR;
- break;
- case 6:
- *syntax = SCHEMA_AS_OID;
- break;
- case 10:
- *syntax = SCHEMA_AS_ENUMERATION;
- break;
- case 18:
- *syntax = SCHEMA_AS_NUMERIC_STRING;
- break;
- case 19:
- *syntax = SCHEMA_AS_PRINTABLE_STRING;
- break;
- case 20:
- *syntax = SCHEMA_AS_CASE_IGNORE_STRING;
- break;
- case 22:
- *syntax = SCHEMA_AS_IA5_STRING;
- break;
- case 23:
- *syntax = SCHEMA_AS_UTC_TIME;
- break;
- case 24:
- *syntax = SCHEMA_AS_GENERALIZED_TIME;
- break;
- case 27:
- *syntax = SCHEMA_AS_CASE_SENSITIVE_STRING;
- break;
- case 64:
- *syntax = SCHEMA_AS_DIRECTORY_STRING;
- break;
- case 65:
- *syntax = SCHEMA_AS_LARGE_INTEGER;
- break;
- case 66:
- *syntax = SCHEMA_AS_OBJECT_SECURITY_DESCRIPTOR;
- break;
- case 127:
- if (!om_class) {
- ret = LDB_ERR_OPERATIONS_ERROR;
- break;
- }
-
- if (memcmp(om_class->data, "\x2b\x0c\x02\x87\x73\x1c\x00\x85\x4a\x00", MIN(om_class->length, 10)) == 0) {
- *syntax = SCHEMA_AS_DN;
- break;
- }
- if (memcmp(om_class->data, "\x2a\x86\x48\x86\xf7\x14\x01\x01\x01\x0b", MIN(om_class->length, 10)) == 0) {
- *syntax = SCHEMA_AS_DN_BINARY;
- break;
- }
- if (memcmp(om_class->data, "\x56\x06\x01\x02\x05\x0b\x1d\x00\x00\x00", MIN(om_class->length, 10)) == 0) {
- *syntax = SCHEMA_AS_OR_NAME;
- break;
- }
- if (memcmp(om_class->data, "\x2a\x86\x48\x86\xf7\x14\x01\x01\x01\x06", MIN(om_class->length, 10)) == 0) {
- *syntax = SCHEMA_AS_REPLICA_LINK;
- break;
- }
- if (memcmp(om_class->data, "\x2b\x0c\x02\x87\x73\x1c\x00\x85\x5c\x00", MIN(om_class->length, 10)) == 0) {
- *syntax = SCHEMA_AS_PRESENTATION_ADDRESS;
- break;
- }
- if (memcmp(om_class->data, "\x2b\x0c\x02\x87\x73\x1c\x00\x85\x3e\x00", MIN(om_class->length, 10)) == 0) {
- *syntax = SCHEMA_AS_ACCESS_POINT;
- break;
- }
- if (memcmp(om_class->data, "\x2a\x86\x48\x86\xf7\x14\x01\x01\x01\x0c", MIN(om_class->length, 10)) == 0) {
- *syntax = SCHEMA_AS_DN_STRING;
- break;
- }
- /* not found will error in default: */
- default:
- ret = LDB_ERR_OPERATIONS_ERROR;
- }
-
- return ret;
-}
-
static int schema_init_attrs(struct ldb_module *module, struct schema_private_data *data)
{
static const char *schema_attrs[] = { "attributeID",
"isSingleValued",
"rangeLower",
"rangeUpper",
+ "searchFlag",
+ "systemFlag",
+ "isDefunct",
NULL };
struct ldb_result *res;
int ret, i;
data->attrs[i]->single = 0;
}
- /* rangeLower and rangeUpper are optional */
- data->attrs[i]->min = ldb_msg_find_attr_as_int(res->msgs[i], "rangeLower", -1);
- data->attrs[i]->max = ldb_msg_find_attr_as_int(res->msgs[i], "rangeUpper", -1);
+ /* the following are optional */
+ data->attrs[i]->min = ldb_msg_find_attr_as_int(res->msgs[i], "rangeLower", INT_MIN);
+ data->attrs[i]->max = ldb_msg_find_attr_as_int(res->msgs[i], "rangeUpper", INT_MAX);
+ data->attrs[i]->systemflag = ldb_msg_find_attr_as_int(res->msgs[i], "systemFlag", 0);
+ data->attrs[i]->searchflag = ldb_msg_find_attr_as_int(res->msgs[i], "searchFlag", 0);
+ data->attrs[i]->isdefunct = ldb_msg_find_attr_as_bool(res->msgs[i], "isDefunct", false);
}
done:
static int schema_init_classes(struct ldb_module *module, struct schema_private_data *data)
{
- static const char *schema_attrs[] = { "governsID",
+ const char *schema_attrs[] = { "governsID",
"lDAPDisplayName",
"objectClassCategory",
+ "defaultObjectCategory",
"systemOnly",
+ "systemFlag",
+ "isDefunct",
"subClassOf",
"systemAuxiliaryClass",
"auxiliaryClass",
/* 0 should not be a valid value, but turn out it is so test with -1 */
SCHEMA_CHECK_VALUE(data->class[i]->type, -1, module);
+ data->class[i]->defobjcat = talloc_strdup(data->class[i],
+ ldb_msg_find_attr_as_string(res->msgs[i],
+ "defaultObjectCategory", NULL));
+/* SCHEMA_CHECK_VALUE(data->class[i]->defobjcat, NULL, module);
+*/
/* the following attributes are all optional */
- data->class[i]->systemOnly = ldb_msg_find_attr_as_bool(res->msgs[i], "systemOnly", False);
+ data->class[i]->systemOnly = ldb_msg_find_attr_as_bool(res->msgs[i], "systemOnly", false);
+ data->class[i]->systemflag = ldb_msg_find_attr_as_int(res->msgs[i], "systemFlag", 0);
+ data->class[i]->isdefunct = ldb_msg_find_attr_as_bool(res->msgs[i], "isDefunct", false);
/* attributes are loaded first, so we can just go an query the attributes repo */
{
struct schema_context *sctx;
- if (!context || !ares) {
- ldb_set_errstring(ldb, "NULL Context or Result in callback");
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
sctx = talloc_get_type(context, struct schema_context);
/* we are interested only in the single reply (base search) we receive here */
static int schema_add_build_parent_req(struct schema_context *sctx)
{
- static const char * const parent_attrs[] = { "objectClass", NULL };
+ const char * const parent_attrs[] = { "objectClass", NULL };
int ret;
sctx->parent_req = talloc_zero(sctx, struct ldb_request);
sctx->parent_req->operation = LDB_SEARCH;
sctx->parent_req->op.search.scope = LDB_SCOPE_BASE;
sctx->parent_req->op.search.base = ldb_dn_get_parent(sctx->parent_req, sctx->orig_req->op.add.message->dn);
- sctx->parent_req->op.search.tree = ldb_parse_tree(sctx->module->ldb, "(objectClass=*)");
+ sctx->parent_req->op.search.tree = ldb_parse_tree(sctx->parent_req, "(objectClass=*)");
sctx->parent_req->op.search.attrs = parent_attrs;
sctx->parent_req->controls = NULL;
sctx->parent_req->context = sctx;
struct schema_class_dlist *temp;
int ret;
+ /* see if this class is usable */
+ if (class->isdefunct) {
+ return LDB_ERR_NO_SUCH_ATTRIBUTE;
+ }
+
/* see if this class already exist in the class list */
if (schema_add_get_dlist_entry_with_class(list, class)) {
return LDB_SUCCESS;
class = schema_store_find(sctx->data->class_store, (char *)el->values[i].data);
if (!class) {
- return LDB_ERR_NO_SUCH_OBJECT;
+ return LDB_ERR_NO_SUCH_ATTRIBUTE;
}
ret = schema_add_class_to_dlist(sctx->class_list, class, class->type);
return LDB_ERR_OPERATIONS_ERROR;
}
+ /* rebuild the objectclass list */
ldb_msg_remove_attr(msg, "objectClass");
- ret = ldb_msg_add_empty(msg, "objectClass", 0);
+ ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
if (ret != LDB_SUCCESS) {
return ret;
}
return ret;
}
}
-
+
+ /* objectCategory can be set only by the system */
+ if (ldb_msg_find_element(msg, "objectCategory")) {
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ /* the OC is mandatory, every class defines it */
+ /* use the one defined in the structural class that defines the object */
+ for (temp = sctx->class_list->next; temp; temp = temp->next) {
+ if (!temp->next) break;
+ if (temp->next->role != SCHEMA_CT_STRUCTURAL) break;
+ }
+/* oc = talloc_strdup(msg, temp->class->defobjcat);
+ ret = ldb_msg_add_string(msg, "objectCategory", oc);
+*/
sctx->down_req->op.add.message = msg;
return LDB_SUCCESS;
}
+static int schema_check_attributes_syntax(struct schema_context *sctx)
+{
+ struct ldb_message *msg;
+ struct schema_attribute *attr;
+ int i, ret;
+
+ msg = sctx->orig_req->op.add.message;
+ for (i = 0; i < msg->num_elements; i++) {
+ attr = schema_store_find(sctx->data->attrs_store, msg->elements[i].name);
+ if (attr == NULL) {
+ return LDB_ERR_NO_SUCH_ATTRIBUTE;
+ }
+ ret = schema_validate(sctx->module->ldb, &msg->elements[i], attr->syntax, attr->single, attr->min, attr->max);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
static int schema_add_continue(struct ldb_handle *h)
{
struct schema_context *sctx;
}
/* check attributes syntax */
- /*
+
ret = schema_check_attributes_syntax(sctx);
if (ret != LDB_SUCCESS) {
break;
}
- */
ret = schema_add_build_down_req(sctx);
if (ret != LDB_SUCCESS) {
static int schema_modify(struct ldb_module *module, struct ldb_request *req)
{
- struct ldb_handle *h;
- struct schema_context *sctx;
-
if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
return ldb_next_request(module, req);
}
static int schema_delete(struct ldb_module *module, struct ldb_request *req)
{
- struct ldb_handle *h;
- struct schema_context *sctx;
-
if (ldb_dn_is_special(req->op.del.dn)) { /* do not manipulate our control entries */
return ldb_next_request(module, req);
}
static int schema_rename(struct ldb_module *module, struct ldb_request *req)
{
- struct ldb_handle *h;
- struct schema_context *sctx;
-
if (ldb_dn_is_special(req->op.rename.olddn) &&
ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
return ldb_next_request(module, req);
struct ldb_result *res;
int ret;
- /* need to let the partiorion module to register first */
+ /* need to let the partition module to register first */
ret = ldb_next_init(module);
if (ret != LDB_SUCCESS) {
return ret;
}
- data = talloc_zero(module, struct schema_private_data);
+ data = ldb_get_opaque(module->ldb, "schema_instance");
+ if (data) {
+ module->private_data = data;
+ return LDB_SUCCESS;
+ }
+
+ data = talloc_zero(module->ldb, struct schema_private_data);
if (data == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
/* find the schema partition */
ret = ldb_search(module->ldb,
- ldb_dn_new(module),
+ ldb_dn_new(module, module->ldb, NULL),
LDB_SCOPE_BASE,
"(objectClass=*)",
schema_attrs,
return LDB_ERR_OPERATIONS_ERROR;
}
- data->schema_dn = ldb_msg_find_attr_as_dn(data, res->msgs[0], "schemaNamingContext");
+ data->schema_dn = ldb_msg_find_attr_as_dn(module->ldb, data, res->msgs[0], "schemaNamingContext");
if (data->schema_dn == NULL) {
/* FIXME: return a clear error string */
talloc_free(data);
}
module->private_data = data;
+ ldb_set_opaque(module->ldb, "schema_instance", data);
+
return LDB_SUCCESS;
}
-static const struct ldb_module_ops schema_ops = {
+_PUBLIC_ const struct ldb_module_ops ldb_schema_module_ops = {
.name = "schema",
.init_context = schema_init,
.add = schema_add,
.rename = schema_rename,
.wait = schema_wait
};
-
-int ldb_schema_init(void)
-{
- return ldb_register_module(&schema_ops);
-}