smbdotconf: finally remove unused "client use spnego principal" option
[Samba.git] / examples / winexe / winexe.c
blob5c2529cb2de220e46cdf2ad99724a2fd7358f670
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(state,
997 state->ev,
998 state->cli,
999 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(state,
1210 state->ev,
1211 state->cli,
1212 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 =
1279 cli_close_send(state, state->ev, state->cli, state->in_pipe, 0);
1280 if (subreq == NULL) {
1281 return false;
1283 tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1284 state->closing = true;
1286 return true;
1289 struct winexe_pipes_state {
1290 struct tevent_req *pipes[3];
1293 static void winexe_pipes_stdin_done(struct tevent_req *subreq);
1294 static void winexe_pipes_stdout_done(struct tevent_req *subreq);
1295 static void winexe_pipes_stderr_done(struct tevent_req *subreq);
1297 static struct tevent_req *winexe_pipes_send(
1298 TALLOC_CTX *mem_ctx,
1299 struct tevent_context *ev,
1300 struct cli_state *cli,
1301 const char *pipe_postfix)
1303 struct tevent_req *req;
1304 struct winexe_pipes_state *state;
1305 char *pipe_name;
1307 req = tevent_req_create(mem_ctx, &state, struct winexe_pipes_state);
1308 if (req == NULL) {
1309 return NULL;
1312 pipe_name = talloc_asprintf(state, "\\ahexec_stdin%s", pipe_postfix);
1313 if (tevent_req_nomem(pipe_name, req)) {
1314 return tevent_req_post(req, ev);
1316 state->pipes[0] = winexe_in_pipe_send(
1317 state,
1319 cli,
1320 pipe_name,
1322 if (tevent_req_nomem(state->pipes[0], req)) {
1323 return tevent_req_post(req, ev);
1325 tevent_req_set_callback(state->pipes[0], winexe_pipes_stdin_done, req);
1327 pipe_name = talloc_asprintf(state, "\\ahexec_stdout%s", pipe_postfix);
1328 if (tevent_req_nomem(pipe_name, req)) {
1329 return tevent_req_post(req, ev);
1331 state->pipes[1] = winexe_out_pipe_send(
1332 state,
1334 cli,
1335 pipe_name,
1337 if (tevent_req_nomem(state->pipes[1], req)) {
1338 return tevent_req_post(req, ev);
1340 tevent_req_set_callback(state->pipes[1], winexe_pipes_stdout_done,
1341 req);
1343 pipe_name = talloc_asprintf(state, "\\ahexec_stderr%s", pipe_postfix);
1344 if (tevent_req_nomem(pipe_name, req)) {
1345 return tevent_req_post(req, ev);
1347 state->pipes[2] = winexe_out_pipe_send(
1348 state,
1350 cli,
1351 pipe_name,
1353 if (tevent_req_nomem(state->pipes[2], req)) {
1354 return tevent_req_post(req, ev);
1356 tevent_req_set_callback(state->pipes[2], winexe_pipes_stderr_done,
1357 req);
1359 DBG_DEBUG("pipes = %p %p %p\n",
1360 state->pipes[0],
1361 state->pipes[1],
1362 state->pipes[2]);
1364 return req;
1367 static void winexe_pipes_stdin_done(struct tevent_req *subreq)
1369 struct tevent_req *req = tevent_req_callback_data(
1370 subreq, struct tevent_req);
1371 struct winexe_pipes_state *state = tevent_req_data(
1372 req, struct winexe_pipes_state);
1373 NTSTATUS status;
1375 status = winexe_in_pipe_recv(subreq);
1376 TALLOC_FREE(subreq);
1378 DBG_DEBUG("stdin returned %s\n", nt_errstr(status));
1380 if (tevent_req_nterror(req, status)) {
1381 return;
1384 state->pipes[0] = NULL;
1386 DBG_DEBUG("pipes = %p %p %p\n",
1387 state->pipes[0],
1388 state->pipes[1],
1389 state->pipes[2]);
1391 if ((state->pipes[1] == NULL) && (state->pipes[2] == NULL)) {
1392 tevent_req_done(req);
1396 static void winexe_pipes_stdout_done(struct tevent_req *subreq)
1398 struct tevent_req *req = tevent_req_callback_data(
1399 subreq, struct tevent_req);
1400 struct winexe_pipes_state *state = tevent_req_data(
1401 req, struct winexe_pipes_state);
1402 NTSTATUS status;
1404 status = winexe_out_pipe_recv(subreq);
1405 TALLOC_FREE(subreq);
1407 DBG_DEBUG("stdout returned %s\n", nt_errstr(status));
1409 if (tevent_req_nterror(req, status)) {
1410 return;
1413 if (state->pipes[0] != NULL) {
1414 winexe_in_pipe_close(state->pipes[0]);
1417 state->pipes[1] = NULL;
1419 DBG_DEBUG("pipes = %p %p %p\n",
1420 state->pipes[0],
1421 state->pipes[1],
1422 state->pipes[2]);
1424 if ((state->pipes[0] == NULL) && (state->pipes[2] == NULL)) {
1425 tevent_req_done(req);
1429 static void winexe_pipes_stderr_done(struct tevent_req *subreq)
1431 struct tevent_req *req = tevent_req_callback_data(
1432 subreq, struct tevent_req);
1433 struct winexe_pipes_state *state = tevent_req_data(
1434 req, struct winexe_pipes_state);
1435 NTSTATUS status;
1437 status = winexe_out_pipe_recv(subreq);
1438 TALLOC_FREE(subreq);
1440 DBG_DEBUG("stderr returned %s\n", nt_errstr(status));
1442 if (tevent_req_nterror(req, status)) {
1443 return;
1446 if (state->pipes[0] != NULL) {
1447 winexe_in_pipe_close(state->pipes[0]);
1450 state->pipes[2] = NULL;
1452 DBG_DEBUG("pipes = %p %p %p\n",
1453 state->pipes[0],
1454 state->pipes[1],
1455 state->pipes[2]);
1457 if ((state->pipes[0] == NULL) && (state->pipes[1] == NULL)) {
1458 tevent_req_done(req);
1462 static NTSTATUS winexe_pipes_recv(struct tevent_req *req)
1464 return tevent_req_simple_recv_ntstatus(req);
1467 struct winexe_ctrl_state {
1468 struct tevent_context *ev;
1469 struct cli_state *cli;
1471 uint16_t ctrl_pipe;
1472 bool ctrl_pipe_done;
1474 char ctrl_inbuf[256];
1475 char *cmd;
1476 int return_code;
1478 struct tevent_req *pipes_req;
1481 static void winexe_ctrl_opened(struct tevent_req *subreq);
1482 static void winexe_ctrl_got_read(struct tevent_req *subreq);
1483 static void winexe_ctrl_wrote_version(struct tevent_req *subreq);
1484 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq);
1485 static void winexe_ctrl_pipes_done(struct tevent_req *subreq);
1486 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq);
1488 static struct tevent_req *winexe_ctrl_send(
1489 TALLOC_CTX *mem_ctx,
1490 struct tevent_context *ev,
1491 struct cli_state *cli,
1492 const char *cmd)
1494 struct tevent_req *req, *subreq;
1495 struct winexe_ctrl_state *state;
1497 req = tevent_req_create(mem_ctx, &state,
1498 struct winexe_ctrl_state);
1499 if (req == NULL) {
1500 return NULL;
1502 state->ev = ev;
1503 state->cli = cli;
1505 state->cmd = talloc_asprintf(state, "run %s\n", cmd);
1506 if (tevent_req_nomem(state->cmd, req)) {
1507 return tevent_req_post(req, ev);
1510 subreq = cli_ntcreate_send(
1511 state,
1512 state->ev,
1513 state->cli,
1514 "\\" PIPE_NAME,
1516 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
1517 SEC_RIGHTS_FILE_EXECUTE,
1518 0, /* FileAttributes */
1519 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1520 FILE_OPEN, /* CreateDisposition */
1521 0, /* CreateOptions */
1522 SMB2_IMPERSONATION_IMPERSONATION,
1523 0); /* SecurityFlags */
1524 if (tevent_req_nomem(subreq, req)) {
1525 return tevent_req_post(req, ev);
1527 tevent_req_set_callback(subreq, winexe_ctrl_opened, req);
1528 return req;
1531 static void winexe_ctrl_opened(struct tevent_req *subreq)
1533 struct tevent_req *req = tevent_req_callback_data(
1534 subreq, struct tevent_req);
1535 struct winexe_ctrl_state *state = tevent_req_data(
1536 req, struct winexe_ctrl_state);
1537 int timeout;
1538 NTSTATUS status;
1539 static const char cmd[] = "get codepage\nget version\n";
1541 status = cli_ntcreate_recv(subreq, &state->ctrl_pipe, NULL);
1542 TALLOC_FREE(subreq);
1543 if (tevent_req_nterror(req, status)) {
1544 return;
1547 timeout = state->cli->timeout;
1548 state->cli->timeout = 0;
1550 subreq = cli_read_send(
1551 state,
1552 state->ev,
1553 state->cli,
1554 state->ctrl_pipe,
1555 state->ctrl_inbuf,
1557 sizeof(state->ctrl_inbuf)-1);
1559 state->cli->timeout = timeout;
1561 if (tevent_req_nomem(subreq, req)) {
1562 return;
1564 tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1566 subreq = cli_writeall_send(
1567 state,
1568 state->ev,
1569 state->cli,
1570 state->ctrl_pipe,
1572 (const uint8_t *)cmd,
1574 strlen(cmd));
1575 if (tevent_req_nomem(subreq, req)) {
1576 return;
1578 tevent_req_set_callback(subreq, winexe_ctrl_wrote_version, req);
1581 static void winexe_ctrl_got_read(struct tevent_req *subreq)
1583 struct tevent_req *req = tevent_req_callback_data(
1584 subreq, struct tevent_req);
1585 struct winexe_ctrl_state *state = tevent_req_data(
1586 req, struct winexe_ctrl_state);
1587 NTSTATUS status;
1588 int timeout;
1589 size_t received;
1590 unsigned int version, return_code;
1591 int ret;
1593 status = cli_read_recv(subreq, &received);
1594 TALLOC_FREE(subreq);
1596 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1597 subreq = cli_close_send(state,
1598 state->ev,
1599 state->cli,
1600 state->ctrl_pipe,
1602 if (tevent_req_nomem(subreq, req)) {
1603 return;
1605 tevent_req_set_callback(subreq, winexe_ctrl_pipe_closed, req);
1606 return;
1608 if (tevent_req_nterror(req, status)) {
1609 return;
1612 DBG_DEBUG("Got %zu bytes\n", received);
1614 timeout = state->cli->timeout;
1615 state->cli->timeout = 0;
1617 subreq = cli_read_send(
1618 state,
1619 state->ev,
1620 state->cli,
1621 state->ctrl_pipe,
1622 state->ctrl_inbuf,
1624 sizeof(state->ctrl_inbuf)-1);
1626 state->cli->timeout = timeout;
1628 if (tevent_req_nomem(subreq, req)) {
1629 return;
1631 tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1633 ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &version);
1634 if (ret == 1) {
1635 DBG_DEBUG("Got version %x\n", version);
1637 subreq = cli_writeall_send(
1638 state,
1639 state->ev,
1640 state->cli,
1641 state->ctrl_pipe,
1643 (const uint8_t *)state->cmd,
1645 strlen(state->cmd));
1646 if (tevent_req_nomem(subreq, req)) {
1647 return;
1649 tevent_req_set_callback(subreq, winexe_ctrl_wrote_cmd, req);
1650 return;
1653 ret = strncmp(state->ctrl_inbuf, "std_io_err ", strlen("std_io_err "));
1654 if (ret == 0) {
1655 char *p = state->ctrl_inbuf + 11;
1656 char *q = strchr(state->ctrl_inbuf, '\n');
1657 char *postfix;
1658 size_t postfix_len;
1660 if (q == NULL) {
1661 DBG_DEBUG("Got invalid pipe postfix\n");
1662 return;
1665 postfix_len = q - p;
1667 postfix = talloc_strndup(state, p, postfix_len);
1668 if (tevent_req_nomem(postfix, req)) {
1669 return;
1672 DBG_DEBUG("Got pipe postfix %s\n", postfix);
1674 subreq = winexe_pipes_send(
1675 state,
1676 state->ev,
1677 state->cli,
1678 postfix);
1679 if (tevent_req_nomem(subreq, req)) {
1680 return;
1682 tevent_req_set_callback(subreq, winexe_ctrl_pipes_done, req);
1684 state->pipes_req = subreq;
1686 return;
1689 ret = strncmp(state->ctrl_inbuf, "error ", strlen("error "));
1690 if (ret == 0) {
1691 printf("Error: %s", state->ctrl_inbuf);
1692 return;
1695 ret = sscanf(state->ctrl_inbuf, "return_code %x\n", &return_code);
1696 if (ret == 1) {
1697 state->return_code = return_code;
1698 return;
1702 static void winexe_ctrl_wrote_version(struct tevent_req *subreq)
1704 struct tevent_req *req = tevent_req_callback_data(
1705 subreq, struct tevent_req);
1706 NTSTATUS status;
1708 status = cli_writeall_recv(subreq, NULL);
1709 TALLOC_FREE(subreq);
1710 if (tevent_req_nterror(req, status)) {
1711 return;
1715 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq)
1717 struct tevent_req *req = tevent_req_callback_data(
1718 subreq, struct tevent_req);
1719 NTSTATUS status;
1721 status = cli_writeall_recv(subreq, NULL);
1722 TALLOC_FREE(subreq);
1723 if (tevent_req_nterror(req, status)) {
1724 return;
1728 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq)
1730 struct tevent_req *req = tevent_req_callback_data(
1731 subreq, struct tevent_req);
1732 struct winexe_ctrl_state *state = tevent_req_data(
1733 req, struct winexe_ctrl_state);
1734 NTSTATUS status;
1736 status = cli_close_recv(subreq);
1737 TALLOC_FREE(subreq);
1738 if (tevent_req_nterror(req, status)) {
1739 return;
1742 state->ctrl_pipe_done = true;
1743 if (state->pipes_req == NULL) {
1744 tevent_req_done(req);
1748 static void winexe_ctrl_pipes_done(struct tevent_req *subreq)
1750 struct tevent_req *req = tevent_req_callback_data(
1751 subreq, struct tevent_req);
1752 struct winexe_ctrl_state *state = tevent_req_data(
1753 req, struct winexe_ctrl_state);
1754 NTSTATUS status;
1756 status = winexe_pipes_recv(subreq);
1757 TALLOC_FREE(subreq);
1758 if (tevent_req_nterror(req, status)) {
1759 return;
1762 state->pipes_req = NULL;
1763 if (state->ctrl_pipe_done) {
1764 tevent_req_done(req);
1768 static NTSTATUS winexe_ctrl_recv(struct tevent_req *req,
1769 int *preturn_code)
1771 struct winexe_ctrl_state *state = tevent_req_data(
1772 req, struct winexe_ctrl_state);
1773 NTSTATUS status;
1775 if (tevent_req_is_nterror(req, &status)) {
1776 return status;
1778 if (preturn_code != NULL) {
1779 *preturn_code = state->return_code;
1781 return NT_STATUS_OK;
1784 static NTSTATUS winexe_ctrl(struct cli_state *cli,
1785 const char *cmd,
1786 int *preturn_code)
1788 struct tevent_context *ev = NULL;
1789 struct tevent_req *req = NULL;
1790 NTSTATUS status = NT_STATUS_NO_MEMORY;
1791 bool ok;
1793 ev = samba_tevent_context_init(cli);
1794 if (ev == NULL) {
1795 goto done;
1797 req = winexe_ctrl_send(ev, ev, cli, cmd);
1798 if (req == NULL) {
1799 goto done;
1801 ok = tevent_req_poll_ntstatus(req, ev, &status);
1802 if (!ok) {
1803 goto done;
1805 status = winexe_ctrl_recv(req, preturn_code);
1806 done:
1807 TALLOC_FREE(req);
1808 TALLOC_FREE(ev);
1809 return status;
1812 #ifdef HAVE_WINEXE_CC_WIN32
1813 const DATA_BLOB *winexesvc32_exe_binary(void);
1814 #endif
1816 #ifdef HAVE_WINEXE_CC_WIN64
1817 const DATA_BLOB *winexesvc64_exe_binary(void);
1818 #endif
1820 int main(int argc, char *argv[])
1822 TALLOC_CTX *frame = talloc_stackframe();
1823 const char **const_argv = discard_const_p(const char *, argv);
1824 struct program_options options = {0};
1825 struct cli_state *cli = NULL;
1826 const char *service_name = SERVICE_NAME;
1827 char *service_filename = NULL;
1828 #ifdef HAVE_WINEXE_CC_WIN32
1829 const DATA_BLOB *winexesvc32_exe = winexesvc32_exe_binary();
1830 #else
1831 const DATA_BLOB *winexesvc32_exe = NULL;
1832 #endif
1833 #ifdef HAVE_WINEXE_CC_WIN64
1834 const DATA_BLOB *winexesvc64_exe = winexesvc64_exe_binary();
1835 #else
1836 const DATA_BLOB *winexesvc64_exe = NULL;
1837 #endif
1838 NTSTATUS status;
1839 int ret = 1;
1840 int return_code = 0;
1842 smb_init_locale();
1844 parse_args(argc, const_argv, frame, &options);
1846 samba_cmdline_burn(argc, argv);
1848 if (options.cmd == NULL) {
1849 fprintf(stderr, "no cmd given\n");
1850 goto done;
1853 service_filename = talloc_asprintf(frame, "%s.exe", service_name);
1854 if (service_filename == NULL) {
1855 DBG_WARNING("talloc_asprintf failed\n");
1856 goto done;
1859 status = cli_full_connection_creds(
1860 &cli,
1861 lp_netbios_name(),
1862 options.hostname,
1863 NULL,
1864 options.port,
1865 "IPC$",
1866 "IPC",
1867 options.credentials,
1868 CLI_FULL_CONNECTION_IPC);
1870 if (!NT_STATUS_IS_OK(status)) {
1871 DBG_WARNING("cli_full_connection_creds failed: %s\n",
1872 nt_errstr(status));
1873 goto done;
1876 status = winexe_svc_install(
1877 cli,
1878 options.hostname,
1879 options.port,
1880 service_name,
1881 service_filename,
1882 winexesvc32_exe,
1883 winexesvc64_exe,
1884 options.credentials,
1885 options.flags);
1886 if (!NT_STATUS_IS_OK(status)) {
1887 DBG_WARNING("winexe_svc_install failed: %s\n",
1888 nt_errstr(status));
1889 goto done;
1892 status = winexe_ctrl(cli, options.cmd, &return_code);
1893 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1894 /* Normal finish */
1895 status = NT_STATUS_OK;
1897 if (!NT_STATUS_IS_OK(status)) {
1898 DBG_WARNING("cli_ctrl failed: %s\n",
1899 nt_errstr(status));
1900 goto done;
1903 if (options.flags & SVC_UNINSTALL) {
1904 status = winexe_svc_uninstall(
1905 cli,
1906 service_name);
1907 if (!NT_STATUS_IS_OK(status)) {
1908 DBG_WARNING("winexe_svc_uninstall failed: %s\n",
1909 nt_errstr(status));
1910 goto done;
1914 ret = return_code;
1915 done:
1916 TALLOC_FREE(frame);
1917 return ret;