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