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/>. */
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 struct other_dom_data {
41 char *dns_domain_name;
46 struct dom_sid *domsid;
47 char *dns_domain_name;
51 static NTSTATUS close_handle(TALLOC_CTX *mem_ctx,
52 struct dcerpc_binding_handle *bind_hnd,
53 struct policy_handle *pol_hnd)
58 status = dcerpc_lsa_Close(bind_hnd, mem_ctx, pol_hnd, &result);
59 if (!NT_STATUS_IS_OK(status)) {
60 DEBUG(0, ("dcerpc_lsa_Close failed with error [%s].\n",
64 if (!NT_STATUS_IS_OK(result)) {
65 DEBUG(0, ("lsa close failed with error [%s].\n",
73 static NTSTATUS create_trust(TALLOC_CTX *mem_ctx,
74 struct dcerpc_binding_handle *bind_hnd,
75 struct policy_handle *pol_hnd,
76 const char *trust_name,
77 const char *trust_name_dns,
78 struct dom_sid *domsid,
79 struct lsa_TrustDomainInfoAuthInfoInternal *authinfo)
82 struct lsa_CreateTrustedDomainEx2 r;
83 struct lsa_TrustDomainInfoInfoEx trustinfo;
84 struct policy_handle trustdom_handle;
86 trustinfo.sid = domsid;
87 trustinfo.netbios_name.string = trust_name;
88 trustinfo.domain_name.string = trust_name_dns;
90 trustinfo.trust_direction = LSA_TRUST_DIRECTION_INBOUND |
91 LSA_TRUST_DIRECTION_OUTBOUND;
93 trustinfo.trust_type = LSA_TRUST_TYPE_UPLEVEL;
95 trustinfo.trust_attributes = LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE;
97 r.in.policy_handle = pol_hnd;
98 r.in.info = &trustinfo;
99 r.in.auth_info = authinfo;
100 r.in.access_mask = LSA_TRUSTED_SET_POSIX | LSA_TRUSTED_SET_AUTH |
101 LSA_TRUSTED_QUERY_DOMAIN_NAME;
102 r.out.trustdom_handle = &trustdom_handle;
104 status = dcerpc_lsa_CreateTrustedDomainEx2_r(bind_hnd, mem_ctx, &r);
105 if (!NT_STATUS_IS_OK(status)) {
106 DEBUG(0, ("dcerpc_lsa_CreateTrustedDomainEx2_r failed "
107 "with error [%s].\n", nt_errstr(status)));
110 if (!NT_STATUS_IS_OK(r.out.result)) {
111 DEBUG(0, ("CreateTrustedDomainEx2_r returned [%s].\n",
112 nt_errstr(r.out.result)));
119 static NTSTATUS get_domain_info(TALLOC_CTX *mem_ctx,
120 struct dcerpc_binding_handle *bind_hdn,
121 struct policy_handle *pol_hnd,
122 struct dom_data *dom_data)
125 struct lsa_QueryInfoPolicy2 qr;
127 qr.in.handle = pol_hnd;
128 qr.in.level = LSA_POLICY_INFO_DNS;
130 status = dcerpc_lsa_QueryInfoPolicy2_r(bind_hdn, mem_ctx, &qr);
131 if (!NT_STATUS_IS_OK(status)) {
132 DEBUG(0, ("dcerpc_lsa_QueryInfoPolicy2_r failed "
133 "with error [%s].\n", nt_errstr(status)));
137 if (!NT_STATUS_IS_OK(qr.out.result)) {
138 DEBUG(0, ("QueryInfoPolicy2 returned [%s].\n",
139 nt_errstr(qr.out.result)));
140 return qr.out.result;
143 dom_data->domain_name = talloc_strdup(mem_ctx,
144 (*qr.out.info)->dns.name.string);
145 dom_data->dns_domain_name = talloc_strdup(mem_ctx,
146 (*qr.out.info)->dns.dns_domain.string);
147 dom_data->domsid = dom_sid_dup(mem_ctx, (*qr.out.info)->dns.sid);
148 if (dom_data->domain_name == NULL ||
149 dom_data->dns_domain_name == NULL ||
150 dom_data->domsid == NULL) {
151 DEBUG(0, ("Copying domain data failed.\n"));
152 return NT_STATUS_NO_MEMORY;
155 DEBUG(0, ("Got the following domain info [%s][%s][%s].\n",
156 dom_data->domain_name, dom_data->dns_domain_name,
157 sid_string_talloc(mem_ctx, dom_data->domsid)));
162 static NTSTATUS connect_and_get_info(TALLOC_CTX *mem_ctx,
163 struct net_context *net_ctx,
164 struct cli_state **cli,
165 struct rpc_pipe_client **pipe_hnd,
166 struct policy_handle *pol_hnd,
167 struct dom_data *dom_data)
172 status = net_make_ipc_connection_ex(net_ctx, NULL, NULL, NULL,
174 if (!NT_STATUS_IS_OK(status)) {
175 DEBUG(0, ("Failed to connect to [%s] with error [%s]\n",
176 net_ctx->opt_host, nt_errstr(status)));
180 status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc.syntax_id, pipe_hnd);
181 if (!NT_STATUS_IS_OK(status)) {
182 DEBUG(0, ("Failed to initialise lsa pipe with error [%s]\n",
187 status = dcerpc_lsa_open_policy2((*pipe_hnd)->binding_handle,
189 (*pipe_hnd)->srv_name_slash,
191 (LSA_POLICY_VIEW_LOCAL_INFORMATION |
192 LSA_POLICY_TRUST_ADMIN |
193 LSA_POLICY_CREATE_SECRET),
196 if (!NT_STATUS_IS_OK(status)) {
197 DEBUG(0, ("Failed to open policy handle with error [%s]\n",
201 if (!NT_STATUS_IS_OK(result)) {
202 DEBUG(0, ("lsa_open_policy2 with error [%s]\n",
207 status = get_domain_info(mem_ctx, (*pipe_hnd)->binding_handle,
209 if (!NT_STATUS_IS_OK(status)) {
210 DEBUG(0, ("get_domain_info failed with error [%s].\n",
218 static bool get_trust_domain_passwords_auth_blob(TALLOC_CTX *mem_ctx,
219 const char *password,
220 DATA_BLOB *auth_blob)
222 struct trustDomainPasswords auth_struct;
223 struct AuthenticationInformation *auth_info_array;
224 enum ndr_err_code ndr_err;
225 size_t converted_size;
227 generate_random_buffer(auth_struct.confounder,
228 sizeof(auth_struct.confounder));
230 auth_info_array = talloc_array(mem_ctx,
231 struct AuthenticationInformation, 1);
232 if (auth_info_array == NULL) {
236 auth_info_array[0].AuthType = TRUST_AUTH_TYPE_CLEAR;
237 if (!convert_string_talloc(mem_ctx, CH_UNIX, CH_UTF16, password,
239 &auth_info_array[0].AuthInfo.clear.password,
244 auth_info_array[0].AuthInfo.clear.size = converted_size;
246 auth_struct.outgoing.count = 1;
247 auth_struct.outgoing.current.count = 1;
248 auth_struct.outgoing.current.array = auth_info_array;
249 auth_struct.outgoing.previous.count = 0;
250 auth_struct.outgoing.previous.array = NULL;
252 auth_struct.incoming.count = 1;
253 auth_struct.incoming.current.count = 1;
254 auth_struct.incoming.current.array = auth_info_array;
255 auth_struct.incoming.previous.count = 0;
256 auth_struct.incoming.previous.array = NULL;
258 ndr_err = ndr_push_struct_blob(auth_blob, mem_ctx, &auth_struct,
259 (ndr_push_flags_fn_t)ndr_push_trustDomainPasswords);
260 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
267 static int parse_trust_args(TALLOC_CTX *mem_ctx, int argc, const char **argv, struct other_dom_data **_o, char **_trustpw)
270 struct other_dom_data *o = NULL;
271 char *trustpw = NULL;
278 o = talloc_zero(mem_ctx, struct other_dom_data);
280 DEBUG(0, ("talloc_zero failed.\n"));
284 for (c = 0; c < argc; c++) {
285 if (strnequal(argv[c], ARG_OTHERSERVER, sizeof(ARG_OTHERSERVER)-1)) {
286 o->host = talloc_strdup(o, argv[c] + sizeof(ARG_OTHERSERVER)-1);
287 if (o->host == NULL) {
291 } else if (strnequal(argv[c], ARG_OTHERUSER, sizeof(ARG_OTHERUSER)-1)) {
292 o->user_name = talloc_strdup(o, argv[c] + sizeof(ARG_OTHERUSER)-1);
293 if (o->user_name == NULL) {
297 } else if (strnequal(argv[c], ARG_OTHERDOMAINSID, sizeof(ARG_OTHERDOMAINSID)-1)) {
298 o->domain_sid_str = talloc_strdup(o, argv[c] + sizeof(ARG_OTHERDOMAINSID)-1);
299 if (o->domain_sid_str == NULL) {
303 } else if (strnequal(argv[c], ARG_OTHERDOMAIN, sizeof(ARG_OTHERDOMAIN)-1)) {
304 o->dns_domain_name = talloc_strdup(o, argv[c] + sizeof(ARG_OTHERDOMAIN)-1);
305 if (o->dns_domain_name == NULL) {
309 } else if (strnequal(argv[c], ARG_OTHERNETBIOSDOMAIN, sizeof(ARG_OTHERNETBIOSDOMAIN)-1)) {
310 o->domain_name = talloc_strdup(o, argv[c] + sizeof(ARG_OTHERNETBIOSDOMAIN)-1);
311 if (o->domain_name == NULL) {
315 } else if (strnequal(argv[c], ARG_TRUSTPW, sizeof(ARG_TRUSTPW)-1)) {
316 trustpw = talloc_strdup(mem_ctx, argv[c] + sizeof(ARG_TRUSTPW)-1);
317 if (trustpw == NULL) {
322 DEBUG(0, ("Unsupported option [%s].\n", argv[c]));
335 talloc_free(trustpw);
339 static void print_trust_usage(void)
342 "net rpc trust create [options]\n"
344 "\totherserver=DC in other domain\n"
345 "\totheruser=Admin user in other domain\n"
346 "\totherdomainsid=SID of other domain\n"
347 "\tother_netbios_domain=NetBIOS/short name of other domain\n"
348 "\totherdomain=Full/DNS name of other domain\n"
349 "\ttrustpw=Trust password\n"
351 "\tnet rpc trust create otherserver=oname otheruser=ouser -S lname -U luser\n"
352 "\tnet rpc trust create otherdomainsid=S-... other_netbios_domain=odom otherdomain=odom.org trustpw=secret -S lname -U luser\n"
355 _("Create trust between two domains"));
358 static int rpc_trust_create(struct net_context *net_ctx, int argc,
365 struct cli_state *cli[2] = {NULL, NULL};
366 struct rpc_pipe_client *pipe_hnd[2] = {NULL, NULL};
367 struct policy_handle pol_hnd[2];
368 struct lsa_TrustDomainInfoAuthInfoInternal authinfo;
370 char *trust_pw = NULL;
371 struct other_dom_data *other_dom_data;
372 struct net_context *other_net_ctx = NULL;
373 struct dom_data dom_data[2];
375 if (net_ctx->display_usage) {
380 mem_ctx = talloc_init("trust create");
381 if (mem_ctx == NULL) {
382 DEBUG(0, ("talloc_init failed.\n"));
386 ret = parse_trust_args(mem_ctx, argc, argv, &other_dom_data, &trust_pw);
391 DEBUG(0, ("Failed to parse arguments.\n"));
396 if (other_dom_data->host != 0) {
397 other_net_ctx = talloc_zero(other_dom_data, struct net_context);
398 if (other_net_ctx == NULL) {
399 DEBUG(0, ("talloc_zero failed.\n"));
403 other_net_ctx->opt_host = other_dom_data->host;
404 other_net_ctx->opt_user_name = other_dom_data->user_name;
406 dom_data[1].domsid = dom_sid_parse_talloc(mem_ctx,
407 other_dom_data->domain_sid_str);
408 dom_data[1].domain_name = other_dom_data->domain_name;
409 dom_data[1].dns_domain_name = other_dom_data->dns_domain_name;
411 if (dom_data[1].domsid == NULL ||
412 dom_data[1].domain_name == NULL ||
413 dom_data[1].dns_domain_name == NULL) {
414 DEBUG(0, ("Missing required argument.\n"));
420 status = connect_and_get_info(mem_ctx, net_ctx, &cli[0], &pipe_hnd[0],
421 &pol_hnd[0], &dom_data[0]);
422 if (!NT_STATUS_IS_OK(status)) {
423 DEBUG(0, ("connect_and_get_info failed with error [%s]\n",
428 if (other_net_ctx != NULL) {
429 status = connect_and_get_info(mem_ctx, other_net_ctx,
430 &cli[1], &pipe_hnd[1],
431 &pol_hnd[1], &dom_data[1]);
432 if (!NT_STATUS_IS_OK(status)) {
433 DEBUG(0, ("connect_and_get_info failed with error [%s]\n",
439 if (trust_pw == NULL) {
440 if (other_net_ctx == NULL) {
441 DEBUG(0, ("Missing either trustpw or otherhost.\n"));
445 DEBUG(0, ("Using random trust password.\n"));
446 /* FIXME: why only 8 characters work? Would it be possible to use a random
447 * binary password? */
448 trust_pw = generate_random_str(mem_ctx, 8);
449 if (trust_pw == NULL) {
450 DEBUG(0, ("generate_random_str failed.\n"));
454 DEBUG(0, ("Using user provided password.\n"));
457 if (!get_trust_domain_passwords_auth_blob(mem_ctx, trust_pw,
459 DEBUG(0, ("get_trust_domain_passwords_auth_blob failed\n"));
463 authinfo.auth_blob.data = talloc_memdup(mem_ctx, auth_blob.data,
465 if (authinfo.auth_blob.data == NULL) {
468 authinfo.auth_blob.size = auth_blob.length;
470 arcfour_crypt_blob(authinfo.auth_blob.data, authinfo.auth_blob.size,
471 &cli[0]->user_session_key);
473 status = create_trust(mem_ctx, pipe_hnd[0]->binding_handle, &pol_hnd[0],
474 dom_data[1].domain_name,
475 dom_data[1].dns_domain_name, dom_data[1].domsid,
477 if (!NT_STATUS_IS_OK(status)) {
478 DEBUG(0, ("create_trust failed with error [%s].\n",
483 if (other_net_ctx != NULL) {
484 talloc_free(authinfo.auth_blob.data);
485 authinfo.auth_blob.data = talloc_memdup(mem_ctx, auth_blob.data,
487 if (authinfo.auth_blob.data == NULL) {
490 authinfo.auth_blob.size = auth_blob.length;
492 arcfour_crypt_blob(authinfo.auth_blob.data, authinfo.auth_blob.size,
493 &cli[1]->user_session_key);
495 status = create_trust(mem_ctx, pipe_hnd[1]->binding_handle,
496 &pol_hnd[1], dom_data[0].domain_name,
497 dom_data[0].dns_domain_name,
498 dom_data[0].domsid, &authinfo);
499 if (!NT_STATUS_IS_OK(status)) {
500 DEBUG(0, ("create_trust failed with error [%s].\n",
506 status = close_handle(mem_ctx, pipe_hnd[0]->binding_handle,
508 if (!NT_STATUS_IS_OK(status)) {
509 DEBUG(0, ("close_handle failed with error [%s].\n",
514 if (other_net_ctx != NULL) {
515 status = close_handle(mem_ctx, pipe_hnd[1]->binding_handle,
517 if (!NT_STATUS_IS_OK(status)) {
518 DEBUG(0, ("close_handle failed with error [%s].\n",
527 cli_shutdown(cli[0]);
528 cli_shutdown(cli[1]);
529 talloc_destroy(mem_ctx);
533 int net_rpc_trust(struct net_context *c, int argc, const char **argv)
535 struct functable func[] = {
541 N_("net rpc trust create\n"
544 {NULL, NULL, 0, NULL, NULL}
547 return net_run_function(c, argc, argv, "net rpc trust", func);