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 "includes.h"
#include "libcli/composite/composite.h"
-#include "libnet/composite.h"
-#include "libnet/userinfo.h"
+#include "librpc/gen_ndr/security.h"
+#include "libcli/security/security.h"
+#include "libnet/libnet.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
-static void userinfo_handler(struct rpc_request *req);
-
-enum userinfo_stage { USERINFO_OPENUSER, USERINFO_GETUSER, USERINFO_CLOSEUSER };
struct userinfo_state {
- enum userinfo_stage stage;
struct dcerpc_pipe *pipe;
- struct rpc_request *req;
+ struct policy_handle domain_handle;
struct policy_handle user_handle;
uint16_t level;
+ struct samr_LookupNames lookup;
struct samr_OpenUser openuser;
struct samr_QueryUserInfo queryuserinfo;
struct samr_Close samrclose;
};
+static void continue_userinfo_lookup(struct tevent_req *subreq);
+static void continue_userinfo_openuser(struct tevent_req *subreq);
+static void continue_userinfo_getuser(struct tevent_req *subreq);
+static void continue_userinfo_closeuser(struct tevent_req *subreq);
+
+
/**
- * Stage 1: Open user policy handle in SAM server.
+ * Stage 1 (optional): Look for a username in SAM server.
*/
-static NTSTATUS userinfo_openuser(struct composite_context *c,
- struct userinfo_state *s)
+static void continue_userinfo_lookup(struct tevent_req *subreq)
{
- /* receive samr_OpenUser reply */
- c->status = dcerpc_ndr_request_recv(s->req);
- NT_STATUS_NOT_OK_RETURN(c->status);
+ struct composite_context *c;
+ struct userinfo_state *s;
+ struct monitor_msg msg;
+ struct msg_rpc_lookup_name *msg_lookup;
- /* prepare parameters for QueryUserInfo call */
- s->queryuserinfo.in.user_handle = &s->user_handle;
- s->queryuserinfo.in.level = s->level;
-
- /* queue rpc call, set event handling and new state */
- s->req = dcerpc_samr_QueryUserInfo_send(s->pipe, c, &s->queryuserinfo);
- if (s->req == NULL) goto failure;
+ c = tevent_req_callback_data(subreq, struct composite_context);
+ s = talloc_get_type_abort(c->private_data, struct userinfo_state);
+
+ /* receive samr_Lookup reply */
+ c->status = dcerpc_samr_LookupNames_r_recv(subreq, s);
+ TALLOC_FREE(subreq);
+ if (!composite_is_ok(c)) return;
- s->req->async.callback = userinfo_handler;
- s->req->async.private = c;
- s->stage = USERINFO_GETUSER;
+ /* there could be a problem with name resolving itself */
+ if (!NT_STATUS_IS_OK(s->lookup.out.result)) {
+ composite_error(c, s->lookup.out.result);
+ return;
+ }
+
+ /* issue a monitor message */
+ if (s->monitor_fn) {
+ msg.type = mon_SamrLookupName;
+ msg_lookup = talloc(s, struct msg_rpc_lookup_name);
+ msg_lookup->rid = s->lookup.out.rids->ids;
+ msg_lookup->count = s->lookup.out.rids->count;
+ msg.data = (void*)msg_lookup;
+ msg.data_size = sizeof(*msg_lookup);
+
+ s->monitor_fn(&msg);
+ }
- return NT_STATUS_OK;
-failure:
- return NT_STATUS_UNSUCCESSFUL;
+ /* have we actually got name resolved
+ - we're looking for only one at the moment */
+ if (s->lookup.out.rids->count == 0) {
+ composite_error(c, NT_STATUS_NO_SUCH_USER);
+ }
+
+ /* TODO: find proper status code for more than one rid found */
+
+ /* prepare parameters for LookupNames */
+ s->openuser.in.domain_handle = &s->domain_handle;
+ s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ s->openuser.in.rid = s->lookup.out.rids->ids[0];
+ s->openuser.out.user_handle = &s->user_handle;
+
+ /* send request */
+ subreq = dcerpc_samr_OpenUser_r_send(s, c->event_ctx,
+ s->pipe->binding_handle,
+ &s->openuser);
+ if (composite_nomem(subreq, c)) return;
+
+ tevent_req_set_callback(subreq, continue_userinfo_openuser, c);
}
/**
- * Stage 2: Get requested user information.
+ * Stage 2: Open user policy handle.
*/
-static NTSTATUS userinfo_getuser(struct composite_context *c,
- struct userinfo_state *s)
+static void continue_userinfo_openuser(struct tevent_req *subreq)
{
- /* receive samr_QueryUserInfo reply */
- c->status = dcerpc_ndr_request_recv(s->req);
- NT_STATUS_NOT_OK_RETURN(c->status);
+ struct composite_context *c;
+ struct userinfo_state *s;
+ struct monitor_msg msg;
+ struct msg_rpc_open_user *msg_open;
+
+ c = tevent_req_callback_data(subreq, struct composite_context);
+ s = talloc_get_type_abort(c->private_data, struct userinfo_state);
+
+ /* receive samr_OpenUser reply */
+ c->status = dcerpc_samr_OpenUser_r_recv(subreq, s);
+ TALLOC_FREE(subreq);
+ if (!composite_is_ok(c)) return;
- s->info = talloc_steal(s, s->queryuserinfo.out.info);
+ if (!NT_STATUS_IS_OK(s->openuser.out.result)) {
+ composite_error(c, s->openuser.out.result);
+ return;
+ }
+
+ /* issue a monitor message */
+ if (s->monitor_fn) {
+ msg.type = mon_SamrOpenUser;
+ msg_open = talloc(s, struct msg_rpc_open_user);
+ msg_open->rid = s->openuser.in.rid;
+ msg_open->access_mask = s->openuser.in.access_mask;
+ msg.data = (void*)msg_open;
+ msg.data_size = sizeof(*msg_open);
+
+ s->monitor_fn(&msg);
+ }
- /* prepare arguments for Close call */
- s->samrclose.in.handle = &s->user_handle;
- s->samrclose.out.handle = &s->user_handle;
+ /* prepare parameters for QueryUserInfo call */
+ s->queryuserinfo.in.user_handle = &s->user_handle;
+ s->queryuserinfo.in.level = s->level;
+ s->queryuserinfo.out.info = talloc(s, union samr_UserInfo *);
+ if (composite_nomem(s->queryuserinfo.out.info, c)) return;
/* queue rpc call, set event handling and new state */
- s->req = dcerpc_samr_Close_send(s->pipe, c, &s->samrclose);
+ subreq = dcerpc_samr_QueryUserInfo_r_send(s, c->event_ctx,
+ s->pipe->binding_handle,
+ &s->queryuserinfo);
+ if (composite_nomem(subreq, c)) return;
- s->req->async.callback = userinfo_handler;
- s->req->async.private = c;
- s->stage = USERINFO_CLOSEUSER;
-
- return NT_STATUS_OK;
+ tevent_req_set_callback(subreq, continue_userinfo_getuser, c);
}
/**
- * Stage 3: Close policy handle associated with opened user.
+ * Stage 3: Get requested user information.
*/
-static NTSTATUS userinfo_closeuser(struct composite_context *c,
- struct userinfo_state *s)
+static void continue_userinfo_getuser(struct tevent_req *subreq)
{
- /* receive samr_Close reply */
- c->status = dcerpc_ndr_request_recv(s->req);
- NT_STATUS_NOT_OK_RETURN(c->status);
+ struct composite_context *c;
+ struct userinfo_state *s;
+ struct monitor_msg msg;
+ struct msg_rpc_query_user *msg_query;
- c->state = COMPOSITE_STATE_DONE;
+ c = tevent_req_callback_data(subreq, struct composite_context);
+ s = talloc_get_type_abort(c->private_data, struct userinfo_state);
- return NT_STATUS_OK;
+ /* receive samr_QueryUserInfo reply */
+ c->status = dcerpc_samr_QueryUserInfo_r_recv(subreq, s);
+ TALLOC_FREE(subreq);
+ if (!composite_is_ok(c)) return;
+
+ /* check if queryuser itself went ok */
+ if (!NT_STATUS_IS_OK(s->queryuserinfo.out.result)) {
+ composite_error(c, s->queryuserinfo.out.result);
+ return;
+ }
+
+ s->info = talloc_steal(s, *(s->queryuserinfo.out.info));
+
+ /* issue a monitor message */
+ if (s->monitor_fn) {
+ msg.type = mon_SamrQueryUser;
+ msg_query = talloc(s, struct msg_rpc_query_user);
+ msg_query->level = s->queryuserinfo.in.level;
+ msg.data = (void*)msg_query;
+ msg.data_size = sizeof(*msg_query);
+
+ s->monitor_fn(&msg);
+ }
+
+ /* prepare arguments for Close call */
+ s->samrclose.in.handle = &s->user_handle;
+ s->samrclose.out.handle = &s->user_handle;
+
+ /* queue rpc call, set event handling and new state */
+ subreq = dcerpc_samr_Close_r_send(s, c->event_ctx,
+ s->pipe->binding_handle,
+ &s->samrclose);
+ if (composite_nomem(subreq, c)) return;
+
+ tevent_req_set_callback(subreq, continue_userinfo_closeuser, c);
}
/**
- * Event handler for asynchronous request. Handles transition through
- * intermediate stages of the call.
- *
- * @param req rpc call context
+ * Stage 4: Close policy handle associated with opened user.
*/
-static void userinfo_handler(struct rpc_request *req)
+static void continue_userinfo_closeuser(struct tevent_req *subreq)
{
- struct composite_context *c = req->async.private;
- struct userinfo_state *s = talloc_get_type(c->private_data, struct userinfo_state);
+ struct composite_context *c;
+ struct userinfo_state *s;
struct monitor_msg msg;
- struct msg_rpc_open_user *msg_open;
- struct msg_rpc_query_user *msg_query;
struct msg_rpc_close_user *msg_close;
-
- /* Stages of the call */
- switch (s->stage) {
- case USERINFO_OPENUSER:
- c->status = userinfo_openuser(c, s);
- msg.type = rpc_open_user;
- msg_open = talloc(s, struct msg_rpc_open_user);
- msg_open->rid = s->openuser.in.rid;
- msg_open->access_mask = s->openuser.in.access_mask;
- msg.data = (void*)msg_open;
- msg.data_size = sizeof(*msg_open);
- break;
+ c = tevent_req_callback_data(subreq, struct composite_context);
+ s = talloc_get_type_abort(c->private_data, struct userinfo_state);
- case USERINFO_GETUSER:
- c->status = userinfo_getuser(c, s);
+ /* receive samr_Close reply */
+ c->status = dcerpc_samr_Close_r_recv(subreq, s);
+ TALLOC_FREE(subreq);
+ if (!composite_is_ok(c)) return;
- msg.type = rpc_query_user;
- msg_query = talloc(s, struct msg_rpc_query_user);
- msg_query->level = s->queryuserinfo.in.level;
- msg.data = (void*)msg_query;
- msg.data_size = sizeof(*msg_query);
- break;
-
- case USERINFO_CLOSEUSER:
- c->status = userinfo_closeuser(c, s);
+ if (!NT_STATUS_IS_OK(s->samrclose.out.result)) {
+ composite_error(c, s->samrclose.out.result);
+ return;
+ }
- msg.type = rpc_close_user;
+ /* issue a monitor message */
+ if (s->monitor_fn) {
+ msg.type = mon_SamrClose;
msg_close = talloc(s, struct msg_rpc_close_user);
msg_close->rid = s->openuser.in.rid;
msg.data = (void*)msg_close;
msg.data_size = sizeof(*msg_close);
- break;
- }
- if (!NT_STATUS_IS_OK(c->status)) {
- c->state = COMPOSITE_STATE_ERROR;
- }
-
- if (s->monitor_fn) {
s->monitor_fn(&msg);
}
- if (c->state >= COMPOSITE_STATE_DONE &&
- c->async.fn) {
- c->async.fn(c);
- }
+ composite_done(c);
}
struct composite_context *c;
struct userinfo_state *s;
struct dom_sid *sid;
+ struct tevent_req *subreq;
if (!p || !io) return NULL;
- c = talloc_zero(p, struct composite_context);
- if (c == NULL) goto failure;
+ c = composite_create(p, dcerpc_event_context(p));
+ if (c == NULL) return c;
s = talloc_zero(c, struct userinfo_state);
- if (s == NULL) goto failure;
+ if (composite_nomem(s, c)) return c;
- s->level = io->in.level;
- s->pipe = p;
- s->monitor_fn = monitor;
-
- sid = dom_sid_parse_talloc(s, io->in.sid);
- if (sid == NULL) goto failure;
- c->state = COMPOSITE_STATE_IN_PROGRESS;
c->private_data = s;
- c->event_ctx = dcerpc_event_context(p);
- /* preparing parameters to send rpc request */
- s->openuser.in.domain_handle = &io->in.domain_handle;
- s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
- s->openuser.in.rid = sid->sub_auths[sid->num_auths - 1];
- s->openuser.out.user_handle = &s->user_handle;
+ s->level = io->in.level;
+ s->pipe = p;
+ s->domain_handle = io->in.domain_handle;
+ s->monitor_fn = monitor;
- /* send request */
- s->req = dcerpc_samr_OpenUser_send(p, c, &s->openuser);
+ if (io->in.sid) {
+ sid = dom_sid_parse_talloc(s, io->in.sid);
+ if (composite_nomem(sid, c)) return c;
- /* callback handler */
- s->req->async.callback = userinfo_handler;
- s->req->async.private = c;
- s->stage = USERINFO_OPENUSER;
+ s->openuser.in.domain_handle = &s->domain_handle;
+ s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ s->openuser.in.rid = sid->sub_auths[sid->num_auths - 1];
+ s->openuser.out.user_handle = &s->user_handle;
+
+ /* send request */
+ subreq = dcerpc_samr_OpenUser_r_send(s, c->event_ctx,
+ p->binding_handle,
+ &s->openuser);
+ if (composite_nomem(subreq, c)) return c;
+
+ tevent_req_set_callback(subreq, continue_userinfo_openuser, c);
+
+ } else {
+ /* preparing parameters to send rpc request */
+ s->lookup.in.domain_handle = &s->domain_handle;
+ s->lookup.in.num_names = 1;
+ s->lookup.in.names = talloc_array(s, struct lsa_String, 1);
+ if (composite_nomem(s->lookup.in.names, c)) return c;
+ s->lookup.out.rids = talloc_zero(s, struct samr_Ids);
+ s->lookup.out.types = talloc_zero(s, struct samr_Ids);
+ if (composite_nomem(s->lookup.out.rids, c)) return c;
+ if (composite_nomem(s->lookup.out.types, c)) return c;
+
+ s->lookup.in.names[0].string = talloc_strdup(s, io->in.username);
+ if (composite_nomem(s->lookup.in.names[0].string, c)) return c;
+
+ /* send request */
+ subreq = dcerpc_samr_LookupNames_r_send(s, c->event_ctx,
+ p->binding_handle,
+ &s->lookup);
+ if (composite_nomem(subreq, c)) return c;
+
+ tevent_req_set_callback(subreq, continue_userinfo_lookup, c);
+ }
return c;
-
-failure:
- talloc_free(c);
- return NULL;
}
status = composite_wait(c);
if (NT_STATUS_IS_OK(status) && io) {
- s = talloc_get_type(c->private_data, struct userinfo_state);
+ s = talloc_get_type_abort(c->private_data, struct userinfo_state);
talloc_steal(mem_ctx, s->info);
io->out.info = *s->info;
}