summaryrefslogtreecommitdiff
path: root/source4/rpc_server/samr/samdb.c
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2004-05-08 00:02:31 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:51:48 -0500
commit0ed08d9398d0ee8d9fdbc0f387415adc32ba675e (patch)
tree6a1dde58667248156c7fd47fb9e3f5aaa2466dec /source4/rpc_server/samr/samdb.c
parenta848b0e3e26a3c572bb32475352d460d247d85ee (diff)
downloadsamba-0ed08d9398d0ee8d9fdbc0f387415adc32ba675e.tar.gz
samba-0ed08d9398d0ee8d9fdbc0f387415adc32ba675e.tar.bz2
samba-0ed08d9398d0ee8d9fdbc0f387415adc32ba675e.zip
r578: initial server side implementation of samr_CreateUser(),
samr_CreateUser2(), samr_LookupNames(), samr_OpenUser(), and samr_DeleteUser() this uses a user template in the SAM db, of objectclass "userTemplate" and dn CN=TemplateUser,CN=Templates,$BASEDN. Using a template allows an admin to add any default user attributes that they might want to the user template and all new users will receive those attributes. (This used to be commit 10b6e0011b5952c98432dc2d4b2058ac89a9cc2d)
Diffstat (limited to 'source4/rpc_server/samr/samdb.c')
-rw-r--r--source4/rpc_server/samr/samdb.c302
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);
+}