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