/* Samba Unix/Linux SMB client library Version 3.0 Distributed SMB/CIFS Server Management Utility Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org) 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" #include "../utils/net.h" /** * @file net_rpc.c * * @brief RPC based subcommands for the 'net' utility. * * This file should contain much of the functionality that used to * be found in rpcclient, execpt that the commands should change * less often, and the fucntionality should be sane (the user is not * expected to know a rid/sid before they conduct an operation etc.) * * @todo Perhaps eventually these should be split out into a number * of files, as this could get quite big. **/ /* A function of this type is passed to the 'run_rpc_command' wrapper */ typedef NTSTATUS (*rpc_command_fn)(const DOM_SID *, struct cli_state *, TALLOC_CTX *, int, const char **); /** * Many of the RPC functions need the domain sid. This function gets * it at the start of every run * * @param cli A cli_state already connected to the remote machine * * @return The Domain SID of the remote machine. */ static DOM_SID *net_get_remote_domain_sid(struct cli_state *cli) { DOM_SID *domain_sid; POLICY_HND pol; NTSTATUS result = NT_STATUS_OK; uint32 info_class = 5; fstring domain_name; TALLOC_CTX *mem_ctx; if (!(domain_sid = malloc(sizeof(DOM_SID)))){ DEBUG(0,("fetch_domain_sid: malloc returned NULL!\n")); goto error; } if (!(mem_ctx=talloc_init())) { DEBUG(0,("fetch_domain_sid: talloc_init returned NULL!\n")); goto error; } if (!cli_nt_session_open (cli, PIPE_LSARPC)) { fprintf(stderr, "could not initialise lsa pipe\n"); goto error; } result = cli_lsa_open_policy(cli, mem_ctx, True, SEC_RIGHTS_MAXIMUM_ALLOWED, &pol); if (!NT_STATUS_IS_OK(result)) { goto error; } result = cli_lsa_query_info_policy(cli, mem_ctx, &pol, info_class, domain_name, domain_sid); if (!NT_STATUS_IS_OK(result)) { goto error; } cli_lsa_close(cli, mem_ctx, &pol); cli_nt_session_close(cli); talloc_destroy(mem_ctx); return domain_sid; error: fprintf(stderr, "could not obtain sid for domain %s\n", cli->domain); if (!NT_STATUS_IS_OK(result)) { fprintf(stderr, "error: %s\n", get_nt_error_msg(result)); } exit(1); } /** * Run a single RPC command, from start to finish. * * @param pipe_name the pipe to connect to (usually a PIPE_ constant) * @param conn_flag a NET_FLAG_ combination. Passed to * net_make_ipc_connection. * @param argc Standard main() style argc * @param argc Standard main() style argv. Initial components are already * stripped * @return A shell status integer (0 for success) */ static int run_rpc_command(const char *pipe_name, int conn_flags, rpc_command_fn fn, int argc, const char **argv) { struct cli_state *cli = net_make_ipc_connection(conn_flags); TALLOC_CTX *mem_ctx; NTSTATUS nt_status; DOM_SID *domain_sid; if (!cli) { return -1; } domain_sid = net_get_remote_domain_sid(cli); /* Create mem_ctx */ if (!(mem_ctx = talloc_init())) { DEBUG(0, ("talloc_init() failed\n")); cli_shutdown(cli); return -1; } if (!cli_nt_session_open(cli, pipe_name)) { DEBUG(0, ("Could not initialise samr pipe\n")); } nt_status = fn(domain_sid, cli, mem_ctx, argc, argv); DEBUG(5, ("rpc command function returned %s\n", get_nt_error_msg(nt_status))); if (cli->nt_pipe_fnum) cli_nt_session_close(cli); talloc_destroy(mem_ctx); return (!NT_STATUS_IS_OK(nt_status)); } /****************************************************************************/ /** * Force a change of the trust acccount password. * * 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 cli A cli_state connected to the server. * @param mem_ctx Talloc context, destoyed on compleation of the function. * @param argc Standard main() style argc * @param argc Standard main() style argv. Initial components are already * stripped * * @return Normal NTSTATUS return. **/ static NTSTATUS rpc_changetrustpw_internals(const DOM_SID *domain_sid, struct cli_state *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { return trust_pw_find_change_and_store_it(cli, mem_ctx, opt_target_workgroup); } /** * Force a change of the trust acccount password. * * @param argc Standard main() style argc * @param argc Standard main() style argv. Initial components are already * stripped * * @return A shell status integer (0 for success) **/ static int rpc_changetrustpw(int argc, const char **argv) { return run_rpc_command(PIPE_NETLOGON, NET_FLAGS_ANONYMOUS | NET_FLAGS_PDC, rpc_changetrustpw_internals, argc, argv); } /****************************************************************************/ /** * Join a domain, the old way. * * This uses 'machinename' as the inital password, and changes it. * * The password should be created with 'server manager' or eqiv first. * * 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 cli A cli_state connected to the server. * @param mem_ctx Talloc context, destoyed on compleation of the function. * @param argc Standard main() style argc * @param argc Standard main() style argv. Initial components are already * stripped * * @return Normal NTSTATUS return. **/ static NTSTATUS rpc_join_oldstyle_internals(const DOM_SID *domain_sid, struct cli_state *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { extern pstring global_myname; fstring trust_passwd; unsigned char orig_trust_passwd_hash[16]; fstrcpy(trust_passwd, global_myname); strlower(trust_passwd); E_md4hash( (uchar *)trust_passwd, orig_trust_passwd_hash); return trust_pw_change_and_store_it(cli, mem_ctx, orig_trust_passwd_hash); } /** * Join a domain, the old way. * * @param argc Standard main() style argc * @param argc Standard main() style argv. Initial components are already * stripped * * @return A shell status integer (0 for success) **/ static int rpc_join_oldstyle(int argc, const char **argv) { return run_rpc_command(PIPE_NETLOGON, NET_FLAGS_ANONYMOUS | NET_FLAGS_PDC, rpc_join_oldstyle_internals, argc, argv); } /** * Basic usage function for 'net rpc join' * @param argc Standard main() style argc * @param argc Standard main() style argv. Initial components are already * stripped **/ static int rpc_join_usage(int argc, const char **argv) { d_printf(" net rpc join \t to join a domain with admin username & password\n"); d_printf(" net rpc join oldstyle \t to join a domain created in server manager\n"); return -1; } /** * 'net rpc join' entrypoint. * @param argc Standard main() style argc * @param argc Standard main() style argv. Initial components are already * stripped * * Main 'net_rpc_join()' (where the admain username/password is used) is * in net_rpc_join.c **/ static int rpc_join(int argc, const char **argv) { struct functable func[] = { {"oldstyle", rpc_join_oldstyle}, {NULL, NULL} }; if (argc == 0) { return net_rpc_join(argc, argv); } return net_run_function(argc, argv, func, rpc_join_usage); } /****************************************************************************/ /** * Add a new user to a remote RPC server * * 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 cli A cli_state connected to the server. * @param mem_ctx Talloc context, destoyed on compleation of the function. * @param argc Standard main() style argc * @param argc Standard main() style argv. Initial components are already * stripped * * @return Normal NTSTATUS return. **/ static NTSTATUS rpc_user_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; const char *acct_name; uint16 acb_info; uint32 unknown, user_rid; if (argc != 1) { d_printf("Usage: net rpc user add username\n"); return NT_STATUS_OK; } acct_name = argv[0]; /* 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 domain user */ acb_info = ACB_NORMAL; unknown = 0xe005000b; /* No idea what this is - a permission mask? */ 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: return result; } /** * Add a new user to a remote RPC server * * @param argc Standard main() style argc * @param argc Standard main() style argv. Initial components are already * stripped * * @return A shell status integer (0 for success) **/ static int rpc_user_add(int argc, const char **argv) { return run_rpc_command(PIPE_SAMR, 0, rpc_user_add_internals, argc, argv); } /** * Basic usage function for 'net rpc join' * @param argc Standard main() style argc * @param argc Standard main() style argv. Initial components are already * stripped **/ static int rpc_user_usage(int argc, const char **argv) { d_printf(" net rpc user add \t to add a user\n"); return -1; } /** * 'net rpc user' entrypoint. * @param argc Standard main() style argc * @param argc Standard main() style argv. Initial components are already * stripped **/ static int rpc_user(int argc, const char **argv) { struct functable func[] = { {"add", rpc_user_add}, {NULL, NULL} }; if (argc == 0) { rpc_user_usage(argc, argv); } return net_run_function(argc, argv, func, rpc_user_usage); } /** * Basic usage function for 'net rpc join' * @param argc Standard main() style argc * @param argc Standard main() style argv. Initial components are already * stripped **/ 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"); return -1; } /** * 'net rpc user' entrypoint. * @param argc Standard main() style argc * @param argc Standard main() style argv. Initial components are already * stripped **/ int net_rpc(int argc, const char **argv) { struct functable func[] = { {"join", rpc_join}, {"user", rpc_user}, {"changetrustpw", rpc_changetrustpw}, {NULL, NULL} }; return net_run_function(argc, argv, func, net_rpc_usage); }