7348595c98215a977c414b11c4b1b38016c4ba6d
[samba.git] / source3 / utils / net_rpc_printer.c
1 /*
2    Samba Unix/Linux SMB client library
3    Distributed SMB/CIFS Server Management Utility
4    Copyright (C) 2004,2009 Guenther Deschner (gd@samba.org)
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 #include "includes.h"
20 #include "system/filesys.h"
21 #include "utils/net.h"
22 #include "rpc_client/rpc_client.h"
23 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
24 #include "rpc_client/cli_spoolss.h"
25 #include "rpc_client/init_spoolss.h"
26 #include "nt_printing.h"
27 #include "registry.h"
28 #include "../libcli/security/security.h"
29 #include "../libcli/registry/util_reg.h"
30 #include "libsmb/libsmb.h"
31 #include "../libcli/smb/smbXcli_base.h"
32
33 /* support itanium as well */
34 static const struct print_architecture_table_node archi_table[]= {
35
36         {"Windows 4.0",          "WIN40",       0 },
37         {"Windows NT x86",       "W32X86",      2 },
38         {"Windows NT x86",       "W32X86",      3 },
39         {"Windows NT R4000",     "W32MIPS",     2 },
40         {"Windows NT Alpha_AXP", "W32ALPHA",    2 },
41         {"Windows NT PowerPC",   "W32PPC",      2 },
42         {"Windows IA64",         "IA64",        3 },
43         {"Windows x64",          "x64",         3 },
44         {NULL,                   "",            -1 }
45 };
46
47
48 /**
49  * This display-printdriver-functions was borrowed from rpcclient/cmd_spoolss.c.
50  * It is here for debugging purpose and should be removed later on.
51  **/
52
53 /****************************************************************************
54  Printer info level 3 display function.
55 ****************************************************************************/
56
57 static void display_print_driver3(struct spoolss_DriverInfo3 *r)
58 {
59         int i;
60
61         if (!r) {
62                 return;
63         }
64
65         printf(_("Printer Driver Info 3:\n"));
66         printf(_("\tVersion: [%x]\n"), r->version);
67         printf(_("\tDriver Name: [%s]\n"), r->driver_name);
68         printf(_("\tArchitecture: [%s]\n"), r->architecture);
69         printf(_("\tDriver Path: [%s]\n"), r->driver_path);
70         printf(_("\tDatafile: [%s]\n"), r->data_file);
71         printf(_("\tConfigfile: [%s]\n\n"), r->config_file);
72         printf(_("\tHelpfile: [%s]\n\n"), r->help_file);
73
74         for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
75                 printf(_("\tDependentfiles: [%s]\n"), r->dependent_files[i]);
76         }
77
78         printf("\n");
79
80         printf(_("\tMonitorname: [%s]\n"), r->monitor_name);
81         printf(_("\tDefaultdatatype: [%s]\n\n"), r->default_datatype);
82 }
83
84 static void display_reg_value(const char *subkey, const char *name, struct registry_value *value)
85 {
86         const char *text;
87
88         switch(value->type) {
89         case REG_DWORD:
90                 if (value->data.length == sizeof(uint32)) {
91                         d_printf(_("\t[%s:%s]: REG_DWORD: 0x%08x\n"), subkey,
92                                  name, IVAL(value->data.data,0));
93                 } else {
94                         d_printf(_("\t[%s:%s]: REG_DWORD: <invalid>\n"), subkey,
95                                  name);
96                 }
97                 break;
98
99         case REG_SZ:
100                 pull_reg_sz(talloc_tos(), &value->data, &text);
101                 if (!text) {
102                         break;
103                 }
104                 d_printf(_("\t[%s:%s]: REG_SZ: %s\n"), subkey, name, text);
105                 break;
106
107         case REG_BINARY:
108                 d_printf(_("\t[%s:%s]: REG_BINARY: unknown length value not "
109                            "displayed\n"),
110                          subkey, name);
111                 break;
112
113         case REG_MULTI_SZ: {
114                 uint32_t i;
115                 const char **values;
116
117                 if (!pull_reg_multi_sz(NULL, &value->data, &values)) {
118                         d_printf("pull_reg_multi_sz failed\n");
119                         break;
120                 }
121
122                 printf("%s: REG_MULTI_SZ: \n", name);
123                 for (i=0; values[i] != NULL; i++) {
124                         d_printf("%s\n", values[i]);
125                 }
126                 TALLOC_FREE(values);
127                 break;
128         }
129
130         default:
131                 d_printf(_("\t%s: unknown type %d\n"), name, value->type);
132         }
133
134 }
135
136 /**
137  * Copies ACLs, DOS-attributes and timestamps from one
138  * file or directory from one connected share to another connected share
139  *
140  * @param c                     A net_context structure
141  * @param mem_ctx               A talloc-context
142  * @param cli_share_src         A connected cli_state
143  * @param cli_share_dst         A connected cli_state
144  * @param src_file              The source file-name
145  * @param dst_file              The destination file-name
146  * @param copy_acls             Whether to copy acls
147  * @param copy_attrs            Whether to copy DOS attributes
148  * @param copy_timestamps       Whether to preserve timestamps
149  * @param is_file               Whether this file is a file or a dir
150  *
151  * @return Normal NTSTATUS return.
152  **/
153
154 NTSTATUS net_copy_fileattr(struct net_context *c,
155                   TALLOC_CTX *mem_ctx,
156                   struct cli_state *cli_share_src,
157                   struct cli_state *cli_share_dst,
158                   const char *src_name, const char *dst_name,
159                   bool copy_acls, bool copy_attrs,
160                   bool copy_timestamps, bool is_file)
161 {
162         NTSTATUS nt_status;
163         uint16_t fnum_src = 0;
164         uint16_t fnum_dst = 0;
165         struct security_descriptor *sd = NULL;
166         uint16_t attr;
167         time_t f_atime, f_ctime, f_mtime;
168
169         if (!copy_timestamps && !copy_acls && !copy_attrs)
170                 return NT_STATUS_OK;
171
172         /* open file/dir on the originating server */
173
174         DEBUGADD(3,("opening %s %s on originating server\n",
175                 is_file?"file":"dir", src_name));
176
177         nt_status = cli_ntcreate(cli_share_src, src_name, 0,
178                                  READ_CONTROL_ACCESS, 0,
179                                  FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN,
180                                  0x0, 0x0, &fnum_src);
181         if (!NT_STATUS_IS_OK(nt_status)) {
182                 DEBUGADD(0,("cannot open %s %s on originating server %s\n",
183                         is_file?"file":"dir", src_name, nt_errstr(nt_status)));
184                 goto out;
185         }
186
187         if (copy_acls) {
188                 /* get the security descriptor */
189                 nt_status = cli_query_secdesc(cli_share_src, fnum_src,
190                                               mem_ctx, &sd);
191                 if (!NT_STATUS_IS_OK(nt_status)) {
192                         DEBUG(0,("failed to get security descriptor: %s\n",
193                                  nt_errstr(nt_status)));
194                         goto out;
195                 }
196
197                 if (c->opt_verbose && DEBUGLEVEL >= 3)
198                         display_sec_desc(sd);
199         }
200
201         if (copy_attrs || copy_timestamps) {
202
203                 /* get file attributes */
204                 nt_status = cli_getattrE(cli_share_src, fnum_src, &attr, NULL,
205                                       &f_ctime, &f_atime, &f_mtime);
206                 if (!NT_STATUS_IS_OK(nt_status)) {
207                         DEBUG(0,("failed to get file-attrs: %s\n",
208                                 nt_errstr(nt_status)));
209                         goto out;
210                 }
211         }
212
213         /* open the file/dir on the destination server */
214         nt_status = cli_ntcreate(cli_share_dst, dst_name, 0,
215                                  WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS, 0,
216                                  FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN,
217                                  0x0, 0x0, &fnum_dst);
218         if (!NT_STATUS_IS_OK(nt_status)) {
219                 DEBUG(0,("failed to open %s on the destination server: %s: %s\n",
220                         is_file?"file":"dir", dst_name, nt_errstr(nt_status)));
221                 goto out;
222         }
223
224         if (copy_timestamps) {
225                 /* set timestamps */
226                 nt_status = cli_setattrE(cli_share_dst, fnum_dst, f_ctime, f_atime, f_mtime);
227                 if (!NT_STATUS_IS_OK(nt_status)) {
228                         DEBUG(0,("failed to set file-attrs (timestamps): %s\n",
229                                 nt_errstr(nt_status)));
230                         goto out;
231                 }
232         }
233
234         if (copy_acls) {
235                 /* set acls */
236                 nt_status = cli_set_secdesc(cli_share_dst, fnum_dst, sd);
237                 if (!NT_STATUS_IS_OK(nt_status)) {
238                         DEBUG(0, ("could not set secdesc on %s: %s\n",
239                                   dst_name, nt_errstr(nt_status)));
240                         goto out;
241                 }
242         }
243
244         if (copy_attrs) {
245                 /* set attrs */
246                 nt_status = cli_setatr(cli_share_dst, dst_name, attr, 0);
247                 if (!NT_STATUS_IS_OK(nt_status)) {
248                         DEBUG(0,("failed to set file-attrs: %s\n",
249                                 nt_errstr(nt_status)));
250                         goto out;
251                 }
252         }
253
254
255         /* closing files */
256         nt_status = cli_close(cli_share_src, fnum_src);
257         if (!NT_STATUS_IS_OK(nt_status)) {
258                 d_fprintf(stderr,
259                         _("could not close %s on originating server: %s\n"),
260                         is_file?"file":"dir", nt_errstr(nt_status));
261                 goto out;
262         }
263
264         nt_status = cli_close(cli_share_dst, fnum_dst);
265         if (!NT_STATUS_IS_OK(nt_status)) {
266                 d_fprintf(stderr,
267                         _("could not close %s on destination server: %s\n"),
268                         is_file?"file":"dir", nt_errstr(nt_status));
269                 goto out;
270         }
271
272
273         nt_status = NT_STATUS_OK;
274
275 out:
276
277         /* cleaning up */
278         if (fnum_src)
279                 cli_close(cli_share_src, fnum_src);
280
281         if (fnum_dst)
282                 cli_close(cli_share_dst, fnum_dst);
283
284         return nt_status;
285 }
286
287 /**
288  * Copy a file or directory from a connected share to another connected share
289  *
290  * @param c                     A net_context structure
291  * @param mem_ctx               A talloc-context
292  * @param cli_share_src         A connected cli_state
293  * @param cli_share_dst         A connected cli_state
294  * @param src_file              The source file-name
295  * @param dst_file              The destination file-name
296  * @param copy_acls             Whether to copy acls
297  * @param copy_attrs            Whether to copy DOS attributes
298  * @param copy_timestamps       Whether to preserve timestamps
299  * @param is_file               Whether this file is a file or a dir
300  *
301  * @return Normal NTSTATUS return.
302  **/
303
304 NTSTATUS net_copy_file(struct net_context *c,
305                        TALLOC_CTX *mem_ctx,
306                        struct cli_state *cli_share_src,
307                        struct cli_state *cli_share_dst,
308                        const char *src_name, const char *dst_name,
309                        bool copy_acls, bool copy_attrs,
310                        bool copy_timestamps, bool is_file)
311 {
312         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
313         uint16_t fnum_src = 0;
314         uint16_t fnum_dst = 0;
315         static int io_bufsize = 64512;
316         int read_size = io_bufsize;
317         char *data = NULL;
318         off_t nread = 0;
319
320
321         if (!src_name || !dst_name)
322                 goto out;
323
324         if (cli_share_src == NULL || cli_share_dst == NULL)
325                 goto out;
326
327         /* open on the originating server */
328         DEBUGADD(3,("opening %s %s on originating server\n",
329                 is_file ? "file":"dir", src_name));
330         if (is_file)
331                 nt_status = cli_open(cli_share_src, src_name, O_RDONLY, DENY_NONE, &fnum_src);
332         else
333                 nt_status = cli_ntcreate(cli_share_src, src_name, 0, READ_CONTROL_ACCESS, 0,
334                                 FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum_src);
335
336         if (!NT_STATUS_IS_OK(nt_status)) {
337                 DEBUGADD(0,("cannot open %s %s on originating server %s\n",
338                         is_file ? "file":"dir",
339                         src_name, nt_errstr(nt_status)));
340                 goto out;
341         }
342
343
344         if (is_file) {
345
346                 /* open file on the destination server */
347                 DEBUGADD(3,("opening file %s on destination server\n", dst_name));
348                 nt_status = cli_open(cli_share_dst, dst_name,
349                                 O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum_dst);
350
351                 if (!NT_STATUS_IS_OK(nt_status)) {
352                         DEBUGADD(1,("cannot create file %s on destination server: %s\n", 
353                                 dst_name, nt_errstr(nt_status)));
354                         goto out;
355                 }
356
357                 /* allocate memory */
358                 if (!(data = (char *)SMB_MALLOC(read_size))) {
359                         d_fprintf(stderr, _("malloc fail for size %d\n"),
360                                   read_size);
361                         nt_status = NT_STATUS_NO_MEMORY;
362                         goto out;
363                 }
364
365         }
366
367
368         if (c->opt_verbose) {
369
370                 d_printf(_("copying [\\\\%s\\%s%s] => [\\\\%s\\%s%s] "
371                            "%s ACLs and %s DOS Attributes %s\n"),
372                         cli_state_remote_name(cli_share_src),
373                         cli_share_src->share, src_name,
374                         cli_state_remote_name(cli_share_dst),
375                         cli_share_dst->share, dst_name,
376                         copy_acls ?  _("with") : _("without"),
377                         copy_attrs ? _("with") : _("without"),
378                         copy_timestamps ? _("(preserving timestamps)") : "" );
379         }
380
381
382         while (is_file) {
383
384                 /* copying file */
385                 size_t n;
386
387                 nt_status = cli_read(cli_share_src, fnum_src, data, nread,
388                                      read_size, &n);
389                 if (!NT_STATUS_IS_OK(nt_status)) {
390                         d_fprintf(stderr,
391                                   _("Error reading file [\\\\%s\\%s%s]: %s\n"),
392                                   cli_state_remote_name(cli_share_src),
393                                   cli_share_src->share,
394                                   src_name, nt_errstr(nt_status));
395                         goto out;
396                 }
397
398                 if (n == 0)
399                         break;
400
401                 nt_status = cli_writeall(cli_share_dst, fnum_dst, 0,
402                                          (uint8_t *)data, nread, n, NULL);
403
404                 if (!NT_STATUS_IS_OK(nt_status)) {
405                         d_fprintf(stderr,
406                                   _("Error writing file: [\\\\%s\\%s%s]: %s\n"),
407                                   cli_state_remote_name(cli_share_dst),
408                                   cli_share_dst->share,
409                                   dst_name, nt_errstr(nt_status));
410                         goto out;
411                 }
412
413                 nread += n;
414         }
415
416
417         if (!is_file && !NT_STATUS_IS_OK(cli_chkpath(cli_share_dst, dst_name))) {
418
419                 /* creating dir */
420                 DEBUGADD(3,("creating dir %s on the destination server\n",
421                         dst_name));
422
423                 nt_status = cli_mkdir(cli_share_dst, dst_name);
424                 if (!NT_STATUS_IS_OK(nt_status)) {
425                         DEBUG(0,("cannot create directory %s: %s\n",
426                                 dst_name, nt_errstr(nt_status)));
427                         nt_status = NT_STATUS_NO_SUCH_FILE;
428                 }
429
430
431                 nt_status = cli_chkpath(cli_share_dst, dst_name);
432                 if (!NT_STATUS_IS_OK(nt_status)) {
433                         d_fprintf(stderr,
434                                 _("cannot check for directory %s: %s\n"),
435                                 dst_name, nt_errstr(nt_status));
436                         goto out;
437                 }
438         }
439
440
441         /* closing files */
442         nt_status = cli_close(cli_share_src, fnum_src);
443         if (!NT_STATUS_IS_OK(nt_status)) {
444                 d_fprintf(stderr,
445                         _("could not close file on originating server: %s\n"),
446                         nt_errstr(nt_status));
447                 goto out;
448         }
449
450         if (is_file) {
451                 nt_status = cli_close(cli_share_dst, fnum_dst);
452                 if (!NT_STATUS_IS_OK(nt_status)) {
453                         d_fprintf(stderr,
454                         _("could not close file on destination server: %s\n"),
455                         nt_errstr(nt_status));
456                         goto out;
457                 }
458         }
459
460         /* possibly we have to copy some file-attributes / acls / sd */
461         nt_status = net_copy_fileattr(c, mem_ctx, cli_share_src, cli_share_dst,
462                                       src_name, dst_name, copy_acls,
463                                       copy_attrs, copy_timestamps, is_file);
464         if (!NT_STATUS_IS_OK(nt_status))
465                 goto out;
466
467
468         nt_status = NT_STATUS_OK;
469
470 out:
471
472         /* cleaning up */
473         if (fnum_src)
474                 cli_close(cli_share_src, fnum_src);
475
476         if (fnum_dst)
477                 cli_close(cli_share_dst, fnum_dst);
478
479         SAFE_FREE(data);
480
481         return nt_status;
482 }
483
484 /**
485  * Copy a driverfile from on connected share to another connected share
486  * This silently assumes that a driver-file is picked up from
487  *
488  *      \\src_server\print$\{arch}\{version}\file
489  *
490  * and copied to
491  *
492  *      \\dst_server\print$\{arch}\file
493  *
494  * to be added via setdriver-calls later.
495  * @param c                     A net_context structure
496  * @param mem_ctx               A talloc-context
497  * @param cli_share_src         A cli_state connected to source print$-share
498  * @param cli_share_dst         A cli_state connected to destination print$-share
499  * @param file                  The file-name to be copied
500  * @param short_archi           The name of the driver-architecture (short form)
501  *
502  * @return Normal NTSTATUS return.
503  **/
504
505 static NTSTATUS net_copy_driverfile(struct net_context *c,
506                                     TALLOC_CTX *mem_ctx,
507                                     struct cli_state *cli_share_src,
508                                     struct cli_state *cli_share_dst,
509                                     const char *file, const char *short_archi) {
510
511         const char *p;
512         char *src_name;
513         char *dst_name;
514         char *version = NULL;
515         char *filename = NULL;
516         char *tok;
517
518         if (!file) {
519                 return NT_STATUS_OK;
520         }
521
522         /* scroll through the file until we have the part
523            beyond archi_table.short_archi */
524         p = file;
525         while (next_token_talloc(mem_ctx, &p, &tok, "\\")) {
526                 if (strequal(tok, short_archi)) {
527                         next_token_talloc(mem_ctx, &p, &version, "\\");
528                         next_token_talloc(mem_ctx, &p, &filename, "\\");
529                 }
530         }
531
532         if (version == NULL || filename == NULL) {
533                 return NT_STATUS_UNSUCCESSFUL;
534         }
535
536         /* build source file name */
537         src_name = talloc_asprintf(mem_ctx, "\\%s\\%s\\%s",
538                                    short_archi, version, filename);
539         if (src_name == NULL) {
540                 return NT_STATUS_NO_MEMORY;
541         }
542
543         /* create destination file name */
544         dst_name = talloc_asprintf(mem_ctx, "\\%s\\%s", short_archi, filename);
545         if (dst_name == NULL) {
546                 return NT_STATUS_NO_MEMORY;
547         }
548
549
550         /* finally copy the file */
551         return net_copy_file(c, mem_ctx, cli_share_src, cli_share_dst,
552                              src_name, dst_name, false, false, false, true);
553 }
554
555 /**
556  * Check for existing Architecture directory on a given server
557  *
558  * @param cli_share             A cli_state connected to a print$-share
559  * @param short_archi           The Architecture for the print-driver
560  *
561  * @return Normal NTSTATUS return.
562  **/
563
564 static NTSTATUS check_arch_dir(struct cli_state *cli_share, const char *short_archi)
565 {
566
567         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
568         char *dir;
569
570         if (asprintf(&dir, "\\%s", short_archi) < 0) {
571                 return NT_STATUS_NO_MEMORY;
572         }
573
574         DEBUG(10,("creating print-driver dir for architecture: %s\n",
575                 short_archi));
576
577         nt_status = cli_mkdir(cli_share, dir);
578         if (!NT_STATUS_IS_OK(nt_status)) {
579                 DEBUG(1,("cannot create directory %s: %s\n",
580                          dir, nt_errstr(nt_status)));
581         }
582
583         nt_status = cli_chkpath(cli_share, dir);
584         if (!NT_STATUS_IS_OK(nt_status)) {
585                 d_fprintf(stderr, _("cannot check %s: %s\n"),
586                         dir, nt_errstr(nt_status));
587                 goto out;
588         }
589
590         nt_status = NT_STATUS_OK;
591
592 out:
593         SAFE_FREE(dir);
594         return nt_status;
595 }
596
597 /**
598  * Copy a print-driver (level 3) from one connected print$-share to another
599  * connected print$-share
600  *
601  * @param c                     A net_context structure
602  * @param mem_ctx               A talloc-context
603  * @param cli_share_src         A cli_state connected to a print$-share
604  * @param cli_share_dst         A cli_state connected to a print$-share
605  * @param short_archi           The Architecture for the print-driver
606  * @param i1                    The DRIVER_INFO_3-struct
607  *
608  * @return Normal NTSTATUS return.
609  **/
610
611 static NTSTATUS copy_print_driver_3(struct net_context *c,
612                     TALLOC_CTX *mem_ctx,
613                     struct cli_state *cli_share_src,
614                     struct cli_state *cli_share_dst,
615                     const char *short_archi,
616                     struct spoolss_DriverInfo3 *r)
617 {
618         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
619         int i;
620
621         if (r == NULL) {
622                 return nt_status;
623         }
624
625         if (c->opt_verbose)
626                 d_printf(_("copying driver: [%s], for architecture: [%s], "
627                            "version: [%d]\n"),
628                           r->driver_name, short_archi, r->version);
629
630         nt_status = net_copy_driverfile(c, mem_ctx, cli_share_src, cli_share_dst,
631                 r->driver_path, short_archi);
632         if (!NT_STATUS_IS_OK(nt_status))
633                 return nt_status;
634
635         nt_status = net_copy_driverfile(c, mem_ctx, cli_share_src, cli_share_dst,
636                 r->data_file, short_archi);
637         if (!NT_STATUS_IS_OK(nt_status))
638                 return nt_status;
639
640         nt_status = net_copy_driverfile(c, mem_ctx, cli_share_src, cli_share_dst,
641                 r->config_file, short_archi);
642         if (!NT_STATUS_IS_OK(nt_status))
643                 return nt_status;
644
645         nt_status = net_copy_driverfile(c, mem_ctx, cli_share_src, cli_share_dst,
646                 r->help_file, short_archi);
647         if (!NT_STATUS_IS_OK(nt_status))
648                 return nt_status;
649
650         for (i=0; r->dependent_files[i] != NULL; i++) {
651
652                 nt_status = net_copy_driverfile(c, mem_ctx,
653                                 cli_share_src, cli_share_dst,
654                                 r->dependent_files[i], short_archi);
655                 if (!NT_STATUS_IS_OK(nt_status)) {
656                         return nt_status;
657                 }
658         }
659
660         return NT_STATUS_OK;
661 }
662
663 /**
664  * net_spoolss-functions
665  * =====================
666  *
667  * the net_spoolss-functions aim to simplify spoolss-client-functions
668  * required during the migration-process wrt buffer-sizes, returned
669  * error-codes, etc.
670  *
671  * this greatly reduces the complexitiy of the migrate-functions.
672  *
673  **/
674
675 static bool net_spoolss_enum_printers(struct rpc_pipe_client *pipe_hnd,
676                                         TALLOC_CTX *mem_ctx,
677                                         char *name,
678                                         uint32_t flags,
679                                         uint32_t level,
680                                         uint32_t *num_printers,
681                                         union spoolss_PrinterInfo **info)
682 {
683         WERROR result;
684
685         /* enum printers */
686
687         result = rpccli_spoolss_enumprinters(pipe_hnd, mem_ctx,
688                                              flags,
689                                              name,
690                                              level,
691                                              0,
692                                              num_printers,
693                                              info);
694         if (!W_ERROR_IS_OK(result)) {
695                 printf(_("cannot enum printers: %s\n"), win_errstr(result));
696                 return false;
697         }
698
699         return true;
700 }
701
702 static bool net_spoolss_open_printer_ex(struct rpc_pipe_client *pipe_hnd,
703                                         TALLOC_CTX *mem_ctx,
704                                         const char *printername,
705                                         uint32_t access_required,
706                                         const char *username,
707                                         struct policy_handle *hnd)
708 {
709         WERROR result;
710         fstring printername2;
711
712         fstrcpy(printername2, pipe_hnd->srv_name_slash);
713         fstrcat(printername2, "\\");
714         fstrcat(printername2, printername);
715
716         DEBUG(10,("connecting to: %s as %s for %s and access: %x\n",
717                 pipe_hnd->srv_name_slash, username, printername2, access_required));
718
719         /* open printer */
720         result = rpccli_spoolss_openprinter_ex(pipe_hnd, mem_ctx,
721                                                printername2,
722                                                access_required,
723                                                hnd);
724
725         /* be more verbose */
726         if (W_ERROR_V(result) == W_ERROR_V(WERR_ACCESS_DENIED)) {
727                 d_fprintf(stderr,
728                         _("no access to printer [%s] on [%s] for user [%s] "
729                           "granted\n"),
730                         printername2, pipe_hnd->srv_name_slash, username);
731                 return false;
732         }
733
734         if (!W_ERROR_IS_OK(result)) {
735                 d_fprintf(stderr,_("cannot open printer %s on server %s: %s\n"),
736                         printername2, pipe_hnd->srv_name_slash, win_errstr(result));
737                 return false;
738         }
739
740         DEBUG(2,("got printer handle for printer: %s, server: %s\n",
741                 printername2, pipe_hnd->srv_name_slash));
742
743         return true;
744 }
745
746 static bool net_spoolss_getprinter(struct rpc_pipe_client *pipe_hnd,
747                                 TALLOC_CTX *mem_ctx,
748                                 struct policy_handle *hnd,
749                                 uint32_t level,
750                                 union spoolss_PrinterInfo *info)
751 {
752         WERROR result;
753
754         /* getprinter call */
755         result = rpccli_spoolss_getprinter(pipe_hnd, mem_ctx,
756                                            hnd,
757                                            level,
758                                            0, /* offered */
759                                            info);
760         if (!W_ERROR_IS_OK(result)) {
761                 printf(_("cannot get printer-info: %s\n"), win_errstr(result));
762                 return false;
763         }
764
765         return true;
766 }
767
768 static bool net_spoolss_setprinter(struct rpc_pipe_client *pipe_hnd,
769                                 TALLOC_CTX *mem_ctx,
770                                 struct policy_handle *hnd,
771                                 uint32_t level,
772                                 union spoolss_PrinterInfo *info)
773 {
774         struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
775         WERROR result;
776         NTSTATUS status;
777         struct spoolss_SetPrinterInfoCtr info_ctr;
778         struct spoolss_SetPrinterInfo2 info2;
779         struct spoolss_DevmodeContainer devmode_ctr;
780         struct sec_desc_buf secdesc_ctr;
781
782         ZERO_STRUCT(devmode_ctr);
783         ZERO_STRUCT(secdesc_ctr);
784
785         /* setprinter call */
786
787         info_ctr.level = level;
788         switch (level) {
789         case 0:
790                 info_ctr.info.info0 = (struct spoolss_SetPrinterInfo0 *)
791                         (void *)&info->info0;
792                 break;
793         case 1:
794                 info_ctr.info.info1 = (struct spoolss_SetPrinterInfo1 *)
795                         (void *)&info->info1;
796                 break;
797         case 2:
798                 spoolss_printerinfo2_to_setprinterinfo2(&info->info2, &info2);
799                 info_ctr.info.info2 = &info2;
800                 break;
801         case 3:
802                 info_ctr.info.info3 = (struct spoolss_SetPrinterInfo3 *)
803                         (void *)&info->info3;
804                 break;
805         case 4:
806                 info_ctr.info.info4 = (struct spoolss_SetPrinterInfo4 *)
807                         (void *)&info->info4;
808                 break;
809         case 5:
810                 info_ctr.info.info5 = (struct spoolss_SetPrinterInfo5 *)
811                         (void *)&info->info5;
812                 break;
813         case 6:
814                 info_ctr.info.info6 = (struct spoolss_SetPrinterInfo6 *)
815                         (void *)&info->info6;
816                 break;
817         case 7:
818                 info_ctr.info.info7 = (struct spoolss_SetPrinterInfo7 *)
819                         (void *)&info->info7;
820                 break;
821 #if 0 /* FIXME GD */
822         case 8:
823                 info_ctr.info.info8 = (struct spoolss_SetPrinterInfo8 *)
824                         (void *)&info->info8;
825                 break;
826         case 9:
827                 info_ctr.info.info9 = (struct spoolss_SetPrinterInfo9 *)
828                         (void *)&info->info9;
829                 break;
830 #endif
831         default:
832                 break; /* FIXME */
833         }
834
835         status = dcerpc_spoolss_SetPrinter(b, mem_ctx,
836                                            hnd,
837                                            &info_ctr,
838                                            &devmode_ctr,
839                                            &secdesc_ctr,
840                                            0, /* command */
841                                            &result);
842         if (!NT_STATUS_IS_OK(status)) {
843                 printf(_("cannot set printer-info: %s\n"), nt_errstr(status));
844                 return false;
845         }
846         if (!W_ERROR_IS_OK(result)) {
847                 printf(_("cannot set printer-info: %s\n"), win_errstr(result));
848                 return false;
849         }
850
851         return true;
852 }
853
854
855 static bool net_spoolss_setprinterdata(struct rpc_pipe_client *pipe_hnd,
856                                        TALLOC_CTX *mem_ctx,
857                                        struct policy_handle *hnd,
858                                        const char *value_name,
859                                        enum winreg_Type type,
860                                        uint8_t *data,
861                                        uint32_t offered)
862 {
863         struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
864         WERROR result;
865         NTSTATUS status;
866
867         /* setprinterdata call */
868         status = dcerpc_spoolss_SetPrinterData(b, mem_ctx,
869                                                hnd,
870                                                value_name,
871                                                type,
872                                                data,
873                                                offered,
874                                                &result);
875         if (!NT_STATUS_IS_OK(status)) {
876                 printf (_("unable to set printerdata: %s\n"),
877                         nt_errstr(status));
878                 return false;
879         }
880         if (!W_ERROR_IS_OK(result)) {
881                 printf (_("unable to set printerdata: %s\n"),
882                         win_errstr(result));
883                 return false;
884         }
885
886         return true;
887 }
888
889
890 static bool net_spoolss_enumprinterkey(struct rpc_pipe_client *pipe_hnd,
891                                         TALLOC_CTX *mem_ctx,
892                                         struct policy_handle *hnd,
893                                         const char *keyname,
894                                         const char ***keylist)
895 {
896         WERROR result;
897
898         /* enumprinterkey call */
899         result = rpccli_spoolss_enumprinterkey(pipe_hnd, mem_ctx, hnd, keyname, keylist, 0);
900
901         if (!W_ERROR_IS_OK(result)) {
902                 printf(_("enumprinterkey failed: %s\n"), win_errstr(result));
903                 return false;
904         }
905
906         return true;
907 }
908
909 static bool net_spoolss_enumprinterdataex(struct rpc_pipe_client *pipe_hnd,
910                                         TALLOC_CTX *mem_ctx,
911                                         uint32_t offered,
912                                         struct policy_handle *hnd,
913                                         const char *keyname,
914                                         uint32_t *count,
915                                         struct spoolss_PrinterEnumValues **info)
916 {
917         WERROR result;
918
919         /* enumprinterdataex call */
920         result = rpccli_spoolss_enumprinterdataex(pipe_hnd, mem_ctx,
921                                                   hnd,
922                                                   keyname,
923                                                   0, /* offered */
924                                                   count,
925                                                   info);
926
927         if (!W_ERROR_IS_OK(result)) {
928                 printf(_("enumprinterdataex failed: %s\n"), win_errstr(result));
929                 return false;
930         }
931
932         return true;
933 }
934
935
936 static bool net_spoolss_setprinterdataex(struct rpc_pipe_client *pipe_hnd,
937                                          TALLOC_CTX *mem_ctx,
938                                          struct policy_handle *hnd,
939                                          const char *keyname,
940                                          const char *name,
941                                          struct registry_value *value)
942 {
943         struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
944         WERROR result;
945         NTSTATUS status;
946
947         /* setprinterdataex call */
948         status = dcerpc_spoolss_SetPrinterDataEx(b, mem_ctx,
949                                                  hnd,
950                                                  keyname,
951                                                  name,
952                                                  value->type,
953                                                  value->data.data,
954                                                  value->data.length,
955                                                  &result);
956         if (!NT_STATUS_IS_OK(status)) {
957                 printf(_("could not set printerdataex: %s\n"),
958                        nt_errstr(status));
959                 return false;
960         }
961         if (!W_ERROR_IS_OK(result)) {
962                 printf(_("could not set printerdataex: %s\n"),
963                        win_errstr(result));
964                 return false;
965         }
966
967         return true;
968 }
969
970 static bool net_spoolss_enumforms(struct rpc_pipe_client *pipe_hnd,
971                                 TALLOC_CTX *mem_ctx,
972                                 struct policy_handle *hnd,
973                                 int level,
974                                 uint32_t *num_forms,
975                                 union spoolss_FormInfo **forms)
976 {
977         WERROR result;
978
979         /* enumforms call */
980         result = rpccli_spoolss_enumforms(pipe_hnd, mem_ctx,
981                                           hnd,
982                                           level,
983                                           0,
984                                           num_forms,
985                                           forms);
986         if (!W_ERROR_IS_OK(result)) {
987                 printf(_("could not enum forms: %s\n"), win_errstr(result));
988                 return false;
989         }
990
991         return true;
992 }
993
994 static bool net_spoolss_enumprinterdrivers (struct rpc_pipe_client *pipe_hnd,
995                                         TALLOC_CTX *mem_ctx,
996                                         uint32_t level, const char *env,
997                                         uint32_t *count,
998                                         union spoolss_DriverInfo **info)
999 {
1000         WERROR result;
1001
1002         /* enumprinterdrivers call */
1003         result = rpccli_spoolss_enumprinterdrivers(pipe_hnd, mem_ctx,
1004                                                    pipe_hnd->srv_name_slash,
1005                                                    env,
1006                                                    level,
1007                                                    0,
1008                                                    count,
1009                                                    info);
1010         if (!W_ERROR_IS_OK(result)) {
1011                 if (W_ERROR_V(result) != W_ERROR_V(WERR_INVALID_ENVIRONMENT)) {
1012                         printf(_("cannot enum drivers for environment %s: %s\n"), env,
1013                                 win_errstr(result));
1014                         return false;
1015                 } else {
1016                         printf(_("Server does not support environment [%s]\n"),
1017                                 env);
1018                 }
1019         }
1020
1021         return true;
1022 }
1023
1024 static bool net_spoolss_getprinterdriver(struct rpc_pipe_client *pipe_hnd,
1025                              TALLOC_CTX *mem_ctx,
1026                              struct policy_handle *hnd, uint32_t level,
1027                              const char *env, int version,
1028                              union spoolss_DriverInfo *info)
1029 {
1030         WERROR result;
1031         uint32_t server_major_version;
1032         uint32_t server_minor_version;
1033
1034         /* getprinterdriver call */
1035         result = rpccli_spoolss_getprinterdriver2(pipe_hnd, mem_ctx,
1036                                                   hnd,
1037                                                   env,
1038                                                   level,
1039                                                   0,
1040                                                   version,
1041                                                   2,
1042                                                   info,
1043                                                   &server_major_version,
1044                                                   &server_minor_version);
1045         if (!W_ERROR_IS_OK(result)) {
1046                 DEBUG(1,("cannot get driver (for architecture: %s): %s\n",
1047                         env, win_errstr(result)));
1048                 if (W_ERROR_V(result) != W_ERROR_V(WERR_UNKNOWN_PRINTER_DRIVER) &&
1049                     W_ERROR_V(result) != W_ERROR_V(WERR_INVALID_ENVIRONMENT)) {
1050                         printf(_("cannot get driver: %s\n"),
1051                                win_errstr(result));
1052                 }
1053                 return false;
1054         }
1055
1056         return true;
1057 }
1058
1059
1060 static bool net_spoolss_addprinterdriver(struct rpc_pipe_client *pipe_hnd,
1061                              TALLOC_CTX *mem_ctx, uint32_t level,
1062                              union spoolss_DriverInfo *info)
1063 {
1064         struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
1065         WERROR result;
1066         NTSTATUS status;
1067         struct spoolss_AddDriverInfoCtr info_ctr;
1068
1069         info_ctr.level = level;
1070
1071         switch (level) {
1072         case 2:
1073                 info_ctr.info.info2 = (struct spoolss_AddDriverInfo2 *)
1074                         (void *)&info->info2;
1075                 break;
1076         case 3:
1077                 info_ctr.info.info3 = (struct spoolss_AddDriverInfo3 *)
1078                         (void *)&info->info3;
1079                 break;
1080         default:
1081                 printf(_("unsupported info level: %d\n"), level);
1082                 return false;
1083         }
1084
1085         /* addprinterdriver call */
1086         status = dcerpc_spoolss_AddPrinterDriver(b, mem_ctx,
1087                                                  pipe_hnd->srv_name_slash,
1088                                                  &info_ctr,
1089                                                  &result);
1090         if (!NT_STATUS_IS_OK(status)) {
1091                 printf(_("cannot add driver: %s\n"), nt_errstr(status));
1092                 return false;
1093         }
1094         /* be more verbose */
1095         if (W_ERROR_V(result) == W_ERROR_V(WERR_ACCESS_DENIED)) {
1096                 printf(_("You are not allowed to add drivers\n"));
1097                 return false;
1098         }
1099         if (!W_ERROR_IS_OK(result)) {
1100                 printf(_("cannot add driver: %s\n"), win_errstr(result));
1101                 return false;
1102         }
1103
1104         return true;
1105 }
1106
1107 /**
1108  * abstraction function to get uint32_t num_printers and PRINTER_INFO_CTR ctr
1109  * for a single printer or for all printers depending on argc/argv
1110  **/
1111
1112 static bool get_printer_info(struct rpc_pipe_client *pipe_hnd,
1113                         TALLOC_CTX *mem_ctx,
1114                         int level,
1115                         int argc,
1116                         const char **argv,
1117                         uint32_t *num_printers,
1118                         union spoolss_PrinterInfo **info_p)
1119 {
1120         struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
1121         struct policy_handle hnd;
1122         WERROR werr;
1123
1124         /* no arguments given, enumerate all printers */
1125         if (argc == 0) {
1126
1127                 if (!net_spoolss_enum_printers(pipe_hnd, mem_ctx, NULL,
1128                                 PRINTER_ENUM_LOCAL|PRINTER_ENUM_SHARED,
1129                                 level, num_printers, info_p))
1130                         return false;
1131
1132                 goto out;
1133         }
1134
1135         /* argument given, get a single printer by name */
1136         if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, argv[0],
1137                                          MAXIMUM_ALLOWED_ACCESS,
1138                                          pipe_hnd->auth->user_name,
1139                                          &hnd))
1140                 return false;
1141
1142         *info_p = talloc_zero(mem_ctx, union spoolss_PrinterInfo);
1143         if (*info_p == NULL) {
1144                 return false;
1145         }
1146
1147         if (!net_spoolss_getprinter(pipe_hnd, mem_ctx, &hnd, level, *info_p)) {
1148                 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &werr);
1149                 return false;
1150         }
1151
1152         dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &werr);
1153
1154         *num_printers = 1;
1155
1156 out:
1157         DEBUG(3,("got %d printers\n", *num_printers));
1158
1159         return true;
1160
1161 }
1162
1163 /**
1164  * List print-queues (including local printers that are not shared)
1165  *
1166  * All parameters are provided by the run_rpc_command function, except for
1167  * argc, argv which are passed through.
1168  *
1169  * @param c     A net_context structure
1170  * @param domain_sid The domain sid aquired from the remote server
1171  * @param cli A cli_state connected to the server.
1172  * @param mem_ctx Talloc context, destoyed on compleation of the function.
1173  * @param argc  Standard main() style argc
1174  * @param argv  Standard main() style argv.  Initial components are already
1175  *              stripped
1176  *
1177  * @return Normal NTSTATUS return.
1178  **/
1179
1180 NTSTATUS rpc_printer_list_internals(struct net_context *c,
1181                                         const struct dom_sid *domain_sid,
1182                                         const char *domain_name,
1183                                         struct cli_state *cli,
1184                                         struct rpc_pipe_client *pipe_hnd,
1185                                         TALLOC_CTX *mem_ctx,
1186                                         int argc,
1187                                         const char **argv)
1188 {
1189         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1190         uint32_t i, num_printers;
1191         uint32_t level = 2;
1192         const char *printername, *sharename;
1193         union spoolss_PrinterInfo *info;
1194
1195         printf("listing printers\n");
1196
1197         if (!get_printer_info(pipe_hnd, mem_ctx, level, argc, argv, &num_printers, &info))
1198                 return nt_status;
1199
1200         for (i = 0; i < num_printers; i++) {
1201
1202                 /* do some initialization */
1203                 printername = info[i].info2.printername;
1204                 sharename = info[i].info2.sharename;
1205
1206                 if (printername && sharename) {
1207                         d_printf(_("printer %d: %s, shared as: %s\n"),
1208                                 i+1, printername, sharename);
1209                 }
1210         }
1211
1212         return NT_STATUS_OK;
1213 }
1214
1215 /**
1216  * List printer-drivers from a server
1217  *
1218  * All parameters are provided by the run_rpc_command function, except for
1219  * argc, argv which are passed through.
1220  *
1221  * @param c     A net_context structure
1222  * @param domain_sid The domain sid aquired from the remote server
1223  * @param cli A cli_state connected to the server.
1224  * @param mem_ctx Talloc context, destoyed on compleation of the function.
1225  * @param argc  Standard main() style argc
1226  * @param argv  Standard main() style argv.  Initial components are already
1227  *              stripped
1228  *
1229  * @return Normal NTSTATUS return.
1230  **/
1231
1232 NTSTATUS rpc_printer_driver_list_internals(struct net_context *c,
1233                                                 const struct dom_sid *domain_sid,
1234                                                 const char *domain_name,
1235                                                 struct cli_state *cli,
1236                                                 struct rpc_pipe_client *pipe_hnd,
1237                                                 TALLOC_CTX *mem_ctx,
1238                                                 int argc,
1239                                                 const char **argv)
1240 {
1241         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1242         uint32_t i;
1243         uint32_t level = 3;
1244         union spoolss_DriverInfo *info;
1245         int d;
1246
1247         printf(_("listing printer-drivers\n"));
1248
1249         for (i=0; archi_table[i].long_archi!=NULL; i++) {
1250
1251                 uint32_t num_drivers;
1252
1253                 /* enum remote drivers */
1254                 if (!net_spoolss_enumprinterdrivers(pipe_hnd, mem_ctx, level,
1255                                 archi_table[i].long_archi,
1256                                 &num_drivers, &info)) {
1257                         nt_status = NT_STATUS_UNSUCCESSFUL;
1258                         goto done;
1259                 }
1260
1261                 if (num_drivers == 0) {
1262                         d_printf(_("no drivers found on server for "
1263                                    "architecture: [%s].\n"),
1264                                 archi_table[i].long_archi);
1265                         continue;
1266                 }
1267
1268                 d_printf(_("got %d printer-drivers for architecture: [%s]\n"),
1269                         num_drivers, archi_table[i].long_archi);
1270
1271
1272                 /* do something for all drivers for architecture */
1273                 for (d = 0; d < num_drivers; d++) {
1274                         display_print_driver3(&info[d].info3);
1275                 }
1276         }
1277
1278         nt_status = NT_STATUS_OK;
1279
1280 done:
1281         return nt_status;
1282
1283 }
1284
1285 /**
1286  * Publish print-queues with args-wrapper
1287  *
1288  * @param cli A cli_state connected to the server.
1289  * @param mem_ctx Talloc context, destoyed on compleation of the function.
1290  * @param argc  Standard main() style argc
1291  * @param argv  Standard main() style argv.  Initial components are already
1292  *              stripped
1293  * @param action
1294  *
1295  * @return Normal NTSTATUS return.
1296  **/
1297
1298 static NTSTATUS rpc_printer_publish_internals_args(struct rpc_pipe_client *pipe_hnd,
1299                                         TALLOC_CTX *mem_ctx,
1300                                         int argc,
1301                                         const char **argv,
1302                                         uint32_t action)
1303 {
1304         struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
1305         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1306         uint32_t i, num_printers;
1307         uint32_t level = 7;
1308         const char *printername, *sharename;
1309         union spoolss_PrinterInfo *info_enum;
1310         union spoolss_PrinterInfo info;
1311         struct spoolss_SetPrinterInfoCtr info_ctr;
1312         struct spoolss_DevmodeContainer devmode_ctr;
1313         struct sec_desc_buf secdesc_ctr;
1314         struct policy_handle hnd = { 0, };
1315         WERROR result;
1316         const char *action_str;
1317
1318         if (!get_printer_info(pipe_hnd, mem_ctx, 2, argc, argv, &num_printers, &info_enum))
1319                 return nt_status;
1320
1321         for (i = 0; i < num_printers; i++) {
1322
1323                 /* do some initialization */
1324                 printername = info_enum[i].info2.printername;
1325                 sharename = info_enum[i].info2.sharename;
1326                 if (!printername || !sharename) {
1327                         goto done;
1328                 }
1329
1330                 /* open printer handle */
1331                 if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
1332                         PRINTER_ALL_ACCESS, pipe_hnd->auth->user_name, &hnd))
1333                         goto done;
1334
1335                 /* check for existing dst printer */
1336                 if (!net_spoolss_getprinter(pipe_hnd, mem_ctx, &hnd, level, &info))
1337                         goto done;
1338
1339                 /* check action and set string */
1340                 switch (action) {
1341                 case DSPRINT_PUBLISH:
1342                         action_str = N_("published");
1343                         break;
1344                 case DSPRINT_UPDATE:
1345                         action_str = N_("updated");
1346                         break;
1347                 case DSPRINT_UNPUBLISH:
1348                         action_str = N_("unpublished");
1349                         break;
1350                 default:
1351                         action_str = N_("unknown action");
1352                         printf(_("unknown action: %d\n"), action);
1353                         break;
1354                 }
1355
1356                 info.info7.action = action;
1357                 info_ctr.level = 7;
1358                 info_ctr.info.info7 = (struct spoolss_SetPrinterInfo7 *)
1359                         (void *)&info.info7;
1360
1361                 ZERO_STRUCT(devmode_ctr);
1362                 ZERO_STRUCT(secdesc_ctr);
1363
1364                 nt_status = dcerpc_spoolss_SetPrinter(b, mem_ctx,
1365                                                       &hnd,
1366                                                       &info_ctr,
1367                                                       &devmode_ctr,
1368                                                       &secdesc_ctr,
1369                                                       0, /* command */
1370                                                       &result);
1371                 if (!NT_STATUS_IS_OK(nt_status)) {
1372                         printf(_("cannot set printer-info: %s\n"),
1373                                nt_errstr(nt_status));
1374                         goto done;
1375                 }
1376                 if (!W_ERROR_IS_OK(result) && !W_ERROR_EQUAL(result, WERR_IO_PENDING)) {
1377                         if ((action == DSPRINT_UPDATE) && W_ERROR_EQUAL(result, W_ERROR(0x80070002))) {
1378                                 printf(_("printer not published yet\n"));
1379                         } else {
1380                                 printf(_("cannot set printer-info: %s\n"),
1381                                        win_errstr(result));
1382                         }
1383                         nt_status = werror_to_ntstatus(result);
1384                         goto done;
1385                 }
1386
1387                 printf(_("successfully %s printer %s in Active Directory\n"),
1388                        action_str, sharename);
1389         }
1390
1391         nt_status = NT_STATUS_OK;
1392
1393 done:
1394         if (is_valid_policy_hnd(&hnd)) {
1395                 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &result);
1396         }
1397
1398         return nt_status;
1399 }
1400
1401 NTSTATUS rpc_printer_publish_publish_internals(struct net_context *c,
1402                                                 const struct dom_sid *domain_sid,
1403                                                 const char *domain_name,
1404                                                 struct cli_state *cli,
1405                                                 struct rpc_pipe_client *pipe_hnd,
1406                                                 TALLOC_CTX *mem_ctx,
1407                                                 int argc,
1408                                                 const char **argv)
1409 {
1410         return rpc_printer_publish_internals_args(pipe_hnd, mem_ctx, argc, argv, DSPRINT_PUBLISH);
1411 }
1412
1413 NTSTATUS rpc_printer_publish_unpublish_internals(struct net_context *c,
1414                                                 const struct dom_sid *domain_sid,
1415                                                 const char *domain_name,
1416                                                 struct cli_state *cli,
1417                                                 struct rpc_pipe_client *pipe_hnd,
1418                                                 TALLOC_CTX *mem_ctx,
1419                                                 int argc,
1420                                                 const char **argv)
1421 {
1422         return rpc_printer_publish_internals_args(pipe_hnd, mem_ctx, argc, argv, DSPRINT_UNPUBLISH);
1423 }
1424
1425 NTSTATUS rpc_printer_publish_update_internals(struct net_context *c,
1426                                                 const struct dom_sid *domain_sid,
1427                                                 const char *domain_name,
1428                                                 struct cli_state *cli,
1429                                                 struct rpc_pipe_client *pipe_hnd,
1430                                                 TALLOC_CTX *mem_ctx,
1431                                                 int argc,
1432                                                 const char **argv)
1433 {
1434         return rpc_printer_publish_internals_args(pipe_hnd, mem_ctx, argc, argv, DSPRINT_UPDATE);
1435 }
1436
1437 /**
1438  * List print-queues w.r.t. their publishing state
1439  *
1440  * All parameters are provided by the run_rpc_command function, except for
1441  * argc, argv which are passed through.
1442  *
1443  * @param c     A net_context structure
1444  * @param domain_sid The domain sid aquired from the remote server
1445  * @param cli A cli_state connected to the server.
1446  * @param mem_ctx Talloc context, destoyed on compleation of the function.
1447  * @param argc  Standard main() style argc
1448  * @param argv  Standard main() style argv.  Initial components are already
1449  *              stripped
1450  *
1451  * @return Normal NTSTATUS return.
1452  **/
1453
1454 NTSTATUS rpc_printer_publish_list_internals(struct net_context *c,
1455                                                 const struct dom_sid *domain_sid,
1456                                                 const char *domain_name,
1457                                                 struct cli_state *cli,
1458                                                 struct rpc_pipe_client *pipe_hnd,
1459                                                 TALLOC_CTX *mem_ctx,
1460                                                 int argc,
1461                                                 const char **argv)
1462 {
1463         struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
1464         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1465         uint32_t i, num_printers;
1466         uint32_t level = 7;
1467         const char *printername, *sharename;
1468         union spoolss_PrinterInfo *info_enum;
1469         union spoolss_PrinterInfo info;
1470         struct policy_handle hnd = { 0, };
1471         int state;
1472         WERROR werr;
1473
1474         if (!get_printer_info(pipe_hnd, mem_ctx, 2, argc, argv, &num_printers, &info_enum))
1475                 return nt_status;
1476
1477         for (i = 0; i < num_printers; i++) {
1478
1479                 /* do some initialization */
1480                 printername = info_enum[i].info2.printername;
1481                 sharename = info_enum[i].info2.sharename;
1482
1483                 if (!printername || !sharename) {
1484                         goto done;
1485                 }
1486
1487                 /* open printer handle */
1488                 if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
1489                         PRINTER_ALL_ACCESS, cli->user_name, &hnd))
1490                         goto done;
1491
1492                 /* check for existing dst printer */
1493                 if (!net_spoolss_getprinter(pipe_hnd, mem_ctx, &hnd, level, &info))
1494                         goto done;
1495
1496                 if (!info.info7.guid) {
1497                         goto done;
1498                 }
1499                 state = info.info7.action;
1500                 switch (state) {
1501                         case DSPRINT_PUBLISH:
1502                                 printf(_("printer [%s] is published"),
1503                                        sharename);
1504                                 if (c->opt_verbose)
1505                                         printf(_(", guid: %s"),info.info7.guid);
1506                                 printf("\n");
1507                                 break;
1508                         case DSPRINT_UNPUBLISH:
1509                                 printf(_("printer [%s] is unpublished\n"),
1510                                        sharename);
1511                                 break;
1512                         case DSPRINT_UPDATE:
1513                                 printf(_("printer [%s] is currently updating\n"),
1514                                        sharename);
1515                                 break;
1516                         default:
1517                                 printf(_("unknown state: %d\n"), state);
1518                                 break;
1519                 }
1520         }
1521
1522         nt_status = NT_STATUS_OK;
1523
1524 done:
1525         if (is_valid_policy_hnd(&hnd)) {
1526                 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &werr);
1527         }
1528
1529         return nt_status;
1530 }
1531
1532 /**
1533  * Migrate Printer-ACLs from a source server to the destination server
1534  *
1535  * All parameters are provided by the run_rpc_command function, except for
1536  * argc, argv which are passed through.
1537  *
1538  * @param c     A net_context structure
1539  * @param domain_sid The domain sid aquired from the remote server
1540  * @param cli A cli_state connected to the server.
1541  * @param mem_ctx Talloc context, destoyed on compleation of the function.
1542  * @param argc  Standard main() style argc
1543  * @param argv  Standard main() style argv.  Initial components are already
1544  *              stripped
1545  *
1546  * @return Normal NTSTATUS return.
1547  **/
1548
1549 NTSTATUS rpc_printer_migrate_security_internals(struct net_context *c,
1550                                                 const struct dom_sid *domain_sid,
1551                                                 const char *domain_name,
1552                                                 struct cli_state *cli,
1553                                                 struct rpc_pipe_client *pipe_hnd,
1554                                                 TALLOC_CTX *mem_ctx,
1555                                                 int argc,
1556                                                 const char **argv)
1557 {
1558         struct dcerpc_binding_handle *b_src = pipe_hnd->binding_handle;
1559         /* TODO: what now, info2 or info3 ?
1560            convince jerry that we should add clientside setacls level 3 at least
1561         */
1562         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1563         uint32_t i = 0;
1564         uint32_t num_printers;
1565         uint32_t level = 2;
1566         const char *printername, *sharename;
1567         struct rpc_pipe_client *pipe_hnd_dst = NULL;
1568         struct dcerpc_binding_handle *b_dst = NULL;
1569         struct policy_handle hnd_src = { 0, };
1570         struct policy_handle hnd_dst = { 0, };
1571         union spoolss_PrinterInfo *info_enum;
1572         struct cli_state *cli_dst = NULL;
1573         union spoolss_PrinterInfo info_src, info_dst;
1574         WERROR werr;
1575
1576         DEBUG(3,("copying printer ACLs\n"));
1577
1578         /* connect destination PI_SPOOLSS */
1579         nt_status = connect_dst_pipe(c, &cli_dst, &pipe_hnd_dst,
1580                                      &ndr_table_spoolss.syntax_id);
1581         if (!NT_STATUS_IS_OK(nt_status)) {
1582                 return nt_status;
1583         }
1584         b_dst = pipe_hnd_dst->binding_handle;
1585
1586         /* enum source printers */
1587         if (!get_printer_info(pipe_hnd, mem_ctx, level, argc, argv, &num_printers, &info_enum)) {
1588                 nt_status = NT_STATUS_UNSUCCESSFUL;
1589                 goto done;
1590         }
1591
1592         if (!num_printers) {
1593                 printf (_("no printers found on server.\n"));
1594                 nt_status = NT_STATUS_OK;
1595                 goto done;
1596         }
1597
1598         /* do something for all printers */
1599         for (i = 0; i < num_printers; i++) {
1600
1601                 /* do some initialization */
1602                 printername = info_enum[i].info2.printername;
1603                 sharename = info_enum[i].info2.sharename;
1604
1605                 if (!printername || !sharename) {
1606                         nt_status = NT_STATUS_UNSUCCESSFUL;
1607                         goto done;
1608                 }
1609
1610                 /* we can reset NT_STATUS here because we do not
1611                    get any real NT_STATUS-codes anymore from now on */
1612                 nt_status = NT_STATUS_UNSUCCESSFUL;
1613
1614                 d_printf(_("migrating printer ACLs for:     [%s] / [%s]\n"),
1615                         printername, sharename);
1616
1617                 /* according to msdn you have specify these access-rights
1618                    to see the security descriptor
1619                         - READ_CONTROL (DACL)
1620                         - ACCESS_SYSTEM_SECURITY (SACL)
1621                 */
1622
1623                 /* open src printer handle */
1624                 if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
1625                         MAXIMUM_ALLOWED_ACCESS, cli->user_name, &hnd_src))
1626                         goto done;
1627
1628                 /* open dst printer handle */
1629                 if (!net_spoolss_open_printer_ex(pipe_hnd_dst, mem_ctx, sharename,
1630                         PRINTER_ALL_ACCESS, cli_dst->user_name, &hnd_dst))
1631                         goto done;
1632
1633                 /* check for existing dst printer */
1634                 if (!net_spoolss_getprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, level, &info_dst))
1635                         goto done;
1636
1637                 /* check for existing src printer */
1638                 if (!net_spoolss_getprinter(pipe_hnd, mem_ctx, &hnd_src, 3, &info_src))
1639                         goto done;
1640
1641                 /* Copy Security Descriptor */
1642
1643                 /* copy secdesc (info level 2) */
1644                 info_dst.info2.devmode = NULL;
1645                 info_dst.info2.secdesc = dup_sec_desc(mem_ctx, info_src.info3.secdesc);
1646
1647                 if (c->opt_verbose)
1648                         display_sec_desc(info_dst.info2.secdesc);
1649
1650                 if (!net_spoolss_setprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, 2, &info_dst))
1651                         goto done;
1652
1653                 DEBUGADD(1,("\tSetPrinter of SECDESC succeeded\n"));
1654
1655
1656                 /* close printer handles here */
1657                 if (is_valid_policy_hnd(&hnd_src)) {
1658                         dcerpc_spoolss_ClosePrinter(b_src, mem_ctx, &hnd_src, &werr);
1659                 }
1660
1661                 if (is_valid_policy_hnd(&hnd_dst)) {
1662                         dcerpc_spoolss_ClosePrinter(b_dst, mem_ctx, &hnd_dst, &werr);
1663                 }
1664
1665         }
1666
1667         nt_status = NT_STATUS_OK;
1668
1669 done:
1670
1671         if (is_valid_policy_hnd(&hnd_src)) {
1672                 dcerpc_spoolss_ClosePrinter(b_src, mem_ctx, &hnd_src, &werr);
1673         }
1674
1675         if (is_valid_policy_hnd(&hnd_dst)) {
1676                 dcerpc_spoolss_ClosePrinter(b_dst, mem_ctx, &hnd_dst, &werr);
1677         }
1678
1679         if (cli_dst) {
1680                 cli_shutdown(cli_dst);
1681         }
1682         return nt_status;
1683 }
1684
1685 /**
1686  * Migrate printer-forms from a src server to the dst server
1687  *
1688  * All parameters are provided by the run_rpc_command function, except for
1689  * argc, argv which are passed through.
1690  *
1691  * @param c     A net_context structure
1692  * @param domain_sid The domain sid aquired from the remote server
1693  * @param cli A cli_state connected to the server.
1694  * @param mem_ctx Talloc context, destoyed on compleation of the function.
1695  * @param argc  Standard main() style argc
1696  * @param argv  Standard main() style argv.  Initial components are already
1697  *              stripped
1698  *
1699  * @return Normal NTSTATUS return.
1700  **/
1701
1702 NTSTATUS rpc_printer_migrate_forms_internals(struct net_context *c,
1703                                                 const struct dom_sid *domain_sid,
1704                                                 const char *domain_name,
1705                                                 struct cli_state *cli,
1706                                                 struct rpc_pipe_client *pipe_hnd,
1707                                                 TALLOC_CTX *mem_ctx,
1708                                                 int argc,
1709                                                 const char **argv)
1710 {
1711         struct dcerpc_binding_handle *b_src = pipe_hnd->binding_handle;
1712         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1713         WERROR result;
1714         uint32_t i, f;
1715         uint32_t num_printers;
1716         uint32_t level = 1;
1717         const char *printername, *sharename;
1718         struct rpc_pipe_client *pipe_hnd_dst = NULL;
1719         struct dcerpc_binding_handle *b_dst = NULL;
1720         struct policy_handle hnd_src = { 0, };
1721         struct policy_handle hnd_dst = { 0, };
1722         union spoolss_PrinterInfo *info_enum;
1723         union spoolss_PrinterInfo info_dst;
1724         uint32_t num_forms;
1725         union spoolss_FormInfo *forms;
1726         struct cli_state *cli_dst = NULL;
1727
1728         DEBUG(3,("copying forms\n"));
1729
1730         /* connect destination PI_SPOOLSS */
1731         nt_status = connect_dst_pipe(c, &cli_dst, &pipe_hnd_dst,
1732                                      &ndr_table_spoolss.syntax_id);
1733         if (!NT_STATUS_IS_OK(nt_status)) {
1734                 return nt_status;
1735         }
1736         b_dst = pipe_hnd_dst->binding_handle;
1737
1738         /* enum src printers */
1739         if (!get_printer_info(pipe_hnd, mem_ctx, 2, argc, argv, &num_printers, &info_enum)) {
1740                 nt_status = NT_STATUS_UNSUCCESSFUL;
1741                 goto done;
1742         }
1743
1744         if (!num_printers) {
1745                 printf (_("no printers found on server.\n"));
1746                 nt_status = NT_STATUS_OK;
1747                 goto done;
1748         }
1749
1750         /* do something for all printers */
1751         for (i = 0; i < num_printers; i++) {
1752
1753                 /* do some initialization */
1754                 printername = info_enum[i].info2.printername;
1755                 sharename = info_enum[i].info2.sharename;
1756
1757                 if (!printername || !sharename) {
1758                         nt_status = NT_STATUS_UNSUCCESSFUL;
1759                         goto done;
1760                 }
1761                 /* we can reset NT_STATUS here because we do not
1762                    get any real NT_STATUS-codes anymore from now on */
1763                 nt_status = NT_STATUS_UNSUCCESSFUL;
1764
1765                 d_printf(_("migrating printer forms for:    [%s] / [%s]\n"),
1766                         printername, sharename);
1767
1768
1769                 /* open src printer handle */
1770                 if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
1771                         MAXIMUM_ALLOWED_ACCESS, cli->user_name, &hnd_src))
1772                         goto done;
1773
1774                 /* open dst printer handle */
1775                 if (!net_spoolss_open_printer_ex(pipe_hnd_dst, mem_ctx, sharename,
1776                         PRINTER_ALL_ACCESS, cli->user_name, &hnd_dst))
1777                         goto done;
1778
1779                 /* check for existing dst printer */
1780                 if (!net_spoolss_getprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, level, &info_dst))
1781                         goto done;
1782
1783                 /* finally migrate forms */
1784                 if (!net_spoolss_enumforms(pipe_hnd, mem_ctx, &hnd_src, level, &num_forms, &forms))
1785                         goto done;
1786
1787                 DEBUG(1,("got %d forms for printer\n", num_forms));
1788
1789
1790                 for (f = 0; f < num_forms; f++) {
1791
1792                         union spoolss_AddFormInfo info;
1793                         NTSTATUS status;
1794
1795                         /* only migrate FORM_PRINTER types, according to jerry
1796                            FORM_BUILTIN-types are hard-coded in samba */
1797                         if (forms[f].info1.flags != SPOOLSS_FORM_PRINTER)
1798                                 continue;
1799
1800                         if (c->opt_verbose)
1801                                 d_printf(_("\tmigrating form # %d [%s] of type "
1802                                            "[%d]\n"),
1803                                         f, forms[f].info1.form_name,
1804                                         forms[f].info1.flags);
1805
1806                         info.info1 = (struct spoolss_AddFormInfo1 *)
1807                                 (void *)&forms[f].info1;
1808
1809                         /* FIXME: there might be something wrong with samba's
1810                            builtin-forms */
1811                         status = dcerpc_spoolss_AddForm(b_dst, mem_ctx,
1812                                                         &hnd_dst,
1813                                                         1,
1814                                                         info,
1815                                                         &result);
1816                         if (!NT_STATUS_IS_OK(status)) {
1817                                 d_printf(_("\tdcerpc_spoolss_AddForm form %d: [%s] - %s\n"),
1818                                         f, forms[f].info1.form_name, nt_errstr(status));
1819                                 continue;
1820                         }
1821                         if (!W_ERROR_IS_OK(result)) {
1822                                 d_printf(_("\tAddForm form %d: [%s] refused.\n"),
1823                                         f, forms[f].info1.form_name);
1824                                 continue;
1825                         }
1826
1827                         DEBUGADD(1,("\tAddForm of [%s] succeeded\n",
1828                                 forms[f].info1.form_name));
1829                 }
1830
1831
1832                 /* close printer handles here */
1833                 if (is_valid_policy_hnd(&hnd_src)) {
1834                         dcerpc_spoolss_ClosePrinter(b_src, mem_ctx, &hnd_src, &result);
1835                 }
1836
1837                 if (is_valid_policy_hnd(&hnd_dst)) {
1838                         dcerpc_spoolss_ClosePrinter(b_dst, mem_ctx, &hnd_dst, &result);
1839                 }
1840         }
1841
1842         nt_status = NT_STATUS_OK;
1843
1844 done:
1845
1846         if (is_valid_policy_hnd(&hnd_src)) {
1847                 dcerpc_spoolss_ClosePrinter(b_src, mem_ctx, &hnd_src, &result);
1848         }
1849
1850         if (is_valid_policy_hnd(&hnd_dst)) {
1851                 dcerpc_spoolss_ClosePrinter(b_dst, mem_ctx, &hnd_dst, &result);
1852         }
1853
1854         if (cli_dst) {
1855                 cli_shutdown(cli_dst);
1856         }
1857         return nt_status;
1858 }
1859
1860 /**
1861  * Migrate printer-drivers from a src server to the dst server
1862  *
1863  * All parameters are provided by the run_rpc_command function, except for
1864  * argc, argv which are passed through.
1865  *
1866  * @param c     A net_context structure
1867  * @param domain_sid The domain sid aquired from the remote server
1868  * @param cli A cli_state connected to the server.
1869  * @param mem_ctx Talloc context, destoyed on compleation of the function.
1870  * @param argc  Standard main() style argc
1871  * @param argv  Standard main() style argv.  Initial components are already
1872  *              stripped
1873  *
1874  * @return Normal NTSTATUS return.
1875  **/
1876
1877 NTSTATUS rpc_printer_migrate_drivers_internals(struct net_context *c,
1878                                                 const struct dom_sid *domain_sid,
1879                                                 const char *domain_name,
1880                                                 struct cli_state *cli,
1881                                                 struct rpc_pipe_client *pipe_hnd,
1882                                                 TALLOC_CTX *mem_ctx,
1883                                                 int argc,
1884                                                 const char **argv)
1885 {
1886         struct dcerpc_binding_handle *b_src = pipe_hnd->binding_handle;
1887         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1888         uint32_t i, p;
1889         uint32_t num_printers;
1890         uint32_t level = 3;
1891         const char *printername, *sharename;
1892         bool got_src_driver_share = false;
1893         bool got_dst_driver_share = false;
1894         struct rpc_pipe_client *pipe_hnd_dst = NULL;
1895         struct dcerpc_binding_handle *b_dst = NULL;
1896         struct policy_handle hnd_src = { 0, };
1897         struct policy_handle hnd_dst = { 0, };
1898         union spoolss_DriverInfo drv_info_src;
1899         union spoolss_PrinterInfo *info_enum;
1900         union spoolss_PrinterInfo info_dst;
1901         struct cli_state *cli_dst = NULL;
1902         struct cli_state *cli_share_src = NULL;
1903         struct cli_state *cli_share_dst = NULL;
1904         const char *drivername = NULL;
1905         WERROR werr;
1906
1907         DEBUG(3,("copying printer-drivers\n"));
1908
1909         nt_status = connect_dst_pipe(c, &cli_dst, &pipe_hnd_dst,
1910                                      &ndr_table_spoolss.syntax_id);
1911         if (!NT_STATUS_IS_OK(nt_status)) {
1912                 return nt_status;
1913         }
1914         b_dst = pipe_hnd_dst->binding_handle;
1915
1916         /* open print$-share on the src server */
1917         nt_status = connect_to_service(c, &cli_share_src,
1918                                        smbXcli_conn_remote_sockaddr(cli->conn),
1919                                        cli_state_remote_name(cli),
1920                                        "print$", "A:");
1921         if (!NT_STATUS_IS_OK(nt_status))
1922                 goto done;
1923
1924         got_src_driver_share = true;
1925
1926
1927         /* open print$-share on the dst server */
1928         nt_status = connect_to_service(c, &cli_share_dst,
1929                                        smbXcli_conn_remote_sockaddr(cli_dst->conn),
1930                                        cli_state_remote_name(cli_dst),
1931                                        "print$", "A:");
1932         if (!NT_STATUS_IS_OK(nt_status))
1933                 return nt_status;
1934
1935         got_dst_driver_share = true;
1936
1937
1938         /* enum src printers */
1939         if (!get_printer_info(pipe_hnd, mem_ctx, 2, argc, argv, &num_printers, &info_enum)) {
1940                 nt_status = NT_STATUS_UNSUCCESSFUL;
1941                 goto done;
1942         }
1943
1944         if (num_printers == 0) {
1945                 printf (_("no printers found on server.\n"));
1946                 nt_status = NT_STATUS_OK;
1947                 goto done;
1948         }
1949
1950
1951         /* do something for all printers */
1952         for (p = 0; p < num_printers; p++) {
1953
1954                 /* do some initialization */
1955                 printername = info_enum[p].info2.printername;
1956                 sharename = info_enum[p].info2.sharename;
1957
1958                 if (!printername || !sharename) {
1959                         nt_status = NT_STATUS_UNSUCCESSFUL;
1960                         goto done;
1961                 }
1962
1963                 /* we can reset NT_STATUS here because we do not
1964                    get any real NT_STATUS-codes anymore from now on */
1965                 nt_status = NT_STATUS_UNSUCCESSFUL;
1966
1967                 d_printf(_("migrating printer driver for:   [%s] / [%s]\n"),
1968                         printername, sharename);
1969
1970                 /* open dst printer handle */
1971                 if (!net_spoolss_open_printer_ex(pipe_hnd_dst, mem_ctx, sharename,
1972                         PRINTER_ALL_ACCESS, cli->user_name, &hnd_dst))
1973                         goto done;
1974
1975                 /* check for existing dst printer */
1976                 if (!net_spoolss_getprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, 2, &info_dst))
1977                         goto done;
1978
1979
1980                 /* open src printer handle */
1981                 if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
1982                                                  MAXIMUM_ALLOWED_ACCESS,
1983                                                  pipe_hnd->auth->user_name,
1984                                                  &hnd_src))
1985                         goto done;
1986
1987                 /* in a first step call getdriver for each shared printer (per arch)
1988                    to get a list of all files that have to be copied */
1989
1990                 for (i=0; archi_table[i].long_archi!=NULL; i++) {
1991
1992                         /* getdriver src */
1993                         if (!net_spoolss_getprinterdriver(pipe_hnd, mem_ctx, &hnd_src,
1994                                         level, archi_table[i].long_archi,
1995                                         archi_table[i].version, &drv_info_src))
1996                                 continue;
1997
1998                         drivername = drv_info_src.info3.driver_name;
1999
2000                         if (c->opt_verbose)
2001                                 display_print_driver3(&drv_info_src.info3);
2002
2003                         /* check arch dir */
2004                         nt_status = check_arch_dir(cli_share_dst, archi_table[i].short_archi);
2005                         if (!NT_STATUS_IS_OK(nt_status))
2006                                 goto done;
2007
2008
2009                         /* copy driver-files */
2010                         nt_status = copy_print_driver_3(c, mem_ctx, cli_share_src, cli_share_dst,
2011                                                         archi_table[i].short_archi,
2012                                                         &drv_info_src.info3);
2013                         if (!NT_STATUS_IS_OK(nt_status))
2014                                 goto done;
2015
2016
2017                         /* adddriver dst */
2018                         if (!net_spoolss_addprinterdriver(pipe_hnd_dst, mem_ctx, level, &drv_info_src)) {
2019                                 nt_status = NT_STATUS_UNSUCCESSFUL;
2020                                 goto done;
2021                         }
2022
2023                         DEBUGADD(1,("Sucessfully added driver [%s] for printer [%s]\n",
2024                                 drivername, printername));
2025
2026                 }
2027
2028                 if (!drivername || strlen(drivername) == 0) {
2029                         DEBUGADD(1,("Did not get driver for printer %s\n",
2030                                     printername));
2031                         goto done;
2032                 }
2033
2034                 /* setdriver dst */
2035                 info_dst.info2.drivername = drivername;
2036
2037                 if (!net_spoolss_setprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, 2, &info_dst)) {
2038                         nt_status = NT_STATUS_UNSUCCESSFUL;
2039                         goto done;
2040                 }
2041
2042                 DEBUGADD(1,("Sucessfully set driver %s for printer %s\n",
2043                         drivername, printername));
2044
2045                 /* close dst */
2046                 if (is_valid_policy_hnd(&hnd_dst)) {
2047                         dcerpc_spoolss_ClosePrinter(b_dst, mem_ctx, &hnd_dst, &werr);
2048                 }
2049
2050                 /* close src */
2051                 if (is_valid_policy_hnd(&hnd_src)) {
2052                         dcerpc_spoolss_ClosePrinter(b_src, mem_ctx, &hnd_src, &werr);
2053                 }
2054         }
2055
2056         nt_status = NT_STATUS_OK;
2057
2058 done:
2059
2060         if (is_valid_policy_hnd(&hnd_dst)) {
2061                 dcerpc_spoolss_ClosePrinter(b_dst, mem_ctx, &hnd_dst, &werr);
2062         }
2063
2064         /* close src */
2065         if (is_valid_policy_hnd(&hnd_src)) {
2066                 dcerpc_spoolss_ClosePrinter(b_src, mem_ctx, &hnd_src, &werr);
2067         }
2068
2069         if (cli_dst) {
2070                 cli_shutdown(cli_dst);
2071         }
2072
2073         if (got_src_driver_share)
2074                 cli_shutdown(cli_share_src);
2075
2076         if (got_dst_driver_share)
2077                 cli_shutdown(cli_share_dst);
2078
2079         return nt_status;
2080
2081 }
2082
2083 /**
2084  * Migrate printer-queues from a src to the dst server
2085  * (requires a working "addprinter command" to be installed for the local smbd)
2086  *
2087  * All parameters are provided by the run_rpc_command function, except for
2088  * argc, argv which are passed through.
2089  *
2090  * @param c     A net_context structure
2091  * @param domain_sid The domain sid aquired from the remote server
2092  * @param cli A cli_state connected to the server.
2093  * @param mem_ctx Talloc context, destoyed on compleation of the function.
2094  * @param argc  Standard main() style argc
2095  * @param argv  Standard main() style argv.  Initial components are already
2096  *              stripped
2097  *
2098  * @return Normal NTSTATUS return.
2099  **/
2100
2101 NTSTATUS rpc_printer_migrate_printers_internals(struct net_context *c,
2102                                                 const struct dom_sid *domain_sid,
2103                                                 const char *domain_name,
2104                                                 struct cli_state *cli,
2105                                                 struct rpc_pipe_client *pipe_hnd,
2106                                                 TALLOC_CTX *mem_ctx,
2107                                                 int argc,
2108                                                 const char **argv)
2109 {
2110         struct dcerpc_binding_handle *b_src = pipe_hnd->binding_handle;
2111         WERROR result;
2112         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
2113         uint32_t i = 0, num_printers;
2114         uint32_t level = 2;
2115         union spoolss_PrinterInfo info_dst, info_src;
2116         union spoolss_PrinterInfo *info_enum;
2117         struct cli_state *cli_dst = NULL;
2118         struct policy_handle hnd_src = { 0, };
2119         struct policy_handle hnd_dst = { 0, };
2120         const char *printername, *sharename;
2121         struct rpc_pipe_client *pipe_hnd_dst = NULL;
2122         struct dcerpc_binding_handle *b_dst = NULL;
2123         struct spoolss_SetPrinterInfoCtr info_ctr;
2124
2125         DEBUG(3,("copying printers\n"));
2126
2127         /* connect destination PI_SPOOLSS */
2128         nt_status = connect_dst_pipe(c, &cli_dst, &pipe_hnd_dst,
2129                                      &ndr_table_spoolss.syntax_id);
2130         if (!NT_STATUS_IS_OK(nt_status)) {
2131                 return nt_status;
2132         }
2133         b_dst = pipe_hnd_dst->binding_handle;
2134
2135         /* enum printers */
2136         if (!get_printer_info(pipe_hnd, mem_ctx, level, argc, argv, &num_printers, &info_enum)) {
2137                 nt_status = NT_STATUS_UNSUCCESSFUL;
2138                 goto done;
2139         }
2140
2141         if (!num_printers) {
2142                 printf (_("no printers found on server.\n"));
2143                 nt_status = NT_STATUS_OK;
2144                 goto done;
2145         }
2146
2147         /* do something for all printers */
2148         for (i = 0; i < num_printers; i++) {
2149
2150                 struct spoolss_SetPrinterInfo2 info2;
2151
2152                 /* do some initialization */
2153                 printername = info_enum[i].info2.printername;
2154                 sharename = info_enum[i].info2.sharename;
2155
2156                 if (!printername || !sharename) {
2157                         nt_status = NT_STATUS_UNSUCCESSFUL;
2158                         goto done;
2159                 }
2160                 /* we can reset NT_STATUS here because we do not
2161                    get any real NT_STATUS-codes anymore from now on */
2162                 nt_status = NT_STATUS_UNSUCCESSFUL;
2163
2164                 d_printf(_("migrating printer queue for:    [%s] / [%s]\n"),
2165                         printername, sharename);
2166
2167                 /* open dst printer handle */
2168                 if (!net_spoolss_open_printer_ex(pipe_hnd_dst, mem_ctx, sharename,
2169                         PRINTER_ALL_ACCESS, cli->user_name, &hnd_dst)) {
2170
2171                         DEBUG(1,("could not open printer: %s\n", sharename));
2172                 }
2173
2174                 /* check for existing dst printer */
2175                 if (!net_spoolss_getprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, level, &info_dst)) {
2176                         printf (_("could not get printer, creating printer.\n"));
2177                 } else {
2178                         DEBUG(1,("printer already exists: %s\n", sharename));
2179                         /* close printer handle here - dst only, not got src yet. */
2180                         if (is_valid_policy_hnd(&hnd_dst)) {
2181                                 dcerpc_spoolss_ClosePrinter(b_dst, mem_ctx, &hnd_dst, &result);
2182                         }
2183                         continue;
2184                 }
2185
2186                 /* now get again src printer ctr via getprinter,
2187                    we first need a handle for that */
2188
2189                 /* open src printer handle */
2190                 if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
2191                         MAXIMUM_ALLOWED_ACCESS, cli->user_name, &hnd_src))
2192                         goto done;
2193
2194                 /* getprinter on the src server */
2195                 if (!net_spoolss_getprinter(pipe_hnd, mem_ctx, &hnd_src, level, &info_src))
2196                         goto done;
2197
2198                 /* copy each src printer to a dst printer 1:1,
2199                    maybe some values have to be changed though */
2200                 d_printf(_("creating printer: %s\n"), printername);
2201
2202                 info_ctr.level = level;
2203                 spoolss_printerinfo2_to_setprinterinfo2(&info_src.info2, &info2);
2204                 info_ctr.info.info2 = &info2;
2205
2206                 result = rpccli_spoolss_addprinterex(pipe_hnd_dst,
2207                                                      mem_ctx,
2208                                                      &info_ctr);
2209
2210                 if (W_ERROR_IS_OK(result))
2211                         d_printf (_("printer [%s] successfully added.\n"),
2212                                   printername);
2213                 else if (W_ERROR_V(result) == W_ERROR_V(WERR_PRINTER_ALREADY_EXISTS))
2214                         d_fprintf (stderr, _("printer [%s] already exists.\n"),
2215                                    printername);
2216                 else {
2217                         d_fprintf (stderr, _("could not create printer [%s]\n"),
2218                                    printername);
2219                         goto done;
2220                 }
2221
2222                 /* close printer handles here */
2223                 if (is_valid_policy_hnd(&hnd_src)) {
2224                         dcerpc_spoolss_ClosePrinter(b_src, mem_ctx, &hnd_src, &result);
2225                 }
2226
2227                 if (is_valid_policy_hnd(&hnd_dst)) {
2228                         dcerpc_spoolss_ClosePrinter(b_dst, mem_ctx, &hnd_dst, &result);
2229                 }
2230         }
2231
2232         nt_status = NT_STATUS_OK;
2233
2234 done:
2235         if (is_valid_policy_hnd(&hnd_src)) {
2236                 dcerpc_spoolss_ClosePrinter(b_src, mem_ctx, &hnd_src, &result);
2237         }
2238
2239         if (is_valid_policy_hnd(&hnd_dst)) {
2240                 dcerpc_spoolss_ClosePrinter(b_dst, mem_ctx, &hnd_dst, &result);
2241         }
2242
2243         if (cli_dst) {
2244                 cli_shutdown(cli_dst);
2245         }
2246         return nt_status;
2247 }
2248
2249 /**
2250  * Migrate Printer-Settings from a src server to the dst server
2251  * (for this to work, printers and drivers already have to be migrated earlier)
2252  *
2253  * All parameters are provided by the run_rpc_command function, except for
2254  * argc, argv which are passed through.
2255  *
2256  * @param c     A net_context structure
2257  * @param domain_sid The domain sid aquired from the remote server
2258  * @param cli A cli_state connected to the server.
2259  * @param mem_ctx Talloc context, destoyed on compleation of the function.
2260  * @param argc  Standard main() style argc
2261  * @param argv  Standard main() style argv.  Initial components are already
2262  *              stripped
2263  *
2264  * @return Normal NTSTATUS return.
2265  **/
2266
2267 NTSTATUS rpc_printer_migrate_settings_internals(struct net_context *c,
2268                                                 const struct dom_sid *domain_sid,
2269                                                 const char *domain_name,
2270                                                 struct cli_state *cli,
2271                                                 struct rpc_pipe_client *pipe_hnd,
2272                                                 TALLOC_CTX *mem_ctx,
2273                                                 int argc,
2274                                                 const char **argv)
2275 {
2276         struct dcerpc_binding_handle *b_src = pipe_hnd->binding_handle;
2277
2278         /* FIXME: Here the nightmare begins */
2279
2280         WERROR result;
2281         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
2282         uint32_t i = 0, j = 0;
2283         uint32_t num_printers;
2284         uint32_t level = 2;
2285         const char *printername, *sharename;
2286         struct rpc_pipe_client *pipe_hnd_dst = NULL;
2287         struct dcerpc_binding_handle *b_dst = NULL;
2288         struct policy_handle hnd_src = { 0, };
2289         struct policy_handle hnd_dst = { 0, };
2290         union spoolss_PrinterInfo *info_enum;
2291         union spoolss_PrinterInfo info_dst_publish;
2292         union spoolss_PrinterInfo info_dst;
2293         struct cli_state *cli_dst = NULL;
2294         const char *longname;
2295         const char **keylist = NULL;
2296
2297         /* FIXME GD */
2298         ZERO_STRUCT(info_dst_publish);
2299
2300         DEBUG(3,("copying printer settings\n"));
2301
2302         /* connect destination PI_SPOOLSS */
2303         nt_status = connect_dst_pipe(c, &cli_dst, &pipe_hnd_dst,
2304                                      &ndr_table_spoolss.syntax_id);
2305         if (!NT_STATUS_IS_OK(nt_status)) {
2306                 return nt_status;
2307         }
2308         b_dst = pipe_hnd_dst->binding_handle;
2309
2310         /* enum src printers */
2311         if (!get_printer_info(pipe_hnd, mem_ctx, level, argc, argv, &num_printers, &info_enum)) {
2312                 nt_status = NT_STATUS_UNSUCCESSFUL;
2313                 goto done;
2314         }
2315
2316         if (!num_printers) {
2317                 printf (_("no printers found on server.\n"));
2318                 nt_status = NT_STATUS_OK;
2319                 goto done;
2320         }
2321
2322
2323         /* needed for dns-strings in regkeys */
2324         longname = get_mydnsfullname();
2325         if (!longname) {
2326                 nt_status = NT_STATUS_UNSUCCESSFUL;
2327                 goto done;
2328         }
2329
2330         /* do something for all printers */
2331         for (i = 0; i < num_printers; i++) {
2332
2333                 uint32_t value_needed;
2334                 uint32_t data_needed;
2335                 enum winreg_Type type;
2336                 struct spoolss_EnumPrinterData r;
2337
2338                 /* do some initialization */
2339                 printername = info_enum[i].info2.printername;
2340                 sharename = info_enum[i].info2.sharename;
2341
2342                 if (!printername || !sharename) {
2343                         nt_status = NT_STATUS_UNSUCCESSFUL;
2344                         goto done;
2345                 }
2346                 /* we can reset NT_STATUS here because we do not
2347                    get any real NT_STATUS-codes anymore from now on */
2348                 nt_status = NT_STATUS_UNSUCCESSFUL;
2349
2350                 d_printf(_("migrating printer settings for: [%s] / [%s]\n"),
2351                         printername, sharename);
2352
2353
2354                 /* open src printer handle */
2355                 if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
2356                         MAXIMUM_ALLOWED_ACCESS, cli->user_name, &hnd_src))
2357                         goto done;
2358
2359                 /* open dst printer handle */
2360                 if (!net_spoolss_open_printer_ex(pipe_hnd_dst, mem_ctx, sharename,
2361                         PRINTER_ALL_ACCESS, cli_dst->user_name, &hnd_dst))
2362                         goto done;
2363
2364                 /* check for existing dst printer */
2365                 if (!net_spoolss_getprinter(pipe_hnd_dst, mem_ctx, &hnd_dst,
2366                                 level, &info_dst))
2367                         goto done;
2368
2369
2370                 /* STEP 1: COPY DEVICE-MODE and other
2371                            PRINTER_INFO_2-attributes
2372                 */
2373
2374                 info_dst.info2 = info_enum[i].info2;
2375
2376                 /* why is the port always disconnected when the printer
2377                    is correctly installed (incl. driver ???) */
2378                 info_dst.info2.portname = SAMBA_PRINTER_PORT_NAME;
2379
2380                 /* check if printer is published */
2381                 if (info_enum[i].info2.attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
2382
2383                         /* check for existing dst printer */
2384                         if (!net_spoolss_getprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, 7, &info_dst_publish))
2385                                 goto done;
2386
2387                         info_dst_publish.info7.action = DSPRINT_PUBLISH;
2388
2389                         /* ignore false from setprinter due to WERR_IO_PENDING */
2390                         net_spoolss_setprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, 7, &info_dst_publish);
2391
2392                         DEBUG(3,("republished printer\n"));
2393                 }
2394
2395                 if (info_enum[i].info2.devmode != NULL) {
2396
2397                         /* copy devmode (info level 2) */
2398                         info_dst.info2.devmode = info_enum[i].info2.devmode;
2399
2400                         /* do not copy security descriptor (we have another
2401                          * command for that) */
2402                         info_dst.info2.secdesc = NULL;
2403
2404 #if 0
2405                         info_dst.info2.devmode.devicename =
2406                                 talloc_asprintf(mem_ctx, "\\\\%s\\%s",
2407                                                 longname, printername);
2408                         if (!info_dst.info2.devmode.devicename) {
2409                                 nt_status = NT_STATUS_NO_MEMORY;
2410                                 goto done;
2411                         }
2412 #endif
2413                         if (!net_spoolss_setprinter(pipe_hnd_dst, mem_ctx, &hnd_dst,
2414                                                     level, &info_dst))
2415                                 goto done;
2416
2417                         DEBUGADD(1,("\tSetPrinter of DEVICEMODE succeeded\n"));
2418                 }
2419
2420                 /* STEP 2: COPY REGISTRY VALUES */
2421
2422                 /* please keep in mind that samba parse_spools gives horribly
2423                    crippled results when used to rpccli_spoolss_enumprinterdataex
2424                    a win2k3-server.  (Bugzilla #1851)
2425                    FIXME: IIRC I've seen it too on a win2k-server
2426                 */
2427
2428                 r.in.handle = &hnd_src;
2429                 r.in.enum_index = 0;
2430                 r.in.value_offered = 0;
2431                 r.in.data_offered = 0;
2432                 r.out.value_name = NULL;
2433                 r.out.value_needed = &value_needed;
2434                 r.out.type = &type;
2435                 r.out.data = NULL;
2436                 r.out.data_needed = &data_needed;
2437
2438                 /* enumerate data on src handle */
2439                 nt_status = dcerpc_spoolss_EnumPrinterData_r(b_src, mem_ctx, &r);
2440
2441                 r.in.data_offered       = *r.out.data_needed;
2442                 r.in.value_offered      = *r.out.value_needed;
2443                 r.out.data              = talloc_zero_array(mem_ctx, uint8_t, r.in.data_offered);
2444                 r.out.value_name        = talloc_zero_array(mem_ctx, char, r.in.value_offered);
2445
2446                 /* loop for all printerdata of "PrinterDriverData" */
2447                 while (NT_STATUS_IS_OK(nt_status) && W_ERROR_IS_OK(r.out.result)) {
2448
2449                         r.in.enum_index++;
2450
2451                         nt_status = dcerpc_spoolss_EnumPrinterData_r(b_src, mem_ctx, &r);
2452
2453                         /* loop for all reg_keys */
2454                         if (NT_STATUS_IS_OK(nt_status) && W_ERROR_IS_OK(r.out.result)) {
2455
2456                                 /* display_value */
2457                                 if (c->opt_verbose) {
2458                                         struct registry_value v;
2459                                         v.type = *r.out.type;
2460                                         v.data = data_blob_const(
2461                                                 r.out.data, r.in.data_offered);
2462
2463                                         display_reg_value(SPOOL_PRINTERDATA_KEY,
2464                                                           r.out.value_name, &v);
2465                                 }
2466
2467                                 /* set_value */
2468                                 if (!net_spoolss_setprinterdata(pipe_hnd_dst, mem_ctx,
2469                                                                 &hnd_dst, r.out.value_name,
2470                                                                 *r.out.type, r.out.data, r.in.data_offered))
2471                                         goto done;
2472
2473                                 DEBUGADD(1,("\tSetPrinterData of [%s] succeeded\n",
2474                                             r.out.value_name));
2475                         }
2476                 }
2477
2478                 /* STEP 3: COPY SUBKEY VALUES */
2479
2480                 /* here we need to enum all printer_keys and then work
2481                    on the result with enum_printer_key_ex. nt4 does not
2482                    respond to enumprinterkey, win2k does, so continue
2483                    in case of an error */
2484
2485                 if (!net_spoolss_enumprinterkey(pipe_hnd, mem_ctx, &hnd_src, "", &keylist)) {
2486                         printf(_("got no key-data\n"));
2487                         continue;
2488                 }
2489
2490
2491                 /* work on a list of printer keys
2492                    each key has to be enumerated to get all required
2493                    information.  information is then set via setprinterdataex-calls */
2494
2495                 if (keylist == NULL)
2496                         continue;
2497
2498                 for (i=0; keylist && keylist[i] != NULL; i++) {
2499
2500                         const char *subkey = keylist[i];
2501                         uint32_t count;
2502                         struct spoolss_PrinterEnumValues *info;
2503
2504                         /* enumerate all src subkeys */
2505                         if (!net_spoolss_enumprinterdataex(pipe_hnd, mem_ctx, 0,
2506                                                            &hnd_src, subkey,
2507                                                            &count, &info)) {
2508                                 goto done;
2509                         }
2510
2511                         for (j=0; j < count; j++) {
2512
2513                                 struct registry_value value;
2514                                 const char *value_name = info[j].value_name;
2515                                 value.type = REG_SZ;
2516
2517                                 /* although samba replies with sane data in most cases we
2518                                    should try to avoid writing wrong registry data */
2519
2520                                 if (strequal(value_name, SPOOL_REG_PORTNAME)) {
2521                                         /* although windows uses a multi-sz, we use a sz */
2522                                         push_reg_sz(mem_ctx, &value.data, SAMBA_PRINTER_PORT_NAME);
2523                                 }
2524                                 else if (strequal(value_name, SPOOL_REG_UNCNAME)) {
2525                                         char *unc_name;
2526                                         if (asprintf(&unc_name, "\\\\%s\\%s", longname, sharename) < 0) {
2527                                                 nt_status = NT_STATUS_NO_MEMORY;
2528                                                 goto done;
2529                                         }
2530                                         push_reg_sz(mem_ctx, &value.data, unc_name);
2531                                         free(unc_name);
2532                                 }
2533                                 else if (strequal(value_name, SPOOL_REG_URL)) {
2534                                         continue;
2535 #if 0
2536                                         /* FIXME: should we really do that ??? */
2537                                         if (asprintf(&url, "http://%s:631/printers/%s", longname, sharename) < 0) {
2538                                                 nt_status = NT_STATUS_NO_MEMORY;
2539                                                 goto done;
2540                                         }
2541                                         push_reg_sz(mem_ctx, NULL, &value.data, url);
2542                                         free(url);
2543 #endif
2544                                 }
2545                                 else if (strequal(value_name, SPOOL_REG_SERVERNAME)) {
2546                                         push_reg_sz(mem_ctx, &value.data, longname);
2547                                 }
2548                                 else if (strequal(value_name, SPOOL_REG_SHORTSERVERNAME)) {
2549                                         push_reg_sz(mem_ctx, &value.data, lp_netbios_name());
2550                                 }
2551                                 else {
2552                                         value.type = info[j].type;
2553                                         value.data = *info[j].data;
2554                                 }
2555
2556                                 if (c->opt_verbose) {
2557                                         display_reg_value(subkey, value_name, &value);
2558                                 }
2559
2560                                 /* here we have to set all subkeys on the dst server */
2561                                 if (!net_spoolss_setprinterdataex(pipe_hnd_dst, mem_ctx, &hnd_dst,
2562                                                                   subkey, value_name, &value))
2563                                 {
2564                                         goto done;
2565                                 }
2566
2567                                 DEBUGADD(1,("\tSetPrinterDataEx of key [%s\\%s] succeeded\n",
2568                                                 subkey, info[j].value_name));
2569
2570                         }
2571                 }
2572
2573                 TALLOC_FREE(keylist);
2574
2575                 /* close printer handles here */
2576                 if (is_valid_policy_hnd(&hnd_src)) {
2577                         dcerpc_spoolss_ClosePrinter(b_src, mem_ctx, &hnd_src, &result);
2578                 }
2579
2580                 if (is_valid_policy_hnd(&hnd_dst)) {
2581                         dcerpc_spoolss_ClosePrinter(b_dst, mem_ctx, &hnd_dst, &result);
2582                 }
2583         }
2584
2585         nt_status = NT_STATUS_OK;
2586
2587 done:
2588         if (is_valid_policy_hnd(&hnd_src)) {
2589                 dcerpc_spoolss_ClosePrinter(b_src, mem_ctx, &hnd_src, &result);
2590         }
2591
2592         if (is_valid_policy_hnd(&hnd_dst)) {
2593                 dcerpc_spoolss_ClosePrinter(b_dst, mem_ctx, &hnd_dst, &result);
2594         }
2595
2596         if (cli_dst) {
2597                 cli_shutdown(cli_dst);
2598         }
2599         return nt_status;
2600 }