From 8daa83a594a2e98f39d764422bfbdbc62c9efd44 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 19:20:00 +0200 Subject: Adding upstream version 2:4.20.0+dfsg. Signed-off-by: Daniel Baumann --- source3/utils/net_rpc_trust.c | 735 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 735 insertions(+) create mode 100644 source3/utils/net_rpc_trust.c (limited to 'source3/utils/net_rpc_trust.c') diff --git a/source3/utils/net_rpc_trust.c b/source3/utils/net_rpc_trust.c new file mode 100644 index 0000000..a3354ad --- /dev/null +++ b/source3/utils/net_rpc_trust.c @@ -0,0 +1,735 @@ +/* + Samba Unix/Linux SMB client library + Distributed SMB/CIFS Server Management Utility + Copyright (C) 2011 Sumit Bose (sbose@redhat.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + + +#include "includes.h" +#include "utils/net.h" +#include "rpc_client/cli_pipe.h" +#include "rpc_client/cli_lsarpc.h" +#include "librpc/gen_ndr/ndr_drsblobs.h" +#include "../librpc/gen_ndr/ndr_lsa_c.h" +#include "../libcli/security/dom_sid.h" +#include "libsmb/libsmb.h" + +#include "lib/crypto/gnutls_helpers.h" +#include +#include + +#define ARG_OTHERSERVER "otherserver=" +#define ARG_OTHERUSER "otheruser=" +#define ARG_OTHERDOMAINSID "otherdomainsid=" +#define ARG_OTHERDOMAIN "otherdomain=" +#define ARG_OTHERNETBIOSDOMAIN "other_netbios_domain=" +#define ARG_TRUSTPW "trustpw=" + +enum trust_op { + TRUST_CREATE, + TRUST_DELETE +}; + +struct other_dom_data { + char *host; + char *user_name; + char *domain_sid_str; + char *dns_domain_name; + char *domain_name; +}; + +struct dom_data { + struct dom_sid *domsid; + char *dns_domain_name; + char *domain_name; +}; + +static NTSTATUS close_handle(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *bind_hnd, + struct policy_handle *pol_hnd) +{ + NTSTATUS status; + NTSTATUS result; + + status = dcerpc_lsa_Close(bind_hnd, mem_ctx, pol_hnd, &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("dcerpc_lsa_Close failed with error [%s].\n", + nt_errstr(status))); + return status; + } + if (!NT_STATUS_IS_OK(result)) { + DEBUG(0, ("lsa close failed with error [%s].\n", + nt_errstr(result))); + return result; + } + + return NT_STATUS_OK; +} + +static NTSTATUS delete_trust(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *bind_hnd, + struct policy_handle *pol_hnd, + struct dom_sid *domsid) +{ + NTSTATUS status; + struct lsa_DeleteTrustedDomain dr; + + dr.in.handle = pol_hnd; + dr.in.dom_sid = domsid; + + status = dcerpc_lsa_DeleteTrustedDomain_r(bind_hnd, mem_ctx, &dr); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("dcerpc_lsa_DeleteTrustedDomain_r failed with [%s]\n", + nt_errstr(status))); + return status; + } + if (!NT_STATUS_IS_OK(dr.out.result)) { + DEBUG(0, ("DeleteTrustedDomain returned [%s]\n", + nt_errstr(dr.out.result))); + return dr.out.result; + } + + return NT_STATUS_OK; +} + +static NTSTATUS create_trust(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *bind_hnd, + struct policy_handle *pol_hnd, + const char *trust_name, + const char *trust_name_dns, + struct dom_sid *domsid, + struct lsa_TrustDomainInfoAuthInfoInternal *authinfo) +{ + NTSTATUS status; + struct lsa_CreateTrustedDomainEx2 r; + struct lsa_TrustDomainInfoInfoEx trustinfo; + struct policy_handle trustdom_handle; + bool is_nt4 = trust_name_dns == NULL; + + if (!is_nt4) { + fprintf(stdout, "Creating AD trust\n"); + trustinfo.trust_type = LSA_TRUST_TYPE_UPLEVEL; + trustinfo.trust_attributes = LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE; + } else { + fprintf(stdout, "Creating NT4 trust\n"); + trustinfo.trust_type = LSA_TRUST_TYPE_DOWNLEVEL; + trustinfo.trust_attributes = 0; + trust_name_dns = trust_name; + } + + trustinfo.sid = domsid; + trustinfo.netbios_name.string = trust_name; + trustinfo.domain_name.string = trust_name_dns; + + trustinfo.trust_direction = LSA_TRUST_DIRECTION_INBOUND | + LSA_TRUST_DIRECTION_OUTBOUND; + + r.in.policy_handle = pol_hnd; + r.in.info = &trustinfo; + r.in.auth_info_internal = authinfo; + r.in.access_mask = LSA_TRUSTED_SET_POSIX | LSA_TRUSTED_SET_AUTH | + LSA_TRUSTED_QUERY_DOMAIN_NAME; + r.out.trustdom_handle = &trustdom_handle; + + status = dcerpc_lsa_CreateTrustedDomainEx2_r(bind_hnd, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("dcerpc_lsa_CreateTrustedDomainEx2_r failed " + "with error [%s].\n", nt_errstr(status))); + return status; + } + if (!NT_STATUS_IS_OK(r.out.result)) { + DEBUG(0, ("CreateTrustedDomainEx2_r returned [%s].\n", + nt_errstr(r.out.result))); + return r.out.result; + } + + return NT_STATUS_OK; +} + +static NTSTATUS get_domain_info(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *bind_hdn, + struct policy_handle *pol_hnd, + struct dom_data *dom_data) +{ + NTSTATUS status; + struct lsa_QueryInfoPolicy2 qr; + struct dom_sid_buf buf; + + qr.in.handle = pol_hnd; + qr.in.level = LSA_POLICY_INFO_DNS; + + status = dcerpc_lsa_QueryInfoPolicy2_r(bind_hdn, mem_ctx, &qr); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("dcerpc_lsa_QueryInfoPolicy2_r failed " + "with error [%s].\n", nt_errstr(status))); + return status; + } + + if (!NT_STATUS_IS_OK(qr.out.result)) { + DEBUG(0, ("QueryInfoPolicy2 returned [%s].\n", + nt_errstr(qr.out.result))); + return qr.out.result; + } + + dom_data->domain_name = talloc_strdup(mem_ctx, + (*qr.out.info)->dns.name.string); + dom_data->dns_domain_name = talloc_strdup(mem_ctx, + (*qr.out.info)->dns.dns_domain.string); + dom_data->domsid = dom_sid_dup(mem_ctx, (*qr.out.info)->dns.sid); + if (dom_data->domain_name == NULL || + dom_data->dns_domain_name == NULL || + dom_data->domsid == NULL) { + DEBUG(0, ("Copying domain data failed.\n")); + return NT_STATUS_NO_MEMORY; + } + + DEBUG(0, ("Got the following domain info [%s][%s][%s].\n", + dom_data->domain_name, dom_data->dns_domain_name, + dom_sid_str_buf(dom_data->domsid, &buf))); + + return NT_STATUS_OK; +} + +static NTSTATUS connect_and_get_info(TALLOC_CTX *mem_ctx, + struct net_context *net_ctx, + struct cli_state **cli, + struct rpc_pipe_client **pipe_hnd, + struct policy_handle *pol_hnd, + struct dom_data *dom_data, + DATA_BLOB *session_key) +{ + NTSTATUS status; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32_t out_version = 0; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + + status = net_make_ipc_connection_ex(net_ctx, NULL, NULL, NULL, + NET_FLAGS_PDC, cli); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Failed to connect to [%s] with error [%s]\n", + net_ctx->opt_host, nt_errstr(status))); + return status; + } + + status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc, pipe_hnd); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Failed to initialise lsa pipe with error [%s]\n", + nt_errstr(status))); + return status; + } + + status = dcerpc_lsa_open_policy_fallback( + (*pipe_hnd)->binding_handle, + mem_ctx, + (*pipe_hnd)->srv_name_slash, + false, + LSA_POLICY_VIEW_LOCAL_INFORMATION | + LSA_POLICY_TRUST_ADMIN | + LSA_POLICY_CREATE_SECRET, + &out_version, + &out_revision_info, + pol_hnd, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + DBG_ERR("Failed to open policy handle: %s\n", + nt_errstr(result)); + return status; + } + + status = get_domain_info(mem_ctx, (*pipe_hnd)->binding_handle, + pol_hnd, dom_data); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("get_domain_info failed with error [%s].\n", + nt_errstr(status))); + return status; + } + + status = cli_get_session_key(mem_ctx, *pipe_hnd, session_key); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Error getting session_key of LSA pipe. Error was %s\n", + nt_errstr(status))); + return status; + } + + return NT_STATUS_OK; +} + +static bool get_trust_domain_passwords_auth_blob(TALLOC_CTX *mem_ctx, + const char *password, + DATA_BLOB *auth_blob) +{ + struct trustDomainPasswords auth_struct; + struct AuthenticationInformation *auth_info_array; + enum ndr_err_code ndr_err; + size_t converted_size; + + generate_random_buffer(auth_struct.confounder, + sizeof(auth_struct.confounder)); + + auth_info_array = talloc_array(mem_ctx, + struct AuthenticationInformation, 1); + if (auth_info_array == NULL) { + return false; + } + + auth_info_array[0].AuthType = TRUST_AUTH_TYPE_CLEAR; + if (!convert_string_talloc(mem_ctx, CH_UNIX, CH_UTF16, password, + strlen(password), + &auth_info_array[0].AuthInfo.clear.password, + &converted_size)) { + return false; + } + + auth_info_array[0].AuthInfo.clear.size = converted_size; + + auth_struct.outgoing.count = 1; + auth_struct.outgoing.current.count = 1; + auth_struct.outgoing.current.array = auth_info_array; + auth_struct.outgoing.previous.count = 0; + auth_struct.outgoing.previous.array = NULL; + + auth_struct.incoming.count = 1; + auth_struct.incoming.current.count = 1; + auth_struct.incoming.current.array = auth_info_array; + auth_struct.incoming.previous.count = 0; + auth_struct.incoming.previous.array = NULL; + + ndr_err = ndr_push_struct_blob(auth_blob, mem_ctx, &auth_struct, + (ndr_push_flags_fn_t)ndr_push_trustDomainPasswords); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return false; + } + + return true; +} + +static int parse_trust_args(TALLOC_CTX *mem_ctx, int argc, const char **argv, struct other_dom_data **_o, char **_trustpw) +{ + size_t c; + struct other_dom_data *o = NULL; + char *trustpw = NULL; + int ret = EFAULT; + + if (argc == 0) { + return EINVAL; + } + + o = talloc_zero(mem_ctx, struct other_dom_data); + if (o == NULL) { + DEBUG(0, ("talloc_zero failed.\n")); + return ENOMEM; + } + + for (c = 0; c < argc; c++) { + if (strnequal(argv[c], ARG_OTHERSERVER, sizeof(ARG_OTHERSERVER)-1)) { + o->host = talloc_strdup(o, argv[c] + sizeof(ARG_OTHERSERVER)-1); + if (o->host == NULL) { + ret = ENOMEM; + goto failed; + } + } else if (strnequal(argv[c], ARG_OTHERUSER, sizeof(ARG_OTHERUSER)-1)) { + o->user_name = talloc_strdup(o, argv[c] + sizeof(ARG_OTHERUSER)-1); + if (o->user_name == NULL) { + ret = ENOMEM; + goto failed; + } + } else if (strnequal(argv[c], ARG_OTHERDOMAINSID, sizeof(ARG_OTHERDOMAINSID)-1)) { + o->domain_sid_str = talloc_strdup(o, argv[c] + sizeof(ARG_OTHERDOMAINSID)-1); + if (o->domain_sid_str == NULL) { + ret = ENOMEM; + goto failed; + } + } else if (strnequal(argv[c], ARG_OTHERDOMAIN, sizeof(ARG_OTHERDOMAIN)-1)) { + o->dns_domain_name = talloc_strdup(o, argv[c] + sizeof(ARG_OTHERDOMAIN)-1); + if (o->dns_domain_name == NULL) { + ret = ENOMEM; + goto failed; + } + } else if (strnequal(argv[c], ARG_OTHERNETBIOSDOMAIN, sizeof(ARG_OTHERNETBIOSDOMAIN)-1)) { + o->domain_name = talloc_strdup(o, argv[c] + sizeof(ARG_OTHERNETBIOSDOMAIN)-1); + if (o->domain_name == NULL) { + ret = ENOMEM; + goto failed; + } + } else if (strnequal(argv[c], ARG_TRUSTPW, sizeof(ARG_TRUSTPW)-1)) { + trustpw = talloc_strdup(mem_ctx, argv[c] + sizeof(ARG_TRUSTPW)-1); + if (trustpw == NULL) { + ret = ENOMEM; + goto failed; + } + } else { + DEBUG(0, ("Unsupported option [%s].\n", argv[c])); + ret = EINVAL; + goto failed; + } + } + + *_o = o; + *_trustpw = trustpw; + + return 0; + +failed: + talloc_free(o); + talloc_free(trustpw); + return ret; +} + +static void print_trust_delete_usage(void) +{ + d_printf( "%s\n" + "net rpc trust delete [options]\n" + "\nOptions:\n" + "\totherserver=DC in other domain\n" + "\totheruser=Admin user in other domain\n" + "\totherdomainsid=SID of other domain\n" + "\nExamples:\n" + "\tnet rpc trust delete otherserver=oname otheruser=ouser -S lname -U luser\n" + "\tnet rpc trust delete otherdomainsid=S-... -S lname -U luser\n" + " %s\n", + _("Usage:"), + _("Remove trust between two domains")); +} + +static void print_trust_usage(void) +{ + d_printf( "%s\n" + "net rpc trust create [options]\n" + "\nOptions:\n" + "\totherserver=DC in other domain\n" + "\totheruser=Admin user in other domain\n" + "\totherdomainsid=SID of other domain\n" + "\tother_netbios_domain=NetBIOS/short name of other domain\n" + "\totherdomain=Full/DNS name of other domain (if not used, create an NT4 trust)\n" + "\ttrustpw=Trust password\n" + "\nExamples:\n" + "\tnet rpc trust create otherserver=oname otheruser=ouser -S lname -U luser\n" + "\tnet rpc trust create otherdomainsid=S-... other_netbios_domain=odom otherdomain=odom.org trustpw=secret -S lname -U luser\n" + " %s\n", + _("Usage:"), + _("Create trust between two domains")); +} + +static int rpc_trust_common(struct net_context *net_ctx, int argc, + const char **argv, enum trust_op op) +{ + TALLOC_CTX *mem_ctx; + NTSTATUS status; + int ret; + int success = -1; + struct cli_state *cli[2] = {NULL, NULL}; + struct rpc_pipe_client *pipe_hnd[2] = {NULL, NULL}; + DATA_BLOB session_key[2]; + struct policy_handle pol_hnd[2]; + struct lsa_TrustDomainInfoAuthInfoInternal authinfo; + DATA_BLOB auth_blob; + char *trust_pw = NULL; + struct other_dom_data *other_dom_data; + struct net_context *other_net_ctx = NULL; + struct dom_data dom_data[2]; + void (*usage)(void); + + ZERO_STRUCT(session_key); + + switch (op) { + case TRUST_CREATE: + usage = print_trust_usage; + break; + case TRUST_DELETE: + usage = print_trust_delete_usage; + break; + default: + DEBUG(0, ("Unsupported trust operation.\n")); + return -1; + } + + if (net_ctx->display_usage) { + usage(); + return 0; + } + + mem_ctx = talloc_init("trust op"); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_init failed.\n")); + return -1; + } + + ret = parse_trust_args(mem_ctx, argc, argv, &other_dom_data, &trust_pw); + if (ret != 0) { + if (ret == EINVAL) { + usage(); + } else { + DEBUG(0, ("Failed to parse arguments.\n")); + } + goto done; + } + + if (other_dom_data->host != 0) { + other_net_ctx = talloc_zero(other_dom_data, struct net_context); + if (other_net_ctx == NULL) { + DEBUG(0, ("talloc_zero failed.\n")); + goto done; + } + + other_net_ctx->opt_host = other_dom_data->host; + other_net_ctx->creds = cli_credentials_init(other_net_ctx); + cli_credentials_parse_string(other_net_ctx->creds, + other_dom_data->user_name, + CRED_SPECIFIED); + } else { + dom_data[1].domsid = dom_sid_parse_talloc(mem_ctx, + other_dom_data->domain_sid_str); + dom_data[1].domain_name = other_dom_data->domain_name; + dom_data[1].dns_domain_name = other_dom_data->dns_domain_name; + + if (dom_data[1].dns_domain_name == NULL) { + fprintf(stdout, "No DNS domain name passed, " + "assuming NT4 trust!\n"); + } + + if (dom_data[1].domsid == NULL || + (op == TRUST_CREATE && + (dom_data[1].domain_name == NULL))) { + DEBUG(0, ("Missing required argument.\n")); + usage(); + goto done; + } + } + + status = connect_and_get_info(mem_ctx, net_ctx, &cli[0], &pipe_hnd[0], + &pol_hnd[0], &dom_data[0], &session_key[0]); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("connect_and_get_info failed with error [%s]\n", + nt_errstr(status))); + goto done; + } + + if (other_net_ctx != NULL) { + status = connect_and_get_info(mem_ctx, other_net_ctx, + &cli[1], &pipe_hnd[1], + &pol_hnd[1], &dom_data[1], + &session_key[1]); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("connect_and_get_info failed with error [%s]\n", + nt_errstr(status))); + goto done; + } + } + + if (op == TRUST_CREATE) { + gnutls_cipher_hd_t cipher_hnd = NULL; + gnutls_datum_t enc_session_key = { + .data = session_key[0].data, + .size = session_key[0].length, + }; + int rc; + + if (trust_pw == NULL) { + if (other_net_ctx == NULL) { + DEBUG(0, ("Missing either trustpw or otherhost.\n")); + goto done; + } + + DEBUG(0, ("Using random trust password.\n")); + trust_pw = trust_pw_new_value(mem_ctx, + SEC_CHAN_DOMAIN, + SEC_DOMAIN); + if (trust_pw == NULL) { + DEBUG(0, ("generate_random_password failed.\n")); + goto done; + } + } else { + DEBUG(0, ("Using user provided password.\n")); + } + + if (!get_trust_domain_passwords_auth_blob(mem_ctx, trust_pw, + &auth_blob)) { + DEBUG(0, ("get_trust_domain_passwords_auth_blob failed\n")); + goto done; + } + + authinfo.auth_blob.data = (uint8_t *)talloc_memdup( + mem_ctx, + auth_blob.data, + auth_blob.length); + if (authinfo.auth_blob.data == NULL) { + goto done; + } + authinfo.auth_blob.size = auth_blob.length; + + rc = gnutls_cipher_init(&cipher_hnd, + GNUTLS_CIPHER_ARCFOUR_128, + &enc_session_key, + NULL); + if (rc < 0) { + status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID); + goto done; + } + rc = gnutls_cipher_encrypt(cipher_hnd, + authinfo.auth_blob.data, + authinfo.auth_blob.size); + gnutls_cipher_deinit(cipher_hnd); + if (rc < 0) { + status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID); + goto done; + } + + status = create_trust(mem_ctx, pipe_hnd[0]->binding_handle, + &pol_hnd[0], + dom_data[1].domain_name, + dom_data[1].dns_domain_name, + dom_data[1].domsid, + &authinfo); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("create_trust failed with error [%s].\n", + nt_errstr(status))); + goto done; + } + + if (other_net_ctx != NULL) { + talloc_free(authinfo.auth_blob.data); + authinfo.auth_blob.data = (uint8_t *)talloc_memdup( + mem_ctx, + auth_blob.data, + auth_blob.length); + if (authinfo.auth_blob.data == NULL) { + goto done; + } + authinfo.auth_blob.size = auth_blob.length; + + enc_session_key = (gnutls_datum_t) { + .data = session_key[1].data, + .size = session_key[1].length, + }; + + rc = gnutls_cipher_init(&cipher_hnd, + GNUTLS_CIPHER_ARCFOUR_128, + &enc_session_key, + NULL); + if (rc < 0) { + status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID); + goto done; + } + rc = gnutls_cipher_encrypt(cipher_hnd, + authinfo.auth_blob.data, + authinfo.auth_blob.size); + gnutls_cipher_deinit(cipher_hnd); + if (rc < 0) { + status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID); + goto done; + } + + status = create_trust(mem_ctx, + pipe_hnd[1]->binding_handle, + &pol_hnd[1], + dom_data[0].domain_name, + dom_data[0].dns_domain_name, + dom_data[0].domsid, &authinfo); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("create_trust failed with error [%s].\n", + nt_errstr(status))); + goto done; + } + } + } else if (op == TRUST_DELETE) { + status = delete_trust(mem_ctx, pipe_hnd[0]->binding_handle, + &pol_hnd[0], dom_data[1].domsid); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("delete_trust failed with [%s].\n", + nt_errstr(status))); + goto done; + } + + if (other_net_ctx != NULL) { + status = delete_trust(mem_ctx, + pipe_hnd[1]->binding_handle, + &pol_hnd[1], dom_data[0].domsid); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("delete_trust failed with [%s].\n", + nt_errstr(status))); + goto done; + } + } + } + + status = close_handle(mem_ctx, pipe_hnd[0]->binding_handle, + &pol_hnd[0]); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("close_handle failed with error [%s].\n", + nt_errstr(status))); + goto done; + } + + if (other_net_ctx != NULL) { + status = close_handle(mem_ctx, pipe_hnd[1]->binding_handle, + &pol_hnd[1]); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("close_handle failed with error [%s].\n", + nt_errstr(status))); + goto done; + } + } + + success = 0; + +done: + data_blob_clear_free(&session_key[0]); + data_blob_clear_free(&session_key[1]); + cli_shutdown(cli[0]); + cli_shutdown(cli[1]); + talloc_destroy(mem_ctx); + return success; +} + +static int rpc_trust_create(struct net_context *net_ctx, int argc, + const char **argv) +{ + return rpc_trust_common(net_ctx, argc, argv, TRUST_CREATE); +} + +static int rpc_trust_delete(struct net_context *net_ctx, int argc, + const char **argv) +{ + return rpc_trust_common(net_ctx, argc, argv, TRUST_DELETE); +} + +int net_rpc_trust(struct net_context *c, int argc, const char **argv) +{ + struct functable func[] = { + { + "create", + rpc_trust_create, + NET_TRANSPORT_RPC, + N_("Create trusts"), + N_("net rpc trust create\n" + " Create trusts") + }, + { + "delete", + rpc_trust_delete, + NET_TRANSPORT_RPC, + N_("Remove trusts"), + N_("net rpc trust delete\n" + " Remove trusts") + }, + {NULL, NULL, 0, NULL, NULL} + }; + + return net_run_function(c, argc, argv, "net rpc trust", func); +} -- cgit v1.2.3