selftest: put the target on the environment
[Samba.git] / source3 / utils / net_rpc_trust.c
blob9d945a4cad99d1d95d20543650cad214b53271f5
1 /*
2 Samba Unix/Linux SMB client library
3 Distributed SMB/CIFS Server Management Utility
4 Copyright (C) 2011 Sumit Bose (sbose@redhat.com)
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.
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.
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/>. */
20 #include "includes.h"
21 #include "utils/net.h"
22 #include "rpc_client/cli_pipe.h"
23 #include "rpc_client/cli_lsarpc.h"
24 #include "librpc/gen_ndr/ndr_drsblobs.h"
25 #include "../librpc/gen_ndr/ndr_lsa_c.h"
26 #include "../lib/crypto/crypto.h"
27 #include "../libcli/security/dom_sid.h"
30 #define ARG_OTHERSERVER "otherserver="
31 #define ARG_OTHERUSER "otheruser="
32 #define ARG_OTHERDOMAINSID "otherdomainsid="
33 #define ARG_OTHERDOMAIN "otherdomain="
34 #define ARG_OTHERNETBIOSDOMAIN "other_netbios_domain="
35 #define ARG_TRUSTPW "trustpw="
37 enum trust_op {
38 TRUST_CREATE,
39 TRUST_DELETE
42 struct other_dom_data {
43 char *host;
44 char *user_name;
45 char *domain_sid_str;
46 char *dns_domain_name;
47 char *domain_name;
50 struct dom_data {
51 struct dom_sid *domsid;
52 char *dns_domain_name;
53 char *domain_name;
56 static NTSTATUS close_handle(TALLOC_CTX *mem_ctx,
57 struct dcerpc_binding_handle *bind_hnd,
58 struct policy_handle *pol_hnd)
60 NTSTATUS status;
61 NTSTATUS result;
63 status = dcerpc_lsa_Close(bind_hnd, mem_ctx, pol_hnd, &result);
64 if (!NT_STATUS_IS_OK(status)) {
65 DEBUG(0, ("dcerpc_lsa_Close failed with error [%s].\n",
66 nt_errstr(status)));
67 return status;
69 if (!NT_STATUS_IS_OK(result)) {
70 DEBUG(0, ("lsa close failed with error [%s].\n",
71 nt_errstr(result)));
72 return result;
75 return NT_STATUS_OK;
78 static NTSTATUS delete_trust(TALLOC_CTX *mem_ctx,
79 struct dcerpc_binding_handle *bind_hnd,
80 struct policy_handle *pol_hnd,
81 struct dom_sid *domsid)
83 NTSTATUS status;
84 struct lsa_DeleteTrustedDomain dr;
86 dr.in.handle = pol_hnd;
87 dr.in.dom_sid = domsid;
89 status = dcerpc_lsa_DeleteTrustedDomain_r(bind_hnd, mem_ctx, &dr);
90 if (!NT_STATUS_IS_OK(status)) {
91 DEBUG(0, ("dcerpc_lsa_DeleteTrustedDomain_r failed with [%s]\n",
92 nt_errstr(status)));
93 return status;
95 if (!NT_STATUS_IS_OK(dr.out.result)) {
96 DEBUG(0, ("DeleteTrustedDomain returned [%s]\n",
97 nt_errstr(dr.out.result)));
98 return dr.out.result;
101 return NT_STATUS_OK;
104 static NTSTATUS create_trust(TALLOC_CTX *mem_ctx,
105 struct dcerpc_binding_handle *bind_hnd,
106 struct policy_handle *pol_hnd,
107 const char *trust_name,
108 const char *trust_name_dns,
109 struct dom_sid *domsid,
110 struct lsa_TrustDomainInfoAuthInfoInternal *authinfo)
112 NTSTATUS status;
113 struct lsa_CreateTrustedDomainEx2 r;
114 struct lsa_TrustDomainInfoInfoEx trustinfo;
115 struct policy_handle trustdom_handle;
117 trustinfo.sid = domsid;
118 trustinfo.netbios_name.string = trust_name;
119 trustinfo.domain_name.string = trust_name_dns;
121 trustinfo.trust_direction = LSA_TRUST_DIRECTION_INBOUND |
122 LSA_TRUST_DIRECTION_OUTBOUND;
124 trustinfo.trust_type = LSA_TRUST_TYPE_UPLEVEL;
126 trustinfo.trust_attributes = LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE;
128 r.in.policy_handle = pol_hnd;
129 r.in.info = &trustinfo;
130 r.in.auth_info = authinfo;
131 r.in.access_mask = LSA_TRUSTED_SET_POSIX | LSA_TRUSTED_SET_AUTH |
132 LSA_TRUSTED_QUERY_DOMAIN_NAME;
133 r.out.trustdom_handle = &trustdom_handle;
135 status = dcerpc_lsa_CreateTrustedDomainEx2_r(bind_hnd, mem_ctx, &r);
136 if (!NT_STATUS_IS_OK(status)) {
137 DEBUG(0, ("dcerpc_lsa_CreateTrustedDomainEx2_r failed "
138 "with error [%s].\n", nt_errstr(status)));
139 return status;
141 if (!NT_STATUS_IS_OK(r.out.result)) {
142 DEBUG(0, ("CreateTrustedDomainEx2_r returned [%s].\n",
143 nt_errstr(r.out.result)));
144 return r.out.result;
147 return NT_STATUS_OK;
150 static NTSTATUS get_domain_info(TALLOC_CTX *mem_ctx,
151 struct dcerpc_binding_handle *bind_hdn,
152 struct policy_handle *pol_hnd,
153 struct dom_data *dom_data)
155 NTSTATUS status;
156 struct lsa_QueryInfoPolicy2 qr;
158 qr.in.handle = pol_hnd;
159 qr.in.level = LSA_POLICY_INFO_DNS;
161 status = dcerpc_lsa_QueryInfoPolicy2_r(bind_hdn, mem_ctx, &qr);
162 if (!NT_STATUS_IS_OK(status)) {
163 DEBUG(0, ("dcerpc_lsa_QueryInfoPolicy2_r failed "
164 "with error [%s].\n", nt_errstr(status)));
165 return status;
168 if (!NT_STATUS_IS_OK(qr.out.result)) {
169 DEBUG(0, ("QueryInfoPolicy2 returned [%s].\n",
170 nt_errstr(qr.out.result)));
171 return qr.out.result;
174 dom_data->domain_name = talloc_strdup(mem_ctx,
175 (*qr.out.info)->dns.name.string);
176 dom_data->dns_domain_name = talloc_strdup(mem_ctx,
177 (*qr.out.info)->dns.dns_domain.string);
178 dom_data->domsid = dom_sid_dup(mem_ctx, (*qr.out.info)->dns.sid);
179 if (dom_data->domain_name == NULL ||
180 dom_data->dns_domain_name == NULL ||
181 dom_data->domsid == NULL) {
182 DEBUG(0, ("Copying domain data failed.\n"));
183 return NT_STATUS_NO_MEMORY;
186 DEBUG(0, ("Got the following domain info [%s][%s][%s].\n",
187 dom_data->domain_name, dom_data->dns_domain_name,
188 sid_string_talloc(mem_ctx, dom_data->domsid)));
190 return NT_STATUS_OK;
193 static NTSTATUS connect_and_get_info(TALLOC_CTX *mem_ctx,
194 struct net_context *net_ctx,
195 struct cli_state **cli,
196 struct rpc_pipe_client **pipe_hnd,
197 struct policy_handle *pol_hnd,
198 struct dom_data *dom_data)
200 NTSTATUS status;
201 NTSTATUS result;
203 status = net_make_ipc_connection_ex(net_ctx, NULL, NULL, NULL,
204 NET_FLAGS_PDC, cli);
205 if (!NT_STATUS_IS_OK(status)) {
206 DEBUG(0, ("Failed to connect to [%s] with error [%s]\n",
207 net_ctx->opt_host, nt_errstr(status)));
208 return status;
211 status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc.syntax_id, pipe_hnd);
212 if (!NT_STATUS_IS_OK(status)) {
213 DEBUG(0, ("Failed to initialise lsa pipe with error [%s]\n",
214 nt_errstr(status)));
215 return status;
218 status = dcerpc_lsa_open_policy2((*pipe_hnd)->binding_handle,
219 mem_ctx,
220 (*pipe_hnd)->srv_name_slash,
221 false,
222 (LSA_POLICY_VIEW_LOCAL_INFORMATION |
223 LSA_POLICY_TRUST_ADMIN |
224 LSA_POLICY_CREATE_SECRET),
225 pol_hnd,
226 &result);
227 if (!NT_STATUS_IS_OK(status)) {
228 DEBUG(0, ("Failed to open policy handle with error [%s]\n",
229 nt_errstr(status)));
230 return status;
232 if (!NT_STATUS_IS_OK(result)) {
233 DEBUG(0, ("lsa_open_policy2 with error [%s]\n",
234 nt_errstr(result)));
235 return result;
238 status = get_domain_info(mem_ctx, (*pipe_hnd)->binding_handle,
239 pol_hnd, dom_data);
240 if (!NT_STATUS_IS_OK(status)) {
241 DEBUG(0, ("get_domain_info failed with error [%s].\n",
242 nt_errstr(status)));
243 return status;
246 return NT_STATUS_OK;
249 static bool get_trust_domain_passwords_auth_blob(TALLOC_CTX *mem_ctx,
250 const char *password,
251 DATA_BLOB *auth_blob)
253 struct trustDomainPasswords auth_struct;
254 struct AuthenticationInformation *auth_info_array;
255 enum ndr_err_code ndr_err;
256 size_t converted_size;
258 generate_random_buffer(auth_struct.confounder,
259 sizeof(auth_struct.confounder));
261 auth_info_array = talloc_array(mem_ctx,
262 struct AuthenticationInformation, 1);
263 if (auth_info_array == NULL) {
264 return false;
267 auth_info_array[0].AuthType = TRUST_AUTH_TYPE_CLEAR;
268 if (!convert_string_talloc(mem_ctx, CH_UNIX, CH_UTF16, password,
269 strlen(password),
270 &auth_info_array[0].AuthInfo.clear.password,
271 &converted_size, true)) {
272 return false;
275 auth_info_array[0].AuthInfo.clear.size = converted_size;
277 auth_struct.outgoing.count = 1;
278 auth_struct.outgoing.current.count = 1;
279 auth_struct.outgoing.current.array = auth_info_array;
280 auth_struct.outgoing.previous.count = 0;
281 auth_struct.outgoing.previous.array = NULL;
283 auth_struct.incoming.count = 1;
284 auth_struct.incoming.current.count = 1;
285 auth_struct.incoming.current.array = auth_info_array;
286 auth_struct.incoming.previous.count = 0;
287 auth_struct.incoming.previous.array = NULL;
289 ndr_err = ndr_push_struct_blob(auth_blob, mem_ctx, &auth_struct,
290 (ndr_push_flags_fn_t)ndr_push_trustDomainPasswords);
291 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
292 return false;
295 return true;
298 static int parse_trust_args(TALLOC_CTX *mem_ctx, int argc, const char **argv, struct other_dom_data **_o, char **_trustpw)
300 size_t c;
301 struct other_dom_data *o = NULL;
302 char *trustpw = NULL;
303 int ret = EFAULT;
305 if (argc == 0) {
306 return EINVAL;
309 o = talloc_zero(mem_ctx, struct other_dom_data);
310 if (o == NULL) {
311 DEBUG(0, ("talloc_zero failed.\n"));
312 return ENOMEM;
315 for (c = 0; c < argc; c++) {
316 if (strnequal(argv[c], ARG_OTHERSERVER, sizeof(ARG_OTHERSERVER)-1)) {
317 o->host = talloc_strdup(o, argv[c] + sizeof(ARG_OTHERSERVER)-1);
318 if (o->host == NULL) {
319 ret = ENOMEM;
320 goto failed;
322 } else if (strnequal(argv[c], ARG_OTHERUSER, sizeof(ARG_OTHERUSER)-1)) {
323 o->user_name = talloc_strdup(o, argv[c] + sizeof(ARG_OTHERUSER)-1);
324 if (o->user_name == NULL) {
325 ret = ENOMEM;
326 goto failed;
328 } else if (strnequal(argv[c], ARG_OTHERDOMAINSID, sizeof(ARG_OTHERDOMAINSID)-1)) {
329 o->domain_sid_str = talloc_strdup(o, argv[c] + sizeof(ARG_OTHERDOMAINSID)-1);
330 if (o->domain_sid_str == NULL) {
331 ret = ENOMEM;
332 goto failed;
334 } else if (strnequal(argv[c], ARG_OTHERDOMAIN, sizeof(ARG_OTHERDOMAIN)-1)) {
335 o->dns_domain_name = talloc_strdup(o, argv[c] + sizeof(ARG_OTHERDOMAIN)-1);
336 if (o->dns_domain_name == NULL) {
337 ret = ENOMEM;
338 goto failed;
340 } else if (strnequal(argv[c], ARG_OTHERNETBIOSDOMAIN, sizeof(ARG_OTHERNETBIOSDOMAIN)-1)) {
341 o->domain_name = talloc_strdup(o, argv[c] + sizeof(ARG_OTHERNETBIOSDOMAIN)-1);
342 if (o->domain_name == NULL) {
343 ret = ENOMEM;
344 goto failed;
346 } else if (strnequal(argv[c], ARG_TRUSTPW, sizeof(ARG_TRUSTPW)-1)) {
347 trustpw = talloc_strdup(mem_ctx, argv[c] + sizeof(ARG_TRUSTPW)-1);
348 if (trustpw == NULL) {
349 ret = ENOMEM;
350 goto failed;
352 } else {
353 DEBUG(0, ("Unsupported option [%s].\n", argv[c]));
354 ret = EINVAL;
355 goto failed;
359 *_o = o;
360 *_trustpw = trustpw;
362 return 0;
364 failed:
365 talloc_free(o);
366 talloc_free(trustpw);
367 return ret;
370 static void print_trust_delete_usage(void)
372 d_printf( "%s\n"
373 "net rpc trust delete [options]\n"
374 "\nOptions:\n"
375 "\totherserver=DC in other domain\n"
376 "\totheruser=Admin user in other domain\n"
377 "\totherdomainsid=SID of other domain\n"
378 "\nExamples:\n"
379 "\tnet rpc trust delete otherserver=oname otheruser=ouser -S lname -U luser\n"
380 "\tnet rpc trust delete otherdomainsid=S-... -S lname -U luser\n"
381 " %s\n",
382 _("Usage:"),
383 _("Remove trust between two domains"));
386 static void print_trust_usage(void)
388 d_printf( "%s\n"
389 "net rpc trust create [options]\n"
390 "\nOptions:\n"
391 "\totherserver=DC in other domain\n"
392 "\totheruser=Admin user in other domain\n"
393 "\totherdomainsid=SID of other domain\n"
394 "\tother_netbios_domain=NetBIOS/short name of other domain\n"
395 "\totherdomain=Full/DNS name of other domain\n"
396 "\ttrustpw=Trust password\n"
397 "\nExamples:\n"
398 "\tnet rpc trust create otherserver=oname otheruser=ouser -S lname -U luser\n"
399 "\tnet rpc trust create otherdomainsid=S-... other_netbios_domain=odom otherdomain=odom.org trustpw=secret -S lname -U luser\n"
400 " %s\n",
401 _("Usage:"),
402 _("Create trust between two domains"));
405 static int rpc_trust_common(struct net_context *net_ctx, int argc,
406 const char **argv, enum trust_op op)
408 TALLOC_CTX *mem_ctx;
409 NTSTATUS status;
410 int ret;
411 int success = -1;
412 struct cli_state *cli[2] = {NULL, NULL};
413 struct rpc_pipe_client *pipe_hnd[2] = {NULL, NULL};
414 struct policy_handle pol_hnd[2];
415 struct lsa_TrustDomainInfoAuthInfoInternal authinfo;
416 DATA_BLOB auth_blob;
417 char *trust_pw = NULL;
418 struct other_dom_data *other_dom_data;
419 struct net_context *other_net_ctx = NULL;
420 struct dom_data dom_data[2];
422 if (net_ctx->display_usage) {
423 switch (op) {
424 case TRUST_CREATE:
425 print_trust_usage();
426 break;
427 case TRUST_DELETE:
428 print_trust_delete_usage();
429 break;
430 default:
431 DEBUG(0, ("Unsupported trust operation.\n"));
432 return -1;
434 return 0;
437 mem_ctx = talloc_init("trust op");
438 if (mem_ctx == NULL) {
439 DEBUG(0, ("talloc_init failed.\n"));
440 return -1;
443 ret = parse_trust_args(mem_ctx, argc, argv, &other_dom_data, &trust_pw);
444 if (ret != 0) {
445 if (ret == EINVAL) {
446 print_trust_usage();
447 } else {
448 DEBUG(0, ("Failed to parse arguments.\n"));
450 goto done;
453 if (other_dom_data->host != 0) {
454 other_net_ctx = talloc_zero(other_dom_data, struct net_context);
455 if (other_net_ctx == NULL) {
456 DEBUG(0, ("talloc_zero failed.\n"));
457 goto done;
460 other_net_ctx->opt_host = other_dom_data->host;
461 other_net_ctx->opt_user_name = other_dom_data->user_name;
462 } else {
463 dom_data[1].domsid = dom_sid_parse_talloc(mem_ctx,
464 other_dom_data->domain_sid_str);
465 dom_data[1].domain_name = other_dom_data->domain_name;
466 dom_data[1].dns_domain_name = other_dom_data->dns_domain_name;
468 if (dom_data[1].domsid == NULL ||
469 (op == TRUST_CREATE &&
470 (dom_data[1].domain_name == NULL ||
471 dom_data[1].dns_domain_name == NULL))) {
472 DEBUG(0, ("Missing required argument.\n"));
473 print_trust_usage();
474 goto done;
478 status = connect_and_get_info(mem_ctx, net_ctx, &cli[0], &pipe_hnd[0],
479 &pol_hnd[0], &dom_data[0]);
480 if (!NT_STATUS_IS_OK(status)) {
481 DEBUG(0, ("connect_and_get_info failed with error [%s]\n",
482 nt_errstr(status)));
483 goto done;
486 if (other_net_ctx != NULL) {
487 status = connect_and_get_info(mem_ctx, other_net_ctx,
488 &cli[1], &pipe_hnd[1],
489 &pol_hnd[1], &dom_data[1]);
490 if (!NT_STATUS_IS_OK(status)) {
491 DEBUG(0, ("connect_and_get_info failed with error [%s]\n",
492 nt_errstr(status)));
493 goto done;
497 if (op == TRUST_CREATE) {
498 if (trust_pw == NULL) {
499 if (other_net_ctx == NULL) {
500 DEBUG(0, ("Missing either trustpw or otherhost.\n"));
501 goto done;
504 DEBUG(0, ("Using random trust password.\n"));
505 /* FIXME: why only 8 characters work? Would it be possible to use a
506 * random binary password? */
507 trust_pw = generate_random_str(mem_ctx, 8);
508 if (trust_pw == NULL) {
509 DEBUG(0, ("generate_random_str failed.\n"));
510 goto done;
512 } else {
513 DEBUG(0, ("Using user provided password.\n"));
516 if (!get_trust_domain_passwords_auth_blob(mem_ctx, trust_pw,
517 &auth_blob)) {
518 DEBUG(0, ("get_trust_domain_passwords_auth_blob failed\n"));
519 goto done;
522 authinfo.auth_blob.data = (uint8_t *)talloc_memdup(
523 mem_ctx,
524 auth_blob.data,
525 auth_blob.length);
526 if (authinfo.auth_blob.data == NULL) {
527 goto done;
529 authinfo.auth_blob.size = auth_blob.length;
531 arcfour_crypt_blob(authinfo.auth_blob.data,
532 authinfo.auth_blob.size,
533 &cli[0]->user_session_key);
535 status = create_trust(mem_ctx, pipe_hnd[0]->binding_handle,
536 &pol_hnd[0],
537 dom_data[1].domain_name,
538 dom_data[1].dns_domain_name,
539 dom_data[1].domsid,
540 &authinfo);
541 if (!NT_STATUS_IS_OK(status)) {
542 DEBUG(0, ("create_trust failed with error [%s].\n",
543 nt_errstr(status)));
544 goto done;
547 if (other_net_ctx != NULL) {
548 talloc_free(authinfo.auth_blob.data);
549 authinfo.auth_blob.data = (uint8_t *)talloc_memdup(
550 mem_ctx,
551 auth_blob.data,
552 auth_blob.length);
553 if (authinfo.auth_blob.data == NULL) {
554 goto done;
556 authinfo.auth_blob.size = auth_blob.length;
558 arcfour_crypt_blob(authinfo.auth_blob.data,
559 authinfo.auth_blob.size,
560 &cli[1]->user_session_key);
562 status = create_trust(mem_ctx,
563 pipe_hnd[1]->binding_handle,
564 &pol_hnd[1],
565 dom_data[0].domain_name,
566 dom_data[0].dns_domain_name,
567 dom_data[0].domsid, &authinfo);
568 if (!NT_STATUS_IS_OK(status)) {
569 DEBUG(0, ("create_trust failed with error [%s].\n",
570 nt_errstr(status)));
571 goto done;
574 } else if (op == TRUST_DELETE) {
575 status = delete_trust(mem_ctx, pipe_hnd[0]->binding_handle,
576 &pol_hnd[0], dom_data[1].domsid);
577 if (!NT_STATUS_IS_OK(status)) {
578 DEBUG(0, ("delete_trust failed with [%s].\n",
579 nt_errstr(status)));
580 goto done;
583 if (other_net_ctx != NULL) {
584 status = delete_trust(mem_ctx,
585 pipe_hnd[1]->binding_handle,
586 &pol_hnd[1], dom_data[0].domsid);
587 if (!NT_STATUS_IS_OK(status)) {
588 DEBUG(0, ("delete_trust failed with [%s].\n",
589 nt_errstr(status)));
590 goto done;
595 status = close_handle(mem_ctx, pipe_hnd[0]->binding_handle,
596 &pol_hnd[0]);
597 if (!NT_STATUS_IS_OK(status)) {
598 DEBUG(0, ("close_handle failed with error [%s].\n",
599 nt_errstr(status)));
600 goto done;
603 if (other_net_ctx != NULL) {
604 status = close_handle(mem_ctx, pipe_hnd[1]->binding_handle,
605 &pol_hnd[1]);
606 if (!NT_STATUS_IS_OK(status)) {
607 DEBUG(0, ("close_handle failed with error [%s].\n",
608 nt_errstr(status)));
609 goto done;
613 success = 0;
615 done:
616 cli_shutdown(cli[0]);
617 cli_shutdown(cli[1]);
618 talloc_destroy(mem_ctx);
619 return success;
622 static int rpc_trust_create(struct net_context *net_ctx, int argc,
623 const char **argv)
625 return rpc_trust_common(net_ctx, argc, argv, TRUST_CREATE);
628 static int rpc_trust_delete(struct net_context *net_ctx, int argc,
629 const char **argv)
631 return rpc_trust_common(net_ctx, argc, argv, TRUST_DELETE);
634 int net_rpc_trust(struct net_context *c, int argc, const char **argv)
636 struct functable func[] = {
638 "create",
639 rpc_trust_create,
640 NET_TRANSPORT_RPC,
641 N_("Create trusts"),
642 N_("net rpc trust create\n"
643 " Create trusts")
646 "delete",
647 rpc_trust_delete,
648 NET_TRANSPORT_RPC,
649 N_("Remove trusts"),
650 N_("net rpc trust delete\n"
651 " Remove trusts")
653 {NULL, NULL, 0, NULL, NULL}
656 return net_run_function(c, argc, argv, "net rpc trust", func);