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(
364 if (!NT_STATUS_IS_OK(status)) {
365 DBG_WARNING("cli_full_connection_creds failed: %s\n",
370 if (flags & SVC_FORCE_UPLOAD) {
371 status = cli_unlink(cli, service_filename, 0);
372 if (!NT_STATUS_IS_OK(status)) {
373 DBG_WARNING("cli_unlink failed: %s\n",
378 if (flags & SVC_OSCHOOSE) {
379 status = cli_chkpath(cli, "SysWoW64");
380 if (NT_STATUS_IS_OK(status)) {
381 flags |= SVC_OS64BIT;
385 if (flags & SVC_OS64BIT) {
391 if (binary == NULL) {
395 status = cli_ntcreate(
399 SEC_FILE_WRITE_DATA, /* DesiredAccess */
400 FILE_ATTRIBUTE_NORMAL, /* FileAttributes */
401 FILE_SHARE_WRITE|FILE_SHARE_READ, /* ShareAccess */
402 FILE_OPEN_IF, /* CreateDisposition */
403 FILE_NON_DIRECTORY_FILE, /* CreateOptions */
404 0, /* SecurityFlags */
406 NULL); /* CreateReturns */
407 if (!NT_STATUS_IS_OK(status)) {
408 DBG_WARNING("Could not create %s: %s\n", service_filename,
413 status = cli_writeall(
421 if (!NT_STATUS_IS_OK(status)) {
422 DBG_WARNING("Could not write file: %s\n", nt_errstr(status));
427 status = cli_close(cli, fnum);
428 if (!NT_STATUS_IS_OK(status)) {
429 DBG_WARNING("Close(%"PRIu16") failed for %s: %s\n", fnum,
430 service_filename, nt_errstr(status));
437 static NTSTATUS winexe_svc_install(
438 struct cli_state *cli,
439 const char *hostname,
441 const char *service_name,
442 const char *service_filename,
443 const DATA_BLOB *svc32_exe,
444 const DATA_BLOB *svc64_exe,
445 struct cli_credentials *credentials,
448 TALLOC_CTX *frame = talloc_stackframe();
449 struct rpc_pipe_client *rpccli;
450 struct policy_handle scmanager_handle;
451 struct policy_handle service_handle;
452 struct SERVICE_STATUS service_status;
453 bool need_start = false;
454 bool need_conf = false;
458 status = cli_rpc_pipe_open_noauth_transport(
463 if (!NT_STATUS_IS_OK(status)) {
464 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
469 status = dcerpc_svcctl_OpenSCManagerW(
470 rpccli->binding_handle,
472 smbXcli_conn_remote_name(cli->conn),
474 SEC_FLAG_MAXIMUM_ALLOWED,
477 if (!NT_STATUS_IS_OK(status)) {
478 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
482 if (!W_ERROR_IS_OK(werr)) {
483 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
488 status = dcerpc_svcctl_OpenServiceW(
489 rpccli->binding_handle,
496 if (!NT_STATUS_IS_OK(status)) {
497 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
499 goto close_scmanager;
502 if (W_ERROR_EQUAL(werr, WERR_SERVICE_DOES_NOT_EXIST)) {
503 status = dcerpc_svcctl_CreateServiceW(
504 rpccli->binding_handle,
510 SERVICE_TYPE_WIN32_OWN_PROCESS |
511 ((flags & SVC_INTERACTIVE) ?
512 SERVICE_TYPE_INTERACTIVE_PROCESS : 0),
514 SVCCTL_SVC_ERROR_NORMAL,
525 if (!NT_STATUS_IS_OK(status)) {
526 DBG_WARNING("dcerpc_svcctl_CreateServiceW "
527 "failed: %s\n", nt_errstr(status));
528 goto close_scmanager;
530 if (!W_ERROR_IS_OK(werr)) {
531 DBG_WARNING("dcerpc_svcctl_CreateServiceW "
532 "failed: %s\n", win_errstr(werr));
533 status = werror_to_ntstatus(werr);
534 goto close_scmanager;
538 status = dcerpc_svcctl_QueryServiceStatus(
539 rpccli->binding_handle,
545 if (!NT_STATUS_IS_OK(status)) {
546 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
547 "failed: %s\n", nt_errstr(status));
550 if (!W_ERROR_IS_OK(werr)) {
551 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
552 "failed: %s\n", win_errstr(werr));
553 status = werror_to_ntstatus(werr);
557 if (!(flags & SVC_IGNORE_INTERACTIVE)) {
559 !(service_status.type &
560 SERVICE_TYPE_INTERACTIVE_PROCESS) ^
561 !(flags & SVC_INTERACTIVE);
564 if (service_status.state == SVCCTL_STOPPED) {
566 } else if (need_conf) {
567 status = dcerpc_svcctl_ControlService(
568 rpccli->binding_handle,
575 if (!NT_STATUS_IS_OK(status)) {
576 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
577 "failed: %s\n", nt_errstr(status));
580 if (!W_ERROR_IS_OK(werr)) {
581 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
582 "failed: %s\n", win_errstr(werr));
583 status = werror_to_ntstatus(werr);
590 status = dcerpc_svcctl_QueryServiceStatus(
591 rpccli->binding_handle,
597 if (!NT_STATUS_IS_OK(status)) {
598 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
599 "failed: %s\n", nt_errstr(status));
602 if (!W_ERROR_IS_OK(werr)) {
603 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
604 "failed: %s\n", win_errstr(werr));
605 status = werror_to_ntstatus(werr);
608 } while (service_status.state == SVCCTL_STOP_PENDING);
614 status = dcerpc_svcctl_ChangeServiceConfigW(
615 rpccli->binding_handle,
618 SERVICE_TYPE_WIN32_OWN_PROCESS |
619 ((flags & SVC_INTERACTIVE) ?
620 SERVICE_TYPE_INTERACTIVE_PROCESS : 0), /* type */
621 UINT32_MAX, /* start_type, SERVICE_NO_CHANGE */
622 UINT32_MAX, /* error_control, SERVICE_NO_CHANGE */
623 NULL, /* binary_path */
624 NULL, /* load_order_group */
626 NULL, /* dependencies */
627 0, /* dwDependSize */
628 NULL, /* service_start_name */
631 NULL, /* display_name */
634 if (!NT_STATUS_IS_OK(status)) {
635 DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
636 "failed: %s\n", nt_errstr(status));
639 if (!W_ERROR_IS_OK(werr)) {
640 DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
641 "failed: %s\n", win_errstr(werr));
642 status = werror_to_ntstatus(werr);
648 status = winexe_svc_upload(
656 if (!NT_STATUS_IS_OK(status)) {
657 DBG_WARNING("winexe_svc_upload failed: %s\n",
662 status = dcerpc_svcctl_StartServiceW(
663 rpccli->binding_handle,
667 NULL, /* arguments */
670 if (!NT_STATUS_IS_OK(status)) {
671 DBG_WARNING("dcerpc_svcctl_StartServiceW "
672 "failed: %s\n", nt_errstr(status));
675 if (!W_ERROR_IS_OK(werr)) {
676 DBG_WARNING("dcerpc_svcctl_StartServiceW "
677 "failed: %s\n", win_errstr(werr));
678 status = werror_to_ntstatus(werr);
685 status = dcerpc_svcctl_QueryServiceStatus(
686 rpccli->binding_handle,
692 if (!NT_STATUS_IS_OK(status)) {
693 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
694 "failed: %s\n", nt_errstr(status));
697 if (!W_ERROR_IS_OK(werr)) {
698 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
699 "failed: %s\n", win_errstr(werr));
700 status = werror_to_ntstatus(werr);
703 } while (service_status.state == SVCCTL_START_PENDING);
705 if (service_status.state != SVCCTL_RUNNING) {
706 DBG_WARNING("Failed to start service\n");
707 status = NT_STATUS_UNSUCCESSFUL;
714 NTSTATUS close_status;
717 close_status = dcerpc_svcctl_CloseServiceHandle(
718 rpccli->binding_handle,
722 if (!NT_STATUS_IS_OK(close_status)) {
723 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
724 "failed: %s\n", nt_errstr(close_status));
727 if (!W_ERROR_IS_OK(close_werr)) {
728 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
729 " failed: %s\n", win_errstr(close_werr));
736 NTSTATUS close_status;
739 close_status = dcerpc_svcctl_CloseServiceHandle(
740 rpccli->binding_handle,
744 if (!NT_STATUS_IS_OK(close_status)) {
745 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
746 "failed: %s\n", nt_errstr(close_status));
749 if (!W_ERROR_IS_OK(close_werr)) {
750 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
751 " failed: %s\n", win_errstr(close_werr));
762 static NTSTATUS winexe_svc_uninstall(
763 struct cli_state *cli,
764 const char *service_name)
766 TALLOC_CTX *frame = talloc_stackframe();
767 struct rpc_pipe_client *rpccli;
768 struct policy_handle scmanager_handle;
769 struct policy_handle service_handle;
770 struct SERVICE_STATUS service_status;
774 status = cli_rpc_pipe_open_noauth_transport(
779 if (!NT_STATUS_IS_OK(status)) {
780 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
785 status = dcerpc_svcctl_OpenSCManagerW(
786 rpccli->binding_handle,
788 smbXcli_conn_remote_name(cli->conn),
790 SEC_FLAG_MAXIMUM_ALLOWED,
793 if (!NT_STATUS_IS_OK(status)) {
794 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
798 if (!W_ERROR_IS_OK(werr)) {
799 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
804 status = dcerpc_svcctl_OpenServiceW(
805 rpccli->binding_handle,
812 if (!NT_STATUS_IS_OK(status)) {
813 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
815 goto close_scmanager;
817 if (!W_ERROR_IS_OK(werr)) {
818 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
820 status = werror_to_ntstatus(werr);
821 goto close_scmanager;
824 status = dcerpc_svcctl_ControlService(
825 rpccli->binding_handle,
831 if (!NT_STATUS_IS_OK(status)) {
832 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
833 "failed: %s\n", nt_errstr(status));
836 if (!W_ERROR_IS_OK(werr)) {
837 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
838 "failed: %s\n", win_errstr(werr));
839 status = werror_to_ntstatus(werr);
846 status = dcerpc_svcctl_QueryServiceStatus(
847 rpccli->binding_handle,
853 if (!NT_STATUS_IS_OK(status)) {
854 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
855 "failed: %s\n", nt_errstr(status));
858 if (!W_ERROR_IS_OK(werr)) {
859 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
860 "failed: %s\n", win_errstr(werr));
861 status = werror_to_ntstatus(werr);
864 } while (service_status.state != SVCCTL_STOPPED);
866 status = dcerpc_svcctl_DeleteService(
867 rpccli->binding_handle,
871 if (!NT_STATUS_IS_OK(status)) {
872 DBG_WARNING("dcerpc_svcctl_DeleteService "
873 "failed: %s\n", nt_errstr(status));
876 if (!W_ERROR_IS_OK(werr)) {
877 DBG_WARNING("dcerpc_svcctl_DeleteService "
878 "failed: %s\n", win_errstr(werr));
879 status = werror_to_ntstatus(werr);
885 NTSTATUS close_status;
888 close_status = dcerpc_svcctl_CloseServiceHandle(
889 rpccli->binding_handle,
893 if (!NT_STATUS_IS_OK(close_status)) {
894 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
895 "failed: %s\n", nt_errstr(close_status));
898 if (!W_ERROR_IS_OK(close_werr)) {
899 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
900 " failed: %s\n", win_errstr(close_werr));
907 NTSTATUS close_status;
910 close_status = dcerpc_svcctl_CloseServiceHandle(
911 rpccli->binding_handle,
915 if (!NT_STATUS_IS_OK(close_status)) {
916 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
917 "failed: %s\n", nt_errstr(close_status));
920 if (!W_ERROR_IS_OK(close_werr)) {
921 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
922 " failed: %s\n", win_errstr(close_werr));
933 struct winexe_out_pipe_state {
934 struct tevent_context *ev;
935 struct cli_state *cli;
941 static void winexe_out_pipe_opened(struct tevent_req *subreq);
942 static void winexe_out_pipe_got_data(struct tevent_req *subreq);
943 static void winexe_out_pipe_closed(struct tevent_req *subreq);
945 static struct tevent_req *winexe_out_pipe_send(
947 struct tevent_context *ev,
948 struct cli_state *cli,
949 const char *pipe_name,
952 struct tevent_req *req, *subreq;
953 struct winexe_out_pipe_state *state;
955 req = tevent_req_create(mem_ctx, &state,
956 struct winexe_out_pipe_state);
962 state->out_fd = out_fd;
964 subreq = cli_ntcreate_send(
970 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
971 SEC_RIGHTS_FILE_EXECUTE,
972 0, /* FileAttributes */
973 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
974 FILE_OPEN, /* CreateDisposition */
975 0, /* CreateOptions */
976 SMB2_IMPERSONATION_IMPERSONATION,
977 0); /* SecurityFlags */
978 if (tevent_req_nomem(subreq, req)) {
979 return tevent_req_post(req, ev);
981 tevent_req_set_callback(subreq, winexe_out_pipe_opened, req);
985 static void winexe_out_pipe_opened(struct tevent_req *subreq)
987 struct tevent_req *req = tevent_req_callback_data(
988 subreq, struct tevent_req);
989 struct winexe_out_pipe_state *state = tevent_req_data(
990 req, struct winexe_out_pipe_state);
994 status = cli_ntcreate_recv(subreq, &state->out_pipe, NULL);
996 if (tevent_req_nterror(req, status)) {
1000 timeout = state->cli->timeout;
1001 state->cli->timeout = 0;
1003 subreq = cli_read_send(
1010 sizeof(state->out_inbuf));
1012 state->cli->timeout = timeout;
1014 if (tevent_req_nomem(subreq, req)) {
1017 tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
1020 static void winexe_out_pipe_got_data(struct tevent_req *subreq)
1022 struct tevent_req *req = tevent_req_callback_data(
1023 subreq, struct tevent_req);
1024 struct winexe_out_pipe_state *state = tevent_req_data(
1025 req, struct winexe_out_pipe_state);
1031 status = cli_read_recv(subreq, &received);
1032 TALLOC_FREE(subreq);
1034 DBG_DEBUG("cli_read for %d gave %s\n",
1038 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1039 subreq = cli_close_send(
1044 if (tevent_req_nomem(subreq, req)) {
1047 tevent_req_set_callback(subreq, winexe_out_pipe_closed, req);
1051 if (tevent_req_nterror(req, status)) {
1056 written = sys_write(state->out_fd, state->out_inbuf, received);
1057 if (written == -1) {
1058 tevent_req_nterror(req, map_nt_error_from_unix(errno));
1063 timeout = state->cli->timeout;
1064 state->cli->timeout = 0;
1066 subreq = cli_read_send(
1073 sizeof(state->out_inbuf));
1075 state->cli->timeout = timeout;
1077 if (tevent_req_nomem(subreq, req)) {
1080 tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
1083 static void winexe_out_pipe_closed(struct tevent_req *subreq)
1085 struct tevent_req *req = tevent_req_callback_data(
1086 subreq, struct tevent_req);
1089 status = cli_close_recv(subreq);
1090 TALLOC_FREE(subreq);
1091 if (tevent_req_nterror(req, status)) {
1094 tevent_req_done(req);
1097 static NTSTATUS winexe_out_pipe_recv(struct tevent_req *req)
1099 return tevent_req_simple_recv_ntstatus(req);
1102 struct winexe_in_pipe_state {
1103 struct tevent_context *ev;
1104 struct cli_state *cli;
1105 struct tevent_req *fd_read_req;
1106 bool close_requested;
1113 static void winexe_in_pipe_opened(struct tevent_req *subreq);
1114 static void winexe_in_pipe_got_data(struct tevent_req *subreq);
1115 static void winexe_in_pipe_written(struct tevent_req *subreq);
1116 static void winexe_in_pipe_closed(struct tevent_req *subreq);
1118 static struct tevent_req *winexe_in_pipe_send(
1119 TALLOC_CTX *mem_ctx,
1120 struct tevent_context *ev,
1121 struct cli_state *cli,
1122 const char *pipe_name,
1125 struct tevent_req *req, *subreq;
1126 struct winexe_in_pipe_state *state;
1128 req = tevent_req_create(mem_ctx, &state,
1129 struct winexe_in_pipe_state);
1135 state->in_fd = in_fd;
1137 subreq = cli_ntcreate_send(
1143 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
1144 SEC_RIGHTS_FILE_EXECUTE,
1145 0, /* FileAttributes */
1146 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1147 FILE_OPEN, /* CreateDisposition */
1148 0, /* CreateOptions */
1149 SMB2_IMPERSONATION_IMPERSONATION,
1150 0); /* SecurityFlags */
1151 if (tevent_req_nomem(subreq, req)) {
1152 return tevent_req_post(req, ev);
1154 tevent_req_set_callback(subreq, winexe_in_pipe_opened, req);
1158 static void winexe_in_pipe_opened(struct tevent_req *subreq)
1160 struct tevent_req *req = tevent_req_callback_data(
1161 subreq, struct tevent_req);
1162 struct winexe_in_pipe_state *state = tevent_req_data(
1163 req, struct winexe_in_pipe_state);
1166 status = cli_ntcreate_recv(subreq, &state->in_pipe, NULL);
1167 TALLOC_FREE(subreq);
1168 if (tevent_req_nterror(req, status)) {
1172 subreq = wait_for_read_send(
1177 if (tevent_req_nomem(subreq, req)) {
1180 tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
1182 state->fd_read_req = subreq;
1185 static void winexe_in_pipe_got_data(struct tevent_req *subreq)
1187 struct tevent_req *req = tevent_req_callback_data(
1188 subreq, struct tevent_req);
1189 struct winexe_in_pipe_state *state = tevent_req_data(
1190 req, struct winexe_in_pipe_state);
1196 ok = wait_for_read_recv(subreq, &err);
1197 TALLOC_FREE(subreq);
1199 tevent_req_nterror(req, map_nt_error_from_unix(err));
1202 state->fd_read_req = NULL;
1204 nread = sys_read(state->in_fd, &state->inbuf, sizeof(state->inbuf));
1206 tevent_req_nterror(req, map_nt_error_from_unix(errno));
1210 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
1214 timeout = state->cli->timeout;
1215 state->cli->timeout = 0;
1217 subreq = cli_writeall_send(
1223 (uint8_t *)state->inbuf,
1227 state->cli->timeout = timeout;
1229 if (tevent_req_nomem(subreq, req)) {
1232 tevent_req_set_callback(subreq, winexe_in_pipe_written, req);
1235 static void winexe_in_pipe_written(struct tevent_req *subreq)
1237 struct tevent_req *req = tevent_req_callback_data(
1238 subreq, struct tevent_req);
1239 struct winexe_in_pipe_state *state = tevent_req_data(
1240 req, struct winexe_in_pipe_state);
1243 status = cli_writeall_recv(subreq, NULL);
1244 TALLOC_FREE(subreq);
1246 DBG_DEBUG("cli_writeall for %d gave %s\n",
1250 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED) ||
1251 state->close_requested) {
1252 subreq = cli_close_send(
1257 if (tevent_req_nomem(subreq, req)) {
1260 tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1261 state->closing = true;
1265 if (tevent_req_nterror(req, status)) {
1269 subreq = wait_for_read_send(
1274 if (tevent_req_nomem(subreq, req)) {
1277 tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
1279 state->fd_read_req = subreq;
1282 static void winexe_in_pipe_closed(struct tevent_req *subreq)
1284 struct tevent_req *req = tevent_req_callback_data(
1285 subreq, struct tevent_req);
1288 status = cli_close_recv(subreq);
1289 TALLOC_FREE(subreq);
1290 if (tevent_req_nterror(req, status)) {
1293 return tevent_req_done(req);
1296 static NTSTATUS winexe_in_pipe_recv(struct tevent_req *req)
1298 return tevent_req_simple_recv_ntstatus(req);
1301 static bool winexe_in_pipe_close(struct tevent_req *req)
1303 struct winexe_in_pipe_state *state = tevent_req_data(
1304 req, struct winexe_in_pipe_state);
1305 struct tevent_req *subreq;
1307 if (state->closing) {
1311 if (state->fd_read_req == NULL) {
1313 * cli_writeall active, wait for it to return
1315 state->close_requested = true;
1319 TALLOC_FREE(state->fd_read_req);
1321 subreq = cli_close_send(
1326 if (subreq == NULL) {
1329 tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1330 state->closing = true;
1335 struct winexe_pipes_state {
1336 struct tevent_req *pipes[3];
1339 static void winexe_pipes_stdin_done(struct tevent_req *subreq);
1340 static void winexe_pipes_stdout_done(struct tevent_req *subreq);
1341 static void winexe_pipes_stderr_done(struct tevent_req *subreq);
1343 static struct tevent_req *winexe_pipes_send(
1344 TALLOC_CTX *mem_ctx,
1345 struct tevent_context *ev,
1346 struct cli_state *cli,
1347 const char *pipe_postfix)
1349 struct tevent_req *req;
1350 struct winexe_pipes_state *state;
1353 req = tevent_req_create(mem_ctx, &state, struct winexe_pipes_state);
1358 pipe_name = talloc_asprintf(state, "\\ahexec_stdin%s", pipe_postfix);
1359 if (tevent_req_nomem(pipe_name, req)) {
1360 return tevent_req_post(req, ev);
1362 state->pipes[0] = winexe_in_pipe_send(
1368 if (tevent_req_nomem(state->pipes[0], req)) {
1369 return tevent_req_post(req, ev);
1371 tevent_req_set_callback(state->pipes[0], winexe_pipes_stdin_done, req);
1373 pipe_name = talloc_asprintf(state, "\\ahexec_stdout%s", pipe_postfix);
1374 if (tevent_req_nomem(pipe_name, req)) {
1375 return tevent_req_post(req, ev);
1377 state->pipes[1] = winexe_out_pipe_send(
1383 if (tevent_req_nomem(state->pipes[1], req)) {
1384 return tevent_req_post(req, ev);
1386 tevent_req_set_callback(state->pipes[1], winexe_pipes_stdout_done,
1389 pipe_name = talloc_asprintf(state, "\\ahexec_stderr%s", pipe_postfix);
1390 if (tevent_req_nomem(pipe_name, req)) {
1391 return tevent_req_post(req, ev);
1393 state->pipes[2] = winexe_out_pipe_send(
1399 if (tevent_req_nomem(state->pipes[2], req)) {
1400 return tevent_req_post(req, ev);
1402 tevent_req_set_callback(state->pipes[2], winexe_pipes_stderr_done,
1405 DBG_DEBUG("pipes = %p %p %p\n",
1413 static void winexe_pipes_stdin_done(struct tevent_req *subreq)
1415 struct tevent_req *req = tevent_req_callback_data(
1416 subreq, struct tevent_req);
1417 struct winexe_pipes_state *state = tevent_req_data(
1418 req, struct winexe_pipes_state);
1421 status = winexe_in_pipe_recv(subreq);
1422 TALLOC_FREE(subreq);
1424 DBG_DEBUG("stdin returned %s\n", nt_errstr(status));
1426 if (tevent_req_nterror(req, status)) {
1430 state->pipes[0] = NULL;
1432 DBG_DEBUG("pipes = %p %p %p\n",
1437 if ((state->pipes[1] == NULL) && (state->pipes[2] == NULL)) {
1438 tevent_req_done(req);
1442 static void winexe_pipes_stdout_done(struct tevent_req *subreq)
1444 struct tevent_req *req = tevent_req_callback_data(
1445 subreq, struct tevent_req);
1446 struct winexe_pipes_state *state = tevent_req_data(
1447 req, struct winexe_pipes_state);
1450 status = winexe_out_pipe_recv(subreq);
1451 TALLOC_FREE(subreq);
1453 DBG_DEBUG("stdout returned %s\n", nt_errstr(status));
1455 if (tevent_req_nterror(req, status)) {
1459 if (state->pipes[0] != NULL) {
1460 winexe_in_pipe_close(state->pipes[0]);
1463 state->pipes[1] = NULL;
1465 DBG_DEBUG("pipes = %p %p %p\n",
1470 if ((state->pipes[0] == NULL) && (state->pipes[2] == NULL)) {
1471 tevent_req_done(req);
1475 static void winexe_pipes_stderr_done(struct tevent_req *subreq)
1477 struct tevent_req *req = tevent_req_callback_data(
1478 subreq, struct tevent_req);
1479 struct winexe_pipes_state *state = tevent_req_data(
1480 req, struct winexe_pipes_state);
1483 status = winexe_out_pipe_recv(subreq);
1484 TALLOC_FREE(subreq);
1486 DBG_DEBUG("stderr returned %s\n", nt_errstr(status));
1488 if (tevent_req_nterror(req, status)) {
1492 if (state->pipes[0] != NULL) {
1493 winexe_in_pipe_close(state->pipes[0]);
1496 state->pipes[2] = NULL;
1498 DBG_DEBUG("pipes = %p %p %p\n",
1503 if ((state->pipes[0] == NULL) && (state->pipes[1] == NULL)) {
1504 tevent_req_done(req);
1508 static NTSTATUS winexe_pipes_recv(struct tevent_req *req)
1510 return tevent_req_simple_recv_ntstatus(req);
1513 struct winexe_ctrl_state {
1514 struct tevent_context *ev;
1515 struct cli_state *cli;
1518 bool ctrl_pipe_done;
1520 char ctrl_inbuf[256];
1524 struct tevent_req *pipes_req;
1527 static void winexe_ctrl_opened(struct tevent_req *subreq);
1528 static void winexe_ctrl_got_read(struct tevent_req *subreq);
1529 static void winexe_ctrl_wrote_version(struct tevent_req *subreq);
1530 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq);
1531 static void winexe_ctrl_pipes_done(struct tevent_req *subreq);
1532 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq);
1534 static struct tevent_req *winexe_ctrl_send(
1535 TALLOC_CTX *mem_ctx,
1536 struct tevent_context *ev,
1537 struct cli_state *cli,
1540 struct tevent_req *req, *subreq;
1541 struct winexe_ctrl_state *state;
1543 req = tevent_req_create(mem_ctx, &state,
1544 struct winexe_ctrl_state);
1551 state->cmd = talloc_asprintf(state, "run %s\n", cmd);
1552 if (tevent_req_nomem(state->cmd, req)) {
1553 return tevent_req_post(req, ev);
1556 subreq = cli_ntcreate_send(
1562 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
1563 SEC_RIGHTS_FILE_EXECUTE,
1564 0, /* FileAttributes */
1565 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1566 FILE_OPEN, /* CreateDisposition */
1567 0, /* CreateOptions */
1568 SMB2_IMPERSONATION_IMPERSONATION,
1569 0); /* SecurityFlags */
1570 if (tevent_req_nomem(subreq, req)) {
1571 return tevent_req_post(req, ev);
1573 tevent_req_set_callback(subreq, winexe_ctrl_opened, req);
1577 static void winexe_ctrl_opened(struct tevent_req *subreq)
1579 struct tevent_req *req = tevent_req_callback_data(
1580 subreq, struct tevent_req);
1581 struct winexe_ctrl_state *state = tevent_req_data(
1582 req, struct winexe_ctrl_state);
1585 static const char cmd[] = "get codepage\nget version\n";
1587 status = cli_ntcreate_recv(subreq, &state->ctrl_pipe, NULL);
1588 TALLOC_FREE(subreq);
1589 if (tevent_req_nterror(req, status)) {
1593 timeout = state->cli->timeout;
1594 state->cli->timeout = 0;
1596 subreq = cli_read_send(
1603 sizeof(state->ctrl_inbuf)-1);
1605 state->cli->timeout = timeout;
1607 if (tevent_req_nomem(subreq, req)) {
1610 tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1612 subreq = cli_writeall_send(
1618 (const uint8_t *)cmd,
1621 if (tevent_req_nomem(subreq, req)) {
1624 tevent_req_set_callback(subreq, winexe_ctrl_wrote_version, req);
1627 static void winexe_ctrl_got_read(struct tevent_req *subreq)
1629 struct tevent_req *req = tevent_req_callback_data(
1630 subreq, struct tevent_req);
1631 struct winexe_ctrl_state *state = tevent_req_data(
1632 req, struct winexe_ctrl_state);
1636 unsigned int version, return_code;
1639 status = cli_read_recv(subreq, &received);
1640 TALLOC_FREE(subreq);
1642 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1643 subreq = cli_close_send(
1648 if (tevent_req_nomem(subreq, req)) {
1651 tevent_req_set_callback(subreq, winexe_ctrl_pipe_closed, req);
1654 if (tevent_req_nterror(req, status)) {
1658 DBG_DEBUG("Got %zu bytes\n", received);
1660 timeout = state->cli->timeout;
1661 state->cli->timeout = 0;
1663 subreq = cli_read_send(
1670 sizeof(state->ctrl_inbuf)-1);
1672 state->cli->timeout = timeout;
1674 if (tevent_req_nomem(subreq, req)) {
1677 tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1679 ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &version);
1681 DBG_DEBUG("Got version %x\n", version);
1683 subreq = cli_writeall_send(
1689 (const uint8_t *)state->cmd,
1691 strlen(state->cmd));
1692 if (tevent_req_nomem(subreq, req)) {
1695 tevent_req_set_callback(subreq, winexe_ctrl_wrote_cmd, req);
1699 ret = strncmp(state->ctrl_inbuf, "std_io_err ", strlen("std_io_err "));
1701 char *p = state->ctrl_inbuf + 11;
1702 char *q = strchr(state->ctrl_inbuf, '\n');
1707 DBG_DEBUG("Got invalid pipe postfix\n");
1711 postfix_len = q - p;
1713 postfix = talloc_strndup(state, p, postfix_len);
1714 if (tevent_req_nomem(postfix, req)) {
1718 DBG_DEBUG("Got pipe postfix %s\n", postfix);
1720 subreq = winexe_pipes_send(
1725 if (tevent_req_nomem(subreq, req)) {
1728 tevent_req_set_callback(subreq, winexe_ctrl_pipes_done, req);
1730 state->pipes_req = subreq;
1735 ret = strncmp(state->ctrl_inbuf, "error ", strlen("error "));
1737 printf("Error: %s", state->ctrl_inbuf);
1741 ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &return_code);
1743 state->return_code = return_code;
1748 static void winexe_ctrl_wrote_version(struct tevent_req *subreq)
1750 struct tevent_req *req = tevent_req_callback_data(
1751 subreq, struct tevent_req);
1754 status = cli_writeall_recv(subreq, NULL);
1755 TALLOC_FREE(subreq);
1756 if (tevent_req_nterror(req, status)) {
1761 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq)
1763 struct tevent_req *req = tevent_req_callback_data(
1764 subreq, struct tevent_req);
1767 status = cli_writeall_recv(subreq, NULL);
1768 TALLOC_FREE(subreq);
1769 if (tevent_req_nterror(req, status)) {
1774 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq)
1776 struct tevent_req *req = tevent_req_callback_data(
1777 subreq, struct tevent_req);
1778 struct winexe_ctrl_state *state = tevent_req_data(
1779 req, struct winexe_ctrl_state);
1782 status = cli_close_recv(subreq);
1783 TALLOC_FREE(subreq);
1784 if (tevent_req_nterror(req, status)) {
1788 state->ctrl_pipe_done = true;
1789 if (state->pipes_req == NULL) {
1790 tevent_req_done(req);
1794 static void winexe_ctrl_pipes_done(struct tevent_req *subreq)
1796 struct tevent_req *req = tevent_req_callback_data(
1797 subreq, struct tevent_req);
1798 struct winexe_ctrl_state *state = tevent_req_data(
1799 req, struct winexe_ctrl_state);
1802 status = winexe_pipes_recv(subreq);
1803 TALLOC_FREE(subreq);
1804 if (tevent_req_nterror(req, status)) {
1808 state->pipes_req = NULL;
1809 if (state->ctrl_pipe_done) {
1810 tevent_req_done(req);
1814 static NTSTATUS winexe_ctrl_recv(struct tevent_req *req,
1817 struct winexe_ctrl_state *state = tevent_req_data(
1818 req, struct winexe_ctrl_state);
1821 if (tevent_req_is_nterror(req, &status)) {
1824 if (preturn_code != NULL) {
1825 *preturn_code = state->return_code;
1827 return NT_STATUS_OK;
1830 static NTSTATUS winexe_ctrl(struct cli_state *cli,
1834 struct tevent_context *ev = NULL;
1835 struct tevent_req *req = NULL;
1836 NTSTATUS status = NT_STATUS_NO_MEMORY;
1839 ev = samba_tevent_context_init(cli);
1843 req = winexe_ctrl_send(ev, ev, cli, cmd);
1847 ok = tevent_req_poll_ntstatus(req, ev, &status);
1851 status = winexe_ctrl_recv(req, preturn_code);
1858 #ifdef HAVE_WINEXE_CC_WIN32
1859 const DATA_BLOB *winexesvc32_exe_binary(void);
1862 #ifdef HAVE_WINEXE_CC_WIN64
1863 const DATA_BLOB *winexesvc64_exe_binary(void);
1866 int main(int argc, const char *argv[])
1868 TALLOC_CTX *frame = talloc_stackframe();
1869 struct program_options options = {0};
1870 struct loadparm_context *lp_ctx;
1871 struct cli_state *cli;
1872 const char *service_name = SERVICE_NAME;
1873 char *service_filename = NULL;
1874 #ifdef HAVE_WINEXE_CC_WIN32
1875 const DATA_BLOB *winexesvc32_exe = winexesvc32_exe_binary();
1877 const DATA_BLOB *winexesvc32_exe = NULL;
1879 #ifdef HAVE_WINEXE_CC_WIN64
1880 const DATA_BLOB *winexesvc64_exe = winexesvc64_exe_binary();
1882 const DATA_BLOB *winexesvc64_exe = NULL;
1886 int return_code = 0;
1888 lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
1889 if (lp_ctx == NULL) {
1890 fprintf(stderr, "loadparm_init_s3 failed\n");
1895 setup_logging("winexe", DEBUG_STDOUT);
1897 lp_load_global(get_dyn_CONFIGFILE());
1899 parse_args(argc, argv, frame, &options, lp_ctx);
1901 if (options.cmd == NULL) {
1902 fprintf(stderr, "no cmd given\n");
1906 service_filename = talloc_asprintf(frame, "%s.exe", service_name);
1907 if (service_filename == NULL) {
1908 DBG_WARNING("talloc_asprintf failed\n");
1912 status = cli_full_connection_creds(
1920 options.credentials,
1921 CLI_FULL_CONNECTION_IPC);
1923 if (!NT_STATUS_IS_OK(status)) {
1924 DBG_WARNING("cli_full_connection_creds failed: %s\n",
1929 status = winexe_svc_install(
1937 options.credentials,
1939 if (!NT_STATUS_IS_OK(status)) {
1940 DBG_WARNING("winexe_svc_install failed: %s\n",
1945 status = winexe_ctrl(cli, options.cmd, &return_code);
1946 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1948 status = NT_STATUS_OK;
1950 if (!NT_STATUS_IS_OK(status)) {
1951 DBG_WARNING("cli_ctrl failed: %s\n",
1956 if (options.flags & SVC_UNINSTALL) {
1957 status = winexe_svc_uninstall(
1960 if (!NT_STATUS_IS_OK(status)) {
1961 DBG_WARNING("winexe_svc_uninstall failed: %s\n",