diff options
Diffstat (limited to 'source3/rpcclient')
24 files changed, 21948 insertions, 0 deletions
diff --git a/source3/rpcclient/cmd_clusapi.c b/source3/rpcclient/cmd_clusapi.c new file mode 100644 index 0000000..7f208a1 --- /dev/null +++ b/source3/rpcclient/cmd_clusapi.c @@ -0,0 +1,753 @@ +/* + Unix SMB/CIFS implementation. + RPC pipe client + + Copyright (C) Günther Deschner 2015 + + 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" +#include "../librpc/gen_ndr/ndr_clusapi_c.h" + +static WERROR cmd_clusapi_open_cluster(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + WERROR error; + struct policy_handle Cluster; + + status = dcerpc_clusapi_OpenCluster(b, mem_ctx, + &error, + &Cluster); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(error)) { + printf("error: %s\n", win_errstr(error)); + return error; + } + + printf("successfully opened cluster\n"); + + status = dcerpc_clusapi_CloseCluster(b, mem_ctx, + &Cluster, + &error); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(error)) { + printf("error: %s\n", win_errstr(error)); + return error; + } + + printf("successfully closed cluster\n"); + + return WERR_OK; +} + +static WERROR cmd_clusapi_get_cluster_name(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + WERROR error; + const char *ClusterName; + const char *NodeName; + + status = dcerpc_clusapi_GetClusterName(b, mem_ctx, + &ClusterName, + &NodeName, + &error); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(error)) { + printf("error: %s\n", win_errstr(error)); + return error; + } + + printf("ClusterName: %s\n", ClusterName); + printf("NodeName: %s\n", NodeName); + + return WERR_OK; +} + +static WERROR cmd_clusapi_get_cluster_version(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + WERROR error; + uint16_t lpwMajorVersion; + uint16_t lpwMinorVersion; + uint16_t lpwBuildNumber; + const char *lpszVendorId; + const char *lpszCSDVersion; + + status = dcerpc_clusapi_GetClusterVersion(b, mem_ctx, + &lpwMajorVersion, + &lpwMinorVersion, + &lpwBuildNumber, + &lpszVendorId, + &lpszCSDVersion, + &error); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(error)) { + printf("error: %s\n", win_errstr(error)); + return error; + } + + printf("lpwMajorVersion: %d\n", lpwMajorVersion); + printf("lpwMinorVersion: %d\n", lpwMinorVersion); + printf("lpwBuildNumber: %d\n", lpwBuildNumber); + printf("lpszVendorId: %s\n", lpszVendorId); + printf("lpszCSDVersion: %s\n", lpszCSDVersion); + + return WERR_OK; +} + +static WERROR cmd_clusapi_get_quorum_resource(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + WERROR error; + const char *lpszResourceName; + const char *lpszDeviceName; + uint32_t pdwMaxQuorumLogSize; + WERROR rpc_status; + + status = dcerpc_clusapi_GetQuorumResource(b, mem_ctx, + &lpszResourceName, + &lpszDeviceName, + &pdwMaxQuorumLogSize, + &rpc_status, + &error); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(error)) { + printf("error: %s\n", win_errstr(error)); + return error; + } + + printf("lpszResourceName: %s\n", lpszResourceName); + printf("lpszDeviceName: %s\n", lpszDeviceName); + printf("pdwMaxQuorumLogSize: %d\n", pdwMaxQuorumLogSize); + printf("rpc_status: %s\n", win_errstr(rpc_status)); + + return WERR_OK; +} + +static WERROR cmd_clusapi_create_enum(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + WERROR error; + uint32_t dwType = 1; + struct ENUM_LIST *ReturnEnum; + WERROR rpc_status; + + if (argc >= 2) { + sscanf(argv[1],"%x",&dwType); + } + + status = dcerpc_clusapi_CreateEnum(b, mem_ctx, + dwType, + &ReturnEnum, + &rpc_status, + &error); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(error)) { + printf("error: %s\n", win_errstr(error)); + return error; + } + + printf("rpc_status: %s\n", win_errstr(rpc_status)); + + return WERR_OK; +} + +static WERROR cmd_clusapi_create_enumex(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + WERROR error; + uint32_t dwType = 1; + struct ENUM_LIST *ReturnIdEnum; + struct ENUM_LIST *ReturnNameEnum; + WERROR rpc_status, ignore; + struct policy_handle Cluster; + + status = dcerpc_clusapi_OpenCluster(b, mem_ctx, + &error, + &Cluster); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(error)) { + printf("error: %s\n", win_errstr(error)); + return error; + } + + if (argc >= 2) { + sscanf(argv[1],"%x",&dwType); + } + + status = dcerpc_clusapi_CreateEnumEx(b, mem_ctx, + Cluster, + dwType, + 0, + &ReturnIdEnum, + &ReturnNameEnum, + &rpc_status, + &error); + dcerpc_clusapi_CloseCluster(b, mem_ctx, + &Cluster, + &ignore); + + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(error)) { + printf("error: %s\n", win_errstr(error)); + return error; + } + + printf("rpc_status: %s\n", win_errstr(rpc_status)); + + return WERR_OK; +} + + +static WERROR cmd_clusapi_open_resource(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + const char *lpszResourceName = "Cluster Name"; + WERROR Status; + struct policy_handle hResource; + WERROR rpc_status, ignore; + + if (argc >= 2) { + lpszResourceName = argv[1]; + } + + status = dcerpc_clusapi_OpenResource(b, mem_ctx, + lpszResourceName, + &Status, + &rpc_status, + &hResource); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(Status)) { + printf("Status: %s\n", win_errstr(Status)); + return Status; + } + + printf("rpc_status: %s\n", win_errstr(rpc_status)); + + dcerpc_clusapi_CloseResource(b, mem_ctx, + &hResource, + &ignore); + + return WERR_OK; +} + +static WERROR cmd_clusapi_online_resource(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + const char *lpszResourceName = "Cluster Name"; + WERROR Status; + struct policy_handle hResource; + WERROR rpc_status, ignore; + + if (argc >= 2) { + lpszResourceName = argv[1]; + } + + status = dcerpc_clusapi_OpenResource(b, mem_ctx, + lpszResourceName, + &Status, + &rpc_status, + &hResource); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(Status)) { + printf("Status: %s\n", win_errstr(Status)); + return Status; + } + + status = dcerpc_clusapi_OnlineResource(b, mem_ctx, + hResource, + &Status, + &rpc_status); + dcerpc_clusapi_CloseResource(b, mem_ctx, + &hResource, + &ignore); + + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(Status)) { + printf("Status: %s\n", win_errstr(Status)); + return Status; + } + + printf("rpc_status: %s\n", win_errstr(rpc_status)); + + return WERR_OK; +} + +static WERROR cmd_clusapi_offline_resource(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + const char *lpszResourceName = "Cluster Name"; + WERROR Status; + struct policy_handle hResource; + WERROR rpc_status, ignore; + + if (argc >= 2) { + lpszResourceName = argv[1]; + } + + status = dcerpc_clusapi_OpenResource(b, mem_ctx, + lpszResourceName, + &Status, + &rpc_status, + &hResource); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(Status)) { + printf("Status: %s\n", win_errstr(Status)); + return Status; + } + + status = dcerpc_clusapi_OfflineResource(b, mem_ctx, + hResource, + &Status, + &rpc_status); + dcerpc_clusapi_CloseResource(b, mem_ctx, + &hResource, + &ignore); + + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(Status)) { + printf("Status: %s\n", win_errstr(Status)); + return Status; + } + + printf("rpc_status: %s\n", win_errstr(rpc_status)); + + return WERR_OK; +} + +static WERROR cmd_clusapi_get_resource_state(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + const char *lpszResourceName = "Cluster Name"; + WERROR Status; + struct policy_handle hResource; + WERROR rpc_status; + enum clusapi_ClusterResourceState State; + const char *NodeName; + const char *GroupName; + WERROR result, ignore; + + if (argc >= 2) { + lpszResourceName = argv[1]; + } + + status = dcerpc_clusapi_OpenResource(b, mem_ctx, + lpszResourceName, + &Status, + &rpc_status, + &hResource); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(Status)) { + printf("Status: %s\n", win_errstr(Status)); + return Status; + } + + status = dcerpc_clusapi_GetResourceState(b, mem_ctx, + hResource, + &State, + &NodeName, + &GroupName, + &rpc_status, + &result); + dcerpc_clusapi_CloseResource(b, mem_ctx, + &hResource, + &ignore); + + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(Status)) { + printf("Status: %s\n", win_errstr(Status)); + return Status; + } + + printf("rpc_status: %s\n", win_errstr(rpc_status)); + + return WERR_OK; +} + +static WERROR cmd_clusapi_get_cluster_version2(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + uint16_t lpwMajorVersion; + uint16_t lpwMinorVersion; + uint16_t lpwBuildNumber; + const char *lpszVendorId; + const char *lpszCSDVersion; + struct CLUSTER_OPERATIONAL_VERSION_INFO *ppClusterOpVerInfo; + WERROR rpc_status; + WERROR result; + + status = dcerpc_clusapi_GetClusterVersion2(b, mem_ctx, + &lpwMajorVersion, + &lpwMinorVersion, + &lpwBuildNumber, + &lpszVendorId, + &lpszCSDVersion, + &ppClusterOpVerInfo, + &rpc_status, + &result); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(result)) { + printf("result: %s\n", win_errstr(result)); + return result; + } + + printf("rpc_status: %s\n", win_errstr(rpc_status)); + + return WERR_OK; +} + +static WERROR cmd_clusapi_pause_node(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + const char *lpszNodeName = "CTDB_NODE_0"; + WERROR Status; + struct policy_handle hNode; + WERROR rpc_status; + WERROR result, ignore; + + if (argc >= 2) { + lpszNodeName = argv[1]; + } + + status = dcerpc_clusapi_OpenNode(b, mem_ctx, + lpszNodeName, + &Status, + &rpc_status, + &hNode); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(Status)) { + printf("Failed to open node %s\n", lpszNodeName); + printf("Status: %s\n", win_errstr(Status)); + return Status; + } + + status = dcerpc_clusapi_PauseNode(b, mem_ctx, + hNode, + &rpc_status, + &result); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + printf("Failed to pause node %s\n", lpszNodeName); + printf("Status: %s\n", win_errstr(result)); + return result; + } + + dcerpc_clusapi_CloseNode(b, mem_ctx, + &hNode, + &ignore); + + printf("Cluster node %s has been paused\n", lpszNodeName); + printf("rpc_status: %s\n", win_errstr(rpc_status)); + + return WERR_OK; +} + +static WERROR cmd_clusapi_resume_node(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + const char *lpszNodeName = "CTDB_NODE_0"; + WERROR Status; + struct policy_handle hNode; + WERROR rpc_status; + WERROR result, ignore; + + if (argc >= 2) { + lpszNodeName = argv[1]; + } + + status = dcerpc_clusapi_OpenNode(b, mem_ctx, + lpszNodeName, + &Status, + &rpc_status, + &hNode); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(Status)) { + printf("Failed to open node %s\n", lpszNodeName); + printf("Status: %s\n", win_errstr(Status)); + return Status; + } + + status = dcerpc_clusapi_ResumeNode(b, mem_ctx, + hNode, + &rpc_status, + &result); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + printf("Failed to resume node %s\n", lpszNodeName); + printf("Status: %s\n", win_errstr(result)); + return result; + } + + dcerpc_clusapi_CloseNode(b, mem_ctx, + &hNode, + &ignore); + + printf("Cluster node %s has been resumed\n", lpszNodeName); + printf("rpc_status: %s\n", win_errstr(rpc_status)); + + return WERR_OK; +} + + +struct cmd_set clusapi_commands[] = { + + { + .name = "CLUSAPI", + }, + { + .name = "clusapi_open_cluster", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_clusapi_open_cluster, + .table = &ndr_table_clusapi, + .rpc_pipe = NULL, + .description = "Open cluster", + .usage = "", + }, + { + .name = "clusapi_get_cluster_name", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_clusapi_get_cluster_name, + .table = &ndr_table_clusapi, + .rpc_pipe = NULL, + .description = "Get cluster name", + .usage = "", + }, + { + .name = "clusapi_get_cluster_version", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_clusapi_get_cluster_version, + .table = &ndr_table_clusapi, + .rpc_pipe = NULL, + .description = "Get cluster version", + .usage = "", + }, + { + .name = "clusapi_get_quorum_resource", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_clusapi_get_quorum_resource, + .table = &ndr_table_clusapi, + .rpc_pipe = NULL, + .description = "Get quorum resource", + .usage = "", + }, + { + .name = "clusapi_create_enum", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_clusapi_create_enum, + .table = &ndr_table_clusapi, + .rpc_pipe = NULL, + .description = "Create enum query", + .usage = "", + }, + { + .name = "clusapi_create_enumex", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_clusapi_create_enumex, + .table = &ndr_table_clusapi, + .rpc_pipe = NULL, + .description = "Create enumex query", + .usage = "", + }, + { + .name = "clusapi_open_resource", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_clusapi_open_resource, + .table = &ndr_table_clusapi, + .rpc_pipe = NULL, + .description = "Open cluster resource", + .usage = "", + }, + { + .name = "clusapi_online_resource", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_clusapi_online_resource, + .table = &ndr_table_clusapi, + .rpc_pipe = NULL, + .description = "Set cluster resource online", + .usage = "", + }, + { + .name = "clusapi_offline_resource", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_clusapi_offline_resource, + .table = &ndr_table_clusapi, + .rpc_pipe = NULL, + .description = "Set cluster resource offline", + .usage = "", + }, + { + .name = "clusapi_get_resource_state", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_clusapi_get_resource_state, + .table = &ndr_table_clusapi, + .rpc_pipe = NULL, + .description = "Get cluster resource state", + .usage = "", + }, + { + .name = "clusapi_get_cluster_version2", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_clusapi_get_cluster_version2, + .table = &ndr_table_clusapi, + .rpc_pipe = NULL, + .description = "Get cluster version2", + .usage = "", + }, + { + .name = "clusapi_pause_node", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_clusapi_pause_node, + .table = &ndr_table_clusapi, + .rpc_pipe = NULL, + .description = "Pause cluster node", + .usage = "", + }, + { + .name = "clusapi_resume_node", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_clusapi_resume_node, + .table = &ndr_table_clusapi, + .rpc_pipe = NULL, + .description = "Resume cluster node", + .usage = "", + }, + { + .name = NULL, + }, +}; diff --git a/source3/rpcclient/cmd_dfs.c b/source3/rpcclient/cmd_dfs.c new file mode 100644 index 0000000..8177871 --- /dev/null +++ b/source3/rpcclient/cmd_dfs.c @@ -0,0 +1,396 @@ +/* + 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" +#include "../librpc/gen_ndr/ndr_dfs_c.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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc != 1) { + printf("Usage: %s\n", argv[0]); + return WERR_OK; + } + + result = dcerpc_dfs_GetManagerVersion(b, 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_t flags = 0; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 = dcerpc_dfs_Add(b, 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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 = dcerpc_dfs_Remove(b, 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_t 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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + NTSTATUS result; + WERROR werr; + uint32_t 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); + return WERR_OK; + } + + result = dcerpc_dfs_Enum(b, mem_ctx, str.level, 0xFFFFFFFF, &str, + &total, &werr); + if (!NT_STATUS_IS_OK(result)) { + return ntstatus_to_werror(result); + } + if (W_ERROR_IS_OK(werr)) { + 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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + NTSTATUS result; + WERROR werr; + uint32_t 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); + return WERR_OK; + } + + result = dcerpc_dfs_EnumEx(b, mem_ctx, argv[1], str.level, + 0xFFFFFFFF, &str, &total, &werr); + if (!NT_STATUS_IS_OK(result)) { + return ntstatus_to_werror(result); + } + if (W_ERROR_IS_OK(werr)) { + 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_t info_level = 1; + union dfs_Info ctr; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 = dcerpc_dfs_GetInfo(b, mem_ctx, path, servername, + sharename, info_level, &ctr, &werr); + if (!NT_STATUS_IS_OK(result)) { + return ntstatus_to_werror(result); + } + if (W_ERROR_IS_OK(werr)) { + display_dfs_info(info_level, &ctr); + } + + return werr; +} + +/* List of commands exported by this module */ + +struct cmd_set dfs_commands[] = { + + { .name = "DFS" }, + + { + .name = "dfsversion", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_dfs_version, + .table = &ndr_table_netdfs, + .rpc_pipe = NULL, + .description = "Query DFS support", + .usage = "", + }, + { + .name = "dfsadd", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_dfs_add, + .table = &ndr_table_netdfs, + .rpc_pipe = NULL, + .description = "Add a DFS share", + .usage = "", + }, + { + .name = "dfsremove", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_dfs_remove, + .table = &ndr_table_netdfs, + .rpc_pipe = NULL, + .description = "Remove a DFS share", + .usage = "", + }, + { + .name = "dfsgetinfo", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_dfs_getinfo, + .table = &ndr_table_netdfs, + .rpc_pipe = NULL, + .description = "Query DFS share info", + .usage = "", + }, + { + .name = "dfsenum", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_dfs_enum, + .table = &ndr_table_netdfs, + .rpc_pipe = NULL, + .description = "Enumerate dfs shares", + .usage = "", + }, + { + .name = "dfsenumex", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_dfs_enumex, + .table = &ndr_table_netdfs, + .rpc_pipe = NULL, + .description = "Enumerate dfs shares", + .usage = "", + }, + + { .name = NULL } +}; diff --git a/source3/rpcclient/cmd_drsuapi.c b/source3/rpcclient/cmd_drsuapi.c new file mode 100644 index 0000000..bf87a26 --- /dev/null +++ b/source3/rpcclient/cmd_drsuapi.c @@ -0,0 +1,723 @@ +/* + 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" +#include "../librpc/gen_ndr/ndr_drsuapi_c.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; + uint32_t level = 1; + union drsuapi_DsNameRequest req; + uint32_t level_out; + struct drsuapi_DsNameString *names; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 = dcerpc_drsuapi_DsCrackNames(b, 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; + struct dcerpc_binding_handle *b = cli->binding_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 = dcerpc_drsuapi_DsBind(b, mem_ctx, + &bind_guid, + NULL, + &bind_handle, + &werr); + + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + werr = cracknames(cli, mem_ctx, + &bind_handle, + DRSUAPI_DS_NAME_FORMAT_UNKNOWN, + 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)) { + WERROR _werr; + dcerpc_drsuapi_DsUnbind(b, 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; + struct dcerpc_binding_handle *b = cli->binding_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 = dcerpc_drsuapi_DsBind(b, mem_ctx, + &bind_guid, + NULL, + &bind_handle, + &werr); + + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + req.req1.domain_name = domain; + req.req1.level = level; + + status = dcerpc_drsuapi_DsGetDomainControllerInfo(b, 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)) { + WERROR _werr; + dcerpc_drsuapi_DsUnbind(b, mem_ctx, &bind_handle, &_werr); + } + + return werr; +} + +static WERROR cmd_drsuapi_writeaccountspn(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; + struct dcerpc_binding_handle *b = cli->binding_handle; + struct drsuapi_DsNameString *spn_names = NULL; + + int i = 0; + uint32_t level_out; + union drsuapi_DsWriteAccountSpnRequest req; + union drsuapi_DsWriteAccountSpnResult result; + + if (argc < 4) { + printf("usage: %s [add|replace|delete] dn [spn_names]+\n", argv[0]); + return WERR_OK; + } + + req.req1.unknown1 = 0; /* Unused, must be 0 */ + req.req1.object_dn = argv[2]; + req.req1.count = argc - 3; + + if (strcmp(argv[1], "add") == 0) { + req.req1.operation = DRSUAPI_DS_SPN_OPERATION_ADD; + } else if (strcmp(argv[1], "replace") == 0) { + req.req1.operation = DRSUAPI_DS_SPN_OPERATION_REPLACE; + } else if (strcmp(argv[1], "delete") == 0) { + req.req1.operation = DRSUAPI_DS_SPN_OPERATION_DELETE; + } else { + printf("usage: %s [add|replace|delete] dn [spn_names]+\n", argv[0]); + return WERR_OK; + } + + spn_names = talloc_zero_array(mem_ctx, + struct drsuapi_DsNameString, + req.req1.count); + W_ERROR_HAVE_NO_MEMORY(spn_names); + + for (i=0; i<req.req1.count; i++) { + spn_names[i].str = argv[i + 3]; + } + + req.req1.spn_names = spn_names; + + GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid); + + status = dcerpc_drsuapi_DsBind(b, mem_ctx, + &bind_guid, + NULL, + &bind_handle, + &werr); + + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + status = dcerpc_drsuapi_DsWriteAccountSpn(b, mem_ctx, + &bind_handle, + 1, + &req, + &level_out, + &result, + &werr); + + if (!NT_STATUS_IS_OK(status)) { + werr = ntstatus_to_werror(status); + goto out; + } + + if (!W_ERROR_IS_OK(werr)) { + goto out; + } + + out: + if (is_valid_policy_hnd(&bind_handle)) { + WERROR _werr; + dcerpc_drsuapi_DsUnbind(b, 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 dcerpc_binding_handle *b = cli->binding_handle; + + struct GUID bind_guid; + struct drsuapi_DsBindInfoCtr bind_info; + struct drsuapi_DsBindInfo28 info28; + + const char *nc_dn = NULL; + + DATA_BLOB session_key; + + uint32_t level = 8; + bool single = false; + uint32_t level_out = 0; + union drsuapi_DsGetNCChangesRequest req; + union drsuapi_DsGetNCChangesCtr ctr; + struct drsuapi_DsReplicaObjectIdentifier nc; + + struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL; + struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL; + uint32_t out_level = 0; + int y; + + uint32_t supported_extensions = 0; + uint32_t replica_flags = DRSUAPI_DRS_WRIT_REP | + DRSUAPI_DRS_INIT_SYNC | + DRSUAPI_DRS_PER_SYNC | + DRSUAPI_DRS_GET_ANC | + DRSUAPI_DRS_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(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 = dcerpc_drsuapi_DsBind(b, 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 == 32) { + supported_extensions = bind_info.info.info32.supported_extensions; + } else if (bind_info.length == 48) { + supported_extensions = bind_info.info.info48.supported_extensions; + } else if (bind_info.length == 52) { + supported_extensions = bind_info.info.info52.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_UNKNOWN, + 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 = (struct dom_sid) {0}; + + 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 = dcerpc_drsuapi_DsGetNCChanges(b, mem_ctx, + &bind_handle, + level, + &req, + &level_out, + &ctr, + &werr); + if (!NT_STATUS_IS_OK(status)) { + werr = ntstatus_to_werror(status); + printf("Failed to get NC Changes: %s", + get_friendly_nt_error_msg(status)); + goto out; + } + + if (!W_ERROR_IS_OK(werr)) { + printf("Failed to get NC Changes: %s", + get_friendly_werror_msg(werr)); + goto out; + } + + if (level_out == 1) { + out_level = 1; + ctr1 = &ctr.ctr1; + } else if (level_out == 2 && ctr.ctr2.mszip1.ts) { + out_level = 1; + ctr1 = &ctr.ctr2.mszip1.ts->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 + && ctr.ctr7.ctr.mszip6.ts) { + out_level = 6; + ctr6 = &ctr.ctr7.ctr.mszip6.ts->ctr6; + } else if (level_out == 7 + && ctr.ctr7.level == 6 + && ctr.ctr7.type == DRSUAPI_COMPRESSION_TYPE_WIN2K3_LZ77_DIRECT2 + && ctr.ctr7.ctr.xpress6.ts) { + out_level = 6; + ctr6 = &ctr.ctr7.ctr.xpress6.ts->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[] = { + + { + .name = "DRSUAPI", + }, + { + .name = "dscracknames", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_drsuapi_cracknames, + .table = &ndr_table_drsuapi, + .rpc_pipe = NULL, + .description = "Crack Name", + .usage = "", + }, + { + .name = "dsgetdcinfo", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_drsuapi_getdcinfo, + .table = &ndr_table_drsuapi, + .rpc_pipe = NULL, + .description = "Get Domain Controller Info", + .usage = "", + }, + { + .name = "dsgetncchanges", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_drsuapi_getncchanges, + .table = &ndr_table_drsuapi, + .rpc_pipe = NULL, + .description = "Get NC Changes", + .usage = "", + }, + { + .name = "dswriteaccountspn", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_drsuapi_writeaccountspn, + .table = &ndr_table_drsuapi, + .rpc_pipe = NULL, + .description = "Write Account SPN", + .usage = "", + }, + { + .name = NULL, + }, +}; diff --git a/source3/rpcclient/cmd_dssetup.c b/source3/rpcclient/cmd_dssetup.c new file mode 100644 index 0000000..611cf63 --- /dev/null +++ b/source3/rpcclient/cmd_dssetup.c @@ -0,0 +1,84 @@ +/* + 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" +#include "../librpc/gen_ndr/ndr_dssetup_c.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) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + WERROR werr; + union dssetup_DsRoleInfo info; + + status = dcerpc_dssetup_DsRoleGetPrimaryDomainInformation(b, 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[] = { + + { + .name = "LSARPC-DS" + }, + + { + .name = "dsroledominfo", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_ds_dsrole_getprimarydominfo, + .table = &ndr_table_dssetup, + .rpc_pipe = NULL, + .description = "Get Primary Domain Information", + .usage = "" + }, + + { + .name = NULL, + } +}; diff --git a/source3/rpcclient/cmd_echo.c b/source3/rpcclient/cmd_echo.c new file mode 100644 index 0000000..6a387ea --- /dev/null +++ b/source3/rpcclient/cmd_echo.c @@ -0,0 +1,232 @@ +/* + 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" +#include "../librpc/gen_ndr/ndr_echo_c.h" + +static NTSTATUS cmd_echo_add_one(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + uint32_t request = 1, response; + NTSTATUS status; + + if (argc > 2) { + printf("Usage: %s [num]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc == 2) { + request = atoi(argv[1]); + } + + status = dcerpc_echo_AddOne(b, mem_ctx, request, &response); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + printf("%d + 1 = %d\n", request, response); + +done: + return status; +} + +static NTSTATUS cmd_echo_data(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + uint32_t size, i; + NTSTATUS status; + 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); + status = 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); + status = NT_STATUS_NO_MEMORY; + goto done; + } + + for (i = 0; i < size; i++) { + in_data[i] = i & 0xff; + } + + status = dcerpc_echo_EchoData(b, mem_ctx, size, in_data, out_data); + if (!NT_STATUS_IS_OK(status)) { + 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]); + status = NT_STATUS_UNSUCCESSFUL; + } + } + +done: + SAFE_FREE(in_data); + SAFE_FREE(out_data); + + return status; +} + +static NTSTATUS cmd_echo_source_data(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + uint32_t size, i; + NTSTATUS status; + 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); + status = NT_STATUS_NO_MEMORY; + goto done; + } + + + status = dcerpc_echo_SourceData(b, mem_ctx, size, out_data); + if (!NT_STATUS_IS_OK(status)) { + 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); + status = NT_STATUS_UNSUCCESSFUL; + } + } + +done: + + SAFE_FREE(out_data); + return status; +} + +static NTSTATUS cmd_echo_sink_data(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + uint32_t size, i; + NTSTATUS status; + 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); + status = NT_STATUS_NO_MEMORY; + goto done; + } + + for (i = 0; i < size; i++) { + in_data[i] = i & 0xff; + } + + status = dcerpc_echo_SinkData(b, mem_ctx, size, in_data); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + +done: + SAFE_FREE(in_data); + + return status; +} + +/* List of commands exported by this module */ + +struct cmd_set echo_commands[] = { + + { + .name = "ECHO", + }, + + { + .name = "echoaddone", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_echo_add_one, + .wfn = NULL, + .table = &ndr_table_rpcecho, + .rpc_pipe = NULL, + .description = "Add one to a number", + .usage = "", + }, + { + .name = "echodata", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_echo_data, + .wfn = NULL, + .table = &ndr_table_rpcecho, + .rpc_pipe = NULL, + .description = "Echo data", + .usage = "", + }, + { + .name = "sinkdata", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_echo_sink_data, + .wfn = NULL, + .table = &ndr_table_rpcecho, + .rpc_pipe = NULL, + .description = "Sink data", + .usage = "", + }, + { + .name = "sourcedata", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_echo_source_data, + .wfn = NULL, + .table = &ndr_table_rpcecho, + .rpc_pipe = NULL, + .description = "Source data", + .usage = "", + }, + { + .name = NULL + }, +}; diff --git a/source3/rpcclient/cmd_epmapper.c b/source3/rpcclient/cmd_epmapper.c new file mode 100644 index 0000000..236f753 --- /dev/null +++ b/source3/rpcclient/cmd_epmapper.c @@ -0,0 +1,270 @@ +/* + Unix SMB/CIFS implementation. + RPC pipe client + + Copyright (C) Volker Lendecke 2009 + + 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" +#include "../librpc/gen_ndr/ndr_epmapper_c.h" +#include "librpc/ndr/ndr_table.h" + +static NTSTATUS cmd_epmapper_map(struct rpc_pipe_client *p, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct dcerpc_binding_handle *b = p->binding_handle; + struct dcerpc_binding *map_binding; + struct epm_twr_t map_tower; + struct epm_twr_p_t towers[500]; + struct policy_handle entry_handle; + struct ndr_syntax_id abstract_syntax; + uint32_t num_towers; + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + NTSTATUS status; + uint32_t result; + uint32_t i; + const struct ndr_interface_list *l; + const char *interface_name = "lsarpc"; + enum dcerpc_transport_t transport = NCACN_NP; + bool ok = false; + struct GUID object_uuid = GUID_zero(); + + if (argc > 4) { + d_fprintf(stderr, + "Usage: %s [interface_name] [transport] " + "[object_uuid]\n", + argv[0]); + return NT_STATUS_OK; + } + + if (argc >= 2) { + interface_name = argv[1]; + } + + for (l = ndr_table_list(); l != NULL; l = l->next) { + + ok = strequal(interface_name, l->table->name); + if (ok) { + abstract_syntax = l->table->syntax_id; + break; + } + } + + if (!ok) { + d_fprintf(stderr, "unknown interface: %s\n", + interface_name); + status = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + if (argc >= 3) { + transport = dcerpc_transport_by_name(argv[2]); + if (transport == NCA_UNKNOWN) { + d_fprintf(stderr, "unknown transport: %s\n", + argv[2]); + status = NT_STATUS_UNSUCCESSFUL; + goto done; + } + } + + if (argc >= 4) { + status = GUID_from_string(argv[3], &object_uuid); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + } + + /* 127.0.0.1[0] => correct? needed? */ + status = dcerpc_parse_binding(tmp_ctx, "ncacn_np:127.0.0.1[0]", + &map_binding); + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "dcerpc_parse_binding returned %s\n", + nt_errstr(status)); + goto done; + } + + status = dcerpc_binding_set_transport(map_binding, transport); + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "dcerpc_binding_set_transport returned %s\n", + nt_errstr(status)); + goto done; + } + + status = dcerpc_binding_set_abstract_syntax(map_binding, + &abstract_syntax); + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "dcerpc_binding_set_abstract_syntax returned %s\n", + nt_errstr(status)); + goto done; + } + + status = dcerpc_binding_build_tower(tmp_ctx, map_binding, + &map_tower.tower); + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "dcerpc_binding_build_tower returned %s\n", + nt_errstr(status)); + goto done; + } + + ZERO_STRUCT(towers); + ZERO_STRUCT(entry_handle); + + status = dcerpc_epm_Map( + b, tmp_ctx, &object_uuid, + &map_tower, &entry_handle, ARRAY_SIZE(towers), + &num_towers, towers, &result); + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "dcerpc_epm_Map returned %s\n", + nt_errstr(status)); + goto done; + } + + if (result != EPMAPPER_STATUS_OK) { + d_fprintf(stderr, "epm_Map returned %u (0x%08X)\n", + result, result); + status = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + d_printf("num_tower[%u]\n", num_towers); + + for (i=0; i < num_towers; i++) { + struct dcerpc_binding *binding; + + if (towers[i].twr == NULL) { + d_fprintf(stderr, "tower[%u] NULL\n", i); + break; + } + + status = dcerpc_binding_from_tower(tmp_ctx, &towers[i].twr->tower, + &binding); + if (!NT_STATUS_IS_OK(status)) { + break; + } + + d_printf("tower[%u] %s\n", i, dcerpc_binding_string(tmp_ctx, binding)); + } +done: + TALLOC_FREE(tmp_ctx); + return status; +} + +static NTSTATUS cmd_epmapper_lookup(struct rpc_pipe_client *p, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct dcerpc_binding_handle *b = p->binding_handle; + struct policy_handle entry_handle; + + ZERO_STRUCT(entry_handle); + + while (true) { + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + uint32_t num_entries; + struct epm_entry_t entry; + NTSTATUS status; + char *guid_string; + struct dcerpc_binding *binding; + uint32_t result; + + status = dcerpc_epm_Lookup(b, tmp_ctx, + 0, /* rpc_c_ep_all */ + NULL, + NULL, + 0, /* rpc_c_vers_all */ + &entry_handle, + 1, /* max_ents */ + &num_entries, &entry, + &result); + if (!NT_STATUS_IS_OK(status)) { + d_fprintf(stderr, "dcerpc_epm_Lookup returned %s\n", + nt_errstr(status)); + break; + } + + if (result == EPMAPPER_STATUS_NO_MORE_ENTRIES) { + d_fprintf(stderr, "epm_Lookup no more entries\n"); + break; + } + + if (result != EPMAPPER_STATUS_OK) { + d_fprintf(stderr, "epm_Lookup returned %u (0x%08X)\n", + result, result); + break; + } + + if (num_entries != 1) { + d_fprintf(stderr, "epm_Lookup returned %d " + "entries, expected one\n", (int)num_entries); + break; + } + + guid_string = GUID_string(tmp_ctx, &entry.object); + if (guid_string == NULL) { + break; + } + + status = dcerpc_binding_from_tower(tmp_ctx, &entry.tower->tower, + &binding); + if (!NT_STATUS_IS_OK(status)) { + break; + } + + d_printf("%s %s: %s\n", guid_string, + dcerpc_binding_string(tmp_ctx, binding), + entry.annotation); + + TALLOC_FREE(tmp_ctx); + } + + return NT_STATUS_OK; +} + + +/* List of commands exported by this module */ + +struct cmd_set epmapper_commands[] = { + + { + .name = "EPMAPPER", + }, + + { + .name = "epmmap", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_epmapper_map, + .wfn = NULL, + .table = &ndr_table_epmapper, + .rpc_pipe = NULL, + .description = "Map a binding", + .usage = "", + }, + { + .name = "epmlookup", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_epmapper_lookup, + .wfn = NULL, + .table = &ndr_table_epmapper, + .rpc_pipe = NULL, + .description = "Lookup bindings", + .usage = "", + }, + { + .name = NULL, + }, +}; diff --git a/source3/rpcclient/cmd_eventlog.c b/source3/rpcclient/cmd_eventlog.c new file mode 100644 index 0000000..a22ab8a --- /dev/null +++ b/source3/rpcclient/cmd_eventlog.c @@ -0,0 +1,650 @@ +/* + Unix SMB/CIFS implementation. + RPC pipe client + + Copyright (C) Günther Deschner 2009 + + 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" +#include "../librpc/gen_ndr/ndr_eventlog.h" +#include "../librpc/gen_ndr/ndr_eventlog_c.h" +#include "rpc_client/init_lsa.h" + +static NTSTATUS get_eventlog_handle(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + const char *log, + struct policy_handle *handle) +{ + NTSTATUS status, result; + struct eventlog_OpenUnknown0 unknown0; + struct lsa_String logname, servername; + struct dcerpc_binding_handle *b = cli->binding_handle; + + unknown0.unknown0 = 0x005c; + unknown0.unknown1 = 0x0001; + + init_lsa_String(&logname, log); + init_lsa_String(&servername, NULL); + + status = dcerpc_eventlog_OpenEventLogW(b, mem_ctx, + &unknown0, + &logname, + &servername, + 0x00000001, /* major */ + 0x00000001, /* minor */ + handle, + &result); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return result; +} + +static NTSTATUS cmd_eventlog_readlog(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status = NT_STATUS_OK; + NTSTATUS result = NT_STATUS_OK; + struct policy_handle handle; + struct dcerpc_binding_handle *b = cli->binding_handle; + + uint32_t flags = EVENTLOG_BACKWARDS_READ | + EVENTLOG_SEQUENTIAL_READ; + uint32_t offset = 0; + uint32_t number_of_bytes = 0; + uint8_t *data; + uint32_t sent_size = 0; + uint32_t real_size = 0; + + if (argc < 2 || argc > 4) { + printf("Usage: %s logname [offset] [number_of_bytes]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc >= 3) { + offset = atoi(argv[2]); + } + + if (argc >= 4) { + number_of_bytes = atoi(argv[3]); + } + + status = get_eventlog_handle(cli, mem_ctx, argv[1], &handle); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + data = talloc_array(mem_ctx, uint8_t, number_of_bytes); + if (data == NULL) { + goto done; + } + + do { + + enum ndr_err_code ndr_err; + DATA_BLOB blob; + struct EVENTLOGRECORD r; + uint32_t size = 0; + uint32_t pos = 0; + + status = dcerpc_eventlog_ReadEventLogW(b, mem_ctx, + &handle, + flags, + offset, + number_of_bytes, + data, + &sent_size, + &real_size, + &result); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + if (NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL) && + real_size > 0 ) { + number_of_bytes = real_size; + data = talloc_realloc(mem_ctx, data, uint8_t, real_size); + if (data == NULL) { + goto done; + } + status = dcerpc_eventlog_ReadEventLogW(b, mem_ctx, + &handle, + flags, + offset, + number_of_bytes, + data, + &sent_size, + &real_size, + &result); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + + if (!NT_STATUS_EQUAL(result, NT_STATUS_END_OF_FILE) && + !NT_STATUS_IS_OK(result)) { + goto done; + } + + number_of_bytes = 0; + + size = IVAL(data, pos); + + while (size > 0) { + + blob = data_blob_const(data + pos, size); + /* dump_data(0, blob.data, blob.length); */ + ndr_err = ndr_pull_struct_blob_all(&blob, mem_ctx, &r, + (ndr_pull_flags_fn_t)ndr_pull_EVENTLOGRECORD); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + status = ndr_map_error2ntstatus(ndr_err); + goto done; + } + + NDR_PRINT_DEBUG(EVENTLOGRECORD, &r); + + pos += size; + + if (pos + 4 > sent_size) { + break; + } + + size = IVAL(data, pos); + } + + offset++; + + } while (NT_STATUS_IS_OK(result)); + + done: + dcerpc_eventlog_CloseEventLog(b, mem_ctx, &handle, &result); + + return status; +} + +static NTSTATUS cmd_eventlog_numrecords(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status, result; + struct policy_handle handle; + uint32_t number = 0; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc != 2) { + printf("Usage: %s logname\n", argv[0]); + return NT_STATUS_OK; + } + + status = get_eventlog_handle(cli, mem_ctx, argv[1], &handle); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = dcerpc_eventlog_GetNumRecords(b, mem_ctx, + &handle, + &number, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + printf("number of records: %d\n", number); + + done: + dcerpc_eventlog_CloseEventLog(b, mem_ctx, &handle, &result); + + return status; +} + +static NTSTATUS cmd_eventlog_oldestrecord(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status, result; + struct policy_handle handle; + uint32_t oldest_entry = 0; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc != 2) { + printf("Usage: %s logname\n", argv[0]); + return NT_STATUS_OK; + } + + status = get_eventlog_handle(cli, mem_ctx, argv[1], &handle); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = dcerpc_eventlog_GetOldestRecord(b, mem_ctx, + &handle, + &oldest_entry, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + printf("oldest entry: %d\n", oldest_entry); + + done: + dcerpc_eventlog_CloseEventLog(b, mem_ctx, &handle, &result); + + return status; +} + +static NTSTATUS cmd_eventlog_reportevent(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status, result; + struct policy_handle handle; + struct dcerpc_binding_handle *b = cli->binding_handle; + + uint16_t num_of_strings = 1; + uint32_t data_size = 0; + struct lsa_String servername; + struct lsa_String *strings; + uint8_t *data = NULL; + uint32_t record_number = 0; + time_t time_written = 0; + + if (argc != 2) { + printf("Usage: %s logname\n", argv[0]); + return NT_STATUS_OK; + } + + status = get_eventlog_handle(cli, mem_ctx, argv[1], &handle); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + strings = talloc_array(mem_ctx, struct lsa_String, num_of_strings); + if (!strings) { + return NT_STATUS_NO_MEMORY; + } + + init_lsa_String(&strings[0], "test event written by rpcclient\n"); + init_lsa_String(&servername, NULL); + + status = dcerpc_eventlog_ReportEventW(b, mem_ctx, + &handle, + time(NULL), + EVENTLOG_INFORMATION_TYPE, + 0, /* event_category */ + 0, /* event_id */ + num_of_strings, + data_size, + &servername, + NULL, /* user_sid */ + &strings, + data, + 0, /* flags */ + &record_number, + &time_written, + &result); + + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + printf("entry: %d written at %s\n", record_number, + http_timestring(talloc_tos(), time_written)); + + done: + dcerpc_eventlog_CloseEventLog(b, mem_ctx, &handle, &result); + + return status; +} + +static NTSTATUS cmd_eventlog_reporteventsource(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status, result; + struct policy_handle handle; + struct dcerpc_binding_handle *b = cli->binding_handle; + + uint16_t num_of_strings = 1; + uint32_t data_size = 0; + struct lsa_String servername, sourcename; + struct lsa_String *strings; + uint8_t *data = NULL; + uint32_t record_number = 0; + time_t time_written = 0; + + if (argc != 2) { + printf("Usage: %s logname\n", argv[0]); + return NT_STATUS_OK; + } + + status = get_eventlog_handle(cli, mem_ctx, argv[1], &handle); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + strings = talloc_array(mem_ctx, struct lsa_String, num_of_strings); + if (!strings) { + return NT_STATUS_NO_MEMORY; + } + + init_lsa_String(&strings[0], "test event written by rpcclient\n"); + init_lsa_String(&servername, NULL); + init_lsa_String(&sourcename, "rpcclient"); + + status = dcerpc_eventlog_ReportEventAndSourceW(b, mem_ctx, + &handle, + time(NULL), + EVENTLOG_INFORMATION_TYPE, + 0, /* event_category */ + 0, /* event_id */ + &sourcename, + num_of_strings, + data_size, + &servername, + NULL, /* user_sid */ + &strings, + data, + 0, /* flags */ + &record_number, + &time_written, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + printf("entry: %d written at %s\n", record_number, + http_timestring(talloc_tos(), time_written)); + + done: + dcerpc_eventlog_CloseEventLog(b, mem_ctx, &handle, &result); + + return status; +} + +static NTSTATUS cmd_eventlog_registerevsource(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status, result; + struct policy_handle log_handle; + struct lsa_String module_name, reg_module_name; + struct eventlog_OpenUnknown0 unknown0; + struct dcerpc_binding_handle *b = cli->binding_handle; + + unknown0.unknown0 = 0x005c; + unknown0.unknown1 = 0x0001; + + if (argc != 2) { + printf("Usage: %s logname\n", argv[0]); + return NT_STATUS_OK; + } + + init_lsa_String(&module_name, "rpcclient"); + init_lsa_String(®_module_name, NULL); + + status = dcerpc_eventlog_RegisterEventSourceW(b, mem_ctx, + &unknown0, + &module_name, + ®_module_name, + 1, /* major_version */ + 1, /* minor_version */ + &log_handle, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + done: + dcerpc_eventlog_DeregisterEventSource(b, mem_ctx, &log_handle, &result); + + return status; +} + +static NTSTATUS cmd_eventlog_backuplog(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status, result; + struct policy_handle handle; + struct lsa_String backup_filename; + const char *tmp; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc != 3) { + printf("Usage: %s logname backupname\n", argv[0]); + return NT_STATUS_OK; + } + + status = get_eventlog_handle(cli, mem_ctx, argv[1], &handle); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + tmp = talloc_asprintf(mem_ctx, "\\??\\%s", argv[2]); + if (!tmp) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + init_lsa_String(&backup_filename, tmp); + + status = dcerpc_eventlog_BackupEventLogW(b, mem_ctx, + &handle, + &backup_filename, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + done: + dcerpc_eventlog_CloseEventLog(b, mem_ctx, &handle, &result); + + return status; +} + +static NTSTATUS cmd_eventlog_loginfo(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status, result; + struct policy_handle handle; + uint8_t *buffer = NULL; + uint32_t buf_size = 0; + uint32_t bytes_needed = 0; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc != 2) { + printf("Usage: %s logname\n", argv[0]); + return NT_STATUS_OK; + } + + status = get_eventlog_handle(cli, mem_ctx, argv[1], &handle); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + buffer = talloc_array(mem_ctx, uint8_t, bytes_needed); + if (buffer == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + status = dcerpc_eventlog_GetLogInformation(b, mem_ctx, + &handle, + 0, /* level */ + buffer, + buf_size, + &bytes_needed, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result) && + !NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)) { + goto done; + } + + buf_size = bytes_needed; + buffer = talloc_realloc(mem_ctx, buffer, uint8_t, bytes_needed); + if (buffer == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + status = dcerpc_eventlog_GetLogInformation(b, mem_ctx, + &handle, + 0, /* level */ + buffer, + buf_size, + &bytes_needed, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + done: + dcerpc_eventlog_CloseEventLog(b, mem_ctx, &handle, &result); + + return status; +} + + +struct cmd_set eventlog_commands[] = { + { + .name = "EVENTLOG", + }, + { + .name = "eventlog_readlog", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_eventlog_readlog, + .wfn = NULL, + .table = &ndr_table_eventlog, + .rpc_pipe = NULL, + .description = "Read Eventlog", + .usage = "", + }, + { + .name = "eventlog_numrecord", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_eventlog_numrecords, + .wfn = NULL, + .table = &ndr_table_eventlog, + .rpc_pipe = NULL, + .description = "Get number of records", + .usage = "", + }, + { + .name = "eventlog_oldestrecord", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_eventlog_oldestrecord, + .wfn = NULL, + .table = &ndr_table_eventlog, + .rpc_pipe = NULL, + .description = "Get oldest record", + .usage = "", + }, + { + .name = "eventlog_reportevent", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_eventlog_reportevent, + .wfn = NULL, + .table = &ndr_table_eventlog, + .rpc_pipe = NULL, + .description = "Report event", + .usage = "", + }, + { + .name = "eventlog_reporteventsource", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_eventlog_reporteventsource, + .wfn = NULL, + .table = &ndr_table_eventlog, + .rpc_pipe = NULL, + .description = "Report event and source", + .usage = "", + }, + { + .name = "eventlog_registerevsource", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_eventlog_registerevsource, + .wfn = NULL, + .table = &ndr_table_eventlog, + .rpc_pipe = NULL, + .description = "Register event source", + .usage = "", + }, + { + .name = "eventlog_backuplog", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_eventlog_backuplog, + .wfn = NULL, + .table = &ndr_table_eventlog, + .rpc_pipe = NULL, + .description = "Backup Eventlog File", + .usage = "", + }, + { + .name = "eventlog_loginfo", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_eventlog_loginfo, + .wfn = NULL, + .table = &ndr_table_eventlog, + .rpc_pipe = NULL, + .description = "Get Eventlog Information", + .usage = "", + }, + { + .name = NULL, + }, +}; diff --git a/source3/rpcclient/cmd_fss.c b/source3/rpcclient/cmd_fss.c new file mode 100644 index 0000000..1d7883e --- /dev/null +++ b/source3/rpcclient/cmd_fss.c @@ -0,0 +1,759 @@ +/* + * Unix SMB/CIFS implementation. + * + * File Server Remote VSS Protocol (FSRVP) client + * + * Copyright (C) David Disseldorp 2012 + * + * 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" +#include "../librpc/gen_ndr/ndr_fsrvp.h" +#include "../librpc/gen_ndr/ndr_fsrvp_c.h" +#include "../libcli/util/hresult.h" + +static const struct { + uint32_t error_code; + const char *error_str; +} fss_errors[] = { + { + FSRVP_E_BAD_STATE, + "A method call was invalid because of the state of the server." + }, + { + FSRVP_E_SHADOW_COPY_SET_IN_PROGRESS, + "A call was made to either \'SetContext\' or \'StartShadowCopySet\' while the creation of another shadow copy set is in progress." + }, + { + FSRVP_E_NOT_SUPPORTED, + "The file store which contains the share to be shadow copied is not supported by the server." + }, + { + FSRVP_E_WAIT_TIMEOUT, + "The wait for a shadow copy commit or expose operation has timed out." + }, + { + FSRVP_E_WAIT_FAILED, + "The wait for a shadow copy commit expose operation has failed." + }, + { + FSRVP_E_OBJECT_NOT_FOUND, + "The specified object does not exist." + }, + { + FSRVP_E_UNSUPPORTED_CONTEXT, + "The specified context value is invalid." + }, + { + FSRVP_E_SHADOWCOPYSET_ID_MISMATCH, + "The provided ShadowCopySetId does not exist." + }, +}; + +struct fss_context_map { + uint32_t ctx_val; + const char *ctx_str; + const char *ctx_desc; +}; +struct fss_context_map ctx_map[] = { + { + .ctx_val = FSRVP_CTX_BACKUP, + .ctx_str = "backup", + .ctx_desc = "auto-release, non-persistent shadow-copy.", + }, + { + .ctx_val = FSRVP_CTX_FILE_SHARE_BACKUP, + .ctx_str = "file_share_backup", + .ctx_desc = "auto-release, non-persistent shadow-copy created " + "without writer involvement.", + }, + { + .ctx_val = FSRVP_CTX_NAS_ROLLBACK, + .ctx_str = "nas_rollback", + .ctx_desc = "non-auto-release, persistent shadow-copy created " + "without writer involvement.", + }, + { + .ctx_val = FSRVP_CTX_APP_ROLLBACK, + .ctx_str = "app_rollback", + .ctx_desc = "non-auto-release, persistent shadow-copy.", + }, + { 0, NULL, NULL }, +}; + +static const char *get_error_str(uint32_t code) +{ + static const char *default_err = "Unknown Error"; + const char *result = default_err; + int i; + for (i = 0; i < ARRAY_SIZE(fss_errors); ++i) { + if (code == fss_errors[i].error_code) { + result = fss_errors[i].error_str; + break; + } + } + /* error isn't specific fsrvp one, check hresult errors */ + if (result == default_err) { + const char *hres_err = hresult_errstr_const(HRES_ERROR(code)); + if (hres_err) { + result = hres_err; + } + } + return result; +}; + +static bool map_fss_ctx_str(const char *ctx_str, + uint32_t *ctx_val) +{ + int i; + + for (i = 0; ctx_map[i].ctx_str != NULL; i++) { + if (!strcmp(ctx_map[i].ctx_str, ctx_str)) { + *ctx_val = ctx_map[i].ctx_val; + return true; + } + } + return false; +} + +static void cmd_fss_is_path_sup_usage(const char *script_name) +{ + printf("usage: %s [share_name]\n", script_name); +} + +static NTSTATUS cmd_fss_is_path_sup(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status; + struct fss_IsPathSupported r; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc != 2) { + cmd_fss_is_path_sup_usage(argv[0]); + return NT_STATUS_UNSUCCESSFUL; + } + + ZERO_STRUCT(r); + r.in.ShareName = talloc_asprintf(mem_ctx, "%s\\%s\\", + cli->srv_name_slash, argv[1]); + if (r.in.ShareName == NULL) { + return NT_STATUS_NO_MEMORY; + } + + status = dcerpc_fss_IsPathSupported_r(b, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("IsPathSupported failed with UNC %s\n", + r.in.ShareName)); + return NT_STATUS_UNSUCCESSFUL; + } else if (r.out.result) { + DEBUG(0, ("failed IsPathSupported response: 0x%x - \"%s\"\n", + r.out.result, get_error_str(r.out.result))); + return NT_STATUS_UNSUCCESSFUL; + } + printf("UNC %s %s shadow copy requests\n", r.in.ShareName, + *r.out.SupportedByThisProvider ? "supports" : "does not support"); + + return NT_STATUS_OK; +} + +static void cmd_fss_get_sup_version_usage(const char *script_name) +{ + printf("usage: %s\n", script_name); +} + +static NTSTATUS cmd_fss_get_sup_version(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status; + struct fss_GetSupportedVersion r; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc != 1) { + cmd_fss_get_sup_version_usage(argv[0]); + return NT_STATUS_UNSUCCESSFUL; + } + + ZERO_STRUCT(r); + status = dcerpc_fss_GetSupportedVersion_r(b, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status) || (r.out.result != 0)) { + DEBUG(0, ("GetSupportedVersion failed: %s result: 0x%x\n", + nt_errstr(status), r.out.result)); + return NT_STATUS_UNSUCCESSFUL; + } + printf("server %s supports FSRVP versions from %u to %u\n", + cli->desthost, *r.out.MinVersion, *r.out.MaxVersion); + + return NT_STATUS_OK; +} + +static void cmd_fss_create_expose_usage(const char *script_name) +{ + int i; + + printf("usage: %s [fss_context] [ro|rw] [share1] <share2> ...\n" + "[fss_context] values:\n", script_name); + for (i = 0; ctx_map[i].ctx_str != NULL; i++) { + printf("\t%s: %s\n", ctx_map[i].ctx_str, ctx_map[i].ctx_desc); + } +} + +static NTSTATUS cmd_fss_create_expose_parse(TALLOC_CTX *mem_ctx, int argc, + const char **argv, + const char *desthost, + uint32_t *fss_ctx_val, + int *num_maps, + struct fssagent_share_mapping_1 **maps) +{ + int num_non_share_args = 3; + int num_share_args; + int i; + struct fssagent_share_mapping_1 *map_array; + + if (argc < 4) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (!map_fss_ctx_str(argv[1], fss_ctx_val)) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (!strcmp(argv[2], "rw")) { + /* shadow-copy is created as read-write */ + *fss_ctx_val |= ATTR_AUTO_RECOVERY; + } else if (strcmp(argv[2], "ro")) { + return NT_STATUS_INVALID_PARAMETER; + } + + num_share_args = argc - num_non_share_args; + map_array = talloc_array(mem_ctx, struct fssagent_share_mapping_1, + num_share_args); + if (map_array == NULL) { + return NT_STATUS_NO_MEMORY; + } + + for (i = 0; i < num_share_args; i++) { + /* + * A trailing slash should to be present in the request UNC, + * otherwise Windows Server 2012 FSRVP servers don't append + * a '$' to exposed hidden share shadow-copies. E.g. + * AddToShadowCopySet(UNC=\\server\hidden$) + * CommitShadowCopySet() + * ExposeShadowCopySet() + * -> new share = \\server\hidden$@{ShadowCopy.ShadowCopyId} + * But... + * AddToShadowCopySet(UNC=\\server\hidden$\) + * CommitShadowCopySet() + * ExposeShadowCopySet() + * -> new share = \\server\hidden$@{ShadowCopy.ShadowCopyId}$ + */ + map_array[i].ShareNameUNC = talloc_asprintf(mem_ctx, + "\\\\%s\\%s\\", + desthost, + argv[i + num_non_share_args]); + if (map_array[i].ShareNameUNC == NULL) { + return NT_STATUS_NO_MEMORY; + } + } + *num_maps = num_share_args; + *maps = map_array; + + return NT_STATUS_OK; +} + +static NTSTATUS cmd_fss_abort(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *b, + struct GUID *sc_set_id) +{ + NTSTATUS status; + struct fss_AbortShadowCopySet r_scset_abort; + + ZERO_STRUCT(r_scset_abort); + r_scset_abort.in.ShadowCopySetId = *sc_set_id; + status = dcerpc_fss_AbortShadowCopySet_r(b, mem_ctx, &r_scset_abort); + if (!NT_STATUS_IS_OK(status) || (r_scset_abort.out.result != 0)) { + DEBUG(0, ("AbortShadowCopySet failed: %s result: 0x%x\n", + nt_errstr(status), r_scset_abort.out.result)); + return NT_STATUS_UNSUCCESSFUL; + } + return NT_STATUS_OK; +} + +static NTSTATUS cmd_fss_create_expose(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status; + struct fss_GetSupportedVersion r_version_get; + struct fss_SetContext r_context_set; + struct fss_StartShadowCopySet r_scset_start; + struct fss_PrepareShadowCopySet r_scset_prep; + struct fss_CommitShadowCopySet r_scset_commit; + struct fss_ExposeShadowCopySet r_scset_expose; + struct dcerpc_binding_handle *b = cli->binding_handle; + time_t start_time; + TALLOC_CTX *tmp_ctx; + uint32_t fss_ctx_val; + int num_maps; + struct fssagent_share_mapping_1 *req_maps; + int i; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + return NT_STATUS_NO_MEMORY; + } + + status = cmd_fss_create_expose_parse(tmp_ctx, argc, argv, cli->desthost, + &fss_ctx_val, &num_maps, &req_maps); + if (!NT_STATUS_IS_OK(status)) { + cmd_fss_create_expose_usage(argv[0]); + goto err_out; + } + + /* + * PrepareShadowCopySet & CommitShadowCopySet often exceed the default + * 60 second dcerpc request timeout against Windows Server "8" Beta. + * ACHTUNG! dcerpc_binding_handle_set_timeout() value is interpreted as + * seconds on a source4 transport and as msecs here. + */ + dcerpc_binding_handle_set_timeout(b, 240 * 1000); + + for (i = 0; i < num_maps; i++) { + struct fss_IsPathSupported r_pathsupport_get; + r_pathsupport_get.in.ShareName = req_maps[i].ShareNameUNC; + status = dcerpc_fss_IsPathSupported_r(b, tmp_ctx, &r_pathsupport_get); + if (!NT_STATUS_IS_OK(status) || (r_pathsupport_get.out.result != 0)) { + DEBUG(0, ("IsPathSupported failed: %s result: 0x%x\n", + nt_errstr(status), r_pathsupport_get.out.result)); + goto err_out; + } + if (!r_pathsupport_get.out.SupportedByThisProvider) { + printf("path %s does not supported shadow-copies\n", + req_maps[i].ShareNameUNC); + status = NT_STATUS_NOT_SUPPORTED; + goto err_out; + } + } + + ZERO_STRUCT(r_version_get); + status = dcerpc_fss_GetSupportedVersion_r(b, tmp_ctx, &r_version_get); + if (!NT_STATUS_IS_OK(status) || (r_version_get.out.result != 0)) { + DEBUG(0, ("GetSupportedVersion failed: %s result: 0x%x\n", + nt_errstr(status), r_version_get.out.result)); + goto err_out; + } + + ZERO_STRUCT(r_context_set); + r_context_set.in.Context = fss_ctx_val; + status = dcerpc_fss_SetContext_r(b, tmp_ctx, &r_context_set); + if (!NT_STATUS_IS_OK(status) || (r_context_set.out.result != 0)) { + DEBUG(0, ("SetContext failed: %s result: 0x%x\n", + nt_errstr(status), r_context_set.out.result)); + goto err_out; + } + + ZERO_STRUCT(r_scset_start); + r_scset_start.in.ClientShadowCopySetId = GUID_random(); + status = dcerpc_fss_StartShadowCopySet_r(b, tmp_ctx, &r_scset_start); + if (!NT_STATUS_IS_OK(status) || (r_scset_start.out.result != 0)) { + DEBUG(0, ("StartShadowCopySet failed: %s result: 0x%x\n", + nt_errstr(status), r_scset_start.out.result)); + goto err_out; + } + printf("%s: shadow-copy set created\n", + GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId)); + + for (i = 0; i < num_maps; i++) { + struct fss_AddToShadowCopySet r_scset_add; + r_scset_add.in.ClientShadowCopyId = GUID_random(); + r_scset_add.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId; + r_scset_add.in.ShareName = req_maps[i].ShareNameUNC; + status = dcerpc_fss_AddToShadowCopySet_r(b, tmp_ctx, &r_scset_add); + if (!NT_STATUS_IS_OK(status) || (r_scset_add.out.result != 0)) { + DEBUG(0, ("AddToShadowCopySet failed: %s result: 0x%x\n", + nt_errstr(status), r_scset_add.out.result)); + goto err_sc_set_abort; + } + printf("%s(%s): %s shadow-copy added to set\n", + GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId), + GUID_string(tmp_ctx, r_scset_add.out.pShadowCopyId), + r_scset_add.in.ShareName); + req_maps[i].ShadowCopySetId = *r_scset_start.out.pShadowCopySetId; + req_maps[i].ShadowCopyId = *r_scset_add.out.pShadowCopyId; + } + + start_time = time_mono(NULL); + ZERO_STRUCT(r_scset_prep); + r_scset_prep.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId; + r_scset_prep.in.TimeOutInMilliseconds = (240 * 1000); + status = dcerpc_fss_PrepareShadowCopySet_r(b, tmp_ctx, &r_scset_prep); + if (!NT_STATUS_IS_OK(status) || (r_scset_prep.out.result != 0)) { + DEBUG(0, ("PrepareShadowCopySet failed: %s result: 0x%x\n", + nt_errstr(status), r_scset_prep.out.result)); + goto err_sc_set_abort; + } + printf("%s: prepare completed in %llu secs\n", + GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId), + (long long unsigned int)(time_mono(NULL) - start_time)); + + start_time = time_mono(NULL); + ZERO_STRUCT(r_scset_commit); + r_scset_commit.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId; + r_scset_commit.in.TimeOutInMilliseconds = (180 * 1000); /* win8 */ + status = dcerpc_fss_CommitShadowCopySet_r(b, tmp_ctx, &r_scset_commit); + if (!NT_STATUS_IS_OK(status) || (r_scset_commit.out.result != 0)) { + DEBUG(0, ("CommitShadowCopySet failed: %s result: 0x%x\n", + nt_errstr(status), r_scset_commit.out.result)); + goto err_sc_set_abort; + } + printf("%s: commit completed in %llu secs\n", + GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId), + (long long unsigned int)(time_mono(NULL) - start_time)); + + ZERO_STRUCT(r_scset_expose); + r_scset_expose.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId; + r_scset_expose.in.TimeOutInMilliseconds = (120 * 1000); /* win8 */ + status = dcerpc_fss_ExposeShadowCopySet_r(b, tmp_ctx, &r_scset_expose); + if (!NT_STATUS_IS_OK(status) || (r_scset_expose.out.result != 0)) { + DEBUG(0, ("ExposeShadowCopySet failed: %s result: 0x%x\n", + nt_errstr(status), r_scset_expose.out.result)); + goto err_out; + } + + for (i = 0; i < num_maps; i++) { + struct fss_GetShareMapping r_sharemap_get; + struct fssagent_share_mapping_1 *map; + r_sharemap_get.in.ShadowCopyId = req_maps[i].ShadowCopyId; + r_sharemap_get.in.ShadowCopySetId = req_maps[i].ShadowCopySetId; + r_sharemap_get.in.ShareName = req_maps[i].ShareNameUNC; + r_sharemap_get.in.Level = 1; + status = dcerpc_fss_GetShareMapping_r(b, tmp_ctx, &r_sharemap_get); + if (!NT_STATUS_IS_OK(status) || (r_sharemap_get.out.result != 0)) { + DEBUG(0, ("GetShareMapping failed: %s result: 0x%x\n", + nt_errstr(status), r_sharemap_get.out.result)); + goto err_out; + } + map = r_sharemap_get.out.ShareMapping->ShareMapping1; + printf("%s(%s): share %s exposed as a snapshot of %s\n", + GUID_string(tmp_ctx, &map->ShadowCopySetId), + GUID_string(tmp_ctx, &map->ShadowCopyId), + map->ShadowCopyShareName, map->ShareNameUNC); + } + + talloc_free(tmp_ctx); + return NT_STATUS_OK; + +err_sc_set_abort: + cmd_fss_abort(tmp_ctx, b, r_scset_start.out.pShadowCopySetId); +err_out: + talloc_free(tmp_ctx); + return status; +} + +static void cmd_fss_delete_usage(const char *script_name) +{ + printf("usage: %s [base_share] [shadow_copy_set_id] [shadow_copy_id]\n", + script_name); +} + +static NTSTATUS cmd_fss_delete(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + struct fss_DeleteShareMapping r_sharemap_del; + const char *sc_set_id; + const char *sc_id; + NTSTATUS status; + TALLOC_CTX *tmp_ctx; + + if (argc < 4) { + cmd_fss_delete_usage(argv[0]); + return NT_STATUS_UNSUCCESSFUL; + } + sc_set_id = argv[2]; + sc_id = argv[3]; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + return NT_STATUS_NO_MEMORY; + } + + ZERO_STRUCT(r_sharemap_del); + r_sharemap_del.in.ShareName = talloc_asprintf(tmp_ctx, "\\\\%s\\%s\\", + cli->desthost, argv[1]); + if (r_sharemap_del.in.ShareName == NULL) { + status = NT_STATUS_NO_MEMORY; + goto err_out; + } + status = GUID_from_string(sc_set_id, &r_sharemap_del.in.ShadowCopySetId); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Invalid shadow_copy_set_id parameter\n")); + goto err_out; + } + status = GUID_from_string(sc_id, &r_sharemap_del.in.ShadowCopyId); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Invalid shadow_copy_id parameter\n")); + goto err_out; + } + status = dcerpc_fss_DeleteShareMapping_r(b, tmp_ctx, &r_sharemap_del); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("DeleteShareMapping failed\n")); + goto err_out; + } else if (r_sharemap_del.out.result != 0) { + DEBUG(0, ("failed DeleteShareMapping response: 0x%x\n", + r_sharemap_del.out.result)); + status = NT_STATUS_UNSUCCESSFUL; + goto err_out; + } + + printf("%s(%s): %s shadow-copy deleted\n", + sc_set_id, sc_id, r_sharemap_del.in.ShareName); + +err_out: + talloc_free(tmp_ctx); + return status; +} + +static void cmd_fss_is_shadow_copied_usage(const char *script_name) +{ + printf("usage: %s [share_name]\n", script_name); +} + +static NTSTATUS cmd_fss_is_shadow_copied(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status; + struct fss_IsPathShadowCopied r; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc != 2) { + cmd_fss_is_shadow_copied_usage(argv[0]); + return NT_STATUS_UNSUCCESSFUL; + } + + ZERO_STRUCT(r); + r.in.ShareName = talloc_asprintf(mem_ctx, "%s\\%s\\", + cli->srv_name_slash, argv[1]); + if (r.in.ShareName == NULL) { + return NT_STATUS_NO_MEMORY; + } + + status = dcerpc_fss_IsPathShadowCopied_r(b, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("IsPathShadowCopied failed with UNC %s\n", + r.in.ShareName)); + return NT_STATUS_UNSUCCESSFUL; + } else if (r.out.result) { + DEBUG(0, ("failed IsPathShadowCopied response: 0x%x\n", + r.out.result)); + return NT_STATUS_UNSUCCESSFUL; + } + printf("UNC %s %s an associated shadow-copy with compatibility 0x%x\n", + r.in.ShareName, + *r.out.ShadowCopyPresent ? "has" : "does not have", + *r.out.ShadowCopyCompatibility); + + return NT_STATUS_OK; +} + +static void cmd_fss_get_mapping_usage(const char *script_name) +{ + printf("usage: %s [base_share] [shadow_copy_set_id] [shadow_copy_id]\n", + script_name); +} + +static NTSTATUS cmd_fss_get_mapping(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + struct fss_GetShareMapping r_sharemap_get; + const char *sc_set_id; + const char *sc_id; + struct fssagent_share_mapping_1 *map; + NTSTATUS status; + TALLOC_CTX *tmp_ctx; + + if (argc < 4) { + cmd_fss_get_mapping_usage(argv[0]); + return NT_STATUS_UNSUCCESSFUL; + } + sc_set_id = argv[2]; + sc_id = argv[3]; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + return NT_STATUS_NO_MEMORY; + } + + ZERO_STRUCT(r_sharemap_get); + r_sharemap_get.in.ShareName = talloc_asprintf(tmp_ctx, "\\\\%s\\%s\\", + cli->desthost, argv[1]); + if (r_sharemap_get.in.ShareName == NULL) { + status = NT_STATUS_NO_MEMORY; + goto err_out; + } + status = GUID_from_string(sc_set_id, &r_sharemap_get.in.ShadowCopySetId); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Invalid shadow_copy_set_id parameter\n")); + goto err_out; + } + status = GUID_from_string(sc_id, &r_sharemap_get.in.ShadowCopyId); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Invalid shadow_copy_id parameter\n")); + goto err_out; + } + r_sharemap_get.in.Level = 1; + status = dcerpc_fss_GetShareMapping_r(b, tmp_ctx, &r_sharemap_get); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("GetShareMapping failed\n")); + goto err_out; + } else if (r_sharemap_get.out.result != 0) { + DEBUG(0, ("failed GetShareMapping response: 0x%x\n", + r_sharemap_get.out.result)); + status = NT_STATUS_UNSUCCESSFUL; + goto err_out; + } + + map = r_sharemap_get.out.ShareMapping->ShareMapping1; + printf("%s(%s): share %s is a shadow-copy of %s at %s\n", + GUID_string(tmp_ctx, &map->ShadowCopySetId), + GUID_string(tmp_ctx, &map->ShadowCopyId), + map->ShadowCopyShareName, map->ShareNameUNC, + nt_time_string(tmp_ctx, map->tstamp)); + +err_out: + talloc_free(tmp_ctx); + return status; +} + +static void cmd_fss_recov_complete_usage(const char *script_name) +{ + printf("usage: %s [shadow_copy_set_id]\n", script_name); +} + +static NTSTATUS cmd_fss_recov_complete(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status; + struct fss_RecoveryCompleteShadowCopySet r; + struct dcerpc_binding_handle *b = cli->binding_handle; + const char *sc_set_id; + + if (argc != 2) { + cmd_fss_recov_complete_usage(argv[0]); + return NT_STATUS_UNSUCCESSFUL; + } + sc_set_id = argv[1]; + + ZERO_STRUCT(r); + status = GUID_from_string(sc_set_id, &r.in.ShadowCopySetId); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Invalid shadow_copy_set_id\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + status = dcerpc_fss_RecoveryCompleteShadowCopySet_r(b, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status) || (r.out.result != 0)) { + DEBUG(0, ("RecoveryCompleteShadowCopySet failed: %s " + "result: 0x%x\n", nt_errstr(status), r.out.result)); + return status; + } + printf("%s: shadow-copy set marked recovery complete\n", sc_set_id); + + return NT_STATUS_OK; +} + +/* List of commands exported by this module */ +struct cmd_set fss_commands[] = { + + { + .name = "FSRVP", + }, + + { + .name = "fss_is_path_sup", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_fss_is_path_sup, + .table = &ndr_table_FileServerVssAgent, + .rpc_pipe = NULL, + .description = "Check whether a share supports shadow-copy " + "requests", + .usage = "", + }, + { + .name = "fss_get_sup_version", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_fss_get_sup_version, + .table = &ndr_table_FileServerVssAgent, + .rpc_pipe = NULL, + .description = "Get supported FSRVP version from server", + .usage = "", + }, + { + .name = "fss_create_expose", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_fss_create_expose, + .table = &ndr_table_FileServerVssAgent, + .rpc_pipe = NULL, + .description = "Request shadow-copy creation and exposure", + .usage = "", + }, + { + .name = "fss_delete", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_fss_delete, + .table = &ndr_table_FileServerVssAgent, + .rpc_pipe = NULL, + .description = "Request shadow-copy share deletion", + .usage = "", + }, + { + .name = "fss_has_shadow_copy", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_fss_is_shadow_copied, + .table = &ndr_table_FileServerVssAgent, + .rpc_pipe = NULL, + .description = "Check for an associated share shadow-copy", + .usage = "", + }, + { + .name = "fss_get_mapping", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_fss_get_mapping, + .table = &ndr_table_FileServerVssAgent, + .rpc_pipe = NULL, + .description = "Get shadow-copy share mapping information", + .usage = "", + }, + { + .name = "fss_recovery_complete", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_fss_recov_complete, + .table = &ndr_table_FileServerVssAgent, + .rpc_pipe = NULL, + .description = "Flag read-write snapshot as recovery complete, " + "allowing further shadow-copy requests", + .usage = "", + }, + { + .name = NULL, + }, +}; diff --git a/source3/rpcclient/cmd_iremotewinspool.c b/source3/rpcclient/cmd_iremotewinspool.c new file mode 100644 index 0000000..5a8096b --- /dev/null +++ b/source3/rpcclient/cmd_iremotewinspool.c @@ -0,0 +1,195 @@ +/* + Unix SMB/CIFS implementation. + RPC pipe client + + Copyright (C) 2013-2016 Guenther Deschner <gd@samba.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 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" +#include "../librpc/gen_ndr/ndr_winspool.h" +#include "libsmb/libsmb.h" +#include "auth/gensec/gensec.h" +#include "auth/credentials/credentials.h" +#include "rpc_client/init_spoolss.h" + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_iremotewinspool_async_open_printer(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS status; + WERROR werror; + struct policy_handle hnd; + struct spoolss_DevmodeContainer devmode_ctr; + struct spoolss_UserLevelCtr client_info_ctr; + struct spoolss_UserLevel1 level1; + uint32_t access_mask = PRINTER_ALL_ACCESS; + struct dcerpc_binding_handle *b = cli->binding_handle; + struct GUID uuid; + struct winspool_AsyncOpenPrinter r; + struct cli_credentials *creds = gensec_get_credentials(cli->auth->auth_ctx); + + if (argc < 2) { + printf("Usage: %s <printername> [access_mask]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 3) { + sscanf(argv[2], "%x", &access_mask); + } + + status = GUID_from_string(IREMOTEWINSPOOL_OBJECT_GUID, &uuid); + if (!NT_STATUS_IS_OK(status)) { + return WERR_NOT_ENOUGH_MEMORY; + } + + ZERO_STRUCT(devmode_ctr); + + werror = spoolss_init_spoolss_UserLevel1(mem_ctx, + cli_credentials_get_username(creds), + &level1); + if (!W_ERROR_IS_OK(werror)) { + return werror; + } + + level1.processor = PROCESSOR_ARCHITECTURE_AMD64; + + client_info_ctr.level = 1; + client_info_ctr.user_info.level1 = &level1; + + r.in.pPrinterName = argv[1]; + r.in.pDatatype = "RAW"; + r.in.pDevModeContainer = &devmode_ctr; + r.in.AccessRequired = access_mask; + r.in.pClientInfo = &client_info_ctr; + r.out.pHandle = &hnd; + + /* Open the printer handle */ + + status = dcerpc_binding_handle_call(b, + &uuid, + &ndr_table_iremotewinspool, + NDR_WINSPOOL_ASYNCOPENPRINTER, + mem_ctx, + &r); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(r.out.result)) { + return r.out.result; + } + + printf("Printer %s opened successfully\n", argv[1]); + + return WERR_OK; +} + +static WERROR cmd_iremotewinspool_async_core_printer_driver_installed(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS status; + struct dcerpc_binding_handle *b = cli->binding_handle; + struct GUID uuid, core_printer_driver_guid; + struct winspool_AsyncCorePrinterDriverInstalled r; + const char *guid_str = SPOOLSS_CORE_PRINT_PACKAGE_FILES_XPSDRV; + const char *architecture = SPOOLSS_ARCHITECTURE_x64; + int32_t pbDriverInstalled; + + if (argc > 4) { + printf("Usage: %s <CORE_PRINTER_DRIVER_GUID> [architecture]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + guid_str = argv[1]; + } + + if (argc >= 3) { + architecture = argv[2]; + } + + status = GUID_from_string(IREMOTEWINSPOOL_OBJECT_GUID, &uuid); + if (!NT_STATUS_IS_OK(status)) { + return WERR_NOT_ENOUGH_MEMORY; + } + status = GUID_from_string(guid_str, &core_printer_driver_guid); + if (!NT_STATUS_IS_OK(status)) { + return WERR_NOT_ENOUGH_MEMORY; + } + + r.in.pszServer = NULL; + r.in.pszEnvironment = architecture; + r.in.CoreDriverGUID = core_printer_driver_guid; + r.in.ftDriverDate = 0; + r.in.dwlDriverVersion = 0; + r.out.pbDriverInstalled = &pbDriverInstalled; + + status = dcerpc_binding_handle_call(b, + &uuid, + &ndr_table_iremotewinspool, + NDR_WINSPOOL_ASYNCCOREPRINTERDRIVERINSTALLED, + mem_ctx, + &r); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + if (!HRES_IS_OK(r.out.result)) { + return W_ERROR(WIN32_FROM_HRESULT(r.out.result)); + } + + printf("Core Printer Driver %s is%s installed\n", guid_str, + *r.out.pbDriverInstalled ? "" : " NOT"); + + return WERR_OK; +} + +/* List of commands exported by this module */ +struct cmd_set iremotewinspool_commands[] = { + + { + .name = "IRemoteWinspool", + }, + + { + .name = "winspool_AsyncOpenPrinter", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_iremotewinspool_async_open_printer, + .table = &ndr_table_iremotewinspool, + .rpc_pipe = NULL, + .description = "Open printer handle", + .usage = "", + }, + + { + .name = "winspool_AsyncCorePrinterDriverInstalled", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_iremotewinspool_async_core_printer_driver_installed, + .table = &ndr_table_iremotewinspool, + .rpc_pipe = NULL, + .description = "Query Core Printer Driver Installed", + .usage = "", + }, + + { + .name = NULL, + }, +}; diff --git a/source3/rpcclient/cmd_lsarpc.c b/source3/rpcclient/cmd_lsarpc.c new file mode 100644 index 0000000..5374c9a --- /dev/null +++ b/source3/rpcclient/cmd_lsarpc.c @@ -0,0 +1,3000 @@ +/* + 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" +#include "../libcli/auth/libcli_auth.h" +#include "../librpc/gen_ndr/ndr_lsa.h" +#include "../librpc/gen_ndr/ndr_lsa_c.h" +#include "rpc_client/cli_lsarpc.h" +#include "rpc_client/init_lsa.h" +#include "../libcli/security/security.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, + struct dom_sid *sid, + const char *name) +{ + struct policy_handle pol; + enum lsa_SidType *sid_types; + NTSTATUS status, result; + struct dom_sid *sids; + struct dcerpc_binding_handle *b = cli->binding_handle; + + /* maybe its a raw SID */ + if (strncmp(name, "S-", 2) == 0 && + string_to_sid(sid, name)) { + return NT_STATUS_OK; + } + + status = rpccli_lsa_open_policy(cli, mem_ctx, True, + SEC_FLAG_MAXIMUM_ALLOWED, + &pol); + if (!NT_STATUS_IS_OK(status)) + goto done; + + status = rpccli_lsa_lookup_names(cli, mem_ctx, &pol, 1, &name, NULL, 1, &sids, &sid_types); + if (!NT_STATUS_IS_OK(status)) + goto done; + + dcerpc_lsa_Close(b, mem_ctx, &pol, &result); + + *sid = sids[0]; + +done: + return status; +} + +static void display_query_info_1(struct lsa_AuditLogInfo *r) +{ + d_printf("percent_full:\t%d\n", r->percent_full); + d_printf("maximum_log_size:\t%d\n", r->maximum_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); +} + +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) +{ + struct dom_sid_buf buf; + d_printf("Domain Name: %s\n", r->name.string); + d_printf("Domain Sid: %s\n", dom_sid_str_buf(r->sid, &buf)); +} + +static void display_query_info_5(struct lsa_DomainInfo *r) +{ + struct dom_sid_buf buf; + d_printf("Domain Name: %s\n", r->name.string); + d_printf("Domain Sid: %s\n", dom_sid_str_buf(r->sid, &buf)); +} + +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); +} + +static void display_query_info_12(struct lsa_DnsDomainInfo *r) +{ + struct dom_sid_buf buf; + 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", dom_sid_str_buf(r->sid, &buf)); + d_printf("Domain GUID: %s\n", GUID_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) +{ + struct policy_handle pol; + NTSTATUS status, result; + union lsa_PolicyInformation *info = NULL; + struct dcerpc_binding_handle *b = cli->binding_handle; + + uint32_t 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: { + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + status = dcerpc_lsa_open_policy_fallback( + b, + mem_ctx, + cli->srv_name_slash, + true, + SEC_FLAG_MAXIMUM_ALLOWED, + &out_version, + &out_revision_info, + &pol, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + goto done; + } + + status = dcerpc_lsa_QueryInfoPolicy2(b, mem_ctx, + &pol, + info_class, + &info, + &result); + break; + } + default: + status = rpccli_lsa_open_policy(cli, mem_ctx, True, + SEC_FLAG_MAXIMUM_ALLOWED, + &pol); + + if (!NT_STATUS_IS_OK(status)) + goto done; + + status = dcerpc_lsa_QueryInfoPolicy(b, mem_ctx, + &pol, + info_class, + &info, + &result); + } + + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + status = result; + if (NT_STATUS_IS_OK(result)) { + display_lsa_query_info(info, info_class); + } + + dcerpc_lsa_Close(b, mem_ctx, &pol, &result); + + done: + return status; +} + +/* 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) +{ + struct policy_handle pol; + NTSTATUS status, result; + struct dom_sid *sids; + enum lsa_SidType *types; + int i; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc == 1) { + printf("Usage: %s [name1 [name2 [...]]]\n", argv[0]); + return NT_STATUS_OK; + } + + status = rpccli_lsa_open_policy(cli, mem_ctx, True, + LSA_POLICY_LOOKUP_NAMES, + &pol); + + if (!NT_STATUS_IS_OK(status)) + goto done; + + status = rpccli_lsa_lookup_names(cli, mem_ctx, &pol, argc - 1, + (const char**)(argv + 1), NULL, 1, &sids, &types); + + if (!NT_STATUS_IS_OK(status) && NT_STATUS_V(status) != + NT_STATUS_V(STATUS_SOME_UNMAPPED)) + goto done; + + status = NT_STATUS_OK; + + /* Print results */ + + for (i = 0; i < (argc - 1); i++) { + struct dom_sid_buf sid_str; + printf("%s %s (%s: %d)\n", + argv[i + 1], + dom_sid_str_buf(&sids[i], &sid_str), + sid_type_lookup(types[i]), + types[i]); + } + + dcerpc_lsa_Close(b, mem_ctx, &pol, &result); + + done: + return status; +} + +/* 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) +{ + struct policy_handle pol; + NTSTATUS status, result; + struct dom_sid *sids = NULL; + enum lsa_SidType *types = NULL; + int i, level; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc < 3) { + printf("Usage: %s [level] [name1 [name2 [...]]]\n", argv[0]); + return NT_STATUS_OK; + } + + status = rpccli_lsa_open_policy(cli, mem_ctx, True, + LSA_POLICY_LOOKUP_NAMES, + &pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + level = atoi(argv[1]); + + status = rpccli_lsa_lookup_names(cli, mem_ctx, &pol, argc - 2, + (const char**)(argv + 2), NULL, level, &sids, &types); + + if (!NT_STATUS_IS_OK(status) && NT_STATUS_V(status) != + NT_STATUS_V(STATUS_SOME_UNMAPPED)) + { + goto done; + } + + status = NT_STATUS_OK; + + /* Print results */ + + for (i = 0; i < (argc - 2); i++) { + struct dom_sid_buf sid_str; + printf("%s %s (%s: %d)\n", + argv[i + 2], + dom_sid_str_buf(&sids[i], &sid_str), + sid_type_lookup(types[i]), + types[i]); + } + + dcerpc_lsa_Close(b, mem_ctx, &pol, &result); + + done: + return status; +} + +static NTSTATUS cmd_lsa_lookup_names4(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status, result; + + uint32_t num_names; + struct lsa_String *names; + struct lsa_RefDomainList *domains = NULL; + struct lsa_TransSidArray3 sids; + uint32_t count = 0; + int i; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc == 1) { + printf("Usage: %s [name1 [name2 [...]]]\n", argv[0]); + return NT_STATUS_OK; + } + + ZERO_STRUCT(sids); + + num_names = argc-1; + names = talloc_array(mem_ctx, struct lsa_String, num_names); + NT_STATUS_HAVE_NO_MEMORY(names); + + for (i=0; i < num_names; i++) { + init_lsa_String(&names[i], argv[i+1]); + } + + status = dcerpc_lsa_LookupNames4(b, mem_ctx, + num_names, + names, + &domains, + &sids, + 1, + &count, + 0, + 0, + &result); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + if (!NT_STATUS_IS_OK(result)) { + return result; + } + + if (sids.count != num_names) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + + for (i = 0; i < sids.count; i++) { + struct dom_sid_buf sid_str; + printf("%s %s (%s: %d)\n", + argv[i+1], + dom_sid_str_buf(sids.sids[i].sid, &sid_str), + sid_type_lookup(sids.sids[i].sid_type), + sids.sids[i].sid_type); + } + + return status; +} + +/* 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) +{ + struct policy_handle pol; + NTSTATUS status, result; + struct dom_sid *sids; + char **domains; + char **names; + enum lsa_SidType *types; + int i; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc == 1) { + printf("Usage: %s [sid1 [sid2 [...]]]\n", argv[0]); + return NT_STATUS_OK; + } + + status = rpccli_lsa_open_policy(cli, mem_ctx, True, + LSA_POLICY_LOOKUP_NAMES, + &pol); + + if (!NT_STATUS_IS_OK(status)) + goto done; + + /* Convert arguments to sids */ + + sids = talloc_array(mem_ctx, struct 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])) { + status = NT_STATUS_INVALID_SID; + goto done; + } + + /* Lookup the SIDs */ + + status = rpccli_lsa_lookup_sids(cli, mem_ctx, &pol, argc - 1, sids, + &domains, &names, &types); + + if (!NT_STATUS_IS_OK(status) && NT_STATUS_V(status) != + NT_STATUS_V(STATUS_SOME_UNMAPPED)) + goto done; + + status = NT_STATUS_OK; + + /* Print results */ + + for (i = 0; i < (argc - 1); i++) { + struct dom_sid_buf sid_str; + + dom_sid_str_buf(&sids[i], &sid_str); + if (types[i] == SID_NAME_DOMAIN) { + printf("%s %s (%d)\n", sid_str.buf, + domains[i] ? domains[i] : "*unknown*", + types[i]); + } else { + printf("%s %s\\%s (%d)\n", sid_str.buf, + domains[i] ? domains[i] : "*unknown*", + names[i] ? names[i] : "*unknown*", + types[i]); + } + } + + dcerpc_lsa_Close(b, mem_ctx, &pol, &result); + + done: + return status; +} + +static NTSTATUS cmd_lsa_lookup_sids_level(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + struct policy_handle pol; + NTSTATUS status, result; + struct dom_sid *sids = NULL; + char **domains = NULL; + char **names = NULL; + enum lsa_SidType *types = NULL; + int i, level; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc < 3) { + printf("Usage: %s [level] [sid1 [sid2 [...]]]\n", argv[0]); + return NT_STATUS_OK; + } + + status = rpccli_lsa_open_policy(cli, mem_ctx, True, + LSA_POLICY_LOOKUP_NAMES, + &pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + level = atoi(argv[1]); + + /* Convert arguments to sids */ + + sids = talloc_array(mem_ctx, struct dom_sid, argc - 2); + if (sids == NULL) { + printf("could not allocate memory for %d sids\n", argc - 2); + goto done; + } + + for (i = 0; i < argc - 2; i++) { + if (!string_to_sid(&sids[i], argv[i + 2])) { + status = NT_STATUS_INVALID_SID; + goto done; + } + } + + /* Lookup the SIDs */ + + status = dcerpc_lsa_lookup_sids_generic(cli->binding_handle, + mem_ctx, + &pol, + argc - 2, + sids, + level, + &domains, + &names, + &types, + false, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + status = result; + + if (!NT_STATUS_IS_OK(status) && NT_STATUS_V(status) != + NT_STATUS_V(STATUS_SOME_UNMAPPED)) + { + goto done; + } + + status = NT_STATUS_OK; + + /* Print results */ + + for (i = 0; i < (argc - 2); i++) { + struct dom_sid_buf sid_str; + + dom_sid_str_buf(&sids[i], &sid_str); + if (types[i] == SID_NAME_DOMAIN) { + printf("%s %s (%d)\n", sid_str.buf, + domains[i] ? domains[i] : "*unknown*", + types[i]); + } else { + printf("%s %s\\%s (%d)\n", sid_str.buf, + domains[i] ? domains[i] : "*unknown*", + names[i] ? names[i] : "*unknown*", + types[i]); + } + } + + dcerpc_lsa_Close(b, mem_ctx, &pol, &result); + + done: + return status; +} + +/* Resolve a list of SIDs to a list of names */ + +static NTSTATUS cmd_lsa_lookup_sids3(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result; + int i; + struct lsa_SidArray sids; + struct lsa_RefDomainList *domains = NULL; + struct lsa_TransNameArray2 names; + uint32_t count = 0; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc == 1) { + printf("Usage: %s [sid1 [sid2 [...]]]\n", argv[0]); + return NT_STATUS_OK; + } + + ZERO_STRUCT(names); + + /* Convert arguments to sids */ + + sids.num_sids = argc-1; + sids.sids = talloc_array(mem_ctx, struct lsa_SidPtr, sids.num_sids); + if (!sids.sids) { + printf("could not allocate memory for %d sids\n", sids.num_sids); + goto done; + } + + for (i = 0; i < sids.num_sids; i++) { + sids.sids[i].sid = talloc(sids.sids, struct dom_sid); + if (sids.sids[i].sid == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + if (!string_to_sid(sids.sids[i].sid, argv[i+1])) { + status = NT_STATUS_INVALID_SID; + goto done; + } + } + + /* Lookup the SIDs */ + status = dcerpc_lsa_LookupSids3(b, mem_ctx, + &sids, + &domains, + &names, + 1, + &count, + 0, + 0, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result) && NT_STATUS_V(result) != + NT_STATUS_V(STATUS_SOME_UNMAPPED)) { + status = result; + goto done; + } + + status = NT_STATUS_OK; + + /* Print results */ + + for (i = 0; i < names.count; i++) { + struct dom_sid_buf sid_str; + + if (i >= sids.num_sids) { + break; + } + printf("%s %s (%d)\n", + dom_sid_str_buf(sids.sids[i].sid, &sid_str), + names.names[i].name.string, + names.names[i].sid_type); + } + + done: + return status; +} + + +/* 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) +{ + struct policy_handle pol; + NTSTATUS status, result; + struct lsa_DomainList domain_list; + struct dcerpc_binding_handle *b = cli->binding_handle; + + /* defaults, but may be changed using params */ + uint32_t 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]); + } + + status = rpccli_lsa_open_policy(cli, mem_ctx, True, + LSA_POLICY_VIEW_LOCAL_INFORMATION, + &pol); + + if (!NT_STATUS_IS_OK(status)) + goto done; + + status = STATUS_MORE_ENTRIES; + + while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) { + + /* Lookup list of trusted domains */ + + status = dcerpc_lsa_EnumTrustDom(b, mem_ctx, + &pol, + &enum_ctx, + &domain_list, + max_size, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result) && + !NT_STATUS_EQUAL(result, NT_STATUS_NO_MORE_ENTRIES) && + !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) { + status = result; + goto done; + } + + /* Print results: list of names and sids returned in this + * response. */ + for (i = 0; i < domain_list.count; i++) { + struct dom_sid_buf sid_str; + + printf("%s %s\n", + domain_list.domains[i].name.string ? + domain_list.domains[i].name.string : "*unknown*", + dom_sid_str_buf(domain_list.domains[i].sid, + &sid_str)); + } + } + + dcerpc_lsa_Close(b, mem_ctx, &pol, &result); + done: + return status; +} + +/* Enumerates privileges */ + +static NTSTATUS cmd_lsa_enum_privilege(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct policy_handle pol; + NTSTATUS status, result; + struct lsa_PrivArray priv_array; + struct dcerpc_binding_handle *b = cli->binding_handle; + + uint32_t enum_context=0; + uint32_t 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]); + + status = rpccli_lsa_open_policy(cli, mem_ctx, True, + SEC_FLAG_MAXIMUM_ALLOWED, + &pol); + + if (!NT_STATUS_IS_OK(status)) + goto done; + + status = dcerpc_lsa_EnumPrivs(b, mem_ctx, + &pol, + &enum_context, + &priv_array, + pref_max_length, + &result); + if (!NT_STATUS_IS_OK(status)) + goto done; + if (!NT_STATUS_IS_OK(result)) { + status = 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); + } + + dcerpc_lsa_Close(b, mem_ctx, &pol, &result); + done: + return status; +} + +/* Get privilege name */ + +static NTSTATUS cmd_lsa_get_dispname(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct policy_handle pol; + NTSTATUS status, result; + struct dcerpc_binding_handle *b = cli->binding_handle; + + uint16_t lang_id=0; + uint16_t lang_id_sys=0; + uint16_t 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; + } + + status = rpccli_lsa_open_policy(cli, mem_ctx, True, + SEC_FLAG_MAXIMUM_ALLOWED, + &pol); + + if (!NT_STATUS_IS_OK(status)) + goto done; + + init_lsa_String(&lsa_name, argv[1]); + + status = dcerpc_lsa_LookupPrivDisplayName(b, mem_ctx, + &pol, + &lsa_name, + lang_id, + lang_id_sys, + &description, + &lang_id_desc, + &result); + if (!NT_STATUS_IS_OK(status)) + goto done; + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + /* Print results */ + printf("%s -> %s (language: 0x%x)\n", argv[1], description->string, lang_id_desc); + + dcerpc_lsa_Close(b, mem_ctx, &pol, &result); + done: + return status; +} + +/* Enumerate the LSA SIDS */ + +static NTSTATUS cmd_lsa_enum_sids(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct policy_handle pol; + NTSTATUS status, result; + struct dcerpc_binding_handle *b = cli->binding_handle; + + uint32_t enum_context=0; + uint32_t 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]); + + status = rpccli_lsa_open_policy(cli, mem_ctx, True, + SEC_FLAG_MAXIMUM_ALLOWED, + &pol); + + if (!NT_STATUS_IS_OK(status)) + goto done; + + status = dcerpc_lsa_EnumAccounts(b, mem_ctx, + &pol, + &enum_context, + &sid_array, + pref_max_length, + &result); + if (!NT_STATUS_IS_OK(status)) + goto done; + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + /* Print results */ + printf("found %d SIDs\n\n", sid_array.num_sids); + + for (i = 0; i < sid_array.num_sids; i++) { + struct dom_sid_buf sid_str; + + printf("%s\n", + dom_sid_str_buf(sid_array.sids[i].sid, &sid_str)); + } + + dcerpc_lsa_Close(b, mem_ctx, &pol, &result); + done: + return status; +} + +/* Create a new account */ + +static NTSTATUS cmd_lsa_create_account(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct policy_handle dom_pol; + struct policy_handle user_pol; + NTSTATUS status, result; + uint32_t des_access = 0x000f000f; + struct dcerpc_binding_handle *b = cli->binding_handle; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + struct dom_sid sid; + + if (argc != 2 ) { + printf("Usage: %s SID\n", argv[0]); + return NT_STATUS_OK; + } + + status = name_to_sid(cli, mem_ctx, &sid, argv[1]); + if (!NT_STATUS_IS_OK(status)) + goto done; + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + SEC_FLAG_MAXIMUM_ALLOWED, + &out_version, + &out_revision_info, + &dom_pol, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + goto done; + } + + status = dcerpc_lsa_CreateAccount(b, mem_ctx, + &dom_pol, + &sid, + des_access, + &user_pol, + &result); + if (!NT_STATUS_IS_OK(status)) + goto done; + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + printf("Account for SID %s successfully created\n\n", argv[1]); + status = NT_STATUS_OK; + + dcerpc_lsa_Close(b, mem_ctx, &dom_pol, &result); + done: + return status; +} + + +/* 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) +{ + struct policy_handle dom_pol; + struct policy_handle user_pol; + NTSTATUS status, result; + uint32_t access_desired = 0x000f000f; + struct dom_sid sid; + struct lsa_PrivilegeSet *privs = NULL; + int i; + struct dcerpc_binding_handle *b = cli->binding_handle; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + if (argc != 2 ) { + printf("Usage: %s SID\n", argv[0]); + return NT_STATUS_OK; + } + + status = name_to_sid(cli, mem_ctx, &sid, argv[1]); + if (!NT_STATUS_IS_OK(status)) + goto done; + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + SEC_FLAG_MAXIMUM_ALLOWED, + &out_version, + &out_revision_info, + &dom_pol, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + goto done; + } + + status = dcerpc_lsa_OpenAccount(b, mem_ctx, + &dom_pol, + &sid, + access_desired, + &user_pol, + &result); + if (!NT_STATUS_IS_OK(status)) + goto done; + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = dcerpc_lsa_EnumPrivsAccount(b, mem_ctx, + &user_pol, + &privs, + &result); + if (!NT_STATUS_IS_OK(status)) + goto done; + if (!NT_STATUS_IS_OK(result)) { + status = 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); + } + + dcerpc_lsa_Close(b, mem_ctx, &dom_pol, &result); + done: + return status; +} + + +/* 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) +{ + struct policy_handle dom_pol; + NTSTATUS status, result; + struct dom_sid sid; + struct dom_sid_buf buf; + struct lsa_RightSet rights; + struct dcerpc_binding_handle *b = cli->binding_handle; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + int i; + + if (argc != 2 ) { + printf("Usage: %s SID\n", argv[0]); + return NT_STATUS_OK; + } + + status = name_to_sid(cli, mem_ctx, &sid, argv[1]); + if (!NT_STATUS_IS_OK(status)) + goto done; + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + SEC_FLAG_MAXIMUM_ALLOWED, + &out_version, + &out_revision_info, + &dom_pol, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + goto done; + } + + status = dcerpc_lsa_EnumAccountRights(b, mem_ctx, + &dom_pol, + &sid, + &rights, + &result); + if (!NT_STATUS_IS_OK(status)) + goto done; + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + printf("found %d privileges for SID %s\n", rights.count, + dom_sid_str_buf(&sid, &buf)); + + for (i = 0; i < rights.count; i++) { + printf("\t%s\n", rights.names[i].string); + } + + dcerpc_lsa_Close(b, mem_ctx, &dom_pol, &result); + done: + return status; +} + + +/* 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) +{ + struct policy_handle dom_pol; + NTSTATUS status, result; + struct lsa_RightSet rights; + struct dom_sid sid; + int i; + struct dcerpc_binding_handle *b = cli->binding_handle; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + if (argc < 3 ) { + printf("Usage: %s SID [rights...]\n", argv[0]); + return NT_STATUS_OK; + } + + status = name_to_sid(cli, mem_ctx, &sid, argv[1]); + if (!NT_STATUS_IS_OK(status)) + goto done; + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + SEC_FLAG_MAXIMUM_ALLOWED, + &out_version, + &out_revision_info, + &dom_pol, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + 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]); + } + + status = dcerpc_lsa_AddAccountRights(b, mem_ctx, + &dom_pol, + &sid, + &rights, + &result); + if (!NT_STATUS_IS_OK(status)) + goto done; + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + dcerpc_lsa_Close(b, mem_ctx, &dom_pol, &result); + done: + return status; +} + + +/* 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) +{ + struct policy_handle dom_pol; + NTSTATUS status, result; + struct lsa_RightSet rights; + struct dom_sid sid; + int i; + struct dcerpc_binding_handle *b = cli->binding_handle; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + if (argc < 3 ) { + printf("Usage: %s SID [rights...]\n", argv[0]); + return NT_STATUS_OK; + } + + status = name_to_sid(cli, mem_ctx, &sid, argv[1]); + if (!NT_STATUS_IS_OK(status)) + goto done; + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + SEC_FLAG_MAXIMUM_ALLOWED, + &out_version, + &out_revision_info, + &dom_pol, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + 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]); + } + + status = dcerpc_lsa_RemoveAccountRights(b, mem_ctx, + &dom_pol, + &sid, + false, + &rights, + &result); + if (!NT_STATUS_IS_OK(status)) + goto done; + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + dcerpc_lsa_Close(b, mem_ctx, &dom_pol, &result); + + done: + return status; +} + + +/* 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) +{ + struct policy_handle pol; + NTSTATUS status, result; + struct lsa_LUID luid; + struct lsa_String name; + struct dcerpc_binding_handle *b = cli->binding_handle; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + if (argc != 2 ) { + printf("Usage: %s name\n", argv[0]); + return NT_STATUS_OK; + } + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + SEC_FLAG_MAXIMUM_ALLOWED, + &out_version, + &out_revision_info, + &pol, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + goto done; + } + + init_lsa_String(&name, argv[1]); + + status = dcerpc_lsa_LookupPrivValue(b, mem_ctx, + &pol, + &name, + &luid, + &result); + if (!NT_STATUS_IS_OK(status)) + goto done; + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + /* Print results */ + + printf("%u:%u (0x%x:0x%x)\n", luid.high, luid.low, luid.high, luid.low); + + dcerpc_lsa_Close(b, mem_ctx, &pol, &result); + done: + return status; +} + +/* Query LSA security object */ + +static NTSTATUS cmd_lsa_query_secobj(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct policy_handle pol; + NTSTATUS status, result; + struct sec_desc_buf *sdb; + uint32_t sec_info = SECINFO_DACL; + struct dcerpc_binding_handle *b = cli->binding_handle; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + if (argc < 1 || argc > 2) { + printf("Usage: %s [sec_info]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc == 2) + sscanf(argv[1], "%x", &sec_info); + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + SEC_FLAG_MAXIMUM_ALLOWED, + &out_version, + &out_revision_info, + &pol, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + goto done; + } + + status = dcerpc_lsa_QuerySecurity(b, mem_ctx, + &pol, + sec_info, + &sdb, + &result); + if (!NT_STATUS_IS_OK(status)) + goto done; + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + /* Print results */ + + display_sec_desc(sdb->sd); + + dcerpc_lsa_Close(b, mem_ctx, &pol, &result); + done: + return status; +} + +static void display_trust_dom_info_4(struct lsa_TrustDomainInfoPassword *p, + DATA_BLOB session_key) +{ + char *pwd, *pwd_old; + + DATA_BLOB data = data_blob_const(p->password->data, p->password->length); + DATA_BLOB data_old = data_blob_const(p->old_password->data, p->old_password->length); + + pwd = sess_decrypt_string(talloc_tos(), &data, &session_key); + pwd_old = sess_decrypt_string(talloc_tos(), &data_old, &session_key); + + d_printf("Password:\t%s\n", pwd); + d_printf("Old Password:\t%s\n", pwd_old); + + talloc_free(pwd); + talloc_free(pwd_old); +} + +static void display_trust_dom_info(TALLOC_CTX *mem_ctx, + union lsa_TrustedDomainInfo *info, + enum lsa_TrustDomInfoEnum info_class, + DATA_BLOB session_key) +{ + switch (info_class) { + case LSA_TRUSTED_DOMAIN_INFO_PASSWORD: + display_trust_dom_info_4(&info->password, session_key); + 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) +{ + struct policy_handle pol; + NTSTATUS status, result; + struct dom_sid dom_sid; + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + union lsa_TrustedDomainInfo *info = NULL; + enum lsa_TrustDomInfoEnum info_class = 1; + DATA_BLOB session_key; + struct dcerpc_binding_handle *b = cli->binding_handle; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + 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]); + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + access_mask, + &out_version, + &out_revision_info, + &pol, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + goto done; + } + + status = dcerpc_lsa_QueryTrustedDomainInfoBySid(b, mem_ctx, + &pol, + &dom_sid, + info_class, + &info, + &result); + if (!NT_STATUS_IS_OK(status)) + goto done; + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = cli_get_session_key(mem_ctx, cli, &session_key); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Could not retrieve session key: %s\n", nt_errstr(status))); + goto done; + } + + display_trust_dom_info(mem_ctx, info, info_class, session_key); + + done: + dcerpc_lsa_Close(b, mem_ctx, &pol, &result); + + return status; +} + +static NTSTATUS cmd_lsa_query_trustdominfobyname(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct policy_handle pol; + NTSTATUS status, result; + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + union lsa_TrustedDomainInfo *info = NULL; + enum lsa_TrustDomInfoEnum info_class = 1; + struct lsa_String trusted_domain; + struct dcerpc_binding_handle *b = cli->binding_handle; + DATA_BLOB session_key; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + 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]); + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + access_mask, + &out_version, + &out_revision_info, + &pol, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + goto done; + } + + init_lsa_String(&trusted_domain, argv[1]); + + status = dcerpc_lsa_QueryTrustedDomainInfoByName(b, mem_ctx, + &pol, + &trusted_domain, + info_class, + &info, + &result); + if (!NT_STATUS_IS_OK(status)) + goto done; + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = cli_get_session_key(mem_ctx, cli, &session_key); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Could not retrieve session key: %s\n", nt_errstr(status))); + goto done; + } + + display_trust_dom_info(mem_ctx, info, info_class, session_key); + + done: + dcerpc_lsa_Close(b, mem_ctx, &pol, &result); + + return status; +} + +static NTSTATUS cmd_lsa_set_trustdominfo(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + struct policy_handle pol, trustdom_pol; + NTSTATUS status, result; + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + union lsa_TrustedDomainInfo info; + struct dom_sid dom_sid; + enum lsa_TrustDomInfoEnum info_class = 1; + struct dcerpc_binding_handle *b = cli->binding_handle; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + if (argc > 4 || argc < 3) { + printf("Usage: %s [sid] [info_class] [value]\n", argv[0]); + return NT_STATUS_OK; + } + + if (!string_to_sid(&dom_sid, argv[1])) { + return NT_STATUS_NO_MEMORY; + } + + + info_class = atoi(argv[2]); + + switch (info_class) { + case 13: /* LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES */ + info.enc_types.enc_types = atoi(argv[3]); + break; + default: + return NT_STATUS_INVALID_PARAMETER; + } + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + access_mask, + &out_version, + &out_revision_info, + &pol, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + goto done; + } + + status = dcerpc_lsa_OpenTrustedDomain(b, mem_ctx, + &pol, + &dom_sid, + access_mask, + &trustdom_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = dcerpc_lsa_SetInformationTrustedDomain(b, mem_ctx, + &trustdom_pol, + info_class, + &info, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + done: + dcerpc_lsa_Close(b, mem_ctx, &trustdom_pol, &result); + dcerpc_lsa_Close(b, mem_ctx, &pol, &result); + + return status; +} + +static NTSTATUS cmd_lsa_query_trustdominfo(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct policy_handle pol, trustdom_pol; + NTSTATUS status, result; + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + union lsa_TrustedDomainInfo *info = NULL; + struct dom_sid dom_sid; + enum lsa_TrustDomInfoEnum info_class = 1; + DATA_BLOB session_key; + struct dcerpc_binding_handle *b = cli->binding_handle; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + 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]); + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + access_mask, + &out_version, + &out_revision_info, + &pol, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + goto done; + } + + status = dcerpc_lsa_OpenTrustedDomain(b, mem_ctx, + &pol, + &dom_sid, + access_mask, + &trustdom_pol, + &result); + if (!NT_STATUS_IS_OK(status)) + goto done; + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = dcerpc_lsa_QueryTrustedDomainInfo(b, mem_ctx, + &trustdom_pol, + info_class, + &info, + &result); + if (!NT_STATUS_IS_OK(status)) + goto done; + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = cli_get_session_key(mem_ctx, cli, &session_key); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Could not retrieve session key: %s\n", nt_errstr(status))); + goto done; + } + + display_trust_dom_info(mem_ctx, info, info_class, session_key); + + done: + dcerpc_lsa_Close(b, mem_ctx, &pol, &result); + + return status; +} + +static NTSTATUS cmd_lsa_get_username(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status, result; + const char *servername = cli->desthost; + struct lsa_String *account_name = NULL; + struct lsa_String *authority_name = NULL; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc > 2) { + printf("Usage: %s servername\n", argv[0]); + return NT_STATUS_OK; + } + + status = dcerpc_lsa_GetUserName(b, mem_ctx, + servername, + &account_name, + &authority_name, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + /* Print results */ + + printf("Account Name: %s, Authority Name: %s\n", + account_name->string, authority_name ? authority_name->string : + ""); + + done: + return status; +} + +static NTSTATUS cmd_lsa_add_priv(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + struct policy_handle dom_pol, user_pol; + NTSTATUS status, result; + struct lsa_PrivilegeSet privs; + struct lsa_LUIDAttribute *set = NULL; + struct dom_sid sid; + int i; + struct dcerpc_binding_handle *b = cli->binding_handle; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + ZERO_STRUCT(privs); + + if (argc < 3 ) { + printf("Usage: %s SID [rights...]\n", argv[0]); + return NT_STATUS_OK; + } + + status = name_to_sid(cli, mem_ctx, &sid, argv[1]); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + SEC_FLAG_MAXIMUM_ALLOWED, + &out_version, + &out_revision_info, + &dom_pol, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + goto done; + } + + status = dcerpc_lsa_OpenAccount(b, mem_ctx, + &dom_pol, + &sid, + SEC_FLAG_MAXIMUM_ALLOWED, + &user_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = 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]); + + status = dcerpc_lsa_LookupPrivValue(b, mem_ctx, + &dom_pol, + &priv_name, + &luid, + &result); + if (!NT_STATUS_IS_OK(status)) { + continue; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + continue; + } + + privs.count++; + set = talloc_realloc(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; + + status = dcerpc_lsa_AddPrivilegesToAccount(b, mem_ctx, + &user_pol, + &privs, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + dcerpc_lsa_Close(b, mem_ctx, &user_pol, &result); + dcerpc_lsa_Close(b, mem_ctx, &dom_pol, &result); + done: + return status; +} + +static NTSTATUS cmd_lsa_del_priv(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + struct policy_handle dom_pol, user_pol; + NTSTATUS status, result; + struct lsa_PrivilegeSet privs; + struct lsa_LUIDAttribute *set = NULL; + struct dom_sid sid; + int i; + struct dcerpc_binding_handle *b = cli->binding_handle; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + ZERO_STRUCT(privs); + + if (argc < 3 ) { + printf("Usage: %s SID [rights...]\n", argv[0]); + return NT_STATUS_OK; + } + + status = name_to_sid(cli, mem_ctx, &sid, argv[1]); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + SEC_FLAG_MAXIMUM_ALLOWED, + &out_version, + &out_revision_info, + &dom_pol, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + goto done; + } + + status = dcerpc_lsa_OpenAccount(b, mem_ctx, + &dom_pol, + &sid, + SEC_FLAG_MAXIMUM_ALLOWED, + &user_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = 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]); + + status = dcerpc_lsa_LookupPrivValue(b, mem_ctx, + &dom_pol, + &priv_name, + &luid, + &result); + if (!NT_STATUS_IS_OK(status)) { + continue; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + continue; + } + + privs.count++; + set = talloc_realloc(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; + + + status = dcerpc_lsa_RemovePrivilegesFromAccount(b, mem_ctx, + &user_pol, + false, + &privs, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + dcerpc_lsa_Close(b, mem_ctx, &user_pol, &result); + dcerpc_lsa_Close(b, mem_ctx, &dom_pol, &result); + done: + return status; +} + +static NTSTATUS cmd_lsa_create_secret(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status, result; + struct policy_handle handle, sec_handle; + struct lsa_String name; + struct dcerpc_binding_handle *b = cli->binding_handle; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + if (argc < 2) { + printf("Usage: %s name\n", argv[0]); + return NT_STATUS_OK; + } + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + SEC_FLAG_MAXIMUM_ALLOWED, + &out_version, + &out_revision_info, + &sec_handle, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + return status; + } + + init_lsa_String(&name, argv[1]); + + status = dcerpc_lsa_CreateSecret(b, mem_ctx, + &handle, + name, + SEC_FLAG_MAXIMUM_ALLOWED, + &sec_handle, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + done: + if (is_valid_policy_hnd(&sec_handle)) { + dcerpc_lsa_Close(b, mem_ctx, &sec_handle, &result); + } + if (is_valid_policy_hnd(&handle)) { + dcerpc_lsa_Close(b, mem_ctx, &handle, &result); + } + + return status; +} + +static NTSTATUS cmd_lsa_delete_secret(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status, result; + struct policy_handle handle, sec_handle; + struct lsa_String name; + struct dcerpc_binding_handle *b = cli->binding_handle; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + if (argc < 2) { + printf("Usage: %s name\n", argv[0]); + return NT_STATUS_OK; + } + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + SEC_FLAG_MAXIMUM_ALLOWED, + &out_version, + &out_revision_info, + &handle, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + return status; + } + + init_lsa_String(&name, argv[1]); + + status = dcerpc_lsa_OpenSecret(b, mem_ctx, + &handle, + name, + SEC_FLAG_MAXIMUM_ALLOWED, + &sec_handle, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = dcerpc_lsa_DeleteObject(b, mem_ctx, + &sec_handle, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + done: + if (is_valid_policy_hnd(&sec_handle)) { + dcerpc_lsa_Close(b, mem_ctx, &sec_handle, &result); + } + if (is_valid_policy_hnd(&handle)) { + dcerpc_lsa_Close(b, mem_ctx, &handle, &result); + } + + return status; +} + +static NTSTATUS cmd_lsa_query_secret(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status, result; + struct policy_handle handle, sec_handle; + struct lsa_String name; + struct lsa_DATA_BUF_PTR new_val; + NTTIME new_mtime = 0; + struct lsa_DATA_BUF_PTR old_val; + NTTIME old_mtime = 0; + DATA_BLOB session_key; + DATA_BLOB new_blob = data_blob_null; + DATA_BLOB old_blob = data_blob_null; + char *new_secret, *old_secret; + struct dcerpc_binding_handle *b = cli->binding_handle; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + if (argc < 2) { + printf("Usage: %s name\n", argv[0]); + return NT_STATUS_OK; + } + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + SEC_FLAG_MAXIMUM_ALLOWED, + &out_version, + &out_revision_info, + &handle, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + return status; + } + + init_lsa_String(&name, argv[1]); + + status = dcerpc_lsa_OpenSecret(b, mem_ctx, + &handle, + name, + SEC_FLAG_MAXIMUM_ALLOWED, + &sec_handle, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + ZERO_STRUCT(new_val); + ZERO_STRUCT(old_val); + + status = dcerpc_lsa_QuerySecret(b, mem_ctx, + &sec_handle, + &new_val, + &new_mtime, + &old_val, + &old_mtime, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = cli_get_session_key(mem_ctx, cli, &session_key); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + if (new_val.buf) { + new_blob = data_blob_const(new_val.buf->data, new_val.buf->length); + } + if (old_val.buf) { + old_blob = data_blob_const(old_val.buf->data, old_val.buf->length); + } + + new_secret = sess_decrypt_string(mem_ctx, &new_blob, &session_key); + old_secret = sess_decrypt_string(mem_ctx, &old_blob, &session_key); + if (new_secret) { + d_printf("new secret: %s\n", new_secret); + } + if (old_secret) { + d_printf("old secret: %s\n", old_secret); + } + + done: + if (is_valid_policy_hnd(&sec_handle)) { + dcerpc_lsa_Close(b, mem_ctx, &sec_handle, &result); + } + if (is_valid_policy_hnd(&handle)) { + dcerpc_lsa_Close(b, mem_ctx, &handle, &result); + } + + return status; +} + +static NTSTATUS cmd_lsa_set_secret(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status, result; + struct policy_handle handle, sec_handle; + struct lsa_String name; + struct lsa_DATA_BUF new_val; + struct lsa_DATA_BUF old_val; + DATA_BLOB enc_key; + DATA_BLOB session_key; + struct dcerpc_binding_handle *b = cli->binding_handle; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + if (argc < 3) { + printf("Usage: %s name secret\n", argv[0]); + return NT_STATUS_OK; + } + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + SEC_FLAG_MAXIMUM_ALLOWED, + &out_version, + &out_revision_info, + &handle, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + return status; + } + + init_lsa_String(&name, argv[1]); + + status = dcerpc_lsa_OpenSecret(b, mem_ctx, + &handle, + name, + SEC_FLAG_MAXIMUM_ALLOWED, + &sec_handle, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + ZERO_STRUCT(new_val); + ZERO_STRUCT(old_val); + + status = cli_get_session_key(mem_ctx, cli, &session_key); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + enc_key = sess_encrypt_string(argv[2], &session_key); + + new_val.length = enc_key.length; + new_val.size = enc_key.length; + new_val.data = enc_key.data; + + status = dcerpc_lsa_SetSecret(b, mem_ctx, + &sec_handle, + &new_val, + NULL, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + done: + if (is_valid_policy_hnd(&sec_handle)) { + dcerpc_lsa_Close(b, mem_ctx, &sec_handle, &result); + } + if (is_valid_policy_hnd(&handle)) { + dcerpc_lsa_Close(b, mem_ctx, &handle, &result); + } + + return status; +} + +static NTSTATUS cmd_lsa_retrieve_private_data(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status, result; + struct policy_handle handle; + struct lsa_String name; + struct lsa_DATA_BUF *val; + DATA_BLOB session_key; + DATA_BLOB blob = data_blob_null; + char *secret; + struct dcerpc_binding_handle *b = cli->binding_handle; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + if (argc < 2) { + printf("Usage: %s name\n", argv[0]); + return NT_STATUS_OK; + } + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + SEC_FLAG_MAXIMUM_ALLOWED, + &out_version, + &out_revision_info, + &handle, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + return status; + } + + init_lsa_String(&name, argv[1]); + + ZERO_STRUCT(val); + + status = dcerpc_lsa_RetrievePrivateData(b, mem_ctx, + &handle, + &name, + &val, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = cli_get_session_key(mem_ctx, cli, &session_key); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + if (val) { + blob = data_blob_const(val->data, val->length); + } + + secret = sess_decrypt_string(mem_ctx, &blob, &session_key); + if (secret) { + d_printf("secret: %s\n", secret); + } + + done: + if (is_valid_policy_hnd(&handle)) { + dcerpc_lsa_Close(b, mem_ctx, &handle, &result); + } + + return status; +} + +static NTSTATUS cmd_lsa_store_private_data(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status, result; + struct policy_handle handle; + struct lsa_String name; + struct lsa_DATA_BUF val; + DATA_BLOB session_key; + DATA_BLOB enc_key; + struct dcerpc_binding_handle *b = cli->binding_handle; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + if (argc < 3) { + printf("Usage: %s name secret\n", argv[0]); + return NT_STATUS_OK; + } + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + SEC_FLAG_MAXIMUM_ALLOWED, + &out_version, + &out_revision_info, + &handle, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + return status; + } + + init_lsa_String(&name, argv[1]); + + ZERO_STRUCT(val); + + status = cli_get_session_key(mem_ctx, cli, &session_key); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + enc_key = sess_encrypt_string(argv[2], &session_key); + + val.length = enc_key.length; + val.size = enc_key.length; + val.data = enc_key.data; + + status = dcerpc_lsa_StorePrivateData(b, mem_ctx, + &handle, + &name, + &val, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + done: + if (is_valid_policy_hnd(&handle)) { + dcerpc_lsa_Close(b, mem_ctx, &handle, &result); + } + + return status; +} + +static NTSTATUS cmd_lsa_create_trusted_domain(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status, result; + struct policy_handle handle, trustdom_handle; + struct dom_sid sid; + struct lsa_DomainInfo info; + struct dcerpc_binding_handle *b = cli->binding_handle; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + if (argc < 3) { + printf("Usage: %s name sid\n", argv[0]); + return NT_STATUS_OK; + } + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + SEC_FLAG_MAXIMUM_ALLOWED, + &out_version, + &out_revision_info, + &handle, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + return status; + } + + init_lsa_StringLarge(&info.name, argv[1]); + info.sid = &sid; + string_to_sid(&sid, argv[2]); + + status = dcerpc_lsa_CreateTrustedDomain(b, mem_ctx, + &handle, + &info, + SEC_FLAG_MAXIMUM_ALLOWED, + &trustdom_handle, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + done: + if (is_valid_policy_hnd(&trustdom_handle)) { + dcerpc_lsa_Close(b, mem_ctx, &trustdom_handle, &result); + } + + if (is_valid_policy_hnd(&handle)) { + dcerpc_lsa_Close(b, mem_ctx, &handle, &result); + } + + return status; +} + +static NTSTATUS cmd_lsa_delete_trusted_domain(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status, result; + struct policy_handle handle, trustdom_handle; + struct lsa_String name; + struct dom_sid *sid = NULL; + struct dcerpc_binding_handle *b = cli->binding_handle; + union lsa_revision_info out_revision_info = { + .info1 = { + .revision = 0, + }, + }; + uint32_t out_version = 0; + + if (argc < 2) { + printf("Usage: %s name\n", argv[0]); + return NT_STATUS_OK; + } + + status = dcerpc_lsa_open_policy_fallback(b, + mem_ctx, + cli->srv_name_slash, + true, + SEC_FLAG_MAXIMUM_ALLOWED, + &out_version, + &out_revision_info, + &handle, + &result); + if (any_nt_status_not_ok(status, result, &status)) { + return status; + } + + init_lsa_String(&name, argv[1]); + + status = dcerpc_lsa_OpenTrustedDomainByName(b, mem_ctx, + &handle, + name, + SEC_FLAG_MAXIMUM_ALLOWED, + &trustdom_handle, + &result); + if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) { + goto delete_object; + } + + { + uint32_t resume_handle = 0; + struct lsa_DomainList domains; + int i; + + status = dcerpc_lsa_EnumTrustDom(b, mem_ctx, + &handle, + &resume_handle, + &domains, + 0xffff, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + for (i=0; i < domains.count; i++) { + if (strequal(domains.domains[i].name.string, argv[1])) { + sid = domains.domains[i].sid; + break; + } + } + + if (!sid) { + return NT_STATUS_INVALID_SID; + } + } + + status = dcerpc_lsa_OpenTrustedDomain(b, mem_ctx, + &handle, + sid, + SEC_FLAG_MAXIMUM_ALLOWED, + &trustdom_handle, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + delete_object: + status = dcerpc_lsa_DeleteObject(b, mem_ctx, + &trustdom_handle, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + done: + if (is_valid_policy_hnd(&trustdom_handle)) { + dcerpc_lsa_Close(b, mem_ctx, &trustdom_handle, &result); + } + + if (is_valid_policy_hnd(&handle)) { + dcerpc_lsa_Close(b, mem_ctx, &handle, &result); + } + + return status; +} + + +/* List of commands exported by this module */ + +struct cmd_set lsarpc_commands[] = { + + { + .name = "LSARPC", + }, + + { + .name = "lsaquery", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_query_info_policy, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Query info policy", + .usage = "", + }, + { + .name = "lookupsids", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_lookup_sids, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Convert SIDs to names", + .usage = "", + }, + { + .name = "lookupsids3", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_lookup_sids3, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Convert SIDs to names", + .usage = "", + }, + { + .name = "lookupsids_level", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_lookup_sids_level, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Convert SIDs to names", + .usage = "", + }, + { + .name = "lookupnames", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_lookup_names, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Convert names to SIDs", + .usage = "", + }, + { + .name = "lookupnames4", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_lookup_names4, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Convert names to SIDs", + .usage = "", + }, + { + .name = "lookupnames_level", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_lookup_names_level, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Convert names to SIDs", + .usage = "", + }, + { + .name = "enumtrust", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_enum_trust_dom, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Enumerate trusted domains", + .usage = "Usage: [preferred max number] [enum context (0)]", + }, + { + .name = "enumprivs", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_enum_privilege, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Enumerate privileges", + .usage = "", + }, + { + .name = "getdispname", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_get_dispname, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Get the privilege name", + .usage = "", + }, + { + .name = "lsaenumsid", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_enum_sids, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Enumerate the LSA SIDS", + .usage = "", + }, + { + .name = "lsacreateaccount", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_create_account, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Create a new lsa account", + .usage = "", + }, + { + .name = "lsaenumprivsaccount", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_enum_privsaccounts, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Enumerate the privileges of an SID", + .usage = "", + }, + { + .name = "lsaenumacctrights", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_enum_acct_rights, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Enumerate the rights of an SID", + .usage = "", + }, + { + .name = "lsaaddpriv", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_add_priv, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Assign a privilege to a SID", + .usage = "", + }, + { + .name = "lsadelpriv", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_del_priv, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Revoke a privilege from a SID", + .usage = "", + }, + { + .name = "lsaaddacctrights", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_add_acct_rights, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Add rights to an account", + .usage = "", + }, + { + .name = "lsaremoveacctrights", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_remove_acct_rights, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Remove rights from an account", + .usage = "", + }, + { + .name = "lsalookupprivvalue", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_lookup_priv_value, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Get a privilege value given its name", + .usage = "", + }, + { + .name = "lsaquerysecobj", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_query_secobj, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Query LSA security object", + .usage = "", + }, + { + .name = "lsaquerytrustdominfo", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_query_trustdominfo, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Query LSA trusted domains info (given a SID)", + .usage = "", + }, + { + .name = "lsaquerytrustdominfobyname", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_query_trustdominfobyname, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Query LSA trusted domains info (given a name), only works for Windows > 2k", + .usage = "", + }, + { + .name = "lsaquerytrustdominfobysid", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_query_trustdominfobysid, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Query LSA trusted domains info (given a SID)", + .usage = "", + }, + { + .name = "lsasettrustdominfo", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_set_trustdominfo, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Set LSA trusted domain info", + .usage = "", + }, + { + .name = "getusername", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_get_username, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Get username", + .usage = "", + }, + { + .name = "createsecret", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_create_secret, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Create Secret", + .usage = "", + }, + { + .name = "deletesecret", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_delete_secret, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Delete Secret", + .usage = "", + }, + { + .name = "querysecret", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_query_secret, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Query Secret", + .usage = "", + }, + { + .name = "setsecret", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_set_secret, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Set Secret", + .usage = "", + }, + { + .name = "retrieveprivatedata", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_retrieve_private_data, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Retrieve Private Data", + .usage = "", + }, + { + .name = "storeprivatedata", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_store_private_data, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Store Private Data", + .usage = "", + }, + { + .name = "createtrustdom", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_create_trusted_domain, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Create Trusted Domain", + .usage = "", + }, + { + .name = "deletetrustdom", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_lsa_delete_trusted_domain, + .wfn = NULL, + .table = &ndr_table_lsarpc, + .rpc_pipe = NULL, + .description = "Delete Trusted Domain", + .usage = "", + }, + { + .name = NULL, + }, +}; diff --git a/source3/rpcclient/cmd_netlogon.c b/source3/rpcclient/cmd_netlogon.c new file mode 100644 index 0000000..bb5b9da --- /dev/null +++ b/source3/rpcclient/cmd_netlogon.c @@ -0,0 +1,1186 @@ +/* + 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" +#include "../libcli/auth/libcli_auth.h" +#include "../librpc/gen_ndr/ndr_netlogon.h" +#include "../librpc/gen_ndr/ndr_netlogon_c.h" +#include "rpc_client/cli_netlogon.h" +#include "secrets.h" +#include "../libcli/auth/netlogon_creds_cli.h" +#include "rpc_client/util_netlogon.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(); + struct dcerpc_binding_handle *b = cli->binding_handle; + int i; +#define fn_code_level(x, item) { x, #x, #item } + struct { + enum netr_LogonControlCode code; + const char *name; + const char *argument; + } supported_levels[] = { + fn_code_level(NETLOGON_CONTROL_REDISCOVER, domain), + fn_code_level(NETLOGON_CONTROL_TC_QUERY, domain), + fn_code_level(NETLOGON_CONTROL_TRANSPORT_NOTIFY, domain), + fn_code_level(NETLOGON_CONTROL_FIND_USER, user), + fn_code_level(NETLOGON_CONTROL_CHANGE_PASSWORD, domain), + fn_code_level(NETLOGON_CONTROL_TC_VERIFY, domain), + fn_code_level(NETLOGON_CONTROL_SET_DBFLAG, debug_level), + {0, 0, 0} + }; +#undef fn_code_level + if ((argc > 5) || (argc < 2)) { + fprintf(stderr, "Usage: %s <logon_server> <function_code> " + "<level:1..4> <argument>\n", argv[0]); + fprintf(stderr, "Supported combinations:\n"); + fprintf(stderr, "function_code\targument\n"); + for(i=0; supported_levels[i].code; i++) { + fprintf(stderr, "%7d\t\t%s\t(%s)\n", + supported_levels[i].code, + supported_levels[i].argument, + supported_levels[i].name); + } + 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: + case NETLOGON_CONTROL_CHANGE_PASSWORD: + case NETLOGON_CONTROL_TRANSPORT_NOTIFY: + case NETLOGON_CONTROL_TC_VERIFY: + data.domain = domain; + break; + case NETLOGON_CONTROL_FIND_USER: + data.user = domain; + break; + case NETLOGON_CONTROL_SET_DBFLAG: + data.debug_level = atoi(domain); + break; + default: + break; + } + + status = dcerpc_netr_LogonControl2(b, 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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 = dcerpc_netr_GetAnyDCName(b, 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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 = dcerpc_netr_GetDcName(b, 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_t flags = DS_RETURN_DNS_NAME; + const char *server_name = cli->desthost; + const char *domain_name = NULL; + struct GUID domain_guid = GUID_zero(); + struct GUID site_guid = GUID_zero(); + struct netr_DsRGetDCNameInfo *info = NULL; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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_NOT_ENOUGH_MEMORY; + } + } + + if (argc >= 4) { + if (!NT_STATUS_IS_OK(GUID_from_string(argv[3], &site_guid))) { + return WERR_NOT_ENOUGH_MEMORY; + } + } + + if (argc >= 5) + sscanf(argv[4], "%x", &flags); + + result = dcerpc_netr_DsRGetDCName(b, mem_ctx, + server_name, + domain_name, + &domain_guid, + &site_guid, + flags, + &info, + &werr); + if (!NT_STATUS_IS_OK(result)) { + return ntstatus_to_werror(result); + } + + 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", + win_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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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_NOT_ENOUGH_MEMORY; + } + } + + if (argc >= 4) { + site_name = argv[3]; + } + + if (argc >= 5) { + sscanf(argv[4], "%x", &flags); + } + + status = dcerpc_netr_DsRGetDCNameEx(b, 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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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_NOT_ENOUGH_MEMORY; + } + } + + if (argc >= 6) { + site_name = argv[5]; + } + + if (argc >= 7) { + sscanf(argv[6], "%x", &flags); + } + + status = dcerpc_netr_DsRGetDCNameEx2(b, 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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc != 2) { + fprintf(stderr, "Usage: %s computername\n", argv[0]); + return WERR_OK; + } + + status = dcerpc_netr_DsRGetSiteName(b, 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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 = dcerpc_netr_LogonControl(b, 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; +} + +/* 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 = NetlogonNetworkInformation; + const char *username, *password; + uint32_t logon_param = 0; + const char *workstation = NULL; + struct netr_SamInfo3 *info3 = NULL; + uint8_t authoritative = 1; + uint32_t flags = 0; + uint16_t validation_level; + union netr_Validation *validation = NULL; + uint64_t logon_id = 0; + + /* Check arguments */ + + if (argc < 3 || argc > 6) { + fprintf(stderr, "Usage: samlogon <username> <password> [workstation]" + "[logon_type (1 or 2)] [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], "%x", &logon_param); + + if (rpcclient_netlogon_creds == NULL) { + result = NT_STATUS_UNSUCCESSFUL; + goto done; + } + logon_id = generate_random_u64(); + + /* Perform the sam logon */ + + result = rpccli_netlogon_password_logon(rpcclient_netlogon_creds, + cli->binding_handle, + mem_ctx, + logon_param, + lp_workgroup(), + username, + password, + workstation, + logon_id, + logon_type, + &authoritative, + &flags, + &validation_level, + &validation); + if (!NT_STATUS_IS_OK(result)) + goto done; + + result = map_validation_to_info3(mem_ctx, + validation_level, + validation, + &info3); + if (!NT_STATUS_IS_OK(result)) { + return result; + } + + 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; + const char *dcname = cli->desthost; + + /* Check arguments */ + + if (argc > 1) { + fprintf(stderr, "Usage: change_trust_pw"); + return NT_STATUS_OK; + } + + result = trust_pw_change(rpcclient_netlogon_creds, + rpcclient_msg_ctx, + cli->binding_handle, + lp_workgroup(), + dcname, + true); /* force */ + 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_GEN_FAILURE; + const char *server_name = cli->desthost; + const char *domain_name = lp_workgroup(); + uint32_t rid = 0; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 = dcerpc_netr_LogonGetTrustRid(b, mem_ctx, + server_name, + domain_name, + &rid, + &werr); + if (!NT_STATUS_IS_OK(status)) { + werr = ntstatus_to_werror(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_GEN_FAILURE; + const char *server_name = cli->desthost; + uint32_t trust_flags = NETR_TRUST_FLAG_IN_FOREST; + struct netr_DomainTrustList trusts; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx, + server_name, + trust_flags, + &trusts, + &werr); + if (!NT_STATUS_IS_OK(status)) { + werr = ntstatus_to_werror(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_GEN_FAILURE; + const char *server_name = cli->desthost; + const char *domain = lp_workgroup(); + const char *dns_host = NULL; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 = dcerpc_netr_DsrDeregisterDNSHostRecords(b, mem_ctx, + server_name, + domain, + NULL, + NULL, + dns_host, + &werr); + if (!NT_STATUS_IS_OK(status)) { + werr = ntstatus_to_werror(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_GEN_FAILURE; + const char *server_name = cli->desthost; + const char *trusted_domain_name = NULL; + struct lsa_ForestTrustInformation *info = NULL; + uint32_t flags = 0; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 = dcerpc_netr_DsRGetForestTrustInformation(b, mem_ctx, + server_name, + trusted_domain_name, + flags, + &info, + &werr); + if (!NT_STATUS_IS_OK(status)) { + werr = ntstatus_to_werror(status); + goto done; + } + + if (W_ERROR_IS_OK(werr)) { + printf("success\n"); + } + done: + return werr; +} + +static NTSTATUS cmd_netlogon_enumtrusteddomains(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + NTSTATUS result; + const char *server_name = cli->desthost; + struct netr_Blob blob; + struct dcerpc_binding_handle *b = cli->binding_handle; + + + if (argc < 1 || argc > 3) { + fprintf(stderr, "Usage: %s <server_name>\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc >= 2) { + server_name = argv[1]; + } + + status = dcerpc_netr_NetrEnumerateTrustedDomains(b, mem_ctx, + server_name, + &blob, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + printf("success\n"); + dump_data(1, blob.data, blob.length); + done: + return status; +} + +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_GEN_FAILURE; + const char *server_name = cli->desthost; + struct netr_DomainTrustList list; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 = dcerpc_netr_NetrEnumerateTrustedDomainsEx(b, mem_ctx, + server_name, + &list, + &werr); + if (!NT_STATUS_IS_OK(status)) { + werr = ntstatus_to_werror(status); + goto done; + } + + if (W_ERROR_IS_OK(werr)) { + printf("success\n"); + } + done: + return werr; +} + +static WERROR cmd_netlogon_getdcsitecoverage(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + WERROR werr = WERR_GEN_FAILURE; + const char *server_name = cli->desthost; + struct DcSitesCtr *ctr = NULL; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 = dcerpc_netr_DsrGetDcSiteCoverageW(b, mem_ctx, + server_name, + &ctr, + &werr); + if (!NT_STATUS_IS_OK(status)) { + werr = ntstatus_to_werror(status); + goto done; + } + + if (W_ERROR_IS_OK(werr) && ctr->num_sites) { + int i; + printf("sites covered by this DC: %d\n", ctr->num_sites); + for (i=0; i<ctr->num_sites; i++) { + printf("%s\n", ctr->sites[i].string); + } + } + done: + return werr; +} + +static NTSTATUS cmd_netlogon_capabilities(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + struct netlogon_creds_cli_lck *lck; + union netr_Capabilities capabilities; + NTSTATUS status; + + if (argc > 1) { + fprintf(stderr, "Usage: %s\n", argv[0]); + return NT_STATUS_OK; + } + + status = netlogon_creds_cli_lck(rpcclient_netlogon_creds, + NETLOGON_CREDS_CLI_LCK_EXCLUSIVE, + mem_ctx, &lck); + if (!NT_STATUS_IS_OK(status)) { + fprintf(stderr, "netlogon_creds_cli_lck failed: %s\n", + nt_errstr(status)); + return status; + } + + status = netlogon_creds_cli_check(rpcclient_netlogon_creds, + cli->binding_handle, + &capabilities); + if (!NT_STATUS_IS_OK(status)) { + fprintf(stderr, "netlogon_creds_cli_check failed: %s\n", + nt_errstr(status)); + return status; + } + + TALLOC_FREE(lck); + + printf("capabilities: 0x%08x\n", capabilities.server_capabilities); + + return NT_STATUS_OK; +} + +static NTSTATUS cmd_netlogon_logongetdomaininfo(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + union netr_WorkstationInfo query; + struct netr_WorkstationInformation workstation_info; + union netr_DomainInfo *domain_info; + NTSTATUS status; + char *s; + + if (argc > 1) { + fprintf(stderr, "Usage: %s\n", argv[0]); + return NT_STATUS_OK; + } + + ZERO_STRUCT(workstation_info); + + query.workstation_info = &workstation_info; + + status = netlogon_creds_cli_LogonGetDomainInfo(rpcclient_netlogon_creds, + cli->binding_handle, + mem_ctx, + 1, + &query, + &domain_info); + if (!NT_STATUS_IS_OK(status)) { + fprintf(stderr, "netlogon_creds_cli_LogonGetDomainInfo failed: %s\n", + nt_errstr(status)); + return status; + } + + s = NDR_PRINT_STRUCT_STRING(mem_ctx, netr_DomainInformation, domain_info->domain_info); + if (s) { + printf("%s\n", s); + TALLOC_FREE(s); + } + + return NT_STATUS_OK; +} + +/* List of commands exported by this module */ + +struct cmd_set netlogon_commands[] = { + + { + .name = "NETLOGON", + }, + + { + .name = "logonctrl2", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_netlogon_logon_ctrl2, + .table = &ndr_table_netlogon, + .rpc_pipe = NULL, + .description = "Logon Control 2", + .usage = "", + }, + { + .name = "getanydcname", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_netlogon_getanydcname, + .table = &ndr_table_netlogon, + .rpc_pipe = NULL, + .description = "Get trusted DC name", + .usage = "", + }, + { + .name = "getdcname", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_netlogon_getdcname, + .table = &ndr_table_netlogon, + .rpc_pipe = NULL, + .description = "Get trusted PDC name", + .usage = "", + }, + { + .name = "dsr_getdcname", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_netlogon_dsr_getdcname, + .table = &ndr_table_netlogon, + .rpc_pipe = NULL, + .description = "Get trusted DC name", + .usage = "", + }, + { + .name = "dsr_getdcnameex", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_netlogon_dsr_getdcnameex, + .table = &ndr_table_netlogon, + .rpc_pipe = NULL, + .description = "Get trusted DC name", + .usage = "", + }, + { + .name = "dsr_getdcnameex2", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_netlogon_dsr_getdcnameex2, + .table = &ndr_table_netlogon, + .rpc_pipe = NULL, + .description = "Get trusted DC name", + .usage = "", + }, + { + .name = "dsr_getsitename", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_netlogon_dsr_getsitename, + .table = &ndr_table_netlogon, + .rpc_pipe = NULL, + .description = "Get sitename", + .usage = "", + }, + { + .name = "dsr_getforesttrustinfo", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_netlogon_dsr_getforesttrustinfo, + .table = &ndr_table_netlogon, + .rpc_pipe = NULL, + .description = "Get Forest Trust Info", + .usage = "", + }, + { + .name = "logonctrl", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_netlogon_logon_ctrl, + .table = &ndr_table_netlogon, + .rpc_pipe = NULL, + .description = "Logon Control", + .usage = "", + }, + { + .name = "samlogon", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_netlogon_sam_logon, + .wfn = NULL, + .table = &ndr_table_netlogon, + .rpc_pipe = NULL, + .description = "Sam Logon", + .usage = "", + .use_netlogon_creds = true, + }, + { + .name = "change_trust_pw", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_netlogon_change_trust_pw, + .wfn = NULL, + .table = &ndr_table_netlogon, + .rpc_pipe = NULL, + .description = "Change Trust Account Password", + .usage = "", + .use_netlogon_creds = true, + }, + { + .name = "gettrustrid", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_netlogon_gettrustrid, + .table = &ndr_table_netlogon, + .rpc_pipe = NULL, + .description = "Get trust rid", + .usage = "", + }, + { + .name = "dsr_enumtrustdom", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_netlogon_dsr_enumtrustdom, + .table = &ndr_table_netlogon, + .rpc_pipe = NULL, + .description = "Enumerate trusted domains", + .usage = "", + }, + { + .name = "dsenumdomtrusts", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_netlogon_dsr_enumtrustdom, + .table = &ndr_table_netlogon, + .rpc_pipe = NULL, + .description = "Enumerate all trusted domains in an AD forest", + .usage = "", + }, + { + .name = "deregisterdnsrecords", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_netlogon_deregisterdnsrecords, + .table = &ndr_table_netlogon, + .rpc_pipe = NULL, + .description = "Deregister DNS records", + .usage = "", + }, + { + .name = "netrenumtrusteddomains", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_netlogon_enumtrusteddomains, + .wfn = NULL, + .table = &ndr_table_netlogon, + .rpc_pipe = NULL, + .description = "Enumerate trusted domains", + .usage = "", + }, + { + .name = "netrenumtrusteddomainsex", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_netlogon_enumtrusteddomainsex, + .table = &ndr_table_netlogon, + .rpc_pipe = NULL, + .description = "Enumerate trusted domains", + .usage = "", + }, + { + .name = "getdcsitecoverage", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_netlogon_getdcsitecoverage, + .table = &ndr_table_netlogon, + .rpc_pipe = NULL, + .description = "Get the Site-Coverage from a DC", + .usage = "", + }, + { + .name = "capabilities", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_netlogon_capabilities, + .wfn = NULL, + .table = &ndr_table_netlogon, + .rpc_pipe = NULL, + .description = "Return Capabilities", + .usage = "", + .use_netlogon_creds = true, + }, + { + .name = "logongetdomaininfo", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_netlogon_logongetdomaininfo, + .wfn = NULL, + .table = &ndr_table_netlogon, + .rpc_pipe = NULL, + .description = "Return LogonGetDomainInfo", + .usage = "", + .use_netlogon_creds = true, + }, + { + .name = NULL, + } +}; diff --git a/source3/rpcclient/cmd_ntsvcs.c b/source3/rpcclient/cmd_ntsvcs.c new file mode 100644 index 0000000..15a2357 --- /dev/null +++ b/source3/rpcclient/cmd_ntsvcs.c @@ -0,0 +1,361 @@ +/* + 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" +#include "../librpc/gen_ndr/ndr_ntsvcs_c.h" + +static WERROR cmd_ntsvcs_get_version(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + WERROR werr; + uint16_t version; + + status = dcerpc_PNP_GetVersion(b, 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) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + 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 = dcerpc_PNP_ValidateDeviceInstance(b, mem_ctx, + devicepath, + flags, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + return werr; +} + +static WERROR cmd_ntsvcs_hw_prof_flags(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + WERROR werr; + const char *devicepath = NULL; + uint32_t profile_flags = 0; + uint16_t veto_type = 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 = dcerpc_PNP_HwProfFlags(b, mem_ctx, + 0, + devicepath, + 0, + &profile_flags, + &veto_type, + 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) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + WERROR werr; + uint32_t idx = 0; + struct PNP_HwProfInfo info; + uint32_t size = 0, flags = 0; + + ZERO_STRUCT(info); + + status = dcerpc_PNP_GetHwProfInfo(b, mem_ctx, + idx, + &info, + size, + flags, + &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) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + WERROR werr; + const char *devicepath = NULL; + uint32_t property = DEV_REGPROP_DESC; + uint32_t reg_data_type = REG_NONE; + uint8_t *buffer; + uint32_t buffer_size = 0; + uint32_t needed = 0; + uint32_t flags = 0; + + if (argc < 2) { + printf("usage: %s [devicepath] [buffersize]\n", argv[0]); + return WERR_OK; + } + + devicepath = argv[1]; + + if (argc >= 3) { + buffer_size = atoi(argv[2]); + needed = buffer_size; + } + + buffer = talloc_array(mem_ctx, uint8_t, buffer_size); + W_ERROR_HAVE_NO_MEMORY(buffer); + + status = dcerpc_PNP_GetDeviceRegProp(b, mem_ctx, + devicepath, + property, + ®_data_type, + buffer, + &buffer_size, + &needed, + flags, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + return werr; +} + +static WERROR cmd_ntsvcs_get_dev_list_size(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + WERROR werr; + uint32_t size = 0; + uint32_t flags = 0; + const char *filter = NULL; + + if (argc > 3) { + printf("usage: %s [filter] [flags]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + filter = argv[1]; + } + + if (argc >= 3) { + flags = atoi(argv[2]); + } + + status = dcerpc_PNP_GetDeviceListSize(b, mem_ctx, + filter, + &size, + flags, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + printf("size: %d\n", size); + + return werr; +} + +static WERROR cmd_ntsvcs_get_dev_list(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + WERROR werr; + const char *filter = NULL; + uint16_t *buffer = NULL; + uint32_t length = 0; + uint32_t flags = 0; + + if (argc > 4) { + printf("usage: %s [filter] [length] [flags]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + filter = argv[1]; + } + + if (argc >= 3) { + length = atoi(argv[2]); + } + + if (argc >= 4) { + flags = atoi(argv[3]); + } + + buffer = talloc(mem_ctx, uint16_t); + if (!buffer) { + return WERR_NOT_ENOUGH_MEMORY; + } + + status = dcerpc_PNP_GetDeviceList(b, mem_ctx, + filter, + buffer, + &length, + flags, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + printf("devlist needs size: %d\n", length); + + return werr; +} + +struct cmd_set ntsvcs_commands[] = { + + { + .name = "NTSVCS", + }, + { + .name = "ntsvcs_getversion", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_ntsvcs_get_version, + .table = &ndr_table_ntsvcs, + .rpc_pipe = NULL, + .description = "Query NTSVCS version", + .usage = "", + }, + { + .name = "ntsvcs_validatedevinst", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_ntsvcs_validate_dev_inst, + .table = &ndr_table_ntsvcs, + .rpc_pipe = NULL, + .description = "Query NTSVCS device instance", + .usage = "", + }, + { + .name = "ntsvcs_hwprofflags", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_ntsvcs_hw_prof_flags, + .table = &ndr_table_ntsvcs, + .rpc_pipe = NULL, + .description = "Query NTSVCS HW prof flags", + .usage = "", + }, + { + .name = "ntsvcs_hwprofinfo", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_ntsvcs_get_hw_prof_info, + .table = &ndr_table_ntsvcs, + .rpc_pipe = NULL, + .description = "Query NTSVCS HW prof info", + .usage = "", + }, + { + .name = "ntsvcs_getdevregprop", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_ntsvcs_get_dev_reg_prop, + .table = &ndr_table_ntsvcs, + .rpc_pipe = NULL, + .description = "Query NTSVCS device registry property", + .usage = "", + }, + { + .name = "ntsvcs_getdevlistsize", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_ntsvcs_get_dev_list_size, + .table = &ndr_table_ntsvcs, + .rpc_pipe = NULL, + .description = "Query NTSVCS device list size", + .usage = "", + }, + { + .name = "ntsvcs_getdevlist", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_ntsvcs_get_dev_list, + .table = &ndr_table_ntsvcs, + .rpc_pipe = NULL, + .description = "Query NTSVCS device list", + .usage = "", + }, + { + .name = NULL, + }, +}; diff --git a/source3/rpcclient/cmd_samr.c b/source3/rpcclient/cmd_samr.c new file mode 100644 index 0000000..8106ca9 --- /dev/null +++ b/source3/rpcclient/cmd_samr.c @@ -0,0 +1,3941 @@ +/* + 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" +#include "../libcli/auth/libcli_auth.h" +#include "../librpc/gen_ndr/ndr_samr.h" +#include "../librpc/gen_ndr/ndr_samr_c.h" +#include "rpc_client/cli_samr.h" +#include "rpc_client/init_samr.h" +#include "rpc_client/init_lsa.h" +#include "../libcli/security/security.h" +#include "lib/util/smb_strtox.h" + +static struct 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(talloc_tos(), nt_time_to_unix(r->last_logon))); + printf("\tLogoff Time :\t%s\n", + http_timestring(talloc_tos(), nt_time_to_unix(r->last_logoff))); + printf("\tKickoff Time :\t%s\n", + http_timestring(talloc_tos(), nt_time_to_unix(r->acct_expiry))); + printf("\tPassword last set Time :\t%s\n", + http_timestring(talloc_tos(), nt_time_to_unix(r->last_password_change))); + printf("\tPassword can change Time :\t%s\n", + http_timestring(talloc_tos(), nt_time_to_unix(r->allow_password_change))); + printf("\tPassword must change Time:\t%s\n", + http_timestring(talloc_tos(), 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_DomGeneralInformation *general) +{ + printf("Domain:\t\t%s\n", general->domain_name.string); + printf("Server:\t\t%s\n", general->primary.string); + printf("Comment:\t%s\n", general->oem_information.string); + + printf("Total Users:\t%d\n", general->num_users); + printf("Total Groups:\t%d\n", general->num_groups); + printf("Total Aliases:\t%d\n", general->num_aliases); + + printf("Sequence No:\t%llu\n", (unsigned long long)general->sequence_num); + + printf("Force Logoff:\t%d\n", + (int)nt_time_to_unix_abs(&general->force_logoff_time)); + + printf("Domain Server State:\t0x%x\n", general->domain_server_state); + printf("Server Role:\t%s\n", server_role_str(general->role)); + printf("Unknown 3:\t0x%x\n", general->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_DomOEMInformation *oem) +{ + printf("Comment:\t%s\n", oem->oem_information.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(talloc_tos(), nt_time_to_unix(info8->domain_create_time))); +} + +static void display_sam_dom_info_9(struct samr_DomInfo9 *info9) +{ + printf("Domain Server State:\t0x%x\n", info9->domain_server_state); +} + +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(talloc_tos(), nt_time_to_unix(info13->domain_create_time))); + printf("Sequence No at last promotion:\t%llu\n", + (unsigned long long)info13->modified_count_at_last_promotion); +} + +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); +} + +static NTSTATUS rpccli_try_samr_connects( + struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + uint32_t access_mask, + struct policy_handle *connect_pol) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32_t start_idx = 0; + uint32_t i, num_entries; + struct samr_SamArray *sam = NULL; + struct dom_sid *domsid = NULL; + + status = dcerpc_try_samr_connects( + b, + mem_ctx, + cli->srv_name_slash, + access_mask, + connect_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + if (!NT_STATUS_IS_OK(result)) { + return result; + } + + if (!is_null_sid(&domain_sid)) { + return NT_STATUS_OK; + } + + /* + * Look up the servers domain SID. Just pick the first + * non-builtin domain from samr_EnumDomains. + */ + + status = dcerpc_samr_EnumDomains( + b, + mem_ctx, + connect_pol, + &start_idx, + &sam, + 0xffff, + &num_entries, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto fail; + } + + for (i=0; i<num_entries; i++) { + if (!strequal(sam->entries[i].name.string, "builtin")) { + break; + } + } + if (i == num_entries) { + status = NT_STATUS_NOT_FOUND; + goto fail; + } + + status = dcerpc_samr_LookupDomain( + b, + mem_ctx, + connect_pol, + &sam->entries[i].name, + &domsid, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto fail; + } + + sid_copy(&domain_sid, domsid); + TALLOC_FREE(domsid); + + return NT_STATUS_OK; + +fail: + dcerpc_samr_Close(b, mem_ctx, connect_pol, &result); + return status; +} + +/**************************************************************************** + ****************************************************************************/ + +static NTSTATUS get_domain_handle(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + const char *sam, + struct policy_handle *connect_pol, + uint32_t access_mask, + struct dom_sid *_domain_sid, + struct policy_handle *domain_pol) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status = NT_STATUS_INVALID_PARAMETER, result; + + if (strcasecmp_m(sam, "domain") == 0) { + status = dcerpc_samr_OpenDomain(b, mem_ctx, + connect_pol, + access_mask, + _domain_sid, + domain_pol, + &result); + } else if (strcasecmp_m(sam, "builtin") == 0) { + status = dcerpc_samr_OpenDomain(b, mem_ctx, + connect_pol, + access_mask, + discard_const_p(struct dom_sid2, &global_sid_Builtin), + domain_pol, + &result); + } + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return result; +} + +/********************************************************************** + * Query user information + */ +static NTSTATUS cmd_samr_query_user(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle connect_pol, domain_pol, user_pol; + NTSTATUS status, result; + uint32_t info_level = 21; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + union samr_UserInfo *info = NULL; + uint32_t user_rid = 0; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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); + + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = dcerpc_samr_OpenDomain(b, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = dcerpc_samr_OpenUser(b, mem_ctx, + &domain_pol, + access_mask, + user_rid, + &user_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + 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]); + + status = dcerpc_samr_LookupNames(b, mem_ctx, + &domain_pol, + 1, + &lsa_acct_name, + &rids, + &types, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + if (NT_STATUS_IS_OK(result)) { + if (rids.count != 1) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (types.count != 1) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + + status = dcerpc_samr_OpenUser(b, mem_ctx, + &domain_pol, + access_mask, + rids.ids[0], + &user_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + } + } + + + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = dcerpc_samr_QueryUserInfo(b, mem_ctx, + &user_pol, + info_level, + &info, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = 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; + } + + dcerpc_samr_Close(b, mem_ctx, &user_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + +done: + return status; +} + +/**************************************************************************** + 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) +{ + struct policy_handle connect_pol, domain_pol, group_pol; + NTSTATUS status, result; + enum samr_GroupInfoEnum info_level = GROUPINFOALL; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + union samr_GroupInfo *group_info = NULL; + uint32_t group_rid; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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); + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = dcerpc_samr_OpenDomain(b, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = dcerpc_samr_OpenGroup(b, mem_ctx, + &domain_pol, + access_mask, + group_rid, + &group_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = dcerpc_samr_QueryGroupInfo(b, mem_ctx, + &group_pol, + info_level, + &group_info, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + display_group_info(group_info, info_level); + + dcerpc_samr_Close(b, mem_ctx, &group_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); +done: + return status; +} + +/* 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) +{ + struct policy_handle connect_pol, + domain_pol, + user_pol; + NTSTATUS status, result; + uint32_t user_rid; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + int i; + struct samr_RidWithAttributeArray *rid_array = NULL; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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); + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = dcerpc_samr_OpenDomain(b, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = dcerpc_samr_OpenUser(b, mem_ctx, + &domain_pol, + access_mask, + user_rid, + &user_pol, + &result); + + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = dcerpc_samr_GetGroupsForUser(b, mem_ctx, + &user_pol, + &rid_array, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = 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); + } + + dcerpc_samr_Close(b, mem_ctx, &user_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + done: + return status; +} + +/* 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) +{ + struct policy_handle connect_pol, domain_pol; + NTSTATUS status, result; + struct dom_sid *sids; + uint32_t num_sids; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + int i; + struct lsa_SidArray sid_array; + struct samr_Ids alias_rids; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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++) { + struct 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 = dom_sid_dup(mem_ctx, &sids[i]); + if (!sid_array.sids[i].sid) { + return NT_STATUS_NO_MEMORY; + } + } + + sid_array.num_sids = num_sids; + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = get_domain_handle(cli, mem_ctx, argv[1], + &connect_pol, + access_mask, + &domain_sid, + &domain_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = dcerpc_samr_GetAliasMembership(b, mem_ctx, + &domain_pol, + &sid_array, + &alias_rids, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + for (i = 0; i < alias_rids.count; i++) { + printf("\tgroup rid:[0x%x]\n", alias_rids.ids[i]); + } + + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + done: + return status; +} + +/* 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) +{ + struct policy_handle connect_pol, domain_pol, group_pol; + NTSTATUS status, result; + uint32_t group_rid; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + int i; + unsigned int old_timeout; + struct samr_RidAttrArray *rids = NULL; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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); + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = dcerpc_samr_OpenDomain(b, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = dcerpc_samr_OpenGroup(b, mem_ctx, + &domain_pol, + access_mask, + group_rid, + &group_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = 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 */ + + status = dcerpc_samr_QueryGroupMember(b, mem_ctx, + &group_pol, + &rids, + &result); + + rpccli_set_timeout(cli, old_timeout); + + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + for (i = 0; i < rids->count; i++) { + printf("\trid:[0x%x] attr:[0x%x]\n", rids->rids[i], + rids->attributes[i]); + } + + dcerpc_samr_Close(b, mem_ctx, &group_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + done: + return status; +} + +/* Enumerate domain users */ + +static NTSTATUS cmd_samr_enum_dom_users(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle connect_pol; + struct policy_handle domain_pol = { 0, }; + NTSTATUS status, result; + uint32_t start_idx, num_dom_users, i; + struct samr_SamArray *dom_users = NULL; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + uint32_t acb_mask = ACB_NORMAL; + uint32_t size = 0xffff; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if ((argc < 1) || (argc > 4)) { + printf("Usage: %s [access_mask] [acb_mask] [size]\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); + } + + if (argc > 3) { + sscanf(argv[3], "%x", &size); + } + + /* Get sam policy handle */ + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Get domain policy handle */ + + status = get_domain_handle(cli, mem_ctx, "domain", + &connect_pol, + access_mask, + &domain_sid, + &domain_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Enumerate domain users */ + + start_idx = 0; + + do { + status = dcerpc_samr_EnumDomainUsers(b, mem_ctx, + &domain_pol, + &start_idx, + acb_mask, + &dom_users, + size, + &num_dom_users, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + 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 (is_valid_policy_hnd(&domain_pol)) + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + + if (is_valid_policy_hnd(&connect_pol)) + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + + return status; +} + +/* Enumerate domain groups */ + +static NTSTATUS cmd_samr_enum_dom_groups(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle connect_pol; + struct policy_handle domain_pol = { 0, }; + NTSTATUS status, result; + uint32_t start_idx, num_dom_groups, i; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + struct samr_SamArray *dom_groups = NULL; + uint32_t size = 0xffff; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if ((argc < 1) || (argc > 3)) { + printf("Usage: %s [access_mask] [max_size]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc > 1) { + sscanf(argv[1], "%x", &access_mask); + } + + if (argc > 2) { + sscanf(argv[2], "%x", &size); + } + + /* Get sam policy handle */ + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Get domain policy handle */ + + status = get_domain_handle(cli, mem_ctx, "domain", + &connect_pol, + access_mask, + &domain_sid, + &domain_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Enumerate domain groups */ + + start_idx = 0; + + do { + status = dcerpc_samr_EnumDomainGroups(b, mem_ctx, + &domain_pol, + &start_idx, + &dom_groups, + size, + &num_dom_groups, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + 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 (is_valid_policy_hnd(&domain_pol)) + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + + if (is_valid_policy_hnd(&connect_pol)) + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + + return status; +} + +/* Enumerate alias groups */ + +static NTSTATUS cmd_samr_enum_als_groups(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle connect_pol; + struct policy_handle domain_pol = { 0, }; + NTSTATUS status, result; + uint32_t start_idx, num_als_groups, i; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + struct samr_SamArray *als_groups = NULL; + uint32_t size = 0xffff; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if ((argc < 2) || (argc > 4)) { + printf("Usage: %s builtin|domain [access mask] [max_size]\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc > 2) { + sscanf(argv[2], "%x", &access_mask); + } + + if (argc > 3) { + sscanf(argv[3], "%x", &size); + } + + /* Get sam policy handle */ + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Get domain policy handle */ + + status = get_domain_handle(cli, mem_ctx, argv[1], + &connect_pol, + access_mask, + &domain_sid, + &domain_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Enumerate alias groups */ + + start_idx = 0; + + do { + status = dcerpc_samr_EnumDomainAliases(b, mem_ctx, + &domain_pol, + &start_idx, + &als_groups, + size, + &num_als_groups, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + 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 (is_valid_policy_hnd(&domain_pol)) + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + + if (is_valid_policy_hnd(&connect_pol)) + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + + return status; +} + +/* Enumerate domains */ + +static NTSTATUS cmd_samr_enum_domains(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle connect_pol; + NTSTATUS status, result; + uint32_t start_idx, size, num_entries, i; + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct samr_SamArray *sam = NULL; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 */ + + status = rpccli_try_samr_connects(cli, mem_ctx, + access_mask, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Enumerate domains */ + + start_idx = 0; + size = 0xffff; + + do { + status = dcerpc_samr_EnumDomains(b, mem_ctx, + &connect_pol, + &start_idx, + &sam, + size, + &num_entries, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + 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 (is_valid_policy_hnd(&connect_pol)) { + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + } + + return status; +} + + +/* Query alias membership */ + +static NTSTATUS cmd_samr_query_aliasmem(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle connect_pol, domain_pol, alias_pol; + NTSTATUS status, result; + uint32_t alias_rid, i; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + struct lsa_SidArray sid_array; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 */ + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Open handle on domain */ + + status = get_domain_handle(cli, mem_ctx, argv[1], + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Open handle on alias */ + + status = dcerpc_samr_OpenAlias(b, mem_ctx, + &domain_pol, + access_mask, + alias_rid, + &alias_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = dcerpc_samr_GetMembersInAlias(b, mem_ctx, + &alias_pol, + &sid_array, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + for (i = 0; i < sid_array.num_sids; i++) { + struct dom_sid_buf sid_str; + + printf("\tsid:[%s]\n", + dom_sid_str_buf(sid_array.sids[i].sid, &sid_str)); + } + + dcerpc_samr_Close(b, mem_ctx, &alias_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + done: + return status; +} + +/* Query alias info */ + +static NTSTATUS cmd_samr_query_aliasinfo(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle connect_pol, domain_pol, alias_pol; + NTSTATUS status, result; + uint32_t alias_rid; + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + union samr_AliasInfo *info = NULL; + enum samr_AliasInfoEnum level = ALIASINFOALL; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 */ + + status = rpccli_try_samr_connects(cli, mem_ctx, + SEC_FLAG_MAXIMUM_ALLOWED, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Open handle on domain */ + + status = get_domain_handle(cli, mem_ctx, argv[1], + &connect_pol, + SEC_FLAG_MAXIMUM_ALLOWED, + &domain_sid, + &domain_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Open handle on alias */ + + status = dcerpc_samr_OpenAlias(b, mem_ctx, + &domain_pol, + access_mask, + alias_rid, + &alias_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = dcerpc_samr_QueryAliasInfo(b, mem_ctx, + &alias_pol, + level, + &info, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = 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; + } + + dcerpc_samr_Close(b, mem_ctx, &alias_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + done: + return status; +} + + +/* 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) +{ + struct policy_handle connect_pol, domain_pol, alias_pol; + NTSTATUS status, result; + uint32_t alias_rid; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + struct dcerpc_binding_handle *b = cli->binding_handle; + int error = 0; + + if (argc != 3) { + printf("Usage: %s builtin|domain [rid|name]\n", argv[0]); + return NT_STATUS_OK; + } + + alias_rid = smb_strtoul(argv[2], NULL, 10, &error, SMB_STR_STANDARD); + if (error != 0) { + return NT_STATUS_INVALID_PARAMETER; + } + + + /* Open SAMR handle */ + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Open handle on domain */ + + status = get_domain_handle(cli, mem_ctx, argv[1], + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Open handle on alias */ + + status = dcerpc_samr_OpenAlias(b, mem_ctx, + &domain_pol, + access_mask, + alias_rid, + &alias_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + 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]); + + status = dcerpc_samr_LookupNames(b, mem_ctx, + &domain_pol, + 1, + &lsa_acct_name, + &rids, + &types, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (NT_STATUS_IS_OK(result)) { + if (rids.count != 1) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (types.count != 1) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + + status = dcerpc_samr_OpenAlias(b, mem_ctx, + &domain_pol, + access_mask, + rids.ids[0], + &alias_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + } + } + + status = dcerpc_samr_DeleteDomAlias(b, mem_ctx, + &alias_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + done: + return status; +} + +/* 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) +{ + struct policy_handle connect_pol, domain_pol; + NTSTATUS status, result; + uint32_t start_idx=0, max_entries=250, max_size = 0xffff, num_entries = 0, i; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + uint32_t 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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 */ + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Get domain policy handle */ + + status = dcerpc_samr_OpenDomain(b, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + /* Query display info */ + + do { + + if (!got_params) + dcerpc_get_query_dispinfo_params( + loop_count, &max_entries, &max_size); + + switch (opcode) { + case NDR_SAMR_QUERYDISPLAYINFO: + status = dcerpc_samr_QueryDisplayInfo(b, mem_ctx, + &domain_pol, + info_level, + start_idx, + max_entries, + max_size, + &total_size, + &returned_size, + &info, + &result); + break; + case NDR_SAMR_QUERYDISPLAYINFO2: + status = dcerpc_samr_QueryDisplayInfo2(b, mem_ctx, + &domain_pol, + info_level, + start_idx, + max_entries, + max_size, + &total_size, + &returned_size, + &info, + &result); + + break; + case NDR_SAMR_QUERYDISPLAYINFO3: + status = dcerpc_samr_QueryDisplayInfo3(b, mem_ctx, + &domain_pol, + info_level, + start_idx, + max_entries, + max_size, + &total_size, + &returned_size, + &info, + &result); + + break; + default: + return NT_STATUS_INVALID_PARAMETER; + } + + if (!NT_STATUS_IS_OK(status)) { + break; + } + status = result; + 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)); + + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + done: + return status; +} + +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) +{ + struct policy_handle connect_pol, domain_pol; + NTSTATUS status, result; + uint32_t switch_level = 2; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + union samr_DomainInfo *info = NULL; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 */ + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Get domain policy handle */ + + status = dcerpc_samr_OpenDomain(b, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + /* Query domain info */ + + status = dcerpc_samr_QueryDomainInfo(b, mem_ctx, + &domain_pol, + switch_level, + &info, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = 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->general); + break; + case 3: + display_sam_dom_info_3(&info->info3); + break; + case 4: + display_sam_dom_info_4(&info->oem); + 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: + + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + return status; +} + +/* Create domain user */ + +static NTSTATUS cmd_samr_create_dom_user(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle connect_pol, domain_pol, user_pol; + NTSTATUS status, result; + struct lsa_String acct_name; + uint32_t acb_info; + uint32_t acct_flags, user_rid; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + uint32_t access_granted = 0; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 */ + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Get domain policy handle */ + + status = dcerpc_samr_OpenDomain(b, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = 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; + + status = dcerpc_samr_CreateUser2(b, mem_ctx, + &domain_pol, + &acct_name, + acb_info, + acct_flags, + &user_pol, + &access_granted, + &user_rid, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = dcerpc_samr_Close(b, mem_ctx, &user_pol, &result); + if (!NT_STATUS_IS_OK(status)) goto done; + + status = dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + if (!NT_STATUS_IS_OK(status)) goto done; + + status = dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + if (!NT_STATUS_IS_OK(status)) goto done; + + done: + return status; +} + +/* Create domain group */ + +static NTSTATUS cmd_samr_create_dom_group(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle connect_pol, domain_pol, group_pol; + NTSTATUS status, result; + struct lsa_String grp_name; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + uint32_t rid = 0; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 */ + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Get domain policy handle */ + + status = dcerpc_samr_OpenDomain(b, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + /* Create domain user */ + status = dcerpc_samr_CreateDomainGroup(b, mem_ctx, + &domain_pol, + &grp_name, + MAXIMUM_ALLOWED_ACCESS, + &group_pol, + &rid, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = dcerpc_samr_Close(b, mem_ctx, &group_pol, &result); + if (!NT_STATUS_IS_OK(status)) goto done; + + status = dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + if (!NT_STATUS_IS_OK(status)) goto done; + + status = dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + if (!NT_STATUS_IS_OK(status)) goto done; + + done: + return status; +} + +/* Create domain alias */ + +static NTSTATUS cmd_samr_create_dom_alias(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle connect_pol, domain_pol, alias_pol; + NTSTATUS status, result; + struct lsa_String alias_name; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + uint32_t rid = 0; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 */ + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Get domain policy handle */ + + status = dcerpc_samr_OpenDomain(b, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + /* Create domain user */ + + status = dcerpc_samr_CreateDomAlias(b, mem_ctx, + &domain_pol, + &alias_name, + MAXIMUM_ALLOWED_ACCESS, + &alias_pol, + &rid, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + + status = dcerpc_samr_Close(b, mem_ctx, &alias_pol, &result); + if (!NT_STATUS_IS_OK(status)) goto done; + + status = dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + if (!NT_STATUS_IS_OK(status)) goto done; + + status = dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + if (!NT_STATUS_IS_OK(status)) goto done; + + done: + return status; +} + +/* Lookup sam names */ + +static NTSTATUS cmd_samr_lookup_names(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS status, result; + struct policy_handle connect_pol, domain_pol; + uint32_t num_names; + struct samr_Ids rids, name_types; + int i; + struct lsa_String *names = NULL; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 */ + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = get_domain_handle(cli, mem_ctx, argv[1], + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Look up names */ + + num_names = argc - 2; + + if ((names = talloc_array(mem_ctx, struct lsa_String, num_names)) == NULL) { + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + status = NT_STATUS_NO_MEMORY; + goto done; + } + + for (i = 0; i < num_names; i++) { + init_lsa_String(&names[i], argv[i + 2]); + } + + status = dcerpc_samr_LookupNames(b, mem_ctx, + &domain_pol, + num_names, + names, + &rids, + &name_types, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + if (rids.count != num_names) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (name_types.count != num_names) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + 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]); + + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + done: + return status; +} + +/* Lookup sam rids */ + +static NTSTATUS cmd_samr_lookup_rids(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS status, result; + struct policy_handle connect_pol, domain_pol; + uint32_t num_rids, *rids; + struct lsa_Strings names; + struct samr_Ids types; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 */ + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = get_domain_handle(cli, mem_ctx, argv[1], + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Look up rids */ + + num_rids = argc - 2; + + if ((rids = talloc_array(mem_ctx, uint32_t, num_rids)) == NULL) { + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + status = NT_STATUS_NO_MEMORY; + goto done; + } + + for (i = 0; i < argc - 2; i++) + sscanf(argv[i + 2], "%i", &rids[i]); + + status = dcerpc_samr_LookupRids(b, mem_ctx, + &domain_pol, + num_rids, + rids, + &names, + &types, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + status = result; + if (!NT_STATUS_IS_OK(result) && + !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) + goto done; + + /* Display results */ + if (num_rids != names.count) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (num_rids != types.count) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + + for (i = 0; i < num_rids; i++) { + printf("rid 0x%x: %s (%d)\n", + rids[i], names.names[i].string, types.ids[i]); + } + + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + done: + return status; +} + +/* 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 status, result; + struct policy_handle connect_pol, domain_pol, group_pol; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 */ + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = dcerpc_samr_OpenDomain(b, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = 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]); + + status = dcerpc_samr_LookupNames(b, mem_ctx, + &domain_pol, + 1, + &lsa_acct_name, + &group_rids, + &name_types, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + if (group_rids.count != 1) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (name_types.count != 1) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + + status = dcerpc_samr_OpenGroup(b, mem_ctx, + &domain_pol, + access_mask, + group_rids.ids[0], + &group_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + } + + /* Delete group */ + + status = dcerpc_samr_DeleteDomainGroup(b, mem_ctx, + &group_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + /* Display results */ + + dcerpc_samr_Close(b, mem_ctx, &group_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + + done: + return status; +} + +/* 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 status, result; + struct policy_handle connect_pol, domain_pol, user_pol; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 */ + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = dcerpc_samr_OpenDomain(b, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = 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]); + + status = dcerpc_samr_LookupNames(b, mem_ctx, + &domain_pol, + 1, + &lsa_acct_name, + &user_rids, + &name_types, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + if (user_rids.count != 1) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (name_types.count != 1) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + + status = dcerpc_samr_OpenUser(b, mem_ctx, + &domain_pol, + access_mask, + user_rids.ids[0], + &user_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + } + + /* Delete user */ + + status = dcerpc_samr_DeleteUser(b, mem_ctx, + &user_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + /* Display results */ + + dcerpc_samr_Close(b, mem_ctx, &user_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + + done: + return status; +} + +/********************************************************************** + * 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) +{ + struct policy_handle connect_pol, domain_pol, user_pol, *pol; + NTSTATUS status, result; + uint32_t sec_info = SECINFO_DACL; + uint32_t user_rid = 0; + TALLOC_CTX *ctx = NULL; + struct sec_desc_buf *sec_desc_buf=NULL; + bool domain = False; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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]); + } + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + if (domain || user_rid) { + status = dcerpc_samr_OpenDomain(b, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + } + + if (user_rid) { + status = dcerpc_samr_OpenUser(b, mem_ctx, + &domain_pol, + MAXIMUM_ALLOWED_ACCESS, + user_rid, + &user_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = 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 */ + + status = dcerpc_samr_QuerySecurity(b, mem_ctx, + pol, + sec_info, + &sec_desc_buf, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + display_sec_desc(sec_desc_buf->sd); + + dcerpc_samr_Close(b, mem_ctx, &user_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); +done: + talloc_destroy(ctx); + return status; +} + +static NTSTATUS cmd_samr_get_usrdom_pwinfo(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS status, result; + struct policy_handle connect_pol, domain_pol, user_pol; + struct samr_PwInfo info; + uint32_t rid; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc != 2) { + printf("Usage: %s rid\n", argv[0]); + return NT_STATUS_OK; + } + + sscanf(argv[1], "%i", &rid); + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = dcerpc_samr_OpenDomain(b, mem_ctx, + &connect_pol, + MAXIMUM_ALLOWED_ACCESS, + &domain_sid, + &domain_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = dcerpc_samr_OpenUser(b, mem_ctx, + &domain_pol, + MAXIMUM_ALLOWED_ACCESS, + rid, + &user_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = dcerpc_samr_GetUserPwInfo(b, mem_ctx, + &user_pol, + &info, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + status = result; + if (NT_STATUS_IS_OK(result)) { + printf("%s\n", + NDR_PRINT_STRUCT_STRING(mem_ctx, + samr_PwInfo, &info)); + } + + done: + dcerpc_samr_Close(b, mem_ctx, &user_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + + return status; +} + +static NTSTATUS cmd_samr_get_dom_pwinfo(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS status, result; + struct lsa_String domain_name; + struct samr_PwInfo info; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc < 1 || argc > 3) { + printf("Usage: %s <domain>\n", argv[0]); + return NT_STATUS_OK; + } + + init_lsa_String(&domain_name, argv[1]); + + status = dcerpc_samr_GetDomPwInfo(b, mem_ctx, + &domain_name, + &info, + &result); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + 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) +{ + struct policy_handle connect_pol, domain_pol; + NTSTATUS status, result; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + struct lsa_String domain_name; + struct dom_sid *sid = NULL; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc != 2) { + printf("Usage: %s domain_name\n", argv[0]); + return NT_STATUS_OK; + } + + init_lsa_String(&domain_name, argv[1]); + + status = rpccli_try_samr_connects(cli, mem_ctx, + access_mask, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = dcerpc_samr_OpenDomain(b, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = dcerpc_samr_LookupDomain(b, mem_ctx, + &connect_pol, + &domain_name, + &sid, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + if (NT_STATUS_IS_OK(result)) { + struct dom_sid_buf sid_str; + printf("SAMR_LOOKUP_DOMAIN: Domain Name: %s Domain SID: %s\n", + argv[1], + dom_sid_str_buf(sid, &sid_str)); + } + + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); +done: + return status; +} + +/* Change user password */ + +static NTSTATUS cmd_samr_chgpasswd(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle connect_pol; + struct policy_handle domain_pol = { 0, }; + struct policy_handle user_pol = { 0, }; + NTSTATUS status, result; + const char *user, *oldpass, *newpass; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + struct samr_Ids rids, types; + struct lsa_String lsa_acct_name; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 */ + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Get domain policy handle */ + + status = dcerpc_samr_OpenDomain(b, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + init_lsa_String(&lsa_acct_name, user); + + status = dcerpc_samr_LookupNames(b, mem_ctx, + &domain_pol, + 1, + &lsa_acct_name, + &rids, + &types, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + if (rids.count != 1) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (types.count != 1) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + + status = dcerpc_samr_OpenUser(b, mem_ctx, + &domain_pol, + access_mask, + rids.ids[0], + &user_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + /* Change user password */ + status = rpccli_samr_chgpasswd_user(cli, mem_ctx, + &user_pol, + newpass, + oldpass); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + done: + if (is_valid_policy_hnd(&user_pol)) { + dcerpc_samr_Close(b, mem_ctx, &user_pol, &result); + } + if (is_valid_policy_hnd(&domain_pol)) { + dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + } + if (is_valid_policy_hnd(&connect_pol)) { + dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + } + + return status; +} + + +/* Change user password */ + +static NTSTATUS cmd_samr_chgpasswd2(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle connect_pol, domain_pol; + NTSTATUS status, result; + const char *user, *oldpass, *newpass; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 */ + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Get domain policy handle */ + + status = dcerpc_samr_OpenDomain(b, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + /* Change user password */ + status = rpccli_samr_chgpasswd_user2(cli, mem_ctx, user, newpass, oldpass); + + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + if (!NT_STATUS_IS_OK(status)) goto done; + + status = dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + if (!NT_STATUS_IS_OK(status)) goto done; + + done: + return status; +} + + +/* Change user password */ + +static NTSTATUS cmd_samr_chgpasswd3(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle connect_pol, domain_pol; + NTSTATUS status, result; + const char *user, *oldpass, *newpass; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + struct samr_DomInfo1 *info = NULL; + struct userPwdChangeFailureInformation *reject = NULL; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc < 4) { + 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 */ + + status = rpccli_try_samr_connects(cli, mem_ctx, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Get domain policy handle */ + + status = dcerpc_samr_OpenDomain(b, mem_ctx, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + /* Change user password */ + status = rpccli_samr_chgpasswd_user3(cli, mem_ctx, + user, + newpass, + oldpass, + &info, + &reject); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION)) { + + display_sam_dom_info_1(info); + + switch (reject->extendedFailureReason) { + case SAM_PWD_CHANGE_PASSWORD_TOO_SHORT: + d_printf("SAM_PWD_CHANGE_PASSWORD_TOO_SHORT\n"); + break; + case SAM_PWD_CHANGE_PWD_IN_HISTORY: + d_printf("SAM_PWD_CHANGE_PWD_IN_HISTORY\n"); + break; + case SAM_PWD_CHANGE_NOT_COMPLEX: + d_printf("SAM_PWD_CHANGE_NOT_COMPLEX\n"); + break; + default: + d_printf("unknown reject reason: %d\n", + reject->extendedFailureReason); + break; + } + } + + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = dcerpc_samr_Close(b, mem_ctx, &domain_pol, &result); + if (!NT_STATUS_IS_OK(status)) goto done; + + status = dcerpc_samr_Close(b, mem_ctx, &connect_pol, &result); + if (!NT_STATUS_IS_OK(status)) goto done; + + done: + return status; +} + +static NTSTATUS cmd_samr_chgpasswd4(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + const char *srv_name_slash = cli->srv_name_slash; + const char *user = NULL; + const char *oldpass = NULL; + const char *newpass = NULL; + NTSTATUS status; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + + if (argc < 4) { + printf("Usage: %s username oldpass newpass\n", argv[0]); + return NT_STATUS_INVALID_PARAMETER; + } + + user = argv[1]; + oldpass = argv[2]; + newpass = argv[3]; + + /* Change user password */ + status = dcerpc_samr_chgpasswd_user4(b, + mem_ctx, + srv_name_slash, + user, + oldpass, + newpass, + &result); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + } + + return status; +} + +static NTSTATUS cmd_samr_setuserinfo_int(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv, + int opcode) +{ + struct policy_handle connect_pol, domain_pol, user_pol; + NTSTATUS status, result; + const char *user, *param; + uint32_t access_mask = MAXIMUM_ALLOWED_ACCESS; + uint32_t level; + uint32_t user_rid; + union samr_UserInfo info; + struct samr_CryptPassword pwd_buf; + struct samr_CryptPasswordEx pwd_buf_ex; + struct samr_EncryptedPasswordAES pwd_buf_aes; + uint8_t nt_hash[16]; + uint8_t lm_hash[16]; + DATA_BLOB session_key; + uint8_t salt_data[16]; + DATA_BLOB salt = { + .data = salt_data, + .length = sizeof(salt_data), + }; + uint8_t password_expired = 0; + struct dcerpc_binding_handle *b = cli->binding_handle; + TALLOC_CTX *frame = NULL; + int rc; + + if (argc < 4) { + printf("Usage: %s username level password [password_expired]\n", + argv[0]); + return NT_STATUS_INVALID_PARAMETER; + } + + frame = talloc_stackframe(); + + user = argv[1]; + level = atoi(argv[2]); + param = argv[3]; + + if (argc >= 5) { + password_expired = atoi(argv[4]); + } + + status = cli_get_session_key(frame, cli, &session_key); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + generate_nonce_buffer(salt.data, salt.length); + + switch(level) { + case 18: + case 21: + nt_lm_owf_gen(param, nt_hash, lm_hash); + break; + case 23: + case 24: + status = init_samr_CryptPassword(param, &session_key, &pwd_buf); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + break; + case 25: + case 26: + status = init_samr_CryptPasswordEx(param, &session_key, &pwd_buf_ex); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + break; + case 31: + status = init_samr_CryptPasswordAES(frame, + param, + &salt, + &session_key, + &pwd_buf_aes); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + break; + default: + break; + } + + switch (level) { + case 18: + { + DATA_BLOB in,out; + in = data_blob_const(nt_hash, 16); + out = data_blob_talloc_zero(frame, 16); + if (out.data == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + rc = sess_crypt_blob(&out, &in, &session_key, SAMBA_GNUTLS_ENCRYPT); + if (rc != 0) { + status = gnutls_error_to_ntstatus(rc, + NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER); + } + memcpy(nt_hash, out.data, out.length); + } + { + DATA_BLOB in,out; + in = data_blob_const(lm_hash, 16); + out = data_blob_talloc_zero(frame, 15); + if (out.data == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + rc = sess_crypt_blob(&out, &in, &session_key, SAMBA_GNUTLS_ENCRYPT); + if (rc != 0) { + status = gnutls_error_to_ntstatus(rc, + NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER); + } + memcpy(lm_hash, out.data, out.length); + } + + memcpy(info.info18.nt_pwd.hash, nt_hash, 16); + memcpy(info.info18.lm_pwd.hash, lm_hash, 16); + info.info18.nt_pwd_active = true; + info.info18.lm_pwd_active = true; + info.info18.password_expired = password_expired; + + break; + case 21: + ZERO_STRUCT(info.info21); + + info.info21.fields_present = SAMR_FIELD_NT_PASSWORD_PRESENT | + SAMR_FIELD_LM_PASSWORD_PRESENT; + if (argc >= 5) { + info.info21.fields_present |= SAMR_FIELD_EXPIRED_FLAG; + info.info21.password_expired = password_expired; + } + + info.info21.lm_password_set = true; + info.info21.lm_owf_password.length = 16; + info.info21.lm_owf_password.size = 16; + + info.info21.nt_password_set = true; + info.info21.nt_owf_password.length = 16; + info.info21.nt_owf_password.size = 16; + + { + DATA_BLOB in,out; + in = data_blob_const(nt_hash, 16); + out = data_blob_talloc_zero(frame, 16); + if (out.data == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + rc = sess_crypt_blob(&out, &in, &session_key, SAMBA_GNUTLS_ENCRYPT); + if (rc != 0) { + status = gnutls_error_to_ntstatus(rc, + NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER); + } + info.info21.nt_owf_password.array = + (uint16_t *)talloc_memdup(frame, out.data, 16); + } + { + DATA_BLOB in,out; + in = data_blob_const(lm_hash, 16); + out = data_blob_talloc_zero(frame, 16); + rc = sess_crypt_blob(&out, &in, &session_key, SAMBA_GNUTLS_ENCRYPT); + if (rc != 0) { + status = gnutls_error_to_ntstatus(rc, + NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER); + } + info.info21.lm_owf_password.array = + (uint16_t *)talloc_memdup(frame, out.data, 16); + if (out.data == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + } + + break; + case 23: + ZERO_STRUCT(info.info23); + + info.info23.info.fields_present = SAMR_FIELD_NT_PASSWORD_PRESENT | + SAMR_FIELD_LM_PASSWORD_PRESENT; + if (argc >= 5) { + info.info23.info.fields_present |= SAMR_FIELD_EXPIRED_FLAG; + info.info23.info.password_expired = password_expired; + } + + info.info23.password = pwd_buf; + + break; + case 24: + info.info24.password = pwd_buf; + info.info24.password_expired = password_expired; + + break; + case 25: + ZERO_STRUCT(info.info25); + + info.info25.info.fields_present = SAMR_FIELD_NT_PASSWORD_PRESENT | + SAMR_FIELD_LM_PASSWORD_PRESENT; + if (argc >= 5) { + info.info25.info.fields_present |= SAMR_FIELD_EXPIRED_FLAG; + info.info25.info.password_expired = password_expired; + } + + info.info25.password = pwd_buf_ex; + + break; + case 26: + info.info26.password = pwd_buf_ex; + info.info26.password_expired = password_expired; + + break; + case 31: + info.info31.password = pwd_buf_aes; + info.info31.password_expired = password_expired; + break; + default: + status = NT_STATUS_INVALID_INFO_CLASS; + goto done; + } + + /* Get sam policy handle */ + + status = rpccli_try_samr_connects(cli, frame, + MAXIMUM_ALLOWED_ACCESS, + &connect_pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* Get domain policy handle */ + + status = dcerpc_samr_OpenDomain(b, frame, + &connect_pol, + access_mask, + &domain_sid, + &domain_pol, + &result); + + if (!NT_STATUS_IS_OK(status)) + goto done; + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + user_rid = strtol(user, NULL, 0); + if (user_rid) { + status = dcerpc_samr_OpenUser(b, frame, + &domain_pol, + access_mask, + user_rid, + &user_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = result; + } + + if (NT_STATUS_EQUAL(status, 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, user); + + status = dcerpc_samr_LookupNames(b, frame, + &domain_pol, + 1, + &lsa_acct_name, + &rids, + &types, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + if (rids.count != 1) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (types.count != 1) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + + status = dcerpc_samr_OpenUser(b, frame, + &domain_pol, + access_mask, + rids.ids[0], + &user_pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + } + + switch (opcode) { + case NDR_SAMR_SETUSERINFO: + status = dcerpc_samr_SetUserInfo(b, frame, + &user_pol, + level, + &info, + &result); + break; + case NDR_SAMR_SETUSERINFO2: + status = dcerpc_samr_SetUserInfo2(b, frame, + &user_pol, + level, + &info, + &result); + break; + default: + status = NT_STATUS_INVALID_PARAMETER; + goto done; + } + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("status: %s\n", nt_errstr(status))); + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + DEBUG(0,("result: %s\n", nt_errstr(status))); + goto done; + } + + status = NT_STATUS_OK; + done: + TALLOC_FREE(frame); + return status; +} + +static NTSTATUS cmd_samr_setuserinfo(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + return cmd_samr_setuserinfo_int(cli, mem_ctx, argc, argv, + NDR_SAMR_SETUSERINFO); +} + +static NTSTATUS cmd_samr_setuserinfo2(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + return cmd_samr_setuserinfo_int(cli, mem_ctx, argc, argv, + NDR_SAMR_SETUSERINFO2); +} + +static NTSTATUS cmd_samr_get_dispinfo_idx(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + NTSTATUS status, result; + struct policy_handle connect_handle; + struct policy_handle domain_handle = { 0, }; + uint16_t level = 1; + struct lsa_String name; + uint32_t idx = 0; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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_FLAG_MAXIMUM_ALLOWED, + &connect_handle); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = dcerpc_samr_OpenDomain(b, mem_ctx, + &connect_handle, + SEC_FLAG_MAXIMUM_ALLOWED, + &domain_sid, + &domain_handle, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto done; + } + + status = dcerpc_samr_GetDisplayEnumerationIndex(b, mem_ctx, + &domain_handle, + level, + &name, + &idx, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = result; + + 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)) { + dcerpc_samr_Close(b, mem_ctx, &domain_handle, &result); + } + if (is_valid_policy_hnd(&connect_handle)) { + dcerpc_samr_Close(b, mem_ctx, &connect_handle, &result); + } + + return status; + +} +/* List of commands exported by this module */ + +struct cmd_set samr_commands[] = { + + { + .name = "SAMR", + }, + + { + .name = "queryuser", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_query_user, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Query user info", + .usage = "", + }, + { + .name = "querygroup", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_query_group, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Query group info", + .usage = "", + }, + { + .name = "queryusergroups", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_query_usergroups, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Query user groups", + .usage = "", + }, + { + .name = "queryuseraliases", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_query_useraliases, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Query user aliases", + .usage = "", + }, + { + .name = "querygroupmem", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_query_groupmem, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Query group membership", + .usage = "", + }, + { + .name = "queryaliasmem", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_query_aliasmem, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Query alias membership", + .usage = "", + }, + { + .name = "queryaliasinfo", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_query_aliasinfo, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Query alias info", + .usage = "", + }, + { + .name = "deletealias", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_delete_alias, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Delete an alias", + .usage = "", + }, + { + .name = "querydispinfo", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_query_dispinfo, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Query display info", + .usage = "", + }, + { + .name = "querydispinfo2", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_query_dispinfo2, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Query display info", + .usage = "", + }, + { + .name = "querydispinfo3", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_query_dispinfo3, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Query display info", + .usage = "", + }, + { + .name = "querydominfo", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_query_dominfo, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Query domain info", + .usage = "", + }, + { + .name = "enumdomusers", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_enum_dom_users, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Enumerate domain users", + .usage = "", + }, + { + .name = "enumdomgroups", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_enum_dom_groups, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Enumerate domain groups", + .usage = "", + }, + { + .name = "enumalsgroups", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_enum_als_groups, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Enumerate alias groups", + .usage = "", + }, + { + .name = "enumdomains", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_enum_domains, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Enumerate domains", + .usage = "", + }, + + { + .name = "createdomuser", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_create_dom_user, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Create domain user", + .usage = "", + }, + { + .name = "createdomgroup", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_create_dom_group, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Create domain group", + .usage = "", + }, + { + .name = "createdomalias", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_create_dom_alias, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Create domain alias", + .usage = "", + }, + { + .name = "samlookupnames", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_lookup_names, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Look up names", + .usage = "", + }, + { + .name = "samlookuprids", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_lookup_rids, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Look up names", + .usage = "", + }, + { + .name = "deletedomgroup", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_delete_dom_group, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Delete domain group", + .usage = "", + }, + { + .name = "deletedomuser", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_delete_dom_user, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Delete domain user", + .usage = "", + }, + { + .name = "samquerysecobj", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_query_sec_obj, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Query SAMR security object", + .usage = "", + }, + { + .name = "getdompwinfo", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_get_dom_pwinfo, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Retrieve domain password info", + .usage = "", + }, + { + .name = "getusrdompwinfo", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_get_usrdom_pwinfo, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Retrieve user domain password info", + .usage = "", + }, + + { + .name = "lookupdomain", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_lookup_domain, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Lookup Domain Name", + .usage = "", + }, + { + .name = "chgpasswd", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_chgpasswd, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Change user password", + .usage = "", + }, + { + .name = "chgpasswd2", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_chgpasswd2, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Change user password", + .usage = "", + }, + { + .name = "chgpasswd3", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_chgpasswd3, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Change user password", + .usage = "", + }, + { + .name = "chgpasswd4", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_chgpasswd4, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Change user password", + .usage = "", + }, + { + .name = "getdispinfoidx", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_get_dispinfo_idx, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Get Display Information Index", + .usage = "", + }, + { + .name = "setuserinfo", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_setuserinfo, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Set user info", + .usage = "", + }, + { + .name = "setuserinfo2", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_samr_setuserinfo2, + .wfn = NULL, + .table = &ndr_table_samr, + .rpc_pipe = NULL, + .description = "Set user info2", + .usage = "", + }, + { + .name = NULL, + }, +}; diff --git a/source3/rpcclient/cmd_shutdown.c b/source3/rpcclient/cmd_shutdown.c new file mode 100644 index 0000000..72027a8 --- /dev/null +++ b/source3/rpcclient/cmd_shutdown.c @@ -0,0 +1,137 @@ +/* + 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_t 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[] = { + + { + .name = "SHUTDOWN", + }, + +#if 0 + { + .name = "shutdowninit", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_shutdown_init, + .wfn = NULL, + .table = &ndr_table_initshutdown.syntax_id, + .rpc_pipe = "Remote Shutdown (over shutdown pipe)", + .description = "syntax: shutdown [-m message] " + "[-t timeout] [-r] [-h] [-f] (-r == " + "reboot, -h == halt, -f == force)", + }, + + { + .name = "shutdownabort", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_shutdown_abort, + .wfn = NULL, + .table = &ndr_table_initshutdown.syntax_id, + .rpc_pipe = "Abort Shutdown (over shutdown pipe)", + .description = "syntax: shutdownabort", + }, +#endif + { + .name = NULL, + }, +}; diff --git a/source3/rpcclient/cmd_spoolss.c b/source3/rpcclient/cmd_spoolss.c new file mode 100644 index 0000000..f425e75 --- /dev/null +++ b/source3/rpcclient/cmd_spoolss.c @@ -0,0 +1,4543 @@ +/* + 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 + Copyright (C) Guenther Deschner 2009 + + 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" +#include "../librpc/gen_ndr/ndr_spoolss_c.h" +#include "../librpc/gen_ndr/ndr_spoolss.h" +#include "rpc_client/cli_spoolss.h" +#include "rpc_client/init_spoolss.h" +#include "nt_printing.h" +#include "../libcli/security/display_sec.h" +#include "../libcli/security/security_descriptor.h" +#include "../libcli/registry/util_reg.h" +#include "libsmb/libsmb.h" +#include "lib/util/smb_strtox.h" +#include "lib/util/string_wrappers.h" +#include "lib/cmdline/cmdline.h" + +#define RPCCLIENT_PRINTERNAME(_printername, _cli, _arg) \ +{ \ + _printername = talloc_asprintf_strupper_m(mem_ctx, "%s\\%s", \ + _cli->srv_name_slash, _arg); \ + W_ERROR_HAVE_NO_MEMORY(_printername); \ +} + + +/** + * @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 dependent directory\n")); + do { + i++; + } while ( (archi_table[i].long_archi!=NULL ) && + strcasecmp_m(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; + struct policy_handle hnd; + uint32_t access_mask = PRINTER_ALL_ACCESS; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc < 2) { + printf("Usage: %s <printername> [access_mask]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 3) { + sscanf(argv[2], "%x", &access_mask); + } + + /* Open the printer handle */ + + werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + argv[1], + access_mask, + &hnd); + if (W_ERROR_IS_OK(werror)) { + printf("Printer %s opened successfully\n", argv[1]); + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &werror); + + if (!W_ERROR_IS_OK(werror)) { + printf("Error closing printer handle! (%s)\n", + get_dos_error_msg(werror)); + } + } + + return werror; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_open_printer(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR werror; + struct policy_handle hnd; + uint32_t access_mask = PRINTER_ALL_ACCESS; + NTSTATUS status; + struct spoolss_DevmodeContainer devmode_ctr; + struct dcerpc_binding_handle *b = cli->binding_handle; + + ZERO_STRUCT(devmode_ctr); + + if (argc < 2) { + printf("Usage: %s <printername> [access_mask]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 3) { + sscanf(argv[2], "%x", &access_mask); + } + + /* Open the printer handle */ + + status = dcerpc_spoolss_OpenPrinter(b, mem_ctx, + argv[1], + NULL, + devmode_ctr, + access_mask, + &hnd, + &werror); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + if (W_ERROR_IS_OK(werror)) { + printf("Printer %s opened successfully\n", argv[1]); + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &werror); + + if (!W_ERROR_IS_OK(werror)) { + printf("Error closing printer handle! (%s)\n", + get_dos_error_msg(werror)); + } + } + + return werror; +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_info0(struct spoolss_PrinterInfo0 *r) +{ + if (!r) + return; + + printf("\tprintername:[%s]\n", r->printername); + printf("\tservername:[%s]\n", r->servername); + printf("\tcjobs:[0x%x]\n", r->cjobs); + printf("\ttotal_jobs:[0x%x]\n", r->total_jobs); + printf("\ttotal_bytes:[0x%x]\n", r->total_bytes); + printf("\t:date: [%d]-[%d]-[%d] (%d)\n", r->time.year, r->time.month, + r->time.day, r->time.day_of_week); + printf("\t:time: [%d]-[%d]-[%d]-[%d]\n", r->time.hour, r->time.minute, + r->time.second, r->time.millisecond); + + printf("\tglobal_counter:[0x%x]\n", r->global_counter); + printf("\ttotal_pages:[0x%x]\n", r->total_pages); + + printf("\tversion:[0x%x]\n", r->version); + printf("\tfree_build:[0x%x]\n", r->free_build); + printf("\tspooling:[0x%x]\n", r->spooling); + printf("\tmax_spooling:[0x%x]\n", r->max_spooling); + printf("\tsession_counter:[0x%x]\n", r->session_counter); + printf("\tnum_error_out_of_paper:[0x%x]\n", r->num_error_out_of_paper); + printf("\tnum_error_not_ready:[0x%x]\n", r->num_error_not_ready); + printf("\tjob_error:[0x%x]\n", r->job_error); + printf("\tnumber_of_processors:[0x%x]\n", r->number_of_processors); + printf("\tprocessor_type:[0x%x]\n", r->processor_type); + printf("\thigh_part_total_bytes:[0x%x]\n", r->high_part_total_bytes); + printf("\tchange_id:[0x%x]\n", r->change_id); + printf("\tlast_error: %s\n", win_errstr(r->last_error)); + printf("\tstatus:[0x%x]\n", r->status); + printf("\tenumerate_network_printers:[0x%x]\n", r->enumerate_network_printers); + printf("\tc_setprinter:[0x%x]\n", r->c_setprinter); + printf("\tprocessor_architecture:[0x%x]\n", r->processor_architecture); + printf("\tprocessor_level:[0x%x]\n", r->processor_level); + printf("\tref_ic:[0x%x]\n", r->ref_ic); + printf("\treserved2:[0x%x]\n", r->reserved2); + printf("\treserved3:[0x%x]\n", r->reserved3); + + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_info1(struct spoolss_PrinterInfo1 *r) +{ + printf("\tflags:[0x%x]\n", r->flags); + printf("\tname:[%s]\n", r->name); + printf("\tdescription:[%s]\n", r->description); + printf("\tcomment:[%s]\n", r->comment); + + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_info2(struct spoolss_PrinterInfo2 *r) +{ + printf("\tservername:[%s]\n", r->servername); + printf("\tprintername:[%s]\n", r->printername); + printf("\tsharename:[%s]\n", r->sharename); + printf("\tportname:[%s]\n", r->portname); + printf("\tdrivername:[%s]\n", r->drivername); + printf("\tcomment:[%s]\n", r->comment); + printf("\tlocation:[%s]\n", r->location); + printf("\tsepfile:[%s]\n", r->sepfile); + printf("\tprintprocessor:[%s]\n", r->printprocessor); + printf("\tdatatype:[%s]\n", r->datatype); + printf("\tparameters:[%s]\n", r->parameters); + printf("\tattributes:[0x%x]\n", r->attributes); + printf("\tpriority:[0x%x]\n", r->priority); + printf("\tdefaultpriority:[0x%x]\n", r->defaultpriority); + printf("\tstarttime:[0x%x]\n", r->starttime); + printf("\tuntiltime:[0x%x]\n", r->untiltime); + printf("\tstatus:[0x%x]\n", r->status); + printf("\tcjobs:[0x%x]\n", r->cjobs); + printf("\taverageppm:[0x%x]\n", r->averageppm); + + if (r->secdesc) + display_sec_desc(r->secdesc); + + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_info3(struct spoolss_PrinterInfo3 *r) +{ + display_sec_desc(r->secdesc); + + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_info4(struct spoolss_PrinterInfo4 *r) +{ + printf("\tservername:[%s]\n", r->servername); + printf("\tprintername:[%s]\n", r->printername); + printf("\tattributes:[0x%x]\n", r->attributes); + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_info5(struct spoolss_PrinterInfo5 *r) +{ + printf("\tprintername:[%s]\n", r->printername); + printf("\tportname:[%s]\n", r->portname); + printf("\tattributes:[0x%x]\n", r->attributes); + printf("\tdevice_not_selected_timeout:[0x%x]\n", r->device_not_selected_timeout); + printf("\ttransmission_retry_timeout:[0x%x]\n", r->transmission_retry_timeout); + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_info6(struct spoolss_PrinterInfo6 *r) +{ + printf("\tstatus:[0x%x]\n", r->status); + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_info7(struct spoolss_PrinterInfo7 *r) +{ + printf("\tguid:[%s]\n", r->guid); + printf("\taction:[0x%x]\n", r->action); + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_enum_printers(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR result; + uint32_t level = 1; + union spoolss_PrinterInfo *info; + uint32_t i, count; + const char *name; + uint32_t flags = PRINTER_ENUM_LOCAL; + + if (argc > 4) { + printf("Usage: %s [level] [name] [flags]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + level = atoi(argv[1]); + } + + if (argc >= 3) { + name = argv[2]; + } else { + name = cli->srv_name_slash; + } + + if (argc == 4) { + flags = atoi(argv[3]); + } + + result = rpccli_spoolss_enumprinters(cli, mem_ctx, + flags, + name, + level, + 0, + &count, + &info); + if (W_ERROR_IS_OK(result)) { + + if (!count) { + printf ("No printers returned.\n"); + goto done; + } + + for (i = 0; i < count; i++) { + switch (level) { + case 0: + display_print_info0(&info[i].info0); + break; + case 1: + display_print_info1(&info[i].info1); + break; + case 2: + display_print_info2(&info[i].info2); + break; + case 3: + display_print_info3(&info[i].info3); + break; + case 4: + display_print_info4(&info[i].info4); + break; + case 5: + display_print_info5(&info[i].info5); + break; + case 6: + display_print_info6(&info[i].info6); + break; + default: + printf("unknown info level %d\n", level); + goto done; + } + } + } + done: + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static void display_port_info_1(struct spoolss_PortInfo1 *r) +{ + printf("\tPort Name:\t[%s]\n", r->port_name); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_port_info_2(struct spoolss_PortInfo2 *r) +{ + printf("\tPort Name:\t[%s]\n", r->port_name); + printf("\tMonitor Name:\t[%s]\n", r->monitor_name); + printf("\tDescription:\t[%s]\n", r->description); + printf("\tPort Type:\t" ); + if (r->port_type) { + int comma = 0; /* hack */ + printf( "[" ); + if (r->port_type & SPOOLSS_PORT_TYPE_READ) { + printf( "Read" ); + comma = 1; + } + if (r->port_type & SPOOLSS_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 (r->port_type & SPOOLSS_PORT_TYPE_REDIRECTED) { + printf( "%sRedirected", comma ? ", " : "" ); + comma = 1; + } + if (r->port_type & SPOOLSS_PORT_TYPE_NET_ATTACHED) { + printf( "%sNet-Attached", comma ? ", " : "" ); + } + printf( "]\n" ); + } else { + printf( "[Unset]\n" ); + } + printf("\tReserved:\t[%d]\n", r->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_t level = 1; + uint32_t count; + union spoolss_PortInfo *info; + + if (argc > 2) { + printf("Usage: %s [level]\n", argv[0]); + return WERR_OK; + } + + if (argc == 2) { + level = atoi(argv[1]); + } + + /* Enumerate ports */ + + result = rpccli_spoolss_enumports(cli, mem_ctx, + cli->srv_name_slash, + level, + 0, + &count, + &info); + if (W_ERROR_IS_OK(result)) { + int i; + + for (i = 0; i < count; i++) { + switch (level) { + case 1: + display_port_info_1(&info[i].info1); + break; + case 2: + display_port_info_2(&info[i].info2); + break; + default: + printf("unknown info level %d\n", level); + break; + } + } + } + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_setprinter(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle pol; + WERROR result; + NTSTATUS status; + uint32_t info_level = 2; + union spoolss_PrinterInfo info; + struct spoolss_SetPrinterInfoCtr info_ctr; + struct spoolss_SetPrinterInfo2 info2; + const char *printername, *comment = NULL; + struct spoolss_DevmodeContainer devmode_ctr; + struct sec_desc_buf secdesc_ctr; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc == 1 || argc > 3) { + printf("Usage: %s printername comment\n", argv[0]); + + return WERR_OK; + } + + /* Open a printer handle */ + if (argc == 3) { + comment = argv[2]; + } + + ZERO_STRUCT(devmode_ctr); + ZERO_STRUCT(secdesc_ctr); + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + /* get a printer handle */ + result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + PRINTER_ALL_ACCESS, + &pol); + if (!W_ERROR_IS_OK(result)) + goto done; + + /* Get printer info */ + result = rpccli_spoolss_getprinter(cli, mem_ctx, + &pol, + info_level, + 0, + &info); + if (!W_ERROR_IS_OK(result)) + goto done; + + + /* Modify the comment. */ + spoolss_printerinfo2_to_setprinterinfo2(&info.info2, &info2); + info2.comment = comment; + + info_ctr.level = 2; + info_ctr.info.info2 = &info2; + + status = dcerpc_spoolss_SetPrinter(b, mem_ctx, + &pol, + &info_ctr, + &devmode_ctr, + &secdesc_ctr, + 0, /* command */ + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + if (W_ERROR_IS_OK(result)) + printf("Success in setting comment.\n"); + + done: + if (is_valid_policy_hnd(&pol)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result); + } + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_setprintername(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle pol; + WERROR result; + NTSTATUS status; + uint32_t info_level = 2; + union spoolss_PrinterInfo info; + const char *printername, + *new_printername = NULL; + struct spoolss_SetPrinterInfoCtr info_ctr; + struct spoolss_SetPrinterInfo2 info2; + struct spoolss_DevmodeContainer devmode_ctr; + struct sec_desc_buf secdesc_ctr; + struct dcerpc_binding_handle *b = cli->binding_handle; + + ZERO_STRUCT(devmode_ctr); + ZERO_STRUCT(secdesc_ctr); + + if (argc == 1 || argc > 3) { + printf("Usage: %s printername new_printername\n", argv[0]); + + return WERR_OK; + } + + /* Open a printer handle */ + if (argc == 3) { + new_printername = argv[2]; + } + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + /* get a printer handle */ + result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + PRINTER_ALL_ACCESS, + &pol); + if (!W_ERROR_IS_OK(result)) + goto done; + + /* Get printer info */ + result = rpccli_spoolss_getprinter(cli, mem_ctx, + &pol, + info_level, + 0, + &info); + if (!W_ERROR_IS_OK(result)) + goto done; + + /* Modify the printername. */ + spoolss_printerinfo2_to_setprinterinfo2(&info.info2, &info2); + info2.printername = new_printername; + + info_ctr.level = 2; + info_ctr.info.info2 = &info2; + + status = dcerpc_spoolss_SetPrinter(b, mem_ctx, + &pol, + &info_ctr, + &devmode_ctr, + &secdesc_ctr, + 0, /* command */ + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + if (W_ERROR_IS_OK(result)) + printf("Success in setting printername.\n"); + + done: + if (is_valid_policy_hnd(&pol)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result); + } + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_getprinter(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle pol; + WERROR result; + uint32_t level = 1; + const char *printername; + union spoolss_PrinterInfo info; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc == 1 || argc > 3) { + printf("Usage: %s <printername> [level]\n", argv[0]); + return WERR_OK; + } + + /* Open a printer handle */ + if (argc == 3) { + level = atoi(argv[2]); + } + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + /* get a printer handle */ + + result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + SEC_FLAG_MAXIMUM_ALLOWED, + &pol); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + /* Get printer info */ + + result = rpccli_spoolss_getprinter(cli, mem_ctx, + &pol, + level, + 0, + &info); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + /* Display printer info */ + switch (level) { + case 0: + display_print_info0(&info.info0); + break; + case 1: + display_print_info1(&info.info1); + break; + case 2: + display_print_info2(&info.info2); + break; + case 3: + display_print_info3(&info.info3); + break; + case 4: + display_print_info4(&info.info4); + break; + case 5: + display_print_info5(&info.info5); + break; + case 6: + display_print_info6(&info.info6); + break; + case 7: + display_print_info7(&info.info7); + break; + default: + printf("unknown info level %d\n", level); + break; + } + done: + if (is_valid_policy_hnd(&pol)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result); + } + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static void display_reg_value(const char *name, enum winreg_Type type, DATA_BLOB blob) +{ + const char *text = NULL; + + switch(type) { + case REG_DWORD: + if (blob.length >= sizeof(uint32_t)) { + printf("%s: REG_DWORD: 0x%08x\n", name, IVAL(blob.data,0)); + } else { + printf("%s: REG_DWORD: <invalid>\n", name); + } + break; + case REG_SZ: + pull_reg_sz(talloc_tos(), &blob, &text); + printf("%s: REG_SZ: %s\n", name, text ? text : ""); + break; + case REG_BINARY: { + char *hex = hex_encode_talloc(NULL, blob.data, blob.length); + size_t i, len; + printf("%s: REG_BINARY:", name); + 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_t i; + const char **values; + + if (!pull_reg_multi_sz(NULL, &blob, &values)) { + d_printf("pull_reg_multi_sz failed\n"); + break; + } + + printf("%s: REG_MULTI_SZ: \n", name); + for (i=0; values[i] != NULL; i++) { + d_printf("%s\n", values[i]); + } + TALLOC_FREE(values); + break; + } + default: + printf("%s: unknown type %d\n", name, type); + } + +} + +/**************************************************************************** +****************************************************************************/ + +static void display_printer_data(const char *v, + enum winreg_Type type, + uint8_t *data, + uint32_t length) +{ + int i; + union spoolss_PrinterData r; + DATA_BLOB blob = data_blob_const(data, length); + WERROR result; + enum ndr_err_code ndr_err; + + result = pull_spoolss_PrinterData(talloc_tos(), &blob, &r, type); + if (!W_ERROR_IS_OK(result)) { + return; + } + + switch (type) { + case REG_DWORD: + printf("%s: REG_DWORD: 0x%08x\n", v, r.value); + break; + case REG_SZ: + printf("%s: REG_SZ: %s\n", v, r.string); + break; + case REG_BINARY: { + char *hex = hex_encode_talloc(NULL, + r.binary.data, r.binary.length); + size_t len; + printf("%s: REG_BINARY:", v); + 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'); + putchar('\n'); + + if (strequal(v, "OsVersion")) { + struct spoolss_OSVersion os; + ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &os, + (ndr_pull_flags_fn_t)ndr_pull_spoolss_OSVersion); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + // add output here; + printf("OsMajor: %u\n", os.major); + printf("OsMinor: %u\n", os.minor); + printf("OsBuild: %u\n", os.build); + NDR_PRINT_DEBUG(spoolss_OSVersion, &os); + } + } + if (strequal(v, "OsVersionEx")) { + struct spoolss_OSVersionEx os; + ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &os, + (ndr_pull_flags_fn_t)ndr_pull_spoolss_OSVersionEx); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + printf("OsMajor: %u\n", os.major); + printf("OsMinor: %u\n", os.minor); + printf("OsBuild: %u\n", os.build); + printf("ServicePackMajor: %u\n", os.service_pack_major); + printf("ServicePackMinor: %u\n", os.service_pack_minor); + NDR_PRINT_DEBUG(spoolss_OSVersionEx, &os); + } + } + break; + } + case REG_MULTI_SZ: + printf("%s: REG_MULTI_SZ: ", v); + for (i=0; r.string_array[i] != NULL; i++) { + printf("%s ", r.string_array[i]); + } + printf("\n"); + break; + default: + printf("%s: unknown type 0x%02x:\n", v, type); + break; + } +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_getprinterdata(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle pol; + WERROR result; + fstring printername; + const char *valuename; + enum winreg_Type type; + uint8_t *data; + uint32_t needed; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 */ + + if (strncmp(argv[1], ".", sizeof(".")) == 0) + fstrcpy(printername, cli->srv_name_slash); + else + slprintf(printername, sizeof(printername)-1, "%s\\%s", + cli->srv_name_slash, argv[1]); + + /* get a printer handle */ + + result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + SEC_FLAG_MAXIMUM_ALLOWED, + &pol); + if (!W_ERROR_IS_OK(result)) + goto done; + + /* Get printer info */ + + result = rpccli_spoolss_getprinterdata(cli, mem_ctx, + &pol, + valuename, + 0, + &type, + &needed, + &data); + if (!W_ERROR_IS_OK(result)) + goto done; + + /* Display printer data */ + + display_printer_data(valuename, type, data, needed); + + done: + if (is_valid_policy_hnd(&pol)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result); + } + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_getprinterdataex(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle pol; + WERROR result; + NTSTATUS status; + fstring printername; + const char *valuename, *keyname; + + enum winreg_Type type; + uint8_t *data = NULL; + uint32_t offered = 0; + uint32_t needed; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 */ + + if (strncmp(argv[1], ".", sizeof(".")) == 0) + fstrcpy(printername, cli->srv_name_slash); + else + slprintf(printername, sizeof(printername)-1, "%s\\%s", + cli->srv_name_slash, argv[1]); + + /* get a printer handle */ + + result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + SEC_FLAG_MAXIMUM_ALLOWED, + &pol); + if (!W_ERROR_IS_OK(result)) + goto done; + + /* Get printer info */ + + data = talloc_zero_array(mem_ctx, uint8_t, offered); + if (!data) { + goto done; + } + + status = dcerpc_spoolss_GetPrinterDataEx(b, mem_ctx, + &pol, + keyname, + valuename, + &type, + data, + offered, + &needed, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + if (W_ERROR_EQUAL(result, WERR_MORE_DATA)) { + offered = needed; + data = talloc_zero_array(mem_ctx, uint8_t, offered); + if (!data) { + goto done; + } + status = dcerpc_spoolss_GetPrinterDataEx(b, mem_ctx, + &pol, + keyname, + valuename, + &type, + data, + offered, + &needed, + &result); + } + + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + + if (!W_ERROR_IS_OK(result)) + goto done; + + /* Display printer data */ + + display_printer_data(valuename, type, data, needed); + + + done: + if (is_valid_policy_hnd(&pol)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result); + } + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_driver1(struct spoolss_DriverInfo1 *r) +{ + if (!r) { + return; + } + + printf("Printer Driver Info 1:\n"); + printf("\tDriver Name: [%s]\n", r->driver_name); + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_driver2(struct spoolss_DriverInfo2 *r) +{ + if (!r) { + return; + } + + printf("Printer Driver Info 2:\n"); + printf("\tVersion: [%x]\n", r->version); + printf("\tDriver Name: [%s]\n", r->driver_name); + printf("\tArchitecture: [%s]\n", r->architecture); + printf("\tDriver Path: [%s]\n", r->driver_path); + printf("\tDatafile: [%s]\n", r->data_file); + printf("\tConfigfile: [%s]\n", r->config_file); + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_driver3(struct spoolss_DriverInfo3 *r) +{ + int i; + + if (!r) { + return; + } + + printf("Printer Driver Info 3:\n"); + printf("\tVersion: [%x]\n", r->version); + printf("\tDriver Name: [%s]\n", r->driver_name); + printf("\tArchitecture: [%s]\n", r->architecture); + printf("\tDriver Path: [%s]\n", r->driver_path); + printf("\tDatafile: [%s]\n", r->data_file); + printf("\tConfigfile: [%s]\n", r->config_file); + printf("\tHelpfile: [%s]\n", r->help_file); + + for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) { + printf("\tDependentfiles: [%s]\n", r->dependent_files[i]); + } + + printf("\tMonitorname: [%s]\n", r->monitor_name); + printf("\tDefaultdatatype: [%s]\n", r->default_datatype); + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_driver4(struct spoolss_DriverInfo4 *r) +{ + int i; + + if (!r) { + return; + } + + printf("Printer Driver Info 4:\n"); + printf("\tVersion: [%x]\n", r->version); + printf("\tDriver Name: [%s]\n", r->driver_name); + printf("\tArchitecture: [%s]\n", r->architecture); + printf("\tDriver Path: [%s]\n", r->driver_path); + printf("\tDatafile: [%s]\n", r->data_file); + printf("\tConfigfile: [%s]\n", r->config_file); + printf("\tHelpfile: [%s]\n", r->help_file); + + for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) { + printf("\tDependentfiles: [%s]\n", r->dependent_files[i]); + } + + printf("\tMonitorname: [%s]\n", r->monitor_name); + printf("\tDefaultdatatype: [%s]\n", r->default_datatype); + + for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) { + printf("\tPrevious Names: [%s]\n", r->previous_names[i]); + } + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_driver5(struct spoolss_DriverInfo5 *r) +{ + if (!r) { + return; + } + + printf("Printer Driver Info 5:\n"); + printf("\tVersion: [%x]\n", r->version); + printf("\tDriver Name: [%s]\n", r->driver_name); + printf("\tArchitecture: [%s]\n", r->architecture); + printf("\tDriver Path: [%s]\n", r->driver_path); + printf("\tDatafile: [%s]\n", r->data_file); + printf("\tConfigfile: [%s]\n", r->config_file); + printf("\tDriver Attributes: [0x%x]\n", r->driver_attributes); + printf("\tConfig Version: [0x%x]\n", r->config_version); + printf("\tDriver Version: [0x%x]\n", r->driver_version); + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_driver6(struct spoolss_DriverInfo6 *r) +{ + int i; + + if (!r) { + return; + } + + printf("Printer Driver Info 6:\n"); + printf("\tVersion: [%x]\n", r->version); + printf("\tDriver Name: [%s]\n", r->driver_name); + printf("\tArchitecture: [%s]\n", r->architecture); + printf("\tDriver Path: [%s]\n", r->driver_path); + printf("\tDatafile: [%s]\n", r->data_file); + printf("\tConfigfile: [%s]\n", r->config_file); + printf("\tHelpfile: [%s]\n", r->help_file); + + for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) { + printf("\tDependentfiles: [%s]\n", r->dependent_files[i]); + } + + printf("\tMonitorname: [%s]\n", r->monitor_name); + printf("\tDefaultdatatype: [%s]\n", r->default_datatype); + + for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) { + printf("\tPrevious Names: [%s]\n", r->previous_names[i]); + } + + printf("\tDriver Date: [%s]\n", nt_time_string(talloc_tos(), r->driver_date)); + printf("\tDriver Version: [0x%016llx]\n", (long long unsigned int)r->driver_version); + printf("\tManufacturer Name: [%s]\n", r->manufacturer_name); + printf("\tManufacturer Url: [%s]\n", r->manufacturer_url); + printf("\tHardware ID: [%s]\n", r->hardware_id); + printf("\tProvider: [%s]\n", r->provider); + + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_print_driver8(struct spoolss_DriverInfo8 *r) +{ + int i; + + if (!r) { + return; + } + + printf("Printer Driver Info 8:\n"); + printf("\tVersion: [%x]\n", r->version); + printf("\tDriver Name: [%s]\n", r->driver_name); + printf("\tArchitecture: [%s]\n", r->architecture); + printf("\tDriver Path: [%s]\n", r->driver_path); + printf("\tDatafile: [%s]\n", r->data_file); + printf("\tConfigfile: [%s]\n", r->config_file); + printf("\tHelpfile: [%s]\n", r->help_file); + printf("\tMonitorname: [%s]\n", r->monitor_name); + printf("\tDefaultdatatype: [%s]\n", r->default_datatype); + + for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) { + printf("\tDependentfiles: [%s]\n", r->dependent_files[i]); + } + + for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) { + printf("\tPrevious Names: [%s]\n", r->previous_names[i]); + } + + printf("\tDriver Date: [%s]\n", nt_time_string(talloc_tos(), r->driver_date)); + printf("\tDriver Version: [0x%016llx]\n", (long long unsigned int)r->driver_version); + printf("\tManufacturer Name: [%s]\n", r->manufacturer_name); + printf("\tManufacturer Url: [%s]\n", r->manufacturer_url); + printf("\tHardware ID: [%s]\n", r->hardware_id); + printf("\tProvider: [%s]\n", r->provider); + printf("\tPrint Processor: [%s]\n", r->print_processor); + printf("\tVendor Setup: [%s]\n", r->vendor_setup); + for (i=0; r->color_profiles && r->color_profiles[i] != NULL; i++) { + printf("\tColor Profiles: [%s]\n", r->color_profiles[i]); + } + printf("\tInf Path: [%s]\n", r->inf_path); + printf("\tPrinter Driver Attributes: [0x%x]\n", r->printer_driver_attributes); + for (i=0; r->core_driver_dependencies && r->core_driver_dependencies[i] != NULL; i++) { + printf("\tCore Driver Dependencies: [%s]\n", r->core_driver_dependencies[i]); + } + printf("\tMin Driver Inbox Driver Version Date: [%s]\n", nt_time_string(talloc_tos(), r->min_inbox_driver_ver_date)); + printf("\tMin Driver Inbox Driver Version Version: [0x%016llx]\n", + (long long unsigned int)r->min_inbox_driver_ver_version); + + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_getdriver(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle pol; + WERROR werror; + uint32_t level = 3; + const char *printername; + uint32_t i; + bool success = false; + union spoolss_DriverInfo info; + uint32_t server_major_version; + uint32_t server_minor_version; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 */ + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + if (argc == 3) { + level = atoi(argv[2]); + } + + /* Open a printer handle */ + + werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + PRINTER_ACCESS_USE, + &pol); + if (!W_ERROR_IS_OK(werror)) { + printf("Error opening printer handle for %s!\n", printername); + return werror; + } + + /* loop through and print driver info level for each architecture */ + + for (i=0; archi_table[i].long_archi!=NULL; i++) { + + werror = rpccli_spoolss_getprinterdriver2(cli, mem_ctx, + &pol, + archi_table[i].long_archi, + level, + 0, /* offered */ + archi_table[i].version, + 2, + &info, + &server_major_version, + &server_minor_version); + if (!W_ERROR_IS_OK(werror)) { + continue; + } + + /* need at least one success */ + + success = true; + + printf("\n[%s]\n", archi_table[i].long_archi); + + switch (level) { + case 1: + display_print_driver1(&info.info1); + break; + case 2: + display_print_driver2(&info.info2); + break; + case 3: + display_print_driver3(&info.info3); + break; + case 4: + display_print_driver4(&info.info4); + break; + case 5: + display_print_driver5(&info.info5); + break; + case 6: + display_print_driver6(&info.info6); + break; + case 8: + display_print_driver8(&info.info8); + break; + default: + printf("unknown info level %d\n", level); + break; + } + } + + /* Cleanup */ + + if (is_valid_policy_hnd(&pol)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result); + } + + if (success) { + werror = WERR_OK; + } + + return werror; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR enum_driver_by_architecture(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + const char *architecture, + uint32_t level) +{ + WERROR werror; + uint32_t count = 0; + union spoolss_DriverInfo *info = NULL; + uint32_t j; + + werror = rpccli_spoolss_enumprinterdrivers(cli, mem_ctx, + cli->srv_name_slash, + architecture, + level, + 0, + &count, + &info); + + if (W_ERROR_EQUAL(werror, WERR_INVALID_ENVIRONMENT)) { + printf("Server does not support environment [%s]\n", + architecture); + return WERR_OK; + } + + if (count == 0) { + return WERR_OK; + } + + if (!W_ERROR_IS_OK(werror)) { + printf("Error getting driver for environment [%s] - %s\n", + architecture, win_errstr(werror)); + return werror; + } + + printf("\n[%s]\n", architecture); + + switch (level) { + case 1: + for (j=0; j < count; j++) { + display_print_driver1(&info[j].info1); + } + break; + case 2: + for (j=0; j < count; j++) { + display_print_driver2(&info[j].info2); + } + break; + case 3: + for (j=0; j < count; j++) { + display_print_driver3(&info[j].info3); + } + break; + case 4: + for (j=0; j < count; j++) { + display_print_driver4(&info[j].info4); + } + break; + case 5: + for (j=0; j < count; j++) { + display_print_driver5(&info[j].info5); + } + break; + case 6: + for (j=0; j < count; j++) { + display_print_driver6(&info[j].info6); + } + break; + case 8: + for (j=0; j < count; j++) { + display_print_driver8(&info[j].info8); + } + break; + default: + printf("unknown info level %d\n", level); + return WERR_INVALID_LEVEL; + } + + 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_t level = 1; + uint32_t i; + const char *architecture = NULL; + + if (argc > 3) { + printf("Usage: enumdrivers [level] [architecture]\n"); + return WERR_OK; + } + + if (argc >= 2) { + level = atoi(argv[1]); + } + + if (argc == 3) { + architecture = argv[2]; + } + + if (architecture) { + return enum_driver_by_architecture(cli, mem_ctx, + architecture, + level); + } + + /* 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 = enum_driver_by_architecture(cli, mem_ctx, + archi_table[i].long_archi, + level); + if (!W_ERROR_IS_OK(werror)) { + break; + } + } + + return werror; +} + +/**************************************************************************** +****************************************************************************/ + +static void display_printdriverdir_1(struct spoolss_DriverDirectoryInfo1 *r) +{ + printf("\tDirectory Name:[%s]\n", r->directory_name); +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_getdriverdir(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR result; + NTSTATUS status; + const char *env = SPOOLSS_ARCHITECTURE_NT_X86; + DATA_BLOB buffer; + uint32_t offered; + union spoolss_DriverDirectoryInfo info; + uint32_t needed; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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) { + env = argv[1]; + } + + /* Get the directory. Only use Info level 1 */ + + status = dcerpc_spoolss_GetPrinterDriverDirectory(b, mem_ctx, + cli->srv_name_slash, + env, + 1, + NULL, /* buffer */ + 0, /* offered */ + NULL, /* info */ + &needed, + &result); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) { + offered = needed; + buffer = data_blob_talloc_zero(mem_ctx, needed); + + status = dcerpc_spoolss_GetPrinterDriverDirectory(b, mem_ctx, + cli->srv_name_slash, + env, + 1, + &buffer, + offered, + &info, + &needed, + &result); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + } + + if (W_ERROR_IS_OK(result)) { + display_printdriverdir_1(&info.info1); + } + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_getdriverpackagepath(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + HRESULT hresult; + NTSTATUS status; + const char *env = SPOOLSS_ARCHITECTURE_NT_X86; + uint32_t offered; + uint32_t needed; + struct dcerpc_binding_handle *b = cli->binding_handle; + const char *package_id = ""; + const char *cab = NULL; + + if (argc > 4) { + printf("Usage: %s [environment] [package_id]\n", argv[0]); + return WERR_OK; + } + + /* Get the arguments need to open the printer handle */ + + if (argc >= 2) { + env = argv[1]; + } + + if (argc == 3) { + package_id = argv[2]; + } + + offered = 1; + cab = talloc_zero_array(mem_ctx, char, offered); + if (cab == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + status = dcerpc_spoolss_GetPrinterDriverPackagePath(b, mem_ctx, + cli->srv_name_slash, + env, + NULL, + package_id, + cab, + offered, + &needed, + &hresult); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (W_ERROR_EQUAL(W_ERROR(WIN32_FROM_HRESULT(hresult)), WERR_INSUFFICIENT_BUFFER)) { + offered = needed; + cab = talloc_zero_array(mem_ctx, char, offered); + if (cab == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + status = dcerpc_spoolss_GetPrinterDriverPackagePath(b, mem_ctx, + cli->srv_name_slash, + env, + NULL, + package_id, + cab, + offered, + &needed, + &hresult); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + } + + return W_ERROR(WIN32_FROM_HRESULT(hresult)); +} + + +/**************************************************************************** +****************************************************************************/ + +static void set_drv_info_3_env(TALLOC_CTX *mem_ctx, + struct spoolss_AddDriverInfo3 *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; + info->architecture = talloc_strdup(mem_ctx, 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(TALLOC_CTX *mem_ctx, char *str, + const char *delim, const char **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_m(ptr, "NULL") == 0)) { + ptr = NULL; + } + + if (dest != NULL) { + *dest = talloc_strdup(mem_ctx, ptr); + } + + return ptr; +} + +/******************************************************************************** + fill in the members of a spoolss_AddDriverInfo3 struct using a character + string in the form of + <Long Driver 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, struct spoolss_AddDriverInfo3 *r, + char *args) +{ + char *str, *str2; + size_t count = 0; + char *saveptr = NULL; + struct spoolss_StringArray *deps; + const char **file_array = NULL; + int i; + + /* fill in the UNISTR fields */ + str = get_driver_3_param(mem_ctx, args, ":", &r->driver_name, &saveptr); + str = get_driver_3_param(mem_ctx, NULL, ":", &r->driver_path, &saveptr); + str = get_driver_3_param(mem_ctx, NULL, ":", &r->data_file, &saveptr); + str = get_driver_3_param(mem_ctx, NULL, ":", &r->config_file, &saveptr); + str = get_driver_3_param(mem_ctx, NULL, ":", &r->help_file, &saveptr); + str = get_driver_3_param(mem_ctx, NULL, ":", &r->monitor_name, &saveptr); + str = get_driver_3_param(mem_ctx, NULL, ":", &r->default_datatype, &saveptr); + + /* <Comma Separated List of Dependent Files> */ + /* save the beginning of the string */ + str2 = get_driver_3_param(mem_ctx, NULL, ":", NULL, &saveptr); + str = str2; + + /* begin to strip out each filename */ + str = strtok_r(str, ",", &saveptr); + + /* no dependent files, we are done */ + if (!str) { + return true; + } + + deps = talloc_zero(mem_ctx, struct spoolss_StringArray); + if (!deps) { + return false; + } + + while (str != NULL) { + bool ok; + ok = add_string_to_array(deps, str, &file_array, &count); + if (!ok) { + return false; + } + str = strtok_r(NULL, ",", &saveptr); + } + + deps->string = talloc_zero_array(deps, const char *, count + 1); + if (!deps->string) { + return false; + } + + for (i=0; i < count; i++) { + deps->string[i] = file_array[i]; + } + + r->dependent_files = deps; + + return true; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_addprinterdriver(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR result; + NTSTATUS status; + uint32_t level = 3; + struct spoolss_AddDriverInfoCtr info_ctr; + struct spoolss_AddDriverInfo3 info3; + const char *arch; + char *driver_args; + struct dcerpc_binding_handle *b = cli->binding_handle; + + /* parse the command arguments */ + if (argc != 3 && argc != 4) + { + printf ("Usage: %s <Environment> \\\n", argv[0]); + printf ("\t<Long Driver 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 spoolss_AddDriverInfo3 struct */ + ZERO_STRUCT(info3); + + arch = cmd_spoolss_get_short_archi(argv[1]); + if (!arch) { + printf ("Error Unknown architecture [%s]\n", argv[1]); + return WERR_INVALID_PARAMETER; + } + + set_drv_info_3_env(mem_ctx, &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_PARAMETER; + } + + /* 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]); + } + + + info_ctr.level = level; + info_ctr.info.info3 = &info3; + + status = dcerpc_spoolss_AddPrinterDriver(b, mem_ctx, + cli->srv_name_slash, + &info_ctr, + &result); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + if (W_ERROR_IS_OK(result)) { + printf ("Printer Driver %s successfully installed.\n", + info3.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; + struct spoolss_SetPrinterInfoCtr info_ctr; + struct spoolss_SetPrinterInfo2 info2; + + /* parse the command arguments */ + if (argc != 5) + { + printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]); + return WERR_OK; + } + + /* Fill in the DRIVER_INFO_2 struct */ + ZERO_STRUCT(info2); + + info2.printername = argv[1]; + info2.drivername = argv[3]; + info2.sharename = argv[2]; + info2.portname = argv[4]; + info2.comment = "Created by rpcclient"; + info2.printprocessor = "winprint"; + info2.datatype = "RAW"; + info2.devmode_ptr = 0; + info2.secdesc_ptr = 0; + 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; + */ + + info_ctr.level = 2; + info_ctr.info.info2 = &info2; + + result = rpccli_spoolss_addprinterex(cli, mem_ctx, + &info_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) +{ + struct policy_handle pol; + WERROR result; + NTSTATUS status; + uint32_t level = 2; + const char *printername; + union spoolss_PrinterInfo info; + struct spoolss_SetPrinterInfoCtr info_ctr; + struct spoolss_SetPrinterInfo2 info2; + struct spoolss_DevmodeContainer devmode_ctr; + struct sec_desc_buf secdesc_ctr; + struct dcerpc_binding_handle *b = cli->binding_handle; + + ZERO_STRUCT(devmode_ctr); + ZERO_STRUCT(secdesc_ctr); + + /* parse the command arguments */ + if (argc != 3) + { + printf ("Usage: %s <printer> <driver>\n", argv[0]); + return WERR_OK; + } + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + /* Get a printer handle */ + + result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + PRINTER_ALL_ACCESS, + &pol); + if (!W_ERROR_IS_OK(result)) + goto done; + + /* Get printer info */ + + result = rpccli_spoolss_getprinter(cli, mem_ctx, + &pol, + level, + 0, + &info); + if (!W_ERROR_IS_OK(result)) { + printf ("Unable to retrieve printer information!\n"); + goto done; + } + + /* Set the printer driver */ + + spoolss_printerinfo2_to_setprinterinfo2(&info.info2, &info2); + info2.drivername = argv[2]; + + info_ctr.level = 2; + info_ctr.info.info2 = &info2; + + status = dcerpc_spoolss_SetPrinter(b, mem_ctx, + &pol, + &info_ctr, + &devmode_ctr, + &secdesc_ctr, + 0, /* command */ + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + 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 (is_valid_policy_hnd(&pol)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result); + } + + 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; + NTSTATUS status; + struct dcerpc_binding_handle *b = cli->binding_handle; + + int i; + int vers = -1; + + const char *arch = NULL; + uint32_t delete_flags = 0; + + /* parse the command arguments */ + if (argc < 2 || argc > 5) { + printf("Usage: %s <driver> [arch] [version] [flags]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 3) + arch = argv[2]; + if (argc >= 4) { + vers = atoi(argv[3]); + delete_flags |= DPD_DELETE_SPECIFIC_VERSION; + } + if (argc == 5) + delete_flags = atoi(argv[4]); + + /* 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 */ + status = dcerpc_spoolss_DeletePrinterDriverEx(b, mem_ctx, + cli->srv_name_slash, + archi_table[i].long_archi, + argv[1], + delete_flags, + archi_table[i].version, + &result); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + 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, win_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; + NTSTATUS status; + int i; + struct dcerpc_binding_handle *b = cli->binding_handle; + + /* parse the command arguments */ + if (argc != 2) { + printf ("Usage: %s <driver>\n", argv[0]); + return WERR_OK; + } + + /* delete the driver for all architectures */ + for (i=0; archi_table[i].long_archi; i++) { + result = WERR_OK; + + /* make the call to remove the driver */ + status = dcerpc_spoolss_DeletePrinterDriver(b, mem_ctx, + cli->srv_name_slash, + archi_table[i].long_archi, + argv[1], + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + continue; + } + 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 %s!\n", + argv[1], archi_table[i].long_archi, + win_errstr(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; + NTSTATUS status; + const char *environment = SPOOLSS_ARCHITECTURE_NT_X86; + DATA_BLOB buffer; + uint32_t offered; + union spoolss_PrintProcessorDirectoryInfo info = {}; + uint32_t needed; + struct dcerpc_binding_handle *b = cli->binding_handle; + + /* parse the command arguments */ + if (argc > 2) { + printf ("Usage: %s [environment]\n", argv[0]); + return WERR_OK; + } + + if (argc == 2) { + environment = argv[1]; + } + + status = dcerpc_spoolss_GetPrintProcessorDirectory(b, mem_ctx, + cli->srv_name_slash, + environment, + 1, + NULL, /* buffer */ + 0, /* offered */ + NULL, /* info */ + &needed, + &result); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) { + offered = needed; + buffer = data_blob_talloc_zero(mem_ctx, needed); + + status = dcerpc_spoolss_GetPrintProcessorDirectory(b, mem_ctx, + cli->srv_name_slash, + environment, + 1, + &buffer, + offered, + &info, + &needed, + &result); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + } + + if (W_ERROR_IS_OK(result) && info.info1.directory_name != NULL) { + printf("%s\n", info.info1.directory_name); + } + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_addform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle handle; + WERROR werror; + NTSTATUS status; + const char *printername; + struct spoolss_AddFormInfoCtr info_ctr; + struct spoolss_AddFormInfo1 info1; + struct spoolss_AddFormInfo2 info2; + uint32_t level = 1; + struct dcerpc_binding_handle *b = cli->binding_handle; + + /* Parse the command arguments */ + + if (argc < 3 || argc > 5) { + printf ("Usage: %s <printer> <formname> [level]\n", argv[0]); + return WERR_OK; + } + + /* Get a printer handle */ + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + PRINTER_ALL_ACCESS, + &handle); + if (!W_ERROR_IS_OK(werror)) + goto done; + + /* Dummy up some values for the form data */ + + if (argc == 4) { + level = atoi(argv[3]); + } + + switch (level) { + case 1: + info1.flags = SPOOLSS_FORM_USER; + info1.form_name = argv[2]; + info1.size.width = 100; + info1.size.height = 100; + info1.area.left = 0; + info1.area.top = 10; + info1.area.right = 20; + info1.area.bottom = 30; + + info_ctr.level = 1; + info_ctr.info.info1 = &info1; + + break; + case 2: + info2.flags = SPOOLSS_FORM_USER; + info2.form_name = argv[2]; + info2.size.width = 100; + info2.size.height = 100; + info2.area.left = 0; + info2.area.top = 10; + info2.area.right = 20; + info2.area.bottom = 30; + info2.keyword = argv[2]; + info2.string_type = SPOOLSS_FORM_STRING_TYPE_NONE; + info2.mui_dll = NULL; + info2.ressource_id = 0; + info2.display_name = argv[2]; + info2.lang_id = 0; + + info_ctr.level = 2; + info_ctr.info.info2 = &info2; + + break; + default: + werror = WERR_INVALID_PARAMETER; + goto done; + } + + /* Add the form */ + + status = dcerpc_spoolss_AddForm(b, mem_ctx, + &handle, + &info_ctr, + &werror); + if (!NT_STATUS_IS_OK(status)) { + werror = ntstatus_to_werror(status); + goto done; + } + done: + if (is_valid_policy_hnd(&handle)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result); + } + + return werror; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_setform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle handle; + WERROR werror; + NTSTATUS status; + const char *printername; + struct spoolss_AddFormInfoCtr info_ctr; + struct spoolss_AddFormInfo1 info1; + struct dcerpc_binding_handle *b = cli->binding_handle; + + /* Parse the command arguments */ + + if (argc != 3) { + printf ("Usage: %s <printer> <formname>\n", argv[0]); + return WERR_OK; + } + + /* Get a printer handle */ + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + SEC_FLAG_MAXIMUM_ALLOWED, + &handle); + if (!W_ERROR_IS_OK(werror)) + goto done; + + /* Dummy up some values for the form data */ + + info1.flags = SPOOLSS_FORM_PRINTER; + info1.size.width = 100; + info1.size.height = 100; + info1.area.left = 0; + info1.area.top = 1000; + info1.area.right = 2000; + info1.area.bottom = 3000; + info1.form_name = argv[2]; + + info_ctr.info.info1 = &info1; + info_ctr.level = 1; + + /* Set the form */ + + status = dcerpc_spoolss_SetForm(b, mem_ctx, + &handle, + argv[2], + &info_ctr, + &werror); + if (!NT_STATUS_IS_OK(status)) { + werror = ntstatus_to_werror(status); + goto done; + } + done: + if (is_valid_policy_hnd(&handle)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result); + } + + return werror; +} + +/**************************************************************************** +****************************************************************************/ + +static const char *get_form_flag(int form_flag) +{ + switch (form_flag) { + case SPOOLSS_FORM_USER: + return "FORM_USER"; + case SPOOLSS_FORM_BUILTIN: + return "FORM_BUILTIN"; + case SPOOLSS_FORM_PRINTER: + return "FORM_PRINTER"; + default: + return "unknown"; + } +} + +/**************************************************************************** +****************************************************************************/ + +static void display_form_info1(struct spoolss_FormInfo1 *r) +{ + printf("%s\n" \ + "\tflag: %s (%d)\n" \ + "\twidth: %d, length: %d\n" \ + "\tleft: %d, right: %d, top: %d, bottom: %d\n\n", + r->form_name, get_form_flag(r->flags), r->flags, + r->size.width, r->size.height, + r->area.left, r->area.right, + r->area.top, r->area.bottom); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_form_info2(struct spoolss_FormInfo2 *r) +{ + printf("%s\n" \ + "\tflag: %s (%d)\n" \ + "\twidth: %d, length: %d\n" \ + "\tleft: %d, right: %d, top: %d, bottom: %d\n", + r->form_name, get_form_flag(r->flags), r->flags, + r->size.width, r->size.height, + r->area.left, r->area.right, + r->area.top, r->area.bottom); + printf("\tkeyword: %s\n", r->keyword); + printf("\tstring_type: 0x%08x\n", r->string_type); + printf("\tmui_dll: %s\n", r->mui_dll); + printf("\tressource_id: 0x%08x\n", r->ressource_id); + printf("\tdisplay_name: %s\n", r->display_name); + printf("\tlang_id: %d\n", r->lang_id); + printf("\n"); +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_getform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct policy_handle handle; + WERROR werror; + NTSTATUS status; + const char *printername; + DATA_BLOB buffer; + uint32_t offered = 0; + union spoolss_FormInfo info; + uint32_t needed; + uint32_t level = 1; + struct dcerpc_binding_handle *b = cli->binding_handle; + + /* Parse the command arguments */ + + if (argc < 3 || argc > 5) { + printf ("Usage: %s <printer> <formname> [level]\n", argv[0]); + return WERR_OK; + } + + /* Get a printer handle */ + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + SEC_FLAG_MAXIMUM_ALLOWED, + &handle); + if (!W_ERROR_IS_OK(werror)) + goto done; + + if (argc == 4) { + level = atoi(argv[3]); + } + + /* Get the form */ + + status = dcerpc_spoolss_GetForm(b, mem_ctx, + &handle, + argv[2], + level, + NULL, + offered, + &info, + &needed, + &werror); + if (!NT_STATUS_IS_OK(status)) { + werror = ntstatus_to_werror(status); + goto done; + } + if (W_ERROR_EQUAL(werror, WERR_INSUFFICIENT_BUFFER)) { + buffer = data_blob_talloc_zero(mem_ctx, needed); + offered = needed; + status = dcerpc_spoolss_GetForm(b, mem_ctx, + &handle, + argv[2], + level, + &buffer, + offered, + &info, + &needed, + &werror); + if (!NT_STATUS_IS_OK(status)) { + werror = ntstatus_to_werror(status); + goto done; + } + } + + if (!W_ERROR_IS_OK(werror)) { + goto done; + } + + switch (level) { + case 1: + display_form_info1(&info.info1); + break; + case 2: + display_form_info2(&info.info2); + break; + } + + done: + if (is_valid_policy_hnd(&handle)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result); + } + + return werror; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_deleteform(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + struct policy_handle handle; + WERROR werror; + NTSTATUS status; + const char *printername; + struct dcerpc_binding_handle *b = cli->binding_handle; + + /* Parse the command arguments */ + + if (argc != 3) { + printf ("Usage: %s <printer> <formname>\n", argv[0]); + return WERR_OK; + } + + /* Get a printer handle */ + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + SEC_FLAG_MAXIMUM_ALLOWED, + &handle); + if (!W_ERROR_IS_OK(werror)) + goto done; + + /* Delete the form */ + + status = dcerpc_spoolss_DeleteForm(b, mem_ctx, + &handle, + argv[2], + &werror); + if (!NT_STATUS_IS_OK(status)) { + werror = ntstatus_to_werror(status); + goto done; + } + + done: + if (is_valid_policy_hnd(&handle)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result); + } + + return werror; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_enum_forms(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + struct policy_handle handle; + WERROR werror; + const char *printername; + uint32_t num_forms, level = 1, i; + union spoolss_FormInfo *forms; + struct dcerpc_binding_handle *b = cli->binding_handle; + + /* Parse the command arguments */ + + if (argc < 2 || argc > 4) { + printf ("Usage: %s <printer> [level]\n", argv[0]); + return WERR_OK; + } + + /* Get a printer handle */ + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + SEC_FLAG_MAXIMUM_ALLOWED, + &handle); + if (!W_ERROR_IS_OK(werror)) + goto done; + + if (argc == 3) { + level = atoi(argv[2]); + } + + /* Enumerate forms */ + + werror = rpccli_spoolss_enumforms(cli, mem_ctx, + &handle, + level, + 0, + &num_forms, + &forms); + + if (!W_ERROR_IS_OK(werror)) + goto done; + + /* Display output */ + + for (i = 0; i < num_forms; i++) { + switch (level) { + case 1: + display_form_info1(&forms[i].info1); + break; + case 2: + display_form_info2(&forms[i].info2); + break; + } + } + + done: + if (is_valid_policy_hnd(&handle)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result); + } + + return werror; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_setprinterdata(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + WERROR result; + NTSTATUS status; + const char *printername; + struct policy_handle pol = { 0, }; + union spoolss_PrinterInfo info; + enum winreg_Type type; + union spoolss_PrinterData data; + DATA_BLOB blob; + struct dcerpc_binding_handle *b = cli->binding_handle; + int error = 0; + + /* parse the command arguments */ + if (argc < 5) { + printf ("Usage: %s <printer> <string|binary|dword|multistring>" + " <value> <data>\n", + argv[0]); + return WERR_OK; + } + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + type = REG_NONE; + + if (strequal(argv[2], "string")) { + type = REG_SZ; + } + + if (strequal(argv[2], "binary")) { + type = REG_BINARY; + } + + if (strequal(argv[2], "dword")) { + type = REG_DWORD; + } + + if (strequal(argv[2], "multistring")) { + type = REG_MULTI_SZ; + } + + if (type == REG_NONE) { + printf("Unknown data type: %s\n", argv[2]); + result = WERR_INVALID_PARAMETER; + goto done; + } + + /* get a printer handle */ + + result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + SEC_FLAG_MAXIMUM_ALLOWED, + &pol); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + result = rpccli_spoolss_getprinter(cli, mem_ctx, + &pol, + 0, + 0, + &info); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + printf("%s\n", current_timestring(mem_ctx, true)); + printf("\tchange_id (before set)\t:[0x%x]\n", info.info0.change_id); + + /* Set the printer data */ + + switch (type) { + case REG_SZ: + data.string = talloc_strdup(mem_ctx, argv[4]); + W_ERROR_HAVE_NO_MEMORY(data.string); + break; + case REG_DWORD: + data.value = smb_strtoul(argv[4], + NULL, + 10, + &error, + SMB_STR_STANDARD); + if (error != 0) { + result = WERR_INVALID_PARAMETER; + goto done; + } + + break; + case REG_BINARY: + data.binary = strhex_to_data_blob(mem_ctx, argv[4]); + break; + case REG_MULTI_SZ: { + int i; + size_t num_strings; + const char **strings = NULL; + + num_strings = 0; + + for (i=4; i<argc; i++) { + if (strcmp(argv[i], "NULL") == 0) { + argv[i] = ""; + } + if (!add_string_to_array(mem_ctx, argv[i], + &strings, + &num_strings)) { + result = WERR_NOT_ENOUGH_MEMORY; + goto done; + } + } + data.string_array = talloc_zero_array(mem_ctx, const char *, num_strings + 1); + if (!data.string_array) { + result = WERR_NOT_ENOUGH_MEMORY; + goto done; + } + for (i=0; i < num_strings; i++) { + data.string_array[i] = strings[i]; + } + break; + } + default: + printf("Unknown data type: %s\n", argv[2]); + result = WERR_INVALID_PARAMETER; + goto done; + } + + result = push_spoolss_PrinterData(mem_ctx, &blob, type, &data); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_spoolss_SetPrinterData(b, mem_ctx, + &pol, + argv[3], /* value_name */ + type, + blob.data, + blob.length, + &result); + if (!NT_STATUS_IS_OK(status)) { + printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]); + result = ntstatus_to_werror(status); + goto done; + } + 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, + 0, + &info); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + printf("%s\n", current_timestring(mem_ctx, true)); + printf("\tchange_id (after set)\t:[0x%x]\n", info.info0.change_id); + +done: + /* cleanup */ + if (is_valid_policy_hnd(&pol)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result); + } + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static void display_job_info1(struct spoolss_JobInfo1 *r) +{ + printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", r->position, r->job_id, + r->user_name, r->document_name, r->text_status, r->pages_printed, + r->total_pages); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_job_info2(struct spoolss_JobInfo2 *r) +{ + printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n", + r->position, r->job_id, + r->user_name, r->document_name, r->text_status, r->pages_printed, + r->total_pages, r->size); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_job_info3(struct spoolss_JobInfo3 *r) +{ + printf("jobid[%d], next_jobid[%d]\n", + r->job_id, r->next_job_id); +} + +/**************************************************************************** +****************************************************************************/ + +static void display_job_info4(struct spoolss_JobInfo4 *r) +{ + printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d/%d bytes\n", + r->position, r->job_id, + r->user_name, r->document_name, r->text_status, r->pages_printed, + r->total_pages, r->size, r->size_high); +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_enum_jobs(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + WERROR result; + uint32_t level = 1, count, i; + const char *printername; + struct policy_handle hnd; + union spoolss_JobInfo *info; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 */ + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + SEC_FLAG_MAXIMUM_ALLOWED, + &hnd); + if (!W_ERROR_IS_OK(result)) + goto done; + + /* Enumerate ports */ + + result = rpccli_spoolss_enumjobs(cli, mem_ctx, + &hnd, + 0, /* firstjob */ + 1000, /* numjobs */ + level, + 0, + &count, + &info); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + for (i = 0; i < count; i++) { + switch (level) { + case 1: + display_job_info1(&info[i].info1); + break; + case 2: + display_job_info2(&info[i].info2); + break; + default: + d_printf("unknown info level %d\n", level); + break; + } + } + +done: + if (is_valid_policy_hnd(&hnd)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result); + } + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_get_job(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + WERROR result; + const char *printername; + struct policy_handle hnd; + uint32_t job_id; + uint32_t level = 1; + union spoolss_JobInfo info; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc < 3 || argc > 4) { + printf("Usage: %s printername job_id [level]\n", argv[0]); + return WERR_OK; + } + + job_id = atoi(argv[2]); + + if (argc == 4) { + level = atoi(argv[3]); + } + + /* Open printer handle */ + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + SEC_FLAG_MAXIMUM_ALLOWED, + &hnd); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + /* Enumerate ports */ + + result = rpccli_spoolss_getjob(cli, mem_ctx, + &hnd, + job_id, + level, + 0, + &info); + + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + switch (level) { + case 1: + display_job_info1(&info.info1); + break; + case 2: + display_job_info2(&info.info2); + break; + case 3: + display_job_info3(&info.info3); + break; + case 4: + display_job_info4(&info.info4); + break; + default: + d_printf("unknown info level %d\n", level); + break; + } + +done: + if (is_valid_policy_hnd(&hnd)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result); + } + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static struct { + const char *name; + enum spoolss_JobControl val; +} cmdvals[] = { + {"PAUSE", SPOOLSS_JOB_CONTROL_PAUSE}, + {"RESUME", SPOOLSS_JOB_CONTROL_RESUME}, + {"CANCEL", SPOOLSS_JOB_CONTROL_CANCEL}, + {"RESTART", SPOOLSS_JOB_CONTROL_RESTART}, + {"DELETE", SPOOLSS_JOB_CONTROL_DELETE}, + {"SEND_TO_PRINTER", SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER}, + {"EJECTED", SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED}, + {"RETAIN", SPOOLSS_JOB_CONTROL_RETAIN}, + {"RELEASE", SPOOLSS_JOB_CONTROL_RELEASE} +}; + +static enum spoolss_JobControl parse_setjob_command(const char *cmd) +{ + int i; + + for (i = 0; i < sizeof(cmdvals)/sizeof(cmdvals[0]); i++) { + if (strequal(cmdvals[i].name, cmd)) { + return cmdvals[i].val; + } + } + return (enum spoolss_JobControl)atoi(cmd); +} + +static WERROR cmd_spoolss_set_job(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + WERROR result; + NTSTATUS status; + const char *printername; + struct policy_handle hnd; + uint32_t job_id; + enum spoolss_JobControl command; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc != 4) { + printf("Usage: %s printername job_id command\n", argv[0]); + printf("command = [PAUSE|RESUME|CANCEL|RESTART|DELETE|" + "SEND_TO_PRINTER|EJECTED|RETAIN|RELEASE]\n"); + return WERR_OK; + } + + job_id = atoi(argv[2]); + command = parse_setjob_command(argv[3]); + + /* Open printer handle */ + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + SEC_FLAG_MAXIMUM_ALLOWED, + &hnd); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + /* Set Job */ + + status = dcerpc_spoolss_SetJob(b, mem_ctx, + &hnd, + job_id, + NULL, + command, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + +done: + if (is_valid_policy_hnd(&hnd)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result); + } + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_enum_data(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + WERROR result; + NTSTATUS status; + const char *printername; + struct policy_handle hnd; + uint32_t value_needed; + enum winreg_Type type; + uint32_t data_needed; + struct dcerpc_binding_handle *b = cli->binding_handle; + struct spoolss_EnumPrinterData r; + + if (argc != 2) { + printf("Usage: %s printername\n", argv[0]); + return WERR_OK; + } + + /* Open printer handle */ + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + SEC_FLAG_MAXIMUM_ALLOWED, + &hnd); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + /* Enumerate data */ + + r.in.handle = &hnd; + r.in.enum_index = 0; + r.in.value_offered = 0; + r.in.data_offered = 0; + r.out.value_name = NULL; + r.out.value_needed = &value_needed; + r.out.type = &type; + r.out.data = NULL; + r.out.data_needed = &data_needed; + + status = dcerpc_spoolss_EnumPrinterData_r(b, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + + if (!W_ERROR_IS_OK(r.out.result)) { + result = r.out.result; + goto done; + } + + r.in.data_offered = *r.out.data_needed; + r.in.value_offered = *r.out.value_needed; + r.out.data = talloc_zero_array(mem_ctx, uint8_t, r.in.data_offered); + r.out.value_name = talloc_zero_array(mem_ctx, char, r.in.value_offered); + + do { + + status = dcerpc_spoolss_EnumPrinterData_r(b, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + + if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) { + result = WERR_OK; + break; + } + + r.in.enum_index++; + + display_reg_value(r.out.value_name, *r.out.type, + data_blob_const(r.out.data, r.in.data_offered)); + + } while (W_ERROR_IS_OK(r.out.result)); + +done: + if (is_valid_policy_hnd(&hnd)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result); + } + + 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_t i; + const char *printername; + struct policy_handle hnd; + uint32_t count; + struct spoolss_PrinterEnumValues *info; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc != 3) { + printf("Usage: %s printername <keyname>\n", argv[0]); + return WERR_OK; + } + + /* Open printer handle */ + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + SEC_FLAG_MAXIMUM_ALLOWED, + &hnd); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + /* Enumerate subkeys */ + + result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx, + &hnd, + argv[2], + 0, + &count, + &info); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + for (i=0; i < count; i++) { + display_printer_data(info[i].value_name, + info[i].type, + info[i].data->data, + info[i].data->length); + } + + done: + if (is_valid_policy_hnd(&hnd)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result); + } + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_enum_printerkey(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + WERROR result; + const char *printername; + const char *keyname = NULL; + struct policy_handle hnd; + const char **key_buffer = NULL; + int i; + uint32_t offered = 0; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc < 2 || argc > 4) { + printf("Usage: %s printername [keyname] [offered]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 3) { + keyname = argv[2]; + } else { + keyname = ""; + } + + if (argc == 4) { + offered = atoi(argv[3]); + } + + /* Open printer handle */ + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + SEC_FLAG_MAXIMUM_ALLOWED, + &hnd); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + /* Enumerate subkeys */ + + result = rpccli_spoolss_enumprinterkey(cli, mem_ctx, + &hnd, + keyname, + &key_buffer, + offered); + + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + for (i=0; key_buffer && key_buffer[i]; i++) { + printf("%s\n", key_buffer[i]); + } + + done: + + if (is_valid_policy_hnd(&hnd)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result); + } + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR cmd_spoolss_rffpcnex(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + const char *printername; + const char *clientname; + struct policy_handle hnd = { 0, }; + WERROR result; + NTSTATUS status; + struct spoolss_NotifyOption option; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc != 2) { + printf("Usage: %s printername\n", argv[0]); + result = WERR_OK; + goto done; + } + + /* Open printer */ + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + SEC_FLAG_MAXIMUM_ALLOWED, + &hnd); + if (!W_ERROR_IS_OK(result)) { + printf("Error opening %s\n", argv[1]); + goto done; + } + + /* Create spool options */ + + option.version = 2; + option.count = 2; + + option.types = talloc_array(mem_ctx, struct spoolss_NotifyOptionType, 2); + if (option.types == NULL) { + result = WERR_NOT_ENOUGH_MEMORY; + goto done; + } + + option.types[0].type = PRINTER_NOTIFY_TYPE; + option.types[0].count = 1; + option.types[0].fields = talloc_array(mem_ctx, union spoolss_Field, 1); + if (option.types[0].fields == NULL) { + result = WERR_NOT_ENOUGH_MEMORY; + goto done; + } + option.types[0].fields[0].field = PRINTER_NOTIFY_FIELD_SERVER_NAME; + + option.types[1].type = JOB_NOTIFY_TYPE; + option.types[1].count = 1; + option.types[1].fields = talloc_array(mem_ctx, union spoolss_Field, 1); + if (option.types[1].fields == NULL) { + result = WERR_NOT_ENOUGH_MEMORY; + goto done; + } + option.types[1].fields[0].field = JOB_NOTIFY_FIELD_PRINTER_NAME; + + clientname = talloc_asprintf(mem_ctx, "\\\\%s", lp_netbios_name()); + if (!clientname) { + result = WERR_NOT_ENOUGH_MEMORY; + goto done; + } + + /* Send rffpcnex */ + + status = dcerpc_spoolss_RemoteFindFirstPrinterChangeNotifyEx(b, mem_ctx, + &hnd, + 0, + 0, + clientname, + 123, + &option, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + printf("Error rffpcnex %s\n", argv[1]); + goto done; + } + +done: + if (is_valid_policy_hnd(&hnd)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result); + } + + return result; +} + +/**************************************************************************** +****************************************************************************/ + +static bool compare_printer( struct rpc_pipe_client *cli1, struct policy_handle *hnd1, + struct rpc_pipe_client *cli2, struct policy_handle *hnd2 ) +{ + union spoolss_PrinterInfo info1, info2; + 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, + 0, + &info1); + if ( !W_ERROR_IS_OK(werror) ) { + printf("failed (%s)\n", win_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, + 0, + &info2); + if ( !W_ERROR_IS_OK(werror) ) { + printf("failed (%s)\n", win_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, struct policy_handle *hnd1, + struct rpc_pipe_client *cli2, struct policy_handle *hnd2 ) +{ + union spoolss_PrinterInfo info1, info2; + WERROR werror; + TALLOC_CTX *mem_ctx = talloc_init("compare_printer_secdesc"); + struct security_descriptor *sd1, *sd2; + bool result = true; + + + printf("Retrieving printer security for %s...", cli1->desthost); + werror = rpccli_spoolss_getprinter(cli1, mem_ctx, + hnd1, + 3, + 0, + &info1); + if ( !W_ERROR_IS_OK(werror) ) { + printf("failed (%s)\n", win_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, + 0, + &info2); + if ( !W_ERROR_IS_OK(werror) ) { + printf("failed (%s)\n", win_errstr(werror)); + result = false; + goto done; + } + printf("ok\n"); + + + printf("++ "); + + sd1 = info1.info3.secdesc; + sd2 = info2.info3.secdesc; + + if ( (sd1 != sd2) && ( !sd1 || !sd2 ) ) { + printf("NULL secdesc!\n"); + result = false; + goto done; + } + + if (!security_descriptor_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) +{ + const char *printername; + char *printername_path = NULL; + struct cli_state *cli_server2 = NULL; + struct rpc_pipe_client *cli2 = NULL; + struct policy_handle hPrinter1, hPrinter2; + NTSTATUS nt_status; + WERROR werror; + struct cli_credentials *creds = samba_cmdline_get_creds(); + + if ( argc != 3 ) { + printf("Usage: %s <printer> <server>\n", argv[0]); + return WERR_OK; + } + + printername = argv[1]; + + /* first get the connection to the remote server */ + + nt_status = cli_full_connection_creds(&cli_server2, lp_netbios_name(), argv[2], + NULL, 0, + "IPC$", "IPC", + creds, + CLI_FULL_CONNECTION_IPC); + if ( !NT_STATUS_IS_OK(nt_status) ) + return WERR_GEN_FAILURE; + + nt_status = cli_rpc_pipe_open_noauth(cli_server2, &ndr_table_spoolss, + &cli2); + if (!NT_STATUS_IS_OK(nt_status)) { + printf("failed to open spoolss pipe on server %s (%s)\n", + argv[2], nt_errstr(nt_status)); + return WERR_GEN_FAILURE; + } + + /* now open up both printers */ + + RPCCLIENT_PRINTERNAME(printername_path, cli, printername); + + printf("Opening %s...", printername_path); + + werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername_path, + PRINTER_ALL_ACCESS, + &hPrinter1); + if ( !W_ERROR_IS_OK(werror) ) { + printf("failed (%s)\n", win_errstr(werror)); + goto done; + } + printf("ok\n"); + + RPCCLIENT_PRINTERNAME(printername_path, cli2, printername); + + printf("Opening %s...", printername_path); + werror = rpccli_spoolss_openprinter_ex(cli2, mem_ctx, + printername_path, + PRINTER_ALL_ACCESS, + &hPrinter2); + if ( !W_ERROR_IS_OK(werror) ) { + printf("failed (%s)\n", win_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..."); + { + WERROR _result; + dcerpc_spoolss_ClosePrinter(cli->binding_handle, mem_ctx, &hPrinter1, &_result); + dcerpc_spoolss_ClosePrinter(cli2->binding_handle, mem_ctx, &hPrinter2, &_result); + } + printf("ok\n"); + + /* close the second remote connection */ + + cli_shutdown( cli_server2 ); + return WERR_OK; +} + +static void display_proc_info1(struct spoolss_PrintProcessorInfo1 *r) +{ + printf("print_processor_name: %s\n", r->print_processor_name); +} + +static WERROR cmd_spoolss_enum_procs(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + WERROR werror; + const char *environment = SPOOLSS_ARCHITECTURE_NT_X86; + uint32_t num_procs, level = 1, i; + union spoolss_PrintProcessorInfo *procs; + + /* Parse the command arguments */ + + if (argc < 1 || argc > 4) { + printf ("Usage: %s [environment] [level]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + environment = argv[1]; + } + + if (argc == 3) { + level = atoi(argv[2]); + } + + /* Enumerate Print Processors */ + + werror = rpccli_spoolss_enumprintprocessors(cli, mem_ctx, + cli->srv_name_slash, + environment, + level, + 0, + &num_procs, + &procs); + if (!W_ERROR_IS_OK(werror)) + goto done; + + /* Display output */ + + for (i = 0; i < num_procs; i++) { + switch (level) { + case 1: + display_proc_info1(&procs[i].info1); + break; + } + } + + done: + return werror; +} + +static void display_proc_data_types_info1(struct spoolss_PrintProcDataTypesInfo1 *r) +{ + printf("name_array: %s\n", r->name_array); +} + +static WERROR cmd_spoolss_enum_proc_data_types(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + WERROR werror; + const char *print_processor_name = "winprint"; + uint32_t num_procs, level = 1, i; + union spoolss_PrintProcDataTypesInfo *procs; + + /* Parse the command arguments */ + + if (argc < 1 || argc > 4) { + printf ("Usage: %s [environment] [level]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + print_processor_name = argv[1]; + } + + if (argc == 3) { + level = atoi(argv[2]); + } + + /* Enumerate Print Processor Data Types */ + + werror = rpccli_spoolss_enumprintprocessordatatypes(cli, mem_ctx, + cli->srv_name_slash, + print_processor_name, + level, + 0, + &num_procs, + &procs); + if (!W_ERROR_IS_OK(werror)) + goto done; + + /* Display output */ + + for (i = 0; i < num_procs; i++) { + switch (level) { + case 1: + display_proc_data_types_info1(&procs[i].info1); + break; + } + } + + done: + return werror; +} + +static void display_monitor1(const struct spoolss_MonitorInfo1 *r) +{ + printf("monitor_name: %s\n", r->monitor_name); +} + +static void display_monitor2(const struct spoolss_MonitorInfo2 *r) +{ + printf("monitor_name: %s\n", r->monitor_name); + printf("environment: %s\n", r->environment); + printf("dll_name: %s\n", r->dll_name); +} + +static WERROR cmd_spoolss_enum_monitors(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + WERROR werror; + uint32_t count, level = 1, i; + union spoolss_MonitorInfo *info; + + /* Parse the command arguments */ + + if (argc > 2) { + printf("Usage: %s [level]\n", argv[0]); + return WERR_OK; + } + + if (argc == 2) { + level = atoi(argv[1]); + } + + /* Enumerate Print Monitors */ + + werror = rpccli_spoolss_enummonitors(cli, mem_ctx, + cli->srv_name_slash, + level, + 0, + &count, + &info); + if (!W_ERROR_IS_OK(werror)) { + goto done; + } + + /* Display output */ + + for (i = 0; i < count; i++) { + switch (level) { + case 1: + display_monitor1(&info[i].info1); + break; + case 2: + display_monitor2(&info[i].info2); + break; + } + } + + done: + return werror; +} + +static WERROR cmd_spoolss_create_printer_ic(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + WERROR result; + NTSTATUS status; + struct policy_handle handle, gdi_handle; + const char *printername; + struct spoolss_DevmodeContainer devmode_ctr; + struct dcerpc_binding_handle *b = cli->binding_handle; + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + SEC_FLAG_MAXIMUM_ALLOWED, + &handle); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + ZERO_STRUCT(devmode_ctr); + + status = dcerpc_spoolss_CreatePrinterIC(b, mem_ctx, + &handle, + &gdi_handle, + &devmode_ctr, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + done: + if (is_valid_policy_hnd(&gdi_handle)) { + WERROR _result; + dcerpc_spoolss_DeletePrinterIC(b, mem_ctx, &gdi_handle, &_result); + } + if (is_valid_policy_hnd(&handle)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result); + } + + return result; +} + +static WERROR cmd_spoolss_play_gdi_script_on_printer_ic(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + WERROR result; + NTSTATUS status; + struct policy_handle handle, gdi_handle; + const char *printername; + struct spoolss_DevmodeContainer devmode_ctr; + struct dcerpc_binding_handle *b = cli->binding_handle; + DATA_BLOB in,out; + uint32_t count = 0; + + RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); + + result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, + printername, + SEC_FLAG_MAXIMUM_ALLOWED, + &handle); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + ZERO_STRUCT(devmode_ctr); + + status = dcerpc_spoolss_CreatePrinterIC(b, mem_ctx, + &handle, + &gdi_handle, + &devmode_ctr, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + in = data_blob_string_const(""); + out = data_blob_talloc_zero(mem_ctx, 4); + + status = dcerpc_spoolss_PlayGDIScriptOnPrinterIC(b, mem_ctx, + &gdi_handle, + in.data, + in.length, + out.data, + out.length, + 0, /* ul */ + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + count = IVAL(out.data, 0); + + out = data_blob_talloc_zero(mem_ctx, + count * sizeof(struct UNIVERSAL_FONT_ID) + 4); + + status = dcerpc_spoolss_PlayGDIScriptOnPrinterIC(b, mem_ctx, + &gdi_handle, + in.data, + in.length, + out.data, + out.length, + 0, /* ul */ + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + { + enum ndr_err_code ndr_err; + struct UNIVERSAL_FONT_ID_ctr r; + + ndr_err = ndr_pull_struct_blob(&out, mem_ctx, &r, + (ndr_pull_flags_fn_t)ndr_pull_UNIVERSAL_FONT_ID_ctr); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + NDR_PRINT_DEBUG(UNIVERSAL_FONT_ID_ctr, &r); + } + } + + done: + if (is_valid_policy_hnd(&gdi_handle)) { + WERROR _result; + dcerpc_spoolss_DeletePrinterIC(b, mem_ctx, &gdi_handle, &_result); + } + if (is_valid_policy_hnd(&handle)) { + WERROR _result; + dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result); + } + + return result; +} + +static WERROR cmd_spoolss_get_core_printer_drivers(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status; + HRESULT result; + struct dcerpc_binding_handle *b = cli->binding_handle; + const char *architecture = SPOOLSS_ARCHITECTURE_x64; + struct spoolss_CorePrinterDriver core_printer_drivers; + DATA_BLOB blob; + bool ok; + int i; + uint32_t count; + const char **array; + + if (argc == 1) { + count = 1; + array = talloc_zero_array(mem_ctx, const char *, count + 1); + if (array == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + array[0] = talloc_strdup(array, SPOOLSS_CORE_PRINT_PACKAGE_FILES_XPSDRV); + if (array[0] == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + } else { + count = argc -1; + array = talloc_zero_array(mem_ctx, const char *, count + 1); + if (array == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + for (i = 0; i < argc - 1; i++) { + array[i] = talloc_strdup(array, argv[i + 1]); + if (array[i] == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + } + } + + ok = push_reg_multi_sz(mem_ctx, &blob, array); + if (!ok) { + return WERR_NOT_ENOUGH_MEMORY; + } + + status = dcerpc_spoolss_GetCorePrinterDrivers(b, mem_ctx, + cli->srv_name_slash, + architecture, + blob.length/2, + (uint16_t *)blob.data, + count, + &core_printer_drivers, + &result); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (!HRES_IS_OK(result)) { + return W_ERROR(WIN32_FROM_HRESULT(result)); + } + + return WERR_OK; +} + +static WERROR cmd_spoolss_enum_permachineconnections(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status; + WERROR result; + struct dcerpc_binding_handle *b = cli->binding_handle; + const char *servername = cli->srv_name_slash; + DATA_BLOB in = data_blob_null; + struct spoolss_PrinterInfo4 *info; + uint32_t needed, count; + + if (argc > 2) { + printf("usage: %s [servername]\n", argv[0]); + return WERR_OK; + } + + if (argc > 1) { + servername = argv[1]; + } + + status = dcerpc_spoolss_EnumPerMachineConnections(b, mem_ctx, + servername, + &in, + in.length, + &count, + &info, + &needed, + &result); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) { + in = data_blob_talloc_zero(mem_ctx, needed); + status = dcerpc_spoolss_EnumPerMachineConnections(b, mem_ctx, + servername, + &in, + in.length, + &count, + &info, + &needed, + &result); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + } + + return result; +} + +static WERROR cmd_spoolss_add_permachineconnection(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status; + WERROR result; + struct dcerpc_binding_handle *b = cli->binding_handle; + const char *servername = cli->srv_name_slash; + const char *printername = "Microsoft Print to PDF"; + const char *printserver = "samba.org"; + const char *provider = ""; /* refers to Win32spl.dll then */ + const char *composed_printername; + + if (argc > 5) { + printf("usage: %s [servername] [printername] [printserver] [provider]\n", argv[0]); + return WERR_OK; + } + + if (argc > 1) { + servername = argv[1]; + } + if (argc > 2) { + printername = argv[2]; + } + if (argc > 3) { + printserver = argv[3]; + } + if (argc > 4) { + provider = argv[4]; + } + + composed_printername = talloc_asprintf(mem_ctx, "%s\\%s", servername, + printername); + if (composed_printername == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + status = dcerpc_spoolss_AddPerMachineConnection(b, mem_ctx, + servername, + composed_printername, + printserver, + provider, + &result); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + return result; +} + +static WERROR cmd_spoolss_del_permachineconnection(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status; + WERROR result; + struct dcerpc_binding_handle *b = cli->binding_handle; + const char *servername = cli->srv_name_slash; + const char *printername = "Microsoft Print to PDF"; + const char *composed_printername; + + if (argc > 3) { + printf("usage: %s [servername] [printername]\n", argv[0]); + return WERR_OK; + } + + if (argc > 1) { + servername = argv[1]; + } + if (argc > 2) { + printername = argv[2]; + } + + composed_printername = talloc_asprintf(mem_ctx, "%s\\%s", servername, + printername); + if (composed_printername == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + status = dcerpc_spoolss_DeletePerMachineConnection(b, mem_ctx, + servername, + composed_printername, + &result); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + return result; +} + +/* List of commands exported by this module */ +struct cmd_set spoolss_commands[] = { + + { + .name = "SPOOLSS", + }, + + { + .name = "adddriver", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_addprinterdriver, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Add a print driver", + .usage = "", + .use_netlogon_creds = false, + }, + { + .name = "addprinter", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_addprinterex, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Add a printer", + .usage = "", + }, + { + .name = "deldriver", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_deletedriver, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Delete a printer driver", + .usage = "", + }, + { + .name = "deldriverex", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_deletedriverex, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Delete a printer driver with files", + .usage = "", + }, + { + .name = "enumdata", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_enum_data, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Enumerate printer data", + .usage = "", + }, + { + .name = "enumdataex", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_enum_data_ex, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Enumerate printer data for a key", + .usage = "", + }, + { + .name = "enumkey", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_enum_printerkey, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Enumerate printer keys", + .usage = "", + }, + { + .name = "enumjobs", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_enum_jobs, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Enumerate print jobs", + .usage = "", + }, + { + .name = "getjob", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_get_job, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Get print job", + .usage = "", + }, + { + .name = "setjob", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_set_job, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Set print job", + .usage = "", + }, + { + .name = "enumports", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_enum_ports, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Enumerate printer ports", + .usage = "", + }, + { + .name = "enumdrivers", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_enum_drivers, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Enumerate installed printer drivers", + .usage = "", + }, + { + .name = "enumprinters", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_enum_printers, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Enumerate printers", + .usage = "", + }, + { + .name = "getdata", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_getprinterdata, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Get print driver data", + .usage = "", + }, + { + .name = "getdataex", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_getprinterdataex, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Get printer driver data with keyname", + .usage = "", + }, + { + .name = "getdriver", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_getdriver, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Get print driver information", + .usage = "", + }, + { + .name = "getdriverdir", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_getdriverdir, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Get print driver upload directory", + .usage = "", + }, + { + .name = "getdriverpackagepath", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_getdriverpackagepath, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Get print driver package download directory", + .usage = "", + }, + { + .name = "getprinter", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_getprinter, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Get printer info", + .usage = "", + }, + { + .name = "openprinter", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_open_printer, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Open printer handle", + .usage = "", + }, + { + .name = "openprinter_ex", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_open_printer_ex, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Open printer handle", + .usage = "", + }, + { + .name = "setdriver", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_setdriver, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Set printer driver", + .usage = "", + }, + { + .name = "getprintprocdir", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_getprintprocdir, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Get print processor directory", + .usage = "", + }, + { + .name = "addform", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_addform, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Add form", + .usage = "", + }, + { + .name = "setform", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_setform, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Set form", + .usage = "", + }, + { + .name = "getform", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_getform, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Get form", + .usage = "", + }, + { + .name = "deleteform", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_deleteform, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Delete form", + .usage = "", + }, + { + .name = "enumforms", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_enum_forms, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Enumerate forms", + .usage = "", + }, + { + .name = "setprinter", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_setprinter, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Set printer comment", + .usage = "", + }, + { + .name = "setprintername", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_setprintername, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Set printername", + .usage = "", + }, + { + .name = "setprinterdata", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_setprinterdata, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Set REG_SZ printer data", + .usage = "", + }, + { + .name = "rffpcnex", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_rffpcnex, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Rffpcnex test", + .usage = "", + }, + { + .name = "printercmp", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_printercmp, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Printer comparison test", + .usage = "", + }, + { + .name = "enumprocs", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_enum_procs, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Enumerate Print Processors", + .usage = "", + }, + { + .name = "enumprocdatatypes", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_enum_proc_data_types, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Enumerate Print Processor Data Types", + .usage = "", + }, + { + .name = "enummonitors", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_enum_monitors, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Enumerate Print Monitors", + .usage = "", + }, + { + .name = "createprinteric", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_create_printer_ic, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Create Printer IC", + .usage = "", + }, + { + .name = "playgdiscriptonprinteric", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_play_gdi_script_on_printer_ic, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Create Printer IC", + .usage = "", + }, + { + .name = "getcoreprinterdrivers", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_get_core_printer_drivers, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Get CorePrinterDriver", + .usage = "", + }, + { + .name = "enumpermachineconnections", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_enum_permachineconnections, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Enumerate Per Machine Connections", + .usage = "", + }, + { + .name = "addpermachineconnection", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_add_permachineconnection, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Add Per Machine Connection", + .usage = "", + }, + { + .name = "delpermachineconnection", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_spoolss_del_permachineconnection, + .table = &ndr_table_spoolss, + .rpc_pipe = NULL, + .description = "Delete Per Machine Connection", + .usage = "", + }, + { + .name = NULL, + }, +}; diff --git a/source3/rpcclient/cmd_spotlight.c b/source3/rpcclient/cmd_spotlight.c new file mode 100644 index 0000000..ba3f61f --- /dev/null +++ b/source3/rpcclient/cmd_spotlight.c @@ -0,0 +1,420 @@ +/* + Unix SMB/CIFS implementation. + RPC Spotlight client + + Copyright (C) Ralph Boehme 2018 + + 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" +#include "libsmb/libsmb.h" +#include "../librpc/gen_ndr/ndr_mdssvc_c.h" +#include "../rpc_server/mdssvc/mdssvc.h" +#include "../rpc_server/mdssvc/dalloc.h" +#include "../rpc_server/mdssvc/marshalling.h" + +static NTSTATUS cmd_mdssvc_fetch_properties( + struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + uint32_t device_id = 0x2f000045; + uint32_t unkn1 = 23; + uint32_t unkn2 = 0; + struct policy_handle share_handle; + char share_path[1025] = { 0 }; + uint32_t mds_status; + uint32_t flags; /* server always returns 0x6b000001 ? */ + uint32_t unkn3; /* server always returns 0 ? */ + struct mdssvc_blob request_blob; + struct mdssvc_blob response_blob; + uint32_t max_fragment_size = 64 * 1024; + DALLOC_CTX *d, *mds_reply; + uint64_t *uint64var; + sl_array_t *array1, *array2; + uint32_t unkn4; + int result; + bool ok; + + if (argc != 3) { + printf("Usage: %s SHARENAME MOUNTPATH\n", argv[0]); + return NT_STATUS_OK; + } + + status = dcerpc_mdssvc_open(b, mem_ctx, + &device_id, + &unkn1, + &unkn2, + argv[2], + argv[1], + share_path, + &share_handle); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = dcerpc_mdssvc_unknown1(b, mem_ctx, + &share_handle, + 0, + device_id, + unkn1, + 0, + geteuid(), + getegid(), + &mds_status, + &flags, + &unkn3); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + d = dalloc_new(mem_ctx); + if (d == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + mds_reply = dalloc_new(mem_ctx); + if (mds_reply == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + array1 = dalloc_zero(d, sl_array_t); + if (array1 == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + array2 = dalloc_zero(d, sl_array_t); + if (array2 == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + result = dalloc_stradd(array2, "fetchPropertiesForContext:"); + if (result != 0) { + status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + uint64var = talloc_zero_array(mem_ctx, uint64_t, 2); + if (uint64var == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + talloc_set_name(uint64var, "uint64_t *"); + + result = dalloc_add(array2, &uint64var[0], uint64_t *); + if (result != 0) { + status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + result = dalloc_add(array1, array2, sl_array_t); + if (result != 0) { + status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + result = dalloc_add(d, array1, sl_array_t); + if (result != 0) { + status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + status = sl_pack_alloc(mem_ctx, d, &request_blob, max_fragment_size); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = dcerpc_mdssvc_cmd(b, mem_ctx, + &share_handle, + 0, + device_id, + 23, + 0, + 0x6b000001, + request_blob, + 0, + max_fragment_size, + 1, + max_fragment_size, + 0, + 0, + &mds_status, + &response_blob, + &unkn4); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + ok = sl_unpack(mds_reply, (char *)response_blob.spotlight_blob, + response_blob.length); + if (!ok) { + DEBUG(1, ("error unpacking Spotlight RPC blob\n")); + status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + DEBUG(0, ("%s", dalloc_dump(mds_reply, 0))); + +done: + return status; +} + +static NTSTATUS cmd_mdssvc_fetch_attributes( + struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS status; + uint32_t device_id = 0x2f000045; + uint32_t unkn1 = 23; + uint32_t unkn2 = 0; + struct policy_handle share_handle; + char share_path[1025]; + uint32_t mds_status; + uint32_t flags; /* server always returns 0x6b000001 ? */ + uint32_t unkn3; /* server always returns 0 ? */ + struct mdssvc_blob request_blob; + struct mdssvc_blob response_blob; + uint32_t max_fragment_size = 64 * 1024; + DALLOC_CTX *d, *mds_reply; + uint64_t *uint64var; + sl_array_t *array; + sl_array_t *cmd_array; + sl_array_t *attr_array; + sl_cnids_t *cnids; + uint64_t cnid; + uint32_t unkn4; + int result; + bool ok; + + if (argc != 4) { + printf("Usage: %s SHARENAME MOUNTPATH CNID\n", argv[0]); + return NT_STATUS_OK; + } + + ok = conv_str_u64(argv[3], &cnid); + if (!ok) { + printf("Failed to parse: %s\n", argv[3]); + return NT_STATUS_INVALID_PARAMETER; + } + + status = dcerpc_mdssvc_open(b, mem_ctx, + &device_id, + &unkn1, + &unkn2, + argv[2], + argv[1], + share_path, + &share_handle); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = dcerpc_mdssvc_unknown1(b, mem_ctx, + &share_handle, + 0, + device_id, + unkn1, + 0, + geteuid(), + getegid(), + &mds_status, + &flags, + &unkn3); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + d = dalloc_new(mem_ctx); + if (d == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + array = dalloc_zero(d, sl_array_t); + if (array == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + result = dalloc_add(d, array, sl_array_t); + if (result != 0) { + status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + cmd_array = dalloc_zero(d, sl_array_t); + if (cmd_array == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + result = dalloc_add(array, cmd_array, sl_array_t); + if (result != 0) { + status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + result = dalloc_stradd(cmd_array, + "fetchAttributes:forOIDArray:context:"); + if (result != 0) { + status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + uint64var = talloc_zero_array(mem_ctx, uint64_t, 2); + if (uint64var == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + talloc_set_name(uint64var, "uint64_t *"); + uint64var[0] = 0x500a; + uint64var[1] = 0; + + result = dalloc_add(cmd_array, &uint64var[0], uint64_t *); + if (result != 0) { + status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + attr_array = dalloc_zero(d, sl_array_t); + if (attr_array == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + result = dalloc_add(array, attr_array, sl_array_t); + if (result != 0) { + status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + result = dalloc_stradd(attr_array, "kMDItemPath"); + if (result != 0) { + status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + /* CNIDs */ + cnids = talloc_zero(array, sl_cnids_t); + if (cnids == NULL) { + status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + cnids->ca_cnids = dalloc_new(cnids); + if (cnids->ca_cnids == NULL) { + status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + cnids->ca_unkn1 = 0xadd; + cnids->ca_context = 0x6b000020; + + result = dalloc_add_copy(cnids->ca_cnids, &cnid, uint64_t); + if (result != 0) { + status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + result = dalloc_add(array, cnids, sl_cnids_t); + if (result != 0) { + status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + status = sl_pack_alloc(mem_ctx, d, &request_blob, max_fragment_size); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = dcerpc_mdssvc_cmd(b, mem_ctx, + &share_handle, + 0, + device_id, + 23, + 0, + 0x6b000001, + request_blob, + 0, + max_fragment_size, + 1, + max_fragment_size, + 0, + 0, + &mds_status, + &response_blob, + &unkn4); + if (!NT_STATUS_IS_OK(status)) { + printf("dcerpc_mdssvc_cmd failed: %s\n", nt_errstr(status)); + goto done; + } + + if (response_blob.length == 0) { + printf("mdssvc returned empty response\n"); + status = NT_STATUS_RPC_PROTOCOL_ERROR; + goto done; + } + + mds_reply = dalloc_new(mem_ctx); + if (mds_reply == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + ok = sl_unpack(mds_reply, (char *)response_blob.spotlight_blob, + response_blob.length); + if (!ok) { + printf("Unpacking Spotlight RPC blob failed\n"); + status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + printf("%s", dalloc_dump(mds_reply, 0)); + +done: + return status; +} + +/* List of commands exported by this module */ + +struct cmd_set spotlight_commands[] = { + + { + .name = "MDSSVC" + }, + { + .name = "fetch_properties", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_mdssvc_fetch_properties, + .table = &ndr_table_mdssvc, + .description = "Fetch connection properties", + .usage = "", + }, + { + .name = "fetch_attributes", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_mdssvc_fetch_attributes, + .table = &ndr_table_mdssvc, + .description = "Fetch attributes for a CNID", + .usage = "", + }, + {0} +}; diff --git a/source3/rpcclient/cmd_srvsvc.c b/source3/rpcclient/cmd_srvsvc.c new file mode 100644 index 0000000..073e51d --- /dev/null +++ b/source3/rpcclient/cmd_srvsvc.c @@ -0,0 +1,1266 @@ +/* + 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" +#include "../librpc/gen_ndr/ndr_srvsvc.h" +#include "../librpc/gen_ndr/ndr_srvsvc_c.h" +#include "../libcli/security/display_sec.h" +#include "lib/util/string_wrappers.h" + +/* Display server query info */ + +static char *get_server_type_str(uint32_t 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 & ((uint32_t)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_t 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_t info_level = 101; + union srvsvc_NetSrvInfo info; + WERROR result; + NTSTATUS status; + const char *server_unc = cli->srv_name_slash; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc > 3) { + printf("Usage: %s [infolevel] [server_unc]\n", argv[0]); + return WERR_OK; + } + + if (argc >= 2) { + info_level = atoi(argv[1]); + } + + if (argc >= 3) { + server_unc = argv[2]; + } + + status = dcerpc_srvsvc_NetSrvGetInfo(b, mem_ctx, + server_unc, + 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 void display_share_info_1005(struct srvsvc_NetShareInfo1005 *r) +{ + printf("flags: 0x%x\n", r->dfs_flags); + printf("csc caching: %u\n", + (r->dfs_flags & SHARE_1005_CSC_POLICY_MASK) >> + SHARE_1005_CSC_POLICY_SHIFT); +} + +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_t 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 count = 0; + uint32_t resume_handle = 0; + uint32_t *resume_handle_p = NULL; + uint32_t preferred_len = 0xffffffff, i; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 = dcerpc_srvsvc_NetShareEnum(b, mem_ctx, + cli->desthost, + &info_ctr, + preferred_len, + &totalentries, + resume_handle_p, + &result); + break; + case NDR_SRVSVC_NETSHAREENUMALL: + status = dcerpc_srvsvc_NetShareEnumAll(b, mem_ctx, + cli->desthost, + &info_ctr, + preferred_len, + &totalentries, + resume_handle_p, + &result); + break; + default: + return WERR_INVALID_PARAMETER; + } + + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + /* Display results */ + + switch (info_level) { + case 1: + count = info_ctr.ctr.ctr1->count; + for (i = 0; i < count; i++) + display_share_info_1(&info_ctr.ctr.ctr1->array[i]); + break; + case 2: + count = info_ctr.ctr.ctr2->count; + for (i = 0; i < count; i++) + display_share_info_2(&info_ctr.ctr.ctr2->array[i]); + break; + case 502: + count = info_ctr.ctr.ctr502->count; + for (i = 0; i < count; 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_t info_level = 502; + union srvsvc_NetShareInfo info; + WERROR result; + NTSTATUS status; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc < 2 || argc > 3) { + printf("Usage: %s sharename [infolevel 1|2|502|1005]\n", + argv[0]); + return WERR_OK; + } + + if (argc == 3) + info_level = atoi(argv[2]); + + status = dcerpc_srvsvc_NetShareGetInfo(b, mem_ctx, + cli->desthost, + argv[1], + info_level, + &info, + &result); + + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + if (!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; + case 1005: + display_share_info_1005(info.info1005); + 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_t info_level = 502; + union srvsvc_NetShareInfo info_get; + WERROR result; + NTSTATUS status; + uint32_t parm_err = 0; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc > 3) { + printf("Usage: %s [sharename] [comment]\n", argv[0]); + return WERR_OK; + } + + /* retrieve share info */ + status = dcerpc_srvsvc_NetShareGetInfo(b, mem_ctx, + cli->desthost, + argv[1], + info_level, + &info_get, + &result); + + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + info_get.info502->comment = argv[2]; + + /* set share info */ + status = dcerpc_srvsvc_NetShareSetInfo(b, mem_ctx, + cli->desthost, + argv[1], + info_level, + &info_get, + &parm_err, + &result); + + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + /* re-retrieve share info and display */ + status = dcerpc_srvsvc_NetShareGetInfo(b, mem_ctx, + cli->desthost, + argv[1], + info_level, + &info_get, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + display_share_info_502(info_get.info502); + + done: + return result; +} + +static WERROR cmd_srvsvc_net_share_set_dfs_flags(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct srvsvc_NetShareInfo1005 info1005 = { 0 }; + union srvsvc_NetShareInfo info = { .info1005 = &info1005 }; + WERROR result; + NTSTATUS status; + uint32_t parm_err = 0; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc > 3) { + printf("Usage: %s [sharename] [dfsflags]\n", argv[0]); + return WERR_OK; + } + + if (argc > 2) { + info.info1005->dfs_flags = strtol(argv[2], NULL, 0); + } + + /* set share info */ + status = dcerpc_srvsvc_NetShareSetInfo(b, mem_ctx, + cli->desthost, + argv[1], + 1005, + &info, + &parm_err, + &result); + + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + return result; + } + + /* re-retrieve share info and display */ + status = dcerpc_srvsvc_NetShareGetInfo(b, mem_ctx, + cli->desthost, + argv[1], + 1005, + &info, + &result); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + return result; + } + + display_share_info_1005(info.info1005); + + 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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc > 1) { + printf("Usage: %s\n", argv[0]); + return WERR_OK; + } + + status = dcerpc_srvsvc_NetRemoteTOD(b, 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) +{ + struct srvsvc_NetFileCtr3 ctr3 = { 0 }; + struct srvsvc_NetFileInfoCtr info_ctr = { + .level = 3, + .ctr = { + .ctr3 = &ctr3, + }, + }; + WERROR result; + NTSTATUS status; + uint32_t preferred_len = 0xffff; + uint32_t total_entries = 0; + uint32_t resume_handle = 0; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc > 2) { + printf("Usage: %s [infolevel]\n", argv[0]); + return WERR_OK; + } + + if (argc == 2) { + info_ctr.level = atoi(argv[1]); + } + + status = dcerpc_srvsvc_NetFileEnum(b, mem_ctx, + cli->desthost, + NULL, + NULL, + &info_ctr, + preferred_len, + &total_entries, + &resume_handle, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + if (info_ctr.level == 3) { + struct srvsvc_NetFileCtr3 *ret = info_ctr.ctr.ctr3; + uint32_t i; + + for (i=0; i<ret->count; i++) { + printf("%s\n", ret->array[i].path); + } + } + 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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 = dcerpc_srvsvc_NetNameValidate(b, mem_ctx, + cli->desthost, + argv[1], + name_type, + flags, + &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_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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc < 2 || argc > 4) { + printf("Usage: %s [sharename] [file]\n", argv[0]); + return WERR_OK; + } + + status = dcerpc_srvsvc_NetGetFileSecurity(b, mem_ctx, + cli->desthost, + argv[1], + argv[2], + SECINFO_DACL, + &sd_buf, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + + if (!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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc < 2 || argc > 4) { + printf("Usage: %s [client] [user]\n", argv[0]); + return WERR_OK; + } + + status = dcerpc_srvsvc_NetSessDel(b, mem_ctx, + cli->desthost, + argv[1], + argv[2], + &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_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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 = dcerpc_srvsvc_NetSessEnum(b, mem_ctx, + cli->desthost, + client, + user, + &info_ctr, + 0xffffffff, + &total_entries, + resume_handle_p, + &result); + + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + goto done; + } + + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + d_printf("Received %d entries.\n", total_entries); + + 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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 = dcerpc_srvsvc_NetDiskEnum(b, mem_ctx, + cli->desthost, + level, + &info, + 0xffffffff, + &total_entries, + &resume_handle, + &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_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$"; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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_PARAMETER; + } + + status = dcerpc_srvsvc_NetConnEnum(b, mem_ctx, + cli->desthost, + path, + &info_ctr, + 0xffffffff, + &total_entries, + resume_handle_p, + &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_share_add(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + struct srvsvc_NetShareInfo502 info502 = { 0 }; + union srvsvc_NetShareInfo info = { .info502 = &info502 }; + WERROR result; + NTSTATUS status; + uint32_t max_users = -1, parm_error; + struct sec_desc_buf sd_buf = { 0 }; + const char *path, *share_name, *comment = NULL; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc < 3 || argc > 5) { + printf("Usage: %s path share_name [max_users] [comment]\n", + argv[0]); + return WERR_OK; + } + + path = argv[1]; + share_name = argv[2]; + + if (argc >= 4) { + max_users = atoi(argv[3]); + } + + if (argc >= 5) { + comment = argv[4]; + } + + info.info502->name = share_name; + info.info502->type = STYPE_DISKTREE; + info.info502->comment = comment; + info.info502->max_users = max_users; + info.info502->path = path; + info.info502->sd_buf = sd_buf; + + status = dcerpc_srvsvc_NetShareAdd(b, mem_ctx, cli->desthost, + 502, &info, &parm_error, &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + + return result; +} + +static WERROR cmd_srvsvc_net_share_del(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + const char *share_name; + WERROR result; + NTSTATUS status; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc < 2) { + printf("Usage: %s share_name\n", argv[0]); + return WERR_OK; + } + + share_name = argv[1]; + + status = dcerpc_srvsvc_NetShareDel(b, mem_ctx, cli->desthost, + share_name, 0, &result); + + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + + return result; +} + + +/* List of commands exported by this module */ + +struct cmd_set srvsvc_commands[] = { + + { + .name = "SRVSVC", + }, + + { + .name = "srvinfo", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_srvsvc_srv_query_info, + .table = &ndr_table_srvsvc, + .rpc_pipe = NULL, + .description = "Server query info", + .usage = "", + }, + { + .name = "netshareenum", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_srvsvc_net_share_enum, + .table = &ndr_table_srvsvc, + .rpc_pipe = NULL, + .description = "Enumerate shares", + .usage = "", + }, + { + .name = "netshareenumall", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_srvsvc_net_share_enum_all, + .table = &ndr_table_srvsvc, + .rpc_pipe = NULL, + .description = "Enumerate all shares", + .usage = "", + }, + { + .name = "netsharegetinfo", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_srvsvc_net_share_get_info, + .table = &ndr_table_srvsvc, + .rpc_pipe = NULL, + .description = "Get Share Info", + .usage = "", + }, + { + .name = "netsharesetinfo", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_srvsvc_net_share_set_info, + .table = &ndr_table_srvsvc, + .rpc_pipe = NULL, + .description = "Set Share Info", + .usage = "", + }, + { + .name = "netsharesetdfsflags", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_srvsvc_net_share_set_dfs_flags, + .table = &ndr_table_srvsvc, + .rpc_pipe = NULL, + .description = "Set DFS flags", + .usage = "", + }, + { + .name = "netfileenum", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_srvsvc_net_file_enum, + .table = &ndr_table_srvsvc, + .rpc_pipe = NULL, + .description = "Enumerate open files", + .usage = "", + }, + { + .name = "netremotetod", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_srvsvc_net_remote_tod, + .table = &ndr_table_srvsvc, + .rpc_pipe = NULL, + .description = "Fetch remote time of day", + .usage = "", + }, + { + .name = "netnamevalidate", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_srvsvc_net_name_validate, + .table = &ndr_table_srvsvc, + .rpc_pipe = NULL, + .description = "Validate sharename", + .usage = "", + }, + { + .name = "netfilegetsec", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_srvsvc_net_file_get_sec, + .table = &ndr_table_srvsvc, + .rpc_pipe = NULL, + .description = "Get File security", + .usage = "", + }, + { + .name = "netsessdel", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_srvsvc_net_sess_del, + .table = &ndr_table_srvsvc, + .rpc_pipe = NULL, + .description = "Delete Session", + .usage = "", + }, + { + .name = "netsessenum", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_srvsvc_net_sess_enum, + .table = &ndr_table_srvsvc, + .rpc_pipe = NULL, + .description = "Enumerate Sessions", + .usage = "", + }, + { + .name = "netdiskenum", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_srvsvc_net_disk_enum, + .table = &ndr_table_srvsvc, + .rpc_pipe = NULL, + .description = "Enumerate Disks", + .usage = "", + }, + { + .name = "netconnenum", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_srvsvc_net_conn_enum, + .table = &ndr_table_srvsvc, + .rpc_pipe = NULL, + .description = "Enumerate Connections", + .usage = "", + }, + { + .name = "netshareadd", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_srvsvc_net_share_add, + .table = &ndr_table_srvsvc, + .rpc_pipe = NULL, + .description = "Add share", + .usage = "", + }, + { + .name = "netsharedel", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_srvsvc_net_share_del, + .table = &ndr_table_srvsvc, + .rpc_pipe = NULL, + .description = "Delete share", + .usage = "", + }, + + { + .name = NULL, + } +}; diff --git a/source3/rpcclient/cmd_unixinfo.c b/source3/rpcclient/cmd_unixinfo.c new file mode 100644 index 0000000..16f13a2 --- /dev/null +++ b/source3/rpcclient/cmd_unixinfo.c @@ -0,0 +1,141 @@ +/* + * Unix SMB/CIFS implementation. + * + * 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" +#include "../librpc/gen_ndr/ndr_unixinfo_c.h" +#include "libcli/security/dom_sid.h" + +static NTSTATUS cmd_unixinfo_uidtosid( + struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + uint64_t uid = 0; + struct dom_sid sid = { .sid_rev_num = 0, }; + struct dom_sid_buf buf; + NTSTATUS status, result; + + if (argc != 2) { + printf("Usage: %s [uid]\n", argv[0]); + return NT_STATUS_OK; + } + uid = atoi(argv[1]); + + status = dcerpc_unixinfo_UidToSid(b, mem_ctx, uid, &sid, &result); + if (!NT_STATUS_IS_OK(status)) { + fprintf(stderr, + "dcerpc_unixinfo_UidToSid failed: %s\n", + nt_errstr(status)); + goto done; + } + if (!NT_STATUS_IS_OK(result)) { + fprintf(stderr, + "dcerpc_unixinfo_UidToSid returned: %s\n", + nt_errstr(result)); + status = result; + goto done; + } + + printf("UidToSid(%"PRIu64")=%s\n", + uid, + dom_sid_str_buf(&sid, &buf)); + +done: + return status; +} + +static NTSTATUS cmd_unixinfo_getpwuid( + struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct dcerpc_binding_handle *b = cli->binding_handle; + uint32_t count = 1; + uint64_t uids = 0; + struct unixinfo_GetPWUidInfo infos = { .homedir = NULL, }; + NTSTATUS status, result; + + if (argc != 2) { + printf("Usage: %s [uid]\n", argv[0]); + return NT_STATUS_OK; + } + uids = atoi(argv[1]); + + status = dcerpc_unixinfo_GetPWUid( + b, mem_ctx, &count, &uids, &infos, &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + if (!NT_STATUS_IS_OK(status)) { + fprintf(stderr, + "dcerpc_unixinfo_GetPWUid failed: %s\n", + nt_errstr(status)); + return status; + } + if (!NT_STATUS_IS_OK(result)) { + fprintf(stderr, + "dcerpc_unixinfo_GetPWUid returned: %s\n", + nt_errstr(result)); + return result; + } + + printf("status=%s, homedir=%s, shell=%s\n", + nt_errstr(infos.status), + infos.homedir, + infos.shell); + +done: + return status; +} + +/* List of commands exported by this module */ + +struct cmd_set unixinfo_commands[] = { + + { + .name = "UNIXINFO", + }, + + { + .name = "getpwuid", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_unixinfo_getpwuid, + .wfn = NULL, + .table = &ndr_table_unixinfo, + .rpc_pipe = NULL, + .description = "Get shell and homedir", + .usage = "", + }, + { + .name = "uidtosid", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_unixinfo_uidtosid, + .wfn = NULL, + .table = &ndr_table_unixinfo, + .rpc_pipe = NULL, + .description = "Convert uid to sid", + .usage = "", + }, + { + .name = NULL + }, +}; diff --git a/source3/rpcclient/cmd_winreg.c b/source3/rpcclient/cmd_winreg.c new file mode 100644 index 0000000..26fa146 --- /dev/null +++ b/source3/rpcclient/cmd_winreg.c @@ -0,0 +1,491 @@ +/* + Unix SMB/CIFS implementation. + RPC pipe client + + Copyright (C) Guenther Deschner 2009 + + 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" +#include "../librpc/gen_ndr/ndr_winreg_c.h" +#include "../librpc/gen_ndr/ndr_misc.h" + +static WERROR cmd_winreg_enumkeys(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status; + WERROR werr; + struct policy_handle handle; + uint32_t enum_index = 0; + struct winreg_StringBuf name; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc < 2) { + printf("usage: %s [name]\n", argv[0]); + return WERR_OK; + } + + status = dcerpc_winreg_OpenHKLM(b, mem_ctx, + NULL, + SEC_FLAG_MAXIMUM_ALLOWED, + &handle, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + ZERO_STRUCT(name); + + name.name = argv[1]; + name.length = strlen_m_term_null(name.name)*2; + name.size = name.length; + + status = dcerpc_winreg_EnumKey(b, mem_ctx, + &handle, + enum_index, + &name, + NULL, + NULL, + &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 pull_winreg_Data(TALLOC_CTX *mem_ctx, + const DATA_BLOB *blob, + union winreg_Data *data, + enum winreg_Type type) +{ + enum ndr_err_code ndr_err; + ndr_err = ndr_pull_union_blob(blob, mem_ctx, data, type, + (ndr_pull_flags_fn_t)ndr_pull_winreg_Data); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return WERR_GEN_FAILURE; + } + return WERR_OK; +} + +/**************************************************************************** +****************************************************************************/ + +static void display_winreg_data(const char *v, + enum winreg_Type type, + uint8_t *data, + uint32_t length) +{ + size_t i; + union winreg_Data r; + DATA_BLOB blob = data_blob_const(data, length); + WERROR result; + + result = pull_winreg_Data(talloc_tos(), &blob, &r, type); + if (!W_ERROR_IS_OK(result)) { + return; + } + + switch (type) { + case REG_DWORD: + printf("%-20s: REG_DWORD: 0x%08x\n", v, r.value); + break; + case REG_SZ: + printf("%-20s: REG_SZ: %s\n", v, r.string); + break; + case REG_BINARY: { + char *hex = hex_encode_talloc(NULL, + r.binary.data, r.binary.length); + size_t len; + printf("%-20s: REG_BINARY:", v); + 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: + printf("%-20s: REG_MULTI_SZ: ", v); + for (i=0; r.string_array[i] != NULL; i++) { + printf("%s ", r.string_array[i]); + } + printf("\n"); + break; + default: + printf("%-20ss: unknown type 0x%02x:\n", v, type); + break; + } +} + + +static WERROR cmd_winreg_querymultiplevalues_ex(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv, bool multiplevalues2) +{ + NTSTATUS status; + WERROR werr; + struct policy_handle handle, key_handle; + struct winreg_String key_name = { 0, }; + struct dcerpc_binding_handle *b = cli->binding_handle; + + struct QueryMultipleValue *values_in, *values_out; + uint32_t num_values; + uint8_t *buffer = NULL; + uint32_t i; + + + if (argc < 2) { + printf("usage: %s [key] [value1] [value2] ...\n", argv[0]); + return WERR_OK; + } + + status = dcerpc_winreg_OpenHKLM(b, mem_ctx, + NULL, + SEC_FLAG_MAXIMUM_ALLOWED, + &handle, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + key_name.name = argv[1]; + + status = dcerpc_winreg_OpenKey(b, mem_ctx, + &handle, + key_name, + 0, /* options */ + SEC_FLAG_MAXIMUM_ALLOWED, + &key_handle, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + num_values = argc-2; + + values_in = talloc_zero_array(mem_ctx, struct QueryMultipleValue, num_values); + if (values_in == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + values_out = talloc_zero_array(mem_ctx, struct QueryMultipleValue, num_values); + if (values_out == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + for (i=0; i < num_values; i++) { + + values_in[i].ve_valuename = talloc_zero(values_in, struct winreg_ValNameBuf); + if (values_in[i].ve_valuename == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + values_in[i].ve_valuename->name = talloc_strdup(values_in[i].ve_valuename, argv[i+2]); + values_in[i].ve_valuename->length = strlen_m_term_null(values_in[i].ve_valuename->name)*2; + values_in[i].ve_valuename->size = values_in[i].ve_valuename->length; + } + + if (multiplevalues2) { + + uint32_t offered = 0, needed = 0; + + status = dcerpc_winreg_QueryMultipleValues2(b, mem_ctx, + &key_handle, + values_in, + values_out, + num_values, + buffer, + &offered, + &needed, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + if (W_ERROR_EQUAL(werr, WERR_MORE_DATA)) { + offered = needed; + + buffer = talloc_zero_array(mem_ctx, uint8_t, needed); + if (buffer == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + status = dcerpc_winreg_QueryMultipleValues2(b, mem_ctx, + &key_handle, + values_in, + values_out, + num_values, + buffer, + &offered, + &needed, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + } + + } else { + + uint32_t buffer_size = 0xff; + + buffer = talloc_zero_array(mem_ctx, uint8_t, buffer_size); + if (buffer == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + + status = dcerpc_winreg_QueryMultipleValues(b, mem_ctx, + &key_handle, + values_in, + values_out, + num_values, + buffer, + &buffer_size, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + } + + for (i=0; i < num_values; i++) { + if (buffer) { + display_winreg_data(values_in[i].ve_valuename->name, + values_out[i].ve_type, + buffer + values_out[i].ve_valueptr, + values_out[i].ve_valuelen); + } + } + + return WERR_OK; +} + +static WERROR cmd_winreg_querymultiplevalues(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + return cmd_winreg_querymultiplevalues_ex(cli, mem_ctx, argc, argv, false); +} + +static WERROR cmd_winreg_querymultiplevalues2(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + return cmd_winreg_querymultiplevalues_ex(cli, mem_ctx, argc, argv, true); +} + +static WERROR cmd_winreg_enumval(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status; + WERROR werr, ignore; + struct dcerpc_binding_handle *b = cli->binding_handle; + struct policy_handle parent_handle, handle; + uint32_t enum_index = 0; + + if (argc < 1 || argc > 3) { + printf("usage: %s [name]\n", argv[0]); + return WERR_OK; + } + + status = dcerpc_winreg_OpenHKLM(b, mem_ctx, + NULL, + SEC_FLAG_MAXIMUM_ALLOWED, + &parent_handle, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + if (argc >= 2) { + + struct winreg_String keyname; + + ZERO_STRUCT(keyname); + + keyname.name = argv[1]; + + status = dcerpc_winreg_OpenKey(b, mem_ctx, + &parent_handle, + keyname, + 0, + SEC_FLAG_MAXIMUM_ALLOWED, + &handle, + &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + } else { + handle = parent_handle; + } + + do { + struct winreg_ValNameBuf name; + enum winreg_Type type = REG_NONE; + uint32_t size = 0, length = 0; + struct winreg_EnumValue r; + + name.name = ""; + name.size = 1024; + + r.in.handle = &handle; + r.in.enum_index = enum_index; + r.in.name = &name; + r.in.type = &type; + r.in.size = &size; + r.in.length = &length; + r.in.value = talloc_array(mem_ctx, uint8_t, size); + if (r.in.value == NULL) { + werr = WERR_NOT_ENOUGH_MEMORY; + goto done; + } + r.out.name = &name; + r.out.type = &type; + r.out.size = &size; + r.out.length = &length; + r.out.value = r.in.value; + + status = dcerpc_winreg_EnumValue_r(b, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + werr = ntstatus_to_werror(status); + goto done; + } + + werr = r.out.result; + + if (W_ERROR_EQUAL(werr, WERR_MORE_DATA)) { + *r.in.size = *r.out.size; + r.in.value = talloc_zero_array(mem_ctx, uint8_t, *r.in.size); + if (r.in.value == NULL) { + werr = WERR_NOT_ENOUGH_MEMORY; + goto done; + } + + status = dcerpc_winreg_EnumValue_r(b, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + werr = ntstatus_to_werror(status); + goto done; + } + + werr = r.out.result; + } + if (!W_ERROR_IS_OK(r.out.result)) { + goto done; + } + + printf("%02d: ", enum_index++); + + display_winreg_data(r.out.name->name, + *r.out.type, + r.out.value, + *r.out.size); + + } while (W_ERROR_IS_OK(werr)); + + done: + if (argc >= 2) { + dcerpc_winreg_CloseKey(b, mem_ctx, &handle, &ignore); + } + dcerpc_winreg_CloseKey(b, mem_ctx, &parent_handle, &ignore); + + return werr; +} + +/* List of commands exported by this module */ + +struct cmd_set winreg_commands[] = { + + { + .name = "WINREG", + }, + { + .name = "winreg_enumkey", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_winreg_enumkeys, + .table = &ndr_table_winreg, + .rpc_pipe = NULL, + .description = "Enumerate Keys", + .usage = "", + }, + { + .name = "querymultiplevalues", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_winreg_querymultiplevalues, + .table = &ndr_table_winreg, + .rpc_pipe = NULL, + .description = "Query multiple values", + .usage = "", + }, + { + .name = "querymultiplevalues2", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_winreg_querymultiplevalues2, + .table = &ndr_table_winreg, + .rpc_pipe = NULL, + .description = "Query multiple values", + .usage = "", + }, + { + .name = "winreg_enumval", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_winreg_enumval, + .table = &ndr_table_winreg, + .rpc_pipe = NULL, + .description = "Enumerate Values", + .usage = "", + }, + { + .name = NULL, + }, +}; diff --git a/source3/rpcclient/cmd_witness.c b/source3/rpcclient/cmd_witness.c new file mode 100644 index 0000000..987c797 --- /dev/null +++ b/source3/rpcclient/cmd_witness.c @@ -0,0 +1,623 @@ +/* + Unix SMB/CIFS implementation. + RPC pipe client + + Copyright (C) Gregor Beck 2013-2014 + + 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" +#include "librpc/gen_ndr/ndr_witness_c.h" +#include <popt.h> + +/* + * We have to use the same connection for each subcommand + * for the context handles to be meaningful. + */ +static void use_only_one_rpc_pipe_hack(struct rpc_pipe_client *cli); + +static WERROR cmd_witness_GetInterfaceList(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status; + WERROR result; + TALLOC_CTX *frame = talloc_stackframe(); + struct witness_interfaceList *interface_list = NULL; + uint32_t num_interfaces, n; + struct witness_interfaceInfo *interfaces; + + use_only_one_rpc_pipe_hack(cli); + + status = dcerpc_witness_GetInterfaceList(cli->binding_handle, frame, + &interface_list, &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("dcerpc_witness_GetInterfaceList failed, status: %s\n", nt_errstr(status))); + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("dcerpc_witness_GetInterfaceList failed, error: %s\n", win_errstr(result))); + goto done; + } + + SMB_ASSERT(interface_list); + interfaces = interface_list->interfaces; + num_interfaces = interface_list->num_interfaces; + + for (n=0; n < num_interfaces; n++) { + char wif = (interfaces[n].flags & WITNESS_INFO_WITNESS_IF) ? '*' : ' '; + char state = 'X'; + + if (interfaces[n].state == WITNESS_STATE_AVAILABLE) { + state = '+'; + } else if (interfaces[n].state == WITNESS_STATE_UNAVAILABLE) { + state = '-'; + } else if (interfaces[n].state == WITNESS_STATE_UNKNOWN) { + state = '?'; + } + + d_printf("%c%c %s", wif, state, interfaces[n].group_name); + + if (interfaces[n].flags & WITNESS_INFO_IPv4_VALID) { + d_printf(" %s", interfaces[n].ipv4); + } + + if (interfaces[n].flags & WITNESS_INFO_IPv6_VALID) { + d_printf(" %s", interfaces[n].ipv6); + } + + switch (interfaces[n].version) { + case WITNESS_V1: + d_printf(" V1"); + break; + case WITNESS_V2: + d_printf(" V2"); + break; + default: + d_printf(" Unsupported Version (0x%08x)", interfaces[n].version); + } + + d_printf("\n"); + } + +done: + talloc_free(frame); + return result; +} + +static WERROR cmd_witness_Register(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + static char hostname[MAXHOSTNAMELEN] = {'\0'}; + NTSTATUS status; + WERROR result = WERR_OK; + TALLOC_CTX *frame = talloc_stackframe(); + struct policy_handle hnd; + const char *net_name = NULL; + const char *ip_addr = NULL; + const char *client_name = hostname; + long version = WITNESS_V1; + int c; + poptContext optCon; + struct poptOption optionsTable[] = { + { + .longName = "version", + .shortName = 'v', + .argInfo = POPT_ARG_LONG|POPT_ARGFLAG_SHOW_DEFAULT, + .arg = &version, + .val = WITNESS_V2, + .descrip = "witness version", + .argDescrip = "version" + }, + { + .longName = "V1", + .shortName = '1', + .argInfo = POPT_ARG_LONG|POPT_ARG_VAL, + .arg = &version, + .val = WITNESS_V1, + .descrip = "witness version 1", + .argDescrip = NULL + }, + { + .longName = "V2", + .shortName = '2', + .argInfo = POPT_ARG_LONG|POPT_ARG_VAL, + .arg = &version, + .val = WITNESS_V2, + .descrip = "witness version 2", + .argDescrip = NULL + }, + { + .longName = "net", + .shortName = 'n', + .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT, + .arg = &net_name, + .val = 0, + .descrip = "net name", + .argDescrip = NULL + }, + { + .longName = "ip", + .shortName = 'i', + .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT, + .arg = &ip_addr, + .val = 0, + .descrip = "ip address", + .argDescrip = NULL + }, + { + .longName = "client", + .shortName = 'c', + .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT|POPT_ARGFLAG_OPTIONAL, + .arg = &client_name, + .val = 0, + .descrip = "client name", + .argDescrip = NULL + }, + POPT_TABLEEND + }; + + use_only_one_rpc_pipe_hack(cli); + + if (hostname[0] == '\0') { + gethostname (hostname, sizeof(hostname)); + } + + optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); + + while ((c = poptGetNextOpt(optCon)) >= 0) { } + + if (c < -1) { + /* an error occurred during option processing */ + d_fprintf(stderr, "%s: %s\n", + poptBadOption(optCon, POPT_BADOPTION_NOALIAS), + poptStrerror(c)); + goto done; + } + + if (argc < 2 || poptPeekArg(optCon) != NULL) { + poptPrintHelp(optCon, stderr, 0); + goto done; + } + + status = dcerpc_witness_Register(cli->binding_handle, frame, + &hnd, + version, + net_name, ip_addr, client_name, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("dcerpc_witness_Register failed, status: %s\n", nt_errstr(status))); + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("dcerpc_witness_Register failed, error: %s\n", win_errstr(result))); + goto done; + } + + d_printf("%x:%s\n", hnd.handle_type, GUID_string(frame, &hnd.uuid)); + +done: + poptFreeContext(optCon); + talloc_free(frame); + return result; +} + +static WERROR cmd_witness_RegisterEx(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + static char hostname[MAXHOSTNAMELEN] = {'\0'}; + NTSTATUS status; + WERROR result = WERR_OK; + TALLOC_CTX *frame = talloc_stackframe(); + struct policy_handle hnd; + const char *net_name = NULL; + const char *ip_addr = NULL; + const char *share_name = NULL; + const char *client_name = hostname; + long version = WITNESS_V2; + long flags = 0; + long timeout = 0; + int c; + poptContext optCon; + struct poptOption optionsTable[] = { + { + .longName = "version", + .shortName = 'v', + .argInfo = POPT_ARG_LONG|POPT_ARGFLAG_SHOW_DEFAULT, + .arg = &version, + .val = WITNESS_V2, + .descrip = "witness version", + .argDescrip = "version" + }, + { + .longName = "V1", + .shortName = '1', + .argInfo = POPT_ARG_LONG|POPT_ARG_VAL, + .arg = &version, + .val = WITNESS_V1, + .descrip = "witness version 1", + }, + { + .longName = "V2", + .shortName = '2', + .argInfo = POPT_ARG_LONG|POPT_ARG_VAL, + .arg = &version, + .val = WITNESS_V2, + .descrip = "witness version 2", + }, + { + .longName = "net", + .shortName = 'n', + .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT, + .arg = &net_name, + .val = 0, + .descrip = "net name", + }, + { + .longName = "ip", + .shortName = 'i', + .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT, + .arg = &ip_addr, + .val = 0, + .descrip = "ip address", + }, + { + .longName = "share", + .shortName = 's', + .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT, + .arg = &share_name, + .val = 0, + .descrip = "share name", + }, + { + .longName = "client", + .shortName = 'c', + .argInfo = POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT|POPT_ARGFLAG_OPTIONAL, + .arg = &client_name, + .val = 0, + .descrip = "client name", + }, + { + .longName = "flags", + .shortName = 'f', + .argInfo = POPT_ARG_LONG|POPT_ARGFLAG_OR|POPT_ARGFLAG_SHOW_DEFAULT, + .arg = &flags, + .val = 0, + .descrip = "flags", + }, + { + .longName = "timeout", + .shortName = 't', + .argInfo = POPT_ARG_LONG|POPT_ARGFLAG_SHOW_DEFAULT, + .arg = &timeout, + .val = 0, + .descrip = "timeout", + }, + POPT_TABLEEND + }; + + use_only_one_rpc_pipe_hack(cli); + + if (hostname[0] == '\0') { + gethostname (hostname, sizeof(hostname)); + } + + optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); + + while ((c = poptGetNextOpt(optCon)) >= 0) { } + + if (c < -1) { + /* an error occurred during option processing */ + d_fprintf(stderr, "%s: %s\n", + poptBadOption(optCon, POPT_BADOPTION_NOALIAS), + poptStrerror(c)); + goto done; + } + + if (argc < 2 || poptPeekArg(optCon) != NULL) { + poptPrintHelp(optCon, stderr, 0); + goto done; + } + + status = dcerpc_witness_RegisterEx(cli->binding_handle, frame, + &hnd, + version, + net_name, share_name, ip_addr, client_name, + flags, timeout, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("dcerpc_witness_RegisterEx failed, status: %s\n", nt_errstr(status))); + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("dcerpc_witness_RegisterEx failed, error: %s\n", win_errstr(result))); + goto done; + } + + d_printf("%x:%s\n", hnd.handle_type, GUID_string(frame, &hnd.uuid)); + +done: + poptFreeContext(optCon); + talloc_free(frame); + return result; +} + +static bool +read_context_handle(const char *str, struct policy_handle *hnd) +{ + NTSTATUS status; + long type; + char *pos; + struct GUID guid; + + type = strtol(str, &pos, 16); + if (*pos != ':') { + DEBUG(0, ("read_context_handle: failed to parse type\n")); + return false; + } + status = GUID_from_string(pos+1, &guid); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("read_context_handle: failed to parse guid %s\n", nt_errstr(status))); + return false; + } + + hnd->handle_type = type; + hnd->uuid = guid; + return true; +} + +static WERROR cmd_witness_UnRegister(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status; + WERROR result = WERR_OK; + TALLOC_CTX *frame = talloc_stackframe(); + struct policy_handle hnd; + + use_only_one_rpc_pipe_hack(cli); + + if (argc != 2) { + d_printf("%s <context_handle>\n", argv[0]); + goto done; + } + + if (!read_context_handle(argv[1], &hnd)) { + result = WERR_INVALID_PARAMETER; + goto done; + } + + status = dcerpc_witness_UnRegister(cli->binding_handle, frame, + hnd, &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("dcerpc_witness_UnRegister failed, status: %s\n", nt_errstr(status))); + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("dcerpc_witness_UnRegister failed, error: %s\n", win_errstr(result))); + goto done; + } + +done: + talloc_free(frame); + return result; +} + +static void print_notify_response_resource_change(struct witness_ResourceChange *r) +{ + const char *type_str; + + if (r->type == WITNESS_RESOURCE_STATE_UNKNOWN) { + type_str = "Unknown"; + } else if (r->type == WITNESS_RESOURCE_STATE_AVAILABLE) { + type_str = "Available\n"; + } else if (r->type == WITNESS_RESOURCE_STATE_UNAVAILABLE) { + type_str = "Unavailable"; + } else { + type_str = talloc_asprintf(r, "Invalid (%u)", r->type); + } + d_printf("%s -> %s\n", r->name, type_str); +} + +static void print_notify_response_ip_addr_info_list(struct witness_IPaddrInfoList *r) +{ + int i; + + for (i=0; i < r->num; i++) { + uint32_t flags = r->addr[i].flags; + const char *str4 = r->addr[i].ipv4; + const char *str6 = r->addr[i].ipv6; + + d_printf("Flags 0x%08x", flags); + if (flags & WITNESS_IPADDR_V4) { + d_printf(" %s", str4); + } + if (flags & WITNESS_IPADDR_V6) { + d_printf(" %s", str6); + } + if (flags & WITNESS_IPADDR_ONLINE) { + d_printf(" Online"); + } + if (flags & WITNESS_IPADDR_ONLINE) { + d_printf(" Offline"); + } + d_printf("\n"); + } +} + +static void print_notify_response(union witness_notifyResponse_message *r, + uint32_t type) +{ + switch (type) { + case WITNESS_NOTIFY_RESOURCE_CHANGE: + print_notify_response_resource_change(&r->resource_change); + break; + case WITNESS_NOTIFY_CLIENT_MOVE: + case WITNESS_NOTIFY_SHARE_MOVE: + case WITNESS_NOTIFY_IP_CHANGE: + print_notify_response_ip_addr_info_list(&r->client_move); + break; + default: + break; + } +} + +static WERROR cmd_witness_AsyncNotify(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + NTSTATUS status; + WERROR result = WERR_OK; + TALLOC_CTX *frame = talloc_stackframe(); + struct policy_handle hnd; + struct witness_notifyResponse *response = NULL; + uint32_t timeout; + int i; + + use_only_one_rpc_pipe_hack(cli); + + if (argc != 2) { + d_printf("%s <context_handle>\n", argv[0]); + goto done; + } + + if (!read_context_handle(argv[1], &hnd)) { + result = WERR_INVALID_PARAMETER; + goto done; + } + + timeout = dcerpc_binding_handle_set_timeout(cli->binding_handle, UINT32_MAX); + status = dcerpc_witness_AsyncNotify(cli->binding_handle, frame, hnd, + &response, &result); + dcerpc_binding_handle_set_timeout(cli->binding_handle, timeout); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("dcerpc_witness_AsyncNotify failed, status: %s\n", nt_errstr(status))); + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("dcerpc_witness_AsyncNotify failed, error: %s\n", win_errstr(result))); + goto done; + } + + if (response == NULL) { + d_printf("Got an empty response\n"); + goto done; + } + + switch(response->type) { + case WITNESS_NOTIFY_RESOURCE_CHANGE: + d_printf("Resource change"); + break; + case WITNESS_NOTIFY_CLIENT_MOVE: + d_printf("Client move"); + break; + case WITNESS_NOTIFY_SHARE_MOVE: + d_printf("Share move"); + break; + case WITNESS_NOTIFY_IP_CHANGE: + d_printf("IP change"); + break; + default: + d_printf("Unknown (0x%x)", (int)response->type); + } + d_printf(" with %d messages\n", response->num); + + for (i=0; i < response->num; i++) { + print_notify_response(&response->messages[i], response->type); + } +done: + talloc_free(frame); + return result; +} + +struct cmd_set witness_commands[] = { + { + .name = "WITNESS", + }, + { + .name = "GetInterfaceList", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = &cmd_witness_GetInterfaceList, + .table = &ndr_table_witness, + .rpc_pipe = NULL, + .description = "List the interfaces to which witness client connections can be made", + .usage = "", + }, + { + .name = "Register", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = &cmd_witness_Register, + .table = &ndr_table_witness, + .rpc_pipe = NULL, + .description = "Register for resource state change notifications of a NetName and IPAddress", + .usage = "", + }, + { + .name = "UnRegister", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = &cmd_witness_UnRegister, + .table = &ndr_table_witness, + .rpc_pipe = NULL, + .description = "Unregister for notifications from the server</para></listitem></varlistentry>", + .usage = "", + }, + { + .name = "AsyncNotify", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = &cmd_witness_AsyncNotify, + .table = &ndr_table_witness, + .rpc_pipe = NULL, + .description = "Request notification of registered resource changes from the server", + .usage = "", + }, + { + .name = "RegisterEx", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = &cmd_witness_RegisterEx, + .table = &ndr_table_witness, + .rpc_pipe = NULL, + .description = "Register for resource state change notifications of a NetName, ShareName and multiple IPAddresses", + .usage = "", + }, + { + .name = NULL, + } +}; + +/* + * We have to use the same connection for each subcommand + * for the context handles to be meaningful. + */ +static void use_only_one_rpc_pipe_hack(struct rpc_pipe_client *cli) +{ + struct cmd_set *ptr; + + for (ptr = &witness_commands[0]; ptr->name; ptr++) { + ptr->rpc_pipe = cli; + } +} diff --git a/source3/rpcclient/cmd_wkssvc.c b/source3/rpcclient/cmd_wkssvc.c new file mode 100644 index 0000000..b1ffd5f --- /dev/null +++ b/source3/rpcclient/cmd_wkssvc.c @@ -0,0 +1,274 @@ +/* + 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" +#include "../librpc/gen_ndr/ndr_wkssvc_c.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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + 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 = dcerpc_wkssvc_NetWkstaGetInfo(b, 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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + server_name = cli->desthost; + name_buffer = ""; + + status = dcerpc_wkssvc_NetrGetJoinInformation(b, 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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc > 1) { + message = argv[1]; + } + + if (!push_ucs2_talloc(mem_ctx, &message_buffer, message, + &message_size)) + { + return WERR_NOT_ENOUGH_MEMORY; + } + + status = dcerpc_wkssvc_NetrMessageBufferSend(b, 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; + struct dcerpc_binding_handle *b = cli->binding_handle; + + server_name = cli->desthost; + + if (argc >= 2) { + name_type = atoi(argv[1]); + } + + status = dcerpc_wkssvc_NetrEnumerateComputerNames(b, 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; +} + +static WERROR cmd_wkssvc_enumerateusers(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + const char *server_name; + NTSTATUS status; + struct wkssvc_NetWkstaEnumUsersInfo info; + WERROR werr; + uint32_t i, num_entries, resume_handle; + struct dcerpc_binding_handle *b = cli->binding_handle; + + server_name = cli->desthost; + + ZERO_STRUCT(info); + + if (argc >= 2) { + info.level = atoi(argv[1]); + } + + status = dcerpc_wkssvc_NetWkstaEnumUsers(b, mem_ctx, server_name, + &info, 1000, &num_entries, + &resume_handle, &werr); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + for (i=0; i<num_entries; i++) { + const char *user = NULL; + switch (info.level) { + case 0: + user = info.ctr.user0->user0[i].user_name; + break; + case 1: + user = talloc_asprintf( + talloc_tos(), "%s\\%s", + info.ctr.user1->user1[i].logon_domain, + info.ctr.user1->user1[i].user_name); + break; + } + printf("%s\n", user ? user : "(null)"); + } + + return werr; +} + +struct cmd_set wkssvc_commands[] = { + + { + .name = "WKSSVC", + }, + { + .name = "wkssvc_wkstagetinfo", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_wkssvc_wkstagetinfo, + .table = &ndr_table_wkssvc, + .rpc_pipe = NULL, + .description = "Query WKSSVC Workstation Information", + .usage = "", + }, + { + .name = "wkssvc_getjoininformation", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_wkssvc_getjoininformation, + .table = &ndr_table_wkssvc, + .rpc_pipe = NULL, + .description = "Query WKSSVC Join Information", + .usage = "", + }, + { + .name = "wkssvc_messagebuffersend", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_wkssvc_messagebuffersend, + .table = &ndr_table_wkssvc, + .rpc_pipe = NULL, + .description = "Send WKSSVC message", + .usage = "", + }, + { + .name = "wkssvc_enumeratecomputernames", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_wkssvc_enumeratecomputernames, + .table = &ndr_table_wkssvc, + .rpc_pipe = NULL, + .description = "Enumerate WKSSVC computer names", + .usage = "", + }, + { + .name = "wkssvc_enumerateusers", + .returntype = RPC_RTYPE_WERROR, + .ntfn = NULL, + .wfn = cmd_wkssvc_enumerateusers, + .table = &ndr_table_wkssvc, + .rpc_pipe = NULL, + .description = "Enumerate WKSSVC users", + .usage = "", + }, + { + .name =NULL, + }, +}; diff --git a/source3/rpcclient/rpcclient.c b/source3/rpcclient/rpcclient.c new file mode 100644 index 0000000..f59bf6b --- /dev/null +++ b/source3/rpcclient/rpcclient.c @@ -0,0 +1,1389 @@ +/* + 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 "../libcli/auth/netlogon_creds_cli.h" +#include "rpcclient.h" +#include "../libcli/auth/libcli_auth.h" +#include "../librpc/gen_ndr/ndr_lsa_c.h" +#include "rpc_client/cli_lsarpc.h" +#include "../librpc/gen_ndr/ndr_netlogon.h" +#include "rpc_client/cli_netlogon.h" +#include "../libcli/smbreadline/smbreadline.h" +#include "../libcli/security/security.h" +#include "passdb.h" +#include "libsmb/libsmb.h" +#include "auth/gensec/gensec.h" +#include "../libcli/smb/smbXcli_base.h" +#include "messages.h" +#include "cmdline_contexts.h" +#include "../librpc/gen_ndr/ndr_samr.h" +#include "lib/cmdline/cmdline.h" +#include "lib/param/param.h" + +enum pipe_auth_type_spnego { + PIPE_AUTH_TYPE_SPNEGO_NONE = 0, + PIPE_AUTH_TYPE_SPNEGO_NTLMSSP, + PIPE_AUTH_TYPE_SPNEGO_KRB5 +}; + +static unsigned int timeout = 10000; + +struct messaging_context *rpcclient_msg_ctx; +struct netlogon_creds_cli_context *rpcclient_netlogon_creds; +static const char *rpcclient_netlogon_domain; + +/* 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 1000 + char **matches; + size_t 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; +} + +static void binding_get_auth_info( + const struct dcerpc_binding *b, + enum dcerpc_AuthType *_auth_type, + enum dcerpc_AuthLevel *_auth_level, + enum credentials_use_kerberos *_krb5_state) +{ + uint32_t bflags = dcerpc_binding_get_flags(b); + enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE; + enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; + enum credentials_use_kerberos krb5_state = CRED_USE_KERBEROS_DESIRED; + + if (_krb5_state != NULL) { + krb5_state = *_krb5_state; + } + + if (bflags & DCERPC_CONNECT) { + auth_level = DCERPC_AUTH_LEVEL_CONNECT; + } + if (bflags & DCERPC_PACKET) { + auth_level = DCERPC_AUTH_LEVEL_PACKET; + } + if (bflags & DCERPC_SIGN) { + auth_level = DCERPC_AUTH_LEVEL_INTEGRITY; + } + if (bflags & DCERPC_SEAL) { + auth_level = DCERPC_AUTH_LEVEL_PRIVACY; + } + + if (bflags & DCERPC_SCHANNEL) { + auth_type = DCERPC_AUTH_TYPE_SCHANNEL; + } + + if ((auth_level != DCERPC_AUTH_LEVEL_NONE) && + (auth_type == DCERPC_AUTH_TYPE_NONE)) { + auth_type = (krb5_state == CRED_USE_KERBEROS_REQUIRED) ? + DCERPC_AUTH_TYPE_KRB5 : DCERPC_AUTH_TYPE_NTLMSSP; + } + + if (bflags & DCERPC_AUTH_SPNEGO) { + auth_type = DCERPC_AUTH_TYPE_SPNEGO; + + if (bflags & DCERPC_AUTH_NTLM) { + krb5_state = CRED_USE_KERBEROS_DISABLED; + } + if (bflags & DCERPC_AUTH_KRB5) { + krb5_state = CRED_USE_KERBEROS_REQUIRED; + } + } + + if (auth_type != DCERPC_AUTH_TYPE_NONE) { + /* If nothing is requested then default to integrity */ + if (auth_level == DCERPC_AUTH_LEVEL_NONE) { + auth_level = DCERPC_AUTH_LEVEL_INTEGRITY; + } + } + + if (_auth_type != NULL) { + *_auth_type = auth_type; + } + if (_auth_level != NULL) { + *_auth_level = auth_level; + } + if (_krb5_state != NULL) { + *_krb5_state = krb5_state; + } +} + +/* 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_m(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) { + struct loadparm_context *lp_ctx = samba_cmdline_get_lp_ctx(); + lpcfg_set_cmdline(lp_ctx, "log level", 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(struct dcerpc_binding *binding) +{ + struct cmd_list *tmp; + enum dcerpc_AuthType auth_type; + enum dcerpc_AuthLevel auth_level; + + /* Close any existing connections not at this level. */ + + binding_get_auth_info(binding, &auth_type, &auth_level, NULL); + + 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 + != auth_type) + || (tmp_set->rpc_pipe->auth->auth_level + != auth_level)) { + TALLOC_FREE(tmp_set->rpc_pipe); + tmp_set->rpc_pipe = NULL; + } + } + } + return NT_STATUS_OK; +} + +static NTSTATUS cmd_set_transport(struct dcerpc_binding *b) +{ + enum dcerpc_transport_t t = dcerpc_binding_get_transport(b); + 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->transport->transport != t) { + TALLOC_FREE(tmp_set->rpc_pipe); + tmp_set->rpc_pipe = NULL; + } + } + } + return NT_STATUS_OK; +} + +static NTSTATUS binding_reset_auth(struct dcerpc_binding *b) +{ + NTSTATUS status = dcerpc_binding_set_flags( + b, + 0, + DCERPC_PACKET| + DCERPC_CONNECT| + DCERPC_SIGN| + DCERPC_SEAL| + DCERPC_SCHANNEL| + DCERPC_AUTH_SPNEGO| + DCERPC_AUTH_KRB5| + DCERPC_AUTH_NTLM); + return status; +} + +static NTSTATUS binding_set_auth( + struct dcerpc_binding *b, const char *level, const char *type) +{ + NTSTATUS status; + + status = binding_reset_auth(b); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (level != NULL) { + status = dcerpc_binding_set_string_option(b, level, level); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + + if (strequal(type, "SPNEGO")) { + status = dcerpc_binding_set_string_option( + b, "spnego", "spnego"); + return status; + } + if (strequal(type, "NTLMSSP")) { + status = dcerpc_binding_set_string_option(b, "ntlm", "ntlm"); + return status; + } + if (strequal(type, "NTLMSSP_SPNEGO")) { + status = dcerpc_binding_set_string_option( + b, "spnego", "spnego"); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + status = dcerpc_binding_set_string_option(b, "ntlm", "ntlm"); + return status; + } + if (strequal(type, "KRB5")) { + status = dcerpc_binding_set_string_option(b, "krb5", "krb5"); + return status; + } + if (strequal(type, "KRB5_SPNEGO")) { + status = dcerpc_binding_set_string_option( + b, "spnego", "spnego"); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + status = dcerpc_binding_set_string_option(b, "krb5", "krb5"); + return status; + } + if (strequal(type, "SCHANNEL")) { + status = dcerpc_binding_set_string_option( + b, "schannel", "schannel"); + return status; + } + + return NT_STATUS_INVALID_PARAMETER; +} + +static NTSTATUS cmd_set_auth( + struct dcerpc_binding *binding, + const char *level, + const char *display, + int argc, + const char **argv) +{ + const char *p = "[KRB5|KRB5_SPNEGO|NTLMSSP|NTLMSSP_SPNEGO|SCHANNEL]"; + const char *type = "NTLMSSP"; + NTSTATUS status; + + if (argc > 2) { + printf("Usage: %s %s\n", argv[0], p); + return NT_STATUS_OK; + } + + if (argc == 2) { + type = argv[1]; + } + + status = binding_set_auth(binding, level, type); + if (!NT_STATUS_IS_OK(status)) { + printf("Usage: %s %s\n", argv[0], p); + return status; + } + + d_printf("Setting %s - %s: %s\n", type, display, nt_errstr(status)); + + status = cmd_set_ss_level(binding); + return status; +} + +static NTSTATUS cmd_sign( + struct dcerpc_binding *binding, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status = cmd_set_auth(binding, "sign", "sign", argc, argv); + return status; +} + +static NTSTATUS cmd_seal( + struct dcerpc_binding *binding, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status = cmd_set_auth( + binding, "seal", "sign and seal", argc, argv); + return status; +} + +static NTSTATUS cmd_packet( + struct dcerpc_binding *binding, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status = cmd_set_auth( + binding, "packet", "packet", argc, argv); + return status; +} + +static NTSTATUS cmd_timeout(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv) +{ + if (argc > 2) { + printf("Usage: %s timeout\n", argv[0]); + return NT_STATUS_OK; + } + + if (argc == 2) { + timeout = atoi(argv[1]); + } + + printf("timeout is %d\n", timeout); + + return NT_STATUS_OK; +} + + +static NTSTATUS cmd_none( + struct dcerpc_binding *binding, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status = binding_reset_auth(binding); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + status = cmd_set_ss_level(binding); + return status; +} + +static NTSTATUS cmd_schannel( + struct dcerpc_binding *binding, + TALLOC_CTX *mem_ctx, + int argc, + const char **_argv) +{ + const char *argv[] = { "schannel", "SCHANNEL" }; + NTSTATUS status = cmd_set_auth( + binding, "seal", "sign and seal", 2, argv); + return status; +} + +static NTSTATUS cmd_schannel_sign( + struct dcerpc_binding *binding, + TALLOC_CTX *mem_ctx, + int argc, + const char **_argv) +{ + const char *argv[] = { "schannel_sign", "SCHANNEL" }; + NTSTATUS status = cmd_set_auth(binding, "sign", "sign only", 2, argv); + return status; +} + +static NTSTATUS cmd_choose_transport( + struct dcerpc_binding *binding, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + NTSTATUS status; + enum dcerpc_transport_t transport; + + if (argc != 2) { + printf("Usage: %s [NCACN_NP|NCACN_IP_TCP]\n", argv[0]); + return NT_STATUS_OK; + } + + transport = dcerpc_transport_by_name(argv[1]); + if (transport == NCA_UNKNOWN) { + printf("transport type %s unknown\n", argv[1]); + return NT_STATUS_NOT_SUPPORTED; + } + if (!((transport == NCACN_IP_TCP) || + (transport == NCACN_NP) || + (transport == NCALRPC))) { + printf("transport %s not supported\n", argv[1]); + return NT_STATUS_NOT_SUPPORTED; + } + + status = dcerpc_binding_set_transport(binding, transport); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = cmd_set_transport(binding); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + printf("default transport is now: %s\n", argv[1]); + + return NT_STATUS_OK; +} + +/* Built in rpcclient commands */ + +static struct cmd_set rpcclient_commands[] = { + + { + .name = "GENERAL OPTIONS", + }, + + { + .name = "help", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_help, + .description = "Get help on commands", + .usage = "[command]", + }, + { + .name = "?", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_help, + .description = "Get help on commands", + .usage = "[command]", + }, + { + .name = "debuglevel", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_debuglevel, + .description = "Set debug level", + .usage = "level", + }, + { + .name = "debug", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_debuglevel, + .description = "Set debug level", + .usage = "level", + }, + { + .name = "list", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_listcommands, + .description = "List available commands on <pipe>", + .usage = "pipe", + }, + { + .name = "exit", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_quit, + .description = "Exit program", + .usage = "", + }, + { + .name = "quit", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_quit, + .description = "Exit program", + .usage = "", + }, + { + .name = "sign", + .returntype = RPC_RTYPE_BINDING, + .bfn = cmd_sign, + .description = "Force RPC pipe connections to be signed", + .usage = "", + }, + { + .name = "seal", + .returntype = RPC_RTYPE_BINDING, + .bfn = cmd_seal, + .description = "Force RPC pipe connections to be sealed", + .usage = "", + }, + { + .name = "packet", + .returntype = RPC_RTYPE_BINDING, + .bfn = cmd_packet, + .description = "Force RPC pipe connections with packet authentication level", + .usage = "", + }, + { + .name = "schannel", + .returntype = RPC_RTYPE_BINDING, + .bfn = cmd_schannel, + .description = "Force RPC pipe connections to be sealed with 'schannel'. " + "Assumes valid machine account to this domain controller.", + .usage = "", + }, + { + .name = "schannelsign", + .returntype = RPC_RTYPE_BINDING, + .bfn = cmd_schannel_sign, + .description = "Force RPC pipe connections to be signed (not sealed) with " + "'schannel'. Assumes valid machine account to this domain " + "controller.", + .usage = "", + }, + { + .name = "timeout", + .returntype = RPC_RTYPE_NTSTATUS, + .ntfn = cmd_timeout, + .description = "Set timeout (in milliseconds) for RPC operations", + .usage = "", + }, + { + .name = "transport", + .returntype = RPC_RTYPE_BINDING, + .bfn = cmd_choose_transport, + .description = "Choose ncacn transport for RPC operations", + .usage = "", + }, + { + .name = "none", + .returntype = RPC_RTYPE_BINDING, + .bfn = cmd_none, + .description = "Force RPC pipe connections to have no special properties", + .usage = "", + }, + + { .name = NULL, }, +}; + +static struct cmd_set separator_command[] = { + { + .name = "---------------", + .returntype = MAX_RPC_RETURN_TYPE, + .description = "----------------------" + }, + { .name = 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 iremotewinspool_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 epmapper_commands[]; +extern struct cmd_set shutdown_commands[]; +extern struct cmd_set wkssvc_commands[]; +extern struct cmd_set ntsvcs_commands[]; +extern struct cmd_set drsuapi_commands[]; +extern struct cmd_set eventlog_commands[]; +extern struct cmd_set winreg_commands[]; +extern struct cmd_set fss_commands[]; +extern struct cmd_set witness_commands[]; +extern struct cmd_set clusapi_commands[]; +extern struct cmd_set spotlight_commands[]; +extern struct cmd_set unixinfo_commands[]; + +static struct cmd_set *rpcclient_command_list[] = { + rpcclient_commands, + lsarpc_commands, + ds_commands, + samr_commands, + spoolss_commands, + iremotewinspool_commands, + netlogon_commands, + srvsvc_commands, + dfs_commands, + echo_commands, + epmapper_commands, + shutdown_commands, + wkssvc_commands, + ntsvcs_commands, + drsuapi_commands, + eventlog_commands, + winreg_commands, + fss_commands, + witness_commands, + clusapi_commands, + spotlight_commands, + unixinfo_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); +} + +static NTSTATUS rpccli_ncalrpc_connect( + const struct ndr_interface_table *iface, + TALLOC_CTX *mem_ctx, + struct rpc_pipe_client **prpccli) +{ + struct rpc_pipe_client *rpccli = NULL; + struct pipe_auth_data *auth = NULL; + NTSTATUS status; + + status = rpc_pipe_open_ncalrpc(mem_ctx, iface, &rpccli); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("rpc_pipe_open_ncalrpc failed: %s\n", + nt_errstr(status)); + goto fail; + } + + status = rpccli_ncalrpc_bind_data(rpccli, &auth); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("rpccli_ncalrpc_bind_data failed: %s\n", + nt_errstr(status)); + goto fail; + } + + status = rpc_pipe_bind(rpccli, auth); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("rpc_pipe_bind failed: %s\n", nt_errstr(status)); + goto fail; + } + + *prpccli = rpccli; + return NT_STATUS_OK; +fail: + TALLOC_FREE(rpccli); + return status; +} +/** + * 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 cli_credentials *creds, + struct cmd_set *cmd_entry, + struct dcerpc_binding *binding, + int argc, const char **argv) +{ + NTSTATUS ntresult; + WERROR wresult; + enum dcerpc_transport_t transport; + + TALLOC_CTX *mem_ctx = talloc_stackframe(); + const char *remote_name = NULL; + const struct sockaddr_storage *remote_sockaddr = NULL; + struct sockaddr_storage remote_ss = { + .ss_family = AF_UNSPEC, + }; + + transport = dcerpc_binding_get_transport(binding); + + if (cli != NULL) { + remote_name = smbXcli_conn_remote_name(cli->conn); + remote_sockaddr = smbXcli_conn_remote_sockaddr(cli->conn); + } else { + const char *remote_host = + dcerpc_binding_get_string_option(binding, "host"); + remote_name = dcerpc_binding_get_string_option( + binding, "target_hostname"); + + if (remote_host != NULL) { + bool ok = interpret_string_addr( + &remote_ss, remote_host, 0); + if (ok) { + remote_sockaddr = &remote_ss; + } + } + } + + /* Open pipe */ + + if ((cmd_entry->table != NULL) && (cmd_entry->rpc_pipe == NULL)) { + if (transport == NCALRPC) { + ntresult = rpccli_ncalrpc_connect( + cmd_entry->table, cli, &cmd_entry->rpc_pipe); + if (!NT_STATUS_IS_OK(ntresult)) { + TALLOC_FREE(mem_ctx); + return ntresult; + } + } else { + enum dcerpc_AuthType auth_type; + enum dcerpc_AuthLevel auth_level; + enum credentials_use_kerberos krb5_state = + cli_credentials_get_kerberos_state(creds); + + binding_get_auth_info( + binding, &auth_type, &auth_level, &krb5_state); + + switch (auth_type) { + case DCERPC_AUTH_TYPE_NONE: + ntresult = cli_rpc_pipe_open_noauth_transport( + cli, transport, + cmd_entry->table, + remote_name, + remote_sockaddr, + &cmd_entry->rpc_pipe); + break; + case DCERPC_AUTH_TYPE_SPNEGO: + case DCERPC_AUTH_TYPE_NTLMSSP: + case DCERPC_AUTH_TYPE_KRB5: + cli_credentials_set_kerberos_state(creds, + krb5_state, + CRED_SPECIFIED); + + ntresult = cli_rpc_pipe_open_with_creds( + cli, cmd_entry->table, + transport, + auth_type, + auth_level, + remote_name, + remote_sockaddr, + creds, + &cmd_entry->rpc_pipe); + break; + case DCERPC_AUTH_TYPE_SCHANNEL: + TALLOC_FREE(rpcclient_netlogon_creds); + ntresult = cli_rpc_pipe_open_schannel( + cli, rpcclient_msg_ctx, + cmd_entry->table, + transport, + rpcclient_netlogon_domain, + remote_name, + remote_sockaddr, + &cmd_entry->rpc_pipe, + rpcclient_msg_ctx, + &rpcclient_netlogon_creds); + break; + default: + DEBUG(0, ("Could not initialise %s. Invalid " + "auth type %u\n", + cmd_entry->table->name, + auth_type )); + talloc_free(mem_ctx); + return NT_STATUS_UNSUCCESSFUL; + } + if (!NT_STATUS_IS_OK(ntresult)) { + DBG_ERR("Could not initialise %s. " + "Error was %s\n", + cmd_entry->table->name, + nt_errstr(ntresult)); + talloc_free(mem_ctx); + return ntresult; + } + + if (rpcclient_netlogon_creds == NULL && + cmd_entry->use_netlogon_creds) { + const char *dc_name = + cmd_entry->rpc_pipe->desthost; + const char *domain = rpcclient_netlogon_domain; + struct cli_credentials *trust_creds = NULL; + + ntresult = pdb_get_trust_credentials( + domain, + NULL, + mem_ctx, + &trust_creds); + if (!NT_STATUS_IS_OK(ntresult)) { + DBG_ERR("Failed to fetch trust " + "credentials for " + "%s to connect to %s: %s\n", + domain, + cmd_entry->table->name, + nt_errstr(ntresult)); + TALLOC_FREE(cmd_entry->rpc_pipe); + talloc_free(mem_ctx); + return ntresult; + } + + ntresult = rpccli_create_netlogon_creds_ctx( + trust_creds, + dc_name, + rpcclient_msg_ctx, + rpcclient_msg_ctx, + &rpcclient_netlogon_creds); + if (!NT_STATUS_IS_OK(ntresult)) { + DBG_ERR("Could not initialise " + "credentials for %s.\n", + cmd_entry->table->name); + TALLOC_FREE(cmd_entry->rpc_pipe); + TALLOC_FREE(mem_ctx); + return ntresult; + } + + ntresult = rpccli_setup_netlogon_creds( + cli, + NCACN_NP, + rpcclient_netlogon_creds, + false, /* force_reauth */ + trust_creds); + TALLOC_FREE(trust_creds); + if (!NT_STATUS_IS_OK(ntresult)) { + DBG_ERR("Could not initialise " + "credentials for %s.\n", + cmd_entry->table->name); + TALLOC_FREE(cmd_entry->rpc_pipe); + TALLOC_FREE(rpcclient_netlogon_creds); + TALLOC_FREE(mem_ctx); + return ntresult; + } + } + } + } + + /* Set timeout for new connections */ + if (cmd_entry->rpc_pipe) { + rpccli_set_timeout(cmd_entry->rpc_pipe, timeout); + } + + /* Run command */ + + if ( cmd_entry->returntype == RPC_RTYPE_NTSTATUS ) { + ntresult = cmd_entry->ntfn(cmd_entry->rpc_pipe, mem_ctx, argc, argv); + if (!NT_STATUS_IS_OK(ntresult)) { + printf("result was %s\n", nt_errstr(ntresult)); + } + } else if (cmd_entry->returntype == RPC_RTYPE_BINDING) { + ntresult = cmd_entry->bfn(binding, mem_ctx, argc, 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, argv); + /* print out the DOS error */ + if (!W_ERROR_IS_OK(wresult)) { + printf( "result was %s\n", win_errstr(wresult)); + } + ntresult = W_ERROR_IS_OK(wresult)?NT_STATUS_OK:NT_STATUS_UNSUCCESSFUL; + } + + /* Cleanup */ + + talloc_free(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_credentials *creds, + struct cli_state *cli, + struct dcerpc_binding *binding, + char *cmd) +{ + struct cmd_list *temp_list; + NTSTATUS result = NT_STATUS_OK; + int ret; + int argc; + const char **argv = NULL; + + if ((ret = poptParseArgvString(cmd, &argc, &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 *set = temp_list->cmd_set; + + while (set->name != NULL) { + if (!strequal(argv[0], set->name)) { + set += 1; + continue; + } + + if (((set->returntype == RPC_RTYPE_NTSTATUS) && + (set->ntfn == NULL)) || + ((set->returntype == RPC_RTYPE_WERROR) && + (set->wfn == NULL)) || + ((set->returntype == RPC_RTYPE_BINDING) && + (set->bfn == NULL))) { + fprintf (stderr, "Invalid command\n"); + goto out_free; + } + + result = do_cmd( + cli, creds, set, binding, argc, argv); + goto out_free; + } + } + + 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[]) +{ + const char **const_argv = discard_const_p(const 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; + int result = 0; + TALLOC_CTX *frame = talloc_stackframe(); + uint32_t flags = CLI_FULL_CONNECTION_IPC; + struct dcerpc_binding *binding = NULL; + enum dcerpc_transport_t transport; + const char *binding_string = NULL; + const char *host; + struct cli_credentials *creds = NULL; + struct loadparm_context *lp_ctx = NULL; + bool ok; + + /* 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_LEGACY_S3 + POPT_COMMON_VERSION + POPT_TABLEEND + }; + + smb_init_locale(); + + zero_sockaddr(&server_ss); + + setlinebuf(stdout); + + ok = samba_cmdline_init(frame, + SAMBA_CMDLINE_CONFIG_CLIENT, + false /* require_smbconf */); + if (!ok) { + DBG_ERR("Failed to init cmdline parser!\n"); + } + lp_ctx = samba_cmdline_get_lp_ctx(); + lpcfg_set_cmdline(lp_ctx, "log level", "0"); + + /* Parse options */ + pc = samba_popt_get_context(getprogname(), + argc, + const_argv, + long_options, + 0); + if (pc == NULL) { + DBG_ERR("Failed to setup popt context!\n"); + exit(1); + } + + poptSetOtherOptionHelp(pc, "[OPTION...] BINDING-STRING|HOST\nOptions:"); + + 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; + } + break; + case POPT_ERROR_BADOPT: + fprintf(stderr, "\nInvalid option %s: %s\n\n", + poptBadOption(pc, 0), poptStrerror(opt)); + poptPrintUsage(pc, stderr, 0); + exit(1); + } + } + + /* Get server as remaining unparsed argument. Print usage if more + than one unparsed argument is present. */ + + server = talloc_strdup(frame, poptGetArg(pc)); + + if (!server || poptGetArg(pc)) { + poptPrintHelp(pc, stderr, 0); + result = 1; + goto done; + } + + poptFreeContext(pc); + samba_cmdline_burn(argc, argv); + + rpcclient_msg_ctx = cmdline_messaging_context(get_dyn_CONFIGFILE()); + creds = samba_cmdline_get_creds(); + + /* + * Get password + * from stdin if necessary + */ + + if ((server[0] == '/' && server[1] == '/') || + (server[0] == '\\' && server[1] == '\\')) { + server += 2; + } + + nt_status = dcerpc_parse_binding(frame, server, &binding); + + if (!NT_STATUS_IS_OK(nt_status)) { + + binding_string = talloc_asprintf(frame, "ncacn_np:%s", + strip_hostname(server)); + if (!binding_string) { + result = 1; + goto done; + } + + nt_status = dcerpc_parse_binding(frame, binding_string, &binding); + if (!NT_STATUS_IS_OK(nt_status)) { + result = -1; + goto done; + } + } + + transport = dcerpc_binding_get_transport(binding); + + if (transport == NCA_UNKNOWN) { + transport = NCACN_NP; + nt_status = dcerpc_binding_set_transport(binding, transport); + if (!NT_STATUS_IS_OK(nt_status)) { + result = -1; + goto done; + } + } + + host = dcerpc_binding_get_string_option(binding, "host"); + + rpcclient_netlogon_domain = cli_credentials_get_domain(creds); + if (rpcclient_netlogon_domain == NULL || + rpcclient_netlogon_domain[0] == '\0') + { + rpcclient_netlogon_domain = lp_workgroup(); + } + + if (transport == NCACN_NP) { + nt_status = cli_full_connection_creds( + &cli, + lp_netbios_name(), + host, + opt_ipaddr ? &server_ss : NULL, + opt_port, + "IPC$", + "IPC", + creds, + flags); + + 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; + } + + /* Load command lists */ + cli_set_timeout(cli, timeout); + } + +#if 0 /* COMMENT OUT FOR TESTING */ + memset(cmdline_auth_info.password,'X',sizeof(cmdline_auth_info.password)); +#endif + + cmd_set = rpcclient_command_list; + + while(*cmd_set) { + add_command_set(*cmd_set); + add_command_set(separator_command); + cmd_set++; + } + + /* 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(creds, + cli, + binding, + 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) { + printf("\n"); + break; + } + + if (line[0] != '\n') + process_cmd(creds, + cli, + binding, + line); + SAFE_FREE(line); + } + +done: + if (cli != NULL) { + cli_shutdown(cli); + } + netlogon_creds_cli_close_global_db(); + TALLOC_FREE(rpcclient_msg_ctx); + TALLOC_FREE(frame); + return result; +} diff --git a/source3/rpcclient/rpcclient.h b/source3/rpcclient/rpcclient.h new file mode 100644 index 0000000..75ac575 --- /dev/null +++ b/source3/rpcclient/rpcclient.h @@ -0,0 +1,53 @@ +/* + 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 + +#include "rpc_client/cli_pipe.h" + +typedef enum { + RPC_RTYPE_NTSTATUS = 0, + RPC_RTYPE_WERROR, + RPC_RTYPE_BINDING, + 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); + NTSTATUS (*bfn)(struct dcerpc_binding *binding, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv); + const struct ndr_interface_table *table; + struct rpc_pipe_client *rpc_pipe; + const char *description; + const char *usage; + bool use_netlogon_creds; +}; + +extern struct messaging_context *rpcclient_msg_ctx; +extern struct netlogon_creds_cli_context *rpcclient_netlogon_creds; + +#endif /* RPCCLIENT_H */ diff --git a/source3/rpcclient/wscript_build b/source3/rpcclient/wscript_build new file mode 100644 index 0000000..bb3a88c --- /dev/null +++ b/source3/rpcclient/wscript_build @@ -0,0 +1,61 @@ +#!/usr/bin/env python + +bld.SAMBA3_BINARY('rpcclient', + source='''rpcclient.c + cmd_lsarpc.c + cmd_samr.c + cmd_spoolss.c + cmd_netlogon.c + cmd_srvsvc.c + cmd_dfs.c + cmd_epmapper.c + cmd_dssetup.c + cmd_echo.c + cmd_shutdown.c + cmd_wkssvc.c + cmd_ntsvcs.c + cmd_drsuapi.c + cmd_eventlog.c + cmd_winreg.c + cmd_fss.c + cmd_clusapi.c + cmd_witness.c + cmd_iremotewinspool.c + cmd_spotlight.c + cmd_unixinfo.c + ''', + deps=''' + talloc + CMDLINE_S3 + cmdline_contexts + pdb + libsmb + smbconf + ndr-standard + msrpc3 + SMBREADLINE + trusts_util + RPC_NDR_WINREG + RPC_NDR_ECHO + RPC_CLIENT_SCHANNEL + DCUTIL + LIBCLI_SAMR + libcli_lsa3 + libcli_netlogon3 + cli_spoolss + RPC_NDR_SRVSVC + RPC_NDR_WKSSVC + RPC_NDR_DSSETUP + RPC_NDR_DFS + RPC_NDR_DRSUAPI + RPC_NDR_NTSVCS + RPC_NDR_EVENTLOG + INIT_SAMR + RPC_NDR_FSRVP + RPC_NDR_CLUSAPI + RPC_NDR_WITNESS + RPC_NDR_WINSPOOL + mdssvc + RPC_NDR_MDSSVC + RPC_NDR_UNIXINFO + ''') |