/*
Unix SMB/CIFS implementation.
- Copyright (C) Rafal Szczesniak <mimir@samba.org> 2005
+ Copyright (C) Rafal Szczesniak 2005
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 2 of the License, or
+ 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,
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, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "auth/credentials/credentials.h"
#include "librpc/ndr/libndr.h"
#include "librpc/gen_ndr/samr.h"
-#include "librpc/gen_ndr/ndr_samr.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
#include "librpc/gen_ndr/lsa.h"
#include "librpc/gen_ndr/ndr_lsa_c.h"
#include "libcli/security/security.h"
-/**
- * Verify, before actually doing anything with user accounts, whether
- * required domain is already opened and thus ready for operation.
- * If it is not, or if the opened domain is not the one requested, open
- * the requested domain.
- */
-static struct composite_context* domain_opened(struct libnet_context *ctx,
- const char *domain_name,
- struct composite_context *parent_ctx,
- struct libnet_DomainOpen *domain_open,
- void (*continue_fn)(struct composite_context*),
- void (*monitor)(struct monitor_msg*))
-{
- struct composite_context *domopen_req;
-
- if (domain_name == NULL) {
- /*
- * Try to guess the domain name from credentials,
- * if it's not been explicitly specified.
- */
-
- if (policy_handle_empty(&ctx->samr.handle)) {
- domain_open->in.domain_name = cli_credentials_get_domain(ctx->cred);
- domain_open->in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
-
- } else {
- composite_error(parent_ctx, NT_STATUS_INVALID_PARAMETER);
- return parent_ctx;
- }
-
- } else {
- /*
- * The domain name has been specified, so check whether the same
- * domain is already opened. If it is - just return NULL. Start
- * opening a new domain otherwise.
- */
-
- if (policy_handle_empty(&ctx->samr.handle) ||
- !strequal(domain_name, ctx->samr.name)) {
- domain_open->in.domain_name = domain_name;
- domain_open->in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
-
- } else {
- /* domain has already been opened and it's the same domain
- as requested */
- return NULL;
- }
- }
-
- /* send request to open the domain */
- domopen_req = libnet_DomainOpen_send(ctx, domain_open, monitor);
- if (composite_nomem(domopen_req, parent_ctx)) return parent_ctx;
-
- composite_continue(parent_ctx, domopen_req, continue_fn, parent_ctx);
- return parent_ctx;
-}
-
-
struct create_user_state {
struct libnet_CreateUser r;
struct libnet_DomainOpen domain_open;
struct composite_context *c;
struct create_user_state *s;
struct composite_context *create_req;
- struct composite_context *prereq_ctx;
+ bool prereq_met = false;
/* composite context allocation and setup */
- c = talloc_zero(mem_ctx, struct composite_context);
+ c = composite_create(mem_ctx, ctx->event_ctx);
if (c == NULL) return NULL;
s = talloc_zero(c, struct create_user_state);
if (composite_nomem(s, c)) return c;
- c->state = COMPOSITE_STATE_IN_PROGRESS;
c->private_data = s;
- c->event_ctx = ctx->event_ctx;
/* store arguments in the state structure */
s->ctx = ctx;
ZERO_STRUCT(s->r.out);
/* prerequisite: make sure the domain is opened */
- prereq_ctx = domain_opened(ctx, s->r.in.domain_name, c, &s->domain_open,
- continue_domain_open_create, monitor);
- if (prereq_ctx) return prereq_ctx;
+ prereq_met = samr_domain_opened(ctx, s->r.in.domain_name, &c, &s->domain_open,
+ continue_domain_open_create, monitor);
+ if (!prereq_met) return c;
/* prepare arguments for useradd call */
s->user_add.in.username = r->in.user_name;
r->out.error_string = talloc_strdup(mem_ctx, nt_errstr(status));
}
+ talloc_free(c);
return status;
}
struct composite_context *c;
struct delete_user_state *s;
struct composite_context *delete_req;
- struct composite_context *prereq_ctx;
+ bool prereq_met = false;
/* composite context allocation and setup */
- c = talloc_zero(mem_ctx, struct composite_context);
+ c = composite_create(mem_ctx, ctx->event_ctx);
if (c == NULL) return NULL;
s = talloc_zero(c, struct delete_user_state);
if (composite_nomem(s, c)) return c;
c->private_data = s;
- c->state = COMPOSITE_STATE_IN_PROGRESS;
- c->event_ctx = ctx->event_ctx;
/* store arguments in state structure */
s->ctx = ctx;
ZERO_STRUCT(s->r.out);
/* prerequisite: make sure the domain is opened before proceeding */
- prereq_ctx = domain_opened(ctx, s->r.in.domain_name, c, &s->domain_open,
- continue_domain_open_delete, monitor);
- if (prereq_ctx) return prereq_ctx;
+ prereq_met = samr_domain_opened(ctx, s->r.in.domain_name, &c, &s->domain_open,
+ continue_domain_open_delete, monitor);
+ if (!prereq_met) return c;
/* prepare arguments for userdel call */
s->user_del.in.username = r->in.user_name;
r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
}
+ talloc_free(c);
return status;
}
const uint16_t level = 21;
struct composite_context *c;
struct modify_user_state *s;
- struct composite_context *prereq_ctx;
struct composite_context *userinfo_req;
+ bool prereq_met = false;
- c = talloc_zero(mem_ctx, struct composite_context);
+ c = composite_create(mem_ctx, ctx->event_ctx);
if (c == NULL) return NULL;
s = talloc_zero(c, struct modify_user_state);
if (composite_nomem(s, c)) return c;
- c->state = COMPOSITE_STATE_IN_PROGRESS;
c->private_data = s;
- c->event_ctx = ctx->event_ctx;
s->ctx = ctx;
s->r = *r;
- prereq_ctx = domain_opened(ctx, s->r.in.domain_name, c, &s->domain_open,
- continue_domain_open_modify, monitor);
- if (prereq_ctx) return prereq_ctx;
+ prereq_met = samr_domain_opened(ctx, s->r.in.domain_name, &c, &s->domain_open,
+ continue_domain_open_modify, monitor);
+ if (!prereq_met) return c;
s->user_info.in.username = r->in.user_name;
s->user_info.in.domain_handle = ctx->samr.handle;
/* account expiry change */
SET_FIELD_NTTIME(r->in, user, mod, acct_expiry, USERMOD_FIELD_ACCT_EXPIRY);
+ /* account flags change */
+ SET_FIELD_ACCT_FLAGS(r->in, user, mod, acct_flags, USERMOD_FIELD_ACCT_FLAGS);
+
return NT_STATUS_OK;
}
struct libnet_ModifyUser *r)
{
NTSTATUS status = composite_wait(c);
+
+ talloc_free(c);
return status;
}
struct user_info_state {
struct libnet_context *ctx;
const char *domain_name;
+ enum libnet_UserInfo_level level;
const char *user_name;
+ const char *sid_string;
struct libnet_LookupName lookup;
struct libnet_DomainOpen domopen;
struct libnet_rpc_userinfo userinfo;
{
struct composite_context *c;
struct user_info_state *s;
- struct composite_context *prereq_ctx;
- struct composite_context *lookup_req;
+ struct composite_context *lookup_req, *info_req;
+ bool prereq_met = false;
/* composite context allocation and setup */
c = composite_create(mem_ctx, ctx->event_ctx);
s->monitor_fn = monitor;
s->ctx = ctx;
s->domain_name = talloc_strdup(c, r->in.domain_name);
- s->user_name = talloc_strdup(c, r->in.user_name);
+ s->level = r->in.level;
+ switch (s->level) {
+ case USER_INFO_BY_NAME:
+ s->user_name = talloc_strdup(c, r->in.data.user_name);
+ s->sid_string = NULL;
+ break;
+ case USER_INFO_BY_SID:
+ s->user_name = NULL;
+ s->sid_string = dom_sid_string(c, r->in.data.user_sid);
+ break;
+ }
/* prerequisite: make sure the domain is opened */
- prereq_ctx = domain_opened(ctx, s->domain_name, c, &s->domopen,
- continue_domain_open_info, monitor);
- if (prereq_ctx) return prereq_ctx;
-
- /* prepare arguments for LookupName call */
- s->lookup.in.domain_name = s->domain_name;
- s->lookup.in.name = s->user_name;
-
- /* send the request */
- lookup_req = libnet_LookupName_send(ctx, c, &s->lookup, s->monitor_fn);
- if (composite_nomem(lookup_req, c)) return c;
+ prereq_met = samr_domain_opened(ctx, s->domain_name, &c, &s->domopen,
+ continue_domain_open_info, monitor);
+ if (!prereq_met) return c;
+
+ switch (s->level) {
+ case USER_INFO_BY_NAME:
+ /* prepare arguments for LookupName call */
+ s->lookup.in.domain_name = s->domain_name;
+ s->lookup.in.name = s->user_name;
+
+ /* send the request */
+ lookup_req = libnet_LookupName_send(ctx, c, &s->lookup,
+ s->monitor_fn);
+ if (composite_nomem(lookup_req, c)) return c;
+
+ /* set the next stage */
+ composite_continue(c, lookup_req, continue_name_found, c);
+ break;
+ case USER_INFO_BY_SID:
+ /* prepare arguments for UserInfo call */
+ s->userinfo.in.domain_handle = s->ctx->samr.handle;
+ s->userinfo.in.sid = s->sid_string;
+ s->userinfo.in.level = 21;
+
+ /* send the request */
+ info_req = libnet_rpc_userinfo_send(s->ctx->samr.pipe,
+ &s->userinfo,
+ s->monitor_fn);
+ if (composite_nomem(info_req, c)) return c;
+
+ /* set the next stage */
+ composite_continue(c, info_req, continue_info_received, c);
+ break;
+ }
- /* set the next stage */
- composite_continue(c, lookup_req, continue_name_found, c);
return c;
}
{
struct composite_context *c;
struct user_info_state *s;
- struct composite_context *lookup_req;
+ struct composite_context *lookup_req, *info_req;
struct monitor_msg msg;
c = talloc_get_type(ctx->async.private_data, struct composite_context);
/* send monitor message */
if (s->monitor_fn) s->monitor_fn(&msg);
- /* prepare arguments for LookupName call */
- s->lookup.in.domain_name = s->domain_name;
- s->lookup.in.name = s->user_name;
-
- /* send the request */
- lookup_req = libnet_LookupName_send(s->ctx, c, &s->lookup, s->monitor_fn);
- if (composite_nomem(lookup_req, c)) return;
-
- /* set the next stage */
- composite_continue(c, lookup_req, continue_name_found, c);
+ switch (s->level) {
+ case USER_INFO_BY_NAME:
+ /* prepare arguments for LookupName call */
+ s->lookup.in.domain_name = s->domain_name;
+ s->lookup.in.name = s->user_name;
+
+ /* send the request */
+ lookup_req = libnet_LookupName_send(s->ctx, c, &s->lookup, s->monitor_fn);
+ if (composite_nomem(lookup_req, c)) return;
+
+ /* set the next stage */
+ composite_continue(c, lookup_req, continue_name_found, c);
+ break;
+
+ case USER_INFO_BY_SID:
+ /* prepare arguments for UserInfo call */
+ s->userinfo.in.domain_handle = s->ctx->samr.handle;
+ s->userinfo.in.sid = s->sid_string;
+ s->userinfo.in.level = 21;
+
+ /* send the request */
+ info_req = libnet_rpc_userinfo_send(s->ctx->samr.pipe,
+ &s->userinfo,
+ s->monitor_fn);
+ if (composite_nomem(info_req, c)) return;
+
+ /* set the next stage */
+ composite_continue(c, info_req, continue_info_received, c);
+ break;
+ }
}
s = talloc_get_type(c->private_data, struct user_info_state);
info = &s->userinfo.out.info.info21;
+ r->out.user_sid = dom_sid_add_rid(mem_ctx, s->ctx->samr.sid, info->rid);
+ r->out.primary_group_sid = dom_sid_add_rid(mem_ctx, s->ctx->samr.sid, info->primary_gid);
+
/* string fields */
r->out.account_name = talloc_steal(mem_ctx, info->account_name.string);
r->out.full_name = talloc_steal(mem_ctx, info->full_name.string);
r->out.acct_flags = info->acct_flags;
r->out.error_string = talloc_strdup(mem_ctx, "Success");
+
+ } else {
+ r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
}
talloc_free(c);
-
return status;
}
struct userlist_state {
struct libnet_context *ctx;
+ const char *domain_name;
+ struct lsa_DomainInfo dominfo;
int page_size;
- uint32_t resume;
- struct lsa_SidArray sids;
- struct lsa_TransNameArray names;
- struct lsa_RefDomainList domains;
+ uint32_t resume_index;
struct userlist *users;
- uint32_t num_resolved;
+ uint32_t count;
struct libnet_DomainOpen domain_open;
- struct lsa_EnumAccounts user_list;
- struct lsa_LookupSids lookup_sids;
+ struct lsa_QueryInfoPolicy query_domain;
+ struct samr_EnumDomainUsers user_list;
void (*monitor_fn)(struct monitor_msg*);
};
-static void continue_domain_open_userlist(struct composite_context *ctx);
-static void continue_users_enumerated(struct rpc_request *req);
-static void continue_sids_resolved(struct rpc_request *req);
+static void continue_lsa_domain_opened(struct composite_context *ctx);
+static void continue_domain_queried(struct tevent_req *subreq);
+static void continue_samr_domain_opened(struct composite_context *ctx);
+static void continue_users_enumerated(struct tevent_req *subreq);
/**
*
* @param ctx initialised libnet context
* @param mem_ctx memory context of this call
- * @param r pointer to a structure containing arguments and results of this call
+ * @param r pointer to structure containing arguments and results of this call
* @param monitor function pointer for receiving monitor messages
* @return compostite context of this request
*/
{
struct composite_context *c;
struct userlist_state *s;
- struct composite_context *prereq_ctx;
- struct rpc_request *enum_req;
+ struct tevent_req *subreq;
+ bool prereq_met = false;
/* composite context allocation and setup */
- c = composite_create(ctx, ctx->event_ctx);
+ c = composite_create(mem_ctx, ctx->event_ctx);
if (c == NULL) return NULL;
s = talloc_zero(c, struct userlist_state);
c->private_data = s;
/* store the arguments in the state structure */
- s->ctx = ctx;
- s->page_size = r->in.page_size;
- s->resume = (uint32_t)r->in.restore_index;
- s->monitor_fn = monitor;
+ s->ctx = ctx;
+ s->page_size = r->in.page_size;
+ s->resume_index = r->in.resume_index;
+ s->domain_name = talloc_strdup(c, r->in.domain_name);
+ s->monitor_fn = monitor;
/* make sure we have lsa domain handle before doing anything */
- prereq_ctx = lsa_domain_opened(ctx, r->in.domain_name, c, &s->domain_open,
- continue_domain_open_userlist, monitor);
- if (prereq_ctx) return prereq_ctx;
+ prereq_met = lsa_domain_opened(ctx, s->domain_name, &c, &s->domain_open,
+ continue_lsa_domain_opened, monitor);
+ if (!prereq_met) return c;
- /* prepare arguments */
- s->user_list.in.handle = &ctx->lsa.handle;
- s->user_list.in.num_entries = s->page_size;
- s->user_list.in.resume_handle = &s->resume;
- s->user_list.out.resume_handle = &s->resume;
- s->user_list.out.sids = &s->sids;
+ /* prepare arguments of QueryDomainInfo call */
+ s->query_domain.in.handle = &ctx->lsa.handle;
+ s->query_domain.in.level = LSA_POLICY_INFO_DOMAIN;
+ s->query_domain.out.info = talloc_zero(c, union lsa_PolicyInformation *);
+ if (composite_nomem(s->query_domain.out.info, c)) return c;
- /* send request */
- enum_req = dcerpc_lsa_EnumAccounts_send(ctx->lsa.pipe, c, &s->user_list);
- if (composite_nomem(enum_req, c)) return c;
+ /* send the request */
+ subreq = dcerpc_lsa_QueryInfoPolicy_r_send(s, c->event_ctx,
+ ctx->lsa.pipe->binding_handle,
+ &s->query_domain);
+ if (composite_nomem(subreq, c)) return c;
- composite_continue_rpc(c, enum_req, continue_users_enumerated, c);
+ tevent_req_set_callback(subreq, continue_domain_queried, c);
return c;
}
/*
- * Step 0.5 (optional): receive lsa domain handle and request to enumerate accounts
+ * Stage 0.5 (optional): receive lsa domain handle and send
+ * request to query domain info
*/
-static void continue_domain_open_userlist(struct composite_context *ctx)
+static void continue_lsa_domain_opened(struct composite_context *ctx)
{
struct composite_context *c;
struct userlist_state *s;
- struct rpc_request *enum_req;
-
+ struct tevent_req *subreq;
+
c = talloc_get_type(ctx->async.private_data, struct composite_context);
s = talloc_get_type(c->private_data, struct userlist_state);
-
+
/* receive lsa domain handle */
c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
+ if (!composite_is_ok(c)) return;
- /* prepare arguments */
- s->user_list.in.handle = &s->ctx->lsa.handle;
- s->user_list.in.num_entries = s->page_size;
- s->user_list.in.resume_handle = &s->resume;
- s->user_list.out.resume_handle = &s->resume;
- s->user_list.out.sids = &s->sids;
-
- /* send request */
- enum_req = dcerpc_lsa_EnumAccounts_send(s->ctx->lsa.pipe, c, &s->user_list);
- if (composite_nomem(enum_req, c)) return;
+ /* prepare arguments of QueryDomainInfo call */
+ s->query_domain.in.handle = &s->ctx->lsa.handle;
+ s->query_domain.in.level = LSA_POLICY_INFO_DOMAIN;
+ s->query_domain.out.info = talloc_zero(c, union lsa_PolicyInformation *);
+ if (composite_nomem(s->query_domain.out.info, c)) return;
- composite_continue_rpc(c, enum_req, continue_users_enumerated, c);
+ /* send the request */
+ subreq = dcerpc_lsa_QueryInfoPolicy_r_send(s, c->event_ctx,
+ s->ctx->lsa.pipe->binding_handle,
+ &s->query_domain);
+ if (composite_nomem(subreq, c)) return;
+
+ tevent_req_set_callback(subreq, continue_domain_queried, c);
}
/*
- * Step 1: receive enumerated sids and request to resolve them to names
+ * Stage 1: receive domain info and request to enum users,
+ * provided a valid samr handle is opened
*/
-static void continue_users_enumerated(struct rpc_request *req)
+static void continue_domain_queried(struct tevent_req *subreq)
{
struct composite_context *c;
struct userlist_state *s;
- struct rpc_request *sidres_req;
- int i, count;
-
- c = talloc_get_type(req->async.private, struct composite_context);
+ bool prereq_met = false;
+
+ c = tevent_req_callback_data(subreq, struct composite_context);
s = talloc_get_type(c->private_data, struct userlist_state);
- /* receive result of lsa_EnumAccounts request */
- c->status = dcerpc_ndr_request_recv(req);
+ /* receive result of rpc request */
+ c->status = dcerpc_lsa_QueryInfoPolicy_r_recv(subreq, s);
+ TALLOC_FREE(subreq);
+ if (!composite_is_ok(c)) return;
- if (NT_STATUS_IS_OK(c->status) ||
- NT_STATUS_EQUAL(c->status, STATUS_MORE_ENTRIES) ||
- NT_STATUS_EQUAL(c->status, NT_STATUS_NO_MORE_ENTRIES)) {
-
- /* copy received sids */
- count = s->user_list.out.sids->num_sids;
- s->users = talloc_array(c, struct userlist, count);
- for (i = 0; i < count; i++) {
- s->users[i].sid = dom_sid_string(c, s->user_list.out.sids->sids[i].sid);
- }
+ /* get the returned domain info */
+ s->dominfo = (*s->query_domain.out.info)->domain;
+
+ /* make sure we have samr domain handle before continuing */
+ prereq_met = samr_domain_opened(s->ctx, s->domain_name, &c, &s->domain_open,
+ continue_samr_domain_opened, s->monitor_fn);
+ if (!prereq_met) return;
+
+ /* prepare arguments of EnumDomainUsers call */
+ s->user_list.in.domain_handle = &s->ctx->samr.handle;
+ s->user_list.in.max_size = s->page_size;
+ s->user_list.in.resume_handle = &s->resume_index;
+ s->user_list.in.acct_flags = ACB_NORMAL;
+ s->user_list.out.resume_handle = &s->resume_index;
+ s->user_list.out.num_entries = talloc(s, uint32_t);
+ if (composite_nomem(s->user_list.out.num_entries, c)) return;
+ s->user_list.out.sam = talloc(s, struct samr_SamArray *);
+ if (composite_nomem(s->user_list.out.sam, c)) return;
- /* prepare arguments to resolve sids */
- s->lookup_sids.in.handle = &s->ctx->lsa.handle;
- s->lookup_sids.in.sids = &s->sids;
- s->lookup_sids.in.names = &s->names;
- s->lookup_sids.in.level = 1;
- s->lookup_sids.in.count = &s->num_resolved;
- s->lookup_sids.out.names = &s->names;
- s->lookup_sids.out.count = &s->num_resolved;
-
- /* send request */
- sidres_req = dcerpc_lsa_LookupSids_send(s->ctx->lsa.pipe, c, &s->lookup_sids);
- if (composite_nomem(sidres_req, c)) return;
+ /* send the request */
+ subreq = dcerpc_samr_EnumDomainUsers_r_send(s, c->event_ctx,
+ s->ctx->samr.pipe->binding_handle,
+ &s->user_list);
+ if (composite_nomem(subreq, c)) return;
- composite_continue_rpc(c, sidres_req, continue_sids_resolved, c);
+ tevent_req_set_callback(subreq, continue_users_enumerated, c);
+}
- } else {
- composite_error(c, c->status);
- }
+
+/*
+ * Stage 1.5 (optional): receive samr domain handle
+ * and request to enumerate accounts
+ */
+static void continue_samr_domain_opened(struct composite_context *ctx)
+{
+ struct composite_context *c;
+ struct userlist_state *s;
+ struct tevent_req *subreq;
+
+ c = talloc_get_type(ctx->async.private_data, struct composite_context);
+ s = talloc_get_type(c->private_data, struct userlist_state);
+
+ /* receive samr domain handle */
+ c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
+ if (!composite_is_ok(c)) return;
+
+ /* prepare arguments of EnumDomainUsers call */
+ s->user_list.in.domain_handle = &s->ctx->samr.handle;
+ s->user_list.in.max_size = s->page_size;
+ s->user_list.in.resume_handle = &s->resume_index;
+ s->user_list.in.acct_flags = ACB_NORMAL;
+ s->user_list.out.resume_handle = &s->resume_index;
+ s->user_list.out.sam = talloc(s, struct samr_SamArray *);
+ if (composite_nomem(s->user_list.out.sam, c)) return;
+ s->user_list.out.num_entries = talloc(s, uint32_t);
+ if (composite_nomem(s->user_list.out.num_entries, c)) return;
+
+ /* send the request */
+ subreq = dcerpc_samr_EnumDomainUsers_r_send(s, c->event_ctx,
+ s->ctx->samr.pipe->binding_handle,
+ &s->user_list);
+ if (composite_nomem(subreq, c)) return;
+
+ tevent_req_set_callback(subreq, continue_users_enumerated, c);
}
/*
- * Step 2: receive account names and finish the composite function
+ * Stage 2: receive enumerated users and their rids
*/
-static void continue_sids_resolved(struct rpc_request *req)
+static void continue_users_enumerated(struct tevent_req *subreq)
{
struct composite_context *c;
struct userlist_state *s;
- int i, count;
- struct lsa_TransNameArray *names;
+ uint32_t i;
- c = talloc_get_type(req->async.private, struct composite_context);
+ c = tevent_req_callback_data(subreq, struct composite_context);
s = talloc_get_type(c->private_data, struct userlist_state);
- /* receive result of lsa_LookupSids request */
- c->status = dcerpc_ndr_request_recv(req);
+ /* receive result of rpc request */
+ c->status = dcerpc_samr_EnumDomainUsers_r_recv(subreq, s);
+ TALLOC_FREE(subreq);
if (!composite_is_ok(c)) return;
- /* copy received account names */
- count = (int)s->lookup_sids.out.names->count;
- for (i = 0; i < count; i++) {
- names = s->lookup_sids.out.names;
- s->users[i].username = talloc_strdup(c, names->names[i].name.string);
- }
+ /* get the actual status of the rpc call result
+ (instead of rpc layer status) */
+ c->status = s->user_list.out.result;
- composite_done(c);
+ /* we're interested in status "ok" as well as two
+ enum-specific status codes */
+ if (NT_STATUS_IS_OK(c->status) ||
+ NT_STATUS_EQUAL(c->status, STATUS_MORE_ENTRIES) ||
+ NT_STATUS_EQUAL(c->status, NT_STATUS_NO_MORE_ENTRIES)) {
+
+ /* get enumerated accounts counter and resume handle (the latter allows
+ making subsequent call to continue enumeration) */
+ s->resume_index = *s->user_list.out.resume_handle;
+ s->count = *s->user_list.out.num_entries;
+
+ /* prepare returned user accounts array */
+ s->users = talloc_array(c, struct userlist, (*s->user_list.out.sam)->count);
+ if (composite_nomem(s->users, c)) return;
+
+ for (i = 0; i < (*s->user_list.out.sam)->count; i++) {
+ struct dom_sid *user_sid;
+ struct samr_SamEntry *entry = &(*s->user_list.out.sam)->entries[i];
+ struct dom_sid *domain_sid = (*s->query_domain.out.info)->domain.sid;
+
+ /* construct user sid from returned rid and queried domain sid */
+ user_sid = dom_sid_add_rid(c, domain_sid, entry->idx);
+ if (composite_nomem(user_sid, c)) return;
+
+ /* username */
+ s->users[i].username = talloc_strdup(s->users, entry->name.string);
+ if (composite_nomem(s->users[i].username, c)) return;
+
+ /* sid string */
+ s->users[i].sid = dom_sid_string(s->users, user_sid);
+ if (composite_nomem(s->users[i].sid, c)) return;
+ }
+
+ /* that's it */
+ composite_done(c);
+
+ } else {
+ /* something went wrong */
+ composite_error(c, c->status);
+ }
}
*
* @param c composite context returned by send request routine
* @param mem_ctx memory context of this call
- * @param r pointer to a structure containing arguments and result of this call
+ * @param r pointer to structure containing arguments and result of this call
* @return nt status
*/
NTSTATUS libnet_UserList_recv(struct composite_context* c, TALLOC_CTX *mem_ctx,
struct userlist_state *s;
if (c == NULL || mem_ctx == NULL || r == NULL) {
+ talloc_free(c);
return NT_STATUS_INVALID_PARAMETER;
}
-
+
status = composite_wait(c);
if (NT_STATUS_IS_OK(status) ||
NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) ||
s = talloc_get_type(c->private_data, struct userlist_state);
/* get results from composite context */
- r->out.count = s->user_list.out.sids->num_sids;
- r->out.restore_index = (uint)s->resume;
+ r->out.count = s->count;
+ r->out.resume_index = s->resume_index;
r->out.users = talloc_steal(mem_ctx, s->users);
-
- r->out.error_string = talloc_strdup(mem_ctx, "Success");
+
+ if (NT_STATUS_IS_OK(status)) {
+ r->out.error_string = talloc_strdup(mem_ctx, "Success");
+ } else {
+ /* success, but we're not done yet */
+ r->out.error_string = talloc_asprintf(mem_ctx, "Success (status: %s)",
+ nt_errstr(status));
+ }
} else {
r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
}
+ talloc_free(c);
return status;
}
*
* @param ctx initialised libnet context
* @param mem_ctx memory context of this call
- * @param r pointer to a structure containing arguments and result of this call
+ * @param r pointer to structure containing arguments and result of this call
* @return nt status
*/
NTSTATUS libnet_UserList(struct libnet_context *ctx,