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 "../libcli/security/dom_sid.h"
27 #include "libsmb/libsmb.h"
29 #include "lib/crypto/gnutls_helpers.h"
30 #include <gnutls/gnutls.h>
31 #include <gnutls/crypto.h>
33 #define ARG_OTHERSERVER "otherserver="
34 #define ARG_OTHERUSER "otheruser="
35 #define ARG_OTHERDOMAINSID "otherdomainsid="
36 #define ARG_OTHERDOMAIN "otherdomain="
37 #define ARG_OTHERNETBIOSDOMAIN "other_netbios_domain="
38 #define ARG_TRUSTPW "trustpw="
45 struct other_dom_data
{
49 char *dns_domain_name
;
54 struct dom_sid
*domsid
;
55 char *dns_domain_name
;
59 static NTSTATUS
close_handle(TALLOC_CTX
*mem_ctx
,
60 struct dcerpc_binding_handle
*bind_hnd
,
61 struct policy_handle
*pol_hnd
)
66 status
= dcerpc_lsa_Close(bind_hnd
, mem_ctx
, pol_hnd
, &result
);
67 if (!NT_STATUS_IS_OK(status
)) {
68 DEBUG(0, ("dcerpc_lsa_Close failed with error [%s].\n",
72 if (!NT_STATUS_IS_OK(result
)) {
73 DEBUG(0, ("lsa close failed with error [%s].\n",
81 static NTSTATUS
delete_trust(TALLOC_CTX
*mem_ctx
,
82 struct dcerpc_binding_handle
*bind_hnd
,
83 struct policy_handle
*pol_hnd
,
84 struct dom_sid
*domsid
)
87 struct lsa_DeleteTrustedDomain dr
;
89 dr
.in
.handle
= pol_hnd
;
90 dr
.in
.dom_sid
= domsid
;
92 status
= dcerpc_lsa_DeleteTrustedDomain_r(bind_hnd
, mem_ctx
, &dr
);
93 if (!NT_STATUS_IS_OK(status
)) {
94 DEBUG(0, ("dcerpc_lsa_DeleteTrustedDomain_r failed with [%s]\n",
98 if (!NT_STATUS_IS_OK(dr
.out
.result
)) {
99 DEBUG(0, ("DeleteTrustedDomain returned [%s]\n",
100 nt_errstr(dr
.out
.result
)));
101 return dr
.out
.result
;
107 static NTSTATUS
create_trust(TALLOC_CTX
*mem_ctx
,
108 struct dcerpc_binding_handle
*bind_hnd
,
109 struct policy_handle
*pol_hnd
,
110 const char *trust_name
,
111 const char *trust_name_dns
,
112 struct dom_sid
*domsid
,
113 struct lsa_TrustDomainInfoAuthInfoInternal
*authinfo
)
116 struct lsa_CreateTrustedDomainEx2 r
;
117 struct lsa_TrustDomainInfoInfoEx trustinfo
;
118 struct policy_handle trustdom_handle
;
119 bool is_nt4
= trust_name_dns
== NULL
;
122 fprintf(stdout
, "Creating AD trust\n");
123 trustinfo
.trust_type
= LSA_TRUST_TYPE_UPLEVEL
;
124 trustinfo
.trust_attributes
= LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
;
126 fprintf(stdout
, "Creating NT4 trust\n");
127 trustinfo
.trust_type
= LSA_TRUST_TYPE_DOWNLEVEL
;
128 trustinfo
.trust_attributes
= 0;
129 trust_name_dns
= trust_name
;
132 trustinfo
.sid
= domsid
;
133 trustinfo
.netbios_name
.string
= trust_name
;
134 trustinfo
.domain_name
.string
= trust_name_dns
;
136 trustinfo
.trust_direction
= LSA_TRUST_DIRECTION_INBOUND
|
137 LSA_TRUST_DIRECTION_OUTBOUND
;
139 r
.in
.policy_handle
= pol_hnd
;
140 r
.in
.info
= &trustinfo
;
141 r
.in
.auth_info_internal
= authinfo
;
142 r
.in
.access_mask
= LSA_TRUSTED_SET_POSIX
| LSA_TRUSTED_SET_AUTH
|
143 LSA_TRUSTED_QUERY_DOMAIN_NAME
;
144 r
.out
.trustdom_handle
= &trustdom_handle
;
146 status
= dcerpc_lsa_CreateTrustedDomainEx2_r(bind_hnd
, mem_ctx
, &r
);
147 if (!NT_STATUS_IS_OK(status
)) {
148 DEBUG(0, ("dcerpc_lsa_CreateTrustedDomainEx2_r failed "
149 "with error [%s].\n", nt_errstr(status
)));
152 if (!NT_STATUS_IS_OK(r
.out
.result
)) {
153 DEBUG(0, ("CreateTrustedDomainEx2_r returned [%s].\n",
154 nt_errstr(r
.out
.result
)));
161 static NTSTATUS
get_domain_info(TALLOC_CTX
*mem_ctx
,
162 struct dcerpc_binding_handle
*bind_hdn
,
163 struct policy_handle
*pol_hnd
,
164 struct dom_data
*dom_data
)
167 struct lsa_QueryInfoPolicy2 qr
;
168 struct dom_sid_buf buf
;
170 qr
.in
.handle
= pol_hnd
;
171 qr
.in
.level
= LSA_POLICY_INFO_DNS
;
173 status
= dcerpc_lsa_QueryInfoPolicy2_r(bind_hdn
, mem_ctx
, &qr
);
174 if (!NT_STATUS_IS_OK(status
)) {
175 DEBUG(0, ("dcerpc_lsa_QueryInfoPolicy2_r failed "
176 "with error [%s].\n", nt_errstr(status
)));
180 if (!NT_STATUS_IS_OK(qr
.out
.result
)) {
181 DEBUG(0, ("QueryInfoPolicy2 returned [%s].\n",
182 nt_errstr(qr
.out
.result
)));
183 return qr
.out
.result
;
186 dom_data
->domain_name
= talloc_strdup(mem_ctx
,
187 (*qr
.out
.info
)->dns
.name
.string
);
188 dom_data
->dns_domain_name
= talloc_strdup(mem_ctx
,
189 (*qr
.out
.info
)->dns
.dns_domain
.string
);
190 dom_data
->domsid
= dom_sid_dup(mem_ctx
, (*qr
.out
.info
)->dns
.sid
);
191 if (dom_data
->domain_name
== NULL
||
192 dom_data
->dns_domain_name
== NULL
||
193 dom_data
->domsid
== NULL
) {
194 DEBUG(0, ("Copying domain data failed.\n"));
195 return NT_STATUS_NO_MEMORY
;
198 DEBUG(0, ("Got the following domain info [%s][%s][%s].\n",
199 dom_data
->domain_name
, dom_data
->dns_domain_name
,
200 dom_sid_str_buf(dom_data
->domsid
, &buf
)));
205 static NTSTATUS
connect_and_get_info(TALLOC_CTX
*mem_ctx
,
206 struct net_context
*net_ctx
,
207 struct cli_state
**cli
,
208 struct rpc_pipe_client
**pipe_hnd
,
209 struct policy_handle
*pol_hnd
,
210 struct dom_data
*dom_data
,
211 DATA_BLOB
*session_key
)
214 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
215 uint32_t out_version
= 0;
216 union lsa_revision_info out_revision_info
= {
222 status
= net_make_ipc_connection_ex(net_ctx
, NULL
, NULL
, NULL
,
224 if (!NT_STATUS_IS_OK(status
)) {
225 DEBUG(0, ("Failed to connect to [%s] with error [%s]\n",
226 net_ctx
->opt_host
, nt_errstr(status
)));
230 status
= cli_rpc_pipe_open_noauth(*cli
, &ndr_table_lsarpc
, pipe_hnd
);
231 if (!NT_STATUS_IS_OK(status
)) {
232 DEBUG(0, ("Failed to initialise lsa pipe with error [%s]\n",
237 status
= dcerpc_lsa_open_policy_fallback(
238 (*pipe_hnd
)->binding_handle
,
240 (*pipe_hnd
)->srv_name_slash
,
242 LSA_POLICY_VIEW_LOCAL_INFORMATION
|
243 LSA_POLICY_TRUST_ADMIN
|
244 LSA_POLICY_CREATE_SECRET
,
249 if (any_nt_status_not_ok(status
, result
, &status
)) {
250 DBG_ERR("Failed to open policy handle: %s\n",
255 status
= get_domain_info(mem_ctx
, (*pipe_hnd
)->binding_handle
,
257 if (!NT_STATUS_IS_OK(status
)) {
258 DEBUG(0, ("get_domain_info failed with error [%s].\n",
263 status
= dcerpc_binding_handle_transport_session_key(
264 (*pipe_hnd
)->binding_handle
, mem_ctx
, session_key
);
265 if (!NT_STATUS_IS_OK(status
)) {
266 DEBUG(0,("Error getting session_key of LSA pipe. Error was %s\n",
274 static bool get_trust_domain_passwords_auth_blob(TALLOC_CTX
*mem_ctx
,
275 const char *password
,
276 DATA_BLOB
*auth_blob
)
278 struct trustDomainPasswords auth_struct
;
279 struct AuthenticationInformation
*auth_info_array
;
280 enum ndr_err_code ndr_err
;
281 size_t converted_size
;
283 generate_random_buffer(auth_struct
.confounder
,
284 sizeof(auth_struct
.confounder
));
286 auth_info_array
= talloc_array(mem_ctx
,
287 struct AuthenticationInformation
, 1);
288 if (auth_info_array
== NULL
) {
292 auth_info_array
[0].AuthType
= TRUST_AUTH_TYPE_CLEAR
;
293 if (!convert_string_talloc(mem_ctx
, CH_UNIX
, CH_UTF16
, password
,
295 &auth_info_array
[0].AuthInfo
.clear
.password
,
300 auth_info_array
[0].AuthInfo
.clear
.size
= converted_size
;
302 auth_struct
.outgoing
.count
= 1;
303 auth_struct
.outgoing
.current
.count
= 1;
304 auth_struct
.outgoing
.current
.array
= auth_info_array
;
305 auth_struct
.outgoing
.previous
.count
= 0;
306 auth_struct
.outgoing
.previous
.array
= NULL
;
308 auth_struct
.incoming
.count
= 1;
309 auth_struct
.incoming
.current
.count
= 1;
310 auth_struct
.incoming
.current
.array
= auth_info_array
;
311 auth_struct
.incoming
.previous
.count
= 0;
312 auth_struct
.incoming
.previous
.array
= NULL
;
314 ndr_err
= ndr_push_struct_blob(auth_blob
, mem_ctx
, &auth_struct
,
315 (ndr_push_flags_fn_t
)ndr_push_trustDomainPasswords
);
316 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
323 static int parse_trust_args(TALLOC_CTX
*mem_ctx
, int argc
, const char **argv
, struct other_dom_data
**_o
, char **_trustpw
)
326 struct other_dom_data
*o
= NULL
;
327 char *trustpw
= NULL
;
334 o
= talloc_zero(mem_ctx
, struct other_dom_data
);
336 DEBUG(0, ("talloc_zero failed.\n"));
340 for (c
= 0; c
< argc
; c
++) {
341 if (strnequal(argv
[c
], ARG_OTHERSERVER
, sizeof(ARG_OTHERSERVER
)-1)) {
342 o
->host
= talloc_strdup(o
, argv
[c
] + sizeof(ARG_OTHERSERVER
)-1);
343 if (o
->host
== NULL
) {
347 } else if (strnequal(argv
[c
], ARG_OTHERUSER
, sizeof(ARG_OTHERUSER
)-1)) {
348 o
->user_name
= talloc_strdup(o
, argv
[c
] + sizeof(ARG_OTHERUSER
)-1);
349 if (o
->user_name
== NULL
) {
353 } else if (strnequal(argv
[c
], ARG_OTHERDOMAINSID
, sizeof(ARG_OTHERDOMAINSID
)-1)) {
354 o
->domain_sid_str
= talloc_strdup(o
, argv
[c
] + sizeof(ARG_OTHERDOMAINSID
)-1);
355 if (o
->domain_sid_str
== NULL
) {
359 } else if (strnequal(argv
[c
], ARG_OTHERDOMAIN
, sizeof(ARG_OTHERDOMAIN
)-1)) {
360 o
->dns_domain_name
= talloc_strdup(o
, argv
[c
] + sizeof(ARG_OTHERDOMAIN
)-1);
361 if (o
->dns_domain_name
== NULL
) {
365 } else if (strnequal(argv
[c
], ARG_OTHERNETBIOSDOMAIN
, sizeof(ARG_OTHERNETBIOSDOMAIN
)-1)) {
366 o
->domain_name
= talloc_strdup(o
, argv
[c
] + sizeof(ARG_OTHERNETBIOSDOMAIN
)-1);
367 if (o
->domain_name
== NULL
) {
371 } else if (strnequal(argv
[c
], ARG_TRUSTPW
, sizeof(ARG_TRUSTPW
)-1)) {
372 trustpw
= talloc_strdup(mem_ctx
, argv
[c
] + sizeof(ARG_TRUSTPW
)-1);
373 if (trustpw
== NULL
) {
378 DEBUG(0, ("Unsupported option [%s].\n", argv
[c
]));
391 talloc_free(trustpw
);
395 static void print_trust_delete_usage(void)
398 "net rpc trust delete [options]\n"
400 "\totherserver=DC in other domain\n"
401 "\totheruser=Admin user in other domain\n"
402 "\totherdomainsid=SID of other domain\n"
404 "\tnet rpc trust delete otherserver=oname otheruser=ouser -S lname -U luser\n"
405 "\tnet rpc trust delete otherdomainsid=S-... -S lname -U luser\n"
408 _("Remove trust between two domains"));
411 static void print_trust_usage(void)
414 "net rpc trust create [options]\n"
416 "\totherserver=DC in other domain\n"
417 "\totheruser=Admin user in other domain\n"
418 "\totherdomainsid=SID of other domain\n"
419 "\tother_netbios_domain=NetBIOS/short name of other domain\n"
420 "\totherdomain=Full/DNS name of other domain (if not used, create an NT4 trust)\n"
421 "\ttrustpw=Trust password\n"
423 "\tnet rpc trust create otherserver=oname otheruser=ouser -S lname -U luser\n"
424 "\tnet rpc trust create otherdomainsid=S-... other_netbios_domain=odom otherdomain=odom.org trustpw=secret -S lname -U luser\n"
427 _("Create trust between two domains"));
430 static int rpc_trust_common(struct net_context
*net_ctx
, int argc
,
431 const char **argv
, enum trust_op op
)
437 struct cli_state
*cli
[2] = {NULL
, NULL
};
438 struct rpc_pipe_client
*pipe_hnd
[2] = {NULL
, NULL
};
439 DATA_BLOB session_key
[2];
440 struct policy_handle pol_hnd
[2];
441 struct lsa_TrustDomainInfoAuthInfoInternal authinfo
;
443 char *trust_pw
= NULL
;
444 struct other_dom_data
*other_dom_data
;
445 struct net_context
*other_net_ctx
= NULL
;
446 struct dom_data dom_data
[2];
449 ZERO_STRUCT(session_key
);
453 usage
= print_trust_usage
;
456 usage
= print_trust_delete_usage
;
459 DEBUG(0, ("Unsupported trust operation.\n"));
463 if (net_ctx
->display_usage
) {
468 mem_ctx
= talloc_init("trust op");
469 if (mem_ctx
== NULL
) {
470 DEBUG(0, ("talloc_init failed.\n"));
474 ret
= parse_trust_args(mem_ctx
, argc
, argv
, &other_dom_data
, &trust_pw
);
479 DEBUG(0, ("Failed to parse arguments.\n"));
484 if (other_dom_data
->host
!= 0) {
485 other_net_ctx
= talloc_zero(other_dom_data
, struct net_context
);
486 if (other_net_ctx
== NULL
) {
487 DEBUG(0, ("talloc_zero failed.\n"));
491 other_net_ctx
->opt_host
= other_dom_data
->host
;
492 other_net_ctx
->creds
= cli_credentials_init(other_net_ctx
);
493 cli_credentials_parse_string(other_net_ctx
->creds
,
494 other_dom_data
->user_name
,
497 dom_data
[1].domsid
= dom_sid_parse_talloc(mem_ctx
,
498 other_dom_data
->domain_sid_str
);
499 dom_data
[1].domain_name
= other_dom_data
->domain_name
;
500 dom_data
[1].dns_domain_name
= other_dom_data
->dns_domain_name
;
502 if (dom_data
[1].dns_domain_name
== NULL
) {
503 fprintf(stdout
, "No DNS domain name passed, "
504 "assuming NT4 trust!\n");
507 if (dom_data
[1].domsid
== NULL
||
508 (op
== TRUST_CREATE
&&
509 (dom_data
[1].domain_name
== NULL
))) {
510 DEBUG(0, ("Missing required argument.\n"));
516 status
= connect_and_get_info(mem_ctx
, net_ctx
, &cli
[0], &pipe_hnd
[0],
517 &pol_hnd
[0], &dom_data
[0], &session_key
[0]);
518 if (!NT_STATUS_IS_OK(status
)) {
519 DEBUG(0, ("connect_and_get_info failed with error [%s]\n",
524 if (other_net_ctx
!= NULL
) {
525 status
= connect_and_get_info(mem_ctx
, other_net_ctx
,
526 &cli
[1], &pipe_hnd
[1],
527 &pol_hnd
[1], &dom_data
[1],
529 if (!NT_STATUS_IS_OK(status
)) {
530 DEBUG(0, ("connect_and_get_info failed with error [%s]\n",
536 if (op
== TRUST_CREATE
) {
537 gnutls_cipher_hd_t cipher_hnd
= NULL
;
538 gnutls_datum_t enc_session_key
= {
539 .data
= session_key
[0].data
,
540 .size
= session_key
[0].length
,
544 if (trust_pw
== NULL
) {
545 if (other_net_ctx
== NULL
) {
546 DEBUG(0, ("Missing either trustpw or otherhost.\n"));
550 DEBUG(0, ("Using random trust password.\n"));
551 trust_pw
= trust_pw_new_value(mem_ctx
,
554 if (trust_pw
== NULL
) {
555 DEBUG(0, ("generate_random_password failed.\n"));
559 DEBUG(0, ("Using user provided password.\n"));
562 if (!get_trust_domain_passwords_auth_blob(mem_ctx
, trust_pw
,
564 DEBUG(0, ("get_trust_domain_passwords_auth_blob failed\n"));
568 authinfo
.auth_blob
.data
= (uint8_t *)talloc_memdup(
572 if (authinfo
.auth_blob
.data
== NULL
) {
575 authinfo
.auth_blob
.size
= auth_blob
.length
;
577 rc
= gnutls_cipher_init(&cipher_hnd
,
578 GNUTLS_CIPHER_ARCFOUR_128
,
582 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
585 rc
= gnutls_cipher_encrypt(cipher_hnd
,
586 authinfo
.auth_blob
.data
,
587 authinfo
.auth_blob
.size
);
588 gnutls_cipher_deinit(cipher_hnd
);
590 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
594 status
= create_trust(mem_ctx
, pipe_hnd
[0]->binding_handle
,
596 dom_data
[1].domain_name
,
597 dom_data
[1].dns_domain_name
,
600 if (!NT_STATUS_IS_OK(status
)) {
601 DEBUG(0, ("create_trust failed with error [%s].\n",
606 if (other_net_ctx
!= NULL
) {
607 talloc_free(authinfo
.auth_blob
.data
);
608 authinfo
.auth_blob
.data
= (uint8_t *)talloc_memdup(
612 if (authinfo
.auth_blob
.data
== NULL
) {
615 authinfo
.auth_blob
.size
= auth_blob
.length
;
617 enc_session_key
= (gnutls_datum_t
) {
618 .data
= session_key
[1].data
,
619 .size
= session_key
[1].length
,
622 rc
= gnutls_cipher_init(&cipher_hnd
,
623 GNUTLS_CIPHER_ARCFOUR_128
,
627 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
630 rc
= gnutls_cipher_encrypt(cipher_hnd
,
631 authinfo
.auth_blob
.data
,
632 authinfo
.auth_blob
.size
);
633 gnutls_cipher_deinit(cipher_hnd
);
635 status
= gnutls_error_to_ntstatus(rc
, NT_STATUS_CRYPTO_SYSTEM_INVALID
);
639 status
= create_trust(mem_ctx
,
640 pipe_hnd
[1]->binding_handle
,
642 dom_data
[0].domain_name
,
643 dom_data
[0].dns_domain_name
,
644 dom_data
[0].domsid
, &authinfo
);
645 if (!NT_STATUS_IS_OK(status
)) {
646 DEBUG(0, ("create_trust failed with error [%s].\n",
651 } else if (op
== TRUST_DELETE
) {
652 status
= delete_trust(mem_ctx
, pipe_hnd
[0]->binding_handle
,
653 &pol_hnd
[0], dom_data
[1].domsid
);
654 if (!NT_STATUS_IS_OK(status
)) {
655 DEBUG(0, ("delete_trust failed with [%s].\n",
660 if (other_net_ctx
!= NULL
) {
661 status
= delete_trust(mem_ctx
,
662 pipe_hnd
[1]->binding_handle
,
663 &pol_hnd
[1], dom_data
[0].domsid
);
664 if (!NT_STATUS_IS_OK(status
)) {
665 DEBUG(0, ("delete_trust failed with [%s].\n",
672 status
= close_handle(mem_ctx
, pipe_hnd
[0]->binding_handle
,
674 if (!NT_STATUS_IS_OK(status
)) {
675 DEBUG(0, ("close_handle failed with error [%s].\n",
680 if (other_net_ctx
!= NULL
) {
681 status
= close_handle(mem_ctx
, pipe_hnd
[1]->binding_handle
,
683 if (!NT_STATUS_IS_OK(status
)) {
684 DEBUG(0, ("close_handle failed with error [%s].\n",
693 data_blob_clear_free(&session_key
[0]);
694 data_blob_clear_free(&session_key
[1]);
695 cli_shutdown(cli
[0]);
696 cli_shutdown(cli
[1]);
697 talloc_destroy(mem_ctx
);
701 static int rpc_trust_create(struct net_context
*net_ctx
, int argc
,
704 return rpc_trust_common(net_ctx
, argc
, argv
, TRUST_CREATE
);
707 static int rpc_trust_delete(struct net_context
*net_ctx
, int argc
,
710 return rpc_trust_common(net_ctx
, argc
, argv
, TRUST_DELETE
);
713 int net_rpc_trust(struct net_context
*c
, int argc
, const char **argv
)
715 struct functable func
[] = {
721 N_("net rpc trust create\n"
729 N_("net rpc trust delete\n"
732 {NULL
, NULL
, 0, NULL
, NULL
}
735 return net_run_function(c
, argc
, argv
, "net rpc trust", func
);