Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Copyright (C) Stefan Metzmacher <metze@samba.org> 2006
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 : #include "includes.h"
21 : #include "libnet/libnet.h"
22 : #include "libcli/composite/composite.h"
23 : #include "libcli/cldap/cldap.h"
24 : #include <ldb.h>
25 : #include <ldb_errors.h>
26 : #include "ldb_wrap.h"
27 : #include "dsdb/samdb/samdb.h"
28 : #include "../libds/common/flags.h"
29 : #include "librpc/gen_ndr/ndr_drsuapi_c.h"
30 : #include "param/param.h"
31 : #include "lib/tsocket/tsocket.h"
32 :
33 : /*****************************************************************************
34 : * Windows 2003 (w2k3) does the following steps when changing the server role
35 : * from domain controller back to domain member
36 : *
37 : * We mostly do the same.
38 : *****************************************************************************/
39 :
40 : /*
41 : * lookup DC:
42 : * - using nbt name<1C> request and a samlogon mailslot request
43 : * or
44 : * - using a DNS SRV _ldap._tcp.dc._msdcs. request and a CLDAP netlogon request
45 : *
46 : * see: unbecomeDC_send_cldap() and unbecomeDC_recv_cldap()
47 : */
48 :
49 : /*
50 : * Open 1st LDAP connection to the DC using admin credentials
51 : *
52 : * see: unbecomeDC_ldap_connect()
53 : */
54 :
55 : /*
56 : * LDAP search 1st LDAP connection:
57 : *
58 : * see: unbecomeDC_ldap_rootdse()
59 : *
60 : * Request:
61 : * basedn: ""
62 : * scope: base
63 : * filter: (objectClass=*)
64 : * attrs: defaultNamingContext
65 : * configurationNamingContext
66 : * Result:
67 : * ""
68 : * defaultNamingContext: <domain_partition>
69 : * configurationNamingContext:CN=Configuration,<domain_partition>
70 : */
71 :
72 : /*
73 : * LDAP search 1st LDAP connection:
74 : *
75 : * see: unbecomeDC_ldap_computer_object()
76 : *
77 : * Request:
78 : * basedn: <domain_partition>
79 : * scope: sub
80 : * filter: (&(|(objectClass=user)(objectClass=computer))(sAMAccountName=<new_dc_account_name>))
81 : * attrs: distinguishedName
82 : * userAccountControl
83 : * Result:
84 : * CN=<new_dc_netbios_name>,CN=Domain Controllers,<domain_partition>
85 : * distinguishedName: CN=<new_dc_netbios_name>,CN=Domain Controllers,<domain_partition>
86 : * userAccoountControl: 532480 <0x82000>
87 : */
88 :
89 : /*
90 : * LDAP search 1st LDAP connection:
91 : *
92 : * see: unbecomeDC_ldap_modify_computer()
93 : *
94 : * Request:
95 : * basedn: CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
96 : * scope: base
97 : * filter: (objectClass=*)
98 : * attrs: userAccountControl
99 : * Result:
100 : * CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
101 : * userAccoountControl: 532480 <0x82000>
102 : */
103 :
104 : /*
105 : * LDAP modify 1st LDAP connection:
106 : *
107 : * see: unbecomeDC_ldap_modify_computer()
108 : *
109 : * Request (replace):
110 : * CN=<new_dc_netbios_name>,CN=Computers,<domain_partition>
111 : * userAccoountControl: 4096 <0x1000>
112 : * Result:
113 : * <success>
114 : */
115 :
116 : /*
117 : * LDAP search 1st LDAP connection:
118 : *
119 : * see: unbecomeDC_ldap_move_computer()
120 : *
121 : * Request:
122 : * basedn: <WKGUID=aa312825768811d1aded00c04fd8d5cd,<domain_partition>>
123 : * scope: base
124 : * filter: (objectClass=*)
125 : * attrs: 1.1
126 : * Result:
127 : * CN=Computers,<domain_partition>
128 : */
129 :
130 : /*
131 : * LDAP search 1st LDAP connection:
132 : *
133 : * not implemented because it doesn't give any new information
134 : *
135 : * Request:
136 : * basedn: CN=Computers,<domain_partition>
137 : * scope: base
138 : * filter: (objectClass=*)
139 : * attrs: distinguishedName
140 : * Result:
141 : * CN=Computers,<domain_partition>
142 : * distinguishedName: CN=Computers,<domain_partition>
143 : */
144 :
145 : /*
146 : * LDAP modifyRDN 1st LDAP connection:
147 : *
148 : * see: unbecomeDC_ldap_move_computer()
149 : *
150 : * Request:
151 : * entry: CN=<new_dc_netbios_name>,CN=Domain Controllers,<domain_partition>
152 : * newrdn: CN=<new_dc_netbios_name>
153 : * deleteoldrdn: TRUE
154 : * newparent: CN=Computers,<domain_partition>
155 : * Result:
156 : * <success>
157 : */
158 :
159 : /*
160 : * LDAP unbind on the 1st LDAP connection
161 : *
162 : * not implemented, because it's not needed...
163 : */
164 :
165 : /*
166 : * Open 1st DRSUAPI connection to the DC using admin credentials
167 : * DsBind with DRSUAPI_DS_BIND_GUID ("e24d201a-4fd6-11d1-a3da-0000f875ae0d")
168 : *
169 : * see: unbecomeDC_drsuapi_connect_send(), unbecomeDC_drsuapi_connect_recv(),
170 : * unbecomeDC_drsuapi_bind_send() and unbecomeDC_drsuapi_bind_recv()
171 : */
172 :
173 : /*
174 : * DsRemoveDsServer to remove the
175 : * CN=<machine_name>,CN=Servers,CN=<site_name>,CN=Configuration,<domain_partition>
176 : * and CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=<site_name>,CN=Configuration,<domain_partition>
177 : * on the 1st DRSUAPI connection
178 : *
179 : * see: unbecomeDC_drsuapi_remove_ds_server_send() and unbecomeDC_drsuapi_remove_ds_server_recv()
180 : */
181 :
182 : /*
183 : * DsUnbind on the 1st DRSUAPI connection
184 : *
185 : * not implemented, because it's not needed...
186 : */
187 :
188 :
189 : struct libnet_UnbecomeDC_state {
190 : struct composite_context *creq;
191 :
192 : struct libnet_context *libnet;
193 :
194 : struct {
195 : struct cldap_socket *sock;
196 : struct cldap_netlogon io;
197 : struct NETLOGON_SAM_LOGON_RESPONSE_EX netlogon;
198 : } cldap;
199 :
200 : struct {
201 : struct ldb_context *ldb;
202 : } ldap;
203 :
204 : struct {
205 : struct dcerpc_binding *binding;
206 : struct dcerpc_pipe *pipe;
207 : struct dcerpc_binding_handle *drsuapi_handle;
208 : struct drsuapi_DsBind bind_r;
209 : struct GUID bind_guid;
210 : struct drsuapi_DsBindInfoCtr bind_info_ctr;
211 : struct drsuapi_DsBindInfo28 local_info28;
212 : struct drsuapi_DsBindInfo28 remote_info28;
213 : struct policy_handle bind_handle;
214 : struct drsuapi_DsRemoveDSServer rm_ds_srv_r;
215 : } drsuapi;
216 :
217 : struct {
218 : /* input */
219 : const char *dns_name;
220 : const char *netbios_name;
221 :
222 : /* constructed */
223 : struct GUID guid;
224 : const char *dn_str;
225 : } domain;
226 :
227 : struct {
228 : /* constructed */
229 : const char *config_dn_str;
230 : } forest;
231 :
232 : struct {
233 : /* input */
234 : const char *address;
235 :
236 : /* constructed */
237 : const char *dns_name;
238 : const char *netbios_name;
239 : const char *site_name;
240 : } source_dsa;
241 :
242 : struct {
243 : /* input */
244 : const char *netbios_name;
245 :
246 : /* constructed */
247 : const char *dns_name;
248 : const char *site_name;
249 : const char *computer_dn_str;
250 : const char *server_dn_str;
251 : uint32_t user_account_control;
252 : } dest_dsa;
253 : };
254 :
255 : static void unbecomeDC_recv_cldap(struct tevent_req *req);
256 :
257 4 : static void unbecomeDC_send_cldap(struct libnet_UnbecomeDC_state *s)
258 : {
259 4 : struct composite_context *c = s->creq;
260 2 : struct tevent_req *req;
261 2 : struct tsocket_address *dest_address;
262 2 : int ret;
263 :
264 4 : s->cldap.io.in.dest_address = NULL;
265 4 : s->cldap.io.in.dest_port = 0;
266 4 : s->cldap.io.in.realm = s->domain.dns_name;
267 4 : s->cldap.io.in.host = s->dest_dsa.netbios_name;
268 4 : s->cldap.io.in.user = NULL;
269 4 : s->cldap.io.in.domain_guid = NULL;
270 4 : s->cldap.io.in.domain_sid = NULL;
271 4 : s->cldap.io.in.acct_control = -1;
272 4 : s->cldap.io.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
273 4 : s->cldap.io.in.map_response = true;
274 :
275 4 : ret = tsocket_address_inet_from_strings(s, "ip",
276 : s->source_dsa.address,
277 : lpcfg_cldap_port(s->libnet->lp_ctx),
278 : &dest_address);
279 4 : if (ret != 0) {
280 0 : c->status = map_nt_error_from_unix_common(errno);
281 0 : if (!composite_is_ok(c)) return;
282 : }
283 :
284 4 : c->status = cldap_socket_init(s, NULL, dest_address, &s->cldap.sock);
285 4 : if (!composite_is_ok(c)) return;
286 :
287 8 : req = cldap_netlogon_send(s, s->libnet->event_ctx,
288 4 : s->cldap.sock, &s->cldap.io);
289 4 : if (composite_nomem(req, c)) return;
290 4 : tevent_req_set_callback(req, unbecomeDC_recv_cldap, s);
291 : }
292 :
293 : static void unbecomeDC_connect_ldap(struct libnet_UnbecomeDC_state *s);
294 :
295 4 : static void unbecomeDC_recv_cldap(struct tevent_req *req)
296 : {
297 4 : struct libnet_UnbecomeDC_state *s = tevent_req_callback_data(req,
298 : struct libnet_UnbecomeDC_state);
299 4 : struct composite_context *c = s->creq;
300 :
301 4 : c->status = cldap_netlogon_recv(req, s, &s->cldap.io);
302 4 : talloc_free(req);
303 4 : if (!composite_is_ok(c)) return;
304 :
305 4 : s->cldap.netlogon = s->cldap.io.out.netlogon.data.nt5_ex;
306 :
307 4 : s->domain.dns_name = s->cldap.netlogon.dns_domain;
308 4 : s->domain.netbios_name = s->cldap.netlogon.domain_name;
309 4 : s->domain.guid = s->cldap.netlogon.domain_uuid;
310 :
311 4 : s->source_dsa.dns_name = s->cldap.netlogon.pdc_dns_name;
312 4 : s->source_dsa.netbios_name = s->cldap.netlogon.pdc_name;
313 4 : s->source_dsa.site_name = s->cldap.netlogon.server_site;
314 :
315 4 : s->dest_dsa.site_name = s->cldap.netlogon.client_site;
316 :
317 4 : unbecomeDC_connect_ldap(s);
318 : }
319 :
320 4 : static NTSTATUS unbecomeDC_ldap_connect(struct libnet_UnbecomeDC_state *s)
321 : {
322 2 : char *url;
323 :
324 4 : url = talloc_asprintf(s, "ldap://%s/", s->source_dsa.dns_name);
325 4 : NT_STATUS_HAVE_NO_MEMORY(url);
326 :
327 8 : s->ldap.ldb = ldb_wrap_connect(s, s->libnet->event_ctx, s->libnet->lp_ctx, url,
328 : NULL,
329 4 : s->libnet->cred,
330 : 0);
331 4 : talloc_free(url);
332 4 : if (s->ldap.ldb == NULL) {
333 0 : return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
334 : }
335 :
336 4 : return NT_STATUS_OK;
337 : }
338 :
339 4 : static NTSTATUS unbecomeDC_ldap_rootdse(struct libnet_UnbecomeDC_state *s)
340 : {
341 2 : int ret;
342 2 : struct ldb_result *r;
343 2 : struct ldb_dn *basedn;
344 2 : static const char *attrs[] = {
345 : "defaultNamingContext",
346 : "configurationNamingContext",
347 : NULL
348 : };
349 :
350 4 : basedn = ldb_dn_new(s, s->ldap.ldb, NULL);
351 4 : NT_STATUS_HAVE_NO_MEMORY(basedn);
352 :
353 4 : ret = ldb_search(s->ldap.ldb, s, &r, basedn, LDB_SCOPE_BASE, attrs,
354 : "(objectClass=*)");
355 4 : talloc_free(basedn);
356 4 : if (ret != LDB_SUCCESS) {
357 0 : return NT_STATUS_LDAP(ret);
358 4 : } else if (r->count != 1) {
359 0 : talloc_free(r);
360 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
361 : }
362 :
363 4 : s->domain.dn_str = ldb_msg_find_attr_as_string(r->msgs[0], "defaultNamingContext", NULL);
364 4 : if (!s->domain.dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
365 4 : talloc_steal(s, s->domain.dn_str);
366 :
367 4 : s->forest.config_dn_str = ldb_msg_find_attr_as_string(r->msgs[0], "configurationNamingContext", NULL);
368 4 : if (!s->forest.config_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
369 4 : talloc_steal(s, s->forest.config_dn_str);
370 :
371 4 : s->dest_dsa.server_dn_str = talloc_asprintf(s, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
372 : s->dest_dsa.netbios_name,
373 : s->dest_dsa.site_name,
374 : s->forest.config_dn_str);
375 4 : NT_STATUS_HAVE_NO_MEMORY(s->dest_dsa.server_dn_str);
376 :
377 4 : talloc_free(r);
378 4 : return NT_STATUS_OK;
379 : }
380 :
381 4 : static NTSTATUS unbecomeDC_ldap_computer_object(struct libnet_UnbecomeDC_state *s)
382 : {
383 2 : int ret;
384 2 : struct ldb_result *r;
385 2 : struct ldb_dn *basedn;
386 2 : static const char *attrs[] = {
387 : "distinguishedName",
388 : "userAccountControl",
389 : NULL
390 : };
391 :
392 4 : basedn = ldb_dn_new(s, s->ldap.ldb, s->domain.dn_str);
393 4 : NT_STATUS_HAVE_NO_MEMORY(basedn);
394 :
395 4 : ret = ldb_search(s->ldap.ldb, s, &r, basedn, LDB_SCOPE_SUBTREE, attrs,
396 : "(&(|(objectClass=user)(objectClass=computer))(sAMAccountName=%s$))",
397 : s->dest_dsa.netbios_name);
398 4 : talloc_free(basedn);
399 4 : if (ret != LDB_SUCCESS) {
400 0 : return NT_STATUS_LDAP(ret);
401 4 : } else if (r->count != 1) {
402 0 : talloc_free(r);
403 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
404 : }
405 :
406 4 : s->dest_dsa.computer_dn_str = ldb_msg_find_attr_as_string(r->msgs[0], "distinguishedName", NULL);
407 4 : if (!s->dest_dsa.computer_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE;
408 4 : talloc_steal(s, s->dest_dsa.computer_dn_str);
409 :
410 4 : s->dest_dsa.user_account_control = ldb_msg_find_attr_as_uint(r->msgs[0], "userAccountControl", 0);
411 :
412 4 : talloc_free(r);
413 4 : return NT_STATUS_OK;
414 : }
415 :
416 4 : static NTSTATUS unbecomeDC_ldap_modify_computer(struct libnet_UnbecomeDC_state *s)
417 : {
418 2 : int ret;
419 2 : struct ldb_message *msg;
420 4 : uint32_t user_account_control = UF_WORKSTATION_TRUST_ACCOUNT;
421 2 : unsigned int i;
422 :
423 : /* as the value is already as we want it to be, we're done */
424 4 : if (s->dest_dsa.user_account_control == user_account_control) {
425 0 : return NT_STATUS_OK;
426 : }
427 :
428 : /* make a 'modify' msg, and only for serverReference */
429 4 : msg = ldb_msg_new(s);
430 4 : NT_STATUS_HAVE_NO_MEMORY(msg);
431 4 : msg->dn = ldb_dn_new(msg, s->ldap.ldb, s->dest_dsa.computer_dn_str);
432 4 : NT_STATUS_HAVE_NO_MEMORY(msg->dn);
433 :
434 4 : ret = samdb_msg_add_uint(s->ldap.ldb, msg, msg, "userAccountControl",
435 : user_account_control);
436 4 : if (ret != LDB_SUCCESS) {
437 0 : talloc_free(msg);
438 0 : return NT_STATUS_NO_MEMORY;
439 : }
440 :
441 : /* mark all the message elements (should be just one)
442 : as LDB_FLAG_MOD_REPLACE */
443 8 : for (i=0;i<msg->num_elements;i++) {
444 4 : msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
445 : }
446 :
447 4 : ret = ldb_modify(s->ldap.ldb, msg);
448 4 : talloc_free(msg);
449 4 : if (ret != LDB_SUCCESS) {
450 0 : return NT_STATUS_LDAP(ret);
451 : }
452 :
453 4 : s->dest_dsa.user_account_control = user_account_control;
454 :
455 4 : return NT_STATUS_OK;
456 : }
457 :
458 4 : static NTSTATUS unbecomeDC_ldap_move_computer(struct libnet_UnbecomeDC_state *s)
459 : {
460 2 : int ret;
461 2 : struct ldb_result *r;
462 2 : struct ldb_dn *basedn;
463 2 : struct ldb_dn *old_dn;
464 2 : struct ldb_dn *new_dn;
465 2 : static const char *_1_1_attrs[] = {
466 : "1.1",
467 : NULL
468 : };
469 :
470 4 : basedn = ldb_dn_new_fmt(s, s->ldap.ldb, "<WKGUID=aa312825768811d1aded00c04fd8d5cd,%s>",
471 : s->domain.dn_str);
472 4 : NT_STATUS_HAVE_NO_MEMORY(basedn);
473 :
474 4 : ret = ldb_search(s->ldap.ldb, s, &r, basedn, LDB_SCOPE_BASE,
475 : _1_1_attrs, "(objectClass=*)");
476 4 : talloc_free(basedn);
477 4 : if (ret != LDB_SUCCESS) {
478 0 : return NT_STATUS_LDAP(ret);
479 4 : } else if (r->count != 1) {
480 0 : talloc_free(r);
481 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
482 : }
483 :
484 4 : old_dn = ldb_dn_new(r, s->ldap.ldb, s->dest_dsa.computer_dn_str);
485 4 : NT_STATUS_HAVE_NO_MEMORY(old_dn);
486 :
487 4 : new_dn = r->msgs[0]->dn;
488 :
489 4 : if (!ldb_dn_add_child_fmt(new_dn, "CN=%s", s->dest_dsa.netbios_name)) {
490 0 : talloc_free(r);
491 0 : return NT_STATUS_NO_MEMORY;
492 : }
493 :
494 4 : if (ldb_dn_compare(old_dn, new_dn) == 0) {
495 : /* we don't need to rename if the old and new dn match */
496 0 : talloc_free(r);
497 0 : return NT_STATUS_OK;
498 : }
499 :
500 4 : ret = ldb_rename(s->ldap.ldb, old_dn, new_dn);
501 4 : if (ret != LDB_SUCCESS) {
502 0 : talloc_free(r);
503 0 : return NT_STATUS_LDAP(ret);
504 : }
505 :
506 4 : s->dest_dsa.computer_dn_str = ldb_dn_alloc_linearized(s, new_dn);
507 4 : NT_STATUS_HAVE_NO_MEMORY(s->dest_dsa.computer_dn_str);
508 :
509 4 : talloc_free(r);
510 :
511 4 : return NT_STATUS_OK;
512 : }
513 :
514 : static void unbecomeDC_drsuapi_connect_send(struct libnet_UnbecomeDC_state *s);
515 :
516 4 : static void unbecomeDC_connect_ldap(struct libnet_UnbecomeDC_state *s)
517 : {
518 4 : struct composite_context *c = s->creq;
519 :
520 4 : c->status = unbecomeDC_ldap_connect(s);
521 4 : if (!composite_is_ok(c)) return;
522 :
523 4 : c->status = unbecomeDC_ldap_rootdse(s);
524 4 : if (!composite_is_ok(c)) return;
525 :
526 4 : c->status = unbecomeDC_ldap_computer_object(s);
527 4 : if (!composite_is_ok(c)) return;
528 :
529 4 : c->status = unbecomeDC_ldap_modify_computer(s);
530 4 : if (!composite_is_ok(c)) return;
531 :
532 4 : c->status = unbecomeDC_ldap_move_computer(s);
533 4 : if (!composite_is_ok(c)) return;
534 :
535 4 : unbecomeDC_drsuapi_connect_send(s);
536 : }
537 :
538 : static void unbecomeDC_drsuapi_connect_recv(struct composite_context *creq);
539 :
540 4 : static void unbecomeDC_drsuapi_connect_send(struct libnet_UnbecomeDC_state *s)
541 : {
542 4 : struct composite_context *c = s->creq;
543 2 : struct composite_context *creq;
544 2 : char *binding_str;
545 :
546 4 : binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[seal,target_hostname=%s]",
547 : s->source_dsa.address,
548 : s->source_dsa.dns_name);
549 4 : if (composite_nomem(binding_str, c)) return;
550 :
551 4 : c->status = dcerpc_parse_binding(s, binding_str, &s->drsuapi.binding);
552 4 : talloc_free(binding_str);
553 4 : if (!composite_is_ok(c)) return;
554 :
555 4 : if (DEBUGLEVEL >= 10) {
556 0 : c->status = dcerpc_binding_set_flags(s->drsuapi.binding,
557 : DCERPC_DEBUG_PRINT_BOTH,
558 : 0);
559 0 : if (!composite_is_ok(c)) return;
560 : }
561 :
562 8 : creq = dcerpc_pipe_connect_b_send(s, s->drsuapi.binding, &ndr_table_drsuapi,
563 2 : s->libnet->cred, s->libnet->event_ctx,
564 4 : s->libnet->lp_ctx);
565 4 : composite_continue(c, creq, unbecomeDC_drsuapi_connect_recv, s);
566 : }
567 :
568 : static void unbecomeDC_drsuapi_bind_send(struct libnet_UnbecomeDC_state *s);
569 :
570 4 : static void unbecomeDC_drsuapi_connect_recv(struct composite_context *req)
571 : {
572 4 : struct libnet_UnbecomeDC_state *s = talloc_get_type(req->async.private_data,
573 : struct libnet_UnbecomeDC_state);
574 4 : struct composite_context *c = s->creq;
575 :
576 4 : c->status = dcerpc_pipe_connect_b_recv(req, s, &s->drsuapi.pipe);
577 4 : if (!composite_is_ok(c)) return;
578 :
579 4 : s->drsuapi.drsuapi_handle = s->drsuapi.pipe->binding_handle;
580 :
581 4 : unbecomeDC_drsuapi_bind_send(s);
582 : }
583 :
584 : static void unbecomeDC_drsuapi_bind_recv(struct tevent_req *subreq);
585 :
586 4 : static void unbecomeDC_drsuapi_bind_send(struct libnet_UnbecomeDC_state *s)
587 : {
588 4 : struct composite_context *c = s->creq;
589 2 : struct drsuapi_DsBindInfo28 *bind_info28;
590 2 : struct tevent_req *subreq;
591 :
592 4 : GUID_from_string(DRSUAPI_DS_BIND_GUID, &s->drsuapi.bind_guid);
593 :
594 4 : bind_info28 = &s->drsuapi.local_info28;
595 4 : bind_info28->supported_extensions = 0;
596 4 : bind_info28->site_guid = GUID_zero();
597 4 : bind_info28->pid = 0;
598 4 : bind_info28->repl_epoch = 0;
599 :
600 4 : s->drsuapi.bind_info_ctr.length = 28;
601 4 : s->drsuapi.bind_info_ctr.info.info28 = *bind_info28;
602 :
603 4 : s->drsuapi.bind_r.in.bind_guid = &s->drsuapi.bind_guid;
604 4 : s->drsuapi.bind_r.in.bind_info = &s->drsuapi.bind_info_ctr;
605 4 : s->drsuapi.bind_r.out.bind_handle = &s->drsuapi.bind_handle;
606 :
607 4 : subreq = dcerpc_drsuapi_DsBind_r_send(s, c->event_ctx,
608 : s->drsuapi.drsuapi_handle,
609 : &s->drsuapi.bind_r);
610 4 : if (composite_nomem(subreq, c)) return;
611 4 : tevent_req_set_callback(subreq, unbecomeDC_drsuapi_bind_recv, s);
612 : }
613 :
614 : static void unbecomeDC_drsuapi_remove_ds_server_send(struct libnet_UnbecomeDC_state *s);
615 :
616 4 : static void unbecomeDC_drsuapi_bind_recv(struct tevent_req *subreq)
617 : {
618 4 : struct libnet_UnbecomeDC_state *s = tevent_req_callback_data(subreq,
619 : struct libnet_UnbecomeDC_state);
620 4 : struct composite_context *c = s->creq;
621 :
622 4 : c->status = dcerpc_drsuapi_DsBind_r_recv(subreq, s);
623 4 : TALLOC_FREE(subreq);
624 4 : if (!composite_is_ok(c)) return;
625 :
626 4 : if (!W_ERROR_IS_OK(s->drsuapi.bind_r.out.result)) {
627 0 : composite_error(c, werror_to_ntstatus(s->drsuapi.bind_r.out.result));
628 0 : return;
629 : }
630 :
631 4 : ZERO_STRUCT(s->drsuapi.remote_info28);
632 4 : if (s->drsuapi.bind_r.out.bind_info) {
633 4 : switch (s->drsuapi.bind_r.out.bind_info->length) {
634 0 : case 24: {
635 0 : struct drsuapi_DsBindInfo24 *info24;
636 0 : info24 = &s->drsuapi.bind_r.out.bind_info->info.info24;
637 0 : s->drsuapi.remote_info28.supported_extensions = info24->supported_extensions;
638 0 : s->drsuapi.remote_info28.site_guid = info24->site_guid;
639 0 : s->drsuapi.remote_info28.pid = info24->pid;
640 0 : s->drsuapi.remote_info28.repl_epoch = 0;
641 0 : break;
642 : }
643 4 : case 28: {
644 4 : s->drsuapi.remote_info28 = s->drsuapi.bind_r.out.bind_info->info.info28;
645 4 : break;
646 : }
647 0 : case 32: {
648 0 : struct drsuapi_DsBindInfo32 *info32;
649 0 : info32 = &s->drsuapi.bind_r.out.bind_info->info.info32;
650 0 : s->drsuapi.remote_info28.supported_extensions = info32->supported_extensions;
651 0 : s->drsuapi.remote_info28.site_guid = info32->site_guid;
652 0 : s->drsuapi.remote_info28.pid = info32->pid;
653 0 : s->drsuapi.remote_info28.repl_epoch = info32->repl_epoch;
654 0 : break;
655 : }
656 0 : case 48: {
657 0 : struct drsuapi_DsBindInfo48 *info48;
658 0 : info48 = &s->drsuapi.bind_r.out.bind_info->info.info48;
659 0 : s->drsuapi.remote_info28.supported_extensions = info48->supported_extensions;
660 0 : s->drsuapi.remote_info28.site_guid = info48->site_guid;
661 0 : s->drsuapi.remote_info28.pid = info48->pid;
662 0 : s->drsuapi.remote_info28.repl_epoch = info48->repl_epoch;
663 0 : break;
664 : }
665 0 : case 52: {
666 0 : struct drsuapi_DsBindInfo52 *info52;
667 0 : info52 = &s->drsuapi.bind_r.out.bind_info->info.info52;
668 0 : s->drsuapi.remote_info28.supported_extensions = info52->supported_extensions;
669 0 : s->drsuapi.remote_info28.site_guid = info52->site_guid;
670 0 : s->drsuapi.remote_info28.pid = info52->pid;
671 0 : s->drsuapi.remote_info28.repl_epoch = info52->repl_epoch;
672 0 : break;
673 : }
674 0 : default:
675 0 : DEBUG(1, ("Warning: invalid info length in bind info: %d\n",
676 : s->drsuapi.bind_r.out.bind_info->length));
677 0 : break;
678 : }
679 : }
680 :
681 4 : unbecomeDC_drsuapi_remove_ds_server_send(s);
682 : }
683 :
684 : static void unbecomeDC_drsuapi_remove_ds_server_recv(struct tevent_req *subreq);
685 :
686 4 : static void unbecomeDC_drsuapi_remove_ds_server_send(struct libnet_UnbecomeDC_state *s)
687 : {
688 4 : struct composite_context *c = s->creq;
689 4 : struct drsuapi_DsRemoveDSServer *r = &s->drsuapi.rm_ds_srv_r;
690 2 : struct tevent_req *subreq;
691 :
692 4 : r->in.bind_handle = &s->drsuapi.bind_handle;
693 4 : r->in.level = 1;
694 4 : r->in.req = talloc(s, union drsuapi_DsRemoveDSServerRequest);
695 4 : r->in.req->req1.server_dn = s->dest_dsa.server_dn_str;
696 4 : r->in.req->req1.domain_dn = s->domain.dn_str;
697 4 : r->in.req->req1.commit = true;
698 :
699 4 : r->out.level_out = talloc(s, uint32_t);
700 4 : r->out.res = talloc(s, union drsuapi_DsRemoveDSServerResult);
701 :
702 4 : subreq = dcerpc_drsuapi_DsRemoveDSServer_r_send(s, c->event_ctx,
703 : s->drsuapi.drsuapi_handle,
704 : r);
705 4 : if (composite_nomem(subreq, c)) return;
706 4 : tevent_req_set_callback(subreq, unbecomeDC_drsuapi_remove_ds_server_recv, s);
707 : }
708 :
709 4 : static void unbecomeDC_drsuapi_remove_ds_server_recv(struct tevent_req *subreq)
710 : {
711 4 : struct libnet_UnbecomeDC_state *s = tevent_req_callback_data(subreq,
712 : struct libnet_UnbecomeDC_state);
713 4 : struct composite_context *c = s->creq;
714 4 : struct drsuapi_DsRemoveDSServer *r = &s->drsuapi.rm_ds_srv_r;
715 :
716 4 : c->status = dcerpc_drsuapi_DsRemoveDSServer_r_recv(subreq, s);
717 4 : TALLOC_FREE(subreq);
718 4 : if (!composite_is_ok(c)) return;
719 :
720 4 : if (!W_ERROR_IS_OK(r->out.result)) {
721 0 : composite_error(c, werror_to_ntstatus(r->out.result));
722 0 : return;
723 : }
724 :
725 4 : if (*r->out.level_out != 1) {
726 0 : composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
727 0 : return;
728 : }
729 :
730 4 : composite_done(c);
731 : }
732 :
733 4 : struct composite_context *libnet_UnbecomeDC_send(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_UnbecomeDC *r)
734 : {
735 2 : struct composite_context *c;
736 2 : struct libnet_UnbecomeDC_state *s;
737 2 : char *tmp_name;
738 :
739 4 : c = composite_create(mem_ctx, ctx->event_ctx);
740 4 : if (c == NULL) return NULL;
741 :
742 4 : s = talloc_zero(c, struct libnet_UnbecomeDC_state);
743 4 : if (composite_nomem(s, c)) return c;
744 4 : c->private_data = s;
745 4 : s->creq = c;
746 4 : s->libnet = ctx;
747 :
748 : /* Domain input */
749 4 : s->domain.dns_name = talloc_strdup(s, r->in.domain_dns_name);
750 4 : if (composite_nomem(s->domain.dns_name, c)) return c;
751 4 : s->domain.netbios_name = talloc_strdup(s, r->in.domain_netbios_name);
752 4 : if (composite_nomem(s->domain.netbios_name, c)) return c;
753 :
754 : /* Source DSA input */
755 4 : s->source_dsa.address = talloc_strdup(s, r->in.source_dsa_address);
756 4 : if (composite_nomem(s->source_dsa.address, c)) return c;
757 :
758 : /* Destination DSA input */
759 4 : s->dest_dsa.netbios_name= talloc_strdup(s, r->in.dest_dsa_netbios_name);
760 4 : if (composite_nomem(s->dest_dsa.netbios_name, c)) return c;
761 :
762 : /* Destination DSA dns_name construction */
763 4 : tmp_name = strlower_talloc(s, s->dest_dsa.netbios_name);
764 4 : if (composite_nomem(tmp_name, c)) return c;
765 4 : s->dest_dsa.dns_name = talloc_asprintf_append_buffer(tmp_name, ".%s",
766 : s->domain.dns_name);
767 4 : if (composite_nomem(s->dest_dsa.dns_name, c)) return c;
768 :
769 4 : unbecomeDC_send_cldap(s);
770 4 : return c;
771 : }
772 :
773 4 : NTSTATUS libnet_UnbecomeDC_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, struct libnet_UnbecomeDC *r)
774 : {
775 2 : NTSTATUS status;
776 :
777 4 : status = composite_wait(c);
778 :
779 4 : ZERO_STRUCT(r->out);
780 :
781 4 : talloc_free(c);
782 4 : return status;
783 : }
784 :
785 4 : NTSTATUS libnet_UnbecomeDC(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_UnbecomeDC *r)
786 : {
787 2 : NTSTATUS status;
788 2 : struct composite_context *c;
789 4 : c = libnet_UnbecomeDC_send(ctx, mem_ctx, r);
790 4 : status = libnet_UnbecomeDC_recv(c, mem_ctx, r);
791 4 : return status;
792 : }
|