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