s3-rpc_client: Advertise Windows 7 client info
[Samba.git] / examples / winexe / winexe.c
blobcf667a64ebc93c2abf0a660bf58da031288b1e0b
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 <tevent.h>
24 #include <popt.h>
25 #include "version.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 "client.h"
39 #define SVC_INTERACTIVE 1
40 #define SVC_IGNORE_INTERACTIVE 2
41 #define SVC_INTERACTIVE_MASK 3
42 #define SVC_FORCE_UPLOAD 4
43 #define SVC_OS64BIT 8
44 #define SVC_OSCHOOSE 16
45 #define SVC_UNINSTALL 32
46 #define SVC_SYSTEM 64
48 #define SERVICE_NAME "winexesvc"
50 #define PIPE_NAME "ahexec"
51 #define PIPE_NAME_IN "ahexec_stdin%08X"
52 #define PIPE_NAME_OUT "ahexec_stdout%08X"
53 #define PIPE_NAME_ERR "ahexec_stderr%08X"
55 static const char version_message_fmt[] = "winexe version %d.%d\n"
56 "This program may be freely redistributed under the terms of the "
57 "GNU GPLv3\n";
59 struct program_options {
60 char *hostname;
61 char *cmd;
62 struct cli_credentials *credentials;
63 char *runas;
64 char *runas_file;
65 int flags;
68 static void parse_args(int argc, const char *argv[],
69 TALLOC_CTX *mem_ctx,
70 struct program_options *options,
71 struct loadparm_context *lp_ctx)
73 poptContext pc;
74 int opt, i;
75 struct cli_credentials *cred;
77 int argc_new;
78 char **argv_new;
80 int flag_interactive = SVC_IGNORE_INTERACTIVE;
81 int flag_ostype = 2;
82 int flag_reinstall = 0;
83 int flag_uninstall = 0;
84 int flag_help = 0;
85 int flag_version = 0;
86 int flag_nopass = 0;
87 char *opt_user = NULL;
88 char *opt_kerberos = NULL;
89 char *opt_auth_file = NULL;
90 char *opt_debuglevel = NULL;
92 struct poptOption long_options[] = {
93 { "help", 'h', POPT_ARG_NONE, &flag_help, 0,
94 "Display help message" },
95 { "version", 'V', POPT_ARG_NONE, &flag_version, 0,
96 "Display version number" },
97 { "user", 'U', POPT_ARG_STRING, &opt_user, 0,
98 "Set the network username", "[DOMAIN/]USERNAME[%PASSWORD]" },
99 { "authentication-file", 'A',
100 POPT_ARG_STRING, &opt_auth_file, 0,
101 "Get the credentials from a file", "FILE" },
102 { "no-pass", 'N', POPT_ARG_NONE, &flag_nopass, 0,
103 "Do not ask for a password", NULL },
104 { "kerberos", 'k', POPT_ARG_STRING, &opt_kerberos, 0,
105 "Use Kerberos, -k [yes|no]" },
106 { "debuglevel", 'd', POPT_ARG_STRING, &opt_debuglevel, 0,
107 "Set debug level", "DEBUGLEVEL" },
108 { "uninstall", 0, POPT_ARG_NONE, &flag_uninstall, 0,
109 "Uninstall winexe service after remote execution", NULL},
110 { "reinstall", 0, POPT_ARG_NONE, &flag_reinstall, 0,
111 "Reinstall winexe service before remote execution", NULL},
112 { "runas", 0, POPT_ARG_STRING, &options->runas, 0,
113 "Run as the given user (BEWARE: this password is sent "
114 "in cleartext over the network!)",
115 "[DOMAIN\\]USERNAME%PASSWORD"},
116 { "runas-file", 0, POPT_ARG_STRING, &options->runas_file, 0,
117 "Run as user options defined in a file", "FILE"},
118 { "interactive", 0, POPT_ARG_INT, &flag_interactive, 0,
119 "Desktop interaction: 0 - disallow, 1 - allow. If allow, "
120 "also use the --system switch (Windows requirement). Vista "
121 "does not support this option.", "0|1"},
122 { "ostype", 0, POPT_ARG_INT, &flag_ostype, 0,
123 "OS type: 0 - 32-bit, 1 - 64-bit, 2 - winexe will decide. "
124 "Determines which version (32-bit or 64-bit) of service "
125 "will be installed.", "0|1|2"},
126 POPT_TABLEEND
129 ZERO_STRUCTP(options);
131 pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,
134 poptSetOtherOptionHelp(pc, "[OPTION]... //HOST COMMAND\nOptions:");
136 if (((opt = poptGetNextOpt(pc)) != -1) || flag_help || flag_version) {
137 fprintf(stderr, version_message_fmt, SAMBA_VERSION_MAJOR,
138 SAMBA_VERSION_MINOR);
139 if (flag_version) {
140 exit(0);
142 poptPrintHelp(pc, stdout, 0);
143 if (flag_help) {
144 exit(0);
146 exit(1);
149 argv_new = discard_const_p(char *, poptGetArgs(pc));
151 argc_new = argc;
152 for (i = 0; i < argc; i++) {
153 if (!argv_new || argv_new[i] == NULL) {
154 argc_new = i;
155 break;
159 if (argc_new != 2 || argv_new[0][0] != '/' || argv_new[0][1] != '/') {
160 fprintf(stderr, version_message_fmt, SAMBA_VERSION_MAJOR,
161 SAMBA_VERSION_MINOR);
162 poptPrintHelp(pc, stdout, 0);
163 exit(1);
166 if (opt_debuglevel) {
167 lp_set_cmdline("log level", opt_debuglevel);
170 cred = cli_credentials_init(mem_ctx);
172 if (opt_user) {
173 cli_credentials_parse_string(cred, opt_user, CRED_SPECIFIED);
174 } else if (opt_auth_file) {
175 cli_credentials_parse_file(cred, opt_auth_file,
176 CRED_SPECIFIED);
179 cli_credentials_guess(cred, lp_ctx);
180 if (!cli_credentials_get_password(cred) && !flag_nopass) {
181 char *p = getpass("Enter password: ");
182 if (*p) {
183 cli_credentials_set_password(cred, p, CRED_SPECIFIED);
187 if (opt_kerberos) {
188 cli_credentials_set_kerberos_state(cred,
189 strcmp(opt_kerberos, "yes")
190 ? CRED_MUST_USE_KERBEROS
191 : CRED_DONT_USE_KERBEROS);
194 if (options->runas == NULL && options->runas_file != NULL) {
195 struct cli_credentials *runas_cred;
196 const char *user;
197 const char *pass;
199 runas_cred = cli_credentials_init(mem_ctx);
200 cli_credentials_parse_file(runas_cred, options->runas_file,
201 CRED_SPECIFIED);
203 user = cli_credentials_get_username(runas_cred);
204 pass = cli_credentials_get_password(runas_cred);
206 if (user && pass) {
207 char buffer[1024];
208 const char *dom;
210 dom = cli_credentials_get_domain(runas_cred);
211 if (dom) {
212 snprintf(buffer, sizeof(buffer), "%s\\%s%%%s",
213 dom, user, pass);
214 } else {
215 snprintf(buffer, sizeof(buffer), "%s%%%s",
216 user, pass);
218 buffer[sizeof(buffer)-1] = '\0';
219 options->runas = talloc_strdup(mem_ctx, buffer);
223 options->credentials = cred;
225 options->hostname = argv_new[0] + 2;
226 options->cmd = argv_new[1];
228 options->flags = flag_interactive;
229 if (flag_reinstall) {
230 options->flags |= SVC_FORCE_UPLOAD;
232 if (flag_ostype == 1) {
233 options->flags |= SVC_OS64BIT;
235 if (flag_ostype == 2) {
236 options->flags |= SVC_OSCHOOSE;
238 if (flag_uninstall) {
239 options->flags |= SVC_UNINSTALL;
243 static NTSTATUS winexe_svc_upload(
244 const char *hostname,
245 const char *service_filename,
246 const DATA_BLOB *svc32_exe,
247 const DATA_BLOB *svc64_exe,
248 struct cli_credentials *credentials,
249 int flags)
251 struct cli_state *cli;
252 uint16_t fnum;
253 NTSTATUS status;
254 const DATA_BLOB *binary = NULL;
256 status = cli_full_connection_creds(
257 &cli,
258 NULL,
259 hostname,
260 NULL,
261 445,
262 "ADMIN$",
263 "?????",
264 credentials,
267 if (!NT_STATUS_IS_OK(status)) {
268 DBG_WARNING("cli_full_connection_creds failed: %s\n",
269 nt_errstr(status));
270 return status;
273 if (flags & SVC_FORCE_UPLOAD) {
274 status = cli_unlink(cli, service_filename, 0);
275 if (!NT_STATUS_IS_OK(status)) {
276 DBG_WARNING("cli_unlink failed: %s\n",
277 nt_errstr(status));
281 if (flags & SVC_OSCHOOSE) {
282 status = cli_chkpath(cli, "SysWoW64");
283 if (NT_STATUS_IS_OK(status)) {
284 flags |= SVC_OS64BIT;
288 if (flags & SVC_OS64BIT) {
289 binary = svc64_exe;
290 } else {
291 binary = svc32_exe;
294 if (binary == NULL) {
295 //TODO
298 status = cli_ntcreate(
299 cli,
300 service_filename,
301 0, /* CreatFlags */
302 SEC_FILE_WRITE_DATA, /* DesiredAccess */
303 FILE_ATTRIBUTE_NORMAL, /* FileAttributes */
304 FILE_SHARE_WRITE|FILE_SHARE_READ, /* ShareAccess */
305 FILE_OPEN_IF, /* CreateDisposition */
306 FILE_NON_DIRECTORY_FILE, /* CreateOptions */
307 0, /* SecurityFlags */
308 &fnum,
309 NULL); /* CreateReturns */
310 if (!NT_STATUS_IS_OK(status)) {
311 DBG_WARNING("Could not create %s: %s\n", service_filename,
312 nt_errstr(status));
313 goto done;
316 status = cli_writeall(
317 cli,
318 fnum,
320 binary->data,
322 binary->length,
323 NULL);
324 if (!NT_STATUS_IS_OK(status)) {
325 DBG_WARNING("Could not write file: %s\n", nt_errstr(status));
326 goto close_done;
329 close_done:
330 status = cli_close(cli, fnum);
331 if (!NT_STATUS_IS_OK(status)) {
332 DBG_WARNING("Close(%"PRIu16") failed for %s: %s\n", fnum,
333 service_filename, nt_errstr(status));
335 done:
336 TALLOC_FREE(cli);
337 return status;
340 static NTSTATUS winexe_svc_install(
341 struct cli_state *cli,
342 const char *hostname,
343 const char *service_name,
344 const char *service_filename,
345 const DATA_BLOB *svc32_exe,
346 const DATA_BLOB *svc64_exe,
347 struct cli_credentials *credentials,
348 int flags)
350 TALLOC_CTX *frame = talloc_stackframe();
351 struct rpc_pipe_client *rpccli;
352 struct policy_handle scmanager_handle;
353 struct policy_handle service_handle;
354 struct SERVICE_STATUS service_status;
355 bool need_start = false;
356 bool need_conf = false;
357 NTSTATUS status;
358 WERROR werr;
360 status = cli_rpc_pipe_open_noauth_transport(
361 cli,
362 NCACN_NP,
363 &ndr_table_svcctl,
364 &rpccli);
365 if (!NT_STATUS_IS_OK(status)) {
366 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
367 nt_errstr(status));
368 goto done;
371 status = dcerpc_svcctl_OpenSCManagerW(
372 rpccli->binding_handle,
373 frame,
374 smbXcli_conn_remote_name(cli->conn),
375 NULL,
376 SEC_FLAG_MAXIMUM_ALLOWED,
377 &scmanager_handle,
378 &werr);
379 if (!NT_STATUS_IS_OK(status)) {
380 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
381 nt_errstr(status));
382 goto done;
384 if (!W_ERROR_IS_OK(werr)) {
385 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
386 win_errstr(werr));
387 goto done;
390 status = dcerpc_svcctl_OpenServiceW(
391 rpccli->binding_handle,
392 frame,
393 &scmanager_handle,
394 service_name,
395 SERVICE_ALL_ACCESS,
396 &service_handle,
397 &werr);
398 if (!NT_STATUS_IS_OK(status)) {
399 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
400 nt_errstr(status));
401 goto close_scmanager;
404 if (W_ERROR_EQUAL(werr, WERR_SERVICE_DOES_NOT_EXIST)) {
405 status = dcerpc_svcctl_CreateServiceW(
406 rpccli->binding_handle,
407 frame,
408 &scmanager_handle,
409 service_name,
410 NULL,
411 SERVICE_ALL_ACCESS,
412 SERVICE_TYPE_WIN32_OWN_PROCESS |
413 ((flags & SVC_INTERACTIVE) ?
414 SERVICE_TYPE_INTERACTIVE_PROCESS : 0),
415 SVCCTL_DEMAND_START,
416 SVCCTL_SVC_ERROR_NORMAL,
417 service_filename,
418 NULL,
419 NULL,
420 NULL,
422 NULL,
423 NULL,
425 &service_handle,
426 &werr);
427 if (!NT_STATUS_IS_OK(status)) {
428 DBG_WARNING("dcerpc_svcctl_CreateServiceW "
429 "failed: %s\n", nt_errstr(status));
430 goto close_scmanager;
432 if (!W_ERROR_IS_OK(werr)) {
433 DBG_WARNING("dcerpc_svcctl_CreateServiceW "
434 "failed: %s\n", win_errstr(werr));
435 status = werror_to_ntstatus(werr);
436 goto close_scmanager;
440 status = dcerpc_svcctl_QueryServiceStatus(
441 rpccli->binding_handle,
442 frame,
443 &service_handle,
444 &service_status,
445 &werr);
447 if (!NT_STATUS_IS_OK(status)) {
448 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
449 "failed: %s\n", nt_errstr(status));
450 goto close_service;
452 if (!W_ERROR_IS_OK(werr)) {
453 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
454 "failed: %s\n", win_errstr(werr));
455 status = werror_to_ntstatus(werr);
456 goto close_service;
459 if (!(flags & SVC_IGNORE_INTERACTIVE)) {
460 need_conf =
461 !(service_status.type &
462 SERVICE_TYPE_INTERACTIVE_PROCESS) ^
463 !(flags & SVC_INTERACTIVE);
466 if (service_status.state == SVCCTL_STOPPED) {
467 need_start = true;
468 } else if (need_conf) {
469 status = dcerpc_svcctl_ControlService(
470 rpccli->binding_handle,
471 frame,
472 &service_handle,
473 SVCCTL_CONTROL_STOP,
474 &service_status,
475 &werr);
477 if (!NT_STATUS_IS_OK(status)) {
478 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
479 "failed: %s\n", nt_errstr(status));
480 goto close_service;
482 if (!W_ERROR_IS_OK(werr)) {
483 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
484 "failed: %s\n", win_errstr(werr));
485 status = werror_to_ntstatus(werr);
486 goto close_service;
489 do {
490 smb_msleep(100);
492 status = dcerpc_svcctl_QueryServiceStatus(
493 rpccli->binding_handle,
494 frame,
495 &service_handle,
496 &service_status,
497 &werr);
499 if (!NT_STATUS_IS_OK(status)) {
500 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
501 "failed: %s\n", nt_errstr(status));
502 goto close_service;
504 if (!W_ERROR_IS_OK(werr)) {
505 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
506 "failed: %s\n", win_errstr(werr));
507 status = werror_to_ntstatus(werr);
508 goto close_service;
510 } while (service_status.state == SVCCTL_STOP_PENDING);
512 need_start = 1;
515 if (need_conf) {
516 status = dcerpc_svcctl_ChangeServiceConfigW(
517 rpccli->binding_handle,
518 frame,
519 &service_handle,
520 SERVICE_TYPE_WIN32_OWN_PROCESS |
521 ((flags & SVC_INTERACTIVE) ?
522 SERVICE_TYPE_INTERACTIVE_PROCESS : 0), /* type */
523 UINT32_MAX, /* start_type, SERVICE_NO_CHANGE */
524 UINT32_MAX, /* error_control, SERVICE_NO_CHANGE */
525 NULL, /* binary_path */
526 NULL, /* load_order_group */
527 NULL, /* tag_id */
528 NULL, /* dependencies */
529 NULL, /* service_start_name */
530 NULL, /* password */
531 NULL, /* display_name */
532 &werr);
534 if (!NT_STATUS_IS_OK(status)) {
535 DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
536 "failed: %s\n", nt_errstr(status));
537 goto close_service;
539 if (!W_ERROR_IS_OK(werr)) {
540 DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
541 "failed: %s\n", win_errstr(werr));
542 status = werror_to_ntstatus(werr);
543 goto close_service;
547 if (need_start) {
548 status = winexe_svc_upload(
549 hostname,
550 service_filename,
551 svc32_exe,
552 svc64_exe,
553 credentials,
554 flags);
555 if (!NT_STATUS_IS_OK(status)) {
556 DBG_WARNING("winexe_svc_upload failed: %s\n",
557 nt_errstr(status));
558 goto close_service;
561 status = dcerpc_svcctl_StartServiceW(
562 rpccli->binding_handle,
563 frame,
564 &service_handle,
565 0, /* num_args */
566 NULL, /* arguments */
567 &werr);
569 if (!NT_STATUS_IS_OK(status)) {
570 DBG_WARNING("dcerpc_svcctl_StartServiceW "
571 "failed: %s\n", nt_errstr(status));
572 goto close_service;
574 if (!W_ERROR_IS_OK(werr)) {
575 DBG_WARNING("dcerpc_svcctl_StartServiceW "
576 "failed: %s\n", win_errstr(werr));
577 status = werror_to_ntstatus(werr);
578 goto close_service;
581 do {
582 smb_msleep(100);
584 status = dcerpc_svcctl_QueryServiceStatus(
585 rpccli->binding_handle,
586 frame,
587 &service_handle,
588 &service_status,
589 &werr);
591 if (!NT_STATUS_IS_OK(status)) {
592 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
593 "failed: %s\n", nt_errstr(status));
594 goto close_service;
596 if (!W_ERROR_IS_OK(werr)) {
597 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
598 "failed: %s\n", win_errstr(werr));
599 status = werror_to_ntstatus(werr);
600 goto close_service;
602 } while (service_status.state == SVCCTL_START_PENDING);
604 if (service_status.state != SVCCTL_RUNNING) {
605 DBG_WARNING("Failed to start service\n");
606 status = NT_STATUS_UNSUCCESSFUL;
607 goto close_service;
611 close_service:
613 NTSTATUS close_status;
614 WERROR close_werr;
616 close_status = dcerpc_svcctl_CloseServiceHandle(
617 rpccli->binding_handle,
618 frame,
619 &service_handle,
620 &close_werr);
621 if (!NT_STATUS_IS_OK(close_status)) {
622 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
623 "failed: %s\n", nt_errstr(close_status));
624 goto done;
626 if (!W_ERROR_IS_OK(close_werr)) {
627 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
628 " failed: %s\n", win_errstr(close_werr));
629 goto done;
633 close_scmanager:
635 NTSTATUS close_status;
636 WERROR close_werr;
638 close_status = dcerpc_svcctl_CloseServiceHandle(
639 rpccli->binding_handle,
640 frame,
641 &scmanager_handle,
642 &close_werr);
643 if (!NT_STATUS_IS_OK(close_status)) {
644 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
645 "failed: %s\n", nt_errstr(close_status));
646 goto done;
648 if (!W_ERROR_IS_OK(close_werr)) {
649 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
650 " failed: %s\n", win_errstr(close_werr));
651 goto done;
655 done:
656 TALLOC_FREE(rpccli);
657 TALLOC_FREE(frame);
658 return status;
661 static NTSTATUS winexe_svc_uninstall(
662 struct cli_state *cli,
663 const char *service_name)
665 TALLOC_CTX *frame = talloc_stackframe();
666 struct rpc_pipe_client *rpccli;
667 struct policy_handle scmanager_handle;
668 struct policy_handle service_handle;
669 struct SERVICE_STATUS service_status;
670 NTSTATUS status;
671 WERROR werr;
673 status = cli_rpc_pipe_open_noauth_transport(
674 cli,
675 NCACN_NP,
676 &ndr_table_svcctl,
677 &rpccli);
678 if (!NT_STATUS_IS_OK(status)) {
679 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
680 nt_errstr(status));
681 goto done;
684 status = dcerpc_svcctl_OpenSCManagerW(
685 rpccli->binding_handle,
686 frame,
687 smbXcli_conn_remote_name(cli->conn),
688 NULL,
689 SEC_FLAG_MAXIMUM_ALLOWED,
690 &scmanager_handle,
691 &werr);
692 if (!NT_STATUS_IS_OK(status)) {
693 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
694 nt_errstr(status));
695 goto done;
697 if (!W_ERROR_IS_OK(werr)) {
698 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
699 win_errstr(werr));
700 goto done;
703 status = dcerpc_svcctl_OpenServiceW(
704 rpccli->binding_handle,
705 frame,
706 &scmanager_handle,
707 service_name,
708 SERVICE_ALL_ACCESS,
709 &service_handle,
710 &werr);
711 if (!NT_STATUS_IS_OK(status)) {
712 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
713 nt_errstr(status));
714 goto close_scmanager;
716 if (!W_ERROR_IS_OK(werr)) {
717 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
718 win_errstr(werr));
719 status = werror_to_ntstatus(werr);
720 goto close_scmanager;
723 status = dcerpc_svcctl_ControlService(
724 rpccli->binding_handle,
725 frame,
726 &service_handle,
727 SVCCTL_CONTROL_STOP,
728 &service_status,
729 &werr);
730 if (!NT_STATUS_IS_OK(status)) {
731 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
732 "failed: %s\n", nt_errstr(status));
733 goto close_service;
735 if (!W_ERROR_IS_OK(werr)) {
736 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
737 "failed: %s\n", win_errstr(werr));
738 status = werror_to_ntstatus(werr);
739 goto close_service;
742 do {
743 smb_msleep(100);
745 status = dcerpc_svcctl_QueryServiceStatus(
746 rpccli->binding_handle,
747 frame,
748 &service_handle,
749 &service_status,
750 &werr);
752 if (!NT_STATUS_IS_OK(status)) {
753 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
754 "failed: %s\n", nt_errstr(status));
755 goto close_service;
757 if (!W_ERROR_IS_OK(werr)) {
758 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
759 "failed: %s\n", win_errstr(werr));
760 status = werror_to_ntstatus(werr);
761 goto close_service;
763 } while (service_status.state != SVCCTL_STOPPED);
765 status = dcerpc_svcctl_DeleteService(
766 rpccli->binding_handle,
767 frame,
768 &service_handle,
769 &werr);
770 if (!NT_STATUS_IS_OK(status)) {
771 DBG_WARNING("dcerpc_svcctl_DeleteService "
772 "failed: %s\n", nt_errstr(status));
773 goto close_service;
775 if (!W_ERROR_IS_OK(werr)) {
776 DBG_WARNING("dcerpc_svcctl_DeleteService "
777 "failed: %s\n", win_errstr(werr));
778 status = werror_to_ntstatus(werr);
779 goto close_service;
782 close_service:
784 NTSTATUS close_status;
785 WERROR close_werr;
787 close_status = dcerpc_svcctl_CloseServiceHandle(
788 rpccli->binding_handle,
789 frame,
790 &service_handle,
791 &close_werr);
792 if (!NT_STATUS_IS_OK(close_status)) {
793 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
794 "failed: %s\n", nt_errstr(close_status));
795 goto done;
797 if (!W_ERROR_IS_OK(close_werr)) {
798 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
799 " failed: %s\n", win_errstr(close_werr));
800 goto done;
804 close_scmanager:
806 NTSTATUS close_status;
807 WERROR close_werr;
809 close_status = dcerpc_svcctl_CloseServiceHandle(
810 rpccli->binding_handle,
811 frame,
812 &scmanager_handle,
813 &close_werr);
814 if (!NT_STATUS_IS_OK(close_status)) {
815 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
816 "failed: %s\n", nt_errstr(close_status));
817 goto done;
819 if (!W_ERROR_IS_OK(close_werr)) {
820 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
821 " failed: %s\n", win_errstr(close_werr));
822 goto done;
826 done:
827 TALLOC_FREE(rpccli);
828 TALLOC_FREE(frame);
829 return status;
832 struct winexe_out_pipe_state {
833 struct tevent_context *ev;
834 struct cli_state *cli;
835 uint16_t out_pipe;
836 int out_fd;
837 char out_inbuf[256];
840 static void winexe_out_pipe_opened(struct tevent_req *subreq);
841 static void winexe_out_pipe_got_data(struct tevent_req *subreq);
842 static void winexe_out_pipe_closed(struct tevent_req *subreq);
844 static struct tevent_req *winexe_out_pipe_send(
845 TALLOC_CTX *mem_ctx,
846 struct tevent_context *ev,
847 struct cli_state *cli,
848 const char *pipe_name,
849 int out_fd)
851 struct tevent_req *req, *subreq;
852 struct winexe_out_pipe_state *state;
854 req = tevent_req_create(mem_ctx, &state,
855 struct winexe_out_pipe_state);
856 if (req == NULL) {
857 return NULL;
859 state->ev = ev;
860 state->cli = cli;
861 state->out_fd = out_fd;
863 subreq = cli_ntcreate_send(
864 state,
865 state->ev,
866 state->cli,
867 pipe_name,
869 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
870 SEC_RIGHTS_FILE_EXECUTE,
871 0, /* FileAttributes */
872 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
873 FILE_OPEN, /* CreateDisposition */
874 0, /* CreateOptions */
875 0); /* SecurityFlags */
876 if (tevent_req_nomem(subreq, req)) {
877 return tevent_req_post(req, ev);
879 tevent_req_set_callback(subreq, winexe_out_pipe_opened, req);
880 return req;
883 static void winexe_out_pipe_opened(struct tevent_req *subreq)
885 struct tevent_req *req = tevent_req_callback_data(
886 subreq, struct tevent_req);
887 struct winexe_out_pipe_state *state = tevent_req_data(
888 req, struct winexe_out_pipe_state);
889 int timeout;
890 NTSTATUS status;
892 status = cli_ntcreate_recv(subreq, &state->out_pipe, NULL);
893 TALLOC_FREE(subreq);
894 if (tevent_req_nterror(req, status)) {
895 return;
898 timeout = state->cli->timeout;
899 state->cli->timeout = 0;
901 subreq = cli_read_send(
902 state,
903 state->ev,
904 state->cli,
905 state->out_pipe,
906 state->out_inbuf,
908 sizeof(state->out_inbuf));
910 state->cli->timeout = timeout;
912 if (tevent_req_nomem(subreq, req)) {
913 return;
915 tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
918 static void winexe_out_pipe_got_data(struct tevent_req *subreq)
920 struct tevent_req *req = tevent_req_callback_data(
921 subreq, struct tevent_req);
922 struct winexe_out_pipe_state *state = tevent_req_data(
923 req, struct winexe_out_pipe_state);
924 NTSTATUS status;
925 int timeout;
926 size_t received;
927 ssize_t written;
929 status = cli_read_recv(subreq, &received);
930 TALLOC_FREE(subreq);
932 DBG_DEBUG("cli_read for %d gave %s\n",
933 state->out_fd,
934 nt_errstr(status));
936 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
937 subreq = cli_close_send(
938 state,
939 state->ev,
940 state->cli,
941 state->out_pipe);
942 if (tevent_req_nomem(subreq, req)) {
943 return;
945 tevent_req_set_callback(subreq, winexe_out_pipe_closed, req);
946 return;
949 if (tevent_req_nterror(req, status)) {
950 return;
953 if (received > 0) {
954 written = sys_write(state->out_fd, state->out_inbuf, received);
955 if (written == -1) {
956 tevent_req_nterror(req, map_nt_error_from_unix(errno));
957 return;
961 timeout = state->cli->timeout;
962 state->cli->timeout = 0;
964 subreq = cli_read_send(
965 state,
966 state->ev,
967 state->cli,
968 state->out_pipe,
969 state->out_inbuf,
971 sizeof(state->out_inbuf));
973 state->cli->timeout = timeout;
975 if (tevent_req_nomem(subreq, req)) {
976 return;
978 tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
981 static void winexe_out_pipe_closed(struct tevent_req *subreq)
983 struct tevent_req *req = tevent_req_callback_data(
984 subreq, struct tevent_req);
985 NTSTATUS status;
987 status = cli_close_recv(subreq);
988 TALLOC_FREE(subreq);
989 if (tevent_req_nterror(req, status)) {
990 return;
992 tevent_req_done(req);
995 static NTSTATUS winexe_out_pipe_recv(struct tevent_req *req)
997 return tevent_req_simple_recv_ntstatus(req);
1000 struct winexe_in_pipe_state {
1001 struct tevent_context *ev;
1002 struct cli_state *cli;
1003 struct tevent_req *fd_read_req;
1004 bool close_requested;
1005 bool closing;
1006 uint16_t in_pipe;
1007 int in_fd;
1008 char inbuf[256];
1011 static void winexe_in_pipe_opened(struct tevent_req *subreq);
1012 static void winexe_in_pipe_got_data(struct tevent_req *subreq);
1013 static void winexe_in_pipe_written(struct tevent_req *subreq);
1014 static void winexe_in_pipe_closed(struct tevent_req *subreq);
1016 static struct tevent_req *winexe_in_pipe_send(
1017 TALLOC_CTX *mem_ctx,
1018 struct tevent_context *ev,
1019 struct cli_state *cli,
1020 const char *pipe_name,
1021 int in_fd)
1023 struct tevent_req *req, *subreq;
1024 struct winexe_in_pipe_state *state;
1026 req = tevent_req_create(mem_ctx, &state,
1027 struct winexe_in_pipe_state);
1028 if (req == NULL) {
1029 return NULL;
1031 state->ev = ev;
1032 state->cli = cli;
1033 state->in_fd = in_fd;
1035 subreq = cli_ntcreate_send(
1036 state,
1037 state->ev,
1038 state->cli,
1039 pipe_name,
1041 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
1042 SEC_RIGHTS_FILE_EXECUTE,
1043 0, /* FileAttributes */
1044 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1045 FILE_OPEN, /* CreateDisposition */
1046 0, /* CreateOptions */
1047 0); /* SecurityFlags */
1048 if (tevent_req_nomem(subreq, req)) {
1049 return tevent_req_post(req, ev);
1051 tevent_req_set_callback(subreq, winexe_in_pipe_opened, req);
1052 return req;
1055 static void winexe_in_pipe_opened(struct tevent_req *subreq)
1057 struct tevent_req *req = tevent_req_callback_data(
1058 subreq, struct tevent_req);
1059 struct winexe_in_pipe_state *state = tevent_req_data(
1060 req, struct winexe_in_pipe_state);
1061 NTSTATUS status;
1063 status = cli_ntcreate_recv(subreq, &state->in_pipe, NULL);
1064 TALLOC_FREE(subreq);
1065 if (tevent_req_nterror(req, status)) {
1066 return;
1069 subreq = wait_for_read_send(
1070 state,
1071 state->ev,
1072 state->in_fd,
1073 true);
1074 if (tevent_req_nomem(subreq, req)) {
1075 return;
1077 tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
1079 state->fd_read_req = subreq;
1082 static void winexe_in_pipe_got_data(struct tevent_req *subreq)
1084 struct tevent_req *req = tevent_req_callback_data(
1085 subreq, struct tevent_req);
1086 struct winexe_in_pipe_state *state = tevent_req_data(
1087 req, struct winexe_in_pipe_state);
1088 int err;
1089 bool ok;
1090 int timeout;
1091 ssize_t nread;
1093 ok = wait_for_read_recv(subreq, &err);
1094 TALLOC_FREE(subreq);
1095 if (!ok) {
1096 tevent_req_nterror(req, map_nt_error_from_unix(err));
1097 return;
1099 state->fd_read_req = NULL;
1101 nread = sys_read(state->in_fd, &state->inbuf, sizeof(state->inbuf));
1102 if (nread == -1) {
1103 tevent_req_nterror(req, map_nt_error_from_unix(errno));
1104 return;
1106 if (nread == 0) {
1107 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
1108 return;
1111 timeout = state->cli->timeout;
1112 state->cli->timeout = 0;
1114 subreq = cli_writeall_send(
1115 state,
1116 state->ev,
1117 state->cli,
1118 state->in_pipe,
1120 (uint8_t *)state->inbuf,
1122 nread);
1124 state->cli->timeout = timeout;
1126 if (tevent_req_nomem(subreq, req)) {
1127 return;
1129 tevent_req_set_callback(subreq, winexe_in_pipe_written, req);
1132 static void winexe_in_pipe_written(struct tevent_req *subreq)
1134 struct tevent_req *req = tevent_req_callback_data(
1135 subreq, struct tevent_req);
1136 struct winexe_in_pipe_state *state = tevent_req_data(
1137 req, struct winexe_in_pipe_state);
1138 NTSTATUS status;
1140 status = cli_writeall_recv(subreq, NULL);
1141 TALLOC_FREE(subreq);
1143 DBG_DEBUG("cli_writeall for %d gave %s\n",
1144 state->in_fd,
1145 nt_errstr(status));
1147 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED) ||
1148 state->close_requested) {
1149 subreq = cli_close_send(
1150 state,
1151 state->ev,
1152 state->cli,
1153 state->in_pipe);
1154 if (tevent_req_nomem(subreq, req)) {
1155 return;
1157 tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1158 state->closing = true;
1159 return;
1162 if (tevent_req_nterror(req, status)) {
1163 return;
1166 subreq = wait_for_read_send(
1167 state,
1168 state->ev,
1169 state->in_fd,
1170 true);
1171 if (tevent_req_nomem(subreq, req)) {
1172 return;
1174 tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
1176 state->fd_read_req = subreq;
1179 static void winexe_in_pipe_closed(struct tevent_req *subreq)
1181 struct tevent_req *req = tevent_req_callback_data(
1182 subreq, struct tevent_req);
1183 NTSTATUS status;
1185 status = cli_close_recv(subreq);
1186 TALLOC_FREE(subreq);
1187 if (tevent_req_nterror(req, status)) {
1188 return;
1190 return tevent_req_done(req);
1193 static NTSTATUS winexe_in_pipe_recv(struct tevent_req *req)
1195 return tevent_req_simple_recv_ntstatus(req);
1198 static bool winexe_in_pipe_close(struct tevent_req *req)
1200 struct winexe_in_pipe_state *state = tevent_req_data(
1201 req, struct winexe_in_pipe_state);
1202 struct tevent_req *subreq;
1204 if (state->closing) {
1205 return true;
1208 if (state->fd_read_req == NULL) {
1210 * cli_writeall active, wait for it to return
1212 state->close_requested = true;
1213 return true;
1216 TALLOC_FREE(state->fd_read_req);
1218 subreq = cli_close_send(
1219 state,
1220 state->ev,
1221 state->cli,
1222 state->in_pipe);
1223 if (subreq == NULL) {
1224 return false;
1226 tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1227 state->closing = true;
1229 return true;
1232 struct winexe_pipes_state {
1233 struct tevent_req *pipes[3];
1236 static void winexe_pipes_stdin_done(struct tevent_req *subreq);
1237 static void winexe_pipes_stdout_done(struct tevent_req *subreq);
1238 static void winexe_pipes_stderr_done(struct tevent_req *subreq);
1240 static struct tevent_req *winexe_pipes_send(
1241 TALLOC_CTX *mem_ctx,
1242 struct tevent_context *ev,
1243 struct cli_state *cli,
1244 const char *pipe_postfix)
1246 struct tevent_req *req;
1247 struct winexe_pipes_state *state;
1248 char *pipe_name;
1250 req = tevent_req_create(mem_ctx, &state, struct winexe_pipes_state);
1251 if (req == NULL) {
1252 return NULL;
1255 pipe_name = talloc_asprintf(state, "\\ahexec_stdin%s", pipe_postfix);
1256 if (tevent_req_nomem(pipe_name, req)) {
1257 return tevent_req_post(req, ev);
1259 state->pipes[0] = winexe_in_pipe_send(
1260 state,
1262 cli,
1263 pipe_name,
1265 if (tevent_req_nomem(state->pipes[0], req)) {
1266 return tevent_req_post(req, ev);
1268 tevent_req_set_callback(state->pipes[0], winexe_pipes_stdin_done, req);
1270 pipe_name = talloc_asprintf(state, "\\ahexec_stdout%s", pipe_postfix);
1271 if (tevent_req_nomem(pipe_name, req)) {
1272 return tevent_req_post(req, ev);
1274 state->pipes[1] = winexe_out_pipe_send(
1275 state,
1277 cli,
1278 pipe_name,
1280 if (tevent_req_nomem(state->pipes[1], req)) {
1281 return tevent_req_post(req, ev);
1283 tevent_req_set_callback(state->pipes[1], winexe_pipes_stdout_done,
1284 req);
1286 pipe_name = talloc_asprintf(state, "\\ahexec_stderr%s", pipe_postfix);
1287 if (tevent_req_nomem(pipe_name, req)) {
1288 return tevent_req_post(req, ev);
1290 state->pipes[2] = winexe_out_pipe_send(
1291 state,
1293 cli,
1294 pipe_name,
1296 if (tevent_req_nomem(state->pipes[2], req)) {
1297 return tevent_req_post(req, ev);
1299 tevent_req_set_callback(state->pipes[2], winexe_pipes_stderr_done,
1300 req);
1302 DBG_DEBUG("pipes = %p %p %p\n",
1303 state->pipes[0],
1304 state->pipes[1],
1305 state->pipes[2]);
1307 return req;
1310 static void winexe_pipes_stdin_done(struct tevent_req *subreq)
1312 struct tevent_req *req = tevent_req_callback_data(
1313 subreq, struct tevent_req);
1314 struct winexe_pipes_state *state = tevent_req_data(
1315 req, struct winexe_pipes_state);
1316 NTSTATUS status;
1318 status = winexe_in_pipe_recv(subreq);
1319 TALLOC_FREE(subreq);
1321 DBG_DEBUG("stdin returned %s\n", nt_errstr(status));
1323 if (tevent_req_nterror(req, status)) {
1324 return;
1327 state->pipes[0] = NULL;
1329 DBG_DEBUG("pipes = %p %p %p\n",
1330 state->pipes[0],
1331 state->pipes[1],
1332 state->pipes[2]);
1334 if ((state->pipes[1] == NULL) && (state->pipes[2] == NULL)) {
1335 tevent_req_done(req);
1339 static void winexe_pipes_stdout_done(struct tevent_req *subreq)
1341 struct tevent_req *req = tevent_req_callback_data(
1342 subreq, struct tevent_req);
1343 struct winexe_pipes_state *state = tevent_req_data(
1344 req, struct winexe_pipes_state);
1345 NTSTATUS status;
1347 status = winexe_out_pipe_recv(subreq);
1348 TALLOC_FREE(subreq);
1350 DBG_DEBUG("stdout returned %s\n", nt_errstr(status));
1352 if (tevent_req_nterror(req, status)) {
1353 return;
1356 if (state->pipes[0] != NULL) {
1357 winexe_in_pipe_close(state->pipes[0]);
1360 state->pipes[1] = NULL;
1362 DBG_DEBUG("pipes = %p %p %p\n",
1363 state->pipes[0],
1364 state->pipes[1],
1365 state->pipes[2]);
1367 if ((state->pipes[0] == NULL) && (state->pipes[2] == NULL)) {
1368 tevent_req_done(req);
1372 static void winexe_pipes_stderr_done(struct tevent_req *subreq)
1374 struct tevent_req *req = tevent_req_callback_data(
1375 subreq, struct tevent_req);
1376 struct winexe_pipes_state *state = tevent_req_data(
1377 req, struct winexe_pipes_state);
1378 NTSTATUS status;
1380 status = winexe_out_pipe_recv(subreq);
1381 TALLOC_FREE(subreq);
1383 DBG_DEBUG("stderr returned %s\n", nt_errstr(status));
1385 if (tevent_req_nterror(req, status)) {
1386 return;
1389 if (state->pipes[0] != NULL) {
1390 winexe_in_pipe_close(state->pipes[0]);
1393 state->pipes[2] = NULL;
1395 DBG_DEBUG("pipes = %p %p %p\n",
1396 state->pipes[0],
1397 state->pipes[1],
1398 state->pipes[2]);
1400 if ((state->pipes[0] == NULL) && (state->pipes[1] == NULL)) {
1401 tevent_req_done(req);
1405 static NTSTATUS winexe_pipes_recv(struct tevent_req *req)
1407 return tevent_req_simple_recv_ntstatus(req);
1410 struct winexe_ctrl_state {
1411 struct tevent_context *ev;
1412 struct cli_state *cli;
1414 uint16_t ctrl_pipe;
1415 bool ctrl_pipe_done;
1417 char ctrl_inbuf[256];
1418 char *cmd;
1419 int return_code;
1421 struct tevent_req *pipes_req;
1424 static void winexe_ctrl_opened(struct tevent_req *subreq);
1425 static void winexe_ctrl_got_read(struct tevent_req *subreq);
1426 static void winexe_ctrl_wrote_version(struct tevent_req *subreq);
1427 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq);
1428 static void winexe_ctrl_pipes_done(struct tevent_req *subreq);
1429 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq);
1431 static struct tevent_req *winexe_ctrl_send(
1432 TALLOC_CTX *mem_ctx,
1433 struct tevent_context *ev,
1434 struct cli_state *cli,
1435 const char *cmd)
1437 struct tevent_req *req, *subreq;
1438 struct winexe_ctrl_state *state;
1440 req = tevent_req_create(mem_ctx, &state,
1441 struct winexe_ctrl_state);
1442 if (req == NULL) {
1443 return NULL;
1445 state->ev = ev;
1446 state->cli = cli;
1448 state->cmd = talloc_asprintf(state, "run %s\n", cmd);
1449 if (tevent_req_nomem(state->cmd, req)) {
1450 return tevent_req_post(req, ev);
1453 subreq = cli_ntcreate_send(
1454 state,
1455 state->ev,
1456 state->cli,
1457 "\\" PIPE_NAME,
1459 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
1460 SEC_RIGHTS_FILE_EXECUTE,
1461 0, /* FileAttributes */
1462 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1463 FILE_OPEN, /* CreateDisposition */
1464 0, /* CreateOptions */
1465 0); /* SecurityFlags */
1466 if (tevent_req_nomem(subreq, req)) {
1467 return tevent_req_post(req, ev);
1469 tevent_req_set_callback(subreq, winexe_ctrl_opened, req);
1470 return req;
1473 static void winexe_ctrl_opened(struct tevent_req *subreq)
1475 struct tevent_req *req = tevent_req_callback_data(
1476 subreq, struct tevent_req);
1477 struct winexe_ctrl_state *state = tevent_req_data(
1478 req, struct winexe_ctrl_state);
1479 int timeout;
1480 NTSTATUS status;
1481 static const char cmd[] = "get codepage\nget version\n";
1483 status = cli_ntcreate_recv(subreq, &state->ctrl_pipe, NULL);
1484 TALLOC_FREE(subreq);
1485 if (tevent_req_nterror(req, status)) {
1486 return;
1489 timeout = state->cli->timeout;
1490 state->cli->timeout = 0;
1492 subreq = cli_read_send(
1493 state,
1494 state->ev,
1495 state->cli,
1496 state->ctrl_pipe,
1497 state->ctrl_inbuf,
1499 sizeof(state->ctrl_inbuf)-1);
1501 state->cli->timeout = timeout;
1503 if (tevent_req_nomem(subreq, req)) {
1504 return;
1506 tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1508 subreq = cli_writeall_send(
1509 state,
1510 state->ev,
1511 state->cli,
1512 state->ctrl_pipe,
1514 (const uint8_t *)cmd,
1516 strlen(cmd));
1517 if (tevent_req_nomem(subreq, req)) {
1518 return;
1520 tevent_req_set_callback(subreq, winexe_ctrl_wrote_version, req);
1523 static void winexe_ctrl_got_read(struct tevent_req *subreq)
1525 struct tevent_req *req = tevent_req_callback_data(
1526 subreq, struct tevent_req);
1527 struct winexe_ctrl_state *state = tevent_req_data(
1528 req, struct winexe_ctrl_state);
1529 NTSTATUS status;
1530 int timeout;
1531 size_t received;
1532 unsigned int version, return_code;
1533 int ret;
1535 status = cli_read_recv(subreq, &received);
1536 TALLOC_FREE(subreq);
1538 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1539 subreq = cli_close_send(
1540 state,
1541 state->ev,
1542 state->cli,
1543 state->ctrl_pipe);
1544 if (tevent_req_nomem(subreq, req)) {
1545 return;
1547 tevent_req_set_callback(subreq, winexe_ctrl_pipe_closed, req);
1548 return;
1550 if (tevent_req_nterror(req, status)) {
1551 return;
1554 DBG_DEBUG("Got %zu bytes\n", received);
1556 timeout = state->cli->timeout;
1557 state->cli->timeout = 0;
1559 subreq = cli_read_send(
1560 state,
1561 state->ev,
1562 state->cli,
1563 state->ctrl_pipe,
1564 state->ctrl_inbuf,
1566 sizeof(state->ctrl_inbuf)-1);
1568 state->cli->timeout = timeout;
1570 if (tevent_req_nomem(subreq, req)) {
1571 return;
1573 tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1575 ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &version);
1576 if (ret == 1) {
1577 DBG_DEBUG("Got version %x\n", version);
1579 subreq = cli_writeall_send(
1580 state,
1581 state->ev,
1582 state->cli,
1583 state->ctrl_pipe,
1585 (const uint8_t *)state->cmd,
1587 strlen(state->cmd));
1588 if (tevent_req_nomem(subreq, req)) {
1589 return;
1591 tevent_req_set_callback(subreq, winexe_ctrl_wrote_cmd, req);
1592 return;
1595 ret = strncmp(state->ctrl_inbuf, "std_io_err ", strlen("std_io_err "));
1596 if (ret == 0) {
1597 char *p = state->ctrl_inbuf + 11;
1598 char *q = strchr(state->ctrl_inbuf, '\n');
1599 char *postfix;
1600 size_t postfix_len;
1602 if (q == NULL) {
1603 DBG_DEBUG("Got invalid pipe postfix\n");
1604 return;
1607 postfix_len = q - p;
1609 postfix = talloc_strndup(state, p, postfix_len);
1610 if (tevent_req_nomem(postfix, req)) {
1611 return;
1614 DBG_DEBUG("Got pipe postfix %s\n", postfix);
1616 subreq = winexe_pipes_send(
1617 state,
1618 state->ev,
1619 state->cli,
1620 postfix);
1621 if (tevent_req_nomem(subreq, req)) {
1622 return;
1624 tevent_req_set_callback(subreq, winexe_ctrl_pipes_done, req);
1626 state->pipes_req = subreq;
1628 return;
1631 ret = strncmp(state->ctrl_inbuf, "error ", strlen("error "));
1632 if (ret == 0) {
1633 printf("Error: %s", state->ctrl_inbuf);
1634 return;
1637 ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &return_code);
1638 if (ret == 1) {
1639 state->return_code = return_code;
1640 return;
1644 static void winexe_ctrl_wrote_version(struct tevent_req *subreq)
1646 struct tevent_req *req = tevent_req_callback_data(
1647 subreq, struct tevent_req);
1648 NTSTATUS status;
1650 status = cli_writeall_recv(subreq, NULL);
1651 TALLOC_FREE(subreq);
1652 if (tevent_req_nterror(req, status)) {
1653 return;
1657 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq)
1659 struct tevent_req *req = tevent_req_callback_data(
1660 subreq, struct tevent_req);
1661 NTSTATUS status;
1663 status = cli_writeall_recv(subreq, NULL);
1664 TALLOC_FREE(subreq);
1665 if (tevent_req_nterror(req, status)) {
1666 return;
1670 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq)
1672 struct tevent_req *req = tevent_req_callback_data(
1673 subreq, struct tevent_req);
1674 struct winexe_ctrl_state *state = tevent_req_data(
1675 req, struct winexe_ctrl_state);
1676 NTSTATUS status;
1678 status = cli_close_recv(subreq);
1679 TALLOC_FREE(subreq);
1680 if (tevent_req_nterror(req, status)) {
1681 return;
1684 state->ctrl_pipe_done = true;
1685 if (state->pipes_req == NULL) {
1686 tevent_req_done(req);
1690 static void winexe_ctrl_pipes_done(struct tevent_req *subreq)
1692 struct tevent_req *req = tevent_req_callback_data(
1693 subreq, struct tevent_req);
1694 struct winexe_ctrl_state *state = tevent_req_data(
1695 req, struct winexe_ctrl_state);
1696 NTSTATUS status;
1698 status = winexe_pipes_recv(subreq);
1699 TALLOC_FREE(subreq);
1700 if (tevent_req_nterror(req, status)) {
1701 return;
1704 state->pipes_req = NULL;
1705 if (state->ctrl_pipe_done) {
1706 tevent_req_done(req);
1710 static NTSTATUS winexe_ctrl_recv(struct tevent_req *req,
1711 int *preturn_code)
1713 struct winexe_ctrl_state *state = tevent_req_data(
1714 req, struct winexe_ctrl_state);
1715 NTSTATUS status;
1717 if (tevent_req_is_nterror(req, &status)) {
1718 return status;
1720 if (preturn_code != NULL) {
1721 *preturn_code = state->return_code;
1723 return NT_STATUS_OK;
1726 static NTSTATUS winexe_ctrl(struct cli_state *cli,
1727 const char *cmd,
1728 int *preturn_code)
1730 struct tevent_context *ev = NULL;
1731 struct tevent_req *req = NULL;
1732 NTSTATUS status = NT_STATUS_NO_MEMORY;
1733 bool ok;
1735 ev = samba_tevent_context_init(cli);
1736 if (ev == NULL) {
1737 goto done;
1739 req = winexe_ctrl_send(ev, ev, cli, cmd);
1740 if (req == NULL) {
1741 goto done;
1743 ok = tevent_req_poll_ntstatus(req, ev, &status);
1744 if (!ok) {
1745 goto done;
1747 status = winexe_ctrl_recv(req, preturn_code);
1748 done:
1749 TALLOC_FREE(req);
1750 TALLOC_FREE(ev);
1751 return status;
1754 #ifdef HAVE_WINEXE_CC_WIN32
1755 const DATA_BLOB *winexesvc32_exe_binary(void);
1756 #endif
1758 #ifdef HAVE_WINEXE_CC_WIN64
1759 const DATA_BLOB *winexesvc64_exe_binary(void);
1760 #endif
1762 int main(int argc, const char *argv[])
1764 TALLOC_CTX *frame = talloc_stackframe();
1765 struct program_options options = {0};
1766 struct loadparm_context *lp_ctx;
1767 struct cli_state *cli;
1768 const char *service_name = SERVICE_NAME;
1769 char *service_filename = NULL;
1770 #ifdef HAVE_WINEXE_CC_WIN32
1771 const DATA_BLOB *winexesvc32_exe = winexesvc32_exe_binary();
1772 #else
1773 const DATA_BLOB *winexesvc32_exe = NULL;
1774 #endif
1775 #ifdef HAVE_WINEXE_CC_WIN64
1776 const DATA_BLOB *winexesvc64_exe = winexesvc64_exe_binary();
1777 #else
1778 const DATA_BLOB *winexesvc64_exe = NULL;
1779 #endif
1780 NTSTATUS status;
1781 int ret = 1;
1782 int return_code = 0;
1784 lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
1785 if (lp_ctx == NULL) {
1786 fprintf(stderr, "loadparm_init_s3 failed\n");
1787 goto done;
1790 smb_init_locale();
1791 setup_logging("winexe", DEBUG_STDOUT);
1793 lp_load_global(get_dyn_CONFIGFILE());
1795 parse_args(argc, argv, frame, &options, lp_ctx);
1797 if (options.cmd == NULL) {
1798 fprintf(stderr, "no cmd given\n");
1799 goto done;
1802 service_filename = talloc_asprintf(frame, "%s.exe", service_name);
1803 if (service_filename == NULL) {
1804 DBG_WARNING("talloc_asprintf failed\n");
1805 goto done;
1808 status = cli_full_connection_creds(
1809 &cli,
1810 NULL,
1811 options.hostname,
1812 NULL,
1813 445,
1814 "IPC$",
1815 "?????",
1816 options.credentials,
1820 if (!NT_STATUS_IS_OK(status)) {
1821 DBG_WARNING("cli_full_connection_creds failed: %s\n",
1822 nt_errstr(status));
1823 goto done;
1826 status = winexe_svc_install(
1827 cli,
1828 options.hostname,
1829 service_name,
1830 service_filename,
1831 winexesvc32_exe,
1832 winexesvc64_exe,
1833 options.credentials,
1834 options.flags);
1835 if (!NT_STATUS_IS_OK(status)) {
1836 DBG_WARNING("winexe_svc_install failed: %s\n",
1837 nt_errstr(status));
1838 goto done;
1841 status = winexe_ctrl(cli, options.cmd, &return_code);
1842 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1843 /* Normal finish */
1844 status = NT_STATUS_OK;
1846 if (!NT_STATUS_IS_OK(status)) {
1847 DBG_WARNING("cli_ctrl failed: %s\n",
1848 nt_errstr(status));
1849 goto done;
1852 if (options.flags & SVC_UNINSTALL) {
1853 status = winexe_svc_uninstall(
1854 cli,
1855 service_name);
1856 if (!NT_STATUS_IS_OK(status)) {
1857 DBG_WARNING("winexe_svc_uninstall failed: %s\n",
1858 nt_errstr(status));
1859 goto done;
1863 ret = return_code;
1864 done:
1865 TALLOC_FREE(frame);
1866 return ret;