libsmb: Add cli_smb2_query_info_fnum
[Samba.git] / examples / winexe / winexe.c
blob429ba2f5163e60705d98890c6eb598bcbbb1a44f
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 SMB2_IMPERSONATION_IMPERSONATION,
876 0); /* SecurityFlags */
877 if (tevent_req_nomem(subreq, req)) {
878 return tevent_req_post(req, ev);
880 tevent_req_set_callback(subreq, winexe_out_pipe_opened, req);
881 return req;
884 static void winexe_out_pipe_opened(struct tevent_req *subreq)
886 struct tevent_req *req = tevent_req_callback_data(
887 subreq, struct tevent_req);
888 struct winexe_out_pipe_state *state = tevent_req_data(
889 req, struct winexe_out_pipe_state);
890 int timeout;
891 NTSTATUS status;
893 status = cli_ntcreate_recv(subreq, &state->out_pipe, NULL);
894 TALLOC_FREE(subreq);
895 if (tevent_req_nterror(req, status)) {
896 return;
899 timeout = state->cli->timeout;
900 state->cli->timeout = 0;
902 subreq = cli_read_send(
903 state,
904 state->ev,
905 state->cli,
906 state->out_pipe,
907 state->out_inbuf,
909 sizeof(state->out_inbuf));
911 state->cli->timeout = timeout;
913 if (tevent_req_nomem(subreq, req)) {
914 return;
916 tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
919 static void winexe_out_pipe_got_data(struct tevent_req *subreq)
921 struct tevent_req *req = tevent_req_callback_data(
922 subreq, struct tevent_req);
923 struct winexe_out_pipe_state *state = tevent_req_data(
924 req, struct winexe_out_pipe_state);
925 NTSTATUS status;
926 int timeout;
927 size_t received;
928 ssize_t written;
930 status = cli_read_recv(subreq, &received);
931 TALLOC_FREE(subreq);
933 DBG_DEBUG("cli_read for %d gave %s\n",
934 state->out_fd,
935 nt_errstr(status));
937 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
938 subreq = cli_close_send(
939 state,
940 state->ev,
941 state->cli,
942 state->out_pipe);
943 if (tevent_req_nomem(subreq, req)) {
944 return;
946 tevent_req_set_callback(subreq, winexe_out_pipe_closed, req);
947 return;
950 if (tevent_req_nterror(req, status)) {
951 return;
954 if (received > 0) {
955 written = sys_write(state->out_fd, state->out_inbuf, received);
956 if (written == -1) {
957 tevent_req_nterror(req, map_nt_error_from_unix(errno));
958 return;
962 timeout = state->cli->timeout;
963 state->cli->timeout = 0;
965 subreq = cli_read_send(
966 state,
967 state->ev,
968 state->cli,
969 state->out_pipe,
970 state->out_inbuf,
972 sizeof(state->out_inbuf));
974 state->cli->timeout = timeout;
976 if (tevent_req_nomem(subreq, req)) {
977 return;
979 tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
982 static void winexe_out_pipe_closed(struct tevent_req *subreq)
984 struct tevent_req *req = tevent_req_callback_data(
985 subreq, struct tevent_req);
986 NTSTATUS status;
988 status = cli_close_recv(subreq);
989 TALLOC_FREE(subreq);
990 if (tevent_req_nterror(req, status)) {
991 return;
993 tevent_req_done(req);
996 static NTSTATUS winexe_out_pipe_recv(struct tevent_req *req)
998 return tevent_req_simple_recv_ntstatus(req);
1001 struct winexe_in_pipe_state {
1002 struct tevent_context *ev;
1003 struct cli_state *cli;
1004 struct tevent_req *fd_read_req;
1005 bool close_requested;
1006 bool closing;
1007 uint16_t in_pipe;
1008 int in_fd;
1009 char inbuf[256];
1012 static void winexe_in_pipe_opened(struct tevent_req *subreq);
1013 static void winexe_in_pipe_got_data(struct tevent_req *subreq);
1014 static void winexe_in_pipe_written(struct tevent_req *subreq);
1015 static void winexe_in_pipe_closed(struct tevent_req *subreq);
1017 static struct tevent_req *winexe_in_pipe_send(
1018 TALLOC_CTX *mem_ctx,
1019 struct tevent_context *ev,
1020 struct cli_state *cli,
1021 const char *pipe_name,
1022 int in_fd)
1024 struct tevent_req *req, *subreq;
1025 struct winexe_in_pipe_state *state;
1027 req = tevent_req_create(mem_ctx, &state,
1028 struct winexe_in_pipe_state);
1029 if (req == NULL) {
1030 return NULL;
1032 state->ev = ev;
1033 state->cli = cli;
1034 state->in_fd = in_fd;
1036 subreq = cli_ntcreate_send(
1037 state,
1038 state->ev,
1039 state->cli,
1040 pipe_name,
1042 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
1043 SEC_RIGHTS_FILE_EXECUTE,
1044 0, /* FileAttributes */
1045 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1046 FILE_OPEN, /* CreateDisposition */
1047 0, /* CreateOptions */
1048 SMB2_IMPERSONATION_IMPERSONATION,
1049 0); /* SecurityFlags */
1050 if (tevent_req_nomem(subreq, req)) {
1051 return tevent_req_post(req, ev);
1053 tevent_req_set_callback(subreq, winexe_in_pipe_opened, req);
1054 return req;
1057 static void winexe_in_pipe_opened(struct tevent_req *subreq)
1059 struct tevent_req *req = tevent_req_callback_data(
1060 subreq, struct tevent_req);
1061 struct winexe_in_pipe_state *state = tevent_req_data(
1062 req, struct winexe_in_pipe_state);
1063 NTSTATUS status;
1065 status = cli_ntcreate_recv(subreq, &state->in_pipe, NULL);
1066 TALLOC_FREE(subreq);
1067 if (tevent_req_nterror(req, status)) {
1068 return;
1071 subreq = wait_for_read_send(
1072 state,
1073 state->ev,
1074 state->in_fd,
1075 true);
1076 if (tevent_req_nomem(subreq, req)) {
1077 return;
1079 tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
1081 state->fd_read_req = subreq;
1084 static void winexe_in_pipe_got_data(struct tevent_req *subreq)
1086 struct tevent_req *req = tevent_req_callback_data(
1087 subreq, struct tevent_req);
1088 struct winexe_in_pipe_state *state = tevent_req_data(
1089 req, struct winexe_in_pipe_state);
1090 int err;
1091 bool ok;
1092 int timeout;
1093 ssize_t nread;
1095 ok = wait_for_read_recv(subreq, &err);
1096 TALLOC_FREE(subreq);
1097 if (!ok) {
1098 tevent_req_nterror(req, map_nt_error_from_unix(err));
1099 return;
1101 state->fd_read_req = NULL;
1103 nread = sys_read(state->in_fd, &state->inbuf, sizeof(state->inbuf));
1104 if (nread == -1) {
1105 tevent_req_nterror(req, map_nt_error_from_unix(errno));
1106 return;
1108 if (nread == 0) {
1109 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
1110 return;
1113 timeout = state->cli->timeout;
1114 state->cli->timeout = 0;
1116 subreq = cli_writeall_send(
1117 state,
1118 state->ev,
1119 state->cli,
1120 state->in_pipe,
1122 (uint8_t *)state->inbuf,
1124 nread);
1126 state->cli->timeout = timeout;
1128 if (tevent_req_nomem(subreq, req)) {
1129 return;
1131 tevent_req_set_callback(subreq, winexe_in_pipe_written, req);
1134 static void winexe_in_pipe_written(struct tevent_req *subreq)
1136 struct tevent_req *req = tevent_req_callback_data(
1137 subreq, struct tevent_req);
1138 struct winexe_in_pipe_state *state = tevent_req_data(
1139 req, struct winexe_in_pipe_state);
1140 NTSTATUS status;
1142 status = cli_writeall_recv(subreq, NULL);
1143 TALLOC_FREE(subreq);
1145 DBG_DEBUG("cli_writeall for %d gave %s\n",
1146 state->in_fd,
1147 nt_errstr(status));
1149 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED) ||
1150 state->close_requested) {
1151 subreq = cli_close_send(
1152 state,
1153 state->ev,
1154 state->cli,
1155 state->in_pipe);
1156 if (tevent_req_nomem(subreq, req)) {
1157 return;
1159 tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1160 state->closing = true;
1161 return;
1164 if (tevent_req_nterror(req, status)) {
1165 return;
1168 subreq = wait_for_read_send(
1169 state,
1170 state->ev,
1171 state->in_fd,
1172 true);
1173 if (tevent_req_nomem(subreq, req)) {
1174 return;
1176 tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
1178 state->fd_read_req = subreq;
1181 static void winexe_in_pipe_closed(struct tevent_req *subreq)
1183 struct tevent_req *req = tevent_req_callback_data(
1184 subreq, struct tevent_req);
1185 NTSTATUS status;
1187 status = cli_close_recv(subreq);
1188 TALLOC_FREE(subreq);
1189 if (tevent_req_nterror(req, status)) {
1190 return;
1192 return tevent_req_done(req);
1195 static NTSTATUS winexe_in_pipe_recv(struct tevent_req *req)
1197 return tevent_req_simple_recv_ntstatus(req);
1200 static bool winexe_in_pipe_close(struct tevent_req *req)
1202 struct winexe_in_pipe_state *state = tevent_req_data(
1203 req, struct winexe_in_pipe_state);
1204 struct tevent_req *subreq;
1206 if (state->closing) {
1207 return true;
1210 if (state->fd_read_req == NULL) {
1212 * cli_writeall active, wait for it to return
1214 state->close_requested = true;
1215 return true;
1218 TALLOC_FREE(state->fd_read_req);
1220 subreq = cli_close_send(
1221 state,
1222 state->ev,
1223 state->cli,
1224 state->in_pipe);
1225 if (subreq == NULL) {
1226 return false;
1228 tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1229 state->closing = true;
1231 return true;
1234 struct winexe_pipes_state {
1235 struct tevent_req *pipes[3];
1238 static void winexe_pipes_stdin_done(struct tevent_req *subreq);
1239 static void winexe_pipes_stdout_done(struct tevent_req *subreq);
1240 static void winexe_pipes_stderr_done(struct tevent_req *subreq);
1242 static struct tevent_req *winexe_pipes_send(
1243 TALLOC_CTX *mem_ctx,
1244 struct tevent_context *ev,
1245 struct cli_state *cli,
1246 const char *pipe_postfix)
1248 struct tevent_req *req;
1249 struct winexe_pipes_state *state;
1250 char *pipe_name;
1252 req = tevent_req_create(mem_ctx, &state, struct winexe_pipes_state);
1253 if (req == NULL) {
1254 return NULL;
1257 pipe_name = talloc_asprintf(state, "\\ahexec_stdin%s", pipe_postfix);
1258 if (tevent_req_nomem(pipe_name, req)) {
1259 return tevent_req_post(req, ev);
1261 state->pipes[0] = winexe_in_pipe_send(
1262 state,
1264 cli,
1265 pipe_name,
1267 if (tevent_req_nomem(state->pipes[0], req)) {
1268 return tevent_req_post(req, ev);
1270 tevent_req_set_callback(state->pipes[0], winexe_pipes_stdin_done, req);
1272 pipe_name = talloc_asprintf(state, "\\ahexec_stdout%s", pipe_postfix);
1273 if (tevent_req_nomem(pipe_name, req)) {
1274 return tevent_req_post(req, ev);
1276 state->pipes[1] = winexe_out_pipe_send(
1277 state,
1279 cli,
1280 pipe_name,
1282 if (tevent_req_nomem(state->pipes[1], req)) {
1283 return tevent_req_post(req, ev);
1285 tevent_req_set_callback(state->pipes[1], winexe_pipes_stdout_done,
1286 req);
1288 pipe_name = talloc_asprintf(state, "\\ahexec_stderr%s", pipe_postfix);
1289 if (tevent_req_nomem(pipe_name, req)) {
1290 return tevent_req_post(req, ev);
1292 state->pipes[2] = winexe_out_pipe_send(
1293 state,
1295 cli,
1296 pipe_name,
1298 if (tevent_req_nomem(state->pipes[2], req)) {
1299 return tevent_req_post(req, ev);
1301 tevent_req_set_callback(state->pipes[2], winexe_pipes_stderr_done,
1302 req);
1304 DBG_DEBUG("pipes = %p %p %p\n",
1305 state->pipes[0],
1306 state->pipes[1],
1307 state->pipes[2]);
1309 return req;
1312 static void winexe_pipes_stdin_done(struct tevent_req *subreq)
1314 struct tevent_req *req = tevent_req_callback_data(
1315 subreq, struct tevent_req);
1316 struct winexe_pipes_state *state = tevent_req_data(
1317 req, struct winexe_pipes_state);
1318 NTSTATUS status;
1320 status = winexe_in_pipe_recv(subreq);
1321 TALLOC_FREE(subreq);
1323 DBG_DEBUG("stdin returned %s\n", nt_errstr(status));
1325 if (tevent_req_nterror(req, status)) {
1326 return;
1329 state->pipes[0] = NULL;
1331 DBG_DEBUG("pipes = %p %p %p\n",
1332 state->pipes[0],
1333 state->pipes[1],
1334 state->pipes[2]);
1336 if ((state->pipes[1] == NULL) && (state->pipes[2] == NULL)) {
1337 tevent_req_done(req);
1341 static void winexe_pipes_stdout_done(struct tevent_req *subreq)
1343 struct tevent_req *req = tevent_req_callback_data(
1344 subreq, struct tevent_req);
1345 struct winexe_pipes_state *state = tevent_req_data(
1346 req, struct winexe_pipes_state);
1347 NTSTATUS status;
1349 status = winexe_out_pipe_recv(subreq);
1350 TALLOC_FREE(subreq);
1352 DBG_DEBUG("stdout returned %s\n", nt_errstr(status));
1354 if (tevent_req_nterror(req, status)) {
1355 return;
1358 if (state->pipes[0] != NULL) {
1359 winexe_in_pipe_close(state->pipes[0]);
1362 state->pipes[1] = NULL;
1364 DBG_DEBUG("pipes = %p %p %p\n",
1365 state->pipes[0],
1366 state->pipes[1],
1367 state->pipes[2]);
1369 if ((state->pipes[0] == NULL) && (state->pipes[2] == NULL)) {
1370 tevent_req_done(req);
1374 static void winexe_pipes_stderr_done(struct tevent_req *subreq)
1376 struct tevent_req *req = tevent_req_callback_data(
1377 subreq, struct tevent_req);
1378 struct winexe_pipes_state *state = tevent_req_data(
1379 req, struct winexe_pipes_state);
1380 NTSTATUS status;
1382 status = winexe_out_pipe_recv(subreq);
1383 TALLOC_FREE(subreq);
1385 DBG_DEBUG("stderr returned %s\n", nt_errstr(status));
1387 if (tevent_req_nterror(req, status)) {
1388 return;
1391 if (state->pipes[0] != NULL) {
1392 winexe_in_pipe_close(state->pipes[0]);
1395 state->pipes[2] = NULL;
1397 DBG_DEBUG("pipes = %p %p %p\n",
1398 state->pipes[0],
1399 state->pipes[1],
1400 state->pipes[2]);
1402 if ((state->pipes[0] == NULL) && (state->pipes[1] == NULL)) {
1403 tevent_req_done(req);
1407 static NTSTATUS winexe_pipes_recv(struct tevent_req *req)
1409 return tevent_req_simple_recv_ntstatus(req);
1412 struct winexe_ctrl_state {
1413 struct tevent_context *ev;
1414 struct cli_state *cli;
1416 uint16_t ctrl_pipe;
1417 bool ctrl_pipe_done;
1419 char ctrl_inbuf[256];
1420 char *cmd;
1421 int return_code;
1423 struct tevent_req *pipes_req;
1426 static void winexe_ctrl_opened(struct tevent_req *subreq);
1427 static void winexe_ctrl_got_read(struct tevent_req *subreq);
1428 static void winexe_ctrl_wrote_version(struct tevent_req *subreq);
1429 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq);
1430 static void winexe_ctrl_pipes_done(struct tevent_req *subreq);
1431 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq);
1433 static struct tevent_req *winexe_ctrl_send(
1434 TALLOC_CTX *mem_ctx,
1435 struct tevent_context *ev,
1436 struct cli_state *cli,
1437 const char *cmd)
1439 struct tevent_req *req, *subreq;
1440 struct winexe_ctrl_state *state;
1442 req = tevent_req_create(mem_ctx, &state,
1443 struct winexe_ctrl_state);
1444 if (req == NULL) {
1445 return NULL;
1447 state->ev = ev;
1448 state->cli = cli;
1450 state->cmd = talloc_asprintf(state, "run %s\n", cmd);
1451 if (tevent_req_nomem(state->cmd, req)) {
1452 return tevent_req_post(req, ev);
1455 subreq = cli_ntcreate_send(
1456 state,
1457 state->ev,
1458 state->cli,
1459 "\\" PIPE_NAME,
1461 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
1462 SEC_RIGHTS_FILE_EXECUTE,
1463 0, /* FileAttributes */
1464 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1465 FILE_OPEN, /* CreateDisposition */
1466 0, /* CreateOptions */
1467 SMB2_IMPERSONATION_IMPERSONATION,
1468 0); /* SecurityFlags */
1469 if (tevent_req_nomem(subreq, req)) {
1470 return tevent_req_post(req, ev);
1472 tevent_req_set_callback(subreq, winexe_ctrl_opened, req);
1473 return req;
1476 static void winexe_ctrl_opened(struct tevent_req *subreq)
1478 struct tevent_req *req = tevent_req_callback_data(
1479 subreq, struct tevent_req);
1480 struct winexe_ctrl_state *state = tevent_req_data(
1481 req, struct winexe_ctrl_state);
1482 int timeout;
1483 NTSTATUS status;
1484 static const char cmd[] = "get codepage\nget version\n";
1486 status = cli_ntcreate_recv(subreq, &state->ctrl_pipe, NULL);
1487 TALLOC_FREE(subreq);
1488 if (tevent_req_nterror(req, status)) {
1489 return;
1492 timeout = state->cli->timeout;
1493 state->cli->timeout = 0;
1495 subreq = cli_read_send(
1496 state,
1497 state->ev,
1498 state->cli,
1499 state->ctrl_pipe,
1500 state->ctrl_inbuf,
1502 sizeof(state->ctrl_inbuf)-1);
1504 state->cli->timeout = timeout;
1506 if (tevent_req_nomem(subreq, req)) {
1507 return;
1509 tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1511 subreq = cli_writeall_send(
1512 state,
1513 state->ev,
1514 state->cli,
1515 state->ctrl_pipe,
1517 (const uint8_t *)cmd,
1519 strlen(cmd));
1520 if (tevent_req_nomem(subreq, req)) {
1521 return;
1523 tevent_req_set_callback(subreq, winexe_ctrl_wrote_version, req);
1526 static void winexe_ctrl_got_read(struct tevent_req *subreq)
1528 struct tevent_req *req = tevent_req_callback_data(
1529 subreq, struct tevent_req);
1530 struct winexe_ctrl_state *state = tevent_req_data(
1531 req, struct winexe_ctrl_state);
1532 NTSTATUS status;
1533 int timeout;
1534 size_t received;
1535 unsigned int version, return_code;
1536 int ret;
1538 status = cli_read_recv(subreq, &received);
1539 TALLOC_FREE(subreq);
1541 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1542 subreq = cli_close_send(
1543 state,
1544 state->ev,
1545 state->cli,
1546 state->ctrl_pipe);
1547 if (tevent_req_nomem(subreq, req)) {
1548 return;
1550 tevent_req_set_callback(subreq, winexe_ctrl_pipe_closed, req);
1551 return;
1553 if (tevent_req_nterror(req, status)) {
1554 return;
1557 DBG_DEBUG("Got %zu bytes\n", received);
1559 timeout = state->cli->timeout;
1560 state->cli->timeout = 0;
1562 subreq = cli_read_send(
1563 state,
1564 state->ev,
1565 state->cli,
1566 state->ctrl_pipe,
1567 state->ctrl_inbuf,
1569 sizeof(state->ctrl_inbuf)-1);
1571 state->cli->timeout = timeout;
1573 if (tevent_req_nomem(subreq, req)) {
1574 return;
1576 tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1578 ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &version);
1579 if (ret == 1) {
1580 DBG_DEBUG("Got version %x\n", version);
1582 subreq = cli_writeall_send(
1583 state,
1584 state->ev,
1585 state->cli,
1586 state->ctrl_pipe,
1588 (const uint8_t *)state->cmd,
1590 strlen(state->cmd));
1591 if (tevent_req_nomem(subreq, req)) {
1592 return;
1594 tevent_req_set_callback(subreq, winexe_ctrl_wrote_cmd, req);
1595 return;
1598 ret = strncmp(state->ctrl_inbuf, "std_io_err ", strlen("std_io_err "));
1599 if (ret == 0) {
1600 char *p = state->ctrl_inbuf + 11;
1601 char *q = strchr(state->ctrl_inbuf, '\n');
1602 char *postfix;
1603 size_t postfix_len;
1605 if (q == NULL) {
1606 DBG_DEBUG("Got invalid pipe postfix\n");
1607 return;
1610 postfix_len = q - p;
1612 postfix = talloc_strndup(state, p, postfix_len);
1613 if (tevent_req_nomem(postfix, req)) {
1614 return;
1617 DBG_DEBUG("Got pipe postfix %s\n", postfix);
1619 subreq = winexe_pipes_send(
1620 state,
1621 state->ev,
1622 state->cli,
1623 postfix);
1624 if (tevent_req_nomem(subreq, req)) {
1625 return;
1627 tevent_req_set_callback(subreq, winexe_ctrl_pipes_done, req);
1629 state->pipes_req = subreq;
1631 return;
1634 ret = strncmp(state->ctrl_inbuf, "error ", strlen("error "));
1635 if (ret == 0) {
1636 printf("Error: %s", state->ctrl_inbuf);
1637 return;
1640 ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &return_code);
1641 if (ret == 1) {
1642 state->return_code = return_code;
1643 return;
1647 static void winexe_ctrl_wrote_version(struct tevent_req *subreq)
1649 struct tevent_req *req = tevent_req_callback_data(
1650 subreq, struct tevent_req);
1651 NTSTATUS status;
1653 status = cli_writeall_recv(subreq, NULL);
1654 TALLOC_FREE(subreq);
1655 if (tevent_req_nterror(req, status)) {
1656 return;
1660 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq)
1662 struct tevent_req *req = tevent_req_callback_data(
1663 subreq, struct tevent_req);
1664 NTSTATUS status;
1666 status = cli_writeall_recv(subreq, NULL);
1667 TALLOC_FREE(subreq);
1668 if (tevent_req_nterror(req, status)) {
1669 return;
1673 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq)
1675 struct tevent_req *req = tevent_req_callback_data(
1676 subreq, struct tevent_req);
1677 struct winexe_ctrl_state *state = tevent_req_data(
1678 req, struct winexe_ctrl_state);
1679 NTSTATUS status;
1681 status = cli_close_recv(subreq);
1682 TALLOC_FREE(subreq);
1683 if (tevent_req_nterror(req, status)) {
1684 return;
1687 state->ctrl_pipe_done = true;
1688 if (state->pipes_req == NULL) {
1689 tevent_req_done(req);
1693 static void winexe_ctrl_pipes_done(struct tevent_req *subreq)
1695 struct tevent_req *req = tevent_req_callback_data(
1696 subreq, struct tevent_req);
1697 struct winexe_ctrl_state *state = tevent_req_data(
1698 req, struct winexe_ctrl_state);
1699 NTSTATUS status;
1701 status = winexe_pipes_recv(subreq);
1702 TALLOC_FREE(subreq);
1703 if (tevent_req_nterror(req, status)) {
1704 return;
1707 state->pipes_req = NULL;
1708 if (state->ctrl_pipe_done) {
1709 tevent_req_done(req);
1713 static NTSTATUS winexe_ctrl_recv(struct tevent_req *req,
1714 int *preturn_code)
1716 struct winexe_ctrl_state *state = tevent_req_data(
1717 req, struct winexe_ctrl_state);
1718 NTSTATUS status;
1720 if (tevent_req_is_nterror(req, &status)) {
1721 return status;
1723 if (preturn_code != NULL) {
1724 *preturn_code = state->return_code;
1726 return NT_STATUS_OK;
1729 static NTSTATUS winexe_ctrl(struct cli_state *cli,
1730 const char *cmd,
1731 int *preturn_code)
1733 struct tevent_context *ev = NULL;
1734 struct tevent_req *req = NULL;
1735 NTSTATUS status = NT_STATUS_NO_MEMORY;
1736 bool ok;
1738 ev = samba_tevent_context_init(cli);
1739 if (ev == NULL) {
1740 goto done;
1742 req = winexe_ctrl_send(ev, ev, cli, cmd);
1743 if (req == NULL) {
1744 goto done;
1746 ok = tevent_req_poll_ntstatus(req, ev, &status);
1747 if (!ok) {
1748 goto done;
1750 status = winexe_ctrl_recv(req, preturn_code);
1751 done:
1752 TALLOC_FREE(req);
1753 TALLOC_FREE(ev);
1754 return status;
1757 #ifdef HAVE_WINEXE_CC_WIN32
1758 const DATA_BLOB *winexesvc32_exe_binary(void);
1759 #endif
1761 #ifdef HAVE_WINEXE_CC_WIN64
1762 const DATA_BLOB *winexesvc64_exe_binary(void);
1763 #endif
1765 int main(int argc, const char *argv[])
1767 TALLOC_CTX *frame = talloc_stackframe();
1768 struct program_options options = {0};
1769 struct loadparm_context *lp_ctx;
1770 struct cli_state *cli;
1771 const char *service_name = SERVICE_NAME;
1772 char *service_filename = NULL;
1773 #ifdef HAVE_WINEXE_CC_WIN32
1774 const DATA_BLOB *winexesvc32_exe = winexesvc32_exe_binary();
1775 #else
1776 const DATA_BLOB *winexesvc32_exe = NULL;
1777 #endif
1778 #ifdef HAVE_WINEXE_CC_WIN64
1779 const DATA_BLOB *winexesvc64_exe = winexesvc64_exe_binary();
1780 #else
1781 const DATA_BLOB *winexesvc64_exe = NULL;
1782 #endif
1783 NTSTATUS status;
1784 int ret = 1;
1785 int return_code = 0;
1787 lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
1788 if (lp_ctx == NULL) {
1789 fprintf(stderr, "loadparm_init_s3 failed\n");
1790 goto done;
1793 smb_init_locale();
1794 setup_logging("winexe", DEBUG_STDOUT);
1796 lp_load_global(get_dyn_CONFIGFILE());
1798 parse_args(argc, argv, frame, &options, lp_ctx);
1800 if (options.cmd == NULL) {
1801 fprintf(stderr, "no cmd given\n");
1802 goto done;
1805 service_filename = talloc_asprintf(frame, "%s.exe", service_name);
1806 if (service_filename == NULL) {
1807 DBG_WARNING("talloc_asprintf failed\n");
1808 goto done;
1811 status = cli_full_connection_creds(
1812 &cli,
1813 NULL,
1814 options.hostname,
1815 NULL,
1816 445,
1817 "IPC$",
1818 "?????",
1819 options.credentials,
1823 if (!NT_STATUS_IS_OK(status)) {
1824 DBG_WARNING("cli_full_connection_creds failed: %s\n",
1825 nt_errstr(status));
1826 goto done;
1829 status = winexe_svc_install(
1830 cli,
1831 options.hostname,
1832 service_name,
1833 service_filename,
1834 winexesvc32_exe,
1835 winexesvc64_exe,
1836 options.credentials,
1837 options.flags);
1838 if (!NT_STATUS_IS_OK(status)) {
1839 DBG_WARNING("winexe_svc_install failed: %s\n",
1840 nt_errstr(status));
1841 goto done;
1844 status = winexe_ctrl(cli, options.cmd, &return_code);
1845 if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1846 /* Normal finish */
1847 status = NT_STATUS_OK;
1849 if (!NT_STATUS_IS_OK(status)) {
1850 DBG_WARNING("cli_ctrl failed: %s\n",
1851 nt_errstr(status));
1852 goto done;
1855 if (options.flags & SVC_UNINSTALL) {
1856 status = winexe_svc_uninstall(
1857 cli,
1858 service_name);
1859 if (!NT_STATUS_IS_OK(status)) {
1860 DBG_WARNING("winexe_svc_uninstall failed: %s\n",
1861 nt_errstr(status));
1862 goto done;
1866 ret = return_code;
1867 done:
1868 TALLOC_FREE(frame);
1869 return ret;