summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2004-05-08 14:42:45 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:51:48 -0500
commit35ffc464541366ba1da0a332afae203b68512010 (patch)
tree593e24ecc08f6ca8aa02de76647c5c0eee5323d8
parent8c2636f59a48f327b26ebfc05386fa06e8c4841a (diff)
downloadsamba-35ffc464541366ba1da0a332afae203b68512010.tar.gz
samba-35ffc464541366ba1da0a332afae203b68512010.tar.bz2
samba-35ffc464541366ba1da0a332afae203b68512010.zip
r587: added server code for samr_EnumDomainUsers, and started adding
samr_SetUserInfo and samr_QueryUserInfo (This used to be commit e0db9659a85b59e52fbe033a94b411d6c64d9f9c)
-rw-r--r--source4/lib/time.c18
-rw-r--r--source4/librpc/idl/samr.idl4
-rw-r--r--source4/rpc_server/samr/dcesrv_samr.c231
-rw-r--r--source4/rpc_server/samr/samdb.c50
4 files changed, 293 insertions, 10 deletions
diff --git a/source4/lib/time.c b/source4/lib/time.c
index 0bc5fcd3fc..65b85b2180 100644
--- a/source4/lib/time.c
+++ b/source4/lib/time.c
@@ -428,3 +428,21 @@ NTTIME pull_nttime(void *base, uint16 offset)
return ret;
}
+
+/*
+ parse a nttime as a integer in a string and return a NTTIME
+*/
+NTTIME nttime_from_string(const char *s)
+{
+ double t = 0;
+ const double t32 = 4294967296.0;
+ NTTIME ret;
+ /* i wish we could rely on 64 bit systems and sscanf %llu */
+ if (sscanf(s, "%lf", &t) != 1) {
+ ret.low = 0;
+ ret.high = 0;
+ }
+ ret.high = t / t32;
+ ret.low = t - (ret.high*t32);
+ return ret;
+}
diff --git a/source4/librpc/idl/samr.idl b/source4/librpc/idl/samr.idl
index eceaf784ec..2110cd9330 100644
--- a/source4/librpc/idl/samr.idl
+++ b/source4/librpc/idl/samr.idl
@@ -262,6 +262,10 @@
/************************/
/* Function 0x0d */
+
+ /* w2k3 treats max_size as max_users*54 and sets the
+ resume_handle as the rid of the last user sent
+ */
NTSTATUS samr_EnumDomainUsers(
[in,ref] policy_handle *handle,
[in,out,ref] uint32 *resume_handle,
diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c
index bea65dceef..20460ba172 100644
--- a/source4/rpc_server/samr/dcesrv_samr.c
+++ b/source4/rpc_server/samr/dcesrv_samr.c
@@ -500,7 +500,7 @@ static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX
/* check if the user already exists */
name = samdb_search_string(d_state->sam_ctx, mem_ctx, d_state->basedn,
- "name", "(&(name=%s)(objectclass=user))", username);
+ "name", "(&(sAMAccountName=%s)(objectclass=user))", username);
if (name != NULL) {
return NT_STATUS_USER_EXISTS;
}
@@ -611,14 +611,88 @@ static NTSTATUS samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *
return samr_CreateUser2(dce_call, mem_ctx, &r2);
}
+/*
+ comparison function for sorting SamEntry array
+*/
+static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
+{
+ return e1->idx - e2->idx;
+}
/*
samr_EnumDomainUsers
*/
static NTSTATUS samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct samr_EnumDomainUsers *r)
+ struct samr_EnumDomainUsers *r)
{
- DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+ struct dcesrv_handle *h;
+ struct samr_domain_state *state;
+ struct ldb_message **res;
+ int count, i, first;
+ struct samr_SamEntry *entries;
+ const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
+
+ *r->out.resume_handle = 0;
+ r->out.sam = NULL;
+ r->out.num_entries = 0;
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
+
+ state = h->data;
+
+ /* search for all users in this domain. This could possibly be cached and
+ resumed based on resume_key */
+ count = samdb_search(state->sam_ctx, mem_ctx, state->basedn, &res, attrs,
+ "objectclass=user");
+ if (count == -1) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ if (count == 0) {
+ return NT_STATUS_OK;
+ }
+
+ /* convert to SamEntry format */
+ entries = talloc_array_p(mem_ctx, struct samr_SamEntry, count);
+ if (!entries) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ for (i=0;i<count;i++) {
+ entries[i].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0);
+ entries[i].name.name = samdb_result_string(res[i], "sAMAccountName", "");
+ }
+
+ /* sort the results by rid */
+ qsort(entries, count, sizeof(struct samr_SamEntry),
+ (comparison_fn_t)compare_SamEntry);
+
+ /* find the first entry to return */
+ for (first=0;
+ first<count && entries[first].idx <= *r->in.resume_handle;
+ first++) ;
+
+ if (first == count) {
+ return NT_STATUS_OK;
+ }
+
+ /* return the rest, limit by max_size. Note that we
+ use the w2k3 element size value of 54 */
+ r->out.num_entries = count - first;
+ r->out.num_entries = MIN(r->out.num_entries, 1+(r->in.max_size/54));
+
+ r->out.sam = talloc_p(mem_ctx, struct samr_SamArray);
+ if (!r->out.sam) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ r->out.sam->entries = entries+first;
+ r->out.sam->count = r->out.num_entries;
+
+ if (r->out.num_entries < count - first) {
+ *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
+ return STATUS_MORE_ENTRIES;
+ }
+
+ return NT_STATUS_OK;
}
@@ -1016,24 +1090,155 @@ static NTSTATUS samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *
return NT_STATUS_OK;
}
+/* these query macros make samr_QueryUserInfo a bit easier to read */
+#define QUERY_STRING(msg, field, attr) \
+ r->out.info->field = samdb_result_string(msg, attr, "");
+#define QUERY_UINT(msg, field, attr) \
+ r->out.info->field = samdb_result_uint(msg, attr, 0);
+#define QUERY_RID(msg, field, attr) \
+ r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
+#define QUERY_NTTIME(msg, field, attr) \
+ r->out.info->field = samdb_result_nttime(msg, attr, 0);
/*
samr_QueryUserInfo
*/
static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct samr_QueryUserInfo *r)
+ struct samr_QueryUserInfo *r)
{
- DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+ struct dcesrv_handle *h;
+ struct samr_account_state *state;
+ struct ldb_message *msg, **res;
+ int ret;
+
+ r->out.info = NULL;
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
+
+ state = h->data;
+
+ /* pull all the user attributes */
+ ret = samdb_search(state->sam_ctx, mem_ctx, NULL, &res, NULL,
+ "dn=%s", state->basedn);
+ if (ret != 1) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ msg = res[0];
+
+ /* allocate the info structure */
+ r->out.info = talloc_p(mem_ctx, union samr_UserInfo);
+ if (r->out.info == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ ZERO_STRUCTP(r->out.info);
+
+ /* fill in the reply */
+ switch (r->in.level) {
+ case 1:
+ QUERY_STRING(msg, info1.username.name, "sAMAccountName");
+ QUERY_STRING(msg, info1.full_name.name, "displayName");
+ QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
+ QUERY_STRING(msg, info1.description.name, "description");
+ QUERY_STRING(msg, info1.comment.name, "comment");
+ break;
+
+ case 2:
+ QUERY_STRING(msg, info2.comment.name, "comment");
+ QUERY_UINT (msg, info2.country_code, "countryCode");
+ QUERY_UINT (msg, info2.code_page, "codePage");
+ break;
+
+ case 3:
+ QUERY_STRING(msg, info3.username.name, "sAMAccountName");
+ QUERY_STRING(msg, info3.full_name.name, "displayName");
+ QUERY_RID (msg, info3.Rid, "objectSid");
+ QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
+ QUERY_STRING(msg, info3.home_directory.name, "homeDirectory");
+ QUERY_STRING(msg, info3.home_drive.name, "homeDrive");
+ QUERY_STRING(msg, info3.logon_script.name, "scriptPath");
+ QUERY_STRING(msg, info3.profile.name, "profilePath");
+ QUERY_STRING(msg, info3.workstations.name, "userWorkstations");
+ QUERY_NTTIME(msg, info3.last_logon, "lastLogon");
+ QUERY_NTTIME(msg, info3.last_logoff, "lastLogoff");
+ QUERY_NTTIME(msg, info3.last_pwd_change, "pwdLastSet");
+/*
+ QUERY_APASSC(msg, info2.allow_pwd_change, "pwdLastSet");
+ QUERY_LHOURS(msg, info2.logon_hours, "logonHours");
+ QUERY_UINT (msg, info2.bad_pwd_count, "badPwdCount");
+ QUERY_UINT (msg, info2.num_logons, "logonCount");
+ QUERY_AFLAGS(msg, info2.acct_flags, "userAccountControl");
+*/
+ break;
+
+ default:
+ r->out.info = NULL;
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ return NT_STATUS_OK;
}
+/* these are used to make the SetUserInfo code easier to follow */
+#define SET_STRING(mod, field, attr) do { \
+ if (r->in.info->field == NULL) return NT_STATUS_INVALID_PARAMETER; \
+ if (samdb_msg_add_string(state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
+ return NT_STATUS_NO_MEMORY; \
+ } \
+} while (0)
+
+#define SET_UINT(mod, field, attr) do { \
+ if (samdb_msg_add_uint(state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
+ return NT_STATUS_NO_MEMORY; \
+ } \
+} while (0)
+
/*
samr_SetUserInfo
*/
static NTSTATUS samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct samr_SetUserInfo *r)
+ struct samr_SetUserInfo *r)
{
- DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+ struct dcesrv_handle *h;
+ struct samr_account_state *state;
+ struct ldb_message mod;
+ int i, ret;
+
+ DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
+
+ state = h->data;
+
+ ZERO_STRUCT(mod);
+ mod.dn = talloc_strdup(mem_ctx, state->basedn);
+ if (!mod.dn) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ switch (r->in.level) {
+ case 2:
+ SET_STRING(&mod, info2.comment.name, "description");
+ SET_UINT (&mod, info2.country_code, "countryCode");
+ SET_UINT (&mod, info2.code_page, "codePage");
+ break;
+
+ default:
+ /* many info classes are not valid for SetUserInfo */
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
+ for (i=0;i<mod.num_elements;i++) {
+ mod.elements[i].flags = LDB_FLAG_MOD_REPLACE;
+ }
+
+ /* modify the samdb record */
+ ret = samdb_modify(state->sam_ctx, mem_ctx, &mod);
+ if (ret != 0) {
+ /* we really need samdb.c to return NTSTATUS */
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return NT_STATUS_OK;
}
@@ -1271,11 +1476,19 @@ static NTSTATUS samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *me
/*
samr_SetUserInfo2
+
+ just an alias for samr_SetUserInfo
*/
static NTSTATUS samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct samr_SetUserInfo2 *r)
+ struct samr_SetUserInfo2 *r)
{
- DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+ struct samr_SetUserInfo r2;
+
+ r2.in.handle = r->in.handle;
+ r2.in.level = r->in.level;
+ r2.in.info = r->in.info;
+
+ return samr_SetUserInfo(dce_call, mem_ctx, &r2);
}
diff --git a/source4/rpc_server/samr/samdb.c b/source4/rpc_server/samr/samdb.c
index f382dcd136..fc82303f13 100644
--- a/source4/rpc_server/samr/samdb.c
+++ b/source4/rpc_server/samr/samdb.c
@@ -262,11 +262,38 @@ uint_t samdb_result_uint(struct ldb_message *msg, const char *attr, uint_t defau
/*
pull a string from a result set.
*/
-const char *samdb_result_string(struct ldb_message *msg, const char *attr, char *default_value)
+const char *samdb_result_string(struct ldb_message *msg, const char *attr,
+ const char *default_value)
{
return ldb_msg_find_string(msg, attr, default_value);
}
+/*
+ pull a rid from a objectSid in a result set.
+*/
+uint32 samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
+ const char *attr, uint32 default_value)
+{
+ struct dom_sid *sid;
+ const char *sidstr = ldb_msg_find_string(msg, attr, NULL);
+ if (!sidstr) return default_value;
+
+ sid = dom_sid_parse_talloc(mem_ctx, sidstr);
+ if (!sid) return default_value;
+
+ return sid->sub_auths[sid->num_auths-1];
+}
+
+/*
+ pull a rid from a objectSid in a result set.
+*/
+NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr,
+ const char *default_value)
+{
+ const char *str = ldb_msg_find_string(msg, attr, default_value);
+ return nttime_from_string(str);
+}
+
/*
copy from a template record to a message
@@ -424,6 +451,16 @@ int samdb_msg_add_string(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg
}
/*
+ add a uint_t element to a message
+*/
+int samdb_msg_add_uint(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
+ const char *attr_name, uint_t v)
+{
+ const char *s = talloc_asprintf(mem_ctx, "%u", v);
+ return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, s);
+}
+
+/*
set a string element in a message
*/
int samdb_msg_set_string(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
@@ -475,3 +512,14 @@ int samdb_delete(void *ctx, TALLOC_CTX *mem_ctx, const char *dn)
ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
return ldb_delete(sam_ctx->ldb, dn);
}
+
+/*
+ modify a record
+*/
+int samdb_modify(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_modify(sam_ctx->ldb, msg);
+}