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(
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(
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
);
1278 subreq
= cli_close_send(
1283 if (subreq
== NULL
) {
1286 tevent_req_set_callback(subreq
, winexe_in_pipe_closed
, req
);
1287 state
->closing
= true;
1292 struct winexe_pipes_state
{
1293 struct tevent_req
*pipes
[3];
1296 static void winexe_pipes_stdin_done(struct tevent_req
*subreq
);
1297 static void winexe_pipes_stdout_done(struct tevent_req
*subreq
);
1298 static void winexe_pipes_stderr_done(struct tevent_req
*subreq
);
1300 static struct tevent_req
*winexe_pipes_send(
1301 TALLOC_CTX
*mem_ctx
,
1302 struct tevent_context
*ev
,
1303 struct cli_state
*cli
,
1304 const char *pipe_postfix
)
1306 struct tevent_req
*req
;
1307 struct winexe_pipes_state
*state
;
1310 req
= tevent_req_create(mem_ctx
, &state
, struct winexe_pipes_state
);
1315 pipe_name
= talloc_asprintf(state
, "\\ahexec_stdin%s", pipe_postfix
);
1316 if (tevent_req_nomem(pipe_name
, req
)) {
1317 return tevent_req_post(req
, ev
);
1319 state
->pipes
[0] = winexe_in_pipe_send(
1325 if (tevent_req_nomem(state
->pipes
[0], req
)) {
1326 return tevent_req_post(req
, ev
);
1328 tevent_req_set_callback(state
->pipes
[0], winexe_pipes_stdin_done
, req
);
1330 pipe_name
= talloc_asprintf(state
, "\\ahexec_stdout%s", pipe_postfix
);
1331 if (tevent_req_nomem(pipe_name
, req
)) {
1332 return tevent_req_post(req
, ev
);
1334 state
->pipes
[1] = winexe_out_pipe_send(
1340 if (tevent_req_nomem(state
->pipes
[1], req
)) {
1341 return tevent_req_post(req
, ev
);
1343 tevent_req_set_callback(state
->pipes
[1], winexe_pipes_stdout_done
,
1346 pipe_name
= talloc_asprintf(state
, "\\ahexec_stderr%s", pipe_postfix
);
1347 if (tevent_req_nomem(pipe_name
, req
)) {
1348 return tevent_req_post(req
, ev
);
1350 state
->pipes
[2] = winexe_out_pipe_send(
1356 if (tevent_req_nomem(state
->pipes
[2], req
)) {
1357 return tevent_req_post(req
, ev
);
1359 tevent_req_set_callback(state
->pipes
[2], winexe_pipes_stderr_done
,
1362 DBG_DEBUG("pipes = %p %p %p\n",
1370 static void winexe_pipes_stdin_done(struct tevent_req
*subreq
)
1372 struct tevent_req
*req
= tevent_req_callback_data(
1373 subreq
, struct tevent_req
);
1374 struct winexe_pipes_state
*state
= tevent_req_data(
1375 req
, struct winexe_pipes_state
);
1378 status
= winexe_in_pipe_recv(subreq
);
1379 TALLOC_FREE(subreq
);
1381 DBG_DEBUG("stdin returned %s\n", nt_errstr(status
));
1383 if (tevent_req_nterror(req
, status
)) {
1387 state
->pipes
[0] = NULL
;
1389 DBG_DEBUG("pipes = %p %p %p\n",
1394 if ((state
->pipes
[1] == NULL
) && (state
->pipes
[2] == NULL
)) {
1395 tevent_req_done(req
);
1399 static void winexe_pipes_stdout_done(struct tevent_req
*subreq
)
1401 struct tevent_req
*req
= tevent_req_callback_data(
1402 subreq
, struct tevent_req
);
1403 struct winexe_pipes_state
*state
= tevent_req_data(
1404 req
, struct winexe_pipes_state
);
1407 status
= winexe_out_pipe_recv(subreq
);
1408 TALLOC_FREE(subreq
);
1410 DBG_DEBUG("stdout returned %s\n", nt_errstr(status
));
1412 if (tevent_req_nterror(req
, status
)) {
1416 if (state
->pipes
[0] != NULL
) {
1417 winexe_in_pipe_close(state
->pipes
[0]);
1420 state
->pipes
[1] = NULL
;
1422 DBG_DEBUG("pipes = %p %p %p\n",
1427 if ((state
->pipes
[0] == NULL
) && (state
->pipes
[2] == NULL
)) {
1428 tevent_req_done(req
);
1432 static void winexe_pipes_stderr_done(struct tevent_req
*subreq
)
1434 struct tevent_req
*req
= tevent_req_callback_data(
1435 subreq
, struct tevent_req
);
1436 struct winexe_pipes_state
*state
= tevent_req_data(
1437 req
, struct winexe_pipes_state
);
1440 status
= winexe_out_pipe_recv(subreq
);
1441 TALLOC_FREE(subreq
);
1443 DBG_DEBUG("stderr returned %s\n", nt_errstr(status
));
1445 if (tevent_req_nterror(req
, status
)) {
1449 if (state
->pipes
[0] != NULL
) {
1450 winexe_in_pipe_close(state
->pipes
[0]);
1453 state
->pipes
[2] = NULL
;
1455 DBG_DEBUG("pipes = %p %p %p\n",
1460 if ((state
->pipes
[0] == NULL
) && (state
->pipes
[1] == NULL
)) {
1461 tevent_req_done(req
);
1465 static NTSTATUS
winexe_pipes_recv(struct tevent_req
*req
)
1467 return tevent_req_simple_recv_ntstatus(req
);
1470 struct winexe_ctrl_state
{
1471 struct tevent_context
*ev
;
1472 struct cli_state
*cli
;
1475 bool ctrl_pipe_done
;
1477 char ctrl_inbuf
[256];
1481 struct tevent_req
*pipes_req
;
1484 static void winexe_ctrl_opened(struct tevent_req
*subreq
);
1485 static void winexe_ctrl_got_read(struct tevent_req
*subreq
);
1486 static void winexe_ctrl_wrote_version(struct tevent_req
*subreq
);
1487 static void winexe_ctrl_wrote_cmd(struct tevent_req
*subreq
);
1488 static void winexe_ctrl_pipes_done(struct tevent_req
*subreq
);
1489 static void winexe_ctrl_pipe_closed(struct tevent_req
*subreq
);
1491 static struct tevent_req
*winexe_ctrl_send(
1492 TALLOC_CTX
*mem_ctx
,
1493 struct tevent_context
*ev
,
1494 struct cli_state
*cli
,
1497 struct tevent_req
*req
, *subreq
;
1498 struct winexe_ctrl_state
*state
;
1500 req
= tevent_req_create(mem_ctx
, &state
,
1501 struct winexe_ctrl_state
);
1508 state
->cmd
= talloc_asprintf(state
, "run %s\n", cmd
);
1509 if (tevent_req_nomem(state
->cmd
, req
)) {
1510 return tevent_req_post(req
, ev
);
1513 subreq
= cli_ntcreate_send(
1519 SEC_RIGHTS_FILE_READ
|SEC_RIGHTS_FILE_WRITE
|
1520 SEC_RIGHTS_FILE_EXECUTE
,
1521 0, /* FileAttributes */
1522 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
1523 FILE_OPEN
, /* CreateDisposition */
1524 0, /* CreateOptions */
1525 SMB2_IMPERSONATION_IMPERSONATION
,
1526 0); /* SecurityFlags */
1527 if (tevent_req_nomem(subreq
, req
)) {
1528 return tevent_req_post(req
, ev
);
1530 tevent_req_set_callback(subreq
, winexe_ctrl_opened
, req
);
1534 static void winexe_ctrl_opened(struct tevent_req
*subreq
)
1536 struct tevent_req
*req
= tevent_req_callback_data(
1537 subreq
, struct tevent_req
);
1538 struct winexe_ctrl_state
*state
= tevent_req_data(
1539 req
, struct winexe_ctrl_state
);
1542 static const char cmd
[] = "get codepage\nget version\n";
1544 status
= cli_ntcreate_recv(subreq
, &state
->ctrl_pipe
, NULL
);
1545 TALLOC_FREE(subreq
);
1546 if (tevent_req_nterror(req
, status
)) {
1550 timeout
= state
->cli
->timeout
;
1551 state
->cli
->timeout
= 0;
1553 subreq
= cli_read_send(
1560 sizeof(state
->ctrl_inbuf
)-1);
1562 state
->cli
->timeout
= timeout
;
1564 if (tevent_req_nomem(subreq
, req
)) {
1567 tevent_req_set_callback(subreq
, winexe_ctrl_got_read
, req
);
1569 subreq
= cli_writeall_send(
1575 (const uint8_t *)cmd
,
1578 if (tevent_req_nomem(subreq
, req
)) {
1581 tevent_req_set_callback(subreq
, winexe_ctrl_wrote_version
, req
);
1584 static void winexe_ctrl_got_read(struct tevent_req
*subreq
)
1586 struct tevent_req
*req
= tevent_req_callback_data(
1587 subreq
, struct tevent_req
);
1588 struct winexe_ctrl_state
*state
= tevent_req_data(
1589 req
, struct winexe_ctrl_state
);
1593 unsigned int version
, return_code
;
1596 status
= cli_read_recv(subreq
, &received
);
1597 TALLOC_FREE(subreq
);
1599 if (NT_STATUS_EQUAL(status
, NT_STATUS_PIPE_DISCONNECTED
)) {
1600 subreq
= cli_close_send(
1605 if (tevent_req_nomem(subreq
, req
)) {
1608 tevent_req_set_callback(subreq
, winexe_ctrl_pipe_closed
, req
);
1611 if (tevent_req_nterror(req
, status
)) {
1615 DBG_DEBUG("Got %zu bytes\n", received
);
1617 timeout
= state
->cli
->timeout
;
1618 state
->cli
->timeout
= 0;
1620 subreq
= cli_read_send(
1627 sizeof(state
->ctrl_inbuf
)-1);
1629 state
->cli
->timeout
= timeout
;
1631 if (tevent_req_nomem(subreq
, req
)) {
1634 tevent_req_set_callback(subreq
, winexe_ctrl_got_read
, req
);
1636 ret
= sscanf(state
->ctrl_inbuf
, "version 0x%x\n", &version
);
1638 DBG_DEBUG("Got version %x\n", version
);
1640 subreq
= cli_writeall_send(
1646 (const uint8_t *)state
->cmd
,
1648 strlen(state
->cmd
));
1649 if (tevent_req_nomem(subreq
, req
)) {
1652 tevent_req_set_callback(subreq
, winexe_ctrl_wrote_cmd
, req
);
1656 ret
= strncmp(state
->ctrl_inbuf
, "std_io_err ", strlen("std_io_err "));
1658 char *p
= state
->ctrl_inbuf
+ 11;
1659 char *q
= strchr(state
->ctrl_inbuf
, '\n');
1664 DBG_DEBUG("Got invalid pipe postfix\n");
1668 postfix_len
= q
- p
;
1670 postfix
= talloc_strndup(state
, p
, postfix_len
);
1671 if (tevent_req_nomem(postfix
, req
)) {
1675 DBG_DEBUG("Got pipe postfix %s\n", postfix
);
1677 subreq
= winexe_pipes_send(
1682 if (tevent_req_nomem(subreq
, req
)) {
1685 tevent_req_set_callback(subreq
, winexe_ctrl_pipes_done
, req
);
1687 state
->pipes_req
= subreq
;
1692 ret
= strncmp(state
->ctrl_inbuf
, "error ", strlen("error "));
1694 printf("Error: %s", state
->ctrl_inbuf
);
1698 ret
= sscanf(state
->ctrl_inbuf
, "version 0x%x\n", &return_code
);
1700 state
->return_code
= return_code
;
1705 static void winexe_ctrl_wrote_version(struct tevent_req
*subreq
)
1707 struct tevent_req
*req
= tevent_req_callback_data(
1708 subreq
, struct tevent_req
);
1711 status
= cli_writeall_recv(subreq
, NULL
);
1712 TALLOC_FREE(subreq
);
1713 if (tevent_req_nterror(req
, status
)) {
1718 static void winexe_ctrl_wrote_cmd(struct tevent_req
*subreq
)
1720 struct tevent_req
*req
= tevent_req_callback_data(
1721 subreq
, struct tevent_req
);
1724 status
= cli_writeall_recv(subreq
, NULL
);
1725 TALLOC_FREE(subreq
);
1726 if (tevent_req_nterror(req
, status
)) {
1731 static void winexe_ctrl_pipe_closed(struct tevent_req
*subreq
)
1733 struct tevent_req
*req
= tevent_req_callback_data(
1734 subreq
, struct tevent_req
);
1735 struct winexe_ctrl_state
*state
= tevent_req_data(
1736 req
, struct winexe_ctrl_state
);
1739 status
= cli_close_recv(subreq
);
1740 TALLOC_FREE(subreq
);
1741 if (tevent_req_nterror(req
, status
)) {
1745 state
->ctrl_pipe_done
= true;
1746 if (state
->pipes_req
== NULL
) {
1747 tevent_req_done(req
);
1751 static void winexe_ctrl_pipes_done(struct tevent_req
*subreq
)
1753 struct tevent_req
*req
= tevent_req_callback_data(
1754 subreq
, struct tevent_req
);
1755 struct winexe_ctrl_state
*state
= tevent_req_data(
1756 req
, struct winexe_ctrl_state
);
1759 status
= winexe_pipes_recv(subreq
);
1760 TALLOC_FREE(subreq
);
1761 if (tevent_req_nterror(req
, status
)) {
1765 state
->pipes_req
= NULL
;
1766 if (state
->ctrl_pipe_done
) {
1767 tevent_req_done(req
);
1771 static NTSTATUS
winexe_ctrl_recv(struct tevent_req
*req
,
1774 struct winexe_ctrl_state
*state
= tevent_req_data(
1775 req
, struct winexe_ctrl_state
);
1778 if (tevent_req_is_nterror(req
, &status
)) {
1781 if (preturn_code
!= NULL
) {
1782 *preturn_code
= state
->return_code
;
1784 return NT_STATUS_OK
;
1787 static NTSTATUS
winexe_ctrl(struct cli_state
*cli
,
1791 struct tevent_context
*ev
= NULL
;
1792 struct tevent_req
*req
= NULL
;
1793 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1796 ev
= samba_tevent_context_init(cli
);
1800 req
= winexe_ctrl_send(ev
, ev
, cli
, cmd
);
1804 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
1808 status
= winexe_ctrl_recv(req
, preturn_code
);
1815 #ifdef HAVE_WINEXE_CC_WIN32
1816 const DATA_BLOB
*winexesvc32_exe_binary(void);
1819 #ifdef HAVE_WINEXE_CC_WIN64
1820 const DATA_BLOB
*winexesvc64_exe_binary(void);
1823 int main(int argc
, char *argv
[])
1825 TALLOC_CTX
*frame
= talloc_stackframe();
1826 const char **const_argv
= discard_const_p(const char *, argv
);
1827 struct program_options options
= {0};
1828 struct cli_state
*cli
= NULL
;
1829 const char *service_name
= SERVICE_NAME
;
1830 char *service_filename
= NULL
;
1831 #ifdef HAVE_WINEXE_CC_WIN32
1832 const DATA_BLOB
*winexesvc32_exe
= winexesvc32_exe_binary();
1834 const DATA_BLOB
*winexesvc32_exe
= NULL
;
1836 #ifdef HAVE_WINEXE_CC_WIN64
1837 const DATA_BLOB
*winexesvc64_exe
= winexesvc64_exe_binary();
1839 const DATA_BLOB
*winexesvc64_exe
= NULL
;
1843 int return_code
= 0;
1847 parse_args(argc
, const_argv
, frame
, &options
);
1849 samba_cmdline_burn(argc
, argv
);
1851 if (options
.cmd
== NULL
) {
1852 fprintf(stderr
, "no cmd given\n");
1856 service_filename
= talloc_asprintf(frame
, "%s.exe", service_name
);
1857 if (service_filename
== NULL
) {
1858 DBG_WARNING("talloc_asprintf failed\n");
1862 status
= cli_full_connection_creds(
1870 options
.credentials
,
1871 CLI_FULL_CONNECTION_IPC
);
1873 if (!NT_STATUS_IS_OK(status
)) {
1874 DBG_WARNING("cli_full_connection_creds failed: %s\n",
1879 status
= winexe_svc_install(
1887 options
.credentials
,
1889 if (!NT_STATUS_IS_OK(status
)) {
1890 DBG_WARNING("winexe_svc_install failed: %s\n",
1895 status
= winexe_ctrl(cli
, options
.cmd
, &return_code
);
1896 if (NT_STATUS_EQUAL(status
, NT_STATUS_PIPE_DISCONNECTED
)) {
1898 status
= NT_STATUS_OK
;
1900 if (!NT_STATUS_IS_OK(status
)) {
1901 DBG_WARNING("cli_ctrl failed: %s\n",
1906 if (options
.flags
& SVC_UNINSTALL
) {
1907 status
= winexe_svc_uninstall(
1910 if (!NT_STATUS_IS_OK(status
)) {
1911 DBG_WARNING("winexe_svc_uninstall failed: %s\n",