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