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