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"
37 #include "lib/cmdline/cmdline.h"
40 #define SVC_INTERACTIVE 1
41 #define SVC_IGNORE_INTERACTIVE 2
42 #define SVC_INTERACTIVE_MASK 3
43 #define SVC_FORCE_UPLOAD 4
45 #define SVC_OSCHOOSE 16
46 #define SVC_UNINSTALL 32
49 #define SERVICE_NAME "winexesvc"
51 #define PIPE_NAME "ahexec"
52 #define PIPE_NAME_IN "ahexec_stdin%08X"
53 #define PIPE_NAME_OUT "ahexec_stdout%08X"
54 #define PIPE_NAME_ERR "ahexec_stderr%08X"
56 static const char version_message_fmt[] = "winexe version %d.%d\n"
57 "This program may be freely redistributed under the terms of the "
60 struct program_options {
64 struct cli_credentials *credentials;
70 static void parse_args(int argc, const char *argv[],
72 struct program_options *options)
81 char *port_str = NULL;
83 int flag_interactive = SVC_IGNORE_INTERACTIVE;
85 int flag_reinstall = 0;
86 int flag_uninstall = 0;
91 struct poptOption long_options[] = {
94 .longName = "uninstall",
96 .argInfo = POPT_ARG_NONE,
97 .arg = &flag_uninstall,
99 .descrip = "Uninstall winexe service after "
103 .longName = "reinstall",
105 .argInfo = POPT_ARG_NONE,
106 .arg = &flag_reinstall,
108 .descrip = "Reinstall winexe service before "
114 .argInfo = POPT_ARG_STRING,
115 .arg = &options->runas,
117 .descrip = "Run as the given user (BEWARE: this "
118 "password is sent in cleartext over "
120 .argDescrip = "[DOMAIN\\]USERNAME%PASSWORD",
122 .longName = "runas-file",
124 .argInfo = POPT_ARG_STRING,
125 .arg = &options->runas_file,
127 .descrip = "Run as user options defined in a file",
128 .argDescrip = "FILE",
130 .longName = "interactive",
132 .argInfo = POPT_ARG_INT,
133 .arg = &flag_interactive,
135 .descrip = "Desktop interaction: 0 - disallow, "
136 "1 - allow. If allow, also use the "
137 "--system switch (Windows requirement). "
138 "Vista does not support this option.",
141 .longName = "ostype",
143 .argInfo = POPT_ARG_INT,
146 .descrip = "OS type: 0 - 32-bit, 1 - 64-bit, "
147 "2 - winexe will decide. "
148 "Determines which version (32-bit or 64-bit)"
149 " of service will be installed.",
150 .argDescrip = "0|1|2",
153 POPT_COMMON_CREDENTIALS
158 ZERO_STRUCTP(options);
160 ok = samba_cmdline_init(mem_ctx,
161 SAMBA_CMDLINE_CONFIG_CLIENT,
162 false /* require_smbconf */);
164 DBG_ERR("Failed to init cmdline parser!\n");
165 TALLOC_FREE(mem_ctx);
169 pc = samba_popt_get_context(getprogname(),
175 DBG_ERR("Failed to setup popt context!\n");
176 TALLOC_FREE(mem_ctx);
180 poptSetOtherOptionHelp(pc, "[OPTION]... //HOST[:PORT] COMMAND\nOptions:");
182 if (((opt = poptGetNextOpt(pc)) != -1) || flag_help || flag_version) {
183 fprintf(stderr, version_message_fmt, SAMBA_VERSION_MAJOR,
184 SAMBA_VERSION_MINOR);
188 poptPrintHelp(pc, stdout, 0);
195 argv_new = discard_const_p(char *, poptGetArgs(pc));
198 for (i = 0; i < argc; i++) {
199 if (!argv_new || argv_new[i] == NULL) {
205 if (argc_new != 2 || argv_new[0][0] != '/' || argv_new[0][1] != '/') {
206 fprintf(stderr, version_message_fmt, SAMBA_VERSION_MAJOR,
207 SAMBA_VERSION_MINOR);
208 poptPrintHelp(pc, stdout, 0);
212 port_str = strchr(argv_new[0], ':');
214 if (sscanf(port_str + 1, "%d", &port) != 1 || port <= 0) {
215 fprintf(stderr, version_message_fmt,
216 SAMBA_VERSION_MAJOR, SAMBA_VERSION_MINOR);
217 poptPrintHelp(pc, stdout, 0);
223 if (options->runas == NULL && options->runas_file != NULL) {
224 struct cli_credentials *runas_cred;
228 runas_cred = cli_credentials_init(mem_ctx);
229 cli_credentials_parse_file(runas_cred, options->runas_file,
232 user = cli_credentials_get_username(runas_cred);
233 pass = cli_credentials_get_password(runas_cred);
239 dom = cli_credentials_get_domain(runas_cred);
241 snprintf(buffer, sizeof(buffer), "%s\\%s%%%s",
244 snprintf(buffer, sizeof(buffer), "%s%%%s",
247 buffer[sizeof(buffer)-1] = '\0';
248 options->runas = talloc_strdup(mem_ctx, buffer);
252 options->credentials = samba_cmdline_get_creds();
254 options->hostname = talloc_strdup(mem_ctx, argv_new[0] + 2);
255 if (options->hostname == NULL) {
256 DBG_ERR("Out of memory\n");
259 options->port = port;
260 options->cmd = talloc_strdup(mem_ctx, argv_new[1]);
261 if (options->cmd == NULL) {
262 DBG_ERR("Out of memory\n");
268 options->flags = flag_interactive;
269 if (flag_reinstall) {
270 options->flags |= SVC_FORCE_UPLOAD;
272 if (flag_ostype == 1) {
273 options->flags |= SVC_OS64BIT;
275 if (flag_ostype == 2) {
276 options->flags |= SVC_OSCHOOSE;
278 if (flag_uninstall) {
279 options->flags |= SVC_UNINSTALL;
283 static NTSTATUS winexe_svc_upload(
284 const char *hostname,
286 const char *service_filename,
287 const DATA_BLOB *svc32_exe,
288 const DATA_BLOB *svc64_exe,
289 struct cli_credentials *credentials,
292 struct cli_state *cli;
293 uint16_t fnum = 0xffff;
295 const DATA_BLOB *binary = NULL;
297 status = cli_full_connection_creds(
307 if (!NT_STATUS_IS_OK(status)) {
308 DBG_WARNING("cli_full_connection_creds failed: %s\n",
313 if (flags & SVC_FORCE_UPLOAD) {
314 status = cli_unlink(cli, service_filename, 0);
315 if (!NT_STATUS_IS_OK(status)) {
316 DBG_WARNING("cli_unlink failed: %s\n",
321 if (flags & SVC_OSCHOOSE) {
322 status = cli_chkpath(cli, "SysWoW64");
323 if (NT_STATUS_IS_OK(status)) {
324 flags |= SVC_OS64BIT;
328 if (flags & SVC_OS64BIT) {
334 if (binary == NULL) {
338 status = cli_ntcreate(
342 SEC_FILE_WRITE_DATA, /* DesiredAccess */
343 FILE_ATTRIBUTE_NORMAL, /* FileAttributes */
344 FILE_SHARE_WRITE|FILE_SHARE_READ, /* ShareAccess */
345 FILE_OPEN_IF, /* CreateDisposition */
346 FILE_NON_DIRECTORY_FILE, /* CreateOptions */
347 0, /* SecurityFlags */
349 NULL); /* CreateReturns */
350 if (!NT_STATUS_IS_OK(status)) {
351 DBG_WARNING("Could not create %s: %s\n", service_filename,
356 status = cli_writeall(
364 if (!NT_STATUS_IS_OK(status)) {
365 DBG_WARNING("Could not write file: %s\n", nt_errstr(status));
370 if (fnum != 0xffff) {
371 status = cli_close(cli, fnum);
372 if (!NT_STATUS_IS_OK(status)) {
373 DBG_WARNING("Close(%"PRIu16") failed for %s: %s\n",
384 static NTSTATUS winexe_svc_install(
385 struct cli_state *cli,
386 const char *hostname,
388 const char *service_name,
389 const char *service_filename,
390 const DATA_BLOB *svc32_exe,
391 const DATA_BLOB *svc64_exe,
392 struct cli_credentials *credentials,
395 TALLOC_CTX *frame = talloc_stackframe();
396 struct rpc_pipe_client *rpccli;
397 struct policy_handle scmanager_handle;
398 struct policy_handle service_handle;
399 struct SERVICE_STATUS service_status;
400 bool need_start = false;
401 bool need_conf = false;
405 status = cli_rpc_pipe_open_noauth_transport(
410 if (!NT_STATUS_IS_OK(status)) {
411 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
416 status = dcerpc_svcctl_OpenSCManagerW(
417 rpccli->binding_handle,
419 smbXcli_conn_remote_name(cli->conn),
421 SEC_FLAG_MAXIMUM_ALLOWED,
424 if (!NT_STATUS_IS_OK(status)) {
425 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
429 if (!W_ERROR_IS_OK(werr)) {
430 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
435 status = dcerpc_svcctl_OpenServiceW(
436 rpccli->binding_handle,
443 if (!NT_STATUS_IS_OK(status)) {
444 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
446 goto close_scmanager;
449 if (W_ERROR_EQUAL(werr, WERR_SERVICE_DOES_NOT_EXIST)) {
450 status = dcerpc_svcctl_CreateServiceW(
451 rpccli->binding_handle,
457 SERVICE_TYPE_WIN32_OWN_PROCESS |
458 ((flags & SVC_INTERACTIVE) ?
459 SERVICE_TYPE_INTERACTIVE_PROCESS : 0),
461 SVCCTL_SVC_ERROR_NORMAL,
472 if (!NT_STATUS_IS_OK(status)) {
473 DBG_WARNING("dcerpc_svcctl_CreateServiceW "
474 "failed: %s\n", nt_errstr(status));
475 goto close_scmanager;
477 if (!W_ERROR_IS_OK(werr)) {
478 DBG_WARNING("dcerpc_svcctl_CreateServiceW "
479 "failed: %s\n", win_errstr(werr));
480 status = werror_to_ntstatus(werr);
481 goto close_scmanager;
485 status = dcerpc_svcctl_QueryServiceStatus(
486 rpccli->binding_handle,
492 if (!NT_STATUS_IS_OK(status)) {
493 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
494 "failed: %s\n", nt_errstr(status));
497 if (!W_ERROR_IS_OK(werr)) {
498 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
499 "failed: %s\n", win_errstr(werr));
500 status = werror_to_ntstatus(werr);
504 if (!(flags & SVC_IGNORE_INTERACTIVE)) {
506 !(service_status.type &
507 SERVICE_TYPE_INTERACTIVE_PROCESS) ^
508 !(flags & SVC_INTERACTIVE);
511 if (service_status.state == SVCCTL_STOPPED) {
513 } else if (need_conf) {
514 status = dcerpc_svcctl_ControlService(
515 rpccli->binding_handle,
522 if (!NT_STATUS_IS_OK(status)) {
523 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
524 "failed: %s\n", nt_errstr(status));
527 if (!W_ERROR_IS_OK(werr)) {
528 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
529 "failed: %s\n", win_errstr(werr));
530 status = werror_to_ntstatus(werr);
537 status = dcerpc_svcctl_QueryServiceStatus(
538 rpccli->binding_handle,
544 if (!NT_STATUS_IS_OK(status)) {
545 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
546 "failed: %s\n", nt_errstr(status));
549 if (!W_ERROR_IS_OK(werr)) {
550 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
551 "failed: %s\n", win_errstr(werr));
552 status = werror_to_ntstatus(werr);
555 } while (service_status.state == SVCCTL_STOP_PENDING);
561 status = dcerpc_svcctl_ChangeServiceConfigW(
562 rpccli->binding_handle,
565 SERVICE_TYPE_WIN32_OWN_PROCESS |
566 ((flags & SVC_INTERACTIVE) ?
567 SERVICE_TYPE_INTERACTIVE_PROCESS : 0), /* type */
568 UINT32_MAX, /* start_type, SERVICE_NO_CHANGE */
569 UINT32_MAX, /* error_control, SERVICE_NO_CHANGE */
570 NULL, /* binary_path */
571 NULL, /* load_order_group */
573 NULL, /* dependencies */
574 0, /* dwDependSize */
575 NULL, /* service_start_name */
578 NULL, /* display_name */
581 if (!NT_STATUS_IS_OK(status)) {
582 DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
583 "failed: %s\n", nt_errstr(status));
586 if (!W_ERROR_IS_OK(werr)) {
587 DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
588 "failed: %s\n", win_errstr(werr));
589 status = werror_to_ntstatus(werr);
595 status = winexe_svc_upload(
603 if (!NT_STATUS_IS_OK(status)) {
604 DBG_WARNING("winexe_svc_upload failed: %s\n",
609 status = dcerpc_svcctl_StartServiceW(
610 rpccli->binding_handle,
614 NULL, /* arguments */
617 if (!NT_STATUS_IS_OK(status)) {
618 DBG_WARNING("dcerpc_svcctl_StartServiceW "
619 "failed: %s\n", nt_errstr(status));
622 if (!W_ERROR_IS_OK(werr)) {
623 DBG_WARNING("dcerpc_svcctl_StartServiceW "
624 "failed: %s\n", win_errstr(werr));
625 status = werror_to_ntstatus(werr);
632 status = dcerpc_svcctl_QueryServiceStatus(
633 rpccli->binding_handle,
639 if (!NT_STATUS_IS_OK(status)) {
640 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
641 "failed: %s\n", nt_errstr(status));
644 if (!W_ERROR_IS_OK(werr)) {
645 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
646 "failed: %s\n", win_errstr(werr));
647 status = werror_to_ntstatus(werr);
650 } while (service_status.state == SVCCTL_START_PENDING);
652 if (service_status.state != SVCCTL_RUNNING) {
653 DBG_WARNING("Failed to start service\n");
654 status = NT_STATUS_UNSUCCESSFUL;
661 NTSTATUS close_status;
664 close_status = dcerpc_svcctl_CloseServiceHandle(
665 rpccli->binding_handle,
669 if (!NT_STATUS_IS_OK(close_status)) {
670 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
671 "failed: %s\n", nt_errstr(close_status));
674 if (!W_ERROR_IS_OK(close_werr)) {
675 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
676 " failed: %s\n", win_errstr(close_werr));
683 NTSTATUS close_status;
686 close_status = dcerpc_svcctl_CloseServiceHandle(
687 rpccli->binding_handle,
691 if (!NT_STATUS_IS_OK(close_status)) {
692 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
693 "failed: %s\n", nt_errstr(close_status));
696 if (!W_ERROR_IS_OK(close_werr)) {
697 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
698 " failed: %s\n", win_errstr(close_werr));
709 static NTSTATUS winexe_svc_uninstall(
710 struct cli_state *cli,
711 const char *service_name)
713 TALLOC_CTX *frame = talloc_stackframe();
714 struct rpc_pipe_client *rpccli;
715 struct policy_handle scmanager_handle;
716 struct policy_handle service_handle;
717 struct SERVICE_STATUS service_status;
721 status = cli_rpc_pipe_open_noauth_transport(
726 if (!NT_STATUS_IS_OK(status)) {
727 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
732 status = dcerpc_svcctl_OpenSCManagerW(
733 rpccli->binding_handle,
735 smbXcli_conn_remote_name(cli->conn),
737 SEC_FLAG_MAXIMUM_ALLOWED,
740 if (!NT_STATUS_IS_OK(status)) {
741 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
745 if (!W_ERROR_IS_OK(werr)) {
746 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
751 status = dcerpc_svcctl_OpenServiceW(
752 rpccli->binding_handle,
759 if (!NT_STATUS_IS_OK(status)) {
760 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
762 goto close_scmanager;
764 if (!W_ERROR_IS_OK(werr)) {
765 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
767 status = werror_to_ntstatus(werr);
768 goto close_scmanager;
771 status = dcerpc_svcctl_ControlService(
772 rpccli->binding_handle,
778 if (!NT_STATUS_IS_OK(status)) {
779 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
780 "failed: %s\n", nt_errstr(status));
783 if (!W_ERROR_IS_OK(werr)) {
784 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
785 "failed: %s\n", win_errstr(werr));
786 status = werror_to_ntstatus(werr);
793 status = dcerpc_svcctl_QueryServiceStatus(
794 rpccli->binding_handle,
800 if (!NT_STATUS_IS_OK(status)) {
801 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
802 "failed: %s\n", nt_errstr(status));
805 if (!W_ERROR_IS_OK(werr)) {
806 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
807 "failed: %s\n", win_errstr(werr));
808 status = werror_to_ntstatus(werr);
811 } while (service_status.state != SVCCTL_STOPPED);
813 status = dcerpc_svcctl_DeleteService(
814 rpccli->binding_handle,
818 if (!NT_STATUS_IS_OK(status)) {
819 DBG_WARNING("dcerpc_svcctl_DeleteService "
820 "failed: %s\n", nt_errstr(status));
823 if (!W_ERROR_IS_OK(werr)) {
824 DBG_WARNING("dcerpc_svcctl_DeleteService "
825 "failed: %s\n", win_errstr(werr));
826 status = werror_to_ntstatus(werr);
832 NTSTATUS close_status;
835 close_status = dcerpc_svcctl_CloseServiceHandle(
836 rpccli->binding_handle,
840 if (!NT_STATUS_IS_OK(close_status)) {
841 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
842 "failed: %s\n", nt_errstr(close_status));
845 if (!W_ERROR_IS_OK(close_werr)) {
846 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
847 " failed: %s\n", win_errstr(close_werr));
854 NTSTATUS close_status;
857 close_status = dcerpc_svcctl_CloseServiceHandle(
858 rpccli->binding_handle,
862 if (!NT_STATUS_IS_OK(close_status)) {
863 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
864 "failed: %s\n", nt_errstr(close_status));
867 if (!W_ERROR_IS_OK(close_werr)) {
868 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
869 " failed: %s\n", win_errstr(close_werr));
880 struct winexe_out_pipe_state {
881 struct tevent_context *ev;
882 struct cli_state *cli;
888 static void winexe_out_pipe_opened(struct tevent_req *subreq);
889 static void winexe_out_pipe_got_data(struct tevent_req *subreq);
890 static void winexe_out_pipe_closed(struct tevent_req *subreq);
892 static struct tevent_req *winexe_out_pipe_send(
894 struct tevent_context *ev,
895 struct cli_state *cli,
896 const char *pipe_name,
899 struct tevent_req *req, *subreq;
900 struct winexe_out_pipe_state *state;
902 req = tevent_req_create(mem_ctx, &state,
903 struct winexe_out_pipe_state);
909 state->out_fd = out_fd;
911 subreq = cli_ntcreate_send(
917 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
918 SEC_RIGHTS_FILE_EXECUTE,
919 0, /* FileAttributes */
920 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
921 FILE_OPEN, /* CreateDisposition */
922 0, /* CreateOptions */
923 SMB2_IMPERSONATION_IMPERSONATION,
924 0); /* SecurityFlags */
925 if (tevent_req_nomem(subreq, req)) {
926 return tevent_req_post(req, ev);
928 tevent_req_set_callback(subreq, winexe_out_pipe_opened, req);
932 static void winexe_out_pipe_opened(struct tevent_req *subreq)
934 struct tevent_req *req = tevent_req_callback_data(
935 subreq, struct tevent_req);
936 struct winexe_out_pipe_state *state = tevent_req_data(
937 req, struct winexe_out_pipe_state);
941 status = cli_ntcreate_recv(subreq, &state->out_pipe, NULL);
943 if (tevent_req_nterror(req, status)) {
947 timeout = state->cli->timeout;
948 state->cli->timeout = 0;
950 subreq = cli_read_send(
957 sizeof(state->out_inbuf));
959 state->cli->timeout = timeout;
961 if (tevent_req_nomem(subreq, req)) {
964 tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
967 static void winexe_out_pipe_got_data(struct tevent_req *subreq)
969 struct tevent_req *req = tevent_req_callback_data(
970 subreq, struct tevent_req);
971 struct winexe_out_pipe_state *state = tevent_req_data(
972 req, struct winexe_out_pipe_state);
978 status = cli_read_recv(subreq, &received);
981 DBG_DEBUG("cli_read for %d gave %s\n",
985 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
986 subreq = cli_close_send(
991 if (tevent_req_nomem(subreq, req)) {
994 tevent_req_set_callback(subreq, winexe_out_pipe_closed, req);
998 if (tevent_req_nterror(req, status)) {
1003 written = sys_write(state->out_fd, state->out_inbuf, received);
1004 if (written == -1) {
1005 tevent_req_nterror(req, map_nt_error_from_unix(errno));
1010 timeout = state->cli->timeout;
1011 state->cli->timeout = 0;
1013 subreq = cli_read_send(
1020 sizeof(state->out_inbuf));
1022 state->cli->timeout = timeout;
1024 if (tevent_req_nomem(subreq, req)) {
1027 tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
1030 static void winexe_out_pipe_closed(struct tevent_req *subreq)
1032 struct tevent_req *req = tevent_req_callback_data(
1033 subreq, struct tevent_req);
1036 status = cli_close_recv(subreq);
1037 TALLOC_FREE(subreq);
1038 if (tevent_req_nterror(req, status)) {
1041 tevent_req_done(req);
1044 static NTSTATUS winexe_out_pipe_recv(struct tevent_req *req)
1046 return tevent_req_simple_recv_ntstatus(req);
1049 struct winexe_in_pipe_state {
1050 struct tevent_context *ev;
1051 struct cli_state *cli;
1052 struct tevent_req *fd_read_req;
1053 bool close_requested;
1060 static void winexe_in_pipe_opened(struct tevent_req *subreq);
1061 static void winexe_in_pipe_got_data(struct tevent_req *subreq);
1062 static void winexe_in_pipe_written(struct tevent_req *subreq);
1063 static void winexe_in_pipe_closed(struct tevent_req *subreq);
1065 static struct tevent_req *winexe_in_pipe_send(
1066 TALLOC_CTX *mem_ctx,
1067 struct tevent_context *ev,
1068 struct cli_state *cli,
1069 const char *pipe_name,
1072 struct tevent_req *req, *subreq;
1073 struct winexe_in_pipe_state *state;
1075 req = tevent_req_create(mem_ctx, &state,
1076 struct winexe_in_pipe_state);
1082 state->in_fd = in_fd;
1084 subreq = cli_ntcreate_send(
1090 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
1091 SEC_RIGHTS_FILE_EXECUTE,
1092 0, /* FileAttributes */
1093 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1094 FILE_OPEN, /* CreateDisposition */
1095 0, /* CreateOptions */
1096 SMB2_IMPERSONATION_IMPERSONATION,
1097 0); /* SecurityFlags */
1098 if (tevent_req_nomem(subreq, req)) {
1099 return tevent_req_post(req, ev);
1101 tevent_req_set_callback(subreq, winexe_in_pipe_opened, req);
1105 static void winexe_in_pipe_opened(struct tevent_req *subreq)
1107 struct tevent_req *req = tevent_req_callback_data(
1108 subreq, struct tevent_req);
1109 struct winexe_in_pipe_state *state = tevent_req_data(
1110 req, struct winexe_in_pipe_state);
1113 status = cli_ntcreate_recv(subreq, &state->in_pipe, NULL);
1114 TALLOC_FREE(subreq);
1115 if (tevent_req_nterror(req, status)) {
1119 subreq = wait_for_read_send(
1124 if (tevent_req_nomem(subreq, req)) {
1127 tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
1129 state->fd_read_req = subreq;
1132 static void winexe_in_pipe_got_data(struct tevent_req *subreq)
1134 struct tevent_req *req = tevent_req_callback_data(
1135 subreq, struct tevent_req);
1136 struct winexe_in_pipe_state *state = tevent_req_data(
1137 req, struct winexe_in_pipe_state);
1143 ok = wait_for_read_recv(subreq, &err);
1144 TALLOC_FREE(subreq);
1146 tevent_req_nterror(req, map_nt_error_from_unix(err));
1149 state->fd_read_req = NULL;
1151 nread = sys_read(state->in_fd, &state->inbuf, sizeof(state->inbuf));
1153 tevent_req_nterror(req, map_nt_error_from_unix(errno));
1157 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
1161 timeout = state->cli->timeout;
1162 state->cli->timeout = 0;
1164 subreq = cli_writeall_send(
1170 (uint8_t *)state->inbuf,
1174 state->cli->timeout = timeout;
1176 if (tevent_req_nomem(subreq, req)) {
1179 tevent_req_set_callback(subreq, winexe_in_pipe_written, req);
1182 static void winexe_in_pipe_written(struct tevent_req *subreq)
1184 struct tevent_req *req = tevent_req_callback_data(
1185 subreq, struct tevent_req);
1186 struct winexe_in_pipe_state *state = tevent_req_data(
1187 req, struct winexe_in_pipe_state);
1190 status = cli_writeall_recv(subreq, NULL);
1191 TALLOC_FREE(subreq);
1193 DBG_DEBUG("cli_writeall for %d gave %s\n",
1197 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED) ||
1198 state->close_requested) {
1199 subreq = cli_close_send(
1204 if (tevent_req_nomem(subreq, req)) {
1207 tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1208 state->closing = true;
1212 if (tevent_req_nterror(req, status)) {
1216 subreq = wait_for_read_send(
1221 if (tevent_req_nomem(subreq, req)) {
1224 tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
1226 state->fd_read_req = subreq;
1229 static void winexe_in_pipe_closed(struct tevent_req *subreq)
1231 struct tevent_req *req = tevent_req_callback_data(
1232 subreq, struct tevent_req);
1235 status = cli_close_recv(subreq);
1236 TALLOC_FREE(subreq);
1237 if (tevent_req_nterror(req, status)) {
1240 return tevent_req_done(req);
1243 static NTSTATUS winexe_in_pipe_recv(struct tevent_req *req)
1245 return tevent_req_simple_recv_ntstatus(req);
1248 static bool winexe_in_pipe_close(struct tevent_req *req)
1250 struct winexe_in_pipe_state *state = tevent_req_data(
1251 req, struct winexe_in_pipe_state);
1252 struct tevent_req *subreq;
1254 if (state->closing) {
1258 if (state->fd_read_req == NULL) {
1260 * cli_writeall active, wait for it to return
1262 state->close_requested = true;
1266 TALLOC_FREE(state->fd_read_req);
1268 subreq = cli_close_send(
1273 if (subreq == NULL) {
1276 tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1277 state->closing = true;
1282 struct winexe_pipes_state {
1283 struct tevent_req *pipes[3];
1286 static void winexe_pipes_stdin_done(struct tevent_req *subreq);
1287 static void winexe_pipes_stdout_done(struct tevent_req *subreq);
1288 static void winexe_pipes_stderr_done(struct tevent_req *subreq);
1290 static struct tevent_req *winexe_pipes_send(
1291 TALLOC_CTX *mem_ctx,
1292 struct tevent_context *ev,
1293 struct cli_state *cli,
1294 const char *pipe_postfix)
1296 struct tevent_req *req;
1297 struct winexe_pipes_state *state;
1300 req = tevent_req_create(mem_ctx, &state, struct winexe_pipes_state);
1305 pipe_name = talloc_asprintf(state, "\\ahexec_stdin%s", pipe_postfix);
1306 if (tevent_req_nomem(pipe_name, req)) {
1307 return tevent_req_post(req, ev);
1309 state->pipes[0] = winexe_in_pipe_send(
1315 if (tevent_req_nomem(state->pipes[0], req)) {
1316 return tevent_req_post(req, ev);
1318 tevent_req_set_callback(state->pipes[0], winexe_pipes_stdin_done, req);
1320 pipe_name = talloc_asprintf(state, "\\ahexec_stdout%s", pipe_postfix);
1321 if (tevent_req_nomem(pipe_name, req)) {
1322 return tevent_req_post(req, ev);
1324 state->pipes[1] = winexe_out_pipe_send(
1330 if (tevent_req_nomem(state->pipes[1], req)) {
1331 return tevent_req_post(req, ev);
1333 tevent_req_set_callback(state->pipes[1], winexe_pipes_stdout_done,
1336 pipe_name = talloc_asprintf(state, "\\ahexec_stderr%s", pipe_postfix);
1337 if (tevent_req_nomem(pipe_name, req)) {
1338 return tevent_req_post(req, ev);
1340 state->pipes[2] = winexe_out_pipe_send(
1346 if (tevent_req_nomem(state->pipes[2], req)) {
1347 return tevent_req_post(req, ev);
1349 tevent_req_set_callback(state->pipes[2], winexe_pipes_stderr_done,
1352 DBG_DEBUG("pipes = %p %p %p\n",
1360 static void winexe_pipes_stdin_done(struct tevent_req *subreq)
1362 struct tevent_req *req = tevent_req_callback_data(
1363 subreq, struct tevent_req);
1364 struct winexe_pipes_state *state = tevent_req_data(
1365 req, struct winexe_pipes_state);
1368 status = winexe_in_pipe_recv(subreq);
1369 TALLOC_FREE(subreq);
1371 DBG_DEBUG("stdin returned %s\n", nt_errstr(status));
1373 if (tevent_req_nterror(req, status)) {
1377 state->pipes[0] = NULL;
1379 DBG_DEBUG("pipes = %p %p %p\n",
1384 if ((state->pipes[1] == NULL) && (state->pipes[2] == NULL)) {
1385 tevent_req_done(req);
1389 static void winexe_pipes_stdout_done(struct tevent_req *subreq)
1391 struct tevent_req *req = tevent_req_callback_data(
1392 subreq, struct tevent_req);
1393 struct winexe_pipes_state *state = tevent_req_data(
1394 req, struct winexe_pipes_state);
1397 status = winexe_out_pipe_recv(subreq);
1398 TALLOC_FREE(subreq);
1400 DBG_DEBUG("stdout returned %s\n", nt_errstr(status));
1402 if (tevent_req_nterror(req, status)) {
1406 if (state->pipes[0] != NULL) {
1407 winexe_in_pipe_close(state->pipes[0]);
1410 state->pipes[1] = NULL;
1412 DBG_DEBUG("pipes = %p %p %p\n",
1417 if ((state->pipes[0] == NULL) && (state->pipes[2] == NULL)) {
1418 tevent_req_done(req);
1422 static void winexe_pipes_stderr_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("stderr 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[2] = NULL;
1445 DBG_DEBUG("pipes = %p %p %p\n",
1450 if ((state->pipes[0] == NULL) && (state->pipes[1] == NULL)) {
1451 tevent_req_done(req);
1455 static NTSTATUS winexe_pipes_recv(struct tevent_req *req)
1457 return tevent_req_simple_recv_ntstatus(req);
1460 struct winexe_ctrl_state {
1461 struct tevent_context *ev;
1462 struct cli_state *cli;
1465 bool ctrl_pipe_done;
1467 char ctrl_inbuf[256];
1471 struct tevent_req *pipes_req;
1474 static void winexe_ctrl_opened(struct tevent_req *subreq);
1475 static void winexe_ctrl_got_read(struct tevent_req *subreq);
1476 static void winexe_ctrl_wrote_version(struct tevent_req *subreq);
1477 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq);
1478 static void winexe_ctrl_pipes_done(struct tevent_req *subreq);
1479 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq);
1481 static struct tevent_req *winexe_ctrl_send(
1482 TALLOC_CTX *mem_ctx,
1483 struct tevent_context *ev,
1484 struct cli_state *cli,
1487 struct tevent_req *req, *subreq;
1488 struct winexe_ctrl_state *state;
1490 req = tevent_req_create(mem_ctx, &state,
1491 struct winexe_ctrl_state);
1498 state->cmd = talloc_asprintf(state, "run %s\n", cmd);
1499 if (tevent_req_nomem(state->cmd, req)) {
1500 return tevent_req_post(req, ev);
1503 subreq = cli_ntcreate_send(
1509 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
1510 SEC_RIGHTS_FILE_EXECUTE,
1511 0, /* FileAttributes */
1512 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1513 FILE_OPEN, /* CreateDisposition */
1514 0, /* CreateOptions */
1515 SMB2_IMPERSONATION_IMPERSONATION,
1516 0); /* SecurityFlags */
1517 if (tevent_req_nomem(subreq, req)) {
1518 return tevent_req_post(req, ev);
1520 tevent_req_set_callback(subreq, winexe_ctrl_opened, req);
1524 static void winexe_ctrl_opened(struct tevent_req *subreq)
1526 struct tevent_req *req = tevent_req_callback_data(
1527 subreq, struct tevent_req);
1528 struct winexe_ctrl_state *state = tevent_req_data(
1529 req, struct winexe_ctrl_state);
1532 static const char cmd[] = "get codepage\nget version\n";
1534 status = cli_ntcreate_recv(subreq, &state->ctrl_pipe, NULL);
1535 TALLOC_FREE(subreq);
1536 if (tevent_req_nterror(req, status)) {
1540 timeout = state->cli->timeout;
1541 state->cli->timeout = 0;
1543 subreq = cli_read_send(
1550 sizeof(state->ctrl_inbuf)-1);
1552 state->cli->timeout = timeout;
1554 if (tevent_req_nomem(subreq, req)) {
1557 tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1559 subreq = cli_writeall_send(
1565 (const uint8_t *)cmd,
1568 if (tevent_req_nomem(subreq, req)) {
1571 tevent_req_set_callback(subreq, winexe_ctrl_wrote_version, req);
1574 static void winexe_ctrl_got_read(struct tevent_req *subreq)
1576 struct tevent_req *req = tevent_req_callback_data(
1577 subreq, struct tevent_req);
1578 struct winexe_ctrl_state *state = tevent_req_data(
1579 req, struct winexe_ctrl_state);
1583 unsigned int version, return_code;
1586 status = cli_read_recv(subreq, &received);
1587 TALLOC_FREE(subreq);
1589 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1590 subreq = cli_close_send(
1595 if (tevent_req_nomem(subreq, req)) {
1598 tevent_req_set_callback(subreq, winexe_ctrl_pipe_closed, req);
1601 if (tevent_req_nterror(req, status)) {
1605 DBG_DEBUG("Got %zu bytes\n", received);
1607 timeout = state->cli->timeout;
1608 state->cli->timeout = 0;
1610 subreq = cli_read_send(
1617 sizeof(state->ctrl_inbuf)-1);
1619 state->cli->timeout = timeout;
1621 if (tevent_req_nomem(subreq, req)) {
1624 tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1626 ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &version);
1628 DBG_DEBUG("Got version %x\n", version);
1630 subreq = cli_writeall_send(
1636 (const uint8_t *)state->cmd,
1638 strlen(state->cmd));
1639 if (tevent_req_nomem(subreq, req)) {
1642 tevent_req_set_callback(subreq, winexe_ctrl_wrote_cmd, req);
1646 ret = strncmp(state->ctrl_inbuf, "std_io_err ", strlen("std_io_err "));
1648 char *p = state->ctrl_inbuf + 11;
1649 char *q = strchr(state->ctrl_inbuf, '\n');
1654 DBG_DEBUG("Got invalid pipe postfix\n");
1658 postfix_len = q - p;
1660 postfix = talloc_strndup(state, p, postfix_len);
1661 if (tevent_req_nomem(postfix, req)) {
1665 DBG_DEBUG("Got pipe postfix %s\n", postfix);
1667 subreq = winexe_pipes_send(
1672 if (tevent_req_nomem(subreq, req)) {
1675 tevent_req_set_callback(subreq, winexe_ctrl_pipes_done, req);
1677 state->pipes_req = subreq;
1682 ret = strncmp(state->ctrl_inbuf, "error ", strlen("error "));
1684 printf("Error: %s", state->ctrl_inbuf);
1688 ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &return_code);
1690 state->return_code = return_code;
1695 static void winexe_ctrl_wrote_version(struct tevent_req *subreq)
1697 struct tevent_req *req = tevent_req_callback_data(
1698 subreq, struct tevent_req);
1701 status = cli_writeall_recv(subreq, NULL);
1702 TALLOC_FREE(subreq);
1703 if (tevent_req_nterror(req, status)) {
1708 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq)
1710 struct tevent_req *req = tevent_req_callback_data(
1711 subreq, struct tevent_req);
1714 status = cli_writeall_recv(subreq, NULL);
1715 TALLOC_FREE(subreq);
1716 if (tevent_req_nterror(req, status)) {
1721 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq)
1723 struct tevent_req *req = tevent_req_callback_data(
1724 subreq, struct tevent_req);
1725 struct winexe_ctrl_state *state = tevent_req_data(
1726 req, struct winexe_ctrl_state);
1729 status = cli_close_recv(subreq);
1730 TALLOC_FREE(subreq);
1731 if (tevent_req_nterror(req, status)) {
1735 state->ctrl_pipe_done = true;
1736 if (state->pipes_req == NULL) {
1737 tevent_req_done(req);
1741 static void winexe_ctrl_pipes_done(struct tevent_req *subreq)
1743 struct tevent_req *req = tevent_req_callback_data(
1744 subreq, struct tevent_req);
1745 struct winexe_ctrl_state *state = tevent_req_data(
1746 req, struct winexe_ctrl_state);
1749 status = winexe_pipes_recv(subreq);
1750 TALLOC_FREE(subreq);
1751 if (tevent_req_nterror(req, status)) {
1755 state->pipes_req = NULL;
1756 if (state->ctrl_pipe_done) {
1757 tevent_req_done(req);
1761 static NTSTATUS winexe_ctrl_recv(struct tevent_req *req,
1764 struct winexe_ctrl_state *state = tevent_req_data(
1765 req, struct winexe_ctrl_state);
1768 if (tevent_req_is_nterror(req, &status)) {
1771 if (preturn_code != NULL) {
1772 *preturn_code = state->return_code;
1774 return NT_STATUS_OK;
1777 static NTSTATUS winexe_ctrl(struct cli_state *cli,
1781 struct tevent_context *ev = NULL;
1782 struct tevent_req *req = NULL;
1783 NTSTATUS status = NT_STATUS_NO_MEMORY;
1786 ev = samba_tevent_context_init(cli);
1790 req = winexe_ctrl_send(ev, ev, cli, cmd);
1794 ok = tevent_req_poll_ntstatus(req, ev, &status);
1798 status = winexe_ctrl_recv(req, preturn_code);
1805 #ifdef HAVE_WINEXE_CC_WIN32
1806 const DATA_BLOB *winexesvc32_exe_binary(void);
1809 #ifdef HAVE_WINEXE_CC_WIN64
1810 const DATA_BLOB *winexesvc64_exe_binary(void);
1813 int main(int argc, char *argv[])
1815 TALLOC_CTX *frame = talloc_stackframe();
1816 const char **const_argv = discard_const_p(const char *, argv);
1817 struct program_options options = {0};
1818 struct cli_state *cli = NULL;
1819 const char *service_name = SERVICE_NAME;
1820 char *service_filename = NULL;
1821 #ifdef HAVE_WINEXE_CC_WIN32
1822 const DATA_BLOB *winexesvc32_exe = winexesvc32_exe_binary();
1824 const DATA_BLOB *winexesvc32_exe = NULL;
1826 #ifdef HAVE_WINEXE_CC_WIN64
1827 const DATA_BLOB *winexesvc64_exe = winexesvc64_exe_binary();
1829 const DATA_BLOB *winexesvc64_exe = NULL;
1833 int return_code = 0;
1837 parse_args(argc, const_argv, frame, &options);
1839 samba_cmdline_burn(argc, argv);
1841 if (options.cmd == NULL) {
1842 fprintf(stderr, "no cmd given\n");
1846 service_filename = talloc_asprintf(frame, "%s.exe", service_name);
1847 if (service_filename == NULL) {
1848 DBG_WARNING("talloc_asprintf failed\n");
1852 status = cli_full_connection_creds(
1860 options.credentials,
1861 CLI_FULL_CONNECTION_IPC);
1863 if (!NT_STATUS_IS_OK(status)) {
1864 DBG_WARNING("cli_full_connection_creds failed: %s\n",
1869 status = winexe_svc_install(
1877 options.credentials,
1879 if (!NT_STATUS_IS_OK(status)) {
1880 DBG_WARNING("winexe_svc_install failed: %s\n",
1885 status = winexe_ctrl(cli, options.cmd, &return_code);
1886 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1888 status = NT_STATUS_OK;
1890 if (!NT_STATUS_IS_OK(status)) {
1891 DBG_WARNING("cli_ctrl failed: %s\n",
1896 if (options.flags & SVC_UNINSTALL) {
1897 status = winexe_svc_uninstall(
1900 if (!NT_STATUS_IS_OK(status)) {
1901 DBG_WARNING("winexe_svc_uninstall failed: %s\n",