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"
37 #include "lib/cmdline/cmdline.h"
40 #define SVC_INTERACTIVE 1
41 #define SVC_IGNORE_INTERACTIVE 2
42 #define SVC_INTERACTIVE_MASK 3
43 #define SVC_FORCE_UPLOAD 4
45 #define SVC_OSCHOOSE 16
46 #define SVC_UNINSTALL 32
49 #define SERVICE_NAME "winexesvc"
51 #define PIPE_NAME "ahexec"
52 #define PIPE_NAME_IN "ahexec_stdin%08X"
53 #define PIPE_NAME_OUT "ahexec_stdout%08X"
54 #define PIPE_NAME_ERR "ahexec_stderr%08X"
56 static const char version_message_fmt
[] = "winexe version %d.%d\n"
57 "This program may be freely redistributed under the terms of the "
60 struct program_options
{
64 struct cli_credentials
*credentials
;
70 static void parse_args(int argc
, const char *argv
[],
72 struct program_options
*options
)
81 char *port_str
= NULL
;
83 int flag_interactive
= SVC_IGNORE_INTERACTIVE
;
85 int flag_reinstall
= 0;
86 int flag_uninstall
= 0;
91 struct poptOption long_options
[] = {
94 .longName
= "uninstall",
96 .argInfo
= POPT_ARG_NONE
,
97 .arg
= &flag_uninstall
,
99 .descrip
= "Uninstall winexe service after "
103 .longName
= "reinstall",
105 .argInfo
= POPT_ARG_NONE
,
106 .arg
= &flag_reinstall
,
108 .descrip
= "Reinstall winexe service before "
114 .argInfo
= POPT_ARG_STRING
,
115 .arg
= &options
->runas
,
117 .descrip
= "Run as the given user (BEWARE: this "
118 "password is sent in cleartext over "
120 .argDescrip
= "[DOMAIN\\]USERNAME%PASSWORD",
122 .longName
= "runas-file",
124 .argInfo
= POPT_ARG_STRING
,
125 .arg
= &options
->runas_file
,
127 .descrip
= "Run as user options defined in a file",
128 .argDescrip
= "FILE",
130 .longName
= "interactive",
132 .argInfo
= POPT_ARG_INT
,
133 .arg
= &flag_interactive
,
135 .descrip
= "Desktop interaction: 0 - disallow, "
136 "1 - allow. If allow, also use the "
137 "--system switch (Windows requirement). "
138 "Vista does not support this option.",
141 .longName
= "ostype",
143 .argInfo
= POPT_ARG_INT
,
146 .descrip
= "OS type: 0 - 32-bit, 1 - 64-bit, "
147 "2 - winexe will decide. "
148 "Determines which version (32-bit or 64-bit)"
149 " of service will be installed.",
150 .argDescrip
= "0|1|2",
153 POPT_COMMON_CREDENTIALS
158 ZERO_STRUCTP(options
);
160 ok
= samba_cmdline_init(mem_ctx
,
161 SAMBA_CMDLINE_CONFIG_CLIENT
,
162 false /* require_smbconf */);
164 DBG_ERR("Failed to init cmdline parser!\n");
165 TALLOC_FREE(mem_ctx
);
169 pc
= samba_popt_get_context(getprogname(),
175 DBG_ERR("Failed to setup popt context!\n");
176 TALLOC_FREE(mem_ctx
);
180 poptSetOtherOptionHelp(pc
, "[OPTION]... //HOST[:PORT] COMMAND\nOptions:");
182 if (((opt
= poptGetNextOpt(pc
)) != -1) || flag_help
|| flag_version
) {
183 fprintf(stderr
, version_message_fmt
, SAMBA_VERSION_MAJOR
,
184 SAMBA_VERSION_MINOR
);
188 poptPrintHelp(pc
, stdout
, 0);
195 argv_new
= discard_const_p(char *, poptGetArgs(pc
));
198 for (i
= 0; i
< argc
; i
++) {
199 if (!argv_new
|| argv_new
[i
] == NULL
) {
205 if (argc_new
!= 2 || argv_new
[0][0] != '/' || argv_new
[0][1] != '/') {
206 fprintf(stderr
, version_message_fmt
, SAMBA_VERSION_MAJOR
,
207 SAMBA_VERSION_MINOR
);
208 poptPrintHelp(pc
, stdout
, 0);
212 port_str
= strchr(argv_new
[0], ':');
214 if (sscanf(port_str
+ 1, "%d", &port
) != 1 || port
<= 0) {
215 fprintf(stderr
, version_message_fmt
,
216 SAMBA_VERSION_MAJOR
, SAMBA_VERSION_MINOR
);
217 poptPrintHelp(pc
, stdout
, 0);
223 if (options
->runas
== NULL
&& options
->runas_file
!= NULL
) {
224 struct cli_credentials
*runas_cred
;
228 runas_cred
= cli_credentials_init(mem_ctx
);
229 cli_credentials_parse_file(runas_cred
, options
->runas_file
,
232 user
= cli_credentials_get_username(runas_cred
);
233 pass
= cli_credentials_get_password(runas_cred
);
239 dom
= cli_credentials_get_domain(runas_cred
);
241 snprintf(buffer
, sizeof(buffer
), "%s\\%s%%%s",
244 snprintf(buffer
, sizeof(buffer
), "%s%%%s",
247 buffer
[sizeof(buffer
)-1] = '\0';
248 options
->runas
= talloc_strdup(mem_ctx
, buffer
);
252 options
->credentials
= samba_cmdline_get_creds();
254 options
->hostname
= talloc_strdup(mem_ctx
, argv_new
[0] + 2);
255 if (options
->hostname
== NULL
) {
256 DBG_ERR("Out of memory\n");
259 options
->port
= port
;
260 options
->cmd
= talloc_strdup(mem_ctx
, argv_new
[1]);
261 if (options
->cmd
== NULL
) {
262 DBG_ERR("Out of memory\n");
268 options
->flags
= flag_interactive
;
269 if (flag_reinstall
) {
270 options
->flags
|= SVC_FORCE_UPLOAD
;
272 if (flag_ostype
== 1) {
273 options
->flags
|= SVC_OS64BIT
;
275 if (flag_ostype
== 2) {
276 options
->flags
|= SVC_OSCHOOSE
;
278 if (flag_uninstall
) {
279 options
->flags
|= SVC_UNINSTALL
;
283 static NTSTATUS
winexe_svc_upload(
284 const char *hostname
,
286 const char *service_filename
,
287 const DATA_BLOB
*svc32_exe
,
288 const DATA_BLOB
*svc64_exe
,
289 struct cli_credentials
*credentials
,
292 struct cli_state
*cli
;
293 uint16_t fnum
= 0xffff;
295 const DATA_BLOB
*binary
= NULL
;
297 status
= cli_full_connection_creds(
307 if (!NT_STATUS_IS_OK(status
)) {
308 DBG_WARNING("cli_full_connection_creds failed: %s\n",
313 if (flags
& SVC_FORCE_UPLOAD
) {
314 status
= cli_unlink(cli
, service_filename
, 0);
315 if (!NT_STATUS_IS_OK(status
)) {
316 DBG_WARNING("cli_unlink failed: %s\n",
321 if (flags
& SVC_OSCHOOSE
) {
322 status
= cli_chkpath(cli
, "SysWoW64");
323 if (NT_STATUS_IS_OK(status
)) {
324 flags
|= SVC_OS64BIT
;
328 if (flags
& SVC_OS64BIT
) {
334 if (binary
== NULL
) {
338 status
= cli_ntcreate(
342 SEC_FILE_WRITE_DATA
, /* DesiredAccess */
343 FILE_ATTRIBUTE_NORMAL
, /* FileAttributes */
344 FILE_SHARE_WRITE
|FILE_SHARE_READ
, /* ShareAccess */
345 FILE_OPEN_IF
, /* CreateDisposition */
346 FILE_NON_DIRECTORY_FILE
, /* CreateOptions */
347 0, /* SecurityFlags */
349 NULL
); /* CreateReturns */
350 if (!NT_STATUS_IS_OK(status
)) {
351 DBG_WARNING("Could not create %s: %s\n", service_filename
,
356 status
= cli_writeall(
364 if (!NT_STATUS_IS_OK(status
)) {
365 DBG_WARNING("Could not write file: %s\n", nt_errstr(status
));
370 if (fnum
!= 0xffff) {
371 status
= cli_close(cli
, fnum
);
372 if (!NT_STATUS_IS_OK(status
)) {
373 DBG_WARNING("Close(%"PRIu16
") failed for %s: %s\n",
384 static NTSTATUS
winexe_svc_install(
385 struct cli_state
*cli
,
386 const char *hostname
,
388 const char *service_name
,
389 const char *service_filename
,
390 const DATA_BLOB
*svc32_exe
,
391 const DATA_BLOB
*svc64_exe
,
392 struct cli_credentials
*credentials
,
395 TALLOC_CTX
*frame
= talloc_stackframe();
396 struct rpc_pipe_client
*rpccli
;
397 struct policy_handle scmanager_handle
;
398 struct policy_handle service_handle
;
399 struct SERVICE_STATUS service_status
;
400 bool need_start
= false;
401 bool need_conf
= false;
404 const char *remote_name
= smbXcli_conn_remote_name(cli
->conn
);
405 const struct sockaddr_storage
*remote_sockaddr
=
406 smbXcli_conn_remote_sockaddr(cli
->conn
);
408 status
= cli_rpc_pipe_open_noauth_transport(
415 if (!NT_STATUS_IS_OK(status
)) {
416 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
421 status
= dcerpc_svcctl_OpenSCManagerW(
422 rpccli
->binding_handle
,
426 SEC_FLAG_MAXIMUM_ALLOWED
,
429 if (!NT_STATUS_IS_OK(status
)) {
430 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
434 if (!W_ERROR_IS_OK(werr
)) {
435 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
440 status
= dcerpc_svcctl_OpenServiceW(
441 rpccli
->binding_handle
,
448 if (!NT_STATUS_IS_OK(status
)) {
449 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
451 goto close_scmanager
;
454 if (W_ERROR_EQUAL(werr
, WERR_SERVICE_DOES_NOT_EXIST
)) {
455 status
= dcerpc_svcctl_CreateServiceW(
456 rpccli
->binding_handle
,
462 SERVICE_TYPE_WIN32_OWN_PROCESS
|
463 ((flags
& SVC_INTERACTIVE
) ?
464 SERVICE_TYPE_INTERACTIVE_PROCESS
: 0),
466 SVCCTL_SVC_ERROR_NORMAL
,
477 if (!NT_STATUS_IS_OK(status
)) {
478 DBG_WARNING("dcerpc_svcctl_CreateServiceW "
479 "failed: %s\n", nt_errstr(status
));
480 goto close_scmanager
;
482 if (!W_ERROR_IS_OK(werr
)) {
483 DBG_WARNING("dcerpc_svcctl_CreateServiceW "
484 "failed: %s\n", win_errstr(werr
));
485 status
= werror_to_ntstatus(werr
);
486 goto close_scmanager
;
490 status
= dcerpc_svcctl_QueryServiceStatus(
491 rpccli
->binding_handle
,
497 if (!NT_STATUS_IS_OK(status
)) {
498 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
499 "failed: %s\n", nt_errstr(status
));
502 if (!W_ERROR_IS_OK(werr
)) {
503 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
504 "failed: %s\n", win_errstr(werr
));
505 status
= werror_to_ntstatus(werr
);
509 if (!(flags
& SVC_IGNORE_INTERACTIVE
)) {
511 !(service_status
.type
&
512 SERVICE_TYPE_INTERACTIVE_PROCESS
) ^
513 !(flags
& SVC_INTERACTIVE
);
516 if (service_status
.state
== SVCCTL_STOPPED
) {
518 } else if (need_conf
) {
519 status
= dcerpc_svcctl_ControlService(
520 rpccli
->binding_handle
,
527 if (!NT_STATUS_IS_OK(status
)) {
528 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
529 "failed: %s\n", nt_errstr(status
));
532 if (!W_ERROR_IS_OK(werr
)) {
533 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
534 "failed: %s\n", win_errstr(werr
));
535 status
= werror_to_ntstatus(werr
);
542 status
= dcerpc_svcctl_QueryServiceStatus(
543 rpccli
->binding_handle
,
549 if (!NT_STATUS_IS_OK(status
)) {
550 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
551 "failed: %s\n", nt_errstr(status
));
554 if (!W_ERROR_IS_OK(werr
)) {
555 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
556 "failed: %s\n", win_errstr(werr
));
557 status
= werror_to_ntstatus(werr
);
560 } while (service_status
.state
== SVCCTL_STOP_PENDING
);
566 status
= dcerpc_svcctl_ChangeServiceConfigW(
567 rpccli
->binding_handle
,
570 SERVICE_TYPE_WIN32_OWN_PROCESS
|
571 ((flags
& SVC_INTERACTIVE
) ?
572 SERVICE_TYPE_INTERACTIVE_PROCESS
: 0), /* type */
573 UINT32_MAX
, /* start_type, SERVICE_NO_CHANGE */
574 UINT32_MAX
, /* error_control, SERVICE_NO_CHANGE */
575 NULL
, /* binary_path */
576 NULL
, /* load_order_group */
578 NULL
, /* dependencies */
579 0, /* dwDependSize */
580 NULL
, /* service_start_name */
583 NULL
, /* display_name */
586 if (!NT_STATUS_IS_OK(status
)) {
587 DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
588 "failed: %s\n", nt_errstr(status
));
591 if (!W_ERROR_IS_OK(werr
)) {
592 DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
593 "failed: %s\n", win_errstr(werr
));
594 status
= werror_to_ntstatus(werr
);
600 status
= winexe_svc_upload(
608 if (!NT_STATUS_IS_OK(status
)) {
609 DBG_WARNING("winexe_svc_upload failed: %s\n",
614 status
= dcerpc_svcctl_StartServiceW(
615 rpccli
->binding_handle
,
619 NULL
, /* arguments */
622 if (!NT_STATUS_IS_OK(status
)) {
623 DBG_WARNING("dcerpc_svcctl_StartServiceW "
624 "failed: %s\n", nt_errstr(status
));
627 if (!W_ERROR_IS_OK(werr
)) {
628 DBG_WARNING("dcerpc_svcctl_StartServiceW "
629 "failed: %s\n", win_errstr(werr
));
630 status
= werror_to_ntstatus(werr
);
637 status
= dcerpc_svcctl_QueryServiceStatus(
638 rpccli
->binding_handle
,
644 if (!NT_STATUS_IS_OK(status
)) {
645 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
646 "failed: %s\n", nt_errstr(status
));
649 if (!W_ERROR_IS_OK(werr
)) {
650 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
651 "failed: %s\n", win_errstr(werr
));
652 status
= werror_to_ntstatus(werr
);
655 } while (service_status
.state
== SVCCTL_START_PENDING
);
657 if (service_status
.state
!= SVCCTL_RUNNING
) {
658 DBG_WARNING("Failed to start service\n");
659 status
= NT_STATUS_UNSUCCESSFUL
;
666 NTSTATUS close_status
;
669 close_status
= dcerpc_svcctl_CloseServiceHandle(
670 rpccli
->binding_handle
,
674 if (!NT_STATUS_IS_OK(close_status
)) {
675 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
676 "failed: %s\n", nt_errstr(close_status
));
679 if (!W_ERROR_IS_OK(close_werr
)) {
680 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
681 " failed: %s\n", win_errstr(close_werr
));
688 NTSTATUS close_status
;
691 close_status
= dcerpc_svcctl_CloseServiceHandle(
692 rpccli
->binding_handle
,
696 if (!NT_STATUS_IS_OK(close_status
)) {
697 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
698 "failed: %s\n", nt_errstr(close_status
));
701 if (!W_ERROR_IS_OK(close_werr
)) {
702 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
703 " failed: %s\n", win_errstr(close_werr
));
714 static NTSTATUS
winexe_svc_uninstall(
715 struct cli_state
*cli
,
716 const char *service_name
)
718 TALLOC_CTX
*frame
= talloc_stackframe();
719 struct rpc_pipe_client
*rpccli
;
720 struct policy_handle scmanager_handle
;
721 struct policy_handle service_handle
;
722 struct SERVICE_STATUS service_status
;
725 const char *remote_name
= smbXcli_conn_remote_name(cli
->conn
);
726 const struct sockaddr_storage
*remote_sockaddr
=
727 smbXcli_conn_remote_sockaddr(cli
->conn
);
729 status
= cli_rpc_pipe_open_noauth_transport(
736 if (!NT_STATUS_IS_OK(status
)) {
737 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
742 status
= dcerpc_svcctl_OpenSCManagerW(
743 rpccli
->binding_handle
,
747 SEC_FLAG_MAXIMUM_ALLOWED
,
750 if (!NT_STATUS_IS_OK(status
)) {
751 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
755 if (!W_ERROR_IS_OK(werr
)) {
756 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
761 status
= dcerpc_svcctl_OpenServiceW(
762 rpccli
->binding_handle
,
769 if (!NT_STATUS_IS_OK(status
)) {
770 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
772 goto close_scmanager
;
774 if (!W_ERROR_IS_OK(werr
)) {
775 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
777 status
= werror_to_ntstatus(werr
);
778 goto close_scmanager
;
781 status
= dcerpc_svcctl_ControlService(
782 rpccli
->binding_handle
,
788 if (!NT_STATUS_IS_OK(status
)) {
789 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
790 "failed: %s\n", nt_errstr(status
));
793 if (!W_ERROR_IS_OK(werr
)) {
794 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
795 "failed: %s\n", win_errstr(werr
));
796 status
= werror_to_ntstatus(werr
);
803 status
= dcerpc_svcctl_QueryServiceStatus(
804 rpccli
->binding_handle
,
810 if (!NT_STATUS_IS_OK(status
)) {
811 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
812 "failed: %s\n", nt_errstr(status
));
815 if (!W_ERROR_IS_OK(werr
)) {
816 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
817 "failed: %s\n", win_errstr(werr
));
818 status
= werror_to_ntstatus(werr
);
821 } while (service_status
.state
!= SVCCTL_STOPPED
);
823 status
= dcerpc_svcctl_DeleteService(
824 rpccli
->binding_handle
,
828 if (!NT_STATUS_IS_OK(status
)) {
829 DBG_WARNING("dcerpc_svcctl_DeleteService "
830 "failed: %s\n", nt_errstr(status
));
833 if (!W_ERROR_IS_OK(werr
)) {
834 DBG_WARNING("dcerpc_svcctl_DeleteService "
835 "failed: %s\n", win_errstr(werr
));
836 status
= werror_to_ntstatus(werr
);
842 NTSTATUS close_status
;
845 close_status
= dcerpc_svcctl_CloseServiceHandle(
846 rpccli
->binding_handle
,
850 if (!NT_STATUS_IS_OK(close_status
)) {
851 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
852 "failed: %s\n", nt_errstr(close_status
));
855 if (!W_ERROR_IS_OK(close_werr
)) {
856 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
857 " failed: %s\n", win_errstr(close_werr
));
864 NTSTATUS close_status
;
867 close_status
= dcerpc_svcctl_CloseServiceHandle(
868 rpccli
->binding_handle
,
872 if (!NT_STATUS_IS_OK(close_status
)) {
873 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
874 "failed: %s\n", nt_errstr(close_status
));
877 if (!W_ERROR_IS_OK(close_werr
)) {
878 DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
879 " failed: %s\n", win_errstr(close_werr
));
890 struct winexe_out_pipe_state
{
891 struct tevent_context
*ev
;
892 struct cli_state
*cli
;
898 static void winexe_out_pipe_opened(struct tevent_req
*subreq
);
899 static void winexe_out_pipe_got_data(struct tevent_req
*subreq
);
900 static void winexe_out_pipe_closed(struct tevent_req
*subreq
);
902 static struct tevent_req
*winexe_out_pipe_send(
904 struct tevent_context
*ev
,
905 struct cli_state
*cli
,
906 const char *pipe_name
,
909 struct tevent_req
*req
, *subreq
;
910 struct winexe_out_pipe_state
*state
;
912 req
= tevent_req_create(mem_ctx
, &state
,
913 struct winexe_out_pipe_state
);
919 state
->out_fd
= out_fd
;
921 subreq
= cli_ntcreate_send(
927 SEC_RIGHTS_FILE_READ
|SEC_RIGHTS_FILE_WRITE
|
928 SEC_RIGHTS_FILE_EXECUTE
,
929 0, /* FileAttributes */
930 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
931 FILE_OPEN
, /* CreateDisposition */
932 0, /* CreateOptions */
933 SMB2_IMPERSONATION_IMPERSONATION
,
934 0); /* SecurityFlags */
935 if (tevent_req_nomem(subreq
, req
)) {
936 return tevent_req_post(req
, ev
);
938 tevent_req_set_callback(subreq
, winexe_out_pipe_opened
, req
);
942 static void winexe_out_pipe_opened(struct tevent_req
*subreq
)
944 struct tevent_req
*req
= tevent_req_callback_data(
945 subreq
, struct tevent_req
);
946 struct winexe_out_pipe_state
*state
= tevent_req_data(
947 req
, struct winexe_out_pipe_state
);
951 status
= cli_ntcreate_recv(subreq
, &state
->out_pipe
, NULL
);
953 if (tevent_req_nterror(req
, status
)) {
957 timeout
= state
->cli
->timeout
;
958 state
->cli
->timeout
= 0;
960 subreq
= cli_read_send(
967 sizeof(state
->out_inbuf
));
969 state
->cli
->timeout
= timeout
;
971 if (tevent_req_nomem(subreq
, req
)) {
974 tevent_req_set_callback(subreq
, winexe_out_pipe_got_data
, req
);
977 static void winexe_out_pipe_got_data(struct tevent_req
*subreq
)
979 struct tevent_req
*req
= tevent_req_callback_data(
980 subreq
, struct tevent_req
);
981 struct winexe_out_pipe_state
*state
= tevent_req_data(
982 req
, struct winexe_out_pipe_state
);
988 status
= cli_read_recv(subreq
, &received
);
991 DBG_DEBUG("cli_read for %d gave %s\n",
995 if (NT_STATUS_EQUAL(status
, NT_STATUS_PIPE_DISCONNECTED
)) {
996 subreq
= cli_close_send(state
,
1001 if (tevent_req_nomem(subreq
, req
)) {
1004 tevent_req_set_callback(subreq
, winexe_out_pipe_closed
, req
);
1008 if (tevent_req_nterror(req
, status
)) {
1013 written
= sys_write(state
->out_fd
, state
->out_inbuf
, received
);
1014 if (written
== -1) {
1015 tevent_req_nterror(req
, map_nt_error_from_unix(errno
));
1020 timeout
= state
->cli
->timeout
;
1021 state
->cli
->timeout
= 0;
1023 subreq
= cli_read_send(
1030 sizeof(state
->out_inbuf
));
1032 state
->cli
->timeout
= timeout
;
1034 if (tevent_req_nomem(subreq
, req
)) {
1037 tevent_req_set_callback(subreq
, winexe_out_pipe_got_data
, req
);
1040 static void winexe_out_pipe_closed(struct tevent_req
*subreq
)
1042 struct tevent_req
*req
= tevent_req_callback_data(
1043 subreq
, struct tevent_req
);
1046 status
= cli_close_recv(subreq
);
1047 TALLOC_FREE(subreq
);
1048 if (tevent_req_nterror(req
, status
)) {
1051 tevent_req_done(req
);
1054 static NTSTATUS
winexe_out_pipe_recv(struct tevent_req
*req
)
1056 return tevent_req_simple_recv_ntstatus(req
);
1059 struct winexe_in_pipe_state
{
1060 struct tevent_context
*ev
;
1061 struct cli_state
*cli
;
1062 struct tevent_req
*fd_read_req
;
1063 bool close_requested
;
1070 static void winexe_in_pipe_opened(struct tevent_req
*subreq
);
1071 static void winexe_in_pipe_got_data(struct tevent_req
*subreq
);
1072 static void winexe_in_pipe_written(struct tevent_req
*subreq
);
1073 static void winexe_in_pipe_closed(struct tevent_req
*subreq
);
1075 static struct tevent_req
*winexe_in_pipe_send(
1076 TALLOC_CTX
*mem_ctx
,
1077 struct tevent_context
*ev
,
1078 struct cli_state
*cli
,
1079 const char *pipe_name
,
1082 struct tevent_req
*req
, *subreq
;
1083 struct winexe_in_pipe_state
*state
;
1085 req
= tevent_req_create(mem_ctx
, &state
,
1086 struct winexe_in_pipe_state
);
1092 state
->in_fd
= in_fd
;
1094 subreq
= cli_ntcreate_send(
1100 SEC_RIGHTS_FILE_READ
|SEC_RIGHTS_FILE_WRITE
|
1101 SEC_RIGHTS_FILE_EXECUTE
,
1102 0, /* FileAttributes */
1103 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
1104 FILE_OPEN
, /* CreateDisposition */
1105 0, /* CreateOptions */
1106 SMB2_IMPERSONATION_IMPERSONATION
,
1107 0); /* SecurityFlags */
1108 if (tevent_req_nomem(subreq
, req
)) {
1109 return tevent_req_post(req
, ev
);
1111 tevent_req_set_callback(subreq
, winexe_in_pipe_opened
, req
);
1115 static void winexe_in_pipe_opened(struct tevent_req
*subreq
)
1117 struct tevent_req
*req
= tevent_req_callback_data(
1118 subreq
, struct tevent_req
);
1119 struct winexe_in_pipe_state
*state
= tevent_req_data(
1120 req
, struct winexe_in_pipe_state
);
1123 status
= cli_ntcreate_recv(subreq
, &state
->in_pipe
, NULL
);
1124 TALLOC_FREE(subreq
);
1125 if (tevent_req_nterror(req
, status
)) {
1129 subreq
= wait_for_read_send(
1134 if (tevent_req_nomem(subreq
, req
)) {
1137 tevent_req_set_callback(subreq
, winexe_in_pipe_got_data
, req
);
1139 state
->fd_read_req
= subreq
;
1142 static void winexe_in_pipe_got_data(struct tevent_req
*subreq
)
1144 struct tevent_req
*req
= tevent_req_callback_data(
1145 subreq
, struct tevent_req
);
1146 struct winexe_in_pipe_state
*state
= tevent_req_data(
1147 req
, struct winexe_in_pipe_state
);
1153 ok
= wait_for_read_recv(subreq
, &err
);
1154 TALLOC_FREE(subreq
);
1156 tevent_req_nterror(req
, map_nt_error_from_unix(err
));
1159 state
->fd_read_req
= NULL
;
1161 nread
= sys_read(state
->in_fd
, &state
->inbuf
, sizeof(state
->inbuf
));
1163 tevent_req_nterror(req
, map_nt_error_from_unix(errno
));
1167 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
1171 timeout
= state
->cli
->timeout
;
1172 state
->cli
->timeout
= 0;
1174 subreq
= cli_writeall_send(
1180 (uint8_t *)state
->inbuf
,
1184 state
->cli
->timeout
= timeout
;
1186 if (tevent_req_nomem(subreq
, req
)) {
1189 tevent_req_set_callback(subreq
, winexe_in_pipe_written
, req
);
1192 static void winexe_in_pipe_written(struct tevent_req
*subreq
)
1194 struct tevent_req
*req
= tevent_req_callback_data(
1195 subreq
, struct tevent_req
);
1196 struct winexe_in_pipe_state
*state
= tevent_req_data(
1197 req
, struct winexe_in_pipe_state
);
1200 status
= cli_writeall_recv(subreq
, NULL
);
1201 TALLOC_FREE(subreq
);
1203 DBG_DEBUG("cli_writeall for %d gave %s\n",
1207 if (NT_STATUS_EQUAL(status
, NT_STATUS_PIPE_DISCONNECTED
) ||
1208 state
->close_requested
) {
1209 subreq
= cli_close_send(state
,
1214 if (tevent_req_nomem(subreq
, req
)) {
1217 tevent_req_set_callback(subreq
, winexe_in_pipe_closed
, req
);
1218 state
->closing
= true;
1222 if (tevent_req_nterror(req
, status
)) {
1226 subreq
= wait_for_read_send(
1231 if (tevent_req_nomem(subreq
, req
)) {
1234 tevent_req_set_callback(subreq
, winexe_in_pipe_got_data
, req
);
1236 state
->fd_read_req
= subreq
;
1239 static void winexe_in_pipe_closed(struct tevent_req
*subreq
)
1241 struct tevent_req
*req
= tevent_req_callback_data(
1242 subreq
, struct tevent_req
);
1245 status
= cli_close_recv(subreq
);
1246 TALLOC_FREE(subreq
);
1247 if (tevent_req_nterror(req
, status
)) {
1250 return tevent_req_done(req
);
1253 static NTSTATUS
winexe_in_pipe_recv(struct tevent_req
*req
)
1255 return tevent_req_simple_recv_ntstatus(req
);
1258 static bool winexe_in_pipe_close(struct tevent_req
*req
)
1260 struct winexe_in_pipe_state
*state
= tevent_req_data(
1261 req
, struct winexe_in_pipe_state
);
1262 struct tevent_req
*subreq
;
1264 if (state
->closing
) {
1268 if (state
->fd_read_req
== NULL
) {
1270 * cli_writeall active, wait for it to return
1272 state
->close_requested
= true;
1276 TALLOC_FREE(state
->fd_read_req
);
1279 cli_close_send(state
, state
->ev
, state
->cli
, state
->in_pipe
, 0);
1280 if (subreq
== NULL
) {
1283 tevent_req_set_callback(subreq
, winexe_in_pipe_closed
, req
);
1284 state
->closing
= true;
1289 struct winexe_pipes_state
{
1290 struct tevent_req
*pipes
[3];
1293 static void winexe_pipes_stdin_done(struct tevent_req
*subreq
);
1294 static void winexe_pipes_stdout_done(struct tevent_req
*subreq
);
1295 static void winexe_pipes_stderr_done(struct tevent_req
*subreq
);
1297 static struct tevent_req
*winexe_pipes_send(
1298 TALLOC_CTX
*mem_ctx
,
1299 struct tevent_context
*ev
,
1300 struct cli_state
*cli
,
1301 const char *pipe_postfix
)
1303 struct tevent_req
*req
;
1304 struct winexe_pipes_state
*state
;
1307 req
= tevent_req_create(mem_ctx
, &state
, struct winexe_pipes_state
);
1312 pipe_name
= talloc_asprintf(state
, "\\ahexec_stdin%s", pipe_postfix
);
1313 if (tevent_req_nomem(pipe_name
, req
)) {
1314 return tevent_req_post(req
, ev
);
1316 state
->pipes
[0] = winexe_in_pipe_send(
1322 if (tevent_req_nomem(state
->pipes
[0], req
)) {
1323 return tevent_req_post(req
, ev
);
1325 tevent_req_set_callback(state
->pipes
[0], winexe_pipes_stdin_done
, req
);
1327 pipe_name
= talloc_asprintf(state
, "\\ahexec_stdout%s", pipe_postfix
);
1328 if (tevent_req_nomem(pipe_name
, req
)) {
1329 return tevent_req_post(req
, ev
);
1331 state
->pipes
[1] = winexe_out_pipe_send(
1337 if (tevent_req_nomem(state
->pipes
[1], req
)) {
1338 return tevent_req_post(req
, ev
);
1340 tevent_req_set_callback(state
->pipes
[1], winexe_pipes_stdout_done
,
1343 pipe_name
= talloc_asprintf(state
, "\\ahexec_stderr%s", pipe_postfix
);
1344 if (tevent_req_nomem(pipe_name
, req
)) {
1345 return tevent_req_post(req
, ev
);
1347 state
->pipes
[2] = winexe_out_pipe_send(
1353 if (tevent_req_nomem(state
->pipes
[2], req
)) {
1354 return tevent_req_post(req
, ev
);
1356 tevent_req_set_callback(state
->pipes
[2], winexe_pipes_stderr_done
,
1359 DBG_DEBUG("pipes = %p %p %p\n",
1367 static void winexe_pipes_stdin_done(struct tevent_req
*subreq
)
1369 struct tevent_req
*req
= tevent_req_callback_data(
1370 subreq
, struct tevent_req
);
1371 struct winexe_pipes_state
*state
= tevent_req_data(
1372 req
, struct winexe_pipes_state
);
1375 status
= winexe_in_pipe_recv(subreq
);
1376 TALLOC_FREE(subreq
);
1378 DBG_DEBUG("stdin returned %s\n", nt_errstr(status
));
1380 if (tevent_req_nterror(req
, status
)) {
1384 state
->pipes
[0] = NULL
;
1386 DBG_DEBUG("pipes = %p %p %p\n",
1391 if ((state
->pipes
[1] == NULL
) && (state
->pipes
[2] == NULL
)) {
1392 tevent_req_done(req
);
1396 static void winexe_pipes_stdout_done(struct tevent_req
*subreq
)
1398 struct tevent_req
*req
= tevent_req_callback_data(
1399 subreq
, struct tevent_req
);
1400 struct winexe_pipes_state
*state
= tevent_req_data(
1401 req
, struct winexe_pipes_state
);
1404 status
= winexe_out_pipe_recv(subreq
);
1405 TALLOC_FREE(subreq
);
1407 DBG_DEBUG("stdout returned %s\n", nt_errstr(status
));
1409 if (tevent_req_nterror(req
, status
)) {
1413 if (state
->pipes
[0] != NULL
) {
1414 winexe_in_pipe_close(state
->pipes
[0]);
1417 state
->pipes
[1] = NULL
;
1419 DBG_DEBUG("pipes = %p %p %p\n",
1424 if ((state
->pipes
[0] == NULL
) && (state
->pipes
[2] == NULL
)) {
1425 tevent_req_done(req
);
1429 static void winexe_pipes_stderr_done(struct tevent_req
*subreq
)
1431 struct tevent_req
*req
= tevent_req_callback_data(
1432 subreq
, struct tevent_req
);
1433 struct winexe_pipes_state
*state
= tevent_req_data(
1434 req
, struct winexe_pipes_state
);
1437 status
= winexe_out_pipe_recv(subreq
);
1438 TALLOC_FREE(subreq
);
1440 DBG_DEBUG("stderr returned %s\n", nt_errstr(status
));
1442 if (tevent_req_nterror(req
, status
)) {
1446 if (state
->pipes
[0] != NULL
) {
1447 winexe_in_pipe_close(state
->pipes
[0]);
1450 state
->pipes
[2] = NULL
;
1452 DBG_DEBUG("pipes = %p %p %p\n",
1457 if ((state
->pipes
[0] == NULL
) && (state
->pipes
[1] == NULL
)) {
1458 tevent_req_done(req
);
1462 static NTSTATUS
winexe_pipes_recv(struct tevent_req
*req
)
1464 return tevent_req_simple_recv_ntstatus(req
);
1467 struct winexe_ctrl_state
{
1468 struct tevent_context
*ev
;
1469 struct cli_state
*cli
;
1472 bool ctrl_pipe_done
;
1474 char ctrl_inbuf
[256];
1478 struct tevent_req
*pipes_req
;
1481 static void winexe_ctrl_opened(struct tevent_req
*subreq
);
1482 static void winexe_ctrl_got_read(struct tevent_req
*subreq
);
1483 static void winexe_ctrl_wrote_version(struct tevent_req
*subreq
);
1484 static void winexe_ctrl_wrote_cmd(struct tevent_req
*subreq
);
1485 static void winexe_ctrl_pipes_done(struct tevent_req
*subreq
);
1486 static void winexe_ctrl_pipe_closed(struct tevent_req
*subreq
);
1488 static struct tevent_req
*winexe_ctrl_send(
1489 TALLOC_CTX
*mem_ctx
,
1490 struct tevent_context
*ev
,
1491 struct cli_state
*cli
,
1494 struct tevent_req
*req
, *subreq
;
1495 struct winexe_ctrl_state
*state
;
1497 req
= tevent_req_create(mem_ctx
, &state
,
1498 struct winexe_ctrl_state
);
1505 state
->cmd
= talloc_asprintf(state
, "run %s\n", cmd
);
1506 if (tevent_req_nomem(state
->cmd
, req
)) {
1507 return tevent_req_post(req
, ev
);
1510 subreq
= cli_ntcreate_send(
1516 SEC_RIGHTS_FILE_READ
|SEC_RIGHTS_FILE_WRITE
|
1517 SEC_RIGHTS_FILE_EXECUTE
,
1518 0, /* FileAttributes */
1519 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
1520 FILE_OPEN
, /* CreateDisposition */
1521 0, /* CreateOptions */
1522 SMB2_IMPERSONATION_IMPERSONATION
,
1523 0); /* SecurityFlags */
1524 if (tevent_req_nomem(subreq
, req
)) {
1525 return tevent_req_post(req
, ev
);
1527 tevent_req_set_callback(subreq
, winexe_ctrl_opened
, req
);
1531 static void winexe_ctrl_opened(struct tevent_req
*subreq
)
1533 struct tevent_req
*req
= tevent_req_callback_data(
1534 subreq
, struct tevent_req
);
1535 struct winexe_ctrl_state
*state
= tevent_req_data(
1536 req
, struct winexe_ctrl_state
);
1539 static const char cmd
[] = "get codepage\nget version\n";
1541 status
= cli_ntcreate_recv(subreq
, &state
->ctrl_pipe
, NULL
);
1542 TALLOC_FREE(subreq
);
1543 if (tevent_req_nterror(req
, status
)) {
1547 timeout
= state
->cli
->timeout
;
1548 state
->cli
->timeout
= 0;
1550 subreq
= cli_read_send(
1557 sizeof(state
->ctrl_inbuf
)-1);
1559 state
->cli
->timeout
= timeout
;
1561 if (tevent_req_nomem(subreq
, req
)) {
1564 tevent_req_set_callback(subreq
, winexe_ctrl_got_read
, req
);
1566 subreq
= cli_writeall_send(
1572 (const uint8_t *)cmd
,
1575 if (tevent_req_nomem(subreq
, req
)) {
1578 tevent_req_set_callback(subreq
, winexe_ctrl_wrote_version
, req
);
1581 static void winexe_ctrl_got_read(struct tevent_req
*subreq
)
1583 struct tevent_req
*req
= tevent_req_callback_data(
1584 subreq
, struct tevent_req
);
1585 struct winexe_ctrl_state
*state
= tevent_req_data(
1586 req
, struct winexe_ctrl_state
);
1590 unsigned int version
, return_code
;
1593 status
= cli_read_recv(subreq
, &received
);
1594 TALLOC_FREE(subreq
);
1596 if (NT_STATUS_EQUAL(status
, NT_STATUS_PIPE_DISCONNECTED
)) {
1597 subreq
= cli_close_send(state
,
1602 if (tevent_req_nomem(subreq
, req
)) {
1605 tevent_req_set_callback(subreq
, winexe_ctrl_pipe_closed
, req
);
1608 if (tevent_req_nterror(req
, status
)) {
1612 DBG_DEBUG("Got %zu bytes\n", received
);
1614 timeout
= state
->cli
->timeout
;
1615 state
->cli
->timeout
= 0;
1617 subreq
= cli_read_send(
1624 sizeof(state
->ctrl_inbuf
)-1);
1626 state
->cli
->timeout
= timeout
;
1628 if (tevent_req_nomem(subreq
, req
)) {
1631 tevent_req_set_callback(subreq
, winexe_ctrl_got_read
, req
);
1633 ret
= sscanf(state
->ctrl_inbuf
, "version 0x%x\n", &version
);
1635 DBG_DEBUG("Got version %x\n", version
);
1637 subreq
= cli_writeall_send(
1643 (const uint8_t *)state
->cmd
,
1645 strlen(state
->cmd
));
1646 if (tevent_req_nomem(subreq
, req
)) {
1649 tevent_req_set_callback(subreq
, winexe_ctrl_wrote_cmd
, req
);
1653 ret
= strncmp(state
->ctrl_inbuf
, "std_io_err ", strlen("std_io_err "));
1655 char *p
= state
->ctrl_inbuf
+ 11;
1656 char *q
= strchr(state
->ctrl_inbuf
, '\n');
1661 DBG_DEBUG("Got invalid pipe postfix\n");
1665 postfix_len
= q
- p
;
1667 postfix
= talloc_strndup(state
, p
, postfix_len
);
1668 if (tevent_req_nomem(postfix
, req
)) {
1672 DBG_DEBUG("Got pipe postfix %s\n", postfix
);
1674 subreq
= winexe_pipes_send(
1679 if (tevent_req_nomem(subreq
, req
)) {
1682 tevent_req_set_callback(subreq
, winexe_ctrl_pipes_done
, req
);
1684 state
->pipes_req
= subreq
;
1689 ret
= strncmp(state
->ctrl_inbuf
, "error ", strlen("error "));
1691 printf("Error: %s", state
->ctrl_inbuf
);
1695 ret
= sscanf(state
->ctrl_inbuf
, "return_code %x\n", &return_code
);
1697 state
->return_code
= return_code
;
1702 static void winexe_ctrl_wrote_version(struct tevent_req
*subreq
)
1704 struct tevent_req
*req
= tevent_req_callback_data(
1705 subreq
, struct tevent_req
);
1708 status
= cli_writeall_recv(subreq
, NULL
);
1709 TALLOC_FREE(subreq
);
1710 if (tevent_req_nterror(req
, status
)) {
1715 static void winexe_ctrl_wrote_cmd(struct tevent_req
*subreq
)
1717 struct tevent_req
*req
= tevent_req_callback_data(
1718 subreq
, struct tevent_req
);
1721 status
= cli_writeall_recv(subreq
, NULL
);
1722 TALLOC_FREE(subreq
);
1723 if (tevent_req_nterror(req
, status
)) {
1728 static void winexe_ctrl_pipe_closed(struct tevent_req
*subreq
)
1730 struct tevent_req
*req
= tevent_req_callback_data(
1731 subreq
, struct tevent_req
);
1732 struct winexe_ctrl_state
*state
= tevent_req_data(
1733 req
, struct winexe_ctrl_state
);
1736 status
= cli_close_recv(subreq
);
1737 TALLOC_FREE(subreq
);
1738 if (tevent_req_nterror(req
, status
)) {
1742 state
->ctrl_pipe_done
= true;
1743 if (state
->pipes_req
== NULL
) {
1744 tevent_req_done(req
);
1748 static void winexe_ctrl_pipes_done(struct tevent_req
*subreq
)
1750 struct tevent_req
*req
= tevent_req_callback_data(
1751 subreq
, struct tevent_req
);
1752 struct winexe_ctrl_state
*state
= tevent_req_data(
1753 req
, struct winexe_ctrl_state
);
1756 status
= winexe_pipes_recv(subreq
);
1757 TALLOC_FREE(subreq
);
1758 if (tevent_req_nterror(req
, status
)) {
1762 state
->pipes_req
= NULL
;
1763 if (state
->ctrl_pipe_done
) {
1764 tevent_req_done(req
);
1768 static NTSTATUS
winexe_ctrl_recv(struct tevent_req
*req
,
1771 struct winexe_ctrl_state
*state
= tevent_req_data(
1772 req
, struct winexe_ctrl_state
);
1775 if (tevent_req_is_nterror(req
, &status
)) {
1778 if (preturn_code
!= NULL
) {
1779 *preturn_code
= state
->return_code
;
1781 return NT_STATUS_OK
;
1784 static NTSTATUS
winexe_ctrl(struct cli_state
*cli
,
1788 struct tevent_context
*ev
= NULL
;
1789 struct tevent_req
*req
= NULL
;
1790 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1793 ev
= samba_tevent_context_init(cli
);
1797 req
= winexe_ctrl_send(ev
, ev
, cli
, cmd
);
1801 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
1805 status
= winexe_ctrl_recv(req
, preturn_code
);
1812 #ifdef HAVE_WINEXE_CC_WIN32
1813 const DATA_BLOB
*winexesvc32_exe_binary(void);
1816 #ifdef HAVE_WINEXE_CC_WIN64
1817 const DATA_BLOB
*winexesvc64_exe_binary(void);
1820 int main(int argc
, char *argv
[])
1822 TALLOC_CTX
*frame
= talloc_stackframe();
1823 const char **const_argv
= discard_const_p(const char *, argv
);
1824 struct program_options options
= {0};
1825 struct cli_state
*cli
= NULL
;
1826 const char *service_name
= SERVICE_NAME
;
1827 char *service_filename
= NULL
;
1828 #ifdef HAVE_WINEXE_CC_WIN32
1829 const DATA_BLOB
*winexesvc32_exe
= winexesvc32_exe_binary();
1831 const DATA_BLOB
*winexesvc32_exe
= NULL
;
1833 #ifdef HAVE_WINEXE_CC_WIN64
1834 const DATA_BLOB
*winexesvc64_exe
= winexesvc64_exe_binary();
1836 const DATA_BLOB
*winexesvc64_exe
= NULL
;
1840 int return_code
= 0;
1844 parse_args(argc
, const_argv
, frame
, &options
);
1846 samba_cmdline_burn(argc
, argv
);
1848 if (options
.cmd
== NULL
) {
1849 fprintf(stderr
, "no cmd given\n");
1853 service_filename
= talloc_asprintf(frame
, "%s.exe", service_name
);
1854 if (service_filename
== NULL
) {
1855 DBG_WARNING("talloc_asprintf failed\n");
1859 status
= cli_full_connection_creds(
1867 options
.credentials
,
1868 CLI_FULL_CONNECTION_IPC
);
1870 if (!NT_STATUS_IS_OK(status
)) {
1871 DBG_WARNING("cli_full_connection_creds failed: %s\n",
1876 status
= winexe_svc_install(
1884 options
.credentials
,
1886 if (!NT_STATUS_IS_OK(status
)) {
1887 DBG_WARNING("winexe_svc_install failed: %s\n",
1892 status
= winexe_ctrl(cli
, options
.cmd
, &return_code
);
1893 if (NT_STATUS_EQUAL(status
, NT_STATUS_PIPE_DISCONNECTED
)) {
1895 status
= NT_STATUS_OK
;
1897 if (!NT_STATUS_IS_OK(status
)) {
1898 DBG_WARNING("cli_ctrl failed: %s\n",
1903 if (options
.flags
& SVC_UNINSTALL
) {
1904 status
= winexe_svc_uninstall(
1907 if (!NT_STATUS_IS_OK(status
)) {
1908 DBG_WARNING("winexe_svc_uninstall failed: %s\n",