429ba2f5163e60705d98890c6eb598bcbbb1a44f
[metze/samba/wip.git] / examples / winexe / winexe.c
1 /*
2  * Samba Unix/Linux CIFS implementation
3  *
4  * winexe
5  *
6  * Copyright (C) 2018 Volker Lendecke <vl@samba.org>
7  *
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.
12  *
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.
17  *
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/>.
20  */
21
22 #include "includes.h"
23 #include <tevent.h>
24 #include <popt.h>
25 #include "version.h"
26 #include "lib/param/param.h"
27 #include "auth/credentials/credentials.h"
28 #include "lib/util/talloc_stack.h"
29 #include "lib/util/tevent_ntstatus.h"
30 #include "lib/util/sys_rw.h"
31 #include "libsmb/proto.h"
32 #include "librpc/gen_ndr/ndr_svcctl_c.h"
33 #include "rpc_client/cli_pipe.h"
34 #include "libcli/smb/smbXcli_base.h"
35 #include "libcli/util/werror.h"
36 #include "lib/async_req/async_sock.h"
37 #include "client.h"
38
39 #define SVC_INTERACTIVE 1
40 #define SVC_IGNORE_INTERACTIVE 2
41 #define SVC_INTERACTIVE_MASK 3
42 #define SVC_FORCE_UPLOAD 4
43 #define SVC_OS64BIT 8
44 #define SVC_OSCHOOSE 16
45 #define SVC_UNINSTALL 32
46 #define SVC_SYSTEM 64
47
48 #define SERVICE_NAME "winexesvc"
49
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"
54
55 static const char version_message_fmt[] = "winexe version %d.%d\n"
56         "This program may be freely redistributed under the terms of the "
57         "GNU GPLv3\n";
58
59 struct program_options {
60         char *hostname;
61         char *cmd;
62         struct cli_credentials *credentials;
63         char *runas;
64         char *runas_file;
65         int flags;
66 };
67
68 static void parse_args(int argc, const char *argv[],
69                        TALLOC_CTX *mem_ctx,
70                        struct program_options *options,
71                        struct loadparm_context *lp_ctx)
72 {
73         poptContext pc;
74         int opt, i;
75         struct cli_credentials *cred;
76
77         int argc_new;
78         char **argv_new;
79
80         int flag_interactive = SVC_IGNORE_INTERACTIVE;
81         int flag_ostype = 2;
82         int flag_reinstall = 0;
83         int flag_uninstall = 0;
84         int flag_help = 0;
85         int flag_version = 0;
86         int flag_nopass = 0;
87         char *opt_user = NULL;
88         char *opt_kerberos = NULL;
89         char *opt_auth_file = NULL;
90         char *opt_debuglevel = NULL;
91
92         struct poptOption long_options[] = {
93                 { "help", 'h', POPT_ARG_NONE, &flag_help, 0,
94                   "Display help message" },
95                 { "version", 'V', POPT_ARG_NONE, &flag_version, 0,
96                   "Display version number" },
97                 { "user", 'U', POPT_ARG_STRING, &opt_user, 0,
98                   "Set the network username", "[DOMAIN/]USERNAME[%PASSWORD]" },
99                 { "authentication-file", 'A',
100                   POPT_ARG_STRING, &opt_auth_file, 0,
101                   "Get the credentials from a file", "FILE" },
102                 { "no-pass", 'N', POPT_ARG_NONE, &flag_nopass, 0,
103                   "Do not ask for a password", NULL },
104                 { "kerberos", 'k', POPT_ARG_STRING, &opt_kerberos, 0,
105                   "Use Kerberos, -k [yes|no]" },
106                 { "debuglevel", 'd', POPT_ARG_STRING, &opt_debuglevel, 0,
107                   "Set debug level", "DEBUGLEVEL" },
108                 { "uninstall", 0, POPT_ARG_NONE, &flag_uninstall, 0,
109                   "Uninstall winexe service after remote execution", NULL},
110                 { "reinstall", 0, POPT_ARG_NONE, &flag_reinstall, 0,
111                   "Reinstall winexe service before remote execution", NULL},
112                 { "runas", 0, POPT_ARG_STRING, &options->runas, 0,
113                   "Run as the given user (BEWARE: this password is sent "
114                   "in cleartext over the network!)",
115                   "[DOMAIN\\]USERNAME%PASSWORD"},
116                 { "runas-file", 0, POPT_ARG_STRING, &options->runas_file, 0,
117                   "Run as user options defined in a file", "FILE"},
118                 { "interactive", 0, POPT_ARG_INT, &flag_interactive, 0,
119                   "Desktop interaction: 0 - disallow, 1 - allow. If allow, "
120                   "also use the --system switch (Windows requirement). Vista "
121                   "does not support this option.", "0|1"},
122                 { "ostype", 0, POPT_ARG_INT, &flag_ostype, 0,
123                   "OS type: 0 - 32-bit, 1 - 64-bit, 2 - winexe will decide. "
124                   "Determines which version (32-bit or 64-bit) of service "
125                   "will be installed.", "0|1|2"},
126                 POPT_TABLEEND
127         };
128
129         ZERO_STRUCTP(options);
130
131         pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,
132                             0);
133
134         poptSetOtherOptionHelp(pc, "[OPTION]... //HOST COMMAND\nOptions:");
135
136         if (((opt = poptGetNextOpt(pc)) != -1) || flag_help || flag_version) {
137                 fprintf(stderr, version_message_fmt, SAMBA_VERSION_MAJOR,
138                         SAMBA_VERSION_MINOR);
139                 if (flag_version) {
140                         exit(0);
141                 }
142                 poptPrintHelp(pc, stdout, 0);
143                 if (flag_help) {
144                         exit(0);
145                 }
146                 exit(1);
147         }
148
149         argv_new = discard_const_p(char *, poptGetArgs(pc));
150
151         argc_new = argc;
152         for (i = 0; i < argc; i++) {
153                 if (!argv_new || argv_new[i] == NULL) {
154                         argc_new = i;
155                         break;
156                 }
157         }
158
159         if (argc_new != 2 || argv_new[0][0] != '/' || argv_new[0][1] != '/') {
160                 fprintf(stderr, version_message_fmt, SAMBA_VERSION_MAJOR,
161                         SAMBA_VERSION_MINOR);
162                 poptPrintHelp(pc, stdout, 0);
163                 exit(1);
164         }
165
166         if (opt_debuglevel) {
167                 lp_set_cmdline("log level", opt_debuglevel);
168         }
169
170         cred = cli_credentials_init(mem_ctx);
171
172         if (opt_user) {
173                 cli_credentials_parse_string(cred, opt_user, CRED_SPECIFIED);
174         } else if (opt_auth_file) {
175                 cli_credentials_parse_file(cred, opt_auth_file,
176                                            CRED_SPECIFIED);
177         }
178
179         cli_credentials_guess(cred, lp_ctx);
180         if (!cli_credentials_get_password(cred) && !flag_nopass) {
181                 char *p = getpass("Enter password: ");
182                 if (*p) {
183                         cli_credentials_set_password(cred, p, CRED_SPECIFIED);
184                 }
185         }
186
187         if (opt_kerberos) {
188                 cli_credentials_set_kerberos_state(cred,
189                                                    strcmp(opt_kerberos, "yes")
190                                                    ? CRED_MUST_USE_KERBEROS
191                                                    : CRED_DONT_USE_KERBEROS);
192         }
193
194         if (options->runas == NULL && options->runas_file != NULL) {
195                 struct cli_credentials *runas_cred;
196                 const char *user;
197                 const char *pass;
198
199                 runas_cred = cli_credentials_init(mem_ctx);
200                 cli_credentials_parse_file(runas_cred, options->runas_file,
201                                            CRED_SPECIFIED);
202
203                 user = cli_credentials_get_username(runas_cred);
204                 pass = cli_credentials_get_password(runas_cred);
205
206                 if (user && pass) {
207                         char buffer[1024];
208                         const char *dom;
209
210                         dom = cli_credentials_get_domain(runas_cred);
211                         if (dom) {
212                                 snprintf(buffer, sizeof(buffer), "%s\\%s%%%s",
213                                          dom, user, pass);
214                         } else {
215                                 snprintf(buffer, sizeof(buffer), "%s%%%s",
216                                          user, pass);
217                         }
218                         buffer[sizeof(buffer)-1] = '\0';
219                         options->runas = talloc_strdup(mem_ctx, buffer);
220                 }
221         }
222
223         options->credentials = cred;
224
225         options->hostname = argv_new[0] + 2;
226         options->cmd = argv_new[1];
227
228         options->flags = flag_interactive;
229         if (flag_reinstall) {
230                 options->flags |= SVC_FORCE_UPLOAD;
231         }
232         if (flag_ostype == 1) {
233                 options->flags |= SVC_OS64BIT;
234         }
235         if (flag_ostype == 2) {
236                 options->flags |= SVC_OSCHOOSE;
237         }
238         if (flag_uninstall) {
239                 options->flags |= SVC_UNINSTALL;
240         }
241 }
242
243 static NTSTATUS winexe_svc_upload(
244         const char *hostname,
245         const char *service_filename,
246         const DATA_BLOB *svc32_exe,
247         const DATA_BLOB *svc64_exe,
248         struct cli_credentials *credentials,
249         int flags)
250 {
251         struct cli_state *cli;
252         uint16_t fnum;
253         NTSTATUS status;
254         const DATA_BLOB *binary = NULL;
255
256         status = cli_full_connection_creds(
257                 &cli,
258                 NULL,
259                 hostname,
260                 NULL,
261                 445,
262                 "ADMIN$",
263                 "?????",
264                 credentials,
265                 0,
266                 0);
267         if (!NT_STATUS_IS_OK(status)) {
268                 DBG_WARNING("cli_full_connection_creds failed: %s\n",
269                             nt_errstr(status));
270                 return status;
271         }
272
273         if (flags & SVC_FORCE_UPLOAD) {
274                 status = cli_unlink(cli, service_filename, 0);
275                 if (!NT_STATUS_IS_OK(status)) {
276                         DBG_WARNING("cli_unlink failed: %s\n",
277                                     nt_errstr(status));
278                 }
279         }
280
281         if (flags & SVC_OSCHOOSE) {
282                 status = cli_chkpath(cli, "SysWoW64");
283                 if (NT_STATUS_IS_OK(status)) {
284                         flags |= SVC_OS64BIT;
285                 }
286         }
287
288         if (flags & SVC_OS64BIT) {
289                 binary = svc64_exe;
290         } else {
291                 binary = svc32_exe;
292         }
293
294         if (binary == NULL) {
295                 //TODO
296         }
297
298         status = cli_ntcreate(
299                 cli,
300                 service_filename,
301                 0,                      /* CreatFlags */
302                 SEC_FILE_WRITE_DATA,    /* DesiredAccess */
303                 FILE_ATTRIBUTE_NORMAL,  /* FileAttributes */
304                 FILE_SHARE_WRITE|FILE_SHARE_READ, /* ShareAccess */
305                 FILE_OPEN_IF,            /* CreateDisposition */
306                 FILE_NON_DIRECTORY_FILE, /* CreateOptions */
307                 0,                       /* SecurityFlags */
308                 &fnum,
309                 NULL);          /* CreateReturns */
310         if (!NT_STATUS_IS_OK(status)) {
311                 DBG_WARNING("Could not create %s: %s\n", service_filename,
312                             nt_errstr(status));
313                 goto done;
314         }
315
316         status = cli_writeall(
317                 cli,
318                 fnum,
319                 0,
320                 binary->data,
321                 0,
322                 binary->length,
323                 NULL);
324         if (!NT_STATUS_IS_OK(status)) {
325                 DBG_WARNING("Could not write file: %s\n", nt_errstr(status));
326                 goto close_done;
327         }
328
329 close_done:
330         status = cli_close(cli, fnum);
331         if (!NT_STATUS_IS_OK(status)) {
332                 DBG_WARNING("Close(%"PRIu16") failed for %s: %s\n", fnum,
333                             service_filename, nt_errstr(status));
334         }
335 done:
336         TALLOC_FREE(cli);
337         return status;
338 }
339
340 static NTSTATUS winexe_svc_install(
341         struct cli_state *cli,
342         const char *hostname,
343         const char *service_name,
344         const char *service_filename,
345         const DATA_BLOB *svc32_exe,
346         const DATA_BLOB *svc64_exe,
347         struct cli_credentials *credentials,
348         int flags)
349 {
350         TALLOC_CTX *frame = talloc_stackframe();
351         struct rpc_pipe_client *rpccli;
352         struct policy_handle scmanager_handle;
353         struct policy_handle service_handle;
354         struct SERVICE_STATUS service_status;
355         bool need_start = false;
356         bool need_conf = false;
357         NTSTATUS status;
358         WERROR werr;
359
360         status = cli_rpc_pipe_open_noauth_transport(
361                 cli,
362                 NCACN_NP,
363                 &ndr_table_svcctl,
364                 &rpccli);
365         if (!NT_STATUS_IS_OK(status)) {
366                 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
367                             nt_errstr(status));
368                 goto done;
369         }
370
371         status = dcerpc_svcctl_OpenSCManagerW(
372                 rpccli->binding_handle,
373                 frame,
374                 smbXcli_conn_remote_name(cli->conn),
375                 NULL,
376                 SEC_FLAG_MAXIMUM_ALLOWED,
377                 &scmanager_handle,
378                 &werr);
379         if (!NT_STATUS_IS_OK(status)) {
380                 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
381                             nt_errstr(status));
382                 goto done;
383         }
384         if (!W_ERROR_IS_OK(werr)) {
385                 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
386                             win_errstr(werr));
387                 goto done;
388         }
389
390         status = dcerpc_svcctl_OpenServiceW(
391                 rpccli->binding_handle,
392                 frame,
393                 &scmanager_handle,
394                 service_name,
395                 SERVICE_ALL_ACCESS,
396                 &service_handle,
397                 &werr);
398         if (!NT_STATUS_IS_OK(status)) {
399                 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
400                             nt_errstr(status));
401                 goto close_scmanager;
402         }
403
404         if (W_ERROR_EQUAL(werr,  WERR_SERVICE_DOES_NOT_EXIST)) {
405                 status = dcerpc_svcctl_CreateServiceW(
406                         rpccli->binding_handle,
407                         frame,
408                         &scmanager_handle,
409                         service_name,
410                         NULL,
411                         SERVICE_ALL_ACCESS,
412                         SERVICE_TYPE_WIN32_OWN_PROCESS |
413                         ((flags & SVC_INTERACTIVE) ?
414                          SERVICE_TYPE_INTERACTIVE_PROCESS : 0),
415                         SVCCTL_DEMAND_START,
416                         SVCCTL_SVC_ERROR_NORMAL,
417                         service_filename,
418                         NULL,
419                         NULL,
420                         NULL,
421                         0,
422                         NULL,
423                         NULL,
424                         0,
425                         &service_handle,
426                         &werr);
427                 if (!NT_STATUS_IS_OK(status)) {
428                         DBG_WARNING("dcerpc_svcctl_CreateServiceW "
429                                     "failed: %s\n", nt_errstr(status));
430                         goto close_scmanager;
431                 }
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;
437                 }
438         }
439
440         status = dcerpc_svcctl_QueryServiceStatus(
441                 rpccli->binding_handle,
442                 frame,
443                 &service_handle,
444                 &service_status,
445                 &werr);
446
447         if (!NT_STATUS_IS_OK(status)) {
448                 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
449                             "failed: %s\n", nt_errstr(status));
450                 goto close_service;
451         }
452         if (!W_ERROR_IS_OK(werr)) {
453                 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
454                             "failed: %s\n", win_errstr(werr));
455                 status = werror_to_ntstatus(werr);
456                 goto close_service;
457         }
458
459         if (!(flags & SVC_IGNORE_INTERACTIVE)) {
460                 need_conf =
461                         !(service_status.type &
462                           SERVICE_TYPE_INTERACTIVE_PROCESS) ^
463                         !(flags & SVC_INTERACTIVE);
464         }
465
466         if (service_status.state == SVCCTL_STOPPED) {
467                 need_start = true;
468         } else if (need_conf) {
469                 status = dcerpc_svcctl_ControlService(
470                         rpccli->binding_handle,
471                         frame,
472                         &service_handle,
473                         SVCCTL_CONTROL_STOP,
474                         &service_status,
475                         &werr);
476
477                 if (!NT_STATUS_IS_OK(status)) {
478                         DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
479                             "failed: %s\n", nt_errstr(status));
480                         goto close_service;
481                 }
482                 if (!W_ERROR_IS_OK(werr)) {
483                         DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
484                                     "failed: %s\n", win_errstr(werr));
485                         status = werror_to_ntstatus(werr);
486                         goto close_service;
487                 }
488
489                 do {
490                         smb_msleep(100);
491
492                         status = dcerpc_svcctl_QueryServiceStatus(
493                                 rpccli->binding_handle,
494                                 frame,
495                                 &service_handle,
496                                 &service_status,
497                                 &werr);
498
499                         if (!NT_STATUS_IS_OK(status)) {
500                                 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
501                                             "failed: %s\n", nt_errstr(status));
502                                 goto close_service;
503                         }
504                         if (!W_ERROR_IS_OK(werr)) {
505                                 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
506                                             "failed: %s\n", win_errstr(werr));
507                                 status = werror_to_ntstatus(werr);
508                                 goto close_service;
509                         }
510                 } while (service_status.state == SVCCTL_STOP_PENDING);
511
512                 need_start = 1;
513         }
514
515         if (need_conf) {
516                 status = dcerpc_svcctl_ChangeServiceConfigW(
517                         rpccli->binding_handle,
518                         frame,
519                         &service_handle,
520                         SERVICE_TYPE_WIN32_OWN_PROCESS |
521                         ((flags & SVC_INTERACTIVE) ?
522                          SERVICE_TYPE_INTERACTIVE_PROCESS : 0), /* type */
523                         UINT32_MAX, /* start_type, SERVICE_NO_CHANGE */
524                         UINT32_MAX, /* error_control, SERVICE_NO_CHANGE */
525                         NULL,       /* binary_path */
526                         NULL,       /* load_order_group */
527                         NULL,       /* tag_id */
528                         NULL,       /* dependencies */
529                         NULL,       /* service_start_name */
530                         NULL,       /* password */
531                         NULL,       /* display_name */
532                         &werr);
533
534                 if (!NT_STATUS_IS_OK(status)) {
535                         DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
536                                     "failed: %s\n", nt_errstr(status));
537                         goto close_service;
538                 }
539                 if (!W_ERROR_IS_OK(werr)) {
540                         DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
541                                     "failed: %s\n", win_errstr(werr));
542                         status = werror_to_ntstatus(werr);
543                         goto close_service;
544                 }
545         }
546
547         if (need_start) {
548                 status = winexe_svc_upload(
549                         hostname,
550                         service_filename,
551                         svc32_exe,
552                         svc64_exe,
553                         credentials,
554                         flags);
555                 if (!NT_STATUS_IS_OK(status)) {
556                         DBG_WARNING("winexe_svc_upload failed: %s\n",
557                                     nt_errstr(status));
558                         goto close_service;
559                 }
560
561                 status = dcerpc_svcctl_StartServiceW(
562                         rpccli->binding_handle,
563                         frame,
564                         &service_handle,
565                         0,      /* num_args */
566                         NULL,   /* arguments */
567                         &werr);
568
569                 if (!NT_STATUS_IS_OK(status)) {
570                         DBG_WARNING("dcerpc_svcctl_StartServiceW "
571                                     "failed: %s\n", nt_errstr(status));
572                         goto close_service;
573                 }
574                 if (!W_ERROR_IS_OK(werr)) {
575                         DBG_WARNING("dcerpc_svcctl_StartServiceW "
576                                     "failed: %s\n", win_errstr(werr));
577                         status = werror_to_ntstatus(werr);
578                         goto close_service;
579                 }
580
581                 do {
582                         smb_msleep(100);
583
584                         status = dcerpc_svcctl_QueryServiceStatus(
585                                 rpccli->binding_handle,
586                                 frame,
587                                 &service_handle,
588                                 &service_status,
589                                 &werr);
590
591                         if (!NT_STATUS_IS_OK(status)) {
592                                 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
593                                             "failed: %s\n", nt_errstr(status));
594                                 goto close_service;
595                         }
596                         if (!W_ERROR_IS_OK(werr)) {
597                                 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
598                                             "failed: %s\n", win_errstr(werr));
599                                 status = werror_to_ntstatus(werr);
600                                 goto close_service;
601                         }
602                 } while (service_status.state == SVCCTL_START_PENDING);
603
604                 if (service_status.state != SVCCTL_RUNNING) {
605                         DBG_WARNING("Failed to start service\n");
606                         status = NT_STATUS_UNSUCCESSFUL;
607                         goto close_service;
608                 }
609         }
610
611 close_service:
612         {
613                 NTSTATUS close_status;
614                 WERROR close_werr;
615
616                 close_status = dcerpc_svcctl_CloseServiceHandle(
617                         rpccli->binding_handle,
618                         frame,
619                         &service_handle,
620                         &close_werr);
621                 if (!NT_STATUS_IS_OK(close_status)) {
622                         DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
623                                     "failed: %s\n", nt_errstr(close_status));
624                         goto done;
625                 }
626                 if (!W_ERROR_IS_OK(close_werr)) {
627                         DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
628                                     " failed: %s\n", win_errstr(close_werr));
629                         goto done;
630                 }
631         }
632
633 close_scmanager:
634         {
635                 NTSTATUS close_status;
636                 WERROR close_werr;
637
638                 close_status = dcerpc_svcctl_CloseServiceHandle(
639                         rpccli->binding_handle,
640                         frame,
641                         &scmanager_handle,
642                         &close_werr);
643                 if (!NT_STATUS_IS_OK(close_status)) {
644                         DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
645                                     "failed: %s\n", nt_errstr(close_status));
646                         goto done;
647                 }
648                 if (!W_ERROR_IS_OK(close_werr)) {
649                         DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
650                                     " failed: %s\n", win_errstr(close_werr));
651                         goto done;
652                 }
653         }
654
655 done:
656         TALLOC_FREE(rpccli);
657         TALLOC_FREE(frame);
658         return status;
659 }
660
661 static NTSTATUS winexe_svc_uninstall(
662         struct cli_state *cli,
663         const char *service_name)
664 {
665         TALLOC_CTX *frame = talloc_stackframe();
666         struct rpc_pipe_client *rpccli;
667         struct policy_handle scmanager_handle;
668         struct policy_handle service_handle;
669         struct SERVICE_STATUS service_status;
670         NTSTATUS status;
671         WERROR werr;
672
673         status = cli_rpc_pipe_open_noauth_transport(
674                 cli,
675                 NCACN_NP,
676                 &ndr_table_svcctl,
677                 &rpccli);
678         if (!NT_STATUS_IS_OK(status)) {
679                 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
680                             nt_errstr(status));
681                 goto done;
682         }
683
684         status = dcerpc_svcctl_OpenSCManagerW(
685                 rpccli->binding_handle,
686                 frame,
687                 smbXcli_conn_remote_name(cli->conn),
688                 NULL,
689                 SEC_FLAG_MAXIMUM_ALLOWED,
690                 &scmanager_handle,
691                 &werr);
692         if (!NT_STATUS_IS_OK(status)) {
693                 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
694                             nt_errstr(status));
695                 goto done;
696         }
697         if (!W_ERROR_IS_OK(werr)) {
698                 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
699                             win_errstr(werr));
700                 goto done;
701         }
702
703         status = dcerpc_svcctl_OpenServiceW(
704                 rpccli->binding_handle,
705                 frame,
706                 &scmanager_handle,
707                 service_name,
708                 SERVICE_ALL_ACCESS,
709                 &service_handle,
710                 &werr);
711         if (!NT_STATUS_IS_OK(status)) {
712                 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
713                             nt_errstr(status));
714                 goto close_scmanager;
715         }
716         if (!W_ERROR_IS_OK(werr)) {
717                 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
718                             win_errstr(werr));
719                 status = werror_to_ntstatus(werr);
720                 goto close_scmanager;
721         }
722
723         status = dcerpc_svcctl_ControlService(
724                 rpccli->binding_handle,
725                 frame,
726                 &service_handle,
727                 SVCCTL_CONTROL_STOP,
728                 &service_status,
729                 &werr);
730         if (!NT_STATUS_IS_OK(status)) {
731                 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
732                             "failed: %s\n", nt_errstr(status));
733                 goto close_service;
734         }
735         if (!W_ERROR_IS_OK(werr)) {
736                 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
737                             "failed: %s\n", win_errstr(werr));
738                 status = werror_to_ntstatus(werr);
739                 goto close_service;
740         }
741
742         do {
743                 smb_msleep(100);
744
745                 status = dcerpc_svcctl_QueryServiceStatus(
746                         rpccli->binding_handle,
747                         frame,
748                         &service_handle,
749                         &service_status,
750                         &werr);
751
752                 if (!NT_STATUS_IS_OK(status)) {
753                         DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
754                                     "failed: %s\n", nt_errstr(status));
755                         goto close_service;
756                 }
757                 if (!W_ERROR_IS_OK(werr)) {
758                         DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
759                                     "failed: %s\n", win_errstr(werr));
760                         status = werror_to_ntstatus(werr);
761                         goto close_service;
762                 }
763         } while (service_status.state != SVCCTL_STOPPED);
764
765         status = dcerpc_svcctl_DeleteService(
766                 rpccli->binding_handle,
767                 frame,
768                 &service_handle,
769                 &werr);
770         if (!NT_STATUS_IS_OK(status)) {
771                 DBG_WARNING("dcerpc_svcctl_DeleteService "
772                             "failed: %s\n", nt_errstr(status));
773                 goto close_service;
774         }
775         if (!W_ERROR_IS_OK(werr)) {
776                 DBG_WARNING("dcerpc_svcctl_DeleteService "
777                             "failed: %s\n", win_errstr(werr));
778                 status = werror_to_ntstatus(werr);
779                 goto close_service;
780         }
781
782 close_service:
783         {
784                 NTSTATUS close_status;
785                 WERROR close_werr;
786
787                 close_status = dcerpc_svcctl_CloseServiceHandle(
788                         rpccli->binding_handle,
789                         frame,
790                         &service_handle,
791                         &close_werr);
792                 if (!NT_STATUS_IS_OK(close_status)) {
793                         DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
794                                     "failed: %s\n", nt_errstr(close_status));
795                         goto done;
796                 }
797                 if (!W_ERROR_IS_OK(close_werr)) {
798                         DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
799                                     " failed: %s\n", win_errstr(close_werr));
800                         goto done;
801                 }
802         }
803
804 close_scmanager:
805         {
806                 NTSTATUS close_status;
807                 WERROR close_werr;
808
809                 close_status = dcerpc_svcctl_CloseServiceHandle(
810                         rpccli->binding_handle,
811                         frame,
812                         &scmanager_handle,
813                         &close_werr);
814                 if (!NT_STATUS_IS_OK(close_status)) {
815                         DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
816                                     "failed: %s\n", nt_errstr(close_status));
817                         goto done;
818                 }
819                 if (!W_ERROR_IS_OK(close_werr)) {
820                         DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
821                                     " failed: %s\n", win_errstr(close_werr));
822                         goto done;
823                 }
824         }
825
826 done:
827         TALLOC_FREE(rpccli);
828         TALLOC_FREE(frame);
829         return status;
830 }
831
832 struct winexe_out_pipe_state {
833         struct tevent_context *ev;
834         struct cli_state *cli;
835         uint16_t out_pipe;
836         int out_fd;
837         char out_inbuf[256];
838 };
839
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);
843
844 static struct tevent_req *winexe_out_pipe_send(
845         TALLOC_CTX *mem_ctx,
846         struct tevent_context *ev,
847         struct cli_state *cli,
848         const char *pipe_name,
849         int out_fd)
850 {
851         struct tevent_req *req, *subreq;
852         struct winexe_out_pipe_state *state;
853
854         req = tevent_req_create(mem_ctx, &state,
855                                 struct winexe_out_pipe_state);
856         if (req == NULL) {
857                 return NULL;
858         }
859         state->ev = ev;
860         state->cli = cli;
861         state->out_fd = out_fd;
862
863         subreq = cli_ntcreate_send(
864                 state,
865                 state->ev,
866                 state->cli,
867                 pipe_name,
868                 0,
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);
879         }
880         tevent_req_set_callback(subreq, winexe_out_pipe_opened, req);
881         return req;
882 }
883
884 static void winexe_out_pipe_opened(struct tevent_req *subreq)
885 {
886         struct tevent_req *req = tevent_req_callback_data(
887                 subreq, struct tevent_req);
888         struct winexe_out_pipe_state *state = tevent_req_data(
889                 req, struct winexe_out_pipe_state);
890         int timeout;
891         NTSTATUS status;
892
893         status = cli_ntcreate_recv(subreq, &state->out_pipe, NULL);
894         TALLOC_FREE(subreq);
895         if (tevent_req_nterror(req, status)) {
896                 return;
897         }
898
899         timeout = state->cli->timeout;
900         state->cli->timeout = 0;
901
902         subreq = cli_read_send(
903                 state,
904                 state->ev,
905                 state->cli,
906                 state->out_pipe,
907                 state->out_inbuf,
908                 0,
909                 sizeof(state->out_inbuf));
910
911         state->cli->timeout = timeout;
912
913         if (tevent_req_nomem(subreq, req)) {
914                 return;
915         }
916         tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
917 }
918
919 static void winexe_out_pipe_got_data(struct tevent_req *subreq)
920 {
921         struct tevent_req *req = tevent_req_callback_data(
922                 subreq, struct tevent_req);
923         struct winexe_out_pipe_state *state = tevent_req_data(
924                 req, struct winexe_out_pipe_state);
925         NTSTATUS status;
926         int timeout;
927         size_t received;
928         ssize_t written;
929
930         status = cli_read_recv(subreq, &received);
931         TALLOC_FREE(subreq);
932
933         DBG_DEBUG("cli_read for %d gave %s\n",
934                   state->out_fd,
935                   nt_errstr(status));
936
937         if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
938                 subreq = cli_close_send(
939                         state,
940                         state->ev,
941                         state->cli,
942                         state->out_pipe);
943                 if (tevent_req_nomem(subreq, req)) {
944                         return;
945                 }
946                 tevent_req_set_callback(subreq, winexe_out_pipe_closed, req);
947                 return;
948         }
949
950         if (tevent_req_nterror(req, status)) {
951                 return;
952         }
953
954         if (received > 0) {
955                 written = sys_write(state->out_fd, state->out_inbuf, received);
956                 if (written == -1) {
957                         tevent_req_nterror(req, map_nt_error_from_unix(errno));
958                         return;
959                 }
960         }
961
962         timeout = state->cli->timeout;
963         state->cli->timeout = 0;
964
965         subreq = cli_read_send(
966                 state,
967                 state->ev,
968                 state->cli,
969                 state->out_pipe,
970                 state->out_inbuf,
971                 0,
972                 sizeof(state->out_inbuf));
973
974         state->cli->timeout = timeout;
975
976         if (tevent_req_nomem(subreq, req)) {
977                 return;
978         }
979         tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
980 }
981
982 static void winexe_out_pipe_closed(struct tevent_req *subreq)
983 {
984         struct tevent_req *req = tevent_req_callback_data(
985                 subreq, struct tevent_req);
986         NTSTATUS status;
987
988         status = cli_close_recv(subreq);
989         TALLOC_FREE(subreq);
990         if (tevent_req_nterror(req, status)) {
991                 return;
992         }
993         tevent_req_done(req);
994 }
995
996 static NTSTATUS winexe_out_pipe_recv(struct tevent_req *req)
997 {
998         return tevent_req_simple_recv_ntstatus(req);
999 }
1000
1001 struct winexe_in_pipe_state {
1002         struct tevent_context *ev;
1003         struct cli_state *cli;
1004         struct tevent_req *fd_read_req;
1005         bool close_requested;
1006         bool closing;
1007         uint16_t in_pipe;
1008         int in_fd;
1009         char inbuf[256];
1010 };
1011
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);
1016
1017 static struct tevent_req *winexe_in_pipe_send(
1018         TALLOC_CTX *mem_ctx,
1019         struct tevent_context *ev,
1020         struct cli_state *cli,
1021         const char *pipe_name,
1022         int in_fd)
1023 {
1024         struct tevent_req *req, *subreq;
1025         struct winexe_in_pipe_state *state;
1026
1027         req = tevent_req_create(mem_ctx, &state,
1028                                 struct winexe_in_pipe_state);
1029         if (req == NULL) {
1030                 return NULL;
1031         }
1032         state->ev = ev;
1033         state->cli = cli;
1034         state->in_fd = in_fd;
1035
1036         subreq = cli_ntcreate_send(
1037                 state,
1038                 state->ev,
1039                 state->cli,
1040                 pipe_name,
1041                 0,
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);
1052         }
1053         tevent_req_set_callback(subreq, winexe_in_pipe_opened, req);
1054         return req;
1055 }
1056
1057 static void winexe_in_pipe_opened(struct tevent_req *subreq)
1058 {
1059         struct tevent_req *req = tevent_req_callback_data(
1060                 subreq, struct tevent_req);
1061         struct winexe_in_pipe_state *state = tevent_req_data(
1062                 req, struct winexe_in_pipe_state);
1063         NTSTATUS status;
1064
1065         status = cli_ntcreate_recv(subreq, &state->in_pipe, NULL);
1066         TALLOC_FREE(subreq);
1067         if (tevent_req_nterror(req, status)) {
1068                 return;
1069         }
1070
1071         subreq = wait_for_read_send(
1072                 state,
1073                 state->ev,
1074                 state->in_fd,
1075                 true);
1076         if (tevent_req_nomem(subreq, req)) {
1077                 return;
1078         }
1079         tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
1080
1081         state->fd_read_req = subreq;
1082 }
1083
1084 static void winexe_in_pipe_got_data(struct tevent_req *subreq)
1085 {
1086         struct tevent_req *req = tevent_req_callback_data(
1087                 subreq, struct tevent_req);
1088         struct winexe_in_pipe_state *state = tevent_req_data(
1089                 req, struct winexe_in_pipe_state);
1090         int err;
1091         bool ok;
1092         int timeout;
1093         ssize_t nread;
1094
1095         ok = wait_for_read_recv(subreq, &err);
1096         TALLOC_FREE(subreq);
1097         if (!ok) {
1098                 tevent_req_nterror(req, map_nt_error_from_unix(err));
1099                 return;
1100         }
1101         state->fd_read_req = NULL;
1102
1103         nread = sys_read(state->in_fd, &state->inbuf, sizeof(state->inbuf));
1104         if (nread == -1) {
1105                 tevent_req_nterror(req, map_nt_error_from_unix(errno));
1106                 return;
1107         }
1108         if (nread == 0) {
1109                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
1110                 return;
1111         }
1112
1113         timeout = state->cli->timeout;
1114         state->cli->timeout = 0;
1115
1116         subreq = cli_writeall_send(
1117                 state,
1118                 state->ev,
1119                 state->cli,
1120                 state->in_pipe,
1121                 0,
1122                 (uint8_t *)state->inbuf,
1123                 0,
1124                 nread);
1125
1126         state->cli->timeout = timeout;
1127
1128         if (tevent_req_nomem(subreq, req)) {
1129                 return;
1130         }
1131         tevent_req_set_callback(subreq, winexe_in_pipe_written, req);
1132 }
1133
1134 static void winexe_in_pipe_written(struct tevent_req *subreq)
1135 {
1136         struct tevent_req *req = tevent_req_callback_data(
1137                 subreq, struct tevent_req);
1138         struct winexe_in_pipe_state *state = tevent_req_data(
1139                 req, struct winexe_in_pipe_state);
1140         NTSTATUS status;
1141
1142         status = cli_writeall_recv(subreq, NULL);
1143         TALLOC_FREE(subreq);
1144
1145         DBG_DEBUG("cli_writeall for %d gave %s\n",
1146                   state->in_fd,
1147                   nt_errstr(status));
1148
1149         if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED) ||
1150             state->close_requested) {
1151                 subreq = cli_close_send(
1152                         state,
1153                         state->ev,
1154                         state->cli,
1155                         state->in_pipe);
1156                 if (tevent_req_nomem(subreq, req)) {
1157                         return;
1158                 }
1159                 tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1160                 state->closing = true;
1161                 return;
1162         }
1163
1164         if (tevent_req_nterror(req, status)) {
1165                 return;
1166         }
1167
1168         subreq = wait_for_read_send(
1169                 state,
1170                 state->ev,
1171                 state->in_fd,
1172                 true);
1173         if (tevent_req_nomem(subreq, req)) {
1174                 return;
1175         }
1176         tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
1177
1178         state->fd_read_req = subreq;
1179 }
1180
1181 static void winexe_in_pipe_closed(struct tevent_req *subreq)
1182 {
1183         struct tevent_req *req = tevent_req_callback_data(
1184                 subreq, struct tevent_req);
1185         NTSTATUS status;
1186
1187         status = cli_close_recv(subreq);
1188         TALLOC_FREE(subreq);
1189         if (tevent_req_nterror(req, status)) {
1190                 return;
1191         }
1192         return tevent_req_done(req);
1193 }
1194
1195 static NTSTATUS winexe_in_pipe_recv(struct tevent_req *req)
1196 {
1197         return tevent_req_simple_recv_ntstatus(req);
1198 }
1199
1200 static bool winexe_in_pipe_close(struct tevent_req *req)
1201 {
1202         struct winexe_in_pipe_state *state = tevent_req_data(
1203                 req, struct winexe_in_pipe_state);
1204         struct tevent_req *subreq;
1205
1206         if (state->closing) {
1207                 return true;
1208         }
1209
1210         if (state->fd_read_req == NULL) {
1211                 /*
1212                  * cli_writeall active, wait for it to return
1213                  */
1214                 state->close_requested = true;
1215                 return true;
1216         }
1217
1218         TALLOC_FREE(state->fd_read_req);
1219
1220         subreq = cli_close_send(
1221                 state,
1222                 state->ev,
1223                 state->cli,
1224                 state->in_pipe);
1225         if (subreq == NULL) {
1226                 return false;
1227         }
1228         tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1229         state->closing = true;
1230
1231         return true;
1232 }
1233
1234 struct winexe_pipes_state {
1235         struct tevent_req *pipes[3];
1236 };
1237
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);
1241
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)
1247 {
1248         struct tevent_req *req;
1249         struct winexe_pipes_state *state;
1250         char *pipe_name;
1251
1252         req = tevent_req_create(mem_ctx, &state, struct winexe_pipes_state);
1253         if (req == NULL) {
1254                 return NULL;
1255         }
1256
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);
1260         }
1261         state->pipes[0] = winexe_in_pipe_send(
1262                 state,
1263                 ev,
1264                 cli,
1265                 pipe_name,
1266                 0);
1267         if (tevent_req_nomem(state->pipes[0], req)) {
1268                 return tevent_req_post(req, ev);
1269         }
1270         tevent_req_set_callback(state->pipes[0], winexe_pipes_stdin_done, req);
1271
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);
1275         }
1276         state->pipes[1] = winexe_out_pipe_send(
1277                 state,
1278                 ev,
1279                 cli,
1280                 pipe_name,
1281                 1);
1282         if (tevent_req_nomem(state->pipes[1], req)) {
1283                 return tevent_req_post(req, ev);
1284         }
1285         tevent_req_set_callback(state->pipes[1], winexe_pipes_stdout_done,
1286                                 req);
1287
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);
1291         }
1292         state->pipes[2] = winexe_out_pipe_send(
1293                 state,
1294                 ev,
1295                 cli,
1296                 pipe_name,
1297                 2);
1298         if (tevent_req_nomem(state->pipes[2], req)) {
1299                 return tevent_req_post(req, ev);
1300         }
1301         tevent_req_set_callback(state->pipes[2], winexe_pipes_stderr_done,
1302                                 req);
1303
1304         DBG_DEBUG("pipes = %p %p %p\n",
1305                   state->pipes[0],
1306                   state->pipes[1],
1307                   state->pipes[2]);
1308
1309         return req;
1310 }
1311
1312 static void winexe_pipes_stdin_done(struct tevent_req *subreq)
1313 {
1314         struct tevent_req *req = tevent_req_callback_data(
1315                 subreq, struct tevent_req);
1316         struct winexe_pipes_state *state = tevent_req_data(
1317                 req, struct winexe_pipes_state);
1318         NTSTATUS status;
1319
1320         status = winexe_in_pipe_recv(subreq);
1321         TALLOC_FREE(subreq);
1322
1323         DBG_DEBUG("stdin returned %s\n", nt_errstr(status));
1324
1325         if (tevent_req_nterror(req, status)) {
1326                 return;
1327         }
1328
1329         state->pipes[0] = NULL;
1330
1331         DBG_DEBUG("pipes = %p %p %p\n",
1332                   state->pipes[0],
1333                   state->pipes[1],
1334                   state->pipes[2]);
1335
1336         if ((state->pipes[1] == NULL) && (state->pipes[2] == NULL)) {
1337                 tevent_req_done(req);
1338         }
1339 }
1340
1341 static void winexe_pipes_stdout_done(struct tevent_req *subreq)
1342 {
1343         struct tevent_req *req = tevent_req_callback_data(
1344                 subreq, struct tevent_req);
1345         struct winexe_pipes_state *state = tevent_req_data(
1346                 req, struct winexe_pipes_state);
1347         NTSTATUS status;
1348
1349         status = winexe_out_pipe_recv(subreq);
1350         TALLOC_FREE(subreq);
1351
1352         DBG_DEBUG("stdout returned %s\n", nt_errstr(status));
1353
1354         if (tevent_req_nterror(req, status)) {
1355                 return;
1356         }
1357
1358         if (state->pipes[0] != NULL) {
1359                 winexe_in_pipe_close(state->pipes[0]);
1360         }
1361
1362         state->pipes[1] = NULL;
1363
1364         DBG_DEBUG("pipes = %p %p %p\n",
1365                   state->pipes[0],
1366                   state->pipes[1],
1367                   state->pipes[2]);
1368
1369         if ((state->pipes[0] == NULL) && (state->pipes[2] == NULL)) {
1370                 tevent_req_done(req);
1371         }
1372 }
1373
1374 static void winexe_pipes_stderr_done(struct tevent_req *subreq)
1375 {
1376         struct tevent_req *req = tevent_req_callback_data(
1377                 subreq, struct tevent_req);
1378         struct winexe_pipes_state *state = tevent_req_data(
1379                 req, struct winexe_pipes_state);
1380         NTSTATUS status;
1381
1382         status = winexe_out_pipe_recv(subreq);
1383         TALLOC_FREE(subreq);
1384
1385         DBG_DEBUG("stderr returned %s\n", nt_errstr(status));
1386
1387         if (tevent_req_nterror(req, status)) {
1388                 return;
1389         }
1390
1391         if (state->pipes[0] != NULL) {
1392                 winexe_in_pipe_close(state->pipes[0]);
1393         }
1394
1395         state->pipes[2] = NULL;
1396
1397         DBG_DEBUG("pipes = %p %p %p\n",
1398                   state->pipes[0],
1399                   state->pipes[1],
1400                   state->pipes[2]);
1401
1402         if ((state->pipes[0] == NULL) && (state->pipes[1] == NULL)) {
1403                 tevent_req_done(req);
1404         }
1405 }
1406
1407 static NTSTATUS winexe_pipes_recv(struct tevent_req *req)
1408 {
1409         return tevent_req_simple_recv_ntstatus(req);
1410 }
1411
1412 struct winexe_ctrl_state {
1413         struct tevent_context *ev;
1414         struct cli_state *cli;
1415
1416         uint16_t ctrl_pipe;
1417         bool ctrl_pipe_done;
1418
1419         char ctrl_inbuf[256];
1420         char *cmd;
1421         int return_code;
1422
1423         struct tevent_req *pipes_req;
1424 };
1425
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);
1432
1433 static struct tevent_req *winexe_ctrl_send(
1434         TALLOC_CTX *mem_ctx,
1435         struct tevent_context *ev,
1436         struct cli_state *cli,
1437         const char *cmd)
1438 {
1439         struct tevent_req *req, *subreq;
1440         struct winexe_ctrl_state *state;
1441
1442         req = tevent_req_create(mem_ctx, &state,
1443                                 struct winexe_ctrl_state);
1444         if (req == NULL) {
1445                 return NULL;
1446         }
1447         state->ev = ev;
1448         state->cli = cli;
1449
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);
1453         }
1454
1455         subreq = cli_ntcreate_send(
1456                 state,
1457                 state->ev,
1458                 state->cli,
1459                 "\\" PIPE_NAME,
1460                 0,
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);
1471         }
1472         tevent_req_set_callback(subreq, winexe_ctrl_opened, req);
1473         return req;
1474 }
1475
1476 static void winexe_ctrl_opened(struct tevent_req *subreq)
1477 {
1478         struct tevent_req *req = tevent_req_callback_data(
1479                 subreq, struct tevent_req);
1480         struct winexe_ctrl_state *state = tevent_req_data(
1481                 req, struct winexe_ctrl_state);
1482         int timeout;
1483         NTSTATUS status;
1484         static const char cmd[] = "get codepage\nget version\n";
1485
1486         status = cli_ntcreate_recv(subreq, &state->ctrl_pipe, NULL);
1487         TALLOC_FREE(subreq);
1488         if (tevent_req_nterror(req, status)) {
1489                 return;
1490         }
1491
1492         timeout = state->cli->timeout;
1493         state->cli->timeout = 0;
1494
1495         subreq = cli_read_send(
1496                 state,
1497                 state->ev,
1498                 state->cli,
1499                 state->ctrl_pipe,
1500                 state->ctrl_inbuf,
1501                 0,
1502                 sizeof(state->ctrl_inbuf)-1);
1503
1504         state->cli->timeout = timeout;
1505
1506         if (tevent_req_nomem(subreq, req)) {
1507                 return;
1508         }
1509         tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1510
1511         subreq = cli_writeall_send(
1512                 state,
1513                 state->ev,
1514                 state->cli,
1515                 state->ctrl_pipe,
1516                 0,
1517                 (const uint8_t *)cmd,
1518                 0,
1519                 strlen(cmd));
1520         if (tevent_req_nomem(subreq, req)) {
1521                 return;
1522         }
1523         tevent_req_set_callback(subreq, winexe_ctrl_wrote_version, req);
1524 }
1525
1526 static void winexe_ctrl_got_read(struct tevent_req *subreq)
1527 {
1528         struct tevent_req *req = tevent_req_callback_data(
1529                 subreq, struct tevent_req);
1530         struct winexe_ctrl_state *state = tevent_req_data(
1531                 req, struct winexe_ctrl_state);
1532         NTSTATUS status;
1533         int timeout;
1534         size_t received;
1535         unsigned int version, return_code;
1536         int ret;
1537
1538         status = cli_read_recv(subreq, &received);
1539         TALLOC_FREE(subreq);
1540
1541         if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1542                 subreq = cli_close_send(
1543                         state,
1544                         state->ev,
1545                         state->cli,
1546                         state->ctrl_pipe);
1547                 if (tevent_req_nomem(subreq, req)) {
1548                         return;
1549                 }
1550                 tevent_req_set_callback(subreq, winexe_ctrl_pipe_closed, req);
1551                 return;
1552         }
1553         if (tevent_req_nterror(req, status)) {
1554                 return;
1555         }
1556
1557         DBG_DEBUG("Got %zu bytes\n", received);
1558
1559         timeout = state->cli->timeout;
1560         state->cli->timeout = 0;
1561
1562         subreq = cli_read_send(
1563                 state,
1564                 state->ev,
1565                 state->cli,
1566                 state->ctrl_pipe,
1567                 state->ctrl_inbuf,
1568                 0,
1569                 sizeof(state->ctrl_inbuf)-1);
1570
1571         state->cli->timeout = timeout;
1572
1573         if (tevent_req_nomem(subreq, req)) {
1574                 return;
1575         }
1576         tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1577
1578         ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &version);
1579         if (ret == 1) {
1580                 DBG_DEBUG("Got version %x\n", version);
1581
1582                 subreq = cli_writeall_send(
1583                         state,
1584                         state->ev,
1585                         state->cli,
1586                         state->ctrl_pipe,
1587                         0,
1588                         (const uint8_t *)state->cmd,
1589                         0,
1590                         strlen(state->cmd));
1591                 if (tevent_req_nomem(subreq, req)) {
1592                         return;
1593                 }
1594                 tevent_req_set_callback(subreq, winexe_ctrl_wrote_cmd, req);
1595                 return;
1596         }
1597
1598         ret = strncmp(state->ctrl_inbuf, "std_io_err ", strlen("std_io_err "));
1599         if (ret == 0) {
1600                 char *p = state->ctrl_inbuf + 11;
1601                 char *q = strchr(state->ctrl_inbuf, '\n');
1602                 char *postfix;
1603                 size_t postfix_len;
1604
1605                 if (q == NULL) {
1606                         DBG_DEBUG("Got invalid pipe postfix\n");
1607                         return;
1608                 }
1609
1610                 postfix_len = q - p;
1611
1612                 postfix = talloc_strndup(state, p, postfix_len);
1613                 if (tevent_req_nomem(postfix, req)) {
1614                         return;
1615                 }
1616
1617                 DBG_DEBUG("Got pipe postfix %s\n", postfix);
1618
1619                 subreq = winexe_pipes_send(
1620                         state,
1621                         state->ev,
1622                         state->cli,
1623                         postfix);
1624                 if (tevent_req_nomem(subreq, req)) {
1625                         return;
1626                 }
1627                 tevent_req_set_callback(subreq, winexe_ctrl_pipes_done, req);
1628
1629                 state->pipes_req = subreq;
1630
1631                 return;
1632         }
1633
1634         ret = strncmp(state->ctrl_inbuf, "error ", strlen("error "));
1635         if (ret == 0) {
1636                 printf("Error: %s", state->ctrl_inbuf);
1637                 return;
1638         }
1639
1640         ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &return_code);
1641         if (ret == 1) {
1642                 state->return_code = return_code;
1643                 return;
1644         }
1645 }
1646
1647 static void winexe_ctrl_wrote_version(struct tevent_req *subreq)
1648 {
1649         struct tevent_req *req = tevent_req_callback_data(
1650                 subreq, struct tevent_req);
1651         NTSTATUS status;
1652
1653         status = cli_writeall_recv(subreq, NULL);
1654         TALLOC_FREE(subreq);
1655         if (tevent_req_nterror(req, status)) {
1656                 return;
1657         }
1658 }
1659
1660 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq)
1661 {
1662         struct tevent_req *req = tevent_req_callback_data(
1663                 subreq, struct tevent_req);
1664         NTSTATUS status;
1665
1666         status = cli_writeall_recv(subreq, NULL);
1667         TALLOC_FREE(subreq);
1668         if (tevent_req_nterror(req, status)) {
1669                 return;
1670         }
1671 }
1672
1673 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq)
1674 {
1675         struct tevent_req *req = tevent_req_callback_data(
1676                 subreq, struct tevent_req);
1677         struct winexe_ctrl_state *state = tevent_req_data(
1678                 req, struct winexe_ctrl_state);
1679         NTSTATUS status;
1680
1681         status = cli_close_recv(subreq);
1682         TALLOC_FREE(subreq);
1683         if (tevent_req_nterror(req, status)) {
1684                 return;
1685         }
1686
1687         state->ctrl_pipe_done = true;
1688         if (state->pipes_req == NULL) {
1689                 tevent_req_done(req);
1690         }
1691 }
1692
1693 static void winexe_ctrl_pipes_done(struct tevent_req *subreq)
1694 {
1695         struct tevent_req *req = tevent_req_callback_data(
1696                 subreq, struct tevent_req);
1697         struct winexe_ctrl_state *state = tevent_req_data(
1698                 req, struct winexe_ctrl_state);
1699         NTSTATUS status;
1700
1701         status = winexe_pipes_recv(subreq);
1702         TALLOC_FREE(subreq);
1703         if (tevent_req_nterror(req, status)) {
1704                 return;
1705         }
1706
1707         state->pipes_req = NULL;
1708         if (state->ctrl_pipe_done) {
1709                 tevent_req_done(req);
1710         }
1711 }
1712
1713 static NTSTATUS winexe_ctrl_recv(struct tevent_req *req,
1714                                  int *preturn_code)
1715 {
1716         struct winexe_ctrl_state *state = tevent_req_data(
1717                 req, struct winexe_ctrl_state);
1718         NTSTATUS status;
1719
1720         if (tevent_req_is_nterror(req, &status)) {
1721                 return status;
1722         }
1723         if (preturn_code != NULL) {
1724                 *preturn_code = state->return_code;
1725         }
1726         return NT_STATUS_OK;
1727 }
1728
1729 static NTSTATUS winexe_ctrl(struct cli_state *cli,
1730                             const char *cmd,
1731                             int *preturn_code)
1732 {
1733         struct tevent_context *ev = NULL;
1734         struct tevent_req *req = NULL;
1735         NTSTATUS status = NT_STATUS_NO_MEMORY;
1736         bool ok;
1737
1738         ev = samba_tevent_context_init(cli);
1739         if (ev == NULL) {
1740                 goto done;
1741         }
1742         req = winexe_ctrl_send(ev, ev, cli, cmd);
1743         if (req == NULL) {
1744                 goto done;
1745         }
1746         ok = tevent_req_poll_ntstatus(req, ev, &status);
1747         if (!ok) {
1748                 goto done;
1749         }
1750         status = winexe_ctrl_recv(req, preturn_code);
1751 done:
1752         TALLOC_FREE(req);
1753         TALLOC_FREE(ev);
1754         return status;
1755 }
1756
1757 #ifdef HAVE_WINEXE_CC_WIN32
1758 const DATA_BLOB *winexesvc32_exe_binary(void);
1759 #endif
1760
1761 #ifdef HAVE_WINEXE_CC_WIN64
1762 const DATA_BLOB *winexesvc64_exe_binary(void);
1763 #endif
1764
1765 int main(int argc, const char *argv[])
1766 {
1767         TALLOC_CTX *frame = talloc_stackframe();
1768         struct program_options options = {0};
1769         struct loadparm_context *lp_ctx;
1770         struct cli_state *cli;
1771         const char *service_name = SERVICE_NAME;
1772         char *service_filename = NULL;
1773 #ifdef HAVE_WINEXE_CC_WIN32
1774         const DATA_BLOB *winexesvc32_exe = winexesvc32_exe_binary();
1775 #else
1776         const DATA_BLOB *winexesvc32_exe = NULL;
1777 #endif
1778 #ifdef HAVE_WINEXE_CC_WIN64
1779         const DATA_BLOB *winexesvc64_exe = winexesvc64_exe_binary();
1780 #else
1781         const DATA_BLOB *winexesvc64_exe = NULL;
1782 #endif
1783         NTSTATUS status;
1784         int ret = 1;
1785         int return_code = 0;
1786
1787         lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
1788         if (lp_ctx == NULL) {
1789                 fprintf(stderr, "loadparm_init_s3 failed\n");
1790                 goto done;
1791         }
1792
1793         smb_init_locale();
1794         setup_logging("winexe", DEBUG_STDOUT);
1795
1796         lp_load_global(get_dyn_CONFIGFILE());
1797
1798         parse_args(argc, argv, frame, &options, lp_ctx);
1799
1800         if (options.cmd == NULL) {
1801                 fprintf(stderr, "no cmd given\n");
1802                 goto done;
1803         }
1804
1805         service_filename = talloc_asprintf(frame, "%s.exe", service_name);
1806         if (service_filename == NULL) {
1807                 DBG_WARNING("talloc_asprintf failed\n");
1808                 goto done;
1809         }
1810
1811         status = cli_full_connection_creds(
1812                 &cli,
1813                 NULL,
1814                 options.hostname,
1815                 NULL,
1816                 445,
1817                 "IPC$",
1818                 "?????",
1819                 options.credentials,
1820                 0,
1821                 0);
1822
1823         if (!NT_STATUS_IS_OK(status)) {
1824                 DBG_WARNING("cli_full_connection_creds failed: %s\n",
1825                             nt_errstr(status));
1826                 goto done;
1827         }
1828
1829         status = winexe_svc_install(
1830                 cli,
1831                 options.hostname,
1832                 service_name,
1833                 service_filename,
1834                 winexesvc32_exe,
1835                 winexesvc64_exe,
1836                 options.credentials,
1837                 options.flags);
1838         if (!NT_STATUS_IS_OK(status)) {
1839                 DBG_WARNING("winexe_svc_install failed: %s\n",
1840                             nt_errstr(status));
1841                 goto done;
1842         }
1843
1844         status = winexe_ctrl(cli, options.cmd, &return_code);
1845         if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1846                 /* Normal finish */
1847                 status = NT_STATUS_OK;
1848         }
1849         if (!NT_STATUS_IS_OK(status)) {
1850                 DBG_WARNING("cli_ctrl failed: %s\n",
1851                             nt_errstr(status));
1852                 goto done;
1853         }
1854
1855         if (options.flags & SVC_UNINSTALL) {
1856                 status = winexe_svc_uninstall(
1857                         cli,
1858                         service_name);
1859                 if (!NT_STATUS_IS_OK(status)) {
1860                         DBG_WARNING("winexe_svc_uninstall failed: %s\n",
1861                                     nt_errstr(status));
1862                         goto done;
1863                 }
1864         }
1865
1866         ret = return_code;
1867 done:
1868         TALLOC_FREE(frame);
1869         return ret;
1870 }