s4/drs: prefixMap main interface implementation
authorKamen Mazdrashki <kamen.mazdrashki@postpath.com>
Sun, 18 Oct 2009 18:34:21 +0000 (21:34 +0300)
committerAnatoliy Atanasov <anatoliy.atanasov@postpath.com>
Wed, 21 Oct 2009 08:49:51 +0000 (11:49 +0300)
Currenly implemented functions are:
dsdb_schema_pfm_new(), dsdb_schema_pfm_make_attid()
and dsdb_schema_pfm_oid_from_attid()

source4/dsdb/schema/schema_prefixmap.c

index d24c5add00360cf456769e01e792ada80445493c..8173f89ece58673d8ebc8e4153969ce71c0b34fb 100644 (file)
 */
 
 #include "includes.h"
+#include "dsdb/samdb/samdb.h"
+#include "librpc/gen_ndr/ndr_drsuapi.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "../lib/util/asn1.h"
+
+/**
+ * Initial prefixMap creation according to:
+ * [MS-DRSR] section 5.12.2
+ */
+WERROR dsdb_schema_pfm_new(TALLOC_CTX *mem_ctx, struct dsdb_schema_prefixmap **ppfm)
+{
+       uint32_t i;
+       struct dsdb_schema_prefixmap *pfm;
+       const struct {
+               uint32_t        id;
+               const char      *oid_prefix;
+       } pfm_init_data[] = {
+               {.id=0x00000000, .oid_prefix="2.5.4"},
+               {.id=0x00000001, .oid_prefix="2.5.6"},
+               {.id=0x00000002, .oid_prefix="1.2.840.113556.1.2"},
+               {.id=0x00000003, .oid_prefix="1.2.840.113556.1.3"},
+               {.id=0x00000004, .oid_prefix="2.16.840.1.101.2.2.1"},
+               {.id=0x00000005, .oid_prefix="2.16.840.1.101.2.2.3"},
+               {.id=0x00000006, .oid_prefix="2.16.840.1.101.2.1.5"},
+               {.id=0x00000007, .oid_prefix="2.16.840.1.101.2.1.4"},
+               {.id=0x00000008, .oid_prefix="2.5.5"},
+               {.id=0x00000009, .oid_prefix="1.2.840.113556.1.4"},
+               {.id=0x0000000A, .oid_prefix="1.2.840.113556.1.5"},
+               {.id=0x00000013, .oid_prefix="0.9.2342.19200300.100"},
+               {.id=0x00000014, .oid_prefix="2.16.840.1.113730.3"},
+               {.id=0x00000015, .oid_prefix="0.9.2342.19200300.100.1"},
+               {.id=0x00000016, .oid_prefix="2.16.840.1.113730.3.1"},
+               {.id=0x00000017, .oid_prefix="1.2.840.113556.1.5.7000"},
+               {.id=0x00000018, .oid_prefix="2.5.21"},
+               {.id=0x00000019, .oid_prefix="2.5.18"},
+               {.id=0x0000001A, .oid_prefix="2.5.20"},
+       };
+
+       /* allocate mem for prefix map */
+       pfm = talloc_zero(mem_ctx, struct dsdb_schema_prefixmap);
+       W_ERROR_HAVE_NO_MEMORY(pfm);
+
+       pfm->length = ARRAY_SIZE(pfm_init_data);
+       pfm->prefixes = talloc_array(pfm, struct dsdb_schema_prefixmap_oid, pfm->length);
+       W_ERROR_HAVE_NO_MEMORY(pfm->prefixes);
+
+       /* build prefixes */
+       for (i = 0; i < pfm->length; i++) {
+               if (!ber_write_partial_OID_String(pfm, &pfm->prefixes[i].bin_oid, pfm_init_data[i].oid_prefix)) {
+                       talloc_free(pfm);
+                       return WERR_INTERNAL_ERROR;
+               }
+               pfm->prefixes[i].id = pfm_init_data[i].id;
+       }
+
+       *ppfm = pfm;
+
+       return WERR_OK;
+}
+
+
+/**
+ * Adds oid to prefix map.
+ * On success returns ID for newly added index
+ * or ID of existing entry that matches oid
+ * Reference: [MS-DRSR] section 5.12.2
+ *
+ * \param pfm prefixMap
+ * \param bin_oid OID prefix to be added to prefixMap
+ * \param pfm_id Location where to store prefixMap entry ID
+ */
+static WERROR _dsdb_schema_pfm_add_entry(struct dsdb_schema_prefixmap *pfm, DATA_BLOB bin_oid, uint32_t *_idx)
+{
+       uint32_t i;
+       struct dsdb_schema_prefixmap_oid * pfm_entry;
+       struct dsdb_schema_prefixmap_oid * prefixes_new;
+
+       /* dup memory for bin-oid prefix to be added */
+       bin_oid = data_blob_dup_talloc(pfm, &bin_oid);
+       if (!bin_oid.data) {
+               return WERR_NOMEM;
+       }
+
+       /* make room for new entry */
+       prefixes_new = talloc_realloc(pfm, pfm->prefixes, struct dsdb_schema_prefixmap_oid, pfm->length + 1);
+       if (!prefixes_new) {
+               talloc_free(bin_oid.data);
+               return WERR_NOMEM;
+       }
+       pfm->prefixes = prefixes_new;
+
+       /* make new unique ID in prefixMap */
+       pfm_entry = &pfm->prefixes[pfm->length];
+       pfm_entry->id = 0;
+       for (i = 0; i < pfm->length; i++) {
+               if (pfm_entry->id < pfm->prefixes[i].id)
+                       pfm_entry->id = pfm->prefixes[i].id;
+       }
+
+       /* add new bin-oid prefix */
+       pfm_entry->id++;
+       pfm_entry->bin_oid = bin_oid;
+
+       *_idx = pfm->length;
+       pfm->length++;
+
+       return WERR_OK;
+}
+
+
+/**
+ * Make ATTID for given OID
+ * Reference: [MS-DRSR] section 5.12.2
+ */
+WERROR dsdb_schema_pfm_make_attid(struct dsdb_schema_prefixmap *pfm, const char *oid, uint32_t *attid)
+{
+       uint32_t i;
+       uint32_t lo_word, hi_word;
+       DATA_BLOB bin_oid;
+       const char *last_subid;
+       uint32_t last_value;
+       struct dsdb_schema_prefixmap_oid *pfm_entry;
+
+       if (!pfm)       return WERR_INVALID_PARAMETER;
+       if (!oid)       return WERR_INVALID_PARAMETER;
+
+       /* make last sub-identifier value */
+       last_subid = strrchr(oid, '.');
+       if (!last_subid) {
+               return WERR_INVALID_PARAMETER;
+       }
+       last_subid++;
+       last_value = strtoul(last_subid, NULL, 10);
+
+       /* encode oid in BER format */
+       if (!ber_write_OID_String(NULL, &bin_oid, oid)) {
+               return WERR_INTERNAL_ERROR;
+       }
+
+       /* get the prefix of the OID */
+       if (last_value < 128) {
+               bin_oid.length -= 1;
+       } else {
+               bin_oid.length -= 2;
+       }
+
+       /* search the prefix in the prefix table, if none found, add
+        * one entry for new prefix.
+        */
+       pfm_entry = NULL;
+       for (i = 0; i < pfm->length; i++) {
+               if (pfm->prefixes[i].bin_oid.length != bin_oid.length)
+                       continue;
+
+               if (memcmp(pfm->prefixes[i].bin_oid.data, bin_oid.data, bin_oid.length) == 0) {
+                       pfm_entry = &pfm->prefixes[i];
+                       break;
+               }
+       }
+       /* add entry in no entry exists */
+       if (!pfm_entry) {
+               uint32_t idx;
+               WERROR werr = _dsdb_schema_pfm_add_entry(pfm, bin_oid, &idx);
+               W_ERROR_NOT_OK_RETURN(werr);
+
+               pfm_entry = &pfm->prefixes[idx];
+       }
+
+       /* compose the attid */
+       lo_word = last_value % 16384;   /* actually get lower 14 bits: lo_word & 0x3FFF */
+       if (last_value >= 16384) {
+               /* mark it so that it is known to not be the whole lastValue
+                * This will raise 16-th bit*/
+               lo_word += 32768;
+       }
+       hi_word = pfm_entry->id;
+
+       /* make ATTID:
+        * HIWORD is prefixMap id
+        * LOWORD is truncated binary-oid */
+       *attid = (hi_word * 65536) + lo_word;
+
+       return WERR_OK;
+}
+
+
+/**
+ * Make OID for given ATTID.
+ * Reference: [MS-DRSR] section 5.12.2
+ */
+WERROR dsdb_schema_pfm_oid_from_attid(struct dsdb_schema_prefixmap *pfm, uint32_t attid,
+                                     TALLOC_CTX *mem_ctx, const char **_oid)
+{
+       int i;
+       uint32_t hi_word, lo_word;
+       DATA_BLOB bin_oid = {NULL, 0};
+       struct dsdb_schema_prefixmap_oid *pfm_entry;
+       WERROR werr = WERR_OK;
+
+       /* crack attid value */
+       hi_word = attid >> 16;
+       lo_word = attid & 0xFFFF;
+
+       /* locate corRespoNding prefixMap entry */
+       pfm_entry = NULL;
+       for (i = 0; i < pfm->length; i++) {
+               if (hi_word == pfm->prefixes[i].id) {
+                       pfm_entry = &pfm->prefixes[i];
+                       break;
+               }
+       }
+
+       if (!pfm_entry) {
+               return WERR_INTERNAL_ERROR;
+       }
+
+       /* copy oid prefix making enough room */
+       bin_oid.length = pfm_entry->bin_oid.length + 2;
+       bin_oid.data = talloc_array(mem_ctx, uint8_t, bin_oid.length);
+       W_ERROR_HAVE_NO_MEMORY(bin_oid.data);
+       memcpy(bin_oid.data, pfm_entry->bin_oid.data, pfm_entry->bin_oid.length);
+
+       if (lo_word < 128) {
+               bin_oid.length = bin_oid.length - 1;
+               bin_oid.data[bin_oid.length-1] = lo_word;
+       }
+       else {
+               if (lo_word >= 32768) {
+                       lo_word -= 32768;
+               }
+               bin_oid.data[bin_oid.length-2] = (0x80 | ((lo_word>>7) & 0x7f));
+               bin_oid.data[bin_oid.length-1] = lo_word & 0x7f;
+       }
+
+       if (!ber_read_OID_String(mem_ctx, bin_oid, _oid)) {
+               werr = WERR_INTERNAL_ERROR;
+       }
+
+       /* free locally allocated memory */
+       talloc_free(bin_oid.data);
+
+       return werr;
+}
+