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"
28 #include "libsmb/libsmb.h"
31 #define ARG_OTHERSERVER "otherserver="
32 #define ARG_OTHERUSER "otheruser="
33 #define ARG_OTHERDOMAINSID "otherdomainsid="
34 #define ARG_OTHERDOMAIN "otherdomain="
35 #define ARG_OTHERNETBIOSDOMAIN "other_netbios_domain="
36 #define ARG_TRUSTPW "trustpw="
43 struct other_dom_data
{
47 char *dns_domain_name
;
52 struct dom_sid
*domsid
;
53 char *dns_domain_name
;
57 static NTSTATUS
close_handle(TALLOC_CTX
*mem_ctx
,
58 struct dcerpc_binding_handle
*bind_hnd
,
59 struct policy_handle
*pol_hnd
)
64 status
= dcerpc_lsa_Close(bind_hnd
, mem_ctx
, pol_hnd
, &result
);
65 if (!NT_STATUS_IS_OK(status
)) {
66 DEBUG(0, ("dcerpc_lsa_Close failed with error [%s].\n",
70 if (!NT_STATUS_IS_OK(result
)) {
71 DEBUG(0, ("lsa close failed with error [%s].\n",
79 static NTSTATUS
delete_trust(TALLOC_CTX
*mem_ctx
,
80 struct dcerpc_binding_handle
*bind_hnd
,
81 struct policy_handle
*pol_hnd
,
82 struct dom_sid
*domsid
)
85 struct lsa_DeleteTrustedDomain dr
;
87 dr
.in
.handle
= pol_hnd
;
88 dr
.in
.dom_sid
= domsid
;
90 status
= dcerpc_lsa_DeleteTrustedDomain_r(bind_hnd
, mem_ctx
, &dr
);
91 if (!NT_STATUS_IS_OK(status
)) {
92 DEBUG(0, ("dcerpc_lsa_DeleteTrustedDomain_r failed with [%s]\n",
96 if (!NT_STATUS_IS_OK(dr
.out
.result
)) {
97 DEBUG(0, ("DeleteTrustedDomain returned [%s]\n",
98 nt_errstr(dr
.out
.result
)));
105 static NTSTATUS
create_trust(TALLOC_CTX
*mem_ctx
,
106 struct dcerpc_binding_handle
*bind_hnd
,
107 struct policy_handle
*pol_hnd
,
108 const char *trust_name
,
109 const char *trust_name_dns
,
110 struct dom_sid
*domsid
,
111 struct lsa_TrustDomainInfoAuthInfoInternal
*authinfo
)
114 struct lsa_CreateTrustedDomainEx2 r
;
115 struct lsa_TrustDomainInfoInfoEx trustinfo
;
116 struct policy_handle trustdom_handle
;
118 trustinfo
.sid
= domsid
;
119 trustinfo
.netbios_name
.string
= trust_name
;
120 trustinfo
.domain_name
.string
= trust_name_dns
;
122 trustinfo
.trust_direction
= LSA_TRUST_DIRECTION_INBOUND
|
123 LSA_TRUST_DIRECTION_OUTBOUND
;
125 trustinfo
.trust_type
= LSA_TRUST_TYPE_UPLEVEL
;
127 trustinfo
.trust_attributes
= LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
;
129 r
.in
.policy_handle
= pol_hnd
;
130 r
.in
.info
= &trustinfo
;
131 r
.in
.auth_info
= authinfo
;
132 r
.in
.access_mask
= LSA_TRUSTED_SET_POSIX
| LSA_TRUSTED_SET_AUTH
|
133 LSA_TRUSTED_QUERY_DOMAIN_NAME
;
134 r
.out
.trustdom_handle
= &trustdom_handle
;
136 status
= dcerpc_lsa_CreateTrustedDomainEx2_r(bind_hnd
, mem_ctx
, &r
);
137 if (!NT_STATUS_IS_OK(status
)) {
138 DEBUG(0, ("dcerpc_lsa_CreateTrustedDomainEx2_r failed "
139 "with error [%s].\n", nt_errstr(status
)));
142 if (!NT_STATUS_IS_OK(r
.out
.result
)) {
143 DEBUG(0, ("CreateTrustedDomainEx2_r returned [%s].\n",
144 nt_errstr(r
.out
.result
)));
151 static NTSTATUS
get_domain_info(TALLOC_CTX
*mem_ctx
,
152 struct dcerpc_binding_handle
*bind_hdn
,
153 struct policy_handle
*pol_hnd
,
154 struct dom_data
*dom_data
)
157 struct lsa_QueryInfoPolicy2 qr
;
159 qr
.in
.handle
= pol_hnd
;
160 qr
.in
.level
= LSA_POLICY_INFO_DNS
;
162 status
= dcerpc_lsa_QueryInfoPolicy2_r(bind_hdn
, mem_ctx
, &qr
);
163 if (!NT_STATUS_IS_OK(status
)) {
164 DEBUG(0, ("dcerpc_lsa_QueryInfoPolicy2_r failed "
165 "with error [%s].\n", nt_errstr(status
)));
169 if (!NT_STATUS_IS_OK(qr
.out
.result
)) {
170 DEBUG(0, ("QueryInfoPolicy2 returned [%s].\n",
171 nt_errstr(qr
.out
.result
)));
172 return qr
.out
.result
;
175 dom_data
->domain_name
= talloc_strdup(mem_ctx
,
176 (*qr
.out
.info
)->dns
.name
.string
);
177 dom_data
->dns_domain_name
= talloc_strdup(mem_ctx
,
178 (*qr
.out
.info
)->dns
.dns_domain
.string
);
179 dom_data
->domsid
= dom_sid_dup(mem_ctx
, (*qr
.out
.info
)->dns
.sid
);
180 if (dom_data
->domain_name
== NULL
||
181 dom_data
->dns_domain_name
== NULL
||
182 dom_data
->domsid
== NULL
) {
183 DEBUG(0, ("Copying domain data failed.\n"));
184 return NT_STATUS_NO_MEMORY
;
187 DEBUG(0, ("Got the following domain info [%s][%s][%s].\n",
188 dom_data
->domain_name
, dom_data
->dns_domain_name
,
189 sid_string_talloc(mem_ctx
, dom_data
->domsid
)));
194 static NTSTATUS
connect_and_get_info(TALLOC_CTX
*mem_ctx
,
195 struct net_context
*net_ctx
,
196 struct cli_state
**cli
,
197 struct rpc_pipe_client
**pipe_hnd
,
198 struct policy_handle
*pol_hnd
,
199 struct dom_data
*dom_data
)
204 status
= net_make_ipc_connection_ex(net_ctx
, NULL
, NULL
, NULL
,
206 if (!NT_STATUS_IS_OK(status
)) {
207 DEBUG(0, ("Failed to connect to [%s] with error [%s]\n",
208 net_ctx
->opt_host
, nt_errstr(status
)));
212 status
= cli_rpc_pipe_open_noauth(*cli
, &ndr_table_lsarpc
.syntax_id
, pipe_hnd
);
213 if (!NT_STATUS_IS_OK(status
)) {
214 DEBUG(0, ("Failed to initialise lsa pipe with error [%s]\n",
219 status
= dcerpc_lsa_open_policy2((*pipe_hnd
)->binding_handle
,
221 (*pipe_hnd
)->srv_name_slash
,
223 (LSA_POLICY_VIEW_LOCAL_INFORMATION
|
224 LSA_POLICY_TRUST_ADMIN
|
225 LSA_POLICY_CREATE_SECRET
),
228 if (!NT_STATUS_IS_OK(status
)) {
229 DEBUG(0, ("Failed to open policy handle with error [%s]\n",
233 if (!NT_STATUS_IS_OK(result
)) {
234 DEBUG(0, ("lsa_open_policy2 with error [%s]\n",
239 status
= get_domain_info(mem_ctx
, (*pipe_hnd
)->binding_handle
,
241 if (!NT_STATUS_IS_OK(status
)) {
242 DEBUG(0, ("get_domain_info failed with error [%s].\n",
250 static bool get_trust_domain_passwords_auth_blob(TALLOC_CTX
*mem_ctx
,
251 const char *password
,
252 DATA_BLOB
*auth_blob
)
254 struct trustDomainPasswords auth_struct
;
255 struct AuthenticationInformation
*auth_info_array
;
256 enum ndr_err_code ndr_err
;
257 size_t converted_size
;
259 generate_random_buffer(auth_struct
.confounder
,
260 sizeof(auth_struct
.confounder
));
262 auth_info_array
= talloc_array(mem_ctx
,
263 struct AuthenticationInformation
, 1);
264 if (auth_info_array
== NULL
) {
268 auth_info_array
[0].AuthType
= TRUST_AUTH_TYPE_CLEAR
;
269 if (!convert_string_talloc(mem_ctx
, CH_UNIX
, CH_UTF16
, password
,
271 &auth_info_array
[0].AuthInfo
.clear
.password
,
272 &converted_size
, true)) {
276 auth_info_array
[0].AuthInfo
.clear
.size
= converted_size
;
278 auth_struct
.outgoing
.count
= 1;
279 auth_struct
.outgoing
.current
.count
= 1;
280 auth_struct
.outgoing
.current
.array
= auth_info_array
;
281 auth_struct
.outgoing
.previous
.count
= 0;
282 auth_struct
.outgoing
.previous
.array
= NULL
;
284 auth_struct
.incoming
.count
= 1;
285 auth_struct
.incoming
.current
.count
= 1;
286 auth_struct
.incoming
.current
.array
= auth_info_array
;
287 auth_struct
.incoming
.previous
.count
= 0;
288 auth_struct
.incoming
.previous
.array
= NULL
;
290 ndr_err
= ndr_push_struct_blob(auth_blob
, mem_ctx
, &auth_struct
,
291 (ndr_push_flags_fn_t
)ndr_push_trustDomainPasswords
);
292 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
299 static int parse_trust_args(TALLOC_CTX
*mem_ctx
, int argc
, const char **argv
, struct other_dom_data
**_o
, char **_trustpw
)
302 struct other_dom_data
*o
= NULL
;
303 char *trustpw
= NULL
;
310 o
= talloc_zero(mem_ctx
, struct other_dom_data
);
312 DEBUG(0, ("talloc_zero failed.\n"));
316 for (c
= 0; c
< argc
; c
++) {
317 if (strnequal(argv
[c
], ARG_OTHERSERVER
, sizeof(ARG_OTHERSERVER
)-1)) {
318 o
->host
= talloc_strdup(o
, argv
[c
] + sizeof(ARG_OTHERSERVER
)-1);
319 if (o
->host
== NULL
) {
323 } else if (strnequal(argv
[c
], ARG_OTHERUSER
, sizeof(ARG_OTHERUSER
)-1)) {
324 o
->user_name
= talloc_strdup(o
, argv
[c
] + sizeof(ARG_OTHERUSER
)-1);
325 if (o
->user_name
== NULL
) {
329 } else if (strnequal(argv
[c
], ARG_OTHERDOMAINSID
, sizeof(ARG_OTHERDOMAINSID
)-1)) {
330 o
->domain_sid_str
= talloc_strdup(o
, argv
[c
] + sizeof(ARG_OTHERDOMAINSID
)-1);
331 if (o
->domain_sid_str
== NULL
) {
335 } else if (strnequal(argv
[c
], ARG_OTHERDOMAIN
, sizeof(ARG_OTHERDOMAIN
)-1)) {
336 o
->dns_domain_name
= talloc_strdup(o
, argv
[c
] + sizeof(ARG_OTHERDOMAIN
)-1);
337 if (o
->dns_domain_name
== NULL
) {
341 } else if (strnequal(argv
[c
], ARG_OTHERNETBIOSDOMAIN
, sizeof(ARG_OTHERNETBIOSDOMAIN
)-1)) {
342 o
->domain_name
= talloc_strdup(o
, argv
[c
] + sizeof(ARG_OTHERNETBIOSDOMAIN
)-1);
343 if (o
->domain_name
== NULL
) {
347 } else if (strnequal(argv
[c
], ARG_TRUSTPW
, sizeof(ARG_TRUSTPW
)-1)) {
348 trustpw
= talloc_strdup(mem_ctx
, argv
[c
] + sizeof(ARG_TRUSTPW
)-1);
349 if (trustpw
== NULL
) {
354 DEBUG(0, ("Unsupported option [%s].\n", argv
[c
]));
367 talloc_free(trustpw
);
371 static void print_trust_delete_usage(void)
374 "net rpc trust delete [options]\n"
376 "\totherserver=DC in other domain\n"
377 "\totheruser=Admin user in other domain\n"
378 "\totherdomainsid=SID of other domain\n"
380 "\tnet rpc trust delete otherserver=oname otheruser=ouser -S lname -U luser\n"
381 "\tnet rpc trust delete otherdomainsid=S-... -S lname -U luser\n"
384 _("Remove trust between two domains"));
387 static void print_trust_usage(void)
390 "net rpc trust create [options]\n"
392 "\totherserver=DC in other domain\n"
393 "\totheruser=Admin user in other domain\n"
394 "\totherdomainsid=SID of other domain\n"
395 "\tother_netbios_domain=NetBIOS/short name of other domain\n"
396 "\totherdomain=Full/DNS name of other domain\n"
397 "\ttrustpw=Trust password\n"
399 "\tnet rpc trust create otherserver=oname otheruser=ouser -S lname -U luser\n"
400 "\tnet rpc trust create otherdomainsid=S-... other_netbios_domain=odom otherdomain=odom.org trustpw=secret -S lname -U luser\n"
403 _("Create trust between two domains"));
406 static int rpc_trust_common(struct net_context
*net_ctx
, int argc
,
407 const char **argv
, enum trust_op op
)
413 struct cli_state
*cli
[2] = {NULL
, NULL
};
414 struct rpc_pipe_client
*pipe_hnd
[2] = {NULL
, NULL
};
415 struct policy_handle pol_hnd
[2];
416 struct lsa_TrustDomainInfoAuthInfoInternal authinfo
;
418 char *trust_pw
= NULL
;
419 struct other_dom_data
*other_dom_data
;
420 struct net_context
*other_net_ctx
= NULL
;
421 struct dom_data dom_data
[2];
426 usage
= print_trust_usage
;
429 usage
= print_trust_delete_usage
;
432 DEBUG(0, ("Unsupported trust operation.\n"));
436 if (net_ctx
->display_usage
) {
441 mem_ctx
= talloc_init("trust op");
442 if (mem_ctx
== NULL
) {
443 DEBUG(0, ("talloc_init failed.\n"));
447 ret
= parse_trust_args(mem_ctx
, argc
, argv
, &other_dom_data
, &trust_pw
);
452 DEBUG(0, ("Failed to parse arguments.\n"));
457 if (other_dom_data
->host
!= 0) {
458 other_net_ctx
= talloc_zero(other_dom_data
, struct net_context
);
459 if (other_net_ctx
== NULL
) {
460 DEBUG(0, ("talloc_zero failed.\n"));
464 other_net_ctx
->opt_host
= other_dom_data
->host
;
465 other_net_ctx
->opt_user_name
= other_dom_data
->user_name
;
467 dom_data
[1].domsid
= dom_sid_parse_talloc(mem_ctx
,
468 other_dom_data
->domain_sid_str
);
469 dom_data
[1].domain_name
= other_dom_data
->domain_name
;
470 dom_data
[1].dns_domain_name
= other_dom_data
->dns_domain_name
;
472 if (dom_data
[1].domsid
== NULL
||
473 (op
== TRUST_CREATE
&&
474 (dom_data
[1].domain_name
== NULL
||
475 dom_data
[1].dns_domain_name
== NULL
))) {
476 DEBUG(0, ("Missing required argument.\n"));
482 status
= connect_and_get_info(mem_ctx
, net_ctx
, &cli
[0], &pipe_hnd
[0],
483 &pol_hnd
[0], &dom_data
[0]);
484 if (!NT_STATUS_IS_OK(status
)) {
485 DEBUG(0, ("connect_and_get_info failed with error [%s]\n",
490 if (other_net_ctx
!= NULL
) {
491 status
= connect_and_get_info(mem_ctx
, other_net_ctx
,
492 &cli
[1], &pipe_hnd
[1],
493 &pol_hnd
[1], &dom_data
[1]);
494 if (!NT_STATUS_IS_OK(status
)) {
495 DEBUG(0, ("connect_and_get_info failed with error [%s]\n",
501 if (op
== TRUST_CREATE
) {
502 if (trust_pw
== NULL
) {
503 if (other_net_ctx
== NULL
) {
504 DEBUG(0, ("Missing either trustpw or otherhost.\n"));
508 DEBUG(0, ("Using random trust password.\n"));
509 /* FIXME: why only 8 characters work? Would it be possible to use a
510 * random binary password? */
511 trust_pw
= generate_random_str(mem_ctx
, 8);
512 if (trust_pw
== NULL
) {
513 DEBUG(0, ("generate_random_str failed.\n"));
517 DEBUG(0, ("Using user provided password.\n"));
520 if (!get_trust_domain_passwords_auth_blob(mem_ctx
, trust_pw
,
522 DEBUG(0, ("get_trust_domain_passwords_auth_blob failed\n"));
526 authinfo
.auth_blob
.data
= (uint8_t *)talloc_memdup(
530 if (authinfo
.auth_blob
.data
== NULL
) {
533 authinfo
.auth_blob
.size
= auth_blob
.length
;
535 arcfour_crypt_blob(authinfo
.auth_blob
.data
,
536 authinfo
.auth_blob
.size
,
537 &cli
[0]->user_session_key
);
539 status
= create_trust(mem_ctx
, pipe_hnd
[0]->binding_handle
,
541 dom_data
[1].domain_name
,
542 dom_data
[1].dns_domain_name
,
545 if (!NT_STATUS_IS_OK(status
)) {
546 DEBUG(0, ("create_trust failed with error [%s].\n",
551 if (other_net_ctx
!= NULL
) {
552 talloc_free(authinfo
.auth_blob
.data
);
553 authinfo
.auth_blob
.data
= (uint8_t *)talloc_memdup(
557 if (authinfo
.auth_blob
.data
== NULL
) {
560 authinfo
.auth_blob
.size
= auth_blob
.length
;
562 arcfour_crypt_blob(authinfo
.auth_blob
.data
,
563 authinfo
.auth_blob
.size
,
564 &cli
[1]->user_session_key
);
566 status
= create_trust(mem_ctx
,
567 pipe_hnd
[1]->binding_handle
,
569 dom_data
[0].domain_name
,
570 dom_data
[0].dns_domain_name
,
571 dom_data
[0].domsid
, &authinfo
);
572 if (!NT_STATUS_IS_OK(status
)) {
573 DEBUG(0, ("create_trust failed with error [%s].\n",
578 } else if (op
== TRUST_DELETE
) {
579 status
= delete_trust(mem_ctx
, pipe_hnd
[0]->binding_handle
,
580 &pol_hnd
[0], dom_data
[1].domsid
);
581 if (!NT_STATUS_IS_OK(status
)) {
582 DEBUG(0, ("delete_trust failed with [%s].\n",
587 if (other_net_ctx
!= NULL
) {
588 status
= delete_trust(mem_ctx
,
589 pipe_hnd
[1]->binding_handle
,
590 &pol_hnd
[1], dom_data
[0].domsid
);
591 if (!NT_STATUS_IS_OK(status
)) {
592 DEBUG(0, ("delete_trust failed with [%s].\n",
599 status
= close_handle(mem_ctx
, pipe_hnd
[0]->binding_handle
,
601 if (!NT_STATUS_IS_OK(status
)) {
602 DEBUG(0, ("close_handle failed with error [%s].\n",
607 if (other_net_ctx
!= NULL
) {
608 status
= close_handle(mem_ctx
, pipe_hnd
[1]->binding_handle
,
610 if (!NT_STATUS_IS_OK(status
)) {
611 DEBUG(0, ("close_handle failed with error [%s].\n",
620 cli_shutdown(cli
[0]);
621 cli_shutdown(cli
[1]);
622 talloc_destroy(mem_ctx
);
626 static int rpc_trust_create(struct net_context
*net_ctx
, int argc
,
629 return rpc_trust_common(net_ctx
, argc
, argv
, TRUST_CREATE
);
632 static int rpc_trust_delete(struct net_context
*net_ctx
, int argc
,
635 return rpc_trust_common(net_ctx
, argc
, argv
, TRUST_DELETE
);
638 int net_rpc_trust(struct net_context
*c
, int argc
, const char **argv
)
640 struct functable func
[] = {
646 N_("net rpc trust create\n"
654 N_("net rpc trust delete\n"
657 {NULL
, NULL
, 0, NULL
, NULL
}
660 return net_run_function(c
, argc
, argv
, "net rpc trust", func
);