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 domain handling on samr and lsa pipes
22 */
23
24 #include "includes.h"
25 #include "libcli/composite/composite.h"
26 #include "libnet/libnet.h"
27 #include "librpc/gen_ndr/ndr_samr_c.h"
28 #include "librpc/gen_ndr/ndr_lsa_c.h"
29
30
31 struct domain_open_samr_state {
32 struct libnet_context *ctx;
33 struct dcerpc_pipe *pipe;
34 struct libnet_RpcConnect rpcconn;
35 struct samr_Connect connect;
36 struct samr_LookupDomain lookup;
37 struct samr_OpenDomain open;
38 struct samr_Close close;
39 struct lsa_String domain_name;
40 uint32_t access_mask;
41 struct policy_handle connect_handle;
42 struct policy_handle domain_handle;
43 struct dom_sid2 *domain_sid;
44
45 /* information about the progress */
46 void (*monitor_fn)(struct monitor_msg*);
47 };
48
49
50 static void continue_domain_open_close(struct tevent_req *subreq);
51 static void continue_domain_open_connect(struct tevent_req *subreq);
52 static void continue_domain_open_lookup(struct tevent_req *subreq);
53 static void continue_domain_open_open(struct tevent_req *subreq);
54
55
56 /**
57 * Stage 0.5 (optional): Connect to samr rpc pipe
58 */
continue_domain_open_rpc_connect(struct composite_context * ctx)59 static void continue_domain_open_rpc_connect(struct composite_context *ctx)
60 {
61 struct composite_context *c;
62 struct domain_open_samr_state *s;
63 struct tevent_req *subreq;
64
65 c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
66 s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
67
68 c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
69 if (!composite_is_ok(c)) return;
70
71 s->pipe = s->rpcconn.out.dcerpc_pipe;
72
73 /* preparing parameters for samr_Connect rpc call */
74 s->connect.in.system_name = 0;
75 s->connect.in.access_mask = s->access_mask;
76 s->connect.out.connect_handle = &s->connect_handle;
77
78 /* send request */
79 subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
80 s->pipe->binding_handle,
81 &s->connect);
82 if (composite_nomem(subreq, c)) return;
83
84 /* callback handler */
85 tevent_req_set_callback(subreq, continue_domain_open_connect, c);
86 }
87
88
89 /**
90 * Stage 0.5 (optional): Close existing (in libnet context) domain
91 * handle
92 */
continue_domain_open_close(struct tevent_req * subreq)93 static void continue_domain_open_close(struct tevent_req *subreq)
94 {
95 struct composite_context *c;
96 struct domain_open_samr_state *s;
97
98 c = tevent_req_callback_data(subreq, struct composite_context);
99 s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
100
101 /* receive samr_Close reply */
102 c->status = dcerpc_samr_Close_r_recv(subreq, s);
103 TALLOC_FREE(subreq);
104 if (!composite_is_ok(c)) return;
105
106 if (s->monitor_fn) {
107 struct monitor_msg msg;
108
109 msg.type = mon_SamrClose;
110 msg.data = NULL;
111 msg.data_size = 0;
112 s->monitor_fn(&msg);
113 }
114
115 /* reset domain handle and associated data in libnet_context */
116 s->ctx->samr.name = NULL;
117 s->ctx->samr.access_mask = 0;
118 ZERO_STRUCT(s->ctx->samr.handle);
119
120 /* preparing parameters for samr_Connect rpc call */
121 s->connect.in.system_name = 0;
122 s->connect.in.access_mask = s->access_mask;
123 s->connect.out.connect_handle = &s->connect_handle;
124
125 /* send request */
126 subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
127 s->pipe->binding_handle,
128 &s->connect);
129 if (composite_nomem(subreq, c)) return;
130
131 /* callback handler */
132 tevent_req_set_callback(subreq, continue_domain_open_connect, c);
133 }
134
135
136 /**
137 * Stage 1: Connect to SAM server.
138 */
continue_domain_open_connect(struct tevent_req * subreq)139 static void continue_domain_open_connect(struct tevent_req *subreq)
140 {
141 struct composite_context *c;
142 struct domain_open_samr_state *s;
143 struct samr_LookupDomain *r;
144
145 c = tevent_req_callback_data(subreq, struct composite_context);
146 s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
147
148 /* receive samr_Connect reply */
149 c->status = dcerpc_samr_Connect_r_recv(subreq, s);
150 TALLOC_FREE(subreq);
151 if (!composite_is_ok(c)) return;
152
153 if (s->monitor_fn) {
154 struct monitor_msg msg;
155
156 msg.type = mon_SamrConnect;
157 msg.data = NULL;
158 msg.data_size = 0;
159 s->monitor_fn(&msg);
160 }
161
162 r = &s->lookup;
163
164 /* prepare for samr_LookupDomain call */
165 r->in.connect_handle = &s->connect_handle;
166 r->in.domain_name = &s->domain_name;
167 r->out.sid = talloc(s, struct dom_sid2 *);
168 if (composite_nomem(r->out.sid, c)) return;
169
170 subreq = dcerpc_samr_LookupDomain_r_send(s, c->event_ctx,
171 s->pipe->binding_handle,
172 r);
173 if (composite_nomem(subreq, c)) return;
174
175 tevent_req_set_callback(subreq, continue_domain_open_lookup, c);
176 }
177
178
179 /**
180 * Stage 2: Lookup domain by name.
181 */
continue_domain_open_lookup(struct tevent_req * subreq)182 static void continue_domain_open_lookup(struct tevent_req *subreq)
183 {
184 struct composite_context *c;
185 struct domain_open_samr_state *s;
186 struct samr_OpenDomain *r;
187
188 c = tevent_req_callback_data(subreq, struct composite_context);
189 s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
190
191 /* receive samr_LookupDomain reply */
192 c->status = dcerpc_samr_LookupDomain_r_recv(subreq, s);
193 TALLOC_FREE(subreq);
194
195 if (s->monitor_fn) {
196 struct monitor_msg msg;
197 struct msg_rpc_lookup_domain data;
198
199 data.domain_name = s->domain_name.string;
200
201 msg.type = mon_SamrLookupDomain;
202 msg.data = (void*)&data;
203 msg.data_size = sizeof(data);
204 s->monitor_fn(&msg);
205 }
206
207 r = &s->open;
208
209 /* check the rpc layer status */
210 if (!composite_is_ok(c)) return;
211
212 /* check the rpc call itself status */
213 if (!NT_STATUS_IS_OK(s->lookup.out.result)) {
214 composite_error(c, s->lookup.out.result);
215 return;
216 }
217
218 /* prepare for samr_OpenDomain call */
219 r->in.connect_handle = &s->connect_handle;
220 r->in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
221 r->in.sid = *s->lookup.out.sid;
222 r->out.domain_handle = &s->domain_handle;
223
224 subreq = dcerpc_samr_OpenDomain_r_send(s, c->event_ctx,
225 s->pipe->binding_handle,
226 r);
227 if (composite_nomem(subreq, c)) return;
228
229 tevent_req_set_callback(subreq, continue_domain_open_open, c);
230 }
231
232
233 /*
234 * Stage 3: Open domain.
235 */
continue_domain_open_open(struct tevent_req * subreq)236 static void continue_domain_open_open(struct tevent_req *subreq)
237 {
238 struct composite_context *c;
239 struct domain_open_samr_state *s;
240
241 c = tevent_req_callback_data(subreq, struct composite_context);
242 s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
243
244 /* receive samr_OpenDomain reply */
245 c->status = dcerpc_samr_OpenDomain_r_recv(subreq, s);
246 TALLOC_FREE(subreq);
247 if (!composite_is_ok(c)) return;
248
249 if (s->monitor_fn) {
250 struct monitor_msg msg;
251
252 msg.type = mon_SamrOpenDomain;
253 msg.data = NULL;
254 msg.data_size = 0;
255 s->monitor_fn(&msg);
256 }
257
258 composite_done(c);
259 }
260
261
262 /**
263 * Sends asynchronous DomainOpenSamr request
264 *
265 * @param ctx initialised libnet context
266 * @param io arguments and results of the call
267 * @param monitor pointer to monitor function that is passed monitor message
268 */
269
libnet_DomainOpenSamr_send(struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_DomainOpen * io,void (* monitor)(struct monitor_msg *))270 struct composite_context *libnet_DomainOpenSamr_send(struct libnet_context *ctx,
271 TALLOC_CTX *mem_ctx,
272 struct libnet_DomainOpen *io,
273 void (*monitor)(struct monitor_msg*))
274 {
275 struct composite_context *c;
276 struct domain_open_samr_state *s;
277 struct composite_context *rpcconn_req;
278 struct tevent_req *subreq;
279
280 c = composite_create(mem_ctx, ctx->event_ctx);
281 if (c == NULL) return NULL;
282
283 s = talloc_zero(c, struct domain_open_samr_state);
284 if (composite_nomem(s, c)) return c;
285
286 c->private_data = s;
287 s->monitor_fn = monitor;
288
289 s->ctx = ctx;
290 s->pipe = ctx->samr.pipe;
291 s->access_mask = io->in.access_mask;
292 s->domain_name.string = talloc_strdup(c, io->in.domain_name);
293
294 /* check, if there's samr pipe opened already, before opening a domain */
295 if (ctx->samr.pipe == NULL) {
296
297 /* attempting to connect a domain controller */
298 s->rpcconn.level = LIBNET_RPC_CONNECT_DC;
299 s->rpcconn.in.name = io->in.domain_name;
300 s->rpcconn.in.dcerpc_iface = &ndr_table_samr;
301
302 /* send rpc pipe connect request */
303 rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn, s->monitor_fn);
304 if (composite_nomem(rpcconn_req, c)) return c;
305
306 composite_continue(c, rpcconn_req, continue_domain_open_rpc_connect, c);
307 return c;
308 }
309
310 /* libnet context's domain handle is not empty, so check out what
311 was opened first, before doing anything */
312 if (!ndr_policy_handle_empty(&ctx->samr.handle)) {
313 if (strequal(ctx->samr.name, io->in.domain_name) &&
314 ctx->samr.access_mask == io->in.access_mask) {
315
316 /* this domain is already opened */
317 composite_done(c);
318 return c;
319
320 } else {
321 /* another domain or access rights have been
322 requested - close the existing handle first */
323 s->close.in.handle = &ctx->samr.handle;
324
325 /* send request to close domain handle */
326 subreq = dcerpc_samr_Close_r_send(s, c->event_ctx,
327 s->pipe->binding_handle,
328 &s->close);
329 if (composite_nomem(subreq, c)) return c;
330
331 /* callback handler */
332 tevent_req_set_callback(subreq, continue_domain_open_close, c);
333 return c;
334 }
335 }
336
337 /* preparing parameters for samr_Connect rpc call */
338 s->connect.in.system_name = 0;
339 s->connect.in.access_mask = s->access_mask;
340 s->connect.out.connect_handle = &s->connect_handle;
341
342 /* send request */
343 subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
344 s->pipe->binding_handle,
345 &s->connect);
346 if (composite_nomem(subreq, c)) return c;
347
348 /* callback handler */
349 tevent_req_set_callback(subreq, continue_domain_open_connect, c);
350 return c;
351 }
352
353
354 /**
355 * Waits for and receives result of asynchronous DomainOpenSamr call
356 *
357 * @param c composite context returned by asynchronous DomainOpen call
358 * @param ctx initialised libnet context
359 * @param mem_ctx memory context of the call
360 * @param io pointer to results (and arguments) of the call
361 * @return nt status code of execution
362 */
363
libnet_DomainOpenSamr_recv(struct composite_context * c,struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_DomainOpen * io)364 NTSTATUS libnet_DomainOpenSamr_recv(struct composite_context *c, struct libnet_context *ctx,
365 TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
366 {
367 NTSTATUS status;
368 struct domain_open_samr_state *s;
369
370 /* wait for results of sending request */
371 status = composite_wait(c);
372
373 if (NT_STATUS_IS_OK(status) && io) {
374 s = talloc_get_type_abort(c->private_data, struct domain_open_samr_state);
375 io->out.domain_handle = s->domain_handle;
376
377 /* store the resulting handle and related data for use by other
378 libnet functions */
379 ctx->samr.connect_handle = s->connect_handle;
380 ctx->samr.handle = s->domain_handle;
381 ctx->samr.sid = talloc_steal(ctx, *s->lookup.out.sid);
382 ctx->samr.name = talloc_steal(ctx, s->domain_name.string);
383 ctx->samr.access_mask = s->access_mask;
384 }
385
386 talloc_free(c);
387 return status;
388 }
389
390
391 struct domain_open_lsa_state {
392 const char *name;
393 uint32_t access_mask;
394 struct libnet_context *ctx;
395 struct libnet_RpcConnect rpcconn;
396 struct lsa_OpenPolicy2 openpol;
397 struct policy_handle handle;
398 struct dcerpc_pipe *pipe;
399
400 /* information about the progress */
401 void (*monitor_fn)(struct monitor_msg*);
402 };
403
404
405 static void continue_rpc_connect_lsa(struct composite_context *ctx);
406 static void continue_lsa_policy_open(struct tevent_req *subreq);
407
408
409 /**
410 * Sends asynchronous DomainOpenLsa request
411 *
412 * @param ctx initialised libnet context
413 * @param io arguments and results of the call
414 * @param monitor pointer to monitor function that is passed monitor message
415 */
416
libnet_DomainOpenLsa_send(struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_DomainOpen * io,void (* monitor)(struct monitor_msg *))417 struct composite_context* libnet_DomainOpenLsa_send(struct libnet_context *ctx,
418 TALLOC_CTX *mem_ctx,
419 struct libnet_DomainOpen *io,
420 void (*monitor)(struct monitor_msg*))
421 {
422 struct composite_context *c;
423 struct domain_open_lsa_state *s;
424 struct composite_context *rpcconn_req;
425 struct tevent_req *subreq;
426 struct lsa_QosInfo *qos;
427
428 /* create composite context and state */
429 c = composite_create(mem_ctx, ctx->event_ctx);
430 if (c == NULL) return c;
431
432 s = talloc_zero(c, struct domain_open_lsa_state);
433 if (composite_nomem(s, c)) return c;
434
435 c->private_data = s;
436
437 /* store arguments in the state structure */
438 s->name = talloc_strdup(c, io->in.domain_name);
439 s->access_mask = io->in.access_mask;
440 s->ctx = ctx;
441
442 /* check, if there's lsa pipe opened already, before opening a handle */
443 if (ctx->lsa.pipe == NULL) {
444
445 ZERO_STRUCT(s->rpcconn);
446
447 /* attempting to connect a domain controller */
448 s->rpcconn.level = LIBNET_RPC_CONNECT_DC;
449 s->rpcconn.in.name = talloc_strdup(c, io->in.domain_name);
450 s->rpcconn.in.dcerpc_iface = &ndr_table_lsarpc;
451
452 /* send rpc pipe connect request */
453 rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn, s->monitor_fn);
454 if (composite_nomem(rpcconn_req, c)) return c;
455
456 composite_continue(c, rpcconn_req, continue_rpc_connect_lsa, c);
457 return c;
458 }
459
460 s->pipe = ctx->lsa.pipe;
461
462 /* preparing parameters for lsa_OpenPolicy2 rpc call */
463 s->openpol.in.system_name = s->name;
464 s->openpol.in.access_mask = s->access_mask;
465 s->openpol.in.attr = talloc_zero(c, struct lsa_ObjectAttribute);
466
467 qos = talloc_zero(c, struct lsa_QosInfo);
468 qos->len = 0;
469 qos->impersonation_level = 2;
470 qos->context_mode = 1;
471 qos->effective_only = 0;
472
473 s->openpol.in.attr->sec_qos = qos;
474 s->openpol.out.handle = &s->handle;
475
476 /* send rpc request */
477 subreq = dcerpc_lsa_OpenPolicy2_r_send(s, c->event_ctx,
478 s->pipe->binding_handle,
479 &s->openpol);
480 if (composite_nomem(subreq, c)) return c;
481
482 tevent_req_set_callback(subreq, continue_lsa_policy_open, c);
483 return c;
484 }
485
486
487 /*
488 Stage 0.5 (optional): Rpc pipe connected, send lsa open policy request
489 */
continue_rpc_connect_lsa(struct composite_context * ctx)490 static void continue_rpc_connect_lsa(struct composite_context *ctx)
491 {
492 struct composite_context *c;
493 struct domain_open_lsa_state *s;
494 struct lsa_QosInfo *qos;
495 struct tevent_req *subreq;
496
497 c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
498 s = talloc_get_type_abort(c->private_data, struct domain_open_lsa_state);
499
500 /* receive rpc connection */
501 c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
502 if (!composite_is_ok(c)) return;
503
504 /* RpcConnect function leaves the pipe in libnet context,
505 so get it from there */
506 s->pipe = s->ctx->lsa.pipe;
507
508 /* prepare lsa_OpenPolicy2 call */
509 s->openpol.in.system_name = s->name;
510 s->openpol.in.access_mask = s->access_mask;
511 s->openpol.in.attr = talloc_zero(c, struct lsa_ObjectAttribute);
512
513 qos = talloc_zero(c, struct lsa_QosInfo);
514 qos->len = 0;
515 qos->impersonation_level = 2;
516 qos->context_mode = 1;
517 qos->effective_only = 0;
518
519 s->openpol.in.attr->sec_qos = qos;
520 s->openpol.out.handle = &s->handle;
521
522 /* send rpc request */
523 subreq = dcerpc_lsa_OpenPolicy2_r_send(s, c->event_ctx,
524 s->pipe->binding_handle,
525 &s->openpol);
526 if (composite_nomem(subreq, c)) return;
527
528 tevent_req_set_callback(subreq, continue_lsa_policy_open, c);
529 }
530
531
532 /*
533 Stage 1: Lsa policy opened - we're done, if successfully
534 */
continue_lsa_policy_open(struct tevent_req * subreq)535 static void continue_lsa_policy_open(struct tevent_req *subreq)
536 {
537 struct composite_context *c;
538 struct domain_open_lsa_state *s;
539
540 c = tevent_req_callback_data(subreq, struct composite_context);
541 s = talloc_get_type_abort(c->private_data, struct domain_open_lsa_state);
542
543 c->status = dcerpc_lsa_OpenPolicy2_r_recv(subreq, s);
544 TALLOC_FREE(subreq);
545 if (!composite_is_ok(c)) return;
546
547 if (s->monitor_fn) {
548 struct monitor_msg msg;
549
550 msg.type = mon_LsaOpenPolicy;
551 msg.data = NULL;
552 msg.data_size = 0;
553 s->monitor_fn(&msg);
554 }
555
556 composite_done(c);
557 }
558
559
560 /**
561 * Receives result of asynchronous DomainOpenLsa call
562 *
563 * @param c composite context returned by asynchronous DomainOpenLsa call
564 * @param ctx initialised libnet context
565 * @param mem_ctx memory context of the call
566 * @param io pointer to results (and arguments) of the call
567 * @return nt status code of execution
568 */
569
libnet_DomainOpenLsa_recv(struct composite_context * c,struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_DomainOpen * io)570 NTSTATUS libnet_DomainOpenLsa_recv(struct composite_context *c, struct libnet_context *ctx,
571 TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
572 {
573 NTSTATUS status;
574 struct domain_open_lsa_state *s;
575
576 status = composite_wait(c);
577
578 if (NT_STATUS_IS_OK(status) && io) {
579 /* everything went fine - get the results and
580 return the error string */
581 s = talloc_get_type_abort(c->private_data, struct domain_open_lsa_state);
582 io->out.domain_handle = s->handle;
583
584 ctx->lsa.handle = s->handle;
585 ctx->lsa.name = talloc_steal(ctx, s->name);
586 ctx->lsa.access_mask = s->access_mask;
587
588 io->out.error_string = talloc_strdup(mem_ctx, "Success");
589
590 } else if (!NT_STATUS_IS_OK(status)) {
591 /* there was an error, so provide nt status code description */
592 io->out.error_string = talloc_asprintf(mem_ctx,
593 "Failed to open domain: %s",
594 nt_errstr(status));
595 }
596
597 talloc_free(c);
598 return status;
599 }
600
601
602 /**
603 * Sends a request to open a domain in desired service
604 *
605 * @param ctx initialised libnet context
606 * @param io arguments and results of the call
607 * @param monitor pointer to monitor function that is passed monitor message
608 */
609
libnet_DomainOpen_send(struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_DomainOpen * io,void (* monitor)(struct monitor_msg *))610 struct composite_context* libnet_DomainOpen_send(struct libnet_context *ctx,
611 TALLOC_CTX *mem_ctx,
612 struct libnet_DomainOpen *io,
613 void (*monitor)(struct monitor_msg*))
614 {
615 struct composite_context *c;
616
617 switch (io->in.type) {
618 case DOMAIN_LSA:
619 /* reques to open a policy handle on \pipe\lsarpc */
620 c = libnet_DomainOpenLsa_send(ctx, mem_ctx, io, monitor);
621 break;
622
623 case DOMAIN_SAMR:
624 default:
625 /* request to open a domain policy handle on \pipe\samr */
626 c = libnet_DomainOpenSamr_send(ctx, mem_ctx, io, monitor);
627 break;
628 }
629
630 return c;
631 }
632
633
634 /**
635 * Receive result of domain open request
636 *
637 * @param c composite context returned by DomainOpen_send function
638 * @param ctx initialised libnet context
639 * @param mem_ctx memory context of the call
640 * @param io results and arguments of the call
641 */
642
libnet_DomainOpen_recv(struct composite_context * c,struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_DomainOpen * io)643 NTSTATUS libnet_DomainOpen_recv(struct composite_context *c, struct libnet_context *ctx,
644 TALLOC_CTX *mem_ctx, struct libnet_DomainOpen *io)
645 {
646 NTSTATUS status;
647
648 switch (io->in.type) {
649 case DOMAIN_LSA:
650 status = libnet_DomainOpenLsa_recv(c, ctx, mem_ctx, io);
651 break;
652
653 case DOMAIN_SAMR:
654 default:
655 status = libnet_DomainOpenSamr_recv(c, ctx, mem_ctx, io);
656 break;
657 }
658
659 return status;
660 }
661
662
663 /**
664 * Synchronous version of DomainOpen call
665 *
666 * @param ctx initialised libnet context
667 * @param mem_ctx memory context for the call
668 * @param io arguments and results of the call
669 * @return nt status code of execution
670 */
671
libnet_DomainOpen(struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_DomainOpen * io)672 NTSTATUS libnet_DomainOpen(struct libnet_context *ctx,
673 TALLOC_CTX *mem_ctx,
674 struct libnet_DomainOpen *io)
675 {
676 struct composite_context *c = libnet_DomainOpen_send(ctx, mem_ctx, io, NULL);
677 return libnet_DomainOpen_recv(c, ctx, mem_ctx, io);
678 }
679
680
681 struct domain_close_lsa_state {
682 struct dcerpc_pipe *pipe;
683 struct lsa_Close close;
684 struct policy_handle handle;
685
686 void (*monitor_fn)(struct monitor_msg*);
687 };
688
689
690 static void continue_lsa_close(struct tevent_req *subreq);
691
692
libnet_DomainCloseLsa_send(struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_DomainClose * io,void (* monitor)(struct monitor_msg *))693 struct composite_context* libnet_DomainCloseLsa_send(struct libnet_context *ctx,
694 TALLOC_CTX *mem_ctx,
695 struct libnet_DomainClose *io,
696 void (*monitor)(struct monitor_msg*))
697 {
698 struct composite_context *c;
699 struct domain_close_lsa_state *s;
700 struct tevent_req *subreq;
701
702 /* composite context and state structure allocation */
703 c = composite_create(mem_ctx, ctx->event_ctx);
704 if (c == NULL) return c;
705
706 s = talloc_zero(c, struct domain_close_lsa_state);
707 if (composite_nomem(s, c)) return c;
708
709 c->private_data = s;
710 s->monitor_fn = monitor;
711
712 /* TODO: check if lsa pipe pointer is non-null */
713
714 if (!strequal(ctx->lsa.name, io->in.domain_name)) {
715 composite_error(c, NT_STATUS_INVALID_PARAMETER);
716 return c;
717 }
718
719 /* get opened lsarpc pipe pointer */
720 s->pipe = ctx->lsa.pipe;
721
722 /* prepare close handle call arguments */
723 s->close.in.handle = &ctx->lsa.handle;
724 s->close.out.handle = &s->handle;
725
726 /* send the request */
727 subreq = dcerpc_lsa_Close_r_send(s, c->event_ctx,
728 s->pipe->binding_handle,
729 &s->close);
730 if (composite_nomem(subreq, c)) return c;
731
732 tevent_req_set_callback(subreq, continue_lsa_close, c);
733 return c;
734 }
735
736
737 /*
738 Stage 1: Receive result of lsa close call
739 */
continue_lsa_close(struct tevent_req * subreq)740 static void continue_lsa_close(struct tevent_req *subreq)
741 {
742 struct composite_context *c;
743 struct domain_close_lsa_state *s;
744
745 c = tevent_req_callback_data(subreq, struct composite_context);
746 s = talloc_get_type_abort(c->private_data, struct domain_close_lsa_state);
747
748 c->status = dcerpc_lsa_Close_r_recv(subreq, s);
749 TALLOC_FREE(subreq);
750 if (!composite_is_ok(c)) return;
751
752 if (s->monitor_fn) {
753 struct monitor_msg msg;
754
755 msg.type = mon_LsaClose;
756 msg.data = NULL;
757 msg.data_size = 0;
758 s->monitor_fn(&msg);
759 }
760
761 composite_done(c);
762 }
763
764
libnet_DomainCloseLsa_recv(struct composite_context * c,struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_DomainClose * io)765 NTSTATUS libnet_DomainCloseLsa_recv(struct composite_context *c, struct libnet_context *ctx,
766 TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
767 {
768 NTSTATUS status;
769
770 status = composite_wait(c);
771
772 if (NT_STATUS_IS_OK(status) && io) {
773 /* policy handle closed successfully */
774
775 ctx->lsa.name = NULL;
776 ZERO_STRUCT(ctx->lsa.handle);
777
778 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
779
780 } else if (!NT_STATUS_IS_OK(status)) {
781 /* there was an error, so return description of the status code */
782 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
783 }
784
785 talloc_free(c);
786 return status;
787 }
788
789
790 struct domain_close_samr_state {
791 struct samr_Close close;
792 struct policy_handle handle;
793
794 void (*monitor_fn)(struct monitor_msg*);
795 };
796
797
798 static void continue_samr_close(struct tevent_req *subreq);
799
800
libnet_DomainCloseSamr_send(struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_DomainClose * io,void (* monitor)(struct monitor_msg *))801 struct composite_context* libnet_DomainCloseSamr_send(struct libnet_context *ctx,
802 TALLOC_CTX *mem_ctx,
803 struct libnet_DomainClose *io,
804 void (*monitor)(struct monitor_msg*))
805 {
806 struct composite_context *c;
807 struct domain_close_samr_state *s;
808 struct tevent_req *subreq;
809
810 /* composite context and state structure allocation */
811 c = composite_create(mem_ctx, ctx->event_ctx);
812 if (c == NULL) return c;
813
814 s = talloc_zero(c, struct domain_close_samr_state);
815 if (composite_nomem(s, c)) return c;
816
817 c->private_data = s;
818 s->monitor_fn = monitor;
819
820 /* TODO: check if samr pipe pointer is non-null */
821
822 if (!strequal(ctx->samr.name, io->in.domain_name)) {
823 composite_error(c, NT_STATUS_INVALID_PARAMETER);
824 return c;
825 }
826
827 /* prepare close domain handle call arguments */
828 ZERO_STRUCT(s->close);
829 s->close.in.handle = &ctx->samr.handle;
830 s->close.out.handle = &s->handle;
831
832 /* send the request */
833 subreq = dcerpc_samr_Close_r_send(s, c->event_ctx,
834 ctx->samr.pipe->binding_handle,
835 &s->close);
836 if (composite_nomem(subreq, c)) return c;
837
838 tevent_req_set_callback(subreq, continue_samr_close, c);
839 return c;
840 }
841
842
843 /*
844 Stage 1: Receive result of samr close call
845 */
continue_samr_close(struct tevent_req * subreq)846 static void continue_samr_close(struct tevent_req *subreq)
847 {
848 struct composite_context *c;
849 struct domain_close_samr_state *s;
850
851 c = tevent_req_callback_data(subreq, struct composite_context);
852 s = talloc_get_type_abort(c->private_data, struct domain_close_samr_state);
853
854 c->status = dcerpc_samr_Close_r_recv(subreq, s);
855 TALLOC_FREE(subreq);
856 if (!composite_is_ok(c)) return;
857
858 if (s->monitor_fn) {
859 struct monitor_msg msg;
860
861 msg.type = mon_SamrClose;
862 msg.data = NULL;
863 msg.data_size = 0;
864 s->monitor_fn(&msg);
865 }
866
867 composite_done(c);
868 }
869
870
libnet_DomainCloseSamr_recv(struct composite_context * c,struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_DomainClose * io)871 NTSTATUS libnet_DomainCloseSamr_recv(struct composite_context *c, struct libnet_context *ctx,
872 TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
873 {
874 NTSTATUS status;
875
876 status = composite_wait(c);
877
878 if (NT_STATUS_IS_OK(status) && io) {
879 /* domain policy handle closed successfully */
880
881 ZERO_STRUCT(ctx->samr.handle);
882 talloc_free(discard_const_p(char, ctx->samr.name));
883 talloc_free(ctx->samr.sid);
884 ctx->samr.name = NULL;
885 ctx->samr.sid = NULL;
886
887 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
888
889 } else if (!NT_STATUS_IS_OK(status)) {
890 /* there was an error, so return description of the status code */
891 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
892 }
893
894 talloc_free(c);
895 return status;
896 }
897
898
libnet_DomainClose_send(struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_DomainClose * io,void (* monitor)(struct monitor_msg *))899 struct composite_context* libnet_DomainClose_send(struct libnet_context *ctx,
900 TALLOC_CTX *mem_ctx,
901 struct libnet_DomainClose *io,
902 void (*monitor)(struct monitor_msg*))
903 {
904 struct composite_context *c;
905
906 switch (io->in.type) {
907 case DOMAIN_LSA:
908 /* request to close policy handle on \pipe\lsarpc */
909 c = libnet_DomainCloseLsa_send(ctx, mem_ctx, io, monitor);
910 break;
911
912 case DOMAIN_SAMR:
913 default:
914 /* request to close domain policy handle on \pipe\samr */
915 c = libnet_DomainCloseSamr_send(ctx, mem_ctx, io, monitor);
916 break;
917 }
918
919 return c;
920 }
921
922
libnet_DomainClose_recv(struct composite_context * c,struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_DomainClose * io)923 NTSTATUS libnet_DomainClose_recv(struct composite_context *c, struct libnet_context *ctx,
924 TALLOC_CTX *mem_ctx, struct libnet_DomainClose *io)
925 {
926 NTSTATUS status;
927
928 switch (io->in.type) {
929 case DOMAIN_LSA:
930 /* receive result of closing lsa policy handle */
931 status = libnet_DomainCloseLsa_recv(c, ctx, mem_ctx, io);
932 break;
933
934 case DOMAIN_SAMR:
935 default:
936 /* receive result of closing samr domain policy handle */
937 status = libnet_DomainCloseSamr_recv(c, ctx, mem_ctx, io);
938 break;
939 }
940
941 return status;
942 }
943
944
libnet_DomainClose(struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_DomainClose * io)945 NTSTATUS libnet_DomainClose(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
946 struct libnet_DomainClose *io)
947 {
948 struct composite_context *c;
949
950 c = libnet_DomainClose_send(ctx, mem_ctx, io, NULL);
951 return libnet_DomainClose_recv(c, ctx, mem_ctx, io);
952 }
953
954
955 struct domain_list_state {
956 struct libnet_context *ctx;
957 struct libnet_RpcConnect rpcconn;
958 struct samr_Connect samrconn;
959 struct samr_EnumDomains enumdom;
960 struct samr_Close samrclose;
961 const char *hostname;
962 struct policy_handle connect_handle;
963 int buf_size;
964 struct domainlist *domains;
965 uint32_t resume_handle;
966 uint32_t count;
967
968 void (*monitor_fn)(struct monitor_msg*);
969 };
970
971
972 static void continue_rpc_connect(struct composite_context *c);
973 static void continue_samr_connect(struct tevent_req *subreq);
974 static void continue_samr_enum_domains(struct tevent_req *subreq);
975 static void continue_samr_close_handle(struct tevent_req *subreq);
976
977 static struct domainlist* get_domain_list(TALLOC_CTX *mem_ctx, struct domain_list_state *s);
978
979
980 /*
981 Stage 1: Receive connected rpc pipe and send connection
982 request to SAMR service
983 */
continue_rpc_connect(struct composite_context * ctx)984 static void continue_rpc_connect(struct composite_context *ctx)
985 {
986 struct composite_context *c;
987 struct domain_list_state *s;
988 struct tevent_req *subreq;
989
990 c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
991 s = talloc_get_type_abort(c->private_data, struct domain_list_state);
992
993 c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpcconn);
994 if (!composite_is_ok(c)) return;
995
996 s->samrconn.in.system_name = 0;
997 s->samrconn.in.access_mask = SEC_GENERIC_READ; /* should be enough */
998 s->samrconn.out.connect_handle = &s->connect_handle;
999
1000 subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
1001 s->ctx->samr.pipe->binding_handle,
1002 &s->samrconn);
1003 if (composite_nomem(subreq, c)) return;
1004
1005 tevent_req_set_callback(subreq, continue_samr_connect, c);
1006 }
1007
1008
1009 /*
1010 Stage 2: Receive policy handle to the connected SAMR service and issue
1011 a request to enumerate domain databases available
1012 */
continue_samr_connect(struct tevent_req * subreq)1013 static void continue_samr_connect(struct tevent_req *subreq)
1014 {
1015 struct composite_context *c;
1016 struct domain_list_state *s;
1017
1018 c = tevent_req_callback_data(subreq, struct composite_context);
1019 s = talloc_get_type_abort(c->private_data, struct domain_list_state);
1020
1021 c->status = dcerpc_samr_Connect_r_recv(subreq, s);
1022 TALLOC_FREE(subreq);
1023 if (!composite_is_ok(c)) return;
1024
1025 if (s->monitor_fn) {
1026 struct monitor_msg msg;
1027
1028 msg.type = mon_SamrConnect;
1029 msg.data = NULL;
1030 msg.data_size = 0;
1031 s->monitor_fn(&msg);
1032 }
1033
1034 s->enumdom.in.connect_handle = &s->connect_handle;
1035 s->enumdom.in.resume_handle = &s->resume_handle;
1036 s->enumdom.in.buf_size = s->buf_size;
1037 s->enumdom.out.resume_handle = &s->resume_handle;
1038 s->enumdom.out.num_entries = talloc(s, uint32_t);
1039 if (composite_nomem(s->enumdom.out.num_entries, c)) return;
1040 s->enumdom.out.sam = talloc(s, struct samr_SamArray *);
1041 if (composite_nomem(s->enumdom.out.sam, c)) return;
1042
1043 subreq = dcerpc_samr_EnumDomains_r_send(s, c->event_ctx,
1044 s->ctx->samr.pipe->binding_handle,
1045 &s->enumdom);
1046 if (composite_nomem(subreq, c)) return;
1047
1048 tevent_req_set_callback(subreq, continue_samr_enum_domains, c);
1049 }
1050
1051
1052 /*
1053 Stage 3: Receive domain names available and repeat the request
1054 enumeration is not complete yet. Close samr connection handle
1055 upon completion.
1056 */
continue_samr_enum_domains(struct tevent_req * subreq)1057 static void continue_samr_enum_domains(struct tevent_req *subreq)
1058 {
1059 struct composite_context *c;
1060 struct domain_list_state *s;
1061
1062 c = tevent_req_callback_data(subreq, struct composite_context);
1063 s = talloc_get_type_abort(c->private_data, struct domain_list_state);
1064
1065 c->status = dcerpc_samr_EnumDomains_r_recv(subreq, s);
1066 TALLOC_FREE(subreq);
1067 if (!composite_is_ok(c)) return;
1068
1069 if (s->monitor_fn) {
1070 struct monitor_msg msg;
1071
1072 msg.type = mon_SamrEnumDomains;
1073 msg.data = NULL;
1074 msg.data_size = 0;
1075 s->monitor_fn(&msg);
1076 }
1077
1078 if (NT_STATUS_IS_OK(s->enumdom.out.result)) {
1079
1080 s->domains = get_domain_list(c, s);
1081
1082 } else if (NT_STATUS_EQUAL(s->enumdom.out.result, STATUS_MORE_ENTRIES)) {
1083
1084 s->domains = get_domain_list(c, s);
1085
1086 /* prepare next round of enumeration */
1087 s->enumdom.in.connect_handle = &s->connect_handle;
1088 s->enumdom.in.resume_handle = &s->resume_handle;
1089 s->enumdom.in.buf_size = s->ctx->samr.buf_size;
1090 s->enumdom.out.resume_handle = &s->resume_handle;
1091
1092 /* send the request */
1093 subreq = dcerpc_samr_EnumDomains_r_send(s, c->event_ctx,
1094 s->ctx->samr.pipe->binding_handle,
1095 &s->enumdom);
1096 if (composite_nomem(subreq, c)) return;
1097
1098 tevent_req_set_callback(subreq, continue_samr_enum_domains, c);
1099
1100 } else {
1101 composite_error(c, s->enumdom.out.result);
1102 return;
1103 }
1104
1105 /* close samr connection handle */
1106 s->samrclose.in.handle = &s->connect_handle;
1107 s->samrclose.out.handle = &s->connect_handle;
1108
1109 /* send the request */
1110 subreq = dcerpc_samr_Close_r_send(s, c->event_ctx,
1111 s->ctx->samr.pipe->binding_handle,
1112 &s->samrclose);
1113 if (composite_nomem(subreq, c)) return;
1114
1115 tevent_req_set_callback(subreq, continue_samr_close_handle, c);
1116 }
1117
1118
1119 /*
1120 Stage 4: Receive result of closing samr connection handle.
1121 */
continue_samr_close_handle(struct tevent_req * subreq)1122 static void continue_samr_close_handle(struct tevent_req *subreq)
1123 {
1124 struct composite_context *c;
1125 struct domain_list_state *s;
1126
1127 c = tevent_req_callback_data(subreq, struct composite_context);
1128 s = talloc_get_type_abort(c->private_data, struct domain_list_state);
1129
1130 c->status = dcerpc_samr_Close_r_recv(subreq, s);
1131 TALLOC_FREE(subreq);
1132 if (!composite_is_ok(c)) return;
1133
1134 if (s->monitor_fn) {
1135 struct monitor_msg msg;
1136
1137 msg.type = mon_SamrClose;
1138 msg.data = NULL;
1139 msg.data_size = 0;
1140 s->monitor_fn(&msg);
1141 }
1142
1143 /* did everything go fine ? */
1144 if (!NT_STATUS_IS_OK(s->samrclose.out.result)) {
1145 composite_error(c, s->samrclose.out.result);
1146 return;
1147 }
1148
1149 composite_done(c);
1150 }
1151
1152
1153 /*
1154 Utility function to copy domain names from result of samr_EnumDomains call
1155 */
get_domain_list(TALLOC_CTX * mem_ctx,struct domain_list_state * s)1156 static struct domainlist* get_domain_list(TALLOC_CTX *mem_ctx, struct domain_list_state *s)
1157 {
1158 uint32_t i;
1159 if (mem_ctx == NULL || s == NULL) return NULL;
1160
1161 /* prepare domains array */
1162 if (s->domains == NULL) {
1163 s->domains = talloc_array(mem_ctx, struct domainlist,
1164 *s->enumdom.out.num_entries);
1165 } else {
1166 s->domains = talloc_realloc(mem_ctx, s->domains, struct domainlist,
1167 s->count + *s->enumdom.out.num_entries);
1168 }
1169
1170 /* copy domain names returned from samr_EnumDomains call */
1171 for (i = s->count; i < s->count + *s->enumdom.out.num_entries; i++)
1172 {
1173 struct lsa_String *domain_name = &(*s->enumdom.out.sam)->entries[i - s->count].name;
1174
1175 /* strdup name as a child of allocated array to make it follow the array
1176 in case of talloc_steal or talloc_free */
1177 s->domains[i].name = talloc_strdup(s->domains, domain_name->string);
1178 s->domains[i].sid = NULL; /* this is to be filled out later */
1179 }
1180
1181 /* number of entries returned (domains enumerated) */
1182 s->count += *s->enumdom.out.num_entries;
1183
1184 return s->domains;
1185 }
1186
1187
1188 /**
1189 * Sends a request to list domains on given host
1190 *
1191 * @param ctx initialised libnet context
1192 * @param mem_ctx memory context
1193 * @param io arguments and results of the call
1194 * @param monitor pointer to monitor function that is passed monitor messages
1195 */
1196
libnet_DomainList_send(struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_DomainList * io,void (* monitor)(struct monitor_msg *))1197 struct composite_context* libnet_DomainList_send(struct libnet_context *ctx,
1198 TALLOC_CTX *mem_ctx,
1199 struct libnet_DomainList *io,
1200 void (*monitor)(struct monitor_msg*))
1201 {
1202 struct composite_context *c;
1203 struct domain_list_state *s;
1204 struct composite_context *rpcconn_req;
1205 struct tevent_req *subreq;
1206
1207 /* composite context and state structure allocation */
1208 c = composite_create(ctx, ctx->event_ctx);
1209 if (c == NULL) return c;
1210
1211 s = talloc_zero(c, struct domain_list_state);
1212 if (composite_nomem(s, c)) return c;
1213
1214 c->private_data = s;
1215 s->monitor_fn = monitor;
1216
1217 s->ctx = ctx;
1218 s->hostname = talloc_strdup(c, io->in.hostname);
1219 if (composite_nomem(s->hostname, c)) return c;
1220
1221 /* check whether samr pipe has already been opened */
1222 if (ctx->samr.pipe == NULL) {
1223 ZERO_STRUCT(s->rpcconn);
1224
1225 /* prepare rpc connect call */
1226 s->rpcconn.level = LIBNET_RPC_CONNECT_SERVER;
1227 s->rpcconn.in.name = s->hostname;
1228 s->rpcconn.in.dcerpc_iface = &ndr_table_samr;
1229
1230 rpcconn_req = libnet_RpcConnect_send(ctx, c, &s->rpcconn, s->monitor_fn);
1231 if (composite_nomem(rpcconn_req, c)) return c;
1232
1233 composite_continue(c, rpcconn_req, continue_rpc_connect, c);
1234
1235 } else {
1236 /* prepare samr_Connect call */
1237 s->samrconn.in.system_name = 0;
1238 s->samrconn.in.access_mask = SEC_GENERIC_READ;
1239 s->samrconn.out.connect_handle = &s->connect_handle;
1240
1241 subreq = dcerpc_samr_Connect_r_send(s, c->event_ctx,
1242 s->ctx->samr.pipe->binding_handle,
1243 &s->samrconn);
1244 if (composite_nomem(subreq, c)) return c;
1245
1246 tevent_req_set_callback(subreq, continue_samr_connect, c);
1247 }
1248
1249 return c;
1250 }
1251
1252
1253 /**
1254 * Receive result of domain list request
1255 *
1256 * @param c composite context returned by DomainList_send function
1257 * @param ctx initialised libnet context
1258 * @param mem_ctx memory context of the call
1259 * @param io results and arguments of the call
1260 */
1261
libnet_DomainList_recv(struct composite_context * c,struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_DomainList * io)1262 NTSTATUS libnet_DomainList_recv(struct composite_context *c, struct libnet_context *ctx,
1263 TALLOC_CTX *mem_ctx, struct libnet_DomainList *io)
1264 {
1265 NTSTATUS status;
1266 struct domain_list_state *s;
1267
1268 status = composite_wait(c);
1269
1270 s = talloc_get_type_abort(c->private_data, struct domain_list_state);
1271
1272 if (NT_STATUS_IS_OK(status) && ctx && mem_ctx && io) {
1273 /* fetch the results to be returned by io structure */
1274 io->out.count = s->count;
1275 io->out.domains = talloc_steal(mem_ctx, s->domains);
1276 io->out.error_string = talloc_asprintf(mem_ctx, "Success");
1277
1278 } else if (!NT_STATUS_IS_OK(status)) {
1279 /* there was an error, so return description of the status code */
1280 io->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
1281 }
1282
1283 talloc_free(c);
1284 return status;
1285 }
1286
1287
1288 /**
1289 * Synchronous version of DomainList call
1290 *
1291 * @param ctx initialised libnet context
1292 * @param mem_ctx memory context for the call
1293 * @param io arguments and results of the call
1294 * @return nt status code of execution
1295 */
1296
libnet_DomainList(struct libnet_context * ctx,TALLOC_CTX * mem_ctx,struct libnet_DomainList * io)1297 NTSTATUS libnet_DomainList(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
1298 struct libnet_DomainList *io)
1299 {
1300 struct composite_context *c;
1301
1302 c = libnet_DomainList_send(ctx, mem_ctx, io, NULL);
1303 return libnet_DomainList_recv(c, ctx, mem_ctx, io);
1304 }
1305