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 SMB2_IMPERSONATION_IMPERSONATION
,
876 0); /* SecurityFlags */
877 if (tevent_req_nomem(subreq
, req
)) {
878 return tevent_req_post(req
, ev
);
880 tevent_req_set_callback(subreq
, winexe_out_pipe_opened
, req
);
884 static void winexe_out_pipe_opened(struct tevent_req
*subreq
)
886 struct tevent_req
*req
= tevent_req_callback_data(
887 subreq
, struct tevent_req
);
888 struct winexe_out_pipe_state
*state
= tevent_req_data(
889 req
, struct winexe_out_pipe_state
);
893 status
= cli_ntcreate_recv(subreq
, &state
->out_pipe
, NULL
);
895 if (tevent_req_nterror(req
, status
)) {
899 timeout
= state
->cli
->timeout
;
900 state
->cli
->timeout
= 0;
902 subreq
= cli_read_send(
909 sizeof(state
->out_inbuf
));
911 state
->cli
->timeout
= timeout
;
913 if (tevent_req_nomem(subreq
, req
)) {
916 tevent_req_set_callback(subreq
, winexe_out_pipe_got_data
, req
);
919 static void winexe_out_pipe_got_data(struct tevent_req
*subreq
)
921 struct tevent_req
*req
= tevent_req_callback_data(
922 subreq
, struct tevent_req
);
923 struct winexe_out_pipe_state
*state
= tevent_req_data(
924 req
, struct winexe_out_pipe_state
);
930 status
= cli_read_recv(subreq
, &received
);
933 DBG_DEBUG("cli_read for %d gave %s\n",
937 if (NT_STATUS_EQUAL(status
, NT_STATUS_PIPE_DISCONNECTED
)) {
938 subreq
= cli_close_send(
943 if (tevent_req_nomem(subreq
, req
)) {
946 tevent_req_set_callback(subreq
, winexe_out_pipe_closed
, req
);
950 if (tevent_req_nterror(req
, status
)) {
955 written
= sys_write(state
->out_fd
, state
->out_inbuf
, received
);
957 tevent_req_nterror(req
, map_nt_error_from_unix(errno
));
962 timeout
= state
->cli
->timeout
;
963 state
->cli
->timeout
= 0;
965 subreq
= cli_read_send(
972 sizeof(state
->out_inbuf
));
974 state
->cli
->timeout
= timeout
;
976 if (tevent_req_nomem(subreq
, req
)) {
979 tevent_req_set_callback(subreq
, winexe_out_pipe_got_data
, req
);
982 static void winexe_out_pipe_closed(struct tevent_req
*subreq
)
984 struct tevent_req
*req
= tevent_req_callback_data(
985 subreq
, struct tevent_req
);
988 status
= cli_close_recv(subreq
);
990 if (tevent_req_nterror(req
, status
)) {
993 tevent_req_done(req
);
996 static NTSTATUS
winexe_out_pipe_recv(struct tevent_req
*req
)
998 return tevent_req_simple_recv_ntstatus(req
);
1001 struct winexe_in_pipe_state
{
1002 struct tevent_context
*ev
;
1003 struct cli_state
*cli
;
1004 struct tevent_req
*fd_read_req
;
1005 bool close_requested
;
1012 static void winexe_in_pipe_opened(struct tevent_req
*subreq
);
1013 static void winexe_in_pipe_got_data(struct tevent_req
*subreq
);
1014 static void winexe_in_pipe_written(struct tevent_req
*subreq
);
1015 static void winexe_in_pipe_closed(struct tevent_req
*subreq
);
1017 static struct tevent_req
*winexe_in_pipe_send(
1018 TALLOC_CTX
*mem_ctx
,
1019 struct tevent_context
*ev
,
1020 struct cli_state
*cli
,
1021 const char *pipe_name
,
1024 struct tevent_req
*req
, *subreq
;
1025 struct winexe_in_pipe_state
*state
;
1027 req
= tevent_req_create(mem_ctx
, &state
,
1028 struct winexe_in_pipe_state
);
1034 state
->in_fd
= in_fd
;
1036 subreq
= cli_ntcreate_send(
1042 SEC_RIGHTS_FILE_READ
|SEC_RIGHTS_FILE_WRITE
|
1043 SEC_RIGHTS_FILE_EXECUTE
,
1044 0, /* FileAttributes */
1045 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
1046 FILE_OPEN
, /* CreateDisposition */
1047 0, /* CreateOptions */
1048 SMB2_IMPERSONATION_IMPERSONATION
,
1049 0); /* SecurityFlags */
1050 if (tevent_req_nomem(subreq
, req
)) {
1051 return tevent_req_post(req
, ev
);
1053 tevent_req_set_callback(subreq
, winexe_in_pipe_opened
, req
);
1057 static void winexe_in_pipe_opened(struct tevent_req
*subreq
)
1059 struct tevent_req
*req
= tevent_req_callback_data(
1060 subreq
, struct tevent_req
);
1061 struct winexe_in_pipe_state
*state
= tevent_req_data(
1062 req
, struct winexe_in_pipe_state
);
1065 status
= cli_ntcreate_recv(subreq
, &state
->in_pipe
, NULL
);
1066 TALLOC_FREE(subreq
);
1067 if (tevent_req_nterror(req
, status
)) {
1071 subreq
= wait_for_read_send(
1076 if (tevent_req_nomem(subreq
, req
)) {
1079 tevent_req_set_callback(subreq
, winexe_in_pipe_got_data
, req
);
1081 state
->fd_read_req
= subreq
;
1084 static void winexe_in_pipe_got_data(struct tevent_req
*subreq
)
1086 struct tevent_req
*req
= tevent_req_callback_data(
1087 subreq
, struct tevent_req
);
1088 struct winexe_in_pipe_state
*state
= tevent_req_data(
1089 req
, struct winexe_in_pipe_state
);
1095 ok
= wait_for_read_recv(subreq
, &err
);
1096 TALLOC_FREE(subreq
);
1098 tevent_req_nterror(req
, map_nt_error_from_unix(err
));
1101 state
->fd_read_req
= NULL
;
1103 nread
= sys_read(state
->in_fd
, &state
->inbuf
, sizeof(state
->inbuf
));
1105 tevent_req_nterror(req
, map_nt_error_from_unix(errno
));
1109 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
1113 timeout
= state
->cli
->timeout
;
1114 state
->cli
->timeout
= 0;
1116 subreq
= cli_writeall_send(
1122 (uint8_t *)state
->inbuf
,
1126 state
->cli
->timeout
= timeout
;
1128 if (tevent_req_nomem(subreq
, req
)) {
1131 tevent_req_set_callback(subreq
, winexe_in_pipe_written
, req
);
1134 static void winexe_in_pipe_written(struct tevent_req
*subreq
)
1136 struct tevent_req
*req
= tevent_req_callback_data(
1137 subreq
, struct tevent_req
);
1138 struct winexe_in_pipe_state
*state
= tevent_req_data(
1139 req
, struct winexe_in_pipe_state
);
1142 status
= cli_writeall_recv(subreq
, NULL
);
1143 TALLOC_FREE(subreq
);
1145 DBG_DEBUG("cli_writeall for %d gave %s\n",
1149 if (NT_STATUS_EQUAL(status
, NT_STATUS_PIPE_DISCONNECTED
) ||
1150 state
->close_requested
) {
1151 subreq
= cli_close_send(
1156 if (tevent_req_nomem(subreq
, req
)) {
1159 tevent_req_set_callback(subreq
, winexe_in_pipe_closed
, req
);
1160 state
->closing
= true;
1164 if (tevent_req_nterror(req
, status
)) {
1168 subreq
= wait_for_read_send(
1173 if (tevent_req_nomem(subreq
, req
)) {
1176 tevent_req_set_callback(subreq
, winexe_in_pipe_got_data
, req
);
1178 state
->fd_read_req
= subreq
;
1181 static void winexe_in_pipe_closed(struct tevent_req
*subreq
)
1183 struct tevent_req
*req
= tevent_req_callback_data(
1184 subreq
, struct tevent_req
);
1187 status
= cli_close_recv(subreq
);
1188 TALLOC_FREE(subreq
);
1189 if (tevent_req_nterror(req
, status
)) {
1192 return tevent_req_done(req
);
1195 static NTSTATUS
winexe_in_pipe_recv(struct tevent_req
*req
)
1197 return tevent_req_simple_recv_ntstatus(req
);
1200 static bool winexe_in_pipe_close(struct tevent_req
*req
)
1202 struct winexe_in_pipe_state
*state
= tevent_req_data(
1203 req
, struct winexe_in_pipe_state
);
1204 struct tevent_req
*subreq
;
1206 if (state
->closing
) {
1210 if (state
->fd_read_req
== NULL
) {
1212 * cli_writeall active, wait for it to return
1214 state
->close_requested
= true;
1218 TALLOC_FREE(state
->fd_read_req
);
1220 subreq
= cli_close_send(
1225 if (subreq
== NULL
) {
1228 tevent_req_set_callback(subreq
, winexe_in_pipe_closed
, req
);
1229 state
->closing
= true;
1234 struct winexe_pipes_state
{
1235 struct tevent_req
*pipes
[3];
1238 static void winexe_pipes_stdin_done(struct tevent_req
*subreq
);
1239 static void winexe_pipes_stdout_done(struct tevent_req
*subreq
);
1240 static void winexe_pipes_stderr_done(struct tevent_req
*subreq
);
1242 static struct tevent_req
*winexe_pipes_send(
1243 TALLOC_CTX
*mem_ctx
,
1244 struct tevent_context
*ev
,
1245 struct cli_state
*cli
,
1246 const char *pipe_postfix
)
1248 struct tevent_req
*req
;
1249 struct winexe_pipes_state
*state
;
1252 req
= tevent_req_create(mem_ctx
, &state
, struct winexe_pipes_state
);
1257 pipe_name
= talloc_asprintf(state
, "\\ahexec_stdin%s", pipe_postfix
);
1258 if (tevent_req_nomem(pipe_name
, req
)) {
1259 return tevent_req_post(req
, ev
);
1261 state
->pipes
[0] = winexe_in_pipe_send(
1267 if (tevent_req_nomem(state
->pipes
[0], req
)) {
1268 return tevent_req_post(req
, ev
);
1270 tevent_req_set_callback(state
->pipes
[0], winexe_pipes_stdin_done
, req
);
1272 pipe_name
= talloc_asprintf(state
, "\\ahexec_stdout%s", pipe_postfix
);
1273 if (tevent_req_nomem(pipe_name
, req
)) {
1274 return tevent_req_post(req
, ev
);
1276 state
->pipes
[1] = winexe_out_pipe_send(
1282 if (tevent_req_nomem(state
->pipes
[1], req
)) {
1283 return tevent_req_post(req
, ev
);
1285 tevent_req_set_callback(state
->pipes
[1], winexe_pipes_stdout_done
,
1288 pipe_name
= talloc_asprintf(state
, "\\ahexec_stderr%s", pipe_postfix
);
1289 if (tevent_req_nomem(pipe_name
, req
)) {
1290 return tevent_req_post(req
, ev
);
1292 state
->pipes
[2] = winexe_out_pipe_send(
1298 if (tevent_req_nomem(state
->pipes
[2], req
)) {
1299 return tevent_req_post(req
, ev
);
1301 tevent_req_set_callback(state
->pipes
[2], winexe_pipes_stderr_done
,
1304 DBG_DEBUG("pipes = %p %p %p\n",
1312 static void winexe_pipes_stdin_done(struct tevent_req
*subreq
)
1314 struct tevent_req
*req
= tevent_req_callback_data(
1315 subreq
, struct tevent_req
);
1316 struct winexe_pipes_state
*state
= tevent_req_data(
1317 req
, struct winexe_pipes_state
);
1320 status
= winexe_in_pipe_recv(subreq
);
1321 TALLOC_FREE(subreq
);
1323 DBG_DEBUG("stdin returned %s\n", nt_errstr(status
));
1325 if (tevent_req_nterror(req
, status
)) {
1329 state
->pipes
[0] = NULL
;
1331 DBG_DEBUG("pipes = %p %p %p\n",
1336 if ((state
->pipes
[1] == NULL
) && (state
->pipes
[2] == NULL
)) {
1337 tevent_req_done(req
);
1341 static void winexe_pipes_stdout_done(struct tevent_req
*subreq
)
1343 struct tevent_req
*req
= tevent_req_callback_data(
1344 subreq
, struct tevent_req
);
1345 struct winexe_pipes_state
*state
= tevent_req_data(
1346 req
, struct winexe_pipes_state
);
1349 status
= winexe_out_pipe_recv(subreq
);
1350 TALLOC_FREE(subreq
);
1352 DBG_DEBUG("stdout returned %s\n", nt_errstr(status
));
1354 if (tevent_req_nterror(req
, status
)) {
1358 if (state
->pipes
[0] != NULL
) {
1359 winexe_in_pipe_close(state
->pipes
[0]);
1362 state
->pipes
[1] = NULL
;
1364 DBG_DEBUG("pipes = %p %p %p\n",
1369 if ((state
->pipes
[0] == NULL
) && (state
->pipes
[2] == NULL
)) {
1370 tevent_req_done(req
);
1374 static void winexe_pipes_stderr_done(struct tevent_req
*subreq
)
1376 struct tevent_req
*req
= tevent_req_callback_data(
1377 subreq
, struct tevent_req
);
1378 struct winexe_pipes_state
*state
= tevent_req_data(
1379 req
, struct winexe_pipes_state
);
1382 status
= winexe_out_pipe_recv(subreq
);
1383 TALLOC_FREE(subreq
);
1385 DBG_DEBUG("stderr returned %s\n", nt_errstr(status
));
1387 if (tevent_req_nterror(req
, status
)) {
1391 if (state
->pipes
[0] != NULL
) {
1392 winexe_in_pipe_close(state
->pipes
[0]);
1395 state
->pipes
[2] = NULL
;
1397 DBG_DEBUG("pipes = %p %p %p\n",
1402 if ((state
->pipes
[0] == NULL
) && (state
->pipes
[1] == NULL
)) {
1403 tevent_req_done(req
);
1407 static NTSTATUS
winexe_pipes_recv(struct tevent_req
*req
)
1409 return tevent_req_simple_recv_ntstatus(req
);
1412 struct winexe_ctrl_state
{
1413 struct tevent_context
*ev
;
1414 struct cli_state
*cli
;
1417 bool ctrl_pipe_done
;
1419 char ctrl_inbuf
[256];
1423 struct tevent_req
*pipes_req
;
1426 static void winexe_ctrl_opened(struct tevent_req
*subreq
);
1427 static void winexe_ctrl_got_read(struct tevent_req
*subreq
);
1428 static void winexe_ctrl_wrote_version(struct tevent_req
*subreq
);
1429 static void winexe_ctrl_wrote_cmd(struct tevent_req
*subreq
);
1430 static void winexe_ctrl_pipes_done(struct tevent_req
*subreq
);
1431 static void winexe_ctrl_pipe_closed(struct tevent_req
*subreq
);
1433 static struct tevent_req
*winexe_ctrl_send(
1434 TALLOC_CTX
*mem_ctx
,
1435 struct tevent_context
*ev
,
1436 struct cli_state
*cli
,
1439 struct tevent_req
*req
, *subreq
;
1440 struct winexe_ctrl_state
*state
;
1442 req
= tevent_req_create(mem_ctx
, &state
,
1443 struct winexe_ctrl_state
);
1450 state
->cmd
= talloc_asprintf(state
, "run %s\n", cmd
);
1451 if (tevent_req_nomem(state
->cmd
, req
)) {
1452 return tevent_req_post(req
, ev
);
1455 subreq
= cli_ntcreate_send(
1461 SEC_RIGHTS_FILE_READ
|SEC_RIGHTS_FILE_WRITE
|
1462 SEC_RIGHTS_FILE_EXECUTE
,
1463 0, /* FileAttributes */
1464 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
1465 FILE_OPEN
, /* CreateDisposition */
1466 0, /* CreateOptions */
1467 SMB2_IMPERSONATION_IMPERSONATION
,
1468 0); /* SecurityFlags */
1469 if (tevent_req_nomem(subreq
, req
)) {
1470 return tevent_req_post(req
, ev
);
1472 tevent_req_set_callback(subreq
, winexe_ctrl_opened
, req
);
1476 static void winexe_ctrl_opened(struct tevent_req
*subreq
)
1478 struct tevent_req
*req
= tevent_req_callback_data(
1479 subreq
, struct tevent_req
);
1480 struct winexe_ctrl_state
*state
= tevent_req_data(
1481 req
, struct winexe_ctrl_state
);
1484 static const char cmd
[] = "get codepage\nget version\n";
1486 status
= cli_ntcreate_recv(subreq
, &state
->ctrl_pipe
, NULL
);
1487 TALLOC_FREE(subreq
);
1488 if (tevent_req_nterror(req
, status
)) {
1492 timeout
= state
->cli
->timeout
;
1493 state
->cli
->timeout
= 0;
1495 subreq
= cli_read_send(
1502 sizeof(state
->ctrl_inbuf
)-1);
1504 state
->cli
->timeout
= timeout
;
1506 if (tevent_req_nomem(subreq
, req
)) {
1509 tevent_req_set_callback(subreq
, winexe_ctrl_got_read
, req
);
1511 subreq
= cli_writeall_send(
1517 (const uint8_t *)cmd
,
1520 if (tevent_req_nomem(subreq
, req
)) {
1523 tevent_req_set_callback(subreq
, winexe_ctrl_wrote_version
, req
);
1526 static void winexe_ctrl_got_read(struct tevent_req
*subreq
)
1528 struct tevent_req
*req
= tevent_req_callback_data(
1529 subreq
, struct tevent_req
);
1530 struct winexe_ctrl_state
*state
= tevent_req_data(
1531 req
, struct winexe_ctrl_state
);
1535 unsigned int version
, return_code
;
1538 status
= cli_read_recv(subreq
, &received
);
1539 TALLOC_FREE(subreq
);
1541 if (NT_STATUS_EQUAL(status
, NT_STATUS_PIPE_DISCONNECTED
)) {
1542 subreq
= cli_close_send(
1547 if (tevent_req_nomem(subreq
, req
)) {
1550 tevent_req_set_callback(subreq
, winexe_ctrl_pipe_closed
, req
);
1553 if (tevent_req_nterror(req
, status
)) {
1557 DBG_DEBUG("Got %zu bytes\n", received
);
1559 timeout
= state
->cli
->timeout
;
1560 state
->cli
->timeout
= 0;
1562 subreq
= cli_read_send(
1569 sizeof(state
->ctrl_inbuf
)-1);
1571 state
->cli
->timeout
= timeout
;
1573 if (tevent_req_nomem(subreq
, req
)) {
1576 tevent_req_set_callback(subreq
, winexe_ctrl_got_read
, req
);
1578 ret
= sscanf(state
->ctrl_inbuf
, "version 0x%x\n", &version
);
1580 DBG_DEBUG("Got version %x\n", version
);
1582 subreq
= cli_writeall_send(
1588 (const uint8_t *)state
->cmd
,
1590 strlen(state
->cmd
));
1591 if (tevent_req_nomem(subreq
, req
)) {
1594 tevent_req_set_callback(subreq
, winexe_ctrl_wrote_cmd
, req
);
1598 ret
= strncmp(state
->ctrl_inbuf
, "std_io_err ", strlen("std_io_err "));
1600 char *p
= state
->ctrl_inbuf
+ 11;
1601 char *q
= strchr(state
->ctrl_inbuf
, '\n');
1606 DBG_DEBUG("Got invalid pipe postfix\n");
1610 postfix_len
= q
- p
;
1612 postfix
= talloc_strndup(state
, p
, postfix_len
);
1613 if (tevent_req_nomem(postfix
, req
)) {
1617 DBG_DEBUG("Got pipe postfix %s\n", postfix
);
1619 subreq
= winexe_pipes_send(
1624 if (tevent_req_nomem(subreq
, req
)) {
1627 tevent_req_set_callback(subreq
, winexe_ctrl_pipes_done
, req
);
1629 state
->pipes_req
= subreq
;
1634 ret
= strncmp(state
->ctrl_inbuf
, "error ", strlen("error "));
1636 printf("Error: %s", state
->ctrl_inbuf
);
1640 ret
= sscanf(state
->ctrl_inbuf
, "version 0x%x\n", &return_code
);
1642 state
->return_code
= return_code
;
1647 static void winexe_ctrl_wrote_version(struct tevent_req
*subreq
)
1649 struct tevent_req
*req
= tevent_req_callback_data(
1650 subreq
, struct tevent_req
);
1653 status
= cli_writeall_recv(subreq
, NULL
);
1654 TALLOC_FREE(subreq
);
1655 if (tevent_req_nterror(req
, status
)) {
1660 static void winexe_ctrl_wrote_cmd(struct tevent_req
*subreq
)
1662 struct tevent_req
*req
= tevent_req_callback_data(
1663 subreq
, struct tevent_req
);
1666 status
= cli_writeall_recv(subreq
, NULL
);
1667 TALLOC_FREE(subreq
);
1668 if (tevent_req_nterror(req
, status
)) {
1673 static void winexe_ctrl_pipe_closed(struct tevent_req
*subreq
)
1675 struct tevent_req
*req
= tevent_req_callback_data(
1676 subreq
, struct tevent_req
);
1677 struct winexe_ctrl_state
*state
= tevent_req_data(
1678 req
, struct winexe_ctrl_state
);
1681 status
= cli_close_recv(subreq
);
1682 TALLOC_FREE(subreq
);
1683 if (tevent_req_nterror(req
, status
)) {
1687 state
->ctrl_pipe_done
= true;
1688 if (state
->pipes_req
== NULL
) {
1689 tevent_req_done(req
);
1693 static void winexe_ctrl_pipes_done(struct tevent_req
*subreq
)
1695 struct tevent_req
*req
= tevent_req_callback_data(
1696 subreq
, struct tevent_req
);
1697 struct winexe_ctrl_state
*state
= tevent_req_data(
1698 req
, struct winexe_ctrl_state
);
1701 status
= winexe_pipes_recv(subreq
);
1702 TALLOC_FREE(subreq
);
1703 if (tevent_req_nterror(req
, status
)) {
1707 state
->pipes_req
= NULL
;
1708 if (state
->ctrl_pipe_done
) {
1709 tevent_req_done(req
);
1713 static NTSTATUS
winexe_ctrl_recv(struct tevent_req
*req
,
1716 struct winexe_ctrl_state
*state
= tevent_req_data(
1717 req
, struct winexe_ctrl_state
);
1720 if (tevent_req_is_nterror(req
, &status
)) {
1723 if (preturn_code
!= NULL
) {
1724 *preturn_code
= state
->return_code
;
1726 return NT_STATUS_OK
;
1729 static NTSTATUS
winexe_ctrl(struct cli_state
*cli
,
1733 struct tevent_context
*ev
= NULL
;
1734 struct tevent_req
*req
= NULL
;
1735 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1738 ev
= samba_tevent_context_init(cli
);
1742 req
= winexe_ctrl_send(ev
, ev
, cli
, cmd
);
1746 ok
= tevent_req_poll_ntstatus(req
, ev
, &status
);
1750 status
= winexe_ctrl_recv(req
, preturn_code
);
1757 #ifdef HAVE_WINEXE_CC_WIN32
1758 const DATA_BLOB
*winexesvc32_exe_binary(void);
1761 #ifdef HAVE_WINEXE_CC_WIN64
1762 const DATA_BLOB
*winexesvc64_exe_binary(void);
1765 int main(int argc
, const char *argv
[])
1767 TALLOC_CTX
*frame
= talloc_stackframe();
1768 struct program_options options
= {0};
1769 struct loadparm_context
*lp_ctx
;
1770 struct cli_state
*cli
;
1771 const char *service_name
= SERVICE_NAME
;
1772 char *service_filename
= NULL
;
1773 #ifdef HAVE_WINEXE_CC_WIN32
1774 const DATA_BLOB
*winexesvc32_exe
= winexesvc32_exe_binary();
1776 const DATA_BLOB
*winexesvc32_exe
= NULL
;
1778 #ifdef HAVE_WINEXE_CC_WIN64
1779 const DATA_BLOB
*winexesvc64_exe
= winexesvc64_exe_binary();
1781 const DATA_BLOB
*winexesvc64_exe
= NULL
;
1785 int return_code
= 0;
1787 lp_ctx
= loadparm_init_s3(frame
, loadparm_s3_helpers());
1788 if (lp_ctx
== NULL
) {
1789 fprintf(stderr
, "loadparm_init_s3 failed\n");
1794 setup_logging("winexe", DEBUG_STDOUT
);
1796 lp_load_global(get_dyn_CONFIGFILE());
1798 parse_args(argc
, argv
, frame
, &options
, lp_ctx
);
1800 if (options
.cmd
== NULL
) {
1801 fprintf(stderr
, "no cmd given\n");
1805 service_filename
= talloc_asprintf(frame
, "%s.exe", service_name
);
1806 if (service_filename
== NULL
) {
1807 DBG_WARNING("talloc_asprintf failed\n");
1811 status
= cli_full_connection_creds(
1819 options
.credentials
,
1823 if (!NT_STATUS_IS_OK(status
)) {
1824 DBG_WARNING("cli_full_connection_creds failed: %s\n",
1829 status
= winexe_svc_install(
1836 options
.credentials
,
1838 if (!NT_STATUS_IS_OK(status
)) {
1839 DBG_WARNING("winexe_svc_install failed: %s\n",
1844 status
= winexe_ctrl(cli
, options
.cmd
, &return_code
);
1845 if (NT_STATUS_EQUAL(status
, NT_STATUS_PIPE_DISCONNECTED
)) {
1847 status
= NT_STATUS_OK
;
1849 if (!NT_STATUS_IS_OK(status
)) {
1850 DBG_WARNING("cli_ctrl failed: %s\n",
1855 if (options
.flags
& SVC_UNINSTALL
) {
1856 status
= winexe_svc_uninstall(
1859 if (!NT_STATUS_IS_OK(status
)) {
1860 DBG_WARNING("winexe_svc_uninstall failed: %s\n",