diff options
-rw-r--r-- | source4/lib/ldb/modules/schema.c | 452 |
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); } |