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