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