1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-24 02:04:21 +03:00
Andrew Bartlett 52542e1aff Pull in all the schema information during DRS schema fetch
This includes things such as allowed attributes, which were not
populated into the schema structure before.

Andrew Bartlett
2009-03-04 14:06:11 +11:00

1472 lines
48 KiB
C

/*
Unix SMB/CIFS mplementation.
DSDB schema header
Copyright (C) Stefan Metzmacher <metze@samba.org> 2006-2007
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2008
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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
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, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "dsdb/samdb/samdb.h"
#include "lib/ldb/include/ldb_errors.h"
#include "../lib/util/dlinklist.h"
#include "librpc/gen_ndr/ndr_misc.h"
#include "librpc/gen_ndr/ndr_drsuapi.h"
#include "librpc/gen_ndr/ndr_drsblobs.h"
#include "param/param.h"
struct dsdb_schema *dsdb_new_schema(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience)
{
struct dsdb_schema *schema = talloc_zero(mem_ctx, struct dsdb_schema);
if (!schema) {
return NULL;
}
schema->iconv_convenience = iconv_convenience;
return schema;
}
WERROR dsdb_load_oid_mappings_drsuapi(struct dsdb_schema *schema, const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
{
uint32_t i,j;
schema->prefixes = talloc_array(schema, struct dsdb_schema_oid_prefix, ctr->num_mappings);
W_ERROR_HAVE_NO_MEMORY(schema->prefixes);
for (i=0, j=0; i < ctr->num_mappings; i++) {
if (ctr->mappings[i].oid.oid == NULL) {
return WERR_INVALID_PARAM;
}
if (strncasecmp(ctr->mappings[i].oid.oid, "ff", 2) == 0) {
if (ctr->mappings[i].id_prefix != 0) {
return WERR_INVALID_PARAM;
}
/* the magic value should be in the last array member */
if (i != (ctr->num_mappings - 1)) {
return WERR_INVALID_PARAM;
}
if (ctr->mappings[i].oid.__ndr_size != 21) {
return WERR_INVALID_PARAM;
}
schema->schema_info = talloc_strdup(schema, ctr->mappings[i].oid.oid);
W_ERROR_HAVE_NO_MEMORY(schema->schema_info);
} else {
/* the last array member should contain the magic value not a oid */
if (i == (ctr->num_mappings - 1)) {
return WERR_INVALID_PARAM;
}
schema->prefixes[j].id = ctr->mappings[i].id_prefix<<16;
schema->prefixes[j].oid = talloc_asprintf(schema->prefixes, "%s.",
ctr->mappings[i].oid.oid);
W_ERROR_HAVE_NO_MEMORY(schema->prefixes[j].oid);
schema->prefixes[j].oid_len = strlen(schema->prefixes[j].oid);
j++;
}
}
schema->num_prefixes = j;
return WERR_OK;
}
WERROR dsdb_load_oid_mappings_ldb(struct dsdb_schema *schema,
const struct ldb_val *prefixMap,
const struct ldb_val *schemaInfo)
{
WERROR status;
enum ndr_err_code ndr_err;
struct prefixMapBlob pfm;
char *schema_info;
TALLOC_CTX *mem_ctx = talloc_new(schema);
W_ERROR_HAVE_NO_MEMORY(mem_ctx);
ndr_err = ndr_pull_struct_blob(prefixMap, mem_ctx, schema->iconv_convenience, &pfm, (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
talloc_free(mem_ctx);
return ntstatus_to_werror(nt_status);
}
if (pfm.version != PREFIX_MAP_VERSION_DSDB) {
talloc_free(mem_ctx);
return WERR_FOOBAR;
}
if (schemaInfo->length != 21 && schemaInfo->data[0] == 0xFF) {
talloc_free(mem_ctx);
return WERR_FOOBAR;
}
/* append the schema info as last element */
pfm.ctr.dsdb.num_mappings++;
pfm.ctr.dsdb.mappings = talloc_realloc(mem_ctx, pfm.ctr.dsdb.mappings,
struct drsuapi_DsReplicaOIDMapping,
pfm.ctr.dsdb.num_mappings);
W_ERROR_HAVE_NO_MEMORY(pfm.ctr.dsdb.mappings);
schema_info = data_blob_hex_string(pfm.ctr.dsdb.mappings, schemaInfo);
W_ERROR_HAVE_NO_MEMORY(schema_info);
pfm.ctr.dsdb.mappings[pfm.ctr.dsdb.num_mappings - 1].id_prefix = 0;
pfm.ctr.dsdb.mappings[pfm.ctr.dsdb.num_mappings - 1].oid.__ndr_size = schemaInfo->length;
pfm.ctr.dsdb.mappings[pfm.ctr.dsdb.num_mappings - 1].oid.oid = schema_info;
/* call the drsuapi version */
status = dsdb_load_oid_mappings_drsuapi(schema, &pfm.ctr.dsdb);
talloc_free(mem_ctx);
W_ERROR_NOT_OK_RETURN(status);
return WERR_OK;
}
WERROR dsdb_get_oid_mappings_drsuapi(const struct dsdb_schema *schema,
bool include_schema_info,
TALLOC_CTX *mem_ctx,
struct drsuapi_DsReplicaOIDMapping_Ctr **_ctr)
{
struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
uint32_t i;
ctr = talloc(mem_ctx, struct drsuapi_DsReplicaOIDMapping_Ctr);
W_ERROR_HAVE_NO_MEMORY(ctr);
ctr->num_mappings = schema->num_prefixes;
if (include_schema_info) ctr->num_mappings++;
ctr->mappings = talloc_array(schema, struct drsuapi_DsReplicaOIDMapping, ctr->num_mappings);
W_ERROR_HAVE_NO_MEMORY(ctr->mappings);
for (i=0; i < schema->num_prefixes; i++) {
ctr->mappings[i].id_prefix = schema->prefixes[i].id>>16;
ctr->mappings[i].oid.oid = talloc_strndup(ctr->mappings,
schema->prefixes[i].oid,
schema->prefixes[i].oid_len - 1);
W_ERROR_HAVE_NO_MEMORY(ctr->mappings[i].oid.oid);
}
if (include_schema_info) {
ctr->mappings[i].id_prefix = 0;
ctr->mappings[i].oid.oid = talloc_strdup(ctr->mappings,
schema->schema_info);
W_ERROR_HAVE_NO_MEMORY(ctr->mappings[i].oid.oid);
}
*_ctr = ctr;
return WERR_OK;
}
WERROR dsdb_get_oid_mappings_ldb(const struct dsdb_schema *schema,
TALLOC_CTX *mem_ctx,
struct ldb_val *prefixMap,
struct ldb_val *schemaInfo)
{
WERROR status;
enum ndr_err_code ndr_err;
struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
struct prefixMapBlob pfm;
status = dsdb_get_oid_mappings_drsuapi(schema, false, mem_ctx, &ctr);
W_ERROR_NOT_OK_RETURN(status);
pfm.version = PREFIX_MAP_VERSION_DSDB;
pfm.reserved = 0;
pfm.ctr.dsdb = *ctr;
ndr_err = ndr_push_struct_blob(prefixMap, mem_ctx, schema->iconv_convenience, &pfm, (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
talloc_free(ctr);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
return ntstatus_to_werror(nt_status);
}
*schemaInfo = strhex_to_data_blob(mem_ctx, schema->schema_info);
W_ERROR_HAVE_NO_MEMORY(schemaInfo->data);
return WERR_OK;
}
WERROR dsdb_verify_oid_mappings_drsuapi(const struct dsdb_schema *schema, const struct drsuapi_DsReplicaOIDMapping_Ctr *ctr)
{
uint32_t i,j;
for (i=0; i < ctr->num_mappings; i++) {
if (ctr->mappings[i].oid.oid == NULL) {
return WERR_INVALID_PARAM;
}
if (strncasecmp(ctr->mappings[i].oid.oid, "ff", 2) == 0) {
if (ctr->mappings[i].id_prefix != 0) {
return WERR_INVALID_PARAM;
}
/* the magic value should be in the last array member */
if (i != (ctr->num_mappings - 1)) {
return WERR_INVALID_PARAM;
}
if (ctr->mappings[i].oid.__ndr_size != 21) {
return WERR_INVALID_PARAM;
}
if (strcasecmp(schema->schema_info, ctr->mappings[i].oid.oid) != 0) {
return WERR_DS_DRA_SCHEMA_MISMATCH;
}
} else {
/* the last array member should contain the magic value not a oid */
if (i == (ctr->num_mappings - 1)) {
return WERR_INVALID_PARAM;
}
for (j=0; j < schema->num_prefixes; j++) {
size_t oid_len;
if (schema->prefixes[j].id != (ctr->mappings[i].id_prefix<<16)) {
continue;
}
oid_len = strlen(ctr->mappings[i].oid.oid);
if (oid_len != (schema->prefixes[j].oid_len - 1)) {
return WERR_DS_DRA_SCHEMA_MISMATCH;
}
if (strncmp(ctr->mappings[i].oid.oid, schema->prefixes[j].oid, oid_len) != 0) {
return WERR_DS_DRA_SCHEMA_MISMATCH;
}
break;
}
if (j == schema->num_prefixes) {
return WERR_DS_DRA_SCHEMA_MISMATCH;
}
}
}
return WERR_OK;
}
WERROR dsdb_map_oid2int(const struct dsdb_schema *schema, const char *in, uint32_t *out)
{
return dsdb_find_prefix_for_oid(schema->num_prefixes, schema->prefixes, in, out);
}
WERROR dsdb_map_int2oid(const struct dsdb_schema *schema, uint32_t in, TALLOC_CTX *mem_ctx, const char **out)
{
uint32_t i;
for (i=0; i < schema->num_prefixes; i++) {
const char *val;
if (schema->prefixes[i].id != (in & 0xFFFF0000)) {
continue;
}
val = talloc_asprintf(mem_ctx, "%s%u",
schema->prefixes[i].oid,
in & 0xFFFF);
W_ERROR_HAVE_NO_MEMORY(val);
*out = val;
return WERR_OK;
}
return WERR_DS_NO_MSDS_INTID;
}
/*
* this function is called from within a ldb transaction from the schema_fsmo module
*/
WERROR dsdb_create_prefix_mapping(struct ldb_context *ldb, struct dsdb_schema *schema, const char *full_oid)
{
WERROR status;
uint32_t num_prefixes;
struct dsdb_schema_oid_prefix *prefixes;
TALLOC_CTX *mem_ctx;
uint32_t out;
mem_ctx = talloc_new(ldb);
W_ERROR_HAVE_NO_MEMORY(mem_ctx);
/* Read prefixes from disk*/
status = dsdb_read_prefixes_from_ldb( mem_ctx, ldb, &num_prefixes, &prefixes );
if (!W_ERROR_IS_OK(status)) {
DEBUG(0,("dsdb_create_prefix_mapping: dsdb_read_prefixes_from_ldb: %s\n",
win_errstr(status)));
talloc_free(mem_ctx);
return status;
}
/* Check if there is a prefix for the oid in the prefixes array*/
status = dsdb_find_prefix_for_oid( num_prefixes, prefixes, full_oid, &out );
if (W_ERROR_IS_OK(status)) {
/* prefix found*/
talloc_free(mem_ctx);
return status;
} else if (!W_ERROR_EQUAL(WERR_DS_NO_MSDS_INTID, status)) {
/* error */
DEBUG(0,("dsdb_create_prefix_mapping: dsdb_find_prefix_for_oid: %s\n",
win_errstr(status)));
talloc_free(mem_ctx);
return status;
}
/* Create the new mapping for the prefix of full_oid */
status = dsdb_prefix_map_update(mem_ctx, &num_prefixes, &prefixes, full_oid);
if (!W_ERROR_IS_OK(status)) {
DEBUG(0,("dsdb_create_prefix_mapping: dsdb_prefix_map_update: %s\n",
win_errstr(status)));
talloc_free(mem_ctx);
return status;
}
/* Update prefixMap in ldb*/
status = dsdb_write_prefixes_to_ldb(mem_ctx, ldb, num_prefixes, prefixes);
if (!W_ERROR_IS_OK(status)) {
DEBUG(0,("dsdb_create_prefix_mapping: dsdb_write_prefixes_to_ldb: %s\n",
win_errstr(status)));
talloc_free(mem_ctx);
return status;
}
talloc_free(mem_ctx);
return status;
}
WERROR dsdb_prefix_map_update(TALLOC_CTX *mem_ctx, uint32_t *num_prefixes, struct dsdb_schema_oid_prefix **prefixes, const char *oid)
{
uint32_t new_num_prefixes, index_new_prefix, new_entry_id;
const char* lastDotOffset;
size_t size;
new_num_prefixes = *num_prefixes + 1;
index_new_prefix = *num_prefixes;
/*
* this is the algorithm we use to create new mappings for now
*
* TODO: find what algorithm windows use
*/
new_entry_id = (*num_prefixes)<<16;
/* Extract the prefix from the oid*/
lastDotOffset = strrchr(oid, '.');
if (lastDotOffset == NULL) {
DEBUG(0,("dsdb_prefix_map_update: failed to find the last dot\n"));
return WERR_NOT_FOUND;
}
/* Calculate the size of the remainig string that should be the prefix of it */
size = strlen(oid) - strlen(lastDotOffset);
if (size <= 0) {
DEBUG(0,("dsdb_prefix_map_update: size of the remaining string invalid\n"));
return WERR_FOOBAR;
}
/* Add one because we need to copy the dot */
size += 1;
/* Create a spot in the prefixMap for one more prefix*/
(*prefixes) = talloc_realloc(mem_ctx, *prefixes, struct dsdb_schema_oid_prefix, new_num_prefixes);
W_ERROR_HAVE_NO_MEMORY(*prefixes);
/* Add the new prefix entry*/
(*prefixes)[index_new_prefix].id = new_entry_id;
(*prefixes)[index_new_prefix].oid = talloc_strndup(mem_ctx, oid, size);
(*prefixes)[index_new_prefix].oid_len = strlen((*prefixes)[index_new_prefix].oid);
/* Increase num_prefixes because new prefix has been added */
++(*num_prefixes);
return WERR_OK;
}
WERROR dsdb_find_prefix_for_oid(uint32_t num_prefixes, const struct dsdb_schema_oid_prefix *prefixes, const char *in, uint32_t *out)
{
uint32_t i;
for (i=0; i < num_prefixes; i++) {
const char *val_str;
char *end_str;
unsigned val;
if (strncmp(prefixes[i].oid, in, prefixes[i].oid_len) != 0) {
continue;
}
val_str = in + prefixes[i].oid_len;
end_str = NULL;
errno = 0;
if (val_str[0] == '\0') {
return WERR_INVALID_PARAM;
}
/* two '.' chars are invalid */
if (val_str[0] == '.') {
return WERR_INVALID_PARAM;
}
val = strtoul(val_str, &end_str, 10);
if (end_str[0] == '.' && end_str[1] != '\0') {
/*
* if it's a '.' and not the last char
* then maybe an other mapping apply
*/
continue;
} else if (end_str[0] != '\0') {
return WERR_INVALID_PARAM;
} else if (val > 0xFFFF) {
return WERR_INVALID_PARAM;
}
*out = prefixes[i].id | val;
return WERR_OK;
}
return WERR_DS_NO_MSDS_INTID;
}
WERROR dsdb_write_prefixes_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
uint32_t num_prefixes,
const struct dsdb_schema_oid_prefix *prefixes)
{
struct ldb_message msg;
struct ldb_dn *schema_dn;
struct ldb_message_element el;
struct prefixMapBlob pm;
struct ldb_val ndr_blob;
enum ndr_err_code ndr_err;
uint32_t i;
int ret;
schema_dn = samdb_schema_dn(ldb);
if (!schema_dn) {
DEBUG(0,("dsdb_write_prefixes_to_ldb: no schema dn present\n"));
return WERR_FOOBAR;
}
pm.version = PREFIX_MAP_VERSION_DSDB;
pm.ctr.dsdb.num_mappings = num_prefixes;
pm.ctr.dsdb.mappings = talloc_array(mem_ctx,
struct drsuapi_DsReplicaOIDMapping,
pm.ctr.dsdb.num_mappings);
if (!pm.ctr.dsdb.mappings) {
return WERR_NOMEM;
}
for (i=0; i < num_prefixes; i++) {
pm.ctr.dsdb.mappings[i].id_prefix = prefixes[i].id>>16;
pm.ctr.dsdb.mappings[i].oid.oid = talloc_strdup(pm.ctr.dsdb.mappings, prefixes[i].oid);
}
ndr_err = ndr_push_struct_blob(&ndr_blob, ldb,
lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
&pm,
(ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
return WERR_FOOBAR;
}
el.num_values = 1;
el.values = &ndr_blob;
el.flags = LDB_FLAG_MOD_REPLACE;
el.name = talloc_strdup(mem_ctx, "prefixMap");
msg.dn = ldb_dn_copy(mem_ctx, schema_dn);
msg.num_elements = 1;
msg.elements = &el;
ret = ldb_modify( ldb, &msg );
if (ret != 0) {
DEBUG(0,("dsdb_write_prefixes_to_ldb: ldb_modify failed\n"));
return WERR_FOOBAR;
}
return WERR_OK;
}
WERROR dsdb_read_prefixes_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, uint32_t* num_prefixes, struct dsdb_schema_oid_prefix **prefixes)
{
struct prefixMapBlob *blob;
enum ndr_err_code ndr_err;
uint32_t i;
const struct ldb_val *prefix_val;
struct ldb_dn *schema_dn;
struct ldb_result *schema_res;
int ret;
static const char *schema_attrs[] = {
"prefixMap",
NULL
};
schema_dn = samdb_schema_dn(ldb);
if (!schema_dn) {
DEBUG(0,("dsdb_read_prefixes_from_ldb: no schema dn present\n"));
return WERR_FOOBAR;
}
ret = ldb_search(ldb, mem_ctx, &schema_res, schema_dn, LDB_SCOPE_BASE, schema_attrs, NULL);
if (ret == LDB_ERR_NO_SUCH_OBJECT) {
DEBUG(0,("dsdb_read_prefixes_from_ldb: no prefix map present\n"));
talloc_free(schema_res);
return WERR_FOOBAR;
} else if (ret != LDB_SUCCESS) {
DEBUG(0,("dsdb_read_prefixes_from_ldb: failed to search the schema head\n"));
talloc_free(schema_res);
return WERR_FOOBAR;
}
prefix_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "prefixMap");
if (!prefix_val) {
DEBUG(0,("dsdb_read_prefixes_from_ldb: no prefixMap attribute found\n"));
talloc_free(schema_res);
return WERR_FOOBAR;
}
blob = talloc(mem_ctx, struct prefixMapBlob);
W_ERROR_HAVE_NO_MEMORY(blob);
ndr_err = ndr_pull_struct_blob(prefix_val, blob,
lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
blob,
(ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
DEBUG(0,("dsdb_read_prefixes_from_ldb: ndr_pull_struct_blob failed\n"));
talloc_free(blob);
talloc_free(schema_res);
return WERR_FOOBAR;
}
talloc_free(schema_res);
if (blob->version != PREFIX_MAP_VERSION_DSDB) {
DEBUG(0,("dsdb_read_prefixes_from_ldb: blob->version incorect\n"));
talloc_free(blob);
return WERR_FOOBAR;
}
*num_prefixes = blob->ctr.dsdb.num_mappings;
*prefixes = talloc_array(mem_ctx, struct dsdb_schema_oid_prefix, *num_prefixes);
if(!(*prefixes)) {
talloc_free(blob);
return WERR_NOMEM;
}
for (i=0; i < blob->ctr.dsdb.num_mappings; i++) {
char *oid;
(*prefixes)[i].id = blob->ctr.dsdb.mappings[i].id_prefix<<16;
oid = talloc_strdup(mem_ctx, blob->ctr.dsdb.mappings[i].oid.oid);
(*prefixes)[i].oid = talloc_asprintf_append(oid, ".");
(*prefixes)[i].oid_len = strlen(blob->ctr.dsdb.mappings[i].oid.oid);
}
talloc_free(blob);
return WERR_OK;
}
#define GET_STRING_LDB(msg, attr, mem_ctx, p, elem, strict) do { \
(p)->elem = samdb_result_string(msg, attr, NULL);\
if (strict && (p)->elem == NULL) { \
d_printf("%s: %s == NULL\n", __location__, attr); \
return WERR_INVALID_PARAM; \
} \
talloc_steal(mem_ctx, (p)->elem); \
} while (0)
#define GET_STRING_LIST_LDB(msg, attr, mem_ctx, p, elem, strict) do { \
int get_string_list_counter; \
struct ldb_message_element *get_string_list_el = ldb_msg_find_element(msg, attr); \
if (get_string_list_el == NULL) { \
if (strict) { \
d_printf("%s: %s == NULL\n", __location__, attr); \
return WERR_INVALID_PARAM; \
} else { \
(p)->elem = NULL; \
break; \
} \
} \
(p)->elem = talloc_array(mem_ctx, const char *, get_string_list_el->num_values + 1); \
for (get_string_list_counter=0; \
get_string_list_counter < get_string_list_el->num_values; \
get_string_list_counter++) { \
(p)->elem[get_string_list_counter] = talloc_strndup((p)->elem, \
(const char *)get_string_list_el->values[get_string_list_counter].data, \
get_string_list_el->values[get_string_list_counter].length); \
if (!(p)->elem[get_string_list_counter]) { \
d_printf("%s: talloc_strndup failed for %s\n", __location__, attr); \
return WERR_NOMEM; \
} \
(p)->elem[get_string_list_counter+1] = NULL; \
} \
talloc_steal(mem_ctx, (p)->elem); \
} while (0)
#define GET_BOOL_LDB(msg, attr, p, elem, strict) do { \
const char *str; \
str = samdb_result_string(msg, attr, NULL);\
if (str == NULL) { \
if (strict) { \
d_printf("%s: %s == NULL\n", __location__, attr); \
return WERR_INVALID_PARAM; \
} else { \
(p)->elem = false; \
} \
} else if (strcasecmp("TRUE", str) == 0) { \
(p)->elem = true; \
} else if (strcasecmp("FALSE", str) == 0) { \
(p)->elem = false; \
} else { \
d_printf("%s: %s == %s\n", __location__, attr, str); \
return WERR_INVALID_PARAM; \
} \
} while (0)
#define GET_UINT32_LDB(msg, attr, p, elem) do { \
(p)->elem = samdb_result_uint(msg, attr, 0);\
} while (0)
#define GET_UINT32_PTR_LDB(msg, attr, p, elem) do { \
uint64_t _v = samdb_result_uint64(msg, attr, UINT64_MAX);\
if (_v == UINT64_MAX) { \
(p)->elem = NULL; \
} else if (_v > UINT32_MAX) { \
d_printf("%s: %s == 0x%llX\n", __location__, \
attr, (unsigned long long)_v); \
return WERR_INVALID_PARAM; \
} else { \
(p)->elem = talloc(mem_ctx, uint32_t); \
if (!(p)->elem) { \
d_printf("%s: talloc failed for %s\n", __location__, attr); \
return WERR_NOMEM; \
} \
*(p)->elem = (uint32_t)_v; \
} \
} while (0)
#define GET_GUID_LDB(msg, attr, p, elem) do { \
(p)->elem = samdb_result_guid(msg, attr);\
} while (0)
#define GET_BLOB_LDB(msg, attr, mem_ctx, p, elem) do { \
const struct ldb_val *_val;\
_val = ldb_msg_find_ldb_val(msg, attr);\
if (_val) {\
(p)->elem = *_val;\
talloc_steal(mem_ctx, (p)->elem.data);\
} else {\
ZERO_STRUCT((p)->elem);\
}\
} while (0)
WERROR dsdb_attribute_from_ldb(const struct dsdb_schema *schema,
struct ldb_message *msg,
TALLOC_CTX *mem_ctx,
struct dsdb_attribute *attr)
{
WERROR status;
GET_STRING_LDB(msg, "cn", mem_ctx, attr, cn, false);
GET_STRING_LDB(msg, "lDAPDisplayName", mem_ctx, attr, lDAPDisplayName, true);
GET_STRING_LDB(msg, "attributeID", mem_ctx, attr, attributeID_oid, true);
if (schema->num_prefixes == 0) {
/* set an invalid value */
attr->attributeID_id = 0xFFFFFFFF;
} else {
status = dsdb_map_oid2int(schema, attr->attributeID_oid, &attr->attributeID_id);
if (!W_ERROR_IS_OK(status)) {
DEBUG(0,("%s: '%s': unable to map attributeID %s: %s\n",
__location__, attr->lDAPDisplayName, attr->attributeID_oid,
win_errstr(status)));
return status;
}
}
GET_GUID_LDB(msg, "schemaIDGUID", attr, schemaIDGUID);
GET_UINT32_LDB(msg, "mAPIID", attr, mAPIID);
GET_GUID_LDB(msg, "attributeSecurityGUID", attr, attributeSecurityGUID);
GET_UINT32_LDB(msg, "searchFlags", attr, searchFlags);
GET_UINT32_LDB(msg, "systemFlags", attr, systemFlags);
GET_BOOL_LDB(msg, "isMemberOfPartialAttributeSet", attr, isMemberOfPartialAttributeSet, false);
GET_UINT32_LDB(msg, "linkID", attr, linkID);
GET_STRING_LDB(msg, "attributeSyntax", mem_ctx, attr, attributeSyntax_oid, true);
if (schema->num_prefixes == 0) {
/* set an invalid value */
attr->attributeSyntax_id = 0xFFFFFFFF;
} else {
status = dsdb_map_oid2int(schema, attr->attributeSyntax_oid, &attr->attributeSyntax_id);
if (!W_ERROR_IS_OK(status)) {
DEBUG(0,("%s: '%s': unable to map attributeSyntax_ %s: %s\n",
__location__, attr->lDAPDisplayName, attr->attributeSyntax_oid,
win_errstr(status)));
return status;
}
}
GET_UINT32_LDB(msg, "oMSyntax", attr, oMSyntax);
GET_BLOB_LDB(msg, "oMObjectClass", mem_ctx, attr, oMObjectClass);
GET_BOOL_LDB(msg, "isSingleValued", attr, isSingleValued, true);
GET_UINT32_PTR_LDB(msg, "rangeLower", attr, rangeLower);
GET_UINT32_PTR_LDB(msg, "rangeUpper", attr, rangeUpper);
GET_BOOL_LDB(msg, "extendedCharsAllowed", attr, extendedCharsAllowed, false);
GET_UINT32_LDB(msg, "schemaFlagsEx", attr, schemaFlagsEx);
GET_BLOB_LDB(msg, "msDs-Schema-Extensions", mem_ctx, attr, msDs_Schema_Extensions);
GET_BOOL_LDB(msg, "showInAdvancedViewOnly", attr, showInAdvancedViewOnly, false);
GET_STRING_LDB(msg, "adminDisplayName", mem_ctx, attr, adminDisplayName, false);
GET_STRING_LDB(msg, "adminDescription", mem_ctx, attr, adminDescription, false);
GET_STRING_LDB(msg, "classDisplayName", mem_ctx, attr, classDisplayName, false);
GET_BOOL_LDB(msg, "isEphemeral", attr, isEphemeral, false);
GET_BOOL_LDB(msg, "isDefunct", attr, isDefunct, false);
GET_BOOL_LDB(msg, "systemOnly", attr, systemOnly, false);
attr->syntax = dsdb_syntax_for_attribute(attr);
if (!attr->syntax) {
return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
}
return WERR_OK;
}
WERROR dsdb_class_from_ldb(const struct dsdb_schema *schema,
struct ldb_message *msg,
TALLOC_CTX *mem_ctx,
struct dsdb_class *obj)
{
WERROR status;
GET_STRING_LDB(msg, "cn", mem_ctx, obj, cn, false);
GET_STRING_LDB(msg, "lDAPDisplayName", mem_ctx, obj, lDAPDisplayName, true);
GET_STRING_LDB(msg, "governsID", mem_ctx, obj, governsID_oid, true);
if (schema->num_prefixes == 0) {
/* set an invalid value */
obj->governsID_id = 0xFFFFFFFF;
} else {
status = dsdb_map_oid2int(schema, obj->governsID_oid, &obj->governsID_id);
if (!W_ERROR_IS_OK(status)) {
DEBUG(0,("%s: '%s': unable to map governsID %s: %s\n",
__location__, obj->lDAPDisplayName, obj->governsID_oid,
win_errstr(status)));
return status;
}
}
GET_GUID_LDB(msg, "schemaIDGUID", obj, schemaIDGUID);
GET_UINT32_LDB(msg, "objectClassCategory", obj, objectClassCategory);
GET_STRING_LDB(msg, "rDNAttID", mem_ctx, obj, rDNAttID, false);
GET_STRING_LDB(msg, "defaultObjectCategory", mem_ctx, obj, defaultObjectCategory, true);
GET_STRING_LDB(msg, "subClassOf", mem_ctx, obj, subClassOf, true);
GET_STRING_LIST_LDB(msg, "systemAuxiliaryClass", mem_ctx, obj, systemAuxiliaryClass, false);
GET_STRING_LIST_LDB(msg, "auxiliaryClass", mem_ctx, obj, auxiliaryClass, false);
GET_STRING_LIST_LDB(msg, "systemMustContain", mem_ctx, obj, systemMustContain, false);
GET_STRING_LIST_LDB(msg, "systemMayContain", mem_ctx, obj, systemMayContain, false);
GET_STRING_LIST_LDB(msg, "mustContain", mem_ctx, obj, mustContain, false);
GET_STRING_LIST_LDB(msg, "mayContain", mem_ctx, obj, mayContain, false);
GET_STRING_LIST_LDB(msg, "systemPossSuperiors", mem_ctx, obj, systemPossSuperiors, false);
GET_STRING_LIST_LDB(msg, "possSuperiors", mem_ctx, obj, possSuperiors, false);
GET_STRING_LIST_LDB(msg, "possibleInferiors", mem_ctx, obj, possibleInferiors, false);
GET_STRING_LDB(msg, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, false);
GET_UINT32_LDB(msg, "schemaFlagsEx", obj, schemaFlagsEx);
GET_BLOB_LDB(msg, "msDs-Schema-Extensions", mem_ctx, obj, msDs_Schema_Extensions);
GET_BOOL_LDB(msg, "showInAdvancedViewOnly", obj, showInAdvancedViewOnly, false);
GET_STRING_LDB(msg, "adminDisplayName", mem_ctx, obj, adminDisplayName, false);
GET_STRING_LDB(msg, "adminDescription", mem_ctx, obj, adminDescription, false);
GET_STRING_LDB(msg, "classDisplayName", mem_ctx, obj, classDisplayName, false);
GET_BOOL_LDB(msg, "defaultHidingValue", obj, defaultHidingValue, false);
GET_BOOL_LDB(msg, "isDefunct", obj, isDefunct, false);
GET_BOOL_LDB(msg, "systemOnly", obj, systemOnly, false);
return WERR_OK;
}
#define dsdb_oom(error_string, mem_ctx) *error_string = talloc_asprintf(mem_ctx, "dsdb out of memory at %s:%d\n", __FILE__, __LINE__)
int dsdb_schema_from_ldb_results(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
struct smb_iconv_convenience *iconv_convenience,
struct ldb_result *schema_res,
struct ldb_result *attrs_res, struct ldb_result *objectclass_res,
struct dsdb_schema **schema_out,
char **error_string)
{
WERROR status;
uint32_t i;
const struct ldb_val *prefix_val;
const struct ldb_val *info_val;
struct ldb_val info_val_default;
struct dsdb_schema *schema;
schema = dsdb_new_schema(mem_ctx, iconv_convenience);
if (!schema) {
dsdb_oom(error_string, mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
prefix_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "prefixMap");
if (!prefix_val) {
*error_string = talloc_asprintf(mem_ctx,
"schema_fsmo_init: no prefixMap attribute found");
return LDB_ERR_CONSTRAINT_VIOLATION;
}
info_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "schemaInfo");
if (!info_val) {
info_val_default = strhex_to_data_blob(mem_ctx, "FF0000000000000000000000000000000000000000");
if (!info_val_default.data) {
dsdb_oom(error_string, mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
info_val = &info_val_default;
}
status = dsdb_load_oid_mappings_ldb(schema, prefix_val, info_val);
if (!W_ERROR_IS_OK(status)) {
*error_string = talloc_asprintf(mem_ctx,
"schema_fsmo_init: failed to load oid mappings: %s",
win_errstr(status));
return LDB_ERR_CONSTRAINT_VIOLATION;
}
for (i=0; i < attrs_res->count; i++) {
struct dsdb_attribute *sa;
sa = talloc_zero(schema, struct dsdb_attribute);
if (!sa) {
dsdb_oom(error_string, mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
status = dsdb_attribute_from_ldb(schema, attrs_res->msgs[i], sa, sa);
if (!W_ERROR_IS_OK(status)) {
*error_string = talloc_asprintf(mem_ctx,
"schema_fsmo_init: failed to load attribute definition: %s:%s",
ldb_dn_get_linearized(attrs_res->msgs[i]->dn),
win_errstr(status));
return LDB_ERR_CONSTRAINT_VIOLATION;
}
DLIST_ADD_END(schema->attributes, sa, struct dsdb_attribute *);
}
for (i=0; i < objectclass_res->count; i++) {
struct dsdb_class *sc;
sc = talloc_zero(schema, struct dsdb_class);
if (!sc) {
dsdb_oom(error_string, mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
status = dsdb_class_from_ldb(schema, objectclass_res->msgs[i], sc, sc);
if (!W_ERROR_IS_OK(status)) {
*error_string = talloc_asprintf(mem_ctx,
"schema_fsmo_init: failed to load class definition: %s:%s",
ldb_dn_get_linearized(objectclass_res->msgs[i]->dn),
win_errstr(status));
return LDB_ERR_CONSTRAINT_VIOLATION;
}
DLIST_ADD_END(schema->classes, sc, struct dsdb_class *);
}
schema->fsmo.master_dn = ldb_msg_find_attr_as_dn(ldb, schema, schema_res->msgs[0], "fSMORoleOwner");
if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), schema->fsmo.master_dn) == 0) {
schema->fsmo.we_are_master = true;
} else {
schema->fsmo.we_are_master = false;
}
DEBUG(5, ("schema_fsmo_init: we are master: %s\n",
(schema->fsmo.we_are_master?"yes":"no")));
*schema_out = schema;
return LDB_SUCCESS;
}
/* This recursive load of the objectClasses presumes that they
* everything is in a strict subClassOf hirarchy.
*
* We load this in order so we produce certain outputs (such as the
* exported schema for openldap, and sorted objectClass attribute) 'in
* order' */
static int fetch_oc_recursive(struct ldb_context *ldb, struct ldb_dn *schemadn,
TALLOC_CTX *mem_ctx,
struct ldb_result *search_from,
struct ldb_result *res_list)
{
int i;
int ret = 0;
for (i=0; i < search_from->count; i++) {
struct ldb_result *res;
const char *name = ldb_msg_find_attr_as_string(search_from->msgs[i],
"lDAPDisplayname", NULL);
ret = ldb_search(ldb, mem_ctx, &res,
schemadn, LDB_SCOPE_SUBTREE, NULL,
"(&(&(objectClass=classSchema)(subClassOf=%s))(!(lDAPDisplayName=%s)))",
name, name);
if (ret != LDB_SUCCESS) {
return ret;
}
res_list->msgs = talloc_realloc(res_list, res_list->msgs,
struct ldb_message *, res_list->count + 2);
if (!res_list->msgs) {
return LDB_ERR_OPERATIONS_ERROR;
}
res_list->msgs[res_list->count] = talloc_move(res_list,
&search_from->msgs[i]);
res_list->count++;
res_list->msgs[res_list->count] = NULL;
if (res->count > 0) {
ret = fetch_oc_recursive(ldb, schemadn, mem_ctx, res, res_list);
}
if (ret != LDB_SUCCESS) {
return ret;
}
}
return ret;
}
static int fetch_objectclass_schema(struct ldb_context *ldb, struct ldb_dn *schemadn,
TALLOC_CTX *mem_ctx,
struct ldb_result **objectclasses_res,
char **error_string)
{
TALLOC_CTX *local_ctx = talloc_new(mem_ctx);
struct ldb_result *top_res, *ret_res;
int ret;
if (!local_ctx) {
return LDB_ERR_OPERATIONS_ERROR;
}
/* Download 'top' */
ret = ldb_search(ldb, local_ctx, &top_res,
schemadn, LDB_SCOPE_SUBTREE, NULL,
"(&(objectClass=classSchema)(lDAPDisplayName=top))");
if (ret != LDB_SUCCESS) {
*error_string = talloc_asprintf(mem_ctx,
"dsdb_schema: failed to search for top classSchema object: %s",
ldb_errstring(ldb));
return ret;
}
if (top_res->count != 1) {
*error_string = talloc_asprintf(mem_ctx,
"dsdb_schema: failed to find top classSchema object");
return LDB_ERR_NO_SUCH_OBJECT;
}
ret_res = talloc_zero(local_ctx, struct ldb_result);
if (!ret_res) {
return LDB_ERR_OPERATIONS_ERROR;
}
ret = fetch_oc_recursive(ldb, schemadn, local_ctx, top_res, ret_res);
if (ret != LDB_SUCCESS) {
return ret;
}
*objectclasses_res = talloc_move(mem_ctx, &ret_res);
return ret;
}
int dsdb_schema_from_schema_dn(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
struct smb_iconv_convenience *iconv_convenience,
struct ldb_dn *schema_dn,
struct dsdb_schema **schema,
char **error_string_out)
{
TALLOC_CTX *tmp_ctx;
char *error_string;
int ret;
struct ldb_result *schema_res;
struct ldb_result *a_res;
struct ldb_result *c_res;
static const char *schema_attrs[] = {
"prefixMap",
"schemaInfo",
"fSMORoleOwner",
NULL
};
tmp_ctx = talloc_new(mem_ctx);
if (!tmp_ctx) {
dsdb_oom(error_string_out, mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
/*
* setup the prefix mappings and schema info
*/
ret = ldb_search(ldb, tmp_ctx, &schema_res,
schema_dn, LDB_SCOPE_BASE, schema_attrs, NULL);
if (ret == LDB_ERR_NO_SUCH_OBJECT) {
talloc_free(tmp_ctx);
return ret;
} else if (ret != LDB_SUCCESS) {
*error_string_out = talloc_asprintf(mem_ctx,
"dsdb_schema: failed to search the schema head: %s",
ldb_errstring(ldb));
talloc_free(tmp_ctx);
return ret;
}
if (schema_res->count != 1) {
*error_string_out = talloc_asprintf(mem_ctx,
"dsdb_schema: [%u] schema heads found on a base search",
schema_res->count);
talloc_free(tmp_ctx);
return LDB_ERR_CONSTRAINT_VIOLATION;
}
/*
* load the attribute definitions
*/
ret = ldb_search(ldb, tmp_ctx, &a_res,
schema_dn, LDB_SCOPE_ONELEVEL, NULL,
"(objectClass=attributeSchema)");
if (ret != LDB_SUCCESS) {
*error_string_out = talloc_asprintf(mem_ctx,
"dsdb_schema: failed to search attributeSchema objects: %s",
ldb_errstring(ldb));
talloc_free(tmp_ctx);
return ret;
}
/*
* load the objectClass definitions
*/
ret = fetch_objectclass_schema(ldb, schema_dn, tmp_ctx, &c_res, &error_string);
if (ret != LDB_SUCCESS) {
*error_string_out = talloc_asprintf(mem_ctx,
"Failed to fetch objectClass schema elements: %s", error_string);
talloc_free(tmp_ctx);
return ret;
}
ret = dsdb_schema_from_ldb_results(tmp_ctx, ldb,
lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
schema_res, a_res, c_res, schema, &error_string);
if (ret != LDB_SUCCESS) {
*error_string_out = talloc_asprintf(mem_ctx,
"dsdb_schema load failed: %s",
error_string);
talloc_free(tmp_ctx);
return ret;
}
talloc_steal(mem_ctx, *schema);
talloc_free(tmp_ctx);
return LDB_SUCCESS;
}
static const struct {
const char *name;
const char *oid;
} name_mappings[] = {
{ "cn", "2.5.4.3" },
{ "name", "1.2.840.113556.1.4.1" },
{ "lDAPDisplayName", "1.2.840.113556.1.2.460" },
{ "attributeID", "1.2.840.113556.1.2.30" },
{ "schemaIDGUID", "1.2.840.113556.1.4.148" },
{ "mAPIID", "1.2.840.113556.1.2.49" },
{ "attributeSecurityGUID", "1.2.840.113556.1.4.149" },
{ "searchFlags", "1.2.840.113556.1.2.334" },
{ "systemFlags", "1.2.840.113556.1.4.375" },
{ "isMemberOfPartialAttributeSet", "1.2.840.113556.1.4.639" },
{ "linkID", "1.2.840.113556.1.2.50" },
{ "attributeSyntax", "1.2.840.113556.1.2.32" },
{ "oMSyntax", "1.2.840.113556.1.2.231" },
{ "oMObjectClass", "1.2.840.113556.1.2.218" },
{ "isSingleValued", "1.2.840.113556.1.2.33" },
{ "rangeLower", "1.2.840.113556.1.2.34" },
{ "rangeUpper", "1.2.840.113556.1.2.35" },
{ "extendedCharsAllowed", "1.2.840.113556.1.2.380" },
{ "schemaFlagsEx", "1.2.840.113556.1.4.120" },
{ "msDs-Schema-Extensions", "1.2.840.113556.1.4.1440" },
{ "showInAdvancedViewOnly", "1.2.840.113556.1.2.169" },
{ "adminDisplayName", "1.2.840.113556.1.2.194" },
{ "adminDescription", "1.2.840.113556.1.2.226" },
{ "classDisplayName", "1.2.840.113556.1.4.610" },
{ "isEphemeral", "1.2.840.113556.1.4.1212" },
{ "isDefunct", "1.2.840.113556.1.4.661" },
{ "systemOnly", "1.2.840.113556.1.4.170" },
{ "governsID", "1.2.840.113556.1.2.22" },
{ "objectClassCategory", "1.2.840.113556.1.2.370" },
{ "rDNAttID", "1.2.840.113556.1.2.26" },
{ "defaultObjectCategory", "1.2.840.113556.1.4.783" },
{ "subClassOf", "1.2.840.113556.1.2.21" },
{ "systemAuxiliaryClass", "1.2.840.113556.1.4.198" },
{ "systemPossSuperiors", "1.2.840.113556.1.4.195" },
{ "systemMustContain", "1.2.840.113556.1.4.197" },
{ "systemMayContain", "1.2.840.113556.1.4.196" },
{ "auxiliaryClass", "1.2.840.113556.1.2.351" },
{ "possSuperiors", "1.2.840.113556.1.2.8" },
{ "mustContain", "1.2.840.113556.1.2.24" },
{ "mayContain", "1.2.840.113556.1.2.25" },
{ "defaultSecurityDescriptor", "1.2.840.113556.1.4.224" },
{ "defaultHidingValue", "1.2.840.113556.1.4.518" },
};
static struct drsuapi_DsReplicaAttribute *dsdb_find_object_attr_name(struct dsdb_schema *schema,
struct drsuapi_DsReplicaObject *obj,
const char *name,
uint32_t *idx)
{
WERROR status;
uint32_t i, id;
const char *oid = NULL;
for(i=0; i < ARRAY_SIZE(name_mappings); i++) {
if (strcmp(name_mappings[i].name, name) != 0) continue;
oid = name_mappings[i].oid;
break;
}
if (!oid) {
return NULL;
}
status = dsdb_map_oid2int(schema, oid, &id);
if (!W_ERROR_IS_OK(status)) {
return NULL;
}
for (i=0; i < obj->attribute_ctr.num_attributes; i++) {
if (obj->attribute_ctr.attributes[i].attid != id) continue;
if (idx) *idx = i;
return &obj->attribute_ctr.attributes[i];
}
return NULL;
}
#define GET_STRING_DS(s, r, attr, mem_ctx, p, elem, strict) do { \
struct drsuapi_DsReplicaAttribute *_a; \
_a = dsdb_find_object_attr_name(s, r, attr, NULL); \
if (strict && !_a) { \
d_printf("%s: %s == NULL\n", __location__, attr); \
return WERR_INVALID_PARAM; \
} \
if (strict && _a->value_ctr.num_values != 1) { \
d_printf("%s: %s num_values == %u\n", __location__, attr, \
_a->value_ctr.num_values); \
return WERR_INVALID_PARAM; \
} \
if (_a && _a->value_ctr.num_values >= 1) { \
size_t _ret; \
if (!convert_string_talloc_convenience(mem_ctx, s->iconv_convenience, CH_UTF16, CH_UNIX, \
_a->value_ctr.values[0].blob->data, \
_a->value_ctr.values[0].blob->length, \
(void **)discard_const(&(p)->elem), &_ret, false)) { \
DEBUG(0,("%s: invalid data!\n", attr)); \
dump_data(0, \
_a->value_ctr.values[0].blob->data, \
_a->value_ctr.values[0].blob->length); \
return WERR_FOOBAR; \
} \
} else { \
(p)->elem = NULL; \
} \
} while (0)
#define GET_STRING_LIST_DS(s, r, attr, mem_ctx, p, elem, strict) do { \
int get_string_list_counter; \
struct drsuapi_DsReplicaAttribute *_a; \
_a = dsdb_find_object_attr_name(s, r, attr, NULL); \
if (strict && !_a) { \
d_printf("%s: %s == NULL\n", __location__, attr); \
return WERR_INVALID_PARAM; \
} \
(p)->elem = _a ? talloc_array(mem_ctx, const char *, _a->value_ctr.num_values + 1) : NULL; \
for (get_string_list_counter=0; \
_a && get_string_list_counter < _a->value_ctr.num_values; \
get_string_list_counter++) { \
size_t _ret; \
if (!convert_string_talloc_convenience(mem_ctx, s->iconv_convenience, CH_UTF16, CH_UNIX, \
_a->value_ctr.values[get_string_list_counter].blob->data, \
_a->value_ctr.values[get_string_list_counter].blob->length, \
(void **)discard_const(&(p)->elem[get_string_list_counter]), &_ret, false)) { \
DEBUG(0,("%s: invalid data!\n", attr)); \
dump_data(0, \
_a->value_ctr.values[get_string_list_counter].blob->data, \
_a->value_ctr.values[get_string_list_counter].blob->length); \
return WERR_FOOBAR; \
} \
(p)->elem[get_string_list_counter+1] = NULL; \
} \
talloc_steal(mem_ctx, (p)->elem); \
} while (0)
#define GET_DN_DS(s, r, attr, mem_ctx, p, elem, strict) do { \
struct drsuapi_DsReplicaAttribute *_a; \
_a = dsdb_find_object_attr_name(s, r, attr, NULL); \
if (strict && !_a) { \
d_printf("%s: %s == NULL\n", __location__, attr); \
return WERR_INVALID_PARAM; \
} \
if (strict && _a->value_ctr.num_values != 1) { \
d_printf("%s: %s num_values == %u\n", __location__, attr, \
_a->value_ctr.num_values); \
return WERR_INVALID_PARAM; \
} \
if (strict && !_a->value_ctr.values[0].blob) { \
d_printf("%s: %s data == NULL\n", __location__, attr); \
return WERR_INVALID_PARAM; \
} \
if (_a && _a->value_ctr.num_values >= 1 \
&& _a->value_ctr.values[0].blob) { \
struct drsuapi_DsReplicaObjectIdentifier3 _id3; \
enum ndr_err_code _ndr_err; \
_ndr_err = ndr_pull_struct_blob_all(_a->value_ctr.values[0].blob, \
mem_ctx, s->iconv_convenience, &_id3,\
(ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);\
if (!NDR_ERR_CODE_IS_SUCCESS(_ndr_err)) { \
NTSTATUS _nt_status = ndr_map_error2ntstatus(_ndr_err); \
return ntstatus_to_werror(_nt_status); \
} \
(p)->elem = _id3.dn; \
} else { \
(p)->elem = NULL; \
} \
} while (0)
#define GET_BOOL_DS(s, r, attr, p, elem, strict) do { \
struct drsuapi_DsReplicaAttribute *_a; \
_a = dsdb_find_object_attr_name(s, r, attr, NULL); \
if (strict && !_a) { \
d_printf("%s: %s == NULL\n", __location__, attr); \
return WERR_INVALID_PARAM; \
} \
if (strict && _a->value_ctr.num_values != 1) { \
d_printf("%s: %s num_values == %u\n", __location__, attr, \
(unsigned int)_a->value_ctr.num_values); \
return WERR_INVALID_PARAM; \
} \
if (strict && !_a->value_ctr.values[0].blob) { \
d_printf("%s: %s data == NULL\n", __location__, attr); \
return WERR_INVALID_PARAM; \
} \
if (strict && _a->value_ctr.values[0].blob->length != 4) { \
d_printf("%s: %s length == %u\n", __location__, attr, \
(unsigned int)_a->value_ctr.values[0].blob->length); \
return WERR_INVALID_PARAM; \
} \
if (_a && _a->value_ctr.num_values >= 1 \
&& _a->value_ctr.values[0].blob \
&& _a->value_ctr.values[0].blob->length == 4) { \
(p)->elem = (IVAL(_a->value_ctr.values[0].blob->data,0)?true:false);\
} else { \
(p)->elem = false; \
} \
} while (0)
#define GET_UINT32_DS(s, r, attr, p, elem) do { \
struct drsuapi_DsReplicaAttribute *_a; \
_a = dsdb_find_object_attr_name(s, r, attr, NULL); \
if (_a && _a->value_ctr.num_values >= 1 \
&& _a->value_ctr.values[0].blob \
&& _a->value_ctr.values[0].blob->length == 4) { \
(p)->elem = IVAL(_a->value_ctr.values[0].blob->data,0);\
} else { \
(p)->elem = 0; \
} \
} while (0)
#define GET_UINT32_PTR_DS(s, r, attr, p, elem) do { \
struct drsuapi_DsReplicaAttribute *_a; \
_a = dsdb_find_object_attr_name(s, r, attr, NULL); \
if (_a && _a->value_ctr.num_values >= 1 \
&& _a->value_ctr.values[0].blob \
&& _a->value_ctr.values[0].blob->length == 4) { \
(p)->elem = talloc(mem_ctx, uint32_t); \
if (!(p)->elem) { \
d_printf("%s: talloc failed for %s\n", __location__, attr); \
return WERR_NOMEM; \
} \
*(p)->elem = IVAL(_a->value_ctr.values[0].blob->data,0);\
} else { \
(p)->elem = NULL; \
} \
} while (0)
#define GET_GUID_DS(s, r, attr, mem_ctx, p, elem) do { \
struct drsuapi_DsReplicaAttribute *_a; \
_a = dsdb_find_object_attr_name(s, r, attr, NULL); \
if (_a && _a->value_ctr.num_values >= 1 \
&& _a->value_ctr.values[0].blob \
&& _a->value_ctr.values[0].blob->length == 16) { \
enum ndr_err_code _ndr_err; \
_ndr_err = ndr_pull_struct_blob_all(_a->value_ctr.values[0].blob, \
mem_ctx, s->iconv_convenience, &(p)->elem, \
(ndr_pull_flags_fn_t)ndr_pull_GUID); \
if (!NDR_ERR_CODE_IS_SUCCESS(_ndr_err)) { \
NTSTATUS _nt_status = ndr_map_error2ntstatus(_ndr_err); \
return ntstatus_to_werror(_nt_status); \
} \
} else { \
ZERO_STRUCT((p)->elem);\
} \
} while (0)
#define GET_BLOB_DS(s, r, attr, mem_ctx, p, elem) do { \
struct drsuapi_DsReplicaAttribute *_a; \
_a = dsdb_find_object_attr_name(s, r, attr, NULL); \
if (_a && _a->value_ctr.num_values >= 1 \
&& _a->value_ctr.values[0].blob) { \
(p)->elem = *_a->value_ctr.values[0].blob;\
talloc_steal(mem_ctx, (p)->elem.data); \
} else { \
ZERO_STRUCT((p)->elem);\
}\
} while (0)
WERROR dsdb_attribute_from_drsuapi(struct dsdb_schema *schema,
struct drsuapi_DsReplicaObject *r,
TALLOC_CTX *mem_ctx,
struct dsdb_attribute *attr)
{
WERROR status;
GET_STRING_DS(schema, r, "name", mem_ctx, attr, cn, true);
GET_STRING_DS(schema, r, "lDAPDisplayName", mem_ctx, attr, lDAPDisplayName, true);
GET_UINT32_DS(schema, r, "attributeID", attr, attributeID_id);
status = dsdb_map_int2oid(schema, attr->attributeID_id, mem_ctx, &attr->attributeID_oid);
if (!W_ERROR_IS_OK(status)) {
DEBUG(0,("%s: '%s': unable to map attributeID 0x%08X: %s\n",
__location__, attr->lDAPDisplayName, attr->attributeID_id,
win_errstr(status)));
return status;
}
GET_GUID_DS(schema, r, "schemaIDGUID", mem_ctx, attr, schemaIDGUID);
GET_UINT32_DS(schema, r, "mAPIID", attr, mAPIID);
GET_GUID_DS(schema, r, "attributeSecurityGUID", mem_ctx, attr, attributeSecurityGUID);
GET_UINT32_DS(schema, r, "searchFlags", attr, searchFlags);
GET_UINT32_DS(schema, r, "systemFlags", attr, systemFlags);
GET_BOOL_DS(schema, r, "isMemberOfPartialAttributeSet", attr, isMemberOfPartialAttributeSet, false);
GET_UINT32_DS(schema, r, "linkID", attr, linkID);
GET_UINT32_DS(schema, r, "attributeSyntax", attr, attributeSyntax_id);
status = dsdb_map_int2oid(schema, attr->attributeSyntax_id, mem_ctx, &attr->attributeSyntax_oid);
if (!W_ERROR_IS_OK(status)) {
DEBUG(0,("%s: '%s': unable to map attributeSyntax 0x%08X: %s\n",
__location__, attr->lDAPDisplayName, attr->attributeSyntax_id,
win_errstr(status)));
return status;
}
GET_UINT32_DS(schema, r, "oMSyntax", attr, oMSyntax);
GET_BLOB_DS(schema, r, "oMObjectClass", mem_ctx, attr, oMObjectClass);
GET_BOOL_DS(schema, r, "isSingleValued", attr, isSingleValued, true);
GET_UINT32_PTR_DS(schema, r, "rangeLower", attr, rangeLower);
GET_UINT32_PTR_DS(schema, r, "rangeUpper", attr, rangeUpper);
GET_BOOL_DS(schema, r, "extendedCharsAllowed", attr, extendedCharsAllowed, false);
GET_UINT32_DS(schema, r, "schemaFlagsEx", attr, schemaFlagsEx);
GET_BLOB_DS(schema, r, "msDs-Schema-Extensions", mem_ctx, attr, msDs_Schema_Extensions);
GET_BOOL_DS(schema, r, "showInAdvancedViewOnly", attr, showInAdvancedViewOnly, false);
GET_STRING_DS(schema, r, "adminDisplayName", mem_ctx, attr, adminDisplayName, false);
GET_STRING_DS(schema, r, "adminDescription", mem_ctx, attr, adminDescription, false);
GET_STRING_DS(schema, r, "classDisplayName", mem_ctx, attr, classDisplayName, false);
GET_BOOL_DS(schema, r, "isEphemeral", attr, isEphemeral, false);
GET_BOOL_DS(schema, r, "isDefunct", attr, isDefunct, false);
GET_BOOL_DS(schema, r, "systemOnly", attr, systemOnly, false);
attr->syntax = dsdb_syntax_for_attribute(attr);
if (!attr->syntax) {
return WERR_DS_ATT_SCHEMA_REQ_SYNTAX;
}
return WERR_OK;
}
WERROR dsdb_class_from_drsuapi(struct dsdb_schema *schema,
struct drsuapi_DsReplicaObject *r,
TALLOC_CTX *mem_ctx,
struct dsdb_class *obj)
{
WERROR status;
GET_STRING_DS(schema, r, "name", mem_ctx, obj, cn, true);
GET_STRING_DS(schema, r, "lDAPDisplayName", mem_ctx, obj, lDAPDisplayName, true);
GET_UINT32_DS(schema, r, "governsID", obj, governsID_id);
status = dsdb_map_int2oid(schema, obj->governsID_id, mem_ctx, &obj->governsID_oid);
if (!W_ERROR_IS_OK(status)) {
DEBUG(0,("%s: '%s': unable to map governsID 0x%08X: %s\n",
__location__, obj->lDAPDisplayName, obj->governsID_id,
win_errstr(status)));
return status;
}
GET_GUID_DS(schema, r, "schemaIDGUID", mem_ctx, obj, schemaIDGUID);
GET_UINT32_DS(schema, r, "objectClassCategory", obj, objectClassCategory);
GET_STRING_DS(schema, r, "rDNAttID", mem_ctx, obj, rDNAttID, false);
GET_DN_DS(schema, r, "defaultObjectCategory", mem_ctx, obj, defaultObjectCategory, true);
GET_STRING_DS(schema, r, "subClassOf", mem_ctx, obj, subClassOf, true);
GET_STRING_LIST_DS(schema, r, "systemAuxiliaryClass", mem_ctx, obj, systemAuxiliaryClass, false);
GET_STRING_LIST_DS(schema, r, "auxiliaryClass", mem_ctx, obj, auxiliaryClass, false);
GET_STRING_LIST_DS(schema, r, "systemMustContain", mem_ctx, obj, systemMustContain, false);
GET_STRING_LIST_DS(schema, r, "systemMayContain", mem_ctx, obj, systemMayContain, false);
GET_STRING_LIST_DS(schema, r, "mustContain", mem_ctx, obj, mustContain, false);
GET_STRING_LIST_DS(schema, r, "mayContain", mem_ctx, obj, mayContain, false);
GET_STRING_LIST_DS(schema, r, "systemPossSuperiors", mem_ctx, obj, systemPossSuperiors, false);
GET_STRING_LIST_DS(schema, r, "possSuperiors", mem_ctx, obj, possSuperiors, false);
GET_STRING_LIST_DS(schema, r, "possibleInferiors", mem_ctx, obj, possibleInferiors, false);
GET_STRING_DS(schema, r, "defaultSecurityDescriptor", mem_ctx, obj, defaultSecurityDescriptor, false);
GET_UINT32_DS(schema, r, "schemaFlagsEx", obj, schemaFlagsEx);
GET_BLOB_DS(schema, r, "msDs-Schema-Extensions", mem_ctx, obj, msDs_Schema_Extensions);
GET_BOOL_DS(schema, r, "showInAdvancedViewOnly", obj, showInAdvancedViewOnly, false);
GET_STRING_DS(schema, r, "adminDisplayName", mem_ctx, obj, adminDisplayName, false);
GET_STRING_DS(schema, r, "adminDescription", mem_ctx, obj, adminDescription, false);
GET_STRING_DS(schema, r, "classDisplayName", mem_ctx, obj, classDisplayName, false);
GET_BOOL_DS(schema, r, "defaultHidingValue", obj, defaultHidingValue, false);
GET_BOOL_DS(schema, r, "isDefunct", obj, isDefunct, false);
GET_BOOL_DS(schema, r, "systemOnly", obj, systemOnly, false);
return WERR_OK;
}