39c581c65ca0e8dc1a97b804851f2a0cb739a92d
[idra/samba.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         uint32_t access_mask = PRINTER_ALL_ACCESS;
109
110         if (argc < 2) {
111                 printf("Usage: %s <printername> [access_mask]\n", argv[0]);
112                 return WERR_OK;
113         }
114
115         if (argc >= 3) {
116                 sscanf(argv[2], "%x", &access_mask);
117         }
118
119         /* Open the printer handle */
120
121         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
122                                                argv[1],
123                                                access_mask,
124                                                &hnd);
125         if (W_ERROR_IS_OK(werror)) {
126                 printf("Printer %s opened successfully\n", argv[1]);
127                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, &werror);
128
129                 if (!W_ERROR_IS_OK(werror)) {
130                         printf("Error closing printer handle! (%s)\n",
131                                 get_dos_error_msg(werror));
132                 }
133         }
134
135         return werror;
136 }
137
138
139 /****************************************************************************
140 ****************************************************************************/
141
142 static void display_print_info0(struct spoolss_PrinterInfo0 *r)
143 {
144         if (!r)
145                 return;
146
147         printf("\tprintername:[%s]\n", r->printername);
148         printf("\tservername:[%s]\n", r->servername);
149         printf("\tcjobs:[0x%x]\n", r->cjobs);
150         printf("\ttotal_jobs:[0x%x]\n", r->total_jobs);
151         printf("\ttotal_bytes:[0x%x]\n", r->total_bytes);
152         printf("\t:date: [%d]-[%d]-[%d] (%d)\n", r->time.year, r->time.month,
153                r->time.day, r->time.day_of_week);
154         printf("\t:time: [%d]-[%d]-[%d]-[%d]\n", r->time.hour, r->time.minute,
155                r->time.second, r->time.millisecond);
156
157         printf("\tglobal_counter:[0x%x]\n", r->global_counter);
158         printf("\ttotal_pages:[0x%x]\n", r->total_pages);
159
160         printf("\tversion:[0x%x]\n", r->version);
161         printf("\tfree_build:[0x%x]\n", r->free_build);
162         printf("\tspooling:[0x%x]\n", r->spooling);
163         printf("\tmax_spooling:[0x%x]\n", r->max_spooling);
164         printf("\tsession_counter:[0x%x]\n", r->session_counter);
165         printf("\tnum_error_out_of_paper:[0x%x]\n", r->num_error_out_of_paper);
166         printf("\tnum_error_not_ready:[0x%x]\n", r->num_error_not_ready);
167         printf("\tjob_error:[0x%x]\n", r->job_error);
168         printf("\tnumber_of_processors:[0x%x]\n", r->number_of_processors);
169         printf("\tprocessor_type:[0x%x]\n", r->processor_type);
170         printf("\thigh_part_total_bytes:[0x%x]\n", r->high_part_total_bytes);
171         printf("\tchange_id:[0x%x]\n", r->change_id);
172         printf("\tlast_error: %s\n", win_errstr(r->last_error));
173         printf("\tstatus:[0x%x]\n", r->status);
174         printf("\tenumerate_network_printers:[0x%x]\n", r->enumerate_network_printers);
175         printf("\tc_setprinter:[0x%x]\n", r->c_setprinter);
176         printf("\tprocessor_architecture:[0x%x]\n", r->processor_architecture);
177         printf("\tprocessor_level:[0x%x]\n", r->processor_level);
178         printf("\tref_ic:[0x%x]\n", r->ref_ic);
179         printf("\treserved2:[0x%x]\n", r->reserved2);
180         printf("\treserved3:[0x%x]\n", r->reserved3);
181
182         printf("\n");
183 }
184
185 /****************************************************************************
186 ****************************************************************************/
187
188 static void display_print_info1(struct spoolss_PrinterInfo1 *r)
189 {
190         printf("\tflags:[0x%x]\n", r->flags);
191         printf("\tname:[%s]\n", r->name);
192         printf("\tdescription:[%s]\n", r->description);
193         printf("\tcomment:[%s]\n", r->comment);
194
195         printf("\n");
196 }
197
198 /****************************************************************************
199 ****************************************************************************/
200
201 static void display_print_info2(struct spoolss_PrinterInfo2 *r)
202 {
203         printf("\tservername:[%s]\n", r->servername);
204         printf("\tprintername:[%s]\n", r->printername);
205         printf("\tsharename:[%s]\n", r->sharename);
206         printf("\tportname:[%s]\n", r->portname);
207         printf("\tdrivername:[%s]\n", r->drivername);
208         printf("\tcomment:[%s]\n", r->comment);
209         printf("\tlocation:[%s]\n", r->location);
210         printf("\tsepfile:[%s]\n", r->sepfile);
211         printf("\tprintprocessor:[%s]\n", r->printprocessor);
212         printf("\tdatatype:[%s]\n", r->datatype);
213         printf("\tparameters:[%s]\n", r->parameters);
214         printf("\tattributes:[0x%x]\n", r->attributes);
215         printf("\tpriority:[0x%x]\n", r->priority);
216         printf("\tdefaultpriority:[0x%x]\n", r->defaultpriority);
217         printf("\tstarttime:[0x%x]\n", r->starttime);
218         printf("\tuntiltime:[0x%x]\n", r->untiltime);
219         printf("\tstatus:[0x%x]\n", r->status);
220         printf("\tcjobs:[0x%x]\n", r->cjobs);
221         printf("\taverageppm:[0x%x]\n", r->averageppm);
222
223         if (r->secdesc)
224                 display_sec_desc(r->secdesc);
225
226         printf("\n");
227 }
228
229 /****************************************************************************
230 ****************************************************************************/
231
232 static void display_print_info3(struct spoolss_PrinterInfo3 *r)
233 {
234         display_sec_desc(r->secdesc);
235
236         printf("\n");
237 }
238
239 /****************************************************************************
240 ****************************************************************************/
241
242 static void display_print_info4(struct spoolss_PrinterInfo4 *r)
243 {
244         printf("\tservername:[%s]\n", r->servername);
245         printf("\tprintername:[%s]\n", r->printername);
246         printf("\tattributes:[0x%x]\n", r->attributes);
247         printf("\n");
248 }
249
250 /****************************************************************************
251 ****************************************************************************/
252
253 static void display_print_info5(struct spoolss_PrinterInfo5 *r)
254 {
255         printf("\tprintername:[%s]\n", r->printername);
256         printf("\tportname:[%s]\n", r->portname);
257         printf("\tattributes:[0x%x]\n", r->attributes);
258         printf("\tdevice_not_selected_timeout:[0x%x]\n", r->device_not_selected_timeout);
259         printf("\ttransmission_retry_timeout:[0x%x]\n", r->transmission_retry_timeout);
260         printf("\n");
261 }
262
263 /****************************************************************************
264 ****************************************************************************/
265
266 static void display_print_info6(struct spoolss_PrinterInfo6 *r)
267 {
268         printf("\tstatus:[0x%x]\n", r->status);
269         printf("\n");
270 }
271
272 /****************************************************************************
273 ****************************************************************************/
274
275 static void display_print_info7(struct spoolss_PrinterInfo7 *r)
276 {
277         printf("\tguid:[%s]\n", r->guid);
278         printf("\taction:[0x%x]\n", r->action);
279         printf("\n");
280 }
281
282 /****************************************************************************
283 ****************************************************************************/
284
285 static WERROR cmd_spoolss_enum_printers(struct rpc_pipe_client *cli,
286                                         TALLOC_CTX *mem_ctx,
287                                         int argc, const char **argv)
288 {
289         WERROR                  result;
290         uint32_t                level = 1;
291         union spoolss_PrinterInfo *info;
292         uint32_t                i, count;
293         const char *name;
294         uint32_t flags = PRINTER_ENUM_LOCAL;
295
296         if (argc > 4) {
297                 printf("Usage: %s [level] [name] [flags]\n", argv[0]);
298                 return WERR_OK;
299         }
300
301         if (argc >= 2) {
302                 level = atoi(argv[1]);
303         }
304
305         if (argc >= 3) {
306                 name = argv[2];
307         } else {
308                 name = cli->srv_name_slash;
309         }
310
311         if (argc == 4) {
312                 flags = atoi(argv[3]);
313         }
314
315         result = rpccli_spoolss_enumprinters(cli, mem_ctx,
316                                              flags,
317                                              name,
318                                              level,
319                                              0,
320                                              &count,
321                                              &info);
322         if (W_ERROR_IS_OK(result)) {
323
324                 if (!count) {
325                         printf ("No printers returned.\n");
326                         goto done;
327                 }
328
329                 for (i = 0; i < count; i++) {
330                         switch (level) {
331                         case 0:
332                                 display_print_info0(&info[i].info0);
333                                 break;
334                         case 1:
335                                 display_print_info1(&info[i].info1);
336                                 break;
337                         case 2:
338                                 display_print_info2(&info[i].info2);
339                                 break;
340                         case 3:
341                                 display_print_info3(&info[i].info3);
342                                 break;
343                         case 4:
344                                 display_print_info4(&info[i].info4);
345                                 break;
346                         case 5:
347                                 display_print_info5(&info[i].info5);
348                                 break;
349                         case 6:
350                                 display_print_info6(&info[i].info6);
351                                 break;
352                         default:
353                                 printf("unknown info level %d\n", level);
354                                 goto done;
355                         }
356                 }
357         }
358  done:
359
360         return result;
361 }
362
363 /****************************************************************************
364 ****************************************************************************/
365
366 static void display_port_info_1(struct spoolss_PortInfo1 *r)
367 {
368         printf("\tPort Name:\t[%s]\n", r->port_name);
369 }
370
371 /****************************************************************************
372 ****************************************************************************/
373
374 static void display_port_info_2(struct spoolss_PortInfo2 *r)
375 {
376         printf("\tPort Name:\t[%s]\n", r->port_name);
377         printf("\tMonitor Name:\t[%s]\n", r->monitor_name);
378         printf("\tDescription:\t[%s]\n", r->description);
379         printf("\tPort Type:\t" );
380         if (r->port_type) {
381                 int comma = 0; /* hack */
382                 printf( "[" );
383                 if (r->port_type & SPOOLSS_PORT_TYPE_READ) {
384                         printf( "Read" );
385                         comma = 1;
386                 }
387                 if (r->port_type & SPOOLSS_PORT_TYPE_WRITE) {
388                         printf( "%sWrite", comma ? ", " : "" );
389                         comma = 1;
390                 }
391                 /* These two have slightly different interpretations
392                  on 95/98/ME but I'm disregarding that for now */
393                 if (r->port_type & SPOOLSS_PORT_TYPE_REDIRECTED) {
394                         printf( "%sRedirected", comma ? ", " : "" );
395                         comma = 1;
396                 }
397                 if (r->port_type & SPOOLSS_PORT_TYPE_NET_ATTACHED) {
398                         printf( "%sNet-Attached", comma ? ", " : "" );
399                 }
400                 printf( "]\n" );
401         } else {
402                 printf( "[Unset]\n" );
403         }
404         printf("\tReserved:\t[%d]\n", r->reserved);
405         printf("\n");
406 }
407
408 /****************************************************************************
409 ****************************************************************************/
410
411 static WERROR cmd_spoolss_enum_ports(struct rpc_pipe_client *cli,
412                                        TALLOC_CTX *mem_ctx, int argc,
413                                        const char **argv)
414 {
415         WERROR                  result;
416         uint32_t                level = 1;
417         uint32_t                count;
418         union spoolss_PortInfo *info;
419
420         if (argc > 2) {
421                 printf("Usage: %s [level]\n", argv[0]);
422                 return WERR_OK;
423         }
424
425         if (argc == 2) {
426                 level = atoi(argv[1]);
427         }
428
429         /* Enumerate ports */
430
431         result = rpccli_spoolss_enumports(cli, mem_ctx,
432                                           cli->srv_name_slash,
433                                           level,
434                                           0,
435                                           &count,
436                                           &info);
437         if (W_ERROR_IS_OK(result)) {
438                 int i;
439
440                 for (i = 0; i < count; i++) {
441                         switch (level) {
442                         case 1:
443                                 display_port_info_1(&info[i].info1);
444                                 break;
445                         case 2:
446                                 display_port_info_2(&info[i].info2);
447                                 break;
448                         default:
449                                 printf("unknown info level %d\n", level);
450                                 break;
451                         }
452                 }
453         }
454
455         return result;
456 }
457
458 /****************************************************************************
459 ****************************************************************************/
460
461 static WERROR cmd_spoolss_setprinter(struct rpc_pipe_client *cli,
462                                        TALLOC_CTX *mem_ctx,
463                                        int argc, const char **argv)
464 {
465         struct policy_handle pol;
466         WERROR          result;
467         NTSTATUS        status;
468         uint32_t        info_level = 2;
469         union spoolss_PrinterInfo info;
470         struct spoolss_SetPrinterInfoCtr info_ctr;
471         struct spoolss_SetPrinterInfo2 info2;
472         const char      *printername, *comment = NULL;
473         struct spoolss_DevmodeContainer devmode_ctr;
474         struct sec_desc_buf secdesc_ctr;
475
476         if (argc == 1 || argc > 3) {
477                 printf("Usage: %s printername comment\n", argv[0]);
478
479                 return WERR_OK;
480         }
481
482         /* Open a printer handle */
483         if (argc == 3) {
484                 comment = argv[2];
485         }
486
487         ZERO_STRUCT(devmode_ctr);
488         ZERO_STRUCT(secdesc_ctr);
489
490         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
491
492         /* get a printer handle */
493         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
494                                                printername,
495                                                PRINTER_ALL_ACCESS,
496                                                &pol);
497         if (!W_ERROR_IS_OK(result))
498                 goto done;
499
500         /* Get printer info */
501         result = rpccli_spoolss_getprinter(cli, mem_ctx,
502                                            &pol,
503                                            info_level,
504                                            0,
505                                            &info);
506         if (!W_ERROR_IS_OK(result))
507                 goto done;
508
509
510         /* Modify the comment. */
511         spoolss_printerinfo2_to_setprinterinfo2(&info.info2, &info2);
512         info2.comment = comment;
513
514         info_ctr.level = 2;
515         info_ctr.info.info2 = &info2;
516
517         status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
518                                            &pol,
519                                            &info_ctr,
520                                            &devmode_ctr,
521                                            &secdesc_ctr,
522                                            0, /* command */
523                                            &result);
524         if (W_ERROR_IS_OK(result))
525                 printf("Success in setting comment.\n");
526
527  done:
528         if (is_valid_policy_hnd(&pol))
529                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
530
531         return result;
532 }
533
534 /****************************************************************************
535 ****************************************************************************/
536
537 static WERROR cmd_spoolss_setprintername(struct rpc_pipe_client *cli,
538                                        TALLOC_CTX *mem_ctx,
539                                        int argc, const char **argv)
540 {
541         struct policy_handle pol;
542         WERROR          result;
543         NTSTATUS        status;
544         uint32_t        info_level = 2;
545         union spoolss_PrinterInfo info;
546         const char      *printername,
547                         *new_printername = NULL;
548         struct spoolss_SetPrinterInfoCtr info_ctr;
549         struct spoolss_SetPrinterInfo2 info2;
550         struct spoolss_DevmodeContainer devmode_ctr;
551         struct sec_desc_buf secdesc_ctr;
552
553         ZERO_STRUCT(devmode_ctr);
554         ZERO_STRUCT(secdesc_ctr);
555
556         if (argc == 1 || argc > 3) {
557                 printf("Usage: %s printername new_printername\n", argv[0]);
558
559                 return WERR_OK;
560         }
561
562         /* Open a printer handle */
563         if (argc == 3) {
564                 new_printername = argv[2];
565         }
566
567         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
568
569         /* get a printer handle */
570         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
571                                                printername,
572                                                PRINTER_ALL_ACCESS,
573                                                &pol);
574         if (!W_ERROR_IS_OK(result))
575                 goto done;
576
577         /* Get printer info */
578         result = rpccli_spoolss_getprinter(cli, mem_ctx,
579                                            &pol,
580                                            info_level,
581                                            0,
582                                            &info);
583         if (!W_ERROR_IS_OK(result))
584                 goto done;
585
586         /* Modify the printername. */
587         spoolss_printerinfo2_to_setprinterinfo2(&info.info2, &info2);
588         info2.printername = new_printername;
589
590         info_ctr.level = 2;
591         info_ctr.info.info2 = &info2;
592
593         status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
594                                            &pol,
595                                            &info_ctr,
596                                            &devmode_ctr,
597                                            &secdesc_ctr,
598                                            0, /* command */
599                                            &result);
600         if (W_ERROR_IS_OK(result))
601                 printf("Success in setting printername.\n");
602
603  done:
604         if (is_valid_policy_hnd(&pol))
605                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
606
607         return result;
608 }
609
610 /****************************************************************************
611 ****************************************************************************/
612
613 static WERROR cmd_spoolss_getprinter(struct rpc_pipe_client *cli,
614                                        TALLOC_CTX *mem_ctx,
615                                        int argc, const char **argv)
616 {
617         struct policy_handle pol;
618         WERROR          result;
619         uint32_t        level = 1;
620         const char      *printername;
621         union spoolss_PrinterInfo info;
622
623         if (argc == 1 || argc > 3) {
624                 printf("Usage: %s <printername> [level]\n", argv[0]);
625                 return WERR_OK;
626         }
627
628         /* Open a printer handle */
629         if (argc == 3) {
630                 level = atoi(argv[2]);
631         }
632
633         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
634
635         /* get a printer handle */
636
637         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
638                                                printername,
639                                                SEC_FLAG_MAXIMUM_ALLOWED,
640                                                &pol);
641         if (!W_ERROR_IS_OK(result)) {
642                 goto done;
643         }
644
645         /* Get printer info */
646
647         result = rpccli_spoolss_getprinter(cli, mem_ctx,
648                                            &pol,
649                                            level,
650                                            0,
651                                            &info);
652         if (!W_ERROR_IS_OK(result)) {
653                 goto done;
654         }
655
656         /* Display printer info */
657         switch (level) {
658         case 0:
659                 display_print_info0(&info.info0);
660                 break;
661         case 1:
662                 display_print_info1(&info.info1);
663                 break;
664         case 2:
665                 display_print_info2(&info.info2);
666                 break;
667         case 3:
668                 display_print_info3(&info.info3);
669                 break;
670         case 4:
671                 display_print_info4(&info.info4);
672                 break;
673         case 5:
674                 display_print_info5(&info.info5);
675                 break;
676         case 6:
677                 display_print_info6(&info.info6);
678                 break;
679         case 7:
680                 display_print_info7(&info.info7);
681                 break;
682         default:
683                 printf("unknown info level %d\n", level);
684                 break;
685         }
686  done:
687         if (is_valid_policy_hnd(&pol)) {
688                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
689         }
690
691         return result;
692 }
693
694 /****************************************************************************
695 ****************************************************************************/
696
697 static void display_reg_value(struct regval_blob *value)
698 {
699         const char *text = NULL;
700         DATA_BLOB blob;
701
702         switch(regval_type(value)) {
703         case REG_DWORD:
704                 printf("%s: REG_DWORD: 0x%08x\n", regval_name(value),
705                        *((uint32_t *) regval_data_p(value)));
706                 break;
707         case REG_SZ:
708                 blob = data_blob_const(regval_data_p(value), regval_size(value));
709                 pull_reg_sz(talloc_tos(), &blob, &text);
710                 printf("%s: REG_SZ: %s\n", regval_name(value), text ? text : "");
711                 break;
712         case REG_BINARY: {
713                 char *hex = hex_encode_talloc(NULL, regval_data_p(value), regval_size(value));
714                 size_t i, len;
715                 printf("%s: REG_BINARY:", regval_name(value));
716                 len = strlen(hex);
717                 for (i=0; i<len; i++) {
718                         if (hex[i] == '\0') {
719                                 break;
720                         }
721                         if (i%40 == 0) {
722                                 putchar('\n');
723                         }
724                         putchar(hex[i]);
725                 }
726                 TALLOC_FREE(hex);
727                 putchar('\n');
728                 break;
729         }
730         case REG_MULTI_SZ: {
731                 uint32_t i;
732                 const char **values;
733                 blob = data_blob_const(regval_data_p(value), regval_size(value));
734
735                 if (!pull_reg_multi_sz(NULL, &blob, &values)) {
736                         d_printf("pull_reg_multi_sz failed\n");
737                         break;
738                 }
739
740                 printf("%s: REG_MULTI_SZ: \n", regval_name(value));
741                 for (i=0; values[i] != NULL; i++) {
742                         d_printf("%s\n", values[i]);
743                 }
744                 TALLOC_FREE(values);
745                 break;
746         }
747         default:
748                 printf("%s: unknown type %d\n", regval_name(value), regval_type(value));
749         }
750
751 }
752
753 /****************************************************************************
754 ****************************************************************************/
755
756 static void display_printer_data(const char *v,
757                                  enum winreg_Type type,
758                                  uint8_t *data,
759                                  uint32_t length)
760 {
761         int i;
762         union spoolss_PrinterData r;
763         DATA_BLOB blob = data_blob_const(data, length);
764         WERROR result;
765
766         result = pull_spoolss_PrinterData(talloc_tos(), &blob, &r, type);
767         if (!W_ERROR_IS_OK(result)) {
768                 return;
769         }
770
771         switch (type) {
772         case REG_DWORD:
773                 printf("%s: REG_DWORD: 0x%08x\n", v, r.value);
774                 break;
775         case REG_SZ:
776                 printf("%s: REG_SZ: %s\n", v, r.string);
777                 break;
778         case REG_BINARY: {
779                 char *hex = hex_encode_talloc(NULL,
780                         r.binary.data, r.binary.length);
781                 size_t len;
782                 printf("%s: REG_BINARY:", v);
783                 len = strlen(hex);
784                 for (i=0; i<len; i++) {
785                         if (hex[i] == '\0') {
786                                 break;
787                         }
788                         if (i%40 == 0) {
789                                 putchar('\n');
790                         }
791                         putchar(hex[i]);
792                 }
793                 TALLOC_FREE(hex);
794                 putchar('\n');
795                 break;
796         }
797         case REG_MULTI_SZ:
798                 printf("%s: REG_MULTI_SZ: ", v);
799                 for (i=0; r.string_array[i] != NULL; i++) {
800                         printf("%s ", r.string_array[i]);
801                 }
802                 printf("\n");
803                 break;
804         default:
805                 printf("%s: unknown type 0x%02x:\n", v, type);
806                 break;
807         }
808 }
809
810 /****************************************************************************
811 ****************************************************************************/
812
813 static WERROR cmd_spoolss_getprinterdata(struct rpc_pipe_client *cli,
814                                            TALLOC_CTX *mem_ctx,
815                                            int argc, const char **argv)
816 {
817         struct policy_handle pol;
818         WERROR          result;
819         fstring         printername;
820         const char *valuename;
821         enum winreg_Type type;
822         uint8_t *data;
823         uint32_t needed;
824
825         if (argc != 3) {
826                 printf("Usage: %s <printername> <valuename>\n", argv[0]);
827                 printf("<printername> of . queries print server\n");
828                 return WERR_OK;
829         }
830         valuename = argv[2];
831
832         /* Open a printer handle */
833
834         if (strncmp(argv[1], ".", sizeof(".")) == 0)
835                 fstrcpy(printername, cli->srv_name_slash);
836         else
837                 slprintf(printername, sizeof(printername)-1, "%s\\%s",
838                           cli->srv_name_slash, argv[1]);
839
840         /* get a printer handle */
841
842         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
843                                                printername,
844                                                SEC_FLAG_MAXIMUM_ALLOWED,
845                                                &pol);
846         if (!W_ERROR_IS_OK(result))
847                 goto done;
848
849         /* Get printer info */
850
851         result = rpccli_spoolss_getprinterdata(cli, mem_ctx,
852                                                &pol,
853                                                valuename,
854                                                0,
855                                                &type,
856                                                &needed,
857                                                &data);
858         if (!W_ERROR_IS_OK(result))
859                 goto done;
860
861         /* Display printer data */
862
863         display_printer_data(valuename, type, data, needed);
864
865  done:
866         if (is_valid_policy_hnd(&pol))
867                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
868
869         return result;
870 }
871
872 /****************************************************************************
873 ****************************************************************************/
874
875 static WERROR cmd_spoolss_getprinterdataex(struct rpc_pipe_client *cli,
876                                              TALLOC_CTX *mem_ctx,
877                                              int argc, const char **argv)
878 {
879         struct policy_handle pol;
880         WERROR          result;
881         NTSTATUS        status;
882         fstring         printername;
883         const char *valuename, *keyname;
884
885         enum winreg_Type type;
886         uint8_t *data = NULL;
887         uint32_t offered = 0;
888         uint32_t needed;
889
890         if (argc != 4) {
891                 printf("Usage: %s <printername> <keyname> <valuename>\n",
892                        argv[0]);
893                 printf("<printername> of . queries print server\n");
894                 return WERR_OK;
895         }
896         valuename = argv[3];
897         keyname = argv[2];
898
899         /* Open a printer handle */
900
901         if (strncmp(argv[1], ".", sizeof(".")) == 0)
902                 fstrcpy(printername, cli->srv_name_slash);
903         else
904                 slprintf(printername, sizeof(printername)-1, "%s\\%s",
905                           cli->srv_name_slash, argv[1]);
906
907         /* get a printer handle */
908
909         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
910                                                printername,
911                                                SEC_FLAG_MAXIMUM_ALLOWED,
912                                                &pol);
913         if (!W_ERROR_IS_OK(result))
914                 goto done;
915
916         /* Get printer info */
917
918         data = talloc_zero_array(mem_ctx, uint8_t, offered);
919         if (!data) {
920                 goto done;
921         }
922
923         status = rpccli_spoolss_GetPrinterDataEx(cli, mem_ctx,
924                                                  &pol,
925                                                  keyname,
926                                                  valuename,
927                                                  &type,
928                                                  data,
929                                                  offered,
930                                                  &needed,
931                                                  &result);
932         if (W_ERROR_EQUAL(result, WERR_MORE_DATA)) {
933                 offered = needed;
934                 data = talloc_zero_array(mem_ctx, uint8_t, offered);
935                 if (!data) {
936                         goto done;
937                 }
938                 status = rpccli_spoolss_GetPrinterDataEx(cli, mem_ctx,
939                                                          &pol,
940                                                          keyname,
941                                                          valuename,
942                                                          &type,
943                                                          data,
944                                                          offered,
945                                                          &needed,
946                                                          &result);
947         }
948
949         if (!NT_STATUS_IS_OK(status)) {
950                 goto done;
951         }
952
953         if (!W_ERROR_IS_OK(result))
954                 goto done;
955
956         /* Display printer data */
957
958         display_printer_data(valuename, type, data, needed);
959
960
961  done:
962         if (is_valid_policy_hnd(&pol))
963                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
964
965         return result;
966 }
967
968 /****************************************************************************
969 ****************************************************************************/
970
971 static void display_print_driver1(struct spoolss_DriverInfo1 *r)
972 {
973         if (!r) {
974                 return;
975         }
976
977         printf("Printer Driver Info 1:\n");
978         printf("\tDriver Name: [%s]\n", r->driver_name);
979         printf("\n");
980 }
981
982 /****************************************************************************
983 ****************************************************************************/
984
985 static void display_print_driver2(struct spoolss_DriverInfo2 *r)
986 {
987         if (!r) {
988                 return;
989         }
990
991         printf("Printer Driver Info 2:\n");
992         printf("\tVersion: [%x]\n", r->version);
993         printf("\tDriver Name: [%s]\n", r->driver_name);
994         printf("\tArchitecture: [%s]\n", r->architecture);
995         printf("\tDriver Path: [%s]\n", r->driver_path);
996         printf("\tDatafile: [%s]\n", r->data_file);
997         printf("\tConfigfile: [%s]\n", r->config_file);
998         printf("\n");
999 }
1000
1001 /****************************************************************************
1002 ****************************************************************************/
1003
1004 static void display_print_driver3(struct spoolss_DriverInfo3 *r)
1005 {
1006         int i;
1007
1008         if (!r) {
1009                 return;
1010         }
1011
1012         printf("Printer Driver Info 3:\n");
1013         printf("\tVersion: [%x]\n", r->version);
1014         printf("\tDriver Name: [%s]\n", r->driver_name);
1015         printf("\tArchitecture: [%s]\n", r->architecture);
1016         printf("\tDriver Path: [%s]\n", r->driver_path);
1017         printf("\tDatafile: [%s]\n", r->data_file);
1018         printf("\tConfigfile: [%s]\n", r->config_file);
1019         printf("\tHelpfile: [%s]\n", r->help_file);
1020
1021         for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1022                 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1023         }
1024
1025         printf("\tMonitorname: [%s]\n", r->monitor_name);
1026         printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1027         printf("\n");
1028 }
1029
1030 /****************************************************************************
1031 ****************************************************************************/
1032
1033 static void display_print_driver4(struct spoolss_DriverInfo4 *r)
1034 {
1035         int i;
1036
1037         if (!r) {
1038                 return;
1039         }
1040
1041         printf("Printer Driver Info 4:\n");
1042         printf("\tVersion: [%x]\n", r->version);
1043         printf("\tDriver Name: [%s]\n", r->driver_name);
1044         printf("\tArchitecture: [%s]\n", r->architecture);
1045         printf("\tDriver Path: [%s]\n", r->driver_path);
1046         printf("\tDatafile: [%s]\n", r->data_file);
1047         printf("\tConfigfile: [%s]\n", r->config_file);
1048         printf("\tHelpfile: [%s]\n", r->help_file);
1049
1050         for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1051                 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1052         }
1053
1054         printf("\tMonitorname: [%s]\n", r->monitor_name);
1055         printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1056
1057         for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) {
1058                 printf("\tPrevious Names: [%s]\n", r->previous_names[i]);
1059         }
1060         printf("\n");
1061 }
1062
1063 /****************************************************************************
1064 ****************************************************************************/
1065
1066 static void display_print_driver5(struct spoolss_DriverInfo5 *r)
1067 {
1068         if (!r) {
1069                 return;
1070         }
1071
1072         printf("Printer Driver Info 5:\n");
1073         printf("\tVersion: [%x]\n", r->version);
1074         printf("\tDriver Name: [%s]\n", r->driver_name);
1075         printf("\tArchitecture: [%s]\n", r->architecture);
1076         printf("\tDriver Path: [%s]\n", r->driver_path);
1077         printf("\tDatafile: [%s]\n", r->data_file);
1078         printf("\tConfigfile: [%s]\n", r->config_file);
1079         printf("\tDriver Attributes: [0x%x]\n", r->driver_attributes);
1080         printf("\tConfig Version: [0x%x]\n", r->config_version);
1081         printf("\tDriver Version: [0x%x]\n", r->driver_version);
1082         printf("\n");
1083 }
1084
1085 /****************************************************************************
1086 ****************************************************************************/
1087
1088 static void display_print_driver6(struct spoolss_DriverInfo6 *r)
1089 {
1090         int i;
1091
1092         if (!r) {
1093                 return;
1094         }
1095
1096         printf("Printer Driver Info 6:\n");
1097         printf("\tVersion: [%x]\n", r->version);
1098         printf("\tDriver Name: [%s]\n", r->driver_name);
1099         printf("\tArchitecture: [%s]\n", r->architecture);
1100         printf("\tDriver Path: [%s]\n", r->driver_path);
1101         printf("\tDatafile: [%s]\n", r->data_file);
1102         printf("\tConfigfile: [%s]\n", r->config_file);
1103         printf("\tHelpfile: [%s]\n", r->help_file);
1104
1105         for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1106                 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1107         }
1108
1109         printf("\tMonitorname: [%s]\n", r->monitor_name);
1110         printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1111
1112         for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) {
1113                 printf("\tPrevious Names: [%s]\n", r->previous_names[i]);
1114         }
1115
1116         printf("\tDriver Date: [%s]\n", nt_time_string(talloc_tos(), r->driver_date));
1117         printf("\tDriver Version: [0x%016llx]\n", (long long unsigned int)r->driver_version);
1118         printf("\tManufacturer Name: [%s]\n", r->manufacturer_name);
1119         printf("\tManufacturer Url: [%s]\n", r->manufacturer_url);
1120         printf("\tHardware ID: [%s]\n", r->hardware_id);
1121         printf("\tProvider: [%s]\n", r->provider);
1122
1123         printf("\n");
1124 }
1125
1126 /****************************************************************************
1127 ****************************************************************************/
1128
1129 static void display_print_driver8(struct spoolss_DriverInfo8 *r)
1130 {
1131         int i;
1132
1133         if (!r) {
1134                 return;
1135         }
1136
1137         printf("Printer Driver Info 8:\n");
1138         printf("\tVersion: [%x]\n", r->version);
1139         printf("\tDriver Name: [%s]\n", r->driver_name);
1140         printf("\tArchitecture: [%s]\n", r->architecture);
1141         printf("\tDriver Path: [%s]\n", r->driver_path);
1142         printf("\tDatafile: [%s]\n", r->data_file);
1143         printf("\tConfigfile: [%s]\n", r->config_file);
1144         printf("\tHelpfile: [%s]\n", r->help_file);
1145         printf("\tMonitorname: [%s]\n", r->monitor_name);
1146         printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1147
1148         for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1149                 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1150         }
1151
1152         for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) {
1153                 printf("\tPrevious Names: [%s]\n", r->previous_names[i]);
1154         }
1155
1156         printf("\tDriver Date: [%s]\n", nt_time_string(talloc_tos(), r->driver_date));
1157         printf("\tDriver Version: [0x%016llx]\n", (long long unsigned int)r->driver_version);
1158         printf("\tManufacturer Name: [%s]\n", r->manufacturer_name);
1159         printf("\tManufacturer Url: [%s]\n", r->manufacturer_url);
1160         printf("\tHardware ID: [%s]\n", r->hardware_id);
1161         printf("\tProvider: [%s]\n", r->provider);
1162         printf("\tPrint Processor: [%s]\n", r->print_processor);
1163         printf("\tVendor Setup: [%s]\n", r->vendor_setup);
1164         for (i=0; r->color_profiles && r->color_profiles[i] != NULL; i++) {
1165                 printf("\tColor Profiles: [%s]\n", r->color_profiles[i]);
1166         }
1167         printf("\tInf Path: [%s]\n", r->inf_path);
1168         printf("\tPrinter Driver Attributes: [0x%x]\n", r->printer_driver_attributes);
1169         for (i=0; r->core_driver_dependencies && r->core_driver_dependencies[i] != NULL; i++) {
1170                 printf("\tCore Driver Dependencies: [%s]\n", r->core_driver_dependencies[i]);
1171         }
1172         printf("\tMin Driver Inbox Driver Version Date: [%s]\n", nt_time_string(talloc_tos(), r->min_inbox_driver_ver_date));
1173         printf("\tMin Driver Inbox Driver Version Version: [0x%016llx]\n",
1174                 (long long unsigned int)r->min_inbox_driver_ver_version);
1175
1176         printf("\n");
1177 }
1178
1179 /****************************************************************************
1180 ****************************************************************************/
1181
1182 static WERROR cmd_spoolss_getdriver(struct rpc_pipe_client *cli,
1183                                     TALLOC_CTX *mem_ctx,
1184                                     int argc, const char **argv)
1185 {
1186         struct policy_handle pol;
1187         WERROR          werror;
1188         uint32_t        level = 3;
1189         const char      *printername;
1190         uint32_t        i;
1191         bool            success = false;
1192         union spoolss_DriverInfo info;
1193         uint32_t server_major_version;
1194         uint32_t server_minor_version;
1195
1196         if ((argc == 1) || (argc > 3)) {
1197                 printf("Usage: %s <printername> [level]\n", argv[0]);
1198                 return WERR_OK;
1199         }
1200
1201         /* get the arguments need to open the printer handle */
1202
1203         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1204
1205         if (argc == 3) {
1206                 level = atoi(argv[2]);
1207         }
1208
1209         /* Open a printer handle */
1210
1211         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1212                                                printername,
1213                                                PRINTER_ACCESS_USE,
1214                                                &pol);
1215         if (!W_ERROR_IS_OK(werror)) {
1216                 printf("Error opening printer handle for %s!\n", printername);
1217                 return werror;
1218         }
1219
1220         /* loop through and print driver info level for each architecture */
1221
1222         for (i=0; archi_table[i].long_archi!=NULL; i++) {
1223
1224                 werror = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1225                                                           &pol,
1226                                                           archi_table[i].long_archi,
1227                                                           level,
1228                                                           0, /* offered */
1229                                                           archi_table[i].version,
1230                                                           2,
1231                                                           &info,
1232                                                           &server_major_version,
1233                                                           &server_minor_version);
1234                 if (!W_ERROR_IS_OK(werror)) {
1235                         continue;
1236                 }
1237
1238                 /* need at least one success */
1239
1240                 success = true;
1241
1242                 printf("\n[%s]\n", archi_table[i].long_archi);
1243
1244                 switch (level) {
1245                 case 1:
1246                         display_print_driver1(&info.info1);
1247                         break;
1248                 case 2:
1249                         display_print_driver2(&info.info2);
1250                         break;
1251                 case 3:
1252                         display_print_driver3(&info.info3);
1253                         break;
1254                 case 4:
1255                         display_print_driver4(&info.info4);
1256                         break;
1257                 case 5:
1258                         display_print_driver5(&info.info5);
1259                         break;
1260                 case 6:
1261                         display_print_driver6(&info.info6);
1262                         break;
1263                 case 8:
1264                         display_print_driver8(&info.info8);
1265                         break;
1266                 default:
1267                         printf("unknown info level %d\n", level);
1268                         break;
1269                 }
1270         }
1271
1272         /* Cleanup */
1273
1274         if (is_valid_policy_hnd(&pol)) {
1275                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
1276         }
1277
1278         if (success) {
1279                 werror = WERR_OK;
1280         }
1281
1282         return werror;
1283 }
1284
1285 /****************************************************************************
1286 ****************************************************************************/
1287
1288 static WERROR enum_driver_by_architecture(struct rpc_pipe_client *cli,
1289                                           TALLOC_CTX *mem_ctx,
1290                                           const char *architecture,
1291                                           uint32_t level)
1292 {
1293         WERROR werror;
1294         uint32_t count = 0;
1295         union spoolss_DriverInfo *info = NULL;
1296         uint32_t j;
1297
1298         werror = rpccli_spoolss_enumprinterdrivers(cli, mem_ctx,
1299                                                    cli->srv_name_slash,
1300                                                    architecture,
1301                                                    level,
1302                                                    0,
1303                                                    &count,
1304                                                    &info);
1305
1306         if (W_ERROR_EQUAL(werror, WERR_INVALID_ENVIRONMENT)) {
1307                 printf("Server does not support environment [%s]\n",
1308                         architecture);
1309                 return WERR_OK;
1310         }
1311
1312         if (count == 0) {
1313                 return WERR_OK;
1314         }
1315
1316         if (!W_ERROR_IS_OK(werror)) {
1317                 printf("Error getting driver for environment [%s] - %s\n",
1318                         architecture, win_errstr(werror));
1319                 return werror;
1320         }
1321
1322         printf("\n[%s]\n", architecture);
1323
1324         switch (level) {
1325         case 1:
1326                 for (j=0; j < count; j++) {
1327                         display_print_driver1(&info[j].info1);
1328                 }
1329                 break;
1330         case 2:
1331                 for (j=0; j < count; j++) {
1332                         display_print_driver2(&info[j].info2);
1333                 }
1334                 break;
1335         case 3:
1336                 for (j=0; j < count; j++) {
1337                         display_print_driver3(&info[j].info3);
1338                 }
1339                 break;
1340         case 4:
1341                 for (j=0; j < count; j++) {
1342                         display_print_driver4(&info[j].info4);
1343                 }
1344                 break;
1345         case 5:
1346                 for (j=0; j < count; j++) {
1347                         display_print_driver5(&info[j].info5);
1348                 }
1349                 break;
1350         case 6:
1351                 for (j=0; j < count; j++) {
1352                         display_print_driver6(&info[j].info6);
1353                 }
1354                 break;
1355         case 8:
1356                 for (j=0; j < count; j++) {
1357                         display_print_driver8(&info[j].info8);
1358                 }
1359                 break;
1360         default:
1361                 printf("unknown info level %d\n", level);
1362                 return WERR_UNKNOWN_LEVEL;
1363         }
1364
1365         return werror;
1366 }
1367
1368 static WERROR cmd_spoolss_enum_drivers(struct rpc_pipe_client *cli,
1369                                          TALLOC_CTX *mem_ctx,
1370                                          int argc, const char **argv)
1371 {
1372         WERROR werror = WERR_OK;
1373         uint32_t        level = 1;
1374         uint32_t        i;
1375         const char *architecture = NULL;
1376
1377         if (argc > 3) {
1378                 printf("Usage: enumdrivers [level] [architecture]\n");
1379                 return WERR_OK;
1380         }
1381
1382         if (argc >= 2) {
1383                 level = atoi(argv[1]);
1384         }
1385
1386         if (argc == 3) {
1387                 architecture = argv[2];
1388         }
1389
1390         if (architecture) {
1391                 return enum_driver_by_architecture(cli, mem_ctx,
1392                                                    architecture,
1393                                                    level);
1394         }
1395
1396         /* loop through and print driver info level for each architecture */
1397         for (i=0; archi_table[i].long_archi!=NULL; i++) {
1398                 /* check to see if we already asked for this architecture string */
1399
1400                 if (i>0 && strequal(archi_table[i].long_archi, archi_table[i-1].long_archi)) {
1401                         continue;
1402                 }
1403
1404                 werror = enum_driver_by_architecture(cli, mem_ctx,
1405                                                      archi_table[i].long_archi,
1406                                                      level);
1407                 if (!W_ERROR_IS_OK(werror)) {
1408                         break;
1409                 }
1410         }
1411
1412         return werror;
1413 }
1414
1415 /****************************************************************************
1416 ****************************************************************************/
1417
1418 static void display_printdriverdir_1(struct spoolss_DriverDirectoryInfo1 *r)
1419 {
1420         printf("\tDirectory Name:[%s]\n", r->directory_name);
1421 }
1422
1423 /****************************************************************************
1424 ****************************************************************************/
1425
1426 static WERROR cmd_spoolss_getdriverdir(struct rpc_pipe_client *cli,
1427                                          TALLOC_CTX *mem_ctx,
1428                                          int argc, const char **argv)
1429 {
1430         WERROR result;
1431         NTSTATUS status;
1432         const char *env = SPOOLSS_ARCHITECTURE_NT_X86;
1433         DATA_BLOB buffer;
1434         uint32_t offered;
1435         union spoolss_DriverDirectoryInfo info;
1436         uint32_t needed;
1437
1438         if (argc > 2) {
1439                 printf("Usage: %s [environment]\n", argv[0]);
1440                 return WERR_OK;
1441         }
1442
1443         /* Get the arguments need to open the printer handle */
1444
1445         if (argc == 2) {
1446                 env = argv[1];
1447         }
1448
1449         /* Get the directory.  Only use Info level 1 */
1450
1451         status = rpccli_spoolss_GetPrinterDriverDirectory(cli, mem_ctx,
1452                                                           cli->srv_name_slash,
1453                                                           env,
1454                                                           1,
1455                                                           NULL, /* buffer */
1456                                                           0, /* offered */
1457                                                           NULL, /* info */
1458                                                           &needed,
1459                                                           &result);
1460         if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) {
1461                 offered = needed;
1462                 buffer = data_blob_talloc_zero(mem_ctx, needed);
1463
1464                 status = rpccli_spoolss_GetPrinterDriverDirectory(cli, mem_ctx,
1465                                                                   cli->srv_name_slash,
1466                                                                   env,
1467                                                                   1,
1468                                                                   &buffer,
1469                                                                   offered,
1470                                                                   &info,
1471                                                                   &needed,
1472                                                                   &result);
1473         }
1474
1475         if (W_ERROR_IS_OK(result)) {
1476                 display_printdriverdir_1(&info.info1);
1477         }
1478
1479         return result;
1480 }
1481
1482 /****************************************************************************
1483 ****************************************************************************/
1484
1485 static void set_drv_info_3_env(TALLOC_CTX *mem_ctx,
1486                                struct spoolss_AddDriverInfo3 *info,
1487                                const char *arch)
1488 {
1489
1490         int i;
1491
1492         for (i=0; archi_table[i].long_archi != NULL; i++)
1493         {
1494                 if (strcmp(arch, archi_table[i].short_archi) == 0)
1495                 {
1496                         info->version = archi_table[i].version;
1497                         info->architecture = talloc_strdup(mem_ctx, archi_table[i].long_archi);
1498                         break;
1499                 }
1500         }
1501
1502         if (archi_table[i].long_archi == NULL)
1503         {
1504                 DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch));
1505         }
1506
1507         return;
1508 }
1509
1510
1511 /**************************************************************************
1512  wrapper for strtok to get the next parameter from a delimited list.
1513  Needed to handle the empty parameter string denoted by "NULL"
1514  *************************************************************************/
1515
1516 static char *get_driver_3_param(TALLOC_CTX *mem_ctx, char *str,
1517                                 const char *delim, const char **dest,
1518                                 char **saveptr)
1519 {
1520         char    *ptr;
1521
1522         /* get the next token */
1523         ptr = strtok_r(str, delim, saveptr);
1524
1525         /* a string of 'NULL' is used to represent an empty
1526            parameter because two consecutive delimiters
1527            will not return an empty string.  See man strtok(3)
1528            for details */
1529         if (ptr && (StrCaseCmp(ptr, "NULL") == 0)) {
1530                 ptr = NULL;
1531         }
1532
1533         if (dest != NULL) {
1534                 *dest = talloc_strdup(mem_ctx, ptr);
1535         }
1536
1537         return ptr;
1538 }
1539
1540 /********************************************************************************
1541  fill in the members of a spoolss_AddDriverInfo3 struct using a character
1542  string in the form of
1543          <Long Printer Name>:<Driver File Name>:<Data File Name>:\
1544              <Config File Name>:<Help File Name>:<Language Monitor Name>:\
1545              <Default Data Type>:<Comma Separated list of Files>
1546  *******************************************************************************/
1547
1548 static bool init_drv_info_3_members(TALLOC_CTX *mem_ctx, struct spoolss_AddDriverInfo3 *r,
1549                                     char *args)
1550 {
1551         char    *str, *str2;
1552         int count = 0;
1553         char *saveptr = NULL;
1554         struct spoolss_StringArray *deps;
1555         const char **file_array = NULL;
1556         int i;
1557
1558         /* fill in the UNISTR fields */
1559         str = get_driver_3_param(mem_ctx, args, ":", &r->driver_name, &saveptr);
1560         str = get_driver_3_param(mem_ctx, NULL, ":", &r->driver_path, &saveptr);
1561         str = get_driver_3_param(mem_ctx, NULL, ":", &r->data_file, &saveptr);
1562         str = get_driver_3_param(mem_ctx, NULL, ":", &r->config_file, &saveptr);
1563         str = get_driver_3_param(mem_ctx, NULL, ":", &r->help_file, &saveptr);
1564         str = get_driver_3_param(mem_ctx, NULL, ":", &r->monitor_name, &saveptr);
1565         str = get_driver_3_param(mem_ctx, NULL, ":", &r->default_datatype, &saveptr);
1566
1567         /* <Comma Separated List of Dependent Files> */
1568         /* save the beginning of the string */
1569         str2 = get_driver_3_param(mem_ctx, NULL, ":", NULL, &saveptr);
1570         str = str2;
1571
1572         /* begin to strip out each filename */
1573         str = strtok_r(str, ",", &saveptr);
1574
1575         /* no dependent files, we are done */
1576         if (!str) {
1577                 return true;
1578         }
1579
1580         deps = talloc_zero(mem_ctx, struct spoolss_StringArray);
1581         if (!deps) {
1582                 return false;
1583         }
1584
1585         while (str != NULL) {
1586                 add_string_to_array(deps, str, &file_array, &count);
1587                 str = strtok_r(NULL, ",", &saveptr);
1588         }
1589
1590         deps->string = talloc_zero_array(deps, const char *, count + 1);
1591         if (!deps->string) {
1592                 return false;
1593         }
1594
1595         for (i=0; i < count; i++) {
1596                 deps->string[i] = file_array[i];
1597         }
1598
1599         r->dependent_files = deps;
1600
1601         return true;
1602 }
1603
1604 /****************************************************************************
1605 ****************************************************************************/
1606
1607 static WERROR cmd_spoolss_addprinterdriver(struct rpc_pipe_client *cli,
1608                                              TALLOC_CTX *mem_ctx,
1609                                              int argc, const char **argv)
1610 {
1611         WERROR result;
1612         NTSTATUS status;
1613         uint32_t                  level = 3;
1614         struct spoolss_AddDriverInfoCtr info_ctr;
1615         struct spoolss_AddDriverInfo3 info3;
1616         const char              *arch;
1617         char                    *driver_args;
1618
1619         /* parse the command arguments */
1620         if (argc != 3 && argc != 4)
1621         {
1622                 printf ("Usage: %s <Environment> \\\n", argv[0]);
1623                 printf ("\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n");
1624                 printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
1625                 printf ("\t<Default Data Type>:<Comma Separated list of Files> \\\n");
1626                 printf ("\t[version]\n");
1627
1628             return WERR_OK;
1629         }
1630
1631         /* Fill in the spoolss_AddDriverInfo3 struct */
1632         ZERO_STRUCT(info3);
1633
1634         arch = cmd_spoolss_get_short_archi(argv[1]);
1635         if (!arch) {
1636                 printf ("Error Unknown architechture [%s]\n", argv[1]);
1637                 return WERR_INVALID_PARAM;
1638         }
1639
1640         set_drv_info_3_env(mem_ctx, &info3, arch);
1641
1642         driver_args = talloc_strdup( mem_ctx, argv[2] );
1643         if (!init_drv_info_3_members(mem_ctx, &info3, driver_args ))
1644         {
1645                 printf ("Error Invalid parameter list - %s.\n", argv[2]);
1646                 return WERR_INVALID_PARAM;
1647         }
1648
1649         /* if printer driver version specified, override the default version
1650          * used by the architecture.  This allows installation of Windows
1651          * 2000 (version 3) printer drivers. */
1652         if (argc == 4)
1653         {
1654                 info3.version = atoi(argv[3]);
1655         }
1656
1657
1658         info_ctr.level          = level;
1659         info_ctr.info.info3     = &info3;
1660
1661         status = rpccli_spoolss_AddPrinterDriver(cli, mem_ctx,
1662                                                  cli->srv_name_slash,
1663                                                  &info_ctr,
1664                                                  &result);
1665         if (!NT_STATUS_IS_OK(status)) {
1666                 return ntstatus_to_werror(status);
1667         }
1668         if (W_ERROR_IS_OK(result)) {
1669                 printf ("Printer Driver %s successfully installed.\n",
1670                         info3.driver_name);
1671         }
1672
1673         return result;
1674 }
1675
1676
1677 /****************************************************************************
1678 ****************************************************************************/
1679
1680 static WERROR cmd_spoolss_addprinterex(struct rpc_pipe_client *cli,
1681                                          TALLOC_CTX *mem_ctx,
1682                                          int argc, const char **argv)
1683 {
1684         WERROR result;
1685         struct spoolss_SetPrinterInfoCtr info_ctr;
1686         struct spoolss_SetPrinterInfo2 info2;
1687
1688         /* parse the command arguments */
1689         if (argc != 5)
1690         {
1691                 printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]);
1692                 return WERR_OK;
1693         }
1694
1695         /* Fill in the DRIVER_INFO_2 struct */
1696         ZERO_STRUCT(info2);
1697
1698         info2.printername       = argv[1];
1699         info2.drivername        = argv[3];
1700         info2.sharename         = argv[2];
1701         info2.portname          = argv[4];
1702         info2.comment           = "Created by rpcclient";
1703         info2.printprocessor    = "winprint";
1704         info2.datatype          = "RAW";
1705         info2.devmode_ptr       = 0;
1706         info2.secdesc_ptr       = 0;
1707         info2.attributes        = PRINTER_ATTRIBUTE_SHARED;
1708         info2.priority          = 0;
1709         info2.defaultpriority   = 0;
1710         info2.starttime         = 0;
1711         info2.untiltime         = 0;
1712
1713         /* These three fields must not be used by AddPrinter()
1714            as defined in the MS Platform SDK documentation..
1715            --jerry
1716         info2.status            = 0;
1717         info2.cjobs             = 0;
1718         info2.averageppm        = 0;
1719         */
1720
1721         info_ctr.level = 2;
1722         info_ctr.info.info2 = &info2;
1723
1724         result = rpccli_spoolss_addprinterex(cli, mem_ctx,
1725                                              &info_ctr);
1726         if (W_ERROR_IS_OK(result))
1727                 printf ("Printer %s successfully installed.\n", argv[1]);
1728
1729         return result;
1730 }
1731
1732 /****************************************************************************
1733 ****************************************************************************/
1734
1735 static WERROR cmd_spoolss_setdriver(struct rpc_pipe_client *cli,
1736                                       TALLOC_CTX *mem_ctx,
1737                                       int argc, const char **argv)
1738 {
1739         struct policy_handle    pol;
1740         WERROR                  result;
1741         NTSTATUS                status;
1742         uint32_t                level = 2;
1743         const char              *printername;
1744         union spoolss_PrinterInfo info;
1745         struct spoolss_SetPrinterInfoCtr info_ctr;
1746         struct spoolss_SetPrinterInfo2 info2;
1747         struct spoolss_DevmodeContainer devmode_ctr;
1748         struct sec_desc_buf secdesc_ctr;
1749
1750         ZERO_STRUCT(devmode_ctr);
1751         ZERO_STRUCT(secdesc_ctr);
1752
1753         /* parse the command arguments */
1754         if (argc != 3)
1755         {
1756                 printf ("Usage: %s <printer> <driver>\n", argv[0]);
1757                 return WERR_OK;
1758         }
1759
1760         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1761
1762         /* Get a printer handle */
1763
1764         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1765                                                printername,
1766                                                PRINTER_ALL_ACCESS,
1767                                                &pol);
1768         if (!W_ERROR_IS_OK(result))
1769                 goto done;
1770
1771         /* Get printer info */
1772
1773         result = rpccli_spoolss_getprinter(cli, mem_ctx,
1774                                            &pol,
1775                                            level,
1776                                            0,
1777                                            &info);
1778         if (!W_ERROR_IS_OK(result)) {
1779                 printf ("Unable to retrieve printer information!\n");
1780                 goto done;
1781         }
1782
1783         /* Set the printer driver */
1784
1785         spoolss_printerinfo2_to_setprinterinfo2(&info.info2, &info2);
1786         info2.drivername = argv[2];
1787
1788         info_ctr.level = 2;
1789         info_ctr.info.info2 = &info2;
1790
1791         status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
1792                                            &pol,
1793                                            &info_ctr,
1794                                            &devmode_ctr,
1795                                            &secdesc_ctr,
1796                                            0, /* command */
1797                                            &result);
1798         if (!W_ERROR_IS_OK(result)) {
1799                 printf("SetPrinter call failed!\n");
1800                 goto done;;
1801         }
1802
1803         printf("Successfully set %s to driver %s.\n", argv[1], argv[2]);
1804
1805 done:
1806         /* Cleanup */
1807
1808         if (is_valid_policy_hnd(&pol))
1809                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
1810
1811         return result;
1812 }
1813
1814
1815 /****************************************************************************
1816 ****************************************************************************/
1817
1818 static WERROR cmd_spoolss_deletedriverex(struct rpc_pipe_client *cli,
1819                                          TALLOC_CTX *mem_ctx,
1820                                          int argc, const char **argv)
1821 {
1822         WERROR result, ret = WERR_UNKNOWN_PRINTER_DRIVER;
1823         NTSTATUS status;
1824
1825         int   i;
1826         int vers = -1;
1827
1828         const char *arch = NULL;
1829         uint32_t delete_flags = 0;
1830
1831         /* parse the command arguments */
1832         if (argc < 2 || argc > 4) {
1833                 printf ("Usage: %s <driver> [arch] [version]\n", argv[0]);
1834                 return WERR_OK;
1835         }
1836
1837         if (argc >= 3)
1838                 arch = argv[2];
1839         if (argc == 4)
1840                 vers = atoi (argv[3]);
1841
1842         if (vers >= 0) {
1843                 delete_flags |= DPD_DELETE_SPECIFIC_VERSION;
1844         }
1845
1846         /* delete the driver for all architectures */
1847         for (i=0; archi_table[i].long_archi; i++) {
1848
1849                 if (arch &&  !strequal( archi_table[i].long_archi, arch))
1850                         continue;
1851
1852                 if (vers >= 0 && archi_table[i].version != vers)
1853                         continue;
1854
1855                 /* make the call to remove the driver */
1856                 status = rpccli_spoolss_DeletePrinterDriverEx(cli, mem_ctx,
1857                                                               cli->srv_name_slash,
1858                                                               archi_table[i].long_archi,
1859                                                               argv[1],
1860                                                               delete_flags,
1861                                                               archi_table[i].version,
1862                                                               &result);
1863
1864                 if ( !W_ERROR_IS_OK(result) )
1865                 {
1866                         if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1867                                 printf ("Failed to remove driver %s for arch [%s] (version: %d): %s\n",
1868                                         argv[1], archi_table[i].long_archi, archi_table[i].version, win_errstr(result));
1869                         }
1870                 }
1871                 else
1872                 {
1873                         printf ("Driver %s and files removed for arch [%s] (version: %d).\n", argv[1],
1874                         archi_table[i].long_archi, archi_table[i].version);
1875                         ret = WERR_OK;
1876                 }
1877         }
1878
1879         return ret;
1880 }
1881
1882
1883 /****************************************************************************
1884 ****************************************************************************/
1885
1886 static WERROR cmd_spoolss_deletedriver(struct rpc_pipe_client *cli,
1887                                          TALLOC_CTX *mem_ctx,
1888                                          int argc, const char **argv)
1889 {
1890         WERROR result = WERR_OK;
1891         NTSTATUS status;
1892         int                     i;
1893
1894         /* parse the command arguments */
1895         if (argc != 2) {
1896                 printf ("Usage: %s <driver>\n", argv[0]);
1897                 return WERR_OK;
1898         }
1899
1900         /* delete the driver for all architectures */
1901         for (i=0; archi_table[i].long_archi; i++) {
1902                 /* make the call to remove the driver */
1903                 status = rpccli_spoolss_DeletePrinterDriver(cli, mem_ctx,
1904                                                             cli->srv_name_slash,
1905                                                             archi_table[i].long_archi,
1906                                                             argv[1],
1907                                                             &result);
1908                 if (!NT_STATUS_IS_OK(status)) {
1909                         return result;
1910                 }
1911                 if ( !W_ERROR_IS_OK(result) ) {
1912                         if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1913                                 printf ("Failed to remove driver %s for arch [%s] - error 0x%x!\n",
1914                                         argv[1], archi_table[i].long_archi,
1915                                         W_ERROR_V(result));
1916                         }
1917                 } else {
1918                         printf ("Driver %s removed for arch [%s].\n", argv[1],
1919                                 archi_table[i].long_archi);
1920                 }
1921         }
1922
1923         return result;
1924 }
1925
1926 /****************************************************************************
1927 ****************************************************************************/
1928
1929 static WERROR cmd_spoolss_getprintprocdir(struct rpc_pipe_client *cli,
1930                                             TALLOC_CTX *mem_ctx,
1931                                             int argc, const char **argv)
1932 {
1933         WERROR result;
1934         NTSTATUS status;
1935         const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
1936         DATA_BLOB buffer;
1937         uint32_t offered;
1938         union spoolss_PrintProcessorDirectoryInfo info;
1939         uint32_t needed;
1940
1941         /* parse the command arguments */
1942         if (argc > 2) {
1943                 printf ("Usage: %s [environment]\n", argv[0]);
1944                 return WERR_OK;
1945         }
1946
1947         if (argc == 2) {
1948                 environment = argv[1];
1949         }
1950
1951         status = rpccli_spoolss_GetPrintProcessorDirectory(cli, mem_ctx,
1952                                                            cli->srv_name_slash,
1953                                                            environment,
1954                                                            1,
1955                                                            NULL, /* buffer */
1956                                                            0, /* offered */
1957                                                            NULL, /* info */
1958                                                            &needed,
1959                                                            &result);
1960         if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) {
1961                 offered = needed;
1962                 buffer = data_blob_talloc_zero(mem_ctx, needed);
1963
1964                 status = rpccli_spoolss_GetPrintProcessorDirectory(cli, mem_ctx,
1965                                                                    cli->srv_name_slash,
1966                                                                    environment,
1967                                                                    1,
1968                                                                    &buffer,
1969                                                                    offered,
1970                                                                    &info,
1971                                                                    &needed,
1972                                                                    &result);
1973         }
1974
1975         if (W_ERROR_IS_OK(result)) {
1976                 printf("%s\n", info.info1.directory_name);
1977         }
1978
1979         return result;
1980 }
1981
1982 /****************************************************************************
1983 ****************************************************************************/
1984
1985 static WERROR cmd_spoolss_addform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1986                                     int argc, const char **argv)
1987 {
1988         struct policy_handle handle;
1989         WERROR werror;
1990         NTSTATUS status;
1991         const char *printername;
1992         union spoolss_AddFormInfo info;
1993         struct spoolss_AddFormInfo1 info1;
1994         struct spoolss_AddFormInfo2 info2;
1995         uint32_t level = 1;
1996
1997         /* Parse the command arguments */
1998
1999         if (argc < 3 || argc > 5) {
2000                 printf ("Usage: %s <printer> <formname> [level]\n", argv[0]);
2001                 return WERR_OK;
2002         }
2003
2004         /* Get a printer handle */
2005
2006         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2007
2008         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2009                                                printername,
2010                                                PRINTER_ALL_ACCESS,
2011                                                &handle);
2012         if (!W_ERROR_IS_OK(werror))
2013                 goto done;
2014
2015         /* Dummy up some values for the form data */
2016
2017         if (argc == 4) {
2018                 level = atoi(argv[3]);
2019         }
2020
2021         switch (level) {
2022         case 1:
2023                 info1.flags             = SPOOLSS_FORM_USER;
2024                 info1.form_name         = argv[2];
2025                 info1.size.width        = 100;
2026                 info1.size.height       = 100;
2027                 info1.area.left         = 0;
2028                 info1.area.top          = 10;
2029                 info1.area.right        = 20;
2030                 info1.area.bottom       = 30;
2031
2032                 info.info1 = &info1;
2033
2034                 break;
2035         case 2:
2036                 info2.flags             = SPOOLSS_FORM_USER;
2037                 info2.form_name         = argv[2];
2038                 info2.size.width        = 100;
2039                 info2.size.height       = 100;
2040                 info2.area.left         = 0;
2041                 info2.area.top          = 10;
2042                 info2.area.right        = 20;
2043                 info2.area.bottom       = 30;
2044                 info2.keyword           = argv[2];
2045                 info2.string_type       = SPOOLSS_FORM_STRING_TYPE_NONE;
2046                 info2.mui_dll           = NULL;
2047                 info2.ressource_id      = 0;
2048                 info2.display_name      = argv[2];
2049                 info2.lang_id           = 0;
2050
2051                 info.info2 = &info2;
2052
2053                 break;
2054         }
2055
2056         /* Add the form */
2057
2058
2059         status = rpccli_spoolss_AddForm(cli, mem_ctx,
2060                                         &handle,
2061                                         level,
2062                                         info,
2063                                         &werror);
2064
2065  done:
2066         if (is_valid_policy_hnd(&handle))
2067                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2068
2069         return werror;
2070 }
2071
2072 /****************************************************************************
2073 ****************************************************************************/
2074
2075 static WERROR cmd_spoolss_setform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
2076                                     int argc, const char **argv)
2077 {
2078         struct policy_handle handle;
2079         WERROR werror;
2080         NTSTATUS status;
2081         const char *printername;
2082         union spoolss_AddFormInfo info;
2083         struct spoolss_AddFormInfo1 info1;
2084
2085         /* Parse the command arguments */
2086
2087         if (argc != 3) {
2088                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
2089                 return WERR_OK;
2090         }
2091
2092         /* Get a printer handle */
2093
2094         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2095
2096         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2097                                                printername,
2098                                                SEC_FLAG_MAXIMUM_ALLOWED,
2099                                                &handle);
2100         if (!W_ERROR_IS_OK(werror))
2101                 goto done;
2102
2103         /* Dummy up some values for the form data */
2104
2105         info1.flags             = SPOOLSS_FORM_PRINTER;
2106         info1.size.width        = 100;
2107         info1.size.height       = 100;
2108         info1.area.left         = 0;
2109         info1.area.top          = 1000;
2110         info1.area.right        = 2000;
2111         info1.area.bottom       = 3000;
2112         info1.form_name         = argv[2];
2113
2114         info.info1 = &info1;
2115
2116         /* Set the form */
2117
2118         status = rpccli_spoolss_SetForm(cli, mem_ctx,
2119                                         &handle,
2120                                         argv[2],
2121                                         1,
2122                                         info,
2123                                         &werror);
2124
2125  done:
2126         if (is_valid_policy_hnd(&handle))
2127                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2128
2129         return werror;
2130 }
2131
2132 /****************************************************************************
2133 ****************************************************************************/
2134
2135 static const char *get_form_flag(int form_flag)
2136 {
2137         switch (form_flag) {
2138         case SPOOLSS_FORM_USER:
2139                 return "FORM_USER";
2140         case SPOOLSS_FORM_BUILTIN:
2141                 return "FORM_BUILTIN";
2142         case SPOOLSS_FORM_PRINTER:
2143                 return "FORM_PRINTER";
2144         default:
2145                 return "unknown";
2146         }
2147 }
2148
2149 /****************************************************************************
2150 ****************************************************************************/
2151
2152 static void display_form_info1(struct spoolss_FormInfo1 *r)
2153 {
2154         printf("%s\n" \
2155                 "\tflag: %s (%d)\n" \
2156                 "\twidth: %d, length: %d\n" \
2157                 "\tleft: %d, right: %d, top: %d, bottom: %d\n\n",
2158                 r->form_name, get_form_flag(r->flags), r->flags,
2159                 r->size.width, r->size.height,
2160                 r->area.left, r->area.right,
2161                 r->area.top, r->area.bottom);
2162 }
2163
2164 /****************************************************************************
2165 ****************************************************************************/
2166
2167 static void display_form_info2(struct spoolss_FormInfo2 *r)
2168 {
2169         printf("%s\n" \
2170                 "\tflag: %s (%d)\n" \
2171                 "\twidth: %d, length: %d\n" \
2172                 "\tleft: %d, right: %d, top: %d, bottom: %d\n",
2173                 r->form_name, get_form_flag(r->flags), r->flags,
2174                 r->size.width, r->size.height,
2175                 r->area.left, r->area.right,
2176                 r->area.top, r->area.bottom);
2177         printf("\tkeyword: %s\n", r->keyword);
2178         printf("\tstring_type: 0x%08x\n", r->string_type);
2179         printf("\tmui_dll: %s\n", r->mui_dll);
2180         printf("\tressource_id: 0x%08x\n", r->ressource_id);
2181         printf("\tdisplay_name: %s\n", r->display_name);
2182         printf("\tlang_id: %d\n", r->lang_id);
2183         printf("\n");
2184 }
2185
2186 /****************************************************************************
2187 ****************************************************************************/
2188
2189 static WERROR cmd_spoolss_getform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
2190                                     int argc, const char **argv)
2191 {
2192         struct policy_handle handle;
2193         WERROR werror;
2194         NTSTATUS status;
2195         const char *printername;
2196         DATA_BLOB buffer;
2197         uint32_t offered = 0;
2198         union spoolss_FormInfo info;
2199         uint32_t needed;
2200         uint32_t level = 1;
2201
2202         /* Parse the command arguments */
2203
2204         if (argc < 3 || argc > 5) {
2205                 printf ("Usage: %s <printer> <formname> [level]\n", argv[0]);
2206                 return WERR_OK;
2207         }
2208
2209         /* Get a printer handle */
2210
2211         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2212
2213         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2214                                                printername,
2215                                                SEC_FLAG_MAXIMUM_ALLOWED,
2216                                                &handle);
2217         if (!W_ERROR_IS_OK(werror))
2218                 goto done;
2219
2220         if (argc == 4) {
2221                 level = atoi(argv[3]);
2222         }
2223
2224         /* Get the form */
2225
2226         status = rpccli_spoolss_GetForm(cli, mem_ctx,
2227                                         &handle,
2228                                         argv[2],
2229                                         level,
2230                                         NULL,
2231                                         offered,
2232                                         &info,
2233                                         &needed,
2234                                         &werror);
2235         if (W_ERROR_EQUAL(werror, WERR_INSUFFICIENT_BUFFER)) {
2236                 buffer = data_blob_talloc_zero(mem_ctx, needed);
2237                 offered = needed;
2238                 status = rpccli_spoolss_GetForm(cli, mem_ctx,
2239                                                 &handle,
2240                                                 argv[2],
2241                                                 level,
2242                                                 &buffer,
2243                                                 offered,
2244                                                 &info,
2245                                                 &needed,
2246                                                 &werror);
2247         }
2248
2249         if (!NT_STATUS_IS_OK(status)) {
2250                 return werror;
2251         }
2252
2253         switch (level) {
2254         case 1:
2255                 display_form_info1(&info.info1);
2256                 break;
2257         case 2:
2258                 display_form_info2(&info.info2);
2259                 break;
2260         }
2261
2262  done:
2263         if (is_valid_policy_hnd(&handle))
2264                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2265
2266         return werror;
2267 }
2268
2269 /****************************************************************************
2270 ****************************************************************************/
2271
2272 static WERROR cmd_spoolss_deleteform(struct rpc_pipe_client *cli,
2273                                        TALLOC_CTX *mem_ctx, int argc,
2274                                        const char **argv)
2275 {
2276         struct policy_handle handle;
2277         WERROR werror;
2278         NTSTATUS status;
2279         const char *printername;
2280
2281         /* Parse the command arguments */
2282
2283         if (argc != 3) {
2284                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
2285                 return WERR_OK;
2286         }
2287
2288         /* Get a printer handle */
2289
2290         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2291
2292         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2293                                                printername,
2294                                                SEC_FLAG_MAXIMUM_ALLOWED,
2295                                                &handle);
2296         if (!W_ERROR_IS_OK(werror))
2297                 goto done;
2298
2299         /* Delete the form */
2300
2301         status = rpccli_spoolss_DeleteForm(cli, mem_ctx,
2302                                            &handle,
2303                                            argv[2],
2304                                            &werror);
2305         if (!NT_STATUS_IS_OK(status)) {
2306                 return ntstatus_to_werror(status);
2307         }
2308
2309  done:
2310         if (is_valid_policy_hnd(&handle))
2311                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2312
2313         return werror;
2314 }
2315
2316 /****************************************************************************
2317 ****************************************************************************/
2318
2319 static WERROR cmd_spoolss_enum_forms(struct rpc_pipe_client *cli,
2320                                        TALLOC_CTX *mem_ctx, int argc,
2321                                        const char **argv)
2322 {
2323         struct policy_handle handle;
2324         WERROR werror;
2325         const char *printername;
2326         uint32_t num_forms, level = 1, i;
2327         union spoolss_FormInfo *forms;
2328
2329         /* Parse the command arguments */
2330
2331         if (argc < 2 || argc > 4) {
2332                 printf ("Usage: %s <printer> [level]\n", argv[0]);
2333                 return WERR_OK;
2334         }
2335
2336         /* Get a printer handle */
2337
2338         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2339
2340         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2341                                                printername,
2342                                                SEC_FLAG_MAXIMUM_ALLOWED,
2343                                                &handle);
2344         if (!W_ERROR_IS_OK(werror))
2345                 goto done;
2346
2347         if (argc == 3) {
2348                 level = atoi(argv[2]);
2349         }
2350
2351         /* Enumerate forms */
2352
2353         werror = rpccli_spoolss_enumforms(cli, mem_ctx,
2354                                           &handle,
2355                                           level,
2356                                           0,
2357                                           &num_forms,
2358                                           &forms);
2359
2360         if (!W_ERROR_IS_OK(werror))
2361                 goto done;
2362
2363         /* Display output */
2364
2365         for (i = 0; i < num_forms; i++) {
2366                 switch (level) {
2367                 case 1:
2368                         display_form_info1(&forms[i].info1);
2369                         break;
2370                 case 2:
2371                         display_form_info2(&forms[i].info2);
2372                         break;
2373                 }
2374         }
2375
2376  done:
2377         if (is_valid_policy_hnd(&handle))
2378                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2379
2380         return werror;
2381 }
2382
2383 /****************************************************************************
2384 ****************************************************************************/
2385
2386 static WERROR cmd_spoolss_setprinterdata(struct rpc_pipe_client *cli,
2387                                             TALLOC_CTX *mem_ctx,
2388                                             int argc, const char **argv)
2389 {
2390         WERROR result;
2391         NTSTATUS status;
2392         const char *printername;
2393         struct policy_handle pol;
2394         union spoolss_PrinterInfo info;
2395         enum winreg_Type type;
2396         union spoolss_PrinterData data;
2397         DATA_BLOB blob;
2398
2399         /* parse the command arguments */
2400         if (argc < 5) {
2401                 printf ("Usage: %s <printer> <string|binary|dword|multistring>"
2402                         " <value> <data>\n",
2403                         argv[0]);
2404                 return WERR_OK;
2405         }
2406
2407         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2408
2409         type = REG_NONE;
2410
2411         if (strequal(argv[2], "string")) {
2412                 type = REG_SZ;
2413         }
2414
2415         if (strequal(argv[2], "binary")) {
2416                 type = REG_BINARY;
2417         }
2418
2419         if (strequal(argv[2], "dword")) {
2420                 type = REG_DWORD;
2421         }
2422
2423         if (strequal(argv[2], "multistring")) {
2424                 type = REG_MULTI_SZ;
2425         }
2426
2427         if (type == REG_NONE) {
2428                 printf("Unknown data type: %s\n", argv[2]);
2429                 result =  WERR_INVALID_PARAM;
2430                 goto done;
2431         }
2432
2433         /* get a printer handle */
2434
2435         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2436                                                printername,
2437                                                SEC_FLAG_MAXIMUM_ALLOWED,
2438                                                &pol);
2439         if (!W_ERROR_IS_OK(result)) {
2440                 goto done;
2441         }
2442
2443         result = rpccli_spoolss_getprinter(cli, mem_ctx,
2444                                            &pol,
2445                                            0,
2446                                            0,
2447                                            &info);
2448         if (!W_ERROR_IS_OK(result)) {
2449                 goto done;
2450         }
2451
2452         printf("%s\n", current_timestring(mem_ctx, true));
2453         printf("\tchange_id (before set)\t:[0x%x]\n", info.info0.change_id);
2454
2455         /* Set the printer data */
2456
2457         switch (type) {
2458         case REG_SZ:
2459                 data.string = talloc_strdup(mem_ctx, argv[4]);
2460                 W_ERROR_HAVE_NO_MEMORY(data.string);
2461                 break;
2462         case REG_DWORD:
2463                 data.value = strtoul(argv[4], NULL, 10);
2464                 break;
2465         case REG_BINARY:
2466                 data.binary = strhex_to_data_blob(mem_ctx, argv[4]);
2467                 break;
2468         case REG_MULTI_SZ: {
2469                 int i, num_strings;
2470                 const char **strings = NULL;
2471
2472                 for (i=4; i<argc; i++) {
2473                         if (strcmp(argv[i], "NULL") == 0) {
2474                                 argv[i] = "";
2475                         }
2476                         if (!add_string_to_array(mem_ctx, argv[i],
2477                                                  &strings,
2478                                                  &num_strings)) {
2479                                 result = WERR_NOMEM;
2480                                 goto done;
2481                         }
2482                 }
2483                 data.string_array = talloc_zero_array(mem_ctx, const char *, num_strings + 1);
2484                 if (!data.string_array) {
2485                         result = WERR_NOMEM;
2486                         goto done;
2487                 }
2488                 for (i=0; i < num_strings; i++) {
2489                         data.string_array[i] = strings[i];
2490                 }
2491                 break;
2492                 }
2493         default:
2494                 printf("Unknown data type: %s\n", argv[2]);
2495                 result = WERR_INVALID_PARAM;
2496                 goto done;
2497         }
2498
2499         result = push_spoolss_PrinterData(mem_ctx, &blob, type, &data);
2500         if (!W_ERROR_IS_OK(result)) {
2501                 goto done;
2502         }
2503
2504         status = rpccli_spoolss_SetPrinterData(cli, mem_ctx,
2505                                                &pol,
2506                                                argv[3], /* value_name */
2507                                                type,
2508                                                blob.data,
2509                                                blob.length,
2510                                                &result);
2511         if (!W_ERROR_IS_OK(result)) {
2512                 printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]);
2513                 goto done;
2514         }
2515         printf("\tSetPrinterData succeeded [%s: %s]\n", argv[3], argv[4]);
2516
2517         result = rpccli_spoolss_getprinter(cli, mem_ctx,
2518                                            &pol,
2519                                            0,
2520                                            0,
2521                                            &info);
2522         if (!W_ERROR_IS_OK(result)) {
2523                 goto done;
2524         }
2525
2526         printf("%s\n", current_timestring(mem_ctx, true));
2527         printf("\tchange_id (after set)\t:[0x%x]\n", info.info0.change_id);
2528
2529 done:
2530         /* cleanup */
2531         if (is_valid_policy_hnd(&pol)) {
2532                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
2533         }
2534
2535         return result;
2536 }
2537
2538 /****************************************************************************
2539 ****************************************************************************/
2540
2541 static void display_job_info1(struct spoolss_JobInfo1 *r)
2542 {
2543         printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", r->position, r->job_id,
2544                r->user_name, r->document_name, r->text_status, r->pages_printed,
2545                r->total_pages);
2546 }
2547
2548 /****************************************************************************
2549 ****************************************************************************/
2550
2551 static void display_job_info2(struct spoolss_JobInfo2 *r)
2552 {
2553         printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n",
2554                r->position, r->job_id,
2555                r->user_name, r->document_name, r->text_status, r->pages_printed,
2556                r->total_pages, r->size);
2557 }
2558
2559 /****************************************************************************
2560 ****************************************************************************/
2561
2562 static void display_job_info3(struct spoolss_JobInfo3 *r)
2563 {
2564         printf("jobid[%d], next_jobid[%d]\n",
2565                 r->job_id, r->next_job_id);
2566 }
2567
2568 /****************************************************************************
2569 ****************************************************************************/
2570
2571 static void display_job_info4(struct spoolss_JobInfo4 *r)
2572 {
2573         printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d/%d bytes\n",
2574                r->position, r->job_id,
2575                r->user_name, r->document_name, r->text_status, r->pages_printed,
2576                r->total_pages, r->size, r->size_high);
2577 }
2578
2579 /****************************************************************************
2580 ****************************************************************************/
2581
2582 static WERROR cmd_spoolss_enum_jobs(struct rpc_pipe_client *cli,
2583                                       TALLOC_CTX *mem_ctx, int argc,
2584                                       const char **argv)
2585 {
2586         WERROR result;
2587         uint32_t level = 1, count, i;
2588         const char *printername;
2589         struct policy_handle hnd;
2590         union spoolss_JobInfo *info;
2591
2592         if (argc < 2 || argc > 3) {
2593                 printf("Usage: %s printername [level]\n", argv[0]);
2594                 return WERR_OK;
2595         }
2596
2597         if (argc == 3) {
2598                 level = atoi(argv[2]);
2599         }
2600
2601         /* Open printer handle */
2602
2603         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2604
2605         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2606                                                printername,
2607                                                SEC_FLAG_MAXIMUM_ALLOWED,
2608                                                &hnd);
2609         if (!W_ERROR_IS_OK(result))
2610                 goto done;
2611
2612         /* Enumerate ports */
2613
2614         result = rpccli_spoolss_enumjobs(cli, mem_ctx,
2615                                          &hnd,
2616                                          0, /* firstjob */
2617                                          1000, /* numjobs */
2618                                          level,
2619                                          0,
2620                                          &count,
2621                                          &info);
2622         if (!W_ERROR_IS_OK(result)) {
2623                 goto done;
2624         }
2625
2626         for (i = 0; i < count; i++) {
2627                 switch (level) {
2628                 case 1:
2629                         display_job_info1(&info[i].info1);
2630                         break;
2631                 case 2:
2632                         display_job_info2(&info[i].info2);
2633                         break;
2634                 default:
2635                         d_printf("unknown info level %d\n", level);
2636                         break;
2637                 }
2638         }
2639
2640 done:
2641         if (is_valid_policy_hnd(&hnd)) {
2642                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2643         }
2644
2645         return result;
2646 }
2647
2648 /****************************************************************************
2649 ****************************************************************************/
2650
2651 static WERROR cmd_spoolss_get_job(struct rpc_pipe_client *cli,
2652                                   TALLOC_CTX *mem_ctx, int argc,
2653                                   const char **argv)
2654 {
2655         WERROR result;
2656         const char *printername;
2657         struct policy_handle hnd;
2658         uint32_t job_id;
2659         uint32_t level = 1;
2660         union spoolss_JobInfo info;
2661
2662         if (argc < 3 || argc > 4) {
2663                 printf("Usage: %s printername job_id [level]\n", argv[0]);
2664                 return WERR_OK;
2665         }
2666
2667         job_id = atoi(argv[2]);
2668
2669         if (argc == 4) {
2670                 level = atoi(argv[3]);
2671         }
2672
2673         /* Open printer handle */
2674
2675         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2676
2677         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2678                                                printername,
2679                                                SEC_FLAG_MAXIMUM_ALLOWED,
2680                                                &hnd);
2681         if (!W_ERROR_IS_OK(result)) {
2682                 goto done;
2683         }
2684
2685         /* Enumerate ports */
2686
2687         result = rpccli_spoolss_getjob(cli, mem_ctx,
2688                                        &hnd,
2689                                        job_id,
2690                                        level,
2691                                        0,
2692                                        &info);
2693
2694         if (!W_ERROR_IS_OK(result)) {
2695                 goto done;
2696         }
2697
2698         switch (level) {
2699         case 1:
2700                 display_job_info1(&info.info1);
2701                 break;
2702         case 2:
2703                 display_job_info2(&info.info2);
2704                 break;
2705         case 3:
2706                 display_job_info3(&info.info3);
2707                 break;
2708         case 4:
2709                 display_job_info4(&info.info4);
2710                 break;
2711         default:
2712                 d_printf("unknown info level %d\n", level);
2713                 break;
2714         }
2715
2716 done:
2717         if (is_valid_policy_hnd(&hnd)) {
2718                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2719         }
2720
2721         return result;
2722 }
2723
2724 /****************************************************************************
2725 ****************************************************************************/
2726
2727 static WERROR cmd_spoolss_set_job(struct rpc_pipe_client *cli,
2728                                   TALLOC_CTX *mem_ctx, int argc,
2729                                   const char **argv)
2730 {
2731         WERROR result;
2732         NTSTATUS status;
2733         const char *printername;
2734         struct policy_handle hnd;
2735         uint32_t job_id;
2736         enum spoolss_JobControl command;
2737
2738         if (argc != 4) {
2739                 printf("Usage: %s printername job_id command\n", argv[0]);
2740                 return WERR_OK;
2741         }
2742
2743         job_id = atoi(argv[2]);
2744         command = atoi(argv[3]);
2745
2746         /* Open printer handle */
2747
2748         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2749
2750         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2751                                                printername,
2752                                                SEC_FLAG_MAXIMUM_ALLOWED,
2753                                                &hnd);
2754         if (!W_ERROR_IS_OK(result)) {
2755                 goto done;
2756         }
2757
2758         /* Set Job */
2759
2760         status = rpccli_spoolss_SetJob(cli, mem_ctx,
2761                                        &hnd,
2762                                        job_id,
2763                                        NULL,
2764                                        command,
2765                                        &result);
2766
2767         if (!W_ERROR_IS_OK(result)) {
2768                 goto done;
2769         }
2770
2771 done:
2772         if (is_valid_policy_hnd(&hnd)) {
2773                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2774         }
2775
2776         return result;
2777 }
2778
2779 /****************************************************************************
2780 ****************************************************************************/
2781
2782 static WERROR cmd_spoolss_enum_data(struct rpc_pipe_client *cli,
2783                                     TALLOC_CTX *mem_ctx, int argc,
2784                                     const char **argv)
2785 {
2786         WERROR result;
2787         NTSTATUS status;
2788         uint32_t i = 0;
2789         const char *printername;
2790         struct policy_handle hnd;
2791         uint32_t value_offered = 0;
2792         const char *value_name = NULL;
2793         uint32_t value_needed;
2794         enum winreg_Type type;
2795         uint8_t *data = NULL;
2796         uint32_t data_offered = 0;
2797         uint32_t data_needed;
2798
2799         if (argc != 2) {
2800                 printf("Usage: %s printername\n", argv[0]);
2801                 return WERR_OK;
2802         }
2803
2804         /* Open printer handle */
2805
2806         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2807
2808         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2809                                                printername,
2810                                                SEC_FLAG_MAXIMUM_ALLOWED,
2811                                                &hnd);
2812         if (!W_ERROR_IS_OK(result)) {
2813                 goto done;
2814         }
2815
2816         /* Enumerate data */
2817
2818         status = rpccli_spoolss_EnumPrinterData(cli, mem_ctx,
2819                                                 &hnd,
2820                                                 i,
2821                                                 value_name,
2822                                                 value_offered,
2823                                                 &value_needed,
2824                                                 &type,
2825                                                 data,
2826                                                 data_offered,
2827                                                 &data_needed,
2828                                                 &result);
2829
2830         data_offered    = data_needed;
2831         value_offered   = value_needed;
2832         data            = talloc_zero_array(mem_ctx, uint8_t, data_needed);
2833         value_name      = talloc_zero_array(mem_ctx, char, value_needed);
2834
2835         while (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(result)) {
2836
2837                 status = rpccli_spoolss_EnumPrinterData(cli, mem_ctx,
2838                                                         &hnd,
2839                                                         i++,
2840                                                         value_name,
2841                                                         value_offered,
2842                                                         &value_needed,
2843                                                         &type,
2844                                                         data,
2845                                                         data_offered,
2846                                                         &data_needed,
2847                                                         &result);
2848                 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(result)) {
2849                         struct regval_blob *v;
2850
2851                         v = regval_compose(talloc_tos(),
2852                                            value_name,
2853                                            type,
2854                                            data,
2855                                            data_offered);
2856                         if (v == NULL) {
2857                                 result = WERR_NOMEM;
2858                                 goto done;
2859                         }
2860
2861                         display_reg_value(v);
2862                         talloc_free(v);
2863                 }
2864         }
2865
2866         if (W_ERROR_V(result) == ERRnomoreitems) {
2867                 result = W_ERROR(ERRsuccess);
2868         }
2869
2870 done:
2871         if (is_valid_policy_hnd(&hnd)) {
2872                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2873         }
2874
2875         return result;
2876 }
2877
2878 /****************************************************************************
2879 ****************************************************************************/
2880
2881 static WERROR cmd_spoolss_enum_data_ex( struct rpc_pipe_client *cli,
2882                                           TALLOC_CTX *mem_ctx, int argc,
2883                                           const char **argv)
2884 {
2885         WERROR result;
2886         uint32_t i;
2887         const char *printername;
2888         struct policy_handle hnd;
2889         uint32_t count;
2890         struct spoolss_PrinterEnumValues *info;
2891
2892         if (argc != 3) {
2893                 printf("Usage: %s printername <keyname>\n", argv[0]);
2894                 return WERR_OK;
2895         }
2896
2897         /* Open printer handle */
2898
2899         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2900
2901         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2902                                                printername,
2903                                                SEC_FLAG_MAXIMUM_ALLOWED,
2904                                                &hnd);
2905         if (!W_ERROR_IS_OK(result)) {
2906                 goto done;
2907         }
2908
2909         /* Enumerate subkeys */
2910
2911         result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx,
2912                                                   &hnd,
2913                                                   argv[2],
2914                                                   0,
2915                                                   &count,
2916                                                   &info);
2917         if (!W_ERROR_IS_OK(result)) {
2918                 goto done;
2919         }
2920
2921         for (i=0; i < count; i++) {
2922                 display_printer_data(info[i].value_name,
2923                                      info[i].type,
2924                                      info[i].data->data,
2925                                      info[i].data->length);
2926         }
2927
2928  done:
2929         if (is_valid_policy_hnd(&hnd)) {
2930                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2931         }
2932
2933         return result;
2934 }
2935
2936 /****************************************************************************
2937 ****************************************************************************/
2938
2939 static WERROR cmd_spoolss_enum_printerkey(struct rpc_pipe_client *cli,
2940                                           TALLOC_CTX *mem_ctx, int argc,
2941                                           const char **argv)
2942 {
2943         WERROR result;
2944         const char *printername;
2945         const char *keyname = NULL;
2946         struct policy_handle hnd;
2947         const char **key_buffer = NULL;
2948         int i;
2949         uint32_t offered = 0;
2950
2951         if (argc < 2 || argc > 4) {
2952                 printf("Usage: %s printername [keyname] [offered]\n", argv[0]);
2953                 return WERR_OK;
2954         }
2955
2956         if (argc >= 3) {
2957                 keyname = argv[2];
2958         } else {
2959                 keyname = "";
2960         }
2961
2962         if (argc == 4) {
2963                 offered = atoi(argv[3]);
2964         }
2965
2966         /* Open printer handle */
2967
2968         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2969
2970         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2971                                                printername,
2972                                                SEC_FLAG_MAXIMUM_ALLOWED,
2973                                                &hnd);
2974         if (!W_ERROR_IS_OK(result)) {
2975                 goto done;
2976         }
2977
2978         /* Enumerate subkeys */
2979
2980         result = rpccli_spoolss_enumprinterkey(cli, mem_ctx,
2981                                                &hnd,
2982                                                keyname,
2983                                                &key_buffer,
2984                                                offered);
2985
2986         if (!W_ERROR_IS_OK(result)) {
2987                 goto done;
2988         }
2989
2990         for (i=0; key_buffer && key_buffer[i]; i++) {
2991                 printf("%s\n", key_buffer[i]);
2992         }
2993
2994  done:
2995
2996         if (is_valid_policy_hnd(&hnd)) {
2997                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2998         }
2999
3000         return result;
3001 }
3002
3003 /****************************************************************************
3004 ****************************************************************************/
3005
3006 static WERROR cmd_spoolss_rffpcnex(struct rpc_pipe_client *cli,
3007                                      TALLOC_CTX *mem_ctx, int argc,
3008                                      const char **argv)
3009 {
3010         const char *printername;
3011         const char *clientname;
3012         struct policy_handle hnd;
3013         WERROR result;
3014         NTSTATUS status;
3015         struct spoolss_NotifyOption option;
3016
3017         if (argc != 2) {
3018                 printf("Usage: %s printername\n", argv[0]);
3019                 result = WERR_OK;
3020                 goto done;
3021         }
3022
3023         /* Open printer */
3024
3025         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3026
3027         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3028                                                printername,
3029                                                SEC_FLAG_MAXIMUM_ALLOWED,
3030                                                &hnd);
3031         if (!W_ERROR_IS_OK(result)) {
3032                 printf("Error opening %s\n", argv[1]);
3033                 goto done;
3034         }
3035
3036         /* Create spool options */
3037
3038         option.version = 2;
3039         option.count = 2;
3040
3041         option.types = talloc_array(mem_ctx, struct spoolss_NotifyOptionType, 2);
3042         if (option.types == NULL) {
3043                 result = WERR_NOMEM;
3044                 goto done;
3045         }
3046
3047         option.types[0].type = PRINTER_NOTIFY_TYPE;
3048         option.types[0].count = 1;
3049         option.types[0].fields = talloc_array(mem_ctx, union spoolss_Field, 1);
3050         if (option.types[0].fields == NULL) {
3051                 result = WERR_NOMEM;
3052                 goto done;
3053         }
3054         option.types[0].fields[0].field = PRINTER_NOTIFY_FIELD_SERVER_NAME;
3055
3056         option.types[1].type = JOB_NOTIFY_TYPE;
3057         option.types[1].count = 1;
3058         option.types[1].fields = talloc_array(mem_ctx, union spoolss_Field, 1);
3059         if (option.types[1].fields == NULL) {
3060                 result = WERR_NOMEM;
3061                 goto done;
3062         }
3063         option.types[1].fields[0].field = JOB_NOTIFY_FIELD_PRINTER_NAME;
3064
3065         clientname = talloc_asprintf(mem_ctx, "\\\\%s", global_myname());
3066         if (!clientname) {
3067                 result = WERR_NOMEM;
3068                 goto done;
3069         }
3070
3071         /* Send rffpcnex */
3072
3073         status = rpccli_spoolss_RemoteFindFirstPrinterChangeNotifyEx(cli, mem_ctx,
3074                                                                      &hnd,
3075                                                                      0,
3076                                                                      0,
3077                                                                      clientname,
3078                                                                      123,
3079                                                                      &option,
3080                                                                      &result);
3081         if (!W_ERROR_IS_OK(result)) {
3082                 printf("Error rffpcnex %s\n", argv[1]);
3083                 goto done;
3084         }
3085
3086 done:
3087         if (is_valid_policy_hnd(&hnd))
3088                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
3089
3090         return result;
3091 }
3092
3093 /****************************************************************************
3094 ****************************************************************************/
3095
3096 static bool compare_printer( struct rpc_pipe_client *cli1, struct policy_handle *hnd1,
3097                              struct rpc_pipe_client *cli2, struct policy_handle *hnd2 )
3098 {
3099         union spoolss_PrinterInfo info1, info2;
3100         WERROR werror;
3101         TALLOC_CTX *mem_ctx = talloc_init("compare_printer");
3102
3103         printf("Retrieving printer propertiesfor %s...", cli1->desthost);
3104         werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
3105                                            hnd1,
3106                                            2,
3107                                            0,
3108                                            &info1);
3109         if ( !W_ERROR_IS_OK(werror) ) {
3110                 printf("failed (%s)\n", win_errstr(werror));
3111                 talloc_destroy(mem_ctx);
3112                 return false;
3113         }
3114         printf("ok\n");
3115
3116         printf("Retrieving printer properties for %s...", cli2->desthost);
3117         werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
3118                                            hnd2,
3119                                            2,
3120                                            0,
3121                                            &info2);
3122         if ( !W_ERROR_IS_OK(werror) ) {
3123                 printf("failed (%s)\n", win_errstr(werror));
3124                 talloc_destroy(mem_ctx);
3125                 return false;
3126         }
3127         printf("ok\n");
3128
3129         talloc_destroy(mem_ctx);
3130
3131         return true;
3132 }
3133
3134 /****************************************************************************
3135 ****************************************************************************/
3136
3137 static bool compare_printer_secdesc( struct rpc_pipe_client *cli1, struct policy_handle *hnd1,
3138                                      struct rpc_pipe_client *cli2, struct policy_handle *hnd2 )
3139 {
3140         union spoolss_PrinterInfo info1, info2;
3141         WERROR werror;
3142         TALLOC_CTX *mem_ctx = talloc_init("compare_printer_secdesc");
3143         struct security_descriptor *sd1, *sd2;
3144         bool result = true;
3145
3146
3147         printf("Retrieving printer security for %s...", cli1->desthost);
3148         werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
3149                                            hnd1,
3150                                            3,
3151                                            0,
3152                                            &info1);
3153         if ( !W_ERROR_IS_OK(werror) ) {
3154                 printf("failed (%s)\n", win_errstr(werror));
3155                 result = false;
3156                 goto done;
3157         }
3158         printf("ok\n");
3159
3160         printf("Retrieving printer security for %s...", cli2->desthost);
3161         werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
3162                                            hnd2,
3163                                            3,
3164                                            0,
3165                                            &info2);
3166         if ( !W_ERROR_IS_OK(werror) ) {
3167                 printf("failed (%s)\n", win_errstr(werror));
3168                 result = false;
3169                 goto done;
3170         }
3171         printf("ok\n");
3172
3173
3174         printf("++ ");
3175
3176         sd1 = info1.info3.secdesc;
3177         sd2 = info2.info3.secdesc;
3178
3179         if ( (sd1 != sd2) && ( !sd1 || !sd2 ) ) {
3180                 printf("NULL secdesc!\n");
3181                 result = false;
3182                 goto done;
3183         }
3184
3185         if (!security_descriptor_equal( sd1, sd2 ) ) {
3186                 printf("Security Descriptors *not* equal!\n");
3187                 result = false;
3188                 goto done;
3189         }
3190
3191         printf("Security descriptors match\n");
3192
3193 done:
3194         talloc_destroy(mem_ctx);
3195         return result;
3196 }
3197
3198
3199 /****************************************************************************
3200 ****************************************************************************/
3201
3202 extern struct user_auth_info *rpcclient_auth_info;
3203
3204 static WERROR cmd_spoolss_printercmp(struct rpc_pipe_client *cli,
3205                                      TALLOC_CTX *mem_ctx, int argc,
3206                                      const char **argv)
3207 {
3208         const char *printername;
3209         char *printername_path = NULL;
3210         struct cli_state *cli_server2 = NULL;
3211         struct rpc_pipe_client *cli2 = NULL;
3212         struct policy_handle hPrinter1, hPrinter2;
3213         NTSTATUS nt_status;
3214         WERROR werror;
3215
3216         if ( argc != 3 )  {
3217                 printf("Usage: %s <printer> <server>\n", argv[0]);
3218                 return WERR_OK;
3219         }
3220
3221         printername = argv[1];
3222
3223         /* first get the connection to the remote server */
3224
3225         nt_status = cli_full_connection(&cli_server2, global_myname(), argv[2],
3226                                         NULL, 0,
3227                                         "IPC$", "IPC",
3228                                         get_cmdline_auth_info_username(rpcclient_auth_info),
3229                                         lp_workgroup(),
3230                                         get_cmdline_auth_info_password(rpcclient_auth_info),
3231                                         get_cmdline_auth_info_use_kerberos(rpcclient_auth_info) ? CLI_FULL_CONNECTION_USE_KERBEROS : 0,
3232                                         get_cmdline_auth_info_signing_state(rpcclient_auth_info), NULL);
3233
3234         if ( !NT_STATUS_IS_OK(nt_status) )
3235                 return WERR_GENERAL_FAILURE;
3236
3237         nt_status = cli_rpc_pipe_open_noauth(cli_server2, &ndr_table_spoolss.syntax_id,
3238                                              &cli2);
3239         if (!NT_STATUS_IS_OK(nt_status)) {
3240                 printf("failed to open spoolss pipe on server %s (%s)\n",
3241                         argv[2], nt_errstr(nt_status));
3242                 return WERR_GENERAL_FAILURE;
3243         }
3244
3245         /* now open up both printers */
3246
3247         RPCCLIENT_PRINTERNAME(printername_path, cli, printername);
3248
3249         printf("Opening %s...", printername_path);
3250
3251         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3252                                                printername_path,
3253                                                PRINTER_ALL_ACCESS,
3254                                                &hPrinter1);
3255         if ( !W_ERROR_IS_OK(werror) ) {
3256                 printf("failed (%s)\n", win_errstr(werror));
3257                 goto done;
3258         }
3259         printf("ok\n");
3260
3261         RPCCLIENT_PRINTERNAME(printername_path, cli2, printername);
3262
3263         printf("Opening %s...", printername_path);
3264         werror = rpccli_spoolss_openprinter_ex(cli2, mem_ctx,
3265                                                printername_path,
3266                                                PRINTER_ALL_ACCESS,
3267                                                &hPrinter2);
3268         if ( !W_ERROR_IS_OK(werror) ) {
3269                  printf("failed (%s)\n", win_errstr(werror));
3270                 goto done;
3271         }
3272         printf("ok\n");
3273
3274         compare_printer( cli, &hPrinter1, cli2, &hPrinter2 );
3275         compare_printer_secdesc( cli, &hPrinter1, cli2, &hPrinter2 );
3276 #if 0
3277         compare_printerdata( cli_server1, &hPrinter1, cli_server2, &hPrinter2 );
3278 #endif
3279
3280
3281 done:
3282         /* cleanup */
3283
3284         printf("Closing printers...");
3285         rpccli_spoolss_ClosePrinter( cli, mem_ctx, &hPrinter1, NULL );
3286         rpccli_spoolss_ClosePrinter( cli2, mem_ctx, &hPrinter2, NULL );
3287         printf("ok\n");
3288
3289         /* close the second remote connection */
3290
3291         cli_shutdown( cli_server2 );
3292         return WERR_OK;
3293 }
3294
3295 static void display_proc_info1(struct spoolss_PrintProcessorInfo1 *r)
3296 {
3297         printf("print_processor_name: %s\n", r->print_processor_name);
3298 }
3299
3300 static WERROR cmd_spoolss_enum_procs(struct rpc_pipe_client *cli,
3301                                      TALLOC_CTX *mem_ctx, int argc,
3302                                      const char **argv)
3303 {
3304         WERROR werror;
3305         const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
3306         uint32_t num_procs, level = 1, i;
3307         union spoolss_PrintProcessorInfo *procs;
3308
3309         /* Parse the command arguments */
3310
3311         if (argc < 1 || argc > 4) {
3312                 printf ("Usage: %s [environment] [level]\n", argv[0]);
3313                 return WERR_OK;
3314         }
3315
3316         if (argc >= 2) {
3317                 environment = argv[1];
3318         }
3319
3320         if (argc == 3) {
3321                 level = atoi(argv[2]);
3322         }
3323
3324         /* Enumerate Print Processors */
3325
3326         werror = rpccli_spoolss_enumprintprocessors(cli, mem_ctx,
3327                                                     cli->srv_name_slash,
3328                                                     environment,
3329                                                     level,
3330                                                     0,
3331                                                     &num_procs,
3332                                                     &procs);
3333         if (!W_ERROR_IS_OK(werror))
3334                 goto done;
3335
3336         /* Display output */
3337
3338         for (i = 0; i < num_procs; i++) {
3339                 switch (level) {
3340                 case 1:
3341                         display_proc_info1(&procs[i].info1);
3342                         break;
3343                 }
3344         }
3345
3346  done:
3347         return werror;
3348 }
3349
3350 static void display_proc_data_types_info1(struct spoolss_PrintProcDataTypesInfo1 *r)
3351 {
3352         printf("name_array: %s\n", r->name_array);
3353 }
3354
3355 static WERROR cmd_spoolss_enum_proc_data_types(struct rpc_pipe_client *cli,
3356                                                TALLOC_CTX *mem_ctx, int argc,
3357                                                const char **argv)
3358 {
3359         WERROR werror;
3360         const char *print_processor_name = "winprint";
3361         uint32_t num_procs, level = 1, i;
3362         union spoolss_PrintProcDataTypesInfo *procs;
3363
3364         /* Parse the command arguments */
3365
3366         if (argc < 1 || argc > 4) {
3367                 printf ("Usage: %s [environment] [level]\n", argv[0]);
3368                 return WERR_OK;
3369         }
3370
3371         if (argc >= 2) {
3372                 print_processor_name = argv[1];
3373         }
3374
3375         if (argc == 3) {
3376                 level = atoi(argv[2]);
3377         }
3378
3379         /* Enumerate Print Processor Data Types */
3380
3381         werror = rpccli_spoolss_enumprintprocessordatatypes(cli, mem_ctx,
3382                                                             cli->srv_name_slash,
3383                                                             print_processor_name,
3384                                                             level,
3385                                                             0,
3386                                                             &num_procs,
3387                                                             &procs);
3388         if (!W_ERROR_IS_OK(werror))
3389                 goto done;
3390
3391         /* Display output */
3392
3393         for (i = 0; i < num_procs; i++) {
3394                 switch (level) {
3395                 case 1:
3396                         display_proc_data_types_info1(&procs[i].info1);
3397                         break;
3398                 }
3399         }
3400
3401  done:
3402         return werror;
3403 }
3404
3405 static void display_monitor1(const struct spoolss_MonitorInfo1 *r)
3406 {
3407         printf("monitor_name: %s\n", r->monitor_name);
3408 }
3409
3410 static void display_monitor2(const struct spoolss_MonitorInfo2 *r)
3411 {
3412         printf("monitor_name: %s\n", r->monitor_name);
3413         printf("environment: %s\n", r->environment);
3414         printf("dll_name: %s\n", r->dll_name);
3415 }
3416
3417 static WERROR cmd_spoolss_enum_monitors(struct rpc_pipe_client *cli,
3418                                         TALLOC_CTX *mem_ctx, int argc,
3419                                         const char **argv)
3420 {
3421         WERROR werror;
3422         uint32_t count, level = 1, i;
3423         union spoolss_MonitorInfo *info;
3424
3425         /* Parse the command arguments */
3426
3427         if (argc > 2) {
3428                 printf("Usage: %s [level]\n", argv[0]);
3429                 return WERR_OK;
3430         }
3431
3432         if (argc == 2) {
3433                 level = atoi(argv[1]);
3434         }
3435
3436         /* Enumerate Print Monitors */
3437
3438         werror = rpccli_spoolss_enummonitors(cli, mem_ctx,
3439                                              cli->srv_name_slash,
3440                                              level,
3441                                              0,
3442                                              &count,
3443                                              &info);
3444         if (!W_ERROR_IS_OK(werror)) {
3445                 goto done;
3446         }
3447
3448         /* Display output */
3449
3450         for (i = 0; i < count; i++) {
3451                 switch (level) {
3452                 case 1:
3453                         display_monitor1(&info[i].info1);
3454                         break;
3455                 case 2:
3456                         display_monitor2(&info[i].info2);
3457                         break;
3458                 }
3459         }
3460
3461  done:
3462         return werror;
3463 }
3464
3465 static WERROR cmd_spoolss_create_printer_ic(struct rpc_pipe_client *cli,
3466                                             TALLOC_CTX *mem_ctx, int argc,
3467                                             const char **argv)
3468 {
3469         WERROR result;
3470         NTSTATUS status;
3471         struct policy_handle handle, gdi_handle;
3472         const char *printername;
3473         struct spoolss_DevmodeContainer devmode_ctr;
3474
3475         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3476
3477         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3478                                                printername,
3479                                                SEC_FLAG_MAXIMUM_ALLOWED,
3480                                                &handle);
3481         if (!W_ERROR_IS_OK(result)) {
3482                 return result;
3483         }
3484
3485         ZERO_STRUCT(devmode_ctr);
3486
3487         status = rpccli_spoolss_CreatePrinterIC(cli, mem_ctx,
3488                                                 &handle,
3489                                                 &gdi_handle,
3490                                                 &devmode_ctr,
3491                                                 &result);
3492         if (!W_ERROR_IS_OK(result)) {
3493                 goto done;
3494         }
3495
3496  done:
3497         if (is_valid_policy_hnd(&gdi_handle)) {
3498                 rpccli_spoolss_DeletePrinterIC(cli, mem_ctx, &gdi_handle, NULL);
3499         }
3500         if (is_valid_policy_hnd(&handle)) {
3501                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3502         }
3503
3504         return result;
3505 }
3506
3507 /* List of commands exported by this module */
3508 struct cmd_set spoolss_commands[] = {
3509
3510         { "SPOOLSS"  },
3511
3512         { "adddriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterdriver,   &ndr_table_spoolss.syntax_id, NULL, "Add a print driver",                  "" },
3513         { "addprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterex,       &ndr_table_spoolss.syntax_id, NULL, "Add a printer",                       "" },
3514         { "deldriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriver,       &ndr_table_spoolss.syntax_id, NULL, "Delete a printer driver",             "" },
3515         { "deldriverex",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriverex,     &ndr_table_spoolss.syntax_id, NULL, "Delete a printer driver with files",  "" },
3516         { "enumdata",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data,          &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer data",              "" },
3517         { "enumdataex",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data_ex,       &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer data for a key",    "" },
3518         { "enumkey",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printerkey,    &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer keys",              "" },
3519         { "enumjobs",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_jobs,          &ndr_table_spoolss.syntax_id, NULL, "Enumerate print jobs",                "" },
3520         { "getjob",             RPC_RTYPE_WERROR, NULL, cmd_spoolss_get_job,            &ndr_table_spoolss.syntax_id, NULL, "Get print job",                       "" },
3521         { "setjob",             RPC_RTYPE_WERROR, NULL, cmd_spoolss_set_job,            &ndr_table_spoolss.syntax_id, NULL, "Set print job",                       "" },
3522         { "enumports",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_ports,         &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer ports",             "" },
3523         { "enumdrivers",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_drivers,       &ndr_table_spoolss.syntax_id, NULL, "Enumerate installed printer drivers", "" },
3524         { "enumprinters",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printers,      &ndr_table_spoolss.syntax_id, NULL, "Enumerate printers",                  "" },
3525         { "getdata",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdata,     &ndr_table_spoolss.syntax_id, NULL, "Get print driver data",               "" },
3526         { "getdataex",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdataex,   &ndr_table_spoolss.syntax_id, NULL, "Get printer driver data with keyname", ""},
3527         { "getdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriver,          &ndr_table_spoolss.syntax_id, NULL, "Get print driver information",        "" },
3528         { "getdriverdir",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriverdir,       &ndr_table_spoolss.syntax_id, NULL, "Get print driver upload directory",   "" },
3529         { "getprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinter,         &ndr_table_spoolss.syntax_id, NULL, "Get printer info",                    "" },
3530         { "openprinter",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer_ex,    &ndr_table_spoolss.syntax_id, NULL, "Open printer handle",                 "" },
3531         { "setdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_setdriver,          &ndr_table_spoolss.syntax_id, NULL, "Set printer driver",                  "" },
3532         { "getprintprocdir",    RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprintprocdir,    &ndr_table_spoolss.syntax_id, NULL, "Get print processor directory",       "" },
3533         { "addform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_addform,            &ndr_table_spoolss.syntax_id, NULL, "Add form",                            "" },
3534         { "setform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_setform,            &ndr_table_spoolss.syntax_id, NULL, "Set form",                            "" },
3535         { "getform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getform,            &ndr_table_spoolss.syntax_id, NULL, "Get form",                            "" },
3536         { "deleteform",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform,         &ndr_table_spoolss.syntax_id, NULL, "Delete form",                         "" },
3537         { "enumforms",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms,         &ndr_table_spoolss.syntax_id, NULL, "Enumerate forms",                     "" },
3538         { "setprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter,         &ndr_table_spoolss.syntax_id, NULL, "Set printer comment",                 "" },
3539         { "setprintername",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername,     &ndr_table_spoolss.syntax_id, NULL, "Set printername",                 "" },
3540         { "setprinterdata",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata,     &ndr_table_spoolss.syntax_id, NULL, "Set REG_SZ printer data",             "" },
3541         { "rffpcnex",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex,           &ndr_table_spoolss.syntax_id, NULL, "Rffpcnex test", "" },
3542         { "printercmp",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_printercmp,         &ndr_table_spoolss.syntax_id, NULL, "Printer comparison test", "" },
3543         { "enumprocs",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_procs,         &ndr_table_spoolss.syntax_id, NULL, "Enumerate Print Processors",          "" },
3544         { "enumprocdatatypes",  RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_proc_data_types, &ndr_table_spoolss.syntax_id, NULL, "Enumerate Print Processor Data Types", "" },
3545         { "enummonitors",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_monitors,      &ndr_table_spoolss.syntax_id, NULL, "Enumerate Print Monitors", "" },
3546         { "createprinteric",    RPC_RTYPE_WERROR, NULL, cmd_spoolss_create_printer_ic,  &ndr_table_spoolss.syntax_id, NULL, "Create Printer IC", "" },
3547
3548         { NULL }
3549 };