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