2 Samba Unix/Linux SMB client library
3 Distributed SMB/CIFS Server Management Utility
4 Copyright (C) 2004,2009 Guenther Deschner (gd@samba.org)
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.
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.
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/>.
20 #include "utils/net.h"
21 #include "../librpc/gen_ndr/cli_spoolss.h"
22 #include "rpc_client/cli_spoolss.h"
23 #include "rpc_client/init_spoolss.h"
24 #include "nt_printing.h"
26 #include "registry/reg_objects.h"
27 #include "../libcli/security/security.h"
29 /* support itanium as well */
30 static const struct print_architecture_table_node archi_table[]= {
32 {"Windows 4.0", "WIN40", 0 },
33 {"Windows NT x86", "W32X86", 2 },
34 {"Windows NT x86", "W32X86", 3 },
35 {"Windows NT R4000", "W32MIPS", 2 },
36 {"Windows NT Alpha_AXP", "W32ALPHA", 2 },
37 {"Windows NT PowerPC", "W32PPC", 2 },
38 {"Windows IA64", "IA64", 3 },
39 {"Windows x64", "x64", 3 },
45 * This display-printdriver-functions was borrowed from rpcclient/cmd_spoolss.c.
46 * It is here for debugging purpose and should be removed later on.
49 /****************************************************************************
50 Printer info level 3 display function.
51 ****************************************************************************/
53 static void display_print_driver3(struct spoolss_DriverInfo3 *r)
61 printf(_("Printer Driver Info 3:\n"));
62 printf(_("\tVersion: [%x]\n"), r->version);
63 printf(_("\tDriver Name: [%s]\n"), r->driver_name);
64 printf(_("\tArchitecture: [%s]\n"), r->architecture);
65 printf(_("\tDriver Path: [%s]\n"), r->driver_path);
66 printf(_("\tDatafile: [%s]\n"), r->data_file);
67 printf(_("\tConfigfile: [%s]\n\n"), r->config_file);
68 printf(_("\tHelpfile: [%s]\n\n"), r->help_file);
70 for (i=0; r->dependent_files[i] != NULL; i++) {
71 printf(_("\tDependentfiles: [%s]\n"), r->dependent_files[i]);
76 printf(_("\tMonitorname: [%s]\n"), r->monitor_name);
77 printf(_("\tDefaultdatatype: [%s]\n\n"), r->default_datatype);
80 static void display_reg_value(const char *subkey, struct regval_blob *value)
85 switch(regval_type(value)) {
87 d_printf(_("\t[%s:%s]: REG_DWORD: 0x%08x\n"), subkey,
88 regval_name(value), *((uint32_t *) regval_data_p(value)));
92 blob = data_blob_const(regval_data_p(value), regval_size(value));
93 pull_reg_sz(talloc_tos(), &blob, &text);
97 d_printf(_("\t[%s:%s]: REG_SZ: %s\n"), subkey, regval_name(value),
102 d_printf(_("\t[%s:%s]: REG_BINARY: unknown length value not "
104 subkey, regval_name(value));
110 blob = data_blob_const(regval_data_p(value), regval_size(value));
112 if (!pull_reg_multi_sz(NULL, &blob, &values)) {
113 d_printf("pull_reg_multi_sz failed\n");
117 printf("%s: REG_MULTI_SZ: \n", regval_name(value));
118 for (i=0; values[i] != NULL; i++) {
119 d_printf("%s\n", values[i]);
126 d_printf(_("\t%s: unknown type %d\n"), regval_name(value),
133 * Copies ACLs, DOS-attributes and timestamps from one
134 * file or directory from one connected share to another connected share
136 * @param c A net_context structure
137 * @param mem_ctx A talloc-context
138 * @param cli_share_src A connected cli_state
139 * @param cli_share_dst A connected cli_state
140 * @param src_file The source file-name
141 * @param dst_file The destination file-name
142 * @param copy_acls Whether to copy acls
143 * @param copy_attrs Whether to copy DOS attributes
144 * @param copy_timestamps Whether to preserve timestamps
145 * @param is_file Whether this file is a file or a dir
147 * @return Normal NTSTATUS return.
150 NTSTATUS net_copy_fileattr(struct net_context *c,
152 struct cli_state *cli_share_src,
153 struct cli_state *cli_share_dst,
154 const char *src_name, const char *dst_name,
155 bool copy_acls, bool copy_attrs,
156 bool copy_timestamps, bool is_file)
158 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
159 uint16_t fnum_src = 0;
160 uint16_t fnum_dst = 0;
161 struct security_descriptor *sd = NULL;
163 time_t f_atime, f_ctime, f_mtime;
166 if (!copy_timestamps && !copy_acls && !copy_attrs)
169 /* open file/dir on the originating server */
171 DEBUGADD(3,("opening %s %s on originating server\n",
172 is_file?"file":"dir", src_name));
174 if (!NT_STATUS_IS_OK(cli_ntcreate(cli_share_src, src_name, 0, READ_CONTROL_ACCESS, 0,
175 FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum_src))) {
176 DEBUGADD(0,("cannot open %s %s on originating server %s\n",
177 is_file?"file":"dir", src_name, cli_errstr(cli_share_src)));
178 nt_status = cli_nt_error(cli_share_src);
185 /* get the security descriptor */
186 sd = cli_query_secdesc(cli_share_src, fnum_src, mem_ctx);
188 DEBUG(0,("failed to get security descriptor: %s\n",
189 cli_errstr(cli_share_src)));
190 nt_status = cli_nt_error(cli_share_src);
194 if (c->opt_verbose && DEBUGLEVEL >= 3)
195 display_sec_desc(sd);
199 if (copy_attrs || copy_timestamps) {
201 /* get file attributes */
202 if (!NT_STATUS_IS_OK(cli_getattrE(cli_share_src, fnum_src, &attr, NULL,
203 &f_ctime, &f_atime, &f_mtime))) {
204 DEBUG(0,("failed to get file-attrs: %s\n",
205 cli_errstr(cli_share_src)));
206 nt_status = cli_nt_error(cli_share_src);
212 /* open the file/dir on the destination server */
214 if (!NT_STATUS_IS_OK(cli_ntcreate(cli_share_dst, dst_name, 0, WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS, 0,
215 FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum_dst))) {
216 DEBUG(0,("failed to open %s on the destination server: %s: %s\n",
217 is_file?"file":"dir", dst_name, cli_errstr(cli_share_dst)));
218 nt_status = cli_nt_error(cli_share_dst);
222 if (copy_timestamps) {
225 if (!NT_STATUS_IS_OK(cli_setattrE(cli_share_dst, fnum_dst, f_ctime, f_atime, f_mtime))) {
226 DEBUG(0,("failed to set file-attrs (timestamps): %s\n",
227 cli_errstr(cli_share_dst)));
228 nt_status = cli_nt_error(cli_share_dst);
237 status = cli_set_secdesc(cli_share_dst, fnum_dst, sd);
238 if (!NT_STATUS_IS_OK(status)) {
239 DEBUG(0, ("could not set secdesc on %s: %s\n",
240 dst_name, nt_errstr(status)));
249 if (!NT_STATUS_IS_OK(cli_setatr(cli_share_dst, dst_name, attr, 0))) {
250 DEBUG(0,("failed to set file-attrs: %s\n",
251 cli_errstr(cli_share_dst)));
252 nt_status = cli_nt_error(cli_share_dst);
260 if (!NT_STATUS_IS_OK(cli_close(cli_share_src, fnum_src))) {
262 _("could not close %s on originating server: %s\n"),
263 is_file?"file":"dir", cli_errstr(cli_share_src));
264 nt_status = cli_nt_error(cli_share_src);
268 if (!NT_STATUS_IS_OK(cli_close(cli_share_dst, fnum_dst))) {
270 _("could not close %s on destination server: %s\n"),
271 is_file?"file":"dir", cli_errstr(cli_share_dst));
272 nt_status = cli_nt_error(cli_share_dst);
277 nt_status = NT_STATUS_OK;
283 cli_close(cli_share_src, fnum_src);
286 cli_close(cli_share_dst, fnum_dst);
292 * Copy a file or directory from a connected share to another connected share
294 * @param c A net_context structure
295 * @param mem_ctx A talloc-context
296 * @param cli_share_src A connected cli_state
297 * @param cli_share_dst A connected cli_state
298 * @param src_file The source file-name
299 * @param dst_file The destination file-name
300 * @param copy_acls Whether to copy acls
301 * @param copy_attrs Whether to copy DOS attributes
302 * @param copy_timestamps Whether to preserve timestamps
303 * @param is_file Whether this file is a file or a dir
305 * @return Normal NTSTATUS return.
308 NTSTATUS net_copy_file(struct net_context *c,
310 struct cli_state *cli_share_src,
311 struct cli_state *cli_share_dst,
312 const char *src_name, const char *dst_name,
313 bool copy_acls, bool copy_attrs,
314 bool copy_timestamps, bool is_file)
316 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
317 uint16_t fnum_src = 0;
318 uint16_t fnum_dst = 0;
319 static int io_bufsize = 64512;
320 int read_size = io_bufsize;
325 if (!src_name || !dst_name)
328 if (cli_share_src == NULL || cli_share_dst == NULL)
331 /* open on the originating server */
332 DEBUGADD(3,("opening %s %s on originating server\n",
333 is_file ? "file":"dir", src_name));
335 nt_status = cli_open(cli_share_src, src_name, O_RDONLY, DENY_NONE, &fnum_src);
337 nt_status = cli_ntcreate(cli_share_src, src_name, 0, READ_CONTROL_ACCESS, 0,
338 FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum_src);
340 if (!NT_STATUS_IS_OK(nt_status)) {
341 DEBUGADD(0,("cannot open %s %s on originating server %s\n",
342 is_file ? "file":"dir",
343 src_name, cli_errstr(cli_share_src)));
350 /* open file on the destination server */
351 DEBUGADD(3,("opening file %s on destination server\n", dst_name));
352 nt_status = cli_open(cli_share_dst, dst_name,
353 O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum_dst);
355 if (!NT_STATUS_IS_OK(nt_status)) {
356 DEBUGADD(1,("cannot create file %s on destination server: %s\n",
357 dst_name, cli_errstr(cli_share_dst)));
361 /* allocate memory */
362 if (!(data = (char *)SMB_MALLOC(read_size))) {
363 d_fprintf(stderr, _("malloc fail for size %d\n"),
365 nt_status = NT_STATUS_NO_MEMORY;
372 if (c->opt_verbose) {
374 d_printf(_("copying [\\\\%s\\%s%s] => [\\\\%s\\%s%s] "
375 "%s ACLs and %s DOS Attributes %s\n"),
376 cli_share_src->desthost, cli_share_src->share, src_name,
377 cli_share_dst->desthost, cli_share_dst->share, dst_name,
378 copy_acls ? _("with") : _("without"),
379 copy_attrs ? _("with") : _("without"),
380 copy_timestamps ? _("(preserving timestamps)") : "" );
388 n = cli_read(cli_share_src, fnum_src, data, nread,
394 ret = cli_write(cli_share_dst, fnum_dst, 0, data,
398 d_fprintf(stderr, _("Error writing file: %s\n"),
399 cli_errstr(cli_share_dst));
400 nt_status = cli_nt_error(cli_share_dst);
408 if (!is_file && !NT_STATUS_IS_OK(cli_chkpath(cli_share_dst, dst_name))) {
411 DEBUGADD(3,("creating dir %s on the destination server\n",
414 if (!NT_STATUS_IS_OK(cli_mkdir(cli_share_dst, dst_name))) {
415 DEBUG(0,("cannot create directory %s: %s\n",
416 dst_name, cli_errstr(cli_share_dst)));
417 nt_status = NT_STATUS_NO_SUCH_FILE;
420 if (!NT_STATUS_IS_OK(cli_chkpath(cli_share_dst, dst_name))) {
422 _("cannot check for directory %s: %s\n"),
423 dst_name, cli_errstr(cli_share_dst));
430 if (!NT_STATUS_IS_OK(cli_close(cli_share_src, fnum_src))) {
432 _("could not close file on originating server: %s\n"),
433 cli_errstr(cli_share_src));
434 nt_status = cli_nt_error(cli_share_src);
438 if (is_file && !NT_STATUS_IS_OK(cli_close(cli_share_dst, fnum_dst))) {
440 _("could not close file on destination server: %s\n"),
441 cli_errstr(cli_share_dst));
442 nt_status = cli_nt_error(cli_share_dst);
446 /* possibly we have to copy some file-attributes / acls / sd */
447 nt_status = net_copy_fileattr(c, mem_ctx, cli_share_src, cli_share_dst,
448 src_name, dst_name, copy_acls,
449 copy_attrs, copy_timestamps, is_file);
450 if (!NT_STATUS_IS_OK(nt_status))
454 nt_status = NT_STATUS_OK;
460 cli_close(cli_share_src, fnum_src);
463 cli_close(cli_share_dst, fnum_dst);
471 * Copy a driverfile from on connected share to another connected share
472 * This silently assumes that a driver-file is picked up from
474 * \\src_server\print$\{arch}\{version}\file
478 * \\dst_server\print$\{arch}\file
480 * to be added via setdriver-calls later.
481 * @param c A net_context structure
482 * @param mem_ctx A talloc-context
483 * @param cli_share_src A cli_state connected to source print$-share
484 * @param cli_share_dst A cli_state connected to destination print$-share
485 * @param file The file-name to be copied
486 * @param short_archi The name of the driver-architecture (short form)
488 * @return Normal NTSTATUS return.
491 static NTSTATUS net_copy_driverfile(struct net_context *c,
493 struct cli_state *cli_share_src,
494 struct cli_state *cli_share_dst,
495 const char *file, const char *short_archi) {
500 char *version = NULL;
501 char *filename = NULL;
508 /* scroll through the file until we have the part
509 beyond archi_table.short_archi */
511 while (next_token_talloc(mem_ctx, &p, &tok, "\\")) {
512 if (strequal(tok, short_archi)) {
513 next_token_talloc(mem_ctx, &p, &version, "\\");
514 next_token_talloc(mem_ctx, &p, &filename, "\\");
518 if (version == NULL || filename == NULL) {
519 return NT_STATUS_UNSUCCESSFUL;
522 /* build source file name */
523 src_name = talloc_asprintf(mem_ctx, "\\%s\\%s\\%s",
524 short_archi, version, filename);
525 if (src_name == NULL) {
526 return NT_STATUS_NO_MEMORY;
529 /* create destination file name */
530 dst_name = talloc_asprintf(mem_ctx, "\\%s\\%s", short_archi, filename);
531 if (dst_name == NULL) {
532 return NT_STATUS_NO_MEMORY;
536 /* finally copy the file */
537 return net_copy_file(c, mem_ctx, cli_share_src, cli_share_dst,
538 src_name, dst_name, false, false, false, true);
542 * Check for existing Architecture directory on a given server
544 * @param cli_share A cli_state connected to a print$-share
545 * @param short_archi The Architecture for the print-driver
547 * @return Normal NTSTATUS return.
550 static NTSTATUS check_arch_dir(struct cli_state *cli_share, const char *short_archi)
553 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
556 if (asprintf(&dir, "\\%s", short_archi) < 0) {
557 return NT_STATUS_NO_MEMORY;
560 DEBUG(10,("creating print-driver dir for architecture: %s\n",
563 if (!NT_STATUS_IS_OK(cli_mkdir(cli_share, dir))) {
564 DEBUG(1,("cannot create directory %s: %s\n",
565 dir, cli_errstr(cli_share)));
566 nt_status = NT_STATUS_NO_SUCH_FILE;
569 if (!NT_STATUS_IS_OK(cli_chkpath(cli_share, dir))) {
570 d_fprintf(stderr, _("cannot check %s: %s\n"),
571 dir, cli_errstr(cli_share));
575 nt_status = NT_STATUS_OK;
583 * Copy a print-driver (level 3) from one connected print$-share to another
584 * connected print$-share
586 * @param c A net_context structure
587 * @param mem_ctx A talloc-context
588 * @param cli_share_src A cli_state connected to a print$-share
589 * @param cli_share_dst A cli_state connected to a print$-share
590 * @param short_archi The Architecture for the print-driver
591 * @param i1 The DRIVER_INFO_3-struct
593 * @return Normal NTSTATUS return.
596 static NTSTATUS copy_print_driver_3(struct net_context *c,
598 struct cli_state *cli_share_src,
599 struct cli_state *cli_share_dst,
600 const char *short_archi,
601 struct spoolss_DriverInfo3 *r)
603 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
611 d_printf(_("copying driver: [%s], for architecture: [%s], "
613 r->driver_name, short_archi, r->version);
615 nt_status = net_copy_driverfile(c, mem_ctx, cli_share_src, cli_share_dst,
616 r->driver_path, short_archi);
617 if (!NT_STATUS_IS_OK(nt_status))
620 nt_status = net_copy_driverfile(c, mem_ctx, cli_share_src, cli_share_dst,
621 r->data_file, short_archi);
622 if (!NT_STATUS_IS_OK(nt_status))
625 nt_status = net_copy_driverfile(c, mem_ctx, cli_share_src, cli_share_dst,
626 r->config_file, short_archi);
627 if (!NT_STATUS_IS_OK(nt_status))
630 nt_status = net_copy_driverfile(c, mem_ctx, cli_share_src, cli_share_dst,
631 r->help_file, short_archi);
632 if (!NT_STATUS_IS_OK(nt_status))
635 for (i=0; r->dependent_files[i] != NULL; i++) {
637 nt_status = net_copy_driverfile(c, mem_ctx,
638 cli_share_src, cli_share_dst,
639 r->dependent_files[i], short_archi);
640 if (!NT_STATUS_IS_OK(nt_status)) {
649 * net_spoolss-functions
650 * =====================
652 * the net_spoolss-functions aim to simplify spoolss-client-functions
653 * required during the migration-process wrt buffer-sizes, returned
656 * this greatly reduces the complexitiy of the migrate-functions.
660 static bool net_spoolss_enum_printers(struct rpc_pipe_client *pipe_hnd,
665 uint32_t *num_printers,
666 union spoolss_PrinterInfo **info)
672 result = rpccli_spoolss_enumprinters(pipe_hnd, mem_ctx,
679 if (!W_ERROR_IS_OK(result)) {
680 printf(_("cannot enum printers: %s\n"), win_errstr(result));
687 static bool net_spoolss_open_printer_ex(struct rpc_pipe_client *pipe_hnd,
689 const char *printername,
690 uint32_t access_required,
691 const char *username,
692 struct policy_handle *hnd)
695 fstring printername2;
697 fstrcpy(printername2, pipe_hnd->srv_name_slash);
698 fstrcat(printername2, "\\");
699 fstrcat(printername2, printername);
701 DEBUG(10,("connecting to: %s as %s for %s and access: %x\n",
702 pipe_hnd->srv_name_slash, username, printername2, access_required));
705 result = rpccli_spoolss_openprinter_ex(pipe_hnd, mem_ctx,
710 /* be more verbose */
711 if (W_ERROR_V(result) == W_ERROR_V(WERR_ACCESS_DENIED)) {
713 _("no access to printer [%s] on [%s] for user [%s] "
715 printername2, pipe_hnd->srv_name_slash, username);
719 if (!W_ERROR_IS_OK(result)) {
720 d_fprintf(stderr,_("cannot open printer %s on server %s: %s\n"),
721 printername2, pipe_hnd->srv_name_slash, win_errstr(result));
725 DEBUG(2,("got printer handle for printer: %s, server: %s\n",
726 printername2, pipe_hnd->srv_name_slash));
731 static bool net_spoolss_getprinter(struct rpc_pipe_client *pipe_hnd,
733 struct policy_handle *hnd,
735 union spoolss_PrinterInfo *info)
739 /* getprinter call */
740 result = rpccli_spoolss_getprinter(pipe_hnd, mem_ctx,
745 if (!W_ERROR_IS_OK(result)) {
746 printf(_("cannot get printer-info: %s\n"), win_errstr(result));
753 static bool net_spoolss_setprinter(struct rpc_pipe_client *pipe_hnd,
755 struct policy_handle *hnd,
757 union spoolss_PrinterInfo *info)
761 struct spoolss_SetPrinterInfoCtr info_ctr;
762 struct spoolss_SetPrinterInfo2 info2;
763 struct spoolss_DevmodeContainer devmode_ctr;
764 struct sec_desc_buf secdesc_ctr;
766 ZERO_STRUCT(devmode_ctr);
767 ZERO_STRUCT(secdesc_ctr);
769 /* setprinter call */
771 info_ctr.level = level;
774 info_ctr.info.info0 = (struct spoolss_SetPrinterInfo0 *)
775 (void *)&info->info0;
778 info_ctr.info.info1 = (struct spoolss_SetPrinterInfo1 *)
779 (void *)&info->info1;
782 spoolss_printerinfo2_to_setprinterinfo2(&info->info2, &info2);
783 info_ctr.info.info2 = &info2;
786 info_ctr.info.info3 = (struct spoolss_SetPrinterInfo3 *)
787 (void *)&info->info3;
790 info_ctr.info.info4 = (struct spoolss_SetPrinterInfo4 *)
791 (void *)&info->info4;
794 info_ctr.info.info5 = (struct spoolss_SetPrinterInfo5 *)
795 (void *)&info->info5;
798 info_ctr.info.info6 = (struct spoolss_SetPrinterInfo6 *)
799 (void *)&info->info6;
802 info_ctr.info.info7 = (struct spoolss_SetPrinterInfo7 *)
803 (void *)&info->info7;
807 info_ctr.info.info8 = (struct spoolss_SetPrinterInfo8 *)
808 (void *)&info->info8;
811 info_ctr.info.info9 = (struct spoolss_SetPrinterInfo9 *)
812 (void *)&info->info9;
819 status = rpccli_spoolss_SetPrinter(pipe_hnd, mem_ctx,
827 if (!W_ERROR_IS_OK(result)) {
828 printf(_("cannot set printer-info: %s\n"), win_errstr(result));
836 static bool net_spoolss_setprinterdata(struct rpc_pipe_client *pipe_hnd,
838 struct policy_handle *hnd,
839 const char *value_name,
840 enum winreg_Type type,
847 /* setprinterdata call */
848 status = rpccli_spoolss_SetPrinterData(pipe_hnd, mem_ctx,
856 if (!W_ERROR_IS_OK(result)) {
857 printf (_("unable to set printerdata: %s\n"),
866 static bool net_spoolss_enumprinterkey(struct rpc_pipe_client *pipe_hnd,
868 struct policy_handle *hnd,
870 const char ***keylist)
874 /* enumprinterkey call */
875 result = rpccli_spoolss_enumprinterkey(pipe_hnd, mem_ctx, hnd, keyname, keylist, 0);
877 if (!W_ERROR_IS_OK(result)) {
878 printf(_("enumprinterkey failed: %s\n"), win_errstr(result));
885 static bool net_spoolss_enumprinterdataex(struct rpc_pipe_client *pipe_hnd,
888 struct policy_handle *hnd,
891 struct spoolss_PrinterEnumValues **info)
895 /* enumprinterdataex call */
896 result = rpccli_spoolss_enumprinterdataex(pipe_hnd, mem_ctx,
903 if (!W_ERROR_IS_OK(result)) {
904 printf(_("enumprinterdataex failed: %s\n"), win_errstr(result));
912 static bool net_spoolss_setprinterdataex(struct rpc_pipe_client *pipe_hnd,
914 struct policy_handle *hnd,
916 struct regval_blob *value)
921 /* setprinterdataex call */
922 status = rpccli_spoolss_SetPrinterDataEx(pipe_hnd, mem_ctx,
927 regval_data_p(value),
931 if (!W_ERROR_IS_OK(result)) {
932 printf(_("could not set printerdataex: %s\n"),
940 static bool net_spoolss_enumforms(struct rpc_pipe_client *pipe_hnd,
942 struct policy_handle *hnd,
945 union spoolss_FormInfo **forms)
950 result = rpccli_spoolss_enumforms(pipe_hnd, mem_ctx,
956 if (!W_ERROR_IS_OK(result)) {
957 printf(_("could not enum forms: %s\n"), win_errstr(result));
964 static bool net_spoolss_enumprinterdrivers (struct rpc_pipe_client *pipe_hnd,
966 uint32_t level, const char *env,
968 union spoolss_DriverInfo **info)
972 /* enumprinterdrivers call */
973 result = rpccli_spoolss_enumprinterdrivers(pipe_hnd, mem_ctx,
974 pipe_hnd->srv_name_slash,
980 if (!W_ERROR_IS_OK(result)) {
981 if (W_ERROR_V(result) != W_ERROR_V(WERR_INVALID_ENVIRONMENT)) {
982 printf(_("cannot enum drivers for environment %s: %s\n"), env,
986 printf(_("Server does not support environment [%s]\n"),
994 static bool net_spoolss_getprinterdriver(struct rpc_pipe_client *pipe_hnd,
996 struct policy_handle *hnd, uint32_t level,
997 const char *env, int version,
998 union spoolss_DriverInfo *info)
1001 uint32_t server_major_version;
1002 uint32_t server_minor_version;
1004 /* getprinterdriver call */
1005 result = rpccli_spoolss_getprinterdriver2(pipe_hnd, mem_ctx,
1013 &server_major_version,
1014 &server_minor_version);
1015 if (!W_ERROR_IS_OK(result)) {
1016 DEBUG(1,("cannot get driver (for architecture: %s): %s\n",
1017 env, win_errstr(result)));
1018 if (W_ERROR_V(result) != W_ERROR_V(WERR_UNKNOWN_PRINTER_DRIVER) &&
1019 W_ERROR_V(result) != W_ERROR_V(WERR_INVALID_ENVIRONMENT)) {
1020 printf(_("cannot get driver: %s\n"),
1021 win_errstr(result));
1030 static bool net_spoolss_addprinterdriver(struct rpc_pipe_client *pipe_hnd,
1031 TALLOC_CTX *mem_ctx, uint32_t level,
1032 union spoolss_DriverInfo *info)
1036 struct spoolss_AddDriverInfoCtr info_ctr;
1038 info_ctr.level = level;
1042 info_ctr.info.info2 = (struct spoolss_AddDriverInfo2 *)
1043 (void *)&info->info2;
1046 info_ctr.info.info3 = (struct spoolss_AddDriverInfo3 *)
1047 (void *)&info->info3;
1050 printf(_("unsupported info level: %d\n"), level);
1054 /* addprinterdriver call */
1055 status = rpccli_spoolss_AddPrinterDriver(pipe_hnd, mem_ctx,
1056 pipe_hnd->srv_name_slash,
1059 /* be more verbose */
1060 if (W_ERROR_V(result) == W_ERROR_V(WERR_ACCESS_DENIED)) {
1061 printf(_("You are not allowed to add drivers\n"));
1064 if (!W_ERROR_IS_OK(result)) {
1065 printf(_("cannot add driver: %s\n"), win_errstr(result));
1073 * abstraction function to get uint32_t num_printers and PRINTER_INFO_CTR ctr
1074 * for a single printer or for all printers depending on argc/argv
1077 static bool get_printer_info(struct rpc_pipe_client *pipe_hnd,
1078 TALLOC_CTX *mem_ctx,
1082 uint32_t *num_printers,
1083 union spoolss_PrinterInfo **info_p)
1085 struct policy_handle hnd;
1087 /* no arguments given, enumerate all printers */
1090 if (!net_spoolss_enum_printers(pipe_hnd, mem_ctx, NULL,
1091 PRINTER_ENUM_LOCAL|PRINTER_ENUM_SHARED,
1092 level, num_printers, info_p))
1098 /* argument given, get a single printer by name */
1099 if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, argv[0],
1100 MAXIMUM_ALLOWED_ACCESS,
1101 pipe_hnd->auth->user_name,
1105 *info_p = talloc_zero(mem_ctx, union spoolss_PrinterInfo);
1106 if (*info_p == NULL) {
1110 if (!net_spoolss_getprinter(pipe_hnd, mem_ctx, &hnd, level, *info_p)) {
1111 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL);
1115 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL);
1120 DEBUG(3,("got %d printers\n", *num_printers));
1127 * List print-queues (including local printers that are not shared)
1129 * All parameters are provided by the run_rpc_command function, except for
1130 * argc, argv which are passed through.
1132 * @param c A net_context structure
1133 * @param domain_sid The domain sid aquired from the remote server
1134 * @param cli A cli_state connected to the server.
1135 * @param mem_ctx Talloc context, destoyed on compleation of the function.
1136 * @param argc Standard main() style argc
1137 * @param argv Standard main() style argv. Initial components are already
1140 * @return Normal NTSTATUS return.
1143 NTSTATUS rpc_printer_list_internals(struct net_context *c,
1144 const struct dom_sid *domain_sid,
1145 const char *domain_name,
1146 struct cli_state *cli,
1147 struct rpc_pipe_client *pipe_hnd,
1148 TALLOC_CTX *mem_ctx,
1152 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1153 uint32_t i, num_printers;
1155 const char *printername, *sharename;
1156 union spoolss_PrinterInfo *info;
1158 printf("listing printers\n");
1160 if (!get_printer_info(pipe_hnd, mem_ctx, level, argc, argv, &num_printers, &info))
1163 for (i = 0; i < num_printers; i++) {
1165 /* do some initialization */
1166 printername = info[i].info2.printername;
1167 sharename = info[i].info2.sharename;
1169 if (printername && sharename) {
1170 d_printf(_("printer %d: %s, shared as: %s\n"),
1171 i+1, printername, sharename);
1175 return NT_STATUS_OK;
1179 * List printer-drivers from a server
1181 * All parameters are provided by the run_rpc_command function, except for
1182 * argc, argv which are passed through.
1184 * @param c A net_context structure
1185 * @param domain_sid The domain sid aquired from the remote server
1186 * @param cli A cli_state connected to the server.
1187 * @param mem_ctx Talloc context, destoyed on compleation of the function.
1188 * @param argc Standard main() style argc
1189 * @param argv Standard main() style argv. Initial components are already
1192 * @return Normal NTSTATUS return.
1195 NTSTATUS rpc_printer_driver_list_internals(struct net_context *c,
1196 const struct dom_sid *domain_sid,
1197 const char *domain_name,
1198 struct cli_state *cli,
1199 struct rpc_pipe_client *pipe_hnd,
1200 TALLOC_CTX *mem_ctx,
1204 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1207 union spoolss_DriverInfo *info;
1210 printf(_("listing printer-drivers\n"));
1212 for (i=0; archi_table[i].long_archi!=NULL; i++) {
1214 uint32_t num_drivers;
1216 /* enum remote drivers */
1217 if (!net_spoolss_enumprinterdrivers(pipe_hnd, mem_ctx, level,
1218 archi_table[i].long_archi,
1219 &num_drivers, &info)) {
1220 nt_status = NT_STATUS_UNSUCCESSFUL;
1224 if (num_drivers == 0) {
1225 d_printf(_("no drivers found on server for "
1226 "architecture: [%s].\n"),
1227 archi_table[i].long_archi);
1231 d_printf(_("got %d printer-drivers for architecture: [%s]\n"),
1232 num_drivers, archi_table[i].long_archi);
1235 /* do something for all drivers for architecture */
1236 for (d = 0; d < num_drivers; d++) {
1237 display_print_driver3(&info[d].info3);
1241 nt_status = NT_STATUS_OK;
1249 * Publish print-queues with args-wrapper
1251 * @param cli A cli_state connected to the server.
1252 * @param mem_ctx Talloc context, destoyed on compleation of the function.
1253 * @param argc Standard main() style argc
1254 * @param argv Standard main() style argv. Initial components are already
1258 * @return Normal NTSTATUS return.
1261 static NTSTATUS rpc_printer_publish_internals_args(struct rpc_pipe_client *pipe_hnd,
1262 TALLOC_CTX *mem_ctx,
1267 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1268 uint32_t i, num_printers;
1270 const char *printername, *sharename;
1271 union spoolss_PrinterInfo *info_enum;
1272 union spoolss_PrinterInfo info;
1273 struct spoolss_SetPrinterInfoCtr info_ctr;
1274 struct spoolss_DevmodeContainer devmode_ctr;
1275 struct sec_desc_buf secdesc_ctr;
1276 struct policy_handle hnd;
1278 const char *action_str;
1280 if (!get_printer_info(pipe_hnd, mem_ctx, 2, argc, argv, &num_printers, &info_enum))
1283 for (i = 0; i < num_printers; i++) {
1285 /* do some initialization */
1286 printername = info_enum[i].info2.printername;
1287 sharename = info_enum[i].info2.sharename;
1288 if (!printername || !sharename) {
1292 /* open printer handle */
1293 if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
1294 PRINTER_ALL_ACCESS, pipe_hnd->auth->user_name, &hnd))
1297 /* check for existing dst printer */
1298 if (!net_spoolss_getprinter(pipe_hnd, mem_ctx, &hnd, level, &info))
1301 /* check action and set string */
1303 case DSPRINT_PUBLISH:
1304 action_str = N_("published");
1306 case DSPRINT_UPDATE:
1307 action_str = N_("updated");
1309 case DSPRINT_UNPUBLISH:
1310 action_str = N_("unpublished");
1313 action_str = N_("unknown action");
1314 printf(_("unkown action: %d\n"), action);
1318 info.info7.action = action;
1320 info_ctr.info.info7 = (struct spoolss_SetPrinterInfo7 *)
1321 (void *)&info.info7;
1323 ZERO_STRUCT(devmode_ctr);
1324 ZERO_STRUCT(secdesc_ctr);
1326 nt_status = rpccli_spoolss_SetPrinter(pipe_hnd, mem_ctx,
1334 if (!W_ERROR_IS_OK(result) && !W_ERROR_EQUAL(result, WERR_IO_PENDING)) {
1335 if ((action == DSPRINT_UPDATE) && W_ERROR_EQUAL(result, W_ERROR(0x80070002))) {
1336 printf(_("printer not published yet\n"));
1338 printf(_("cannot set printer-info: %s\n"),
1339 win_errstr(result));
1344 printf(_("successfully %s printer %s in Active Directory\n"),
1345 action_str, sharename);
1348 nt_status = NT_STATUS_OK;
1351 if (is_valid_policy_hnd(&hnd))
1352 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL);
1357 NTSTATUS rpc_printer_publish_publish_internals(struct net_context *c,
1358 const struct dom_sid *domain_sid,
1359 const char *domain_name,
1360 struct cli_state *cli,
1361 struct rpc_pipe_client *pipe_hnd,
1362 TALLOC_CTX *mem_ctx,
1366 return rpc_printer_publish_internals_args(pipe_hnd, mem_ctx, argc, argv, DSPRINT_PUBLISH);
1369 NTSTATUS rpc_printer_publish_unpublish_internals(struct net_context *c,
1370 const struct dom_sid *domain_sid,
1371 const char *domain_name,
1372 struct cli_state *cli,
1373 struct rpc_pipe_client *pipe_hnd,
1374 TALLOC_CTX *mem_ctx,
1378 return rpc_printer_publish_internals_args(pipe_hnd, mem_ctx, argc, argv, DSPRINT_UNPUBLISH);
1381 NTSTATUS rpc_printer_publish_update_internals(struct net_context *c,
1382 const struct dom_sid *domain_sid,
1383 const char *domain_name,
1384 struct cli_state *cli,
1385 struct rpc_pipe_client *pipe_hnd,
1386 TALLOC_CTX *mem_ctx,
1390 return rpc_printer_publish_internals_args(pipe_hnd, mem_ctx, argc, argv, DSPRINT_UPDATE);
1394 * List print-queues w.r.t. their publishing state
1396 * All parameters are provided by the run_rpc_command function, except for
1397 * argc, argv which are passed through.
1399 * @param c A net_context structure
1400 * @param domain_sid The domain sid aquired from the remote server
1401 * @param cli A cli_state connected to the server.
1402 * @param mem_ctx Talloc context, destoyed on compleation of the function.
1403 * @param argc Standard main() style argc
1404 * @param argv Standard main() style argv. Initial components are already
1407 * @return Normal NTSTATUS return.
1410 NTSTATUS rpc_printer_publish_list_internals(struct net_context *c,
1411 const struct dom_sid *domain_sid,
1412 const char *domain_name,
1413 struct cli_state *cli,
1414 struct rpc_pipe_client *pipe_hnd,
1415 TALLOC_CTX *mem_ctx,
1419 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1420 uint32_t i, num_printers;
1422 const char *printername, *sharename;
1423 union spoolss_PrinterInfo *info_enum;
1424 union spoolss_PrinterInfo info;
1425 struct policy_handle hnd;
1428 if (!get_printer_info(pipe_hnd, mem_ctx, 2, argc, argv, &num_printers, &info_enum))
1431 for (i = 0; i < num_printers; i++) {
1433 /* do some initialization */
1434 printername = info_enum[i].info2.printername;
1435 sharename = info_enum[i].info2.sharename;
1437 if (!printername || !sharename) {
1441 /* open printer handle */
1442 if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
1443 PRINTER_ALL_ACCESS, cli->user_name, &hnd))
1446 /* check for existing dst printer */
1447 if (!net_spoolss_getprinter(pipe_hnd, mem_ctx, &hnd, level, &info))
1450 if (!info.info7.guid) {
1453 state = info.info7.action;
1455 case DSPRINT_PUBLISH:
1456 printf(_("printer [%s] is published"),
1459 printf(_(", guid: %s"),info.info7.guid);
1462 case DSPRINT_UNPUBLISH:
1463 printf(_("printer [%s] is unpublished\n"),
1466 case DSPRINT_UPDATE:
1467 printf(_("printer [%s] is currently updating\n"),
1471 printf(_("unkown state: %d\n"), state);
1476 nt_status = NT_STATUS_OK;
1479 if (is_valid_policy_hnd(&hnd))
1480 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL);
1486 * Migrate Printer-ACLs from a source server to the destination server
1488 * All parameters are provided by the run_rpc_command function, except for
1489 * argc, argv which are passed through.
1491 * @param c A net_context structure
1492 * @param domain_sid The domain sid aquired from the remote server
1493 * @param cli A cli_state connected to the server.
1494 * @param mem_ctx Talloc context, destoyed on compleation of the function.
1495 * @param argc Standard main() style argc
1496 * @param argv Standard main() style argv. Initial components are already
1499 * @return Normal NTSTATUS return.
1502 NTSTATUS rpc_printer_migrate_security_internals(struct net_context *c,
1503 const struct dom_sid *domain_sid,
1504 const char *domain_name,
1505 struct cli_state *cli,
1506 struct rpc_pipe_client *pipe_hnd,
1507 TALLOC_CTX *mem_ctx,
1511 /* TODO: what now, info2 or info3 ?
1512 convince jerry that we should add clientside setacls level 3 at least
1514 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1516 uint32_t num_printers;
1518 const char *printername, *sharename;
1519 struct rpc_pipe_client *pipe_hnd_dst = NULL;
1520 struct policy_handle hnd_src, hnd_dst;
1521 union spoolss_PrinterInfo *info_enum;
1522 struct cli_state *cli_dst = NULL;
1523 union spoolss_PrinterInfo info_src, info_dst;
1525 DEBUG(3,("copying printer ACLs\n"));
1527 /* connect destination PI_SPOOLSS */
1528 nt_status = connect_dst_pipe(c, &cli_dst, &pipe_hnd_dst,
1529 &ndr_table_spoolss.syntax_id);
1530 if (!NT_STATUS_IS_OK(nt_status))
1534 /* enum source printers */
1535 if (!get_printer_info(pipe_hnd, mem_ctx, level, argc, argv, &num_printers, &info_enum)) {
1536 nt_status = NT_STATUS_UNSUCCESSFUL;
1540 if (!num_printers) {
1541 printf (_("no printers found on server.\n"));
1542 nt_status = NT_STATUS_OK;
1546 /* do something for all printers */
1547 for (i = 0; i < num_printers; i++) {
1549 /* do some initialization */
1550 printername = info_enum[i].info2.printername;
1551 sharename = info_enum[i].info2.sharename;
1553 if (!printername || !sharename) {
1554 nt_status = NT_STATUS_UNSUCCESSFUL;
1558 /* we can reset NT_STATUS here because we do not
1559 get any real NT_STATUS-codes anymore from now on */
1560 nt_status = NT_STATUS_UNSUCCESSFUL;
1562 d_printf(_("migrating printer ACLs for: [%s] / [%s]\n"),
1563 printername, sharename);
1565 /* according to msdn you have specify these access-rights
1566 to see the security descriptor
1567 - READ_CONTROL (DACL)
1568 - ACCESS_SYSTEM_SECURITY (SACL)
1571 /* open src printer handle */
1572 if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
1573 MAXIMUM_ALLOWED_ACCESS, cli->user_name, &hnd_src))
1576 /* open dst printer handle */
1577 if (!net_spoolss_open_printer_ex(pipe_hnd_dst, mem_ctx, sharename,
1578 PRINTER_ALL_ACCESS, cli_dst->user_name, &hnd_dst))
1581 /* check for existing dst printer */
1582 if (!net_spoolss_getprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, level, &info_dst))
1585 /* check for existing src printer */
1586 if (!net_spoolss_getprinter(pipe_hnd, mem_ctx, &hnd_src, 3, &info_src))
1589 /* Copy Security Descriptor */
1591 /* copy secdesc (info level 2) */
1592 info_dst.info2.devmode = NULL;
1593 info_dst.info2.secdesc = dup_sec_desc(mem_ctx, info_src.info3.secdesc);
1596 display_sec_desc(info_dst.info2.secdesc);
1598 if (!net_spoolss_setprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, 2, &info_dst))
1601 DEBUGADD(1,("\tSetPrinter of SECDESC succeeded\n"));
1604 /* close printer handles here */
1605 if (is_valid_policy_hnd(&hnd_src)) {
1606 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd_src, NULL);
1609 if (is_valid_policy_hnd(&hnd_dst)) {
1610 rpccli_spoolss_ClosePrinter(pipe_hnd_dst, mem_ctx, &hnd_dst, NULL);
1615 nt_status = NT_STATUS_OK;
1619 if (is_valid_policy_hnd(&hnd_src)) {
1620 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd_src, NULL);
1623 if (is_valid_policy_hnd(&hnd_dst)) {
1624 rpccli_spoolss_ClosePrinter(pipe_hnd_dst, mem_ctx, &hnd_dst, NULL);
1628 cli_shutdown(cli_dst);
1634 * Migrate printer-forms from a src server to the dst server
1636 * All parameters are provided by the run_rpc_command function, except for
1637 * argc, argv which are passed through.
1639 * @param c A net_context structure
1640 * @param domain_sid The domain sid aquired from the remote server
1641 * @param cli A cli_state connected to the server.
1642 * @param mem_ctx Talloc context, destoyed on compleation of the function.
1643 * @param argc Standard main() style argc
1644 * @param argv Standard main() style argv. Initial components are already
1647 * @return Normal NTSTATUS return.
1650 NTSTATUS rpc_printer_migrate_forms_internals(struct net_context *c,
1651 const struct dom_sid *domain_sid,
1652 const char *domain_name,
1653 struct cli_state *cli,
1654 struct rpc_pipe_client *pipe_hnd,
1655 TALLOC_CTX *mem_ctx,
1659 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1662 uint32_t num_printers;
1664 const char *printername, *sharename;
1665 struct rpc_pipe_client *pipe_hnd_dst = NULL;
1666 struct policy_handle hnd_src, hnd_dst;
1667 union spoolss_PrinterInfo *info_enum;
1668 union spoolss_PrinterInfo info_dst;
1670 union spoolss_FormInfo *forms;
1671 struct cli_state *cli_dst = NULL;
1673 DEBUG(3,("copying forms\n"));
1675 /* connect destination PI_SPOOLSS */
1676 nt_status = connect_dst_pipe(c, &cli_dst, &pipe_hnd_dst,
1677 &ndr_table_spoolss.syntax_id);
1678 if (!NT_STATUS_IS_OK(nt_status))
1681 /* enum src printers */
1682 if (!get_printer_info(pipe_hnd, mem_ctx, 2, argc, argv, &num_printers, &info_enum)) {
1683 nt_status = NT_STATUS_UNSUCCESSFUL;
1687 if (!num_printers) {
1688 printf (_("no printers found on server.\n"));
1689 nt_status = NT_STATUS_OK;
1693 /* do something for all printers */
1694 for (i = 0; i < num_printers; i++) {
1696 /* do some initialization */
1697 printername = info_enum[i].info2.printername;
1698 sharename = info_enum[i].info2.sharename;
1700 if (!printername || !sharename) {
1701 nt_status = NT_STATUS_UNSUCCESSFUL;
1704 /* we can reset NT_STATUS here because we do not
1705 get any real NT_STATUS-codes anymore from now on */
1706 nt_status = NT_STATUS_UNSUCCESSFUL;
1708 d_printf(_("migrating printer forms for: [%s] / [%s]\n"),
1709 printername, sharename);
1712 /* open src printer handle */
1713 if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
1714 MAXIMUM_ALLOWED_ACCESS, cli->user_name, &hnd_src))
1717 /* open dst printer handle */
1718 if (!net_spoolss_open_printer_ex(pipe_hnd_dst, mem_ctx, sharename,
1719 PRINTER_ALL_ACCESS, cli->user_name, &hnd_dst))
1722 /* check for existing dst printer */
1723 if (!net_spoolss_getprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, level, &info_dst))
1726 /* finally migrate forms */
1727 if (!net_spoolss_enumforms(pipe_hnd, mem_ctx, &hnd_src, level, &num_forms, &forms))
1730 DEBUG(1,("got %d forms for printer\n", num_forms));
1733 for (f = 0; f < num_forms; f++) {
1735 union spoolss_AddFormInfo info;
1738 /* only migrate FORM_PRINTER types, according to jerry
1739 FORM_BUILTIN-types are hard-coded in samba */
1740 if (forms[f].info1.flags != SPOOLSS_FORM_PRINTER)
1744 d_printf(_("\tmigrating form # %d [%s] of type "
1746 f, forms[f].info1.form_name,
1747 forms[f].info1.flags);
1749 info.info1 = (struct spoolss_AddFormInfo1 *)
1750 (void *)&forms[f].info1;
1752 /* FIXME: there might be something wrong with samba's
1754 status = rpccli_spoolss_AddForm(pipe_hnd_dst, mem_ctx,
1759 if (!W_ERROR_IS_OK(result)) {
1760 d_printf(_("\tAddForm form %d: [%s] refused.\n"),
1761 f, forms[f].info1.form_name);
1765 DEBUGADD(1,("\tAddForm of [%s] succeeded\n",
1766 forms[f].info1.form_name));
1770 /* close printer handles here */
1771 if (is_valid_policy_hnd(&hnd_src)) {
1772 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd_src, NULL);
1775 if (is_valid_policy_hnd(&hnd_dst)) {
1776 rpccli_spoolss_ClosePrinter(pipe_hnd_dst, mem_ctx, &hnd_dst, NULL);
1780 nt_status = NT_STATUS_OK;
1784 if (is_valid_policy_hnd(&hnd_src))
1785 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd_src, NULL);
1787 if (is_valid_policy_hnd(&hnd_dst))
1788 rpccli_spoolss_ClosePrinter(pipe_hnd_dst, mem_ctx, &hnd_dst, NULL);
1791 cli_shutdown(cli_dst);
1797 * Migrate printer-drivers from a src server to the dst server
1799 * All parameters are provided by the run_rpc_command function, except for
1800 * argc, argv which are passed through.
1802 * @param c A net_context structure
1803 * @param domain_sid The domain sid aquired from the remote server
1804 * @param cli A cli_state connected to the server.
1805 * @param mem_ctx Talloc context, destoyed on compleation of the function.
1806 * @param argc Standard main() style argc
1807 * @param argv Standard main() style argv. Initial components are already
1810 * @return Normal NTSTATUS return.
1813 NTSTATUS rpc_printer_migrate_drivers_internals(struct net_context *c,
1814 const struct dom_sid *domain_sid,
1815 const char *domain_name,
1816 struct cli_state *cli,
1817 struct rpc_pipe_client *pipe_hnd,
1818 TALLOC_CTX *mem_ctx,
1822 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1824 uint32_t num_printers;
1826 const char *printername, *sharename;
1827 bool got_src_driver_share = false;
1828 bool got_dst_driver_share = false;
1829 struct rpc_pipe_client *pipe_hnd_dst = NULL;
1830 struct policy_handle hnd_src, hnd_dst;
1831 union spoolss_DriverInfo drv_info_src;
1832 union spoolss_PrinterInfo *info_enum;
1833 union spoolss_PrinterInfo info_dst;
1834 struct cli_state *cli_dst = NULL;
1835 struct cli_state *cli_share_src = NULL;
1836 struct cli_state *cli_share_dst = NULL;
1837 const char *drivername = NULL;
1839 DEBUG(3,("copying printer-drivers\n"));
1841 nt_status = connect_dst_pipe(c, &cli_dst, &pipe_hnd_dst,
1842 &ndr_table_spoolss.syntax_id);
1843 if (!NT_STATUS_IS_OK(nt_status))
1846 /* open print$-share on the src server */
1847 nt_status = connect_to_service(c, &cli_share_src, &cli->dest_ss,
1848 cli->desthost, "print$", "A:");
1849 if (!NT_STATUS_IS_OK(nt_status))
1852 got_src_driver_share = true;
1855 /* open print$-share on the dst server */
1856 nt_status = connect_to_service(c, &cli_share_dst, &cli_dst->dest_ss,
1857 cli_dst->desthost, "print$", "A:");
1858 if (!NT_STATUS_IS_OK(nt_status))
1861 got_dst_driver_share = true;
1864 /* enum src printers */
1865 if (!get_printer_info(pipe_hnd, mem_ctx, 2, argc, argv, &num_printers, &info_enum)) {
1866 nt_status = NT_STATUS_UNSUCCESSFUL;
1870 if (num_printers == 0) {
1871 printf (_("no printers found on server.\n"));
1872 nt_status = NT_STATUS_OK;
1877 /* do something for all printers */
1878 for (p = 0; p < num_printers; p++) {
1880 /* do some initialization */
1881 printername = info_enum[p].info2.printername;
1882 sharename = info_enum[p].info2.sharename;
1884 if (!printername || !sharename) {
1885 nt_status = NT_STATUS_UNSUCCESSFUL;
1889 /* we can reset NT_STATUS here because we do not
1890 get any real NT_STATUS-codes anymore from now on */
1891 nt_status = NT_STATUS_UNSUCCESSFUL;
1893 d_printf(_("migrating printer driver for: [%s] / [%s]\n"),
1894 printername, sharename);
1896 /* open dst printer handle */
1897 if (!net_spoolss_open_printer_ex(pipe_hnd_dst, mem_ctx, sharename,
1898 PRINTER_ALL_ACCESS, cli->user_name, &hnd_dst))
1901 /* check for existing dst printer */
1902 if (!net_spoolss_getprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, 2, &info_dst))
1906 /* open src printer handle */
1907 if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
1908 MAXIMUM_ALLOWED_ACCESS,
1909 pipe_hnd->auth->user_name,
1913 /* in a first step call getdriver for each shared printer (per arch)
1914 to get a list of all files that have to be copied */
1916 for (i=0; archi_table[i].long_archi!=NULL; i++) {
1919 if (!net_spoolss_getprinterdriver(pipe_hnd, mem_ctx, &hnd_src,
1920 level, archi_table[i].long_archi,
1921 archi_table[i].version, &drv_info_src))
1924 drivername = drv_info_src.info3.driver_name;
1927 display_print_driver3(&drv_info_src.info3);
1929 /* check arch dir */
1930 nt_status = check_arch_dir(cli_share_dst, archi_table[i].short_archi);
1931 if (!NT_STATUS_IS_OK(nt_status))
1935 /* copy driver-files */
1936 nt_status = copy_print_driver_3(c, mem_ctx, cli_share_src, cli_share_dst,
1937 archi_table[i].short_archi,
1938 &drv_info_src.info3);
1939 if (!NT_STATUS_IS_OK(nt_status))
1944 if (!net_spoolss_addprinterdriver(pipe_hnd_dst, mem_ctx, level, &drv_info_src)) {
1945 nt_status = NT_STATUS_UNSUCCESSFUL;
1949 DEBUGADD(1,("Sucessfully added driver [%s] for printer [%s]\n",
1950 drivername, printername));
1954 if (!drivername || strlen(drivername) == 0) {
1955 DEBUGADD(1,("Did not get driver for printer %s\n",
1961 info_dst.info2.drivername = drivername;
1963 if (!net_spoolss_setprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, 2, &info_dst)) {
1964 nt_status = NT_STATUS_UNSUCCESSFUL;
1968 DEBUGADD(1,("Sucessfully set driver %s for printer %s\n",
1969 drivername, printername));
1972 if (is_valid_policy_hnd(&hnd_dst)) {
1973 rpccli_spoolss_ClosePrinter(pipe_hnd_dst, mem_ctx, &hnd_dst, NULL);
1977 if (is_valid_policy_hnd(&hnd_src)) {
1978 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd_src, NULL);
1982 nt_status = NT_STATUS_OK;
1986 if (is_valid_policy_hnd(&hnd_src))
1987 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd_src, NULL);
1989 if (is_valid_policy_hnd(&hnd_dst))
1990 rpccli_spoolss_ClosePrinter(pipe_hnd_dst, mem_ctx, &hnd_dst, NULL);
1993 cli_shutdown(cli_dst);
1996 if (got_src_driver_share)
1997 cli_shutdown(cli_share_src);
1999 if (got_dst_driver_share)
2000 cli_shutdown(cli_share_dst);
2007 * Migrate printer-queues from a src to the dst server
2008 * (requires a working "addprinter command" to be installed for the local smbd)
2010 * All parameters are provided by the run_rpc_command function, except for
2011 * argc, argv which are passed through.
2013 * @param c A net_context structure
2014 * @param domain_sid The domain sid aquired from the remote server
2015 * @param cli A cli_state connected to the server.
2016 * @param mem_ctx Talloc context, destoyed on compleation of the function.
2017 * @param argc Standard main() style argc
2018 * @param argv Standard main() style argv. Initial components are already
2021 * @return Normal NTSTATUS return.
2024 NTSTATUS rpc_printer_migrate_printers_internals(struct net_context *c,
2025 const struct dom_sid *domain_sid,
2026 const char *domain_name,
2027 struct cli_state *cli,
2028 struct rpc_pipe_client *pipe_hnd,
2029 TALLOC_CTX *mem_ctx,
2034 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
2035 uint32_t i = 0, num_printers;
2037 union spoolss_PrinterInfo info_dst, info_src;
2038 union spoolss_PrinterInfo *info_enum;
2039 struct cli_state *cli_dst = NULL;
2040 struct policy_handle hnd_dst, hnd_src;
2041 const char *printername, *sharename;
2042 struct rpc_pipe_client *pipe_hnd_dst = NULL;
2043 struct spoolss_SetPrinterInfoCtr info_ctr;
2045 DEBUG(3,("copying printers\n"));
2047 /* connect destination PI_SPOOLSS */
2048 nt_status = connect_dst_pipe(c, &cli_dst, &pipe_hnd_dst,
2049 &ndr_table_spoolss.syntax_id);
2050 if (!NT_STATUS_IS_OK(nt_status))
2054 if (!get_printer_info(pipe_hnd, mem_ctx, level, argc, argv, &num_printers, &info_enum)) {
2055 nt_status = NT_STATUS_UNSUCCESSFUL;
2059 if (!num_printers) {
2060 printf (_("no printers found on server.\n"));
2061 nt_status = NT_STATUS_OK;
2065 /* do something for all printers */
2066 for (i = 0; i < num_printers; i++) {
2068 struct spoolss_SetPrinterInfo2 info2;
2070 /* do some initialization */
2071 printername = info_enum[i].info2.printername;
2072 sharename = info_enum[i].info2.sharename;
2074 if (!printername || !sharename) {
2075 nt_status = NT_STATUS_UNSUCCESSFUL;
2078 /* we can reset NT_STATUS here because we do not
2079 get any real NT_STATUS-codes anymore from now on */
2080 nt_status = NT_STATUS_UNSUCCESSFUL;
2082 d_printf(_("migrating printer queue for: [%s] / [%s]\n"),
2083 printername, sharename);
2085 /* open dst printer handle */
2086 if (!net_spoolss_open_printer_ex(pipe_hnd_dst, mem_ctx, sharename,
2087 PRINTER_ALL_ACCESS, cli->user_name, &hnd_dst)) {
2089 DEBUG(1,("could not open printer: %s\n", sharename));
2092 /* check for existing dst printer */
2093 if (!net_spoolss_getprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, level, &info_dst)) {
2094 printf (_("could not get printer, creating printer.\n"));
2096 DEBUG(1,("printer already exists: %s\n", sharename));
2097 /* close printer handle here - dst only, not got src yet. */
2098 if (is_valid_policy_hnd(&hnd_dst)) {
2099 rpccli_spoolss_ClosePrinter(pipe_hnd_dst, mem_ctx, &hnd_dst, NULL);
2104 /* now get again src printer ctr via getprinter,
2105 we first need a handle for that */
2107 /* open src printer handle */
2108 if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
2109 MAXIMUM_ALLOWED_ACCESS, cli->user_name, &hnd_src))
2112 /* getprinter on the src server */
2113 if (!net_spoolss_getprinter(pipe_hnd, mem_ctx, &hnd_src, level, &info_src))
2116 /* copy each src printer to a dst printer 1:1,
2117 maybe some values have to be changed though */
2118 d_printf(_("creating printer: %s\n"), printername);
2120 info_ctr.level = level;
2121 spoolss_printerinfo2_to_setprinterinfo2(&info_src.info2, &info2);
2122 info_ctr.info.info2 = &info2;
2124 result = rpccli_spoolss_addprinterex(pipe_hnd_dst,
2128 if (W_ERROR_IS_OK(result))
2129 d_printf (_("printer [%s] successfully added.\n"),
2131 else if (W_ERROR_V(result) == W_ERROR_V(WERR_PRINTER_ALREADY_EXISTS))
2132 d_fprintf (stderr, _("printer [%s] already exists.\n"),
2135 d_fprintf (stderr, _("could not create printer [%s]\n"),
2140 /* close printer handles here */
2141 if (is_valid_policy_hnd(&hnd_src)) {
2142 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd_src, NULL);
2145 if (is_valid_policy_hnd(&hnd_dst)) {
2146 rpccli_spoolss_ClosePrinter(pipe_hnd_dst, mem_ctx, &hnd_dst, NULL);
2150 nt_status = NT_STATUS_OK;
2153 if (is_valid_policy_hnd(&hnd_src))
2154 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd_src, NULL);
2156 if (is_valid_policy_hnd(&hnd_dst))
2157 rpccli_spoolss_ClosePrinter(pipe_hnd_dst, mem_ctx, &hnd_dst, NULL);
2160 cli_shutdown(cli_dst);
2166 * Migrate Printer-Settings from a src server to the dst server
2167 * (for this to work, printers and drivers already have to be migrated earlier)
2169 * All parameters are provided by the run_rpc_command function, except for
2170 * argc, argv which are passed through.
2172 * @param c A net_context structure
2173 * @param domain_sid The domain sid aquired from the remote server
2174 * @param cli A cli_state connected to the server.
2175 * @param mem_ctx Talloc context, destoyed on compleation of the function.
2176 * @param argc Standard main() style argc
2177 * @param argv Standard main() style argv. Initial components are already
2180 * @return Normal NTSTATUS return.
2183 NTSTATUS rpc_printer_migrate_settings_internals(struct net_context *c,
2184 const struct dom_sid *domain_sid,
2185 const char *domain_name,
2186 struct cli_state *cli,
2187 struct rpc_pipe_client *pipe_hnd,
2188 TALLOC_CTX *mem_ctx,
2193 /* FIXME: Here the nightmare begins */
2196 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
2197 uint32_t i = 0, p = 0, j = 0;
2198 uint32_t num_printers;
2200 const char *printername, *sharename;
2201 struct rpc_pipe_client *pipe_hnd_dst = NULL;
2202 struct policy_handle hnd_src, hnd_dst;
2203 union spoolss_PrinterInfo *info_enum;
2204 union spoolss_PrinterInfo info_dst_publish;
2205 union spoolss_PrinterInfo info_dst;
2206 struct cli_state *cli_dst = NULL;
2207 char *devicename = NULL, *unc_name = NULL, *url = NULL;
2208 const char *longname;
2209 const char **keylist = NULL;
2212 ZERO_STRUCT(info_dst_publish);
2214 DEBUG(3,("copying printer settings\n"));
2216 /* connect destination PI_SPOOLSS */
2217 nt_status = connect_dst_pipe(c, &cli_dst, &pipe_hnd_dst,
2218 &ndr_table_spoolss.syntax_id);
2219 if (!NT_STATUS_IS_OK(nt_status))
2222 /* enum src printers */
2223 if (!get_printer_info(pipe_hnd, mem_ctx, level, argc, argv, &num_printers, &info_enum)) {
2224 nt_status = NT_STATUS_UNSUCCESSFUL;
2228 if (!num_printers) {
2229 printf (_("no printers found on server.\n"));
2230 nt_status = NT_STATUS_OK;
2235 /* needed for dns-strings in regkeys */
2236 longname = get_mydnsfullname();
2238 nt_status = NT_STATUS_UNSUCCESSFUL;
2242 /* do something for all printers */
2243 for (i = 0; i < num_printers; i++) {
2245 uint32_t value_offered = 0, value_needed;
2246 uint32_t data_offered = 0, data_needed;
2247 enum winreg_Type type;
2248 uint8_t *buffer = NULL;
2249 const char *value_name = NULL;
2251 /* do some initialization */
2252 printername = info_enum[i].info2.printername;
2253 sharename = info_enum[i].info2.sharename;
2255 if (!printername || !sharename) {
2256 nt_status = NT_STATUS_UNSUCCESSFUL;
2259 /* we can reset NT_STATUS here because we do not
2260 get any real NT_STATUS-codes anymore from now on */
2261 nt_status = NT_STATUS_UNSUCCESSFUL;
2263 d_printf(_("migrating printer settings for: [%s] / [%s]\n"),
2264 printername, sharename);
2267 /* open src printer handle */
2268 if (!net_spoolss_open_printer_ex(pipe_hnd, mem_ctx, sharename,
2269 MAXIMUM_ALLOWED_ACCESS, cli->user_name, &hnd_src))
2272 /* open dst printer handle */
2273 if (!net_spoolss_open_printer_ex(pipe_hnd_dst, mem_ctx, sharename,
2274 PRINTER_ALL_ACCESS, cli_dst->user_name, &hnd_dst))
2277 /* check for existing dst printer */
2278 if (!net_spoolss_getprinter(pipe_hnd_dst, mem_ctx, &hnd_dst,
2283 /* STEP 1: COPY DEVICE-MODE and other
2284 PRINTER_INFO_2-attributes
2287 info_dst.info2 = info_enum[i].info2;
2289 /* why is the port always disconnected when the printer
2290 is correctly installed (incl. driver ???) */
2291 info_dst.info2.portname = SAMBA_PRINTER_PORT_NAME;
2293 /* check if printer is published */
2294 if (info_enum[i].info2.attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
2296 /* check for existing dst printer */
2297 if (!net_spoolss_getprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, 7, &info_dst_publish))
2300 info_dst_publish.info7.action = DSPRINT_PUBLISH;
2302 /* ignore false from setprinter due to WERR_IO_PENDING */
2303 net_spoolss_setprinter(pipe_hnd_dst, mem_ctx, &hnd_dst, 7, &info_dst_publish);
2305 DEBUG(3,("republished printer\n"));
2308 if (info_enum[i].info2.devmode != NULL) {
2310 /* copy devmode (info level 2) */
2311 info_dst.info2.devmode = info_enum[i].info2.devmode;
2313 /* do not copy security descriptor (we have another
2314 * command for that) */
2315 info_dst.info2.secdesc = NULL;
2318 info_dst.info2.devmode.devicename =
2319 talloc_asprintf(mem_ctx, "\\\\%s\\%s",
2320 longname, printername);
2321 if (!info_dst.info2.devmode.devicename) {
2322 nt_status = NT_STATUS_NO_MEMORY;
2326 if (!net_spoolss_setprinter(pipe_hnd_dst, mem_ctx, &hnd_dst,
2330 DEBUGADD(1,("\tSetPrinter of DEVICEMODE succeeded\n"));
2333 /* STEP 2: COPY REGISTRY VALUES */
2335 /* please keep in mind that samba parse_spools gives horribly
2336 crippled results when used to rpccli_spoolss_enumprinterdataex
2337 a win2k3-server. (Bugzilla #1851)
2338 FIXME: IIRC I've seen it too on a win2k-server
2341 /* enumerate data on src handle */
2342 nt_status = rpccli_spoolss_EnumPrinterData(pipe_hnd, mem_ctx,
2354 data_offered = data_needed;
2355 value_offered = value_needed;
2356 buffer = talloc_zero_array(mem_ctx, uint8_t, data_needed);
2357 value_name = talloc_zero_array(mem_ctx, char, value_needed);
2359 /* loop for all printerdata of "PrinterDriverData" */
2360 while (NT_STATUS_IS_OK(nt_status) && W_ERROR_IS_OK(result)) {
2362 nt_status = rpccli_spoolss_EnumPrinterData(pipe_hnd, mem_ctx,
2373 /* loop for all reg_keys */
2374 if (NT_STATUS_IS_OK(nt_status) && W_ERROR_IS_OK(result)) {
2377 if (c->opt_verbose) {
2378 struct regval_blob *v;
2380 v = regval_compose(talloc_tos(),
2386 nt_status = NT_STATUS_NO_MEMORY;
2390 display_reg_value(SPOOL_PRINTERDATA_KEY, v);
2395 if (!net_spoolss_setprinterdata(pipe_hnd_dst, mem_ctx,
2396 &hnd_dst, value_name,
2397 type, buffer, data_offered))
2400 DEBUGADD(1,("\tSetPrinterData of [%s] succeeded\n",
2405 /* STEP 3: COPY SUBKEY VALUES */
2407 /* here we need to enum all printer_keys and then work
2408 on the result with enum_printer_key_ex. nt4 does not
2409 respond to enumprinterkey, win2k does, so continue
2410 in case of an error */
2412 if (!net_spoolss_enumprinterkey(pipe_hnd, mem_ctx, &hnd_src, "", &keylist)) {
2413 printf(_("got no key-data\n"));
2418 /* work on a list of printer keys
2419 each key has to be enumerated to get all required
2420 information. information is then set via setprinterdataex-calls */
2422 if (keylist == NULL)
2425 for (i=0; keylist && keylist[i] != NULL; i++) {
2427 const char *subkey = keylist[i];
2429 struct spoolss_PrinterEnumValues *info;
2431 /* enumerate all src subkeys */
2432 if (!net_spoolss_enumprinterdataex(pipe_hnd, mem_ctx, 0,
2438 for (j=0; j < count; j++) {
2440 struct regval_blob *value;
2445 /* although samba replies with sane data in most cases we
2446 should try to avoid writing wrong registry data */
2448 if (strequal(info[j].value_name, SPOOL_REG_PORTNAME) ||
2449 strequal(info[j].value_name, SPOOL_REG_UNCNAME) ||
2450 strequal(info[j].value_name, SPOOL_REG_URL) ||
2451 strequal(info[j].value_name, SPOOL_REG_SHORTSERVERNAME) ||
2452 strequal(info[j].value_name, SPOOL_REG_SERVERNAME)) {
2454 if (strequal(info[j].value_name, SPOOL_REG_PORTNAME)) {
2456 /* although windows uses a multi-sz, we use a sz */
2457 push_reg_sz(mem_ctx, &blob, SAMBA_PRINTER_PORT_NAME);
2460 if (strequal(info[j].value_name, SPOOL_REG_UNCNAME)) {
2462 if (asprintf(&unc_name, "\\\\%s\\%s", longname, sharename) < 0) {
2463 nt_status = NT_STATUS_NO_MEMORY;
2466 push_reg_sz(mem_ctx, &blob, unc_name);
2469 if (strequal(info[j].value_name, SPOOL_REG_URL)) {
2474 /* FIXME: should we really do that ??? */
2475 if (asprintf(&url, "http://%s:631/printers/%s", longname, sharename) < 0) {
2476 nt_status = NT_STATUS_NO_MEMORY;
2479 push_reg_sz(mem_ctx, NULL, &blob, url);
2480 fstrcpy(value.valuename, SPOOL_REG_URL);
2484 if (strequal(info[j].value_name, SPOOL_REG_SERVERNAME)) {
2486 push_reg_sz(mem_ctx, &blob, longname);
2489 if (strequal(info[j].value_name, SPOOL_REG_SHORTSERVERNAME)) {
2491 push_reg_sz(mem_ctx, &blob, global_myname());
2494 value = regval_compose(talloc_tos(),
2497 blob.length == 0 ? NULL : blob.data,
2499 if (value == NULL) {
2500 nt_status = NT_STATUS_NO_MEMORY;
2505 display_reg_value(subkey, value);
2507 /* here we have to set all subkeys on the dst server */
2508 if (!net_spoolss_setprinterdataex(pipe_hnd_dst, mem_ctx, &hnd_dst,
2518 struct regval_blob *v;
2520 v = regval_compose(talloc_tos(),
2524 info[j].data->length);
2526 nt_status = NT_STATUS_NO_MEMORY;
2530 if (c->opt_verbose) {
2531 display_reg_value(subkey, v);
2534 /* here we have to set all subkeys on the dst server */
2535 if (!net_spoolss_setprinterdataex(pipe_hnd_dst, mem_ctx, &hnd_dst,
2543 DEBUGADD(1,("\tSetPrinterDataEx of key [%s\\%s] succeeded\n",
2544 subkey, info[j].value_name));
2549 TALLOC_FREE(keylist);
2551 /* close printer handles here */
2552 if (is_valid_policy_hnd(&hnd_src)) {
2553 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd_src, NULL);
2556 if (is_valid_policy_hnd(&hnd_dst)) {
2557 rpccli_spoolss_ClosePrinter(pipe_hnd_dst, mem_ctx, &hnd_dst, NULL);
2562 nt_status = NT_STATUS_OK;
2565 SAFE_FREE(devicename);
2567 SAFE_FREE(unc_name);
2569 if (is_valid_policy_hnd(&hnd_src))
2570 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd_src, NULL);
2572 if (is_valid_policy_hnd(&hnd_dst))
2573 rpccli_spoolss_ClosePrinter(pipe_hnd_dst, mem_ctx, &hnd_dst, NULL);
2576 cli_shutdown(cli_dst);