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