2 * Samba Unix/Linux CIFS implementation
6 * Copyright (C) 2018 Volker Lendecke <vl@samba.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "lib/param/param.h"
27 #include "auth/credentials/credentials.h"
28 #include "lib/util/talloc_stack.h"
29 #include "lib/util/tevent_ntstatus.h"
30 #include "lib/util/sys_rw.h"
31 #include "libsmb/proto.h"
32 #include "librpc/gen_ndr/ndr_svcctl_c.h"
33 #include "rpc_client/cli_pipe.h"
34 #include "libcli/smb/smbXcli_base.h"
35 #include "libcli/util/werror.h"
36 #include "lib/async_req/async_sock.h"
39 #define SVC_INTERACTIVE 1
40 #define SVC_IGNORE_INTERACTIVE 2
41 #define SVC_INTERACTIVE_MASK 3
42 #define SVC_FORCE_UPLOAD 4
44 #define SVC_OSCHOOSE 16
45 #define SVC_UNINSTALL 32
48 #define SERVICE_NAME "winexesvc"
50 #define PIPE_NAME "ahexec"
51 #define PIPE_NAME_IN "ahexec_stdin%08X"
52 #define PIPE_NAME_OUT "ahexec_stdout%08X"
53 #define PIPE_NAME_ERR "ahexec_stderr%08X"
55 static const char version_message_fmt[] = "winexe version %d.%d\n"
56 "This program may be freely redistributed under the terms of the "
59 struct program_options {
62 struct cli_credentials *credentials;
68 static void parse_args(int argc, const char *argv[],
70 struct program_options *options,
71 struct loadparm_context *lp_ctx)
75 struct cli_credentials *cred;
80 int flag_interactive = SVC_IGNORE_INTERACTIVE;
82 int flag_reinstall = 0;
83 int flag_uninstall = 0;
87 char *opt_user = NULL;
88 char *opt_kerberos = NULL;
89 char *opt_auth_file = NULL;
90 char *opt_debuglevel = NULL;
92 struct poptOption long_options[] = {
93 { "help", 'h', POPT_ARG_NONE, &flag_help, 0,
94 "Display help message" },
95 { "version", 'V', POPT_ARG_NONE, &flag_version, 0,
96 "Display version number" },
97 { "user", 'U', POPT_ARG_STRING, &opt_user, 0,
98 "Set the network username", "[DOMAIN/]USERNAME[%PASSWORD]" },
99 { "authentication-file", 'A',
100 POPT_ARG_STRING, &opt_auth_file, 0,
101 "Get the credentials from a file", "FILE" },
102 { "no-pass", 'N', POPT_ARG_NONE, &flag_nopass, 0,
103 "Do not ask for a password", NULL },
104 { "kerberos", 'k', POPT_ARG_STRING, &opt_kerberos, 0,
105 "Use Kerberos, -k [yes|no]" },
106 { "debuglevel", 'd', POPT_ARG_STRING, &opt_debuglevel, 0,
107 "Set debug level", "DEBUGLEVEL" },
108 { "uninstall", 0, POPT_ARG_NONE, &flag_uninstall, 0,
109 "Uninstall winexe service after remote execution", NULL},
110 { "reinstall", 0, POPT_ARG_NONE, &flag_reinstall, 0,
111 "Reinstall winexe service before remote execution", NULL},
112 { "runas", 0, POPT_ARG_STRING, &options->runas, 0,
113 "Run as the given user (BEWARE: this password is sent "
114 "in cleartext over the network!)",
115 "[DOMAIN\\]USERNAME%PASSWORD"},
116 { "runas-file", 0, POPT_ARG_STRING, &options->runas_file, 0,
117 "Run as user options defined in a file", "FILE"},
118 { "interactive", 0, POPT_ARG_INT, &flag_interactive, 0,
119 "Desktop interaction: 0 - disallow, 1 - allow. If allow, "
120 "also use the --system switch (Windows requirement). Vista "
121 "does not support this option.", "0|1"},
122 { "ostype", 0, POPT_ARG_INT, &flag_ostype, 0,
123 "OS type: 0 - 32-bit, 1 - 64-bit, 2 - winexe will decide. "
124 "Determines which version (32-bit or 64-bit) of service "
125 "will be installed.", "0|1|2"},
129 ZERO_STRUCTP(options);
131 pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,
134 poptSetOtherOptionHelp(pc, "[OPTION]... //HOST COMMAND\nOptions:");
136 if (((opt = poptGetNextOpt(pc)) != -1) || flag_help || flag_version) {
137 fprintf(stderr, version_message_fmt, SAMBA_VERSION_MAJOR,
138 SAMBA_VERSION_MINOR);
142 poptPrintHelp(pc, stdout, 0);
149 argv_new = discard_const_p(char *, poptGetArgs(pc));
152 for (i = 0; i < argc; i++) {
153 if (!argv_new || argv_new[i] == NULL) {
159 if (argc_new != 2 || argv_new[0][0] != '/' || argv_new[0][1] != '/') {
160 fprintf(stderr, version_message_fmt, SAMBA_VERSION_MAJOR,
161 SAMBA_VERSION_MINOR);
162 poptPrintHelp(pc, stdout, 0);
166 if (opt_debuglevel) {
167 lp_set_cmdline("log level", opt_debuglevel);
170 cred = cli_credentials_init(mem_ctx);
173 cli_credentials_parse_string(cred, opt_user, CRED_SPECIFIED);
174 } else if (opt_auth_file) {
175 cli_credentials_parse_file(cred, opt_auth_file,
179 cli_credentials_guess(cred, lp_ctx);
180 if (!cli_credentials_get_password(cred) && !flag_nopass) {
181 char *p = getpass("Enter password: ");
183 cli_credentials_set_password(cred, p, CRED_SPECIFIED);
188 cli_credentials_set_kerberos_state(cred,
189 strcmp(opt_kerberos, "yes")
190 ? CRED_MUST_USE_KERBEROS
191 : CRED_DONT_USE_KERBEROS);
194 if (options->runas == NULL && options->runas_file != NULL) {
195 struct cli_credentials *runas_cred;
199 runas_cred = cli_credentials_init(mem_ctx);
200 cli_credentials_parse_file(runas_cred, options->runas_file,
203 user = cli_credentials_get_username(runas_cred);
204 pass = cli_credentials_get_password(runas_cred);
210 dom = cli_credentials_get_domain(runas_cred);
212 snprintf(buffer, sizeof(buffer), "%s\\%s%%%s",
215 snprintf(buffer, sizeof(buffer), "%s%%%s",
218 buffer[sizeof(buffer)-1] = '\0';
219 options->runas = talloc_strdup(mem_ctx, buffer);
223 options->credentials = cred;
225 options->hostname = argv_new[0] + 2;
226 options->cmd = argv_new[1];
228 options->flags = flag_interactive;
229 if (flag_reinstall) {
230 options->flags |= SVC_FORCE_UPLOAD;
232 if (flag_ostype == 1) {
233 options->flags |= SVC_OS64BIT;
235 if (flag_ostype == 2) {
236 options->flags |= SVC_OSCHOOSE;
238 if (flag_uninstall) {
239 options->flags |= SVC_UNINSTALL;
243 static NTSTATUS winexe_svc_upload(
244 const char *hostname,
245 const char *service_filename,
246 const DATA_BLOB *svc32_exe,
247 const DATA_BLOB *svc64_exe,
248 struct cli_credentials *credentials,
251 struct cli_state *cli;
254 const DATA_BLOB *binary = NULL;
256 status = cli_full_connection_creds(
267 if (!NT_STATUS_IS_OK(status)) {
268 DBG_WARNING("cli_full_connection_creds failed: %s\n",
273 if (flags & SVC_FORCE_UPLOAD) {
274 status = cli_unlink(cli, service_filename, 0);
275 if (!NT_STATUS_IS_OK(status)) {
276 DBG_WARNING("cli_unlink failed: %s\n",
281 if (flags & SVC_OSCHOOSE) {
282 status = cli_chkpath(cli, "SysWoW64");
283 if (NT_STATUS_IS_OK(status)) {
284 flags |= SVC_OS64BIT;
288 if (flags & SVC_OS64BIT) {
294 if (binary == NULL) {
298 status = cli_ntcreate(
302 SEC_FILE_WRITE_DATA, /* DesiredAccess */
303 FILE_ATTRIBUTE_NORMAL, /* FileAttributes */
304 FILE_SHARE_WRITE|FILE_SHARE_READ, /* ShareAccess */
305 FILE_OPEN_IF, /* CreateDisposition */
306 FILE_NON_DIRECTORY_FILE, /* CreateOptions */
307 0, /* SecurityFlags */
309 NULL); /* CreateReturns */
310 if (!NT_STATUS_IS_OK(status)) {
311 DBG_WARNING("Could not create %s: %s\n", service_filename,
316 status = cli_writeall(
324 if (!NT_STATUS_IS_OK(status)) {
325 DBG_WARNING("Could not write file: %s\n", nt_errstr(status));
330 status = cli_close(cli, fnum);
331 if (!NT_STATUS_IS_OK(status)) {
332 DBG_WARNING("Close(%"PRIu16") failed for %s: %s\n", fnum,
333 service_filename, nt_errstr(status));
340 static NTSTATUS winexe_svc_install(
341 struct cli_state *cli,
342 const char *hostname,
343 const char *service_name,
344 const char *service_filename,
345 const DATA_BLOB *svc32_exe,
346 const DATA_BLOB *svc64_exe,
347 struct cli_credentials *credentials,
350 TALLOC_CTX *frame = talloc_stackframe();
351 struct rpc_pipe_client *rpccli;
352 struct policy_handle scmanager_handle;
353 struct policy_handle service_handle;
354 struct SERVICE_STATUS service_status;
355 bool need_start = false;
356 bool need_conf = false;
360 status = cli_rpc_pipe_open_noauth_transport(
365 if (!NT_STATUS_IS_OK(status)) {
366 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
371 status = dcerpc_svcctl_OpenSCManagerW(
372 rpccli->binding_handle,
374 smbXcli_conn_remote_name(cli->conn),
376 SEC_FLAG_MAXIMUM_ALLOWED,
379 if (!NT_STATUS_IS_OK(status)) {
380 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
384 if (!W_ERROR_IS_OK(werr)) {
385 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
390 status = dcerpc_svcctl_OpenServiceW(
391 rpccli->binding_handle,
398 if (!NT_STATUS_IS_OK(status)) {
399 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
401 goto close_scmanager;
404 if (W_ERROR_EQUAL(werr, WERR_SERVICE_DOES_NOT_EXIST)) {
405 status = dcerpc_svcctl_CreateServiceW(
406 rpccli->binding_handle,
412 SERVICE_TYPE_WIN32_OWN_PROCESS |
413 ((flags & SVC_INTERACTIVE) ?
414 SERVICE_TYPE_INTERACTIVE_PROCESS : 0),
416 SVCCTL_SVC_ERROR_NORMAL,
427 if (!NT_STATUS_IS_OK(status)) {
428 DBG_WARNING("dcerpc_svcctl_CreateServiceW "
429 "failed: %s\n", nt_errstr(status));
430 goto close_scmanager;
432 if (!W_ERROR_IS_OK(werr)) {
433 DBG_WARNING("dcerpc_svcctl_CreateServiceW "
434 "failed: %s\n", win_errstr(werr));
435 status = werror_to_ntstatus(werr);
436 goto close_scmanager;
440 status = dcerpc_svcctl_QueryServiceStatus(
441 rpccli->binding_handle,
447 if (!NT_STATUS_IS_OK(status)) {
448 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
449 "failed: %s\n", nt_errstr(status));
452 if (!W_ERROR_IS_OK(werr)) {
453 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
454 "failed: %s\n", win_errstr(werr));
455 status = werror_to_ntstatus(werr);
459 if (!(flags & SVC_IGNORE_INTERACTIVE)) {
461 !(service_status.type &
462 SERVICE_TYPE_INTERACTIVE_PROCESS) ^
463 !(flags & SVC_INTERACTIVE);
466 if (service_status.state == SVCCTL_STOPPED) {
468 } else if (need_conf) {
469 status = dcerpc_svcctl_ControlService(
470 rpccli->binding_handle,
477 if (!NT_STATUS_IS_OK(status)) {
478 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
479 "failed: %s\n", nt_errstr(status));
482 if (!W_ERROR_IS_OK(werr)) {
483 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
484 "failed: %s\n", win_errstr(werr));
485 status = werror_to_ntstatus(werr);
492 status = dcerpc_svcctl_QueryServiceStatus(
493 rpccli->binding_handle,
499 if (!NT_STATUS_IS_OK(status)) {
500 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
501 "failed: %s\n", nt_errstr(status));
504 if (!W_ERROR_IS_OK(werr)) {
505 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
506 "failed: %s\n", win_errstr(werr));
507 status = werror_to_ntstatus(werr);
510 } while (service_status.state == SVCCTL_STOP_PENDING);
516 status = dcerpc_svcctl_ChangeServiceConfigW(
517 rpccli->binding_handle,
520 SERVICE_TYPE_WIN32_OWN_PROCESS |
521 ((flags & SVC_INTERACTIVE) ?
522 SERVICE_TYPE_INTERACTIVE_PROCESS : 0), /* type */
523 UINT32_MAX, /* start_type, SERVICE_NO_CHANGE */
524 UINT32_MAX, /* error_control, SERVICE_NO_CHANGE */
525 NULL, /* binary_path */
526 NULL, /* load_order_group */
528 NULL, /* dependencies */
529 NULL, /* service_start_name */
531 NULL, /* display_name */
534 if (!NT_STATUS_IS_OK(status)) {
535 DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
536 "failed: %s\n", nt_errstr(status));
539 if (!W_ERROR_IS_OK(werr)) {
540 DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
541 "failed: %s\n", win_errstr(werr));
542 status = werror_to_ntstatus(werr);
548 status = winexe_svc_upload(
555 if (!NT_STATUS_IS_OK(status)) {
556 DBG_WARNING("winexe_svc_upload failed: %s\n",
561 status = dcerpc_svcctl_StartServiceW(
562 rpccli->binding_handle,
566 NULL, /* arguments */
569 if (!NT_STATUS_IS_OK(status)) {
570 DBG_WARNING("dcerpc_svcctl_StartServiceW "
571 "failed: %s\n", nt_errstr(status));
574 if (!W_ERROR_IS_OK(werr)) {
575 DBG_WARNING("dcerpc_svcctl_StartServiceW "
576 "failed: %s\n", win_errstr(werr));
577 status = werror_to_ntstatus(werr);
584 status = dcerpc_svcctl_QueryServiceStatus(
585 rpccli->binding_handle,
591 if (!NT_STATUS_IS_OK(status)) {
592 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
593 "failed: %s\n", nt_errstr(status));
596 if (!W_ERROR_IS_OK(werr)) {
597 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
598 "failed: %s\n", win_errstr(werr));
599 status = werror_to_ntstatus(werr);
602 } while (service_status.state == SVCCTL_START_PENDING);
604 if (service_status.state != SVCCTL_RUNNING) {
605 DBG_WARNING("Failed to start service\n");
606 status = NT_STATUS_UNSUCCESSFUL;
613 NTSTATUS close_status;
616 close_status = dcerpc_svcctl_CloseServiceHandle(
617 rpccli->binding_handle,
621 if (!NT_STATUS_IS_OK(close_status)) {
622 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
623 "failed: %s\n", nt_errstr(close_status));
626 if (!W_ERROR_IS_OK(close_werr)) {
627 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
628 " failed: %s\n", win_errstr(close_werr));
635 NTSTATUS close_status;
638 close_status = dcerpc_svcctl_CloseServiceHandle(
639 rpccli->binding_handle,
643 if (!NT_STATUS_IS_OK(close_status)) {
644 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
645 "failed: %s\n", nt_errstr(close_status));
648 if (!W_ERROR_IS_OK(close_werr)) {
649 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
650 " failed: %s\n", win_errstr(close_werr));
661 static NTSTATUS winexe_svc_uninstall(
662 struct cli_state *cli,
663 const char *service_name)
665 TALLOC_CTX *frame = talloc_stackframe();
666 struct rpc_pipe_client *rpccli;
667 struct policy_handle scmanager_handle;
668 struct policy_handle service_handle;
669 struct SERVICE_STATUS service_status;
673 status = cli_rpc_pipe_open_noauth_transport(
678 if (!NT_STATUS_IS_OK(status)) {
679 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
684 status = dcerpc_svcctl_OpenSCManagerW(
685 rpccli->binding_handle,
687 smbXcli_conn_remote_name(cli->conn),
689 SEC_FLAG_MAXIMUM_ALLOWED,
692 if (!NT_STATUS_IS_OK(status)) {
693 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
697 if (!W_ERROR_IS_OK(werr)) {
698 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
703 status = dcerpc_svcctl_OpenServiceW(
704 rpccli->binding_handle,
711 if (!NT_STATUS_IS_OK(status)) {
712 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
714 goto close_scmanager;
716 if (!W_ERROR_IS_OK(werr)) {
717 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
719 status = werror_to_ntstatus(werr);
720 goto close_scmanager;
723 status = dcerpc_svcctl_ControlService(
724 rpccli->binding_handle,
730 if (!NT_STATUS_IS_OK(status)) {
731 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
732 "failed: %s\n", nt_errstr(status));
735 if (!W_ERROR_IS_OK(werr)) {
736 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
737 "failed: %s\n", win_errstr(werr));
738 status = werror_to_ntstatus(werr);
745 status = dcerpc_svcctl_QueryServiceStatus(
746 rpccli->binding_handle,
752 if (!NT_STATUS_IS_OK(status)) {
753 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
754 "failed: %s\n", nt_errstr(status));
757 if (!W_ERROR_IS_OK(werr)) {
758 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
759 "failed: %s\n", win_errstr(werr));
760 status = werror_to_ntstatus(werr);
763 } while (service_status.state != SVCCTL_STOPPED);
765 status = dcerpc_svcctl_DeleteService(
766 rpccli->binding_handle,
770 if (!NT_STATUS_IS_OK(status)) {
771 DBG_WARNING("dcerpc_svcctl_DeleteService "
772 "failed: %s\n", nt_errstr(status));
775 if (!W_ERROR_IS_OK(werr)) {
776 DBG_WARNING("dcerpc_svcctl_DeleteService "
777 "failed: %s\n", win_errstr(werr));
778 status = werror_to_ntstatus(werr);
784 NTSTATUS close_status;
787 close_status = dcerpc_svcctl_CloseServiceHandle(
788 rpccli->binding_handle,
792 if (!NT_STATUS_IS_OK(close_status)) {
793 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
794 "failed: %s\n", nt_errstr(close_status));
797 if (!W_ERROR_IS_OK(close_werr)) {
798 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
799 " failed: %s\n", win_errstr(close_werr));
806 NTSTATUS close_status;
809 close_status = dcerpc_svcctl_CloseServiceHandle(
810 rpccli->binding_handle,
814 if (!NT_STATUS_IS_OK(close_status)) {
815 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
816 "failed: %s\n", nt_errstr(close_status));
819 if (!W_ERROR_IS_OK(close_werr)) {
820 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
821 " failed: %s\n", win_errstr(close_werr));
832 struct winexe_out_pipe_state {
833 struct tevent_context *ev;
834 struct cli_state *cli;
840 static void winexe_out_pipe_opened(struct tevent_req *subreq);
841 static void winexe_out_pipe_got_data(struct tevent_req *subreq);
842 static void winexe_out_pipe_closed(struct tevent_req *subreq);
844 static struct tevent_req *winexe_out_pipe_send(
846 struct tevent_context *ev,
847 struct cli_state *cli,
848 const char *pipe_name,
851 struct tevent_req *req, *subreq;
852 struct winexe_out_pipe_state *state;
854 req = tevent_req_create(mem_ctx, &state,
855 struct winexe_out_pipe_state);
861 state->out_fd = out_fd;
863 subreq = cli_ntcreate_send(
869 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
870 SEC_RIGHTS_FILE_EXECUTE,
871 0, /* FileAttributes */
872 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
873 FILE_OPEN, /* CreateDisposition */
874 0, /* CreateOptions */
875 SMB2_IMPERSONATION_IMPERSONATION,
876 0); /* SecurityFlags */
877 if (tevent_req_nomem(subreq, req)) {
878 return tevent_req_post(req, ev);
880 tevent_req_set_callback(subreq, winexe_out_pipe_opened, req);
884 static void winexe_out_pipe_opened(struct tevent_req *subreq)
886 struct tevent_req *req = tevent_req_callback_data(
887 subreq, struct tevent_req);
888 struct winexe_out_pipe_state *state = tevent_req_data(
889 req, struct winexe_out_pipe_state);
893 status = cli_ntcreate_recv(subreq, &state->out_pipe, NULL);
895 if (tevent_req_nterror(req, status)) {
899 timeout = state->cli->timeout;
900 state->cli->timeout = 0;
902 subreq = cli_read_send(
909 sizeof(state->out_inbuf));
911 state->cli->timeout = timeout;
913 if (tevent_req_nomem(subreq, req)) {
916 tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
919 static void winexe_out_pipe_got_data(struct tevent_req *subreq)
921 struct tevent_req *req = tevent_req_callback_data(
922 subreq, struct tevent_req);
923 struct winexe_out_pipe_state *state = tevent_req_data(
924 req, struct winexe_out_pipe_state);
930 status = cli_read_recv(subreq, &received);
933 DBG_DEBUG("cli_read for %d gave %s\n",
937 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
938 subreq = cli_close_send(
943 if (tevent_req_nomem(subreq, req)) {
946 tevent_req_set_callback(subreq, winexe_out_pipe_closed, req);
950 if (tevent_req_nterror(req, status)) {
955 written = sys_write(state->out_fd, state->out_inbuf, received);
957 tevent_req_nterror(req, map_nt_error_from_unix(errno));
962 timeout = state->cli->timeout;
963 state->cli->timeout = 0;
965 subreq = cli_read_send(
972 sizeof(state->out_inbuf));
974 state->cli->timeout = timeout;
976 if (tevent_req_nomem(subreq, req)) {
979 tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
982 static void winexe_out_pipe_closed(struct tevent_req *subreq)
984 struct tevent_req *req = tevent_req_callback_data(
985 subreq, struct tevent_req);
988 status = cli_close_recv(subreq);
990 if (tevent_req_nterror(req, status)) {
993 tevent_req_done(req);
996 static NTSTATUS winexe_out_pipe_recv(struct tevent_req *req)
998 return tevent_req_simple_recv_ntstatus(req);
1001 struct winexe_in_pipe_state {
1002 struct tevent_context *ev;
1003 struct cli_state *cli;
1004 struct tevent_req *fd_read_req;
1005 bool close_requested;
1012 static void winexe_in_pipe_opened(struct tevent_req *subreq);
1013 static void winexe_in_pipe_got_data(struct tevent_req *subreq);
1014 static void winexe_in_pipe_written(struct tevent_req *subreq);
1015 static void winexe_in_pipe_closed(struct tevent_req *subreq);
1017 static struct tevent_req *winexe_in_pipe_send(
1018 TALLOC_CTX *mem_ctx,
1019 struct tevent_context *ev,
1020 struct cli_state *cli,
1021 const char *pipe_name,
1024 struct tevent_req *req, *subreq;
1025 struct winexe_in_pipe_state *state;
1027 req = tevent_req_create(mem_ctx, &state,
1028 struct winexe_in_pipe_state);
1034 state->in_fd = in_fd;
1036 subreq = cli_ntcreate_send(
1042 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
1043 SEC_RIGHTS_FILE_EXECUTE,
1044 0, /* FileAttributes */
1045 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1046 FILE_OPEN, /* CreateDisposition */
1047 0, /* CreateOptions */
1048 SMB2_IMPERSONATION_IMPERSONATION,
1049 0); /* SecurityFlags */
1050 if (tevent_req_nomem(subreq, req)) {
1051 return tevent_req_post(req, ev);
1053 tevent_req_set_callback(subreq, winexe_in_pipe_opened, req);
1057 static void winexe_in_pipe_opened(struct tevent_req *subreq)
1059 struct tevent_req *req = tevent_req_callback_data(
1060 subreq, struct tevent_req);
1061 struct winexe_in_pipe_state *state = tevent_req_data(
1062 req, struct winexe_in_pipe_state);
1065 status = cli_ntcreate_recv(subreq, &state->in_pipe, NULL);
1066 TALLOC_FREE(subreq);
1067 if (tevent_req_nterror(req, status)) {
1071 subreq = wait_for_read_send(
1076 if (tevent_req_nomem(subreq, req)) {
1079 tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
1081 state->fd_read_req = subreq;
1084 static void winexe_in_pipe_got_data(struct tevent_req *subreq)
1086 struct tevent_req *req = tevent_req_callback_data(
1087 subreq, struct tevent_req);
1088 struct winexe_in_pipe_state *state = tevent_req_data(
1089 req, struct winexe_in_pipe_state);
1095 ok = wait_for_read_recv(subreq, &err);
1096 TALLOC_FREE(subreq);
1098 tevent_req_nterror(req, map_nt_error_from_unix(err));
1101 state->fd_read_req = NULL;
1103 nread = sys_read(state->in_fd, &state->inbuf, sizeof(state->inbuf));
1105 tevent_req_nterror(req, map_nt_error_from_unix(errno));
1109 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
1113 timeout = state->cli->timeout;
1114 state->cli->timeout = 0;
1116 subreq = cli_writeall_send(
1122 (uint8_t *)state->inbuf,
1126 state->cli->timeout = timeout;
1128 if (tevent_req_nomem(subreq, req)) {
1131 tevent_req_set_callback(subreq, winexe_in_pipe_written, req);
1134 static void winexe_in_pipe_written(struct tevent_req *subreq)
1136 struct tevent_req *req = tevent_req_callback_data(
1137 subreq, struct tevent_req);
1138 struct winexe_in_pipe_state *state = tevent_req_data(
1139 req, struct winexe_in_pipe_state);
1142 status = cli_writeall_recv(subreq, NULL);
1143 TALLOC_FREE(subreq);
1145 DBG_DEBUG("cli_writeall for %d gave %s\n",
1149 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED) ||
1150 state->close_requested) {
1151 subreq = cli_close_send(
1156 if (tevent_req_nomem(subreq, req)) {
1159 tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1160 state->closing = true;
1164 if (tevent_req_nterror(req, status)) {
1168 subreq = wait_for_read_send(
1173 if (tevent_req_nomem(subreq, req)) {
1176 tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
1178 state->fd_read_req = subreq;
1181 static void winexe_in_pipe_closed(struct tevent_req *subreq)
1183 struct tevent_req *req = tevent_req_callback_data(
1184 subreq, struct tevent_req);
1187 status = cli_close_recv(subreq);
1188 TALLOC_FREE(subreq);
1189 if (tevent_req_nterror(req, status)) {
1192 return tevent_req_done(req);
1195 static NTSTATUS winexe_in_pipe_recv(struct tevent_req *req)
1197 return tevent_req_simple_recv_ntstatus(req);
1200 static bool winexe_in_pipe_close(struct tevent_req *req)
1202 struct winexe_in_pipe_state *state = tevent_req_data(
1203 req, struct winexe_in_pipe_state);
1204 struct tevent_req *subreq;
1206 if (state->closing) {
1210 if (state->fd_read_req == NULL) {
1212 * cli_writeall active, wait for it to return
1214 state->close_requested = true;
1218 TALLOC_FREE(state->fd_read_req);
1220 subreq = cli_close_send(
1225 if (subreq == NULL) {
1228 tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1229 state->closing = true;
1234 struct winexe_pipes_state {
1235 struct tevent_req *pipes[3];
1238 static void winexe_pipes_stdin_done(struct tevent_req *subreq);
1239 static void winexe_pipes_stdout_done(struct tevent_req *subreq);
1240 static void winexe_pipes_stderr_done(struct tevent_req *subreq);
1242 static struct tevent_req *winexe_pipes_send(
1243 TALLOC_CTX *mem_ctx,
1244 struct tevent_context *ev,
1245 struct cli_state *cli,
1246 const char *pipe_postfix)
1248 struct tevent_req *req;
1249 struct winexe_pipes_state *state;
1252 req = tevent_req_create(mem_ctx, &state, struct winexe_pipes_state);
1257 pipe_name = talloc_asprintf(state, "\\ahexec_stdin%s", pipe_postfix);
1258 if (tevent_req_nomem(pipe_name, req)) {
1259 return tevent_req_post(req, ev);
1261 state->pipes[0] = winexe_in_pipe_send(
1267 if (tevent_req_nomem(state->pipes[0], req)) {
1268 return tevent_req_post(req, ev);
1270 tevent_req_set_callback(state->pipes[0], winexe_pipes_stdin_done, req);
1272 pipe_name = talloc_asprintf(state, "\\ahexec_stdout%s", pipe_postfix);
1273 if (tevent_req_nomem(pipe_name, req)) {
1274 return tevent_req_post(req, ev);
1276 state->pipes[1] = winexe_out_pipe_send(
1282 if (tevent_req_nomem(state->pipes[1], req)) {
1283 return tevent_req_post(req, ev);
1285 tevent_req_set_callback(state->pipes[1], winexe_pipes_stdout_done,
1288 pipe_name = talloc_asprintf(state, "\\ahexec_stderr%s", pipe_postfix);
1289 if (tevent_req_nomem(pipe_name, req)) {
1290 return tevent_req_post(req, ev);
1292 state->pipes[2] = winexe_out_pipe_send(
1298 if (tevent_req_nomem(state->pipes[2], req)) {
1299 return tevent_req_post(req, ev);
1301 tevent_req_set_callback(state->pipes[2], winexe_pipes_stderr_done,
1304 DBG_DEBUG("pipes = %p %p %p\n",
1312 static void winexe_pipes_stdin_done(struct tevent_req *subreq)
1314 struct tevent_req *req = tevent_req_callback_data(
1315 subreq, struct tevent_req);
1316 struct winexe_pipes_state *state = tevent_req_data(
1317 req, struct winexe_pipes_state);
1320 status = winexe_in_pipe_recv(subreq);
1321 TALLOC_FREE(subreq);
1323 DBG_DEBUG("stdin returned %s\n", nt_errstr(status));
1325 if (tevent_req_nterror(req, status)) {
1329 state->pipes[0] = NULL;
1331 DBG_DEBUG("pipes = %p %p %p\n",
1336 if ((state->pipes[1] == NULL) && (state->pipes[2] == NULL)) {
1337 tevent_req_done(req);
1341 static void winexe_pipes_stdout_done(struct tevent_req *subreq)
1343 struct tevent_req *req = tevent_req_callback_data(
1344 subreq, struct tevent_req);
1345 struct winexe_pipes_state *state = tevent_req_data(
1346 req, struct winexe_pipes_state);
1349 status = winexe_out_pipe_recv(subreq);
1350 TALLOC_FREE(subreq);
1352 DBG_DEBUG("stdout returned %s\n", nt_errstr(status));
1354 if (tevent_req_nterror(req, status)) {
1358 if (state->pipes[0] != NULL) {
1359 winexe_in_pipe_close(state->pipes[0]);
1362 state->pipes[1] = NULL;
1364 DBG_DEBUG("pipes = %p %p %p\n",
1369 if ((state->pipes[0] == NULL) && (state->pipes[2] == NULL)) {
1370 tevent_req_done(req);
1374 static void winexe_pipes_stderr_done(struct tevent_req *subreq)
1376 struct tevent_req *req = tevent_req_callback_data(
1377 subreq, struct tevent_req);
1378 struct winexe_pipes_state *state = tevent_req_data(
1379 req, struct winexe_pipes_state);
1382 status = winexe_out_pipe_recv(subreq);
1383 TALLOC_FREE(subreq);
1385 DBG_DEBUG("stderr returned %s\n", nt_errstr(status));
1387 if (tevent_req_nterror(req, status)) {
1391 if (state->pipes[0] != NULL) {
1392 winexe_in_pipe_close(state->pipes[0]);
1395 state->pipes[2] = NULL;
1397 DBG_DEBUG("pipes = %p %p %p\n",
1402 if ((state->pipes[0] == NULL) && (state->pipes[1] == NULL)) {
1403 tevent_req_done(req);
1407 static NTSTATUS winexe_pipes_recv(struct tevent_req *req)
1409 return tevent_req_simple_recv_ntstatus(req);
1412 struct winexe_ctrl_state {
1413 struct tevent_context *ev;
1414 struct cli_state *cli;
1417 bool ctrl_pipe_done;
1419 char ctrl_inbuf[256];
1423 struct tevent_req *pipes_req;
1426 static void winexe_ctrl_opened(struct tevent_req *subreq);
1427 static void winexe_ctrl_got_read(struct tevent_req *subreq);
1428 static void winexe_ctrl_wrote_version(struct tevent_req *subreq);
1429 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq);
1430 static void winexe_ctrl_pipes_done(struct tevent_req *subreq);
1431 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq);
1433 static struct tevent_req *winexe_ctrl_send(
1434 TALLOC_CTX *mem_ctx,
1435 struct tevent_context *ev,
1436 struct cli_state *cli,
1439 struct tevent_req *req, *subreq;
1440 struct winexe_ctrl_state *state;
1442 req = tevent_req_create(mem_ctx, &state,
1443 struct winexe_ctrl_state);
1450 state->cmd = talloc_asprintf(state, "run %s\n", cmd);
1451 if (tevent_req_nomem(state->cmd, req)) {
1452 return tevent_req_post(req, ev);
1455 subreq = cli_ntcreate_send(
1461 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
1462 SEC_RIGHTS_FILE_EXECUTE,
1463 0, /* FileAttributes */
1464 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1465 FILE_OPEN, /* CreateDisposition */
1466 0, /* CreateOptions */
1467 SMB2_IMPERSONATION_IMPERSONATION,
1468 0); /* SecurityFlags */
1469 if (tevent_req_nomem(subreq, req)) {
1470 return tevent_req_post(req, ev);
1472 tevent_req_set_callback(subreq, winexe_ctrl_opened, req);
1476 static void winexe_ctrl_opened(struct tevent_req *subreq)
1478 struct tevent_req *req = tevent_req_callback_data(
1479 subreq, struct tevent_req);
1480 struct winexe_ctrl_state *state = tevent_req_data(
1481 req, struct winexe_ctrl_state);
1484 static const char cmd[] = "get codepage\nget version\n";
1486 status = cli_ntcreate_recv(subreq, &state->ctrl_pipe, NULL);
1487 TALLOC_FREE(subreq);
1488 if (tevent_req_nterror(req, status)) {
1492 timeout = state->cli->timeout;
1493 state->cli->timeout = 0;
1495 subreq = cli_read_send(
1502 sizeof(state->ctrl_inbuf)-1);
1504 state->cli->timeout = timeout;
1506 if (tevent_req_nomem(subreq, req)) {
1509 tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1511 subreq = cli_writeall_send(
1517 (const uint8_t *)cmd,
1520 if (tevent_req_nomem(subreq, req)) {
1523 tevent_req_set_callback(subreq, winexe_ctrl_wrote_version, req);
1526 static void winexe_ctrl_got_read(struct tevent_req *subreq)
1528 struct tevent_req *req = tevent_req_callback_data(
1529 subreq, struct tevent_req);
1530 struct winexe_ctrl_state *state = tevent_req_data(
1531 req, struct winexe_ctrl_state);
1535 unsigned int version, return_code;
1538 status = cli_read_recv(subreq, &received);
1539 TALLOC_FREE(subreq);
1541 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1542 subreq = cli_close_send(
1547 if (tevent_req_nomem(subreq, req)) {
1550 tevent_req_set_callback(subreq, winexe_ctrl_pipe_closed, req);
1553 if (tevent_req_nterror(req, status)) {
1557 DBG_DEBUG("Got %zu bytes\n", received);
1559 timeout = state->cli->timeout;
1560 state->cli->timeout = 0;
1562 subreq = cli_read_send(
1569 sizeof(state->ctrl_inbuf)-1);
1571 state->cli->timeout = timeout;
1573 if (tevent_req_nomem(subreq, req)) {
1576 tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1578 ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &version);
1580 DBG_DEBUG("Got version %x\n", version);
1582 subreq = cli_writeall_send(
1588 (const uint8_t *)state->cmd,
1590 strlen(state->cmd));
1591 if (tevent_req_nomem(subreq, req)) {
1594 tevent_req_set_callback(subreq, winexe_ctrl_wrote_cmd, req);
1598 ret = strncmp(state->ctrl_inbuf, "std_io_err ", strlen("std_io_err "));
1600 char *p = state->ctrl_inbuf + 11;
1601 char *q = strchr(state->ctrl_inbuf, '\n');
1606 DBG_DEBUG("Got invalid pipe postfix\n");
1610 postfix_len = q - p;
1612 postfix = talloc_strndup(state, p, postfix_len);
1613 if (tevent_req_nomem(postfix, req)) {
1617 DBG_DEBUG("Got pipe postfix %s\n", postfix);
1619 subreq = winexe_pipes_send(
1624 if (tevent_req_nomem(subreq, req)) {
1627 tevent_req_set_callback(subreq, winexe_ctrl_pipes_done, req);
1629 state->pipes_req = subreq;
1634 ret = strncmp(state->ctrl_inbuf, "error ", strlen("error "));
1636 printf("Error: %s", state->ctrl_inbuf);
1640 ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &return_code);
1642 state->return_code = return_code;
1647 static void winexe_ctrl_wrote_version(struct tevent_req *subreq)
1649 struct tevent_req *req = tevent_req_callback_data(
1650 subreq, struct tevent_req);
1653 status = cli_writeall_recv(subreq, NULL);
1654 TALLOC_FREE(subreq);
1655 if (tevent_req_nterror(req, status)) {
1660 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq)
1662 struct tevent_req *req = tevent_req_callback_data(
1663 subreq, struct tevent_req);
1666 status = cli_writeall_recv(subreq, NULL);
1667 TALLOC_FREE(subreq);
1668 if (tevent_req_nterror(req, status)) {
1673 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq)
1675 struct tevent_req *req = tevent_req_callback_data(
1676 subreq, struct tevent_req);
1677 struct winexe_ctrl_state *state = tevent_req_data(
1678 req, struct winexe_ctrl_state);
1681 status = cli_close_recv(subreq);
1682 TALLOC_FREE(subreq);
1683 if (tevent_req_nterror(req, status)) {
1687 state->ctrl_pipe_done = true;
1688 if (state->pipes_req == NULL) {
1689 tevent_req_done(req);
1693 static void winexe_ctrl_pipes_done(struct tevent_req *subreq)
1695 struct tevent_req *req = tevent_req_callback_data(
1696 subreq, struct tevent_req);
1697 struct winexe_ctrl_state *state = tevent_req_data(
1698 req, struct winexe_ctrl_state);
1701 status = winexe_pipes_recv(subreq);
1702 TALLOC_FREE(subreq);
1703 if (tevent_req_nterror(req, status)) {
1707 state->pipes_req = NULL;
1708 if (state->ctrl_pipe_done) {
1709 tevent_req_done(req);
1713 static NTSTATUS winexe_ctrl_recv(struct tevent_req *req,
1716 struct winexe_ctrl_state *state = tevent_req_data(
1717 req, struct winexe_ctrl_state);
1720 if (tevent_req_is_nterror(req, &status)) {
1723 if (preturn_code != NULL) {
1724 *preturn_code = state->return_code;
1726 return NT_STATUS_OK;
1729 static NTSTATUS winexe_ctrl(struct cli_state *cli,
1733 struct tevent_context *ev = NULL;
1734 struct tevent_req *req = NULL;
1735 NTSTATUS status = NT_STATUS_NO_MEMORY;
1738 ev = samba_tevent_context_init(cli);
1742 req = winexe_ctrl_send(ev, ev, cli, cmd);
1746 ok = tevent_req_poll_ntstatus(req, ev, &status);
1750 status = winexe_ctrl_recv(req, preturn_code);
1757 #ifdef HAVE_WINEXE_CC_WIN32
1758 const DATA_BLOB *winexesvc32_exe_binary(void);
1761 #ifdef HAVE_WINEXE_CC_WIN64
1762 const DATA_BLOB *winexesvc64_exe_binary(void);
1765 int main(int argc, const char *argv[])
1767 TALLOC_CTX *frame = talloc_stackframe();
1768 struct program_options options = {0};
1769 struct loadparm_context *lp_ctx;
1770 struct cli_state *cli;
1771 const char *service_name = SERVICE_NAME;
1772 char *service_filename = NULL;
1773 #ifdef HAVE_WINEXE_CC_WIN32
1774 const DATA_BLOB *winexesvc32_exe = winexesvc32_exe_binary();
1776 const DATA_BLOB *winexesvc32_exe = NULL;
1778 #ifdef HAVE_WINEXE_CC_WIN64
1779 const DATA_BLOB *winexesvc64_exe = winexesvc64_exe_binary();
1781 const DATA_BLOB *winexesvc64_exe = NULL;
1785 int return_code = 0;
1787 lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
1788 if (lp_ctx == NULL) {
1789 fprintf(stderr, "loadparm_init_s3 failed\n");
1794 setup_logging("winexe", DEBUG_STDOUT);
1796 lp_load_global(get_dyn_CONFIGFILE());
1798 parse_args(argc, argv, frame, &options, lp_ctx);
1800 if (options.cmd == NULL) {
1801 fprintf(stderr, "no cmd given\n");
1805 service_filename = talloc_asprintf(frame, "%s.exe", service_name);
1806 if (service_filename == NULL) {
1807 DBG_WARNING("talloc_asprintf failed\n");
1811 status = cli_full_connection_creds(
1819 options.credentials,
1823 if (!NT_STATUS_IS_OK(status)) {
1824 DBG_WARNING("cli_full_connection_creds failed: %s\n",
1829 status = winexe_svc_install(
1836 options.credentials,
1838 if (!NT_STATUS_IS_OK(status)) {
1839 DBG_WARNING("winexe_svc_install failed: %s\n",
1844 status = winexe_ctrl(cli, options.cmd, &return_code);
1845 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1847 status = NT_STATUS_OK;
1849 if (!NT_STATUS_IS_OK(status)) {
1850 DBG_WARNING("cli_ctrl failed: %s\n",
1855 if (options.flags & SVC_UNINSTALL) {
1856 status = winexe_svc_uninstall(
1859 if (!NT_STATUS_IS_OK(status)) {
1860 DBG_WARNING("winexe_svc_uninstall failed: %s\n",