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 {
63 struct cli_credentials *credentials;
69 static void parse_args(int argc, const char *argv[],
71 struct program_options *options,
72 struct loadparm_context *lp_ctx)
76 struct cli_credentials *cred;
82 char *port_str = NULL;
84 int flag_interactive = SVC_IGNORE_INTERACTIVE;
86 int flag_reinstall = 0;
87 int flag_uninstall = 0;
91 char *opt_user = NULL;
92 char *opt_kerberos = NULL;
93 char *opt_auth_file = NULL;
94 char *opt_debuglevel = NULL;
95 struct poptOption long_options[] = {
99 .argInfo = POPT_ARG_NONE,
102 .descrip = "Display help message",
105 .longName = "version",
107 .argInfo = POPT_ARG_NONE,
108 .arg = &flag_version,
110 .descrip = "Display version number",
115 .argInfo = POPT_ARG_STRING,
118 .descrip = "Set the network username",
119 .argDescrip = "[DOMAIN/]USERNAME[%PASSWORD]",
121 .longName = "authentication-file",
123 .argInfo = POPT_ARG_STRING,
124 .arg = &opt_auth_file,
126 .descrip = "Get the credentials from a file",
127 .argDescrip = "FILE",
129 .longName = "no-pass",
131 .argInfo = POPT_ARG_NONE,
134 .descrip = "Do not ask for a password",
137 .longName = "kerberos",
139 .argInfo = POPT_ARG_STRING,
140 .arg = &opt_kerberos,
142 .descrip = "Use Kerberos",
143 .argDescrip = "[yes|no]",
145 .longName = "debuglevel",
147 .argInfo = POPT_ARG_STRING,
148 .arg = &opt_debuglevel,
150 .descrip = "Set debug level",
151 .argDescrip = "DEBUGLEVEL",
153 .longName = "uninstall",
155 .argInfo = POPT_ARG_NONE,
156 .arg = &flag_uninstall,
158 .descrip = "Uninstall winexe service after "
162 .longName = "reinstall",
164 .argInfo = POPT_ARG_NONE,
165 .arg = &flag_reinstall,
167 .descrip = "Reinstall winexe service before "
173 .argInfo = POPT_ARG_STRING,
174 .arg = &options->runas,
176 .descrip = "Run as the given user (BEWARE: this "
177 "password is sent in cleartext over "
179 .argDescrip = "[DOMAIN\\]USERNAME%PASSWORD",
181 .longName = "runas-file",
183 .argInfo = POPT_ARG_STRING,
184 .arg = &options->runas_file,
186 .descrip = "Run as user options defined in a file",
187 .argDescrip = "FILE",
189 .longName = "interactive",
191 .argInfo = POPT_ARG_INT,
192 .arg = &flag_interactive,
194 .descrip = "Desktop interaction: 0 - disallow, "
195 "1 - allow. If allow, also use the "
196 "--system switch (Windows requirement). "
197 "Vista does not support this option.",
200 .longName = "ostype",
202 .argInfo = POPT_ARG_INT,
205 .descrip = "OS type: 0 - 32-bit, 1 - 64-bit, "
206 "2 - winexe will decide. "
207 "Determines which version (32-bit or 64-bit)"
208 " of service will be installed.",
209 .argDescrip = "0|1|2",
214 ZERO_STRUCTP(options);
216 pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,
219 poptSetOtherOptionHelp(pc, "[OPTION]... //HOST[:PORT] COMMAND\nOptions:");
221 if (((opt = poptGetNextOpt(pc)) != -1) || flag_help || flag_version) {
222 fprintf(stderr, version_message_fmt, SAMBA_VERSION_MAJOR,
223 SAMBA_VERSION_MINOR);
227 poptPrintHelp(pc, stdout, 0);
234 argv_new = discard_const_p(char *, poptGetArgs(pc));
237 for (i = 0; i < argc; i++) {
238 if (!argv_new || argv_new[i] == NULL) {
244 if (argc_new != 2 || argv_new[0][0] != '/' || argv_new[0][1] != '/') {
245 fprintf(stderr, version_message_fmt, SAMBA_VERSION_MAJOR,
246 SAMBA_VERSION_MINOR);
247 poptPrintHelp(pc, stdout, 0);
251 port_str = strchr(argv_new[0], ':');
253 if (sscanf(port_str + 1, "%d", &port) != 1 || port <= 0) {
254 fprintf(stderr, version_message_fmt,
255 SAMBA_VERSION_MAJOR, SAMBA_VERSION_MINOR);
256 poptPrintHelp(pc, stdout, 0);
262 if (opt_debuglevel) {
263 lp_set_cmdline("log level", opt_debuglevel);
266 cred = cli_credentials_init(mem_ctx);
269 cli_credentials_parse_string(cred, opt_user, CRED_SPECIFIED);
270 } else if (opt_auth_file) {
271 cli_credentials_parse_file(cred, opt_auth_file,
275 cli_credentials_guess(cred, lp_ctx);
276 if (!cli_credentials_get_password(cred) && !flag_nopass) {
277 char *p = getpass("Enter password: ");
279 cli_credentials_set_password(cred, p, CRED_SPECIFIED);
284 cli_credentials_set_kerberos_state(cred,
285 strcmp(opt_kerberos, "yes")
286 ? CRED_MUST_USE_KERBEROS
287 : CRED_DONT_USE_KERBEROS);
290 if (options->runas == NULL && options->runas_file != NULL) {
291 struct cli_credentials *runas_cred;
295 runas_cred = cli_credentials_init(mem_ctx);
296 cli_credentials_parse_file(runas_cred, options->runas_file,
299 user = cli_credentials_get_username(runas_cred);
300 pass = cli_credentials_get_password(runas_cred);
306 dom = cli_credentials_get_domain(runas_cred);
308 snprintf(buffer, sizeof(buffer), "%s\\%s%%%s",
311 snprintf(buffer, sizeof(buffer), "%s%%%s",
314 buffer[sizeof(buffer)-1] = '\0';
315 options->runas = talloc_strdup(mem_ctx, buffer);
319 options->credentials = cred;
321 options->hostname = argv_new[0] + 2;
322 options->port = port;
323 options->cmd = argv_new[1];
325 options->flags = flag_interactive;
326 if (flag_reinstall) {
327 options->flags |= SVC_FORCE_UPLOAD;
329 if (flag_ostype == 1) {
330 options->flags |= SVC_OS64BIT;
332 if (flag_ostype == 2) {
333 options->flags |= SVC_OSCHOOSE;
335 if (flag_uninstall) {
336 options->flags |= SVC_UNINSTALL;
340 static NTSTATUS winexe_svc_upload(
341 const char *hostname,
343 const char *service_filename,
344 const DATA_BLOB *svc32_exe,
345 const DATA_BLOB *svc64_exe,
346 struct cli_credentials *credentials,
349 struct cli_state *cli;
352 const DATA_BLOB *binary = NULL;
354 status = cli_full_connection_creds(
365 if (!NT_STATUS_IS_OK(status)) {
366 DBG_WARNING("cli_full_connection_creds failed: %s\n",
371 if (flags & SVC_FORCE_UPLOAD) {
372 status = cli_unlink(cli, service_filename, 0);
373 if (!NT_STATUS_IS_OK(status)) {
374 DBG_WARNING("cli_unlink failed: %s\n",
379 if (flags & SVC_OSCHOOSE) {
380 status = cli_chkpath(cli, "SysWoW64");
381 if (NT_STATUS_IS_OK(status)) {
382 flags |= SVC_OS64BIT;
386 if (flags & SVC_OS64BIT) {
392 if (binary == NULL) {
396 status = cli_ntcreate(
400 SEC_FILE_WRITE_DATA, /* DesiredAccess */
401 FILE_ATTRIBUTE_NORMAL, /* FileAttributes */
402 FILE_SHARE_WRITE|FILE_SHARE_READ, /* ShareAccess */
403 FILE_OPEN_IF, /* CreateDisposition */
404 FILE_NON_DIRECTORY_FILE, /* CreateOptions */
405 0, /* SecurityFlags */
407 NULL); /* CreateReturns */
408 if (!NT_STATUS_IS_OK(status)) {
409 DBG_WARNING("Could not create %s: %s\n", service_filename,
414 status = cli_writeall(
422 if (!NT_STATUS_IS_OK(status)) {
423 DBG_WARNING("Could not write file: %s\n", nt_errstr(status));
428 status = cli_close(cli, fnum);
429 if (!NT_STATUS_IS_OK(status)) {
430 DBG_WARNING("Close(%"PRIu16") failed for %s: %s\n", fnum,
431 service_filename, nt_errstr(status));
438 static NTSTATUS winexe_svc_install(
439 struct cli_state *cli,
440 const char *hostname,
442 const char *service_name,
443 const char *service_filename,
444 const DATA_BLOB *svc32_exe,
445 const DATA_BLOB *svc64_exe,
446 struct cli_credentials *credentials,
449 TALLOC_CTX *frame = talloc_stackframe();
450 struct rpc_pipe_client *rpccli;
451 struct policy_handle scmanager_handle;
452 struct policy_handle service_handle;
453 struct SERVICE_STATUS service_status;
454 bool need_start = false;
455 bool need_conf = false;
459 status = cli_rpc_pipe_open_noauth_transport(
464 if (!NT_STATUS_IS_OK(status)) {
465 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
470 status = dcerpc_svcctl_OpenSCManagerW(
471 rpccli->binding_handle,
473 smbXcli_conn_remote_name(cli->conn),
475 SEC_FLAG_MAXIMUM_ALLOWED,
478 if (!NT_STATUS_IS_OK(status)) {
479 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
483 if (!W_ERROR_IS_OK(werr)) {
484 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
489 status = dcerpc_svcctl_OpenServiceW(
490 rpccli->binding_handle,
497 if (!NT_STATUS_IS_OK(status)) {
498 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
500 goto close_scmanager;
503 if (W_ERROR_EQUAL(werr, WERR_SERVICE_DOES_NOT_EXIST)) {
504 status = dcerpc_svcctl_CreateServiceW(
505 rpccli->binding_handle,
511 SERVICE_TYPE_WIN32_OWN_PROCESS |
512 ((flags & SVC_INTERACTIVE) ?
513 SERVICE_TYPE_INTERACTIVE_PROCESS : 0),
515 SVCCTL_SVC_ERROR_NORMAL,
526 if (!NT_STATUS_IS_OK(status)) {
527 DBG_WARNING("dcerpc_svcctl_CreateServiceW "
528 "failed: %s\n", nt_errstr(status));
529 goto close_scmanager;
531 if (!W_ERROR_IS_OK(werr)) {
532 DBG_WARNING("dcerpc_svcctl_CreateServiceW "
533 "failed: %s\n", win_errstr(werr));
534 status = werror_to_ntstatus(werr);
535 goto close_scmanager;
539 status = dcerpc_svcctl_QueryServiceStatus(
540 rpccli->binding_handle,
546 if (!NT_STATUS_IS_OK(status)) {
547 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
548 "failed: %s\n", nt_errstr(status));
551 if (!W_ERROR_IS_OK(werr)) {
552 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
553 "failed: %s\n", win_errstr(werr));
554 status = werror_to_ntstatus(werr);
558 if (!(flags & SVC_IGNORE_INTERACTIVE)) {
560 !(service_status.type &
561 SERVICE_TYPE_INTERACTIVE_PROCESS) ^
562 !(flags & SVC_INTERACTIVE);
565 if (service_status.state == SVCCTL_STOPPED) {
567 } else if (need_conf) {
568 status = dcerpc_svcctl_ControlService(
569 rpccli->binding_handle,
576 if (!NT_STATUS_IS_OK(status)) {
577 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
578 "failed: %s\n", nt_errstr(status));
581 if (!W_ERROR_IS_OK(werr)) {
582 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
583 "failed: %s\n", win_errstr(werr));
584 status = werror_to_ntstatus(werr);
591 status = dcerpc_svcctl_QueryServiceStatus(
592 rpccli->binding_handle,
598 if (!NT_STATUS_IS_OK(status)) {
599 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
600 "failed: %s\n", nt_errstr(status));
603 if (!W_ERROR_IS_OK(werr)) {
604 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
605 "failed: %s\n", win_errstr(werr));
606 status = werror_to_ntstatus(werr);
609 } while (service_status.state == SVCCTL_STOP_PENDING);
615 status = dcerpc_svcctl_ChangeServiceConfigW(
616 rpccli->binding_handle,
619 SERVICE_TYPE_WIN32_OWN_PROCESS |
620 ((flags & SVC_INTERACTIVE) ?
621 SERVICE_TYPE_INTERACTIVE_PROCESS : 0), /* type */
622 UINT32_MAX, /* start_type, SERVICE_NO_CHANGE */
623 UINT32_MAX, /* error_control, SERVICE_NO_CHANGE */
624 NULL, /* binary_path */
625 NULL, /* load_order_group */
627 NULL, /* dependencies */
628 0, /* dwDependSize */
629 NULL, /* service_start_name */
632 NULL, /* display_name */
635 if (!NT_STATUS_IS_OK(status)) {
636 DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
637 "failed: %s\n", nt_errstr(status));
640 if (!W_ERROR_IS_OK(werr)) {
641 DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
642 "failed: %s\n", win_errstr(werr));
643 status = werror_to_ntstatus(werr);
649 status = winexe_svc_upload(
657 if (!NT_STATUS_IS_OK(status)) {
658 DBG_WARNING("winexe_svc_upload failed: %s\n",
663 status = dcerpc_svcctl_StartServiceW(
664 rpccli->binding_handle,
668 NULL, /* arguments */
671 if (!NT_STATUS_IS_OK(status)) {
672 DBG_WARNING("dcerpc_svcctl_StartServiceW "
673 "failed: %s\n", nt_errstr(status));
676 if (!W_ERROR_IS_OK(werr)) {
677 DBG_WARNING("dcerpc_svcctl_StartServiceW "
678 "failed: %s\n", win_errstr(werr));
679 status = werror_to_ntstatus(werr);
686 status = dcerpc_svcctl_QueryServiceStatus(
687 rpccli->binding_handle,
693 if (!NT_STATUS_IS_OK(status)) {
694 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
695 "failed: %s\n", nt_errstr(status));
698 if (!W_ERROR_IS_OK(werr)) {
699 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
700 "failed: %s\n", win_errstr(werr));
701 status = werror_to_ntstatus(werr);
704 } while (service_status.state == SVCCTL_START_PENDING);
706 if (service_status.state != SVCCTL_RUNNING) {
707 DBG_WARNING("Failed to start service\n");
708 status = NT_STATUS_UNSUCCESSFUL;
715 NTSTATUS close_status;
718 close_status = dcerpc_svcctl_CloseServiceHandle(
719 rpccli->binding_handle,
723 if (!NT_STATUS_IS_OK(close_status)) {
724 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
725 "failed: %s\n", nt_errstr(close_status));
728 if (!W_ERROR_IS_OK(close_werr)) {
729 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
730 " failed: %s\n", win_errstr(close_werr));
737 NTSTATUS close_status;
740 close_status = dcerpc_svcctl_CloseServiceHandle(
741 rpccli->binding_handle,
745 if (!NT_STATUS_IS_OK(close_status)) {
746 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
747 "failed: %s\n", nt_errstr(close_status));
750 if (!W_ERROR_IS_OK(close_werr)) {
751 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
752 " failed: %s\n", win_errstr(close_werr));
763 static NTSTATUS winexe_svc_uninstall(
764 struct cli_state *cli,
765 const char *service_name)
767 TALLOC_CTX *frame = talloc_stackframe();
768 struct rpc_pipe_client *rpccli;
769 struct policy_handle scmanager_handle;
770 struct policy_handle service_handle;
771 struct SERVICE_STATUS service_status;
775 status = cli_rpc_pipe_open_noauth_transport(
780 if (!NT_STATUS_IS_OK(status)) {
781 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
786 status = dcerpc_svcctl_OpenSCManagerW(
787 rpccli->binding_handle,
789 smbXcli_conn_remote_name(cli->conn),
791 SEC_FLAG_MAXIMUM_ALLOWED,
794 if (!NT_STATUS_IS_OK(status)) {
795 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
799 if (!W_ERROR_IS_OK(werr)) {
800 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
805 status = dcerpc_svcctl_OpenServiceW(
806 rpccli->binding_handle,
813 if (!NT_STATUS_IS_OK(status)) {
814 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
816 goto close_scmanager;
818 if (!W_ERROR_IS_OK(werr)) {
819 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
821 status = werror_to_ntstatus(werr);
822 goto close_scmanager;
825 status = dcerpc_svcctl_ControlService(
826 rpccli->binding_handle,
832 if (!NT_STATUS_IS_OK(status)) {
833 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
834 "failed: %s\n", nt_errstr(status));
837 if (!W_ERROR_IS_OK(werr)) {
838 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
839 "failed: %s\n", win_errstr(werr));
840 status = werror_to_ntstatus(werr);
847 status = dcerpc_svcctl_QueryServiceStatus(
848 rpccli->binding_handle,
854 if (!NT_STATUS_IS_OK(status)) {
855 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
856 "failed: %s\n", nt_errstr(status));
859 if (!W_ERROR_IS_OK(werr)) {
860 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
861 "failed: %s\n", win_errstr(werr));
862 status = werror_to_ntstatus(werr);
865 } while (service_status.state != SVCCTL_STOPPED);
867 status = dcerpc_svcctl_DeleteService(
868 rpccli->binding_handle,
872 if (!NT_STATUS_IS_OK(status)) {
873 DBG_WARNING("dcerpc_svcctl_DeleteService "
874 "failed: %s\n", nt_errstr(status));
877 if (!W_ERROR_IS_OK(werr)) {
878 DBG_WARNING("dcerpc_svcctl_DeleteService "
879 "failed: %s\n", win_errstr(werr));
880 status = werror_to_ntstatus(werr);
886 NTSTATUS close_status;
889 close_status = dcerpc_svcctl_CloseServiceHandle(
890 rpccli->binding_handle,
894 if (!NT_STATUS_IS_OK(close_status)) {
895 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
896 "failed: %s\n", nt_errstr(close_status));
899 if (!W_ERROR_IS_OK(close_werr)) {
900 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
901 " failed: %s\n", win_errstr(close_werr));
908 NTSTATUS close_status;
911 close_status = dcerpc_svcctl_CloseServiceHandle(
912 rpccli->binding_handle,
916 if (!NT_STATUS_IS_OK(close_status)) {
917 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
918 "failed: %s\n", nt_errstr(close_status));
921 if (!W_ERROR_IS_OK(close_werr)) {
922 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
923 " failed: %s\n", win_errstr(close_werr));
934 struct winexe_out_pipe_state {
935 struct tevent_context *ev;
936 struct cli_state *cli;
942 static void winexe_out_pipe_opened(struct tevent_req *subreq);
943 static void winexe_out_pipe_got_data(struct tevent_req *subreq);
944 static void winexe_out_pipe_closed(struct tevent_req *subreq);
946 static struct tevent_req *winexe_out_pipe_send(
948 struct tevent_context *ev,
949 struct cli_state *cli,
950 const char *pipe_name,
953 struct tevent_req *req, *subreq;
954 struct winexe_out_pipe_state *state;
956 req = tevent_req_create(mem_ctx, &state,
957 struct winexe_out_pipe_state);
963 state->out_fd = out_fd;
965 subreq = cli_ntcreate_send(
971 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
972 SEC_RIGHTS_FILE_EXECUTE,
973 0, /* FileAttributes */
974 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
975 FILE_OPEN, /* CreateDisposition */
976 0, /* CreateOptions */
977 SMB2_IMPERSONATION_IMPERSONATION,
978 0); /* SecurityFlags */
979 if (tevent_req_nomem(subreq, req)) {
980 return tevent_req_post(req, ev);
982 tevent_req_set_callback(subreq, winexe_out_pipe_opened, req);
986 static void winexe_out_pipe_opened(struct tevent_req *subreq)
988 struct tevent_req *req = tevent_req_callback_data(
989 subreq, struct tevent_req);
990 struct winexe_out_pipe_state *state = tevent_req_data(
991 req, struct winexe_out_pipe_state);
995 status = cli_ntcreate_recv(subreq, &state->out_pipe, NULL);
997 if (tevent_req_nterror(req, status)) {
1001 timeout = state->cli->timeout;
1002 state->cli->timeout = 0;
1004 subreq = cli_read_send(
1011 sizeof(state->out_inbuf));
1013 state->cli->timeout = timeout;
1015 if (tevent_req_nomem(subreq, req)) {
1018 tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
1021 static void winexe_out_pipe_got_data(struct tevent_req *subreq)
1023 struct tevent_req *req = tevent_req_callback_data(
1024 subreq, struct tevent_req);
1025 struct winexe_out_pipe_state *state = tevent_req_data(
1026 req, struct winexe_out_pipe_state);
1032 status = cli_read_recv(subreq, &received);
1033 TALLOC_FREE(subreq);
1035 DBG_DEBUG("cli_read for %d gave %s\n",
1039 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1040 subreq = cli_close_send(
1045 if (tevent_req_nomem(subreq, req)) {
1048 tevent_req_set_callback(subreq, winexe_out_pipe_closed, req);
1052 if (tevent_req_nterror(req, status)) {
1057 written = sys_write(state->out_fd, state->out_inbuf, received);
1058 if (written == -1) {
1059 tevent_req_nterror(req, map_nt_error_from_unix(errno));
1064 timeout = state->cli->timeout;
1065 state->cli->timeout = 0;
1067 subreq = cli_read_send(
1074 sizeof(state->out_inbuf));
1076 state->cli->timeout = timeout;
1078 if (tevent_req_nomem(subreq, req)) {
1081 tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
1084 static void winexe_out_pipe_closed(struct tevent_req *subreq)
1086 struct tevent_req *req = tevent_req_callback_data(
1087 subreq, struct tevent_req);
1090 status = cli_close_recv(subreq);
1091 TALLOC_FREE(subreq);
1092 if (tevent_req_nterror(req, status)) {
1095 tevent_req_done(req);
1098 static NTSTATUS winexe_out_pipe_recv(struct tevent_req *req)
1100 return tevent_req_simple_recv_ntstatus(req);
1103 struct winexe_in_pipe_state {
1104 struct tevent_context *ev;
1105 struct cli_state *cli;
1106 struct tevent_req *fd_read_req;
1107 bool close_requested;
1114 static void winexe_in_pipe_opened(struct tevent_req *subreq);
1115 static void winexe_in_pipe_got_data(struct tevent_req *subreq);
1116 static void winexe_in_pipe_written(struct tevent_req *subreq);
1117 static void winexe_in_pipe_closed(struct tevent_req *subreq);
1119 static struct tevent_req *winexe_in_pipe_send(
1120 TALLOC_CTX *mem_ctx,
1121 struct tevent_context *ev,
1122 struct cli_state *cli,
1123 const char *pipe_name,
1126 struct tevent_req *req, *subreq;
1127 struct winexe_in_pipe_state *state;
1129 req = tevent_req_create(mem_ctx, &state,
1130 struct winexe_in_pipe_state);
1136 state->in_fd = in_fd;
1138 subreq = cli_ntcreate_send(
1144 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
1145 SEC_RIGHTS_FILE_EXECUTE,
1146 0, /* FileAttributes */
1147 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1148 FILE_OPEN, /* CreateDisposition */
1149 0, /* CreateOptions */
1150 SMB2_IMPERSONATION_IMPERSONATION,
1151 0); /* SecurityFlags */
1152 if (tevent_req_nomem(subreq, req)) {
1153 return tevent_req_post(req, ev);
1155 tevent_req_set_callback(subreq, winexe_in_pipe_opened, req);
1159 static void winexe_in_pipe_opened(struct tevent_req *subreq)
1161 struct tevent_req *req = tevent_req_callback_data(
1162 subreq, struct tevent_req);
1163 struct winexe_in_pipe_state *state = tevent_req_data(
1164 req, struct winexe_in_pipe_state);
1167 status = cli_ntcreate_recv(subreq, &state->in_pipe, NULL);
1168 TALLOC_FREE(subreq);
1169 if (tevent_req_nterror(req, status)) {
1173 subreq = wait_for_read_send(
1178 if (tevent_req_nomem(subreq, req)) {
1181 tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
1183 state->fd_read_req = subreq;
1186 static void winexe_in_pipe_got_data(struct tevent_req *subreq)
1188 struct tevent_req *req = tevent_req_callback_data(
1189 subreq, struct tevent_req);
1190 struct winexe_in_pipe_state *state = tevent_req_data(
1191 req, struct winexe_in_pipe_state);
1197 ok = wait_for_read_recv(subreq, &err);
1198 TALLOC_FREE(subreq);
1200 tevent_req_nterror(req, map_nt_error_from_unix(err));
1203 state->fd_read_req = NULL;
1205 nread = sys_read(state->in_fd, &state->inbuf, sizeof(state->inbuf));
1207 tevent_req_nterror(req, map_nt_error_from_unix(errno));
1211 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
1215 timeout = state->cli->timeout;
1216 state->cli->timeout = 0;
1218 subreq = cli_writeall_send(
1224 (uint8_t *)state->inbuf,
1228 state->cli->timeout = timeout;
1230 if (tevent_req_nomem(subreq, req)) {
1233 tevent_req_set_callback(subreq, winexe_in_pipe_written, req);
1236 static void winexe_in_pipe_written(struct tevent_req *subreq)
1238 struct tevent_req *req = tevent_req_callback_data(
1239 subreq, struct tevent_req);
1240 struct winexe_in_pipe_state *state = tevent_req_data(
1241 req, struct winexe_in_pipe_state);
1244 status = cli_writeall_recv(subreq, NULL);
1245 TALLOC_FREE(subreq);
1247 DBG_DEBUG("cli_writeall for %d gave %s\n",
1251 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED) ||
1252 state->close_requested) {
1253 subreq = cli_close_send(
1258 if (tevent_req_nomem(subreq, req)) {
1261 tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1262 state->closing = true;
1266 if (tevent_req_nterror(req, status)) {
1270 subreq = wait_for_read_send(
1275 if (tevent_req_nomem(subreq, req)) {
1278 tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
1280 state->fd_read_req = subreq;
1283 static void winexe_in_pipe_closed(struct tevent_req *subreq)
1285 struct tevent_req *req = tevent_req_callback_data(
1286 subreq, struct tevent_req);
1289 status = cli_close_recv(subreq);
1290 TALLOC_FREE(subreq);
1291 if (tevent_req_nterror(req, status)) {
1294 return tevent_req_done(req);
1297 static NTSTATUS winexe_in_pipe_recv(struct tevent_req *req)
1299 return tevent_req_simple_recv_ntstatus(req);
1302 static bool winexe_in_pipe_close(struct tevent_req *req)
1304 struct winexe_in_pipe_state *state = tevent_req_data(
1305 req, struct winexe_in_pipe_state);
1306 struct tevent_req *subreq;
1308 if (state->closing) {
1312 if (state->fd_read_req == NULL) {
1314 * cli_writeall active, wait for it to return
1316 state->close_requested = true;
1320 TALLOC_FREE(state->fd_read_req);
1322 subreq = cli_close_send(
1327 if (subreq == NULL) {
1330 tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1331 state->closing = true;
1336 struct winexe_pipes_state {
1337 struct tevent_req *pipes[3];
1340 static void winexe_pipes_stdin_done(struct tevent_req *subreq);
1341 static void winexe_pipes_stdout_done(struct tevent_req *subreq);
1342 static void winexe_pipes_stderr_done(struct tevent_req *subreq);
1344 static struct tevent_req *winexe_pipes_send(
1345 TALLOC_CTX *mem_ctx,
1346 struct tevent_context *ev,
1347 struct cli_state *cli,
1348 const char *pipe_postfix)
1350 struct tevent_req *req;
1351 struct winexe_pipes_state *state;
1354 req = tevent_req_create(mem_ctx, &state, struct winexe_pipes_state);
1359 pipe_name = talloc_asprintf(state, "\\ahexec_stdin%s", pipe_postfix);
1360 if (tevent_req_nomem(pipe_name, req)) {
1361 return tevent_req_post(req, ev);
1363 state->pipes[0] = winexe_in_pipe_send(
1369 if (tevent_req_nomem(state->pipes[0], req)) {
1370 return tevent_req_post(req, ev);
1372 tevent_req_set_callback(state->pipes[0], winexe_pipes_stdin_done, req);
1374 pipe_name = talloc_asprintf(state, "\\ahexec_stdout%s", pipe_postfix);
1375 if (tevent_req_nomem(pipe_name, req)) {
1376 return tevent_req_post(req, ev);
1378 state->pipes[1] = winexe_out_pipe_send(
1384 if (tevent_req_nomem(state->pipes[1], req)) {
1385 return tevent_req_post(req, ev);
1387 tevent_req_set_callback(state->pipes[1], winexe_pipes_stdout_done,
1390 pipe_name = talloc_asprintf(state, "\\ahexec_stderr%s", pipe_postfix);
1391 if (tevent_req_nomem(pipe_name, req)) {
1392 return tevent_req_post(req, ev);
1394 state->pipes[2] = winexe_out_pipe_send(
1400 if (tevent_req_nomem(state->pipes[2], req)) {
1401 return tevent_req_post(req, ev);
1403 tevent_req_set_callback(state->pipes[2], winexe_pipes_stderr_done,
1406 DBG_DEBUG("pipes = %p %p %p\n",
1414 static void winexe_pipes_stdin_done(struct tevent_req *subreq)
1416 struct tevent_req *req = tevent_req_callback_data(
1417 subreq, struct tevent_req);
1418 struct winexe_pipes_state *state = tevent_req_data(
1419 req, struct winexe_pipes_state);
1422 status = winexe_in_pipe_recv(subreq);
1423 TALLOC_FREE(subreq);
1425 DBG_DEBUG("stdin returned %s\n", nt_errstr(status));
1427 if (tevent_req_nterror(req, status)) {
1431 state->pipes[0] = NULL;
1433 DBG_DEBUG("pipes = %p %p %p\n",
1438 if ((state->pipes[1] == NULL) && (state->pipes[2] == NULL)) {
1439 tevent_req_done(req);
1443 static void winexe_pipes_stdout_done(struct tevent_req *subreq)
1445 struct tevent_req *req = tevent_req_callback_data(
1446 subreq, struct tevent_req);
1447 struct winexe_pipes_state *state = tevent_req_data(
1448 req, struct winexe_pipes_state);
1451 status = winexe_out_pipe_recv(subreq);
1452 TALLOC_FREE(subreq);
1454 DBG_DEBUG("stdout returned %s\n", nt_errstr(status));
1456 if (tevent_req_nterror(req, status)) {
1460 if (state->pipes[0] != NULL) {
1461 winexe_in_pipe_close(state->pipes[0]);
1464 state->pipes[1] = NULL;
1466 DBG_DEBUG("pipes = %p %p %p\n",
1471 if ((state->pipes[0] == NULL) && (state->pipes[2] == NULL)) {
1472 tevent_req_done(req);
1476 static void winexe_pipes_stderr_done(struct tevent_req *subreq)
1478 struct tevent_req *req = tevent_req_callback_data(
1479 subreq, struct tevent_req);
1480 struct winexe_pipes_state *state = tevent_req_data(
1481 req, struct winexe_pipes_state);
1484 status = winexe_out_pipe_recv(subreq);
1485 TALLOC_FREE(subreq);
1487 DBG_DEBUG("stderr returned %s\n", nt_errstr(status));
1489 if (tevent_req_nterror(req, status)) {
1493 if (state->pipes[0] != NULL) {
1494 winexe_in_pipe_close(state->pipes[0]);
1497 state->pipes[2] = NULL;
1499 DBG_DEBUG("pipes = %p %p %p\n",
1504 if ((state->pipes[0] == NULL) && (state->pipes[1] == NULL)) {
1505 tevent_req_done(req);
1509 static NTSTATUS winexe_pipes_recv(struct tevent_req *req)
1511 return tevent_req_simple_recv_ntstatus(req);
1514 struct winexe_ctrl_state {
1515 struct tevent_context *ev;
1516 struct cli_state *cli;
1519 bool ctrl_pipe_done;
1521 char ctrl_inbuf[256];
1525 struct tevent_req *pipes_req;
1528 static void winexe_ctrl_opened(struct tevent_req *subreq);
1529 static void winexe_ctrl_got_read(struct tevent_req *subreq);
1530 static void winexe_ctrl_wrote_version(struct tevent_req *subreq);
1531 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq);
1532 static void winexe_ctrl_pipes_done(struct tevent_req *subreq);
1533 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq);
1535 static struct tevent_req *winexe_ctrl_send(
1536 TALLOC_CTX *mem_ctx,
1537 struct tevent_context *ev,
1538 struct cli_state *cli,
1541 struct tevent_req *req, *subreq;
1542 struct winexe_ctrl_state *state;
1544 req = tevent_req_create(mem_ctx, &state,
1545 struct winexe_ctrl_state);
1552 state->cmd = talloc_asprintf(state, "run %s\n", cmd);
1553 if (tevent_req_nomem(state->cmd, req)) {
1554 return tevent_req_post(req, ev);
1557 subreq = cli_ntcreate_send(
1563 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
1564 SEC_RIGHTS_FILE_EXECUTE,
1565 0, /* FileAttributes */
1566 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1567 FILE_OPEN, /* CreateDisposition */
1568 0, /* CreateOptions */
1569 SMB2_IMPERSONATION_IMPERSONATION,
1570 0); /* SecurityFlags */
1571 if (tevent_req_nomem(subreq, req)) {
1572 return tevent_req_post(req, ev);
1574 tevent_req_set_callback(subreq, winexe_ctrl_opened, req);
1578 static void winexe_ctrl_opened(struct tevent_req *subreq)
1580 struct tevent_req *req = tevent_req_callback_data(
1581 subreq, struct tevent_req);
1582 struct winexe_ctrl_state *state = tevent_req_data(
1583 req, struct winexe_ctrl_state);
1586 static const char cmd[] = "get codepage\nget version\n";
1588 status = cli_ntcreate_recv(subreq, &state->ctrl_pipe, NULL);
1589 TALLOC_FREE(subreq);
1590 if (tevent_req_nterror(req, status)) {
1594 timeout = state->cli->timeout;
1595 state->cli->timeout = 0;
1597 subreq = cli_read_send(
1604 sizeof(state->ctrl_inbuf)-1);
1606 state->cli->timeout = timeout;
1608 if (tevent_req_nomem(subreq, req)) {
1611 tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1613 subreq = cli_writeall_send(
1619 (const uint8_t *)cmd,
1622 if (tevent_req_nomem(subreq, req)) {
1625 tevent_req_set_callback(subreq, winexe_ctrl_wrote_version, req);
1628 static void winexe_ctrl_got_read(struct tevent_req *subreq)
1630 struct tevent_req *req = tevent_req_callback_data(
1631 subreq, struct tevent_req);
1632 struct winexe_ctrl_state *state = tevent_req_data(
1633 req, struct winexe_ctrl_state);
1637 unsigned int version, return_code;
1640 status = cli_read_recv(subreq, &received);
1641 TALLOC_FREE(subreq);
1643 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1644 subreq = cli_close_send(
1649 if (tevent_req_nomem(subreq, req)) {
1652 tevent_req_set_callback(subreq, winexe_ctrl_pipe_closed, req);
1655 if (tevent_req_nterror(req, status)) {
1659 DBG_DEBUG("Got %zu bytes\n", received);
1661 timeout = state->cli->timeout;
1662 state->cli->timeout = 0;
1664 subreq = cli_read_send(
1671 sizeof(state->ctrl_inbuf)-1);
1673 state->cli->timeout = timeout;
1675 if (tevent_req_nomem(subreq, req)) {
1678 tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1680 ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &version);
1682 DBG_DEBUG("Got version %x\n", version);
1684 subreq = cli_writeall_send(
1690 (const uint8_t *)state->cmd,
1692 strlen(state->cmd));
1693 if (tevent_req_nomem(subreq, req)) {
1696 tevent_req_set_callback(subreq, winexe_ctrl_wrote_cmd, req);
1700 ret = strncmp(state->ctrl_inbuf, "std_io_err ", strlen("std_io_err "));
1702 char *p = state->ctrl_inbuf + 11;
1703 char *q = strchr(state->ctrl_inbuf, '\n');
1708 DBG_DEBUG("Got invalid pipe postfix\n");
1712 postfix_len = q - p;
1714 postfix = talloc_strndup(state, p, postfix_len);
1715 if (tevent_req_nomem(postfix, req)) {
1719 DBG_DEBUG("Got pipe postfix %s\n", postfix);
1721 subreq = winexe_pipes_send(
1726 if (tevent_req_nomem(subreq, req)) {
1729 tevent_req_set_callback(subreq, winexe_ctrl_pipes_done, req);
1731 state->pipes_req = subreq;
1736 ret = strncmp(state->ctrl_inbuf, "error ", strlen("error "));
1738 printf("Error: %s", state->ctrl_inbuf);
1742 ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &return_code);
1744 state->return_code = return_code;
1749 static void winexe_ctrl_wrote_version(struct tevent_req *subreq)
1751 struct tevent_req *req = tevent_req_callback_data(
1752 subreq, struct tevent_req);
1755 status = cli_writeall_recv(subreq, NULL);
1756 TALLOC_FREE(subreq);
1757 if (tevent_req_nterror(req, status)) {
1762 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq)
1764 struct tevent_req *req = tevent_req_callback_data(
1765 subreq, struct tevent_req);
1768 status = cli_writeall_recv(subreq, NULL);
1769 TALLOC_FREE(subreq);
1770 if (tevent_req_nterror(req, status)) {
1775 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq)
1777 struct tevent_req *req = tevent_req_callback_data(
1778 subreq, struct tevent_req);
1779 struct winexe_ctrl_state *state = tevent_req_data(
1780 req, struct winexe_ctrl_state);
1783 status = cli_close_recv(subreq);
1784 TALLOC_FREE(subreq);
1785 if (tevent_req_nterror(req, status)) {
1789 state->ctrl_pipe_done = true;
1790 if (state->pipes_req == NULL) {
1791 tevent_req_done(req);
1795 static void winexe_ctrl_pipes_done(struct tevent_req *subreq)
1797 struct tevent_req *req = tevent_req_callback_data(
1798 subreq, struct tevent_req);
1799 struct winexe_ctrl_state *state = tevent_req_data(
1800 req, struct winexe_ctrl_state);
1803 status = winexe_pipes_recv(subreq);
1804 TALLOC_FREE(subreq);
1805 if (tevent_req_nterror(req, status)) {
1809 state->pipes_req = NULL;
1810 if (state->ctrl_pipe_done) {
1811 tevent_req_done(req);
1815 static NTSTATUS winexe_ctrl_recv(struct tevent_req *req,
1818 struct winexe_ctrl_state *state = tevent_req_data(
1819 req, struct winexe_ctrl_state);
1822 if (tevent_req_is_nterror(req, &status)) {
1825 if (preturn_code != NULL) {
1826 *preturn_code = state->return_code;
1828 return NT_STATUS_OK;
1831 static NTSTATUS winexe_ctrl(struct cli_state *cli,
1835 struct tevent_context *ev = NULL;
1836 struct tevent_req *req = NULL;
1837 NTSTATUS status = NT_STATUS_NO_MEMORY;
1840 ev = samba_tevent_context_init(cli);
1844 req = winexe_ctrl_send(ev, ev, cli, cmd);
1848 ok = tevent_req_poll_ntstatus(req, ev, &status);
1852 status = winexe_ctrl_recv(req, preturn_code);
1859 #ifdef HAVE_WINEXE_CC_WIN32
1860 const DATA_BLOB *winexesvc32_exe_binary(void);
1863 #ifdef HAVE_WINEXE_CC_WIN64
1864 const DATA_BLOB *winexesvc64_exe_binary(void);
1867 int main(int argc, const char *argv[])
1869 TALLOC_CTX *frame = talloc_stackframe();
1870 struct program_options options = {0};
1871 struct loadparm_context *lp_ctx;
1872 struct cli_state *cli;
1873 const char *service_name = SERVICE_NAME;
1874 char *service_filename = NULL;
1875 #ifdef HAVE_WINEXE_CC_WIN32
1876 const DATA_BLOB *winexesvc32_exe = winexesvc32_exe_binary();
1878 const DATA_BLOB *winexesvc32_exe = NULL;
1880 #ifdef HAVE_WINEXE_CC_WIN64
1881 const DATA_BLOB *winexesvc64_exe = winexesvc64_exe_binary();
1883 const DATA_BLOB *winexesvc64_exe = NULL;
1887 int return_code = 0;
1889 lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
1890 if (lp_ctx == NULL) {
1891 fprintf(stderr, "loadparm_init_s3 failed\n");
1896 setup_logging("winexe", DEBUG_STDOUT);
1898 lp_load_global(get_dyn_CONFIGFILE());
1900 parse_args(argc, argv, frame, &options, lp_ctx);
1902 if (options.cmd == NULL) {
1903 fprintf(stderr, "no cmd given\n");
1907 service_filename = talloc_asprintf(frame, "%s.exe", service_name);
1908 if (service_filename == NULL) {
1909 DBG_WARNING("talloc_asprintf failed\n");
1913 status = cli_full_connection_creds(
1921 options.credentials,
1925 if (!NT_STATUS_IS_OK(status)) {
1926 DBG_WARNING("cli_full_connection_creds failed: %s\n",
1931 status = winexe_svc_install(
1939 options.credentials,
1941 if (!NT_STATUS_IS_OK(status)) {
1942 DBG_WARNING("winexe_svc_install failed: %s\n",
1947 status = winexe_ctrl(cli, options.cmd, &return_code);
1948 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1950 status = NT_STATUS_OK;
1952 if (!NT_STATUS_IS_OK(status)) {
1953 DBG_WARNING("cli_ctrl failed: %s\n",
1958 if (options.flags & SVC_UNINSTALL) {
1959 status = winexe_svc_uninstall(
1962 if (!NT_STATUS_IS_OK(status)) {
1963 DBG_WARNING("winexe_svc_uninstall failed: %s\n",