1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-04 05:18:06 +03:00
samba-mirror/examples/winexe/winexe.c
Volker Lendecke ffa1c040c6 examples: Add winexe re-implemented on current Samba libs
winexe from https://sourceforge.net/projects/winexe/ is a project
based on Samba libraries from 2012. According to the winexe git
repository the last Samba commit winexe was updated to is 47bbf9886f
from November 6, 2012. As winexe uses unpublished Samba internal
libraries, it broke over time.

This is a port of the winexe functionality to more modern Samba
versions. It still uses internal APIs, but it being part of the tree
means that it is much easier to keep up to date.

The Windows service files were taken literally from the original
winexe from the sourceforge git. Andrzej Hajda chose GPLv3 only and
not GPLv3+. As GPL evolves very slowly, this should not be a practical
problem for quite some time.

To build it under Linux, you need mingw binaries on your build
system. Under Debian stretch, the package names are gcc-mingw-w64 and
friends.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>

Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Tue Aug 28 02:03:07 CEST 2018 on sn-devel-144
2018-08-28 02:03:07 +02:00

1868 lines
43 KiB
C

/*
* Samba Unix/Linux CIFS implementation
*
* winexe
*
* Copyright (C) 2018 Volker Lendecke <vl@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 <tevent.h>
#include <popt.h>
#include "version.h"
#include "lib/param/param.h"
#include "auth/credentials/credentials.h"
#include "lib/util/talloc_stack.h"
#include "lib/util/tevent_ntstatus.h"
#include "lib/util/sys_rw.h"
#include "libsmb/proto.h"
#include "librpc/gen_ndr/ndr_svcctl_c.h"
#include "rpc_client/cli_pipe.h"
#include "libcli/smb/smbXcli_base.h"
#include "libcli/util/werror.h"
#include "lib/async_req/async_sock.h"
#include "client.h"
#define SVC_INTERACTIVE 1
#define SVC_IGNORE_INTERACTIVE 2
#define SVC_INTERACTIVE_MASK 3
#define SVC_FORCE_UPLOAD 4
#define SVC_OS64BIT 8
#define SVC_OSCHOOSE 16
#define SVC_UNINSTALL 32
#define SVC_SYSTEM 64
#define SERVICE_NAME "winexesvc"
#define PIPE_NAME "ahexec"
#define PIPE_NAME_IN "ahexec_stdin%08X"
#define PIPE_NAME_OUT "ahexec_stdout%08X"
#define PIPE_NAME_ERR "ahexec_stderr%08X"
static const char version_message_fmt[] = "winexe version %d.%d\n"
"This program may be freely redistributed under the terms of the "
"GNU GPLv3\n";
struct program_options {
char *hostname;
char *cmd;
struct cli_credentials *credentials;
char *runas;
char *runas_file;
int flags;
};
static void parse_args(int argc, const char *argv[],
TALLOC_CTX *mem_ctx,
struct program_options *options,
struct loadparm_context *lp_ctx)
{
poptContext pc;
int opt, i;
struct cli_credentials *cred;
int argc_new;
char **argv_new;
int flag_interactive = SVC_IGNORE_INTERACTIVE;
int flag_ostype = 2;
int flag_reinstall = 0;
int flag_uninstall = 0;
int flag_help = 0;
int flag_version = 0;
int flag_nopass = 0;
char *opt_user = NULL;
char *opt_kerberos = NULL;
char *opt_auth_file = NULL;
char *opt_debuglevel = NULL;
struct poptOption long_options[] = {
{ "help", 'h', POPT_ARG_NONE, &flag_help, 0,
"Display help message" },
{ "version", 'V', POPT_ARG_NONE, &flag_version, 0,
"Display version number" },
{ "user", 'U', POPT_ARG_STRING, &opt_user, 0,
"Set the network username", "[DOMAIN/]USERNAME[%PASSWORD]" },
{ "authentication-file", 'A',
POPT_ARG_STRING, &opt_auth_file, 0,
"Get the credentials from a file", "FILE" },
{ "no-pass", 'N', POPT_ARG_NONE, &flag_nopass, 0,
"Do not ask for a password", NULL },
{ "kerberos", 'k', POPT_ARG_STRING, &opt_kerberos, 0,
"Use Kerberos, -k [yes|no]" },
{ "debuglevel", 'd', POPT_ARG_STRING, &opt_debuglevel, 0,
"Set debug level", "DEBUGLEVEL" },
{ "uninstall", 0, POPT_ARG_NONE, &flag_uninstall, 0,
"Uninstall winexe service after remote execution", NULL},
{ "reinstall", 0, POPT_ARG_NONE, &flag_reinstall, 0,
"Reinstall winexe service before remote execution", NULL},
{ "runas", 0, POPT_ARG_STRING, &options->runas, 0,
"Run as the given user (BEWARE: this password is sent "
"in cleartext over the network!)",
"[DOMAIN\\]USERNAME%PASSWORD"},
{ "runas-file", 0, POPT_ARG_STRING, &options->runas_file, 0,
"Run as user options defined in a file", "FILE"},
{ "interactive", 0, POPT_ARG_INT, &flag_interactive, 0,
"Desktop interaction: 0 - disallow, 1 - allow. If allow, "
"also use the --system switch (Windows requirement). Vista "
"does not support this option.", "0|1"},
{ "ostype", 0, POPT_ARG_INT, &flag_ostype, 0,
"OS type: 0 - 32-bit, 1 - 64-bit, 2 - winexe will decide. "
"Determines which version (32-bit or 64-bit) of service "
"will be installed.", "0|1|2"},
POPT_TABLEEND
};
ZERO_STRUCTP(options);
pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,
0);
poptSetOtherOptionHelp(pc, "[OPTION]... //HOST COMMAND\nOptions:");
if (((opt = poptGetNextOpt(pc)) != -1) || flag_help || flag_version) {
fprintf(stderr, version_message_fmt, SAMBA_VERSION_MAJOR,
SAMBA_VERSION_MINOR);
if (flag_version) {
exit(0);
}
poptPrintHelp(pc, stdout, 0);
if (flag_help) {
exit(0);
}
exit(1);
}
argv_new = discard_const_p(char *, poptGetArgs(pc));
argc_new = argc;
for (i = 0; i < argc; i++) {
if (!argv_new || argv_new[i] == NULL) {
argc_new = i;
break;
}
}
if (argc_new != 2 || argv_new[0][0] != '/' || argv_new[0][1] != '/') {
fprintf(stderr, version_message_fmt, SAMBA_VERSION_MAJOR,
SAMBA_VERSION_MINOR);
poptPrintHelp(pc, stdout, 0);
exit(1);
}
if (opt_debuglevel) {
lp_set_cmdline("log level", opt_debuglevel);
}
cred = cli_credentials_init(mem_ctx);
if (opt_user) {
cli_credentials_parse_string(cred, opt_user, CRED_SPECIFIED);
} else if (opt_auth_file) {
cli_credentials_parse_file(cred, opt_auth_file,
CRED_SPECIFIED);
}
cli_credentials_guess(cred, lp_ctx);
if (!cli_credentials_get_password(cred) && !flag_nopass) {
char *p = getpass("Enter password: ");
if (*p) {
cli_credentials_set_password(cred, p, CRED_SPECIFIED);
}
}
if (opt_kerberos) {
cli_credentials_set_kerberos_state(cred,
strcmp(opt_kerberos, "yes")
? CRED_MUST_USE_KERBEROS
: CRED_DONT_USE_KERBEROS);
}
if (options->runas == NULL && options->runas_file != NULL) {
struct cli_credentials *runas_cred;
const char *user;
const char *pass;
runas_cred = cli_credentials_init(mem_ctx);
cli_credentials_parse_file(runas_cred, options->runas_file,
CRED_SPECIFIED);
user = cli_credentials_get_username(runas_cred);
pass = cli_credentials_get_password(runas_cred);
if (user && pass) {
char buffer[1024];
const char *dom;
dom = cli_credentials_get_domain(runas_cred);
if (dom) {
snprintf(buffer, sizeof(buffer), "%s\\%s%%%s",
dom, user, pass);
} else {
snprintf(buffer, sizeof(buffer), "%s%%%s",
user, pass);
}
buffer[sizeof(buffer)-1] = '\0';
options->runas = talloc_strdup(mem_ctx, buffer);
}
}
options->credentials = cred;
options->hostname = argv_new[0] + 2;
options->cmd = argv_new[1];
options->flags = flag_interactive;
if (flag_reinstall) {
options->flags |= SVC_FORCE_UPLOAD;
}
if (flag_ostype == 1) {
options->flags |= SVC_OS64BIT;
}
if (flag_ostype == 2) {
options->flags |= SVC_OSCHOOSE;
}
if (flag_uninstall) {
options->flags |= SVC_UNINSTALL;
}
}
static NTSTATUS winexe_svc_upload(
const char *hostname,
const char *service_filename,
const DATA_BLOB *svc32_exe,
const DATA_BLOB *svc64_exe,
struct cli_credentials *credentials,
int flags)
{
struct cli_state *cli;
uint16_t fnum;
NTSTATUS status;
const DATA_BLOB *binary = NULL;
status = cli_full_connection_creds(
&cli,
NULL,
hostname,
NULL,
445,
"ADMIN$",
"?????",
credentials,
0,
0);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("cli_full_connection_creds failed: %s\n",
nt_errstr(status));
return status;
}
if (flags & SVC_FORCE_UPLOAD) {
status = cli_unlink(cli, service_filename, 0);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("cli_unlink failed: %s\n",
nt_errstr(status));
}
}
if (flags & SVC_OSCHOOSE) {
status = cli_chkpath(cli, "SysWoW64");
if (NT_STATUS_IS_OK(status)) {
flags |= SVC_OS64BIT;
}
}
if (flags & SVC_OS64BIT) {
binary = svc64_exe;
} else {
binary = svc32_exe;
}
if (binary == NULL) {
//TODO
}
status = cli_ntcreate(
cli,
service_filename,
0, /* CreatFlags */
SEC_FILE_WRITE_DATA, /* DesiredAccess */
FILE_ATTRIBUTE_NORMAL, /* FileAttributes */
FILE_SHARE_WRITE|FILE_SHARE_READ, /* ShareAccess */
FILE_OPEN_IF, /* CreateDisposition */
FILE_NON_DIRECTORY_FILE, /* CreateOptions */
0, /* SecurityFlags */
&fnum,
NULL); /* CreateReturns */
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("Could not create %s: %s\n", service_filename,
nt_errstr(status));
goto done;
}
status = cli_writeall(
cli,
fnum,
0,
binary->data,
0,
binary->length,
NULL);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("Could not write file: %s\n", nt_errstr(status));
goto close_done;
}
close_done:
status = cli_close(cli, fnum);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("Close(%"PRIu16") failed for %s: %s\n", fnum,
service_filename, nt_errstr(status));
}
done:
TALLOC_FREE(cli);
return status;
}
static NTSTATUS winexe_svc_install(
struct cli_state *cli,
const char *hostname,
const char *service_name,
const char *service_filename,
const DATA_BLOB *svc32_exe,
const DATA_BLOB *svc64_exe,
struct cli_credentials *credentials,
int flags)
{
TALLOC_CTX *frame = talloc_stackframe();
struct rpc_pipe_client *rpccli;
struct policy_handle scmanager_handle;
struct policy_handle service_handle;
struct SERVICE_STATUS service_status;
bool need_start = false;
bool need_conf = false;
NTSTATUS status;
WERROR werr;
status = cli_rpc_pipe_open_noauth_transport(
cli,
NCACN_NP,
&ndr_table_svcctl,
&rpccli);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
nt_errstr(status));
goto done;
}
status = dcerpc_svcctl_OpenSCManagerW(
rpccli->binding_handle,
frame,
smbXcli_conn_remote_name(cli->conn),
NULL,
SEC_FLAG_MAXIMUM_ALLOWED,
&scmanager_handle,
&werr);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
nt_errstr(status));
goto done;
}
if (!W_ERROR_IS_OK(werr)) {
DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
win_errstr(werr));
goto done;
}
status = dcerpc_svcctl_OpenServiceW(
rpccli->binding_handle,
frame,
&scmanager_handle,
service_name,
SERVICE_ALL_ACCESS,
&service_handle,
&werr);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
nt_errstr(status));
goto close_scmanager;
}
if (W_ERROR_EQUAL(werr, WERR_SERVICE_DOES_NOT_EXIST)) {
status = dcerpc_svcctl_CreateServiceW(
rpccli->binding_handle,
frame,
&scmanager_handle,
service_name,
NULL,
SERVICE_ALL_ACCESS,
SERVICE_TYPE_WIN32_OWN_PROCESS |
((flags & SVC_INTERACTIVE) ?
SERVICE_TYPE_INTERACTIVE_PROCESS : 0),
SVCCTL_DEMAND_START,
SVCCTL_SVC_ERROR_NORMAL,
service_filename,
NULL,
NULL,
NULL,
0,
NULL,
NULL,
0,
&service_handle,
&werr);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("dcerpc_svcctl_CreateServiceW "
"failed: %s\n", nt_errstr(status));
goto close_scmanager;
}
if (!W_ERROR_IS_OK(werr)) {
DBG_WARNING("dcerpc_svcctl_CreateServiceW "
"failed: %s\n", win_errstr(werr));
status = werror_to_ntstatus(werr);
goto close_scmanager;
}
}
status = dcerpc_svcctl_QueryServiceStatus(
rpccli->binding_handle,
frame,
&service_handle,
&service_status,
&werr);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
"failed: %s\n", nt_errstr(status));
goto close_service;
}
if (!W_ERROR_IS_OK(werr)) {
DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
"failed: %s\n", win_errstr(werr));
status = werror_to_ntstatus(werr);
goto close_service;
}
if (!(flags & SVC_IGNORE_INTERACTIVE)) {
need_conf =
!(service_status.type &
SERVICE_TYPE_INTERACTIVE_PROCESS) ^
!(flags & SVC_INTERACTIVE);
}
if (service_status.state == SVCCTL_STOPPED) {
need_start = true;
} else if (need_conf) {
status = dcerpc_svcctl_ControlService(
rpccli->binding_handle,
frame,
&service_handle,
SVCCTL_CONTROL_STOP,
&service_status,
&werr);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
"failed: %s\n", nt_errstr(status));
goto close_service;
}
if (!W_ERROR_IS_OK(werr)) {
DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
"failed: %s\n", win_errstr(werr));
status = werror_to_ntstatus(werr);
goto close_service;
}
do {
smb_msleep(100);
status = dcerpc_svcctl_QueryServiceStatus(
rpccli->binding_handle,
frame,
&service_handle,
&service_status,
&werr);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
"failed: %s\n", nt_errstr(status));
goto close_service;
}
if (!W_ERROR_IS_OK(werr)) {
DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
"failed: %s\n", win_errstr(werr));
status = werror_to_ntstatus(werr);
goto close_service;
}
} while (service_status.state == SVCCTL_STOP_PENDING);
need_start = 1;
}
if (need_conf) {
status = dcerpc_svcctl_ChangeServiceConfigW(
rpccli->binding_handle,
frame,
&service_handle,
SERVICE_TYPE_WIN32_OWN_PROCESS |
((flags & SVC_INTERACTIVE) ?
SERVICE_TYPE_INTERACTIVE_PROCESS : 0), /* type */
UINT32_MAX, /* start_type, SERVICE_NO_CHANGE */
UINT32_MAX, /* error_control, SERVICE_NO_CHANGE */
NULL, /* binary_path */
NULL, /* load_order_group */
NULL, /* tag_id */
NULL, /* dependencies */
NULL, /* service_start_name */
NULL, /* password */
NULL, /* display_name */
&werr);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
"failed: %s\n", nt_errstr(status));
goto close_service;
}
if (!W_ERROR_IS_OK(werr)) {
DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
"failed: %s\n", win_errstr(werr));
status = werror_to_ntstatus(werr);
goto close_service;
}
}
if (need_start) {
status = winexe_svc_upload(
hostname,
service_filename,
svc32_exe,
svc64_exe,
credentials,
flags);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("winexe_svc_upload failed: %s\n",
nt_errstr(status));
goto close_service;
}
status = dcerpc_svcctl_StartServiceW(
rpccli->binding_handle,
frame,
&service_handle,
0, /* num_args */
NULL, /* arguments */
&werr);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("dcerpc_svcctl_StartServiceW "
"failed: %s\n", nt_errstr(status));
goto close_service;
}
if (!W_ERROR_IS_OK(werr)) {
DBG_WARNING("dcerpc_svcctl_StartServiceW "
"failed: %s\n", win_errstr(werr));
status = werror_to_ntstatus(werr);
goto close_service;
}
do {
smb_msleep(100);
status = dcerpc_svcctl_QueryServiceStatus(
rpccli->binding_handle,
frame,
&service_handle,
&service_status,
&werr);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
"failed: %s\n", nt_errstr(status));
goto close_service;
}
if (!W_ERROR_IS_OK(werr)) {
DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
"failed: %s\n", win_errstr(werr));
status = werror_to_ntstatus(werr);
goto close_service;
}
} while (service_status.state == SVCCTL_START_PENDING);
if (service_status.state != SVCCTL_RUNNING) {
DBG_WARNING("Failed to start service\n");
status = NT_STATUS_UNSUCCESSFUL;
goto close_service;
}
}
close_service:
{
NTSTATUS close_status;
WERROR close_werr;
close_status = dcerpc_svcctl_CloseServiceHandle(
rpccli->binding_handle,
frame,
&service_handle,
&close_werr);
if (!NT_STATUS_IS_OK(close_status)) {
DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
"failed: %s\n", nt_errstr(close_status));
goto done;
}
if (!W_ERROR_IS_OK(close_werr)) {
DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
" failed: %s\n", win_errstr(close_werr));
goto done;
}
}
close_scmanager:
{
NTSTATUS close_status;
WERROR close_werr;
close_status = dcerpc_svcctl_CloseServiceHandle(
rpccli->binding_handle,
frame,
&scmanager_handle,
&close_werr);
if (!NT_STATUS_IS_OK(close_status)) {
DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
"failed: %s\n", nt_errstr(close_status));
goto done;
}
if (!W_ERROR_IS_OK(close_werr)) {
DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
" failed: %s\n", win_errstr(close_werr));
goto done;
}
}
done:
TALLOC_FREE(rpccli);
TALLOC_FREE(frame);
return status;
}
static NTSTATUS winexe_svc_uninstall(
struct cli_state *cli,
const char *service_name)
{
TALLOC_CTX *frame = talloc_stackframe();
struct rpc_pipe_client *rpccli;
struct policy_handle scmanager_handle;
struct policy_handle service_handle;
struct SERVICE_STATUS service_status;
NTSTATUS status;
WERROR werr;
status = cli_rpc_pipe_open_noauth_transport(
cli,
NCACN_NP,
&ndr_table_svcctl,
&rpccli);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
nt_errstr(status));
goto done;
}
status = dcerpc_svcctl_OpenSCManagerW(
rpccli->binding_handle,
frame,
smbXcli_conn_remote_name(cli->conn),
NULL,
SEC_FLAG_MAXIMUM_ALLOWED,
&scmanager_handle,
&werr);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
nt_errstr(status));
goto done;
}
if (!W_ERROR_IS_OK(werr)) {
DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
win_errstr(werr));
goto done;
}
status = dcerpc_svcctl_OpenServiceW(
rpccli->binding_handle,
frame,
&scmanager_handle,
service_name,
SERVICE_ALL_ACCESS,
&service_handle,
&werr);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
nt_errstr(status));
goto close_scmanager;
}
if (!W_ERROR_IS_OK(werr)) {
DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
win_errstr(werr));
status = werror_to_ntstatus(werr);
goto close_scmanager;
}
status = dcerpc_svcctl_ControlService(
rpccli->binding_handle,
frame,
&service_handle,
SVCCTL_CONTROL_STOP,
&service_status,
&werr);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
"failed: %s\n", nt_errstr(status));
goto close_service;
}
if (!W_ERROR_IS_OK(werr)) {
DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
"failed: %s\n", win_errstr(werr));
status = werror_to_ntstatus(werr);
goto close_service;
}
do {
smb_msleep(100);
status = dcerpc_svcctl_QueryServiceStatus(
rpccli->binding_handle,
frame,
&service_handle,
&service_status,
&werr);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
"failed: %s\n", nt_errstr(status));
goto close_service;
}
if (!W_ERROR_IS_OK(werr)) {
DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
"failed: %s\n", win_errstr(werr));
status = werror_to_ntstatus(werr);
goto close_service;
}
} while (service_status.state != SVCCTL_STOPPED);
status = dcerpc_svcctl_DeleteService(
rpccli->binding_handle,
frame,
&service_handle,
&werr);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("dcerpc_svcctl_DeleteService "
"failed: %s\n", nt_errstr(status));
goto close_service;
}
if (!W_ERROR_IS_OK(werr)) {
DBG_WARNING("dcerpc_svcctl_DeleteService "
"failed: %s\n", win_errstr(werr));
status = werror_to_ntstatus(werr);
goto close_service;
}
close_service:
{
NTSTATUS close_status;
WERROR close_werr;
close_status = dcerpc_svcctl_CloseServiceHandle(
rpccli->binding_handle,
frame,
&service_handle,
&close_werr);
if (!NT_STATUS_IS_OK(close_status)) {
DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
"failed: %s\n", nt_errstr(close_status));
goto done;
}
if (!W_ERROR_IS_OK(close_werr)) {
DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
" failed: %s\n", win_errstr(close_werr));
goto done;
}
}
close_scmanager:
{
NTSTATUS close_status;
WERROR close_werr;
close_status = dcerpc_svcctl_CloseServiceHandle(
rpccli->binding_handle,
frame,
&scmanager_handle,
&close_werr);
if (!NT_STATUS_IS_OK(close_status)) {
DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
"failed: %s\n", nt_errstr(close_status));
goto done;
}
if (!W_ERROR_IS_OK(close_werr)) {
DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
" failed: %s\n", win_errstr(close_werr));
goto done;
}
}
done:
TALLOC_FREE(rpccli);
TALLOC_FREE(frame);
return status;
}
struct winexe_out_pipe_state {
struct tevent_context *ev;
struct cli_state *cli;
uint16_t out_pipe;
int out_fd;
char out_inbuf[256];
};
static void winexe_out_pipe_opened(struct tevent_req *subreq);
static void winexe_out_pipe_got_data(struct tevent_req *subreq);
static void winexe_out_pipe_closed(struct tevent_req *subreq);
static struct tevent_req *winexe_out_pipe_send(
TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli,
const char *pipe_name,
int out_fd)
{
struct tevent_req *req, *subreq;
struct winexe_out_pipe_state *state;
req = tevent_req_create(mem_ctx, &state,
struct winexe_out_pipe_state);
if (req == NULL) {
return NULL;
}
state->ev = ev;
state->cli = cli;
state->out_fd = out_fd;
subreq = cli_ntcreate_send(
state,
state->ev,
state->cli,
pipe_name,
0,
SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
SEC_RIGHTS_FILE_EXECUTE,
0, /* FileAttributes */
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
FILE_OPEN, /* CreateDisposition */
0, /* CreateOptions */
0); /* SecurityFlags */
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
tevent_req_set_callback(subreq, winexe_out_pipe_opened, req);
return req;
}
static void winexe_out_pipe_opened(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct winexe_out_pipe_state *state = tevent_req_data(
req, struct winexe_out_pipe_state);
int timeout;
NTSTATUS status;
status = cli_ntcreate_recv(subreq, &state->out_pipe, NULL);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
timeout = state->cli->timeout;
state->cli->timeout = 0;
subreq = cli_read_send(
state,
state->ev,
state->cli,
state->out_pipe,
state->out_inbuf,
0,
sizeof(state->out_inbuf));
state->cli->timeout = timeout;
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
}
static void winexe_out_pipe_got_data(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct winexe_out_pipe_state *state = tevent_req_data(
req, struct winexe_out_pipe_state);
NTSTATUS status;
int timeout;
size_t received;
ssize_t written;
status = cli_read_recv(subreq, &received);
TALLOC_FREE(subreq);
DBG_DEBUG("cli_read for %d gave %s\n",
state->out_fd,
nt_errstr(status));
if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
subreq = cli_close_send(
state,
state->ev,
state->cli,
state->out_pipe);
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, winexe_out_pipe_closed, req);
return;
}
if (tevent_req_nterror(req, status)) {
return;
}
if (received > 0) {
written = sys_write(state->out_fd, state->out_inbuf, received);
if (written == -1) {
tevent_req_nterror(req, map_nt_error_from_unix(errno));
return;
}
}
timeout = state->cli->timeout;
state->cli->timeout = 0;
subreq = cli_read_send(
state,
state->ev,
state->cli,
state->out_pipe,
state->out_inbuf,
0,
sizeof(state->out_inbuf));
state->cli->timeout = timeout;
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
}
static void winexe_out_pipe_closed(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
NTSTATUS status;
status = cli_close_recv(subreq);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
tevent_req_done(req);
}
static NTSTATUS winexe_out_pipe_recv(struct tevent_req *req)
{
return tevent_req_simple_recv_ntstatus(req);
}
struct winexe_in_pipe_state {
struct tevent_context *ev;
struct cli_state *cli;
struct tevent_req *fd_read_req;
bool close_requested;
bool closing;
uint16_t in_pipe;
int in_fd;
char inbuf[256];
};
static void winexe_in_pipe_opened(struct tevent_req *subreq);
static void winexe_in_pipe_got_data(struct tevent_req *subreq);
static void winexe_in_pipe_written(struct tevent_req *subreq);
static void winexe_in_pipe_closed(struct tevent_req *subreq);
static struct tevent_req *winexe_in_pipe_send(
TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli,
const char *pipe_name,
int in_fd)
{
struct tevent_req *req, *subreq;
struct winexe_in_pipe_state *state;
req = tevent_req_create(mem_ctx, &state,
struct winexe_in_pipe_state);
if (req == NULL) {
return NULL;
}
state->ev = ev;
state->cli = cli;
state->in_fd = in_fd;
subreq = cli_ntcreate_send(
state,
state->ev,
state->cli,
pipe_name,
0,
SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
SEC_RIGHTS_FILE_EXECUTE,
0, /* FileAttributes */
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
FILE_OPEN, /* CreateDisposition */
0, /* CreateOptions */
0); /* SecurityFlags */
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
tevent_req_set_callback(subreq, winexe_in_pipe_opened, req);
return req;
}
static void winexe_in_pipe_opened(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct winexe_in_pipe_state *state = tevent_req_data(
req, struct winexe_in_pipe_state);
NTSTATUS status;
status = cli_ntcreate_recv(subreq, &state->in_pipe, NULL);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
subreq = wait_for_read_send(
state,
state->ev,
state->in_fd,
true);
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
state->fd_read_req = subreq;
}
static void winexe_in_pipe_got_data(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct winexe_in_pipe_state *state = tevent_req_data(
req, struct winexe_in_pipe_state);
int err;
bool ok;
int timeout;
ssize_t nread;
ok = wait_for_read_recv(subreq, &err);
TALLOC_FREE(subreq);
if (!ok) {
tevent_req_nterror(req, map_nt_error_from_unix(err));
return;
}
state->fd_read_req = NULL;
nread = sys_read(state->in_fd, &state->inbuf, sizeof(state->inbuf));
if (nread == -1) {
tevent_req_nterror(req, map_nt_error_from_unix(errno));
return;
}
if (nread == 0) {
tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
return;
}
timeout = state->cli->timeout;
state->cli->timeout = 0;
subreq = cli_writeall_send(
state,
state->ev,
state->cli,
state->in_pipe,
0,
(uint8_t *)state->inbuf,
0,
nread);
state->cli->timeout = timeout;
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, winexe_in_pipe_written, req);
}
static void winexe_in_pipe_written(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct winexe_in_pipe_state *state = tevent_req_data(
req, struct winexe_in_pipe_state);
NTSTATUS status;
status = cli_writeall_recv(subreq, NULL);
TALLOC_FREE(subreq);
DBG_DEBUG("cli_writeall for %d gave %s\n",
state->in_fd,
nt_errstr(status));
if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED) ||
state->close_requested) {
subreq = cli_close_send(
state,
state->ev,
state->cli,
state->in_pipe);
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
state->closing = true;
return;
}
if (tevent_req_nterror(req, status)) {
return;
}
subreq = wait_for_read_send(
state,
state->ev,
state->in_fd,
true);
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
state->fd_read_req = subreq;
}
static void winexe_in_pipe_closed(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
NTSTATUS status;
status = cli_close_recv(subreq);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
return tevent_req_done(req);
}
static NTSTATUS winexe_in_pipe_recv(struct tevent_req *req)
{
return tevent_req_simple_recv_ntstatus(req);
}
static bool winexe_in_pipe_close(struct tevent_req *req)
{
struct winexe_in_pipe_state *state = tevent_req_data(
req, struct winexe_in_pipe_state);
struct tevent_req *subreq;
if (state->closing) {
return true;
}
if (state->fd_read_req == NULL) {
/*
* cli_writeall active, wait for it to return
*/
state->close_requested = true;
return true;
}
TALLOC_FREE(state->fd_read_req);
subreq = cli_close_send(
state,
state->ev,
state->cli,
state->in_pipe);
if (subreq == NULL) {
return false;
}
tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
state->closing = true;
return true;
}
struct winexe_pipes_state {
struct tevent_req *pipes[3];
};
static void winexe_pipes_stdin_done(struct tevent_req *subreq);
static void winexe_pipes_stdout_done(struct tevent_req *subreq);
static void winexe_pipes_stderr_done(struct tevent_req *subreq);
static struct tevent_req *winexe_pipes_send(
TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli,
const char *pipe_postfix)
{
struct tevent_req *req;
struct winexe_pipes_state *state;
char *pipe_name;
req = tevent_req_create(mem_ctx, &state, struct winexe_pipes_state);
if (req == NULL) {
return NULL;
}
pipe_name = talloc_asprintf(state, "\\ahexec_stdin%s", pipe_postfix);
if (tevent_req_nomem(pipe_name, req)) {
return tevent_req_post(req, ev);
}
state->pipes[0] = winexe_in_pipe_send(
state,
ev,
cli,
pipe_name,
0);
if (tevent_req_nomem(state->pipes[0], req)) {
return tevent_req_post(req, ev);
}
tevent_req_set_callback(state->pipes[0], winexe_pipes_stdin_done, req);
pipe_name = talloc_asprintf(state, "\\ahexec_stdout%s", pipe_postfix);
if (tevent_req_nomem(pipe_name, req)) {
return tevent_req_post(req, ev);
}
state->pipes[1] = winexe_out_pipe_send(
state,
ev,
cli,
pipe_name,
1);
if (tevent_req_nomem(state->pipes[1], req)) {
return tevent_req_post(req, ev);
}
tevent_req_set_callback(state->pipes[1], winexe_pipes_stdout_done,
req);
pipe_name = talloc_asprintf(state, "\\ahexec_stderr%s", pipe_postfix);
if (tevent_req_nomem(pipe_name, req)) {
return tevent_req_post(req, ev);
}
state->pipes[2] = winexe_out_pipe_send(
state,
ev,
cli,
pipe_name,
2);
if (tevent_req_nomem(state->pipes[2], req)) {
return tevent_req_post(req, ev);
}
tevent_req_set_callback(state->pipes[2], winexe_pipes_stderr_done,
req);
DBG_DEBUG("pipes = %p %p %p\n",
state->pipes[0],
state->pipes[1],
state->pipes[2]);
return req;
}
static void winexe_pipes_stdin_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct winexe_pipes_state *state = tevent_req_data(
req, struct winexe_pipes_state);
NTSTATUS status;
status = winexe_in_pipe_recv(subreq);
TALLOC_FREE(subreq);
DBG_DEBUG("stdin returned %s\n", nt_errstr(status));
if (tevent_req_nterror(req, status)) {
return;
}
state->pipes[0] = NULL;
DBG_DEBUG("pipes = %p %p %p\n",
state->pipes[0],
state->pipes[1],
state->pipes[2]);
if ((state->pipes[1] == NULL) && (state->pipes[2] == NULL)) {
tevent_req_done(req);
}
}
static void winexe_pipes_stdout_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct winexe_pipes_state *state = tevent_req_data(
req, struct winexe_pipes_state);
NTSTATUS status;
status = winexe_out_pipe_recv(subreq);
TALLOC_FREE(subreq);
DBG_DEBUG("stdout returned %s\n", nt_errstr(status));
if (tevent_req_nterror(req, status)) {
return;
}
if (state->pipes[0] != NULL) {
winexe_in_pipe_close(state->pipes[0]);
}
state->pipes[1] = NULL;
DBG_DEBUG("pipes = %p %p %p\n",
state->pipes[0],
state->pipes[1],
state->pipes[2]);
if ((state->pipes[0] == NULL) && (state->pipes[2] == NULL)) {
tevent_req_done(req);
}
}
static void winexe_pipes_stderr_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct winexe_pipes_state *state = tevent_req_data(
req, struct winexe_pipes_state);
NTSTATUS status;
status = winexe_out_pipe_recv(subreq);
TALLOC_FREE(subreq);
DBG_DEBUG("stderr returned %s\n", nt_errstr(status));
if (tevent_req_nterror(req, status)) {
return;
}
if (state->pipes[0] != NULL) {
winexe_in_pipe_close(state->pipes[0]);
}
state->pipes[2] = NULL;
DBG_DEBUG("pipes = %p %p %p\n",
state->pipes[0],
state->pipes[1],
state->pipes[2]);
if ((state->pipes[0] == NULL) && (state->pipes[1] == NULL)) {
tevent_req_done(req);
}
}
static NTSTATUS winexe_pipes_recv(struct tevent_req *req)
{
return tevent_req_simple_recv_ntstatus(req);
}
struct winexe_ctrl_state {
struct tevent_context *ev;
struct cli_state *cli;
uint16_t ctrl_pipe;
bool ctrl_pipe_done;
char ctrl_inbuf[256];
char *cmd;
int return_code;
struct tevent_req *pipes_req;
};
static void winexe_ctrl_opened(struct tevent_req *subreq);
static void winexe_ctrl_got_read(struct tevent_req *subreq);
static void winexe_ctrl_wrote_version(struct tevent_req *subreq);
static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq);
static void winexe_ctrl_pipes_done(struct tevent_req *subreq);
static void winexe_ctrl_pipe_closed(struct tevent_req *subreq);
static struct tevent_req *winexe_ctrl_send(
TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli,
const char *cmd)
{
struct tevent_req *req, *subreq;
struct winexe_ctrl_state *state;
req = tevent_req_create(mem_ctx, &state,
struct winexe_ctrl_state);
if (req == NULL) {
return NULL;
}
state->ev = ev;
state->cli = cli;
state->cmd = talloc_asprintf(state, "run %s\n", cmd);
if (tevent_req_nomem(state->cmd, req)) {
return tevent_req_post(req, ev);
}
subreq = cli_ntcreate_send(
state,
state->ev,
state->cli,
"\\" PIPE_NAME,
0,
SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
SEC_RIGHTS_FILE_EXECUTE,
0, /* FileAttributes */
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
FILE_OPEN, /* CreateDisposition */
0, /* CreateOptions */
0); /* SecurityFlags */
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
tevent_req_set_callback(subreq, winexe_ctrl_opened, req);
return req;
}
static void winexe_ctrl_opened(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct winexe_ctrl_state *state = tevent_req_data(
req, struct winexe_ctrl_state);
int timeout;
NTSTATUS status;
static const char cmd[] = "get codepage\nget version\n";
status = cli_ntcreate_recv(subreq, &state->ctrl_pipe, NULL);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
timeout = state->cli->timeout;
state->cli->timeout = 0;
subreq = cli_read_send(
state,
state->ev,
state->cli,
state->ctrl_pipe,
state->ctrl_inbuf,
0,
sizeof(state->ctrl_inbuf)-1);
state->cli->timeout = timeout;
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
subreq = cli_writeall_send(
state,
state->ev,
state->cli,
state->ctrl_pipe,
0,
(const uint8_t *)cmd,
0,
strlen(cmd));
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, winexe_ctrl_wrote_version, req);
}
static void winexe_ctrl_got_read(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct winexe_ctrl_state *state = tevent_req_data(
req, struct winexe_ctrl_state);
NTSTATUS status;
int timeout;
size_t received;
unsigned int version, return_code;
int ret;
status = cli_read_recv(subreq, &received);
TALLOC_FREE(subreq);
if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
subreq = cli_close_send(
state,
state->ev,
state->cli,
state->ctrl_pipe);
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, winexe_ctrl_pipe_closed, req);
return;
}
if (tevent_req_nterror(req, status)) {
return;
}
DBG_DEBUG("Got %zu bytes\n", received);
timeout = state->cli->timeout;
state->cli->timeout = 0;
subreq = cli_read_send(
state,
state->ev,
state->cli,
state->ctrl_pipe,
state->ctrl_inbuf,
0,
sizeof(state->ctrl_inbuf)-1);
state->cli->timeout = timeout;
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &version);
if (ret == 1) {
DBG_DEBUG("Got version %x\n", version);
subreq = cli_writeall_send(
state,
state->ev,
state->cli,
state->ctrl_pipe,
0,
(const uint8_t *)state->cmd,
0,
strlen(state->cmd));
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, winexe_ctrl_wrote_cmd, req);
return;
}
ret = strncmp(state->ctrl_inbuf, "std_io_err ", strlen("std_io_err "));
if (ret == 0) {
char *p = state->ctrl_inbuf + 11;
char *q = strchr(state->ctrl_inbuf, '\n');
char *postfix;
size_t postfix_len;
if (q == NULL) {
DBG_DEBUG("Got invalid pipe postfix\n");
return;
}
postfix_len = q - p;
postfix = talloc_strndup(state, p, postfix_len);
if (tevent_req_nomem(postfix, req)) {
return;
}
DBG_DEBUG("Got pipe postfix %s\n", postfix);
subreq = winexe_pipes_send(
state,
state->ev,
state->cli,
postfix);
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, winexe_ctrl_pipes_done, req);
state->pipes_req = subreq;
return;
}
ret = strncmp(state->ctrl_inbuf, "error ", strlen("error "));
if (ret == 0) {
printf("Error: %s", state->ctrl_inbuf);
return;
}
ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &return_code);
if (ret == 1) {
state->return_code = return_code;
return;
}
}
static void winexe_ctrl_wrote_version(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
NTSTATUS status;
status = cli_writeall_recv(subreq, NULL);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
}
static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
NTSTATUS status;
status = cli_writeall_recv(subreq, NULL);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
}
static void winexe_ctrl_pipe_closed(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct winexe_ctrl_state *state = tevent_req_data(
req, struct winexe_ctrl_state);
NTSTATUS status;
status = cli_close_recv(subreq);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
state->ctrl_pipe_done = true;
if (state->pipes_req == NULL) {
tevent_req_done(req);
}
}
static void winexe_ctrl_pipes_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct winexe_ctrl_state *state = tevent_req_data(
req, struct winexe_ctrl_state);
NTSTATUS status;
status = winexe_pipes_recv(subreq);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
state->pipes_req = NULL;
if (state->ctrl_pipe_done) {
tevent_req_done(req);
}
}
static NTSTATUS winexe_ctrl_recv(struct tevent_req *req,
int *preturn_code)
{
struct winexe_ctrl_state *state = tevent_req_data(
req, struct winexe_ctrl_state);
NTSTATUS status;
if (tevent_req_is_nterror(req, &status)) {
return status;
}
if (preturn_code != NULL) {
*preturn_code = state->return_code;
}
return NT_STATUS_OK;
}
static NTSTATUS winexe_ctrl(struct cli_state *cli,
const char *cmd,
int *preturn_code)
{
struct tevent_context *ev = NULL;
struct tevent_req *req = NULL;
NTSTATUS status = NT_STATUS_NO_MEMORY;
bool ok;
ev = samba_tevent_context_init(cli);
if (ev == NULL) {
goto done;
}
req = winexe_ctrl_send(ev, ev, cli, cmd);
if (req == NULL) {
goto done;
}
ok = tevent_req_poll_ntstatus(req, ev, &status);
if (!ok) {
goto done;
}
status = winexe_ctrl_recv(req, preturn_code);
done:
TALLOC_FREE(req);
TALLOC_FREE(ev);
return status;
}
#ifdef HAVE_WINEXE_CC_WIN32
const DATA_BLOB *winexesvc32_exe_binary(void);
#endif
#ifdef HAVE_WINEXE_CC_WIN64
const DATA_BLOB *winexesvc64_exe_binary(void);
#endif
int main(int argc, const char *argv[])
{
TALLOC_CTX *frame = talloc_stackframe();
struct program_options options = {0};
struct loadparm_context *lp_ctx;
struct cli_state *cli;
const char *service_name = SERVICE_NAME;
char *service_filename = NULL;
#ifdef HAVE_WINEXE_CC_WIN32
const DATA_BLOB *winexesvc32_exe = winexesvc32_exe_binary();
#else
const DATA_BLOB *winexesvc32_exe = NULL;
#endif
#ifdef HAVE_WINEXE_CC_WIN64
const DATA_BLOB *winexesvc64_exe = winexesvc64_exe_binary();
#else
const DATA_BLOB *winexesvc64_exe = NULL;
#endif
NTSTATUS status;
int ret = 1;
int return_code = 0;
lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
if (lp_ctx == NULL) {
fprintf(stderr, "loadparm_init_s3 failed\n");
goto done;
}
smb_init_locale();
setup_logging("winexe", DEBUG_STDOUT);
lp_load_global(get_dyn_CONFIGFILE());
parse_args(argc, argv, frame, &options, lp_ctx);
if (options.cmd == NULL) {
fprintf(stderr, "no cmd given\n");
goto done;
}
service_filename = talloc_asprintf(frame, "%s.exe", service_name);
if (service_filename == NULL) {
DBG_WARNING("talloc_asprintf failed\n");
goto done;
}
status = cli_full_connection_creds(
&cli,
NULL,
options.hostname,
NULL,
445,
"IPC$",
"?????",
options.credentials,
0,
0);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("cli_full_connection_creds failed: %s\n",
nt_errstr(status));
goto done;
}
status = winexe_svc_install(
cli,
options.hostname,
service_name,
service_filename,
winexesvc32_exe,
winexesvc64_exe,
options.credentials,
options.flags);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("winexe_svc_install failed: %s\n",
nt_errstr(status));
goto done;
}
status = winexe_ctrl(cli, options.cmd, &return_code);
if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
/* Normal finish */
status = NT_STATUS_OK;
}
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("cli_ctrl failed: %s\n",
nt_errstr(status));
goto done;
}
if (options.flags & SVC_UNINSTALL) {
status = winexe_svc_uninstall(
cli,
service_name);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("winexe_svc_uninstall failed: %s\n",
nt_errstr(status));
goto done;
}
}
ret = return_code;
done:
TALLOC_FREE(frame);
return ret;
}