diff options
-rw-r--r-- | source3/include/includes.h | 3 | ||||
-rw-r--r-- | source3/include/secrets.h | 16 | ||||
-rw-r--r-- | source3/libsmb/cli_wkssvc.c | 112 | ||||
-rw-r--r-- | source3/passdb/secrets.c | 92 | ||||
-rw-r--r-- | source3/utils/net.c | 54 | ||||
-rw-r--r-- | source3/utils/net_rpc.c | 372 |
6 files changed, 629 insertions, 20 deletions
diff --git a/source3/include/includes.h b/source3/include/includes.h index 2037b5ae05..51fc0d153b 100644 --- a/source3/include/includes.h +++ b/source3/include/includes.h @@ -699,7 +699,6 @@ extern int errno; #include "hash.h" #include "trans2.h" #include "nterr.h" -#include "secrets.h" #include "messages.h" #include "util_list.h" #include "charset.h" @@ -718,6 +717,8 @@ extern int errno; #include "smbw.h" #include "nameserv.h" +#include "secrets.h" + #include "byteorder.h" #include "ntdomain.h" diff --git a/source3/include/secrets.h b/source3/include/secrets.h index 53d9c8ab88..2ab8d1168f 100644 --- a/source3/include/secrets.h +++ b/source3/include/secrets.h @@ -22,18 +22,32 @@ #define _SECRETS_H /* the first one is for the hashed password (NT4 style) the latter - for plaintext (ADS + for plaintext (ADS) */ #define SECRETS_MACHINE_ACCT_PASS "SECRETS/$MACHINE.ACC" #define SECRETS_MACHINE_PASSWORD "SECRETS/MACHINE_PASSWORD" +/* this one is for storing trusted domain account password */ +#define SECRETS_DOMTRUST_ACCT_PASS "SECRETS/$DOMTRUST.ACC" + #define SECRETS_DOMAIN_SID "SECRETS/SID" #define SECRETS_SAM_SID "SAM/SID" +/* structure for storing machine account password + (ie. when samba server is member of a domain */ struct machine_acct_pass { uint8 hash[16]; time_t mod_time; }; +/* structure for storing trusted domain password */ +struct trusted_dom_pass { + int pass_len; + char* pass; + time_t mod_time; + DOM_SID domain_sid; /* remote domain's sid */ +}; + + #endif /* _SECRETS_H */ diff --git a/source3/libsmb/cli_wkssvc.c b/source3/libsmb/cli_wkssvc.c new file mode 100644 index 0000000000..391aee1782 --- /dev/null +++ b/source3/libsmb/cli_wkssvc.c @@ -0,0 +1,112 @@ +/* + Unix SMB/CIFS implementation. + NT Domain Authentication SMB / MSRPC client + Copyright (C) Andrew Tridgell 1994-2000 + Copyright (C) Luke Kenneth Casson Leighton 1996-2000 + Copyright (C) Tim Potter 2001 + Copytight (C) Rafal Szczesniak 2002 + + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/** + * Opens a SMB connection to the wkssvc pipe + * + * @param cli client structure (not yet initialised) + * @param system_name called rpc server name + * @param creds user credentials + * + * @return client structure with opened pipe + **/ + +struct cli_state *cli_wkssvc_initialise(struct cli_state *cli, + char *system_name, + struct ntuser_creds *creds) +{ + return cli_pipe_initialise(cli, system_name, PIPE_WKSSVC, creds); +} + + +/** + * WksQueryInfo rpc call (like query for server's capabilities) + * + * @param initialised client structure with \PIPE\wkssvc opened + * @param mem_ctx memory context assigned to this rpc binding + * @param wks100 WksQueryInfo structure + * + * @return NTSTATUS of rpc call + */ + +NTSTATUS cli_wks_query_info(struct cli_state *cli, TALLOC_CTX *mem_ctx, + WKS_INFO_100 *wks100) +{ + prs_struct buf; + prs_struct rbuf; + WKS_Q_QUERY_INFO q_o; + WKS_R_QUERY_INFO r_o; + NTSTATUS nt_status; + + if (cli == NULL || wks100 == NULL) + return NT_STATUS_UNSUCCESSFUL; + + /* init rpc parse structures */ + prs_init(&buf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); + prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); + + DEBUG(4, ("WksQueryInfo\n")); + + /* init query structure with rpc call arguments */ + init_wks_q_query_info(&q_o, cli->desthost, 100); + + /* marshall data */ + if (!wks_io_q_query_info("", &q_o, &buf, 0)) { + prs_mem_free(&buf); + prs_mem_free(&rbuf); + return NT_STATUS_UNSUCCESSFUL; + } + + /* actual rpc call over \PIPE\wkssvc */ + if (!rpc_api_pipe_req(cli, WKS_QUERY_INFO, &buf, &rbuf)) { + prs_mem_free(&buf); + prs_mem_free(&rbuf); + return NT_STATUS_UNSUCCESSFUL; + } + + prs_mem_free(&buf); + + r_o.wks100 = wks100; + + /* get call results from response buffer */ + if (!wks_io_r_query_info("", &r_o, &rbuf, 0)) { + prs_mem_free(&rbuf); + return NT_STATUS_UNSUCCESSFUL; + } + + /* check returnet status code */ + if (NT_STATUS_IS_ERR(r_o.status)) { + /* report the error */ + DEBUG(0,("WKS_R_QUERY_INFO: %s\n", get_nt_error_msg(r_o.status))); + prs_mem_free(&rbuf); + return r_o.status; + } + + /* do clean up */ + prs_mem_free(&rbuf); + + return nt_status; +} + diff --git a/source3/passdb/secrets.c b/source3/passdb/secrets.c index 995541ab0c..5afddfec24 100644 --- a/source3/passdb/secrets.c +++ b/source3/passdb/secrets.c @@ -123,7 +123,7 @@ BOOL secrets_fetch_domain_sid(char *domain, DOM_SID *sid) /************************************************************************ -form a key for fetching a domain trust password +form a key for fetching the machine trust account password ************************************************************************/ char *trust_keystr(char *domain) { @@ -135,8 +135,24 @@ char *trust_keystr(char *domain) return keystr; } +/** + * Form a key for fetching a trusted domain password + * + * @param domain domain name + * + * @return stored password's key + **/ +char *trustdom_keystr(char *domain) +{ + static char* keystr; + + asprintf(&keystr, "%s/%s", SECRETS_DOMTRUST_ACCT_PASS, domain); + + return keystr; +} + /************************************************************************ - Routine to get the trust account password for a domain. + Routine to get the machine trust account password for a domain. ************************************************************************/ BOOL secrets_fetch_trust_account_password(char *domain, uint8 ret_pwd[16], time_t *pass_last_set_time) @@ -170,6 +186,41 @@ BOOL secrets_fetch_trust_account_password(char *domain, uint8 ret_pwd[16], return True; } +/************************************************************************ + Routine to get account password to trusted domain +************************************************************************/ +BOOL secrets_fetch_trusted_domain_password(char *domain, char* pwd, + DOM_SID sid, time_t *pass_last_set_time) +{ + struct trusted_dom_pass *pass; + int pass_len; + size_t size; + + if (!(pass = secrets_fetch(trustdom_keystr(domain), &size))) { + DEBUG(5, ("secrets_fetch failed!\n")); + return False; + } + + if (size != sizeof(*pass)) { + DEBUG(0, ("secrets were of incorrect size!\n")); + return False; + } + + memcpy(&pass_len, &(pass->pass_len), sizeof(pass_len)); + + if (pwd) + safe_free(pwd); + else + pwd = (char*)malloc(pass_len + 1); + safe_strcpy(pwd, pass->pass, pass_len); + + if (pass_last_set_time) *pass_last_set_time = pass->mod_time; + + memcpy(&sid, &(pass->domain_sid), sizeof(sid)); + SAFE_FREE(pass); + + return True; +} /************************************************************************ Routine to set the trust account password for a domain. @@ -184,6 +235,32 @@ BOOL secrets_store_trust_account_password(char *domain, uint8 new_pwd[16]) return secrets_store(trust_keystr(domain), (void *)&pass, sizeof(pass)); } +/** + * Routine to set the password for trusted domain + * + * @param domain remote domain name + * @param pwd plain text password of trust relationship + * @param sid remote domain sid + * + * @return true if succeeded + **/ + +BOOL secrets_store_trusted_domain_password(char* domain, char* pwd, + DOM_SID sid) +{ + struct trusted_dom_pass pass; + + pass.mod_time = time(NULL); + + pass.pass_len = strlen(pwd); + pass.pass = (char*)malloc(strlen(pwd) + 1); + safe_strcpy(pass.pass, pwd, strlen(pwd)); + + memcpy(&(pass.domain_sid), &sid, sizeof(sid)); + + return secrets_store(trustdom_keystr(domain), (void *)&pass, sizeof(pass)); +} + /************************************************************************ Routine to set the plaintext machine account password for a realm the password is assumed to be a null terminated ascii string @@ -218,7 +295,7 @@ char *secrets_fetch_machine_password(void) /************************************************************************ - Routine to delete the trust account password file for a domain. + Routine to delete the machine trust account password file for a domain. ************************************************************************/ BOOL trust_password_delete(char *domain) @@ -226,6 +303,15 @@ BOOL trust_password_delete(char *domain) return secrets_delete(trust_keystr(domain)); } +/************************************************************************ + Routine to delete the password for trusted domain +************************************************************************/ +BOOL trusted_domain_password_delete(char *domain) +{ + return secrets_delete(trustdom_keystr(domain)); +} + + /******************************************************************* Reset the 'done' variables so after a client process is created from a fork call these calls will be re-done. This should be diff --git a/source3/utils/net.c b/source3/utils/net.c index 3577b922d3..aac5235ac8 100644 --- a/source3/utils/net.c +++ b/source3/utils/net.c @@ -104,9 +104,9 @@ int net_run_function(int argc, const char **argv, struct functable *table, /**************************************************************************** connect to \\server\ipc$ ****************************************************************************/ -static struct cli_state *connect_to_ipc(struct in_addr *server_ip, const char *server_name) +NTSTATUS connect_to_ipc(struct cli_state **c, struct in_addr *server_ip, + const char *server_name) { - struct cli_state *c; NTSTATUS nt_status; if (!got_pass) { @@ -116,14 +116,14 @@ static struct cli_state *connect_to_ipc(struct in_addr *server_ip, const char *s } } - nt_status = cli_full_connection(&c, opt_requester_name, server_name, + nt_status = cli_full_connection(c, opt_requester_name, server_name, server_ip, opt_port, "IPC$", "IPC", opt_user_name, opt_workgroup, opt_password, strlen(opt_password)); if (NT_STATUS_IS_OK(nt_status)) { - return c; + return nt_status; } else { DEBUG(0,("Cannot connect to server. Error was %s\n", get_nt_error_msg(nt_status))); @@ -134,29 +134,29 @@ static struct cli_state *connect_to_ipc(struct in_addr *server_ip, const char *s NT_STATUS_V(NT_STATUS_LOGON_FAILURE)) d_printf("The username or password was not correct.\n"); - return NULL; + return nt_status; } } /**************************************************************************** connect to \\server\ipc$ anonymously ****************************************************************************/ -static struct cli_state *connect_to_ipc_anonymous(struct in_addr *server_ip, const char *server_name) +NTSTATUS connect_to_ipc_anonymous(struct cli_state **c, + struct in_addr *server_ip, const char *server_name) { - struct cli_state *c; NTSTATUS nt_status; - nt_status = cli_full_connection(&c, opt_requester_name, server_name, + nt_status = cli_full_connection(c, opt_requester_name, server_name, server_ip, opt_port, "IPC$", "IPC", "", "", "", 0); if (NT_STATUS_IS_OK(nt_status)) { - return c; + return nt_status; } else { DEBUG(0,("Cannot connect to server (anonymously). Error was %s\n", get_nt_error_msg(nt_status))); - return NULL; + return nt_status; } } @@ -232,11 +232,39 @@ static BOOL net_find_server(unsigned flags, struct in_addr *server_ip, char **se return True; } + +BOOL net_find_dc(struct in_addr *server_ip, fstring server_name, char *domain_name) +{ + struct in_addr *ip_list; + int addr_count; + + if (get_dc_list(True /* PDC only*/, domain_name, &ip_list, &addr_count)) { + fstring dc_name; + if (addr_count < 1) { + return False; + } + + *server_ip = *ip_list; + + if (is_zero_ip(*server_ip)) + return False; + + if (!lookup_dc_name(global_myname, domain_name, server_ip, dc_name)) + return False; + + safe_strcpy(server_name, dc_name, FSTRING_LEN); + return True; + } else + return False; +} + + struct cli_state *net_make_ipc_connection(unsigned flags) { char *server_name = NULL; struct in_addr server_ip; - struct cli_state *cli; + struct cli_state *cli = NULL; + NTSTATUS nt_status; if (!net_find_server(flags, &server_ip, &server_name)) { d_printf("\nUnable to find a suitable server\n"); @@ -244,9 +272,9 @@ struct cli_state *net_make_ipc_connection(unsigned flags) } if (flags & NET_FLAGS_ANONYMOUS) { - cli = connect_to_ipc_anonymous(&server_ip, server_name); + nt_status = connect_to_ipc_anonymous(&cli, &server_ip, server_name); } else { - cli = connect_to_ipc(&server_ip, server_name); + nt_status = connect_to_ipc(&cli, &server_ip, server_name); } SAFE_FREE(server_name); return cli; diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c index d46644acf5..b19a82f366 100644 --- a/source3/utils/net_rpc.c +++ b/source3/utils/net_rpc.c @@ -302,9 +302,9 @@ static int rpc_join(int argc, const char **argv) * All paramaters are provided by the run_rpc_command funcion, except for * argc, argv which are passes through. * - * @param domain_sid The domain sid aquired from the remote server + * @param domain_sid The domain sid acquired from the remote server * @param cli A cli_state connected to the server. - * @param mem_ctx Talloc context, destoyed on compleation of the function. + * @param mem_ctx Talloc context, destoyed on completion of the function. * @param argc Standard main() style argc * @param argc Standard main() style argv. Initial components are already * stripped @@ -554,6 +554,372 @@ static int rpc_shutdown(int argc, const char **argv) argc, argv); } +/*************************************************************************** + NT Domain trusts code (i.e. 'net rpc trustdom' functionality) + + ***************************************************************************/ + +/** + * Add interdomain trust account to the RPC server. + * All parameters (except for argc and argv) are passed by run_rpc_command + * function. + * + * @param domain_sid The domain sid acquired from the server + * @param cli A cli_state connected to the server. + * @param mem_ctx Talloc context, destoyed on completion of the function. + * @param argc Standard main() style argc + * @param argc Standard main() style argv. Initial components are already + * stripped + * + * @return normal NTSTATUS return code + */ + +static NTSTATUS rpc_trustdom_add_internals(const DOM_SID *domain_sid, struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) { + + POLICY_HND connect_pol, domain_pol, user_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + char *acct_name; + uint16 acb_info; + uint32 unknown, user_rid; + + if (argc != 1) { + d_printf("Usage: net rpc trustdom add <domain_name>\n"); + return NT_STATUS_OK; + } + + /* + * Make valid trusting domain account (ie. uppercased and with '$' appended) + */ + + if (asprintf(&acct_name, "%s$", argv[0]) < 0) { + return NT_STATUS_NO_MEMORY; + } + + strupper(acct_name); + + /* Get sam policy handle */ + + result = cli_samr_connect(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + /* Get domain policy handle */ + + result = cli_samr_open_domain(cli, mem_ctx, &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + domain_sid, &domain_pol); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + /* Create trusting domain's account */ + + acb_info = ACB_DOMTRUST; + unknown = 0xe005000b; /* No idea what this is - a permission mask? + Is it needed for interdomain account also ? */ + + result = cli_samr_create_dom_user(cli, mem_ctx, &domain_pol, + acct_name, acb_info, unknown, + &user_pol, &user_rid); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + done: + SAFE_FREE(acct_name); + return result; +} + +/** + * Create interdomain trust account for a remote domain. + * + * @param argc standard argc + * @param argv standard argv without initial components + * + * @return Integer status (0 means success) + **/ + +static int rpc_trustdom_add(int argc, const char **argv) +{ + return run_rpc_command(PIPE_SAMR, 0, rpc_trustdom_add_internals, + argc, argv); +} + + +/** + * Delete interdomain trust account for a remote domain. + * + * @param argc standard argc + * @param argv standard argv without initial components + * + * @return Integer status (0 means success) + **/ + +static int rpc_trustdom_del(int argc, const char **argv) +{ + d_printf("Sorry, not yet implemented.\n"); + return -1; +} + + +/** + * Establish trust relationship to a trusting domain. + * Interdomain account must already be created on remote PDC. + * + * @param argc standard argc + * @param argv standard argv without initial components + * + * @return Integer status (0 means success) + **/ + +extern char *opt_user_name; +extern char *opt_password; + +static int rpc_trustdom_establish(int argc, const char **argv) { + + struct cli_state *cli; + struct in_addr server_ip; + POLICY_HND connect_hnd; + TALLOC_CTX *mem_ctx; + NTSTATUS nt_status; + DOM_SID domain_sid; + WKS_INFO_100 wks_info; + + char* domain_name; + char* acct_name; + fstring pdc_name; + + /* + * Connect to \\server\ipc$ as 'our domain' account with password + */ + + domain_name = smb_xstrdup(argv[0]); + strupper(domain_name); + + asprintf(&acct_name, "%s$", lp_workgroup()); + strupper(acct_name); + + opt_user_name = (char*)malloc(strlen(acct_name) + 1); + safe_strcpy(opt_user_name, acct_name, strlen(acct_name) + 1); + + /* find the domain controller */ + if (!net_find_dc(&server_ip, pdc_name, domain_name)) { + DEBUG(0, ("Coulnd find domain controller for domain %s\n", domain_name)); + return -1; + } + + /* connect to ipc$ as username/password */ + nt_status = connect_to_ipc(&cli, &server_ip, pdc_name); + if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT)) { + + /* Is it trusting domain account for sure ? */ + DEBUG(0, ("Couldn't verify trusting domain account. Error was %s\n", + get_nt_error_msg(nt_status))); + return -1; + } + + /* + * Connect to \\server\ipc$ again (this time anonymously) + */ + + nt_status = connect_to_ipc_anonymous(&cli, &server_ip, (char*)pdc_name); + + if (NT_STATUS_IS_ERR(nt_status)) { + DEBUG(0, ("Couldn't connect to domain %s controller. Error was %s.\n", + domain_name, get_nt_error_msg(nt_status))); + } + + /* + * Use NetServerEnum2 to make sure we're talking to a proper server + */ + + if (!cli_get_pdc_name(cli, domain_name, (char*)pdc_name)) { + DEBUG(0, ("NetServerEnum2 error: Couldn't find primary domain controller\ + for domain %s\n", domain_name)); + } + + /* + * Call WksQueryInfo to check remote server's capabilities + * FIXME:Is really necessary ? nt serv does this, but from samba's + * point of view it doesn't seem to make the difference + * IDEA: It may be used to get info about type of pdc we're talking to + * (e.g. WinNT or Win2k) + */ + + if (!cli_nt_session_open(cli, PIPE_WKSSVC)) { + DEBUG(0, ("Couldn't not initialise wkssvc pipe\n")); + return -1; + } + + /* TODO: convert this call from rpc_client/cli_wkssvc.c + to cli_wks_query_info() in libsmb/cli_wkssvc.c + UPDATE: already done :) + */ + + if (!(mem_ctx = talloc_init())) { + DEBUG(0, ("talloc_init() failed\n")); + cli_shutdown(cli); + return -1; + } + + nt_status = cli_wks_query_info(cli, mem_ctx, &wks_info); + + if (NT_STATUS_IS_ERR(nt_status)) { + DEBUG(0, ("WksQueryInfo call failed.\n")); + return -1; + } + + if (cli->nt_pipe_fnum) { + cli_nt_session_close(cli); + talloc_destroy(mem_ctx); + } + + + /* + * Call LsaOpenPolicy and LsaQueryInfo + */ + + if (!(mem_ctx = talloc_init())) { + DEBUG(0, ("talloc_init() failed\n")); + cli_shutdown(cli); + return -1; + } + + if (!cli_nt_session_open(cli, PIPE_LSARPC)) { + DEBUG(0, ("Could not initialise lsa pipe\n")); + } + + nt_status = cli_lsa_open_policy2(cli, mem_ctx, True, SEC_RIGHTS_QUERY_VALUE, + &connect_hnd); + if (NT_STATUS_IS_ERR(nt_status)) { + DEBUG(0, ("Couldn't open policy handle. Error was %s\n", + get_nt_error_msg(nt_status))); + return -1; + } + + /* Querying info level 5 */ + + nt_status = cli_lsa_query_info_policy(cli, mem_ctx, &connect_hnd, + 5 /* info level */, domain_name, &domain_sid); + if (NT_STATUS_IS_ERR(nt_status)) { + DEBUG(0, ("LSA Query Info failed. Returned error was %s\n", + get_nt_error_msg(nt_status))); + return -1; + } + + + /* There should be actually query info level 3 (following nt serv behaviour), + but I still don't know if it's _really_ necessary */ + + /* + * Close the pipes and clean up + */ + + nt_status = cli_lsa_close(cli, mem_ctx, &connect_hnd); + if (NT_STATUS_IS_ERR(nt_status)) { + DEBUG(0, ("Couldn't close LSA pipe. Error was %s\n", + get_nt_error_msg(nt_status))); + return -1; + } + + if (cli->nt_pipe_fnum) + cli_nt_session_close(cli); + + talloc_destroy(mem_ctx); + + + /* + * Store the password in secrets db + */ + + if (!secrets_store_trusted_domain_password(domain_name, opt_password, + domain_sid)) { + DEBUG(0, ("Storing password for trusted domain failed.\n")); + return -1; + } + + DEBUG(0, ("Success!\n")); + return 0; +} + +/** + * Revoke trust relationship to the remote domain + * + * @param argc standard argc + * @param argv standard argv without initial components + * + * @return Integer status (0 means success) + **/ + +static int rpc_trustdom_revoke(int argc, const char **argv) { + + char* domain_name; + + if (argc < 1) return -1; + + /* generate upper cased domain name */ + domain_name = smb_xstrdup(argv[0]); + strupper(domain_name); + + /* delete password of the trust */ + if (!trusted_domain_password_delete(domain_name)) { + DEBUG(0, ("Failed to revoke relationship to the trusted domain %s\n", + domain_name)); + return -1; + }; + + return 0; +} + +/** + * Usage for 'net rpc trustdom' command + * + * @param argc standard argc + * @param argv standard argv without inital components + * + * @return Integer status returned to shell + **/ + +static int rpc_trustdom_usage(int argc, const char **argv) { + d_printf(" net rpc trustdom add \t\t add trusting domain's account\n"); + d_printf(" net rpc trustdom del \t\t delete trusting domain's account\n"); + d_printf(" net rpc trustdom establish \t establish relationship to trusted domain\n"); + d_printf(" net rpc trustdom revoke \t abandon relationship to trusted domain\n"); + d_printf(" net rpc trustdom list \t show current interdomain trust relationships\n"); + return -1; +} + + +/** + * Entrypoint for 'net rpc trustdom' code + * + * @param argc standard argc + * @param argv standard argv without initial components + * + * @return Integer status (0 means success) + */ + +static int rpc_trustdom(int argc, const char **argv) +{ + struct functable func[] = { + {"add", rpc_trustdom_add}, + {"del", rpc_trustdom_del}, + {"establish", rpc_trustdom_establish}, + {"revoke", rpc_trustdom_revoke}, + {NULL, NULL} + }; + + if (argc == 0) { + rpc_trustdom_usage(argc, argv); + return -1; + } + + return (net_run_function(argc, argv, func, rpc_user_usage)); +} + /****************************************************************************/ @@ -569,6 +935,7 @@ int net_rpc_usage(int argc, const char **argv) d_printf(" net rpc join \tto join a domain \n"); d_printf(" net rpc user \tto add, delete and list users\n"); d_printf(" net rpc changetrustpw \tto change the trust account password\n"); + d_printf(" net rpc trustdom \tto create trusting domain's account or establish trust\n"); d_printf(" net rpc abortshutdown \tto to abort the shutdown of a remote server\n"); d_printf(" net rpc shutdown \tto to shutdown a remote server\n"); d_printf("\n"); @@ -593,6 +960,7 @@ int net_rpc(int argc, const char **argv) {"join", rpc_join}, {"user", rpc_user}, {"changetrustpw", rpc_changetrustpw}, + {"trustdom", rpc_trustdom}, {"abortshutdown", rpc_shutdown_abort}, {"shutdown", rpc_shutdown}, {NULL, NULL} |