ctdb-daemon: Modernise debug in ctdb_add_public_address()
[samba.git] / examples / winexe / winexe.c
blob8a17107617cc923a25f9cd5c5ba8dd226d085306
1 /*
2 * Samba Unix/Linux CIFS implementation
4 * winexe
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/>.
22 #include "includes.h"
23 #include "version.h"
24 #include <popt.h>
25 #include <tevent.h>
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"
38 #include "client.h"
40 #define SVC_INTERACTIVE 1
41 #define SVC_IGNORE_INTERACTIVE 2
42 #define SVC_INTERACTIVE_MASK 3
43 #define SVC_FORCE_UPLOAD 4
44 #define SVC_OS64BIT 8
45 #define SVC_OSCHOOSE 16
46 #define SVC_UNINSTALL 32
47 #define SVC_SYSTEM 64
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 "
58 "GNU GPLv3\n";
60 struct program_options {
61 char *hostname;
62 int port;
63 char *cmd;
64 struct cli_credentials *credentials;
65 char *runas;
66 char *runas_file;
67 int flags;
70 static void parse_args(int argc, const char *argv[],
71 TALLOC_CTX *mem_ctx,
72 struct program_options *options)
74 poptContext pc;
75 int opt, i;
77 int argc_new;
78 char **argv_new;
80 int port = 445;
81 char *port_str = NULL;
83 int flag_interactive = SVC_IGNORE_INTERACTIVE;
84 int flag_ostype = 2;
85 int flag_reinstall = 0;
86 int flag_uninstall = 0;
87 int flag_help = 0;
88 int flag_version = 0;
89 bool ok;
91 struct poptOption long_options[] = {
92 POPT_AUTOHELP
94 .longName = "uninstall",
95 .shortName = 0,
96 .argInfo = POPT_ARG_NONE,
97 .arg = &flag_uninstall,
98 .val = 0,
99 .descrip = "Uninstall winexe service after "
100 "remote execution",
101 .argDescrip = NULL,
103 .longName = "reinstall",
104 .shortName = 0,
105 .argInfo = POPT_ARG_NONE,
106 .arg = &flag_reinstall,
107 .val = 0,
108 .descrip = "Reinstall winexe service before "
109 "remote execution",
110 .argDescrip = NULL,
112 .longName = "runas",
113 .shortName = 0,
114 .argInfo = POPT_ARG_STRING,
115 .arg = &options->runas,
116 .val = 0,
117 .descrip = "Run as the given user (BEWARE: this "
118 "password is sent in cleartext over "
119 "the network!)",
120 .argDescrip = "[DOMAIN\\]USERNAME%PASSWORD",
122 .longName = "runas-file",
123 .shortName = 0,
124 .argInfo = POPT_ARG_STRING,
125 .arg = &options->runas_file,
126 .val = 0,
127 .descrip = "Run as user options defined in a file",
128 .argDescrip = "FILE",
130 .longName = "interactive",
131 .shortName = 0,
132 .argInfo = POPT_ARG_INT,
133 .arg = &flag_interactive,
134 .val = 0,
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.",
139 .argDescrip = "0|1",
141 .longName = "ostype",
142 .shortName = 0,
143 .argInfo = POPT_ARG_INT,
144 .arg = &flag_ostype,
145 .val = 0,
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",
152 POPT_COMMON_SAMBA
153 POPT_COMMON_CREDENTIALS
154 POPT_COMMON_VERSION
155 POPT_TABLEEND
158 ZERO_STRUCTP(options);
160 ok = samba_cmdline_init(mem_ctx,
161 SAMBA_CMDLINE_CONFIG_CLIENT,
162 false /* require_smbconf */);
163 if (!ok) {
164 DBG_ERR("Failed to init cmdline parser!\n");
165 TALLOC_FREE(mem_ctx);
166 exit(1);
169 pc = samba_popt_get_context(getprogname(),
170 argc,
171 argv,
172 long_options,
174 if (pc == NULL) {
175 DBG_ERR("Failed to setup popt context!\n");
176 TALLOC_FREE(mem_ctx);
177 exit(1);
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);
185 if (flag_version) {
186 exit(0);
188 poptPrintHelp(pc, stdout, 0);
189 if (flag_help) {
190 exit(0);
192 exit(1);
195 argv_new = discard_const_p(char *, poptGetArgs(pc));
197 argc_new = argc;
198 for (i = 0; i < argc; i++) {
199 if (!argv_new || argv_new[i] == NULL) {
200 argc_new = i;
201 break;
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);
209 exit(1);
212 port_str = strchr(argv_new[0], ':');
213 if (port_str) {
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);
218 exit(1);
220 *port_str = '\0';
223 if (options->runas == NULL && options->runas_file != NULL) {
224 struct cli_credentials *runas_cred;
225 const char *user;
226 const char *pass;
228 runas_cred = cli_credentials_init(mem_ctx);
229 cli_credentials_parse_file(runas_cred, options->runas_file,
230 CRED_SPECIFIED);
232 user = cli_credentials_get_username(runas_cred);
233 pass = cli_credentials_get_password(runas_cred);
235 if (user && pass) {
236 char buffer[1024];
237 const char *dom;
239 dom = cli_credentials_get_domain(runas_cred);
240 if (dom) {
241 snprintf(buffer, sizeof(buffer), "%s\\%s%%%s",
242 dom, user, pass);
243 } else {
244 snprintf(buffer, sizeof(buffer), "%s%%%s",
245 user, pass);
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");
257 exit(1);
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");
263 exit(1);
266 poptFreeContext(pc);
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,
285 int port,
286 const char *service_filename,
287 const DATA_BLOB *svc32_exe,
288 const DATA_BLOB *svc64_exe,
289 struct cli_credentials *credentials,
290 int flags)
292 struct cli_state *cli;
293 uint16_t fnum = 0xffff;
294 NTSTATUS status;
295 const DATA_BLOB *binary = NULL;
297 status = cli_full_connection_creds(
298 &cli,
299 NULL,
300 hostname,
301 NULL,
302 port,
303 "ADMIN$",
304 "?????",
305 credentials,
307 if (!NT_STATUS_IS_OK(status)) {
308 DBG_WARNING("cli_full_connection_creds failed: %s\n",
309 nt_errstr(status));
310 return status;
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",
317 nt_errstr(status));
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) {
329 binary = svc64_exe;
330 } else {
331 binary = svc32_exe;
334 if (binary == NULL) {
335 goto done;
338 status = cli_ntcreate(
339 cli,
340 service_filename,
341 0, /* CreatFlags */
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 */
348 &fnum,
349 NULL); /* CreateReturns */
350 if (!NT_STATUS_IS_OK(status)) {
351 DBG_WARNING("Could not create %s: %s\n", service_filename,
352 nt_errstr(status));
353 goto done;
356 status = cli_writeall(
357 cli,
358 fnum,
360 binary->data,
362 binary->length,
363 NULL);
364 if (!NT_STATUS_IS_OK(status)) {
365 DBG_WARNING("Could not write file: %s\n", nt_errstr(status));
366 goto done;
369 done:
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",
374 fnum,
375 service_filename,
376 nt_errstr(status));
380 TALLOC_FREE(cli);
381 return status;
384 static NTSTATUS winexe_svc_install(
385 struct cli_state *cli,
386 const char *hostname,
387 int port,
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,
393 int flags)
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;
402 NTSTATUS status;
403 WERROR werr;
404 const char *remote_name = smbXcli_conn_remote_name(cli->conn);
405 const struct sockaddr_storage *remote_sockaddr =
406 smbXcli_conn_remote_sockaddr(cli->conn);
408 status = cli_rpc_pipe_open_noauth_transport(
409 cli,
410 NCACN_NP,
411 &ndr_table_svcctl,
412 remote_name,
413 remote_sockaddr,
414 &rpccli);
415 if (!NT_STATUS_IS_OK(status)) {
416 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
417 nt_errstr(status));
418 goto done;
421 status = dcerpc_svcctl_OpenSCManagerW(
422 rpccli->binding_handle,
423 frame,
424 remote_name,
425 NULL,
426 SEC_FLAG_MAXIMUM_ALLOWED,
427 &scmanager_handle,
428 &werr);
429 if (!NT_STATUS_IS_OK(status)) {
430 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
431 nt_errstr(status));
432 goto done;
434 if (!W_ERROR_IS_OK(werr)) {
435 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
436 win_errstr(werr));
437 goto done;
440 status = dcerpc_svcctl_OpenServiceW(
441 rpccli->binding_handle,
442 frame,
443 &scmanager_handle,
444 service_name,
445 SERVICE_ALL_ACCESS,
446 &service_handle,
447 &werr);
448 if (!NT_STATUS_IS_OK(status)) {
449 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
450 nt_errstr(status));
451 goto close_scmanager;
454 if (W_ERROR_EQUAL(werr, WERR_SERVICE_DOES_NOT_EXIST)) {
455 status = dcerpc_svcctl_CreateServiceW(
456 rpccli->binding_handle,
457 frame,
458 &scmanager_handle,
459 service_name,
460 NULL,
461 SERVICE_ALL_ACCESS,
462 SERVICE_TYPE_WIN32_OWN_PROCESS |
463 ((flags & SVC_INTERACTIVE) ?
464 SERVICE_TYPE_INTERACTIVE_PROCESS : 0),
465 SVCCTL_DEMAND_START,
466 SVCCTL_SVC_ERROR_NORMAL,
467 service_filename,
468 NULL,
469 NULL,
470 NULL,
472 NULL,
473 NULL,
475 &service_handle,
476 &werr);
477 if (!NT_STATUS_IS_OK(status)) {
478 DBG_WARNING("dcerpc_svcctl_CreateServiceW "
479 "failed: %s\n", nt_errstr(status));
480 goto close_scmanager;
482 if (!W_ERROR_IS_OK(werr)) {
483 DBG_WARNING("dcerpc_svcctl_CreateServiceW "
484 "failed: %s\n", win_errstr(werr));
485 status = werror_to_ntstatus(werr);
486 goto close_scmanager;
490 status = dcerpc_svcctl_QueryServiceStatus(
491 rpccli->binding_handle,
492 frame,
493 &service_handle,
494 &service_status,
495 &werr);
497 if (!NT_STATUS_IS_OK(status)) {
498 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
499 "failed: %s\n", nt_errstr(status));
500 goto close_service;
502 if (!W_ERROR_IS_OK(werr)) {
503 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
504 "failed: %s\n", win_errstr(werr));
505 status = werror_to_ntstatus(werr);
506 goto close_service;
509 if (!(flags & SVC_IGNORE_INTERACTIVE)) {
510 need_conf =
511 !(service_status.type &
512 SERVICE_TYPE_INTERACTIVE_PROCESS) ^
513 !(flags & SVC_INTERACTIVE);
516 if (service_status.state == SVCCTL_STOPPED) {
517 need_start = true;
518 } else if (need_conf) {
519 status = dcerpc_svcctl_ControlService(
520 rpccli->binding_handle,
521 frame,
522 &service_handle,
523 SVCCTL_CONTROL_STOP,
524 &service_status,
525 &werr);
527 if (!NT_STATUS_IS_OK(status)) {
528 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
529 "failed: %s\n", nt_errstr(status));
530 goto close_service;
532 if (!W_ERROR_IS_OK(werr)) {
533 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
534 "failed: %s\n", win_errstr(werr));
535 status = werror_to_ntstatus(werr);
536 goto close_service;
539 do {
540 smb_msleep(100);
542 status = dcerpc_svcctl_QueryServiceStatus(
543 rpccli->binding_handle,
544 frame,
545 &service_handle,
546 &service_status,
547 &werr);
549 if (!NT_STATUS_IS_OK(status)) {
550 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
551 "failed: %s\n", nt_errstr(status));
552 goto close_service;
554 if (!W_ERROR_IS_OK(werr)) {
555 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
556 "failed: %s\n", win_errstr(werr));
557 status = werror_to_ntstatus(werr);
558 goto close_service;
560 } while (service_status.state == SVCCTL_STOP_PENDING);
562 need_start = 1;
565 if (need_conf) {
566 status = dcerpc_svcctl_ChangeServiceConfigW(
567 rpccli->binding_handle,
568 frame,
569 &service_handle,
570 SERVICE_TYPE_WIN32_OWN_PROCESS |
571 ((flags & SVC_INTERACTIVE) ?
572 SERVICE_TYPE_INTERACTIVE_PROCESS : 0), /* type */
573 UINT32_MAX, /* start_type, SERVICE_NO_CHANGE */
574 UINT32_MAX, /* error_control, SERVICE_NO_CHANGE */
575 NULL, /* binary_path */
576 NULL, /* load_order_group */
577 NULL, /* tag_id */
578 NULL, /* dependencies */
579 0, /* dwDependSize */
580 NULL, /* service_start_name */
581 NULL, /* password */
582 0, /* dwPwSize */
583 NULL, /* display_name */
584 &werr);
586 if (!NT_STATUS_IS_OK(status)) {
587 DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
588 "failed: %s\n", nt_errstr(status));
589 goto close_service;
591 if (!W_ERROR_IS_OK(werr)) {
592 DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
593 "failed: %s\n", win_errstr(werr));
594 status = werror_to_ntstatus(werr);
595 goto close_service;
599 if (need_start) {
600 status = winexe_svc_upload(
601 hostname,
602 port,
603 service_filename,
604 svc32_exe,
605 svc64_exe,
606 credentials,
607 flags);
608 if (!NT_STATUS_IS_OK(status)) {
609 DBG_WARNING("winexe_svc_upload failed: %s\n",
610 nt_errstr(status));
611 goto close_service;
614 status = dcerpc_svcctl_StartServiceW(
615 rpccli->binding_handle,
616 frame,
617 &service_handle,
618 0, /* num_args */
619 NULL, /* arguments */
620 &werr);
622 if (!NT_STATUS_IS_OK(status)) {
623 DBG_WARNING("dcerpc_svcctl_StartServiceW "
624 "failed: %s\n", nt_errstr(status));
625 goto close_service;
627 if (!W_ERROR_IS_OK(werr)) {
628 DBG_WARNING("dcerpc_svcctl_StartServiceW "
629 "failed: %s\n", win_errstr(werr));
630 status = werror_to_ntstatus(werr);
631 goto close_service;
634 do {
635 smb_msleep(100);
637 status = dcerpc_svcctl_QueryServiceStatus(
638 rpccli->binding_handle,
639 frame,
640 &service_handle,
641 &service_status,
642 &werr);
644 if (!NT_STATUS_IS_OK(status)) {
645 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
646 "failed: %s\n", nt_errstr(status));
647 goto close_service;
649 if (!W_ERROR_IS_OK(werr)) {
650 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
651 "failed: %s\n", win_errstr(werr));
652 status = werror_to_ntstatus(werr);
653 goto close_service;
655 } while (service_status.state == SVCCTL_START_PENDING);
657 if (service_status.state != SVCCTL_RUNNING) {
658 DBG_WARNING("Failed to start service\n");
659 status = NT_STATUS_UNSUCCESSFUL;
660 goto close_service;
664 close_service:
666 NTSTATUS close_status;
667 WERROR close_werr;
669 close_status = dcerpc_svcctl_CloseServiceHandle(
670 rpccli->binding_handle,
671 frame,
672 &service_handle,
673 &close_werr);
674 if (!NT_STATUS_IS_OK(close_status)) {
675 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
676 "failed: %s\n", nt_errstr(close_status));
677 goto done;
679 if (!W_ERROR_IS_OK(close_werr)) {
680 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
681 " failed: %s\n", win_errstr(close_werr));
682 goto done;
686 close_scmanager:
688 NTSTATUS close_status;
689 WERROR close_werr;
691 close_status = dcerpc_svcctl_CloseServiceHandle(
692 rpccli->binding_handle,
693 frame,
694 &scmanager_handle,
695 &close_werr);
696 if (!NT_STATUS_IS_OK(close_status)) {
697 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
698 "failed: %s\n", nt_errstr(close_status));
699 goto done;
701 if (!W_ERROR_IS_OK(close_werr)) {
702 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
703 " failed: %s\n", win_errstr(close_werr));
704 goto done;
708 done:
709 TALLOC_FREE(rpccli);
710 TALLOC_FREE(frame);
711 return status;
714 static NTSTATUS winexe_svc_uninstall(
715 struct cli_state *cli,
716 const char *service_name)
718 TALLOC_CTX *frame = talloc_stackframe();
719 struct rpc_pipe_client *rpccli;
720 struct policy_handle scmanager_handle;
721 struct policy_handle service_handle;
722 struct SERVICE_STATUS service_status;
723 NTSTATUS status;
724 WERROR werr;
725 const char *remote_name = smbXcli_conn_remote_name(cli->conn);
726 const struct sockaddr_storage *remote_sockaddr =
727 smbXcli_conn_remote_sockaddr(cli->conn);
729 status = cli_rpc_pipe_open_noauth_transport(
730 cli,
731 NCACN_NP,
732 &ndr_table_svcctl,
733 remote_name,
734 remote_sockaddr,
735 &rpccli);
736 if (!NT_STATUS_IS_OK(status)) {
737 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
738 nt_errstr(status));
739 goto done;
742 status = dcerpc_svcctl_OpenSCManagerW(
743 rpccli->binding_handle,
744 frame,
745 remote_name,
746 NULL,
747 SEC_FLAG_MAXIMUM_ALLOWED,
748 &scmanager_handle,
749 &werr);
750 if (!NT_STATUS_IS_OK(status)) {
751 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
752 nt_errstr(status));
753 goto done;
755 if (!W_ERROR_IS_OK(werr)) {
756 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
757 win_errstr(werr));
758 goto done;
761 status = dcerpc_svcctl_OpenServiceW(
762 rpccli->binding_handle,
763 frame,
764 &scmanager_handle,
765 service_name,
766 SERVICE_ALL_ACCESS,
767 &service_handle,
768 &werr);
769 if (!NT_STATUS_IS_OK(status)) {
770 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
771 nt_errstr(status));
772 goto close_scmanager;
774 if (!W_ERROR_IS_OK(werr)) {
775 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
776 win_errstr(werr));
777 status = werror_to_ntstatus(werr);
778 goto close_scmanager;
781 status = dcerpc_svcctl_ControlService(
782 rpccli->binding_handle,
783 frame,
784 &service_handle,
785 SVCCTL_CONTROL_STOP,
786 &service_status,
787 &werr);
788 if (!NT_STATUS_IS_OK(status)) {
789 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
790 "failed: %s\n", nt_errstr(status));
791 goto close_service;
793 if (!W_ERROR_IS_OK(werr)) {
794 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
795 "failed: %s\n", win_errstr(werr));
796 status = werror_to_ntstatus(werr);
797 goto close_service;
800 do {
801 smb_msleep(100);
803 status = dcerpc_svcctl_QueryServiceStatus(
804 rpccli->binding_handle,
805 frame,
806 &service_handle,
807 &service_status,
808 &werr);
810 if (!NT_STATUS_IS_OK(status)) {
811 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
812 "failed: %s\n", nt_errstr(status));
813 goto close_service;
815 if (!W_ERROR_IS_OK(werr)) {
816 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
817 "failed: %s\n", win_errstr(werr));
818 status = werror_to_ntstatus(werr);
819 goto close_service;
821 } while (service_status.state != SVCCTL_STOPPED);
823 status = dcerpc_svcctl_DeleteService(
824 rpccli->binding_handle,
825 frame,
826 &service_handle,
827 &werr);
828 if (!NT_STATUS_IS_OK(status)) {
829 DBG_WARNING("dcerpc_svcctl_DeleteService "
830 "failed: %s\n", nt_errstr(status));
831 goto close_service;
833 if (!W_ERROR_IS_OK(werr)) {
834 DBG_WARNING("dcerpc_svcctl_DeleteService "
835 "failed: %s\n", win_errstr(werr));
836 status = werror_to_ntstatus(werr);
837 goto close_service;
840 close_service:
842 NTSTATUS close_status;
843 WERROR close_werr;
845 close_status = dcerpc_svcctl_CloseServiceHandle(
846 rpccli->binding_handle,
847 frame,
848 &service_handle,
849 &close_werr);
850 if (!NT_STATUS_IS_OK(close_status)) {
851 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
852 "failed: %s\n", nt_errstr(close_status));
853 goto done;
855 if (!W_ERROR_IS_OK(close_werr)) {
856 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
857 " failed: %s\n", win_errstr(close_werr));
858 goto done;
862 close_scmanager:
864 NTSTATUS close_status;
865 WERROR close_werr;
867 close_status = dcerpc_svcctl_CloseServiceHandle(
868 rpccli->binding_handle,
869 frame,
870 &scmanager_handle,
871 &close_werr);
872 if (!NT_STATUS_IS_OK(close_status)) {
873 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
874 "failed: %s\n", nt_errstr(close_status));
875 goto done;
877 if (!W_ERROR_IS_OK(close_werr)) {
878 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
879 " failed: %s\n", win_errstr(close_werr));
880 goto done;
884 done:
885 TALLOC_FREE(rpccli);
886 TALLOC_FREE(frame);
887 return status;
890 struct winexe_out_pipe_state {
891 struct tevent_context *ev;
892 struct cli_state *cli;
893 uint16_t out_pipe;
894 int out_fd;
895 char out_inbuf[256];
898 static void winexe_out_pipe_opened(struct tevent_req *subreq);
899 static void winexe_out_pipe_got_data(struct tevent_req *subreq);
900 static void winexe_out_pipe_closed(struct tevent_req *subreq);
902 static struct tevent_req *winexe_out_pipe_send(
903 TALLOC_CTX *mem_ctx,
904 struct tevent_context *ev,
905 struct cli_state *cli,
906 const char *pipe_name,
907 int out_fd)
909 struct tevent_req *req, *subreq;
910 struct winexe_out_pipe_state *state;
912 req = tevent_req_create(mem_ctx, &state,
913 struct winexe_out_pipe_state);
914 if (req == NULL) {
915 return NULL;
917 state->ev = ev;
918 state->cli = cli;
919 state->out_fd = out_fd;
921 subreq = cli_ntcreate_send(
922 state,
923 state->ev,
924 state->cli,
925 pipe_name,
927 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
928 SEC_RIGHTS_FILE_EXECUTE,
929 0, /* FileAttributes */
930 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
931 FILE_OPEN, /* CreateDisposition */
932 0, /* CreateOptions */
933 SMB2_IMPERSONATION_IMPERSONATION,
934 0); /* SecurityFlags */
935 if (tevent_req_nomem(subreq, req)) {
936 return tevent_req_post(req, ev);
938 tevent_req_set_callback(subreq, winexe_out_pipe_opened, req);
939 return req;
942 static void winexe_out_pipe_opened(struct tevent_req *subreq)
944 struct tevent_req *req = tevent_req_callback_data(
945 subreq, struct tevent_req);
946 struct winexe_out_pipe_state *state = tevent_req_data(
947 req, struct winexe_out_pipe_state);
948 int timeout;
949 NTSTATUS status;
951 status = cli_ntcreate_recv(subreq, &state->out_pipe, NULL);
952 TALLOC_FREE(subreq);
953 if (tevent_req_nterror(req, status)) {
954 return;
957 timeout = state->cli->timeout;
958 state->cli->timeout = 0;
960 subreq = cli_read_send(
961 state,
962 state->ev,
963 state->cli,
964 state->out_pipe,
965 state->out_inbuf,
967 sizeof(state->out_inbuf));
969 state->cli->timeout = timeout;
971 if (tevent_req_nomem(subreq, req)) {
972 return;
974 tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
977 static void winexe_out_pipe_got_data(struct tevent_req *subreq)
979 struct tevent_req *req = tevent_req_callback_data(
980 subreq, struct tevent_req);
981 struct winexe_out_pipe_state *state = tevent_req_data(
982 req, struct winexe_out_pipe_state);
983 NTSTATUS status;
984 int timeout;
985 size_t received;
986 ssize_t written;
988 status = cli_read_recv(subreq, &received);
989 TALLOC_FREE(subreq);
991 DBG_DEBUG("cli_read for %d gave %s\n",
992 state->out_fd,
993 nt_errstr(status));
995 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
996 subreq = cli_close_send(
997 state,
998 state->ev,
999 state->cli,
1000 state->out_pipe);
1001 if (tevent_req_nomem(subreq, req)) {
1002 return;
1004 tevent_req_set_callback(subreq, winexe_out_pipe_closed, req);
1005 return;
1008 if (tevent_req_nterror(req, status)) {
1009 return;
1012 if (received > 0) {
1013 written = sys_write(state->out_fd, state->out_inbuf, received);
1014 if (written == -1) {
1015 tevent_req_nterror(req, map_nt_error_from_unix(errno));
1016 return;
1020 timeout = state->cli->timeout;
1021 state->cli->timeout = 0;
1023 subreq = cli_read_send(
1024 state,
1025 state->ev,
1026 state->cli,
1027 state->out_pipe,
1028 state->out_inbuf,
1030 sizeof(state->out_inbuf));
1032 state->cli->timeout = timeout;
1034 if (tevent_req_nomem(subreq, req)) {
1035 return;
1037 tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
1040 static void winexe_out_pipe_closed(struct tevent_req *subreq)
1042 struct tevent_req *req = tevent_req_callback_data(
1043 subreq, struct tevent_req);
1044 NTSTATUS status;
1046 status = cli_close_recv(subreq);
1047 TALLOC_FREE(subreq);
1048 if (tevent_req_nterror(req, status)) {
1049 return;
1051 tevent_req_done(req);
1054 static NTSTATUS winexe_out_pipe_recv(struct tevent_req *req)
1056 return tevent_req_simple_recv_ntstatus(req);
1059 struct winexe_in_pipe_state {
1060 struct tevent_context *ev;
1061 struct cli_state *cli;
1062 struct tevent_req *fd_read_req;
1063 bool close_requested;
1064 bool closing;
1065 uint16_t in_pipe;
1066 int in_fd;
1067 char inbuf[256];
1070 static void winexe_in_pipe_opened(struct tevent_req *subreq);
1071 static void winexe_in_pipe_got_data(struct tevent_req *subreq);
1072 static void winexe_in_pipe_written(struct tevent_req *subreq);
1073 static void winexe_in_pipe_closed(struct tevent_req *subreq);
1075 static struct tevent_req *winexe_in_pipe_send(
1076 TALLOC_CTX *mem_ctx,
1077 struct tevent_context *ev,
1078 struct cli_state *cli,
1079 const char *pipe_name,
1080 int in_fd)
1082 struct tevent_req *req, *subreq;
1083 struct winexe_in_pipe_state *state;
1085 req = tevent_req_create(mem_ctx, &state,
1086 struct winexe_in_pipe_state);
1087 if (req == NULL) {
1088 return NULL;
1090 state->ev = ev;
1091 state->cli = cli;
1092 state->in_fd = in_fd;
1094 subreq = cli_ntcreate_send(
1095 state,
1096 state->ev,
1097 state->cli,
1098 pipe_name,
1100 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
1101 SEC_RIGHTS_FILE_EXECUTE,
1102 0, /* FileAttributes */
1103 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1104 FILE_OPEN, /* CreateDisposition */
1105 0, /* CreateOptions */
1106 SMB2_IMPERSONATION_IMPERSONATION,
1107 0); /* SecurityFlags */
1108 if (tevent_req_nomem(subreq, req)) {
1109 return tevent_req_post(req, ev);
1111 tevent_req_set_callback(subreq, winexe_in_pipe_opened, req);
1112 return req;
1115 static void winexe_in_pipe_opened(struct tevent_req *subreq)
1117 struct tevent_req *req = tevent_req_callback_data(
1118 subreq, struct tevent_req);
1119 struct winexe_in_pipe_state *state = tevent_req_data(
1120 req, struct winexe_in_pipe_state);
1121 NTSTATUS status;
1123 status = cli_ntcreate_recv(subreq, &state->in_pipe, NULL);
1124 TALLOC_FREE(subreq);
1125 if (tevent_req_nterror(req, status)) {
1126 return;
1129 subreq = wait_for_read_send(
1130 state,
1131 state->ev,
1132 state->in_fd,
1133 true);
1134 if (tevent_req_nomem(subreq, req)) {
1135 return;
1137 tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
1139 state->fd_read_req = subreq;
1142 static void winexe_in_pipe_got_data(struct tevent_req *subreq)
1144 struct tevent_req *req = tevent_req_callback_data(
1145 subreq, struct tevent_req);
1146 struct winexe_in_pipe_state *state = tevent_req_data(
1147 req, struct winexe_in_pipe_state);
1148 int err;
1149 bool ok;
1150 int timeout;
1151 ssize_t nread;
1153 ok = wait_for_read_recv(subreq, &err);
1154 TALLOC_FREE(subreq);
1155 if (!ok) {
1156 tevent_req_nterror(req, map_nt_error_from_unix(err));
1157 return;
1159 state->fd_read_req = NULL;
1161 nread = sys_read(state->in_fd, &state->inbuf, sizeof(state->inbuf));
1162 if (nread == -1) {
1163 tevent_req_nterror(req, map_nt_error_from_unix(errno));
1164 return;
1166 if (nread == 0) {
1167 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
1168 return;
1171 timeout = state->cli->timeout;
1172 state->cli->timeout = 0;
1174 subreq = cli_writeall_send(
1175 state,
1176 state->ev,
1177 state->cli,
1178 state->in_pipe,
1180 (uint8_t *)state->inbuf,
1182 nread);
1184 state->cli->timeout = timeout;
1186 if (tevent_req_nomem(subreq, req)) {
1187 return;
1189 tevent_req_set_callback(subreq, winexe_in_pipe_written, req);
1192 static void winexe_in_pipe_written(struct tevent_req *subreq)
1194 struct tevent_req *req = tevent_req_callback_data(
1195 subreq, struct tevent_req);
1196 struct winexe_in_pipe_state *state = tevent_req_data(
1197 req, struct winexe_in_pipe_state);
1198 NTSTATUS status;
1200 status = cli_writeall_recv(subreq, NULL);
1201 TALLOC_FREE(subreq);
1203 DBG_DEBUG("cli_writeall for %d gave %s\n",
1204 state->in_fd,
1205 nt_errstr(status));
1207 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED) ||
1208 state->close_requested) {
1209 subreq = cli_close_send(
1210 state,
1211 state->ev,
1212 state->cli,
1213 state->in_pipe);
1214 if (tevent_req_nomem(subreq, req)) {
1215 return;
1217 tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1218 state->closing = true;
1219 return;
1222 if (tevent_req_nterror(req, status)) {
1223 return;
1226 subreq = wait_for_read_send(
1227 state,
1228 state->ev,
1229 state->in_fd,
1230 true);
1231 if (tevent_req_nomem(subreq, req)) {
1232 return;
1234 tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
1236 state->fd_read_req = subreq;
1239 static void winexe_in_pipe_closed(struct tevent_req *subreq)
1241 struct tevent_req *req = tevent_req_callback_data(
1242 subreq, struct tevent_req);
1243 NTSTATUS status;
1245 status = cli_close_recv(subreq);
1246 TALLOC_FREE(subreq);
1247 if (tevent_req_nterror(req, status)) {
1248 return;
1250 return tevent_req_done(req);
1253 static NTSTATUS winexe_in_pipe_recv(struct tevent_req *req)
1255 return tevent_req_simple_recv_ntstatus(req);
1258 static bool winexe_in_pipe_close(struct tevent_req *req)
1260 struct winexe_in_pipe_state *state = tevent_req_data(
1261 req, struct winexe_in_pipe_state);
1262 struct tevent_req *subreq;
1264 if (state->closing) {
1265 return true;
1268 if (state->fd_read_req == NULL) {
1270 * cli_writeall active, wait for it to return
1272 state->close_requested = true;
1273 return true;
1276 TALLOC_FREE(state->fd_read_req);
1278 subreq = cli_close_send(
1279 state,
1280 state->ev,
1281 state->cli,
1282 state->in_pipe);
1283 if (subreq == NULL) {
1284 return false;
1286 tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1287 state->closing = true;
1289 return true;
1292 struct winexe_pipes_state {
1293 struct tevent_req *pipes[3];
1296 static void winexe_pipes_stdin_done(struct tevent_req *subreq);
1297 static void winexe_pipes_stdout_done(struct tevent_req *subreq);
1298 static void winexe_pipes_stderr_done(struct tevent_req *subreq);
1300 static struct tevent_req *winexe_pipes_send(
1301 TALLOC_CTX *mem_ctx,
1302 struct tevent_context *ev,
1303 struct cli_state *cli,
1304 const char *pipe_postfix)
1306 struct tevent_req *req;
1307 struct winexe_pipes_state *state;
1308 char *pipe_name;
1310 req = tevent_req_create(mem_ctx, &state, struct winexe_pipes_state);
1311 if (req == NULL) {
1312 return NULL;
1315 pipe_name = talloc_asprintf(state, "\\ahexec_stdin%s", pipe_postfix);
1316 if (tevent_req_nomem(pipe_name, req)) {
1317 return tevent_req_post(req, ev);
1319 state->pipes[0] = winexe_in_pipe_send(
1320 state,
1322 cli,
1323 pipe_name,
1325 if (tevent_req_nomem(state->pipes[0], req)) {
1326 return tevent_req_post(req, ev);
1328 tevent_req_set_callback(state->pipes[0], winexe_pipes_stdin_done, req);
1330 pipe_name = talloc_asprintf(state, "\\ahexec_stdout%s", pipe_postfix);
1331 if (tevent_req_nomem(pipe_name, req)) {
1332 return tevent_req_post(req, ev);
1334 state->pipes[1] = winexe_out_pipe_send(
1335 state,
1337 cli,
1338 pipe_name,
1340 if (tevent_req_nomem(state->pipes[1], req)) {
1341 return tevent_req_post(req, ev);
1343 tevent_req_set_callback(state->pipes[1], winexe_pipes_stdout_done,
1344 req);
1346 pipe_name = talloc_asprintf(state, "\\ahexec_stderr%s", pipe_postfix);
1347 if (tevent_req_nomem(pipe_name, req)) {
1348 return tevent_req_post(req, ev);
1350 state->pipes[2] = winexe_out_pipe_send(
1351 state,
1353 cli,
1354 pipe_name,
1356 if (tevent_req_nomem(state->pipes[2], req)) {
1357 return tevent_req_post(req, ev);
1359 tevent_req_set_callback(state->pipes[2], winexe_pipes_stderr_done,
1360 req);
1362 DBG_DEBUG("pipes = %p %p %p\n",
1363 state->pipes[0],
1364 state->pipes[1],
1365 state->pipes[2]);
1367 return req;
1370 static void winexe_pipes_stdin_done(struct tevent_req *subreq)
1372 struct tevent_req *req = tevent_req_callback_data(
1373 subreq, struct tevent_req);
1374 struct winexe_pipes_state *state = tevent_req_data(
1375 req, struct winexe_pipes_state);
1376 NTSTATUS status;
1378 status = winexe_in_pipe_recv(subreq);
1379 TALLOC_FREE(subreq);
1381 DBG_DEBUG("stdin returned %s\n", nt_errstr(status));
1383 if (tevent_req_nterror(req, status)) {
1384 return;
1387 state->pipes[0] = NULL;
1389 DBG_DEBUG("pipes = %p %p %p\n",
1390 state->pipes[0],
1391 state->pipes[1],
1392 state->pipes[2]);
1394 if ((state->pipes[1] == NULL) && (state->pipes[2] == NULL)) {
1395 tevent_req_done(req);
1399 static void winexe_pipes_stdout_done(struct tevent_req *subreq)
1401 struct tevent_req *req = tevent_req_callback_data(
1402 subreq, struct tevent_req);
1403 struct winexe_pipes_state *state = tevent_req_data(
1404 req, struct winexe_pipes_state);
1405 NTSTATUS status;
1407 status = winexe_out_pipe_recv(subreq);
1408 TALLOC_FREE(subreq);
1410 DBG_DEBUG("stdout returned %s\n", nt_errstr(status));
1412 if (tevent_req_nterror(req, status)) {
1413 return;
1416 if (state->pipes[0] != NULL) {
1417 winexe_in_pipe_close(state->pipes[0]);
1420 state->pipes[1] = NULL;
1422 DBG_DEBUG("pipes = %p %p %p\n",
1423 state->pipes[0],
1424 state->pipes[1],
1425 state->pipes[2]);
1427 if ((state->pipes[0] == NULL) && (state->pipes[2] == NULL)) {
1428 tevent_req_done(req);
1432 static void winexe_pipes_stderr_done(struct tevent_req *subreq)
1434 struct tevent_req *req = tevent_req_callback_data(
1435 subreq, struct tevent_req);
1436 struct winexe_pipes_state *state = tevent_req_data(
1437 req, struct winexe_pipes_state);
1438 NTSTATUS status;
1440 status = winexe_out_pipe_recv(subreq);
1441 TALLOC_FREE(subreq);
1443 DBG_DEBUG("stderr returned %s\n", nt_errstr(status));
1445 if (tevent_req_nterror(req, status)) {
1446 return;
1449 if (state->pipes[0] != NULL) {
1450 winexe_in_pipe_close(state->pipes[0]);
1453 state->pipes[2] = NULL;
1455 DBG_DEBUG("pipes = %p %p %p\n",
1456 state->pipes[0],
1457 state->pipes[1],
1458 state->pipes[2]);
1460 if ((state->pipes[0] == NULL) && (state->pipes[1] == NULL)) {
1461 tevent_req_done(req);
1465 static NTSTATUS winexe_pipes_recv(struct tevent_req *req)
1467 return tevent_req_simple_recv_ntstatus(req);
1470 struct winexe_ctrl_state {
1471 struct tevent_context *ev;
1472 struct cli_state *cli;
1474 uint16_t ctrl_pipe;
1475 bool ctrl_pipe_done;
1477 char ctrl_inbuf[256];
1478 char *cmd;
1479 int return_code;
1481 struct tevent_req *pipes_req;
1484 static void winexe_ctrl_opened(struct tevent_req *subreq);
1485 static void winexe_ctrl_got_read(struct tevent_req *subreq);
1486 static void winexe_ctrl_wrote_version(struct tevent_req *subreq);
1487 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq);
1488 static void winexe_ctrl_pipes_done(struct tevent_req *subreq);
1489 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq);
1491 static struct tevent_req *winexe_ctrl_send(
1492 TALLOC_CTX *mem_ctx,
1493 struct tevent_context *ev,
1494 struct cli_state *cli,
1495 const char *cmd)
1497 struct tevent_req *req, *subreq;
1498 struct winexe_ctrl_state *state;
1500 req = tevent_req_create(mem_ctx, &state,
1501 struct winexe_ctrl_state);
1502 if (req == NULL) {
1503 return NULL;
1505 state->ev = ev;
1506 state->cli = cli;
1508 state->cmd = talloc_asprintf(state, "run %s\n", cmd);
1509 if (tevent_req_nomem(state->cmd, req)) {
1510 return tevent_req_post(req, ev);
1513 subreq = cli_ntcreate_send(
1514 state,
1515 state->ev,
1516 state->cli,
1517 "\\" PIPE_NAME,
1519 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
1520 SEC_RIGHTS_FILE_EXECUTE,
1521 0, /* FileAttributes */
1522 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1523 FILE_OPEN, /* CreateDisposition */
1524 0, /* CreateOptions */
1525 SMB2_IMPERSONATION_IMPERSONATION,
1526 0); /* SecurityFlags */
1527 if (tevent_req_nomem(subreq, req)) {
1528 return tevent_req_post(req, ev);
1530 tevent_req_set_callback(subreq, winexe_ctrl_opened, req);
1531 return req;
1534 static void winexe_ctrl_opened(struct tevent_req *subreq)
1536 struct tevent_req *req = tevent_req_callback_data(
1537 subreq, struct tevent_req);
1538 struct winexe_ctrl_state *state = tevent_req_data(
1539 req, struct winexe_ctrl_state);
1540 int timeout;
1541 NTSTATUS status;
1542 static const char cmd[] = "get codepage\nget version\n";
1544 status = cli_ntcreate_recv(subreq, &state->ctrl_pipe, NULL);
1545 TALLOC_FREE(subreq);
1546 if (tevent_req_nterror(req, status)) {
1547 return;
1550 timeout = state->cli->timeout;
1551 state->cli->timeout = 0;
1553 subreq = cli_read_send(
1554 state,
1555 state->ev,
1556 state->cli,
1557 state->ctrl_pipe,
1558 state->ctrl_inbuf,
1560 sizeof(state->ctrl_inbuf)-1);
1562 state->cli->timeout = timeout;
1564 if (tevent_req_nomem(subreq, req)) {
1565 return;
1567 tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1569 subreq = cli_writeall_send(
1570 state,
1571 state->ev,
1572 state->cli,
1573 state->ctrl_pipe,
1575 (const uint8_t *)cmd,
1577 strlen(cmd));
1578 if (tevent_req_nomem(subreq, req)) {
1579 return;
1581 tevent_req_set_callback(subreq, winexe_ctrl_wrote_version, req);
1584 static void winexe_ctrl_got_read(struct tevent_req *subreq)
1586 struct tevent_req *req = tevent_req_callback_data(
1587 subreq, struct tevent_req);
1588 struct winexe_ctrl_state *state = tevent_req_data(
1589 req, struct winexe_ctrl_state);
1590 NTSTATUS status;
1591 int timeout;
1592 size_t received;
1593 unsigned int version, return_code;
1594 int ret;
1596 status = cli_read_recv(subreq, &received);
1597 TALLOC_FREE(subreq);
1599 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1600 subreq = cli_close_send(
1601 state,
1602 state->ev,
1603 state->cli,
1604 state->ctrl_pipe);
1605 if (tevent_req_nomem(subreq, req)) {
1606 return;
1608 tevent_req_set_callback(subreq, winexe_ctrl_pipe_closed, req);
1609 return;
1611 if (tevent_req_nterror(req, status)) {
1612 return;
1615 DBG_DEBUG("Got %zu bytes\n", received);
1617 timeout = state->cli->timeout;
1618 state->cli->timeout = 0;
1620 subreq = cli_read_send(
1621 state,
1622 state->ev,
1623 state->cli,
1624 state->ctrl_pipe,
1625 state->ctrl_inbuf,
1627 sizeof(state->ctrl_inbuf)-1);
1629 state->cli->timeout = timeout;
1631 if (tevent_req_nomem(subreq, req)) {
1632 return;
1634 tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1636 ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &version);
1637 if (ret == 1) {
1638 DBG_DEBUG("Got version %x\n", version);
1640 subreq = cli_writeall_send(
1641 state,
1642 state->ev,
1643 state->cli,
1644 state->ctrl_pipe,
1646 (const uint8_t *)state->cmd,
1648 strlen(state->cmd));
1649 if (tevent_req_nomem(subreq, req)) {
1650 return;
1652 tevent_req_set_callback(subreq, winexe_ctrl_wrote_cmd, req);
1653 return;
1656 ret = strncmp(state->ctrl_inbuf, "std_io_err ", strlen("std_io_err "));
1657 if (ret == 0) {
1658 char *p = state->ctrl_inbuf + 11;
1659 char *q = strchr(state->ctrl_inbuf, '\n');
1660 char *postfix;
1661 size_t postfix_len;
1663 if (q == NULL) {
1664 DBG_DEBUG("Got invalid pipe postfix\n");
1665 return;
1668 postfix_len = q - p;
1670 postfix = talloc_strndup(state, p, postfix_len);
1671 if (tevent_req_nomem(postfix, req)) {
1672 return;
1675 DBG_DEBUG("Got pipe postfix %s\n", postfix);
1677 subreq = winexe_pipes_send(
1678 state,
1679 state->ev,
1680 state->cli,
1681 postfix);
1682 if (tevent_req_nomem(subreq, req)) {
1683 return;
1685 tevent_req_set_callback(subreq, winexe_ctrl_pipes_done, req);
1687 state->pipes_req = subreq;
1689 return;
1692 ret = strncmp(state->ctrl_inbuf, "error ", strlen("error "));
1693 if (ret == 0) {
1694 printf("Error: %s", state->ctrl_inbuf);
1695 return;
1698 ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &return_code);
1699 if (ret == 1) {
1700 state->return_code = return_code;
1701 return;
1705 static void winexe_ctrl_wrote_version(struct tevent_req *subreq)
1707 struct tevent_req *req = tevent_req_callback_data(
1708 subreq, struct tevent_req);
1709 NTSTATUS status;
1711 status = cli_writeall_recv(subreq, NULL);
1712 TALLOC_FREE(subreq);
1713 if (tevent_req_nterror(req, status)) {
1714 return;
1718 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq)
1720 struct tevent_req *req = tevent_req_callback_data(
1721 subreq, struct tevent_req);
1722 NTSTATUS status;
1724 status = cli_writeall_recv(subreq, NULL);
1725 TALLOC_FREE(subreq);
1726 if (tevent_req_nterror(req, status)) {
1727 return;
1731 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq)
1733 struct tevent_req *req = tevent_req_callback_data(
1734 subreq, struct tevent_req);
1735 struct winexe_ctrl_state *state = tevent_req_data(
1736 req, struct winexe_ctrl_state);
1737 NTSTATUS status;
1739 status = cli_close_recv(subreq);
1740 TALLOC_FREE(subreq);
1741 if (tevent_req_nterror(req, status)) {
1742 return;
1745 state->ctrl_pipe_done = true;
1746 if (state->pipes_req == NULL) {
1747 tevent_req_done(req);
1751 static void winexe_ctrl_pipes_done(struct tevent_req *subreq)
1753 struct tevent_req *req = tevent_req_callback_data(
1754 subreq, struct tevent_req);
1755 struct winexe_ctrl_state *state = tevent_req_data(
1756 req, struct winexe_ctrl_state);
1757 NTSTATUS status;
1759 status = winexe_pipes_recv(subreq);
1760 TALLOC_FREE(subreq);
1761 if (tevent_req_nterror(req, status)) {
1762 return;
1765 state->pipes_req = NULL;
1766 if (state->ctrl_pipe_done) {
1767 tevent_req_done(req);
1771 static NTSTATUS winexe_ctrl_recv(struct tevent_req *req,
1772 int *preturn_code)
1774 struct winexe_ctrl_state *state = tevent_req_data(
1775 req, struct winexe_ctrl_state);
1776 NTSTATUS status;
1778 if (tevent_req_is_nterror(req, &status)) {
1779 return status;
1781 if (preturn_code != NULL) {
1782 *preturn_code = state->return_code;
1784 return NT_STATUS_OK;
1787 static NTSTATUS winexe_ctrl(struct cli_state *cli,
1788 const char *cmd,
1789 int *preturn_code)
1791 struct tevent_context *ev = NULL;
1792 struct tevent_req *req = NULL;
1793 NTSTATUS status = NT_STATUS_NO_MEMORY;
1794 bool ok;
1796 ev = samba_tevent_context_init(cli);
1797 if (ev == NULL) {
1798 goto done;
1800 req = winexe_ctrl_send(ev, ev, cli, cmd);
1801 if (req == NULL) {
1802 goto done;
1804 ok = tevent_req_poll_ntstatus(req, ev, &status);
1805 if (!ok) {
1806 goto done;
1808 status = winexe_ctrl_recv(req, preturn_code);
1809 done:
1810 TALLOC_FREE(req);
1811 TALLOC_FREE(ev);
1812 return status;
1815 #ifdef HAVE_WINEXE_CC_WIN32
1816 const DATA_BLOB *winexesvc32_exe_binary(void);
1817 #endif
1819 #ifdef HAVE_WINEXE_CC_WIN64
1820 const DATA_BLOB *winexesvc64_exe_binary(void);
1821 #endif
1823 int main(int argc, char *argv[])
1825 TALLOC_CTX *frame = talloc_stackframe();
1826 const char **const_argv = discard_const_p(const char *, argv);
1827 struct program_options options = {0};
1828 struct cli_state *cli = NULL;
1829 const char *service_name = SERVICE_NAME;
1830 char *service_filename = NULL;
1831 #ifdef HAVE_WINEXE_CC_WIN32
1832 const DATA_BLOB *winexesvc32_exe = winexesvc32_exe_binary();
1833 #else
1834 const DATA_BLOB *winexesvc32_exe = NULL;
1835 #endif
1836 #ifdef HAVE_WINEXE_CC_WIN64
1837 const DATA_BLOB *winexesvc64_exe = winexesvc64_exe_binary();
1838 #else
1839 const DATA_BLOB *winexesvc64_exe = NULL;
1840 #endif
1841 NTSTATUS status;
1842 int ret = 1;
1843 int return_code = 0;
1845 smb_init_locale();
1847 parse_args(argc, const_argv, frame, &options);
1849 samba_cmdline_burn(argc, argv);
1851 if (options.cmd == NULL) {
1852 fprintf(stderr, "no cmd given\n");
1853 goto done;
1856 service_filename = talloc_asprintf(frame, "%s.exe", service_name);
1857 if (service_filename == NULL) {
1858 DBG_WARNING("talloc_asprintf failed\n");
1859 goto done;
1862 status = cli_full_connection_creds(
1863 &cli,
1864 lp_netbios_name(),
1865 options.hostname,
1866 NULL,
1867 options.port,
1868 "IPC$",
1869 "IPC",
1870 options.credentials,
1871 CLI_FULL_CONNECTION_IPC);
1873 if (!NT_STATUS_IS_OK(status)) {
1874 DBG_WARNING("cli_full_connection_creds failed: %s\n",
1875 nt_errstr(status));
1876 goto done;
1879 status = winexe_svc_install(
1880 cli,
1881 options.hostname,
1882 options.port,
1883 service_name,
1884 service_filename,
1885 winexesvc32_exe,
1886 winexesvc64_exe,
1887 options.credentials,
1888 options.flags);
1889 if (!NT_STATUS_IS_OK(status)) {
1890 DBG_WARNING("winexe_svc_install failed: %s\n",
1891 nt_errstr(status));
1892 goto done;
1895 status = winexe_ctrl(cli, options.cmd, &return_code);
1896 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1897 /* Normal finish */
1898 status = NT_STATUS_OK;
1900 if (!NT_STATUS_IS_OK(status)) {
1901 DBG_WARNING("cli_ctrl failed: %s\n",
1902 nt_errstr(status));
1903 goto done;
1906 if (options.flags & SVC_UNINSTALL) {
1907 status = winexe_svc_uninstall(
1908 cli,
1909 service_name);
1910 if (!NT_STATUS_IS_OK(status)) {
1911 DBG_WARNING("winexe_svc_uninstall failed: %s\n",
1912 nt_errstr(status));
1913 goto done;
1917 ret = return_code;
1918 done:
1919 TALLOC_FREE(frame);
1920 return ret;