s3-spoolss: add and use spoolss_printerinfo2_to_setprinterinfo2().
[vlendec/samba-autobuild/.git] / source3 / rpcclient / cmd_spoolss.c
1 /*
2    Unix SMB/CIFS implementation.
3    RPC pipe client
4
5    Copyright (C) Gerald Carter                2001-2005
6    Copyright (C) Tim Potter                        2000
7    Copyright (C) Andrew Tridgell              1992-1999
8    Copyright (C) Luke Kenneth Casson Leighton 1996-1999
9    Copyright (C) Guenther Deschner                 2009
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "rpcclient.h"
27 #include "../librpc/gen_ndr/cli_spoolss.h"
28 #include "rpc_client/cli_spoolss.h"
29 #include "rpc_client/init_spoolss.h"
30 #include "registry.h"
31 #include "registry/reg_objects.h"
32
33 #define RPCCLIENT_PRINTERNAME(_printername, _cli, _arg) \
34 { \
35         _printername = talloc_asprintf_strupper_m(mem_ctx, "%s\\%s", \
36                 _cli->srv_name_slash, _arg); \
37         W_ERROR_HAVE_NO_MEMORY(_printername); \
38 }
39
40 /* The version int is used by getdrivers.  Note that
41    all architecture strings that support mutliple
42    versions must be grouped together since enumdrivers
43    uses this property to prevent issuing multiple
44    enumdriver calls for the same arch */
45
46
47 static const struct print_architecture_table_node archi_table[]= {
48
49         {"Windows 4.0",          "WIN40",       0 },
50         {"Windows NT x86",       "W32X86",      2 },
51         {"Windows NT x86",       "W32X86",      3 },
52         {"Windows NT R4000",     "W32MIPS",     2 },
53         {"Windows NT Alpha_AXP", "W32ALPHA",    2 },
54         {"Windows NT PowerPC",   "W32PPC",      2 },
55         {"Windows IA64",         "IA64",        3 },
56         {"Windows x64",          "x64",         3 },
57         {NULL,                   "",            -1 }
58 };
59
60 /**
61  * @file
62  *
63  * rpcclient module for SPOOLSS rpc pipe.
64  *
65  * This generally just parses and checks command lines, and then calls
66  * a cli_spoolss function.
67  **/
68
69 /****************************************************************************
70  function to do the mapping between the long architecture name and
71  the short one.
72 ****************************************************************************/
73
74 static const char *cmd_spoolss_get_short_archi(const char *long_archi)
75 {
76         int i=-1;
77
78         DEBUG(107,("Getting architecture dependant directory\n"));
79         do {
80                 i++;
81         } while ( (archi_table[i].long_archi!=NULL ) &&
82                   StrCaseCmp(long_archi, archi_table[i].long_archi) );
83
84         if (archi_table[i].long_archi==NULL) {
85                 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
86                 return NULL;
87         }
88
89         /* this might be client code - but shouldn't this be an fstrcpy etc? */
90
91
92         DEBUGADD(108,("index: [%d]\n", i));
93         DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
94         DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
95
96         return archi_table[i].short_archi;
97 }
98
99 /****************************************************************************
100 ****************************************************************************/
101
102 static WERROR cmd_spoolss_open_printer_ex(struct rpc_pipe_client *cli,
103                                             TALLOC_CTX *mem_ctx,
104                                             int argc, const char **argv)
105 {
106         WERROR          werror;
107         struct policy_handle    hnd;
108
109         if (argc != 2) {
110                 printf("Usage: %s <printername>\n", argv[0]);
111                 return WERR_OK;
112         }
113
114         if (!cli)
115             return WERR_GENERAL_FAILURE;
116
117         /* Open the printer handle */
118
119         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
120                                                argv[1],
121                                                PRINTER_ALL_ACCESS,
122                                                &hnd);
123         if (W_ERROR_IS_OK(werror)) {
124                 printf("Printer %s opened successfully\n", argv[1]);
125                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, &werror);
126
127                 if (!W_ERROR_IS_OK(werror)) {
128                         printf("Error closing printer handle! (%s)\n",
129                                 get_dos_error_msg(werror));
130                 }
131         }
132
133         return werror;
134 }
135
136
137 /****************************************************************************
138 ****************************************************************************/
139
140 static void display_print_info0(struct spoolss_PrinterInfo0 *r)
141 {
142         if (!r)
143                 return;
144
145         printf("\tprintername:[%s]\n", r->printername);
146         printf("\tservername:[%s]\n", r->servername);
147         printf("\tcjobs:[0x%x]\n", r->cjobs);
148         printf("\ttotal_jobs:[0x%x]\n", r->total_jobs);
149         printf("\ttotal_bytes:[0x%x]\n", r->total_bytes);
150         printf("\t:date: [%d]-[%d]-[%d] (%d)\n", r->time.year, r->time.month,
151                r->time.day, r->time.day_of_week);
152         printf("\t:time: [%d]-[%d]-[%d]-[%d]\n", r->time.hour, r->time.minute,
153                r->time.second, r->time.millisecond);
154
155         printf("\tglobal_counter:[0x%x]\n", r->global_counter);
156         printf("\ttotal_pages:[0x%x]\n", r->total_pages);
157
158         printf("\tversion:[0x%x]\n", r->version);
159         printf("\tfree_build:[0x%x]\n", r->free_build);
160         printf("\tspooling:[0x%x]\n", r->spooling);
161         printf("\tmax_spooling:[0x%x]\n", r->max_spooling);
162         printf("\tsession_counter:[0x%x]\n", r->session_counter);
163         printf("\tnum_error_out_of_paper:[0x%x]\n", r->num_error_out_of_paper);
164         printf("\tnum_error_not_ready:[0x%x]\n", r->num_error_not_ready);
165         printf("\tjob_error:[0x%x]\n", r->job_error);
166         printf("\tnumber_of_processors:[0x%x]\n", r->number_of_processors);
167         printf("\tprocessor_type:[0x%x]\n", r->processor_type);
168         printf("\thigh_part_total_bytes:[0x%x]\n", r->high_part_total_bytes);
169         printf("\tchange_id:[0x%x]\n", r->change_id);
170         printf("\tlast_error: %s\n", win_errstr(r->last_error));
171         printf("\tstatus:[0x%x]\n", r->status);
172         printf("\tenumerate_network_printers:[0x%x]\n", r->enumerate_network_printers);
173         printf("\tc_setprinter:[0x%x]\n", r->c_setprinter);
174         printf("\tprocessor_architecture:[0x%x]\n", r->processor_architecture);
175         printf("\tprocessor_level:[0x%x]\n", r->processor_level);
176         printf("\tref_ic:[0x%x]\n", r->ref_ic);
177         printf("\treserved2:[0x%x]\n", r->reserved2);
178         printf("\treserved3:[0x%x]\n", r->reserved3);
179
180         printf("\n");
181 }
182
183 /****************************************************************************
184 ****************************************************************************/
185
186 static void display_print_info1(struct spoolss_PrinterInfo1 *r)
187 {
188         printf("\tflags:[0x%x]\n", r->flags);
189         printf("\tname:[%s]\n", r->name);
190         printf("\tdescription:[%s]\n", r->description);
191         printf("\tcomment:[%s]\n", r->comment);
192
193         printf("\n");
194 }
195
196 /****************************************************************************
197 ****************************************************************************/
198
199 static void display_print_info2(struct spoolss_PrinterInfo2 *r)
200 {
201         printf("\tservername:[%s]\n", r->servername);
202         printf("\tprintername:[%s]\n", r->printername);
203         printf("\tsharename:[%s]\n", r->sharename);
204         printf("\tportname:[%s]\n", r->portname);
205         printf("\tdrivername:[%s]\n", r->drivername);
206         printf("\tcomment:[%s]\n", r->comment);
207         printf("\tlocation:[%s]\n", r->location);
208         printf("\tsepfile:[%s]\n", r->sepfile);
209         printf("\tprintprocessor:[%s]\n", r->printprocessor);
210         printf("\tdatatype:[%s]\n", r->datatype);
211         printf("\tparameters:[%s]\n", r->parameters);
212         printf("\tattributes:[0x%x]\n", r->attributes);
213         printf("\tpriority:[0x%x]\n", r->priority);
214         printf("\tdefaultpriority:[0x%x]\n", r->defaultpriority);
215         printf("\tstarttime:[0x%x]\n", r->starttime);
216         printf("\tuntiltime:[0x%x]\n", r->untiltime);
217         printf("\tstatus:[0x%x]\n", r->status);
218         printf("\tcjobs:[0x%x]\n", r->cjobs);
219         printf("\taverageppm:[0x%x]\n", r->averageppm);
220
221         if (r->secdesc)
222                 display_sec_desc(r->secdesc);
223
224         printf("\n");
225 }
226
227 /****************************************************************************
228 ****************************************************************************/
229
230 static void display_print_info3(struct spoolss_PrinterInfo3 *r)
231 {
232         display_sec_desc(r->secdesc);
233
234         printf("\n");
235 }
236
237 /****************************************************************************
238 ****************************************************************************/
239
240 static void display_print_info4(struct spoolss_PrinterInfo4 *r)
241 {
242         printf("\tservername:[%s]\n", r->servername);
243         printf("\tprintername:[%s]\n", r->printername);
244         printf("\tattributes:[0x%x]\n", r->attributes);
245         printf("\n");
246 }
247
248 /****************************************************************************
249 ****************************************************************************/
250
251 static void display_print_info5(struct spoolss_PrinterInfo5 *r)
252 {
253         printf("\tprintername:[%s]\n", r->printername);
254         printf("\tportname:[%s]\n", r->portname);
255         printf("\tattributes:[0x%x]\n", r->attributes);
256         printf("\tdevice_not_selected_timeout:[0x%x]\n", r->device_not_selected_timeout);
257         printf("\ttransmission_retry_timeout:[0x%x]\n", r->transmission_retry_timeout);
258         printf("\n");
259 }
260
261 /****************************************************************************
262 ****************************************************************************/
263
264 static void display_print_info6(struct spoolss_PrinterInfo6 *r)
265 {
266         printf("\tstatus:[0x%x]\n", r->status);
267         printf("\n");
268 }
269
270 /****************************************************************************
271 ****************************************************************************/
272
273 static void display_print_info7(struct spoolss_PrinterInfo7 *r)
274 {
275         printf("\tguid:[%s]\n", r->guid);
276         printf("\taction:[0x%x]\n", r->action);
277         printf("\n");
278 }
279
280 /****************************************************************************
281 ****************************************************************************/
282
283 static WERROR cmd_spoolss_enum_printers(struct rpc_pipe_client *cli,
284                                         TALLOC_CTX *mem_ctx,
285                                         int argc, const char **argv)
286 {
287         WERROR                  result;
288         uint32_t                level = 1;
289         union spoolss_PrinterInfo *info;
290         uint32_t                i, count;
291         const char *name;
292         uint32_t flags = PRINTER_ENUM_LOCAL;
293
294         if (argc > 4) {
295                 printf("Usage: %s [level] [name] [flags]\n", argv[0]);
296                 return WERR_OK;
297         }
298
299         if (argc >= 2) {
300                 level = atoi(argv[1]);
301         }
302
303         if (argc >= 3) {
304                 name = argv[2];
305         } else {
306                 name = cli->srv_name_slash;
307         }
308
309         if (argc == 4) {
310                 flags = atoi(argv[3]);
311         }
312
313         result = rpccli_spoolss_enumprinters(cli, mem_ctx,
314                                              flags,
315                                              name,
316                                              level,
317                                              0,
318                                              &count,
319                                              &info);
320         if (W_ERROR_IS_OK(result)) {
321
322                 if (!count) {
323                         printf ("No printers returned.\n");
324                         goto done;
325                 }
326
327                 for (i = 0; i < count; i++) {
328                         switch (level) {
329                         case 0:
330                                 display_print_info0(&info[i].info0);
331                                 break;
332                         case 1:
333                                 display_print_info1(&info[i].info1);
334                                 break;
335                         case 2:
336                                 display_print_info2(&info[i].info2);
337                                 break;
338                         case 3:
339                                 display_print_info3(&info[i].info3);
340                                 break;
341                         case 4:
342                                 display_print_info4(&info[i].info4);
343                                 break;
344                         case 5:
345                                 display_print_info5(&info[i].info5);
346                                 break;
347                         case 6:
348                                 display_print_info6(&info[i].info6);
349                                 break;
350                         default:
351                                 printf("unknown info level %d\n", level);
352                                 goto done;
353                         }
354                 }
355         }
356  done:
357
358         return result;
359 }
360
361 /****************************************************************************
362 ****************************************************************************/
363
364 static void display_port_info_1(struct spoolss_PortInfo1 *r)
365 {
366         printf("\tPort Name:\t[%s]\n", r->port_name);
367 }
368
369 /****************************************************************************
370 ****************************************************************************/
371
372 static void display_port_info_2(struct spoolss_PortInfo2 *r)
373 {
374         printf("\tPort Name:\t[%s]\n", r->port_name);
375         printf("\tMonitor Name:\t[%s]\n", r->monitor_name);
376         printf("\tDescription:\t[%s]\n", r->description);
377         printf("\tPort Type:\t" );
378         if (r->port_type) {
379                 int comma = 0; /* hack */
380                 printf( "[" );
381                 if (r->port_type & SPOOLSS_PORT_TYPE_READ) {
382                         printf( "Read" );
383                         comma = 1;
384                 }
385                 if (r->port_type & SPOOLSS_PORT_TYPE_WRITE) {
386                         printf( "%sWrite", comma ? ", " : "" );
387                         comma = 1;
388                 }
389                 /* These two have slightly different interpretations
390                  on 95/98/ME but I'm disregarding that for now */
391                 if (r->port_type & SPOOLSS_PORT_TYPE_REDIRECTED) {
392                         printf( "%sRedirected", comma ? ", " : "" );
393                         comma = 1;
394                 }
395                 if (r->port_type & SPOOLSS_PORT_TYPE_NET_ATTACHED) {
396                         printf( "%sNet-Attached", comma ? ", " : "" );
397                 }
398                 printf( "]\n" );
399         } else {
400                 printf( "[Unset]\n" );
401         }
402         printf("\tReserved:\t[%d]\n", r->reserved);
403         printf("\n");
404 }
405
406 /****************************************************************************
407 ****************************************************************************/
408
409 static WERROR cmd_spoolss_enum_ports(struct rpc_pipe_client *cli,
410                                        TALLOC_CTX *mem_ctx, int argc,
411                                        const char **argv)
412 {
413         WERROR                  result;
414         uint32_t                level = 1;
415         uint32_t                count;
416         union spoolss_PortInfo *info;
417
418         if (argc > 2) {
419                 printf("Usage: %s [level]\n", argv[0]);
420                 return WERR_OK;
421         }
422
423         if (argc == 2) {
424                 level = atoi(argv[1]);
425         }
426
427         /* Enumerate ports */
428
429         result = rpccli_spoolss_enumports(cli, mem_ctx,
430                                           cli->srv_name_slash,
431                                           level,
432                                           0,
433                                           &count,
434                                           &info);
435         if (W_ERROR_IS_OK(result)) {
436                 int i;
437
438                 for (i = 0; i < count; i++) {
439                         switch (level) {
440                         case 1:
441                                 display_port_info_1(&info[i].info1);
442                                 break;
443                         case 2:
444                                 display_port_info_2(&info[i].info2);
445                                 break;
446                         default:
447                                 printf("unknown info level %d\n", level);
448                                 break;
449                         }
450                 }
451         }
452
453         return result;
454 }
455
456 /****************************************************************************
457 ****************************************************************************/
458
459 static WERROR cmd_spoolss_setprinter(struct rpc_pipe_client *cli,
460                                        TALLOC_CTX *mem_ctx,
461                                        int argc, const char **argv)
462 {
463         struct policy_handle pol;
464         WERROR          result;
465         NTSTATUS        status;
466         uint32_t        info_level = 2;
467         union spoolss_PrinterInfo info;
468         struct spoolss_SetPrinterInfoCtr info_ctr;
469         struct spoolss_SetPrinterInfo2 info2;
470         const char      *printername, *comment = NULL;
471         struct spoolss_DevmodeContainer devmode_ctr;
472         struct sec_desc_buf secdesc_ctr;
473
474         if (argc == 1 || argc > 3) {
475                 printf("Usage: %s printername comment\n", argv[0]);
476
477                 return WERR_OK;
478         }
479
480         /* Open a printer handle */
481         if (argc == 3) {
482                 comment = argv[2];
483         }
484
485         ZERO_STRUCT(devmode_ctr);
486         ZERO_STRUCT(secdesc_ctr);
487
488         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
489
490         /* get a printer handle */
491         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
492                                                printername,
493                                                PRINTER_ALL_ACCESS,
494                                                &pol);
495         if (!W_ERROR_IS_OK(result))
496                 goto done;
497
498         /* Get printer info */
499         result = rpccli_spoolss_getprinter(cli, mem_ctx,
500                                            &pol,
501                                            info_level,
502                                            0,
503                                            &info);
504         if (!W_ERROR_IS_OK(result))
505                 goto done;
506
507
508         /* Modify the comment. */
509         spoolss_printerinfo2_to_setprinterinfo2(&info.info2, &info2);
510         info2.comment = comment;
511
512         info_ctr.level = 2;
513         info_ctr.info.info2 = &info2;
514
515         status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
516                                            &pol,
517                                            &info_ctr,
518                                            &devmode_ctr,
519                                            &secdesc_ctr,
520                                            0, /* command */
521                                            &result);
522         if (W_ERROR_IS_OK(result))
523                 printf("Success in setting comment.\n");
524
525  done:
526         if (is_valid_policy_hnd(&pol))
527                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
528
529         return result;
530 }
531
532 /****************************************************************************
533 ****************************************************************************/
534
535 static WERROR cmd_spoolss_setprintername(struct rpc_pipe_client *cli,
536                                        TALLOC_CTX *mem_ctx,
537                                        int argc, const char **argv)
538 {
539         struct policy_handle pol;
540         WERROR          result;
541         NTSTATUS        status;
542         uint32_t        info_level = 2;
543         union spoolss_PrinterInfo info;
544         const char      *printername,
545                         *new_printername = NULL;
546         struct spoolss_SetPrinterInfoCtr info_ctr;
547         struct spoolss_SetPrinterInfo2 info2;
548         struct spoolss_DevmodeContainer devmode_ctr;
549         struct sec_desc_buf secdesc_ctr;
550
551         ZERO_STRUCT(devmode_ctr);
552         ZERO_STRUCT(secdesc_ctr);
553
554         if (argc == 1 || argc > 3) {
555                 printf("Usage: %s printername new_printername\n", argv[0]);
556
557                 return WERR_OK;
558         }
559
560         /* Open a printer handle */
561         if (argc == 3) {
562                 new_printername = argv[2];
563         }
564
565         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
566
567         /* get a printer handle */
568         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
569                                                printername,
570                                                PRINTER_ALL_ACCESS,
571                                                &pol);
572         if (!W_ERROR_IS_OK(result))
573                 goto done;
574
575         /* Get printer info */
576         result = rpccli_spoolss_getprinter(cli, mem_ctx,
577                                            &pol,
578                                            info_level,
579                                            0,
580                                            &info);
581         if (!W_ERROR_IS_OK(result))
582                 goto done;
583
584         /* Modify the printername. */
585         spoolss_printerinfo2_to_setprinterinfo2(&info.info2, &info2);
586         info2.printername = new_printername;
587
588         info_ctr.level = 2;
589         info_ctr.info.info2 = &info2;
590
591         status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
592                                            &pol,
593                                            &info_ctr,
594                                            &devmode_ctr,
595                                            &secdesc_ctr,
596                                            0, /* command */
597                                            &result);
598         if (W_ERROR_IS_OK(result))
599                 printf("Success in setting printername.\n");
600
601  done:
602         if (is_valid_policy_hnd(&pol))
603                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
604
605         return result;
606 }
607
608 /****************************************************************************
609 ****************************************************************************/
610
611 static WERROR cmd_spoolss_getprinter(struct rpc_pipe_client *cli,
612                                        TALLOC_CTX *mem_ctx,
613                                        int argc, const char **argv)
614 {
615         struct policy_handle pol;
616         WERROR          result;
617         uint32_t        level = 1;
618         const char      *printername;
619         union spoolss_PrinterInfo info;
620
621         if (argc == 1 || argc > 3) {
622                 printf("Usage: %s <printername> [level]\n", argv[0]);
623                 return WERR_OK;
624         }
625
626         /* Open a printer handle */
627         if (argc == 3) {
628                 level = atoi(argv[2]);
629         }
630
631         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
632
633         /* get a printer handle */
634
635         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
636                                                printername,
637                                                SEC_FLAG_MAXIMUM_ALLOWED,
638                                                &pol);
639         if (!W_ERROR_IS_OK(result)) {
640                 goto done;
641         }
642
643         /* Get printer info */
644
645         result = rpccli_spoolss_getprinter(cli, mem_ctx,
646                                            &pol,
647                                            level,
648                                            0,
649                                            &info);
650         if (!W_ERROR_IS_OK(result)) {
651                 goto done;
652         }
653
654         /* Display printer info */
655         switch (level) {
656         case 0:
657                 display_print_info0(&info.info0);
658                 break;
659         case 1:
660                 display_print_info1(&info.info1);
661                 break;
662         case 2:
663                 display_print_info2(&info.info2);
664                 break;
665         case 3:
666                 display_print_info3(&info.info3);
667                 break;
668         case 4:
669                 display_print_info4(&info.info4);
670                 break;
671         case 5:
672                 display_print_info5(&info.info5);
673                 break;
674         case 6:
675                 display_print_info6(&info.info6);
676                 break;
677         case 7:
678                 display_print_info7(&info.info7);
679                 break;
680         default:
681                 printf("unknown info level %d\n", level);
682                 break;
683         }
684  done:
685         if (is_valid_policy_hnd(&pol)) {
686                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
687         }
688
689         return result;
690 }
691
692 /****************************************************************************
693 ****************************************************************************/
694
695 static void display_reg_value(struct regval_blob *value)
696 {
697         const char *text = NULL;
698         DATA_BLOB blob;
699
700         switch(regval_type(value)) {
701         case REG_DWORD:
702                 printf("%s: REG_DWORD: 0x%08x\n", regval_name(value),
703                        *((uint32_t *) regval_data_p(value)));
704                 break;
705         case REG_SZ:
706                 blob = data_blob_const(regval_data_p(value), regval_size(value));
707                 pull_reg_sz(talloc_tos(), &blob, &text);
708                 printf("%s: REG_SZ: %s\n", regval_name(value), text ? text : "");
709                 break;
710         case REG_BINARY: {
711                 char *hex = hex_encode_talloc(NULL, regval_data_p(value), regval_size(value));
712                 size_t i, len;
713                 printf("%s: REG_BINARY:", regval_name(value));
714                 len = strlen(hex);
715                 for (i=0; i<len; i++) {
716                         if (hex[i] == '\0') {
717                                 break;
718                         }
719                         if (i%40 == 0) {
720                                 putchar('\n');
721                         }
722                         putchar(hex[i]);
723                 }
724                 TALLOC_FREE(hex);
725                 putchar('\n');
726                 break;
727         }
728         case REG_MULTI_SZ: {
729                 uint32_t i;
730                 const char **values;
731                 blob = data_blob_const(regval_data_p(value), regval_size(value));
732
733                 if (!pull_reg_multi_sz(NULL, &blob, &values)) {
734                         d_printf("pull_reg_multi_sz failed\n");
735                         break;
736                 }
737
738                 printf("%s: REG_MULTI_SZ: \n", regval_name(value));
739                 for (i=0; values[i] != NULL; i++) {
740                         d_printf("%s\n", values[i]);
741                 }
742                 TALLOC_FREE(values);
743                 break;
744         }
745         default:
746                 printf("%s: unknown type %d\n", regval_name(value), regval_type(value));
747         }
748
749 }
750
751 /****************************************************************************
752 ****************************************************************************/
753
754 static void display_printer_data(const char *v,
755                                  enum winreg_Type type,
756                                  uint8_t *data,
757                                  uint32_t length)
758 {
759         int i;
760         union spoolss_PrinterData r;
761         DATA_BLOB blob = data_blob_const(data, length);
762         WERROR result;
763
764         result = pull_spoolss_PrinterData(talloc_tos(), &blob, &r, type);
765         if (!W_ERROR_IS_OK(result)) {
766                 return;
767         }
768
769         switch (type) {
770         case REG_DWORD:
771                 printf("%s: REG_DWORD: 0x%08x\n", v, r.value);
772                 break;
773         case REG_SZ:
774                 printf("%s: REG_SZ: %s\n", v, r.string);
775                 break;
776         case REG_BINARY: {
777                 char *hex = hex_encode_talloc(NULL,
778                         r.binary.data, r.binary.length);
779                 size_t len;
780                 printf("%s: REG_BINARY:", v);
781                 len = strlen(hex);
782                 for (i=0; i<len; i++) {
783                         if (hex[i] == '\0') {
784                                 break;
785                         }
786                         if (i%40 == 0) {
787                                 putchar('\n');
788                         }
789                         putchar(hex[i]);
790                 }
791                 TALLOC_FREE(hex);
792                 putchar('\n');
793                 break;
794         }
795         case REG_MULTI_SZ:
796                 printf("%s: REG_MULTI_SZ: ", v);
797                 for (i=0; r.string_array[i] != NULL; i++) {
798                         printf("%s ", r.string_array[i]);
799                 }
800                 printf("\n");
801                 break;
802         default:
803                 printf("%s: unknown type 0x%02x:\n", v, type);
804                 break;
805         }
806 }
807
808 /****************************************************************************
809 ****************************************************************************/
810
811 static WERROR cmd_spoolss_getprinterdata(struct rpc_pipe_client *cli,
812                                            TALLOC_CTX *mem_ctx,
813                                            int argc, const char **argv)
814 {
815         struct policy_handle pol;
816         WERROR          result;
817         fstring         printername;
818         const char *valuename;
819         enum winreg_Type type;
820         uint8_t *data;
821         uint32_t needed;
822
823         if (argc != 3) {
824                 printf("Usage: %s <printername> <valuename>\n", argv[0]);
825                 printf("<printername> of . queries print server\n");
826                 return WERR_OK;
827         }
828         valuename = argv[2];
829
830         /* Open a printer handle */
831
832         if (strncmp(argv[1], ".", sizeof(".")) == 0)
833                 fstrcpy(printername, cli->srv_name_slash);
834         else
835                 slprintf(printername, sizeof(printername)-1, "%s\\%s",
836                           cli->srv_name_slash, argv[1]);
837
838         /* get a printer handle */
839
840         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
841                                                printername,
842                                                SEC_FLAG_MAXIMUM_ALLOWED,
843                                                &pol);
844         if (!W_ERROR_IS_OK(result))
845                 goto done;
846
847         /* Get printer info */
848
849         result = rpccli_spoolss_getprinterdata(cli, mem_ctx,
850                                                &pol,
851                                                valuename,
852                                                0,
853                                                &type,
854                                                &needed,
855                                                &data);
856         if (!W_ERROR_IS_OK(result))
857                 goto done;
858
859         /* Display printer data */
860
861         display_printer_data(valuename, type, data, needed);
862
863  done:
864         if (is_valid_policy_hnd(&pol))
865                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
866
867         return result;
868 }
869
870 /****************************************************************************
871 ****************************************************************************/
872
873 static WERROR cmd_spoolss_getprinterdataex(struct rpc_pipe_client *cli,
874                                              TALLOC_CTX *mem_ctx,
875                                              int argc, const char **argv)
876 {
877         struct policy_handle pol;
878         WERROR          result;
879         NTSTATUS        status;
880         fstring         printername;
881         const char *valuename, *keyname;
882
883         enum winreg_Type type;
884         uint8_t *data = NULL;
885         uint32_t offered = 0;
886         uint32_t needed;
887
888         if (argc != 4) {
889                 printf("Usage: %s <printername> <keyname> <valuename>\n",
890                        argv[0]);
891                 printf("<printername> of . queries print server\n");
892                 return WERR_OK;
893         }
894         valuename = argv[3];
895         keyname = argv[2];
896
897         /* Open a printer handle */
898
899         if (strncmp(argv[1], ".", sizeof(".")) == 0)
900                 fstrcpy(printername, cli->srv_name_slash);
901         else
902                 slprintf(printername, sizeof(printername)-1, "%s\\%s",
903                           cli->srv_name_slash, argv[1]);
904
905         /* get a printer handle */
906
907         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
908                                                printername,
909                                                SEC_FLAG_MAXIMUM_ALLOWED,
910                                                &pol);
911         if (!W_ERROR_IS_OK(result))
912                 goto done;
913
914         /* Get printer info */
915
916         data = talloc_zero_array(mem_ctx, uint8_t, offered);
917         if (!data) {
918                 goto done;
919         }
920
921         status = rpccli_spoolss_GetPrinterDataEx(cli, mem_ctx,
922                                                  &pol,
923                                                  keyname,
924                                                  valuename,
925                                                  &type,
926                                                  data,
927                                                  offered,
928                                                  &needed,
929                                                  &result);
930         if (W_ERROR_EQUAL(result, WERR_MORE_DATA)) {
931                 offered = needed;
932                 data = talloc_zero_array(mem_ctx, uint8_t, offered);
933                 if (!data) {
934                         goto done;
935                 }
936                 status = rpccli_spoolss_GetPrinterDataEx(cli, mem_ctx,
937                                                          &pol,
938                                                          keyname,
939                                                          valuename,
940                                                          &type,
941                                                          data,
942                                                          offered,
943                                                          &needed,
944                                                          &result);
945         }
946
947         if (!NT_STATUS_IS_OK(status)) {
948                 goto done;
949         }
950
951         if (!W_ERROR_IS_OK(result))
952                 goto done;
953
954         /* Display printer data */
955
956         display_printer_data(valuename, type, data, needed);
957
958
959  done:
960         if (is_valid_policy_hnd(&pol))
961                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
962
963         return result;
964 }
965
966 /****************************************************************************
967 ****************************************************************************/
968
969 static void display_print_driver1(struct spoolss_DriverInfo1 *r)
970 {
971         if (!r) {
972                 return;
973         }
974
975         printf("Printer Driver Info 1:\n");
976         printf("\tDriver Name: [%s]\n", r->driver_name);
977         printf("\n");
978 }
979
980 /****************************************************************************
981 ****************************************************************************/
982
983 static void display_print_driver2(struct spoolss_DriverInfo2 *r)
984 {
985         if (!r) {
986                 return;
987         }
988
989         printf("Printer Driver Info 2:\n");
990         printf("\tVersion: [%x]\n", r->version);
991         printf("\tDriver Name: [%s]\n", r->driver_name);
992         printf("\tArchitecture: [%s]\n", r->architecture);
993         printf("\tDriver Path: [%s]\n", r->driver_path);
994         printf("\tDatafile: [%s]\n", r->data_file);
995         printf("\tConfigfile: [%s]\n", r->config_file);
996         printf("\n");
997 }
998
999 /****************************************************************************
1000 ****************************************************************************/
1001
1002 static void display_print_driver3(struct spoolss_DriverInfo3 *r)
1003 {
1004         int i;
1005
1006         if (!r) {
1007                 return;
1008         }
1009
1010         printf("Printer Driver Info 3:\n");
1011         printf("\tVersion: [%x]\n", r->version);
1012         printf("\tDriver Name: [%s]\n", r->driver_name);
1013         printf("\tArchitecture: [%s]\n", r->architecture);
1014         printf("\tDriver Path: [%s]\n", r->driver_path);
1015         printf("\tDatafile: [%s]\n", r->data_file);
1016         printf("\tConfigfile: [%s]\n", r->config_file);
1017         printf("\tHelpfile: [%s]\n", r->help_file);
1018
1019         for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1020                 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1021         }
1022
1023         printf("\tMonitorname: [%s]\n", r->monitor_name);
1024         printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1025         printf("\n");
1026 }
1027
1028 /****************************************************************************
1029 ****************************************************************************/
1030
1031 static void display_print_driver4(struct spoolss_DriverInfo4 *r)
1032 {
1033         int i;
1034
1035         if (!r) {
1036                 return;
1037         }
1038
1039         printf("Printer Driver Info 4:\n");
1040         printf("\tVersion: [%x]\n", r->version);
1041         printf("\tDriver Name: [%s]\n", r->driver_name);
1042         printf("\tArchitecture: [%s]\n", r->architecture);
1043         printf("\tDriver Path: [%s]\n", r->driver_path);
1044         printf("\tDatafile: [%s]\n", r->data_file);
1045         printf("\tConfigfile: [%s]\n", r->config_file);
1046         printf("\tHelpfile: [%s]\n", r->help_file);
1047
1048         for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1049                 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1050         }
1051
1052         printf("\tMonitorname: [%s]\n", r->monitor_name);
1053         printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1054
1055         for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) {
1056                 printf("\tPrevious Names: [%s]\n", r->previous_names[i]);
1057         }
1058         printf("\n");
1059 }
1060
1061 /****************************************************************************
1062 ****************************************************************************/
1063
1064 static void display_print_driver5(struct spoolss_DriverInfo5 *r)
1065 {
1066         if (!r) {
1067                 return;
1068         }
1069
1070         printf("Printer Driver Info 5:\n");
1071         printf("\tVersion: [%x]\n", r->version);
1072         printf("\tDriver Name: [%s]\n", r->driver_name);
1073         printf("\tArchitecture: [%s]\n", r->architecture);
1074         printf("\tDriver Path: [%s]\n", r->driver_path);
1075         printf("\tDatafile: [%s]\n", r->data_file);
1076         printf("\tConfigfile: [%s]\n", r->config_file);
1077         printf("\tDriver Attributes: [0x%x]\n", r->driver_attributes);
1078         printf("\tConfig Version: [0x%x]\n", r->config_version);
1079         printf("\tDriver Version: [0x%x]\n", r->driver_version);
1080         printf("\n");
1081 }
1082
1083 /****************************************************************************
1084 ****************************************************************************/
1085
1086 static void display_print_driver6(struct spoolss_DriverInfo6 *r)
1087 {
1088         int i;
1089
1090         if (!r) {
1091                 return;
1092         }
1093
1094         printf("Printer Driver Info 6:\n");
1095         printf("\tVersion: [%x]\n", r->version);
1096         printf("\tDriver Name: [%s]\n", r->driver_name);
1097         printf("\tArchitecture: [%s]\n", r->architecture);
1098         printf("\tDriver Path: [%s]\n", r->driver_path);
1099         printf("\tDatafile: [%s]\n", r->data_file);
1100         printf("\tConfigfile: [%s]\n", r->config_file);
1101         printf("\tHelpfile: [%s]\n", r->help_file);
1102
1103         for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1104                 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1105         }
1106
1107         printf("\tMonitorname: [%s]\n", r->monitor_name);
1108         printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1109
1110         for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) {
1111                 printf("\tPrevious Names: [%s]\n", r->previous_names[i]);
1112         }
1113
1114         printf("\tDriver Date: [%s]\n", nt_time_string(talloc_tos(), r->driver_date));
1115         printf("\tDriver Version: [0x%016llx]\n", (long long unsigned int)r->driver_version);
1116         printf("\tManufacturer Name: [%s]\n", r->manufacturer_name);
1117         printf("\tManufacturer Url: [%s]\n", r->manufacturer_url);
1118         printf("\tHardware ID: [%s]\n", r->hardware_id);
1119         printf("\tProvider: [%s]\n", r->provider);
1120
1121         printf("\n");
1122 }
1123
1124 /****************************************************************************
1125 ****************************************************************************/
1126
1127 static void display_print_driver8(struct spoolss_DriverInfo8 *r)
1128 {
1129         int i;
1130
1131         if (!r) {
1132                 return;
1133         }
1134
1135         printf("Printer Driver Info 8:\n");
1136         printf("\tVersion: [%x]\n", r->version);
1137         printf("\tDriver Name: [%s]\n", r->driver_name);
1138         printf("\tArchitecture: [%s]\n", r->architecture);
1139         printf("\tDriver Path: [%s]\n", r->driver_path);
1140         printf("\tDatafile: [%s]\n", r->data_file);
1141         printf("\tConfigfile: [%s]\n", r->config_file);
1142         printf("\tHelpfile: [%s]\n", r->help_file);
1143         printf("\tMonitorname: [%s]\n", r->monitor_name);
1144         printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1145
1146         for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1147                 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1148         }
1149
1150         for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) {
1151                 printf("\tPrevious Names: [%s]\n", r->previous_names[i]);
1152         }
1153
1154         printf("\tDriver Date: [%s]\n", nt_time_string(talloc_tos(), r->driver_date));
1155         printf("\tDriver Version: [0x%016llx]\n", (long long unsigned int)r->driver_version);
1156         printf("\tManufacturer Name: [%s]\n", r->manufacturer_name);
1157         printf("\tManufacturer Url: [%s]\n", r->manufacturer_url);
1158         printf("\tHardware ID: [%s]\n", r->hardware_id);
1159         printf("\tProvider: [%s]\n", r->provider);
1160         printf("\tPrint Processor: [%s]\n", r->print_processor);
1161         printf("\tVendor Setup: [%s]\n", r->vendor_setup);
1162         for (i=0; r->color_profiles && r->color_profiles[i] != NULL; i++) {
1163                 printf("\tColor Profiles: [%s]\n", r->color_profiles[i]);
1164         }
1165         printf("\tInf Path: [%s]\n", r->inf_path);
1166         printf("\tPrinter Driver Attributes: [0x%x]\n", r->printer_driver_attributes);
1167         for (i=0; r->core_driver_dependencies && r->core_driver_dependencies[i] != NULL; i++) {
1168                 printf("\tCore Driver Dependencies: [%s]\n", r->core_driver_dependencies[i]);
1169         }
1170         printf("\tMin Driver Inbox Driver Version Date: [%s]\n", nt_time_string(talloc_tos(), r->min_inbox_driver_ver_date));
1171         printf("\tMin Driver Inbox Driver Version Version: [0x%016llx]\n",
1172                 (long long unsigned int)r->min_inbox_driver_ver_version);
1173
1174         printf("\n");
1175 }
1176
1177 /****************************************************************************
1178 ****************************************************************************/
1179
1180 static WERROR cmd_spoolss_getdriver(struct rpc_pipe_client *cli,
1181                                     TALLOC_CTX *mem_ctx,
1182                                     int argc, const char **argv)
1183 {
1184         struct policy_handle pol;
1185         WERROR          werror;
1186         uint32_t        level = 3;
1187         const char      *printername;
1188         uint32_t        i;
1189         bool            success = false;
1190         union spoolss_DriverInfo info;
1191         uint32_t server_major_version;
1192         uint32_t server_minor_version;
1193
1194         if ((argc == 1) || (argc > 3)) {
1195                 printf("Usage: %s <printername> [level]\n", argv[0]);
1196                 return WERR_OK;
1197         }
1198
1199         /* get the arguments need to open the printer handle */
1200
1201         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1202
1203         if (argc == 3) {
1204                 level = atoi(argv[2]);
1205         }
1206
1207         /* Open a printer handle */
1208
1209         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1210                                                printername,
1211                                                PRINTER_ACCESS_USE,
1212                                                &pol);
1213         if (!W_ERROR_IS_OK(werror)) {
1214                 printf("Error opening printer handle for %s!\n", printername);
1215                 return werror;
1216         }
1217
1218         /* loop through and print driver info level for each architecture */
1219
1220         for (i=0; archi_table[i].long_archi!=NULL; i++) {
1221
1222                 werror = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1223                                                           &pol,
1224                                                           archi_table[i].long_archi,
1225                                                           level,
1226                                                           0, /* offered */
1227                                                           archi_table[i].version,
1228                                                           2,
1229                                                           &info,
1230                                                           &server_major_version,
1231                                                           &server_minor_version);
1232                 if (!W_ERROR_IS_OK(werror)) {
1233                         continue;
1234                 }
1235
1236                 /* need at least one success */
1237
1238                 success = true;
1239
1240                 printf("\n[%s]\n", archi_table[i].long_archi);
1241
1242                 switch (level) {
1243                 case 1:
1244                         display_print_driver1(&info.info1);
1245                         break;
1246                 case 2:
1247                         display_print_driver2(&info.info2);
1248                         break;
1249                 case 3:
1250                         display_print_driver3(&info.info3);
1251                         break;
1252                 case 4:
1253                         display_print_driver4(&info.info4);
1254                         break;
1255                 case 5:
1256                         display_print_driver5(&info.info5);
1257                         break;
1258                 case 6:
1259                         display_print_driver6(&info.info6);
1260                         break;
1261                 case 8:
1262                         display_print_driver8(&info.info8);
1263                         break;
1264                 default:
1265                         printf("unknown info level %d\n", level);
1266                         break;
1267                 }
1268         }
1269
1270         /* Cleanup */
1271
1272         if (is_valid_policy_hnd(&pol)) {
1273                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
1274         }
1275
1276         if (success) {
1277                 werror = WERR_OK;
1278         }
1279
1280         return werror;
1281 }
1282
1283 /****************************************************************************
1284 ****************************************************************************/
1285
1286 static WERROR enum_driver_by_architecture(struct rpc_pipe_client *cli,
1287                                           TALLOC_CTX *mem_ctx,
1288                                           const char *architecture,
1289                                           uint32_t level)
1290 {
1291         WERROR werror;
1292         uint32_t count = 0;
1293         union spoolss_DriverInfo *info = NULL;
1294         uint32_t j;
1295
1296         werror = rpccli_spoolss_enumprinterdrivers(cli, mem_ctx,
1297                                                    cli->srv_name_slash,
1298                                                    architecture,
1299                                                    level,
1300                                                    0,
1301                                                    &count,
1302                                                    &info);
1303
1304         if (W_ERROR_EQUAL(werror, WERR_INVALID_ENVIRONMENT)) {
1305                 printf("Server does not support environment [%s]\n",
1306                         architecture);
1307                 return WERR_OK;
1308         }
1309
1310         if (count == 0) {
1311                 return WERR_OK;
1312         }
1313
1314         if (!W_ERROR_IS_OK(werror)) {
1315                 printf("Error getting driver for environment [%s] - %s\n",
1316                         architecture, win_errstr(werror));
1317                 return werror;
1318         }
1319
1320         printf("\n[%s]\n", architecture);
1321
1322         switch (level) {
1323         case 1:
1324                 for (j=0; j < count; j++) {
1325                         display_print_driver1(&info[j].info1);
1326                 }
1327                 break;
1328         case 2:
1329                 for (j=0; j < count; j++) {
1330                         display_print_driver2(&info[j].info2);
1331                 }
1332                 break;
1333         case 3:
1334                 for (j=0; j < count; j++) {
1335                         display_print_driver3(&info[j].info3);
1336                 }
1337                 break;
1338         case 4:
1339                 for (j=0; j < count; j++) {
1340                         display_print_driver4(&info[j].info4);
1341                 }
1342                 break;
1343         case 5:
1344                 for (j=0; j < count; j++) {
1345                         display_print_driver5(&info[j].info5);
1346                 }
1347                 break;
1348         case 6:
1349                 for (j=0; j < count; j++) {
1350                         display_print_driver6(&info[j].info6);
1351                 }
1352                 break;
1353         case 8:
1354                 for (j=0; j < count; j++) {
1355                         display_print_driver8(&info[j].info8);
1356                 }
1357                 break;
1358         default:
1359                 printf("unknown info level %d\n", level);
1360                 return WERR_UNKNOWN_LEVEL;
1361         }
1362
1363         return werror;
1364 }
1365
1366 static WERROR cmd_spoolss_enum_drivers(struct rpc_pipe_client *cli,
1367                                          TALLOC_CTX *mem_ctx,
1368                                          int argc, const char **argv)
1369 {
1370         WERROR werror = WERR_OK;
1371         uint32_t        level = 1;
1372         uint32_t        i;
1373         const char *architecture = NULL;
1374
1375         if (argc > 3) {
1376                 printf("Usage: enumdrivers [level] [architecture]\n");
1377                 return WERR_OK;
1378         }
1379
1380         if (argc >= 2) {
1381                 level = atoi(argv[1]);
1382         }
1383
1384         if (argc == 3) {
1385                 architecture = argv[2];
1386         }
1387
1388         if (architecture) {
1389                 return enum_driver_by_architecture(cli, mem_ctx,
1390                                                    architecture,
1391                                                    level);
1392         }
1393
1394         /* loop through and print driver info level for each architecture */
1395         for (i=0; archi_table[i].long_archi!=NULL; i++) {
1396                 /* check to see if we already asked for this architecture string */
1397
1398                 if (i>0 && strequal(archi_table[i].long_archi, archi_table[i-1].long_archi)) {
1399                         continue;
1400                 }
1401
1402                 werror = enum_driver_by_architecture(cli, mem_ctx,
1403                                                      archi_table[i].long_archi,
1404                                                      level);
1405                 if (!W_ERROR_IS_OK(werror)) {
1406                         break;
1407                 }
1408         }
1409
1410         return werror;
1411 }
1412
1413 /****************************************************************************
1414 ****************************************************************************/
1415
1416 static void display_printdriverdir_1(struct spoolss_DriverDirectoryInfo1 *r)
1417 {
1418         printf("\tDirectory Name:[%s]\n", r->directory_name);
1419 }
1420
1421 /****************************************************************************
1422 ****************************************************************************/
1423
1424 static WERROR cmd_spoolss_getdriverdir(struct rpc_pipe_client *cli,
1425                                          TALLOC_CTX *mem_ctx,
1426                                          int argc, const char **argv)
1427 {
1428         WERROR result;
1429         NTSTATUS status;
1430         const char *env = SPOOLSS_ARCHITECTURE_NT_X86;
1431         DATA_BLOB buffer;
1432         uint32_t offered;
1433         union spoolss_DriverDirectoryInfo info;
1434         uint32_t needed;
1435
1436         if (argc > 2) {
1437                 printf("Usage: %s [environment]\n", argv[0]);
1438                 return WERR_OK;
1439         }
1440
1441         /* Get the arguments need to open the printer handle */
1442
1443         if (argc == 2) {
1444                 env = argv[1];
1445         }
1446
1447         /* Get the directory.  Only use Info level 1 */
1448
1449         status = rpccli_spoolss_GetPrinterDriverDirectory(cli, mem_ctx,
1450                                                           cli->srv_name_slash,
1451                                                           env,
1452                                                           1,
1453                                                           NULL, /* buffer */
1454                                                           0, /* offered */
1455                                                           NULL, /* info */
1456                                                           &needed,
1457                                                           &result);
1458         if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) {
1459                 offered = needed;
1460                 buffer = data_blob_talloc_zero(mem_ctx, needed);
1461
1462                 status = rpccli_spoolss_GetPrinterDriverDirectory(cli, mem_ctx,
1463                                                                   cli->srv_name_slash,
1464                                                                   env,
1465                                                                   1,
1466                                                                   &buffer,
1467                                                                   offered,
1468                                                                   &info,
1469                                                                   &needed,
1470                                                                   &result);
1471         }
1472
1473         if (W_ERROR_IS_OK(result)) {
1474                 display_printdriverdir_1(&info.info1);
1475         }
1476
1477         return result;
1478 }
1479
1480 /****************************************************************************
1481 ****************************************************************************/
1482
1483 static void set_drv_info_3_env(TALLOC_CTX *mem_ctx,
1484                                struct spoolss_AddDriverInfo3 *info,
1485                                const char *arch)
1486 {
1487
1488         int i;
1489
1490         for (i=0; archi_table[i].long_archi != NULL; i++)
1491         {
1492                 if (strcmp(arch, archi_table[i].short_archi) == 0)
1493                 {
1494                         info->version = archi_table[i].version;
1495                         info->architecture = talloc_strdup(mem_ctx, archi_table[i].long_archi);
1496                         break;
1497                 }
1498         }
1499
1500         if (archi_table[i].long_archi == NULL)
1501         {
1502                 DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch));
1503         }
1504
1505         return;
1506 }
1507
1508
1509 /**************************************************************************
1510  wrapper for strtok to get the next parameter from a delimited list.
1511  Needed to handle the empty parameter string denoted by "NULL"
1512  *************************************************************************/
1513
1514 static char *get_driver_3_param(TALLOC_CTX *mem_ctx, char *str,
1515                                 const char *delim, const char **dest,
1516                                 char **saveptr)
1517 {
1518         char    *ptr;
1519
1520         /* get the next token */
1521         ptr = strtok_r(str, delim, saveptr);
1522
1523         /* a string of 'NULL' is used to represent an empty
1524            parameter because two consecutive delimiters
1525            will not return an empty string.  See man strtok(3)
1526            for details */
1527         if (ptr && (StrCaseCmp(ptr, "NULL") == 0)) {
1528                 ptr = NULL;
1529         }
1530
1531         if (dest != NULL) {
1532                 *dest = talloc_strdup(mem_ctx, ptr);
1533         }
1534
1535         return ptr;
1536 }
1537
1538 /********************************************************************************
1539  fill in the members of a spoolss_AddDriverInfo3 struct using a character
1540  string in the form of
1541          <Long Printer Name>:<Driver File Name>:<Data File Name>:\
1542              <Config File Name>:<Help File Name>:<Language Monitor Name>:\
1543              <Default Data Type>:<Comma Separated list of Files>
1544  *******************************************************************************/
1545
1546 static bool init_drv_info_3_members(TALLOC_CTX *mem_ctx, struct spoolss_AddDriverInfo3 *r,
1547                                     char *args)
1548 {
1549         char    *str, *str2;
1550         int count = 0;
1551         char *saveptr = NULL;
1552         struct spoolss_StringArray *deps;
1553         const char **file_array = NULL;
1554         int i;
1555
1556         /* fill in the UNISTR fields */
1557         str = get_driver_3_param(mem_ctx, args, ":", &r->driver_name, &saveptr);
1558         str = get_driver_3_param(mem_ctx, NULL, ":", &r->driver_path, &saveptr);
1559         str = get_driver_3_param(mem_ctx, NULL, ":", &r->data_file, &saveptr);
1560         str = get_driver_3_param(mem_ctx, NULL, ":", &r->config_file, &saveptr);
1561         str = get_driver_3_param(mem_ctx, NULL, ":", &r->help_file, &saveptr);
1562         str = get_driver_3_param(mem_ctx, NULL, ":", &r->monitor_name, &saveptr);
1563         str = get_driver_3_param(mem_ctx, NULL, ":", &r->default_datatype, &saveptr);
1564
1565         /* <Comma Separated List of Dependent Files> */
1566         /* save the beginning of the string */
1567         str2 = get_driver_3_param(mem_ctx, NULL, ":", NULL, &saveptr);
1568         str = str2;
1569
1570         /* begin to strip out each filename */
1571         str = strtok_r(str, ",", &saveptr);
1572
1573         /* no dependent files, we are done */
1574         if (!str) {
1575                 return true;
1576         }
1577
1578         deps = talloc_zero(mem_ctx, struct spoolss_StringArray);
1579         if (!deps) {
1580                 return false;
1581         }
1582
1583         while (str != NULL) {
1584                 add_string_to_array(deps, str, &file_array, &count);
1585                 str = strtok_r(NULL, ",", &saveptr);
1586         }
1587
1588         deps->string = talloc_zero_array(deps, const char *, count + 1);
1589         if (!deps->string) {
1590                 return false;
1591         }
1592
1593         for (i=0; i < count; i++) {
1594                 deps->string[i] = file_array[i];
1595         }
1596
1597         r->dependent_files = deps;
1598
1599         return true;
1600 }
1601
1602 /****************************************************************************
1603 ****************************************************************************/
1604
1605 static WERROR cmd_spoolss_addprinterdriver(struct rpc_pipe_client *cli,
1606                                              TALLOC_CTX *mem_ctx,
1607                                              int argc, const char **argv)
1608 {
1609         WERROR result;
1610         NTSTATUS status;
1611         uint32_t                  level = 3;
1612         struct spoolss_AddDriverInfoCtr info_ctr;
1613         struct spoolss_AddDriverInfo3 info3;
1614         const char              *arch;
1615         char                    *driver_args;
1616
1617         /* parse the command arguments */
1618         if (argc != 3 && argc != 4)
1619         {
1620                 printf ("Usage: %s <Environment> \\\n", argv[0]);
1621                 printf ("\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n");
1622                 printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
1623                 printf ("\t<Default Data Type>:<Comma Separated list of Files> \\\n");
1624                 printf ("\t[version]\n");
1625
1626             return WERR_OK;
1627         }
1628
1629         /* Fill in the spoolss_AddDriverInfo3 struct */
1630         ZERO_STRUCT(info3);
1631
1632         arch = cmd_spoolss_get_short_archi(argv[1]);
1633         if (!arch) {
1634                 printf ("Error Unknown architechture [%s]\n", argv[1]);
1635                 return WERR_INVALID_PARAM;
1636         }
1637
1638         set_drv_info_3_env(mem_ctx, &info3, arch);
1639
1640         driver_args = talloc_strdup( mem_ctx, argv[2] );
1641         if (!init_drv_info_3_members(mem_ctx, &info3, driver_args ))
1642         {
1643                 printf ("Error Invalid parameter list - %s.\n", argv[2]);
1644                 return WERR_INVALID_PARAM;
1645         }
1646
1647         /* if printer driver version specified, override the default version
1648          * used by the architecture.  This allows installation of Windows
1649          * 2000 (version 3) printer drivers. */
1650         if (argc == 4)
1651         {
1652                 info3.version = atoi(argv[3]);
1653         }
1654
1655
1656         info_ctr.level          = level;
1657         info_ctr.info.info3     = &info3;
1658
1659         status = rpccli_spoolss_AddPrinterDriver(cli, mem_ctx,
1660                                                  cli->srv_name_slash,
1661                                                  &info_ctr,
1662                                                  &result);
1663         if (!NT_STATUS_IS_OK(status)) {
1664                 return ntstatus_to_werror(status);
1665         }
1666         if (W_ERROR_IS_OK(result)) {
1667                 printf ("Printer Driver %s successfully installed.\n",
1668                         info3.driver_name);
1669         }
1670
1671         return result;
1672 }
1673
1674
1675 /****************************************************************************
1676 ****************************************************************************/
1677
1678 static WERROR cmd_spoolss_addprinterex(struct rpc_pipe_client *cli,
1679                                          TALLOC_CTX *mem_ctx,
1680                                          int argc, const char **argv)
1681 {
1682         WERROR result;
1683         struct spoolss_SetPrinterInfoCtr info_ctr;
1684         struct spoolss_SetPrinterInfo2 info2;
1685
1686         /* parse the command arguments */
1687         if (argc != 5)
1688         {
1689                 printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]);
1690                 return WERR_OK;
1691         }
1692
1693         /* Fill in the DRIVER_INFO_2 struct */
1694         ZERO_STRUCT(info2);
1695
1696         info2.printername       = argv[1];
1697         info2.drivername        = argv[3];
1698         info2.sharename         = argv[2];
1699         info2.portname          = argv[4];
1700         info2.comment           = "Created by rpcclient";
1701         info2.printprocessor    = "winprint";
1702         info2.datatype          = "RAW";
1703         info2.devmode_ptr       = 0;
1704         info2.secdesc_ptr       = 0;
1705         info2.attributes        = PRINTER_ATTRIBUTE_SHARED;
1706         info2.priority          = 0;
1707         info2.defaultpriority   = 0;
1708         info2.starttime         = 0;
1709         info2.untiltime         = 0;
1710
1711         /* These three fields must not be used by AddPrinter()
1712            as defined in the MS Platform SDK documentation..
1713            --jerry
1714         info2.status            = 0;
1715         info2.cjobs             = 0;
1716         info2.averageppm        = 0;
1717         */
1718
1719         info_ctr.level = 2;
1720         info_ctr.info.info2 = &info2;
1721
1722         result = rpccli_spoolss_addprinterex(cli, mem_ctx,
1723                                              &info_ctr);
1724         if (W_ERROR_IS_OK(result))
1725                 printf ("Printer %s successfully installed.\n", argv[1]);
1726
1727         return result;
1728 }
1729
1730 /****************************************************************************
1731 ****************************************************************************/
1732
1733 static WERROR cmd_spoolss_setdriver(struct rpc_pipe_client *cli,
1734                                       TALLOC_CTX *mem_ctx,
1735                                       int argc, const char **argv)
1736 {
1737         struct policy_handle    pol;
1738         WERROR                  result;
1739         NTSTATUS                status;
1740         uint32_t                level = 2;
1741         const char              *printername;
1742         union spoolss_PrinterInfo info;
1743         struct spoolss_SetPrinterInfoCtr info_ctr;
1744         struct spoolss_SetPrinterInfo2 info2;
1745         struct spoolss_DevmodeContainer devmode_ctr;
1746         struct sec_desc_buf secdesc_ctr;
1747
1748         ZERO_STRUCT(devmode_ctr);
1749         ZERO_STRUCT(secdesc_ctr);
1750
1751         /* parse the command arguments */
1752         if (argc != 3)
1753         {
1754                 printf ("Usage: %s <printer> <driver>\n", argv[0]);
1755                 return WERR_OK;
1756         }
1757
1758         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1759
1760         /* Get a printer handle */
1761
1762         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1763                                                printername,
1764                                                PRINTER_ALL_ACCESS,
1765                                                &pol);
1766         if (!W_ERROR_IS_OK(result))
1767                 goto done;
1768
1769         /* Get printer info */
1770
1771         result = rpccli_spoolss_getprinter(cli, mem_ctx,
1772                                            &pol,
1773                                            level,
1774                                            0,
1775                                            &info);
1776         if (!W_ERROR_IS_OK(result)) {
1777                 printf ("Unable to retrieve printer information!\n");
1778                 goto done;
1779         }
1780
1781         /* Set the printer driver */
1782
1783         spoolss_printerinfo2_to_setprinterinfo2(&info.info2, &info2);
1784         info2.drivername = argv[2];
1785
1786         info_ctr.level = 2;
1787         info_ctr.info.info2 = &info2;
1788
1789         status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
1790                                            &pol,
1791                                            &info_ctr,
1792                                            &devmode_ctr,
1793                                            &secdesc_ctr,
1794                                            0, /* command */
1795                                            &result);
1796         if (!W_ERROR_IS_OK(result)) {
1797                 printf("SetPrinter call failed!\n");
1798                 goto done;;
1799         }
1800
1801         printf("Successfully set %s to driver %s.\n", argv[1], argv[2]);
1802
1803 done:
1804         /* Cleanup */
1805
1806         if (is_valid_policy_hnd(&pol))
1807                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
1808
1809         return result;
1810 }
1811
1812
1813 /****************************************************************************
1814 ****************************************************************************/
1815
1816 static WERROR cmd_spoolss_deletedriverex(struct rpc_pipe_client *cli,
1817                                          TALLOC_CTX *mem_ctx,
1818                                          int argc, const char **argv)
1819 {
1820         WERROR result, ret = WERR_UNKNOWN_PRINTER_DRIVER;
1821         NTSTATUS status;
1822
1823         int   i;
1824         int vers = -1;
1825
1826         const char *arch = NULL;
1827         uint32_t delete_flags = 0;
1828
1829         /* parse the command arguments */
1830         if (argc < 2 || argc > 4) {
1831                 printf ("Usage: %s <driver> [arch] [version]\n", argv[0]);
1832                 return WERR_OK;
1833         }
1834
1835         if (argc >= 3)
1836                 arch = argv[2];
1837         if (argc == 4)
1838                 vers = atoi (argv[3]);
1839
1840         if (vers >= 0) {
1841                 delete_flags |= DPD_DELETE_SPECIFIC_VERSION;
1842         }
1843
1844         /* delete the driver for all architectures */
1845         for (i=0; archi_table[i].long_archi; i++) {
1846
1847                 if (arch &&  !strequal( archi_table[i].long_archi, arch))
1848                         continue;
1849
1850                 if (vers >= 0 && archi_table[i].version != vers)
1851                         continue;
1852
1853                 /* make the call to remove the driver */
1854                 status = rpccli_spoolss_DeletePrinterDriverEx(cli, mem_ctx,
1855                                                               cli->srv_name_slash,
1856                                                               archi_table[i].long_archi,
1857                                                               argv[1],
1858                                                               delete_flags,
1859                                                               archi_table[i].version,
1860                                                               &result);
1861
1862                 if ( !W_ERROR_IS_OK(result) )
1863                 {
1864                         if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1865                                 printf ("Failed to remove driver %s for arch [%s] (version: %d): %s\n",
1866                                         argv[1], archi_table[i].long_archi, archi_table[i].version, win_errstr(result));
1867                         }
1868                 }
1869                 else
1870                 {
1871                         printf ("Driver %s and files removed for arch [%s] (version: %d).\n", argv[1],
1872                         archi_table[i].long_archi, archi_table[i].version);
1873                         ret = WERR_OK;
1874                 }
1875         }
1876
1877         return ret;
1878 }
1879
1880
1881 /****************************************************************************
1882 ****************************************************************************/
1883
1884 static WERROR cmd_spoolss_deletedriver(struct rpc_pipe_client *cli,
1885                                          TALLOC_CTX *mem_ctx,
1886                                          int argc, const char **argv)
1887 {
1888         WERROR result = WERR_OK;
1889         NTSTATUS status;
1890         int                     i;
1891
1892         /* parse the command arguments */
1893         if (argc != 2) {
1894                 printf ("Usage: %s <driver>\n", argv[0]);
1895                 return WERR_OK;
1896         }
1897
1898         /* delete the driver for all architectures */
1899         for (i=0; archi_table[i].long_archi; i++) {
1900                 /* make the call to remove the driver */
1901                 status = rpccli_spoolss_DeletePrinterDriver(cli, mem_ctx,
1902                                                             cli->srv_name_slash,
1903                                                             archi_table[i].long_archi,
1904                                                             argv[1],
1905                                                             &result);
1906                 if (!NT_STATUS_IS_OK(status)) {
1907                         return result;
1908                 }
1909                 if ( !W_ERROR_IS_OK(result) ) {
1910                         if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1911                                 printf ("Failed to remove driver %s for arch [%s] - error 0x%x!\n",
1912                                         argv[1], archi_table[i].long_archi,
1913                                         W_ERROR_V(result));
1914                         }
1915                 } else {
1916                         printf ("Driver %s removed for arch [%s].\n", argv[1],
1917                                 archi_table[i].long_archi);
1918                 }
1919         }
1920
1921         return result;
1922 }
1923
1924 /****************************************************************************
1925 ****************************************************************************/
1926
1927 static WERROR cmd_spoolss_getprintprocdir(struct rpc_pipe_client *cli,
1928                                             TALLOC_CTX *mem_ctx,
1929                                             int argc, const char **argv)
1930 {
1931         WERROR result;
1932         NTSTATUS status;
1933         const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
1934         DATA_BLOB buffer;
1935         uint32_t offered;
1936         union spoolss_PrintProcessorDirectoryInfo info;
1937         uint32_t needed;
1938
1939         /* parse the command arguments */
1940         if (argc > 2) {
1941                 printf ("Usage: %s [environment]\n", argv[0]);
1942                 return WERR_OK;
1943         }
1944
1945         if (argc == 2) {
1946                 environment = argv[1];
1947         }
1948
1949         status = rpccli_spoolss_GetPrintProcessorDirectory(cli, mem_ctx,
1950                                                            cli->srv_name_slash,
1951                                                            environment,
1952                                                            1,
1953                                                            NULL, /* buffer */
1954                                                            0, /* offered */
1955                                                            NULL, /* info */
1956                                                            &needed,
1957                                                            &result);
1958         if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) {
1959                 offered = needed;
1960                 buffer = data_blob_talloc_zero(mem_ctx, needed);
1961
1962                 status = rpccli_spoolss_GetPrintProcessorDirectory(cli, mem_ctx,
1963                                                                    cli->srv_name_slash,
1964                                                                    environment,
1965                                                                    1,
1966                                                                    &buffer,
1967                                                                    offered,
1968                                                                    &info,
1969                                                                    &needed,
1970                                                                    &result);
1971         }
1972
1973         if (W_ERROR_IS_OK(result)) {
1974                 printf("%s\n", info.info1.directory_name);
1975         }
1976
1977         return result;
1978 }
1979
1980 /****************************************************************************
1981 ****************************************************************************/
1982
1983 static WERROR cmd_spoolss_addform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1984                                     int argc, const char **argv)
1985 {
1986         struct policy_handle handle;
1987         WERROR werror;
1988         NTSTATUS status;
1989         const char *printername;
1990         union spoolss_AddFormInfo info;
1991         struct spoolss_AddFormInfo1 info1;
1992         struct spoolss_AddFormInfo2 info2;
1993         uint32_t level = 1;
1994
1995         /* Parse the command arguments */
1996
1997         if (argc < 3 || argc > 5) {
1998                 printf ("Usage: %s <printer> <formname> [level]\n", argv[0]);
1999                 return WERR_OK;
2000         }
2001
2002         /* Get a printer handle */
2003
2004         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2005
2006         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2007                                                printername,
2008                                                PRINTER_ALL_ACCESS,
2009                                                &handle);
2010         if (!W_ERROR_IS_OK(werror))
2011                 goto done;
2012
2013         /* Dummy up some values for the form data */
2014
2015         if (argc == 4) {
2016                 level = atoi(argv[3]);
2017         }
2018
2019         switch (level) {
2020         case 1:
2021                 info1.flags             = SPOOLSS_FORM_USER;
2022                 info1.form_name         = argv[2];
2023                 info1.size.width        = 100;
2024                 info1.size.height       = 100;
2025                 info1.area.left         = 0;
2026                 info1.area.top          = 10;
2027                 info1.area.right        = 20;
2028                 info1.area.bottom       = 30;
2029
2030                 info.info1 = &info1;
2031
2032                 break;
2033         case 2:
2034                 info2.flags             = SPOOLSS_FORM_USER;
2035                 info2.form_name         = argv[2];
2036                 info2.size.width        = 100;
2037                 info2.size.height       = 100;
2038                 info2.area.left         = 0;
2039                 info2.area.top          = 10;
2040                 info2.area.right        = 20;
2041                 info2.area.bottom       = 30;
2042                 info2.keyword           = argv[2];
2043                 info2.string_type       = SPOOLSS_FORM_STRING_TYPE_NONE;
2044                 info2.mui_dll           = NULL;
2045                 info2.ressource_id      = 0;
2046                 info2.display_name      = argv[2];
2047                 info2.lang_id           = 0;
2048
2049                 info.info2 = &info2;
2050
2051                 break;
2052         }
2053
2054         /* Add the form */
2055
2056
2057         status = rpccli_spoolss_AddForm(cli, mem_ctx,
2058                                         &handle,
2059                                         level,
2060                                         info,
2061                                         &werror);
2062
2063  done:
2064         if (is_valid_policy_hnd(&handle))
2065                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2066
2067         return werror;
2068 }
2069
2070 /****************************************************************************
2071 ****************************************************************************/
2072
2073 static WERROR cmd_spoolss_setform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
2074                                     int argc, const char **argv)
2075 {
2076         struct policy_handle handle;
2077         WERROR werror;
2078         NTSTATUS status;
2079         const char *printername;
2080         union spoolss_AddFormInfo info;
2081         struct spoolss_AddFormInfo1 info1;
2082
2083         /* Parse the command arguments */
2084
2085         if (argc != 3) {
2086                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
2087                 return WERR_OK;
2088         }
2089
2090         /* Get a printer handle */
2091
2092         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2093
2094         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2095                                                printername,
2096                                                SEC_FLAG_MAXIMUM_ALLOWED,
2097                                                &handle);
2098         if (!W_ERROR_IS_OK(werror))
2099                 goto done;
2100
2101         /* Dummy up some values for the form data */
2102
2103         info1.flags             = SPOOLSS_FORM_PRINTER;
2104         info1.size.width        = 100;
2105         info1.size.height       = 100;
2106         info1.area.left         = 0;
2107         info1.area.top          = 1000;
2108         info1.area.right        = 2000;
2109         info1.area.bottom       = 3000;
2110         info1.form_name         = argv[2];
2111
2112         info.info1 = &info1;
2113
2114         /* Set the form */
2115
2116         status = rpccli_spoolss_SetForm(cli, mem_ctx,
2117                                         &handle,
2118                                         argv[2],
2119                                         1,
2120                                         info,
2121                                         &werror);
2122
2123  done:
2124         if (is_valid_policy_hnd(&handle))
2125                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2126
2127         return werror;
2128 }
2129
2130 /****************************************************************************
2131 ****************************************************************************/
2132
2133 static const char *get_form_flag(int form_flag)
2134 {
2135         switch (form_flag) {
2136         case SPOOLSS_FORM_USER:
2137                 return "FORM_USER";
2138         case SPOOLSS_FORM_BUILTIN:
2139                 return "FORM_BUILTIN";
2140         case SPOOLSS_FORM_PRINTER:
2141                 return "FORM_PRINTER";
2142         default:
2143                 return "unknown";
2144         }
2145 }
2146
2147 /****************************************************************************
2148 ****************************************************************************/
2149
2150 static void display_form_info1(struct spoolss_FormInfo1 *r)
2151 {
2152         printf("%s\n" \
2153                 "\tflag: %s (%d)\n" \
2154                 "\twidth: %d, length: %d\n" \
2155                 "\tleft: %d, right: %d, top: %d, bottom: %d\n\n",
2156                 r->form_name, get_form_flag(r->flags), r->flags,
2157                 r->size.width, r->size.height,
2158                 r->area.left, r->area.right,
2159                 r->area.top, r->area.bottom);
2160 }
2161
2162 /****************************************************************************
2163 ****************************************************************************/
2164
2165 static void display_form_info2(struct spoolss_FormInfo2 *r)
2166 {
2167         printf("%s\n" \
2168                 "\tflag: %s (%d)\n" \
2169                 "\twidth: %d, length: %d\n" \
2170                 "\tleft: %d, right: %d, top: %d, bottom: %d\n",
2171                 r->form_name, get_form_flag(r->flags), r->flags,
2172                 r->size.width, r->size.height,
2173                 r->area.left, r->area.right,
2174                 r->area.top, r->area.bottom);
2175         printf("\tkeyword: %s\n", r->keyword);
2176         printf("\tstring_type: 0x%08x\n", r->string_type);
2177         printf("\tmui_dll: %s\n", r->mui_dll);
2178         printf("\tressource_id: 0x%08x\n", r->ressource_id);
2179         printf("\tdisplay_name: %s\n", r->display_name);
2180         printf("\tlang_id: %d\n", r->lang_id);
2181         printf("\n");
2182 }
2183
2184 /****************************************************************************
2185 ****************************************************************************/
2186
2187 static WERROR cmd_spoolss_getform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
2188                                     int argc, const char **argv)
2189 {
2190         struct policy_handle handle;
2191         WERROR werror;
2192         NTSTATUS status;
2193         const char *printername;
2194         DATA_BLOB buffer;
2195         uint32_t offered = 0;
2196         union spoolss_FormInfo info;
2197         uint32_t needed;
2198         uint32_t level = 1;
2199
2200         /* Parse the command arguments */
2201
2202         if (argc < 3 || argc > 5) {
2203                 printf ("Usage: %s <printer> <formname> [level]\n", argv[0]);
2204                 return WERR_OK;
2205         }
2206
2207         /* Get a printer handle */
2208
2209         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2210
2211         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2212                                                printername,
2213                                                SEC_FLAG_MAXIMUM_ALLOWED,
2214                                                &handle);
2215         if (!W_ERROR_IS_OK(werror))
2216                 goto done;
2217
2218         if (argc == 4) {
2219                 level = atoi(argv[3]);
2220         }
2221
2222         /* Get the form */
2223
2224         status = rpccli_spoolss_GetForm(cli, mem_ctx,
2225                                         &handle,
2226                                         argv[2],
2227                                         level,
2228                                         NULL,
2229                                         offered,
2230                                         &info,
2231                                         &needed,
2232                                         &werror);
2233         if (W_ERROR_EQUAL(werror, WERR_INSUFFICIENT_BUFFER)) {
2234                 buffer = data_blob_talloc_zero(mem_ctx, needed);
2235                 offered = needed;
2236                 status = rpccli_spoolss_GetForm(cli, mem_ctx,
2237                                                 &handle,
2238                                                 argv[2],
2239                                                 level,
2240                                                 &buffer,
2241                                                 offered,
2242                                                 &info,
2243                                                 &needed,
2244                                                 &werror);
2245         }
2246
2247         if (!NT_STATUS_IS_OK(status)) {
2248                 return werror;
2249         }
2250
2251         switch (level) {
2252         case 1:
2253                 display_form_info1(&info.info1);
2254                 break;
2255         case 2:
2256                 display_form_info2(&info.info2);
2257                 break;
2258         }
2259
2260  done:
2261         if (is_valid_policy_hnd(&handle))
2262                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2263
2264         return werror;
2265 }
2266
2267 /****************************************************************************
2268 ****************************************************************************/
2269
2270 static WERROR cmd_spoolss_deleteform(struct rpc_pipe_client *cli,
2271                                        TALLOC_CTX *mem_ctx, int argc,
2272                                        const char **argv)
2273 {
2274         struct policy_handle handle;
2275         WERROR werror;
2276         NTSTATUS status;
2277         const char *printername;
2278
2279         /* Parse the command arguments */
2280
2281         if (argc != 3) {
2282                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
2283                 return WERR_OK;
2284         }
2285
2286         /* Get a printer handle */
2287
2288         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2289
2290         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2291                                                printername,
2292                                                SEC_FLAG_MAXIMUM_ALLOWED,
2293                                                &handle);
2294         if (!W_ERROR_IS_OK(werror))
2295                 goto done;
2296
2297         /* Delete the form */
2298
2299         status = rpccli_spoolss_DeleteForm(cli, mem_ctx,
2300                                            &handle,
2301                                            argv[2],
2302                                            &werror);
2303         if (!NT_STATUS_IS_OK(status)) {
2304                 return ntstatus_to_werror(status);
2305         }
2306
2307  done:
2308         if (is_valid_policy_hnd(&handle))
2309                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2310
2311         return werror;
2312 }
2313
2314 /****************************************************************************
2315 ****************************************************************************/
2316
2317 static WERROR cmd_spoolss_enum_forms(struct rpc_pipe_client *cli,
2318                                        TALLOC_CTX *mem_ctx, int argc,
2319                                        const char **argv)
2320 {
2321         struct policy_handle handle;
2322         WERROR werror;
2323         const char *printername;
2324         uint32_t num_forms, level = 1, i;
2325         union spoolss_FormInfo *forms;
2326
2327         /* Parse the command arguments */
2328
2329         if (argc < 2 || argc > 4) {
2330                 printf ("Usage: %s <printer> [level]\n", argv[0]);
2331                 return WERR_OK;
2332         }
2333
2334         /* Get a printer handle */
2335
2336         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2337
2338         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2339                                                printername,
2340                                                SEC_FLAG_MAXIMUM_ALLOWED,
2341                                                &handle);
2342         if (!W_ERROR_IS_OK(werror))
2343                 goto done;
2344
2345         if (argc == 3) {
2346                 level = atoi(argv[2]);
2347         }
2348
2349         /* Enumerate forms */
2350
2351         werror = rpccli_spoolss_enumforms(cli, mem_ctx,
2352                                           &handle,
2353                                           level,
2354                                           0,
2355                                           &num_forms,
2356                                           &forms);
2357
2358         if (!W_ERROR_IS_OK(werror))
2359                 goto done;
2360
2361         /* Display output */
2362
2363         for (i = 0; i < num_forms; i++) {
2364                 switch (level) {
2365                 case 1:
2366                         display_form_info1(&forms[i].info1);
2367                         break;
2368                 case 2:
2369                         display_form_info2(&forms[i].info2);
2370                         break;
2371                 }
2372         }
2373
2374  done:
2375         if (is_valid_policy_hnd(&handle))
2376                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2377
2378         return werror;
2379 }
2380
2381 /****************************************************************************
2382 ****************************************************************************/
2383
2384 static WERROR cmd_spoolss_setprinterdata(struct rpc_pipe_client *cli,
2385                                             TALLOC_CTX *mem_ctx,
2386                                             int argc, const char **argv)
2387 {
2388         WERROR result;
2389         NTSTATUS status;
2390         const char *printername;
2391         struct policy_handle pol;
2392         union spoolss_PrinterInfo info;
2393         enum winreg_Type type;
2394         union spoolss_PrinterData data;
2395         DATA_BLOB blob;
2396
2397         /* parse the command arguments */
2398         if (argc < 5) {
2399                 printf ("Usage: %s <printer> <string|binary|dword|multistring>"
2400                         " <value> <data>\n",
2401                         argv[0]);
2402                 return WERR_OK;
2403         }
2404
2405         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2406
2407         type = REG_NONE;
2408
2409         if (strequal(argv[2], "string")) {
2410                 type = REG_SZ;
2411         }
2412
2413         if (strequal(argv[2], "binary")) {
2414                 type = REG_BINARY;
2415         }
2416
2417         if (strequal(argv[2], "dword")) {
2418                 type = REG_DWORD;
2419         }
2420
2421         if (strequal(argv[2], "multistring")) {
2422                 type = REG_MULTI_SZ;
2423         }
2424
2425         if (type == REG_NONE) {
2426                 printf("Unknown data type: %s\n", argv[2]);
2427                 result =  WERR_INVALID_PARAM;
2428                 goto done;
2429         }
2430
2431         /* get a printer handle */
2432
2433         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2434                                                printername,
2435                                                SEC_FLAG_MAXIMUM_ALLOWED,
2436                                                &pol);
2437         if (!W_ERROR_IS_OK(result)) {
2438                 goto done;
2439         }
2440
2441         result = rpccli_spoolss_getprinter(cli, mem_ctx,
2442                                            &pol,
2443                                            0,
2444                                            0,
2445                                            &info);
2446         if (!W_ERROR_IS_OK(result)) {
2447                 goto done;
2448         }
2449
2450         printf("%s\n", current_timestring(mem_ctx, true));
2451         printf("\tchange_id (before set)\t:[0x%x]\n", info.info0.change_id);
2452
2453         /* Set the printer data */
2454
2455         switch (type) {
2456         case REG_SZ:
2457                 data.string = talloc_strdup(mem_ctx, argv[4]);
2458                 W_ERROR_HAVE_NO_MEMORY(data.string);
2459                 break;
2460         case REG_DWORD:
2461                 data.value = strtoul(argv[4], NULL, 10);
2462                 break;
2463         case REG_BINARY:
2464                 data.binary = strhex_to_data_blob(mem_ctx, argv[4]);
2465                 break;
2466         case REG_MULTI_SZ: {
2467                 int i, num_strings;
2468                 const char **strings = NULL;
2469
2470                 for (i=4; i<argc; i++) {
2471                         if (strcmp(argv[i], "NULL") == 0) {
2472                                 argv[i] = "";
2473                         }
2474                         if (!add_string_to_array(mem_ctx, argv[i],
2475                                                  &strings,
2476                                                  &num_strings)) {
2477                                 result = WERR_NOMEM;
2478                                 goto done;
2479                         }
2480                 }
2481                 data.string_array = talloc_zero_array(mem_ctx, const char *, num_strings + 1);
2482                 if (!data.string_array) {
2483                         result = WERR_NOMEM;
2484                         goto done;
2485                 }
2486                 for (i=0; i < num_strings; i++) {
2487                         data.string_array[i] = strings[i];
2488                 }
2489                 break;
2490                 }
2491         default:
2492                 printf("Unknown data type: %s\n", argv[2]);
2493                 result = WERR_INVALID_PARAM;
2494                 goto done;
2495         }
2496
2497         result = push_spoolss_PrinterData(mem_ctx, &blob, type, &data);
2498         if (!W_ERROR_IS_OK(result)) {
2499                 goto done;
2500         }
2501
2502         status = rpccli_spoolss_SetPrinterData(cli, mem_ctx,
2503                                                &pol,
2504                                                argv[3], /* value_name */
2505                                                type,
2506                                                blob.data,
2507                                                blob.length,
2508                                                &result);
2509         if (!W_ERROR_IS_OK(result)) {
2510                 printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]);
2511                 goto done;
2512         }
2513         printf("\tSetPrinterData succeeded [%s: %s]\n", argv[3], argv[4]);
2514
2515         result = rpccli_spoolss_getprinter(cli, mem_ctx,
2516                                            &pol,
2517                                            0,
2518                                            0,
2519                                            &info);
2520         if (!W_ERROR_IS_OK(result)) {
2521                 goto done;
2522         }
2523
2524         printf("%s\n", current_timestring(mem_ctx, true));
2525         printf("\tchange_id (after set)\t:[0x%x]\n", info.info0.change_id);
2526
2527 done:
2528         /* cleanup */
2529         if (is_valid_policy_hnd(&pol)) {
2530                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
2531         }
2532
2533         return result;
2534 }
2535
2536 /****************************************************************************
2537 ****************************************************************************/
2538
2539 static void display_job_info1(struct spoolss_JobInfo1 *r)
2540 {
2541         printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", r->position, r->job_id,
2542                r->user_name, r->document_name, r->text_status, r->pages_printed,
2543                r->total_pages);
2544 }
2545
2546 /****************************************************************************
2547 ****************************************************************************/
2548
2549 static void display_job_info2(struct spoolss_JobInfo2 *r)
2550 {
2551         printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n",
2552                r->position, r->job_id,
2553                r->user_name, r->document_name, r->text_status, r->pages_printed,
2554                r->total_pages, r->size);
2555 }
2556
2557 /****************************************************************************
2558 ****************************************************************************/
2559
2560 static void display_job_info3(struct spoolss_JobInfo3 *r)
2561 {
2562         printf("jobid[%d], next_jobid[%d]\n",
2563                 r->job_id, r->next_job_id);
2564 }
2565
2566 /****************************************************************************
2567 ****************************************************************************/
2568
2569 static void display_job_info4(struct spoolss_JobInfo4 *r)
2570 {
2571         printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d/%d bytes\n",
2572                r->position, r->job_id,
2573                r->user_name, r->document_name, r->text_status, r->pages_printed,
2574                r->total_pages, r->size, r->size_high);
2575 }
2576
2577 /****************************************************************************
2578 ****************************************************************************/
2579
2580 static WERROR cmd_spoolss_enum_jobs(struct rpc_pipe_client *cli,
2581                                       TALLOC_CTX *mem_ctx, int argc,
2582                                       const char **argv)
2583 {
2584         WERROR result;
2585         uint32_t level = 1, count, i;
2586         const char *printername;
2587         struct policy_handle hnd;
2588         union spoolss_JobInfo *info;
2589
2590         if (argc < 2 || argc > 3) {
2591                 printf("Usage: %s printername [level]\n", argv[0]);
2592                 return WERR_OK;
2593         }
2594
2595         if (argc == 3) {
2596                 level = atoi(argv[2]);
2597         }
2598
2599         /* Open printer handle */
2600
2601         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2602
2603         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2604                                                printername,
2605                                                SEC_FLAG_MAXIMUM_ALLOWED,
2606                                                &hnd);
2607         if (!W_ERROR_IS_OK(result))
2608                 goto done;
2609
2610         /* Enumerate ports */
2611
2612         result = rpccli_spoolss_enumjobs(cli, mem_ctx,
2613                                          &hnd,
2614                                          0, /* firstjob */
2615                                          1000, /* numjobs */
2616                                          level,
2617                                          0,
2618                                          &count,
2619                                          &info);
2620         if (!W_ERROR_IS_OK(result)) {
2621                 goto done;
2622         }
2623
2624         for (i = 0; i < count; i++) {
2625                 switch (level) {
2626                 case 1:
2627                         display_job_info1(&info[i].info1);
2628                         break;
2629                 case 2:
2630                         display_job_info2(&info[i].info2);
2631                         break;
2632                 default:
2633                         d_printf("unknown info level %d\n", level);
2634                         break;
2635                 }
2636         }
2637
2638 done:
2639         if (is_valid_policy_hnd(&hnd)) {
2640                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2641         }
2642
2643         return result;
2644 }
2645
2646 /****************************************************************************
2647 ****************************************************************************/
2648
2649 static WERROR cmd_spoolss_get_job(struct rpc_pipe_client *cli,
2650                                   TALLOC_CTX *mem_ctx, int argc,
2651                                   const char **argv)
2652 {
2653         WERROR result;
2654         const char *printername;
2655         struct policy_handle hnd;
2656         uint32_t job_id;
2657         uint32_t level = 1;
2658         union spoolss_JobInfo info;
2659
2660         if (argc < 3 || argc > 4) {
2661                 printf("Usage: %s printername job_id [level]\n", argv[0]);
2662                 return WERR_OK;
2663         }
2664
2665         job_id = atoi(argv[2]);
2666
2667         if (argc == 4) {
2668                 level = atoi(argv[3]);
2669         }
2670
2671         /* Open printer handle */
2672
2673         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2674
2675         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2676                                                printername,
2677                                                SEC_FLAG_MAXIMUM_ALLOWED,
2678                                                &hnd);
2679         if (!W_ERROR_IS_OK(result)) {
2680                 goto done;
2681         }
2682
2683         /* Enumerate ports */
2684
2685         result = rpccli_spoolss_getjob(cli, mem_ctx,
2686                                        &hnd,
2687                                        job_id,
2688                                        level,
2689                                        0,
2690                                        &info);
2691
2692         if (!W_ERROR_IS_OK(result)) {
2693                 goto done;
2694         }
2695
2696         switch (level) {
2697         case 1:
2698                 display_job_info1(&info.info1);
2699                 break;
2700         case 2:
2701                 display_job_info2(&info.info2);
2702                 break;
2703         case 3:
2704                 display_job_info3(&info.info3);
2705                 break;
2706         case 4:
2707                 display_job_info4(&info.info4);
2708                 break;
2709         default:
2710                 d_printf("unknown info level %d\n", level);
2711                 break;
2712         }
2713
2714 done:
2715         if (is_valid_policy_hnd(&hnd)) {
2716                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2717         }
2718
2719         return result;
2720 }
2721
2722 /****************************************************************************
2723 ****************************************************************************/
2724
2725 static WERROR cmd_spoolss_set_job(struct rpc_pipe_client *cli,
2726                                   TALLOC_CTX *mem_ctx, int argc,
2727                                   const char **argv)
2728 {
2729         WERROR result;
2730         NTSTATUS status;
2731         const char *printername;
2732         struct policy_handle hnd;
2733         uint32_t job_id;
2734         enum spoolss_JobControl command;
2735
2736         if (argc != 4) {
2737                 printf("Usage: %s printername job_id command\n", argv[0]);
2738                 return WERR_OK;
2739         }
2740
2741         job_id = atoi(argv[2]);
2742         command = atoi(argv[3]);
2743
2744         /* Open printer handle */
2745
2746         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2747
2748         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2749                                                printername,
2750                                                SEC_FLAG_MAXIMUM_ALLOWED,
2751                                                &hnd);
2752         if (!W_ERROR_IS_OK(result)) {
2753                 goto done;
2754         }
2755
2756         /* Set Job */
2757
2758         status = rpccli_spoolss_SetJob(cli, mem_ctx,
2759                                        &hnd,
2760                                        job_id,
2761                                        NULL,
2762                                        command,
2763                                        &result);
2764
2765         if (!W_ERROR_IS_OK(result)) {
2766                 goto done;
2767         }
2768
2769 done:
2770         if (is_valid_policy_hnd(&hnd)) {
2771                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2772         }
2773
2774         return result;
2775 }
2776
2777 /****************************************************************************
2778 ****************************************************************************/
2779
2780 static WERROR cmd_spoolss_enum_data(struct rpc_pipe_client *cli,
2781                                     TALLOC_CTX *mem_ctx, int argc,
2782                                     const char **argv)
2783 {
2784         WERROR result;
2785         NTSTATUS status;
2786         uint32_t i = 0;
2787         const char *printername;
2788         struct policy_handle hnd;
2789         uint32_t value_offered = 0;
2790         const char *value_name = NULL;
2791         uint32_t value_needed;
2792         enum winreg_Type type;
2793         uint8_t *data = NULL;
2794         uint32_t data_offered = 0;
2795         uint32_t data_needed;
2796
2797         if (argc != 2) {
2798                 printf("Usage: %s printername\n", argv[0]);
2799                 return WERR_OK;
2800         }
2801
2802         /* Open printer handle */
2803
2804         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2805
2806         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2807                                                printername,
2808                                                SEC_FLAG_MAXIMUM_ALLOWED,
2809                                                &hnd);
2810         if (!W_ERROR_IS_OK(result)) {
2811                 goto done;
2812         }
2813
2814         /* Enumerate data */
2815
2816         status = rpccli_spoolss_EnumPrinterData(cli, mem_ctx,
2817                                                 &hnd,
2818                                                 i,
2819                                                 value_name,
2820                                                 value_offered,
2821                                                 &value_needed,
2822                                                 &type,
2823                                                 data,
2824                                                 data_offered,
2825                                                 &data_needed,
2826                                                 &result);
2827
2828         data_offered    = data_needed;
2829         value_offered   = value_needed;
2830         data            = talloc_zero_array(mem_ctx, uint8_t, data_needed);
2831         value_name      = talloc_zero_array(mem_ctx, char, value_needed);
2832
2833         while (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(result)) {
2834
2835                 status = rpccli_spoolss_EnumPrinterData(cli, mem_ctx,
2836                                                         &hnd,
2837                                                         i++,
2838                                                         value_name,
2839                                                         value_offered,
2840                                                         &value_needed,
2841                                                         &type,
2842                                                         data,
2843                                                         data_offered,
2844                                                         &data_needed,
2845                                                         &result);
2846                 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(result)) {
2847                         struct regval_blob *v;
2848
2849                         v = regval_compose(talloc_tos(),
2850                                            value_name,
2851                                            type,
2852                                            data,
2853                                            data_offered);
2854                         if (v == NULL) {
2855                                 result = WERR_NOMEM;
2856                                 goto done;
2857                         }
2858
2859                         display_reg_value(v);
2860                         talloc_free(v);
2861                 }
2862         }
2863
2864         if (W_ERROR_V(result) == ERRnomoreitems) {
2865                 result = W_ERROR(ERRsuccess);
2866         }
2867
2868 done:
2869         if (is_valid_policy_hnd(&hnd)) {
2870                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2871         }
2872
2873         return result;
2874 }
2875
2876 /****************************************************************************
2877 ****************************************************************************/
2878
2879 static WERROR cmd_spoolss_enum_data_ex( struct rpc_pipe_client *cli,
2880                                           TALLOC_CTX *mem_ctx, int argc,
2881                                           const char **argv)
2882 {
2883         WERROR result;
2884         uint32_t i;
2885         const char *printername;
2886         struct policy_handle hnd;
2887         uint32_t count;
2888         struct spoolss_PrinterEnumValues *info;
2889
2890         if (argc != 3) {
2891                 printf("Usage: %s printername <keyname>\n", argv[0]);
2892                 return WERR_OK;
2893         }
2894
2895         /* Open printer handle */
2896
2897         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2898
2899         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2900                                                printername,
2901                                                SEC_FLAG_MAXIMUM_ALLOWED,
2902                                                &hnd);
2903         if (!W_ERROR_IS_OK(result)) {
2904                 goto done;
2905         }
2906
2907         /* Enumerate subkeys */
2908
2909         result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx,
2910                                                   &hnd,
2911                                                   argv[2],
2912                                                   0,
2913                                                   &count,
2914                                                   &info);
2915         if (!W_ERROR_IS_OK(result)) {
2916                 goto done;
2917         }
2918
2919         for (i=0; i < count; i++) {
2920                 display_printer_data(info[i].value_name,
2921                                      info[i].type,
2922                                      info[i].data->data,
2923                                      info[i].data->length);
2924         }
2925
2926  done:
2927         if (is_valid_policy_hnd(&hnd)) {
2928                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2929         }
2930
2931         return result;
2932 }
2933
2934 /****************************************************************************
2935 ****************************************************************************/
2936
2937 static WERROR cmd_spoolss_enum_printerkey(struct rpc_pipe_client *cli,
2938                                           TALLOC_CTX *mem_ctx, int argc,
2939                                           const char **argv)
2940 {
2941         WERROR result;
2942         const char *printername;
2943         const char *keyname = NULL;
2944         struct policy_handle hnd;
2945         const char **key_buffer = NULL;
2946         int i;
2947         uint32_t offered = 0;
2948