Add parse_setjob_command() to make setting job state easier for users.
[metze/samba/wip.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 struct {
2728         const char *name;
2729         enum spoolss_JobControl val;
2730 } cmdvals[] = {
2731         {"PAUSE", SPOOLSS_JOB_CONTROL_PAUSE},
2732         {"RESUME", SPOOLSS_JOB_CONTROL_RESUME},
2733         {"CANCEL", SPOOLSS_JOB_CONTROL_CANCEL},
2734         {"RESTART", SPOOLSS_JOB_CONTROL_RESTART},
2735         {"DELETE", SPOOLSS_JOB_CONTROL_DELETE},
2736         {"SEND_TO_PRINTER", SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER},
2737         {"EJECTED", SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED},
2738         {"RETAIN", SPOOLSS_JOB_CONTROL_RETAIN},
2739         {"RELEASE", SPOOLSS_JOB_CONTROL_RELEASE}
2740 };
2741
2742 static enum spoolss_JobControl parse_setjob_command(const char *cmd)
2743 {
2744         int i;
2745
2746         for (i = 0; i < sizeof(cmdvals)/sizeof(cmdvals[0]); i++) {
2747                 if (strequal(cmdvals[i].name, cmd)) {
2748                         return cmdvals[i].val;
2749                 }
2750         }
2751         return (enum spoolss_JobControl)atoi(cmd);
2752 }
2753
2754 static WERROR cmd_spoolss_set_job(struct rpc_pipe_client *cli,
2755                                   TALLOC_CTX *mem_ctx, int argc,
2756                                   const char **argv)
2757 {
2758         WERROR result;
2759         NTSTATUS status;
2760         const char *printername;
2761         struct policy_handle hnd;
2762         uint32_t job_id;
2763         enum spoolss_JobControl command;
2764
2765         if (argc != 4) {
2766                 printf("Usage: %s printername job_id command\n", argv[0]);
2767                 printf("command = [PAUSE|RESUME|CANCEL|RESTART|DELETE|"
2768                         "SEND_TO_PRINTER|EJECTED|RETAIN|RELEASE]\n");
2769                 return WERR_OK;
2770         }
2771
2772         job_id = atoi(argv[2]);
2773         command = parse_setjob_command(argv[3]);
2774
2775         /* Open printer handle */
2776
2777         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2778
2779         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2780                                                printername,
2781                                                SEC_FLAG_MAXIMUM_ALLOWED,
2782                                                &hnd);
2783         if (!W_ERROR_IS_OK(result)) {
2784                 goto done;
2785         }
2786
2787         /* Set Job */
2788
2789         status = rpccli_spoolss_SetJob(cli, mem_ctx,
2790                                        &hnd,
2791                                        job_id,
2792                                        NULL,
2793                                        command,
2794                                        &result);
2795
2796         if (!W_ERROR_IS_OK(result)) {
2797                 goto done;
2798         }
2799
2800 done:
2801         if (is_valid_policy_hnd(&hnd)) {
2802                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2803         }
2804
2805         return result;
2806 }
2807
2808 /****************************************************************************
2809 ****************************************************************************/
2810
2811 static WERROR cmd_spoolss_enum_data(struct rpc_pipe_client *cli,
2812                                     TALLOC_CTX *mem_ctx, int argc,
2813                                     const char **argv)
2814 {
2815         WERROR result;
2816         NTSTATUS status;
2817         uint32_t i = 0;
2818         const char *printername;
2819         struct policy_handle hnd;
2820         uint32_t value_offered = 0;
2821         const char *value_name = NULL;
2822         uint32_t value_needed;
2823         enum winreg_Type type;
2824         uint8_t *data = NULL;
2825         uint32_t data_offered = 0;
2826         uint32_t data_needed;
2827
2828         if (argc != 2) {
2829                 printf("Usage: %s printername\n", argv[0]);
2830                 return WERR_OK;
2831         }
2832
2833         /* Open printer handle */
2834
2835         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2836
2837         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2838                                                printername,
2839                                                SEC_FLAG_MAXIMUM_ALLOWED,
2840                                                &hnd);
2841         if (!W_ERROR_IS_OK(result)) {
2842                 goto done;
2843         }
2844
2845         /* Enumerate data */
2846
2847         status = rpccli_spoolss_EnumPrinterData(cli, mem_ctx,
2848                                                 &hnd,
2849                                                 i,
2850                                                 value_name,
2851                                                 value_offered,
2852                                                 &value_needed,
2853                                                 &type,
2854                                                 data,
2855                                                 data_offered,
2856                                                 &data_needed,
2857                                                 &result);
2858
2859         data_offered    = data_needed;
2860         value_offered   = value_needed;
2861         data            = talloc_zero_array(mem_ctx, uint8_t, data_needed);
2862         value_name      = talloc_zero_array(mem_ctx, char, value_needed);
2863
2864         while (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(result)) {
2865
2866                 status = rpccli_spoolss_EnumPrinterData(cli, mem_ctx,
2867                                                         &hnd,
2868                                                         i++,
2869                                                         value_name,
2870                                                         value_offered,
2871                                                         &value_needed,
2872                                                         &type,
2873                                                         data,
2874                                                         data_offered,
2875                                                         &data_needed,
2876                                                         &result);
2877                 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(result)) {
2878                         struct regval_blob *v;
2879
2880                         v = regval_compose(talloc_tos(),
2881                                            value_name,
2882                                            type,
2883                                            data,
2884                                            data_offered);
2885                         if (v == NULL) {
2886                                 result = WERR_NOMEM;
2887                                 goto done;
2888                         }
2889
2890                         display_reg_value(v);
2891                         talloc_free(v);
2892                 }
2893         }
2894
2895         if (W_ERROR_V(result) == ERRnomoreitems) {
2896                 result = W_ERROR(ERRsuccess);
2897         }
2898
2899 done:
2900         if (is_valid_policy_hnd(&hnd)) {
2901                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2902         }
2903
2904         return result;
2905 }
2906
2907 /****************************************************************************
2908 ****************************************************************************/
2909
2910 static WERROR cmd_spoolss_enum_data_ex( struct rpc_pipe_client *cli,
2911                                           TALLOC_CTX *mem_ctx, int argc,
2912                                           const char **argv)
2913 {
2914         WERROR result;
2915         uint32_t i;
2916         const char *printername;
2917         struct policy_handle hnd;
2918         uint32_t count;
2919         struct spoolss_PrinterEnumValues *info;
2920
2921         if (argc != 3) {
2922                 printf("Usage: %s printername <keyname>\n", argv[0]);
2923                 return WERR_OK;
2924         }
2925
2926         /* Open printer handle */
2927
2928         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2929
2930         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2931                                                printername,
2932                                                SEC_FLAG_MAXIMUM_ALLOWED,
2933                                                &hnd);
2934         if (!W_ERROR_IS_OK(result)) {
2935                 goto done;
2936         }
2937
2938         /* Enumerate subkeys */
2939
2940         result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx,
2941                                                   &hnd,
2942                                                   argv[2],
2943                                                   0,
2944                                                   &count,
2945                                                   &info);
2946         if (!W_ERROR_IS_OK(result)) {
2947                 goto done;
2948         }
2949
2950         for (i=0; i < count; i++) {
2951                 display_printer_data(info[i].value_name,
2952                                      info[i].type,
2953                                      info[i].data->data,
2954                                      info[i].data->length);
2955         }
2956
2957  done:
2958         if (is_valid_policy_hnd(&hnd)) {
2959                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2960         }
2961
2962         return result;
2963 }
2964
2965 /****************************************************************************
2966 ****************************************************************************/
2967
2968 static WERROR cmd_spoolss_enum_printerkey(struct rpc_pipe_client *cli,
2969                                           TALLOC_CTX *mem_ctx, int argc,
2970                                           const char **argv)
2971 {
2972         WERROR result;
2973         const char *printername;
2974         const char *keyname = NULL;
2975         struct policy_handle hnd;
2976         const char **key_buffer = NULL;
2977         int i;
2978         uint32_t offered = 0;
2979
2980         if (argc < 2 || argc > 4) {
2981                 printf("Usage: %s printername [keyname] [offered]\n", argv[0]);
2982                 return WERR_OK;
2983         }
2984
2985         if (argc >= 3) {
2986                 keyname = argv[2];
2987         } else {
2988                 keyname = "";
2989         }
2990
2991         if (argc == 4) {
2992                 offered = atoi(argv[3]);
2993         }
2994
2995         /* Open printer handle */
2996
2997         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2998
2999         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3000                                                printername,
3001                                                SEC_FLAG_MAXIMUM_ALLOWED,
3002                                                &hnd);
3003         if (!W_ERROR_IS_OK(result)) {
3004                 goto done;
3005         }
3006
3007         /* Enumerate subkeys */
3008
3009         result = rpccli_spoolss_enumprinterkey(cli, mem_ctx,
3010                                                &hnd,
3011                                                keyname,
3012                                                &key_buffer,
3013                                                offered);
3014
3015         if (!W_ERROR_IS_OK(result)) {
3016                 goto done;
3017         }
3018
3019         for (i=0; key_buffer && key_buffer[i]; i++) {
3020                 printf("%s\n", key_buffer[i]);
3021         }
3022
3023  done:
3024
3025         if (is_valid_policy_hnd(&hnd)) {
3026                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
3027         }
3028
3029         return result;
3030 }
3031
3032 /****************************************************************************
3033 ****************************************************************************/
3034
3035 static WERROR cmd_spoolss_rffpcnex(struct rpc_pipe_client *cli,
3036                                      TALLOC_CTX *mem_ctx, int argc,
3037                                      const char **argv)
3038 {
3039         const char *printername;
3040         const char *clientname;
3041         struct policy_handle hnd;
3042         WERROR result;
3043         NTSTATUS status;
3044         struct spoolss_NotifyOption option;
3045
3046         if (argc != 2) {
3047                 printf("Usage: %s printername\n", argv[0]);
3048                 result = WERR_OK;
3049                 goto done;
3050         }
3051
3052         /* Open printer */
3053
3054         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3055
3056         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3057                                                printername,
3058                                                SEC_FLAG_MAXIMUM_ALLOWED,
3059                                                &hnd);
3060         if (!W_ERROR_IS_OK(result)) {
3061                 printf("Error opening %s\n", argv[1]);
3062                 goto done;
3063         }
3064
3065         /* Create spool options */
3066
3067         option.version = 2;
3068         option.count = 2;
3069
3070         option.types = talloc_array(mem_ctx, struct spoolss_NotifyOptionType, 2);
3071         if (option.types == NULL) {
3072                 result = WERR_NOMEM;
3073                 goto done;
3074         }
3075
3076         option.types[0].type = PRINTER_NOTIFY_TYPE;
3077         option.types[0].count = 1;
3078         option.types[0].fields = talloc_array(mem_ctx, union spoolss_Field, 1);
3079         if (option.types[0].fields == NULL) {
3080                 result = WERR_NOMEM;
3081                 goto done;
3082         }
3083         option.types[0].fields[0].field = PRINTER_NOTIFY_FIELD_SERVER_NAME;
3084
3085         option.types[1].type = JOB_NOTIFY_TYPE;
3086         option.types[1].count = 1;
3087         option.types[1].fields = talloc_array(mem_ctx, union spoolss_Field, 1);
3088         if (option.types[1].fields == NULL) {
3089                 result = WERR_NOMEM;
3090                 goto done;
3091         }
3092         option.types[1].fields[0].field = JOB_NOTIFY_FIELD_PRINTER_NAME;
3093
3094         clientname = talloc_asprintf(mem_ctx, "\\\\%s", global_myname());
3095         if (!clientname) {
3096                 result = WERR_NOMEM;
3097                 goto done;
3098         }
3099
3100         /* Send rffpcnex */
3101
3102         status = rpccli_spoolss_RemoteFindFirstPrinterChangeNotifyEx(cli, mem_ctx,
3103                                                                      &hnd,
3104                                                                      0,
3105                                                                      0,
3106                                                                      clientname,
3107                                                                      123,
3108                                                                      &option,
3109                                                                      &result);
3110         if (!W_ERROR_IS_OK(result)) {
3111                 printf("Error rffpcnex %s\n", argv[1]);
3112                 goto done;
3113         }
3114
3115 done:
3116         if (is_valid_policy_hnd(&hnd))
3117                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
3118
3119         return result;
3120 }
3121
3122 /****************************************************************************
3123 ****************************************************************************/
3124
3125 static bool compare_printer( struct rpc_pipe_client *cli1, struct policy_handle *hnd1,
3126                              struct rpc_pipe_client *cli2, struct policy_handle *hnd2 )
3127 {
3128         union spoolss_PrinterInfo info1, info2;
3129         WERROR werror;
3130         TALLOC_CTX *mem_ctx = talloc_init("compare_printer");
3131
3132         printf("Retrieving printer propertiesfor %s...", cli1->desthost);
3133         werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
3134                                            hnd1,
3135                                            2,
3136                                            0,
3137                                            &info1);
3138         if ( !W_ERROR_IS_OK(werror) ) {
3139                 printf("failed (%s)\n", win_errstr(werror));
3140                 talloc_destroy(mem_ctx);
3141                 return false;
3142         }
3143         printf("ok\n");
3144
3145         printf("Retrieving printer properties for %s...", cli2->desthost);
3146         werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
3147                                            hnd2,
3148                                            2,
3149                                            0,
3150                                            &info2);
3151         if ( !W_ERROR_IS_OK(werror) ) {
3152                 printf("failed (%s)\n", win_errstr(werror));
3153                 talloc_destroy(mem_ctx);
3154                 return false;
3155         }
3156         printf("ok\n");
3157
3158         talloc_destroy(mem_ctx);
3159
3160         return true;
3161 }
3162
3163 /****************************************************************************
3164 ****************************************************************************/
3165
3166 static bool compare_printer_secdesc( struct rpc_pipe_client *cli1, struct policy_handle *hnd1,
3167                                      struct rpc_pipe_client *cli2, struct policy_handle *hnd2 )
3168 {
3169         union spoolss_PrinterInfo info1, info2;
3170         WERROR werror;
3171         TALLOC_CTX *mem_ctx = talloc_init("compare_printer_secdesc");
3172         struct security_descriptor *sd1, *sd2;
3173         bool result = true;
3174
3175
3176         printf("Retrieving printer security for %s...", cli1->desthost);
3177         werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
3178                                            hnd1,
3179                                            3,
3180                                            0,
3181                                            &info1);
3182         if ( !W_ERROR_IS_OK(werror) ) {
3183                 printf("failed (%s)\n", win_errstr(werror));
3184                 result = false;
3185                 goto done;
3186         }
3187         printf("ok\n");
3188
3189         printf("Retrieving printer security for %s...", cli2->desthost);
3190         werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
3191                                            hnd2,
3192                                            3,
3193                                            0,
3194                                            &info2);
3195         if ( !W_ERROR_IS_OK(werror) ) {
3196                 printf("failed (%s)\n", win_errstr(werror));
3197                 result = false;
3198                 goto done;
3199         }
3200         printf("ok\n");
3201
3202
3203         printf("++ ");
3204
3205         sd1 = info1.info3.secdesc;
3206         sd2 = info2.info3.secdesc;
3207
3208         if ( (sd1 != sd2) && ( !sd1 || !sd2 ) ) {
3209                 printf("NULL secdesc!\n");
3210                 result = false;
3211                 goto done;
3212         }
3213
3214         if (!security_descriptor_equal( sd1, sd2 ) ) {
3215                 printf("Security Descriptors *not* equal!\n");
3216                 result = false;
3217                 goto done;
3218         }
3219
3220         printf("Security descriptors match\n");
3221
3222 done:
3223         talloc_destroy(mem_ctx);
3224         return result;
3225 }
3226
3227
3228 /****************************************************************************
3229 ****************************************************************************/
3230
3231 extern struct user_auth_info *rpcclient_auth_info;
3232
3233 static WERROR cmd_spoolss_printercmp(struct rpc_pipe_client *cli,
3234                                      TALLOC_CTX *mem_ctx, int argc,
3235                                      const char **argv)
3236 {
3237         const char *printername;
3238         char *printername_path = NULL;
3239         struct cli_state *cli_server2 = NULL;
3240         struct rpc_pipe_client *cli2 = NULL;
3241         struct policy_handle hPrinter1, hPrinter2;
3242         NTSTATUS nt_status;
3243         WERROR werror;
3244
3245         if ( argc != 3 )  {
3246                 printf("Usage: %s <printer> <server>\n", argv[0]);
3247                 return WERR_OK;
3248         }
3249
3250         printername = argv[1];
3251
3252         /* first get the connection to the remote server */
3253
3254         nt_status = cli_full_connection(&cli_server2, global_myname(), argv[2],
3255                                         NULL, 0,
3256                                         "IPC$", "IPC",
3257                                         get_cmdline_auth_info_username(rpcclient_auth_info),
3258                                         lp_workgroup(),
3259                                         get_cmdline_auth_info_password(rpcclient_auth_info),
3260                                         get_cmdline_auth_info_use_kerberos(rpcclient_auth_info) ? CLI_FULL_CONNECTION_USE_KERBEROS : 0,
3261                                         get_cmdline_auth_info_signing_state(rpcclient_auth_info), NULL);
3262
3263         if ( !NT_STATUS_IS_OK(nt_status) )
3264                 return WERR_GENERAL_FAILURE;
3265
3266         nt_status = cli_rpc_pipe_open_noauth(cli_server2, &ndr_table_spoolss.syntax_id,
3267                                              &cli2);
3268         if (!NT_STATUS_IS_OK(nt_status)) {
3269                 printf("failed to open spoolss pipe on server %s (%s)\n",
3270                         argv[2], nt_errstr(nt_status));
3271                 return WERR_GENERAL_FAILURE;
3272         }
3273
3274         /* now open up both printers */
3275
3276         RPCCLIENT_PRINTERNAME(printername_path, cli, printername);
3277
3278         printf("Opening %s...", printername_path);
3279
3280         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3281                                                printername_path,
3282                                                PRINTER_ALL_ACCESS,
3283                                                &hPrinter1);
3284         if ( !W_ERROR_IS_OK(werror) ) {
3285                 printf("failed (%s)\n", win_errstr(werror));
3286                 goto done;
3287         }
3288         printf("ok\n");
3289
3290         RPCCLIENT_PRINTERNAME(printername_path, cli2, printername);
3291
3292         printf("Opening %s...", printername_path);
3293         werror = rpccli_spoolss_openprinter_ex(cli2, mem_ctx,
3294                                                printername_path,
3295                                                PRINTER_ALL_ACCESS,
3296                                                &hPrinter2);
3297         if ( !W_ERROR_IS_OK(werror) ) {
3298                  printf("failed (%s)\n", win_errstr(werror));
3299                 goto done;
3300         }
3301         printf("ok\n");
3302
3303         compare_printer( cli, &hPrinter1, cli2, &hPrinter2 );
3304         compare_printer_secdesc( cli, &hPrinter1, cli2, &hPrinter2 );
3305 #if 0
3306         compare_printerdata( cli_server1, &hPrinter1, cli_server2, &hPrinter2 );
3307 #endif
3308
3309
3310 done:
3311         /* cleanup */
3312
3313         printf("Closing printers...");
3314         rpccli_spoolss_ClosePrinter( cli, mem_ctx, &hPrinter1, NULL );
3315         rpccli_spoolss_ClosePrinter( cli2, mem_ctx, &hPrinter2, NULL );
3316         printf("ok\n");
3317
3318         /* close the second remote connection */
3319
3320         cli_shutdown( cli_server2 );
3321         return WERR_OK;
3322 }
3323
3324 static void display_proc_info1(struct spoolss_PrintProcessorInfo1 *r)
3325 {
3326         printf("print_processor_name: %s\n", r->print_processor_name);
3327 }
3328
3329 static WERROR cmd_spoolss_enum_procs(struct rpc_pipe_client *cli,
3330                                      TALLOC_CTX *mem_ctx, int argc,
3331                                      const char **argv)
3332 {
3333         WERROR werror;
3334         const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
3335         uint32_t num_procs, level = 1, i;
3336         union spoolss_PrintProcessorInfo *procs;
3337
3338         /* Parse the command arguments */
3339
3340         if (argc < 1 || argc > 4) {
3341                 printf ("Usage: %s [environment] [level]\n", argv[0]);
3342                 return WERR_OK;
3343         }
3344
3345         if (argc >= 2) {
3346                 environment = argv[1];
3347         }
3348
3349         if (argc == 3) {
3350                 level = atoi(argv[2]);
3351         }
3352
3353         /* Enumerate Print Processors */
3354
3355         werror = rpccli_spoolss_enumprintprocessors(cli, mem_ctx,
3356                                                     cli->srv_name_slash,
3357                                                     environment,
3358                                                     level,
3359                                                     0,
3360                                                     &num_procs,
3361                                                     &procs);
3362         if (!W_ERROR_IS_OK(werror))
3363                 goto done;
3364
3365         /* Display output */
3366
3367         for (i = 0; i < num_procs; i++) {
3368                 switch (level) {
3369                 case 1:
3370                         display_proc_info1(&procs[i].info1);
3371                         break;
3372                 }
3373         }
3374
3375  done:
3376         return werror;
3377 }
3378
3379 static void display_proc_data_types_info1(struct spoolss_PrintProcDataTypesInfo1 *r)
3380 {
3381         printf("name_array: %s\n", r->name_array);
3382 }
3383
3384 static WERROR cmd_spoolss_enum_proc_data_types(struct rpc_pipe_client *cli,
3385                                                TALLOC_CTX *mem_ctx, int argc,
3386                                                const char **argv)
3387 {
3388         WERROR werror;
3389         const char *print_processor_name = "winprint";
3390         uint32_t num_procs, level = 1, i;
3391         union spoolss_PrintProcDataTypesInfo *procs;
3392
3393         /* Parse the command arguments */
3394
3395         if (argc < 1 || argc > 4) {
3396                 printf ("Usage: %s [environment] [level]\n", argv[0]);
3397                 return WERR_OK;
3398         }
3399
3400         if (argc >= 2) {
3401                 print_processor_name = argv[1];
3402         }
3403
3404         if (argc == 3) {
3405                 level = atoi(argv[2]);
3406         }
3407
3408         /* Enumerate Print Processor Data Types */
3409
3410         werror = rpccli_spoolss_enumprintprocessordatatypes(cli, mem_ctx,
3411                                                             cli->srv_name_slash,
3412                                                             print_processor_name,
3413                                                             level,
3414                                                             0,
3415                                                             &num_procs,
3416                                                             &procs);
3417         if (!W_ERROR_IS_OK(werror))
3418                 goto done;
3419
3420         /* Display output */
3421
3422         for (i = 0; i < num_procs; i++) {
3423                 switch (level) {
3424                 case 1:
3425                         display_proc_data_types_info1(&procs[i].info1);
3426                         break;
3427                 }
3428         }
3429
3430  done:
3431         return werror;
3432 }
3433
3434 static void display_monitor1(const struct spoolss_MonitorInfo1 *r)
3435 {
3436         printf("monitor_name: %s\n", r->monitor_name);
3437 }
3438
3439 static void display_monitor2(const struct spoolss_MonitorInfo2 *r)
3440 {
3441         printf("monitor_name: %s\n", r->monitor_name);
3442         printf("environment: %s\n", r->environment);
3443         printf("dll_name: %s\n", r->dll_name);
3444 }
3445
3446 static WERROR cmd_spoolss_enum_monitors(struct rpc_pipe_client *cli,
3447                                         TALLOC_CTX *mem_ctx, int argc,
3448                                         const char **argv)
3449 {
3450         WERROR werror;
3451         uint32_t count, level = 1, i;
3452         union spoolss_MonitorInfo *info;
3453
3454         /* Parse the command arguments */
3455
3456         if (argc > 2) {
3457                 printf("Usage: %s [level]\n", argv[0]);
3458                 return WERR_OK;
3459         }
3460
3461         if (argc == 2) {
3462                 level = atoi(argv[1]);
3463         }
3464
3465         /* Enumerate Print Monitors */
3466
3467         werror = rpccli_spoolss_enummonitors(cli, mem_ctx,
3468                                              cli->srv_name_slash,
3469                                              level,
3470                                              0,
3471                                              &count,
3472                                              &info);
3473         if (!W_ERROR_IS_OK(werror)) {
3474                 goto done;
3475         }
3476
3477         /* Display output */
3478
3479         for (i = 0; i < count; i++) {
3480                 switch (level) {
3481                 case 1:
3482                         display_monitor1(&info[i].info1);
3483                         break;
3484                 case 2:
3485                         display_monitor2(&info[i].info2);
3486                         break;
3487                 }
3488         }
3489
3490  done:
3491         return werror;
3492 }
3493
3494 static WERROR cmd_spoolss_create_printer_ic(struct rpc_pipe_client *cli,
3495                                             TALLOC_CTX *mem_ctx, int argc,
3496                                             const char **argv)
3497 {
3498         WERROR result;
3499         NTSTATUS status;
3500         struct policy_handle handle, gdi_handle;
3501         const char *printername;
3502         struct spoolss_DevmodeContainer devmode_ctr;
3503
3504         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3505
3506         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3507                                                printername,
3508                                                SEC_FLAG_MAXIMUM_ALLOWED,
3509                                                &handle);
3510         if (!W_ERROR_IS_OK(result)) {
3511                 return result;
3512         }
3513
3514         ZERO_STRUCT(devmode_ctr);
3515
3516         status = rpccli_spoolss_CreatePrinterIC(cli, mem_ctx,
3517                                                 &handle,
3518                                                 &gdi_handle,
3519                                                 &devmode_ctr,
3520                                                 &result);
3521         if (!W_ERROR_IS_OK(result)) {
3522                 goto done;
3523         }
3524
3525  done:
3526         if (is_valid_policy_hnd(&gdi_handle)) {
3527                 rpccli_spoolss_DeletePrinterIC(cli, mem_ctx, &gdi_handle, NULL);
3528         }
3529         if (is_valid_policy_hnd(&handle)) {
3530                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3531         }
3532
3533         return result;
3534 }
3535
3536 /* List of commands exported by this module */
3537 struct cmd_set spoolss_commands[] = {
3538
3539         { "SPOOLSS"  },
3540
3541         { "adddriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterdriver,   &ndr_table_spoolss.syntax_id, NULL, "Add a print driver",                  "" },
3542         { "addprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterex,       &ndr_table_spoolss.syntax_id, NULL, "Add a printer",                       "" },
3543         { "deldriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriver,       &ndr_table_spoolss.syntax_id, NULL, "Delete a printer driver",             "" },
3544         { "deldriverex",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriverex,     &ndr_table_spoolss.syntax_id, NULL, "Delete a printer driver with files",  "" },
3545         { "enumdata",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data,          &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer data",              "" },
3546         { "enumdataex",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data_ex,       &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer data for a key",    "" },
3547         { "enumkey",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printerkey,    &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer keys",              "" },
3548         { "enumjobs",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_jobs,          &ndr_table_spoolss.syntax_id, NULL, "Enumerate print jobs",                "" },
3549         { "getjob",             RPC_RTYPE_WERROR, NULL, cmd_spoolss_get_job,            &ndr_table_spoolss.syntax_id, NULL, "Get print job",                       "" },
3550         { "setjob",             RPC_RTYPE_WERROR, NULL, cmd_spoolss_set_job,            &ndr_table_spoolss.syntax_id, NULL, "Set print job",                       "" },
3551         { "enumports",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_ports,         &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer ports",             "" },
3552         { "enumdrivers",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_drivers,       &ndr_table_spoolss.syntax_id, NULL, "Enumerate installed printer drivers", "" },
3553         { "enumprinters",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printers,      &ndr_table_spoolss.syntax_id, NULL, "Enumerate printers",                  "" },
3554         { "getdata",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdata,     &ndr_table_spoolss.syntax_id, NULL, "Get print driver data",               "" },
3555         { "getdataex",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdataex,   &ndr_table_spoolss.syntax_id, NULL, "Get printer driver data with keyname", ""},
3556         { "getdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriver,          &ndr_table_spoolss.syntax_id, NULL, "Get print driver information",        "" },
3557         { "getdriverdir",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriverdir,       &ndr_table_spoolss.syntax_id, NULL, "Get print driver upload directory",   "" },
3558         { "getprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinter,         &ndr_table_spoolss.syntax_id, NULL, "Get printer info",                    "" },
3559         { "openprinter",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer_ex,    &ndr_table_spoolss.syntax_id, NULL, "Open printer handle",                 "" },
3560         { "setdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_setdriver,          &ndr_table_spoolss.syntax_id, NULL, "Set printer driver",                  "" },
3561         { "getprintprocdir",    RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprintprocdir,    &ndr_table_spoolss.syntax_id, NULL, "Get print processor directory",       "" },
3562         { "addform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_addform,            &ndr_table_spoolss.syntax_id, NULL, "Add form",                            "" },
3563         { "setform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_setform,            &ndr_table_spoolss.syntax_id, NULL, "Set form",                            "" },
3564         { "getform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getform,            &ndr_table_spoolss.syntax_id, NULL, "Get form",                            "" },
3565         { "deleteform",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform,         &ndr_table_spoolss.syntax_id, NULL, "Delete form",                         "" },
3566         { "enumforms",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms,         &ndr_table_spoolss.syntax_id, NULL, "Enumerate forms",                     "" },
3567         { "setprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter,         &ndr_table_spoolss.syntax_id, NULL, "Set printer comment",                 "" },
3568         { "setprintername",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername,     &ndr_table_spoolss.syntax_id, NULL, "Set printername",                 "" },
3569         { "setprinterdata",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata,     &ndr_table_spoolss.syntax_id, NULL, "Set REG_SZ printer data",             "" },
3570         { "rffpcnex",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex,           &ndr_table_spoolss.syntax_id, NULL, "Rffpcnex test", "" },
3571         { "printercmp",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_printercmp,         &ndr_table_spoolss.syntax_id, NULL, "Printer comparison test", "" },
3572         { "enumprocs",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_procs,         &ndr_table_spoolss.syntax_id, NULL, "Enumerate Print Processors",          "" },
3573         { "enumprocdatatypes",  RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_proc_data_types, &ndr_table_spoolss.syntax_id, NULL, "Enumerate Print Processor Data Types", "" },
3574         { "enummonitors",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_monitors,      &ndr_table_spoolss.syntax_id, NULL, "Enumerate Print Monitors", "" },
3575         { "createprinteric",    RPC_RTYPE_WERROR, NULL, cmd_spoolss_create_printer_ic,  &ndr_table_spoolss.syntax_id, NULL, "Create Printer IC", "" },
3576
3577         { NULL }
3578 };