samldb: Allow automatic generation of mAPIIDs
authorBob Campbell <bobcampbell@catalyst.net.nz>
Tue, 7 Feb 2017 22:40:32 +0000 (11:40 +1300)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 14 Feb 2017 01:20:07 +0000 (02:20 +0100)
This allows us to conform to MS-ADTS 3.1.1.2.3.2, where the OID
1.2.840.113556.1.2.49 can be specified as the mAPIID of a new attribute
in the schema in order to automatically assign it an unused mAPIID.

Signed-off-by: Bob Campbell <bobcampbell@catalyst.net.nz>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source4/dsdb/samdb/ldb_modules/samldb.c

index 755e2ed4fc9769fcee9cd2e70c34867f41daecdb..ea43ccc78f67fc9f4885cdac90e3e0af6e0627db 100644 (file)
@@ -439,8 +439,120 @@ static int samldb_schema_add_handle_linkid(struct samldb_ctx *ac)
        }
 }
 
-/* sAMAccountName handling */
+static int samldb_check_mapiid_used(struct samldb_ctx *ac,
+                                   struct dsdb_schema *schema,
+                                   struct ldb_dn *schema_dn,
+                                   struct ldb_context *ldb,
+                                   int32_t mapiid,
+                                   bool *found)
+{
+       int ret;
+       struct ldb_result *ldb_res;
+
+       ret = dsdb_module_search(ac->module, ac,
+                                &ldb_res,
+                                schema_dn, LDB_SCOPE_ONELEVEL, NULL,
+                                DSDB_FLAG_NEXT_MODULE,
+                                ac->req,
+                                "(mAPIID=%d)", mapiid);
+       if (ret != LDB_SUCCESS) {
+               ldb_debug_set(ldb, LDB_DEBUG_ERROR,
+                             __location__": Searching for mAPIID=%d failed - %s\n",
+                             mapiid,
+                             ldb_errstring(ldb));
+               return ldb_operr(ldb);
+       }
+
+       *found = (ldb_res->count != 0);
+       talloc_free(ldb_res);
+
+       return LDB_SUCCESS;
+}
+
+static int samldb_generate_next_mapiid(struct samldb_ctx *ac,
+                                      struct dsdb_schema *schema,
+                                      int32_t *next_mapiid)
+{
+       int ret;
+       struct ldb_context *ldb;
+       struct ldb_dn *schema_dn;
+       bool mapiid_used = true;
+
+       /* Windows' generation seems to start about here */
+       *next_mapiid = 60000;
+
+       ldb = ldb_module_get_ctx(ac->module);
+       schema_dn = ldb_get_schema_basedn(ldb);
 
+       while (mapiid_used) {
+               *next_mapiid += 1;
+               ret = samldb_check_mapiid_used(ac, schema,
+                                              schema_dn, ldb,
+                                              *next_mapiid, &mapiid_used);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+       }
+
+       return LDB_SUCCESS;
+}
+
+static int samldb_schema_add_handle_mapiid(struct samldb_ctx *ac)
+{
+       int ret;
+       bool ok;
+       struct ldb_message_element *el;
+       const char *enc_str;
+       struct ldb_context *ldb;
+       struct ldb_dn *schema_dn;
+       struct dsdb_schema *schema;
+       int32_t new_mapiid = 0;
+
+       /*
+        * The mAPIID of a new attribute should be automatically generated
+        * if a specific OID is put as the mAPIID, as according to
+        * [MS-ADTS] 3.1.1.2.3.2.
+        */
+
+       ldb = ldb_module_get_ctx(ac->module);
+       schema = dsdb_get_schema(ldb, ac);
+       schema_dn = ldb_get_schema_basedn(ldb);
+
+       el = dsdb_get_single_valued_attr(ac->msg, "mAPIID",
+                                        ac->req->operation);
+       if (el == NULL) {
+               return LDB_SUCCESS;
+       }
+
+       enc_str = ldb_binary_encode(ac, el->values[0]);
+       if (enc_str == NULL) {
+               return ldb_module_oom(ac->module);
+       }
+
+       ok = (strcmp(enc_str, "1.2.840.113556.1.2.49") == 0);
+       if (ok) {
+               ret = samldb_generate_next_mapiid(ac, schema,
+                                                 &new_mapiid);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+
+               ldb_msg_remove_element(ac->msg, el);
+               ret = samdb_msg_add_int(ldb, ac->msg, ac->msg,
+                                       "mAPIID", new_mapiid);
+               return ret;
+       }
+
+       schema_dn = ldb_get_schema_basedn(ldb_module_get_ctx(ac->module));
+       ret = samldb_unique_attr_check(ac, "mAPIID", NULL, schema_dn);
+       if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
+               return LDB_ERR_UNWILLING_TO_PERFORM;
+       } else {
+               return ret;
+       }
+}
+
+/* sAMAccountName handling */
 static int samldb_generate_sAMAccountName(struct ldb_context *ldb,
                                          struct ldb_message *msg)
 {
@@ -3398,6 +3510,11 @@ static int samldb_add(struct ldb_module *module, struct ldb_request *req)
                        if (ret != LDB_SUCCESS) {
                                return ret;
                        }
+
+                       ret = samldb_schema_add_handle_mapiid(ac);
+                       if (ret != LDB_SUCCESS) {
+                               return ret;
+                       }
                }
 
                ret = samldb_schema_ldapdisplayname_valid_check(ac);