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 "libcli/composite/composite.h"
#include "librpc/gen_ndr/security.h"
#include "libcli/security/security.h"
-#include "libnet/composite.h"
-#include "libnet/userinfo.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_LOOKUP, 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;
};
+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 (optional): Look for a username in SAM server.
*/
-static NTSTATUS userinfo_lookup(struct composite_context *c,
- struct userinfo_state *s)
+static void continue_userinfo_lookup(struct tevent_req *subreq)
{
+ struct composite_context *c;
+ struct userinfo_state *s;
+ struct monitor_msg msg;
+ struct msg_rpc_lookup_name *msg_lookup;
+
+ 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_ndr_request_recv(s->req);
- NT_STATUS_NOT_OK_RETURN(c->status);
+ c->status = dcerpc_samr_LookupNames_r_recv(subreq, s);
+ TALLOC_FREE(subreq);
+ if (!composite_is_ok(c)) return;
+
+ /* 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);
+ }
+
/* have we actually got name resolved
- we're looking for only one at the moment */
- if (s->lookup.out.rids.count == 0) {
- return NT_STATUS_NO_SUCH_USER;
+ 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.in.rid = s->lookup.out.rids->ids[0];
s->openuser.out.user_handle = &s->user_handle;
/* send request */
- s->req = dcerpc_samr_OpenUser_send(s->pipe, c, &s->openuser);
- if (s->req == NULL) goto failure;
+ subreq = dcerpc_samr_OpenUser_r_send(s, c->event_ctx,
+ s->pipe->binding_handle,
+ &s->openuser);
+ if (composite_nomem(subreq, c)) return;
- s->req->async.callback = userinfo_handler;
- s->req->async.private = c;
- s->stage = USERINFO_OPENUSER;
-
- return NT_STATUS_OK;
-
-failure:
- return NT_STATUS_UNSUCCESSFUL;
+ tevent_req_set_callback(subreq, continue_userinfo_openuser, c);
}
/**
* Stage 2: Open user policy handle.
*/
-static NTSTATUS userinfo_openuser(struct composite_context *c,
- struct userinfo_state *s)
+static void continue_userinfo_openuser(struct tevent_req *subreq)
{
+ 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_ndr_request_recv(s->req);
- NT_STATUS_NOT_OK_RETURN(c->status);
+ c->status = dcerpc_samr_OpenUser_r_recv(subreq, s);
+ TALLOC_FREE(subreq);
+ if (!composite_is_ok(c)) return;
+
+ 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 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_QueryUserInfo_send(s->pipe, c, &s->queryuserinfo);
- if (s->req == NULL) goto failure;
-
- s->req->async.callback = userinfo_handler;
- s->req->async.private = c;
- s->stage = USERINFO_GETUSER;
+ subreq = dcerpc_samr_QueryUserInfo_r_send(s, c->event_ctx,
+ s->pipe->binding_handle,
+ &s->queryuserinfo);
+ if (composite_nomem(subreq, c)) return;
- return NT_STATUS_OK;
-
-failure:
- return NT_STATUS_UNSUCCESSFUL;
+ tevent_req_set_callback(subreq, continue_userinfo_getuser, c);
}
/**
* Stage 3: Get requested user information.
*/
-static NTSTATUS userinfo_getuser(struct composite_context *c,
- struct userinfo_state *s)
+static void continue_userinfo_getuser(struct tevent_req *subreq)
{
+ struct composite_context *c;
+ struct userinfo_state *s;
+ struct monitor_msg msg;
+ struct msg_rpc_query_user *msg_query;
+
+ c = tevent_req_callback_data(subreq, struct composite_context);
+ s = talloc_get_type_abort(c->private_data, struct userinfo_state);
+
/* receive samr_QueryUserInfo reply */
- c->status = dcerpc_ndr_request_recv(s->req);
- NT_STATUS_NOT_OK_RETURN(c->status);
+ 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));
- 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 */
- s->req = dcerpc_samr_Close_send(s->pipe, c, &s->samrclose);
+ subreq = dcerpc_samr_Close_r_send(s, c->event_ctx,
+ s->pipe->binding_handle,
+ &s->samrclose);
+ 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_closeuser, c);
}
/**
* Stage 4: Close policy handle associated with opened user.
*/
-static NTSTATUS userinfo_closeuser(struct composite_context *c,
- struct userinfo_state *s)
+static void continue_userinfo_closeuser(struct tevent_req *subreq)
{
- /* receive samr_Close reply */
- c->status = dcerpc_ndr_request_recv(s->req);
- NT_STATUS_NOT_OK_RETURN(c->status);
-
- c->state = COMPOSITE_STATE_DONE;
-
- return NT_STATUS_OK;
-}
-
-
-/**
- * Event handler for asynchronous request. Handles transition through
- * intermediate stages of the call.
- *
- * @param req rpc call context
- */
-static void userinfo_handler(struct rpc_request *req)
-{
- 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_LOOKUP:
- c->status = userinfo_lookup(c, s);
- break;
-
- 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;
+
+ c->private_data = s;
s->level = io->in.level;
s->pipe = p;
s->domain_handle = io->in.domain_handle;
s->monitor_fn = monitor;
- c->state = COMPOSITE_STATE_IN_PROGRESS;
- c->private_data = s;
- c->event_ctx = dcerpc_event_context(p);
-
if (io->in.sid) {
sid = dom_sid_parse_talloc(s, io->in.sid);
- if (sid == NULL) goto failure;
+ if (composite_nomem(sid, c)) return c;
s->openuser.in.domain_handle = &s->domain_handle;
s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
s->openuser.out.user_handle = &s->user_handle;
/* send request */
- s->req = dcerpc_samr_OpenUser_send(p, c, &s->openuser);
- if (s->req == NULL) goto failure;
-
- s->stage = USERINFO_OPENUSER;
+ 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 */
- s->req = dcerpc_samr_LookupNames_send(p, c, &s->lookup);
- if (s->req == NULL) goto failure;
+ subreq = dcerpc_samr_LookupNames_r_send(s, c->event_ctx,
+ p->binding_handle,
+ &s->lookup);
+ if (composite_nomem(subreq, c)) return c;
- s->stage = USERINFO_LOOKUP;
+ tevent_req_set_callback(subreq, continue_userinfo_lookup, c);
}
- /* callback handler */
- s->req->async.callback = userinfo_handler;
- s->req->async.private = 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;
}