diff options
Diffstat (limited to 'source4/rpc_server/samr/samdb.c')
-rw-r--r-- | source4/rpc_server/samr/samdb.c | 302 |
1 files changed, 259 insertions, 43 deletions
diff --git a/source4/rpc_server/samr/samdb.c b/source4/rpc_server/samr/samdb.c index d384c6ada7..f382dcd136 100644 --- a/source4/rpc_server/samr/samdb.c +++ b/source4/rpc_server/samr/samdb.c @@ -101,8 +101,9 @@ static void *samdb_alloc(void *context, void *ptr, size_t size) */ int samdb_search_v(void *ctx, TALLOC_CTX *mem_ctx, + const char *basedn, struct ldb_message ***res, - char * const *attrs, + const char * const *attrs, const char *format, va_list ap) { @@ -117,7 +118,7 @@ int samdb_search_v(void *ctx, ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx); - count = ldb_search(sam_ctx->ldb, NULL, LDB_SCOPE_SUBTREE, expr, attrs, res); + count = ldb_search(sam_ctx->ldb, basedn, LDB_SCOPE_SUBTREE, expr, attrs, res); free(expr); @@ -130,15 +131,16 @@ int samdb_search_v(void *ctx, */ int samdb_search(void *ctx, TALLOC_CTX *mem_ctx, + const char *basedn, struct ldb_message ***res, - char * const *attrs, + const char * const *attrs, const char *format, ...) { va_list ap; int count; va_start(ap, format); - count = samdb_search_v(ctx, mem_ctx, res, attrs, format, ap); + count = samdb_search_v(ctx, mem_ctx, basedn, res, attrs, format, ap); va_end(ap); return count; @@ -154,50 +156,52 @@ int samdb_search_free(void *ctx, ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx); return ldb_search_free(sam_ctx->ldb, res); } - /* search the sam for a single string attribute in exactly 1 record */ -char *samdb_search_string(void *ctx, - TALLOC_CTX *mem_ctx, - const char *attr_name, - const char *format, ...) +const char *samdb_search_string_v(void *ctx, + TALLOC_CTX *mem_ctx, + const char *basedn, + const char *attr_name, + const char *format, va_list ap) { - va_list ap; int count; - char * const attrs[2] = { attr_name, NULL }; + const char * const attrs[2] = { attr_name, NULL }; struct ldb_message **res = NULL; - char *str = NULL; - va_start(ap, format); - count = samdb_search_v(ctx, mem_ctx, &res, attrs, format, ap); - va_end(ap); - - if (count == 0) { - return NULL; + count = samdb_search_v(ctx, mem_ctx, basedn, &res, attrs, format, ap); + if (count > 1) { + DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", + attr_name, format, count)); } - - /* make sure its single valued */ - if (count != 1 || - res[0]->num_elements != 1 || - res[0]->elements[0].num_values != 1 || - res[0]->elements[0].values[0].data == NULL) { - DEBUG(1,("samdb: search for %s %s not single valued\n", - attr_name, format)); + if (count != 1) { samdb_search_free(ctx, mem_ctx, res); return NULL; } - str = talloc_strndup(mem_ctx, - res[0]->elements[0].values[0].data, - res[0]->elements[0].values[0].length); + return samdb_result_string(res[0], attr_name, NULL); +} + + +/* + search the sam for a single string attribute in exactly 1 record +*/ +const char *samdb_search_string(void *ctx, + TALLOC_CTX *mem_ctx, + const char *basedn, + const char *attr_name, + const char *format, ...) +{ + va_list ap; + const char *str; - samdb_search_free(ctx, mem_ctx, res); + va_start(ap, format); + str = samdb_search_string_v(ctx, mem_ctx, basedn, attr_name, format, ap); + va_end(ap); return str; } - /* search the sam for multipe records each giving a single string attribute @@ -205,17 +209,18 @@ char *samdb_search_string(void *ctx, */ int samdb_search_string_multiple(void *ctx, TALLOC_CTX *mem_ctx, - char ***strs, + const char *basedn, + const char ***strs, const char *attr_name, const char *format, ...) { va_list ap; int count, i; - char * const attrs[2] = { attr_name, NULL }; + const char * const attrs[2] = { attr_name, NULL }; struct ldb_message **res = NULL; va_start(ap, format); - count = samdb_search_v(ctx, mem_ctx, &res, attrs, format, ap); + count = samdb_search_v(ctx, mem_ctx, basedn, &res, attrs, format, ap); va_end(ap); if (count <= 0) { @@ -224,9 +229,7 @@ int samdb_search_string_multiple(void *ctx, /* make sure its single valued */ for (i=0;i<count;i++) { - if (res[i]->num_elements != 1 || - res[i]->elements[0].num_values != 1 || - res[i]->elements[0].values[0].data == NULL) { + if (res[i]->num_elements != 1) { DEBUG(1,("samdb: search for %s %s not single valued\n", attr_name, format)); samdb_search_free(ctx, mem_ctx, res); @@ -234,21 +237,17 @@ int samdb_search_string_multiple(void *ctx, } } - *strs = talloc_array_p(mem_ctx, char *, count+1); + *strs = talloc_array_p(mem_ctx, const char *, count+1); if (! *strs) { samdb_search_free(ctx, mem_ctx, res); return -1; } for (i=0;i<count;i++) { - (*strs)[i] = talloc_strndup(mem_ctx, - res[i]->elements[0].values[0].data, - res[i]->elements[0].values[0].length); + (*strs)[i] = samdb_result_string(res[i], attr_name, NULL); } (*strs)[count] = NULL; - samdb_search_free(ctx, mem_ctx, res); - return count; } @@ -259,3 +258,220 @@ uint_t samdb_result_uint(struct ldb_message *msg, const char *attr, uint_t defau { return ldb_msg_find_uint(msg, attr, default_value); } + +/* + pull a string from a result set. +*/ +const char *samdb_result_string(struct ldb_message *msg, const char *attr, char *default_value) +{ + return ldb_msg_find_string(msg, attr, default_value); +} + + +/* + copy from a template record to a message +*/ +int samdb_copy_template(void *ctx, TALLOC_CTX *mem_ctx, + struct ldb_message *msg, const char *expression) +{ + struct ldb_message **res, *t; + int ret, i, j; + + + /* pull the template record */ + ret = samdb_search(ctx, mem_ctx, NULL, &res, NULL, expression); + if (ret != 1) { + DEBUG(1,("samdb: ERROR: template '%s' matched %d records\n", + expression, ret)); + return -1; + } + t = res[0]; + + for (i=0;i<t->num_elements;i++) { + struct ldb_message_element *el = &t->elements[i]; + /* some elements should not be copied from the template */ + if (strcasecmp(el->name, "cn") == 0 || + strcasecmp(el->name, "name") == 0 || + strcasecmp(el->name, "sAMAccountName") == 0) { + continue; + } + for (j=0;j<el->num_values;j++) { + if (strcasecmp(el->name, "objectClass") == 0 && + strcasecmp((char *)el->values[j].data, "userTemplate") == 0) { + continue; + } + samdb_msg_add_string(ctx, mem_ctx, msg, el->name, + (char *)el->values[j].data); + } + } + + return 0; +} + + +/* + allocate a new id, attempting to do it atomically + return 0 on failure, the id on success +*/ +static NTSTATUS _samdb_allocate_next_id(void *ctx, TALLOC_CTX *mem_ctx, const char *dn, + const char *attr, uint32 *id) +{ + struct samdb_context *sam_ctx = ctx; + struct ldb_message msg; + int ret; + const char *str; + struct ldb_val vals[2]; + struct ldb_message_element els[2]; + + str = samdb_search_string(ctx, mem_ctx, NULL, attr, "dn=%s", dn); + if (!str) { + DEBUG(1,("id not found at %s %s\n", dn, attr)); + return NT_STATUS_OBJECT_NAME_INVALID; + } + + *id = strtol(str, NULL, 0); + if ((*id)+1 == 0) { + /* out of IDs ! */ + return NT_STATUS_INSUFFICIENT_RESOURCES; + } + + /* we do a delete and add as a single operation. That prevents + a race */ + ZERO_STRUCT(msg); + msg.dn = talloc_strdup(mem_ctx, dn); + if (!msg.dn) { + return NT_STATUS_NO_MEMORY; + } + msg.num_elements = 2; + msg.elements = els; + + els[0].num_values = 1; + els[0].values = &vals[0]; + els[0].flags = LDB_FLAG_MOD_DELETE; + els[0].name = talloc_strdup(mem_ctx, attr); + if (!els[0].name) { + return NT_STATUS_NO_MEMORY; + } + + els[1].num_values = 1; + els[1].values = &vals[1]; + els[1].flags = LDB_FLAG_MOD_ADD; + els[1].name = els[0].name; + + vals[0].data = talloc_asprintf(mem_ctx, "%u", *id); + if (!vals[0].data) { + return NT_STATUS_NO_MEMORY; + } + vals[0].length = strlen(vals[0].data); + + vals[1].data = talloc_asprintf(mem_ctx, "%u", (*id)+1); + if (!vals[1].data) { + return NT_STATUS_NO_MEMORY; + } + vals[1].length = strlen(vals[1].data); + + ret = ldb_modify(sam_ctx->ldb, &msg); + if (ret != 0) { + return NT_STATUS_UNEXPECTED_IO_ERROR; + } + + (*id)++; + + return NT_STATUS_OK; +} + +/* + allocate a new id, attempting to do it atomically + return 0 on failure, the id on success +*/ +NTSTATUS samdb_allocate_next_id(void *ctx, TALLOC_CTX *mem_ctx, const char *dn, const char *attr, + uint32 *id) +{ + int tries = 10; + NTSTATUS status; + + /* we need to try multiple times to cope with two account + creations at the same time */ + while (tries--) { + status = _samdb_allocate_next_id(ctx, mem_ctx, dn, attr, id); + if (!NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) { + break; + } + } + + if (NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) { + DEBUG(1,("Failed to increment id %s at %s\n", attr, dn)); + } + + return status; +} + + +/* + add a string element to a message +*/ +int samdb_msg_add_string(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, const char *str) +{ + struct samdb_context *sam_ctx = ctx; + char *s = talloc_strdup(mem_ctx, str); + char *a = talloc_strdup(mem_ctx, attr_name); + if (s == NULL || a == NULL) { + return -1; + } + ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx); + return ldb_msg_add_string(sam_ctx->ldb, msg, a, s); +} + +/* + set a string element in a message +*/ +int samdb_msg_set_string(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, const char *str) +{ + struct samdb_context *sam_ctx = ctx; + struct ldb_message_element *el; + + ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx); + + el = ldb_msg_find_element(msg, attr_name); + if (el) { + el->num_values = 0; + } + return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, str); +} + +/* + set a ldaptime element in a message +*/ +int samdb_msg_set_ldaptime(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, time_t t) +{ + char *str = ldap_timestring(mem_ctx, t); + if (!str) { + return -1; + } + return samdb_msg_set_string(ctx, mem_ctx, msg, attr_name, str); +} + +/* + add a record +*/ +int samdb_add(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg) +{ + struct samdb_context *sam_ctx = ctx; + + ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx); + return ldb_add(sam_ctx->ldb, msg); +} + +/* + delete a record +*/ +int samdb_delete(void *ctx, TALLOC_CTX *mem_ctx, const char *dn) +{ + struct samdb_context *sam_ctx = ctx; + + ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx); + return ldb_delete(sam_ctx->ldb, dn); +} |