s3-libads: use ldap_init_fd() to initialize a ldap session if possible
[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                         0,          /* dwDependSize */
629                         NULL,       /* service_start_name */
630                         NULL,       /* password */
631                         0,          /* dwPwSize */
632                         NULL,       /* display_name */
633                         &werr);
634
635                 if (!NT_STATUS_IS_OK(status)) {
636                         DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
637                                     "failed: %s\n", nt_errstr(status));
638                         goto close_service;
639                 }
640                 if (!W_ERROR_IS_OK(werr)) {
641                         DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
642                                     "failed: %s\n", win_errstr(werr));
643                         status = werror_to_ntstatus(werr);
644                         goto close_service;
645                 }
646         }
647
648         if (need_start) {
649                 status = winexe_svc_upload(
650                         hostname,
651                         port,
652                         service_filename,
653                         svc32_exe,
654                         svc64_exe,
655                         credentials,
656                         flags);
657                 if (!NT_STATUS_IS_OK(status)) {
658                         DBG_WARNING("winexe_svc_upload failed: %s\n",
659                                     nt_errstr(status));
660                         goto close_service;
661                 }
662
663                 status = dcerpc_svcctl_StartServiceW(
664                         rpccli->binding_handle,
665                         frame,
666                         &service_handle,
667                         0,      /* num_args */
668                         NULL,   /* arguments */
669                         &werr);
670
671                 if (!NT_STATUS_IS_OK(status)) {
672                         DBG_WARNING("dcerpc_svcctl_StartServiceW "
673                                     "failed: %s\n", nt_errstr(status));
674                         goto close_service;
675                 }
676                 if (!W_ERROR_IS_OK(werr)) {
677                         DBG_WARNING("dcerpc_svcctl_StartServiceW "
678                                     "failed: %s\n", win_errstr(werr));
679                         status = werror_to_ntstatus(werr);
680                         goto close_service;
681                 }
682
683                 do {
684                         smb_msleep(100);
685
686                         status = dcerpc_svcctl_QueryServiceStatus(
687                                 rpccli->binding_handle,
688                                 frame,
689                                 &service_handle,
690                                 &service_status,
691                                 &werr);
692
693                         if (!NT_STATUS_IS_OK(status)) {
694                                 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
695                                             "failed: %s\n", nt_errstr(status));
696                                 goto close_service;
697                         }
698                         if (!W_ERROR_IS_OK(werr)) {
699                                 DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
700                                             "failed: %s\n", win_errstr(werr));
701                                 status = werror_to_ntstatus(werr);
702                                 goto close_service;
703                         }
704                 } while (service_status.state == SVCCTL_START_PENDING);
705
706                 if (service_status.state != SVCCTL_RUNNING) {
707                         DBG_WARNING("Failed to start service\n");
708                         status = NT_STATUS_UNSUCCESSFUL;
709                         goto close_service;
710                 }
711         }
712
713 close_service:
714         {
715                 NTSTATUS close_status;
716                 WERROR close_werr;
717
718                 close_status = dcerpc_svcctl_CloseServiceHandle(
719                         rpccli->binding_handle,
720                         frame,
721                         &service_handle,
722                         &close_werr);
723                 if (!NT_STATUS_IS_OK(close_status)) {
724                         DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
725                                     "failed: %s\n", nt_errstr(close_status));
726                         goto done;
727                 }
728                 if (!W_ERROR_IS_OK(close_werr)) {
729                         DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
730                                     " failed: %s\n", win_errstr(close_werr));
731                         goto done;
732                 }
733         }
734
735 close_scmanager:
736         {
737                 NTSTATUS close_status;
738                 WERROR close_werr;
739
740                 close_status = dcerpc_svcctl_CloseServiceHandle(
741                         rpccli->binding_handle,
742                         frame,
743                         &scmanager_handle,
744                         &close_werr);
745                 if (!NT_STATUS_IS_OK(close_status)) {
746                         DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
747                                     "failed: %s\n", nt_errstr(close_status));
748                         goto done;
749                 }
750                 if (!W_ERROR_IS_OK(close_werr)) {
751                         DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
752                                     " failed: %s\n", win_errstr(close_werr));
753                         goto done;
754                 }
755         }
756
757 done:
758         TALLOC_FREE(rpccli);
759         TALLOC_FREE(frame);
760         return status;
761 }
762
763 static NTSTATUS winexe_svc_uninstall(
764         struct cli_state *cli,
765         const char *service_name)
766 {
767         TALLOC_CTX *frame = talloc_stackframe();
768         struct rpc_pipe_client *rpccli;
769         struct policy_handle scmanager_handle;
770         struct policy_handle service_handle;
771         struct SERVICE_STATUS service_status;
772         NTSTATUS status;
773         WERROR werr;
774
775         status = cli_rpc_pipe_open_noauth_transport(
776                 cli,
777                 NCACN_NP,
778                 &ndr_table_svcctl,
779                 &rpccli);
780         if (!NT_STATUS_IS_OK(status)) {
781                 DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
782                             nt_errstr(status));
783                 goto done;
784         }
785
786         status = dcerpc_svcctl_OpenSCManagerW(
787                 rpccli->binding_handle,
788                 frame,
789                 smbXcli_conn_remote_name(cli->conn),
790                 NULL,
791                 SEC_FLAG_MAXIMUM_ALLOWED,
792                 &scmanager_handle,
793                 &werr);
794         if (!NT_STATUS_IS_OK(status)) {
795                 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
796                             nt_errstr(status));
797                 goto done;
798         }
799         if (!W_ERROR_IS_OK(werr)) {
800                 DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
801                             win_errstr(werr));
802                 goto done;
803         }
804
805         status = dcerpc_svcctl_OpenServiceW(
806                 rpccli->binding_handle,
807                 frame,
808                 &scmanager_handle,
809                 service_name,
810                 SERVICE_ALL_ACCESS,
811                 &service_handle,
812                 &werr);
813         if (!NT_STATUS_IS_OK(status)) {
814                 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
815                             nt_errstr(status));
816                 goto close_scmanager;
817         }
818         if (!W_ERROR_IS_OK(werr)) {
819                 DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
820                             win_errstr(werr));
821                 status = werror_to_ntstatus(werr);
822                 goto close_scmanager;
823         }
824
825         status = dcerpc_svcctl_ControlService(
826                 rpccli->binding_handle,
827                 frame,
828                 &service_handle,
829                 SVCCTL_CONTROL_STOP,
830                 &service_status,
831                 &werr);
832         if (!NT_STATUS_IS_OK(status)) {
833                 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
834                             "failed: %s\n", nt_errstr(status));
835                 goto close_service;
836         }
837         if (!W_ERROR_IS_OK(werr)) {
838                 DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
839                             "failed: %s\n", win_errstr(werr));
840                 status = werror_to_ntstatus(werr);
841                 goto close_service;
842         }
843
844         do {
845                 smb_msleep(100);
846
847                 status = dcerpc_svcctl_QueryServiceStatus(
848                         rpccli->binding_handle,
849                         frame,
850                         &service_handle,
851                         &service_status,
852                         &werr);
853
854                 if (!NT_STATUS_IS_OK(status)) {
855                         DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
856                                     "failed: %s\n", nt_errstr(status));
857                         goto close_service;
858                 }
859                 if (!W_ERROR_IS_OK(werr)) {
860                         DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
861                                     "failed: %s\n", win_errstr(werr));
862                         status = werror_to_ntstatus(werr);
863                         goto close_service;
864                 }
865         } while (service_status.state != SVCCTL_STOPPED);
866
867         status = dcerpc_svcctl_DeleteService(
868                 rpccli->binding_handle,
869                 frame,
870                 &service_handle,
871                 &werr);
872         if (!NT_STATUS_IS_OK(status)) {
873                 DBG_WARNING("dcerpc_svcctl_DeleteService "
874                             "failed: %s\n", nt_errstr(status));
875                 goto close_service;
876         }
877         if (!W_ERROR_IS_OK(werr)) {
878                 DBG_WARNING("dcerpc_svcctl_DeleteService "
879                             "failed: %s\n", win_errstr(werr));
880                 status = werror_to_ntstatus(werr);
881                 goto close_service;
882         }
883
884 close_service:
885         {
886                 NTSTATUS close_status;
887                 WERROR close_werr;
888
889                 close_status = dcerpc_svcctl_CloseServiceHandle(
890                         rpccli->binding_handle,
891                         frame,
892                         &service_handle,
893                         &close_werr);
894                 if (!NT_STATUS_IS_OK(close_status)) {
895                         DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
896                                     "failed: %s\n", nt_errstr(close_status));
897                         goto done;
898                 }
899                 if (!W_ERROR_IS_OK(close_werr)) {
900                         DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
901                                     " failed: %s\n", win_errstr(close_werr));
902                         goto done;
903                 }
904         }
905
906 close_scmanager:
907         {
908                 NTSTATUS close_status;
909                 WERROR close_werr;
910
911                 close_status = dcerpc_svcctl_CloseServiceHandle(
912                         rpccli->binding_handle,
913                         frame,
914                         &scmanager_handle,
915                         &close_werr);
916                 if (!NT_STATUS_IS_OK(close_status)) {
917                         DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
918                                     "failed: %s\n", nt_errstr(close_status));
919                         goto done;
920                 }
921                 if (!W_ERROR_IS_OK(close_werr)) {
922                         DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
923                                     " failed: %s\n", win_errstr(close_werr));
924                         goto done;
925                 }
926         }
927
928 done:
929         TALLOC_FREE(rpccli);
930         TALLOC_FREE(frame);
931         return status;
932 }
933
934 struct winexe_out_pipe_state {
935         struct tevent_context *ev;
936         struct cli_state *cli;
937         uint16_t out_pipe;
938         int out_fd;
939         char out_inbuf[256];
940 };
941
942 static void winexe_out_pipe_opened(struct tevent_req *subreq);
943 static void winexe_out_pipe_got_data(struct tevent_req *subreq);
944 static void winexe_out_pipe_closed(struct tevent_req *subreq);
945
946 static struct tevent_req *winexe_out_pipe_send(
947         TALLOC_CTX *mem_ctx,
948         struct tevent_context *ev,
949         struct cli_state *cli,
950         const char *pipe_name,
951         int out_fd)
952 {
953         struct tevent_req *req, *subreq;
954         struct winexe_out_pipe_state *state;
955
956         req = tevent_req_create(mem_ctx, &state,
957                                 struct winexe_out_pipe_state);
958         if (req == NULL) {
959                 return NULL;
960         }
961         state->ev = ev;
962         state->cli = cli;
963         state->out_fd = out_fd;
964
965         subreq = cli_ntcreate_send(
966                 state,
967                 state->ev,
968                 state->cli,
969                 pipe_name,
970                 0,
971                 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
972                 SEC_RIGHTS_FILE_EXECUTE,
973                 0,              /* FileAttributes */
974                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
975                 FILE_OPEN,      /* CreateDisposition */
976                 0,              /* CreateOptions */
977                 SMB2_IMPERSONATION_IMPERSONATION,
978                 0);             /* SecurityFlags */
979         if (tevent_req_nomem(subreq, req)) {
980                 return tevent_req_post(req, ev);
981         }
982         tevent_req_set_callback(subreq, winexe_out_pipe_opened, req);
983         return req;
984 }
985
986 static void winexe_out_pipe_opened(struct tevent_req *subreq)
987 {
988         struct tevent_req *req = tevent_req_callback_data(
989                 subreq, struct tevent_req);
990         struct winexe_out_pipe_state *state = tevent_req_data(
991                 req, struct winexe_out_pipe_state);
992         int timeout;
993         NTSTATUS status;
994
995         status = cli_ntcreate_recv(subreq, &state->out_pipe, NULL);
996         TALLOC_FREE(subreq);
997         if (tevent_req_nterror(req, status)) {
998                 return;
999         }
1000
1001         timeout = state->cli->timeout;
1002         state->cli->timeout = 0;
1003
1004         subreq = cli_read_send(
1005                 state,
1006                 state->ev,
1007                 state->cli,
1008                 state->out_pipe,
1009                 state->out_inbuf,
1010                 0,
1011                 sizeof(state->out_inbuf));
1012
1013         state->cli->timeout = timeout;
1014
1015         if (tevent_req_nomem(subreq, req)) {
1016                 return;
1017         }
1018         tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
1019 }
1020
1021 static void winexe_out_pipe_got_data(struct tevent_req *subreq)
1022 {
1023         struct tevent_req *req = tevent_req_callback_data(
1024                 subreq, struct tevent_req);
1025         struct winexe_out_pipe_state *state = tevent_req_data(
1026                 req, struct winexe_out_pipe_state);
1027         NTSTATUS status;
1028         int timeout;
1029         size_t received;
1030         ssize_t written;
1031
1032         status = cli_read_recv(subreq, &received);
1033         TALLOC_FREE(subreq);
1034
1035         DBG_DEBUG("cli_read for %d gave %s\n",
1036                   state->out_fd,
1037                   nt_errstr(status));
1038
1039         if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1040                 subreq = cli_close_send(
1041                         state,
1042                         state->ev,
1043                         state->cli,
1044                         state->out_pipe);
1045                 if (tevent_req_nomem(subreq, req)) {
1046                         return;
1047                 }
1048                 tevent_req_set_callback(subreq, winexe_out_pipe_closed, req);
1049                 return;
1050         }
1051
1052         if (tevent_req_nterror(req, status)) {
1053                 return;
1054         }
1055
1056         if (received > 0) {
1057                 written = sys_write(state->out_fd, state->out_inbuf, received);
1058                 if (written == -1) {
1059                         tevent_req_nterror(req, map_nt_error_from_unix(errno));
1060                         return;
1061                 }
1062         }
1063
1064         timeout = state->cli->timeout;
1065         state->cli->timeout = 0;
1066
1067         subreq = cli_read_send(
1068                 state,
1069                 state->ev,
1070                 state->cli,
1071                 state->out_pipe,
1072                 state->out_inbuf,
1073                 0,
1074                 sizeof(state->out_inbuf));
1075
1076         state->cli->timeout = timeout;
1077
1078         if (tevent_req_nomem(subreq, req)) {
1079                 return;
1080         }
1081         tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
1082 }
1083
1084 static void winexe_out_pipe_closed(struct tevent_req *subreq)
1085 {
1086         struct tevent_req *req = tevent_req_callback_data(
1087                 subreq, struct tevent_req);
1088         NTSTATUS status;
1089
1090         status = cli_close_recv(subreq);
1091         TALLOC_FREE(subreq);
1092         if (tevent_req_nterror(req, status)) {
1093                 return;
1094         }
1095         tevent_req_done(req);
1096 }
1097
1098 static NTSTATUS winexe_out_pipe_recv(struct tevent_req *req)
1099 {
1100         return tevent_req_simple_recv_ntstatus(req);
1101 }
1102
1103 struct winexe_in_pipe_state {
1104         struct tevent_context *ev;
1105         struct cli_state *cli;
1106         struct tevent_req *fd_read_req;
1107         bool close_requested;
1108         bool closing;
1109         uint16_t in_pipe;
1110         int in_fd;
1111         char inbuf[256];
1112 };
1113
1114 static void winexe_in_pipe_opened(struct tevent_req *subreq);
1115 static void winexe_in_pipe_got_data(struct tevent_req *subreq);
1116 static void winexe_in_pipe_written(struct tevent_req *subreq);
1117 static void winexe_in_pipe_closed(struct tevent_req *subreq);
1118
1119 static struct tevent_req *winexe_in_pipe_send(
1120         TALLOC_CTX *mem_ctx,
1121         struct tevent_context *ev,
1122         struct cli_state *cli,
1123         const char *pipe_name,
1124         int in_fd)
1125 {
1126         struct tevent_req *req, *subreq;
1127         struct winexe_in_pipe_state *state;
1128
1129         req = tevent_req_create(mem_ctx, &state,
1130                                 struct winexe_in_pipe_state);
1131         if (req == NULL) {
1132                 return NULL;
1133         }
1134         state->ev = ev;
1135         state->cli = cli;
1136         state->in_fd = in_fd;
1137
1138         subreq = cli_ntcreate_send(
1139                 state,
1140                 state->ev,
1141                 state->cli,
1142                 pipe_name,
1143                 0,
1144                 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
1145                 SEC_RIGHTS_FILE_EXECUTE,
1146                 0,              /* FileAttributes */
1147                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1148                 FILE_OPEN,      /* CreateDisposition */
1149                 0,              /* CreateOptions */
1150                 SMB2_IMPERSONATION_IMPERSONATION,
1151                 0);             /* SecurityFlags */
1152         if (tevent_req_nomem(subreq, req)) {
1153                 return tevent_req_post(req, ev);
1154         }
1155         tevent_req_set_callback(subreq, winexe_in_pipe_opened, req);
1156         return req;
1157 }
1158
1159 static void winexe_in_pipe_opened(struct tevent_req *subreq)
1160 {
1161         struct tevent_req *req = tevent_req_callback_data(
1162                 subreq, struct tevent_req);
1163         struct winexe_in_pipe_state *state = tevent_req_data(
1164                 req, struct winexe_in_pipe_state);
1165         NTSTATUS status;
1166
1167         status = cli_ntcreate_recv(subreq, &state->in_pipe, NULL);
1168         TALLOC_FREE(subreq);
1169         if (tevent_req_nterror(req, status)) {
1170                 return;
1171         }
1172
1173         subreq = wait_for_read_send(
1174                 state,
1175                 state->ev,
1176                 state->in_fd,
1177                 true);
1178         if (tevent_req_nomem(subreq, req)) {
1179                 return;
1180         }
1181         tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
1182
1183         state->fd_read_req = subreq;
1184 }
1185
1186 static void winexe_in_pipe_got_data(struct tevent_req *subreq)
1187 {
1188         struct tevent_req *req = tevent_req_callback_data(
1189                 subreq, struct tevent_req);
1190         struct winexe_in_pipe_state *state = tevent_req_data(
1191                 req, struct winexe_in_pipe_state);
1192         int err;
1193         bool ok;
1194         int timeout;
1195         ssize_t nread;
1196
1197         ok = wait_for_read_recv(subreq, &err);
1198         TALLOC_FREE(subreq);
1199         if (!ok) {
1200                 tevent_req_nterror(req, map_nt_error_from_unix(err));
1201                 return;
1202         }
1203         state->fd_read_req = NULL;
1204
1205         nread = sys_read(state->in_fd, &state->inbuf, sizeof(state->inbuf));
1206         if (nread == -1) {
1207                 tevent_req_nterror(req, map_nt_error_from_unix(errno));
1208                 return;
1209         }
1210         if (nread == 0) {
1211                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
1212                 return;
1213         }
1214
1215         timeout = state->cli->timeout;
1216         state->cli->timeout = 0;
1217
1218         subreq = cli_writeall_send(
1219                 state,
1220                 state->ev,
1221                 state->cli,
1222                 state->in_pipe,
1223                 0,
1224                 (uint8_t *)state->inbuf,
1225                 0,
1226                 nread);
1227
1228         state->cli->timeout = timeout;
1229
1230         if (tevent_req_nomem(subreq, req)) {
1231                 return;
1232         }
1233         tevent_req_set_callback(subreq, winexe_in_pipe_written, req);
1234 }
1235
1236 static void winexe_in_pipe_written(struct tevent_req *subreq)
1237 {
1238         struct tevent_req *req = tevent_req_callback_data(
1239                 subreq, struct tevent_req);
1240         struct winexe_in_pipe_state *state = tevent_req_data(
1241                 req, struct winexe_in_pipe_state);
1242         NTSTATUS status;
1243
1244         status = cli_writeall_recv(subreq, NULL);
1245         TALLOC_FREE(subreq);
1246
1247         DBG_DEBUG("cli_writeall for %d gave %s\n",
1248                   state->in_fd,
1249                   nt_errstr(status));
1250
1251         if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED) ||
1252             state->close_requested) {
1253                 subreq = cli_close_send(
1254                         state,
1255                         state->ev,
1256                         state->cli,
1257                         state->in_pipe);
1258                 if (tevent_req_nomem(subreq, req)) {
1259                         return;
1260                 }
1261                 tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1262                 state->closing = true;
1263                 return;
1264         }
1265
1266         if (tevent_req_nterror(req, status)) {
1267                 return;
1268         }
1269
1270         subreq = wait_for_read_send(
1271                 state,
1272                 state->ev,
1273                 state->in_fd,
1274                 true);
1275         if (tevent_req_nomem(subreq, req)) {
1276                 return;
1277         }
1278         tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
1279
1280         state->fd_read_req = subreq;
1281 }
1282
1283 static void winexe_in_pipe_closed(struct tevent_req *subreq)
1284 {
1285         struct tevent_req *req = tevent_req_callback_data(
1286                 subreq, struct tevent_req);
1287         NTSTATUS status;
1288
1289         status = cli_close_recv(subreq);
1290         TALLOC_FREE(subreq);
1291         if (tevent_req_nterror(req, status)) {
1292                 return;
1293         }
1294         return tevent_req_done(req);
1295 }
1296
1297 static NTSTATUS winexe_in_pipe_recv(struct tevent_req *req)
1298 {
1299         return tevent_req_simple_recv_ntstatus(req);
1300 }
1301
1302 static bool winexe_in_pipe_close(struct tevent_req *req)
1303 {
1304         struct winexe_in_pipe_state *state = tevent_req_data(
1305                 req, struct winexe_in_pipe_state);
1306         struct tevent_req *subreq;
1307
1308         if (state->closing) {
1309                 return true;
1310         }
1311
1312         if (state->fd_read_req == NULL) {
1313                 /*
1314                  * cli_writeall active, wait for it to return
1315                  */
1316                 state->close_requested = true;
1317                 return true;
1318         }
1319
1320         TALLOC_FREE(state->fd_read_req);
1321
1322         subreq = cli_close_send(
1323                 state,
1324                 state->ev,
1325                 state->cli,
1326                 state->in_pipe);
1327         if (subreq == NULL) {
1328                 return false;
1329         }
1330         tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
1331         state->closing = true;
1332
1333         return true;
1334 }
1335
1336 struct winexe_pipes_state {
1337         struct tevent_req *pipes[3];
1338 };
1339
1340 static void winexe_pipes_stdin_done(struct tevent_req *subreq);
1341 static void winexe_pipes_stdout_done(struct tevent_req *subreq);
1342 static void winexe_pipes_stderr_done(struct tevent_req *subreq);
1343
1344 static struct tevent_req *winexe_pipes_send(
1345         TALLOC_CTX *mem_ctx,
1346         struct tevent_context *ev,
1347         struct cli_state *cli,
1348         const char *pipe_postfix)
1349 {
1350         struct tevent_req *req;
1351         struct winexe_pipes_state *state;
1352         char *pipe_name;
1353
1354         req = tevent_req_create(mem_ctx, &state, struct winexe_pipes_state);
1355         if (req == NULL) {
1356                 return NULL;
1357         }
1358
1359         pipe_name = talloc_asprintf(state, "\\ahexec_stdin%s", pipe_postfix);
1360         if (tevent_req_nomem(pipe_name, req)) {
1361                 return tevent_req_post(req, ev);
1362         }
1363         state->pipes[0] = winexe_in_pipe_send(
1364                 state,
1365                 ev,
1366                 cli,
1367                 pipe_name,
1368                 0);
1369         if (tevent_req_nomem(state->pipes[0], req)) {
1370                 return tevent_req_post(req, ev);
1371         }
1372         tevent_req_set_callback(state->pipes[0], winexe_pipes_stdin_done, req);
1373
1374         pipe_name = talloc_asprintf(state, "\\ahexec_stdout%s", pipe_postfix);
1375         if (tevent_req_nomem(pipe_name, req)) {
1376                 return tevent_req_post(req, ev);
1377         }
1378         state->pipes[1] = winexe_out_pipe_send(
1379                 state,
1380                 ev,
1381                 cli,
1382                 pipe_name,
1383                 1);
1384         if (tevent_req_nomem(state->pipes[1], req)) {
1385                 return tevent_req_post(req, ev);
1386         }
1387         tevent_req_set_callback(state->pipes[1], winexe_pipes_stdout_done,
1388                                 req);
1389
1390         pipe_name = talloc_asprintf(state, "\\ahexec_stderr%s", pipe_postfix);
1391         if (tevent_req_nomem(pipe_name, req)) {
1392                 return tevent_req_post(req, ev);
1393         }
1394         state->pipes[2] = winexe_out_pipe_send(
1395                 state,
1396                 ev,
1397                 cli,
1398                 pipe_name,
1399                 2);
1400         if (tevent_req_nomem(state->pipes[2], req)) {
1401                 return tevent_req_post(req, ev);
1402         }
1403         tevent_req_set_callback(state->pipes[2], winexe_pipes_stderr_done,
1404                                 req);
1405
1406         DBG_DEBUG("pipes = %p %p %p\n",
1407                   state->pipes[0],
1408                   state->pipes[1],
1409                   state->pipes[2]);
1410
1411         return req;
1412 }
1413
1414 static void winexe_pipes_stdin_done(struct tevent_req *subreq)
1415 {
1416         struct tevent_req *req = tevent_req_callback_data(
1417                 subreq, struct tevent_req);
1418         struct winexe_pipes_state *state = tevent_req_data(
1419                 req, struct winexe_pipes_state);
1420         NTSTATUS status;
1421
1422         status = winexe_in_pipe_recv(subreq);
1423         TALLOC_FREE(subreq);
1424
1425         DBG_DEBUG("stdin returned %s\n", nt_errstr(status));
1426
1427         if (tevent_req_nterror(req, status)) {
1428                 return;
1429         }
1430
1431         state->pipes[0] = NULL;
1432
1433         DBG_DEBUG("pipes = %p %p %p\n",
1434                   state->pipes[0],
1435                   state->pipes[1],
1436                   state->pipes[2]);
1437
1438         if ((state->pipes[1] == NULL) && (state->pipes[2] == NULL)) {
1439                 tevent_req_done(req);
1440         }
1441 }
1442
1443 static void winexe_pipes_stdout_done(struct tevent_req *subreq)
1444 {
1445         struct tevent_req *req = tevent_req_callback_data(
1446                 subreq, struct tevent_req);
1447         struct winexe_pipes_state *state = tevent_req_data(
1448                 req, struct winexe_pipes_state);
1449         NTSTATUS status;
1450
1451         status = winexe_out_pipe_recv(subreq);
1452         TALLOC_FREE(subreq);
1453
1454         DBG_DEBUG("stdout returned %s\n", nt_errstr(status));
1455
1456         if (tevent_req_nterror(req, status)) {
1457                 return;
1458         }
1459
1460         if (state->pipes[0] != NULL) {
1461                 winexe_in_pipe_close(state->pipes[0]);
1462         }
1463
1464         state->pipes[1] = NULL;
1465
1466         DBG_DEBUG("pipes = %p %p %p\n",
1467                   state->pipes[0],
1468                   state->pipes[1],
1469                   state->pipes[2]);
1470
1471         if ((state->pipes[0] == NULL) && (state->pipes[2] == NULL)) {
1472                 tevent_req_done(req);
1473         }
1474 }
1475
1476 static void winexe_pipes_stderr_done(struct tevent_req *subreq)
1477 {
1478         struct tevent_req *req = tevent_req_callback_data(
1479                 subreq, struct tevent_req);
1480         struct winexe_pipes_state *state = tevent_req_data(
1481                 req, struct winexe_pipes_state);
1482         NTSTATUS status;
1483
1484         status = winexe_out_pipe_recv(subreq);
1485         TALLOC_FREE(subreq);
1486
1487         DBG_DEBUG("stderr returned %s\n", nt_errstr(status));
1488
1489         if (tevent_req_nterror(req, status)) {
1490                 return;
1491         }
1492
1493         if (state->pipes[0] != NULL) {
1494                 winexe_in_pipe_close(state->pipes[0]);
1495         }
1496
1497         state->pipes[2] = NULL;
1498
1499         DBG_DEBUG("pipes = %p %p %p\n",
1500                   state->pipes[0],
1501                   state->pipes[1],
1502                   state->pipes[2]);
1503
1504         if ((state->pipes[0] == NULL) && (state->pipes[1] == NULL)) {
1505                 tevent_req_done(req);
1506         }
1507 }
1508
1509 static NTSTATUS winexe_pipes_recv(struct tevent_req *req)
1510 {
1511         return tevent_req_simple_recv_ntstatus(req);
1512 }
1513
1514 struct winexe_ctrl_state {
1515         struct tevent_context *ev;
1516         struct cli_state *cli;
1517
1518         uint16_t ctrl_pipe;
1519         bool ctrl_pipe_done;
1520
1521         char ctrl_inbuf[256];
1522         char *cmd;
1523         int return_code;
1524
1525         struct tevent_req *pipes_req;
1526 };
1527
1528 static void winexe_ctrl_opened(struct tevent_req *subreq);
1529 static void winexe_ctrl_got_read(struct tevent_req *subreq);
1530 static void winexe_ctrl_wrote_version(struct tevent_req *subreq);
1531 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq);
1532 static void winexe_ctrl_pipes_done(struct tevent_req *subreq);
1533 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq);
1534
1535 static struct tevent_req *winexe_ctrl_send(
1536         TALLOC_CTX *mem_ctx,
1537         struct tevent_context *ev,
1538         struct cli_state *cli,
1539         const char *cmd)
1540 {
1541         struct tevent_req *req, *subreq;
1542         struct winexe_ctrl_state *state;
1543
1544         req = tevent_req_create(mem_ctx, &state,
1545                                 struct winexe_ctrl_state);
1546         if (req == NULL) {
1547                 return NULL;
1548         }
1549         state->ev = ev;
1550         state->cli = cli;
1551
1552         state->cmd = talloc_asprintf(state, "run %s\n", cmd);
1553         if (tevent_req_nomem(state->cmd, req)) {
1554                 return tevent_req_post(req, ev);
1555         }
1556
1557         subreq = cli_ntcreate_send(
1558                 state,
1559                 state->ev,
1560                 state->cli,
1561                 "\\" PIPE_NAME,
1562                 0,
1563                 SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
1564                 SEC_RIGHTS_FILE_EXECUTE,
1565                 0,              /* FileAttributes */
1566                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1567                 FILE_OPEN,      /* CreateDisposition */
1568                 0,              /* CreateOptions */
1569                 SMB2_IMPERSONATION_IMPERSONATION,
1570                 0);             /* SecurityFlags */
1571         if (tevent_req_nomem(subreq, req)) {
1572                 return tevent_req_post(req, ev);
1573         }
1574         tevent_req_set_callback(subreq, winexe_ctrl_opened, req);
1575         return req;
1576 }
1577
1578 static void winexe_ctrl_opened(struct tevent_req *subreq)
1579 {
1580         struct tevent_req *req = tevent_req_callback_data(
1581                 subreq, struct tevent_req);
1582         struct winexe_ctrl_state *state = tevent_req_data(
1583                 req, struct winexe_ctrl_state);
1584         int timeout;
1585         NTSTATUS status;
1586         static const char cmd[] = "get codepage\nget version\n";
1587
1588         status = cli_ntcreate_recv(subreq, &state->ctrl_pipe, NULL);
1589         TALLOC_FREE(subreq);
1590         if (tevent_req_nterror(req, status)) {
1591                 return;
1592         }
1593
1594         timeout = state->cli->timeout;
1595         state->cli->timeout = 0;
1596
1597         subreq = cli_read_send(
1598                 state,
1599                 state->ev,
1600                 state->cli,
1601                 state->ctrl_pipe,
1602                 state->ctrl_inbuf,
1603                 0,
1604                 sizeof(state->ctrl_inbuf)-1);
1605
1606         state->cli->timeout = timeout;
1607
1608         if (tevent_req_nomem(subreq, req)) {
1609                 return;
1610         }
1611         tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1612
1613         subreq = cli_writeall_send(
1614                 state,
1615                 state->ev,
1616                 state->cli,
1617                 state->ctrl_pipe,
1618                 0,
1619                 (const uint8_t *)cmd,
1620                 0,
1621                 strlen(cmd));
1622         if (tevent_req_nomem(subreq, req)) {
1623                 return;
1624         }
1625         tevent_req_set_callback(subreq, winexe_ctrl_wrote_version, req);
1626 }
1627
1628 static void winexe_ctrl_got_read(struct tevent_req *subreq)
1629 {
1630         struct tevent_req *req = tevent_req_callback_data(
1631                 subreq, struct tevent_req);
1632         struct winexe_ctrl_state *state = tevent_req_data(
1633                 req, struct winexe_ctrl_state);
1634         NTSTATUS status;
1635         int timeout;
1636         size_t received;
1637         unsigned int version, return_code;
1638         int ret;
1639
1640         status = cli_read_recv(subreq, &received);
1641         TALLOC_FREE(subreq);
1642
1643         if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1644                 subreq = cli_close_send(
1645                         state,
1646                         state->ev,
1647                         state->cli,
1648                         state->ctrl_pipe);
1649                 if (tevent_req_nomem(subreq, req)) {
1650                         return;
1651                 }
1652                 tevent_req_set_callback(subreq, winexe_ctrl_pipe_closed, req);
1653                 return;
1654         }
1655         if (tevent_req_nterror(req, status)) {
1656                 return;
1657         }
1658
1659         DBG_DEBUG("Got %zu bytes\n", received);
1660
1661         timeout = state->cli->timeout;
1662         state->cli->timeout = 0;
1663
1664         subreq = cli_read_send(
1665                 state,
1666                 state->ev,
1667                 state->cli,
1668                 state->ctrl_pipe,
1669                 state->ctrl_inbuf,
1670                 0,
1671                 sizeof(state->ctrl_inbuf)-1);
1672
1673         state->cli->timeout = timeout;
1674
1675         if (tevent_req_nomem(subreq, req)) {
1676                 return;
1677         }
1678         tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
1679
1680         ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &version);
1681         if (ret == 1) {
1682                 DBG_DEBUG("Got version %x\n", version);
1683
1684                 subreq = cli_writeall_send(
1685                         state,
1686                         state->ev,
1687                         state->cli,
1688                         state->ctrl_pipe,
1689                         0,
1690                         (const uint8_t *)state->cmd,
1691                         0,
1692                         strlen(state->cmd));
1693                 if (tevent_req_nomem(subreq, req)) {
1694                         return;
1695                 }
1696                 tevent_req_set_callback(subreq, winexe_ctrl_wrote_cmd, req);
1697                 return;
1698         }
1699
1700         ret = strncmp(state->ctrl_inbuf, "std_io_err ", strlen("std_io_err "));
1701         if (ret == 0) {
1702                 char *p = state->ctrl_inbuf + 11;
1703                 char *q = strchr(state->ctrl_inbuf, '\n');
1704                 char *postfix;
1705                 size_t postfix_len;
1706
1707                 if (q == NULL) {
1708                         DBG_DEBUG("Got invalid pipe postfix\n");
1709                         return;
1710                 }
1711
1712                 postfix_len = q - p;
1713
1714                 postfix = talloc_strndup(state, p, postfix_len);
1715                 if (tevent_req_nomem(postfix, req)) {
1716                         return;
1717                 }
1718
1719                 DBG_DEBUG("Got pipe postfix %s\n", postfix);
1720
1721                 subreq = winexe_pipes_send(
1722                         state,
1723                         state->ev,
1724                         state->cli,
1725                         postfix);
1726                 if (tevent_req_nomem(subreq, req)) {
1727                         return;
1728                 }
1729                 tevent_req_set_callback(subreq, winexe_ctrl_pipes_done, req);
1730
1731                 state->pipes_req = subreq;
1732
1733                 return;
1734         }
1735
1736         ret = strncmp(state->ctrl_inbuf, "error ", strlen("error "));
1737         if (ret == 0) {
1738                 printf("Error: %s", state->ctrl_inbuf);
1739                 return;
1740         }
1741
1742         ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &return_code);
1743         if (ret == 1) {
1744                 state->return_code = return_code;
1745                 return;
1746         }
1747 }
1748
1749 static void winexe_ctrl_wrote_version(struct tevent_req *subreq)
1750 {
1751         struct tevent_req *req = tevent_req_callback_data(
1752                 subreq, struct tevent_req);
1753         NTSTATUS status;
1754
1755         status = cli_writeall_recv(subreq, NULL);
1756         TALLOC_FREE(subreq);
1757         if (tevent_req_nterror(req, status)) {
1758                 return;
1759         }
1760 }
1761
1762 static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq)
1763 {
1764         struct tevent_req *req = tevent_req_callback_data(
1765                 subreq, struct tevent_req);
1766         NTSTATUS status;
1767
1768         status = cli_writeall_recv(subreq, NULL);
1769         TALLOC_FREE(subreq);
1770         if (tevent_req_nterror(req, status)) {
1771                 return;
1772         }
1773 }
1774
1775 static void winexe_ctrl_pipe_closed(struct tevent_req *subreq)
1776 {
1777         struct tevent_req *req = tevent_req_callback_data(
1778                 subreq, struct tevent_req);
1779         struct winexe_ctrl_state *state = tevent_req_data(
1780                 req, struct winexe_ctrl_state);
1781         NTSTATUS status;
1782
1783         status = cli_close_recv(subreq);
1784         TALLOC_FREE(subreq);
1785         if (tevent_req_nterror(req, status)) {
1786                 return;
1787         }
1788
1789         state->ctrl_pipe_done = true;
1790         if (state->pipes_req == NULL) {
1791                 tevent_req_done(req);
1792         }
1793 }
1794
1795 static void winexe_ctrl_pipes_done(struct tevent_req *subreq)
1796 {
1797         struct tevent_req *req = tevent_req_callback_data(
1798                 subreq, struct tevent_req);
1799         struct winexe_ctrl_state *state = tevent_req_data(
1800                 req, struct winexe_ctrl_state);
1801         NTSTATUS status;
1802
1803         status = winexe_pipes_recv(subreq);
1804         TALLOC_FREE(subreq);
1805         if (tevent_req_nterror(req, status)) {
1806                 return;
1807         }
1808
1809         state->pipes_req = NULL;
1810         if (state->ctrl_pipe_done) {
1811                 tevent_req_done(req);
1812         }
1813 }
1814
1815 static NTSTATUS winexe_ctrl_recv(struct tevent_req *req,
1816                                  int *preturn_code)
1817 {
1818         struct winexe_ctrl_state *state = tevent_req_data(
1819                 req, struct winexe_ctrl_state);
1820         NTSTATUS status;
1821
1822         if (tevent_req_is_nterror(req, &status)) {
1823                 return status;
1824         }
1825         if (preturn_code != NULL) {
1826                 *preturn_code = state->return_code;
1827         }
1828         return NT_STATUS_OK;
1829 }
1830
1831 static NTSTATUS winexe_ctrl(struct cli_state *cli,
1832                             const char *cmd,
1833                             int *preturn_code)
1834 {
1835         struct tevent_context *ev = NULL;
1836         struct tevent_req *req = NULL;
1837         NTSTATUS status = NT_STATUS_NO_MEMORY;
1838         bool ok;
1839
1840         ev = samba_tevent_context_init(cli);
1841         if (ev == NULL) {
1842                 goto done;
1843         }
1844         req = winexe_ctrl_send(ev, ev, cli, cmd);
1845         if (req == NULL) {
1846                 goto done;
1847         }
1848         ok = tevent_req_poll_ntstatus(req, ev, &status);
1849         if (!ok) {
1850                 goto done;
1851         }
1852         status = winexe_ctrl_recv(req, preturn_code);
1853 done:
1854         TALLOC_FREE(req);
1855         TALLOC_FREE(ev);
1856         return status;
1857 }
1858
1859 #ifdef HAVE_WINEXE_CC_WIN32
1860 const DATA_BLOB *winexesvc32_exe_binary(void);
1861 #endif
1862
1863 #ifdef HAVE_WINEXE_CC_WIN64
1864 const DATA_BLOB *winexesvc64_exe_binary(void);
1865 #endif
1866
1867 int main(int argc, const char *argv[])
1868 {
1869         TALLOC_CTX *frame = talloc_stackframe();
1870         struct program_options options = {0};
1871         struct loadparm_context *lp_ctx;
1872         struct cli_state *cli;
1873         const char *service_name = SERVICE_NAME;
1874         char *service_filename = NULL;
1875 #ifdef HAVE_WINEXE_CC_WIN32
1876         const DATA_BLOB *winexesvc32_exe = winexesvc32_exe_binary();
1877 #else
1878         const DATA_BLOB *winexesvc32_exe = NULL;
1879 #endif
1880 #ifdef HAVE_WINEXE_CC_WIN64
1881         const DATA_BLOB *winexesvc64_exe = winexesvc64_exe_binary();
1882 #else
1883         const DATA_BLOB *winexesvc64_exe = NULL;
1884 #endif
1885         NTSTATUS status;
1886         int ret = 1;
1887         int return_code = 0;
1888
1889         lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
1890         if (lp_ctx == NULL) {
1891                 fprintf(stderr, "loadparm_init_s3 failed\n");
1892                 goto done;
1893         }
1894
1895         smb_init_locale();
1896         setup_logging("winexe", DEBUG_STDOUT);
1897
1898         lp_load_global(get_dyn_CONFIGFILE());
1899
1900         parse_args(argc, argv, frame, &options, lp_ctx);
1901
1902         if (options.cmd == NULL) {
1903                 fprintf(stderr, "no cmd given\n");
1904                 goto done;
1905         }
1906
1907         service_filename = talloc_asprintf(frame, "%s.exe", service_name);
1908         if (service_filename == NULL) {
1909                 DBG_WARNING("talloc_asprintf failed\n");
1910                 goto done;
1911         }
1912
1913         status = cli_full_connection_creds(
1914                 &cli,
1915                 NULL,
1916                 options.hostname,
1917                 NULL,
1918                 options.port,
1919                 "IPC$",
1920                 "?????",
1921                 options.credentials,
1922                 0,
1923                 0);
1924
1925         if (!NT_STATUS_IS_OK(status)) {
1926                 DBG_WARNING("cli_full_connection_creds failed: %s\n",
1927                             nt_errstr(status));
1928                 goto done;
1929         }
1930
1931         status = winexe_svc_install(
1932                 cli,
1933                 options.hostname,
1934                 options.port,
1935                 service_name,
1936                 service_filename,
1937                 winexesvc32_exe,
1938                 winexesvc64_exe,
1939                 options.credentials,
1940                 options.flags);
1941         if (!NT_STATUS_IS_OK(status)) {
1942                 DBG_WARNING("winexe_svc_install failed: %s\n",
1943                             nt_errstr(status));
1944                 goto done;
1945         }
1946
1947         status = winexe_ctrl(cli, options.cmd, &return_code);
1948         if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
1949                 /* Normal finish */
1950                 status = NT_STATUS_OK;
1951         }
1952         if (!NT_STATUS_IS_OK(status)) {
1953                 DBG_WARNING("cli_ctrl failed: %s\n",
1954                             nt_errstr(status));
1955                 goto done;
1956         }
1957
1958         if (options.flags & SVC_UNINSTALL) {
1959                 status = winexe_svc_uninstall(
1960                         cli,
1961                         service_name);
1962                 if (!NT_STATUS_IS_OK(status)) {
1963                         DBG_WARNING("winexe_svc_uninstall failed: %s\n",
1964                                     nt_errstr(status));
1965                         goto done;
1966                 }
1967         }
1968
1969         ret = return_code;
1970 done:
1971         TALLOC_FREE(frame);
1972         return ret;
1973 }