Convert some more files to GPLv3.
[jra/samba/.git] / source4 / dsdb / samdb / ldb_modules / schema.c
index 21a6527e10a015558af0803f5a9a0e4ddf4eda56..f2c4d383051dfe48e33743a5fd2958772616d1ff 100644 (file)
@@ -5,7 +5,7 @@
 
    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,
@@ -14,8 +14,7 @@
    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,
@@ -77,27 +49,33 @@ enum schema_class_type {
 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 */
@@ -253,108 +231,6 @@ struct schema_attribute **schema_get_attrs_list(struct ldb_module *module,
        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",
@@ -365,6 +241,9 @@ static int schema_init_attrs(struct ldb_module *module, struct schema_private_da
                                                "isSingleValued",
                                                "rangeLower",
                                                "rangeUpper",
+                                               "searchFlag",
+                                               "systemFlag",
+                                               "isDefunct",
                                                NULL };
        struct ldb_result *res;
        int ret, i;
@@ -433,9 +312,12 @@ static int schema_init_attrs(struct ldb_module *module, struct schema_private_da
                        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:
@@ -445,10 +327,13 @@ 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",
@@ -503,9 +388,16 @@ static int schema_init_classes(struct ldb_module *module, struct schema_private_
                /* 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 */
                
@@ -629,11 +521,6 @@ static int schema_add_check_parent(struct ldb_context *ldb, void *context, struc
 {
        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 */
@@ -653,7 +540,7 @@ static int schema_add_check_parent(struct ldb_context *ldb, void *context, struc
 
 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);
@@ -665,7 +552,7 @@ static int schema_add_build_parent_req(struct schema_context *sctx)
        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;
@@ -689,6 +576,11 @@ static int schema_add_class_to_dlist(struct schema_class_dlist *list, struct sch
        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;
@@ -828,7 +720,7 @@ static int schema_add_build_objectclass_list(struct schema_context *sctx)
 
                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);
@@ -999,8 +891,9 @@ static int schema_add_build_down_req(struct schema_context *sctx)
                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;
        }
@@ -1012,12 +905,47 @@ static int schema_add_build_down_req(struct schema_context *sctx)
                        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;
@@ -1059,12 +987,11 @@ static int schema_add_continue(struct ldb_handle *h)
                }
 
                /* 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) {
@@ -1108,9 +1035,6 @@ static int schema_add(struct ldb_module *module, struct ldb_request *req)
 
 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);
        }
@@ -1120,9 +1044,6 @@ static int schema_modify(struct ldb_module *module, struct ldb_request *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);
        }
@@ -1134,9 +1055,6 @@ static int schema_delete(struct ldb_module *module, struct ldb_request *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);
@@ -1241,20 +1159,26 @@ static int schema_init(struct ldb_module *module)
        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,
@@ -1267,7 +1191,7 @@ static int schema_init(struct ldb_module *module)
                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);
@@ -1290,10 +1214,12 @@ static int schema_init(struct ldb_module *module)
        }
 
        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,
@@ -1302,8 +1228,3 @@ static const struct ldb_module_ops schema_ops = {
        .rename        = schema_rename,
        .wait          = schema_wait
 };
-
-int ldb_schema_init(void)
-{
-       return ldb_register_module(&schema_ops);
-}