r4513: add experimental modification attribute checking
authorSimo Sorce <idra@samba.org>
Tue, 4 Jan 2005 15:18:50 +0000 (15:18 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:08:17 +0000 (13:08 -0500)
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)

source4/lib/ldb/modules/schema.c

index f083eeb6e5667c669c4165d1395337819bb18cb3..1f9017976e3b11f0612a4b796dc80cd067171d19 100644 (file)
@@ -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);
 }