summaryrefslogtreecommitdiffstats
path: root/source3/rpcclient
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
commit8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch)
tree4099e8021376c7d8c05bdf8503093d80e9c7bad0 /source3/rpcclient
parentInitial commit. (diff)
downloadsamba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz
samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'source3/rpcclient')
-rw-r--r--source3/rpcclient/cmd_clusapi.c753
-rw-r--r--source3/rpcclient/cmd_dfs.c396
-rw-r--r--source3/rpcclient/cmd_drsuapi.c723
-rw-r--r--source3/rpcclient/cmd_dssetup.c84
-rw-r--r--source3/rpcclient/cmd_echo.c232
-rw-r--r--source3/rpcclient/cmd_epmapper.c270
-rw-r--r--source3/rpcclient/cmd_eventlog.c650
-rw-r--r--source3/rpcclient/cmd_fss.c759
-rw-r--r--source3/rpcclient/cmd_iremotewinspool.c195
-rw-r--r--source3/rpcclient/cmd_lsarpc.c3000
-rw-r--r--source3/rpcclient/cmd_netlogon.c1186
-rw-r--r--source3/rpcclient/cmd_ntsvcs.c361
-rw-r--r--source3/rpcclient/cmd_samr.c3941
-rw-r--r--source3/rpcclient/cmd_shutdown.c137
-rw-r--r--source3/rpcclient/cmd_spoolss.c4543
-rw-r--r--source3/rpcclient/cmd_spotlight.c420
-rw-r--r--source3/rpcclient/cmd_srvsvc.c1266
-rw-r--r--source3/rpcclient/cmd_unixinfo.c141
-rw-r--r--source3/rpcclient/cmd_winreg.c491
-rw-r--r--source3/rpcclient/cmd_witness.c623
-rw-r--r--source3/rpcclient/cmd_wkssvc.c274
-rw-r--r--source3/rpcclient/rpcclient.c1389
-rw-r--r--source3/rpcclient/rpcclient.h53
-rw-r--r--source3/rpcclient/wscript_build61
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(&reg_module_name, NULL);
+
+ status = dcerpc_eventlog_RegisterEventSourceW(b, mem_ctx,
+ &unknown0,
+ &module_name,
+ &reg_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,
+ &reg_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
+ ''')