summaryrefslogtreecommitdiff
path: root/source4/lib/ldb/modules/schema.c
diff options
context:
space:
mode:
authorSimo Sorce <idra@samba.org>2005-01-04 15:18:50 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:08:17 -0500
commit8d8c21f8d0669b469b2540c3f9e91ca5d076db09 (patch)
tree9a038e7ccd92451777e28c61b14b4cdf7dc15a33 /source4/lib/ldb/modules/schema.c
parent5f8802ff01aaf8a9604dfca734b9924ebf5d4d4e (diff)
downloadsamba-8d8c21f8d0669b469b2540c3f9e91ca5d076db09.tar.gz
samba-8d8c21f8d0669b469b2540c3f9e91ca5d076db09.tar.bz2
samba-8d8c21f8d0669b469b2540c3f9e91ca5d076db09.zip
r4513: add experimental modification attribute checking
still not complete but works with add and replace, not tested with delete lot of duplicated code to remove (This used to be commit ea051f6cd39d0e729bb425eb08034a0eee0996dc)
Diffstat (limited to 'source4/lib/ldb/modules/schema.c')
-rw-r--r--source4/lib/ldb/modules/schema.c452
1 files changed, 451 insertions, 1 deletions
diff --git a/source4/lib/ldb/modules/schema.c b/source4/lib/ldb/modules/schema.c
index f083eeb6e5..1f9017976e 100644
--- a/source4/lib/ldb/modules/schema.c
+++ b/source4/lib/ldb/modules/schema.c
@@ -136,6 +136,7 @@ static int schema_add_record(struct ldb_module *module, const struct ldb_message
}
ss->ol = NULL;
+ ss->num_objc = 0;
ss->num_cl = msg->num_elements;
ss->cl = talloc_array_p(ss, struct check_list, ss->num_cl);
SCHEMA_TALLOC_CHECK(ss, ss->cl, -1);
@@ -306,7 +307,7 @@ static int schema_add_record(struct ldb_module *module, const struct ldb_message
}
}
- ldb_search_free(module->ldb, srch);
+ ldb_search_free(data->schema_db, srch);
}
/* now check all musts are present */
@@ -362,6 +363,455 @@ static int schema_add_record(struct ldb_module *module, const struct ldb_message
static int schema_modify_record(struct ldb_module *module, const struct ldb_message *msg)
{
struct private_data *data = (struct private_data *)module->private_data;
+ struct ldb_message **srch;
+ struct schema_structures *ss, *ms;
+ int i, j, k, l;
+ int ret;
+
+ /* First implementation:
+ Retrieve the ldap entry and get the objectclasses,
+ add msg contained objectclasses if any.
+ Build up a list of must and mays from each objectclass
+ Check all musts for the defined objectclass and it's specific
+ inheritance are there.
+ Check all other the attributes are mays or musts.
+ Throw an error in case a check fail.
+ Free all structures and commit the change.
+ */
+
+ ss = talloc_p(module, struct schema_structures);
+ if (!ss) {
+ return -1;
+ }
+
+ ms = talloc_p(module, struct schema_structures);
+ SCHEMA_TALLOC_CHECK(ss, ms, -1);
+
+ ms->ol = NULL;
+ ms->num_objc = 0;
+ ms->num_cl = msg->num_elements;
+ ms->cl = talloc_array_p(ms, struct check_list, ms->num_cl);
+ SCHEMA_TALLOC_CHECK(ss, ms->cl, -1);
+ for (i = 0, j = 0; i < msg->num_elements; i++) {
+ if (strcasecmp(msg->elements[i].name, "objectclass") == 0) {
+ ms->num_objc = msg->elements[i].num_values;
+ ms->ol = talloc_array_p(ms, struct objc_list, ms->num_objc);
+ SCHEMA_TALLOC_CHECK(ss, ms->ol, -1);
+ for (k = 0; k < ms->num_objc; k++) {
+ ms->ol[k].name = talloc_strndup(ms->ol, msg->elements[i].values[k].data, msg->elements[i].values[k].length);
+ SCHEMA_TALLOC_CHECK(ss, ms->ol[k].name, -1);
+ ms->ol[k].aux = 0;
+ }
+ }
+
+ ms->cl[j].check = 0;
+ ms->cl[j].name = talloc_strdup(ms->cl, msg->elements[i].name);
+ SCHEMA_TALLOC_CHECK(ss, ms->cl[j].name, -1);
+ j++;
+ }
+
+ /* find all modify objectclasses recursively if any objectclass is being added */
+ ms->must = NULL;
+ ms->may = NULL;
+ ms->num_must = 0;
+ ms->num_may = 0;
+ for (i = 0; i < ms->num_objc; i++) {
+ char *filter;
+
+ filter = talloc_asprintf(ss, "lDAPDisplayName=%s", ms->ol[i].name);
+ SCHEMA_TALLOC_CHECK(ss, filter, -1);
+ ret = ldb_search(data->schema_db, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &srch);
+ if (ret == 0) {
+ int ok;
+
+ ok = 0;
+ /* suppose auxiliary classess are not required */
+ if (ms->ol[i].aux) {
+ int d;
+ ok = 1;
+ ms->num_objc -= 1;
+ for (d = i; d < ms->num_objc; d++) {
+ ms->ol[d] = ms->ol[d + 1];
+ }
+ i -= 1;
+ }
+ if (!ok) {
+ /* Schema Violation: Object Class Description Not Found */
+ data->error_string = "ObjectClass not found";
+ talloc_free(ss);
+ return -1;
+ }
+ continue;
+ } else {
+ if (ret < 0) {
+ /* Schema DB Error: Error occurred retrieving Object Class Description */
+ data->error_string = "Internal error. Error retrieving schema objectclass";
+ talloc_free(ss);
+ return -1;
+ }
+ if (ret > 1) {
+ /* Schema DB Error: Too Many Records */
+ data->error_string = "Internal error. Too many records searching for schema objectclass";
+ talloc_free(ss);
+ return -1;
+ }
+ }
+
+ /* Add inherited classes eliminating duplicates */
+ /* fill in kust and may attribute lists */
+ for (j = 0; j < (*srch)->num_elements; j++) {
+ int o, is_aux, is_class;
+
+ is_aux = 0;
+ is_class = 0;
+ if (strcasecmp((*srch)->elements[j].name, "systemAuxiliaryclass") == 0) {
+ is_aux = 1;
+ is_class = 1;
+ }
+ if (strcasecmp((*srch)->elements[j].name, "subClassOf") == 0) {
+ is_class = 1;
+ }
+
+ if (is_class) {
+ o = (*srch)->elements[j].num_values;
+ ms->ol = talloc_realloc_p(ms, ms->ol, struct objc_list, ms->num_objc + o);
+ SCHEMA_TALLOC_CHECK(ss, ms->ol, -1);
+ for (k = 0, l = 0; k < o; k++) {
+ int c, found, len;
+
+ found = 0;
+ for (c = 0; c < ms->num_objc; c++) {
+ len = strlen(ms->ol[c].name);
+ if (len == (*srch)->elements[j].values[k].length) {
+ if (strncasecmp(ss->ol[c].name, (*srch)->elements[j].values[k].data, len) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ ms->ol[l + ms->num_objc].name = talloc_strndup(ms->ol, (*srch)->elements[j].values[k].data, (*srch)->elements[j].values[k].length);
+ SCHEMA_TALLOC_CHECK(ss, ms->ol[l + ms->num_objc].name, -1);
+ ms->ol[l + ms->num_objc].aux = is_aux;
+ l++;
+ }
+ }
+ ms->num_objc += l;
+ } else {
+
+ if (strcasecmp((*srch)->elements[j].name, "mustContain") == 0 || strcasecmp((*srch)->elements[j].name, "SystemMustContain") == 0) {
+ int m;
+
+ m = (*srch)->elements[j].num_values;
+
+ ms->must = talloc_realloc_p(ms, ms->must, struct attr_list, ms->num_must + m);
+ SCHEMA_TALLOC_CHECK(ss, ms->must, -1);
+ for (k = 0, l = 0; k < m; k++) {
+ int c, found, len;
+
+ found = 0;
+ for (c = 0; c < ms->num_must; c++) {
+ len = strlen(ms->must[c].name);
+ if (len == (*srch)->elements[j].values[k].length) {
+ if (strncasecmp(ms->must[c].name, (*srch)->elements[j].values[k].data, len) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ ms->must[l + ms->num_must].name = talloc_strndup(ms->must, (*srch)->elements[j].values[k].data, (*srch)->elements[j].values[k].length);
+ SCHEMA_TALLOC_CHECK(ss, ms->must[l + ms->num_must].name, -1);
+ l++;
+ }
+ }
+ ms->num_must += l;
+ }
+
+ if (strcasecmp((*srch)->elements[j].name, "mayContain") == 0 || strcasecmp((*srch)->elements[j].name, "SystemMayContain") == 0) {
+ int m;
+
+ m = (*srch)->elements[j].num_values;
+
+ ms->may = talloc_realloc_p(ms, ms->may, struct attr_list, ms->num_may + m);
+ SCHEMA_TALLOC_CHECK(ss, ms->may, -1);
+ for (k = 0, l = 0; k < m; k++) {
+ int c, found, len;
+
+ found = 0;
+ for (c = 0; c < ms->num_may; c++) {
+ len = strlen(ms->may[c].name);
+ if (len == (*srch)->elements[j].values[k].length) {
+ if (strncasecmp(ms->may[c].name, (*srch)->elements[j].values[k].data, (*srch)->elements[j].values[k].length) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ ms->may[l + ms->num_may].name = talloc_strndup(ms->may, (*srch)->elements[j].values[k].data, (*srch)->elements[j].values[k].length);
+ SCHEMA_TALLOC_CHECK(ss, ms->may[l + ms->num_may].name, -1);
+ l++;
+ }
+ }
+ ms->num_may += l;
+ }
+ }
+ }
+
+ ldb_search_free(data->schema_db, srch);
+ }
+
+ /* now search for the original object objectclasses */
+
+ ss->ol = NULL;
+ ss->num_objc = 0;
+
+ /* find all other objectclasses recursively */
+ {
+ char *filter = talloc_asprintf(ss, "dn=%s", msg->dn);
+ const char *attrs[] = {"objectClass", NULL};
+
+ ret = ldb_search(module->ldb, NULL, LDB_SCOPE_SUBTREE, filter, attrs, &srch);
+ if (ret == 1) {
+ for (i = 0; i < msg->num_elements; i++) {
+ ss->num_objc = (*srch)->elements[i].num_values;
+ ss->ol = talloc_array_p(ss, struct objc_list, ss->num_objc);
+ SCHEMA_TALLOC_CHECK(ss, ss->ol, -1);
+ for (k = 0; k < ss->num_objc; k++) {
+ ss->ol[k].name = talloc_strndup(ss->ol, (*srch)->elements[i].values[k].data, (*srch)->elements[i].values[k].length);
+ SCHEMA_TALLOC_CHECK(ss, ss->ol[k].name, -1);
+ ss->ol[k].aux = 0;
+ }
+ }
+ ldb_search_free(module->ldb, srch);
+ } else {
+ ldb_search_free(module->ldb, srch);
+ return -1;
+ }
+ }
+
+ ss->must = NULL;
+ ss->may = NULL;
+ ss->num_must = 0;
+ ss->num_may = 0;
+ for (i = 0; i < ss->num_objc; i++) {
+ char *filter;
+
+ filter = talloc_asprintf(ss, "lDAPDisplayName=%s", ss->ol[i].name);
+ SCHEMA_TALLOC_CHECK(ss, filter, -1);
+ ret = ldb_search(data->schema_db, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &srch);
+ if (ret == 0) {
+ int ok;
+
+ ok = 0;
+ /* suppose auxiliary classess are not required */
+ if (ss->ol[i].aux) {
+ int d;
+ ok = 1;
+ ss->num_objc -= 1;
+ for (d = i; d < ss->num_objc; d++) {
+ ss->ol[d] = ss->ol[d + 1];
+ }
+ i -= 1;
+ }
+ if (!ok) {
+ /* Schema Violation: Object Class Description Not Found */
+ data->error_string = "ObjectClass not found";
+ talloc_free(ss);
+ return -1;
+ }
+ continue;
+ } else {
+ if (ret < 0) {
+ /* Schema DB Error: Error occurred retrieving Object Class Description */
+ data->error_string = "Internal error. Error retrieving schema objectclass";
+ talloc_free(ss);
+ return -1;
+ }
+ if (ret > 1) {
+ /* Schema DB Error: Too Many Records */
+ data->error_string = "Internal error. Too many records searching for schema objectclass";
+ talloc_free(ss);
+ return -1;
+ }
+ }
+
+ /* Add inherited classes eliminating duplicates */
+ /* fill in kust and may attribute lists */
+ for (j = 0; j < (*srch)->num_elements; j++) {
+ int o, is_aux, is_class;
+
+ is_aux = 0;
+ is_class = 0;
+ if (strcasecmp((*srch)->elements[j].name, "systemAuxiliaryclass") == 0) {
+ is_aux = 1;
+ is_class = 1;
+ }
+ if (strcasecmp((*srch)->elements[j].name, "subClassOf") == 0) {
+ is_class = 1;
+ }
+
+ if (is_class) {
+ o = (*srch)->elements[j].num_values;
+ ss->ol = talloc_realloc_p(ss, ss->ol, struct objc_list, ss->num_objc + o);
+ SCHEMA_TALLOC_CHECK(ss, ss->ol, -1);
+ for (k = 0, l = 0; k < o; k++) {
+ int c, found, len;
+
+ found = 0;
+ for (c = 0; c < ss->num_objc; c++) {
+ len = strlen(ss->ol[c].name);
+ if (len == (*srch)->elements[j].values[k].length) {
+ if (strncasecmp(ss->ol[c].name, (*srch)->elements[j].values[k].data, len) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ ss->ol[l + ss->num_objc].name = talloc_strndup(ss->ol, (*srch)->elements[j].values[k].data, (*srch)->elements[j].values[k].length);
+ SCHEMA_TALLOC_CHECK(ss, ss->ol[l + ss->num_objc].name, -1);
+ ss->ol[l + ss->num_objc].aux = is_aux;
+ l++;
+ }
+ }
+ ss->num_objc += l;
+ } else {
+
+ if (strcasecmp((*srch)->elements[j].name, "mustContain") == 0 || strcasecmp((*srch)->elements[j].name, "SystemMustContain") == 0) {
+ int m;
+
+ m = (*srch)->elements[j].num_values;
+
+ ss->must = talloc_realloc_p(ss, ss->must, struct attr_list, ss->num_must + m);
+ SCHEMA_TALLOC_CHECK(ss, ss->must, -1);
+ for (k = 0, l = 0; k < m; k++) {
+ int c, found, len;
+
+ found = 0;
+ for (c = 0; c < ss->num_must; c++) {
+ len = strlen(ss->must[c].name);
+ if (len == (*srch)->elements[j].values[k].length) {
+ if (strncasecmp(ss->must[c].name, (*srch)->elements[j].values[k].data, len) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ ss->must[l + ss->num_must].name = talloc_strndup(ss->must, (*srch)->elements[j].values[k].data, (*srch)->elements[j].values[k].length);
+ SCHEMA_TALLOC_CHECK(ss, ss->must[l + ss->num_must].name, -1);
+ l++;
+ }
+ }
+ ss->num_must += l;
+ }
+
+ if (strcasecmp((*srch)->elements[j].name, "mayContain") == 0 || strcasecmp((*srch)->elements[j].name, "SystemMayContain") == 0) {
+ int m;
+
+ m = (*srch)->elements[j].num_values;
+
+ ss->may = talloc_realloc_p(ss, ss->may, struct attr_list, ss->num_may + m);
+ SCHEMA_TALLOC_CHECK(ss, ss->may, -1);
+ for (k = 0, l = 0; k < m; k++) {
+ int c, found, len;
+
+ found = 0;
+ for (c = 0; c < ss->num_may; c++) {
+ len = strlen(ss->may[c].name);
+ if (len == (*srch)->elements[j].values[k].length) {
+ if (strncasecmp(ss->may[c].name, (*srch)->elements[j].values[k].data, (*srch)->elements[j].values[k].length) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ ss->may[l + ss->num_may].name = talloc_strndup(ss->may, (*srch)->elements[j].values[k].data, (*srch)->elements[j].values[k].length);
+ SCHEMA_TALLOC_CHECK(ss, ss->may[l + ss->num_may].name, -1);
+ l++;
+ }
+ }
+ ss->num_may += l;
+ }
+ }
+ }
+
+ ldb_search_free(data->schema_db, srch);
+ }
+
+ /* now check all entries are present either as musts or mays of curent objectclasses */
+ /* do not return errors there may be attirbutes defined in new objectclasses */
+ /* just mark them as being proved valid attribs */
+ for (i = 0; i < ms->num_cl; i++) {
+ int found;
+
+ found = 0;
+ for (j = 0; j < ss->num_may; j++) {
+ if (strcasecmp(ss->may[j].name, ms->cl[i].name) == 0) {
+ ms->cl[i].check = 1;
+ found = 1;
+ break;
+ }
+ }
+ if ( ! found) {
+ for (j = 0; j < ss->num_must; j++) {
+ if (strcasecmp(ss->must[j].name, ms->cl[i].name) == 0) {
+ ms->cl[i].check = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ /* now check all new objectclasses musts are present */
+ for (i = 0; i < ms->num_must; i++) {
+ int found;
+
+ found = 0;
+ for (j = 0; j < ms->num_cl; j++) {
+ if (strcasecmp(ms->must[i].name, ms->cl[j].name) == 0) {
+ ms->cl[j].check = 1;
+ found = 1;
+ break;
+ }
+ }
+
+ if ( ! found ) {
+ /* TODO: set the error string */
+ data->error_string = "Objectclass violation, a required attribute is missing";
+ talloc_free(ss);
+ return -1;
+ }
+ }
+
+ /* now check all others atribs are found in mays */
+ for (i = 0; i < ms->num_cl; i++) {
+
+ if ( ! ms->cl[i].check ) {
+ int found;
+
+ found = 0;
+ for (j = 0; j < ms->num_may; j++) {
+ if (strcasecmp(ms->may[j].name, ms->cl[i].name) == 0) {
+ ms->cl[i].check = 1;
+ found = 1;
+ break;
+ }
+ }
+
+ if ( ! found ) {
+ data->error_string = "Objectclass violation, an invalid attribute name was found";
+ talloc_free(ss);
+ return -1;
+ }
+ }
+ }
+
+ talloc_free(ss);
+
return ldb_next_modify_record(module, msg);
}