Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Copyright (C) Rafal Szczesniak 2005
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : /*
21 : a composite function for getting user information via samr pipe
22 : */
23 :
24 : #include "includes.h"
25 : #include "libcli/composite/composite.h"
26 : #include "librpc/gen_ndr/security.h"
27 : #include "libcli/security/security.h"
28 : #include "libnet/libnet.h"
29 : #include "librpc/gen_ndr/ndr_samr_c.h"
30 :
31 :
32 : struct userinfo_state {
33 : struct dcerpc_binding_handle *binding_handle;
34 : struct policy_handle domain_handle;
35 : struct policy_handle user_handle;
36 : uint16_t level;
37 : struct samr_LookupNames lookup;
38 : struct samr_OpenUser openuser;
39 : struct samr_QueryUserInfo queryuserinfo;
40 : struct samr_Close samrclose;
41 : union samr_UserInfo *info;
42 :
43 : /* information about the progress */
44 : void (*monitor_fn)(struct monitor_msg *);
45 : };
46 :
47 :
48 : static void continue_userinfo_lookup(struct tevent_req *subreq);
49 : static void continue_userinfo_openuser(struct tevent_req *subreq);
50 : static void continue_userinfo_getuser(struct tevent_req *subreq);
51 : static void continue_userinfo_closeuser(struct tevent_req *subreq);
52 :
53 :
54 : /**
55 : * Stage 1 (optional): Look for a username in SAM server.
56 : */
57 22 : static void continue_userinfo_lookup(struct tevent_req *subreq)
58 : {
59 22 : struct composite_context *c;
60 22 : struct userinfo_state *s;
61 22 : struct monitor_msg msg;
62 22 : struct msg_rpc_lookup_name *msg_lookup;
63 :
64 22 : c = tevent_req_callback_data(subreq, struct composite_context);
65 22 : s = talloc_get_type_abort(c->private_data, struct userinfo_state);
66 :
67 : /* receive samr_Lookup reply */
68 22 : c->status = dcerpc_samr_LookupNames_r_recv(subreq, s);
69 22 : TALLOC_FREE(subreq);
70 22 : if (!composite_is_ok(c)) return;
71 :
72 : /* there could be a problem with name resolving itself */
73 22 : if (!NT_STATUS_IS_OK(s->lookup.out.result)) {
74 0 : composite_error(c, s->lookup.out.result);
75 0 : return;
76 : }
77 :
78 : /* issue a monitor message */
79 22 : if (s->monitor_fn) {
80 1 : msg.type = mon_SamrLookupName;
81 1 : msg_lookup = talloc(s, struct msg_rpc_lookup_name);
82 1 : msg_lookup->rid = s->lookup.out.rids->ids;
83 1 : msg_lookup->count = s->lookup.out.rids->count;
84 1 : msg.data = (void*)msg_lookup;
85 1 : msg.data_size = sizeof(*msg_lookup);
86 :
87 1 : s->monitor_fn(&msg);
88 : }
89 :
90 :
91 : /* have we actually got name resolved
92 : - we're looking for only one at the moment */
93 22 : if (s->lookup.out.rids->count != s->lookup.in.num_names) {
94 0 : composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
95 0 : return;
96 : }
97 22 : if (s->lookup.out.types->count != s->lookup.in.num_names) {
98 0 : composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
99 0 : return;
100 : }
101 :
102 : /* TODO: find proper status code for more than one rid found */
103 :
104 : /* prepare parameters for LookupNames */
105 22 : s->openuser.in.domain_handle = &s->domain_handle;
106 22 : s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
107 22 : s->openuser.in.rid = s->lookup.out.rids->ids[0];
108 22 : s->openuser.out.user_handle = &s->user_handle;
109 :
110 : /* send request */
111 22 : subreq = dcerpc_samr_OpenUser_r_send(s, c->event_ctx,
112 : s->binding_handle,
113 : &s->openuser);
114 22 : if (composite_nomem(subreq, c)) return;
115 :
116 22 : tevent_req_set_callback(subreq, continue_userinfo_openuser, c);
117 : }
118 :
119 :
120 : /**
121 : * Stage 2: Open user policy handle.
122 : */
123 35 : static void continue_userinfo_openuser(struct tevent_req *subreq)
124 : {
125 35 : struct composite_context *c;
126 35 : struct userinfo_state *s;
127 35 : struct monitor_msg msg;
128 35 : struct msg_rpc_open_user *msg_open;
129 :
130 35 : c = tevent_req_callback_data(subreq, struct composite_context);
131 35 : s = talloc_get_type_abort(c->private_data, struct userinfo_state);
132 :
133 : /* receive samr_OpenUser reply */
134 35 : c->status = dcerpc_samr_OpenUser_r_recv(subreq, s);
135 35 : TALLOC_FREE(subreq);
136 35 : if (!composite_is_ok(c)) return;
137 :
138 35 : if (!NT_STATUS_IS_OK(s->openuser.out.result)) {
139 0 : composite_error(c, s->openuser.out.result);
140 0 : return;
141 : }
142 :
143 : /* issue a monitor message */
144 35 : if (s->monitor_fn) {
145 2 : msg.type = mon_SamrOpenUser;
146 2 : msg_open = talloc(s, struct msg_rpc_open_user);
147 2 : msg_open->rid = s->openuser.in.rid;
148 2 : msg_open->access_mask = s->openuser.in.access_mask;
149 2 : msg.data = (void*)msg_open;
150 2 : msg.data_size = sizeof(*msg_open);
151 :
152 2 : s->monitor_fn(&msg);
153 : }
154 :
155 : /* prepare parameters for QueryUserInfo call */
156 35 : s->queryuserinfo.in.user_handle = &s->user_handle;
157 35 : s->queryuserinfo.in.level = s->level;
158 35 : s->queryuserinfo.out.info = talloc(s, union samr_UserInfo *);
159 35 : if (composite_nomem(s->queryuserinfo.out.info, c)) return;
160 :
161 : /* queue rpc call, set event handling and new state */
162 35 : subreq = dcerpc_samr_QueryUserInfo_r_send(s, c->event_ctx,
163 : s->binding_handle,
164 : &s->queryuserinfo);
165 35 : if (composite_nomem(subreq, c)) return;
166 :
167 35 : tevent_req_set_callback(subreq, continue_userinfo_getuser, c);
168 : }
169 :
170 :
171 : /**
172 : * Stage 3: Get requested user information.
173 : */
174 35 : static void continue_userinfo_getuser(struct tevent_req *subreq)
175 : {
176 35 : struct composite_context *c;
177 35 : struct userinfo_state *s;
178 35 : struct monitor_msg msg;
179 35 : struct msg_rpc_query_user *msg_query;
180 :
181 35 : c = tevent_req_callback_data(subreq, struct composite_context);
182 35 : s = talloc_get_type_abort(c->private_data, struct userinfo_state);
183 :
184 : /* receive samr_QueryUserInfo reply */
185 35 : c->status = dcerpc_samr_QueryUserInfo_r_recv(subreq, s);
186 35 : TALLOC_FREE(subreq);
187 35 : if (!composite_is_ok(c)) return;
188 :
189 : /* check if queryuser itself went ok */
190 35 : if (!NT_STATUS_IS_OK(s->queryuserinfo.out.result)) {
191 0 : composite_error(c, s->queryuserinfo.out.result);
192 0 : return;
193 : }
194 :
195 35 : s->info = talloc_steal(s, *(s->queryuserinfo.out.info));
196 :
197 : /* issue a monitor message */
198 35 : if (s->monitor_fn) {
199 2 : msg.type = mon_SamrQueryUser;
200 2 : msg_query = talloc(s, struct msg_rpc_query_user);
201 2 : msg_query->level = s->queryuserinfo.in.level;
202 2 : msg.data = (void*)msg_query;
203 2 : msg.data_size = sizeof(*msg_query);
204 :
205 2 : s->monitor_fn(&msg);
206 : }
207 :
208 : /* prepare arguments for Close call */
209 35 : s->samrclose.in.handle = &s->user_handle;
210 35 : s->samrclose.out.handle = &s->user_handle;
211 :
212 : /* queue rpc call, set event handling and new state */
213 35 : subreq = dcerpc_samr_Close_r_send(s, c->event_ctx,
214 : s->binding_handle,
215 : &s->samrclose);
216 35 : if (composite_nomem(subreq, c)) return;
217 :
218 35 : tevent_req_set_callback(subreq, continue_userinfo_closeuser, c);
219 : }
220 :
221 :
222 : /**
223 : * Stage 4: Close policy handle associated with opened user.
224 : */
225 35 : static void continue_userinfo_closeuser(struct tevent_req *subreq)
226 : {
227 35 : struct composite_context *c;
228 35 : struct userinfo_state *s;
229 35 : struct monitor_msg msg;
230 35 : struct msg_rpc_close_user *msg_close;
231 :
232 35 : c = tevent_req_callback_data(subreq, struct composite_context);
233 35 : s = talloc_get_type_abort(c->private_data, struct userinfo_state);
234 :
235 : /* receive samr_Close reply */
236 35 : c->status = dcerpc_samr_Close_r_recv(subreq, s);
237 35 : TALLOC_FREE(subreq);
238 35 : if (!composite_is_ok(c)) return;
239 :
240 35 : if (!NT_STATUS_IS_OK(s->samrclose.out.result)) {
241 0 : composite_error(c, s->samrclose.out.result);
242 0 : return;
243 : }
244 :
245 : /* issue a monitor message */
246 35 : if (s->monitor_fn) {
247 2 : msg.type = mon_SamrClose;
248 2 : msg_close = talloc(s, struct msg_rpc_close_user);
249 2 : msg_close->rid = s->openuser.in.rid;
250 2 : msg.data = (void*)msg_close;
251 2 : msg.data_size = sizeof(*msg_close);
252 :
253 2 : s->monitor_fn(&msg);
254 : }
255 :
256 35 : composite_done(c);
257 : }
258 :
259 :
260 : /**
261 : * Sends asynchronous userinfo request
262 : *
263 : * @param p dce/rpc call pipe
264 : * @param io arguments and results of the call
265 : */
266 35 : struct composite_context *libnet_rpc_userinfo_send(TALLOC_CTX *mem_ctx,
267 : struct tevent_context *ev,
268 : struct dcerpc_binding_handle *b,
269 : struct libnet_rpc_userinfo *io,
270 : void (*monitor)(struct monitor_msg*))
271 : {
272 35 : struct composite_context *c;
273 35 : struct userinfo_state *s;
274 35 : struct dom_sid *sid;
275 35 : struct tevent_req *subreq;
276 :
277 35 : if (!b || !io) return NULL;
278 :
279 35 : c = composite_create(mem_ctx, ev);
280 35 : if (c == NULL) return c;
281 :
282 35 : s = talloc_zero(c, struct userinfo_state);
283 35 : if (composite_nomem(s, c)) return c;
284 :
285 35 : c->private_data = s;
286 :
287 35 : s->level = io->in.level;
288 35 : s->binding_handle= b;
289 35 : s->domain_handle = io->in.domain_handle;
290 35 : s->monitor_fn = monitor;
291 :
292 35 : if (io->in.sid) {
293 13 : sid = dom_sid_parse_talloc(s, io->in.sid);
294 13 : if (composite_nomem(sid, c)) return c;
295 :
296 13 : s->openuser.in.domain_handle = &s->domain_handle;
297 13 : s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
298 13 : s->openuser.in.rid = sid->sub_auths[sid->num_auths - 1];
299 13 : s->openuser.out.user_handle = &s->user_handle;
300 :
301 : /* send request */
302 13 : subreq = dcerpc_samr_OpenUser_r_send(s, c->event_ctx,
303 : s->binding_handle,
304 : &s->openuser);
305 13 : if (composite_nomem(subreq, c)) return c;
306 :
307 13 : tevent_req_set_callback(subreq, continue_userinfo_openuser, c);
308 :
309 : } else {
310 : /* preparing parameters to send rpc request */
311 22 : s->lookup.in.domain_handle = &s->domain_handle;
312 22 : s->lookup.in.num_names = 1;
313 22 : s->lookup.in.names = talloc_array(s, struct lsa_String, 1);
314 22 : if (composite_nomem(s->lookup.in.names, c)) return c;
315 22 : s->lookup.out.rids = talloc_zero(s, struct samr_Ids);
316 22 : s->lookup.out.types = talloc_zero(s, struct samr_Ids);
317 22 : if (composite_nomem(s->lookup.out.rids, c)) return c;
318 22 : if (composite_nomem(s->lookup.out.types, c)) return c;
319 :
320 22 : s->lookup.in.names[0].string = talloc_strdup(s, io->in.username);
321 22 : if (composite_nomem(s->lookup.in.names[0].string, c)) return c;
322 :
323 : /* send request */
324 22 : subreq = dcerpc_samr_LookupNames_r_send(s, c->event_ctx,
325 : s->binding_handle,
326 : &s->lookup);
327 22 : if (composite_nomem(subreq, c)) return c;
328 :
329 22 : tevent_req_set_callback(subreq, continue_userinfo_lookup, c);
330 : }
331 :
332 0 : return c;
333 : }
334 :
335 :
336 : /**
337 : * Waits for and receives result of asynchronous userinfo call
338 : *
339 : * @param c composite context returned by asynchronous userinfo call
340 : * @param mem_ctx memory context of the call
341 : * @param io pointer to results (and arguments) of the call
342 : * @return nt status code of execution
343 : */
344 :
345 35 : NTSTATUS libnet_rpc_userinfo_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
346 : struct libnet_rpc_userinfo *io)
347 : {
348 35 : NTSTATUS status;
349 35 : struct userinfo_state *s;
350 :
351 : /* wait for results of sending request */
352 35 : status = composite_wait(c);
353 :
354 35 : if (NT_STATUS_IS_OK(status) && io) {
355 35 : s = talloc_get_type_abort(c->private_data, struct userinfo_state);
356 35 : talloc_steal(mem_ctx, s->info);
357 35 : io->out.info = *s->info;
358 : }
359 :
360 : /* memory context associated to composite context is no longer needed */
361 35 : talloc_free(c);
362 35 : return status;
363 : }
364 :
365 :
366 : /**
367 : * Synchronous version of userinfo call
368 : *
369 : * @param pipe dce/rpc call pipe
370 : * @param mem_ctx memory context for the call
371 : * @param io arguments and results of the call
372 : * @return nt status code of execution
373 : */
374 :
375 12 : NTSTATUS libnet_rpc_userinfo(struct tevent_context *ev,
376 : struct dcerpc_binding_handle *b,
377 : TALLOC_CTX *mem_ctx,
378 : struct libnet_rpc_userinfo *io)
379 : {
380 12 : struct composite_context *c = libnet_rpc_userinfo_send(mem_ctx, ev, b, io, NULL);
381 12 : return libnet_rpc_userinfo_recv(c, mem_ctx, io);
382 : }
|