s3-rpcclient: fix rpcclient after spoolss_SetPrinterData{Ex} IDL change.
[vlendec/samba-autobuild/.git] / source3 / rpcclient / cmd_spoolss.c
1 /*
2    Unix SMB/CIFS implementation.
3    RPC pipe client
4
5    Copyright (C) Gerald Carter                2001-2005
6    Copyright (C) Tim Potter                        2000
7    Copyright (C) Andrew Tridgell              1992-1999
8    Copyright (C) Luke Kenneth Casson Leighton 1996-1999
9    Copyright (C) Guenther Deschner                 2009
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "rpcclient.h"
27 #include "../librpc/gen_ndr/cli_spoolss.h"
28
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         DATA_BLOB blob;
2372
2373         /* parse the command arguments */
2374         if (argc < 5) {
2375                 printf ("Usage: %s <printer> <string|binary|dword|multistring>"
2376                         " <value> <data>\n",
2377                         argv[0]);
2378                 result = WERR_INVALID_PARAM;
2379                 goto done;
2380         }
2381
2382         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2383
2384         type = REG_NONE;
2385
2386         if (strequal(argv[2], "string")) {
2387                 type = REG_SZ;
2388         }
2389
2390         if (strequal(argv[2], "binary")) {
2391                 type = REG_BINARY;
2392         }
2393
2394         if (strequal(argv[2], "dword")) {
2395                 type = REG_DWORD;
2396         }
2397
2398         if (strequal(argv[2], "multistring")) {
2399                 type = REG_MULTI_SZ;
2400         }
2401
2402         if (type == REG_NONE) {
2403                 printf("Unknown data type: %s\n", argv[2]);
2404                 result =  WERR_INVALID_PARAM;
2405                 goto done;
2406         }
2407
2408         /* get a printer handle */
2409
2410         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2411                                                printername,
2412                                                SEC_FLAG_MAXIMUM_ALLOWED,
2413                                                &pol);
2414         if (!W_ERROR_IS_OK(result)) {
2415                 goto done;
2416         }
2417
2418         result = rpccli_spoolss_getprinter(cli, mem_ctx,
2419                                            &pol,
2420                                            0,
2421                                            0,
2422                                            &info);
2423         if (!W_ERROR_IS_OK(result)) {
2424                 goto done;
2425         }
2426
2427         printf("%s\n", current_timestring(mem_ctx, true));
2428         printf("\tchange_id (before set)\t:[0x%x]\n", info.info0.change_id);
2429
2430         /* Set the printer data */
2431
2432         switch (type) {
2433         case REG_SZ:
2434                 data.string = talloc_strdup(mem_ctx, argv[4]);
2435                 W_ERROR_HAVE_NO_MEMORY(data.string);
2436                 break;
2437         case REG_DWORD:
2438                 data.value = strtoul(argv[4], NULL, 10);
2439                 break;
2440         case REG_BINARY:
2441                 data.binary = strhex_to_data_blob(mem_ctx, argv[4]);
2442                 break;
2443         case REG_MULTI_SZ: {
2444                 int i, num_strings;
2445                 const char **strings = NULL;
2446
2447                 for (i=4; i<argc; i++) {
2448                         if (strcmp(argv[i], "NULL") == 0) {
2449                                 argv[i] = "";
2450                         }
2451                         if (!add_string_to_array(mem_ctx, argv[i],
2452                                                  &strings,
2453                                                  &num_strings)) {
2454                                 result = WERR_NOMEM;
2455                                 goto done;
2456                         }
2457                 }
2458                 data.string_array = talloc_zero_array(mem_ctx, const char *, num_strings + 1);
2459                 if (!data.string_array) {
2460                         result = WERR_NOMEM;
2461                         goto done;
2462                 }
2463                 for (i=0; i < num_strings; i++) {
2464                         data.string_array[i] = strings[i];
2465                 }
2466                 break;
2467                 }
2468         default:
2469                 printf("Unknown data type: %s\n", argv[2]);
2470                 result = WERR_INVALID_PARAM;
2471                 goto done;
2472         }
2473
2474         result = push_spoolss_PrinterData(mem_ctx, &blob, type, &data);
2475         if (!W_ERROR_IS_OK(result)) {
2476                 goto done;
2477         }
2478
2479         status = rpccli_spoolss_SetPrinterData(cli, mem_ctx,
2480                                                &pol,
2481                                                argv[3], /* value_name */
2482                                                type,
2483                                                blob.data,
2484                                                blob.length,
2485                                                &result);
2486         if (!W_ERROR_IS_OK(result)) {
2487                 printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]);
2488                 goto done;
2489         }
2490         printf("\tSetPrinterData succeeded [%s: %s]\n", argv[3], argv[4]);
2491
2492         result = rpccli_spoolss_getprinter(cli, mem_ctx,
2493                                            &pol,
2494                                            0,
2495                                            0,
2496                                            &info);
2497         if (!W_ERROR_IS_OK(result)) {
2498                 goto done;
2499         }
2500
2501         printf("%s\n", current_timestring(mem_ctx, true));
2502         printf("\tchange_id (after set)\t:[0x%x]\n", info.info0.change_id);
2503
2504 done:
2505         /* cleanup */
2506         if (is_valid_policy_hnd(&pol)) {
2507                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
2508         }
2509
2510         return result;
2511 }
2512
2513 /****************************************************************************
2514 ****************************************************************************/
2515
2516 static void display_job_info1(struct spoolss_JobInfo1 *r)
2517 {
2518         printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", r->position, r->job_id,
2519                r->user_name, r->document_name, r->text_status, r->pages_printed,
2520                r->total_pages);
2521 }
2522
2523 /****************************************************************************
2524 ****************************************************************************/
2525
2526 static void display_job_info2(struct spoolss_JobInfo2 *r)
2527 {
2528         printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n",
2529                r->position, r->job_id,
2530                r->user_name, r->document_name, r->text_status, r->pages_printed,
2531                r->total_pages, r->size);
2532 }
2533
2534 /****************************************************************************
2535 ****************************************************************************/
2536
2537 static void display_job_info3(struct spoolss_JobInfo3 *r)
2538 {
2539         printf("jobid[%d], next_jobid[%d]\n",
2540                 r->job_id, r->next_job_id);
2541 }
2542
2543 /****************************************************************************
2544 ****************************************************************************/
2545
2546 static void display_job_info4(struct spoolss_JobInfo4 *r)
2547 {
2548         printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d/%d bytes\n",
2549                r->position, r->job_id,
2550                r->user_name, r->document_name, r->text_status, r->pages_printed,
2551                r->total_pages, r->size, r->size_high);
2552 }
2553
2554 /****************************************************************************
2555 ****************************************************************************/
2556
2557 static WERROR cmd_spoolss_enum_jobs(struct rpc_pipe_client *cli,
2558                                       TALLOC_CTX *mem_ctx, int argc,
2559                                       const char **argv)
2560 {
2561         WERROR result;
2562         uint32_t level = 1, count, i;
2563         const char *printername;
2564         struct policy_handle hnd;
2565         union spoolss_JobInfo *info;
2566
2567         if (argc < 2 || argc > 3) {
2568                 printf("Usage: %s printername [level]\n", argv[0]);
2569                 return WERR_OK;
2570         }
2571
2572         if (argc == 3) {
2573                 level = atoi(argv[2]);
2574         }
2575
2576         /* Open printer handle */
2577
2578         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2579
2580         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2581                                                printername,
2582                                                SEC_FLAG_MAXIMUM_ALLOWED,
2583                                                &hnd);
2584         if (!W_ERROR_IS_OK(result))
2585                 goto done;
2586
2587         /* Enumerate ports */
2588
2589         result = rpccli_spoolss_enumjobs(cli, mem_ctx,
2590                                          &hnd,
2591                                          0, /* firstjob */
2592                                          1000, /* numjobs */
2593                                          level,
2594                                          0,
2595                                          &count,
2596                                          &info);
2597         if (!W_ERROR_IS_OK(result)) {
2598                 goto done;
2599         }
2600
2601         for (i = 0; i < count; i++) {
2602                 switch (level) {
2603                 case 1:
2604                         display_job_info1(&info[i].info1);
2605                         break;
2606                 case 2:
2607                         display_job_info2(&info[i].info2);
2608                         break;
2609                 default:
2610                         d_printf("unknown info level %d\n", level);
2611                         break;
2612                 }
2613         }
2614
2615 done:
2616         if (is_valid_policy_hnd(&hnd)) {
2617                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2618         }
2619
2620         return result;
2621 }
2622
2623 /****************************************************************************
2624 ****************************************************************************/
2625
2626 static WERROR cmd_spoolss_get_job(struct rpc_pipe_client *cli,
2627                                   TALLOC_CTX *mem_ctx, int argc,
2628                                   const char **argv)
2629 {
2630         WERROR result;
2631         const char *printername;
2632         struct policy_handle hnd;
2633         uint32_t job_id;
2634         uint32_t level = 1;
2635         union spoolss_JobInfo info;
2636
2637         if (argc < 3 || argc > 4) {
2638                 printf("Usage: %s printername job_id [level]\n", argv[0]);
2639                 return WERR_OK;
2640         }
2641
2642         job_id = atoi(argv[2]);
2643
2644         if (argc == 4) {
2645                 level = atoi(argv[3]);
2646         }
2647
2648         /* Open printer handle */
2649
2650         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2651
2652         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2653                                                printername,
2654                                                SEC_FLAG_MAXIMUM_ALLOWED,
2655                                                &hnd);
2656         if (!W_ERROR_IS_OK(result)) {
2657                 goto done;
2658         }
2659
2660         /* Enumerate ports */
2661
2662         result = rpccli_spoolss_getjob(cli, mem_ctx,
2663                                        &hnd,
2664                                        job_id,
2665                                        level,
2666                                        0,
2667                                        &info);
2668
2669         if (!W_ERROR_IS_OK(result)) {
2670                 goto done;
2671         }
2672
2673         switch (level) {
2674         case 1:
2675                 display_job_info1(&info.info1);
2676                 break;
2677         case 2:
2678                 display_job_info2(&info.info2);
2679                 break;
2680         case 3:
2681                 display_job_info3(&info.info3);
2682                 break;
2683         case 4:
2684                 display_job_info4(&info.info4);
2685                 break;
2686         default:
2687                 d_printf("unknown info level %d\n", level);
2688                 break;
2689         }
2690
2691 done:
2692         if (is_valid_policy_hnd(&hnd)) {
2693                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2694         }
2695
2696         return result;
2697 }
2698
2699 /****************************************************************************
2700 ****************************************************************************/
2701
2702 static WERROR cmd_spoolss_set_job(struct rpc_pipe_client *cli,
2703                                   TALLOC_CTX *mem_ctx, int argc,
2704                                   const char **argv)
2705 {
2706         WERROR result;
2707         NTSTATUS status;
2708         const char *printername;
2709         struct policy_handle hnd;
2710         uint32_t job_id;
2711         enum spoolss_JobControl command;
2712
2713         if (argc != 4) {
2714                 printf("Usage: %s printername job_id command\n", argv[0]);
2715                 return WERR_OK;
2716         }
2717
2718         job_id = atoi(argv[2]);
2719         command = atoi(argv[3]);
2720
2721         /* Open printer handle */
2722
2723         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2724
2725         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2726                                                printername,
2727                                                SEC_FLAG_MAXIMUM_ALLOWED,
2728                                                &hnd);
2729         if (!W_ERROR_IS_OK(result)) {
2730                 goto done;
2731         }
2732
2733         /* Set Job */
2734
2735         status = rpccli_spoolss_SetJob(cli, mem_ctx,
2736                                        &hnd,
2737                                        job_id,
2738                                        NULL,
2739                                        command,
2740                                        &result);
2741
2742         if (!W_ERROR_IS_OK(result)) {
2743                 goto done;
2744         }
2745
2746 done:
2747         if (is_valid_policy_hnd(&hnd)) {
2748                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2749         }
2750
2751         return result;
2752 }
2753
2754 /****************************************************************************
2755 ****************************************************************************/
2756
2757 static WERROR cmd_spoolss_enum_data(struct rpc_pipe_client *cli,
2758                                     TALLOC_CTX *mem_ctx, int argc,
2759                                     const char **argv)
2760 {
2761         WERROR result;
2762         NTSTATUS status;
2763         uint32_t i = 0;
2764         const char *printername;
2765         struct policy_handle hnd;
2766         uint32_t value_offered = 0;
2767         const char *value_name = NULL;
2768         uint32_t value_needed;
2769         enum winreg_Type type;
2770         uint8_t *data = NULL;
2771         uint32_t data_offered = 0;
2772         uint32_t data_needed;
2773
2774         if (argc != 2) {
2775                 printf("Usage: %s printername\n", argv[0]);
2776                 return WERR_OK;
2777         }
2778
2779         /* Open printer handle */
2780
2781         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2782
2783         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2784                                                printername,
2785                                                SEC_FLAG_MAXIMUM_ALLOWED,
2786                                                &hnd);
2787         if (!W_ERROR_IS_OK(result)) {
2788                 goto done;
2789         }
2790
2791         /* Enumerate data */
2792
2793         status = rpccli_spoolss_EnumPrinterData(cli, mem_ctx,
2794                                                 &hnd,
2795                                                 i,
2796                                                 value_name,
2797                                                 value_offered,
2798                                                 &value_needed,
2799                                                 &type,
2800                                                 data,
2801                                                 data_offered,
2802                                                 &data_needed,
2803                                                 &result);
2804
2805         data_offered    = data_needed;
2806         value_offered   = value_needed;
2807         data            = talloc_zero_array(mem_ctx, uint8_t, data_needed);
2808         value_name      = talloc_zero_array(mem_ctx, char, value_needed);
2809
2810         while (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(result)) {
2811
2812                 status = rpccli_spoolss_EnumPrinterData(cli, mem_ctx,
2813                                                         &hnd,
2814                                                         i++,
2815                                                         value_name,
2816                                                         value_offered,
2817                                                         &value_needed,
2818                                                         &type,
2819                                                         data,
2820                                                         data_offered,
2821                                                         &data_needed,
2822                                                         &result);
2823                 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(result)) {
2824                         struct regval_blob v;
2825                         fstrcpy(v.valuename, value_name);
2826                         v.type = type;
2827                         v.size = data_offered;
2828                         v.data_p = data;
2829                         display_reg_value(v);
2830                 }
2831         }
2832
2833         if (W_ERROR_V(result) == ERRnomoreitems) {
2834                 result = W_ERROR(ERRsuccess);
2835         }
2836
2837 done:
2838         if (is_valid_policy_hnd(&hnd)) {
2839                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2840         }
2841
2842         return result;
2843 }
2844
2845 /****************************************************************************
2846 ****************************************************************************/
2847
2848 static WERROR cmd_spoolss_enum_data_ex( struct rpc_pipe_client *cli,
2849                                           TALLOC_CTX *mem_ctx, int argc,
2850                                           const char **argv)
2851 {
2852         WERROR result;
2853         uint32_t i;
2854         const char *printername;
2855         struct policy_handle hnd;
2856         uint32_t count;
2857         struct spoolss_PrinterEnumValues *info;
2858
2859         if (argc != 3) {
2860                 printf("Usage: %s printername <keyname>\n", argv[0]);
2861                 return WERR_OK;
2862         }
2863
2864         /* Open printer handle */
2865
2866         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2867
2868         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2869                                                printername,
2870                                                SEC_FLAG_MAXIMUM_ALLOWED,
2871                                                &hnd);
2872         if (!W_ERROR_IS_OK(result)) {
2873                 goto done;
2874         }
2875
2876         /* Enumerate subkeys */
2877
2878         result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx,
2879                                                   &hnd,
2880                                                   argv[2],
2881                                                   0,
2882                                                   &count,
2883                                                   &info);
2884         if (!W_ERROR_IS_OK(result)) {
2885                 goto done;
2886         }
2887
2888         for (i=0; i < count; i++) {
2889                 display_printer_data(info[i].value_name,
2890                                      info[i].type,
2891                                      info[i].data);
2892         }
2893
2894  done:
2895         if (is_valid_policy_hnd(&hnd)) {
2896                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2897         }
2898
2899         return result;
2900 }
2901
2902 /****************************************************************************
2903 ****************************************************************************/
2904
2905 static WERROR cmd_spoolss_enum_printerkey(struct rpc_pipe_client *cli,
2906                                           TALLOC_CTX *mem_ctx, int argc,
2907                                           const char **argv)
2908 {
2909         WERROR result;
2910         const char *printername;
2911         const char *keyname = NULL;
2912         struct policy_handle hnd;
2913         const char **key_buffer = NULL;
2914         int i;
2915         uint32_t offered = 0;
2916
2917         if (argc < 2 || argc > 4) {
2918                 printf("Usage: %s printername [keyname] [offered]\n", argv[0]);
2919                 return WERR_OK;
2920         }
2921
2922         if (argc >= 3) {
2923                 keyname = argv[2];
2924         } else {
2925                 keyname = "";
2926         }
2927
2928         if (argc == 4) {
2929                 offered = atoi(argv[3]);
2930         }
2931
2932         /* Open printer handle */
2933
2934         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2935
2936         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2937                                                printername,
2938                                                SEC_FLAG_MAXIMUM_ALLOWED,
2939                                                &hnd);
2940         if (!W_ERROR_IS_OK(result)) {
2941                 goto done;
2942         }
2943
2944         /* Enumerate subkeys */
2945
2946         result = rpccli_spoolss_enumprinterkey(cli, mem_ctx,
2947                                                &hnd,
2948                                                keyname,
2949                                                &key_buffer,
2950                                                offered);
2951
2952         if (!W_ERROR_IS_OK(result)) {
2953                 goto done;
2954         }
2955
2956         for (i=0; key_buffer && key_buffer[i]; i++) {
2957                 printf("%s\n", key_buffer[i]);
2958         }
2959
2960  done:
2961
2962         if (is_valid_policy_hnd(&hnd)) {
2963                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2964         }
2965
2966         return result;
2967 }
2968
2969 /****************************************************************************
2970 ****************************************************************************/
2971
2972 static WERROR cmd_spoolss_rffpcnex(struct rpc_pipe_client *cli,
2973                                      TALLOC_CTX *mem_ctx, int argc,
2974                                      const char **argv)
2975 {
2976         const char *printername;
2977         const char *clientname;
2978         struct policy_handle hnd;
2979         WERROR result;
2980         NTSTATUS status;
2981         struct spoolss_NotifyOption option;
2982
2983         if (argc != 2) {
2984                 printf("Usage: %s printername\n", argv[0]);
2985                 result = WERR_OK;
2986                 goto done;
2987         }
2988
2989         /* Open printer */
2990
2991         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2992
2993         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2994                                                printername,
2995                                                SEC_FLAG_MAXIMUM_ALLOWED,
2996                                                &hnd);
2997         if (!W_ERROR_IS_OK(result)) {
2998                 printf("Error opening %s\n", argv[1]);
2999                 goto done;
3000         }
3001
3002         /* Create spool options */
3003
3004         option.version = 2;
3005         option.count = 2;
3006
3007         option.types = talloc_array(mem_ctx, struct spoolss_NotifyOptionType, 2);
3008         if (option.types == NULL) {
3009                 result = WERR_NOMEM;
3010                 goto done;
3011         }
3012
3013         option.types[0].type = PRINTER_NOTIFY_TYPE;
3014         option.types[0].count = 1;
3015         option.types[0].fields = talloc_array(mem_ctx, union spoolss_Field, 1);
3016         if (option.types[0].fields == NULL) {
3017                 result = WERR_NOMEM;
3018                 goto done;
3019         }
3020         option.types[0].fields[0].field = PRINTER_NOTIFY_FIELD_SERVER_NAME;
3021
3022         option.types[1].type = JOB_NOTIFY_TYPE;
3023         option.types[1].count = 1;
3024         option.types[1].fields = talloc_array(mem_ctx, union spoolss_Field, 1);
3025         if (option.types[1].fields == NULL) {
3026                 result = WERR_NOMEM;
3027                 goto done;
3028         }
3029         option.types[1].fields[0].field = JOB_NOTIFY_FIELD_PRINTER_NAME;
3030
3031         clientname = talloc_asprintf(mem_ctx, "\\\\%s", global_myname());
3032         if (!clientname) {
3033                 result = WERR_NOMEM;
3034                 goto done;
3035         }
3036
3037         /* Send rffpcnex */
3038
3039         status = rpccli_spoolss_RemoteFindFirstPrinterChangeNotifyEx(cli, mem_ctx,
3040                                                                      &hnd,
3041                                                                      0,
3042                                                                      0,
3043                                                                      clientname,
3044                                                                      123,
3045                                                                      &option,
3046                                                                      &result);
3047         if (!W_ERROR_IS_OK(result)) {
3048                 printf("Error rffpcnex %s\n", argv[1]);
3049                 goto done;
3050         }
3051
3052 done:
3053         if (is_valid_policy_hnd(&hnd))
3054                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
3055
3056         return result;
3057 }
3058
3059 /****************************************************************************
3060 ****************************************************************************/
3061
3062 static bool compare_printer( struct rpc_pipe_client *cli1, struct policy_handle *hnd1,
3063                              struct rpc_pipe_client *cli2, struct policy_handle *hnd2 )
3064 {
3065         union spoolss_PrinterInfo info1, info2;
3066         WERROR werror;
3067         TALLOC_CTX *mem_ctx = talloc_init("compare_printer");
3068
3069         printf("Retrieving printer propertiesfor %s...", cli1->desthost);
3070         werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
3071                                            hnd1,
3072                                            2,
3073                                            0,
3074                                            &info1);
3075         if ( !W_ERROR_IS_OK(werror) ) {
3076                 printf("failed (%s)\n", win_errstr(werror));
3077                 talloc_destroy(mem_ctx);
3078                 return false;
3079         }
3080         printf("ok\n");
3081
3082         printf("Retrieving printer properties for %s...", cli2->desthost);
3083         werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
3084                                            hnd2,
3085                                            2,
3086                                            0,
3087                                            &info2);
3088         if ( !W_ERROR_IS_OK(werror) ) {
3089                 printf("failed (%s)\n", win_errstr(werror));
3090                 talloc_destroy(mem_ctx);
3091                 return false;
3092         }
3093         printf("ok\n");
3094
3095         talloc_destroy(mem_ctx);
3096
3097         return true;
3098 }
3099
3100 /****************************************************************************
3101 ****************************************************************************/
3102
3103 static bool compare_printer_secdesc( struct rpc_pipe_client *cli1, struct policy_handle *hnd1,
3104                                      struct rpc_pipe_client *cli2, struct policy_handle *hnd2 )
3105 {
3106         union spoolss_PrinterInfo info1, info2;
3107         WERROR werror;
3108         TALLOC_CTX *mem_ctx = talloc_init("compare_printer_secdesc");
3109         SEC_DESC *sd1, *sd2;
3110         bool result = true;
3111
3112
3113         printf("Retrieving printer security for %s...", cli1->desthost);
3114         werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
3115                                            hnd1,
3116                                            3,
3117                                            0,
3118                                            &info1);
3119         if ( !W_ERROR_IS_OK(werror) ) {
3120                 printf("failed (%s)\n", win_errstr(werror));
3121                 result = false;
3122                 goto done;
3123         }
3124         printf("ok\n");
3125
3126         printf("Retrieving printer security for %s...", cli2->desthost);
3127         werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
3128                                            hnd2,
3129                                            3,
3130                                            0,
3131                                            &info2);
3132         if ( !W_ERROR_IS_OK(werror) ) {
3133                 printf("failed (%s)\n", win_errstr(werror));
3134                 result = false;
3135                 goto done;
3136         }
3137         printf("ok\n");
3138
3139
3140         printf("++ ");
3141
3142         sd1 = info1.info3.secdesc;
3143         sd2 = info2.info3.secdesc;
3144
3145         if ( (sd1 != sd2) && ( !sd1 || !sd2 ) ) {
3146                 printf("NULL secdesc!\n");
3147                 result = false;
3148                 goto done;
3149         }
3150
3151         if (!security_descriptor_equal( sd1, sd2 ) ) {
3152                 printf("Security Descriptors *not* equal!\n");
3153                 result = false;
3154                 goto done;
3155         }
3156
3157         printf("Security descriptors match\n");
3158
3159 done:
3160         talloc_destroy(mem_ctx);
3161         return result;
3162 }
3163
3164
3165 /****************************************************************************
3166 ****************************************************************************/
3167
3168 extern struct user_auth_info *rpcclient_auth_info;
3169
3170 static WERROR cmd_spoolss_printercmp(struct rpc_pipe_client *cli,
3171                                      TALLOC_CTX *mem_ctx, int argc,
3172                                      const char **argv)
3173 {
3174         const char *printername;
3175         char *printername_path = NULL;
3176         struct cli_state *cli_server2 = NULL;
3177         struct rpc_pipe_client *cli2 = NULL;
3178         struct policy_handle hPrinter1, hPrinter2;
3179         NTSTATUS nt_status;
3180         WERROR werror;
3181
3182         if ( argc != 3 )  {
3183                 printf("Usage: %s <printer> <server>\n", argv[0]);
3184                 return WERR_OK;
3185         }
3186
3187         printername = argv[1];
3188
3189         /* first get the connection to the remote server */
3190
3191         nt_status = cli_full_connection(&cli_server2, global_myname(), argv[2],
3192                                         NULL, 0,
3193                                         "IPC$", "IPC",
3194                                         get_cmdline_auth_info_username(rpcclient_auth_info),
3195                                         lp_workgroup(),
3196                                         get_cmdline_auth_info_password(rpcclient_auth_info),
3197                                         get_cmdline_auth_info_use_kerberos(rpcclient_auth_info) ? CLI_FULL_CONNECTION_USE_KERBEROS : 0,
3198                                         get_cmdline_auth_info_signing_state(rpcclient_auth_info), NULL);
3199
3200         if ( !NT_STATUS_IS_OK(nt_status) )
3201                 return WERR_GENERAL_FAILURE;
3202
3203         nt_status = cli_rpc_pipe_open_noauth(cli_server2, &ndr_table_spoolss.syntax_id,
3204                                              &cli2);
3205         if (!NT_STATUS_IS_OK(nt_status)) {
3206                 printf("failed to open spoolss pipe on server %s (%s)\n",
3207                         argv[2], nt_errstr(nt_status));
3208                 return WERR_GENERAL_FAILURE;
3209         }
3210
3211         /* now open up both printers */
3212
3213         RPCCLIENT_PRINTERNAME(printername_path, cli, printername);
3214
3215         printf("Opening %s...", printername_path);
3216
3217         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3218                                                printername_path,
3219                                                PRINTER_ALL_ACCESS,
3220                                                &hPrinter1);
3221         if ( !W_ERROR_IS_OK(werror) ) {
3222                 printf("failed (%s)\n", win_errstr(werror));
3223                 goto done;
3224         }
3225         printf("ok\n");
3226
3227         RPCCLIENT_PRINTERNAME(printername_path, cli2, printername);
3228
3229         printf("Opening %s...", printername_path);
3230         werror = rpccli_spoolss_openprinter_ex(cli2, mem_ctx,
3231                                                printername_path,
3232                                                PRINTER_ALL_ACCESS,
3233                                                &hPrinter2);
3234         if ( !W_ERROR_IS_OK(werror) ) {
3235                  printf("failed (%s)\n", win_errstr(werror));
3236                 goto done;
3237         }
3238         printf("ok\n");
3239
3240         compare_printer( cli, &hPrinter1, cli2, &hPrinter2 );
3241         compare_printer_secdesc( cli, &hPrinter1, cli2, &hPrinter2 );
3242 #if 0
3243         compare_printerdata( cli_server1, &hPrinter1, cli_server2, &hPrinter2 );
3244 #endif
3245
3246
3247 done:
3248         /* cleanup */
3249
3250         printf("Closing printers...");
3251         rpccli_spoolss_ClosePrinter( cli, mem_ctx, &hPrinter1, NULL );
3252         rpccli_spoolss_ClosePrinter( cli2, mem_ctx, &hPrinter2, NULL );
3253         printf("ok\n");
3254
3255         /* close the second remote connection */
3256
3257         cli_shutdown( cli_server2 );
3258         return WERR_OK;
3259 }
3260
3261 static void display_proc_info1(struct spoolss_PrintProcessorInfo1 *r)
3262 {
3263         printf("print_processor_name: %s\n", r->print_processor_name);
3264 }
3265
3266 static WERROR cmd_spoolss_enum_procs(struct rpc_pipe_client *cli,
3267                                      TALLOC_CTX *mem_ctx, int argc,
3268                                      const char **argv)
3269 {
3270         WERROR werror;
3271         const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
3272         uint32_t num_procs, level = 1, i;
3273         union spoolss_PrintProcessorInfo *procs;
3274
3275         /* Parse the command arguments */
3276
3277         if (argc < 1 || argc > 4) {
3278                 printf ("Usage: %s [environment] [level]\n", argv[0]);
3279                 return WERR_OK;
3280         }
3281
3282         if (argc >= 2) {
3283                 environment = argv[1];
3284         }
3285
3286         if (argc == 3) {
3287                 level = atoi(argv[2]);
3288         }
3289
3290         /* Enumerate Print Processors */
3291
3292         werror = rpccli_spoolss_enumprintprocessors(cli, mem_ctx,
3293                                                     cli->srv_name_slash,
3294                                                     environment,
3295                                                     level,
3296                                                     0,
3297                                                     &num_procs,
3298                                                     &procs);
3299         if (!W_ERROR_IS_OK(werror))
3300                 goto done;
3301
3302         /* Display output */
3303
3304         for (i = 0; i < num_procs; i++) {
3305                 switch (level) {
3306                 case 1:
3307                         display_proc_info1(&procs[i].info1);
3308                         break;
3309                 }
3310         }
3311
3312  done:
3313         return werror;
3314 }
3315
3316 static void display_proc_data_types_info1(struct spoolss_PrintProcDataTypesInfo1 *r)
3317 {
3318         printf("name_array: %s\n", r->name_array);
3319 }
3320
3321 static WERROR cmd_spoolss_enum_proc_data_types(struct rpc_pipe_client *cli,
3322                                                TALLOC_CTX *mem_ctx, int argc,
3323                                                const char **argv)
3324 {
3325         WERROR werror;
3326         const char *print_processor_name = "winprint";
3327         uint32_t num_procs, level = 1, i;
3328         union spoolss_PrintProcDataTypesInfo *procs;
3329
3330         /* Parse the command arguments */
3331
3332         if (argc < 1 || argc > 4) {
3333                 printf ("Usage: %s [environment] [level]\n", argv[0]);
3334                 return WERR_OK;
3335         }
3336
3337         if (argc >= 2) {
3338                 print_processor_name = argv[1];
3339         }
3340
3341         if (argc == 3) {
3342                 level = atoi(argv[2]);
3343         }
3344
3345         /* Enumerate Print Processor Data Types */
3346
3347         werror = rpccli_spoolss_enumprintprocessordatatypes(cli, mem_ctx,
3348                                                             cli->srv_name_slash,
3349                                                             print_processor_name,
3350                                                             level,
3351                                                             0,
3352                                                             &num_procs,
3353                                                             &procs);
3354         if (!W_ERROR_IS_OK(werror))
3355                 goto done;
3356
3357         /* Display output */
3358
3359         for (i = 0; i < num_procs; i++) {
3360                 switch (level) {
3361                 case 1:
3362                         display_proc_data_types_info1(&procs[i].info1);
3363                         break;
3364                 }
3365         }
3366
3367  done:
3368         return werror;
3369 }
3370
3371 static void display_monitor1(const struct spoolss_MonitorInfo1 *r)
3372 {
3373         printf("monitor_name: %s\n", r->monitor_name);
3374 }
3375
3376 static void display_monitor2(const struct spoolss_MonitorInfo2 *r)
3377 {
3378         printf("monitor_name: %s\n", r->monitor_name);
3379         printf("environment: %s\n", r->environment);
3380         printf("dll_name: %s\n", r->dll_name);
3381 }
3382
3383 static WERROR cmd_spoolss_enum_monitors(struct rpc_pipe_client *cli,
3384                                         TALLOC_CTX *mem_ctx, int argc,
3385                                         const char **argv)
3386 {
3387         WERROR werror;
3388         uint32_t count, level = 1, i;
3389         union spoolss_MonitorInfo *info;
3390
3391         /* Parse the command arguments */
3392
3393         if (argc > 2) {
3394                 printf("Usage: %s [level]\n", argv[0]);
3395                 return WERR_OK;
3396         }
3397
3398         if (argc == 2) {
3399                 level = atoi(argv[1]);
3400         }
3401
3402         /* Enumerate Print Monitors */
3403
3404         werror = rpccli_spoolss_enummonitors(cli, mem_ctx,
3405                                              cli->srv_name_slash,
3406                                              level,
3407                                              0,
3408                                              &count,
3409                                              &info);
3410         if (!W_ERROR_IS_OK(werror)) {
3411                 goto done;
3412         }
3413
3414         /* Display output */
3415
3416         for (i = 0; i < count; i++) {
3417                 switch (level) {
3418                 case 1:
3419                         display_monitor1(&info[i].info1);
3420                         break;
3421                 case 2:
3422                         display_monitor2(&info[i].info2);
3423                         break;
3424                 }
3425         }
3426
3427  done:
3428         return werror;
3429 }
3430
3431 static WERROR cmd_spoolss_create_printer_ic(struct rpc_pipe_client *cli,
3432                                             TALLOC_CTX *mem_ctx, int argc,
3433                                             const char **argv)
3434 {
3435         WERROR result;
3436         NTSTATUS status;
3437         struct policy_handle handle, gdi_handle;
3438         const char *printername;
3439         struct spoolss_DevmodeContainer devmode_ctr;
3440
3441         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3442
3443         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3444                                                printername,
3445                                                SEC_FLAG_MAXIMUM_ALLOWED,
3446                                                &handle);
3447         if (!W_ERROR_IS_OK(result)) {
3448                 return result;
3449         }
3450
3451         ZERO_STRUCT(devmode_ctr);
3452
3453         status = rpccli_spoolss_CreatePrinterIC(cli, mem_ctx,
3454                                                 &handle,
3455                                                 &gdi_handle,
3456                                                 &devmode_ctr,
3457                                                 &result);
3458         if (!W_ERROR_IS_OK(result)) {
3459                 goto done;
3460         }
3461
3462  done:
3463         if (is_valid_policy_hnd(&gdi_handle)) {
3464                 rpccli_spoolss_DeletePrinterIC(cli, mem_ctx, &gdi_handle, NULL);
3465         }
3466         if (is_valid_policy_hnd(&handle)) {
3467                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
3468         }
3469
3470         return result;
3471 }
3472
3473 /* List of commands exported by this module */
3474 struct cmd_set spoolss_commands[] = {
3475
3476         { "SPOOLSS"  },
3477
3478         { "adddriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterdriver,   &ndr_table_spoolss.syntax_id, NULL, "Add a print driver",                  "" },
3479         { "addprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterex,       &ndr_table_spoolss.syntax_id, NULL, "Add a printer",                       "" },
3480         { "deldriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriver,       &ndr_table_spoolss.syntax_id, NULL, "Delete a printer driver",             "" },
3481         { "deldriverex",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriverex,     &ndr_table_spoolss.syntax_id, NULL, "Delete a printer driver with files",  "" },
3482         { "enumdata",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data,          &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer data",              "" },
3483         { "enumdataex",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data_ex,       &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer data for a key",    "" },
3484         { "enumkey",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printerkey,    &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer keys",              "" },
3485         { "enumjobs",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_jobs,          &ndr_table_spoolss.syntax_id, NULL, "Enumerate print jobs",                "" },
3486         { "getjob",             RPC_RTYPE_WERROR, NULL, cmd_spoolss_get_job,            &ndr_table_spoolss.syntax_id, NULL, "Get print job",                       "" },
3487         { "setjob",             RPC_RTYPE_WERROR, NULL, cmd_spoolss_set_job,            &ndr_table_spoolss.syntax_id, NULL, "Set print job",                       "" },
3488         { "enumports",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_ports,         &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer ports",             "" },
3489         { "enumdrivers",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_drivers,       &ndr_table_spoolss.syntax_id, NULL, "Enumerate installed printer drivers", "" },
3490         { "enumprinters",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printers,      &ndr_table_spoolss.syntax_id, NULL, "Enumerate printers",                  "" },
3491         { "getdata",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdata,     &ndr_table_spoolss.syntax_id, NULL, "Get print driver data",               "" },
3492         { "getdataex",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdataex,   &ndr_table_spoolss.syntax_id, NULL, "Get printer driver data with keyname", ""},
3493         { "getdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriver,          &ndr_table_spoolss.syntax_id, NULL, "Get print driver information",        "" },
3494         { "getdriverdir",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriverdir,       &ndr_table_spoolss.syntax_id, NULL, "Get print driver upload directory",   "" },
3495         { "getprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinter,         &ndr_table_spoolss.syntax_id, NULL, "Get printer info",                    "" },
3496         { "openprinter",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer_ex,    &ndr_table_spoolss.syntax_id, NULL, "Open printer handle",                 "" },
3497         { "setdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_setdriver,          &ndr_table_spoolss.syntax_id, NULL, "Set printer driver",                  "" },
3498         { "getprintprocdir",    RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprintprocdir,    &ndr_table_spoolss.syntax_id, NULL, "Get print processor directory",       "" },
3499         { "addform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_addform,            &ndr_table_spoolss.syntax_id, NULL, "Add form",                            "" },
3500         { "setform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_setform,            &ndr_table_spoolss.syntax_id, NULL, "Set form",                            "" },
3501         { "getform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getform,            &ndr_table_spoolss.syntax_id, NULL, "Get form",                            "" },
3502         { "deleteform",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform,         &ndr_table_spoolss.syntax_id, NULL, "Delete form",                         "" },
3503         { "enumforms",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms,         &ndr_table_spoolss.syntax_id, NULL, "Enumerate forms",                     "" },
3504         { "setprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter,         &ndr_table_spoolss.syntax_id, NULL, "Set printer comment",                 "" },
3505         { "setprintername",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername,     &ndr_table_spoolss.syntax_id, NULL, "Set printername",                 "" },
3506         { "setprinterdata",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata,     &ndr_table_spoolss.syntax_id, NULL, "Set REG_SZ printer data",             "" },
3507         { "rffpcnex",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex,           &ndr_table_spoolss.syntax_id, NULL, "Rffpcnex test", "" },
3508         { "printercmp",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_printercmp,         &ndr_table_spoolss.syntax_id, NULL, "Printer comparison test", "" },
3509         { "enumprocs",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_procs,         &ndr_table_spoolss.syntax_id, NULL, "Enumerate Print Processors",          "" },
3510         { "enumprocdatatypes",  RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_proc_data_types, &ndr_table_spoolss.syntax_id, NULL, "Enumerate Print Processor Data Types", "" },
3511         { "enummonitors",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_monitors,      &ndr_table_spoolss.syntax_id, NULL, "Enumerate Print Monitors", "" },
3512         { "createprinteric",    RPC_RTYPE_WERROR, NULL, cmd_spoolss_create_printer_ic,  &ndr_table_spoolss.syntax_id, NULL, "Create Printer IC", "" },
3513
3514         { NULL }
3515 };