source: vendor/current/source4/libnet/libnet_domain.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 35.2 KB
Line 
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
31struct 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
50static void continue_domain_open_close(struct tevent_req *subreq);
51static void continue_domain_open_connect(struct tevent_req *subreq);
52static void continue_domain_open_lookup(struct tevent_req *subreq);
53static void continue_domain_open_open(struct tevent_req *subreq);
54
55
56/**
57 * Stage 0.5 (optional): Connect to samr rpc pipe
58 */
59static 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 */
93static 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 */
139static 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 */
182static 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 */
236static 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
270struct 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
364NTSTATUS 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
391struct 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
405static void continue_rpc_connect_lsa(struct composite_context *ctx);
406static 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
417struct 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 */
490static 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 */
535static 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
570NTSTATUS 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 initalised 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
610struct 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
643NTSTATUS 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
672NTSTATUS 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
681struct 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
690static void continue_lsa_close(struct tevent_req *subreq);
691
692
693struct 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*/
740static 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
765NTSTATUS 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
790struct 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
798static void continue_samr_close(struct tevent_req *subreq);
799
800
801struct 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*/
846static 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
871NTSTATUS 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
899struct 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
923NTSTATUS 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
945NTSTATUS 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
955struct 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
972static void continue_rpc_connect(struct composite_context *c);
973static void continue_samr_connect(struct tevent_req *subreq);
974static void continue_samr_enum_domains(struct tevent_req *subreq);
975static void continue_samr_close_handle(struct tevent_req *subreq);
976
977static 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*/
984static 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*/
1013static 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*/
1057static 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*/
1122static 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*/
1156static 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 initalised 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
1197struct 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
1262NTSTATUS 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
1297NTSTATUS 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}
Note: See TracBrowser for help on using the repository browser.