diff options
Diffstat (limited to 'source3/rpcclient')
-rw-r--r-- | source3/rpcclient/cmd_dfs.c | 329 | ||||
-rw-r--r-- | source3/rpcclient/cmd_drsuapi.c | 566 | ||||
-rw-r--r-- | source3/rpcclient/cmd_dssetup.c | 69 | ||||
-rw-r--r-- | source3/rpcclient/cmd_echo.c | 184 | ||||
-rw-r--r-- | source3/rpcclient/cmd_lsarpc.c | 1395 | ||||
-rw-r--r-- | source3/rpcclient/cmd_netlogon.c | 1034 | ||||
-rw-r--r-- | source3/rpcclient/cmd_ntsvcs.c | 229 | ||||
-rw-r--r-- | source3/rpcclient/cmd_samr.c | 2763 | ||||
-rw-r--r-- | source3/rpcclient/cmd_shutdown.c | 117 | ||||
-rw-r--r-- | source3/rpcclient/cmd_spoolss.c | 2782 | ||||
-rw-r--r-- | source3/rpcclient/cmd_srvsvc.c | 891 | ||||
-rw-r--r-- | source3/rpcclient/cmd_test.c | 75 | ||||
-rw-r--r-- | source3/rpcclient/cmd_wkssvc.c | 170 | ||||
-rw-r--r-- | source3/rpcclient/rpcclient.c | 959 | ||||
-rw-r--r-- | source3/rpcclient/rpcclient.h | 42 |
15 files changed, 11605 insertions, 0 deletions
diff --git a/source3/rpcclient/cmd_dfs.c b/source3/rpcclient/cmd_dfs.c new file mode 100644 index 0000000000..d55261bea3 --- /dev/null +++ b/source3/rpcclient/cmd_dfs.c @@ -0,0 +1,329 @@ +/* + Unix SMB/CIFS implementation. + RPC pipe client + + Copyright (C) Tim Potter 2000 + Copyright (C) Jelmer Vernooij 2005. + + 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 <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "rpcclient.h" + +/* Check DFS is supported by the remote server */ + +static WERROR cmd_dfs_version(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + enum dfs_ManagerVersion version; + NTSTATUS result; + + if (argc != 1) { + printf("Usage: %s\n", argv[0]); + return WERR_OK; + } + + result = rpccli_dfs_GetManagerVersion(cli, mem_ctx, &version); + + if (!NT_STATUS_IS_OK(result)) { + return ntstatus_to_werror(result); + } + + if (version > 0) { + printf("dfs is present (%d)\n", version); + } else { + printf("dfs is not present\n"); + } + + return WERR_OK; +} + +static WERROR cmd_dfs_add(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS result; + WERROR werr; + const char *path, *servername, *sharename, *comment; + uint32 flags = 0; + + if (argc != 5) { + printf("Usage: %s path servername sharename comment\n", + argv[0]); + return WERR_OK; + } + + path = argv[1]; + servername = argv[2]; + sharename = argv[3]; + comment = argv[4]; + + result = rpccli_dfs_Add(cli, mem_ctx, path, servername, + sharename, comment, flags, &werr); + if (!NT_STATUS_IS_OK(result)) { + return ntstatus_to_werror(result); + } + + return werr; +} + +static WERROR cmd_dfs_remove(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS result; + WERROR werr; + const char *path, *servername, *sharename; + + if (argc != 4) { + printf("Usage: %s path servername sharename\n", argv[0]); + return WERR_OK; + } + + path = argv[1]; + servername = argv[2]; + sharename = argv[3]; + + result = rpccli_dfs_Remove(cli, mem_ctx, path, servername, + sharename, &werr); + if (!NT_STATUS_IS_OK(result)) { + return ntstatus_to_werror(result); + } + + return werr; +} + +/* Display a DFS_INFO_1 structure */ + +static void display_dfs_info_1(struct dfs_Info1 *info1) +{ + printf("path: %s\n", info1->path); +} + +/* Display a DFS_INFO_2 structure */ + +static void display_dfs_info_2(struct dfs_Info2 *info2) +{ + printf("path: %s\n", info2->path); + printf("\tcomment: %s\n", info2->comment); + + printf("\tstate: %d\n", info2->state); + printf("\tnum_stores: %d\n", info2->num_stores); +} + +/* Display a DFS_INFO_3 structure */ + +static void display_dfs_info_3(struct dfs_Info3 *info3) +{ + int i; + + printf("path: %s\n", info3->path); + + printf("\tcomment: %s\n", info3->comment); + + printf("\tstate: %d\n", info3->state); + printf("\tnum_stores: %d\n", info3->num_stores); + + for (i = 0; i < info3->num_stores; i++) { + struct dfs_StorageInfo *dsi = &info3->stores[i]; + + printf("\t\tstorage[%d] server: %s\n", i, dsi->server); + + printf("\t\tstorage[%d] share: %s\n", i, dsi->share); + } +} + + +/* Display a DFS_INFO_CTR structure */ +static void display_dfs_info(uint32 level, union dfs_Info *ctr) +{ + switch (level) { + case 0x01: + display_dfs_info_1(ctr->info1); + break; + case 0x02: + display_dfs_info_2(ctr->info2); + break; + case 0x03: + display_dfs_info_3(ctr->info3); + break; + default: + printf("unsupported info level %d\n", + level); + break; + } +} + +static void display_dfs_enumstruct(struct dfs_EnumStruct *ctr) +{ + int i; + + /* count is always the first element, so we can just use info1 here */ + for (i = 0; i < ctr->e.info1->count; i++) { + switch (ctr->level) { + case 1: display_dfs_info_1(&ctr->e.info1->s[i]); break; + case 2: display_dfs_info_2(&ctr->e.info2->s[i]); break; + case 3: display_dfs_info_3(&ctr->e.info3->s[i]); break; + default: + printf("unsupported info level %d\n", + ctr->level); + return; + } + } +} + +/* Enumerate dfs shares */ + +static WERROR cmd_dfs_enum(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct dfs_EnumStruct str; + struct dfs_EnumArray1 info1; + struct dfs_EnumArray2 info2; + struct dfs_EnumArray3 info3; + struct dfs_EnumArray4 info4; + struct dfs_EnumArray200 info200; + struct dfs_EnumArray300 info300; + + NTSTATUS result; + WERROR werr; + uint32 total = 0; + + if (argc > 2) { + printf("Usage: %s [info_level]\n", argv[0]); + return WERR_OK; + } + + str.level = 1; + if (argc == 2) + str.level = atoi(argv[1]); + + switch (str.level) { + case 1: str.e.info1 = &info1; ZERO_STRUCT(info1); break; + case 2: str.e.info2 = &info2; ZERO_STRUCT(info2); break; + case 3: str.e.info3 = &info3; ZERO_STRUCT(info3); break; + case 4: str.e.info4 = &info4; ZERO_STRUCT(info4); break; + case 200: str.e.info200 = &info200; ZERO_STRUCT(info200); break; + case 300: str.e.info300 = &info300; ZERO_STRUCT(info300); break; + default: + printf("Unknown info level %d\n", str.level); + break; + } + + result = rpccli_dfs_Enum(cli, mem_ctx, str.level, 0xFFFFFFFF, &str, + &total, &werr); + + if (NT_STATUS_IS_OK(result)) { + display_dfs_enumstruct(&str); + } + + return werr; +} + +/* Enumerate dfs shares */ + +static WERROR cmd_dfs_enumex(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct dfs_EnumStruct str; + struct dfs_EnumArray1 info1; + struct dfs_EnumArray2 info2; + struct dfs_EnumArray3 info3; + struct dfs_EnumArray4 info4; + struct dfs_EnumArray200 info200; + struct dfs_EnumArray300 info300; + + NTSTATUS result; + WERROR werr; + uint32 total = 0; + + if (argc < 2 || argc > 3) { + printf("Usage: %s dfs_name [info_level]\n", argv[0]); + return WERR_OK; + } + + str.level = 1; + + if (argc == 3) + str.level = atoi(argv[2]); + + switch (str.level) { + case 1: str.e.info1 = &info1; ZERO_STRUCT(info1); break; + case 2: str.e.info2 = &info2; ZERO_STRUCT(info2); break; + case 3: str.e.info3 = &info3; ZERO_STRUCT(info3); break; + case 4: str.e.info4 = &info4; ZERO_STRUCT(info4); break; + case 200: str.e.info200 = &info200; ZERO_STRUCT(info200); break; + case 300: str.e.info300 = &info300; ZERO_STRUCT(info300); break; + default: + printf("Unknown info level %d\n", str.level); + break; + } + + result = rpccli_dfs_EnumEx(cli, mem_ctx, argv[1], str.level, + 0xFFFFFFFF, &str, &total, &werr); + + if (NT_STATUS_IS_OK(result)) { + display_dfs_enumstruct(&str); + } + + return werr; +} + + +static WERROR cmd_dfs_getinfo(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS result; + WERROR werr; + const char *path, *servername, *sharename; + uint32 info_level = 1; + union dfs_Info ctr; + + if (argc < 4 || argc > 5) { + printf("Usage: %s path servername sharename " + "[info_level]\n", argv[0]); + return WERR_OK; + } + + path = argv[1]; + servername = argv[2]; + sharename = argv[3]; + + if (argc == 5) + info_level = atoi(argv[4]); + + result = rpccli_dfs_GetInfo(cli, mem_ctx, path, servername, + sharename, info_level, &ctr, &werr); + + if (NT_STATUS_IS_OK(result)) { + display_dfs_info(info_level, &ctr); + } + + return werr; +} + +/* List of commands exported by this module */ + +struct cmd_set dfs_commands[] = { + + { "DFS" }, + + { "dfsversion", RPC_RTYPE_WERROR, NULL, cmd_dfs_version, &ndr_table_netdfs.syntax_id, NULL, "Query DFS support", "" }, + { "dfsadd", RPC_RTYPE_WERROR, NULL, cmd_dfs_add, &ndr_table_netdfs.syntax_id, NULL, "Add a DFS share", "" }, + { "dfsremove", RPC_RTYPE_WERROR, NULL, cmd_dfs_remove, &ndr_table_netdfs.syntax_id, NULL, "Remove a DFS share", "" }, + { "dfsgetinfo", RPC_RTYPE_WERROR, NULL, cmd_dfs_getinfo, &ndr_table_netdfs.syntax_id, NULL, "Query DFS share info", "" }, + { "dfsenum", RPC_RTYPE_WERROR, NULL, cmd_dfs_enum, &ndr_table_netdfs.syntax_id, NULL, "Enumerate dfs shares", "" }, + { "dfsenumex", RPC_RTYPE_WERROR, NULL, cmd_dfs_enumex, &ndr_table_netdfs.syntax_id, NULL, "Enumerate dfs shares", "" }, + + { NULL } +}; diff --git a/source3/rpcclient/cmd_drsuapi.c b/source3/rpcclient/cmd_drsuapi.c new file mode 100644 index 0000000000..71757f5ea3 --- /dev/null +++ b/source3/rpcclient/cmd_drsuapi.c @@ -0,0 +1,566 @@ +/* + Unix SMB/CIFS implementation. + RPC pipe client + + Copyright (C) Guenther Deschner 2008 + + 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 <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "rpcclient.h" + +static WERROR cracknames(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + struct policy_handle *bind_handle, + enum drsuapi_DsNameFormat format_offered, + enum drsuapi_DsNameFormat format_desired, + int argc, + const char **argv, + union drsuapi_DsNameCtr *ctr) +{ + NTSTATUS status; + WERROR werr; + int i; + int32_t level = 1; + union drsuapi_DsNameRequest req; + int32_t level_out; + struct drsuapi_DsNameString *names; + + names = TALLOC_ZERO_ARRAY(mem_ctx, struct drsuapi_DsNameString, argc); + W_ERROR_HAVE_NO_MEMORY(names); + + for (i=0; i<argc; i++) { + names[i].str = argv[i]; + } + + req.req1.codepage = 1252; /* german */ + req.req1.language = 0x00000407; /* german */ + req.req1.count = argc; + req.req1.names = names; + req.req1.format_flags = DRSUAPI_DS_NAME_FLAG_NO_FLAGS; + req.req1.format_offered = format_offered; + req.req1.format_desired = format_desired; + + status = rpccli_drsuapi_DsCrackNames(cli, mem_ctx, + bind_handle, + level, + &req, + &level_out, + ctr, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + return WERR_OK; +} + +static WERROR cmd_drsuapi_cracknames(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status; + WERROR werr; + int i; + + struct GUID bind_guid; + struct policy_handle bind_handle; + + union drsuapi_DsNameCtr ctr; + + if (argc < 2) { + printf("usage: %s name\n", argv[0]); + return WERR_OK; + } + + GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid); + + status = rpccli_drsuapi_DsBind(cli, mem_ctx, + &bind_guid, + NULL, + &bind_handle, + &werr); + + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + werr = cracknames(cli, mem_ctx, + &bind_handle, + DRSUAPI_DS_NAME_FORMAT_UKNOWN, + DRSUAPI_DS_NAME_FORMAT_FQDN_1779, + 1, + argv+1, + &ctr); + + if (!W_ERROR_IS_OK(werr)) { + goto out; + } + + for (i=0; i < ctr.ctr1->count; i++) { + printf("status: %d\n", + ctr.ctr1->array[i].status); + printf("dns_domain_name: %s\n", + ctr.ctr1->array[i].dns_domain_name); + printf("result_name: %s\n", + ctr.ctr1->array[i].result_name); + } + + out: + if (is_valid_policy_hnd(&bind_handle)) { + rpccli_drsuapi_DsUnbind(cli, mem_ctx, &bind_handle, &werr); + } + + return werr; +} + +static void display_domain_controller_info_01(struct drsuapi_DsGetDCConnection01 *r) +{ + printf("client_ip_address:\t%s\n", r->client_ip_address); + printf("unknown2:\t%d\n", r->unknown2); + printf("connection_time:\t%d\n", r->connection_time); + printf("unknown4:\t%d\n", r->unknown4); + printf("unknown5:\t%d\n", r->unknown5); + printf("unknown6:\t%d\n", r->unknown6); + printf("client_account:\t%s\n", r->client_account); +} + +static void display_domain_controller_info_1(struct drsuapi_DsGetDCInfo1 *r) +{ + printf("netbios_name:\t%s\n", r->netbios_name); + printf("dns_name:\t%s\n", r->dns_name); + printf("site_name:\t%s\n", r->site_name); + printf("computer_dn:\t%s\n", r->computer_dn); + printf("server_dn:\t%s\n", r->server_dn); + printf("is_pdc:\t\t%s\n", r->is_pdc ? "true" : "false"); + printf("is_enabled:\t%s\n", r->is_enabled ? "true" : "false"); +} + +static void display_domain_controller_info_2(struct drsuapi_DsGetDCInfo2 *r) +{ + printf("netbios_name:\t%s\n", r->netbios_name); + printf("dns_name:\t%s\n", r->dns_name); + printf("site_name:\t%s\n", r->site_name); + printf("site_dn:\t%s\n", r->site_dn); + printf("computer_dn:\t%s\n", r->computer_dn); + printf("server_dn:\t%s\n", r->server_dn); + printf("ntds_dn:\t%s\n", r->ntds_dn); + printf("is_pdc:\t\t%s\n", r->is_pdc ? "true" : "false"); + printf("is_enabled:\t%s\n", r->is_enabled ? "true" : "false"); + printf("is_gc:\t\t%s\n", r->is_gc ? "true" : "false"); + printf("site_guid:\t%s\n", GUID_string(talloc_tos(), &r->site_guid)); + printf("computer_guid:\t%s\n", GUID_string(talloc_tos(), &r->computer_guid)); + printf("server_guid:\t%s\n", GUID_string(talloc_tos(), &r->server_guid)); + printf("ntds_guid:\t%s\n", GUID_string(talloc_tos(), &r->ntds_guid)); +} + +static void display_domain_controller_info_3(struct drsuapi_DsGetDCInfo3 *r) +{ + printf("netbios_name:\t%s\n", r->netbios_name); + printf("dns_name:\t%s\n", r->dns_name); + printf("site_name:\t%s\n", r->site_name); + printf("site_dn:\t%s\n", r->site_dn); + printf("computer_dn:\t%s\n", r->computer_dn); + printf("server_dn:\t%s\n", r->server_dn); + printf("ntds_dn:\t%s\n", r->ntds_dn); + printf("is_pdc:\t\t%s\n", r->is_pdc ? "true" : "false"); + printf("is_enabled:\t%s\n", r->is_enabled ? "true" : "false"); + printf("is_gc:\t\t%s\n", r->is_gc ? "true" : "false"); + printf("is_rodc:\t%s\n", r->is_rodc ? "true" : "false"); + printf("site_guid:\t%s\n", GUID_string(talloc_tos(), &r->site_guid)); + printf("computer_guid:\t%s\n", GUID_string(talloc_tos(), &r->computer_guid)); + printf("server_guid:\t%s\n", GUID_string(talloc_tos(), &r->server_guid)); + printf("ntds_guid:\t%s\n", GUID_string(talloc_tos(), &r->ntds_guid)); +} + +static void display_domain_controller_info(int32_t level, + union drsuapi_DsGetDCInfoCtr *ctr) +{ + int i; + + switch (level) { + case DRSUAPI_DC_CONNECTION_CTR_01: + for (i=0; i<ctr->ctr01.count; i++) { + printf("----------\n"); + display_domain_controller_info_01(&ctr->ctr01.array[i]); + } + break; + case DRSUAPI_DC_INFO_CTR_1: + for (i=0; i<ctr->ctr1.count; i++) { + printf("----------\n"); + display_domain_controller_info_1(&ctr->ctr1.array[i]); + } + break; + case DRSUAPI_DC_INFO_CTR_2: + for (i=0; i<ctr->ctr2.count; i++) { + printf("----------\n"); + display_domain_controller_info_2(&ctr->ctr2.array[i]); + } + break; + case DRSUAPI_DC_INFO_CTR_3: + for (i=0; i<ctr->ctr3.count; i++) { + printf("----------\n"); + display_domain_controller_info_3(&ctr->ctr3.array[i]); + } + break; + default: + break; + } +} + +static WERROR cmd_drsuapi_getdcinfo(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status; + WERROR werr; + + struct GUID bind_guid; + struct policy_handle bind_handle; + + const char *domain = NULL; + int32_t level = 1; + int32_t level_out; + union drsuapi_DsGetDCInfoRequest req; + union drsuapi_DsGetDCInfoCtr ctr; + + if (argc < 2) { + printf("usage: %s domain [level]\n", argv[0]); + return WERR_OK; + } + + domain = argv[1]; + if (argc >= 3) { + level = atoi(argv[2]); + } + + GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid); + + status = rpccli_drsuapi_DsBind(cli, mem_ctx, + &bind_guid, + NULL, + &bind_handle, + &werr); + + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + req.req1.domain_name = domain; + req.req1.level = level; + + status = rpccli_drsuapi_DsGetDomainControllerInfo(cli, mem_ctx, + &bind_handle, + 1, + &req, + &level_out, + &ctr, + &werr); + if (!NT_STATUS_IS_OK(status)) { + werr = ntstatus_to_werror(status); + goto out; + } + + if (!W_ERROR_IS_OK(werr)) { + goto out; + } + + display_domain_controller_info(level_out, &ctr); + out: + if (is_valid_policy_hnd(&bind_handle)) { + rpccli_drsuapi_DsUnbind(cli, mem_ctx, &bind_handle, &werr); + } + + return werr; +} + +static WERROR cmd_drsuapi_getncchanges(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status; + WERROR werr; + + struct policy_handle bind_handle; + + struct GUID bind_guid; + struct drsuapi_DsBindInfoCtr bind_info; + struct drsuapi_DsBindInfo28 info28; + + const char *nc_dn = NULL; + + DATA_BLOB session_key; + + int32_t level = 8; + bool single = false; + int32_t level_out = 0; + union drsuapi_DsGetNCChangesRequest req; + union drsuapi_DsGetNCChangesCtr ctr; + struct drsuapi_DsReplicaObjectIdentifier nc; + struct dom_sid null_sid; + + struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL; + struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL; + int32_t out_level = 0; + int y; + + uint32_t supported_extensions = 0; + uint32_t replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE | + DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP | + DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS | + DRSUAPI_DS_REPLICA_NEIGHBOUR_RETURN_OBJECT_PARENTS | + DRSUAPI_DS_REPLICA_NEIGHBOUR_NEVER_SYNCED; + + if (argc > 3) { + printf("usage: %s [naming_context_or_object_dn [single]]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + nc_dn = argv[1]; + } + + if (argc == 3) { + if (strequal(argv[2], "single")) { + single = true; + } else { + printf("warning: ignoring unknown argument '%s'\n", + argv[2]); + } + } + + ZERO_STRUCT(info28); + + ZERO_STRUCT(null_sid); + ZERO_STRUCT(req); + + GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid); + + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_BASE; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7; + info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT; + info28.site_guid = GUID_zero(); + info28.pid = 0; + info28.repl_epoch = 0; + + bind_info.length = 28; + bind_info.info.info28 = info28; + + status = rpccli_drsuapi_DsBind(cli, mem_ctx, + &bind_guid, + &bind_info, + &bind_handle, + &werr); + + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + if (bind_info.length == 24) { + supported_extensions = bind_info.info.info24.supported_extensions; + } else if (bind_info.length == 28) { + supported_extensions = bind_info.info.info28.supported_extensions; + } else if (bind_info.length == 48) { + supported_extensions = bind_info.info.info48.supported_extensions; + } + + if (!nc_dn) { + + union drsuapi_DsNameCtr crack_ctr; + const char *name; + + name = talloc_asprintf(mem_ctx, "%s\\", lp_workgroup()); + W_ERROR_HAVE_NO_MEMORY(name); + + werr = cracknames(cli, mem_ctx, + &bind_handle, + DRSUAPI_DS_NAME_FORMAT_UKNOWN, + DRSUAPI_DS_NAME_FORMAT_FQDN_1779, + 1, + &name, + &crack_ctr); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + if (crack_ctr.ctr1->count != 1) { + return WERR_NO_SUCH_DOMAIN; + } + + if (crack_ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) { + return WERR_NO_SUCH_DOMAIN; + } + + nc_dn = talloc_strdup(mem_ctx, crack_ctr.ctr1->array[0].result_name); + W_ERROR_HAVE_NO_MEMORY(nc_dn); + + printf("using: %s\n", nc_dn); + } + + nc.dn = nc_dn; + nc.guid = GUID_zero(); + nc.sid = null_sid; + + if (supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) { + level = 8; + req.req8.naming_context = &nc; + req.req8.replica_flags = replica_flags; + req.req8.max_object_count = 402; + req.req8.max_ndr_size = 402116; + if (single) { + req.req8.extended_op = DRSUAPI_EXOP_REPL_OBJ; + } + } else { + level = 5; + req.req5.naming_context = &nc; + req.req5.replica_flags = replica_flags; + req.req5.max_object_count = 402; + req.req5.max_ndr_size = 402116; + if (single) { + req.req5.extended_op = DRSUAPI_EXOP_REPL_OBJ; + } + } + + for (y=0; ;y++) { + + if (level == 8) { + DEBUG(1,("start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",y, + (long long)req.req8.highwatermark.tmp_highest_usn, + (long long)req.req8.highwatermark.highest_usn)); + } + + status = rpccli_drsuapi_DsGetNCChanges(cli, mem_ctx, + &bind_handle, + level, + &req, + &level_out, + &ctr, + &werr); + if (!NT_STATUS_IS_OK(status)) { + printf("Failed to get NC Changes: %s", + get_friendly_werror_msg(werr)); + goto out; + } + + if (!W_ERROR_IS_OK(werr)) { + status = werror_to_ntstatus(werr); + goto out; + } + + if (level_out == 1) { + out_level = 1; + ctr1 = &ctr.ctr1; + } else if (level_out == 2) { + out_level = 1; + ctr1 = ctr.ctr2.ctr.mszip1.ctr1; + } + + status = cli_get_session_key(mem_ctx, cli, &session_key); + if (!NT_STATUS_IS_OK(status)) { + printf("Failed to get Session Key: %s", + nt_errstr(status)); + return ntstatus_to_werror(status); + } + + if (out_level == 1) { + DEBUG(1,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y, + (long long)ctr1->new_highwatermark.tmp_highest_usn, + (long long)ctr1->new_highwatermark.highest_usn)); +#if 0 + libnet_dssync_decrypt_attributes(mem_ctx, + &session_key, + ctr1->first_object); +#endif + if (ctr1->more_data) { + req.req5.highwatermark = ctr1->new_highwatermark; + continue; + } + } + + if (level_out == 6) { + out_level = 6; + ctr6 = &ctr.ctr6; + } else if (level_out == 7 + && ctr.ctr7.level == 6 + && ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP) { + out_level = 6; + ctr6 = ctr.ctr7.ctr.mszip6.ctr6; + } + + if (out_level == 6) { + DEBUG(1,("end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",y, + (long long)ctr6->new_highwatermark.tmp_highest_usn, + (long long)ctr6->new_highwatermark.highest_usn)); +#if 0 + libnet_dssync_decrypt_attributes(mem_ctx, + &session_key, + ctr6->first_object); +#endif + if (ctr6->more_data) { + req.req8.highwatermark = ctr6->new_highwatermark; + continue; + } + } + + break; + } + + out: + return werr; +} + +/* List of commands exported by this module */ + +struct cmd_set drsuapi_commands[] = { + + { "DRSUAPI" }, + { "dscracknames", RPC_RTYPE_WERROR, NULL, cmd_drsuapi_cracknames, &ndr_table_drsuapi.syntax_id, NULL, "Crack Name", "" }, + { "dsgetdcinfo", RPC_RTYPE_WERROR, NULL, cmd_drsuapi_getdcinfo, &ndr_table_drsuapi.syntax_id, NULL, "Get Domain Controller Info", "" }, + { "dsgetncchanges", RPC_RTYPE_WERROR, NULL, cmd_drsuapi_getncchanges, &ndr_table_drsuapi.syntax_id, NULL, "Get NC Changes", "" }, + { NULL } +}; diff --git a/source3/rpcclient/cmd_dssetup.c b/source3/rpcclient/cmd_dssetup.c new file mode 100644 index 0000000000..f2fd124967 --- /dev/null +++ b/source3/rpcclient/cmd_dssetup.c @@ -0,0 +1,69 @@ +/* + Unix SMB/CIFS implementation. + RPC pipe client + + Copyright (C) Gerald Carter 2002 + Copyright (C) Guenther Deschner 2008 + + 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 <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "rpcclient.h" + +/* Look up domain related information on a remote host */ + +static WERROR cmd_ds_dsrole_getprimarydominfo(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status; + WERROR werr; + union dssetup_DsRoleInfo info; + + status = rpccli_dssetup_DsRoleGetPrimaryDomainInformation(cli, mem_ctx, + DS_ROLE_BASIC_INFORMATION, + &info, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + printf ("Machine Role = [%d]\n", info.basic.role); + + if (info.basic.flags & DS_ROLE_PRIMARY_DS_RUNNING) { + printf("Directory Service is running.\n"); + printf("Domain is in %s mode.\n", + (info.basic.flags & DS_ROLE_PRIMARY_DS_MIXED_MODE) ? "mixed" : "native" ); + } else { + printf("Directory Service not running on server\n"); + } + + return werr; +} + +/* List of commands exported by this module */ + +struct cmd_set ds_commands[] = { + + { "LSARPC-DS" }, + + { "dsroledominfo", RPC_RTYPE_WERROR, NULL, cmd_ds_dsrole_getprimarydominfo, &ndr_table_dssetup.syntax_id, NULL, "Get Primary Domain Information", "" }, + +{ NULL } +}; diff --git a/source3/rpcclient/cmd_echo.c b/source3/rpcclient/cmd_echo.c new file mode 100644 index 0000000000..d90ef3499f --- /dev/null +++ b/source3/rpcclient/cmd_echo.c @@ -0,0 +1,184 @@ +/* + Unix SMB/CIFS implementation. + RPC pipe client + + Copyright (C) Tim Potter 2003 + + 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 <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "rpcclient.h" + +static NTSTATUS cmd_echo_add_one(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + uint32 request = 1, response; + NTSTATUS result; + + if (argc > 2) { + printf("Usage: %s [num]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc == 2) + request = atoi(argv[1]); + + result = rpccli_echo_AddOne(cli, mem_ctx, request, &response); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + printf("%d + 1 = %d\n", request, response); + +done: + return result; +} + +static NTSTATUS cmd_echo_data(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + uint32 size, i; + NTSTATUS result; + uint8_t *in_data = NULL, *out_data = NULL; + + if (argc != 2) { + printf("Usage: %s num\n", argv[0]); + return NT_STATUS_OK; + } + + size = atoi(argv[1]); + if ( (in_data = (uint8_t*)SMB_MALLOC(size)) == NULL ) { + printf("Failure to allocate buff of %d bytes\n", + size); + result = NT_STATUS_NO_MEMORY; + goto done; + } + if ( (out_data = (uint8_t*)SMB_MALLOC(size)) == NULL ) { + printf("Failure to allocate buff of %d bytes\n", + size); + result = NT_STATUS_NO_MEMORY; + goto done; + } + + for (i = 0; i < size; i++) + in_data[i] = i & 0xff; + + result = rpccli_echo_EchoData(cli, mem_ctx, size, in_data, out_data); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + for (i = 0; i < size; i++) { + if (in_data[i] != out_data[i]) { + printf("mismatch at offset %d, %d != %d\n", + i, in_data[i], out_data[i]); + result = NT_STATUS_UNSUCCESSFUL; + } + } + +done: + SAFE_FREE(in_data); + SAFE_FREE(out_data); + + return result; +} + +static NTSTATUS cmd_echo_source_data(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + uint32 size, i; + NTSTATUS result; + uint8_t *out_data = NULL; + + if (argc != 2) { + printf("Usage: %s num\n", argv[0]); + return NT_STATUS_OK; + } + + size = atoi(argv[1]); + if ( (out_data = (uint8_t*)SMB_MALLOC(size)) == NULL ) { + printf("Failure to allocate buff of %d bytes\n", + size); + result = NT_STATUS_NO_MEMORY; + goto done; + } + + + result = rpccli_echo_SourceData(cli, mem_ctx, size, out_data); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + for (i = 0; i < size; i++) { + if (out_data && out_data[i] != (i & 0xff)) { + printf("mismatch at offset %d, %d != %d\n", + i, out_data[i], i & 0xff); + result = NT_STATUS_UNSUCCESSFUL; + } + } + +done: + + SAFE_FREE(out_data); + return result; +} + +static NTSTATUS cmd_echo_sink_data(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + uint32 size, i; + NTSTATUS result; + uint8_t *in_data = NULL; + + if (argc != 2) { + printf("Usage: %s num\n", argv[0]); + return NT_STATUS_OK; + } + + size = atoi(argv[1]); + if ( (in_data = (uint8_t*)SMB_MALLOC(size)) == NULL ) { + printf("Failure to allocate buff of %d bytes\n", + size); + result = NT_STATUS_NO_MEMORY; + goto done; + } + + for (i = 0; i < size; i++) + in_data[i] = i & 0xff; + + result = rpccli_echo_SinkData(cli, mem_ctx, size, in_data); + + if (!NT_STATUS_IS_OK(result)) + goto done; + +done: + SAFE_FREE(in_data); + + return result; +} + +/* List of commands exported by this module */ + +struct cmd_set echo_commands[] = { + + { "ECHO" }, + + { "echoaddone", RPC_RTYPE_NTSTATUS, cmd_echo_add_one, NULL, &ndr_table_rpcecho.syntax_id, NULL, "Add one to a number", "" }, + { "echodata", RPC_RTYPE_NTSTATUS, cmd_echo_data, NULL, &ndr_table_rpcecho.syntax_id, NULL, "Echo data", "" }, + { "sinkdata", RPC_RTYPE_NTSTATUS, cmd_echo_sink_data, NULL, &ndr_table_rpcecho.syntax_id, NULL, "Sink data", "" }, + { "sourcedata", RPC_RTYPE_NTSTATUS, cmd_echo_source_data, NULL, &ndr_table_rpcecho.syntax_id, NULL, "Source data", "" }, + { NULL } +}; diff --git a/source3/rpcclient/cmd_lsarpc.c b/source3/rpcclient/cmd_lsarpc.c new file mode 100644 index 0000000000..5b5b4ff78c --- /dev/null +++ b/source3/rpcclient/cmd_lsarpc.c @@ -0,0 +1,1395 @@ +/* + Unix SMB/CIFS implementation. + RPC pipe client + + Copyright (C) Tim Potter 2000 + Copyright (C) Rafal Szczesniak 2002 + Copyright (C) Guenther Deschner 2008 + + 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 <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "rpcclient.h" + +/* useful function to allow entering a name instead of a SID and + * looking it up automatically */ +static NTSTATUS name_to_sid(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + DOM_SID *sid, const char *name) +{ + POLICY_HND pol; + enum lsa_SidType *sid_types; + NTSTATUS result; + DOM_SID *sids; + + /* maybe its a raw SID */ + if (strncmp(name, "S-", 2) == 0 && + string_to_sid(sid, name)) { + return NT_STATUS_OK; + } + + result = rpccli_lsa_open_policy(cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &pol); + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_lsa_lookup_names(cli, mem_ctx, &pol, 1, &name, NULL, 1, &sids, &sid_types); + if (!NT_STATUS_IS_OK(result)) + goto done; + + rpccli_lsa_Close(cli, mem_ctx, &pol); + + *sid = sids[0]; + +done: + return result; +} + +static void display_query_info_1(struct lsa_AuditLogInfo *r) +{ + d_printf("percent_full:\t%d\n", r->percent_full); + d_printf("log_size:\t%d\n", r->log_size); + d_printf("retention_time:\t%lld\n", (long long)r->retention_time); + d_printf("shutdown_in_progress:\t%d\n", r->shutdown_in_progress); + d_printf("time_to_shutdown:\t%lld\n", (long long)r->time_to_shutdown); + d_printf("next_audit_record:\t%d\n", r->next_audit_record); + d_printf("unknown:\t%d\n", r->unknown); +} + +static void display_query_info_2(struct lsa_AuditEventsInfo *r) +{ + int i; + d_printf("Auditing enabled:\t%d\n", r->auditing_mode); + d_printf("Auditing categories:\t%d\n", r->count); + d_printf("Auditsettings:\n"); + for (i=0; i<r->count; i++) { + const char *val = audit_policy_str(talloc_tos(), r->settings[i]); + const char *policy = audit_description_str(i); + d_printf("%s:\t%s\n", policy, val); + } +} + +static void display_query_info_3(struct lsa_DomainInfo *r) +{ + d_printf("Domain Name: %s\n", r->name.string); + d_printf("Domain Sid: %s\n", sid_string_tos(r->sid)); +} + +static void display_query_info_5(struct lsa_DomainInfo *r) +{ + d_printf("Domain Name: %s\n", r->name.string); + d_printf("Domain Sid: %s\n", sid_string_tos(r->sid)); +} + +static void display_query_info_10(struct lsa_AuditFullSetInfo *r) +{ + d_printf("Shutdown on full: %d\n", r->shutdown_on_full); +} + +static void display_query_info_11(struct lsa_AuditFullQueryInfo *r) +{ + d_printf("Shutdown on full: %d\n", r->shutdown_on_full); + d_printf("Log is full: %d\n", r->log_is_full); + d_printf("Unknown: %d\n", r->unknown); +} + +static void display_query_info_12(struct lsa_DnsDomainInfo *r) +{ + d_printf("Domain NetBios Name: %s\n", r->name.string); + d_printf("Domain DNS Name: %s\n", r->dns_domain.string); + d_printf("Domain Forest Name: %s\n", r->dns_forest.string); + d_printf("Domain Sid: %s\n", sid_string_tos(r->sid)); + d_printf("Domain GUID: %s\n", smb_uuid_string(talloc_tos(), + r->domain_guid)); +} + +static void display_lsa_query_info(union lsa_PolicyInformation *info, + enum lsa_PolicyInfo level) +{ + switch (level) { + case 1: + display_query_info_1(&info->audit_log); + break; + case 2: + display_query_info_2(&info->audit_events); + break; + case 3: + display_query_info_3(&info->domain); + break; + case 5: + display_query_info_5(&info->account_domain); + break; + case 10: + display_query_info_10(&info->auditfullset); + break; + case 11: + display_query_info_11(&info->auditfullquery); + break; + case 12: + display_query_info_12(&info->dns); + break; + default: + printf("can't display info level: %d\n", level); + break; + } +} + +static NTSTATUS cmd_lsa_query_info_policy(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + union lsa_PolicyInformation *info = NULL; + + uint32 info_class = 3; + + if (argc > 2) { + printf("Usage: %s [info_class]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc == 2) + info_class = atoi(argv[1]); + + switch (info_class) { + case 12: + result = rpccli_lsa_open_policy2(cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_lsa_QueryInfoPolicy2(cli, mem_ctx, + &pol, + info_class, + &info); + break; + default: + result = rpccli_lsa_open_policy(cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_lsa_QueryInfoPolicy(cli, mem_ctx, + &pol, + info_class, + &info); + } + + if (NT_STATUS_IS_OK(result)) { + display_lsa_query_info(info, info_class); + } + + rpccli_lsa_Close(cli, mem_ctx, &pol); + + done: + return result; +} + +/* Resolve a list of names to a list of sids */ + +static NTSTATUS cmd_lsa_lookup_names(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + DOM_SID *sids; + enum lsa_SidType *types; + int i; + + if (argc == 1) { + printf("Usage: %s [name1 [name2 [...]]]\n", argv[0]); + return NT_STATUS_OK; + } + + result = rpccli_lsa_open_policy(cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_lsa_lookup_names(cli, mem_ctx, &pol, argc - 1, + (const char**)(argv + 1), NULL, 1, &sids, &types); + + if (!NT_STATUS_IS_OK(result) && NT_STATUS_V(result) != + NT_STATUS_V(STATUS_SOME_UNMAPPED)) + goto done; + + result = NT_STATUS_OK; + + /* Print results */ + + for (i = 0; i < (argc - 1); i++) { + fstring sid_str; + sid_to_fstring(sid_str, &sids[i]); + printf("%s %s (%s: %d)\n", argv[i + 1], sid_str, + sid_type_lookup(types[i]), types[i]); + } + + rpccli_lsa_Close(cli, mem_ctx, &pol); + + done: + return result; +} + +/* Resolve a list of names to a list of sids */ + +static NTSTATUS cmd_lsa_lookup_names_level(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + DOM_SID *sids; + enum lsa_SidType *types; + int i, level; + + if (argc < 3) { + printf("Usage: %s [level] [name1 [name2 [...]]]\n", argv[0]); + return NT_STATUS_OK; + } + + result = rpccli_lsa_open_policy(cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + level = atoi(argv[1]); + + result = rpccli_lsa_lookup_names(cli, mem_ctx, &pol, argc - 2, + (const char**)(argv + 2), NULL, level, &sids, &types); + + if (!NT_STATUS_IS_OK(result) && NT_STATUS_V(result) != + NT_STATUS_V(STATUS_SOME_UNMAPPED)) + goto done; + + result = NT_STATUS_OK; + + /* Print results */ + + for (i = 0; i < (argc - 2); i++) { + fstring sid_str; + sid_to_fstring(sid_str, &sids[i]); + printf("%s %s (%s: %d)\n", argv[i + 2], sid_str, + sid_type_lookup(types[i]), types[i]); + } + + rpccli_lsa_Close(cli, mem_ctx, &pol); + + done: + return result; +} + + +/* Resolve a list of SIDs to a list of names */ + +static NTSTATUS cmd_lsa_lookup_sids(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + DOM_SID *sids; + char **domains; + char **names; + enum lsa_SidType *types; + int i; + + if (argc == 1) { + printf("Usage: %s [sid1 [sid2 [...]]]\n", argv[0]); + return NT_STATUS_OK; + } + + result = rpccli_lsa_open_policy(cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Convert arguments to sids */ + + sids = TALLOC_ARRAY(mem_ctx, DOM_SID, argc - 1); + + if (!sids) { + printf("could not allocate memory for %d sids\n", argc - 1); + goto done; + } + + for (i = 0; i < argc - 1; i++) + if (!string_to_sid(&sids[i], argv[i + 1])) { + result = NT_STATUS_INVALID_SID; + goto done; + } + + /* Lookup the SIDs */ + + result = rpccli_lsa_lookup_sids(cli, mem_ctx, &pol, argc - 1, sids, + &domains, &names, &types); + + if (!NT_STATUS_IS_OK(result) && NT_STATUS_V(result) != + NT_STATUS_V(STATUS_SOME_UNMAPPED)) + goto done; + + result = NT_STATUS_OK; + + /* Print results */ + + for (i = 0; i < (argc - 1); i++) { + fstring sid_str; + + sid_to_fstring(sid_str, &sids[i]); + printf("%s %s\\%s (%d)\n", sid_str, + domains[i] ? domains[i] : "*unknown*", + names[i] ? names[i] : "*unknown*", types[i]); + } + + rpccli_lsa_Close(cli, mem_ctx, &pol); + + done: + return result; +} + +/* Enumerate list of trusted domains */ + +static NTSTATUS cmd_lsa_enum_trust_dom(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + struct lsa_DomainList domain_list; + + /* defaults, but may be changed using params */ + uint32 enum_ctx = 0; + int i; + uint32_t max_size = (uint32_t)-1; + + if (argc > 2) { + printf("Usage: %s [enum context (0)]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc == 2 && argv[1]) { + enum_ctx = atoi(argv[2]); + } + + result = rpccli_lsa_open_policy(cli, mem_ctx, True, + LSA_POLICY_VIEW_LOCAL_INFORMATION, + &pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = STATUS_MORE_ENTRIES; + + while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) { + + /* Lookup list of trusted domains */ + + result = rpccli_lsa_EnumTrustDom(cli, mem_ctx, + &pol, + &enum_ctx, + &domain_list, + max_size); + if (!NT_STATUS_IS_OK(result) && + !NT_STATUS_EQUAL(result, NT_STATUS_NO_MORE_ENTRIES) && + !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) + goto done; + + /* Print results: list of names and sids returned in this + * response. */ + for (i = 0; i < domain_list.count; i++) { + fstring sid_str; + + sid_to_fstring(sid_str, domain_list.domains[i].sid); + printf("%s %s\n", + domain_list.domains[i].name.string ? + domain_list.domains[i].name.string : "*unknown*", + sid_str); + } + } + + rpccli_lsa_Close(cli, mem_ctx, &pol); + done: + return result; +} + +/* Enumerates privileges */ + +static NTSTATUS cmd_lsa_enum_privilege(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + struct lsa_PrivArray priv_array; + + uint32 enum_context=0; + uint32 pref_max_length=0x1000; + int i; + + if (argc > 3) { + printf("Usage: %s [enum context] [max length]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc>=2) + enum_context=atoi(argv[1]); + + if (argc==3) + pref_max_length=atoi(argv[2]); + + result = rpccli_lsa_open_policy(cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_lsa_EnumPrivs(cli, mem_ctx, + &pol, + &enum_context, + &priv_array, + pref_max_length); + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Print results */ + printf("found %d privileges\n\n", priv_array.count); + + for (i = 0; i < priv_array.count; i++) { + printf("%s \t\t%d:%d (0x%x:0x%x)\n", + priv_array.privs[i].name.string ? priv_array.privs[i].name.string : "*unknown*", + priv_array.privs[i].luid.high, + priv_array.privs[i].luid.low, + priv_array.privs[i].luid.high, + priv_array.privs[i].luid.low); + } + + rpccli_lsa_Close(cli, mem_ctx, &pol); + done: + return result; +} + +/* Get privilege name */ + +static NTSTATUS cmd_lsa_get_dispname(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + + uint16 lang_id=0; + uint16 lang_id_sys=0; + uint16 lang_id_desc; + struct lsa_String lsa_name; + struct lsa_StringLarge *description = NULL; + + if (argc != 2) { + printf("Usage: %s privilege name\n", argv[0]); + return NT_STATUS_OK; + } + + result = rpccli_lsa_open_policy(cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + init_lsa_String(&lsa_name, argv[1]); + + result = rpccli_lsa_LookupPrivDisplayName(cli, mem_ctx, + &pol, + &lsa_name, + lang_id, + lang_id_sys, + &description, + &lang_id_desc); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Print results */ + printf("%s -> %s (language: 0x%x)\n", argv[1], description->string, lang_id_desc); + + rpccli_lsa_Close(cli, mem_ctx, &pol); + done: + return result; +} + +/* Enumerate the LSA SIDS */ + +static NTSTATUS cmd_lsa_enum_sids(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + + uint32 enum_context=0; + uint32 pref_max_length=0x1000; + struct lsa_SidArray sid_array; + int i; + + if (argc > 3) { + printf("Usage: %s [enum context] [max length]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc>=2) + enum_context=atoi(argv[1]); + + if (argc==3) + pref_max_length=atoi(argv[2]); + + result = rpccli_lsa_open_policy(cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_lsa_EnumAccounts(cli, mem_ctx, + &pol, + &enum_context, + &sid_array, + pref_max_length); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Print results */ + printf("found %d SIDs\n\n", sid_array.num_sids); + + for (i = 0; i < sid_array.num_sids; i++) { + fstring sid_str; + + sid_to_fstring(sid_str, sid_array.sids[i].sid); + printf("%s\n", sid_str); + } + + rpccli_lsa_Close(cli, mem_ctx, &pol); + done: + return result; +} + +/* Create a new account */ + +static NTSTATUS cmd_lsa_create_account(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND dom_pol; + POLICY_HND user_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 des_access = 0x000f000f; + + DOM_SID sid; + + if (argc != 2 ) { + printf("Usage: %s SID\n", argv[0]); + return NT_STATUS_OK; + } + + result = name_to_sid(cli, mem_ctx, &sid, argv[1]); + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_lsa_open_policy2(cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &dom_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_lsa_CreateAccount(cli, mem_ctx, + &dom_pol, + &sid, + des_access, + &user_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + printf("Account for SID %s successfully created\n\n", argv[1]); + result = NT_STATUS_OK; + + rpccli_lsa_Close(cli, mem_ctx, &dom_pol); + done: + return result; +} + + +/* Enumerate the privileges of an SID */ + +static NTSTATUS cmd_lsa_enum_privsaccounts(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND dom_pol; + POLICY_HND user_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 access_desired = 0x000f000f; + DOM_SID sid; + struct lsa_PrivilegeSet *privs = NULL; + int i; + + if (argc != 2 ) { + printf("Usage: %s SID\n", argv[0]); + return NT_STATUS_OK; + } + + result = name_to_sid(cli, mem_ctx, &sid, argv[1]); + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_lsa_open_policy2(cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &dom_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_lsa_OpenAccount(cli, mem_ctx, + &dom_pol, + &sid, + access_desired, + &user_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_lsa_EnumPrivsAccount(cli, mem_ctx, + &user_pol, + &privs); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Print results */ + printf("found %d privileges for SID %s\n\n", privs->count, argv[1]); + printf("high\tlow\tattribute\n"); + + for (i = 0; i < privs->count; i++) { + printf("%u\t%u\t%u\n", + privs->set[i].luid.high, + privs->set[i].luid.low, + privs->set[i].attribute); + } + + rpccli_lsa_Close(cli, mem_ctx, &dom_pol); + done: + return result; +} + + +/* Enumerate the privileges of an SID via LsaEnumerateAccountRights */ + +static NTSTATUS cmd_lsa_enum_acct_rights(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND dom_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + DOM_SID sid; + struct lsa_RightSet rights; + + int i; + + if (argc != 2 ) { + printf("Usage: %s SID\n", argv[0]); + return NT_STATUS_OK; + } + + result = name_to_sid(cli, mem_ctx, &sid, argv[1]); + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_lsa_open_policy2(cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &dom_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_lsa_EnumAccountRights(cli, mem_ctx, + &dom_pol, + &sid, + &rights); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + printf("found %d privileges for SID %s\n", rights.count, + sid_string_tos(&sid)); + + for (i = 0; i < rights.count; i++) { + printf("\t%s\n", rights.names[i].string); + } + + rpccli_lsa_Close(cli, mem_ctx, &dom_pol); + done: + return result; +} + + +/* add some privileges to a SID via LsaAddAccountRights */ + +static NTSTATUS cmd_lsa_add_acct_rights(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND dom_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + struct lsa_RightSet rights; + DOM_SID sid; + int i; + + if (argc < 3 ) { + printf("Usage: %s SID [rights...]\n", argv[0]); + return NT_STATUS_OK; + } + + result = name_to_sid(cli, mem_ctx, &sid, argv[1]); + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_lsa_open_policy2(cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &dom_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + rights.count = argc-2; + rights.names = TALLOC_ARRAY(mem_ctx, struct lsa_StringLarge, + rights.count); + if (!rights.names) { + return NT_STATUS_NO_MEMORY; + } + + for (i=0; i<argc-1; i++) { + init_lsa_StringLarge(&rights.names[i], argv[i+2]); + } + + result = rpccli_lsa_AddAccountRights(cli, mem_ctx, + &dom_pol, + &sid, + &rights); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + rpccli_lsa_Close(cli, mem_ctx, &dom_pol); + done: + return result; +} + + +/* remove some privileges to a SID via LsaRemoveAccountRights */ + +static NTSTATUS cmd_lsa_remove_acct_rights(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND dom_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + struct lsa_RightSet rights; + DOM_SID sid; + int i; + + if (argc < 3 ) { + printf("Usage: %s SID [rights...]\n", argv[0]); + return NT_STATUS_OK; + } + + result = name_to_sid(cli, mem_ctx, &sid, argv[1]); + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_lsa_open_policy2(cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &dom_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + rights.count = argc-2; + rights.names = TALLOC_ARRAY(mem_ctx, struct lsa_StringLarge, + rights.count); + if (!rights.names) { + return NT_STATUS_NO_MEMORY; + } + + for (i=0; i<argc-2; i++) { + init_lsa_StringLarge(&rights.names[i], argv[i+2]); + } + + result = rpccli_lsa_RemoveAccountRights(cli, mem_ctx, + &dom_pol, + &sid, + false, + &rights); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + rpccli_lsa_Close(cli, mem_ctx, &dom_pol); + + done: + return result; +} + + +/* Get a privilege value given its name */ + +static NTSTATUS cmd_lsa_lookup_priv_value(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + struct lsa_LUID luid; + struct lsa_String name; + + if (argc != 2 ) { + printf("Usage: %s name\n", argv[0]); + return NT_STATUS_OK; + } + + result = rpccli_lsa_open_policy2(cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + init_lsa_String(&name, argv[1]); + + result = rpccli_lsa_LookupPrivValue(cli, mem_ctx, + &pol, + &name, + &luid); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Print results */ + + printf("%u:%u (0x%x:0x%x)\n", luid.high, luid.low, luid.high, luid.low); + + rpccli_lsa_Close(cli, mem_ctx, &pol); + done: + return result; +} + +/* Query LSA security object */ + +static NTSTATUS cmd_lsa_query_secobj(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + SEC_DESC_BUF *sdb; + uint32 sec_info = DACL_SECURITY_INFORMATION; + + if (argc < 1 || argc > 2) { + printf("Usage: %s [sec_info]\n", argv[0]); + return NT_STATUS_OK; + } + + result = rpccli_lsa_open_policy2(cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &pol); + + if (argc == 2) + sscanf(argv[1], "%x", &sec_info); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_lsa_QuerySecurity(cli, mem_ctx, + &pol, + sec_info, + &sdb); + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Print results */ + + display_sec_desc(sdb->sd); + + rpccli_lsa_Close(cli, mem_ctx, &pol); + done: + return result; +} + +static void display_trust_dom_info_4(struct lsa_TrustDomainInfoPassword *p, + uint8_t nt_hash[16]) +{ + char *pwd, *pwd_old; + + DATA_BLOB data = data_blob(NULL, p->password->length); + DATA_BLOB data_old = data_blob(NULL, p->old_password->length); + + memcpy(data.data, p->password->data, p->password->length); + memcpy(data_old.data, p->old_password->data, p->old_password->length); + + pwd = decrypt_trustdom_secret(nt_hash, &data); + pwd_old = decrypt_trustdom_secret(nt_hash, &data_old); + + d_printf("Password:\t%s\n", pwd); + d_printf("Old Password:\t%s\n", pwd_old); + + SAFE_FREE(pwd); + SAFE_FREE(pwd_old); + + data_blob_free(&data); + data_blob_free(&data_old); +} + +static void display_trust_dom_info(TALLOC_CTX *mem_ctx, + union lsa_TrustedDomainInfo *info, + enum lsa_TrustDomInfoEnum info_class, + uint8_t nt_hash[16]) +{ + switch (info_class) { + case LSA_TRUSTED_DOMAIN_INFO_PASSWORD: + display_trust_dom_info_4(&info->password, nt_hash); + break; + default: { + const char *str = NULL; + str = NDR_PRINT_UNION_STRING(mem_ctx, + lsa_TrustedDomainInfo, + info_class, info); + if (str) { + d_printf("%s\n", str); + } + break; + } + } +} + +static NTSTATUS cmd_lsa_query_trustdominfobysid(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + DOM_SID dom_sid; + uint32 access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED; + union lsa_TrustedDomainInfo *info = NULL; + enum lsa_TrustDomInfoEnum info_class = 1; + uint8_t nt_hash[16]; + + if (argc > 3 || argc < 2) { + printf("Usage: %s [sid] [info_class]\n", argv[0]); + return NT_STATUS_OK; + } + + if (!string_to_sid(&dom_sid, argv[1])) + return NT_STATUS_NO_MEMORY; + + if (argc == 3) + info_class = atoi(argv[2]); + + result = rpccli_lsa_open_policy2(cli, mem_ctx, True, access_mask, &pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_lsa_QueryTrustedDomainInfoBySid(cli, mem_ctx, + &pol, + &dom_sid, + info_class, + &info); + if (!NT_STATUS_IS_OK(result)) + goto done; + + if (!rpccli_get_pwd_hash(cli, nt_hash)) { + d_fprintf(stderr, "Could not get pwd hash\n"); + goto done; + } + + display_trust_dom_info(mem_ctx, info, info_class, nt_hash); + + done: + rpccli_lsa_Close(cli, mem_ctx, &pol); + + return result; +} + +static NTSTATUS cmd_lsa_query_trustdominfobyname(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED; + union lsa_TrustedDomainInfo *info = NULL; + enum lsa_TrustDomInfoEnum info_class = 1; + struct lsa_String trusted_domain; + uint8_t nt_hash[16]; + + if (argc > 3 || argc < 2) { + printf("Usage: %s [name] [info_class]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc == 3) + info_class = atoi(argv[2]); + + result = rpccli_lsa_open_policy2(cli, mem_ctx, True, access_mask, &pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + init_lsa_String(&trusted_domain, argv[1]); + + result = rpccli_lsa_QueryTrustedDomainInfoByName(cli, mem_ctx, + &pol, + &trusted_domain, + info_class, + &info); + if (!NT_STATUS_IS_OK(result)) + goto done; + + if (!rpccli_get_pwd_hash(cli, nt_hash)) { + d_fprintf(stderr, "Could not get pwd hash\n"); + goto done; + } + + display_trust_dom_info(mem_ctx, info, info_class, nt_hash); + + done: + rpccli_lsa_Close(cli, mem_ctx, &pol); + + return result; +} + +static NTSTATUS cmd_lsa_query_trustdominfo(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND pol, trustdom_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED; + union lsa_TrustedDomainInfo *info = NULL; + DOM_SID dom_sid; + enum lsa_TrustDomInfoEnum info_class = 1; + uint8_t nt_hash[16]; + + if (argc > 3 || argc < 2) { + printf("Usage: %s [sid] [info_class]\n", argv[0]); + return NT_STATUS_OK; + } + + if (!string_to_sid(&dom_sid, argv[1])) + return NT_STATUS_NO_MEMORY; + + + if (argc == 3) + info_class = atoi(argv[2]); + + result = rpccli_lsa_open_policy2(cli, mem_ctx, True, access_mask, &pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_lsa_OpenTrustedDomain(cli, mem_ctx, + &pol, + &dom_sid, + access_mask, + &trustdom_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_lsa_QueryTrustedDomainInfo(cli, mem_ctx, + &trustdom_pol, + info_class, + &info); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + if (!rpccli_get_pwd_hash(cli, nt_hash)) { + d_fprintf(stderr, "Could not get pwd hash\n"); + goto done; + } + + display_trust_dom_info(mem_ctx, info, info_class, nt_hash); + + done: + rpccli_lsa_Close(cli, mem_ctx, &pol); + + return result; +} + +static NTSTATUS cmd_lsa_get_username(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + const char *servername = cli->desthost; + struct lsa_String *account_name = NULL; + struct lsa_String *authority_name = NULL; + + if (argc > 2) { + printf("Usage: %s servername\n", argv[0]); + return NT_STATUS_OK; + } + + result = rpccli_lsa_open_policy(cli, mem_ctx, true, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &pol); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + result = rpccli_lsa_GetUserName(cli, mem_ctx, + servername, + &account_name, + &authority_name); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + /* Print results */ + + printf("Account Name: %s, Authority Name: %s\n", + account_name->string, authority_name->string); + + rpccli_lsa_Close(cli, mem_ctx, &pol); + done: + return result; +} + +static NTSTATUS cmd_lsa_add_priv(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND dom_pol, user_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + struct lsa_PrivilegeSet privs; + struct lsa_LUIDAttribute *set = NULL; + DOM_SID sid; + int i; + + ZERO_STRUCT(privs); + + if (argc < 3 ) { + printf("Usage: %s SID [rights...]\n", argv[0]); + return NT_STATUS_OK; + } + + result = name_to_sid(cli, mem_ctx, &sid, argv[1]); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + result = rpccli_lsa_open_policy2(cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &dom_pol); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + result = rpccli_lsa_OpenAccount(cli, mem_ctx, + &dom_pol, + &sid, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &user_pol); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + for (i=2; i<argc; i++) { + + struct lsa_String priv_name; + struct lsa_LUID luid; + + init_lsa_String(&priv_name, argv[i]); + + result = rpccli_lsa_LookupPrivValue(cli, mem_ctx, + &dom_pol, + &priv_name, + &luid); + if (!NT_STATUS_IS_OK(result)) { + continue; + } + + privs.count++; + set = TALLOC_REALLOC_ARRAY(mem_ctx, set, + struct lsa_LUIDAttribute, + privs.count); + if (!set) { + return NT_STATUS_NO_MEMORY; + } + + set[privs.count-1].luid = luid; + set[privs.count-1].attribute = 0; + } + + privs.set = set; + + result = rpccli_lsa_AddPrivilegesToAccount(cli, mem_ctx, + &user_pol, + &privs); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + rpccli_lsa_Close(cli, mem_ctx, &user_pol); + rpccli_lsa_Close(cli, mem_ctx, &dom_pol); + done: + return result; +} + +static NTSTATUS cmd_lsa_del_priv(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND dom_pol, user_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + struct lsa_PrivilegeSet privs; + struct lsa_LUIDAttribute *set = NULL; + DOM_SID sid; + int i; + + ZERO_STRUCT(privs); + + if (argc < 3 ) { + printf("Usage: %s SID [rights...]\n", argv[0]); + return NT_STATUS_OK; + } + + result = name_to_sid(cli, mem_ctx, &sid, argv[1]); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + result = rpccli_lsa_open_policy2(cli, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &dom_pol); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + result = rpccli_lsa_OpenAccount(cli, mem_ctx, + &dom_pol, + &sid, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &user_pol); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + for (i=2; i<argc; i++) { + + struct lsa_String priv_name; + struct lsa_LUID luid; + + init_lsa_String(&priv_name, argv[i]); + + result = rpccli_lsa_LookupPrivValue(cli, mem_ctx, + &dom_pol, + &priv_name, + &luid); + if (!NT_STATUS_IS_OK(result)) { + continue; + } + + privs.count++; + set = TALLOC_REALLOC_ARRAY(mem_ctx, set, + struct lsa_LUIDAttribute, + privs.count); + if (!set) { + return NT_STATUS_NO_MEMORY; + } + + set[privs.count-1].luid = luid; + set[privs.count-1].attribute = 0; + } + + privs.set = set; + + + result = rpccli_lsa_RemovePrivilegesFromAccount(cli, mem_ctx, + &user_pol, + false, + &privs); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + rpccli_lsa_Close(cli, mem_ctx, &user_pol); + rpccli_lsa_Close(cli, mem_ctx, &dom_pol); + done: + return result; +} + + +/* List of commands exported by this module */ + +struct cmd_set lsarpc_commands[] = { + + { "LSARPC" }, + + { "lsaquery", RPC_RTYPE_NTSTATUS, cmd_lsa_query_info_policy, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Query info policy", "" }, + { "lookupsids", RPC_RTYPE_NTSTATUS, cmd_lsa_lookup_sids, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Convert SIDs to names", "" }, + { "lookupnames", RPC_RTYPE_NTSTATUS, cmd_lsa_lookup_names, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Convert names to SIDs", "" }, + { "lookupnames_level", RPC_RTYPE_NTSTATUS, cmd_lsa_lookup_names_level, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Convert names to SIDs", "" }, + { "enumtrust", RPC_RTYPE_NTSTATUS, cmd_lsa_enum_trust_dom, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Enumerate trusted domains", "Usage: [preferred max number] [enum context (0)]" }, + { "enumprivs", RPC_RTYPE_NTSTATUS, cmd_lsa_enum_privilege, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Enumerate privileges", "" }, + { "getdispname", RPC_RTYPE_NTSTATUS, cmd_lsa_get_dispname, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Get the privilege name", "" }, + { "lsaenumsid", RPC_RTYPE_NTSTATUS, cmd_lsa_enum_sids, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Enumerate the LSA SIDS", "" }, + { "lsacreateaccount", RPC_RTYPE_NTSTATUS, cmd_lsa_create_account, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Create a new lsa account", "" }, + { "lsaenumprivsaccount", RPC_RTYPE_NTSTATUS, cmd_lsa_enum_privsaccounts, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Enumerate the privileges of an SID", "" }, + { "lsaenumacctrights", RPC_RTYPE_NTSTATUS, cmd_lsa_enum_acct_rights, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Enumerate the rights of an SID", "" }, + { "lsaaddpriv", RPC_RTYPE_NTSTATUS, cmd_lsa_add_priv, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Assign a privilege to a SID", "" }, + { "lsadelpriv", RPC_RTYPE_NTSTATUS, cmd_lsa_del_priv, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Revoke a privilege from a SID", "" }, + { "lsaaddacctrights", RPC_RTYPE_NTSTATUS, cmd_lsa_add_acct_rights, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Add rights to an account", "" }, + { "lsaremoveacctrights", RPC_RTYPE_NTSTATUS, cmd_lsa_remove_acct_rights, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Remove rights from an account", "" }, + { "lsalookupprivvalue", RPC_RTYPE_NTSTATUS, cmd_lsa_lookup_priv_value, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Get a privilege value given its name", "" }, + { "lsaquerysecobj", RPC_RTYPE_NTSTATUS, cmd_lsa_query_secobj, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Query LSA security object", "" }, + { "lsaquerytrustdominfo",RPC_RTYPE_NTSTATUS, cmd_lsa_query_trustdominfo, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Query LSA trusted domains info (given a SID)", "" }, + { "lsaquerytrustdominfobyname",RPC_RTYPE_NTSTATUS, cmd_lsa_query_trustdominfobyname, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Query LSA trusted domains info (given a name), only works for Windows > 2k", "" }, + { "lsaquerytrustdominfobysid",RPC_RTYPE_NTSTATUS, cmd_lsa_query_trustdominfobysid, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Query LSA trusted domains info (given a SID)", "" }, + { "getusername", RPC_RTYPE_NTSTATUS, cmd_lsa_get_username, NULL, &ndr_table_lsarpc.syntax_id, NULL, "Get username", "" }, + + { NULL } +}; + diff --git a/source3/rpcclient/cmd_netlogon.c b/source3/rpcclient/cmd_netlogon.c new file mode 100644 index 0000000000..87ba65c14b --- /dev/null +++ b/source3/rpcclient/cmd_netlogon.c @@ -0,0 +1,1034 @@ +/* + Unix SMB/CIFS implementation. + RPC pipe client + + Copyright (C) Tim Potter 2000 + Copyright (C) Guenther Deschner 2008 + + 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 <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "rpcclient.h" + +static WERROR cmd_netlogon_logon_ctrl2(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + WERROR werr; + const char *logon_server = cli->desthost; + enum netr_LogonControlCode function_code = NETLOGON_CONTROL_REDISCOVER; + uint32_t level = 1; + union netr_CONTROL_DATA_INFORMATION data; + union netr_CONTROL_QUERY_INFORMATION query; + const char *domain = lp_workgroup(); + + if (argc > 5) { + fprintf(stderr, "Usage: %s <logon_server> <function_code> " + "<level> <domain>\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + logon_server = argv[1]; + } + + if (argc >= 3) { + function_code = atoi(argv[2]); + } + + if (argc >= 4) { + level = atoi(argv[3]); + } + + if (argc >= 5) { + domain = argv[4]; + } + + switch (function_code) { + case NETLOGON_CONTROL_REDISCOVER: + case NETLOGON_CONTROL_TC_QUERY: + data.domain = domain; + break; + default: + break; + } + + status = rpccli_netr_LogonControl2(cli, mem_ctx, + logon_server, + function_code, + level, + &data, + &query, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + /* Display results */ + + return werr; +} + +static WERROR cmd_netlogon_getanydcname(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + const char *dcname = NULL; + WERROR werr; + NTSTATUS status; + int old_timeout; + + if (argc != 2) { + fprintf(stderr, "Usage: %s domainname\n", argv[0]); + return WERR_OK; + } + + /* Make sure to wait for our DC's reply */ + old_timeout = rpccli_set_timeout(cli, 30000); /* 30 seconds. */ + rpccli_set_timeout(cli, MAX(old_timeout, 30000)); /* At least 30 sec */ + + status = rpccli_netr_GetAnyDCName(cli, mem_ctx, + cli->desthost, + argv[1], + &dcname, + &werr); + rpccli_set_timeout(cli, old_timeout); + + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + /* Display results */ + + printf("%s\n", dcname); + + return werr; +} + +static WERROR cmd_netlogon_getdcname(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + const char *dcname = NULL; + NTSTATUS status; + WERROR werr; + int old_timeout; + + if (argc != 2) { + fprintf(stderr, "Usage: %s domainname\n", argv[0]); + return WERR_OK; + } + + /* Make sure to wait for our DC's reply */ + old_timeout = rpccli_set_timeout(cli, 30000); /* 30 seconds. */ + rpccli_set_timeout(cli, MAX(30000, old_timeout)); /* At least 30 sec */ + + status = rpccli_netr_GetDcName(cli, mem_ctx, + cli->desthost, + argv[1], + &dcname, + &werr); + rpccli_set_timeout(cli, old_timeout); + + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + /* Display results */ + + printf("%s\n", dcname); + + return werr; +} + +static WERROR cmd_netlogon_dsr_getdcname(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS result; + WERROR werr = WERR_OK; + uint32 flags = DS_RETURN_DNS_NAME; + const char *server_name = cli->desthost; + const char *domain_name; + struct GUID domain_guid = GUID_zero(); + struct GUID site_guid = GUID_zero(); + struct netr_DsRGetDCNameInfo *info = NULL; + + if (argc < 2) { + fprintf(stderr, "Usage: %s [domain_name] [domain_guid] " + "[site_guid] [flags]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) + domain_name = argv[1]; + + if (argc >= 3) { + if (!NT_STATUS_IS_OK(GUID_from_string(argv[2], &domain_guid))) { + return WERR_NOMEM; + } + } + + if (argc >= 4) { + if (!NT_STATUS_IS_OK(GUID_from_string(argv[3], &site_guid))) { + return WERR_NOMEM; + } + } + + if (argc >= 5) + sscanf(argv[4], "%x", &flags); + + debug_dsdcinfo_flags(1,flags); + + result = rpccli_netr_DsRGetDCName(cli, mem_ctx, + server_name, + domain_name, + &domain_guid, + &site_guid, + flags, + &info, + &werr); + + if (W_ERROR_IS_OK(werr)) { + d_printf("DsGetDcName gave: %s\n", + NDR_PRINT_STRUCT_STRING(mem_ctx, netr_DsRGetDCNameInfo, info)); + return WERR_OK; + } + + printf("rpccli_netlogon_dsr_getdcname returned %s\n", + dos_errstr(werr)); + + return werr; +} + +static WERROR cmd_netlogon_dsr_getdcnameex(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + WERROR result; + NTSTATUS status; + uint32_t flags = DS_RETURN_DNS_NAME; + const char *server_name = cli->desthost; + const char *domain_name; + const char *site_name = NULL; + struct GUID domain_guid = GUID_zero(); + struct netr_DsRGetDCNameInfo *info = NULL; + + if (argc < 2) { + fprintf(stderr, "Usage: %s [domain_name] [domain_guid] " + "[site_name] [flags]\n", argv[0]); + return WERR_OK; + } + + domain_name = argv[1]; + + if (argc >= 3) { + if (!NT_STATUS_IS_OK(GUID_from_string(argv[2], &domain_guid))) { + return WERR_NOMEM; + } + } + + if (argc >= 4) { + site_name = argv[3]; + } + + if (argc >= 5) { + sscanf(argv[4], "%x", &flags); + } + + debug_dsdcinfo_flags(1,flags); + + status = rpccli_netr_DsRGetDCNameEx(cli, mem_ctx, + server_name, + domain_name, + &domain_guid, + site_name, + flags, + &info, + &result); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(result)) { + return result; + } + + d_printf("DsRGetDCNameEx gave %s\n", + NDR_PRINT_STRUCT_STRING(mem_ctx, netr_DsRGetDCNameInfo, info)); + + return result; +} + +static WERROR cmd_netlogon_dsr_getdcnameex2(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + WERROR result; + NTSTATUS status; + uint32_t flags = DS_RETURN_DNS_NAME; + const char *server_name = cli->desthost; + const char *domain_name = NULL; + const char *client_account = NULL; + uint32_t mask = 0; + const char *site_name = NULL; + struct GUID domain_guid = GUID_zero(); + struct netr_DsRGetDCNameInfo *info = NULL; + + if (argc < 2) { + fprintf(stderr, "Usage: %s [client_account] [acb_mask] " + "[domain_name] [domain_guid] [site_name] " + "[flags]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + client_account = argv[1]; + } + + if (argc >= 3) { + mask = atoi(argv[2]); + } + + if (argc >= 4) { + domain_name = argv[3]; + } + + if (argc >= 5) { + if (!NT_STATUS_IS_OK(GUID_from_string(argv[4], &domain_guid))) { + return WERR_NOMEM; + } + } + + if (argc >= 6) { + site_name = argv[5]; + } + + if (argc >= 7) { + sscanf(argv[6], "%x", &flags); + } + + debug_dsdcinfo_flags(1,flags); + + status = rpccli_netr_DsRGetDCNameEx2(cli, mem_ctx, + server_name, + client_account, + mask, + domain_name, + &domain_guid, + site_name, + flags, + &info, + &result); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(result)) { + return result; + } + + d_printf("DsRGetDCNameEx2 gave %s\n", + NDR_PRINT_STRUCT_STRING(mem_ctx, netr_DsRGetDCNameInfo, info)); + + return result; +} + + +static WERROR cmd_netlogon_dsr_getsitename(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + WERROR werr; + NTSTATUS status; + const char *sitename = NULL; + + if (argc != 2) { + fprintf(stderr, "Usage: %s computername\n", argv[0]); + return WERR_OK; + } + + status = rpccli_netr_DsRGetSiteName(cli, mem_ctx, + argv[1], + &sitename, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(werr)) { + printf("rpccli_netlogon_dsr_gesitename returned %s\n", + nt_errstr(werror_to_ntstatus(werr))); + return werr; + } + + printf("Computer %s is on Site: %s\n", argv[1], sitename); + + return WERR_OK; +} + +static WERROR cmd_netlogon_logon_ctrl(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + WERROR werr; + const char *logon_server = cli->desthost; + enum netr_LogonControlCode function_code = 1; + uint32_t level = 1; + union netr_CONTROL_QUERY_INFORMATION info; + + if (argc > 4) { + fprintf(stderr, "Usage: %s <logon_server> <function_code> " + "<level>\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + logon_server = argv[1]; + } + + if (argc >= 3) { + function_code = atoi(argv[2]); + } + + if (argc >= 4) { + level = atoi(argv[3]); + } + + status = rpccli_netr_LogonControl(cli, mem_ctx, + logon_server, + function_code, + level, + &info, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + /* Display results */ + + return werr; +} + +/* Display sam synchronisation information */ + +static void display_sam_sync(struct netr_DELTA_ENUM_ARRAY *r) +{ + uint32_t i, j; + + for (i=0; i < r->num_deltas; i++) { + + union netr_DELTA_UNION u = r->delta_enum[i].delta_union; + union netr_DELTA_ID_UNION id = r->delta_enum[i].delta_id_union; + + switch (r->delta_enum[i].delta_type) { + case NETR_DELTA_DOMAIN: + printf("Domain: %s\n", + u.domain->domain_name.string); + break; + case NETR_DELTA_GROUP: + printf("Group: %s\n", + u.group->group_name.string); + break; + case NETR_DELTA_DELETE_GROUP: + printf("Delete Group: %d\n", + u.delete_account.unknown); + break; + case NETR_DELTA_RENAME_GROUP: + printf("Rename Group: %s -> %s\n", + u.rename_group->OldName.string, + u.rename_group->NewName.string); + break; + case NETR_DELTA_USER: + printf("Account: %s\n", + u.user->account_name.string); + break; + case NETR_DELTA_DELETE_USER: + printf("Delete User: %d\n", + id.rid); + break; + case NETR_DELTA_RENAME_USER: + printf("Rename user: %s -> %s\n", + u.rename_user->OldName.string, + u.rename_user->NewName.string); + break; + case NETR_DELTA_GROUP_MEMBER: + for (j=0; j < u.group_member->num_rids; j++) { + printf("rid 0x%x, attrib 0x%08x\n", + u.group_member->rids[j], + u.group_member->attribs[j]); + } + break; + case NETR_DELTA_ALIAS: + printf("Alias: %s\n", + u.alias->alias_name.string); + break; + case NETR_DELTA_DELETE_ALIAS: + printf("Delete Alias: %d\n", + r->delta_enum[i].delta_id_union.rid); + break; + case NETR_DELTA_RENAME_ALIAS: + printf("Rename alias: %s -> %s\n", + u.rename_alias->OldName.string, + u.rename_alias->NewName.string); + break; + case NETR_DELTA_ALIAS_MEMBER: + for (j=0; j < u.alias_member->sids.num_sids; j++) { + fstring sid_str; + sid_to_fstring(sid_str, + u.alias_member->sids.sids[j].sid); + printf("%s\n", sid_str); + } + break; + case NETR_DELTA_POLICY: + printf("Policy\n"); + break; + case NETR_DELTA_TRUSTED_DOMAIN: + printf("Trusted Domain: %s\n", + u.trusted_domain->domain_name.string); + break; + case NETR_DELTA_DELETE_TRUST: + printf("Delete Trust: %d\n", + u.delete_trust.unknown); + break; + case NETR_DELTA_ACCOUNT: + printf("Account\n"); + break; + case NETR_DELTA_DELETE_ACCOUNT: + printf("Delete Account: %d\n", + u.delete_account.unknown); + break; + case NETR_DELTA_SECRET: + printf("Secret\n"); + break; + case NETR_DELTA_DELETE_SECRET: + printf("Delete Secret: %d\n", + u.delete_secret.unknown); + break; + case NETR_DELTA_DELETE_GROUP2: + printf("Delete Group2: %s\n", + u.delete_group->account_name); + break; + case NETR_DELTA_DELETE_USER2: + printf("Delete User2: %s\n", + u.delete_user->account_name); + break; + case NETR_DELTA_MODIFY_COUNT: + printf("sam sequence update: 0x%016llx\n", + (unsigned long long) *u.modified_count); + break; + default: + printf("unknown delta type 0x%02x\n", + r->delta_enum[i].delta_type); + break; + } + } +} + +/* Perform sam synchronisation */ + +static NTSTATUS cmd_netlogon_sam_sync(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + const char *logon_server = cli->desthost; + const char *computername = global_myname(); + struct netr_Authenticator credential; + struct netr_Authenticator return_authenticator; + enum netr_SamDatabaseID database_id = SAM_DATABASE_DOMAIN; + uint16_t restart_state = 0; + uint32_t sync_context = 0; + + if (argc > 2) { + fprintf(stderr, "Usage: %s [database_id]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc == 2) { + database_id = atoi(argv[1]); + } + + /* Synchronise sam database */ + + do { + struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL; + + netlogon_creds_client_step(cli->dc, &credential); + + result = rpccli_netr_DatabaseSync2(cli, mem_ctx, + logon_server, + computername, + &credential, + &return_authenticator, + database_id, + restart_state, + &sync_context, + &delta_enum_array, + 0xffff); + + /* Check returned credentials. */ + if (!netlogon_creds_client_check(cli->dc, + &return_authenticator.cred)) { + DEBUG(0,("credentials chain check failed\n")); + return NT_STATUS_ACCESS_DENIED; + } + + if (NT_STATUS_IS_ERR(result)) { + break; + } + + /* Display results */ + + display_sam_sync(delta_enum_array); + + TALLOC_FREE(delta_enum_array); + + } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)); + + return result; +} + +/* Perform sam delta synchronisation */ + +static NTSTATUS cmd_netlogon_sam_deltas(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32_t tmp; + const char *logon_server = cli->desthost; + const char *computername = global_myname(); + struct netr_Authenticator credential; + struct netr_Authenticator return_authenticator; + enum netr_SamDatabaseID database_id = SAM_DATABASE_DOMAIN; + uint64_t sequence_num; + + if (argc != 3) { + fprintf(stderr, "Usage: %s database_id seqnum\n", argv[0]); + return NT_STATUS_OK; + } + + database_id = atoi(argv[1]); + tmp = atoi(argv[2]); + + sequence_num = tmp & 0xffff; + + do { + struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL; + + netlogon_creds_client_step(cli->dc, &credential); + + result = rpccli_netr_DatabaseDeltas(cli, mem_ctx, + logon_server, + computername, + &credential, + &return_authenticator, + database_id, + &sequence_num, + &delta_enum_array, + 0xffff); + + /* Check returned credentials. */ + if (!netlogon_creds_client_check(cli->dc, + &return_authenticator.cred)) { + DEBUG(0,("credentials chain check failed\n")); + return NT_STATUS_ACCESS_DENIED; + } + + if (NT_STATUS_IS_ERR(result)) { + break; + } + + /* Display results */ + + display_sam_sync(delta_enum_array); + + TALLOC_FREE(delta_enum_array); + + } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)); + + return result; +} + +/* Log on a domain user */ + +static NTSTATUS cmd_netlogon_sam_logon(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + int logon_type = NET_LOGON_TYPE; + const char *username, *password; + int auth_level = 2; + uint32 logon_param = 0; + const char *workstation = NULL; + + /* Check arguments */ + + if (argc < 3 || argc > 7) { + fprintf(stderr, "Usage: samlogon <username> <password> [workstation]" + "[logon_type (1 or 2)] [auth level (2 or 3)] [logon_parameter]\n"); + return NT_STATUS_OK; + } + + username = argv[1]; + password = argv[2]; + + if (argc >= 4) + workstation = argv[3]; + + if (argc >= 5) + sscanf(argv[4], "%i", &logon_type); + + if (argc >= 6) + sscanf(argv[5], "%i", &auth_level); + + if (argc == 7) + sscanf(argv[6], "%x", &logon_param); + + /* Perform the sam logon */ + + result = rpccli_netlogon_sam_logon(cli, mem_ctx, logon_param, lp_workgroup(), username, password, workstation, logon_type); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + done: + return result; +} + +/* Change the trust account password */ + +static NTSTATUS cmd_netlogon_change_trust_pw(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + + /* Check arguments */ + + if (argc > 1) { + fprintf(stderr, "Usage: change_trust_pw"); + return NT_STATUS_OK; + } + + /* Perform the sam logon */ + + result = trust_pw_find_change_and_store_it(cli, mem_ctx, + lp_workgroup()); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + done: + return result; +} + +static WERROR cmd_netlogon_gettrustrid(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + WERROR werr = WERR_GENERAL_FAILURE; + const char *server_name = cli->desthost; + const char *domain_name = lp_workgroup(); + uint32_t rid = 0; + + if (argc < 1 || argc > 3) { + fprintf(stderr, "Usage: %s <server_name> <domain_name>\n", + argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + server_name = argv[1]; + } + + if (argc >= 3) { + domain_name = argv[2]; + } + + status = rpccli_netr_LogonGetTrustRid(cli, mem_ctx, + server_name, + domain_name, + &rid, + &werr); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + if (W_ERROR_IS_OK(werr)) { + printf("Rid: %d\n", rid); + } + done: + return werr; +} + +static WERROR cmd_netlogon_dsr_enumtrustdom(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + WERROR werr = WERR_GENERAL_FAILURE; + const char *server_name = cli->desthost; + uint32_t trust_flags = NETR_TRUST_FLAG_IN_FOREST; + struct netr_DomainTrustList trusts; + + if (argc < 1 || argc > 3) { + fprintf(stderr, "Usage: %s <server_name> <trust_flags>\n", + argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + server_name = argv[1]; + } + + if (argc >= 3) { + sscanf(argv[2], "%x", &trust_flags); + } + + status = rpccli_netr_DsrEnumerateDomainTrusts(cli, mem_ctx, + server_name, + trust_flags, + &trusts, + &werr); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + if (W_ERROR_IS_OK(werr)) { + int i; + + printf("%d domains returned\n", trusts.count); + + for (i=0; i<trusts.count; i++ ) { + printf("%s (%s)\n", + trusts.array[i].dns_name, + trusts.array[i].netbios_name); + } + } + done: + return werr; +} + +static WERROR cmd_netlogon_deregisterdnsrecords(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + WERROR werr = WERR_GENERAL_FAILURE; + const char *server_name = cli->desthost; + const char *domain = lp_workgroup(); + const char *dns_host = NULL; + + if (argc < 1 || argc > 4) { + fprintf(stderr, "Usage: %s <server_name> <domain_name> " + "<dns_host>\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + server_name = argv[1]; + } + + if (argc >= 3) { + domain = argv[2]; + } + + if (argc >= 4) { + dns_host = argv[3]; + } + + status = rpccli_netr_DsrDeregisterDNSHostRecords(cli, mem_ctx, + server_name, + domain, + NULL, + NULL, + dns_host, + &werr); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + if (W_ERROR_IS_OK(werr)) { + printf("success\n"); + } + done: + return werr; +} + +static WERROR cmd_netlogon_dsr_getforesttrustinfo(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + WERROR werr = WERR_GENERAL_FAILURE; + const char *server_name = cli->desthost; + const char *trusted_domain_name = NULL; + struct lsa_ForestTrustInformation *info = NULL; + uint32_t flags = 0; + + if (argc < 1 || argc > 4) { + fprintf(stderr, "Usage: %s <server_name> <trusted_domain_name> " + "<flags>\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + server_name = argv[1]; + } + + if (argc >= 3) { + trusted_domain_name = argv[2]; + } + + if (argc >= 4) { + sscanf(argv[3], "%x", &flags); + } + + status = rpccli_netr_DsRGetForestTrustInformation(cli, mem_ctx, + server_name, + trusted_domain_name, + flags, + &info, + &werr); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + if (W_ERROR_IS_OK(werr)) { + printf("success\n"); + } + done: + return werr; +} + +static WERROR cmd_netlogon_enumtrusteddomains(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + WERROR werr = WERR_GENERAL_FAILURE; + const char *server_name = cli->desthost; + struct netr_Blob blob; + + + if (argc < 1 || argc > 3) { + fprintf(stderr, "Usage: %s <server_name>\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + server_name = argv[1]; + } + + status = rpccli_netr_NetrEnumerateTrustedDomains(cli, mem_ctx, + server_name, + &blob, + &werr); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + if (W_ERROR_IS_OK(werr)) { + printf("success\n"); + dump_data(1, blob.data, blob.length); + } + done: + return werr; +} + +static WERROR cmd_netlogon_enumtrusteddomainsex(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + WERROR werr = WERR_GENERAL_FAILURE; + const char *server_name = cli->desthost; + struct netr_DomainTrustList list; + + if (argc < 1 || argc > 3) { + fprintf(stderr, "Usage: %s <server_name>\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + server_name = argv[1]; + } + + status = rpccli_netr_NetrEnumerateTrustedDomainsEx(cli, mem_ctx, + server_name, + &list, + &werr); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + if (W_ERROR_IS_OK(werr)) { + printf("success\n"); + } + done: + return werr; +} + + +/* List of commands exported by this module */ + +struct cmd_set netlogon_commands[] = { + + { "NETLOGON" }, + + { "logonctrl2", RPC_RTYPE_WERROR, NULL, cmd_netlogon_logon_ctrl2, &ndr_table_netlogon.syntax_id, NULL, "Logon Control 2", "" }, + { "getanydcname", RPC_RTYPE_WERROR, NULL, cmd_netlogon_getanydcname, &ndr_table_netlogon.syntax_id, NULL, "Get trusted DC name", "" }, + { "getdcname", RPC_RTYPE_WERROR, NULL, cmd_netlogon_getdcname, &ndr_table_netlogon.syntax_id, NULL, "Get trusted PDC name", "" }, + { "dsr_getdcname", RPC_RTYPE_WERROR, NULL, cmd_netlogon_dsr_getdcname, &ndr_table_netlogon.syntax_id, NULL, "Get trusted DC name", "" }, + { "dsr_getdcnameex", RPC_RTYPE_WERROR, NULL, cmd_netlogon_dsr_getdcnameex, &ndr_table_netlogon.syntax_id, NULL, "Get trusted DC name", "" }, + { "dsr_getdcnameex2", RPC_RTYPE_WERROR, NULL, cmd_netlogon_dsr_getdcnameex2, &ndr_table_netlogon.syntax_id, NULL, "Get trusted DC name", "" }, + { "dsr_getsitename", RPC_RTYPE_WERROR, NULL, cmd_netlogon_dsr_getsitename, &ndr_table_netlogon.syntax_id, NULL, "Get sitename", "" }, + { "dsr_getforesttrustinfo", RPC_RTYPE_WERROR, NULL, cmd_netlogon_dsr_getforesttrustinfo, &ndr_table_netlogon.syntax_id, NULL, "Get Forest Trust Info", "" }, + { "logonctrl", RPC_RTYPE_WERROR, NULL, cmd_netlogon_logon_ctrl, &ndr_table_netlogon.syntax_id, NULL, "Logon Control", "" }, + { "samsync", RPC_RTYPE_NTSTATUS, cmd_netlogon_sam_sync, NULL, &ndr_table_netlogon.syntax_id, NULL, "Sam Synchronisation", "" }, + { "samdeltas", RPC_RTYPE_NTSTATUS, cmd_netlogon_sam_deltas, NULL, &ndr_table_netlogon.syntax_id, NULL, "Query Sam Deltas", "" }, + { "samlogon", RPC_RTYPE_NTSTATUS, cmd_netlogon_sam_logon, NULL, &ndr_table_netlogon.syntax_id, NULL, "Sam Logon", "" }, + { "change_trust_pw", RPC_RTYPE_NTSTATUS, cmd_netlogon_change_trust_pw, NULL, &ndr_table_netlogon.syntax_id, NULL, "Change Trust Account Password", "" }, + { "gettrustrid", RPC_RTYPE_WERROR, NULL, cmd_netlogon_gettrustrid, &ndr_table_netlogon.syntax_id, NULL, "Get trust rid", "" }, + { "dsr_enumtrustdom", RPC_RTYPE_WERROR, NULL, cmd_netlogon_dsr_enumtrustdom, &ndr_table_netlogon.syntax_id, NULL, "Enumerate trusted domains", "" }, + { "dsenumdomtrusts", RPC_RTYPE_WERROR, NULL, cmd_netlogon_dsr_enumtrustdom, &ndr_table_netlogon.syntax_id, NULL, "Enumerate all trusted domains in an AD forest", "" }, + { "deregisterdnsrecords", RPC_RTYPE_WERROR, NULL, cmd_netlogon_deregisterdnsrecords, &ndr_table_netlogon.syntax_id, NULL, "Deregister DNS records", "" }, + { "netrenumtrusteddomains", RPC_RTYPE_WERROR, NULL, cmd_netlogon_enumtrusteddomains, &ndr_table_netlogon.syntax_id, NULL, "Enumerate trusted domains", "" }, + { "netrenumtrusteddomainsex", RPC_RTYPE_WERROR, NULL, cmd_netlogon_enumtrusteddomainsex, &ndr_table_netlogon.syntax_id, NULL, "Enumerate trusted domains", "" }, + + { NULL } +}; diff --git a/source3/rpcclient/cmd_ntsvcs.c b/source3/rpcclient/cmd_ntsvcs.c new file mode 100644 index 0000000000..377a8a2a00 --- /dev/null +++ b/source3/rpcclient/cmd_ntsvcs.c @@ -0,0 +1,229 @@ +/* + Unix SMB/CIFS implementation. + RPC pipe client + + Copyright (C) Günther Deschner 2008 + + 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 <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "rpcclient.h" + +static WERROR cmd_ntsvcs_get_version(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status; + WERROR werr; + uint16_t version; + + status = rpccli_PNP_GetVersion(cli, mem_ctx, + &version, &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (W_ERROR_IS_OK(werr)) { + printf("version: %d\n", version); + } + + return werr; +} + +static WERROR cmd_ntsvcs_validate_dev_inst(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status; + WERROR werr; + const char *devicepath = NULL; + uint32_t flags = 0; + + if (argc < 2 || argc > 3) { + printf("usage: %s [devicepath] <flags>\n", argv[0]); + return WERR_OK; + } + + devicepath = argv[1]; + + if (argc >= 3) { + flags = atoi(argv[2]); + } + + status = rpccli_PNP_ValidateDeviceInstance(cli, mem_ctx, + devicepath, + flags, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + return werr; +} + +static WERROR cmd_ntsvcs_get_device_list_size(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status; + WERROR werr; + const char *devicename = NULL; + uint32_t flags = 0; + uint32_t size = 0; + + if (argc < 2 || argc > 4) { + printf("usage: %s [devicename] <flags>\n", argv[0]); + return WERR_OK; + } + + devicename = argv[1]; + + if (argc >= 3) { + flags = atoi(argv[2]); + } + + status = rpccli_PNP_GetDeviceListSize(cli, mem_ctx, + devicename, + &size, + flags, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (W_ERROR_IS_OK(werr)) { + printf("size: %d\n", size); + } + + return werr; +} + +static WERROR cmd_ntsvcs_hw_prof_flags(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status; + WERROR werr; + const char *devicepath = NULL; + uint32_t unk3 = 0; + uint16_t unk4 = 0; + const char *unk5 = NULL; + const char *unk5a = NULL; + + if (argc < 2) { + printf("usage: %s [devicepath]\n", argv[0]); + return WERR_OK; + } + + devicepath = argv[1]; + + status = rpccli_PNP_HwProfFlags(cli, mem_ctx, + 0, + devicepath, + 0, + &unk3, + &unk4, + unk5, + &unk5a, + 0, + 0, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + return werr; +} + +static WERROR cmd_ntsvcs_get_hw_prof_info(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status; + WERROR werr; + uint32_t idx = 0; + struct PNP_HwProfInfo info; + uint32_t unknown1 = 0, unknown2 = 0; + + ZERO_STRUCT(info); + + status = rpccli_PNP_GetHwProfInfo(cli, mem_ctx, + idx, + &info, + unknown1, + unknown2, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + return werr; +} + +static WERROR cmd_ntsvcs_get_dev_reg_prop(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status; + WERROR werr; + const char *devicepath = NULL; + uint32_t property = DEV_REGPROP_DESC; + uint32_t unknown1 = 0; + uint8_t buffer; + uint32_t buffer_size = 0; + uint32_t unknown2 = 0; + uint32_t unknown3 = 0; + + if (argc < 2) { + printf("usage: %s [devicepath]\n", argv[0]); + return WERR_OK; + } + + devicepath = argv[1]; + + status = rpccli_PNP_GetDeviceRegProp(cli, mem_ctx, + devicepath, + property, + &unknown1, + &buffer, + &buffer_size, + &unknown2, + unknown3, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + return werr; +} + + +struct cmd_set ntsvcs_commands[] = { + + { "NTSVCS" }, + { "ntsvcs_getversion", RPC_RTYPE_WERROR, NULL, cmd_ntsvcs_get_version, &ndr_table_ntsvcs.syntax_id, NULL, "Query NTSVCS version", "" }, + { "ntsvcs_validatedevinst", RPC_RTYPE_WERROR, NULL, cmd_ntsvcs_validate_dev_inst, &ndr_table_ntsvcs.syntax_id, NULL, "Query NTSVCS device instance", "" }, + { "ntsvcs_getdevlistsize", RPC_RTYPE_WERROR, NULL, cmd_ntsvcs_get_device_list_size, &ndr_table_ntsvcs.syntax_id, NULL, "Query NTSVCS get device list", "" }, + { "ntsvcs_hwprofflags", RPC_RTYPE_WERROR, NULL, cmd_ntsvcs_hw_prof_flags, &ndr_table_ntsvcs.syntax_id, NULL, "Query NTSVCS HW prof flags", "" }, + { "ntsvcs_hwprofinfo", RPC_RTYPE_WERROR, NULL, cmd_ntsvcs_get_hw_prof_info, &ndr_table_ntsvcs.syntax_id, NULL, "Query NTSVCS HW prof info", "" }, + { "ntsvcs_getdevregprop", RPC_RTYPE_WERROR, NULL, cmd_ntsvcs_get_dev_reg_prop, &ndr_table_ntsvcs.syntax_id, NULL, "Query NTSVCS device registry property", "" }, + { NULL } +}; diff --git a/source3/rpcclient/cmd_samr.c b/source3/rpcclient/cmd_samr.c new file mode 100644 index 0000000000..fa1e0fda4d --- /dev/null +++ b/source3/rpcclient/cmd_samr.c @@ -0,0 +1,2763 @@ +/* + Unix SMB/CIFS implementation. + RPC pipe client + + Copyright (C) Andrew Tridgell 1992-2000, + Copyright (C) Luke Kenneth Casson Leighton 1996-2000, + Copyright (C) Elrond 2000, + Copyright (C) Tim Potter 2000 + Copyright (C) Guenther Deschner 2008 + + 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 <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "rpcclient.h" + +extern DOM_SID domain_sid; + +/**************************************************************************** + display samr_user_info_7 structure + ****************************************************************************/ +static void display_samr_user_info_7(struct samr_UserInfo7 *r) +{ + printf("\tUser Name :\t%s\n", r->account_name.string); +} + +/**************************************************************************** + display samr_user_info_9 structure + ****************************************************************************/ +static void display_samr_user_info_9(struct samr_UserInfo9 *r) +{ + printf("\tPrimary group RID :\tox%x\n", r->primary_gid); +} + +/**************************************************************************** + display samr_user_info_16 structure + ****************************************************************************/ +static void display_samr_user_info_16(struct samr_UserInfo16 *r) +{ + printf("\tAcct Flags :\tox%x\n", r->acct_flags); +} + +/**************************************************************************** + display samr_user_info_20 structure + ****************************************************************************/ +static void display_samr_user_info_20(struct samr_UserInfo20 *r) +{ + printf("\tRemote Dial :\n"); + dump_data(0, (uint8_t *)r->parameters.array, r->parameters.length*2); +} + + +/**************************************************************************** + display samr_user_info_21 structure + ****************************************************************************/ +static void display_samr_user_info_21(struct samr_UserInfo21 *r) +{ + printf("\tUser Name :\t%s\n", r->account_name.string); + printf("\tFull Name :\t%s\n", r->full_name.string); + printf("\tHome Drive :\t%s\n", r->home_directory.string); + printf("\tDir Drive :\t%s\n", r->home_drive.string); + printf("\tProfile Path:\t%s\n", r->profile_path.string); + printf("\tLogon Script:\t%s\n", r->logon_script.string); + printf("\tDescription :\t%s\n", r->description.string); + printf("\tWorkstations:\t%s\n", r->workstations.string); + printf("\tComment :\t%s\n", r->comment.string); + printf("\tRemote Dial :\n"); + dump_data(0, (uint8_t *)r->parameters.array, r->parameters.length*2); + + printf("\tLogon Time :\t%s\n", + http_timestring(nt_time_to_unix(r->last_logon))); + printf("\tLogoff Time :\t%s\n", + http_timestring(nt_time_to_unix(r->last_logoff))); + printf("\tKickoff Time :\t%s\n", + http_timestring(nt_time_to_unix(r->acct_expiry))); + printf("\tPassword last set Time :\t%s\n", + http_timestring(nt_time_to_unix(r->last_password_change))); + printf("\tPassword can change Time :\t%s\n", + http_timestring(nt_time_to_unix(r->allow_password_change))); + printf("\tPassword must change Time:\t%s\n", + http_timestring(nt_time_to_unix(r->force_password_change))); + + printf("\tunknown_2[0..31]...\n"); /* user passwords? */ + + printf("\tuser_rid :\t0x%x\n" , r->rid); /* User ID */ + printf("\tgroup_rid:\t0x%x\n" , r->primary_gid); /* Group ID */ + printf("\tacb_info :\t0x%08x\n", r->acct_flags); /* Account Control Info */ + + printf("\tfields_present:\t0x%08x\n", r->fields_present); /* 0x00ff ffff */ + printf("\tlogon_divs:\t%d\n", r->logon_hours.units_per_week); /* 0x0000 00a8 which is 168 which is num hrs in a week */ + printf("\tbad_password_count:\t0x%08x\n", r->bad_password_count); + printf("\tlogon_count:\t0x%08x\n", r->logon_count); + + printf("\tpadding1[0..7]...\n"); + + if (r->logon_hours.bits) { + printf("\tlogon_hrs[0..%d]...\n", r->logon_hours.units_per_week/8); + } +} + + +static void display_password_properties(uint32_t password_properties) +{ + printf("password_properties: 0x%08x\n", password_properties); + + if (password_properties & DOMAIN_PASSWORD_COMPLEX) + printf("\tDOMAIN_PASSWORD_COMPLEX\n"); + + if (password_properties & DOMAIN_PASSWORD_NO_ANON_CHANGE) + printf("\tDOMAIN_PASSWORD_NO_ANON_CHANGE\n"); + + if (password_properties & DOMAIN_PASSWORD_NO_CLEAR_CHANGE) + printf("\tDOMAIN_PASSWORD_NO_CLEAR_CHANGE\n"); + + if (password_properties & DOMAIN_PASSWORD_LOCKOUT_ADMINS) + printf("\tDOMAIN_PASSWORD_LOCKOUT_ADMINS\n"); + + if (password_properties & DOMAIN_PASSWORD_STORE_CLEARTEXT) + printf("\tDOMAIN_PASSWORD_STORE_CLEARTEXT\n"); + + if (password_properties & DOMAIN_REFUSE_PASSWORD_CHANGE) + printf("\tDOMAIN_REFUSE_PASSWORD_CHANGE\n"); +} + +static void display_sam_dom_info_1(struct samr_DomInfo1 *info1) +{ + printf("Minimum password length:\t\t\t%d\n", + info1->min_password_length); + printf("Password uniqueness (remember x passwords):\t%d\n", + info1->password_history_length); + display_password_properties(info1->password_properties); + printf("password expire in:\t\t\t\t%s\n", + display_time(info1->max_password_age)); + printf("Min password age (allow changing in x days):\t%s\n", + display_time(info1->min_password_age)); +} + +static void display_sam_dom_info_2(struct samr_DomInfo2 *info2) +{ + printf("Domain:\t\t%s\n", info2->domain_name.string); + printf("Server:\t\t%s\n", info2->primary.string); + printf("Comment:\t%s\n", info2->comment.string); + + printf("Total Users:\t%d\n", info2->num_users); + printf("Total Groups:\t%d\n", info2->num_groups); + printf("Total Aliases:\t%d\n", info2->num_aliases); + + printf("Sequence No:\t%llu\n", (unsigned long long)info2->sequence_num); + + printf("Force Logoff:\t%d\n", + (int)nt_time_to_unix_abs(&info2->force_logoff_time)); + + printf("Unknown 2:\t0x%x\n", info2->unknown2); + printf("Server Role:\t%s\n", server_role_str(info2->role)); + printf("Unknown 3:\t0x%x\n", info2->unknown3); +} + +static void display_sam_dom_info_3(struct samr_DomInfo3 *info3) +{ + printf("Force Logoff:\t%d\n", + (int)nt_time_to_unix_abs(&info3->force_logoff_time)); +} + +static void display_sam_dom_info_4(struct samr_DomInfo4 *info4) +{ + printf("Comment:\t%s\n", info4->comment.string); +} + +static void display_sam_dom_info_5(struct samr_DomInfo5 *info5) +{ + printf("Domain:\t\t%s\n", info5->domain_name.string); +} + +static void display_sam_dom_info_6(struct samr_DomInfo6 *info6) +{ + printf("Server:\t\t%s\n", info6->primary.string); +} + +static void display_sam_dom_info_7(struct samr_DomInfo7 *info7) +{ + printf("Server Role:\t%s\n", server_role_str(info7->role)); +} + +static void display_sam_dom_info_8(struct samr_DomInfo8 *info8) +{ + printf("Sequence No:\t%llu\n", (unsigned long long)info8->sequence_num); + printf("Domain Create Time:\t%s\n", + http_timestring(nt_time_to_unix(info8->domain_create_time))); +} + +static void display_sam_dom_info_9(struct samr_DomInfo9 *info9) +{ + printf("unknown:\t%d (0x%08x)\n", info9->unknown, info9->unknown); +} + +static void display_sam_dom_info_12(struct samr_DomInfo12 *info12) +{ + printf("Bad password lockout duration: %s\n", + display_time(info12->lockout_duration)); + printf("Reset Lockout after: %s\n", + display_time(info12->lockout_window)); + printf("Lockout after bad attempts: %d\n", + info12->lockout_threshold); +} + +static void display_sam_dom_info_13(struct samr_DomInfo13 *info13) +{ + printf("Sequence No:\t%llu\n", (unsigned long long)info13->sequence_num); + printf("Domain Create Time:\t%s\n", + http_timestring(nt_time_to_unix(info13->domain_create_time))); + printf("Unknown1:\t%d\n", info13->unknown1); + printf("Unknown2:\t%d\n", info13->unknown2); + +} + +static void display_sam_info_1(struct samr_DispEntryGeneral *r) +{ + printf("index: 0x%x ", r->idx); + printf("RID: 0x%x ", r->rid); + printf("acb: 0x%08x ", r->acct_flags); + printf("Account: %s\t", r->account_name.string); + printf("Name: %s\t", r->full_name.string); + printf("Desc: %s\n", r->description.string); +} + +static void display_sam_info_2(struct samr_DispEntryFull *r) +{ + printf("index: 0x%x ", r->idx); + printf("RID: 0x%x ", r->rid); + printf("acb: 0x%08x ", r->acct_flags); + printf("Account: %s\t", r->account_name.string); + printf("Desc: %s\n", r->description.string); +} + +static void display_sam_info_3(struct samr_DispEntryFullGroup *r) +{ + printf("index: 0x%x ", r->idx); + printf("RID: 0x%x ", r->rid); + printf("acb: 0x%08x ", r->acct_flags); + printf("Account: %s\t", r->account_name.string); + printf("Desc: %s\n", r->description.string); +} + +static void display_sam_info_4(struct samr_DispEntryAscii *r) +{ + printf("index: 0x%x ", r->idx); + printf("Account: %s\n", r->account_name.string); +} + +static void display_sam_info_5(struct samr_DispEntryAscii *r) +{ + printf("index: 0x%x ", r->idx); + printf("Account: %s\n", r->account_name.string); +} + +/********************************************************************** + * Query user information + */ +static NTSTATUS cmd_samr_query_user(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol, user_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 info_level = 21; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + union samr_UserInfo *info = NULL; + uint32 user_rid = 0; + + if ((argc < 2) || (argc > 4)) { + printf("Usage: %s rid [info level] [access mask] \n", argv[0]); + return NT_STATUS_OK; + } + + sscanf(argv[1], "%i", &user_rid); + + if (argc > 2) + sscanf(argv[2], "%i", &info_level); + + if (argc > 3) + sscanf(argv[3], "%x", &access_mask); + + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol); + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_OpenUser(cli, mem_ctx, + &domain_pol, + access_mask, + user_rid, + &user_pol); + + if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) && + (user_rid == 0)) { + + /* Probably this was a user name, try lookupnames */ + struct samr_Ids rids, types; + struct lsa_String lsa_acct_name; + + init_lsa_String(&lsa_acct_name, argv[1]); + + result = rpccli_samr_LookupNames(cli, mem_ctx, + &domain_pol, + 1, + &lsa_acct_name, + &rids, + &types); + + if (NT_STATUS_IS_OK(result)) { + result = rpccli_samr_OpenUser(cli, mem_ctx, + &domain_pol, + access_mask, + rids.ids[0], + &user_pol); + } + } + + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_QueryUserInfo(cli, mem_ctx, + &user_pol, + info_level, + &info); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + switch (info_level) { + case 7: + display_samr_user_info_7(&info->info7); + break; + case 9: + display_samr_user_info_9(&info->info9); + break; + case 16: + display_samr_user_info_16(&info->info16); + break; + case 20: + display_samr_user_info_20(&info->info20); + break; + case 21: + display_samr_user_info_21(&info->info21); + break; + default: + printf("Unsupported infolevel: %d\n", info_level); + break; + } + + rpccli_samr_Close(cli, mem_ctx, &user_pol); + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + +done: + return result; +} + +/**************************************************************************** + display group info + ****************************************************************************/ +static void display_group_info1(struct samr_GroupInfoAll *info1) +{ + printf("\tGroup Name:\t%s\n", info1->name.string); + printf("\tDescription:\t%s\n", info1->description.string); + printf("\tGroup Attribute:%d\n", info1->attributes); + printf("\tNum Members:%d\n", info1->num_members); +} + +/**************************************************************************** + display group info + ****************************************************************************/ +static void display_group_info2(struct lsa_String *info2) +{ + printf("\tGroup Description:%s\n", info2->string); +} + + +/**************************************************************************** + display group info + ****************************************************************************/ +static void display_group_info3(struct samr_GroupInfoAttributes *info3) +{ + printf("\tGroup Attribute:%d\n", info3->attributes); +} + + +/**************************************************************************** + display group info + ****************************************************************************/ +static void display_group_info4(struct lsa_String *info4) +{ + printf("\tGroup Description:%s\n", info4->string); +} + +/**************************************************************************** + display group info + ****************************************************************************/ +static void display_group_info5(struct samr_GroupInfoAll *info5) +{ + printf("\tGroup Name:\t%s\n", info5->name.string); + printf("\tDescription:\t%s\n", info5->description.string); + printf("\tGroup Attribute:%d\n", info5->attributes); + printf("\tNum Members:%d\n", info5->num_members); +} + +/**************************************************************************** + display sam sync structure + ****************************************************************************/ +static void display_group_info(union samr_GroupInfo *info, + enum samr_GroupInfoEnum level) +{ + switch (level) { + case 1: + display_group_info1(&info->all); + break; + case 2: + display_group_info2(&info->name); + break; + case 3: + display_group_info3(&info->attributes); + break; + case 4: + display_group_info4(&info->description); + break; + case 5: + display_group_info5(&info->all2); + break; + } +} + +/*********************************************************************** + * Query group information + */ +static NTSTATUS cmd_samr_query_group(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol, group_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + enum samr_GroupInfoEnum info_level = GROUPINFOALL; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + union samr_GroupInfo *group_info = NULL; + uint32 group_rid; + + if ((argc < 2) || (argc > 4)) { + printf("Usage: %s rid [info level] [access mask]\n", argv[0]); + return NT_STATUS_OK; + } + + sscanf(argv[1], "%i", &group_rid); + + if (argc > 2) + info_level = atoi(argv[2]); + + if (argc > 3) + sscanf(argv[3], "%x", &access_mask); + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_OpenGroup(cli, mem_ctx, + &domain_pol, + access_mask, + group_rid, + &group_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_QueryGroupInfo(cli, mem_ctx, + &group_pol, + info_level, + &group_info); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + display_group_info(group_info, info_level); + + rpccli_samr_Close(cli, mem_ctx, &group_pol); + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + rpccli_samr_Close(cli, mem_ctx, &connect_pol); +done: + return result; +} + +/* Query groups a user is a member of */ + +static NTSTATUS cmd_samr_query_usergroups(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, + domain_pol, + user_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 user_rid; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + int i; + struct samr_RidWithAttributeArray *rid_array = NULL; + + if ((argc < 2) || (argc > 3)) { + printf("Usage: %s rid [access mask]\n", argv[0]); + return NT_STATUS_OK; + } + + sscanf(argv[1], "%i", &user_rid); + + if (argc > 2) + sscanf(argv[2], "%x", &access_mask); + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, &domain_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_OpenUser(cli, mem_ctx, + &domain_pol, + access_mask, + user_rid, + &user_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_GetGroupsForUser(cli, mem_ctx, + &user_pol, + &rid_array); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + for (i = 0; i < rid_array->count; i++) { + printf("\tgroup rid:[0x%x] attr:[0x%x]\n", + rid_array->rids[i].rid, + rid_array->rids[i].attributes); + } + + rpccli_samr_Close(cli, mem_ctx, &user_pol); + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + done: + return result; +} + +/* Query aliases a user is a member of */ + +static NTSTATUS cmd_samr_query_useraliases(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + DOM_SID *sids; + size_t num_sids; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + int i; + struct lsa_SidArray sid_array; + struct samr_Ids alias_rids; + + if (argc < 3) { + printf("Usage: %s builtin|domain sid1 sid2 ...\n", argv[0]); + return NT_STATUS_INVALID_PARAMETER; + } + + sids = NULL; + num_sids = 0; + + for (i=2; i<argc; i++) { + DOM_SID tmp_sid; + if (!string_to_sid(&tmp_sid, argv[i])) { + printf("%s is not a legal SID\n", argv[i]); + return NT_STATUS_INVALID_PARAMETER; + } + result = add_sid_to_array(mem_ctx, &tmp_sid, &sids, &num_sids); + if (!NT_STATUS_IS_OK(result)) { + return result; + } + } + + if (num_sids) { + sid_array.sids = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_SidPtr, num_sids); + if (sid_array.sids == NULL) + return NT_STATUS_NO_MEMORY; + } else { + sid_array.sids = NULL; + } + + for (i=0; i<num_sids; i++) { + sid_array.sids[i].sid = sid_dup_talloc(mem_ctx, &sids[i]); + if (!sid_array.sids[i].sid) { + return NT_STATUS_NO_MEMORY; + } + } + + sid_array.num_sids = num_sids; + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + if (StrCaseCmp(argv[1], "domain")==0) + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, &domain_pol); + else if (StrCaseCmp(argv[1], "builtin")==0) + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + access_mask, + CONST_DISCARD(struct dom_sid2 *, &global_sid_Builtin), + &domain_pol); + else { + printf("Usage: %s builtin|domain sid1 sid2 ...\n", argv[0]); + return NT_STATUS_INVALID_PARAMETER; + } + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_GetAliasMembership(cli, mem_ctx, + &domain_pol, + &sid_array, + &alias_rids); + if (!NT_STATUS_IS_OK(result)) + goto done; + + for (i = 0; i < alias_rids.count; i++) { + printf("\tgroup rid:[0x%x]\n", alias_rids.ids[i]); + } + + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + done: + return result; +} + +/* Query members of a group */ + +static NTSTATUS cmd_samr_query_groupmem(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol, group_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 group_rid; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + int i; + unsigned int old_timeout; + struct samr_RidTypeArray *rids = NULL; + + if ((argc < 2) || (argc > 3)) { + printf("Usage: %s rid [access mask]\n", argv[0]); + return NT_STATUS_OK; + } + + sscanf(argv[1], "%i", &group_rid); + + if (argc > 2) + sscanf(argv[2], "%x", &access_mask); + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_OpenGroup(cli, mem_ctx, + &domain_pol, + access_mask, + group_rid, + &group_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Make sure to wait for our DC's reply */ + old_timeout = rpccli_set_timeout(cli, 30000); /* 30 seconds. */ + rpccli_set_timeout(cli, MAX(30000, old_timeout)); /* At least 30 sec */ + + result = rpccli_samr_QueryGroupMember(cli, mem_ctx, + &group_pol, + &rids); + + rpccli_set_timeout(cli, old_timeout); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + for (i = 0; i < rids->count; i++) { + printf("\trid:[0x%x] attr:[0x%x]\n", rids->rids[i], + rids->types[i]); + } + + rpccli_samr_Close(cli, mem_ctx, &group_pol); + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + done: + return result; +} + +/* Enumerate domain users */ + +static NTSTATUS cmd_samr_enum_dom_users(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 start_idx, size, num_dom_users, i; + struct samr_SamArray *dom_users = NULL; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + uint32 acb_mask = ACB_NORMAL; + bool got_connect_pol = False, got_domain_pol = False; + + if ((argc < 1) || (argc > 3)) { + printf("Usage: %s [access_mask] [acb_mask]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc > 1) + sscanf(argv[1], "%x", &access_mask); + + if (argc > 2) + sscanf(argv[2], "%x", &acb_mask); + + /* Get sam policy handle */ + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + got_connect_pol = True; + + /* Get domain policy handle */ + + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + got_domain_pol = True; + + /* Enumerate domain users */ + + start_idx = 0; + size = 0xffff; + + do { + result = rpccli_samr_EnumDomainUsers(cli, mem_ctx, + &domain_pol, + &start_idx, + acb_mask, + &dom_users, + size, + &num_dom_users); + + if (NT_STATUS_IS_OK(result) || + NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES)) { + + for (i = 0; i < num_dom_users; i++) + printf("user:[%s] rid:[0x%x]\n", + dom_users->entries[i].name.string, + dom_users->entries[i].idx); + } + + } while (NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES)); + + done: + if (got_domain_pol) + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + + if (got_connect_pol) + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + + return result; +} + +/* Enumerate domain groups */ + +static NTSTATUS cmd_samr_enum_dom_groups(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 start_idx, size, num_dom_groups, i; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + struct samr_SamArray *dom_groups = NULL; + bool got_connect_pol = False, got_domain_pol = False; + + if ((argc < 1) || (argc > 2)) { + printf("Usage: %s [access_mask]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc > 1) + sscanf(argv[1], "%x", &access_mask); + + /* Get sam policy handle */ + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + got_connect_pol = True; + + /* Get domain policy handle */ + + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + got_domain_pol = True; + + /* Enumerate domain groups */ + + start_idx = 0; + size = 0xffff; + + do { + result = rpccli_samr_EnumDomainGroups(cli, mem_ctx, + &domain_pol, + &start_idx, + &dom_groups, + size, + &num_dom_groups); + if (NT_STATUS_IS_OK(result) || + NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES)) { + + for (i = 0; i < num_dom_groups; i++) + printf("group:[%s] rid:[0x%x]\n", + dom_groups->entries[i].name.string, + dom_groups->entries[i].idx); + } + + } while (NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES)); + + done: + if (got_domain_pol) + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + + if (got_connect_pol) + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + + return result; +} + +/* Enumerate alias groups */ + +static NTSTATUS cmd_samr_enum_als_groups(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 start_idx, size, num_als_groups, i; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + struct samr_SamArray *als_groups = NULL; + bool got_connect_pol = False, got_domain_pol = False; + + if ((argc < 2) || (argc > 3)) { + printf("Usage: %s builtin|domain [access mask]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc > 2) + sscanf(argv[2], "%x", &access_mask); + + /* Get sam policy handle */ + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + got_connect_pol = True; + + /* Get domain policy handle */ + + if (StrCaseCmp(argv[1], "domain")==0) + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol); + else if (StrCaseCmp(argv[1], "builtin")==0) + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + access_mask, + CONST_DISCARD(struct dom_sid2 *, &global_sid_Builtin), + &domain_pol); + else + return NT_STATUS_OK; + + if (!NT_STATUS_IS_OK(result)) + goto done; + + got_domain_pol = True; + + /* Enumerate alias groups */ + + start_idx = 0; + size = 0xffff; /* Number of groups to retrieve */ + + do { + result = rpccli_samr_EnumDomainAliases(cli, mem_ctx, + &domain_pol, + &start_idx, + &als_groups, + size, + &num_als_groups); + + if (NT_STATUS_IS_OK(result) || + NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES)) { + + for (i = 0; i < num_als_groups; i++) + printf("group:[%s] rid:[0x%x]\n", + als_groups->entries[i].name.string, + als_groups->entries[i].idx); + } + } while (NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES)); + + done: + if (got_domain_pol) + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + + if (got_connect_pol) + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + + return result; +} + +/* Enumerate domains */ + +static NTSTATUS cmd_samr_enum_domains(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 start_idx, size, num_entries, i; + uint32 access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + bool got_connect_pol = false; + struct samr_SamArray *sam = NULL; + + if ((argc < 1) || (argc > 2)) { + printf("Usage: %s [access mask]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc > 1) { + sscanf(argv[1], "%x", &access_mask); + } + + /* Get sam policy handle */ + + result = rpccli_try_samr_connects(cli, mem_ctx, + access_mask, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + got_connect_pol = true; + + /* Enumerate alias groups */ + + start_idx = 0; + size = 0xffff; + + do { + result = rpccli_samr_EnumDomains(cli, mem_ctx, + &connect_pol, + &start_idx, + &sam, + size, + &num_entries); + + if (NT_STATUS_IS_OK(result) || + NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES)) { + + for (i = 0; i < num_entries; i++) + printf("name:[%s] idx:[0x%x]\n", + sam->entries[i].name.string, + sam->entries[i].idx); + } + } while (NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES)); + + done: + if (got_connect_pol) { + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + } + + return result; +} + + +/* Query alias membership */ + +static NTSTATUS cmd_samr_query_aliasmem(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol, alias_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 alias_rid, i; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + struct lsa_SidArray sid_array; + + if ((argc < 3) || (argc > 4)) { + printf("Usage: %s builtin|domain rid [access mask]\n", argv[0]); + return NT_STATUS_OK; + } + + sscanf(argv[2], "%i", &alias_rid); + + if (argc > 3) + sscanf(argv[3], "%x", &access_mask); + + /* Open SAMR handle */ + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Open handle on domain */ + + if (StrCaseCmp(argv[1], "domain")==0) + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol); + else if (StrCaseCmp(argv[1], "builtin")==0) + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + CONST_DISCARD(struct dom_sid2 *, &global_sid_Builtin), + &domain_pol); + else + return NT_STATUS_OK; + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Open handle on alias */ + + result = rpccli_samr_OpenAlias(cli, mem_ctx, + &domain_pol, + access_mask, + alias_rid, + &alias_pol); + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_GetMembersInAlias(cli, mem_ctx, + &alias_pol, + &sid_array); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + for (i = 0; i < sid_array.num_sids; i++) { + fstring sid_str; + + sid_to_fstring(sid_str, sid_array.sids[i].sid); + printf("\tsid:[%s]\n", sid_str); + } + + rpccli_samr_Close(cli, mem_ctx, &alias_pol); + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + done: + return result; +} + +/* Query alias info */ + +static NTSTATUS cmd_samr_query_aliasinfo(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol, alias_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32_t alias_rid; + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + union samr_AliasInfo *info = NULL; + enum samr_AliasInfoEnum level = ALIASINFOALL; + + if ((argc < 3) || (argc > 4)) { + printf("Usage: %s builtin|domain rid [level] [access mask]\n", + argv[0]); + return NT_STATUS_OK; + } + + sscanf(argv[2], "%i", &alias_rid); + + if (argc > 2) { + level = atoi(argv[3]); + } + + if (argc > 3) { + sscanf(argv[4], "%x", &access_mask); + } + + /* Open SAMR handle */ + + result = rpccli_try_samr_connects(cli, mem_ctx, + SEC_FLAG_MAXIMUM_ALLOWED, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + /* Open handle on domain */ + + if (strequal(argv[1], "domain")) { + + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + SEC_FLAG_MAXIMUM_ALLOWED, + &domain_sid, + &domain_pol); + + } else if (strequal(argv[1], "builtin")) { + + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + SEC_FLAG_MAXIMUM_ALLOWED, + CONST_DISCARD(struct dom_sid2 *, &global_sid_Builtin), + &domain_pol); + + } else { + return NT_STATUS_OK; + } + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + /* Open handle on alias */ + + result = rpccli_samr_OpenAlias(cli, mem_ctx, + &domain_pol, + access_mask, + alias_rid, + &alias_pol); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + result = rpccli_samr_QueryAliasInfo(cli, mem_ctx, + &alias_pol, + level, + &info); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + switch (level) { + case ALIASINFOALL: + printf("Name: %s\n", info->all.name.string); + printf("Description: %s\n", info->all.description.string); + printf("Num Members: %d\n", info->all.num_members); + break; + case ALIASINFONAME: + printf("Name: %s\n", info->name.string); + break; + case ALIASINFODESCRIPTION: + printf("Description: %s\n", info->description.string); + break; + default: + break; + } + + rpccli_samr_Close(cli, mem_ctx, &alias_pol); + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + done: + return result; +} + + +/* Query delete an alias membership */ + +static NTSTATUS cmd_samr_delete_alias(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol, alias_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 alias_rid; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + + if (argc != 3) { + printf("Usage: %s builtin|domain [rid|name]\n", argv[0]); + return NT_STATUS_OK; + } + + alias_rid = strtoul(argv[2], NULL, 10); + + /* Open SAMR handle */ + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Open handle on domain */ + + if (StrCaseCmp(argv[1], "domain")==0) + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol); + else if (StrCaseCmp(argv[1], "builtin")==0) + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + CONST_DISCARD(struct dom_sid2 *, &global_sid_Builtin), + &domain_pol); + else + return NT_STATUS_INVALID_PARAMETER; + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Open handle on alias */ + + result = rpccli_samr_OpenAlias(cli, mem_ctx, + &domain_pol, + access_mask, + alias_rid, + &alias_pol); + if (!NT_STATUS_IS_OK(result) && (alias_rid == 0)) { + /* Probably this was a user name, try lookupnames */ + struct samr_Ids rids, types; + struct lsa_String lsa_acct_name; + + init_lsa_String(&lsa_acct_name, argv[2]); + + result = rpccli_samr_LookupNames(cli, mem_ctx, + &domain_pol, + 1, + &lsa_acct_name, + &rids, + &types); + + if (NT_STATUS_IS_OK(result)) { + result = rpccli_samr_OpenAlias(cli, mem_ctx, + &domain_pol, + access_mask, + rids.ids[0], + &alias_pol); + } + } + + result = rpccli_samr_DeleteDomAlias(cli, mem_ctx, + &alias_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + done: + return result; +} + +/* Query display info */ + +static NTSTATUS cmd_samr_query_dispinfo_internal(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv, + uint32_t opcode) +{ + POLICY_HND connect_pol, domain_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 start_idx=0, max_entries=250, max_size = 0xffff, num_entries = 0, i; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + uint32 info_level = 1; + union samr_DispInfo info; + int loop_count = 0; + bool got_params = False; /* Use get_query_dispinfo_params() or not? */ + uint32_t total_size, returned_size; + + if (argc > 6) { + printf("Usage: %s [info level] [start index] [max entries] [max size] [access mask]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc >= 2) + sscanf(argv[1], "%i", &info_level); + + if (argc >= 3) + sscanf(argv[2], "%i", &start_idx); + + if (argc >= 4) { + sscanf(argv[3], "%i", &max_entries); + got_params = True; + } + + if (argc >= 5) { + sscanf(argv[4], "%i", &max_size); + got_params = True; + } + + if (argc >= 6) + sscanf(argv[5], "%x", &access_mask); + + /* Get sam policy handle */ + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Get domain policy handle */ + + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Query display info */ + + do { + + if (!got_params) + get_query_dispinfo_params( + loop_count, &max_entries, &max_size); + + switch (opcode) { + case NDR_SAMR_QUERYDISPLAYINFO: + result = rpccli_samr_QueryDisplayInfo(cli, mem_ctx, + &domain_pol, + info_level, + start_idx, + max_entries, + max_size, + &total_size, + &returned_size, + &info); + break; + case NDR_SAMR_QUERYDISPLAYINFO2: + result = rpccli_samr_QueryDisplayInfo2(cli, mem_ctx, + &domain_pol, + info_level, + start_idx, + max_entries, + max_size, + &total_size, + &returned_size, + &info); + + break; + case NDR_SAMR_QUERYDISPLAYINFO3: + result = rpccli_samr_QueryDisplayInfo3(cli, mem_ctx, + &domain_pol, + info_level, + start_idx, + max_entries, + max_size, + &total_size, + &returned_size, + &info); + + break; + default: + return NT_STATUS_INVALID_PARAMETER; + } + + if (!NT_STATUS_IS_OK(result) && + !NT_STATUS_EQUAL(result, NT_STATUS_NO_MORE_ENTRIES) && + !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) { + break; + } + + loop_count++; + + switch (info_level) { + case 1: + num_entries = info.info1.count; + break; + case 2: + num_entries = info.info2.count; + break; + case 3: + num_entries = info.info3.count; + break; + case 4: + num_entries = info.info4.count; + break; + case 5: + num_entries = info.info5.count; + break; + default: + break; + } + + start_idx += num_entries; + + if (num_entries == 0) + break; + + for (i = 0; i < num_entries; i++) { + switch (info_level) { + case 1: + display_sam_info_1(&info.info1.entries[i]); + break; + case 2: + display_sam_info_2(&info.info2.entries[i]); + break; + case 3: + display_sam_info_3(&info.info3.entries[i]); + break; + case 4: + display_sam_info_4(&info.info4.entries[i]); + break; + case 5: + display_sam_info_5(&info.info5.entries[i]); + break; + } + } + } while ( NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)); + + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + done: + return result; +} + +static NTSTATUS cmd_samr_query_dispinfo(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + return cmd_samr_query_dispinfo_internal(cli, mem_ctx, argc, argv, + NDR_SAMR_QUERYDISPLAYINFO); +} + +static NTSTATUS cmd_samr_query_dispinfo2(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + return cmd_samr_query_dispinfo_internal(cli, mem_ctx, argc, argv, + NDR_SAMR_QUERYDISPLAYINFO2); +} + +static NTSTATUS cmd_samr_query_dispinfo3(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + return cmd_samr_query_dispinfo_internal(cli, mem_ctx, argc, argv, + NDR_SAMR_QUERYDISPLAYINFO3); +} + +/* Query domain info */ + +static NTSTATUS cmd_samr_query_dominfo(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 switch_level = 2; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + union samr_DomainInfo *info = NULL; + + if (argc > 3) { + printf("Usage: %s [info level] [access mask]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc > 1) + sscanf(argv[1], "%i", &switch_level); + + if (argc > 2) + sscanf(argv[2], "%x", &access_mask); + + /* Get sam policy handle */ + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Get domain policy handle */ + + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Query domain info */ + + result = rpccli_samr_QueryDomainInfo(cli, mem_ctx, + &domain_pol, + switch_level, + &info); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Display domain info */ + + switch (switch_level) { + case 1: + display_sam_dom_info_1(&info->info1); + break; + case 2: + display_sam_dom_info_2(&info->info2); + break; + case 3: + display_sam_dom_info_3(&info->info3); + break; + case 4: + display_sam_dom_info_4(&info->info4); + break; + case 5: + display_sam_dom_info_5(&info->info5); + break; + case 6: + display_sam_dom_info_6(&info->info6); + break; + case 7: + display_sam_dom_info_7(&info->info7); + break; + case 8: + display_sam_dom_info_8(&info->info8); + break; + case 9: + display_sam_dom_info_9(&info->info9); + break; + case 12: + display_sam_dom_info_12(&info->info12); + break; + case 13: + display_sam_dom_info_13(&info->info13); + break; + + default: + printf("cannot display domain info for switch value %d\n", + switch_level); + break; + } + + done: + + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + return result; +} + +/* Create domain user */ + +static NTSTATUS cmd_samr_create_dom_user(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol, user_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + struct lsa_String acct_name; + uint32 acb_info; + uint32 acct_flags, user_rid; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + uint32_t access_granted = 0; + + if ((argc < 2) || (argc > 3)) { + printf("Usage: %s username [access mask]\n", argv[0]); + return NT_STATUS_OK; + } + + init_lsa_String(&acct_name, argv[1]); + + if (argc > 2) + sscanf(argv[2], "%x", &access_mask); + + /* Get sam policy handle */ + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Get domain policy handle */ + + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Create domain user */ + + acb_info = ACB_NORMAL; + acct_flags = SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE | + SEC_STD_WRITE_DAC | SEC_STD_DELETE | + SAMR_USER_ACCESS_SET_PASSWORD | + SAMR_USER_ACCESS_GET_ATTRIBUTES | + SAMR_USER_ACCESS_SET_ATTRIBUTES; + + result = rpccli_samr_CreateUser2(cli, mem_ctx, + &domain_pol, + &acct_name, + acb_info, + acct_flags, + &user_pol, + &access_granted, + &user_rid); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_Close(cli, mem_ctx, &user_pol); + if (!NT_STATUS_IS_OK(result)) goto done; + + result = rpccli_samr_Close(cli, mem_ctx, &domain_pol); + if (!NT_STATUS_IS_OK(result)) goto done; + + result = rpccli_samr_Close(cli, mem_ctx, &connect_pol); + if (!NT_STATUS_IS_OK(result)) goto done; + + done: + return result; +} + +/* Create domain group */ + +static NTSTATUS cmd_samr_create_dom_group(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol, group_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + struct lsa_String grp_name; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + uint32_t rid = 0; + + if ((argc < 2) || (argc > 3)) { + printf("Usage: %s groupname [access mask]\n", argv[0]); + return NT_STATUS_OK; + } + + init_lsa_String(&grp_name, argv[1]); + + if (argc > 2) + sscanf(argv[2], "%x", &access_mask); + + /* Get sam policy handle */ + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Get domain policy handle */ + + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Create domain user */ + result = rpccli_samr_CreateDomainGroup(cli, mem_ctx, + &domain_pol, + &grp_name, + MAXIMUM_ALLOWED_ACCESS, + &group_pol, + &rid); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_Close(cli, mem_ctx, &group_pol); + if (!NT_STATUS_IS_OK(result)) goto done; + + result = rpccli_samr_Close(cli, mem_ctx, &domain_pol); + if (!NT_STATUS_IS_OK(result)) goto done; + + result = rpccli_samr_Close(cli, mem_ctx, &connect_pol); + if (!NT_STATUS_IS_OK(result)) goto done; + + done: + return result; +} + +/* Create domain alias */ + +static NTSTATUS cmd_samr_create_dom_alias(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol, alias_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + struct lsa_String alias_name; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + uint32_t rid = 0; + + if ((argc < 2) || (argc > 3)) { + printf("Usage: %s aliasname [access mask]\n", argv[0]); + return NT_STATUS_OK; + } + + init_lsa_String(&alias_name, argv[1]); + + if (argc > 2) + sscanf(argv[2], "%x", &access_mask); + + /* Get sam policy handle */ + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Get domain policy handle */ + + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Create domain user */ + + result = rpccli_samr_CreateDomAlias(cli, mem_ctx, + &domain_pol, + &alias_name, + MAXIMUM_ALLOWED_ACCESS, + &alias_pol, + &rid); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_Close(cli, mem_ctx, &alias_pol); + if (!NT_STATUS_IS_OK(result)) goto done; + + result = rpccli_samr_Close(cli, mem_ctx, &domain_pol); + if (!NT_STATUS_IS_OK(result)) goto done; + + result = rpccli_samr_Close(cli, mem_ctx, &connect_pol); + if (!NT_STATUS_IS_OK(result)) goto done; + + done: + return result; +} + +/* Lookup sam names */ + +static NTSTATUS cmd_samr_lookup_names(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + POLICY_HND connect_pol, domain_pol; + uint32 num_names; + struct samr_Ids rids, name_types; + int i; + struct lsa_String *names = NULL;; + + if (argc < 3) { + printf("Usage: %s domain|builtin name1 [name2 [name3] [...]]\n", argv[0]); + printf("check on the domain SID: S-1-5-21-x-y-z\n"); + printf("or check on the builtin SID: S-1-5-32\n"); + return NT_STATUS_OK; + } + + /* Get sam policy and domain handles */ + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + if (StrCaseCmp(argv[1], "domain")==0) + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol); + else if (StrCaseCmp(argv[1], "builtin")==0) + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + CONST_DISCARD(struct dom_sid2 *, &global_sid_Builtin), + &domain_pol); + else + return NT_STATUS_OK; + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Look up names */ + + num_names = argc - 2; + + if ((names = TALLOC_ARRAY(mem_ctx, struct lsa_String, num_names)) == NULL) { + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + result = NT_STATUS_NO_MEMORY; + goto done; + } + + for (i = 0; i < num_names; i++) { + init_lsa_String(&names[i], argv[i + 2]); + } + + result = rpccli_samr_LookupNames(cli, mem_ctx, + &domain_pol, + num_names, + names, + &rids, + &name_types); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Display results */ + + for (i = 0; i < num_names; i++) + printf("name %s: 0x%x (%d)\n", names[i].string, rids.ids[i], + name_types.ids[i]); + + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + done: + return result; +} + +/* Lookup sam rids */ + +static NTSTATUS cmd_samr_lookup_rids(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + POLICY_HND connect_pol, domain_pol; + uint32_t num_rids, *rids; + struct lsa_Strings names; + struct samr_Ids types; + + int i; + + if (argc < 3) { + printf("Usage: %s domain|builtin rid1 [rid2 [rid3] [...]]\n", argv[0]); + return NT_STATUS_OK; + } + + /* Get sam policy and domain handles */ + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + if (StrCaseCmp(argv[1], "domain")==0) + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol); + else if (StrCaseCmp(argv[1], "builtin")==0) + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + CONST_DISCARD(struct dom_sid2 *, &global_sid_Builtin), + &domain_pol); + else + return NT_STATUS_OK; + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Look up rids */ + + num_rids = argc - 2; + + if ((rids = TALLOC_ARRAY(mem_ctx, uint32, num_rids)) == NULL) { + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + result = NT_STATUS_NO_MEMORY; + goto done; + } + + for (i = 0; i < argc - 2; i++) + sscanf(argv[i + 2], "%i", &rids[i]); + + result = rpccli_samr_LookupRids(cli, mem_ctx, + &domain_pol, + num_rids, + rids, + &names, + &types); + + if (!NT_STATUS_IS_OK(result) && + !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) + goto done; + + /* Display results */ + + for (i = 0; i < num_rids; i++) { + printf("rid 0x%x: %s (%d)\n", + rids[i], names.names[i].string, types.ids[i]); + } + + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + done: + return result; +} + +/* Delete domain group */ + +static NTSTATUS cmd_samr_delete_dom_group(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + POLICY_HND connect_pol, domain_pol, group_pol; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + + if ((argc < 2) || (argc > 3)) { + printf("Usage: %s groupname\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc > 2) + sscanf(argv[2], "%x", &access_mask); + + /* Get sam policy and domain handles */ + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Get handle on group */ + + { + struct samr_Ids group_rids, name_types; + struct lsa_String lsa_acct_name; + + init_lsa_String(&lsa_acct_name, argv[1]); + + result = rpccli_samr_LookupNames(cli, mem_ctx, + &domain_pol, + 1, + &lsa_acct_name, + &group_rids, + &name_types); + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_OpenGroup(cli, mem_ctx, + &domain_pol, + access_mask, + group_rids.ids[0], + &group_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + } + + /* Delete group */ + + result = rpccli_samr_DeleteDomainGroup(cli, mem_ctx, + &group_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Display results */ + + rpccli_samr_Close(cli, mem_ctx, &group_pol); + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + + done: + return result; +} + +/* Delete domain user */ + +static NTSTATUS cmd_samr_delete_dom_user(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + POLICY_HND connect_pol, domain_pol, user_pol; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + + if ((argc < 2) || (argc > 3)) { + printf("Usage: %s username\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc > 2) + sscanf(argv[2], "%x", &access_mask); + + /* Get sam policy and domain handles */ + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Get handle on user */ + + { + struct samr_Ids user_rids, name_types; + struct lsa_String lsa_acct_name; + + init_lsa_String(&lsa_acct_name, argv[1]); + + result = rpccli_samr_LookupNames(cli, mem_ctx, + &domain_pol, + 1, + &lsa_acct_name, + &user_rids, + &name_types); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_OpenUser(cli, mem_ctx, + &domain_pol, + access_mask, + user_rids.ids[0], + &user_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + } + + /* Delete user */ + + result = rpccli_samr_DeleteUser(cli, mem_ctx, + &user_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Display results */ + + rpccli_samr_Close(cli, mem_ctx, &user_pol); + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + + done: + return result; +} + +/********************************************************************** + * Query user security object + */ +static NTSTATUS cmd_samr_query_sec_obj(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol, user_pol, *pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 sec_info = DACL_SECURITY_INFORMATION; + uint32 user_rid = 0; + TALLOC_CTX *ctx = NULL; + SEC_DESC_BUF *sec_desc_buf=NULL; + bool domain = False; + + ctx=talloc_init("cmd_samr_query_sec_obj"); + + if ((argc < 1) || (argc > 3)) { + printf("Usage: %s [rid|-d] [sec_info]\n", argv[0]); + printf("\tSpecify rid for security on user, -d for security on domain\n"); + talloc_destroy(ctx); + return NT_STATUS_OK; + } + + if (argc > 1) { + if (strcmp(argv[1], "-d") == 0) + domain = True; + else + sscanf(argv[1], "%i", &user_rid); + } + + if (argc == 3) { + sec_info = atoi(argv[2]); + } + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + if (domain || user_rid) + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + if (user_rid) + result = rpccli_samr_OpenUser(cli, mem_ctx, + &domain_pol, + MAXIMUM_ALLOWED_ACCESS, + user_rid, + &user_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Pick which query pol to use */ + + pol = &connect_pol; + + if (domain) + pol = &domain_pol; + + if (user_rid) + pol = &user_pol; + + /* Query SAM security object */ + + result = rpccli_samr_QuerySecurity(cli, mem_ctx, + pol, + sec_info, + &sec_desc_buf); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + display_sec_desc(sec_desc_buf->sd); + + rpccli_samr_Close(cli, mem_ctx, &user_pol); + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + rpccli_samr_Close(cli, mem_ctx, &connect_pol); +done: + talloc_destroy(ctx); + return result; +} + +static NTSTATUS cmd_samr_get_usrdom_pwinfo(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + POLICY_HND connect_pol, domain_pol, user_pol; + struct samr_PwInfo info; + uint32_t rid; + + if (argc != 2) { + printf("Usage: %s rid\n", argv[0]); + return NT_STATUS_OK; + } + + sscanf(argv[1], "%i", &rid); + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + result = rpccli_samr_OpenUser(cli, mem_ctx, + &domain_pol, + MAXIMUM_ALLOWED_ACCESS, + rid, + &user_pol); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + result = rpccli_samr_GetUserPwInfo(cli, mem_ctx, &user_pol, &info); + if (NT_STATUS_IS_OK(result)) { + printf("min_password_length: %d\n", info.min_password_length); + printf("%s\n", + NDR_PRINT_STRUCT_STRING(mem_ctx, + samr_PasswordProperties, &info.password_properties)); + } + + done: + rpccli_samr_Close(cli, mem_ctx, &user_pol); + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + + return result; +} + +static NTSTATUS cmd_samr_get_dom_pwinfo(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + struct lsa_String domain_name; + struct samr_PwInfo info; + + if (argc < 1 || argc > 3) { + printf("Usage: %s <domain>\n", argv[0]); + return NT_STATUS_OK; + } + + init_lsa_String(&domain_name, argv[1]); + + result = rpccli_samr_GetDomPwInfo(cli, mem_ctx, &domain_name, &info); + + if (NT_STATUS_IS_OK(result)) { + printf("min_password_length: %d\n", info.min_password_length); + display_password_properties(info.password_properties); + } + + return result; +} + +/* Look up domain name */ + +static NTSTATUS cmd_samr_lookup_domain(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + fstring sid_string; + struct lsa_String domain_name; + DOM_SID *sid = NULL; + + if (argc != 2) { + printf("Usage: %s domain_name\n", argv[0]); + return NT_STATUS_OK; + } + + init_lsa_String(&domain_name, argv[1]); + + result = rpccli_try_samr_connects(cli, mem_ctx, + access_mask, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_LookupDomain(cli, mem_ctx, + &connect_pol, + &domain_name, + &sid); + + if (NT_STATUS_IS_OK(result)) { + sid_to_fstring(sid_string, sid); + printf("SAMR_LOOKUP_DOMAIN: Domain Name: %s Domain SID: %s\n", + argv[1], sid_string); + } + + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + rpccli_samr_Close(cli, mem_ctx, &connect_pol); +done: + return result; +} + +/* Change user password */ + +static NTSTATUS cmd_samr_chgpasswd(struct rpc_pipe_client *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 *user, *oldpass, *newpass; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + struct samr_Ids rids, types; + struct lsa_String lsa_acct_name; + + if (argc < 3) { + printf("Usage: %s username oldpass newpass\n", argv[0]); + return NT_STATUS_INVALID_PARAMETER; + } + + user = argv[1]; + oldpass = argv[2]; + newpass = argv[3]; + + /* Get sam policy handle */ + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + /* Get domain policy handle */ + + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + init_lsa_String(&lsa_acct_name, user); + + result = rpccli_samr_LookupNames(cli, mem_ctx, + &domain_pol, + 1, + &lsa_acct_name, + &rids, + &types); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + result = rpccli_samr_OpenUser(cli, mem_ctx, + &domain_pol, + access_mask, + rids.ids[0], + &user_pol); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + /* Change user password */ + result = rpccli_samr_chgpasswd_user(cli, mem_ctx, + &user_pol, + newpass, + oldpass); + + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + + done: + if (is_valid_policy_hnd(&user_pol)) { + rpccli_samr_Close(cli, mem_ctx, &user_pol); + } + if (is_valid_policy_hnd(&domain_pol)) { + rpccli_samr_Close(cli, mem_ctx, &domain_pol); + } + if (is_valid_policy_hnd(&connect_pol)) { + rpccli_samr_Close(cli, mem_ctx, &connect_pol); + } + + return result; +} + + +/* Change user password */ + +static NTSTATUS cmd_samr_chgpasswd2(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + const char *user, *oldpass, *newpass; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + + if (argc < 3) { + printf("Usage: %s username oldpass newpass\n", argv[0]); + return NT_STATUS_INVALID_PARAMETER; + } + + user = argv[1]; + oldpass = argv[2]; + newpass = argv[3]; + + /* Get sam policy handle */ + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Get domain policy handle */ + + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Change user password */ + result = rpccli_samr_chgpasswd_user2(cli, mem_ctx, user, newpass, oldpass); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_Close(cli, mem_ctx, &domain_pol); + if (!NT_STATUS_IS_OK(result)) goto done; + + result = rpccli_samr_Close(cli, mem_ctx, &connect_pol); + if (!NT_STATUS_IS_OK(result)) goto done; + + done: + return result; +} + + +/* Change user password */ + +static NTSTATUS cmd_samr_chgpasswd3(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND connect_pol, domain_pol; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + const char *user, *oldpass, *newpass; + uint32 access_mask = MAXIMUM_ALLOWED_ACCESS; + struct samr_DomInfo1 *info = NULL; + struct samr_ChangeReject *reject = NULL; + + if (argc < 3) { + printf("Usage: %s username oldpass newpass\n", argv[0]); + return NT_STATUS_INVALID_PARAMETER; + } + + user = argv[1]; + oldpass = argv[2]; + newpass = argv[3]; + + /* Get sam policy handle */ + + result = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Get domain policy handle */ + + result = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Change user password */ + result = rpccli_samr_chgpasswd_user3(cli, mem_ctx, + user, + newpass, + oldpass, + &info, + &reject); + + if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION)) { + + display_sam_dom_info_1(info); + + switch (reject->reason) { + case SAMR_REJECT_TOO_SHORT: + d_printf("SAMR_REJECT_TOO_SHORT\n"); + break; + case SAMR_REJECT_IN_HISTORY: + d_printf("SAMR_REJECT_IN_HISTORY\n"); + break; + case SAMR_REJECT_COMPLEXITY: + d_printf("SAMR_REJECT_COMPLEXITY\n"); + break; + case SAMR_REJECT_OTHER: + d_printf("SAMR_REJECT_OTHER\n"); + break; + default: + d_printf("unknown reject reason: %d\n", + reject->reason); + break; + } + } + + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = rpccli_samr_Close(cli, mem_ctx, &domain_pol); + if (!NT_STATUS_IS_OK(result)) goto done; + + result = rpccli_samr_Close(cli, mem_ctx, &connect_pol); + if (!NT_STATUS_IS_OK(result)) goto done; + + done: + return result; +} + +static NTSTATUS cmd_samr_get_dispinfo_idx(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS status; + struct policy_handle connect_handle; + struct policy_handle domain_handle; + uint16_t level = 1; + struct lsa_String name; + uint32_t idx = 0; + + if (argc < 2 || argc > 3) { + printf("Usage: %s name level\n", argv[0]); + return NT_STATUS_INVALID_PARAMETER; + } + + init_lsa_String(&name, argv[1]); + + if (argc == 3) { + level = atoi(argv[2]); + } + + status = rpccli_try_samr_connects(cli, mem_ctx, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &connect_handle); + + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = rpccli_samr_OpenDomain(cli, mem_ctx, + &connect_handle, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &domain_sid, + &domain_handle); + + if (!NT_STATUS_IS_OK(status)) + goto done; + + + status = rpccli_samr_GetDisplayEnumerationIndex(cli, mem_ctx, + &domain_handle, + level, + &name, + &idx); + + if (NT_STATUS_IS_OK(status) || + NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) { + printf("idx: %d (0x%08x)\n", idx, idx); + } + done: + + if (is_valid_policy_hnd(&domain_handle)) { + rpccli_samr_Close(cli, mem_ctx, &domain_handle); + } + if (is_valid_policy_hnd(&connect_handle)) { + rpccli_samr_Close(cli, mem_ctx, &connect_handle); + } + + return status; + +} +/* List of commands exported by this module */ + +struct cmd_set samr_commands[] = { + + { "SAMR" }, + + { "queryuser", RPC_RTYPE_NTSTATUS, cmd_samr_query_user, NULL, &ndr_table_samr.syntax_id, NULL, "Query user info", "" }, + { "querygroup", RPC_RTYPE_NTSTATUS, cmd_samr_query_group, NULL, &ndr_table_samr.syntax_id, NULL, "Query group info", "" }, + { "queryusergroups", RPC_RTYPE_NTSTATUS, cmd_samr_query_usergroups, NULL, &ndr_table_samr.syntax_id, NULL, "Query user groups", "" }, + { "queryuseraliases", RPC_RTYPE_NTSTATUS, cmd_samr_query_useraliases, NULL, &ndr_table_samr.syntax_id, NULL, "Query user aliases", "" }, + { "querygroupmem", RPC_RTYPE_NTSTATUS, cmd_samr_query_groupmem, NULL, &ndr_table_samr.syntax_id, NULL, "Query group membership", "" }, + { "queryaliasmem", RPC_RTYPE_NTSTATUS, cmd_samr_query_aliasmem, NULL, &ndr_table_samr.syntax_id, NULL, "Query alias membership", "" }, + { "queryaliasinfo", RPC_RTYPE_NTSTATUS, cmd_samr_query_aliasinfo, NULL, &ndr_table_samr.syntax_id, NULL, "Query alias info", "" }, + { "deletealias", RPC_RTYPE_NTSTATUS, cmd_samr_delete_alias, NULL, &ndr_table_samr.syntax_id, NULL, "Delete an alias", "" }, + { "querydispinfo", RPC_RTYPE_NTSTATUS, cmd_samr_query_dispinfo, NULL, &ndr_table_samr.syntax_id, NULL, "Query display info", "" }, + { "querydispinfo2", RPC_RTYPE_NTSTATUS, cmd_samr_query_dispinfo2, NULL, &ndr_table_samr.syntax_id, NULL, "Query display info", "" }, + { "querydispinfo3", RPC_RTYPE_NTSTATUS, cmd_samr_query_dispinfo3, NULL, &ndr_table_samr.syntax_id, NULL, "Query display info", "" }, + { "querydominfo", RPC_RTYPE_NTSTATUS, cmd_samr_query_dominfo, NULL, &ndr_table_samr.syntax_id, NULL, "Query domain info", "" }, + { "enumdomusers", RPC_RTYPE_NTSTATUS, cmd_samr_enum_dom_users, NULL, &ndr_table_samr.syntax_id, NULL, "Enumerate domain users", "" }, + { "enumdomgroups", RPC_RTYPE_NTSTATUS, cmd_samr_enum_dom_groups, NULL, &ndr_table_samr.syntax_id, NULL, "Enumerate domain groups", "" }, + { "enumalsgroups", RPC_RTYPE_NTSTATUS, cmd_samr_enum_als_groups, NULL, &ndr_table_samr.syntax_id, NULL, "Enumerate alias groups", "" }, + { "enumdomains", RPC_RTYPE_NTSTATUS, cmd_samr_enum_domains, NULL, &ndr_table_samr.syntax_id, NULL, "Enumerate domains", "" }, + + { "createdomuser", RPC_RTYPE_NTSTATUS, cmd_samr_create_dom_user, NULL, &ndr_table_samr.syntax_id, NULL, "Create domain user", "" }, + { "createdomgroup", RPC_RTYPE_NTSTATUS, cmd_samr_create_dom_group, NULL, &ndr_table_samr.syntax_id, NULL, "Create domain group", "" }, + { "createdomalias", RPC_RTYPE_NTSTATUS, cmd_samr_create_dom_alias, NULL, &ndr_table_samr.syntax_id, NULL, "Create domain alias", "" }, + { "samlookupnames", RPC_RTYPE_NTSTATUS, cmd_samr_lookup_names, NULL, &ndr_table_samr.syntax_id, NULL, "Look up names", "" }, + { "samlookuprids", RPC_RTYPE_NTSTATUS, cmd_samr_lookup_rids, NULL, &ndr_table_samr.syntax_id, NULL, "Look up names", "" }, + { "deletedomgroup", RPC_RTYPE_NTSTATUS, cmd_samr_delete_dom_group, NULL, &ndr_table_samr.syntax_id, NULL, "Delete domain group", "" }, + { "deletedomuser", RPC_RTYPE_NTSTATUS, cmd_samr_delete_dom_user, NULL, &ndr_table_samr.syntax_id, NULL, "Delete domain user", "" }, + { "samquerysecobj", RPC_RTYPE_NTSTATUS, cmd_samr_query_sec_obj, NULL, &ndr_table_samr.syntax_id, NULL, "Query SAMR security object", "" }, + { "getdompwinfo", RPC_RTYPE_NTSTATUS, cmd_samr_get_dom_pwinfo, NULL, &ndr_table_samr.syntax_id, NULL, "Retrieve domain password info", "" }, + { "getusrdompwinfo", RPC_RTYPE_NTSTATUS, cmd_samr_get_usrdom_pwinfo, NULL, &ndr_table_samr.syntax_id, NULL, "Retrieve user domain password info", "" }, + + { "lookupdomain", RPC_RTYPE_NTSTATUS, cmd_samr_lookup_domain, NULL, &ndr_table_samr.syntax_id, NULL, "Lookup Domain Name", "" }, + { "chgpasswd", RPC_RTYPE_NTSTATUS, cmd_samr_chgpasswd, NULL, &ndr_table_samr.syntax_id, NULL, "Change user password", "" }, + { "chgpasswd2", RPC_RTYPE_NTSTATUS, cmd_samr_chgpasswd2, NULL, &ndr_table_samr.syntax_id, NULL, "Change user password", "" }, + { "chgpasswd3", RPC_RTYPE_NTSTATUS, cmd_samr_chgpasswd3, NULL, &ndr_table_samr.syntax_id, NULL, "Change user password", "" }, + { "getdispinfoidx", RPC_RTYPE_NTSTATUS, cmd_samr_get_dispinfo_idx, NULL, &ndr_table_samr.syntax_id, NULL, "Get Display Information Index", "" }, + { NULL } +}; diff --git a/source3/rpcclient/cmd_shutdown.c b/source3/rpcclient/cmd_shutdown.c new file mode 100644 index 0000000000..f79c9aad02 --- /dev/null +++ b/source3/rpcclient/cmd_shutdown.c @@ -0,0 +1,117 @@ +/* + Unix SMB/CIFS implementation. + NT Domain Authentication SMB / MSRPC client + Copyright (C) Andrew Tridgell 1994-1997, + Copyright (C) Luke Kenneth Casson Leighton 1996-1997, + Copyright (C) Simo Sorce 2001, + Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003. + + 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 <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "rpcclient.h" + +#if 0 /* don't uncomment this unless you remove the getopt() calls */ + /* use net rpc shutdown instead */ + +/**************************************************************************** +nt shutdown init +****************************************************************************/ +static NTSTATUS cmd_shutdown_init(struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + fstring msg; + uint32 timeout = 20; + bool force = False; + bool reboot = False; + int opt; + + *msg = 0; + optind = 0; /* TODO: test if this hack works on other systems too --simo */ + + while ((opt = getopt(argc, argv, "m:t:rf")) != EOF) + { + /*fprintf (stderr, "[%s]\n", argv[argc-1]);*/ + + switch (opt) + { + case 'm': + fstrcpy(msg, optarg); + /*fprintf (stderr, "[%s|%s]\n", optarg, msg);*/ + break; + + case 't': + timeout = atoi(optarg); + /*fprintf (stderr, "[%s|%d]\n", optarg, timeout);*/ + break; + + case 'r': + reboot = True; + break; + + case 'f': + force = True; + break; + + } + } + + /* create an entry */ + result = cli_shutdown_init(cli, mem_ctx, msg, timeout, reboot, force); + + if (NT_STATUS_IS_OK(result)) + DEBUG(5,("cmd_shutdown_init: query succeeded\n")); + else + DEBUG(5,("cmd_shutdown_init: query failed\n")); + + return result; +} + +/**************************************************************************** +abort a shutdown +****************************************************************************/ +static NTSTATUS cmd_shutdown_abort(struct cli_state *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + + result = cli_shutdown_abort(cli, mem_ctx); + + if (NT_STATUS_IS_OK(result)) + DEBUG(5,("cmd_shutdown_abort: query succeeded\n")); + else + DEBUG(5,("cmd_shutdown_abort: query failed\n")); + + return result; +} +#endif + + +/* List of commands exported by this module */ +struct cmd_set shutdown_commands[] = { + + { "SHUTDOWN" }, + +#if 0 + { "shutdowninit", RPC_RTYPE_NTSTATUS, cmd_shutdown_init, NULL, &ndr_table_initshutdown.syntax_id, "Remote Shutdown (over shutdown pipe)", + "syntax: shutdown [-m message] [-t timeout] [-r] [-h] [-f] (-r == reboot, -h == halt, -f == force)" }, + + { "shutdownabort", RPC_RTYPE_NTSTATUS, cmd_shutdown_abort, NULL, &ndr_table_initshutdown.syntax_id, "Abort Shutdown (over shutdown pipe)", + "syntax: shutdownabort" }, +#endif + { NULL } +}; diff --git a/source3/rpcclient/cmd_spoolss.c b/source3/rpcclient/cmd_spoolss.c new file mode 100644 index 0000000000..2a9f2b82bb --- /dev/null +++ b/source3/rpcclient/cmd_spoolss.c @@ -0,0 +1,2782 @@ +/* + Unix SMB/CIFS implementation. + RPC pipe client + + Copyright (C) Gerald Carter 2001-2005 + Copyright (C) Tim Potter 2000 + Copyright (C) Andrew Tridgell 1992-1999 + Copyright (C) Luke Kenneth Casson Leighton 1996-1999 + + 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 <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "rpcclient.h" + +struct table_node { + const char *long_archi; + const char *short_archi; + int version; +}; + +/* The version int is used by getdrivers. Note that + all architecture strings that support mutliple + versions must be grouped together since enumdrivers + uses this property to prevent issuing multiple + enumdriver calls for the same arch */ + + +static const struct table_node archi_table[]= { + + {"Windows 4.0", "WIN40", 0 }, + {"Windows NT x86", "W32X86", 2 }, + {"Windows NT x86", "W32X86", 3 }, + {"Windows NT R4000", "W32MIPS", 2 }, + {"Windows NT Alpha_AXP", "W32ALPHA", 2 }, + {"Windows NT PowerPC", "W32PPC", 2 }, + {"Windows IA64", "IA64", 3 }, + {"Windows x64", "x64", 3 }, + {NULL, "", -1 } +}; + +/** + * @file + * + * rpcclient module for SPOOLSS rpc pipe. + * + * This generally just parses and checks command lines, and then calls + * a cli_spoolss function. + **/ + +/**************************************************************************** + function to do the mapping between the long architecture name and + the short one. +****************************************************************************/ + +static const char *cmd_spoolss_get_short_archi(const char *long_archi) +{ + int i=-1; + + DEBUG(107,("Getting architecture dependant directory\n")); + do { + i++; + } while ( (archi_table[i].long_archi!=NULL ) && + StrCaseCmp(long_archi, archi_table[i].long_archi) ); + + if (archi_table[i].long_archi==NULL) { + DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi)); + return NULL; + } + + /* this might be client code - but shouldn't this be an fstrcpy etc? */ + + + DEBUGADD(108,("index: [%d]\n", i)); + DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi)); + DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi)); + + return archi_table[i].short_archi; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_open_printer_ex(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR werror; + fstring printername; + fstring servername, user; + POLICY_HND hnd; + + if (argc != 2) { + printf("Usage: %s <printername>\n", argv[0]); + return WERR_OK; + } + + if (!cli) + return WERR_GENERAL_FAILURE; + + slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost); + strupper_m(servername); + fstrcpy(user, cli->auth->user_name); + fstrcpy(printername, argv[1]); + + /* Open the printer handle */ + + werror = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, + "", PRINTER_ALL_ACCESS, + servername, user, &hnd); + + if (W_ERROR_IS_OK(werror)) { + printf("Printer %s opened successfully\n", printername); + werror = rpccli_spoolss_close_printer(cli, mem_ctx, &hnd); + + if (!W_ERROR_IS_OK(werror)) { + printf("Error closing printer handle! (%s)\n", + get_dos_error_msg(werror)); + } + } + + return werror; +} + + +/**************************************************************************** +****************************************************************************/ + +static void display_print_info_0(PRINTER_INFO_0 *i0) +{ + fstring name = ""; + fstring servername = ""; + + if (!i0) + return; + + rpcstr_pull(name, i0->printername.buffer, sizeof(name), -1, STR_TERMINATE); + + rpcstr_pull(servername, i0->servername.buffer, sizeof(servername), -1,STR_TERMINATE); + + printf("\tprintername:[%s]\n", name); + printf("\tservername:[%s]\n", servername); + printf("\tcjobs:[0x%x]\n", i0->cjobs); + printf("\ttotal_jobs:[0x%x]\n", i0->total_jobs); + + printf("\t:date: [%d]-[%d]-[%d] (%d)\n", i0->year, i0->month, + i0->day, i0->dayofweek); + printf("\t:time: [%d]-[%d]-[%d]-[%d]\n", i0->hour, i0->minute, + i0->second, i0->milliseconds); + + printf("\tglobal_counter:[0x%x]\n", i0->global_counter); + printf("\ttotal_pages:[0x%x]\n", i0->total_pages); + + printf("\tmajorversion:[0x%x]\n", i0->major_version); + printf("\tbuildversion:[0x%x]\n", i0->build_version); + + printf("\tunknown7:[0x%x]\n", i0->unknown7); + printf("\tunknown8:[0x%x]\n", i0->unknown8); + printf("\tunknown9:[0x%x]\n", i0->unknown9); + printf("\tsession_counter:[0x%x]\n", i0->session_counter); + printf("\tunknown11:[0x%x]\n", i0->unknown11); + printf("\tprinter_errors:[0x%x]\n", i0->printer_errors); + printf("\tunknown13:[0x%x]\n", i0->unknown13); + printf("\tunknown14:[0x%x]\n", i0->unknown14); + printf("\tunknown15:[0x%x]\n", i0->unknown15); + printf("\tunknown16:[0x%x]\n", i0->unknown16); + printf("\tchange_id:[0x%x]\n", i0->change_id); + printf("\tunknown18:[0x%x]\n", i0->unknown18); + printf("\tstatus:[0x%x]\n", i0->status); + printf("\tunknown20:[0x%x]\n", i0->unknown20); + printf("\tc_setprinter:[0x%x]\n", i0->c_setprinter); + printf("\tunknown22:[0x%x]\n", i0->unknown22); + printf("\tunknown23:[0x%x]\n", i0->unknown23); + printf("\tunknown24:[0x%x]\n", i0->unknown24); + printf("\tunknown25:[0x%x]\n", i0->unknown25); + printf("\tunknown26:[0x%x]\n", i0->unknown26); + printf("\tunknown27:[0x%x]\n", i0->unknown27); + printf("\tunknown28:[0x%x]\n", i0->unknown28); + printf("\tunknown29:[0x%x]\n", i0->unknown29); + + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_info_1(PRINTER_INFO_1 *i1) +{ + fstring desc = ""; + fstring name = ""; + fstring comm = ""; + + rpcstr_pull(desc, i1->description.buffer, sizeof(desc), -1, + STR_TERMINATE); + + rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE); + rpcstr_pull(comm, i1->comment.buffer, sizeof(comm), -1, STR_TERMINATE); + + printf("\tflags:[0x%x]\n", i1->flags); + printf("\tname:[%s]\n", name); + printf("\tdescription:[%s]\n", desc); + printf("\tcomment:[%s]\n", comm); + + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_info_2(PRINTER_INFO_2 *i2) +{ + fstring servername = ""; + fstring printername = ""; + fstring sharename = ""; + fstring portname = ""; + fstring drivername = ""; + fstring comment = ""; + fstring location = ""; + fstring sepfile = ""; + fstring printprocessor = ""; + fstring datatype = ""; + fstring parameters = ""; + + rpcstr_pull(servername, i2->servername.buffer,sizeof(servername), -1, STR_TERMINATE); + rpcstr_pull(printername, i2->printername.buffer,sizeof(printername), -1, STR_TERMINATE); + rpcstr_pull(sharename, i2->sharename.buffer,sizeof(sharename), -1, STR_TERMINATE); + rpcstr_pull(portname, i2->portname.buffer,sizeof(portname), -1, STR_TERMINATE); + rpcstr_pull(drivername, i2->drivername.buffer,sizeof(drivername), -1, STR_TERMINATE); + rpcstr_pull(comment, i2->comment.buffer,sizeof(comment), -1, STR_TERMINATE); + rpcstr_pull(location, i2->location.buffer,sizeof(location), -1, STR_TERMINATE); + rpcstr_pull(sepfile, i2->sepfile.buffer,sizeof(sepfile), -1, STR_TERMINATE); + rpcstr_pull(printprocessor, i2->printprocessor.buffer,sizeof(printprocessor), -1, STR_TERMINATE); + rpcstr_pull(datatype, i2->datatype.buffer,sizeof(datatype), -1, STR_TERMINATE); + rpcstr_pull(parameters, i2->parameters.buffer,sizeof(parameters), -1, STR_TERMINATE); + + printf("\tservername:[%s]\n", servername); + printf("\tprintername:[%s]\n", printername); + printf("\tsharename:[%s]\n", sharename); + printf("\tportname:[%s]\n", portname); + printf("\tdrivername:[%s]\n", drivername); + printf("\tcomment:[%s]\n", comment); + printf("\tlocation:[%s]\n", location); + printf("\tsepfile:[%s]\n", sepfile); + printf("\tprintprocessor:[%s]\n", printprocessor); + printf("\tdatatype:[%s]\n", datatype); + printf("\tparameters:[%s]\n", parameters); + printf("\tattributes:[0x%x]\n", i2->attributes); + printf("\tpriority:[0x%x]\n", i2->priority); + printf("\tdefaultpriority:[0x%x]\n", i2->defaultpriority); + printf("\tstarttime:[0x%x]\n", i2->starttime); + printf("\tuntiltime:[0x%x]\n", i2->untiltime); + printf("\tstatus:[0x%x]\n", i2->status); + printf("\tcjobs:[0x%x]\n", i2->cjobs); + printf("\taverageppm:[0x%x]\n", i2->averageppm); + + if (i2->secdesc) + display_sec_desc(i2->secdesc); + + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_info_3(PRINTER_INFO_3 *i3) +{ + display_sec_desc(i3->secdesc); + + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_info_7(PRINTER_INFO_7 *i7) +{ + fstring guid = ""; + rpcstr_pull(guid, i7->guid.buffer,sizeof(guid), -1, STR_TERMINATE); + printf("\tguid:[%s]\n", guid); + printf("\taction:[0x%x]\n", i7->action); +} + + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_enum_printers(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR result; + uint32 info_level = 1; + PRINTER_INFO_CTR ctr; + uint32 i = 0, num_printers; + fstring name; + + if (argc > 3) + { + printf("Usage: %s [level] [name]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) + info_level = atoi(argv[1]); + + if (argc == 3) + fstrcpy(name, argv[2]); + else { + slprintf(name, sizeof(name)-1, "\\\\%s", cli->desthost); + strupper_m(name); + } + + ZERO_STRUCT(ctr); + + result = rpccli_spoolss_enum_printers(cli, mem_ctx, name, PRINTER_ENUM_LOCAL, + info_level, &num_printers, &ctr); + + if (W_ERROR_IS_OK(result)) { + + if (!num_printers) { + printf ("No printers returned.\n"); + goto done; + } + + for (i = 0; i < num_printers; i++) { + switch(info_level) { + case 0: + display_print_info_0(&ctr.printers_0[i]); + break; + case 1: + display_print_info_1(&ctr.printers_1[i]); + break; + case 2: + display_print_info_2(&ctr.printers_2[i]); + break; + case 3: + display_print_info_3(&ctr.printers_3[i]); + break; + default: + printf("unknown info level %d\n", info_level); + goto done; + } + } + } + done: + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static void display_port_info_1(PORT_INFO_1 *i1) +{ + fstring buffer; + + rpcstr_pull(buffer, i1->port_name.buffer, sizeof(buffer), -1, STR_TERMINATE); + printf("\tPort Name:\t[%s]\n", buffer); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_port_info_2(PORT_INFO_2 *i2) +{ + fstring buffer; + + rpcstr_pull(buffer, i2->port_name.buffer, sizeof(buffer), -1, STR_TERMINATE); + printf("\tPort Name:\t[%s]\n", buffer); + rpcstr_pull(buffer, i2->monitor_name.buffer, sizeof(buffer), -1, STR_TERMINATE); + + printf("\tMonitor Name:\t[%s]\n", buffer); + rpcstr_pull(buffer, i2->description.buffer, sizeof(buffer), -1, STR_TERMINATE); + + printf("\tDescription:\t[%s]\n", buffer); + printf("\tPort Type:\t" ); + if ( i2->port_type ) { + int comma = 0; /* hack */ + printf( "[" ); + if ( i2->port_type & PORT_TYPE_READ ) { + printf( "Read" ); + comma = 1; + } + if ( i2->port_type & PORT_TYPE_WRITE ) { + printf( "%sWrite", comma ? ", " : "" ); + comma = 1; + } + /* These two have slightly different interpretations + on 95/98/ME but I'm disregarding that for now */ + if ( i2->port_type & PORT_TYPE_REDIRECTED ) { + printf( "%sRedirected", comma ? ", " : "" ); + comma = 1; + } + if ( i2->port_type & PORT_TYPE_NET_ATTACHED ) { + printf( "%sNet-Attached", comma ? ", " : "" ); + } + printf( "]\n" ); + } else { + printf( "[Unset]\n" ); + } + printf("\tReserved:\t[%d]\n", i2->reserved); + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_enum_ports(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + WERROR result; + uint32 info_level = 1; + PORT_INFO_CTR ctr; + uint32 returned; + + if (argc > 2) { + printf("Usage: %s [level]\n", argv[0]); + return WERR_OK; + } + + if (argc == 2) + info_level = atoi(argv[1]); + + /* Enumerate ports */ + + ZERO_STRUCT(ctr); + + result = rpccli_spoolss_enum_ports(cli, mem_ctx, info_level, &returned, &ctr); + + if (W_ERROR_IS_OK(result)) { + int i; + + for (i = 0; i < returned; i++) { + switch (info_level) { + case 1: + display_port_info_1(&ctr.port.info_1[i]); + break; + case 2: + display_port_info_2(&ctr.port.info_2[i]); + break; + default: + printf("unknown info level %d\n", info_level); + break; + } + } + } + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_setprinter(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND pol; + WERROR result; + uint32 info_level = 2; + bool opened_hnd = False; + PRINTER_INFO_CTR ctr; + fstring printername, + servername, + user, + comment; + + if (argc == 1 || argc > 3) { + printf("Usage: %s printername comment\n", argv[0]); + + return WERR_OK; + } + + /* Open a printer handle */ + if (argc == 3) { + fstrcpy(comment, argv[2]); + } + + slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost); + strupper_m(servername); + slprintf(printername, sizeof(servername)-1, "%s\\%s", servername, argv[1]); + fstrcpy(user, cli->auth->user_name); + + /* get a printer handle */ + result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", + PRINTER_ALL_ACCESS, servername, + user, &pol); + + if (!W_ERROR_IS_OK(result)) + goto done; + + opened_hnd = True; + + /* Get printer info */ + result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, info_level, &ctr); + + if (!W_ERROR_IS_OK(result)) + goto done; + + + /* Modify the comment. */ + init_unistr(&ctr.printers_2->comment, comment); + ctr.printers_2->devmode = NULL; + ctr.printers_2->secdesc = NULL; + + result = rpccli_spoolss_setprinter(cli, mem_ctx, &pol, info_level, &ctr, 0); + if (W_ERROR_IS_OK(result)) + printf("Success in setting comment.\n"); + + done: + if (opened_hnd) + rpccli_spoolss_close_printer(cli, mem_ctx, &pol); + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_setprintername(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND pol; + WERROR result; + uint32 info_level = 2; + bool opened_hnd = False; + PRINTER_INFO_CTR ctr; + fstring printername, + servername, + user, + new_printername; + + if (argc == 1 || argc > 3) { + printf("Usage: %s printername new_printername\n", argv[0]); + + return WERR_OK; + } + + /* Open a printer handle */ + if (argc == 3) { + fstrcpy(new_printername, argv[2]); + } + + slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost); + strupper_m(servername); + slprintf(printername, sizeof(printername)-1, "%s\\%s", servername, argv[1]); + fstrcpy(user, cli->auth->user_name); + + /* get a printer handle */ + result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", + PRINTER_ALL_ACCESS, servername, + user, &pol); + + if (!W_ERROR_IS_OK(result)) + goto done; + + opened_hnd = True; + + /* Get printer info */ + result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, info_level, &ctr); + + if (!W_ERROR_IS_OK(result)) + goto done; + + /* Modify the printername. */ + init_unistr(&ctr.printers_2->printername, new_printername); + ctr.printers_2->devmode = NULL; + ctr.printers_2->secdesc = NULL; + + result = rpccli_spoolss_setprinter(cli, mem_ctx, &pol, info_level, &ctr, 0); + if (W_ERROR_IS_OK(result)) + printf("Success in setting printername.\n"); + + done: + if (opened_hnd) + rpccli_spoolss_close_printer(cli, mem_ctx, &pol); + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_getprinter(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND pol; + WERROR result; + uint32 info_level = 1; + bool opened_hnd = False; + PRINTER_INFO_CTR ctr; + fstring printername, + servername, + user; + + if (argc == 1 || argc > 3) { + printf("Usage: %s <printername> [level]\n", argv[0]); + return WERR_OK; + } + + /* Open a printer handle */ + if (argc == 3) { + info_level = atoi(argv[2]); + } + + slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost); + strupper_m(servername); + slprintf(printername, sizeof(printername)-1, "%s\\%s", servername, argv[1]); + fstrcpy(user, cli->auth->user_name); + + /* get a printer handle */ + + result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, + "", MAXIMUM_ALLOWED_ACCESS, + servername, user, &pol); + + if (!W_ERROR_IS_OK(result)) + goto done; + + opened_hnd = True; + + /* Get printer info */ + + result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, info_level, &ctr); + + if (!W_ERROR_IS_OK(result)) + goto done; + + /* Display printer info */ + + switch (info_level) { + case 0: + display_print_info_0(ctr.printers_0); + break; + case 1: + display_print_info_1(ctr.printers_1); + break; + case 2: + display_print_info_2(ctr.printers_2); + break; + case 3: + display_print_info_3(ctr.printers_3); + break; + case 7: + display_print_info_7(ctr.printers_7); + break; + default: + printf("unknown info level %d\n", info_level); + break; + } + + done: + if (opened_hnd) + rpccli_spoolss_close_printer(cli, mem_ctx, &pol); + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static void display_reg_value(REGISTRY_VALUE value) +{ + char *text = NULL; + + switch(value.type) { + case REG_DWORD: + printf("%s: REG_DWORD: 0x%08x\n", value.valuename, + *((uint32 *) value.data_p)); + break; + case REG_SZ: + rpcstr_pull_talloc(talloc_tos(), + &text, + value.data_p, + value.size, + STR_TERMINATE); + printf("%s: REG_SZ: %s\n", value.valuename, text ? text : ""); + break; + case REG_BINARY: { + char *hex = hex_encode(NULL, value.data_p, value.size); + size_t i, len; + printf("%s: REG_BINARY:", value.valuename); + len = strlen(hex); + for (i=0; i<len; i++) { + if (hex[i] == '\0') { + break; + } + if (i%40 == 0) { + putchar('\n'); + } + putchar(hex[i]); + } + TALLOC_FREE(hex); + putchar('\n'); + break; + } + case REG_MULTI_SZ: { + uint32 i, num_values; + char **values; + + if (!W_ERROR_IS_OK(reg_pull_multi_sz(NULL, value.data_p, + value.size, &num_values, + &values))) { + d_printf("reg_pull_multi_sz failed\n"); + break; + } + + for (i=0; i<num_values; i++) { + d_printf("%s\n", values[i]); + } + TALLOC_FREE(values); + break; + } + default: + printf("%s: unknown type %d\n", value.valuename, value.type); + } + +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_getprinterdata(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND pol; + WERROR result; + bool opened_hnd = False; + fstring printername, + servername, + user; + const char *valuename; + REGISTRY_VALUE value; + + if (argc != 3) { + printf("Usage: %s <printername> <valuename>\n", argv[0]); + printf("<printername> of . queries print server\n"); + return WERR_OK; + } + valuename = argv[2]; + + /* Open a printer handle */ + + slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost); + strupper_m(servername); + if (strncmp(argv[1], ".", sizeof(".")) == 0) + fstrcpy(printername, servername); + else + slprintf(printername, sizeof(servername)-1, "%s\\%s", + servername, argv[1]); + fstrcpy(user, cli->auth->user_name); + + /* get a printer handle */ + + result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, + "", MAXIMUM_ALLOWED_ACCESS, + servername, user, &pol); + + if (!W_ERROR_IS_OK(result)) + goto done; + + opened_hnd = True; + + /* Get printer info */ + + result = rpccli_spoolss_getprinterdata(cli, mem_ctx, &pol, valuename, &value); + + if (!W_ERROR_IS_OK(result)) + goto done; + + /* Display printer data */ + + fstrcpy(value.valuename, valuename); + display_reg_value(value); + + + done: + if (opened_hnd) + rpccli_spoolss_close_printer(cli, mem_ctx, &pol); + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_getprinterdataex(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND pol; + WERROR result; + bool opened_hnd = False; + fstring printername, + servername, + user; + const char *valuename, *keyname; + REGISTRY_VALUE value; + + if (argc != 4) { + printf("Usage: %s <printername> <keyname> <valuename>\n", + argv[0]); + printf("<printername> of . queries print server\n"); + return WERR_OK; + } + valuename = argv[3]; + keyname = argv[2]; + + /* Open a printer handle */ + + slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost); + strupper_m(servername); + if (strncmp(argv[1], ".", sizeof(".")) == 0) + fstrcpy(printername, servername); + else + slprintf(printername, sizeof(printername)-1, "%s\\%s", + servername, argv[1]); + fstrcpy(user, cli->auth->user_name); + + /* get a printer handle */ + + result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, + "", MAXIMUM_ALLOWED_ACCESS, + servername, user, &pol); + + if (!W_ERROR_IS_OK(result)) + goto done; + + opened_hnd = True; + + /* Get printer info */ + + result = rpccli_spoolss_getprinterdataex(cli, mem_ctx, &pol, keyname, + valuename, &value); + + if (!W_ERROR_IS_OK(result)) + goto done; + + /* Display printer data */ + + fstrcpy(value.valuename, valuename); + display_reg_value(value); + + + done: + if (opened_hnd) + rpccli_spoolss_close_printer(cli, mem_ctx, &pol); + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_driver_1(DRIVER_INFO_1 *i1) +{ + fstring name; + if (i1 == NULL) + return; + + rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE); + + printf ("Printer Driver Info 1:\n"); + printf ("\tDriver Name: [%s]\n\n", name); + + return; +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_driver_2(DRIVER_INFO_2 *i1) +{ + fstring name; + fstring architecture; + fstring driverpath; + fstring datafile; + fstring configfile; + if (i1 == NULL) + return; + + rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE); + rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), -1, STR_TERMINATE); + rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), -1, STR_TERMINATE); + rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), -1, STR_TERMINATE); + rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), -1, STR_TERMINATE); + + printf ("Printer Driver Info 2:\n"); + printf ("\tVersion: [%x]\n", i1->version); + printf ("\tDriver Name: [%s]\n", name); + printf ("\tArchitecture: [%s]\n", architecture); + printf ("\tDriver Path: [%s]\n", driverpath); + printf ("\tDatafile: [%s]\n", datafile); + printf ("\tConfigfile: [%s]\n\n", configfile); + + return; +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_driver_3(DRIVER_INFO_3 *i1) +{ + fstring name = ""; + fstring architecture = ""; + fstring driverpath = ""; + fstring datafile = ""; + fstring configfile = ""; + fstring helpfile = ""; + fstring dependentfiles = ""; + fstring monitorname = ""; + fstring defaultdatatype = ""; + + int length=0; + bool valid = True; + + if (i1 == NULL) + return; + + rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE); + rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), -1, STR_TERMINATE); + rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), -1, STR_TERMINATE); + rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), -1, STR_TERMINATE); + rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), -1, STR_TERMINATE); + rpcstr_pull(helpfile, i1->helpfile.buffer, sizeof(helpfile), -1, STR_TERMINATE); + rpcstr_pull(monitorname, i1->monitorname.buffer, sizeof(monitorname), -1, STR_TERMINATE); + rpcstr_pull(defaultdatatype, i1->defaultdatatype.buffer, sizeof(defaultdatatype), -1, STR_TERMINATE); + + printf ("Printer Driver Info 3:\n"); + printf ("\tVersion: [%x]\n", i1->version); + printf ("\tDriver Name: [%s]\n",name); + printf ("\tArchitecture: [%s]\n", architecture); + printf ("\tDriver Path: [%s]\n", driverpath); + printf ("\tDatafile: [%s]\n", datafile); + printf ("\tConfigfile: [%s]\n", configfile); + printf ("\tHelpfile: [%s]\n\n", helpfile); + + while (valid) + { + rpcstr_pull(dependentfiles, i1->dependentfiles+length, sizeof(dependentfiles), -1, STR_TERMINATE); + + length+=strlen(dependentfiles)+1; + + if (strlen(dependentfiles) > 0) + { + printf ("\tDependentfiles: [%s]\n", dependentfiles); + } + else + { + valid = False; + } + } + + printf ("\n"); + + printf ("\tMonitorname: [%s]\n", monitorname); + printf ("\tDefaultdatatype: [%s]\n\n", defaultdatatype); + + return; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_getdriver(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND pol; + WERROR werror; + uint32 info_level = 3; + bool opened_hnd = False; + PRINTER_DRIVER_CTR ctr; + fstring printername, + servername, + user; + uint32 i; + bool success = False; + + if ((argc == 1) || (argc > 3)) + { + printf("Usage: %s <printername> [level]\n", argv[0]); + return WERR_OK; + } + + /* get the arguments need to open the printer handle */ + slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost); + strupper_m(servername); + fstrcpy(user, cli->auth->user_name); + slprintf(printername, sizeof(servername)-1, "%s\\%s", servername, argv[1]); + if (argc == 3) + info_level = atoi(argv[2]); + + /* Open a printer handle */ + + werror = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", + PRINTER_ACCESS_USE, + servername, user, &pol); + + if (!W_ERROR_IS_OK(werror)) { + printf("Error opening printer handle for %s!\n", printername); + return werror; + } + + opened_hnd = True; + + /* loop through and print driver info level for each architecture */ + + for (i=0; archi_table[i].long_archi!=NULL; i++) { + + werror = rpccli_spoolss_getprinterdriver( cli, mem_ctx, &pol, info_level, + archi_table[i].long_archi, archi_table[i].version, + &ctr); + + if (!W_ERROR_IS_OK(werror)) + continue; + + /* need at least one success */ + + success = True; + + printf ("\n[%s]\n", archi_table[i].long_archi); + + switch (info_level) { + case 1: + display_print_driver_1 (ctr.info1); + break; + case 2: + display_print_driver_2 (ctr.info2); + break; + case 3: + display_print_driver_3 (ctr.info3); + break; + default: + printf("unknown info level %d\n", info_level); + break; + } + } + + /* Cleanup */ + + if (opened_hnd) + rpccli_spoolss_close_printer (cli, mem_ctx, &pol); + + if ( success ) + werror = WERR_OK; + + return werror; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_enum_drivers(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR werror = WERR_OK; + uint32 info_level = 1; + PRINTER_DRIVER_CTR ctr; + uint32 i, j, + returned; + + if (argc > 2) { + printf("Usage: enumdrivers [level]\n"); + return WERR_OK; + } + + if (argc == 2) + info_level = atoi(argv[1]); + + + /* loop through and print driver info level for each architecture */ + for (i=0; archi_table[i].long_archi!=NULL; i++) { + /* check to see if we already asked for this architecture string */ + + if ( i>0 && strequal(archi_table[i].long_archi, archi_table[i-1].long_archi) ) + continue; + + werror = rpccli_spoolss_enumprinterdrivers( + cli, mem_ctx, info_level, + archi_table[i].long_archi, &returned, &ctr); + + if (W_ERROR_V(werror) == W_ERROR_V(WERR_INVALID_ENVIRONMENT)) { + printf ("Server does not support environment [%s]\n", + archi_table[i].long_archi); + werror = WERR_OK; + continue; + } + + if (returned == 0) + continue; + + if (!W_ERROR_IS_OK(werror)) { + printf ("Error getting driver for environment [%s] - %d\n", + archi_table[i].long_archi, W_ERROR_V(werror)); + continue; + } + + printf ("\n[%s]\n", archi_table[i].long_archi); + switch (info_level) + { + + case 1: + for (j=0; j < returned; j++) { + display_print_driver_1 (&ctr.info1[j]); + } + break; + case 2: + for (j=0; j < returned; j++) { + display_print_driver_2 (&ctr.info2[j]); + } + break; + case 3: + for (j=0; j < returned; j++) { + display_print_driver_3 (&ctr.info3[j]); + } + break; + default: + printf("unknown info level %d\n", info_level); + return WERR_UNKNOWN_LEVEL; + } + } + + return werror; +} + +/**************************************************************************** +****************************************************************************/ + +static void display_printdriverdir_1(DRIVER_DIRECTORY_1 *i1) +{ + fstring name; + if (i1 == NULL) + return; + + rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE); + + printf ("\tDirectory Name:[%s]\n", name); +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_getdriverdir(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR result; + fstring env; + DRIVER_DIRECTORY_CTR ctr; + + if (argc > 2) { + printf("Usage: %s [environment]\n", argv[0]); + return WERR_OK; + } + + /* Get the arguments need to open the printer handle */ + + if (argc == 2) + fstrcpy (env, argv[1]); + else + fstrcpy (env, "Windows NT x86"); + + /* Get the directory. Only use Info level 1 */ + + result = rpccli_spoolss_getprinterdriverdir(cli, mem_ctx, 1, env, &ctr); + + if (W_ERROR_IS_OK(result)) + display_printdriverdir_1(ctr.info1); + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +void set_drv_info_3_env (DRIVER_INFO_3 *info, const char *arch) +{ + + int i; + + for (i=0; archi_table[i].long_archi != NULL; i++) + { + if (strcmp(arch, archi_table[i].short_archi) == 0) + { + info->version = archi_table[i].version; + init_unistr (&info->architecture, archi_table[i].long_archi); + break; + } + } + + if (archi_table[i].long_archi == NULL) + { + DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch)); + } + + return; +} + + +/************************************************************************** + wrapper for strtok to get the next parameter from a delimited list. + Needed to handle the empty parameter string denoted by "NULL" + *************************************************************************/ + +static char* get_driver_3_param (char* str, const char* delim, UNISTR* dest, + char **saveptr) +{ + char *ptr; + + /* get the next token */ + ptr = strtok_r(str, delim, saveptr); + + /* a string of 'NULL' is used to represent an empty + parameter because two consecutive delimiters + will not return an empty string. See man strtok(3) + for details */ + if (ptr && (StrCaseCmp(ptr, "NULL") == 0)) + ptr = NULL; + + if (dest != NULL) + init_unistr(dest, ptr); + + return ptr; +} + +/******************************************************************************** + fill in the members of a DRIVER_INFO_3 struct using a character + string in the form of + <Long Printer Name>:<Driver File Name>:<Data File Name>:\ + <Config File Name>:<Help File Name>:<Language Monitor Name>:\ + <Default Data Type>:<Comma Separated list of Files> + *******************************************************************************/ +static bool init_drv_info_3_members ( TALLOC_CTX *mem_ctx, DRIVER_INFO_3 *info, + char *args ) +{ + char *str, *str2; + uint32 len, i; + char *saveptr = NULL; + + /* fill in the UNISTR fields */ + str = get_driver_3_param (args, ":", &info->name, &saveptr); + str = get_driver_3_param (NULL, ":", &info->driverpath, &saveptr); + str = get_driver_3_param (NULL, ":", &info->datafile, &saveptr); + str = get_driver_3_param (NULL, ":", &info->configfile, &saveptr); + str = get_driver_3_param (NULL, ":", &info->helpfile, &saveptr); + str = get_driver_3_param (NULL, ":", &info->monitorname, &saveptr); + str = get_driver_3_param (NULL, ":", &info->defaultdatatype, &saveptr); + + /* <Comma Separated List of Dependent Files> */ + /* save the beginning of the string */ + str2 = get_driver_3_param (NULL, ":", NULL, &saveptr); + str = str2; + + /* begin to strip out each filename */ + str = strtok_r(str, ",", &saveptr); + len = 0; + while (str != NULL) + { + /* keep a cumlative count of the str lengths */ + len += strlen(str)+1; + str = strtok_r(NULL, ",", &saveptr); + } + + /* allocate the space; add one extra slot for a terminating NULL. + Each filename is NULL terminated and the end contains a double + NULL */ + if ((info->dependentfiles=TALLOC_ARRAY(mem_ctx, uint16, len+1)) == NULL) + { + DEBUG(0,("init_drv_info_3_members: Unable to malloc memory for dependenfiles\n")); + return False; + } + for (i=0; i<len; i++) + { + SSVAL(&info->dependentfiles[i], 0, str2[i]); + } + info->dependentfiles[len] = '\0'; + + return True; +} + + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_addprinterdriver(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR result; + uint32 level = 3; + PRINTER_DRIVER_CTR ctr; + DRIVER_INFO_3 info3; + const char *arch; + fstring driver_name; + char *driver_args; + + /* parse the command arguments */ + if (argc != 3 && argc != 4) + { + printf ("Usage: %s <Environment> \\\n", argv[0]); + printf ("\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n"); + printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n"); + printf ("\t<Default Data Type>:<Comma Separated list of Files> \\\n"); + printf ("\t[version]\n"); + + return WERR_OK; + } + + /* Fill in the DRIVER_INFO_3 struct */ + ZERO_STRUCT(info3); + if (!(arch = cmd_spoolss_get_short_archi(argv[1]))) + { + printf ("Error Unknown architechture [%s]\n", argv[1]); + return WERR_INVALID_PARAM; + } + else + set_drv_info_3_env(&info3, arch); + + driver_args = talloc_strdup( mem_ctx, argv[2] ); + if (!init_drv_info_3_members(mem_ctx, &info3, driver_args )) + { + printf ("Error Invalid parameter list - %s.\n", argv[2]); + return WERR_INVALID_PARAM; + } + + /* if printer driver version specified, override the default version + * used by the architecture. This allows installation of Windows + * 2000 (version 3) printer drivers. */ + if (argc == 4) + { + info3.version = atoi(argv[3]); + } + + + ctr.info3 = &info3; + result = rpccli_spoolss_addprinterdriver (cli, mem_ctx, level, &ctr); + + if (W_ERROR_IS_OK(result)) { + rpcstr_pull(driver_name, info3.name.buffer, + sizeof(driver_name), -1, STR_TERMINATE); + printf ("Printer Driver %s successfully installed.\n", + driver_name); + } + + return result; +} + + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_addprinterex(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR result; + uint32 level = 2; + PRINTER_INFO_CTR ctr; + PRINTER_INFO_2 info2; + fstring servername; + + /* parse the command arguments */ + if (argc != 5) + { + printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]); + return WERR_OK; + } + + slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost); + strupper_m(servername); + + /* Fill in the DRIVER_INFO_2 struct */ + ZERO_STRUCT(info2); + + init_unistr( &info2.printername, argv[1]); + init_unistr( &info2.sharename, argv[2]); + init_unistr( &info2.drivername, argv[3]); + init_unistr( &info2.portname, argv[4]); + init_unistr( &info2.comment, "Created by rpcclient"); + init_unistr( &info2.printprocessor, "winprint"); + init_unistr( &info2.datatype, "RAW"); + info2.devmode = NULL; + info2.secdesc = NULL; + info2.attributes = PRINTER_ATTRIBUTE_SHARED; + info2.priority = 0; + info2.defaultpriority = 0; + info2.starttime = 0; + info2.untiltime = 0; + + /* These three fields must not be used by AddPrinter() + as defined in the MS Platform SDK documentation.. + --jerry + info2.status = 0; + info2.cjobs = 0; + info2.averageppm = 0; + */ + + ctr.printers_2 = &info2; + result = rpccli_spoolss_addprinterex (cli, mem_ctx, level, &ctr); + + if (W_ERROR_IS_OK(result)) + printf ("Printer %s successfully installed.\n", argv[1]); + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_setdriver(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND pol; + WERROR result; + uint32 level = 2; + bool opened_hnd = False; + PRINTER_INFO_CTR ctr; + PRINTER_INFO_2 info2; + fstring servername, + printername, + user; + + /* parse the command arguments */ + if (argc != 3) + { + printf ("Usage: %s <printer> <driver>\n", argv[0]); + return WERR_OK; + } + + slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost); + strupper_m(servername); + slprintf(printername, sizeof(printername)-1, "%s\\%s", servername, argv[1]); + fstrcpy(user, cli->auth->user_name); + + /* Get a printer handle */ + + result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", + PRINTER_ALL_ACCESS, + servername, user, &pol); + + if (!W_ERROR_IS_OK(result)) + goto done; + + opened_hnd = True; + + /* Get printer info */ + + ZERO_STRUCT (info2); + ctr.printers_2 = &info2; + + result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, level, &ctr); + + if (!W_ERROR_IS_OK(result)) { + printf ("Unable to retrieve printer information!\n"); + goto done; + } + + /* Set the printer driver */ + + init_unistr(&ctr.printers_2->drivername, argv[2]); + + result = rpccli_spoolss_setprinter(cli, mem_ctx, &pol, level, &ctr, 0); + + if (!W_ERROR_IS_OK(result)) { + printf("SetPrinter call failed!\n"); + goto done;; + } + + printf("Successfully set %s to driver %s.\n", argv[1], argv[2]); + +done: + /* Cleanup */ + + if (opened_hnd) + rpccli_spoolss_close_printer(cli, mem_ctx, &pol); + + return result; +} + + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_deletedriverex(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR result, ret = WERR_UNKNOWN_PRINTER_DRIVER; + + int i; + int vers = -1; + + const char *arch = NULL; + + /* parse the command arguments */ + if (argc < 2 || argc > 4) { + printf ("Usage: %s <driver> [arch] [version]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 3) + arch = argv[2]; + if (argc == 4) + vers = atoi (argv[3]); + + + /* delete the driver for all architectures */ + for (i=0; archi_table[i].long_archi; i++) { + + if (arch && !strequal( archi_table[i].long_archi, arch)) + continue; + + if (vers >= 0 && archi_table[i].version != vers) + continue; + + /* make the call to remove the driver */ + result = rpccli_spoolss_deleteprinterdriverex( + cli, mem_ctx, archi_table[i].long_archi, argv[1], archi_table[i].version); + + if ( !W_ERROR_IS_OK(result) ) + { + if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) { + printf ("Failed to remove driver %s for arch [%s] (version: %d): %s\n", + argv[1], archi_table[i].long_archi, archi_table[i].version, dos_errstr(result)); + } + } + else + { + printf ("Driver %s and files removed for arch [%s] (version: %d).\n", argv[1], + archi_table[i].long_archi, archi_table[i].version); + ret = WERR_OK; + } + } + + return ret; +} + + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_deletedriver(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR result = WERR_OK; + fstring servername; + int i; + + /* parse the command arguments */ + if (argc != 2) { + printf ("Usage: %s <driver>\n", argv[0]); + return WERR_OK; + } + + slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost); + strupper_m(servername); + + /* delete the driver for all architectures */ + for (i=0; archi_table[i].long_archi; i++) { + /* make the call to remove the driver */ + result = rpccli_spoolss_deleteprinterdriver( + cli, mem_ctx, archi_table[i].long_archi, argv[1]); + + if ( !W_ERROR_IS_OK(result) ) { + if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) { + printf ("Failed to remove driver %s for arch [%s] - error 0x%x!\n", + argv[1], archi_table[i].long_archi, + W_ERROR_V(result)); + } + } else { + printf ("Driver %s removed for arch [%s].\n", argv[1], + archi_table[i].long_archi); + } + } + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_getprintprocdir(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR result; + char *servername = NULL, *environment = NULL; + fstring procdir; + + /* parse the command arguments */ + if (argc > 2) { + printf ("Usage: %s [environment]\n", argv[0]); + return WERR_OK; + } + + if (asprintf(&servername, "\\\\%s", cli->desthost) < 0) + return WERR_NOMEM; + strupper_m(servername); + + if (asprintf(&environment, "%s", (argc == 2) ? argv[1] : + PRINTER_DRIVER_ARCHITECTURE) < 0) { + SAFE_FREE(servername); + return WERR_NOMEM; + } + + result = rpccli_spoolss_getprintprocessordirectory( + cli, mem_ctx, servername, environment, procdir); + + if (W_ERROR_IS_OK(result)) + printf("%s\n", procdir); + + SAFE_FREE(servername); + SAFE_FREE(environment); + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_addform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND handle; + WERROR werror; + char *servername = NULL, *printername = NULL; + FORM form; + bool got_handle = False; + + /* Parse the command arguments */ + + if (argc != 3) { + printf ("Usage: %s <printer> <formname>\n", argv[0]); + return WERR_OK; + } + + /* Get a printer handle */ + + asprintf(&servername, "\\\\%s", cli->desthost); + strupper_m(servername); + asprintf(&printername, "%s\\%s", servername, argv[1]); + + werror = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", + PRINTER_ALL_ACCESS, + servername, cli->auth->user_name, + &handle); + + if (!W_ERROR_IS_OK(werror)) + goto done; + + got_handle = True; + + /* Dummy up some values for the form data */ + + form.flags = FORM_USER; + form.size_x = form.size_y = 100; + form.left = 0; + form.top = 10; + form.right = 20; + form.bottom = 30; + + init_unistr2(&form.name, argv[2], UNI_STR_TERMINATE); + + /* Add the form */ + + + werror = rpccli_spoolss_addform(cli, mem_ctx, &handle, 1, &form); + + done: + if (got_handle) + rpccli_spoolss_close_printer(cli, mem_ctx, &handle); + + SAFE_FREE(servername); + SAFE_FREE(printername); + + return werror; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_setform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND handle; + WERROR werror; + char *servername = NULL, *printername = NULL; + FORM form; + bool got_handle = False; + + /* Parse the command arguments */ + + if (argc != 3) { + printf ("Usage: %s <printer> <formname>\n", argv[0]); + return WERR_OK; + } + + /* Get a printer handle */ + + asprintf(&servername, "\\\\%s", cli->desthost); + strupper_m(servername); + asprintf(&printername, "%s\\%s", servername, argv[1]); + + werror = rpccli_spoolss_open_printer_ex( + cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, + servername, cli->auth->user_name, &handle); + + if (!W_ERROR_IS_OK(werror)) + goto done; + + got_handle = True; + + /* Dummy up some values for the form data */ + + form.flags = FORM_PRINTER; + form.size_x = form.size_y = 100; + form.left = 0; + form.top = 1000; + form.right = 2000; + form.bottom = 3000; + + init_unistr2(&form.name, argv[2], UNI_STR_TERMINATE); + + /* Set the form */ + + werror = rpccli_spoolss_setform(cli, mem_ctx, &handle, 1, argv[2], &form); + + done: + if (got_handle) + rpccli_spoolss_close_printer(cli, mem_ctx, &handle); + + SAFE_FREE(servername); + SAFE_FREE(printername); + + return werror; +} + +/**************************************************************************** +****************************************************************************/ + +static const char *get_form_flag(int form_flag) +{ + switch (form_flag) { + case FORM_USER: + return "FORM_USER"; + case FORM_BUILTIN: + return "FORM_BUILTIN"; + case FORM_PRINTER: + return "FORM_PRINTER"; + default: + return "unknown"; + } +} + +/**************************************************************************** +****************************************************************************/ + +static void display_form(FORM_1 *form) +{ + fstring form_name = ""; + + if (form->name.buffer) + rpcstr_pull(form_name, form->name.buffer, + sizeof(form_name), -1, STR_TERMINATE); + + printf("%s\n" \ + "\tflag: %s (%d)\n" \ + "\twidth: %d, length: %d\n" \ + "\tleft: %d, right: %d, top: %d, bottom: %d\n\n", + form_name, get_form_flag(form->flag), form->flag, + form->width, form->length, + form->left, form->right, + form->top, form->bottom); +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_getform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + POLICY_HND handle; + WERROR werror; + char *servername = NULL, *printername = NULL; + FORM_1 form; + bool got_handle = False; + + /* Parse the command arguments */ + + if (argc != 3) { + printf ("Usage: %s <printer> <formname>\n", argv[0]); + return WERR_OK; + } + + /* Get a printer handle */ + + asprintf(&servername, "\\\\%s", cli->desthost); + strupper_m(servername); + asprintf(&printername, "%s\\%s", servername, argv[1]); + + werror = rpccli_spoolss_open_printer_ex( + cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, + servername, cli->auth->user_name, &handle); + + if (!W_ERROR_IS_OK(werror)) + goto done; + + got_handle = True; + + /* Get the form */ + + werror = rpccli_spoolss_getform(cli, mem_ctx, &handle, argv[2], 1, &form); + + if (!W_ERROR_IS_OK(werror)) + goto done; + + display_form(&form); + + done: + if (got_handle) + rpccli_spoolss_close_printer(cli, mem_ctx, &handle); + + SAFE_FREE(servername); + SAFE_FREE(printername); + + return werror; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_deleteform(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND handle; + WERROR werror; + char *servername = NULL, *printername = NULL; + bool got_handle = False; + + /* Parse the command arguments */ + + if (argc != 3) { + printf ("Usage: %s <printer> <formname>\n", argv[0]); + return WERR_OK; + } + + /* Get a printer handle */ + + asprintf(&servername, "\\\\%s", cli->desthost); + strupper_m(servername); + asprintf(&printername, "%s\\%s", servername, argv[1]); + + werror = rpccli_spoolss_open_printer_ex( + cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, + servername, cli->auth->user_name, &handle); + + if (!W_ERROR_IS_OK(werror)) + goto done; + + got_handle = True; + + /* Delete the form */ + + werror = rpccli_spoolss_deleteform(cli, mem_ctx, &handle, argv[2]); + + done: + if (got_handle) + rpccli_spoolss_close_printer(cli, mem_ctx, &handle); + + SAFE_FREE(servername); + SAFE_FREE(printername); + + return werror; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_enum_forms(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + POLICY_HND handle; + WERROR werror; + char *servername = NULL, *printername = NULL; + bool got_handle = False; + uint32 num_forms, level = 1, i; + FORM_1 *forms; + + /* Parse the command arguments */ + + if (argc != 2) { + printf ("Usage: %s <printer>\n", argv[0]); + return WERR_OK; + } + + /* Get a printer handle */ + + asprintf(&servername, "\\\\%s", cli->desthost); + strupper_m(servername); + asprintf(&printername, "%s\\%s", servername, argv[1]); + + werror = rpccli_spoolss_open_printer_ex( + cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, + servername, cli->auth->user_name, &handle); + + if (!W_ERROR_IS_OK(werror)) + goto done; + + got_handle = True; + + /* Enumerate forms */ + + werror = rpccli_spoolss_enumforms(cli, mem_ctx, &handle, level, &num_forms, &forms); + + if (!W_ERROR_IS_OK(werror)) + goto done; + + /* Display output */ + + for (i = 0; i < num_forms; i++) { + + display_form(&forms[i]); + + } + + done: + if (got_handle) + rpccli_spoolss_close_printer(cli, mem_ctx, &handle); + + SAFE_FREE(servername); + SAFE_FREE(printername); + + return werror; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_setprinterdata(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR result; + fstring servername, printername, user; + POLICY_HND pol; + bool opened_hnd = False; + PRINTER_INFO_CTR ctr; + PRINTER_INFO_0 info; + REGISTRY_VALUE value; + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + + /* parse the command arguments */ + if (argc < 5) { + printf ("Usage: %s <printer> <string|binary|dword|multistring>" + " <value> <data>\n", + argv[0]); + result = WERR_INVALID_PARAM; + goto done; + } + + slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost); + strupper_m(servername); + slprintf(printername, sizeof(servername)-1, "%s\\%s", servername, argv[1]); + fstrcpy(user, cli->auth->user_name); + + value.type = REG_NONE; + + if (strequal(argv[2], "string")) { + value.type = REG_SZ; + } + + if (strequal(argv[2], "binary")) { + value.type = REG_BINARY; + } + + if (strequal(argv[2], "dword")) { + value.type = REG_DWORD; + } + + if (strequal(argv[2], "multistring")) { + value.type = REG_MULTI_SZ; + } + + if (value.type == REG_NONE) { + printf("Unknown data type: %s\n", argv[2]); + result = WERR_INVALID_PARAM; + goto done; + } + + /* get a printer handle */ + result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", + MAXIMUM_ALLOWED_ACCESS, servername, + user, &pol); + if (!W_ERROR_IS_OK(result)) + goto done; + + opened_hnd = True; + + ctr.printers_0 = &info; + + result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, 0, &ctr); + + if (!W_ERROR_IS_OK(result)) + goto done; + + printf("%s\n", current_timestring(tmp_ctx, True)); + printf("\tchange_id (before set)\t:[0x%x]\n", info.change_id); + + /* Set the printer data */ + + fstrcpy(value.valuename, argv[3]); + + switch (value.type) { + case REG_SZ: { + UNISTR2 data; + init_unistr2(&data, argv[4], UNI_STR_TERMINATE); + value.size = data.uni_str_len * 2; + if (value.size) { + value.data_p = (uint8 *)TALLOC_MEMDUP(mem_ctx, data.buffer, + value.size); + } else { + value.data_p = NULL; + } + break; + } + case REG_DWORD: { + uint32 data = strtoul(argv[4], NULL, 10); + value.size = sizeof(data); + if (sizeof(data)) { + value.data_p = (uint8 *)TALLOC_MEMDUP(mem_ctx, &data, + sizeof(data)); + } else { + value.data_p = NULL; + } + break; + } + case REG_BINARY: { + DATA_BLOB data = strhex_to_data_blob(mem_ctx, argv[4]); + value.data_p = data.data; + value.size = data.length; + break; + } + case REG_MULTI_SZ: { + int i; + size_t len = 0; + char *p; + + for (i=4; i<argc; i++) { + if (strcmp(argv[i], "NULL") == 0) { + argv[i] = ""; + } + len += strlen(argv[i])+1; + } + + value.size = len*2; + value.data_p = TALLOC_ARRAY(mem_ctx, unsigned char, value.size); + if (value.data_p == NULL) { + result = WERR_NOMEM; + goto done; + } + + p = (char *)value.data_p; + len = value.size; + for (i=4; i<argc; i++) { + size_t l = (strlen(argv[i])+1)*2; + rpcstr_push(p, argv[i], len, STR_TERMINATE); + p += l; + len -= l; + } + SMB_ASSERT(len == 0); + break; + } + default: + printf("Unknown data type: %s\n", argv[2]); + result = WERR_INVALID_PARAM; + goto done; + } + + result = rpccli_spoolss_setprinterdata(cli, mem_ctx, &pol, &value); + + if (!W_ERROR_IS_OK(result)) { + printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]); + goto done; + } + printf("\tSetPrinterData succeeded [%s: %s]\n", argv[3], argv[4]); + + result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, 0, &ctr); + + if (!W_ERROR_IS_OK(result)) + goto done; + + printf("%s\n", current_timestring(tmp_ctx, True)); + printf("\tchange_id (after set)\t:[0x%x]\n", info.change_id); + +done: + /* cleanup */ + TALLOC_FREE(tmp_ctx); + if (opened_hnd) + rpccli_spoolss_close_printer(cli, mem_ctx, &pol); + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static void display_job_info_1(JOB_INFO_1 *job) +{ + fstring username = "", document = "", text_status = ""; + + rpcstr_pull(username, job->username.buffer, + sizeof(username), -1, STR_TERMINATE); + + rpcstr_pull(document, job->document.buffer, + sizeof(document), -1, STR_TERMINATE); + + rpcstr_pull(text_status, job->text_status.buffer, + sizeof(text_status), -1, STR_TERMINATE); + + printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", job->position, job->jobid, + username, document, text_status, job->pagesprinted, + job->totalpages); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_job_info_2(JOB_INFO_2 *job) +{ + fstring username = "", document = "", text_status = ""; + + rpcstr_pull(username, job->username.buffer, + sizeof(username), -1, STR_TERMINATE); + + rpcstr_pull(document, job->document.buffer, + sizeof(document), -1, STR_TERMINATE); + + rpcstr_pull(text_status, job->text_status.buffer, + sizeof(text_status), -1, STR_TERMINATE); + + printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n", job->position, job->jobid, + username, document, text_status, job->pagesprinted, + job->totalpages, job->size); +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_enum_jobs(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + WERROR result; + uint32 level = 1, num_jobs, i; + bool got_hnd = False; + char *printername = NULL; + fstring servername, user; + POLICY_HND hnd; + JOB_INFO_CTR ctr; + + if (argc < 2 || argc > 3) { + printf("Usage: %s printername [level]\n", argv[0]); + return WERR_OK; + } + + if (argc == 3) + level = atoi(argv[2]); + + /* Open printer handle */ + + slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost); + strupper_m(servername); + fstrcpy(user, cli->auth->user_name); + printername = talloc_asprintf(mem_ctx, "\\\\%s\\", cli->desthost); + if (!printername) { + return WERR_NOMEM; + } + strupper_m(printername); + printername = talloc_asprintf_append(printername, "%s", argv[1]); + if (!printername) { + return WERR_NOMEM; + } + + result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, + "", MAXIMUM_ALLOWED_ACCESS, + servername, user, &hnd); + + if (!W_ERROR_IS_OK(result)) + goto done; + + got_hnd = True; + + /* Enumerate ports */ + + result = rpccli_spoolss_enumjobs(cli, mem_ctx, &hnd, level, 0, 1000, + &num_jobs, &ctr); + + if (!W_ERROR_IS_OK(result)) + goto done; + + for (i = 0; i < num_jobs; i++) { + switch(level) { + case 1: + display_job_info_1(&ctr.job.job_info_1[i]); + break; + case 2: + display_job_info_2(&ctr.job.job_info_2[i]); + break; + default: + d_printf("unknown info level %d\n", level); + break; + } + } + +done: + if (got_hnd) + rpccli_spoolss_close_printer(cli, mem_ctx, &hnd); + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_enum_data( struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + WERROR result; + uint32 i=0, val_needed, data_needed; + bool got_hnd = False; + char *printername = NULL; + fstring servername, user; + POLICY_HND hnd; + + if (argc != 2) { + printf("Usage: %s printername\n", argv[0]); + return WERR_OK; + } + + /* Open printer handle */ + + slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost); + strupper_m(servername); + fstrcpy(user, cli->auth->user_name); + printername = talloc_asprintf(mem_ctx, "\\\\%s\\", cli->desthost); + if (!printername) { + return WERR_NOMEM; + } + strupper_m(printername); + printername = talloc_asprintf_append(printername, "%s", argv[1]); + if (!printername) { + return WERR_NOMEM; + } + + result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, + "", MAXIMUM_ALLOWED_ACCESS, + servername, user, &hnd); + + if (!W_ERROR_IS_OK(result)) + goto done; + + got_hnd = True; + + /* Enumerate data */ + + result = rpccli_spoolss_enumprinterdata(cli, mem_ctx, &hnd, i, 0, 0, + &val_needed, &data_needed, + NULL); + while (W_ERROR_IS_OK(result)) { + REGISTRY_VALUE value; + result = rpccli_spoolss_enumprinterdata( + cli, mem_ctx, &hnd, i++, val_needed, + data_needed, 0, 0, &value); + if (W_ERROR_IS_OK(result)) + display_reg_value(value); + } + if (W_ERROR_V(result) == ERRnomoreitems) + result = W_ERROR(ERRsuccess); + +done: + if (got_hnd) + rpccli_spoolss_close_printer(cli, mem_ctx, &hnd); + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_enum_data_ex( struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + WERROR result; + uint32 i; + bool got_hnd = False; + char *printername = NULL; + fstring servername, user; + const char *keyname = NULL; + POLICY_HND hnd; + REGVAL_CTR *ctr = NULL; + + if (argc != 3) { + printf("Usage: %s printername <keyname>\n", argv[0]); + return WERR_OK; + } + + keyname = argv[2]; + + /* Open printer handle */ + + slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost); + strupper_m(servername); + fstrcpy(user, cli->auth->user_name); + + printername = talloc_asprintf(mem_ctx, "\\\\%s\\", cli->desthost); + if (!printername) { + return WERR_NOMEM; + } + strupper_m(printername); + printername = talloc_asprintf_append(printername, "%s", argv[1]); + if (!printername) { + return WERR_NOMEM; + } + + result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, + "", MAXIMUM_ALLOWED_ACCESS, + servername, user, &hnd); + + if (!W_ERROR_IS_OK(result)) + goto done; + + got_hnd = True; + + /* Enumerate subkeys */ + + if ( !(ctr = TALLOC_ZERO_P( mem_ctx, REGVAL_CTR )) ) + return WERR_NOMEM; + + result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx, &hnd, keyname, ctr); + + if (!W_ERROR_IS_OK(result)) + goto done; + + for (i=0; i < ctr->num_values; i++) { + display_reg_value(*(ctr->values[i])); + } + + TALLOC_FREE( ctr ); + +done: + if (got_hnd) + rpccli_spoolss_close_printer(cli, mem_ctx, &hnd); + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_enum_printerkey( struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + WERROR result; + bool got_hnd = False; + char *printername = NULL; + fstring servername, user; + const char *keyname = NULL; + POLICY_HND hnd; + uint16 *keylist = NULL, *curkey; + + if (argc < 2 || argc > 3) { + printf("Usage: %s printername [keyname]\n", argv[0]); + return WERR_OK; + } + + if (argc == 3) + keyname = argv[2]; + else + keyname = ""; + + /* Open printer handle */ + + slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->desthost); + strupper_m(servername); + fstrcpy(user, cli->auth->user_name); + + printername = talloc_asprintf(mem_ctx, "\\\\%s\\", cli->desthost); + if (!printername) { + return WERR_NOMEM; + } + strupper_m(printername); + printername = talloc_asprintf_append(printername, "%s", argv[1]); + if (!printername) { + return WERR_NOMEM; + } + + + result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, + "", MAXIMUM_ALLOWED_ACCESS, + servername, user, &hnd); + + if (!W_ERROR_IS_OK(result)) + goto done; + + got_hnd = True; + + /* Enumerate subkeys */ + + result = rpccli_spoolss_enumprinterkey(cli, mem_ctx, &hnd, keyname, &keylist, NULL); + + if (!W_ERROR_IS_OK(result)) + goto done; + + curkey = keylist; + while (*curkey != 0) { + char *subkey = NULL; + rpcstr_pull_talloc(mem_ctx, &subkey, curkey, -1, + STR_TERMINATE); + if (!subkey) { + break; + } + printf("%s\n", subkey); + curkey += strlen(subkey) + 1; + } + +done: + + SAFE_FREE(keylist); + + if (got_hnd) + rpccli_spoolss_close_printer(cli, mem_ctx, &hnd); + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_rffpcnex(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + fstring servername, printername; + POLICY_HND hnd; + bool got_hnd = False; + WERROR result; + SPOOL_NOTIFY_OPTION option; + + if (argc != 2) { + printf("Usage: %s printername\n", argv[0]); + result = WERR_OK; + goto done; + } + + /* Open printer */ + + slprintf(servername, sizeof(servername) - 1, "\\\\%s", cli->desthost); + strupper_m(servername); + + slprintf(printername, sizeof(printername) - 1, "\\\\%s\\%s", + cli->desthost, argv[1]); + strupper_m(printername); + + result = rpccli_spoolss_open_printer_ex( + cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, + servername, cli->auth->user_name, &hnd); + + if (!W_ERROR_IS_OK(result)) { + printf("Error opening %s\n", argv[1]); + goto done; + } + + got_hnd = True; + + /* Create spool options */ + + ZERO_STRUCT(option); + + option.version = 2; + option.option_type_ptr = 1; + option.count = option.ctr.count = 2; + + option.ctr.type = TALLOC_ARRAY(mem_ctx, SPOOL_NOTIFY_OPTION_TYPE, 2); + if (option.ctr.type == NULL) { + result = WERR_NOMEM; + goto done; + } + + ZERO_STRUCT(option.ctr.type[0]); + option.ctr.type[0].type = PRINTER_NOTIFY_TYPE; + option.ctr.type[0].count = option.ctr.type[0].count2 = 1; + option.ctr.type[0].fields_ptr = 1; + option.ctr.type[0].fields[0] = PRINTER_NOTIFY_SERVER_NAME; + + ZERO_STRUCT(option.ctr.type[1]); + option.ctr.type[1].type = JOB_NOTIFY_TYPE; + option.ctr.type[1].count = option.ctr.type[1].count2 = 1; + option.ctr.type[1].fields_ptr = 1; + option.ctr.type[1].fields[0] = JOB_NOTIFY_PRINTER_NAME; + + /* Send rffpcnex */ + + slprintf(servername, sizeof(servername) - 1, "\\\\%s", myhostname()); + strupper_m(servername); + + result = rpccli_spoolss_rffpcnex( + cli, mem_ctx, &hnd, 0, 0, servername, 123, &option); + + if (!W_ERROR_IS_OK(result)) { + printf("Error rffpcnex %s\n", argv[1]); + goto done; + } + +done: + if (got_hnd) + rpccli_spoolss_close_printer(cli, mem_ctx, &hnd); + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static bool compare_printer( struct rpc_pipe_client *cli1, POLICY_HND *hnd1, + struct rpc_pipe_client *cli2, POLICY_HND *hnd2 ) +{ + PRINTER_INFO_CTR ctr1, ctr2; + WERROR werror; + TALLOC_CTX *mem_ctx = talloc_init("compare_printer"); + + printf("Retrieving printer propertiesfor %s...", cli1->desthost); + werror = rpccli_spoolss_getprinter( cli1, mem_ctx, hnd1, 2, &ctr1); + if ( !W_ERROR_IS_OK(werror) ) { + printf("failed (%s)\n", dos_errstr(werror)); + talloc_destroy(mem_ctx); + return False; + } + printf("ok\n"); + + printf("Retrieving printer properties for %s...", cli2->desthost); + werror = rpccli_spoolss_getprinter( cli2, mem_ctx, hnd2, 2, &ctr2); + if ( !W_ERROR_IS_OK(werror) ) { + printf("failed (%s)\n", dos_errstr(werror)); + talloc_destroy(mem_ctx); + return False; + } + printf("ok\n"); + + talloc_destroy(mem_ctx); + + return True; +} + +/**************************************************************************** +****************************************************************************/ + +static bool compare_printer_secdesc( struct rpc_pipe_client *cli1, POLICY_HND *hnd1, + struct rpc_pipe_client *cli2, POLICY_HND *hnd2 ) +{ + PRINTER_INFO_CTR ctr1, ctr2; + WERROR werror; + TALLOC_CTX *mem_ctx = talloc_init("compare_printer_secdesc"); + SEC_DESC *sd1, *sd2; + bool result = True; + + + printf("Retrieving printer security for %s...", cli1->desthost); + werror = rpccli_spoolss_getprinter( cli1, mem_ctx, hnd1, 3, &ctr1); + if ( !W_ERROR_IS_OK(werror) ) { + printf("failed (%s)\n", dos_errstr(werror)); + result = False; + goto done; + } + printf("ok\n"); + + printf("Retrieving printer security for %s...", cli2->desthost); + werror = rpccli_spoolss_getprinter( cli2, mem_ctx, hnd2, 3, &ctr2); + if ( !W_ERROR_IS_OK(werror) ) { + printf("failed (%s)\n", dos_errstr(werror)); + result = False; + goto done; + } + printf("ok\n"); + + + printf("++ "); + + if ( (ctr1.printers_3 != ctr2.printers_3) && (!ctr1.printers_3 || !ctr2.printers_3) ) { + printf("NULL PRINTER_INFO_3!\n"); + result = False; + goto done; + } + + sd1 = ctr1.printers_3->secdesc; + sd2 = ctr2.printers_3->secdesc; + + if ( (sd1 != sd2) && ( !sd1 || !sd2 ) ) { + printf("NULL secdesc!\n"); + result = False; + goto done; + } + + if (!sec_desc_equal( sd1, sd2 ) ) { + printf("Security Descriptors *not* equal!\n"); + result = False; + goto done; + } + + printf("Security descriptors match\n"); + +done: + talloc_destroy(mem_ctx); + return result; +} + + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_printercmp(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + fstring printername, servername1, servername2; + char *printername_path = NULL; + struct cli_state *cli_server1 = rpc_pipe_np_smb_conn(cli); + struct cli_state *cli_server2 = NULL; + struct rpc_pipe_client *cli2 = NULL; + POLICY_HND hPrinter1, hPrinter2; + NTSTATUS nt_status; + WERROR werror; + + if ( argc != 3 ) { + printf("Usage: %s <printer> <server>\n", argv[0]); + return WERR_OK; + } + + fstrcpy( printername, argv[1] ); + + fstrcpy( servername1, cli->desthost ); + fstrcpy( servername2, argv[2] ); + strupper_m( servername1 ); + strupper_m( servername2 ); + + /* first get the connection to the remote server */ + + nt_status = cli_full_connection(&cli_server2, global_myname(), servername2, + NULL, 0, + "IPC$", "IPC", + get_cmdline_auth_info_username(), + lp_workgroup(), + get_cmdline_auth_info_password(), + get_cmdline_auth_info_use_kerberos() ? CLI_FULL_CONNECTION_USE_KERBEROS : 0, + get_cmdline_auth_info_signing_state(), NULL); + + if ( !NT_STATUS_IS_OK(nt_status) ) + return WERR_GENERAL_FAILURE; + + nt_status = cli_rpc_pipe_open_noauth(cli_server2, &syntax_spoolss, + &cli2); + if (!NT_STATUS_IS_OK(nt_status)) { + printf("failed to open spoolss pipe on server %s (%s)\n", + servername2, nt_errstr(nt_status)); + return WERR_GENERAL_FAILURE; + } + + /* now open up both printers */ + + printername_path = talloc_asprintf(mem_ctx, + "\\\\%s\\%s", + servername1, + printername); + if (!printername_path) { + return WERR_NOMEM; + } + printf("Opening %s...", printername_path); + werror = rpccli_spoolss_open_printer_ex( cli, mem_ctx, printername_path, + "", PRINTER_ALL_ACCESS, servername1, cli_server1->user_name, &hPrinter1); + if ( !W_ERROR_IS_OK(werror) ) { + printf("failed (%s)\n", dos_errstr(werror)); + goto done; + } + printf("ok\n"); + + printername_path = talloc_asprintf(mem_ctx, + "\\\\%s\\%s", + servername2, + printername); + if (!printername_path) { + return WERR_NOMEM; + } + printf("Opening %s...", printername_path); + werror = rpccli_spoolss_open_printer_ex( cli2, mem_ctx, printername_path, + "", PRINTER_ALL_ACCESS, servername2, cli_server2->user_name, &hPrinter2 ); + if ( !W_ERROR_IS_OK(werror) ) { + printf("failed (%s)\n", dos_errstr(werror)); + goto done; + } + printf("ok\n"); + + compare_printer( cli, &hPrinter1, cli2, &hPrinter2 ); + compare_printer_secdesc( cli, &hPrinter1, cli2, &hPrinter2 ); +#if 0 + compare_printerdata( cli_server1, &hPrinter1, cli_server2, &hPrinter2 ); +#endif + + +done: + /* cleanup */ + + printf("Closing printers..."); + rpccli_spoolss_close_printer( cli, mem_ctx, &hPrinter1 ); + rpccli_spoolss_close_printer( cli2, mem_ctx, &hPrinter2 ); + printf("ok\n"); + + /* close the second remote connection */ + + cli_shutdown( cli_server2 ); + return WERR_OK; +} + +/* List of commands exported by this module */ +struct cmd_set spoolss_commands[] = { + + { "SPOOLSS" }, + + { "adddriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterdriver, &syntax_spoolss, NULL, "Add a print driver", "" }, + { "addprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterex, &syntax_spoolss, NULL, "Add a printer", "" }, + { "deldriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriver, &syntax_spoolss, NULL, "Delete a printer driver", "" }, + { "deldriverex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriverex, &syntax_spoolss, NULL, "Delete a printer driver with files", "" }, + { "enumdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data, &syntax_spoolss, NULL, "Enumerate printer data", "" }, + { "enumdataex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data_ex, &syntax_spoolss, NULL, "Enumerate printer data for a key", "" }, + { "enumkey", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printerkey, &syntax_spoolss, NULL, "Enumerate printer keys", "" }, + { "enumjobs", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_jobs, &syntax_spoolss, NULL, "Enumerate print jobs", "" }, + { "enumports", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_ports, &syntax_spoolss, NULL, "Enumerate printer ports", "" }, + { "enumdrivers", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_drivers, &syntax_spoolss, NULL, "Enumerate installed printer drivers", "" }, + { "enumprinters", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printers, &syntax_spoolss, NULL, "Enumerate printers", "" }, + { "getdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdata, &syntax_spoolss, NULL, "Get print driver data", "" }, + { "getdataex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdataex, &syntax_spoolss, NULL, "Get printer driver data with keyname", ""}, + { "getdriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriver, &syntax_spoolss, NULL, "Get print driver information", "" }, + { "getdriverdir", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriverdir, &syntax_spoolss, NULL, "Get print driver upload directory", "" }, + { "getprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinter, &syntax_spoolss, NULL, "Get printer info", "" }, + { "openprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer_ex, &syntax_spoolss, NULL, "Open printer handle", "" }, + { "setdriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setdriver, &syntax_spoolss, NULL, "Set printer driver", "" }, + { "getprintprocdir", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprintprocdir, &syntax_spoolss, NULL, "Get print processor directory", "" }, + { "addform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addform, &syntax_spoolss, NULL, "Add form", "" }, + { "setform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setform, &syntax_spoolss, NULL, "Set form", "" }, + { "getform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getform, &syntax_spoolss, NULL, "Get form", "" }, + { "deleteform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform, &syntax_spoolss, NULL, "Delete form", "" }, + { "enumforms", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms, &syntax_spoolss, NULL, "Enumerate forms", "" }, + { "setprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter, &syntax_spoolss, NULL, "Set printer comment", "" }, + { "setprintername", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername, &syntax_spoolss, NULL, "Set printername", "" }, + { "setprinterdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata, &syntax_spoolss, NULL, "Set REG_SZ printer data", "" }, + { "rffpcnex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex, &syntax_spoolss, NULL, "Rffpcnex test", "" }, + { "printercmp", RPC_RTYPE_WERROR, NULL, cmd_spoolss_printercmp, &syntax_spoolss, NULL, "Printer comparison test", "" }, + + { NULL } +}; diff --git a/source3/rpcclient/cmd_srvsvc.c b/source3/rpcclient/cmd_srvsvc.c new file mode 100644 index 0000000000..10017fa19b --- /dev/null +++ b/source3/rpcclient/cmd_srvsvc.c @@ -0,0 +1,891 @@ +/* + Unix SMB/CIFS implementation. + RPC pipe client + + Copyright (C) Andrew Tridgell 1992-1999 + Copyright (C) Luke Kenneth Casson Leighton 1996 - 1999 + Copyright (C) Tim Potter 2000,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 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 <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "rpcclient.h" + +/* Display server query info */ + +static char *get_server_type_str(uint32 type) +{ + static fstring typestr; + int i; + + if (type == SV_TYPE_ALL) { + fstrcpy(typestr, "All"); + return typestr; + } + + typestr[0] = 0; + + for (i = 0; i < 32; i++) { + if (type & (1 << i)) { + switch (1 << i) { + case SV_TYPE_WORKSTATION: + fstrcat(typestr, "Wk "); + break; + case SV_TYPE_SERVER: + fstrcat(typestr, "Sv "); + break; + case SV_TYPE_SQLSERVER: + fstrcat(typestr, "Sql "); + break; + case SV_TYPE_DOMAIN_CTRL: + fstrcat(typestr, "PDC "); + break; + case SV_TYPE_DOMAIN_BAKCTRL: + fstrcat(typestr, "BDC "); + break; + case SV_TYPE_TIME_SOURCE: + fstrcat(typestr, "Tim "); + break; + case SV_TYPE_AFP: + fstrcat(typestr, "AFP "); + break; + case SV_TYPE_NOVELL: + fstrcat(typestr, "Nov "); + break; + case SV_TYPE_DOMAIN_MEMBER: + fstrcat(typestr, "Dom "); + break; + case SV_TYPE_PRINTQ_SERVER: + fstrcat(typestr, "PrQ "); + break; + case SV_TYPE_DIALIN_SERVER: + fstrcat(typestr, "Din "); + break; + case SV_TYPE_SERVER_UNIX: + fstrcat(typestr, "Unx "); + break; + case SV_TYPE_NT: + fstrcat(typestr, "NT "); + break; + case SV_TYPE_WFW: + fstrcat(typestr, "Wfw "); + break; + case SV_TYPE_SERVER_MFPN: + fstrcat(typestr, "Mfp "); + break; + case SV_TYPE_SERVER_NT: + fstrcat(typestr, "SNT "); + break; + case SV_TYPE_POTENTIAL_BROWSER: + fstrcat(typestr, "PtB "); + break; + case SV_TYPE_BACKUP_BROWSER: + fstrcat(typestr, "BMB "); + break; + case SV_TYPE_MASTER_BROWSER: + fstrcat(typestr, "LMB "); + break; + case SV_TYPE_DOMAIN_MASTER: + fstrcat(typestr, "DMB "); + break; + case SV_TYPE_SERVER_OSF: + fstrcat(typestr, "OSF "); + break; + case SV_TYPE_SERVER_VMS: + fstrcat(typestr, "VMS "); + break; + case SV_TYPE_WIN95_PLUS: + fstrcat(typestr, "W95 "); + break; + case SV_TYPE_ALTERNATE_XPORT: + fstrcat(typestr, "Xpt "); + break; + case SV_TYPE_LOCAL_LIST_ONLY: + fstrcat(typestr, "Dom "); + break; + case SV_TYPE_DOMAIN_ENUM: + fstrcat(typestr, "Loc "); + break; + } + } + } + + i = strlen(typestr) - 1; + + if (typestr[i] == ' ') + typestr[i] = 0; + + return typestr; +} + +static void display_server(const char *sname, uint32 type, const char *comment) +{ + printf("\t%-15.15s%-20s %s\n", sname, get_server_type_str(type), + comment); +} + +static void display_srv_info_101(struct srvsvc_NetSrvInfo101 *r) +{ + display_server(r->server_name, r->server_type, r->comment); + + printf("\tplatform_id :\t%d\n", r->platform_id); + printf("\tos version :\t%d.%d\n", + r->version_major, r->version_minor); + printf("\tserver type :\t0x%x\n", r->server_type); +} + +static void display_srv_info_102(struct srvsvc_NetSrvInfo102 *r) +{ + display_server(r->server_name, r->server_type, r->comment); + + printf("\tplatform_id :\t%d\n", r->platform_id); + printf("\tos version :\t%d.%d\n", + r->version_major, r->version_minor); + printf("\tserver type :\t0x%x\n", r->server_type); + + printf("\tusers :\t%x\n", r->users); + printf("\tdisc, hidden :\t%x, %x\n", r->disc, r->hidden); + printf("\tannounce, delta :\t%d, %d\n", r->announce, + r->anndelta); + printf("\tlicenses :\t%d\n", r->licenses); + printf("\tuser path :\t%s\n", r->userpath); +} + +/* Server query info */ +static WERROR cmd_srvsvc_srv_query_info(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + uint32 info_level = 101; + union srvsvc_NetSrvInfo info; + WERROR result; + NTSTATUS status; + + if (argc > 2) { + printf("Usage: %s [infolevel]\n", argv[0]); + return WERR_OK; + } + + if (argc == 2) + info_level = atoi(argv[1]); + + status = rpccli_srvsvc_NetSrvGetInfo(cli, mem_ctx, + cli->srv_name_slash, + info_level, + &info, + &result); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + /* Display results */ + + switch (info_level) { + case 101: + display_srv_info_101(info.info101); + break; + case 102: + display_srv_info_102(info.info102); + break; + default: + printf("unsupported info level %d\n", info_level); + break; + } + + done: + return result; +} + +static void display_share_info_1(struct srvsvc_NetShareInfo1 *r) +{ + printf("netname: %s\n", r->name); + printf("\tremark:\t%s\n", r->comment); +} + +static void display_share_info_2(struct srvsvc_NetShareInfo2 *r) +{ + printf("netname: %s\n", r->name); + printf("\tremark:\t%s\n", r->comment); + printf("\tpath:\t%s\n", r->path); + printf("\tpassword:\t%s\n", r->password); +} + +static void display_share_info_502(struct srvsvc_NetShareInfo502 *r) +{ + printf("netname: %s\n", r->name); + printf("\tremark:\t%s\n", r->comment); + printf("\tpath:\t%s\n", r->path); + printf("\tpassword:\t%s\n", r->password); + + printf("\ttype:\t0x%x\n", r->type); + printf("\tperms:\t%d\n", r->permissions); + printf("\tmax_uses:\t%d\n", r->max_users); + printf("\tnum_uses:\t%d\n", r->current_users); + + if (r->sd_buf.sd) + display_sec_desc(r->sd_buf.sd); + +} + +static WERROR cmd_srvsvc_net_share_enum_int(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv, + uint32_t opcode) +{ + uint32 info_level = 2; + struct srvsvc_NetShareInfoCtr info_ctr; + struct srvsvc_NetShareCtr0 ctr0; + struct srvsvc_NetShareCtr1 ctr1; + struct srvsvc_NetShareCtr2 ctr2; + struct srvsvc_NetShareCtr501 ctr501; + struct srvsvc_NetShareCtr502 ctr502; + struct srvsvc_NetShareCtr1004 ctr1004; + struct srvsvc_NetShareCtr1005 ctr1005; + struct srvsvc_NetShareCtr1006 ctr1006; + struct srvsvc_NetShareCtr1007 ctr1007; + struct srvsvc_NetShareCtr1501 ctr1501; + WERROR result; + NTSTATUS status; + uint32_t totalentries = 0; + uint32_t resume_handle = 0; + uint32_t *resume_handle_p = NULL; + uint32 preferred_len = 0xffffffff, i; + + if (argc > 3) { + printf("Usage: %s [infolevel] [resume_handle]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + info_level = atoi(argv[1]); + } + + if (argc == 3) { + resume_handle = atoi(argv[2]); + resume_handle_p = &resume_handle; + } + + ZERO_STRUCT(info_ctr); + + info_ctr.level = info_level; + + switch (info_level) { + case 0: + ZERO_STRUCT(ctr0); + info_ctr.ctr.ctr0 = &ctr0; + break; + case 1: + ZERO_STRUCT(ctr1); + info_ctr.ctr.ctr1 = &ctr1; + break; + case 2: + ZERO_STRUCT(ctr2); + info_ctr.ctr.ctr2 = &ctr2; + break; + case 501: + ZERO_STRUCT(ctr501); + info_ctr.ctr.ctr501 = &ctr501; + break; + case 502: + ZERO_STRUCT(ctr502); + info_ctr.ctr.ctr502 = &ctr502; + break; + case 1004: + ZERO_STRUCT(ctr1004); + info_ctr.ctr.ctr1004 = &ctr1004; + break; + case 1005: + ZERO_STRUCT(ctr1005); + info_ctr.ctr.ctr1005 = &ctr1005; + break; + case 1006: + ZERO_STRUCT(ctr1006); + info_ctr.ctr.ctr1006 = &ctr1006; + break; + case 1007: + ZERO_STRUCT(ctr1007); + info_ctr.ctr.ctr1007 = &ctr1007; + break; + case 1501: + ZERO_STRUCT(ctr1501); + info_ctr.ctr.ctr1501 = &ctr1501; + break; + } + + switch (opcode) { + case NDR_SRVSVC_NETSHAREENUM: + status = rpccli_srvsvc_NetShareEnum(cli, mem_ctx, + cli->desthost, + &info_ctr, + preferred_len, + &totalentries, + resume_handle_p, + &result); + break; + case NDR_SRVSVC_NETSHAREENUMALL: + status = rpccli_srvsvc_NetShareEnumAll(cli, mem_ctx, + cli->desthost, + &info_ctr, + preferred_len, + &totalentries, + resume_handle_p, + &result); + break; + default: + return WERR_INVALID_PARAM; + } + + if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) { + goto done; + } + + /* Display results */ + + switch (info_level) { + case 1: + for (i = 0; i < totalentries; i++) + display_share_info_1(&info_ctr.ctr.ctr1->array[i]); + break; + case 2: + for (i = 0; i < totalentries; i++) + display_share_info_2(&info_ctr.ctr.ctr2->array[i]); + break; + case 502: + for (i = 0; i < totalentries; i++) + display_share_info_502(&info_ctr.ctr.ctr502->array[i]); + break; + default: + printf("unsupported info level %d\n", info_level); + break; + } + + done: + return result; +} + +static WERROR cmd_srvsvc_net_share_enum(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + return cmd_srvsvc_net_share_enum_int(cli, mem_ctx, + argc, argv, + NDR_SRVSVC_NETSHAREENUM); +} + +static WERROR cmd_srvsvc_net_share_enum_all(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + return cmd_srvsvc_net_share_enum_int(cli, mem_ctx, + argc, argv, + NDR_SRVSVC_NETSHAREENUMALL); +} + +static WERROR cmd_srvsvc_net_share_get_info(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + uint32 info_level = 502; + union srvsvc_NetShareInfo info; + WERROR result; + NTSTATUS status; + + if (argc < 2 || argc > 3) { + printf("Usage: %s [sharename] [infolevel]\n", argv[0]); + return WERR_OK; + } + + if (argc == 3) + info_level = atoi(argv[2]); + + status = rpccli_srvsvc_NetShareGetInfo(cli, mem_ctx, + cli->desthost, + argv[1], + info_level, + &info, + &result); + + if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) { + goto done; + } + + /* Display results */ + + switch (info_level) { + case 1: + display_share_info_1(info.info1); + break; + case 2: + display_share_info_2(info.info2); + break; + case 502: + display_share_info_502(info.info502); + break; + default: + printf("unsupported info level %d\n", info_level); + break; + } + + done: + return result; +} + +static WERROR cmd_srvsvc_net_share_set_info(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + uint32 info_level = 502; + union srvsvc_NetShareInfo info_get; + WERROR result; + NTSTATUS status; + uint32_t parm_err = 0; + + if (argc > 3) { + printf("Usage: %s [sharename] [comment]\n", argv[0]); + return WERR_OK; + } + + /* retrieve share info */ + status = rpccli_srvsvc_NetShareGetInfo(cli, mem_ctx, + cli->desthost, + argv[1], + info_level, + &info_get, + &result); + + if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) { + goto done; + } + + info_get.info502->comment = argv[2]; + + /* set share info */ + status = rpccli_srvsvc_NetShareSetInfo(cli, mem_ctx, + cli->desthost, + argv[1], + info_level, + &info_get, + &parm_err, + &result); + + if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) { + goto done; + } + + /* re-retrieve share info and display */ + status = rpccli_srvsvc_NetShareGetInfo(cli, mem_ctx, + cli->desthost, + argv[1], + info_level, + &info_get, + &result); + + if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) { + goto done; + } + + display_share_info_502(info_get.info502); + + done: + return result; +} + +static WERROR cmd_srvsvc_net_remote_tod(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct srvsvc_NetRemoteTODInfo *tod = NULL; + WERROR result; + NTSTATUS status; + + if (argc > 1) { + printf("Usage: %s\n", argv[0]); + return WERR_OK; + } + + status = rpccli_srvsvc_NetRemoteTOD(cli, mem_ctx, + cli->srv_name_slash, + &tod, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + + if (!W_ERROR_IS_OK(result)) + goto done; + + done: + return result; +} + +static WERROR cmd_srvsvc_net_file_enum(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + uint32 info_level = 3; + struct srvsvc_NetFileInfoCtr info_ctr; + struct srvsvc_NetFileCtr3 ctr3; + WERROR result; + NTSTATUS status; + uint32 preferred_len = 0xffff; + uint32_t total_entries = 0; + uint32_t resume_handle = 0; + + if (argc > 2) { + printf("Usage: %s [infolevel]\n", argv[0]); + return WERR_OK; + } + + if (argc == 2) + info_level = atoi(argv[1]); + + ZERO_STRUCT(info_ctr); + ZERO_STRUCT(ctr3); + + info_ctr.level = info_level; + info_ctr.ctr.ctr3 = &ctr3; + + status = rpccli_srvsvc_NetFileEnum(cli, mem_ctx, + cli->desthost, + NULL, + NULL, + &info_ctr, + preferred_len, + &total_entries, + &resume_handle, + &result); + + if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) + goto done; + + done: + return result; +} + +static WERROR cmd_srvsvc_net_name_validate(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR result; + NTSTATUS status; + uint32_t name_type = 9; + uint32_t flags = 0; + + if (argc < 2 || argc > 3) { + printf("Usage: %s [sharename] [type]\n", argv[0]); + return WERR_OK; + } + + if (argc == 3) { + name_type = atoi(argv[2]); + } + + status = rpccli_srvsvc_NetNameValidate(cli, mem_ctx, + cli->desthost, + argv[1], + name_type, + flags, + &result); + + if (!W_ERROR_IS_OK(result)) + goto done; + + done: + return result; +} + +static WERROR cmd_srvsvc_net_file_get_sec(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR result; + NTSTATUS status; + struct sec_desc_buf *sd_buf = NULL; + + if (argc < 2 || argc > 4) { + printf("Usage: %s [sharename] [file]\n", argv[0]); + return WERR_OK; + } + + status = rpccli_srvsvc_NetGetFileSecurity(cli, mem_ctx, + cli->desthost, + argv[1], + argv[2], + SECINFO_DACL, + &sd_buf, + &result); + + if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) { + goto done; + } + + display_sec_desc(sd_buf->sd); + + done: + return result; +} + +static WERROR cmd_srvsvc_net_sess_del(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR result; + NTSTATUS status; + + if (argc < 2 || argc > 4) { + printf("Usage: %s [client] [user]\n", argv[0]); + return WERR_OK; + } + + status = rpccli_srvsvc_NetSessDel(cli, mem_ctx, + cli->desthost, + argv[1], + argv[2], + &result); + + if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) { + goto done; + } + + done: + return result; +} + +static WERROR cmd_srvsvc_net_sess_enum(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR result; + NTSTATUS status; + struct srvsvc_NetSessInfoCtr info_ctr; + struct srvsvc_NetSessCtr0 ctr0; + struct srvsvc_NetSessCtr1 ctr1; + struct srvsvc_NetSessCtr2 ctr2; + struct srvsvc_NetSessCtr10 ctr10; + struct srvsvc_NetSessCtr502 ctr502; + uint32_t total_entries = 0; + uint32_t resume_handle = 0; + uint32_t *resume_handle_p = NULL; + uint32_t level = 1; + const char *client = NULL; + const char *user = NULL; + + if (argc > 6) { + printf("Usage: %s [client] [user] [level] [resume_handle]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + client = argv[1]; + } + + if (argc >= 3) { + user = argv[2]; + } + + if (argc >= 4) { + level = atoi(argv[3]); + } + + if (argc >= 5) { + resume_handle = atoi(argv[4]); + resume_handle_p = &resume_handle; + } + + ZERO_STRUCT(info_ctr); + + info_ctr.level = level; + + d_printf("trying level: %d\n", level); + + switch (level) { + case 0: + ZERO_STRUCT(ctr0); + info_ctr.ctr.ctr0 = &ctr0; + break; + case 1: + ZERO_STRUCT(ctr1); + info_ctr.ctr.ctr1 = &ctr1; + break; + case 2: + ZERO_STRUCT(ctr2); + info_ctr.ctr.ctr2 = &ctr2; + break; + case 10: + ZERO_STRUCT(ctr10); + info_ctr.ctr.ctr10 = &ctr10; + break; + case 502: + ZERO_STRUCT(ctr502); + info_ctr.ctr.ctr502 = &ctr502; + break; + } + + status = rpccli_srvsvc_NetSessEnum(cli, mem_ctx, + cli->desthost, + client, + user, + &info_ctr, + 0xffffffff, + &total_entries, + resume_handle_p, + &result); + + if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) { + goto done; + } + + done: + return result; +} + +static WERROR cmd_srvsvc_net_disk_enum(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct srvsvc_NetDiskInfo info; + WERROR result; + NTSTATUS status; + uint32_t total_entries = 0; + uint32_t resume_handle = 0; + uint32_t level = 0; + + if (argc > 4) { + printf("Usage: %s [level] [resume_handle]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + level = atoi(argv[1]); + } + + if (argc >= 3) { + resume_handle = atoi(argv[2]); + } + + ZERO_STRUCT(info); + + status = rpccli_srvsvc_NetDiskEnum(cli, mem_ctx, + cli->desthost, + level, + &info, + 0xffffffff, + &total_entries, + &resume_handle, + &result); + + if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) { + goto done; + } + + done: + return result; +} + +static WERROR cmd_srvsvc_net_conn_enum(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct srvsvc_NetConnInfoCtr info_ctr; + struct srvsvc_NetConnCtr0 ctr0; + struct srvsvc_NetConnCtr1 ctr1; + WERROR result; + NTSTATUS status; + uint32_t total_entries = 0; + uint32_t resume_handle = 0; + uint32_t *resume_handle_p = NULL; + uint32_t level = 1; + const char *path = "IPC$"; + + if (argc > 4) { + printf("Usage: %s [level] [path] [resume_handle]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + level = atoi(argv[1]); + } + + if (argc >= 3) { + path = argv[2]; + } + + if (argc >= 4) { + resume_handle = atoi(argv[3]); + resume_handle_p = &resume_handle; + } + + ZERO_STRUCT(info_ctr); + + info_ctr.level = level; + + switch (level) { + case 0: + ZERO_STRUCT(ctr0); + info_ctr.ctr.ctr0 = &ctr0; + break; + case 1: + ZERO_STRUCT(ctr1); + info_ctr.ctr.ctr1 = &ctr1; + break; + default: + return WERR_INVALID_PARAM; + } + + status = rpccli_srvsvc_NetConnEnum(cli, mem_ctx, + cli->desthost, + path, + &info_ctr, + 0xffffffff, + &total_entries, + resume_handle_p, + &result); + + if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) { + goto done; + } + + done: + return result; +} + + +/* List of commands exported by this module */ + +struct cmd_set srvsvc_commands[] = { + + { "SRVSVC" }, + + { "srvinfo", RPC_RTYPE_WERROR, NULL, cmd_srvsvc_srv_query_info, &ndr_table_srvsvc.syntax_id, NULL, "Server query info", "" }, + { "netshareenum",RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_share_enum, &ndr_table_srvsvc.syntax_id, NULL, "Enumerate shares", "" }, + { "netshareenumall",RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_share_enum_all, &ndr_table_srvsvc.syntax_id, NULL, "Enumerate all shares", "" }, + { "netsharegetinfo",RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_share_get_info, &ndr_table_srvsvc.syntax_id, NULL, "Get Share Info", "" }, + { "netsharesetinfo",RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_share_set_info, &ndr_table_srvsvc.syntax_id, NULL, "Set Share Info", "" }, + { "netfileenum", RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_file_enum, &ndr_table_srvsvc.syntax_id, NULL, "Enumerate open files", "" }, + { "netremotetod",RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_remote_tod, &ndr_table_srvsvc.syntax_id, NULL, "Fetch remote time of day", "" }, + { "netnamevalidate", RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_name_validate, &ndr_table_srvsvc.syntax_id, NULL, "Validate sharename", "" }, + { "netfilegetsec", RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_file_get_sec, &ndr_table_srvsvc.syntax_id, NULL, "Get File security", "" }, + { "netsessdel", RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_sess_del, &ndr_table_srvsvc.syntax_id, NULL, "Delete Session", "" }, + { "netsessenum", RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_sess_enum, &ndr_table_srvsvc.syntax_id, NULL, "Enumerate Sessions", "" }, + { "netdiskenum", RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_disk_enum, &ndr_table_srvsvc.syntax_id, NULL, "Enumerate Disks", "" }, + { "netconnenum", RPC_RTYPE_WERROR, NULL, cmd_srvsvc_net_conn_enum, &ndr_table_srvsvc.syntax_id, NULL, "Enumerate Connections", "" }, + + { NULL } +}; diff --git a/source3/rpcclient/cmd_test.c b/source3/rpcclient/cmd_test.c new file mode 100644 index 0000000000..0f1d4221ca --- /dev/null +++ b/source3/rpcclient/cmd_test.c @@ -0,0 +1,75 @@ +/* + Unix SMB/CIFS implementation. + RPC pipe client + + Copyright (C) Volker Lendecke 2005 + + 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 <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "rpcclient.h" + +static NTSTATUS cmd_testme(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct rpc_pipe_client *lsa_pipe = NULL, *samr_pipe = NULL; + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + POLICY_HND pol; + + d_printf("testme\n"); + + status = cli_rpc_pipe_open_noauth(rpc_pipe_np_smb_conn(cli), + &ndr_table_lsarpc.syntax_id, + &lsa_pipe); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = cli_rpc_pipe_open_noauth(rpc_pipe_np_smb_conn(cli), + &ndr_table_samr.syntax_id, + &samr_pipe); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, False, + SEC_RIGHTS_QUERY_VALUE, &pol); + + if (!NT_STATUS_IS_OK(status)) + goto done; + + status = rpccli_lsa_Close(lsa_pipe, mem_ctx, &pol); + + if (!NT_STATUS_IS_OK(status)) + goto done; + + done: + TALLOC_FREE(lsa_pipe); + TALLOC_FREE(samr_pipe); + + return status; +} + +/* List of commands exported by this module */ + +struct cmd_set test_commands[] = { + + { "TESTING" }, + + { "testme", RPC_RTYPE_NTSTATUS, cmd_testme, NULL, + NULL, NULL, "Sample test", "testme" }, + + { NULL } +}; diff --git a/source3/rpcclient/cmd_wkssvc.c b/source3/rpcclient/cmd_wkssvc.c new file mode 100644 index 0000000000..7a34c450ab --- /dev/null +++ b/source3/rpcclient/cmd_wkssvc.c @@ -0,0 +1,170 @@ +/* + Unix SMB/CIFS implementation. + RPC pipe client + + Copyright (C) Günther Deschner 2007 + + 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 <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "rpcclient.h" + +static WERROR cmd_wkssvc_wkstagetinfo(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status; + WERROR werr; + uint32_t level = 100; + union wkssvc_NetWkstaInfo info; + const char *server_name; + + if (argc > 2) { + printf("usage: %s <level>\n", argv[0]); + return WERR_OK; + } + + if (argc > 1) { + level = atoi(argv[1]); + } + + server_name = cli->desthost; + + status = rpccli_wkssvc_NetWkstaGetInfo(cli, mem_ctx, + server_name, + level, + &info, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + return werr; +} + +static WERROR cmd_wkssvc_getjoininformation(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + const char *server_name; + const char *name_buffer; + enum wkssvc_NetJoinStatus name_type; + NTSTATUS status; + WERROR werr; + + server_name = cli->desthost; + name_buffer = ""; + + status = rpccli_wkssvc_NetrGetJoinInformation(cli, mem_ctx, + server_name, + &name_buffer, + &name_type, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (W_ERROR_IS_OK(werr)) { + printf("%s (%d)\n", name_buffer, name_type); + } + + return werr; +} + +static WERROR cmd_wkssvc_messagebuffersend(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + const char *server_name = cli->desthost; + const char *message_name = cli->desthost; + const char *message_sender_name = cli->desthost; + smb_ucs2_t *message_buffer = NULL; + size_t message_size = 0; + const char *message = "my message"; + NTSTATUS status; + WERROR werr; + + if (argc > 1) { + message = argv[1]; + } + + if (!push_ucs2_talloc(mem_ctx, &message_buffer, message, + &message_size)) + { + return WERR_NOMEM; + } + + status = rpccli_wkssvc_NetrMessageBufferSend(cli, mem_ctx, + server_name, + message_name, + message_sender_name, + (uint8_t *)message_buffer, + message_size, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + return werr; +} + +static WERROR cmd_wkssvc_enumeratecomputernames(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + const char *server_name; + enum wkssvc_ComputerNameType name_type = NetAllComputerNames; + NTSTATUS status; + struct wkssvc_ComputerNamesCtr *ctr = NULL; + WERROR werr; + + server_name = cli->desthost; + + if (argc >= 2) { + name_type = atoi(argv[1]); + } + + status = rpccli_wkssvc_NetrEnumerateComputerNames(cli, mem_ctx, + server_name, + name_type, 0, + &ctr, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (W_ERROR_IS_OK(werr)) { + int i=0; + for (i = 0; i < ctr->count; i++) { + printf("name: %d %s\n", i, ctr->computer_name->string); + } + } + + return werr; +} + +struct cmd_set wkssvc_commands[] = { + + { "WKSSVC" }, + { "wkssvc_wkstagetinfo", RPC_RTYPE_WERROR, NULL, cmd_wkssvc_wkstagetinfo, &ndr_table_wkssvc.syntax_id, NULL, "Query WKSSVC Workstation Information", "" }, + { "wkssvc_getjoininformation", RPC_RTYPE_WERROR, NULL, cmd_wkssvc_getjoininformation, &ndr_table_wkssvc.syntax_id, NULL, "Query WKSSVC Join Information", "" }, + { "wkssvc_messagebuffersend", RPC_RTYPE_WERROR, NULL, cmd_wkssvc_messagebuffersend, &ndr_table_wkssvc.syntax_id, NULL, "Send WKSSVC message", "" }, + { "wkssvc_enumeratecomputernames", RPC_RTYPE_WERROR, NULL, cmd_wkssvc_enumeratecomputernames, &ndr_table_wkssvc.syntax_id, NULL, "Enumerate WKSSVC computer names", "" }, + { NULL } +}; diff --git a/source3/rpcclient/rpcclient.c b/source3/rpcclient/rpcclient.c new file mode 100644 index 0000000000..e4cdd9c3f3 --- /dev/null +++ b/source3/rpcclient/rpcclient.c @@ -0,0 +1,959 @@ +/* + Unix SMB/CIFS implementation. + RPC pipe client + + Copyright (C) Tim Potter 2000-2001 + Copyright (C) Martin Pool 2003 + + 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 <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "rpcclient.h" + +DOM_SID domain_sid; + +static enum pipe_auth_type pipe_default_auth_type = PIPE_AUTH_TYPE_NONE; +static enum pipe_auth_level pipe_default_auth_level = PIPE_AUTH_LEVEL_NONE; +static unsigned int timeout = 0; + +/* List to hold groups of commands. + * + * Commands are defined in a list of arrays: arrays are easy to + * statically declare, and lists are easier to dynamically extend. + */ + +static struct cmd_list { + struct cmd_list *prev, *next; + struct cmd_set *cmd_set; +} *cmd_list; + +/**************************************************************************** +handle completion of commands for readline +****************************************************************************/ +static char **completion_fn(const char *text, int start, int end) +{ +#define MAX_COMPLETIONS 100 + char **matches; + int i, count=0; + struct cmd_list *commands = cmd_list; + +#if 0 /* JERRY */ + /* FIXME!!! -- what to do when completing argument? */ + /* for words not at the start of the line fallback + to filename completion */ + if (start) + return NULL; +#endif + + /* make sure we have a list of valid commands */ + if (!commands) { + return NULL; + } + + matches = SMB_MALLOC_ARRAY(char *, MAX_COMPLETIONS); + if (!matches) { + return NULL; + } + + matches[count++] = SMB_STRDUP(text); + if (!matches[0]) { + SAFE_FREE(matches); + return NULL; + } + + while (commands && count < MAX_COMPLETIONS-1) { + if (!commands->cmd_set) { + break; + } + + for (i=0; commands->cmd_set[i].name; i++) { + if ((strncmp(text, commands->cmd_set[i].name, strlen(text)) == 0) && + (( commands->cmd_set[i].returntype == RPC_RTYPE_NTSTATUS && + commands->cmd_set[i].ntfn ) || + ( commands->cmd_set[i].returntype == RPC_RTYPE_WERROR && + commands->cmd_set[i].wfn))) { + matches[count] = SMB_STRDUP(commands->cmd_set[i].name); + if (!matches[count]) { + for (i = 0; i < count; i++) { + SAFE_FREE(matches[count]); + } + SAFE_FREE(matches); + return NULL; + } + count++; + } + } + commands = commands->next; + + } + + if (count == 2) { + SAFE_FREE(matches[0]); + matches[0] = SMB_STRDUP(matches[1]); + } + matches[count] = NULL; + return matches; +} + +static char *next_command (char **cmdstr) +{ + char *command; + char *p; + + if (!cmdstr || !(*cmdstr)) + return NULL; + + p = strchr_m(*cmdstr, ';'); + if (p) + *p = '\0'; + command = SMB_STRDUP(*cmdstr); + if (p) + *cmdstr = p + 1; + else + *cmdstr = NULL; + + return command; +} + +/* Fetch the SID for this computer */ + +static void fetch_machine_sid(struct cli_state *cli) +{ + POLICY_HND pol; + NTSTATUS result = NT_STATUS_OK; + static bool got_domain_sid; + TALLOC_CTX *mem_ctx; + struct rpc_pipe_client *lsapipe = NULL; + union lsa_PolicyInformation *info = NULL; + + if (got_domain_sid) return; + + if (!(mem_ctx=talloc_init("fetch_machine_sid"))) { + DEBUG(0,("fetch_machine_sid: talloc_init returned NULL!\n")); + goto error; + } + + result = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id, + &lsapipe); + if (!NT_STATUS_IS_OK(result)) { + fprintf(stderr, "could not initialise lsa pipe. Error was %s\n", nt_errstr(result) ); + goto error; + } + + result = rpccli_lsa_open_policy(lsapipe, mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &pol); + if (!NT_STATUS_IS_OK(result)) { + goto error; + } + + result = rpccli_lsa_QueryInfoPolicy(lsapipe, mem_ctx, + &pol, + LSA_POLICY_INFO_ACCOUNT_DOMAIN, + &info); + if (!NT_STATUS_IS_OK(result)) { + goto error; + } + + got_domain_sid = True; + sid_copy(&domain_sid, info->account_domain.sid); + + rpccli_lsa_Close(lsapipe, mem_ctx, &pol); + TALLOC_FREE(lsapipe); + talloc_destroy(mem_ctx); + + return; + + error: + + if (lsapipe) { + TALLOC_FREE(lsapipe); + } + + fprintf(stderr, "could not obtain sid for domain %s\n", cli->domain); + + if (!NT_STATUS_IS_OK(result)) { + fprintf(stderr, "error: %s\n", nt_errstr(result)); + } + + exit(1); +} + +/* List the available commands on a given pipe */ + +static NTSTATUS cmd_listcommands(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct cmd_list *tmp; + struct cmd_set *tmp_set; + int i; + + /* Usage */ + + if (argc != 2) { + printf("Usage: %s <pipe>\n", argv[0]); + return NT_STATUS_OK; + } + + /* Help on one command */ + + for (tmp = cmd_list; tmp; tmp = tmp->next) + { + tmp_set = tmp->cmd_set; + + if (!StrCaseCmp(argv[1], tmp_set->name)) + { + printf("Available commands on the %s pipe:\n\n", tmp_set->name); + + i = 0; + tmp_set++; + while(tmp_set->name) { + printf("%30s", tmp_set->name); + tmp_set++; + i++; + if (i%3 == 0) + printf("\n"); + } + + /* drop out of the loop */ + break; + } + } + printf("\n\n"); + + return NT_STATUS_OK; +} + +/* Display help on commands */ + +static NTSTATUS cmd_help(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct cmd_list *tmp; + struct cmd_set *tmp_set; + + /* Usage */ + + if (argc > 2) { + printf("Usage: %s [command]\n", argv[0]); + return NT_STATUS_OK; + } + + /* Help on one command */ + + if (argc == 2) { + for (tmp = cmd_list; tmp; tmp = tmp->next) { + + tmp_set = tmp->cmd_set; + + while(tmp_set->name) { + if (strequal(argv[1], tmp_set->name)) { + if (tmp_set->usage && + tmp_set->usage[0]) + printf("%s\n", tmp_set->usage); + else + printf("No help for %s\n", tmp_set->name); + + return NT_STATUS_OK; + } + + tmp_set++; + } + } + + printf("No such command: %s\n", argv[1]); + return NT_STATUS_OK; + } + + /* List all commands */ + + for (tmp = cmd_list; tmp; tmp = tmp->next) { + + tmp_set = tmp->cmd_set; + + while(tmp_set->name) { + + printf("%15s\t\t%s\n", tmp_set->name, + tmp_set->description ? tmp_set->description: + ""); + + tmp_set++; + } + } + + return NT_STATUS_OK; +} + +/* Change the debug level */ + +static NTSTATUS cmd_debuglevel(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + if (argc > 2) { + printf("Usage: %s [debuglevel]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc == 2) { + DEBUGLEVEL = atoi(argv[1]); + } + + printf("debuglevel is %d\n", DEBUGLEVEL); + + return NT_STATUS_OK; +} + +static NTSTATUS cmd_quit(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + exit(0); + return NT_STATUS_OK; /* NOTREACHED */ +} + +static NTSTATUS cmd_set_ss_level(void) +{ + struct cmd_list *tmp; + + /* Close any existing connections not at this level. */ + + for (tmp = cmd_list; tmp; tmp = tmp->next) { + struct cmd_set *tmp_set; + + for (tmp_set = tmp->cmd_set; tmp_set->name; tmp_set++) { + if (tmp_set->rpc_pipe == NULL) { + continue; + } + + if ((tmp_set->rpc_pipe->auth->auth_type + != pipe_default_auth_type) + || (tmp_set->rpc_pipe->auth->auth_level + != pipe_default_auth_level)) { + TALLOC_FREE(tmp_set->rpc_pipe); + tmp_set->rpc_pipe = NULL; + } + } + } + return NT_STATUS_OK; +} + +static NTSTATUS cmd_sign(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + const char *type = "NTLMSSP"; + + pipe_default_auth_level = PIPE_AUTH_LEVEL_INTEGRITY; + pipe_default_auth_type = PIPE_AUTH_TYPE_NTLMSSP; + + if (argc > 2) { + printf("Usage: %s [NTLMSSP|NTLMSSP_SPNEGO|SCHANNEL]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc == 2) { + type = argv[1]; + if (strequal(type, "NTLMSSP")) { + pipe_default_auth_type = PIPE_AUTH_TYPE_NTLMSSP; + } else if (strequal(type, "NTLMSSP_SPNEGO")) { + pipe_default_auth_type = PIPE_AUTH_TYPE_SPNEGO_NTLMSSP; + } else if (strequal(type, "SCHANNEL")) { + pipe_default_auth_type = PIPE_AUTH_TYPE_SCHANNEL; + } else { + printf("unknown type %s\n", type); + return NT_STATUS_INVALID_LEVEL; + } + } + + d_printf("Setting %s - sign\n", type); + + return cmd_set_ss_level(); +} + +static NTSTATUS cmd_seal(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + const char *type = "NTLMSSP"; + + pipe_default_auth_level = PIPE_AUTH_LEVEL_PRIVACY; + pipe_default_auth_type = PIPE_AUTH_TYPE_NTLMSSP; + + if (argc > 2) { + printf("Usage: %s [NTLMSSP|NTLMSSP_SPNEGO|SCHANNEL]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc == 2) { + type = argv[1]; + if (strequal(type, "NTLMSSP")) { + pipe_default_auth_type = PIPE_AUTH_TYPE_NTLMSSP; + } else if (strequal(type, "NTLMSSP_SPNEGO")) { + pipe_default_auth_type = PIPE_AUTH_TYPE_SPNEGO_NTLMSSP; + } else if (strequal(type, "SCHANNEL")) { + pipe_default_auth_type = PIPE_AUTH_TYPE_SCHANNEL; + } else { + printf("unknown type %s\n", type); + return NT_STATUS_INVALID_LEVEL; + } + } + + d_printf("Setting %s - sign and seal\n", type); + + return cmd_set_ss_level(); +} + +static NTSTATUS cmd_timeout(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct cmd_list *tmp; + + if (argc > 2) { + printf("Usage: %s timeout\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc == 2) { + timeout = atoi(argv[1]); + + for (tmp = cmd_list; tmp; tmp = tmp->next) { + + struct cmd_set *tmp_set; + + for (tmp_set = tmp->cmd_set; tmp_set->name; tmp_set++) { + if (tmp_set->rpc_pipe == NULL) { + continue; + } + + rpccli_set_timeout(tmp_set->rpc_pipe, timeout); + } + } + } + + printf("timeout is %d\n", timeout); + + return NT_STATUS_OK; +} + + +static NTSTATUS cmd_none(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + pipe_default_auth_level = PIPE_AUTH_LEVEL_NONE; + pipe_default_auth_type = PIPE_AUTH_TYPE_NONE; + + return cmd_set_ss_level(); +} + +static NTSTATUS cmd_schannel(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + d_printf("Setting schannel - sign and seal\n"); + pipe_default_auth_level = PIPE_AUTH_LEVEL_PRIVACY; + pipe_default_auth_type = PIPE_AUTH_TYPE_SCHANNEL; + + return cmd_set_ss_level(); +} + +static NTSTATUS cmd_schannel_sign(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + d_printf("Setting schannel - sign only\n"); + pipe_default_auth_level = PIPE_AUTH_LEVEL_INTEGRITY; + pipe_default_auth_type = PIPE_AUTH_TYPE_SCHANNEL; + + return cmd_set_ss_level(); +} + + +/* Built in rpcclient commands */ + +static struct cmd_set rpcclient_commands[] = { + + { "GENERAL OPTIONS" }, + + { "help", RPC_RTYPE_NTSTATUS, cmd_help, NULL, NULL, NULL, "Get help on commands", "[command]" }, + { "?", RPC_RTYPE_NTSTATUS, cmd_help, NULL, NULL, NULL, "Get help on commands", "[command]" }, + { "debuglevel", RPC_RTYPE_NTSTATUS, cmd_debuglevel, NULL, NULL, NULL, "Set debug level", "level" }, + { "debug", RPC_RTYPE_NTSTATUS, cmd_debuglevel, NULL, NULL, NULL, "Set debug level", "level" }, + { "list", RPC_RTYPE_NTSTATUS, cmd_listcommands, NULL, NULL, NULL, "List available commands on <pipe>", "pipe" }, + { "exit", RPC_RTYPE_NTSTATUS, cmd_quit, NULL, NULL, NULL, "Exit program", "" }, + { "quit", RPC_RTYPE_NTSTATUS, cmd_quit, NULL, NULL, NULL, "Exit program", "" }, + { "sign", RPC_RTYPE_NTSTATUS, cmd_sign, NULL, NULL, NULL, "Force RPC pipe connections to be signed", "" }, + { "seal", RPC_RTYPE_NTSTATUS, cmd_seal, NULL, NULL, NULL, "Force RPC pipe connections to be sealed", "" }, + { "schannel", RPC_RTYPE_NTSTATUS, cmd_schannel, NULL, NULL, NULL, "Force RPC pipe connections to be sealed with 'schannel'. Assumes valid machine account to this domain controller.", "" }, + { "schannelsign", RPC_RTYPE_NTSTATUS, cmd_schannel_sign, NULL, NULL, NULL, "Force RPC pipe connections to be signed (not sealed) with 'schannel'. Assumes valid machine account to this domain controller.", "" }, + { "timeout", RPC_RTYPE_NTSTATUS, cmd_timeout, NULL, NULL, NULL, "Set timeout (in milliseonds) for RPC operations", "" }, + { "none", RPC_RTYPE_NTSTATUS, cmd_none, NULL, NULL, NULL, "Force RPC pipe connections to have no special properties", "" }, + + { NULL } +}; + +static struct cmd_set separator_command[] = { + { "---------------", MAX_RPC_RETURN_TYPE, NULL, NULL, NULL, NULL, "----------------------" }, + { NULL } +}; + + +/* Various pipe commands */ + +extern struct cmd_set lsarpc_commands[]; +extern struct cmd_set samr_commands[]; +extern struct cmd_set spoolss_commands[]; +extern struct cmd_set netlogon_commands[]; +extern struct cmd_set srvsvc_commands[]; +extern struct cmd_set dfs_commands[]; +extern struct cmd_set ds_commands[]; +extern struct cmd_set echo_commands[]; +extern struct cmd_set shutdown_commands[]; +extern struct cmd_set test_commands[]; +extern struct cmd_set wkssvc_commands[]; +extern struct cmd_set ntsvcs_commands[]; +extern struct cmd_set drsuapi_commands[]; + +static struct cmd_set *rpcclient_command_list[] = { + rpcclient_commands, + lsarpc_commands, + ds_commands, + samr_commands, + spoolss_commands, + netlogon_commands, + srvsvc_commands, + dfs_commands, + echo_commands, + shutdown_commands, + test_commands, + wkssvc_commands, + ntsvcs_commands, + drsuapi_commands, + NULL +}; + +static void add_command_set(struct cmd_set *cmd_set) +{ + struct cmd_list *entry; + + if (!(entry = SMB_MALLOC_P(struct cmd_list))) { + DEBUG(0, ("out of memory\n")); + return; + } + + ZERO_STRUCTP(entry); + + entry->cmd_set = cmd_set; + DLIST_ADD(cmd_list, entry); +} + + +/** + * Call an rpcclient function, passing an argv array. + * + * @param cmd Command to run, as a single string. + **/ +static NTSTATUS do_cmd(struct cli_state *cli, + struct cmd_set *cmd_entry, + int argc, char **argv) +{ + NTSTATUS ntresult; + WERROR wresult; + + TALLOC_CTX *mem_ctx; + + /* Create mem_ctx */ + + if (!(mem_ctx = talloc_init("do_cmd"))) { + DEBUG(0, ("talloc_init() failed\n")); + return NT_STATUS_NO_MEMORY; + } + + /* Open pipe */ + + if ((cmd_entry->interface != NULL) && (cmd_entry->rpc_pipe == NULL)) { + switch (pipe_default_auth_type) { + case PIPE_AUTH_TYPE_NONE: + ntresult = cli_rpc_pipe_open_noauth( + cli, cmd_entry->interface, + &cmd_entry->rpc_pipe); + break; + case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP: + ntresult = cli_rpc_pipe_open_spnego_ntlmssp( + cli, cmd_entry->interface, + pipe_default_auth_level, + lp_workgroup(), + get_cmdline_auth_info_username(), + get_cmdline_auth_info_password(), + &cmd_entry->rpc_pipe); + break; + case PIPE_AUTH_TYPE_NTLMSSP: + ntresult = cli_rpc_pipe_open_ntlmssp( + cli, cmd_entry->interface, + pipe_default_auth_level, + lp_workgroup(), + get_cmdline_auth_info_username(), + get_cmdline_auth_info_password(), + &cmd_entry->rpc_pipe); + break; + case PIPE_AUTH_TYPE_SCHANNEL: + ntresult = cli_rpc_pipe_open_schannel( + cli, cmd_entry->interface, + pipe_default_auth_level, + lp_workgroup(), + &cmd_entry->rpc_pipe); + break; + default: + DEBUG(0, ("Could not initialise %s. Invalid " + "auth type %u\n", + cli_get_pipe_name_from_iface( + debug_ctx(), cli, + cmd_entry->interface), + pipe_default_auth_type )); + return NT_STATUS_UNSUCCESSFUL; + } + if (!NT_STATUS_IS_OK(ntresult)) { + DEBUG(0, ("Could not initialise %s. Error was %s\n", + cli_get_pipe_name_from_iface( + debug_ctx(), cli, + cmd_entry->interface), + nt_errstr(ntresult) )); + return ntresult; + } + + if (ndr_syntax_id_equal(cmd_entry->interface, + &ndr_table_netlogon.syntax_id)) { + uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; + uint32 sec_channel_type; + uchar trust_password[16]; + + if (!secrets_fetch_trust_account_password(lp_workgroup(), + trust_password, + NULL, &sec_channel_type)) { + return NT_STATUS_UNSUCCESSFUL; + } + + ntresult = rpccli_netlogon_setup_creds(cmd_entry->rpc_pipe, + cli->desthost, /* server name */ + lp_workgroup(), /* domain */ + global_myname(), /* client name */ + global_myname(), /* machine account name */ + trust_password, + sec_channel_type, + &neg_flags); + + if (!NT_STATUS_IS_OK(ntresult)) { + DEBUG(0, ("Could not initialise credentials for %s.\n", + cli_get_pipe_name_from_iface( + debug_ctx(), cli, + cmd_entry->interface))); + return ntresult; + } + } + } + + /* Run command */ + + if ( cmd_entry->returntype == RPC_RTYPE_NTSTATUS ) { + ntresult = cmd_entry->ntfn(cmd_entry->rpc_pipe, mem_ctx, argc, (const char **) argv); + if (!NT_STATUS_IS_OK(ntresult)) { + printf("result was %s\n", nt_errstr(ntresult)); + } + } else { + wresult = cmd_entry->wfn(cmd_entry->rpc_pipe, mem_ctx, argc, (const char **) argv); + /* print out the DOS error */ + if (!W_ERROR_IS_OK(wresult)) { + printf( "result was %s\n", dos_errstr(wresult)); + } + ntresult = W_ERROR_IS_OK(wresult)?NT_STATUS_OK:NT_STATUS_UNSUCCESSFUL; + } + + /* Cleanup */ + + talloc_destroy(mem_ctx); + + return ntresult; +} + + +/** + * Process a command entered at the prompt or as part of -c + * + * @returns The NTSTATUS from running the command. + **/ +static NTSTATUS process_cmd(struct cli_state *cli, char *cmd) +{ + struct cmd_list *temp_list; + NTSTATUS result = NT_STATUS_OK; + int ret; + int argc; + char **argv = NULL; + + if ((ret = poptParseArgvString(cmd, &argc, (const char ***) &argv)) != 0) { + fprintf(stderr, "rpcclient: %s\n", poptStrerror(ret)); + return NT_STATUS_UNSUCCESSFUL; + } + + + /* Walk through a dlist of arrays of commands. */ + for (temp_list = cmd_list; temp_list; temp_list = temp_list->next) { + struct cmd_set *temp_set = temp_list->cmd_set; + + while (temp_set->name) { + if (strequal(argv[0], temp_set->name)) { + if (!(temp_set->returntype == RPC_RTYPE_NTSTATUS && temp_set->ntfn ) && + !(temp_set->returntype == RPC_RTYPE_WERROR && temp_set->wfn )) { + fprintf (stderr, "Invalid command\n"); + goto out_free; + } + + result = do_cmd(cli, temp_set, argc, argv); + + goto out_free; + } + temp_set++; + } + } + + if (argv[0]) { + printf("command not found: %s\n", argv[0]); + } + +out_free: +/* moved to do_cmd() + if (!NT_STATUS_IS_OK(result)) { + printf("result was %s\n", nt_errstr(result)); + } +*/ + + /* NOTE: popt allocates the whole argv, including the + * strings, as a single block. So a single free is + * enough to release it -- we don't free the + * individual strings. rtfm. */ + free(argv); + + return result; +} + + +/* Main function */ + + int main(int argc, char *argv[]) +{ + int opt; + static char *cmdstr = NULL; + const char *server; + struct cli_state *cli = NULL; + static char *opt_ipaddr=NULL; + struct cmd_set **cmd_set; + struct sockaddr_storage server_ss; + NTSTATUS nt_status; + static int opt_port = 0; + fstring new_workgroup; + int result = 0; + TALLOC_CTX *frame = talloc_stackframe(); + uint32_t flags = 0; + + /* make sure the vars that get altered (4th field) are in + a fixed location or certain compilers complain */ + poptContext pc; + struct poptOption long_options[] = { + POPT_AUTOHELP + {"command", 'c', POPT_ARG_STRING, &cmdstr, 'c', "Execute semicolon separated cmds", "COMMANDS"}, + {"dest-ip", 'I', POPT_ARG_STRING, &opt_ipaddr, 'I', "Specify destination IP address", "IP"}, + {"port", 'p', POPT_ARG_INT, &opt_port, 'p', "Specify port number", "PORT"}, + POPT_COMMON_SAMBA + POPT_COMMON_CONNECTION + POPT_COMMON_CREDENTIALS + POPT_TABLEEND + }; + + load_case_tables(); + + zero_addr(&server_ss); + + setlinebuf(stdout); + + /* the following functions are part of the Samba debugging + facilities. See lib/debug.c */ + setup_logging("rpcclient", True); + + /* Parse options */ + + pc = poptGetContext("rpcclient", argc, (const char **) argv, + long_options, 0); + + if (argc == 1) { + poptPrintHelp(pc, stderr, 0); + goto done; + } + + while((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + + case 'I': + if (!interpret_string_addr(&server_ss, + opt_ipaddr, + AI_NUMERICHOST)) { + fprintf(stderr, "%s not a valid IP address\n", + opt_ipaddr); + result = 1; + goto done; + } + } + } + + /* Get server as remaining unparsed argument. Print usage if more + than one unparsed argument is present. */ + + server = poptGetArg(pc); + + if (!server || poptGetArg(pc)) { + poptPrintHelp(pc, stderr, 0); + result = 1; + goto done; + } + + poptFreeContext(pc); + + load_interfaces(); + + if (!init_names()) { + result = 1; + goto done; + } + + /* save the workgroup... + + FIXME!! do we need to do this for other options as well + (or maybe a generic way to keep lp_load() from overwriting + everything)? */ + + fstrcpy( new_workgroup, lp_workgroup() ); + + /* Load smb.conf file */ + + if (!lp_load(get_dyn_CONFIGFILE(),True,False,False,True)) + fprintf(stderr, "Can't load %s\n", get_dyn_CONFIGFILE()); + + if ( strlen(new_workgroup) != 0 ) + set_global_myworkgroup( new_workgroup ); + + /* + * Get password + * from stdin if necessary + */ + + if (get_cmdline_auth_info_use_machine_account() && + !set_cmdline_auth_info_machine_account_creds()) { + result = 1; + goto done; + } + + if (!get_cmdline_auth_info_got_pass()) { + char *pass = getpass("Password:"); + if (pass) { + set_cmdline_auth_info_password(pass); + } + } + + if ((server[0] == '/' && server[1] == '/') || + (server[0] == '\\' && server[1] == '\\')) { + server += 2; + } + + if (get_cmdline_auth_info_use_kerberos()) { + flags |= CLI_FULL_CONNECTION_USE_KERBEROS | + CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS; + } + + + nt_status = cli_full_connection(&cli, global_myname(), server, + opt_ipaddr ? &server_ss : NULL, opt_port, + "IPC$", "IPC", + get_cmdline_auth_info_username(), + lp_workgroup(), + get_cmdline_auth_info_password(), + flags, + get_cmdline_auth_info_signing_state(),NULL); + + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(0,("Cannot connect to server. Error was %s\n", nt_errstr(nt_status))); + result = 1; + goto done; + } + + if (get_cmdline_auth_info_smb_encrypt()) { + nt_status = cli_cm_force_encryption(cli, + get_cmdline_auth_info_username(), + get_cmdline_auth_info_password(), + lp_workgroup(), + "IPC$"); + if (!NT_STATUS_IS_OK(nt_status)) { + result = 1; + goto done; + } + } + +#if 0 /* COMMENT OUT FOR TESTING */ + memset(cmdline_auth_info.password,'X',sizeof(cmdline_auth_info.password)); +#endif + + /* Load command lists */ + + timeout = cli_set_timeout(cli, 10000); + + cmd_set = rpcclient_command_list; + + while(*cmd_set) { + add_command_set(*cmd_set); + add_command_set(separator_command); + cmd_set++; + } + + fetch_machine_sid(cli); + + /* Do anything specified with -c */ + if (cmdstr && cmdstr[0]) { + char *cmd; + char *p = cmdstr; + + result = 0; + + while((cmd=next_command(&p)) != NULL) { + NTSTATUS cmd_result = process_cmd(cli, cmd); + SAFE_FREE(cmd); + result = NT_STATUS_IS_ERR(cmd_result); + } + + goto done; + } + + /* Loop around accepting commands */ + + while(1) { + char *line = NULL; + + line = smb_readline("rpcclient $> ", NULL, completion_fn); + + if (line == NULL) + break; + + if (line[0] != '\n') + process_cmd(cli, line); + SAFE_FREE(line); + } + +done: + if (cli != NULL) { + cli_shutdown(cli); + } + TALLOC_FREE(frame); + return result; +} diff --git a/source3/rpcclient/rpcclient.h b/source3/rpcclient/rpcclient.h new file mode 100644 index 0000000000..91810b63a9 --- /dev/null +++ b/source3/rpcclient/rpcclient.h @@ -0,0 +1,42 @@ +/* + Unix SMB/CIFS implementation. + RPC pipe client + + Copyright (C) Tim Potter 2000 + + 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 <http://www.gnu.org/licenses/>. +*/ + +#ifndef RPCCLIENT_H +#define RPCCLIENT_H + +typedef enum { + RPC_RTYPE_NTSTATUS = 0, + RPC_RTYPE_WERROR, + MAX_RPC_RETURN_TYPE +} RPC_RETURN_TYPE; + +struct cmd_set { + const char *name; + RPC_RETURN_TYPE returntype; + NTSTATUS (*ntfn)(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, + const char **argv); + WERROR (*wfn)(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv); + const struct ndr_syntax_id *interface; + struct rpc_pipe_client *rpc_pipe; + const char *description; + const char *usage; +}; + +#endif /* RPCCLIENT_H */ |