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;
91 struct poptOption long_options[] = {
95 .argInfo = POPT_ARG_NONE,
98 .descrip = "Display help message",
101 .longName = "version",
103 .argInfo = POPT_ARG_NONE,
104 .arg = &flag_version,
106 .descrip = "Display version number",
111 .argInfo = POPT_ARG_STRING,
114 .descrip = "Set the network username",
115 .argDescrip = "[DOMAIN/]USERNAME[%PASSWORD]",
117 .longName = "authentication-file",
119 .argInfo = POPT_ARG_STRING,
120 .arg = &opt_auth_file,
122 .descrip = "Get the credentials from a file",
123 .argDescrip = "FILE",
125 .longName = "no-pass",
127 .argInfo = POPT_ARG_NONE,
130 .descrip = "Do not ask for a password",
133 .longName = "kerberos",
135 .argInfo = POPT_ARG_STRING,
136 .arg = &opt_kerberos,
138 .descrip = "Use Kerberos",
139 .argDescrip = "[yes|no]",
141 .longName = "debuglevel",
143 .argInfo = POPT_ARG_STRING,
144 .arg = &opt_debuglevel,
146 .descrip = "Set debug level",
147 .argDescrip = "DEBUGLEVEL",
149 .longName = "uninstall",
151 .argInfo = POPT_ARG_NONE,
152 .arg = &flag_uninstall,
154 .descrip = "Uninstall winexe service after "
158 .longName = "reinstall",
160 .argInfo = POPT_ARG_NONE,
161 .arg = &flag_reinstall,
163 .descrip = "Reinstall winexe service before "
169 .argInfo = POPT_ARG_STRING,
170 .arg = &options->runas,
172 .descrip = "Run as the given user (BEWARE: this "
173 "password is sent in cleartext over "
175 .argDescrip = "[DOMAIN\\]USERNAME%PASSWORD",
177 .longName = "runas-file",
179 .argInfo = POPT_ARG_STRING,
180 .arg = &options->runas_file,
182 .descrip = "Run as user options defined in a file",
183 .argDescrip = "FILE",
185 .longName = "interactive",
187 .argInfo = POPT_ARG_INT,
188 .arg = &flag_interactive,
190 .descrip = "Desktop interaction: 0 - disallow, "
191 "1 - allow. If allow, also use the "
192 "--system switch (Windows requirement). "
193 "Vista does not support this option.",
196 .longName = "ostype",
198 .argInfo = POPT_ARG_INT,
201 .descrip = "OS type: 0 - 32-bit, 1 - 64-bit, "
202 "2 - winexe will decide. "
203 "Determines which version (32-bit or 64-bit)"
204 " of service will be installed.",
205 .argDescrip = "0|1|2",
210 ZERO_STRUCTP(options);
212 pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,
215 poptSetOtherOptionHelp(pc, "[OPTION]... //HOST COMMAND\nOptions:");
217 if (((opt = poptGetNextOpt(pc)) != -1) || flag_help || flag_version) {
218 fprintf(stderr, version_message_fmt, SAMBA_VERSION_MAJOR,
219 SAMBA_VERSION_MINOR);
223 poptPrintHelp(pc, stdout, 0);
230 argv_new = discard_const_p(char *, poptGetArgs(pc));
233 for (i = 0; i < argc; i++) {
234 if (!argv_new || argv_new[i] == NULL) {
240 if (argc_new != 2 || argv_new[0][0] != '/' || argv_new[0][1] != '/') {
241 fprintf(stderr, version_message_fmt, SAMBA_VERSION_MAJOR,
242 SAMBA_VERSION_MINOR);
243 poptPrintHelp(pc, stdout, 0);
247 if (opt_debuglevel) {
248 lp_set_cmdline("log level", opt_debuglevel);
251 cred = cli_credentials_init(mem_ctx);
254 cli_credentials_parse_string(cred, opt_user, CRED_SPECIFIED);
255 } else if (opt_auth_file) {
256 cli_credentials_parse_file(cred, opt_auth_file,
260 cli_credentials_guess(cred, lp_ctx);
261 if (!cli_credentials_get_password(cred) && !flag_nopass) {
262 char *p = getpass("Enter password: ");
264 cli_credentials_set_password(cred, p, CRED_SPECIFIED);
269 cli_credentials_set_kerberos_state(cred,
270 strcmp(opt_kerberos, "yes")
271 ? CRED_MUST_USE_KERBEROS
272 : CRED_DONT_USE_KERBEROS);
275 if (options->runas == NULL && options->runas_file != NULL) {
276 struct cli_credentials *runas_cred;
280 runas_cred = cli_credentials_init(mem_ctx);
281 cli_credentials_parse_file(runas_cred, options->runas_file,
284 user = cli_credentials_get_username(runas_cred);
285 pass = cli_credentials_get_password(runas_cred);
291 dom = cli_credentials_get_domain(runas_cred);
293 snprintf(buffer, sizeof(buffer), "%s\\%s%%%s",
296 snprintf(buffer, sizeof(buffer), "%s%%%s",
299 buffer[sizeof(buffer)-1] = '\0';
300 options->runas = talloc_strdup(mem_ctx, buffer);
304 options->credentials = cred;
306 options->hostname = argv_new[0] + 2;
307 options->cmd = argv_new[1];
309 options->flags = flag_interactive;
310 if (flag_reinstall) {
311 options->flags |= SVC_FORCE_UPLOAD;
313 if (flag_ostype == 1) {
314 options->flags |= SVC_OS64BIT;
316 if (flag_ostype == 2) {
317 options->flags |= SVC_OSCHOOSE;
319 if (flag_uninstall) {
320 options->flags |= SVC_UNINSTALL;
324 static NTSTATUS winexe_svc_upload(
325 const char *hostname,
326 const char *service_filename,
327 const DATA_BLOB *svc32_exe,
328 const DATA_BLOB *svc64_exe,
329 struct cli_credentials *credentials,
332 struct cli_state *cli;
335 const DATA_BLOB *binary = NULL;
337 status = cli_full_connection_creds(
348 if (!NT_STATUS_IS_OK(status)) {
349 DBG_WARNING("cli_full_connection_creds failed: %s\n",
354 if (flags & SVC_FORCE_UPLOAD) {
355 status = cli_unlink(cli, service_filename, 0);
356 if (!NT_STATUS_IS_OK(status)) {
357 DBG_WARNING("cli_unlink failed: %s\n",
362 if (flags & SVC_OSCHOOSE) {
363 status = cli_chkpath(cli, "SysWoW64");
364 if (NT_STATUS_IS_OK(status)) {
365 flags |= SVC_OS64BIT;
369 if (flags & SVC_OS64BIT) {
375 if (binary == NULL) {
379 status = cli_ntcreate(
383 SEC_FILE_WRITE_DATA, /* DesiredAccess */
384 FILE_ATTRIBUTE_NORMAL, /* FileAttributes */
385 FILE_SHARE_WRITE|FILE_SHARE_READ, /* ShareAccess */
386 FILE_OPEN_IF, /* CreateDisposition */
387 FILE_NON_DIRECTORY_FILE, /* CreateOptions */
388 0, /* SecurityFlags */
390 NULL); /* CreateReturns */
391 if (!NT_STATUS_IS_OK(status)) {
392 DBG_WARNING("Could not create %s: %s\n", service_filename,
397 status = cli_writeall(
405 if (!NT_STATUS_IS_OK(status)) {
406 DBG_WARNING("Could not write file: %s\n", nt_errstr(status));
411 status = cli_close(cli, fnum);
412 if (!NT_STATUS_IS_OK(status)) {
413 DBG_WARNING("Close(%"PRIu16") failed for %s: %s\n", fnum,
414 service_filename, nt_errstr(status));
421 static NTSTATUS winexe_svc_install(
422 struct cli_state *cli,
423 const char *hostname,
424 const char *service_name,
425 const char *service_filename,
426 const DATA_BLOB *svc32_exe,
427 const DATA_BLOB *svc64_exe,
428 struct cli_credentials *credentials,
431 TALLOC_CTX *frame = talloc_stackframe();
432 struct rpc_pipe_client *rpccli;
433 struct policy_handle scmanager_handle;
434 struct policy_handle service_handle;
435 struct SERVICE_STATUS service_status;
436 bool need_start = false;
437 bool need_conf = false;
441 status = cli_rpc_pipe_open_noauth_transport(
446 if (!NT_STATUS_IS_OK(status)) {
447 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
452 status = dcerpc_svcctl_OpenSCManagerW(
453 rpccli->binding_handle,
455 smbXcli_conn_remote_name(cli->conn),
457 SEC_FLAG_MAXIMUM_ALLOWED,
460 if (!NT_STATUS_IS_OK(status)) {
461 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
465 if (!W_ERROR_IS_OK(werr)) {
466 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
471 status = dcerpc_svcctl_OpenServiceW(
472 rpccli->binding_handle,
479 if (!NT_STATUS_IS_OK(status)) {
480 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
482 goto close_scmanager;
485 if (W_ERROR_EQUAL(werr, WERR_SERVICE_DOES_NOT_EXIST)) {
486 status = dcerpc_svcctl_CreateServiceW(
487 rpccli->binding_handle,
493 SERVICE_TYPE_WIN32_OWN_PROCESS |
494 ((flags & SVC_INTERACTIVE) ?
495 SERVICE_TYPE_INTERACTIVE_PROCESS : 0),
497 SVCCTL_SVC_ERROR_NORMAL,
508 if (!NT_STATUS_IS_OK(status)) {
509 DBG_WARNING("dcerpc_svcctl_CreateServiceW "
510 "failed: %s\n", nt_errstr(status));
511 goto close_scmanager;
513 if (!W_ERROR_IS_OK(werr)) {
514 DBG_WARNING("dcerpc_svcctl_CreateServiceW "
515 "failed: %s\n", win_errstr(werr));
516 status = werror_to_ntstatus(werr);
517 goto close_scmanager;
521 status = dcerpc_svcctl_QueryServiceStatus(
522 rpccli->binding_handle,
528 if (!NT_STATUS_IS_OK(status)) {
529 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
530 "failed: %s\n", nt_errstr(status));
533 if (!W_ERROR_IS_OK(werr)) {
534 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
535 "failed: %s\n", win_errstr(werr));
536 status = werror_to_ntstatus(werr);
540 if (!(flags & SVC_IGNORE_INTERACTIVE)) {
542 !(service_status.type &
543 SERVICE_TYPE_INTERACTIVE_PROCESS) ^
544 !(flags & SVC_INTERACTIVE);
547 if (service_status.state == SVCCTL_STOPPED) {
549 } else if (need_conf) {
550 status = dcerpc_svcctl_ControlService(
551 rpccli->binding_handle,
558 if (!NT_STATUS_IS_OK(status)) {
559 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
560 "failed: %s\n", nt_errstr(status));
563 if (!W_ERROR_IS_OK(werr)) {
564 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
565 "failed: %s\n", win_errstr(werr));
566 status = werror_to_ntstatus(werr);
573 status = dcerpc_svcctl_QueryServiceStatus(
574 rpccli->binding_handle,
580 if (!NT_STATUS_IS_OK(status)) {
581 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
582 "failed: %s\n", nt_errstr(status));
585 if (!W_ERROR_IS_OK(werr)) {
586 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
587 "failed: %s\n", win_errstr(werr));
588 status = werror_to_ntstatus(werr);
591 } while (service_status.state == SVCCTL_STOP_PENDING);
597 status = dcerpc_svcctl_ChangeServiceConfigW(
598 rpccli->binding_handle,
601 SERVICE_TYPE_WIN32_OWN_PROCESS |
602 ((flags & SVC_INTERACTIVE) ?
603 SERVICE_TYPE_INTERACTIVE_PROCESS : 0), /* type */
604 UINT32_MAX, /* start_type, SERVICE_NO_CHANGE */
605 UINT32_MAX, /* error_control, SERVICE_NO_CHANGE */
606 NULL, /* binary_path */
607 NULL, /* load_order_group */
609 NULL, /* dependencies */
610 NULL, /* service_start_name */
612 NULL, /* display_name */
615 if (!NT_STATUS_IS_OK(status)) {
616 DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
617 "failed: %s\n", nt_errstr(status));
620 if (!W_ERROR_IS_OK(werr)) {
621 DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
622 "failed: %s\n", win_errstr(werr));
623 status = werror_to_ntstatus(werr);
629 status = winexe_svc_upload(
636 if (!NT_STATUS_IS_OK(status)) {
637 DBG_WARNING("winexe_svc_upload failed: %s\n",
642 status = dcerpc_svcctl_StartServiceW(
643 rpccli->binding_handle,
647 NULL, /* arguments */
650 if (!NT_STATUS_IS_OK(status)) {
651 DBG_WARNING("dcerpc_svcctl_StartServiceW "
652 "failed: %s\n", nt_errstr(status));
655 if (!W_ERROR_IS_OK(werr)) {
656 DBG_WARNING("dcerpc_svcctl_StartServiceW "
657 "failed: %s\n", win_errstr(werr));
658 status = werror_to_ntstatus(werr);
665 status = dcerpc_svcctl_QueryServiceStatus(
666 rpccli->binding_handle,
672 if (!NT_STATUS_IS_OK(status)) {
673 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
674 "failed: %s\n", nt_errstr(status));
677 if (!W_ERROR_IS_OK(werr)) {
678 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
679 "failed: %s\n", win_errstr(werr));
680 status = werror_to_ntstatus(werr);
683 } while (service_status.state == SVCCTL_START_PENDING);
685 if (service_status.state != SVCCTL_RUNNING) {
686 DBG_WARNING("Failed to start service\n");
687 status = NT_STATUS_UNSUCCESSFUL;
694 NTSTATUS close_status;
697 close_status = dcerpc_svcctl_CloseServiceHandle(
698 rpccli->binding_handle,
702 if (!NT_STATUS_IS_OK(close_status)) {
703 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
704 "failed: %s\n", nt_errstr(close_status));
707 if (!W_ERROR_IS_OK(close_werr)) {
708 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
709 " failed: %s\n", win_errstr(close_werr));
716 NTSTATUS close_status;
719 close_status = dcerpc_svcctl_CloseServiceHandle(
720 rpccli->binding_handle,
724 if (!NT_STATUS_IS_OK(close_status)) {
725 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
726 "failed: %s\n", nt_errstr(close_status));
729 if (!W_ERROR_IS_OK(close_werr)) {
730 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
731 " failed: %s\n", win_errstr(close_werr));
742 static NTSTATUS winexe_svc_uninstall(
743 struct cli_state *cli,
744 const char *service_name)
746 TALLOC_CTX *frame = talloc_stackframe();
747 struct rpc_pipe_client *rpccli;
748 struct policy_handle scmanager_handle;
749 struct policy_handle service_handle;
750 struct SERVICE_STATUS service_status;
754 status = cli_rpc_pipe_open_noauth_transport(
759 if (!NT_STATUS_IS_OK(status)) {
760 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
765 status = dcerpc_svcctl_OpenSCManagerW(
766 rpccli->binding_handle,
768 smbXcli_conn_remote_name(cli->conn),
770 SEC_FLAG_MAXIMUM_ALLOWED,
773 if (!NT_STATUS_IS_OK(status)) {
774 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
778 if (!W_ERROR_IS_OK(werr)) {
779 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
784 status = dcerpc_svcctl_OpenServiceW(
785 rpccli->binding_handle,
792 if (!NT_STATUS_IS_OK(status)) {
793 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
795 goto close_scmanager;
797 if (!W_ERROR_IS_OK(werr)) {
798 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
800 status = werror_to_ntstatus(werr);
801 goto close_scmanager;
804 status = dcerpc_svcctl_ControlService(
805 rpccli->binding_handle,
811 if (!NT_STATUS_IS_OK(status)) {
812 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
813 "failed: %s\n", nt_errstr(status));
816 if (!W_ERROR_IS_OK(werr)) {
817 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
818 "failed: %s\n", win_errstr(werr));
819 status = werror_to_ntstatus(werr);
826 status = dcerpc_svcctl_QueryServiceStatus(
827 rpccli->binding_handle,
833 if (!NT_STATUS_IS_OK(status)) {
834 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
835 "failed: %s\n", nt_errstr(status));
838 if (!W_ERROR_IS_OK(werr)) {
839 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
840 "failed: %s\n", win_errstr(werr));
841 status = werror_to_ntstatus(werr);
844 } while (service_status.state != SVCCTL_STOPPED);
846 status = dcerpc_svcctl_DeleteService(
847 rpccli->binding_handle,
851 if (!NT_STATUS_IS_OK(status)) {
852 DBG_WARNING("dcerpc_svcctl_DeleteService "
853 "failed: %s\n", nt_errstr(status));
856 if (!W_ERROR_IS_OK(werr)) {
857 DBG_WARNING("dcerpc_svcctl_DeleteService "
858 "failed: %s\n", win_errstr(werr));
859 status = werror_to_ntstatus(werr);
865 NTSTATUS close_status;
868 close_status = dcerpc_svcctl_CloseServiceHandle(
869 rpccli->binding_handle,
873 if (!NT_STATUS_IS_OK(close_status)) {
874 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
875 "failed: %s\n", nt_errstr(close_status));
878 if (!W_ERROR_IS_OK(close_werr)) {
879 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
880 " failed: %s\n", win_errstr(close_werr));
887 NTSTATUS close_status;
890 close_status = dcerpc_svcctl_CloseServiceHandle(
891 rpccli->binding_handle,
895 if (!NT_STATUS_IS_OK(close_status)) {
896 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
897 "failed: %s\n", nt_errstr(close_status));
900 if (!W_ERROR_IS_OK(close_werr)) {
901 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
902 " failed: %s\n", win_errstr(close_werr));
913 struct winexe_out_pipe_state {
914 struct tevent_context *ev;
915 struct cli_state *cli;
921 static void winexe_out_pipe_opened(struct tevent_req *subreq);
922 static void winexe_out_pipe_got_data(struct tevent_req *subreq);
923 static void winexe_out_pipe_closed(struct tevent_req *subreq);
925 static struct tevent_req *winexe_out_pipe_send(
927 struct tevent_context *ev,
928 struct cli_state *cli,
929 const char *pipe_name,
932 struct tevent_req *req, *subreq;
933 struct winexe_out_pipe_state *state;
935 req = tevent_req_create(mem_ctx, &state,
936 struct winexe_out_pipe_state);
942 state->out_fd = out_fd;
944 subreq = cli_ntcreate_send(
950 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
951 SEC_RIGHTS_FILE_EXECUTE,
952 0, /* FileAttributes */
953 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
954 FILE_OPEN, /* CreateDisposition */
955 0, /* CreateOptions */
956 SMB2_IMPERSONATION_IMPERSONATION,
957 0); /* SecurityFlags */
958 if (tevent_req_nomem(subreq, req)) {
959 return tevent_req_post(req, ev);
961 tevent_req_set_callback(subreq, winexe_out_pipe_opened, req);
965 static void winexe_out_pipe_opened(struct tevent_req *subreq)
967 struct tevent_req *req = tevent_req_callback_data(
968 subreq, struct tevent_req);
969 struct winexe_out_pipe_state *state = tevent_req_data(
970 req, struct winexe_out_pipe_state);
974 status = cli_ntcreate_recv(subreq, &state->out_pipe, NULL);
976 if (tevent_req_nterror(req, status)) {
980 timeout = state->cli->timeout;
981 state->cli->timeout = 0;
983 subreq = cli_read_send(
990 sizeof(state->out_inbuf));
992 state->cli->timeout = timeout;
994 if (tevent_req_nomem(subreq, req)) {
997 tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
1000 static void winexe_out_pipe_got_data(struct tevent_req *subreq)
1002 struct tevent_req *req = tevent_req_callback_data(
1003 subreq, struct tevent_req);
1004 struct winexe_out_pipe_state *state = tevent_req_data(
1005 req, struct winexe_out_pipe_state);
1011 status = cli_read_recv(subreq, &received);
1012 TALLOC_FREE(subreq);
1014 DBG_DEBUG("cli_read for %d gave %s\n",
1018 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1019 subreq = cli_close_send(
1024 if (tevent_req_nomem(subreq, req)) {
1027 tevent_req_set_callback(subreq, winexe_out_pipe_closed, req);
1031 if (tevent_req_nterror(req, status)) {
1036 written = sys_write(state->out_fd, state->out_inbuf, received);
1037 if (written == -1) {
1038 tevent_req_nterror(req, map_nt_error_from_unix(errno));
1043 timeout = state->cli->timeout;
1044 state->cli->timeout = 0;
1046 subreq = cli_read_send(
1053 sizeof(state->out_inbuf));
1055 state->cli->timeout = timeout;
1057 if (tevent_req_nomem(subreq, req)) {
1060 tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
1063 static void winexe_out_pipe_closed(struct tevent_req *subreq)
1065 struct tevent_req *req = tevent_req_callback_data(
1066 subreq, struct tevent_req);
1069 status = cli_close_recv(subreq);
1070 TALLOC_FREE(subreq);
1071 if (tevent_req_nterror(req, status)) {
1074 tevent_req_done(req);
1077 static NTSTATUS winexe_out_pipe_recv(struct tevent_req *req)
1079 return tevent_req_simple_recv_ntstatus(req);
1082 struct winexe_in_pipe_state {
1083 struct tevent_context *ev;
1084 struct cli_state *cli;
1085 struct tevent_req *fd_read_req;
1086 bool close_requested;
1093 static void winexe_in_pipe_opened(struct tevent_req *subreq);
1094 static void winexe_in_pipe_got_data(struct tevent_req *subreq);
1095 static void winexe_in_pipe_written(struct tevent_req *subreq);
1096 static void winexe_in_pipe_closed(struct tevent_req *subreq);
1098 static struct tevent_req *winexe_in_pipe_send(
1099 TALLOC_CTX *mem_ctx,
1100 struct tevent_context *ev,
1101 struct cli_state *cli,
1102 const char *pipe_name,
1105 struct tevent_req *req, *subreq;
1106 struct winexe_in_pipe_state *state;
1108 req = tevent_req_create(mem_ctx, &state,
1109 struct winexe_in_pipe_state);
1115 state->in_fd = in_fd;
1117 subreq = cli_ntcreate_send(
1123 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
1124 SEC_RIGHTS_FILE_EXECUTE,
1125 0, /* FileAttributes */
1126 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1127 FILE_OPEN, /* CreateDisposition */
1128 0, /* CreateOptions */
1129 SMB2_IMPERSONATION_IMPERSONATION,
1130 0); /* SecurityFlags */
1131 if (tevent_req_nomem(subreq, req)) {
1132 return tevent_req_post(req, ev);
1134 tevent_req_set_callback(subreq, winexe_in_pipe_opened, req);
1138 static void winexe_in_pipe_opened(struct tevent_req *subreq)
1140 struct tevent_req *req = tevent_req_callback_data(
1141 subreq, struct tevent_req);
1142 struct winexe_in_pipe_state *state = tevent_req_data(
1143 req, struct winexe_in_pipe_state);
1146 status = cli_ntcreate_recv(subreq, &state->in_pipe, NULL);
1147 TALLOC_FREE(subreq);
1148 if (tevent_req_nterror(req, status)) {
1152 subreq = wait_for_read_send(
1157 if (tevent_req_nomem(subreq, req)) {
1160 tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
1162 state->fd_read_req = subreq;
1165 static void winexe_in_pipe_got_data(struct tevent_req *subreq)
1167 struct tevent_req *req = tevent_req_callback_data(
1168 subreq, struct tevent_req);
1169 struct winexe_in_pipe_state *state = tevent_req_data(
1170 req, struct winexe_in_pipe_state);
1176 ok = wait_for_read_recv(subreq, &err);
1177 TALLOC_FREE(subreq);
1179 tevent_req_nterror(req, map_nt_error_from_unix(err));
1182 state->fd_read_req = NULL;
1184 nread = sys_read(state->in_fd, &state->inbuf, sizeof(state->inbuf));
1186 tevent_req_nterror(req, map_nt_error_from_unix(errno));
1190 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
1194 timeout = state->cli->timeout;
1195 state->cli->timeout = 0;
1197 subreq = cli_writeall_send(
1203 (uint8_t *)state->inbuf,
1207 state->cli->timeout = timeout;
1209 if (tevent_req_nomem(subreq, req)) {
1212 tevent_req_set_callback(subreq, winexe_in_pipe_written, req);
1215 static void winexe_in_pipe_written(struct tevent_req *subreq)
1217 struct tevent_req *req = tevent_req_callback_data(
1218 subreq, struct tevent_req);
1219 struct winexe_in_pipe_state *state = tevent_req_data(
1220 req, struct winexe_in_pipe_state);
1223 status = cli_writeall_recv(subreq, NULL);
1224 TALLOC_FREE(subreq);
1226 DBG_DEBUG("cli_writeall for %d gave %s\n",
1230 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED) ||
1231 state->close_requested) {
1232 subreq = cli_close_send(
1237 if (tevent_req_nomem(subreq, req)) {
1240 tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1241 state->closing = true;
1245 if (tevent_req_nterror(req, status)) {
1249 subreq = wait_for_read_send(
1254 if (tevent_req_nomem(subreq, req)) {
1257 tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
1259 state->fd_read_req = subreq;
1262 static void winexe_in_pipe_closed(struct tevent_req *subreq)
1264 struct tevent_req *req = tevent_req_callback_data(
1265 subreq, struct tevent_req);
1268 status = cli_close_recv(subreq);
1269 TALLOC_FREE(subreq);
1270 if (tevent_req_nterror(req, status)) {
1273 return tevent_req_done(req);
1276 static NTSTATUS winexe_in_pipe_recv(struct tevent_req *req)
1278 return tevent_req_simple_recv_ntstatus(req);
1281 static bool winexe_in_pipe_close(struct tevent_req *req)
1283 struct winexe_in_pipe_state *state = tevent_req_data(
1284 req, struct winexe_in_pipe_state);
1285 struct tevent_req *subreq;
1287 if (state->closing) {
1291 if (state->fd_read_req == NULL) {
1293 * cli_writeall active, wait for it to return
1295 state->close_requested = true;
1299 TALLOC_FREE(state->fd_read_req);
1301 subreq = cli_close_send(
1306 if (subreq == NULL) {
1309 tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1310 state->closing = true;
1315 struct winexe_pipes_state {
1316 struct tevent_req *pipes[3];
1319 static void winexe_pipes_stdin_done(struct tevent_req *subreq);
1320 static void winexe_pipes_stdout_done(struct tevent_req *subreq);
1321 static void winexe_pipes_stderr_done(struct tevent_req *subreq);
1323 static struct tevent_req *winexe_pipes_send(
1324 TALLOC_CTX *mem_ctx,
1325 struct tevent_context *ev,
1326 struct cli_state *cli,
1327 const char *pipe_postfix)
1329 struct tevent_req *req;
1330 struct winexe_pipes_state *state;
1333 req = tevent_req_create(mem_ctx, &state, struct winexe_pipes_state);
1338 pipe_name = talloc_asprintf(state, "\\ahexec_stdin%s", pipe_postfix);
1339 if (tevent_req_nomem(pipe_name, req)) {
1340 return tevent_req_post(req, ev);
1342 state->pipes[0] = winexe_in_pipe_send(
1348 if (tevent_req_nomem(state->pipes[0], req)) {
1349 return tevent_req_post(req, ev);
1351 tevent_req_set_callback(state->pipes[0], winexe_pipes_stdin_done, req);
1353 pipe_name = talloc_asprintf(state, "\\ahexec_stdout%s", pipe_postfix);
1354 if (tevent_req_nomem(pipe_name, req)) {
1355 return tevent_req_post(req, ev);
1357 state->pipes[1] = winexe_out_pipe_send(
1363 if (tevent_req_nomem(state->pipes[1], req)) {
1364 return tevent_req_post(req, ev);
1366 tevent_req_set_callback(state->pipes[1], winexe_pipes_stdout_done,
1369 pipe_name = talloc_asprintf(state, "\\ahexec_stderr%s", pipe_postfix);
1370 if (tevent_req_nomem(pipe_name, req)) {
1371 return tevent_req_post(req, ev);
1373 state->pipes[2] = winexe_out_pipe_send(
1379 if (tevent_req_nomem(state->pipes[2], req)) {
1380 return tevent_req_post(req, ev);
1382 tevent_req_set_callback(state->pipes[2], winexe_pipes_stderr_done,
1385 DBG_DEBUG("pipes = %p %p %p\n",
1393 static void winexe_pipes_stdin_done(struct tevent_req *subreq)
1395 struct tevent_req *req = tevent_req_callback_data(
1396 subreq, struct tevent_req);
1397 struct winexe_pipes_state *state = tevent_req_data(
1398 req, struct winexe_pipes_state);
1401 status = winexe_in_pipe_recv(subreq);
1402 TALLOC_FREE(subreq);
1404 DBG_DEBUG("stdin returned %s\n", nt_errstr(status));
1406 if (tevent_req_nterror(req, status)) {
1410 state->pipes[0] = NULL;
1412 DBG_DEBUG("pipes = %p %p %p\n",
1417 if ((state->pipes[1] == NULL) && (state->pipes[2] == NULL)) {
1418 tevent_req_done(req);
1422 static void winexe_pipes_stdout_done(struct tevent_req *subreq)
1424 struct tevent_req *req = tevent_req_callback_data(
1425 subreq, struct tevent_req);
1426 struct winexe_pipes_state *state = tevent_req_data(
1427 req, struct winexe_pipes_state);
1430 status = winexe_out_pipe_recv(subreq);
1431 TALLOC_FREE(subreq);
1433 DBG_DEBUG("stdout returned %s\n", nt_errstr(status));
1435 if (tevent_req_nterror(req, status)) {
1439 if (state->pipes[0] != NULL) {
1440 winexe_in_pipe_close(state->pipes[0]);
1443 state->pipes[1] = NULL;
1445 DBG_DEBUG("pipes = %p %p %p\n",
1450 if ((state->pipes[0] == NULL) && (state->pipes[2] == NULL)) {
1451 tevent_req_done(req);
1455 static void winexe_pipes_stderr_done(struct tevent_req *subreq)
1457 struct tevent_req *req = tevent_req_callback_data(
1458 subreq, struct tevent_req);
1459 struct winexe_pipes_state *state = tevent_req_data(
1460 req, struct winexe_pipes_state);
1463 status = winexe_out_pipe_recv(subreq);
1464 TALLOC_FREE(subreq);
1466 DBG_DEBUG("stderr returned %s\n", nt_errstr(status));
1468 if (tevent_req_nterror(req, status)) {
1472 if (state->pipes[0] != NULL) {
1473 winexe_in_pipe_close(state->pipes[0]);
1476 state->pipes[2] = NULL;
1478 DBG_DEBUG("pipes = %p %p %p\n",
1483 if ((state->pipes[0] == NULL) && (state->pipes[1] == NULL)) {
1484 tevent_req_done(req);
1488 static NTSTATUS winexe_pipes_recv(struct tevent_req *req)
1490 return tevent_req_simple_recv_ntstatus(req);
1493 struct winexe_ctrl_state {
1494 struct tevent_context *ev;
1495 struct cli_state *cli;
1498 bool ctrl_pipe_done;
1500 char ctrl_inbuf[256];
1504 struct tevent_req *pipes_req;
1507 static void winexe_ctrl_opened(struct tevent_req *subreq);
1508 static void winexe_ctrl_got_read(struct tevent_req *subreq);
1509 static void winexe_ctrl_wrote_version(struct tevent_req *subreq);
1510 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq);
1511 static void winexe_ctrl_pipes_done(struct tevent_req *subreq);
1512 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq);
1514 static struct tevent_req *winexe_ctrl_send(
1515 TALLOC_CTX *mem_ctx,
1516 struct tevent_context *ev,
1517 struct cli_state *cli,
1520 struct tevent_req *req, *subreq;
1521 struct winexe_ctrl_state *state;
1523 req = tevent_req_create(mem_ctx, &state,
1524 struct winexe_ctrl_state);
1531 state->cmd = talloc_asprintf(state, "run %s\n", cmd);
1532 if (tevent_req_nomem(state->cmd, req)) {
1533 return tevent_req_post(req, ev);
1536 subreq = cli_ntcreate_send(
1542 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
1543 SEC_RIGHTS_FILE_EXECUTE,
1544 0, /* FileAttributes */
1545 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1546 FILE_OPEN, /* CreateDisposition */
1547 0, /* CreateOptions */
1548 SMB2_IMPERSONATION_IMPERSONATION,
1549 0); /* SecurityFlags */
1550 if (tevent_req_nomem(subreq, req)) {
1551 return tevent_req_post(req, ev);
1553 tevent_req_set_callback(subreq, winexe_ctrl_opened, req);
1557 static void winexe_ctrl_opened(struct tevent_req *subreq)
1559 struct tevent_req *req = tevent_req_callback_data(
1560 subreq, struct tevent_req);
1561 struct winexe_ctrl_state *state = tevent_req_data(
1562 req, struct winexe_ctrl_state);
1565 static const char cmd[] = "get codepage\nget version\n";
1567 status = cli_ntcreate_recv(subreq, &state->ctrl_pipe, NULL);
1568 TALLOC_FREE(subreq);
1569 if (tevent_req_nterror(req, status)) {
1573 timeout = state->cli->timeout;
1574 state->cli->timeout = 0;
1576 subreq = cli_read_send(
1583 sizeof(state->ctrl_inbuf)-1);
1585 state->cli->timeout = timeout;
1587 if (tevent_req_nomem(subreq, req)) {
1590 tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1592 subreq = cli_writeall_send(
1598 (const uint8_t *)cmd,
1601 if (tevent_req_nomem(subreq, req)) {
1604 tevent_req_set_callback(subreq, winexe_ctrl_wrote_version, req);
1607 static void winexe_ctrl_got_read(struct tevent_req *subreq)
1609 struct tevent_req *req = tevent_req_callback_data(
1610 subreq, struct tevent_req);
1611 struct winexe_ctrl_state *state = tevent_req_data(
1612 req, struct winexe_ctrl_state);
1616 unsigned int version, return_code;
1619 status = cli_read_recv(subreq, &received);
1620 TALLOC_FREE(subreq);
1622 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1623 subreq = cli_close_send(
1628 if (tevent_req_nomem(subreq, req)) {
1631 tevent_req_set_callback(subreq, winexe_ctrl_pipe_closed, req);
1634 if (tevent_req_nterror(req, status)) {
1638 DBG_DEBUG("Got %zu bytes\n", received);
1640 timeout = state->cli->timeout;
1641 state->cli->timeout = 0;
1643 subreq = cli_read_send(
1650 sizeof(state->ctrl_inbuf)-1);
1652 state->cli->timeout = timeout;
1654 if (tevent_req_nomem(subreq, req)) {
1657 tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1659 ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &version);
1661 DBG_DEBUG("Got version %x\n", version);
1663 subreq = cli_writeall_send(
1669 (const uint8_t *)state->cmd,
1671 strlen(state->cmd));
1672 if (tevent_req_nomem(subreq, req)) {
1675 tevent_req_set_callback(subreq, winexe_ctrl_wrote_cmd, req);
1679 ret = strncmp(state->ctrl_inbuf, "std_io_err ", strlen("std_io_err "));
1681 char *p = state->ctrl_inbuf + 11;
1682 char *q = strchr(state->ctrl_inbuf, '\n');
1687 DBG_DEBUG("Got invalid pipe postfix\n");
1691 postfix_len = q - p;
1693 postfix = talloc_strndup(state, p, postfix_len);
1694 if (tevent_req_nomem(postfix, req)) {
1698 DBG_DEBUG("Got pipe postfix %s\n", postfix);
1700 subreq = winexe_pipes_send(
1705 if (tevent_req_nomem(subreq, req)) {
1708 tevent_req_set_callback(subreq, winexe_ctrl_pipes_done, req);
1710 state->pipes_req = subreq;
1715 ret = strncmp(state->ctrl_inbuf, "error ", strlen("error "));
1717 printf("Error: %s", state->ctrl_inbuf);
1721 ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &return_code);
1723 state->return_code = return_code;
1728 static void winexe_ctrl_wrote_version(struct tevent_req *subreq)
1730 struct tevent_req *req = tevent_req_callback_data(
1731 subreq, struct tevent_req);
1734 status = cli_writeall_recv(subreq, NULL);
1735 TALLOC_FREE(subreq);
1736 if (tevent_req_nterror(req, status)) {
1741 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq)
1743 struct tevent_req *req = tevent_req_callback_data(
1744 subreq, struct tevent_req);
1747 status = cli_writeall_recv(subreq, NULL);
1748 TALLOC_FREE(subreq);
1749 if (tevent_req_nterror(req, status)) {
1754 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq)
1756 struct tevent_req *req = tevent_req_callback_data(
1757 subreq, struct tevent_req);
1758 struct winexe_ctrl_state *state = tevent_req_data(
1759 req, struct winexe_ctrl_state);
1762 status = cli_close_recv(subreq);
1763 TALLOC_FREE(subreq);
1764 if (tevent_req_nterror(req, status)) {
1768 state->ctrl_pipe_done = true;
1769 if (state->pipes_req == NULL) {
1770 tevent_req_done(req);
1774 static void winexe_ctrl_pipes_done(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 = winexe_pipes_recv(subreq);
1783 TALLOC_FREE(subreq);
1784 if (tevent_req_nterror(req, status)) {
1788 state->pipes_req = NULL;
1789 if (state->ctrl_pipe_done) {
1790 tevent_req_done(req);
1794 static NTSTATUS winexe_ctrl_recv(struct tevent_req *req,
1797 struct winexe_ctrl_state *state = tevent_req_data(
1798 req, struct winexe_ctrl_state);
1801 if (tevent_req_is_nterror(req, &status)) {
1804 if (preturn_code != NULL) {
1805 *preturn_code = state->return_code;
1807 return NT_STATUS_OK;
1810 static NTSTATUS winexe_ctrl(struct cli_state *cli,
1814 struct tevent_context *ev = NULL;
1815 struct tevent_req *req = NULL;
1816 NTSTATUS status = NT_STATUS_NO_MEMORY;
1819 ev = samba_tevent_context_init(cli);
1823 req = winexe_ctrl_send(ev, ev, cli, cmd);
1827 ok = tevent_req_poll_ntstatus(req, ev, &status);
1831 status = winexe_ctrl_recv(req, preturn_code);
1838 #ifdef HAVE_WINEXE_CC_WIN32
1839 const DATA_BLOB *winexesvc32_exe_binary(void);
1842 #ifdef HAVE_WINEXE_CC_WIN64
1843 const DATA_BLOB *winexesvc64_exe_binary(void);
1846 int main(int argc, const char *argv[])
1848 TALLOC_CTX *frame = talloc_stackframe();
1849 struct program_options options = {0};
1850 struct loadparm_context *lp_ctx;
1851 struct cli_state *cli;
1852 const char *service_name = SERVICE_NAME;
1853 char *service_filename = NULL;
1854 #ifdef HAVE_WINEXE_CC_WIN32
1855 const DATA_BLOB *winexesvc32_exe = winexesvc32_exe_binary();
1857 const DATA_BLOB *winexesvc32_exe = NULL;
1859 #ifdef HAVE_WINEXE_CC_WIN64
1860 const DATA_BLOB *winexesvc64_exe = winexesvc64_exe_binary();
1862 const DATA_BLOB *winexesvc64_exe = NULL;
1866 int return_code = 0;
1868 lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
1869 if (lp_ctx == NULL) {
1870 fprintf(stderr, "loadparm_init_s3 failed\n");
1875 setup_logging("winexe", DEBUG_STDOUT);
1877 lp_load_global(get_dyn_CONFIGFILE());
1879 parse_args(argc, argv, frame, &options, lp_ctx);
1881 if (options.cmd == NULL) {
1882 fprintf(stderr, "no cmd given\n");
1886 service_filename = talloc_asprintf(frame, "%s.exe", service_name);
1887 if (service_filename == NULL) {
1888 DBG_WARNING("talloc_asprintf failed\n");
1892 status = cli_full_connection_creds(
1900 options.credentials,
1904 if (!NT_STATUS_IS_OK(status)) {
1905 DBG_WARNING("cli_full_connection_creds failed: %s\n",
1910 status = winexe_svc_install(
1917 options.credentials,
1919 if (!NT_STATUS_IS_OK(status)) {
1920 DBG_WARNING("winexe_svc_install failed: %s\n",
1925 status = winexe_ctrl(cli, options.cmd, &return_code);
1926 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1928 status = NT_STATUS_OK;
1930 if (!NT_STATUS_IS_OK(status)) {
1931 DBG_WARNING("cli_ctrl failed: %s\n",
1936 if (options.flags & SVC_UNINSTALL) {
1937 status = winexe_svc_uninstall(
1940 if (!NT_STATUS_IS_OK(status)) {
1941 DBG_WARNING("winexe_svc_uninstall failed: %s\n",