2 * Samba Unix/Linux CIFS implementation
6 * Copyright (C) 2018 Volker Lendecke <vl@samba.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "lib/param/param.h"
27 #include "auth/credentials/credentials.h"
28 #include "lib/util/talloc_stack.h"
29 #include "lib/util/tevent_ntstatus.h"
30 #include "lib/util/sys_rw.h"
31 #include "libsmb/proto.h"
32 #include "librpc/gen_ndr/ndr_svcctl_c.h"
33 #include "rpc_client/cli_pipe.h"
34 #include "libcli/smb/smbXcli_base.h"
35 #include "libcli/util/werror.h"
36 #include "lib/async_req/async_sock.h"
39 #define SVC_INTERACTIVE 1
40 #define SVC_IGNORE_INTERACTIVE 2
41 #define SVC_INTERACTIVE_MASK 3
42 #define SVC_FORCE_UPLOAD 4
44 #define SVC_OSCHOOSE 16
45 #define SVC_UNINSTALL 32
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 "
59 struct program_options
{
62 struct cli_credentials
*credentials
;
68 static void parse_args(int argc
, const char *argv
[],
70 struct program_options
*options
,
71 struct loadparm_context
*lp_ctx
)
75 struct cli_credentials
*cred
;
80 int flag_interactive
= SVC_IGNORE_INTERACTIVE
;
82 int flag_reinstall
= 0;
83 int flag_uninstall
= 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"},
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
);
142 poptPrintHelp(pc
, stdout
, 0);
149 argv_new
= discard_const_p(char *, poptGetArgs(pc
));
152 for (i
= 0; i
< argc
; i
++) {
153 if (!argv_new
|| argv_new
[i
] == NULL
) {
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);
166 if (opt_debuglevel
) {
167 lp_set_cmdline("log level", opt_debuglevel
);
170 cred
= cli_credentials_init(mem_ctx
);
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
,
179 cli_credentials_guess(cred
, lp_ctx
);
180 if (!cli_credentials_get_password(cred
) && !flag_nopass
) {
181 char *p
= getpass("Enter password: ");
183 cli_credentials_set_password(cred
, p
, CRED_SPECIFIED
);
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
;
199 runas_cred
= cli_credentials_init(mem_ctx
);
200 cli_credentials_parse_file(runas_cred
, options
->runas_file
,
203 user
= cli_credentials_get_username(runas_cred
);
204 pass
= cli_credentials_get_password(runas_cred
);
210 dom
= cli_credentials_get_domain(runas_cred
);
212 snprintf(buffer
, sizeof(buffer
), "%s\\%s%%%s",
215 snprintf(buffer
, sizeof(buffer
), "%s%%%s",
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
,
251 struct cli_state
*cli
;
254 const DATA_BLOB
*binary
= NULL
;
256 status
= cli_full_connection_creds(
267 if (!NT_STATUS_IS_OK(status
)) {
268 DBG_WARNING("cli_full_connection_creds failed: %s\n",
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",
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
) {
294 if (binary
== NULL
) {
298 status
= cli_ntcreate(
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 */
309 NULL
); /* CreateReturns */
310 if (!NT_STATUS_IS_OK(status
)) {
311 DBG_WARNING("Could not create %s: %s\n", service_filename
,
316 status
= cli_writeall(
324 if (!NT_STATUS_IS_OK(status
)) {
325 DBG_WARNING("Could not write file: %s\n", nt_errstr(status
));
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
));
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
,
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;
360 status
= cli_rpc_pipe_open_noauth_transport(
365 if (!NT_STATUS_IS_OK(status
)) {
366 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
371 status
= dcerpc_svcctl_OpenSCManagerW(
372 rpccli
->binding_handle
,
374 smbXcli_conn_remote_name(cli
->conn
),
376 SEC_FLAG_MAXIMUM_ALLOWED
,
379 if (!NT_STATUS_IS_OK(status
)) {
380 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
384 if (!W_ERROR_IS_OK(werr
)) {
385 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
390 status
= dcerpc_svcctl_OpenServiceW(
391 rpccli
->binding_handle
,
398 if (!NT_STATUS_IS_OK(status
)) {
399 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
401 goto close_scmanager
;
404 if (W_ERROR_EQUAL(werr
, WERR_SERVICE_DOES_NOT_EXIST
)) {
405 status
= dcerpc_svcctl_CreateServiceW(
406 rpccli
->binding_handle
,
412 SERVICE_TYPE_WIN32_OWN_PROCESS
|
413 ((flags
& SVC_INTERACTIVE
) ?
414 SERVICE_TYPE_INTERACTIVE_PROCESS
: 0),
416 SVCCTL_SVC_ERROR_NORMAL
,
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
,
447 if (!NT_STATUS_IS_OK(status
)) {
448 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
449 "failed: %s\n", nt_errstr(status
));
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
);
459 if (!(flags
& SVC_IGNORE_INTERACTIVE
)) {
461 !(service_status
.type
&
462 SERVICE_TYPE_INTERACTIVE_PROCESS
) ^
463 !(flags
& SVC_INTERACTIVE
);
466 if (service_status
.state
== SVCCTL_STOPPED
) {
468 } else if (need_conf
) {
469 status
= dcerpc_svcctl_ControlService(
470 rpccli
->binding_handle
,
477 if (!NT_STATUS_IS_OK(status
)) {
478 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
479 "failed: %s\n", nt_errstr(status
));
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
);
492 status
= dcerpc_svcctl_QueryServiceStatus(
493 rpccli
->binding_handle
,
499 if (!NT_STATUS_IS_OK(status
)) {
500 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
501 "failed: %s\n", nt_errstr(status
));
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
);
510 } while (service_status
.state
== SVCCTL_STOP_PENDING
);
516 status
= dcerpc_svcctl_ChangeServiceConfigW(
517 rpccli
->binding_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 */
528 NULL
, /* dependencies */
529 NULL
, /* service_start_name */
531 NULL
, /* display_name */
534 if (!NT_STATUS_IS_OK(status
)) {
535 DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
536 "failed: %s\n", nt_errstr(status
));
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
);
548 status
= winexe_svc_upload(
555 if (!NT_STATUS_IS_OK(status
)) {
556 DBG_WARNING("winexe_svc_upload failed: %s\n",
561 status
= dcerpc_svcctl_StartServiceW(
562 rpccli
->binding_handle
,
566 NULL
, /* arguments */
569 if (!NT_STATUS_IS_OK(status
)) {
570 DBG_WARNING("dcerpc_svcctl_StartServiceW "
571 "failed: %s\n", nt_errstr(status
));
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
);
584 status
= dcerpc_svcctl_QueryServiceStatus(
585 rpccli
->binding_handle
,
591 if (!NT_STATUS_IS_OK(status
)) {
592 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
593 "failed: %s\n", nt_errstr(status
));
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
);
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
;
613 NTSTATUS close_status
;
616 close_status
= dcerpc_svcctl_CloseServiceHandle(
617 rpccli
->binding_handle
,
621 if (!NT_STATUS_IS_OK(close_status
)) {
622 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
623 "failed: %s\n", nt_errstr(close_status
));
626 if (!W_ERROR_IS_OK(close_werr
)) {
627 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
628 " failed: %s\n", win_errstr(close_werr
));
635 NTSTATUS close_status
;
638 close_status
= dcerpc_svcctl_CloseServiceHandle(
639 rpccli
->binding_handle
,
643 if (!NT_STATUS_IS_OK(close_status
)) {
644 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
645 "failed: %s\n", nt_errstr(close_status
));
648 if (!W_ERROR_IS_OK(close_werr
)) {
649 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
650 " failed: %s\n", win_errstr(close_werr
));
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
;
673 status
= cli_rpc_pipe_open_noauth_transport(
678 if (!NT_STATUS_IS_OK(status
)) {
679 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
684 status
= dcerpc_svcctl_OpenSCManagerW(
685 rpccli
->binding_handle
,
687 smbXcli_conn_remote_name(cli
->conn
),
689 SEC_FLAG_MAXIMUM_ALLOWED
,
692 if (!NT_STATUS_IS_OK(status
)) {
693 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
697 if (!W_ERROR_IS_OK(werr
)) {
698 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
703 status
= dcerpc_svcctl_OpenServiceW(
704 rpccli
->binding_handle
,
711 if (!NT_STATUS_IS_OK(status
)) {
712 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
714 goto close_scmanager
;
716 if (!W_ERROR_IS_OK(werr
)) {
717 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
719 status
= werror_to_ntstatus(werr
);
720 goto close_scmanager
;
723 status
= dcerpc_svcctl_ControlService(
724 rpccli
->binding_handle
,
730 if (!NT_STATUS_IS_OK(status
)) {
731 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
732 "failed: %s\n", nt_errstr(status
));
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
);
745 status
= dcerpc_svcctl_QueryServiceStatus(
746 rpccli
->binding_handle
,
752 if (!NT_STATUS_IS_OK(status
)) {
753 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
754 "failed: %s\n", nt_errstr(status
));
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
);
763 } while (service_status
.state
!= SVCCTL_STOPPED
);
765 status
= dcerpc_svcctl_DeleteService(
766 rpccli
->binding_handle
,
770 if (!NT_STATUS_IS_OK(status
)) {
771 DBG_WARNING("dcerpc_svcctl_DeleteService "
772 "failed: %s\n", nt_errstr(status
));
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
);
784 NTSTATUS close_status
;
787 close_status
= dcerpc_svcctl_CloseServiceHandle(
788 rpccli
->binding_handle
,
792 if (!NT_STATUS_IS_OK(close_status
)) {
793 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
794 "failed: %s\n", nt_errstr(close_status
));
797 if (!W_ERROR_IS_OK(close_werr
)) {
798 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
799 " failed: %s\n", win_errstr(close_werr
));
806 NTSTATUS close_status
;
809 close_status
= dcerpc_svcctl_CloseServiceHandle(
810 rpccli
->binding_handle
,
814 if (!NT_STATUS_IS_OK(close_status
)) {
815 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
816 "failed: %s\n", nt_errstr(close_status
));
819 if (!W_ERROR_IS_OK(close_werr
)) {
820 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
821 " failed: %s\n", win_errstr(close_werr
));
832 struct winexe_out_pipe_state
{
833 struct tevent_context
*ev
;
834 struct cli_state
*cli
;
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(
846 struct tevent_context
*ev
,
847 struct cli_state
*cli
,
848 const char *pipe_name
,
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
);
861 state
->out_fd
= out_fd
;
863 subreq
= cli_ntcreate_send(
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
);
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
);
892 status
= cli_ntcreate_recv(subreq
, &state
->out_pipe
, NULL
);
894 if (tevent_req_nterror(req
, status
)) {
898 timeout
= state
->cli
->timeout
;
899 state
->cli
->timeout
= 0;
901 subreq
= cli_read_send(
908 sizeof(state
->out_inbuf
));
910 state
->cli
->timeout
= timeout
;
912 if (tevent_req_nomem(subreq
, req
)) {
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
);
929 status
= cli_read_recv(subreq
, &received
);
932 DBG_DEBUG("cli_read for %d gave %s\n",
936 if (NT_STATUS_EQUAL(status
, NT_STATUS_PIPE_DISCONNECTED
)) {
937 subreq
= cli_close_send(
942 if (tevent_req_nomem(subreq
, req
)) {
945 tevent_req_set_callback(subreq
, winexe_out_pipe_closed
, req
);
949 if (tevent_req_nterror(req
, status
)) {
954 written
= sys_write(state
->out_fd
, state
->out_inbuf
, received
);
956 tevent_req_nterror(req
, map_nt_error_from_unix(errno
));
961 timeout
= state
->cli
->timeout
;
962 state
->cli
->timeout
= 0;
964 subreq
= cli_read_send(
971 sizeof(state
->out_inbuf
));
973 state
->cli
->timeout
= timeout
;
975 if (tevent_req_nomem(subreq
, req
)) {
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
);
987 status
= cli_close_recv(subreq
);
989 if (tevent_req_nterror(req
, status
)) {
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
;
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
,
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
);
1033 state
->in_fd
= in_fd
;
1035 subreq
= cli_ntcreate_send(
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
);
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
);
1063 status
= cli_ntcreate_recv(subreq
, &state
->in_pipe
, NULL
);
1064 TALLOC_FREE(subreq
);
1065 if (tevent_req_nterror(req
, status
)) {
1069 subreq
= wait_for_read_send(
1074 if (tevent_req_nomem(subreq
, req
)) {
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
);
1093 ok
= wait_for_read_recv(subreq
, &err
);
1094 TALLOC_FREE(subreq
);
1096 tevent_req_nterror(req
, map_nt_error_from_unix(err
));
1099 state
->fd_read_req
= NULL
;
1101 nread
= sys_read(state
->in_fd
, &state
->inbuf
, sizeof(state
->inbuf
));
1103 tevent_req_nterror(req
, map_nt_error_from_unix(errno
));
1107 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
1111 timeout
= state
->cli
->timeout
;
1112 state
->cli
->timeout
= 0;
1114 subreq
= cli_writeall_send(
1120 (uint8_t *)state
->inbuf
,
1124 state
->cli
->timeout
= timeout
;
1126 if (tevent_req_nomem(subreq
, req
)) {
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
);
1140 status
= cli_writeall_recv(subreq
, NULL
);
1141 TALLOC_FREE(subreq
);
1143 DBG_DEBUG("cli_writeall for %d gave %s\n",
1147 if (NT_STATUS_EQUAL(status
, NT_STATUS_PIPE_DISCONNECTED
) ||
1148 state
->close_requested
) {
1149 subreq
= cli_close_send(
1154 if (tevent_req_nomem(subreq
, req
)) {
1157 tevent_req_set_callback(subreq
, winexe_in_pipe_closed
, req
);
1158 state
->closing
= true;
1162 if (tevent_req_nterror(req
, status
)) {
1166 subreq
= wait_for_read_send(
1171 if (tevent_req_nomem(subreq
, req
)) {
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
);
1185 status
= cli_close_recv(subreq
);
1186 TALLOC_FREE(subreq
);
1187 if (tevent_req_nterror(req
, status
)) {
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
) {
1208 if (state
->fd_read_req
== NULL
) {
1210 * cli_writeall active, wait for it to return
1212 state
->close_requested
= true;
1216 TALLOC_FREE(state
->fd_read_req
);
1218 subreq
= cli_close_send(
1223 if (subreq
== NULL
) {
1226 tevent_req_set_callback(subreq
, winexe_in_pipe_closed
, req
);
1227 state
->closing
= 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
;
1250 req
= tevent_req_create(mem_ctx
, &state
, struct winexe_pipes_state
);
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(
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(
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
,
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(
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
,
1302 DBG_DEBUG("pipes = %p %p %p\n",
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
);
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
)) {
1327 state
->pipes
[0] = NULL
;
1329 DBG_DEBUG("pipes = %p %p %p\n",
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
);
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
)) {
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",
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
);
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
)) {
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",
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
;
1415 bool ctrl_pipe_done
;
1417 char ctrl_inbuf
[256];
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
,
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
);
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(
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
);
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
);
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
)) {
1489 timeout
= state
->cli
->timeout
;
1490 state
->cli
->timeout
= 0;
1492 subreq
= cli_read_send(
1499 sizeof(state
->ctrl_inbuf
)-1);
1501 state
->cli
->timeout
= timeout
;
1503 if (tevent_req_nomem(subreq
, req
)) {
1506 tevent_req_set_callback(subreq
, winexe_ctrl_got_read
, req
);
1508 subreq
= cli_writeall_send(
1514 (const uint8_t *)cmd
,
1517 if (tevent_req_nomem(subreq
, req
)) {
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
);
1532 unsigned int version
, return_code
;
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(
1544 if (tevent_req_nomem(subreq
, req
)) {
1547 tevent_req_set_callback(subreq
, winexe_ctrl_pipe_closed
, req
);
1550 if (tevent_req_nterror(req
, status
)) {
1554 DBG_DEBUG("Got %zu bytes\n", received
);
1556 timeout
= state
->cli
->timeout
;
1557 state
->cli
->timeout
= 0;
1559 subreq
= cli_read_send(
1566 sizeof(state
->ctrl_inbuf
)-1);
1568 state
->cli
->timeout
= timeout
;
1570 if (tevent_req_nomem(subreq
, req
)) {
1573 tevent_req_set_callback(subreq
, winexe_ctrl_got_read
, req
);
1575 ret
= sscanf(state
->ctrl_inbuf
, "version 0x%x\n", &version
);
1577 DBG_DEBUG("Got version %x\n", version
);
1579 subreq
= cli_writeall_send(
1585 (const uint8_t *)state
->cmd
,
1587 strlen(state
->cmd
));
1588 if (tevent_req_nomem(subreq
, req
)) {
1591 tevent_req_set_callback(subreq
, winexe_ctrl_wrote_cmd
, req
);
1595 ret
= strncmp(state
->ctrl_inbuf
, "std_io_err ", strlen("std_io_err "));
1597 char *p
= state
->ctrl_inbuf
+ 11;
1598 char *q
= strchr(state
->ctrl_inbuf
, '\n');
1603 DBG_DEBUG("Got invalid pipe postfix\n");
1607 postfix_len
= q
- p
;
1609 postfix
= talloc_strndup(state
, p
, postfix_len
);
1610 if (tevent_req_nomem(postfix
, req
)) {
1614 DBG_DEBUG("Got pipe postfix %s\n", postfix
);
1616 subreq
= winexe_pipes_send(
1621 if (tevent_req_nomem(subreq
, req
)) {
1624 tevent_req_set_callback(subreq
, winexe_ctrl_pipes_done
, req
);
1626 state
->pipes_req
= subreq
;
1631 ret
= strncmp(state
->ctrl_inbuf
, "error ", strlen("error "));
1633 printf("Error: %s", state
->ctrl_inbuf
);
1637 ret
= sscanf(state
->ctrl_inbuf
, "version 0x%x\n", &return_code
);
1639 state
->return_code
= return_code
;
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
);
1650 status
= cli_writeall_recv(subreq
, NULL
);
1651 TALLOC_FREE(subreq
);
1652 if (tevent_req_nterror(req
, status
)) {
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
);
1663 status
= cli_writeall_recv(subreq
, NULL
);
1664 TALLOC_FREE(subreq
);
1665 if (tevent_req_nterror(req
, status
)) {
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
);
1678 status
= cli_close_recv(subreq
);
1679 TALLOC_FREE(subreq
);
1680 if (tevent_req_nterror(req
, status
)) {
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
);
1698 status
= winexe_pipes_recv(subreq
);
1699 TALLOC_FREE(subreq
);
1700 if (tevent_req_nterror(req
, status
)) {
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
,
1713 struct winexe_ctrl_state
*state
= tevent_req_data(
1714 req
, struct winexe_ctrl_state
);
1717 if (tevent_req_is_nterror(req
, &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
,
1730 struct tevent_context
*ev
= NULL
;
1731 struct tevent_req
*req
= NULL
;
1732 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1735 ev
= samba_tevent_context_init(cli
);
1739 req
= winexe_ctrl_send(ev
, ev
, cli
, cmd
);
1743 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
1747 status
= winexe_ctrl_recv(req
, preturn_code
);
1754 #ifdef HAVE_WINEXE_CC_WIN32
1755 const DATA_BLOB
*winexesvc32_exe_binary(void);
1758 #ifdef HAVE_WINEXE_CC_WIN64
1759 const DATA_BLOB
*winexesvc64_exe_binary(void);
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();
1773 const DATA_BLOB
*winexesvc32_exe
= NULL
;
1775 #ifdef HAVE_WINEXE_CC_WIN64
1776 const DATA_BLOB
*winexesvc64_exe
= winexesvc64_exe_binary();
1778 const DATA_BLOB
*winexesvc64_exe
= NULL
;
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");
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");
1802 service_filename
= talloc_asprintf(frame
, "%s.exe", service_name
);
1803 if (service_filename
== NULL
) {
1804 DBG_WARNING("talloc_asprintf failed\n");
1808 status
= cli_full_connection_creds(
1816 options
.credentials
,
1820 if (!NT_STATUS_IS_OK(status
)) {
1821 DBG_WARNING("cli_full_connection_creds failed: %s\n",
1826 status
= winexe_svc_install(
1833 options
.credentials
,
1835 if (!NT_STATUS_IS_OK(status
)) {
1836 DBG_WARNING("winexe_svc_install failed: %s\n",
1841 status
= winexe_ctrl(cli
, options
.cmd
, &return_code
);
1842 if (NT_STATUS_EQUAL(status
, NT_STATUS_PIPE_DISCONNECTED
)) {
1844 status
= NT_STATUS_OK
;
1846 if (!NT_STATUS_IS_OK(status
)) {
1847 DBG_WARNING("cli_ctrl failed: %s\n",
1852 if (options
.flags
& SVC_UNINSTALL
) {
1853 status
= winexe_svc_uninstall(
1856 if (!NT_STATUS_IS_OK(status
)) {
1857 DBG_WARNING("winexe_svc_uninstall failed: %s\n",