s3-rpcclient: Fix bug #7880: cmd_spoolss_deletedriver() returned without checking...
[samba.git] / source3 / rpcclient / cmd_spoolss.c
1 /*
2    Unix SMB/CIFS implementation.
3    RPC pipe client
4
5    Copyright (C) Gerald Carter                2001-2005
6    Copyright (C) Tim Potter                        2000
7    Copyright (C) Andrew Tridgell              1992-1999
8    Copyright (C) Luke Kenneth Casson Leighton 1996-1999
9    Copyright (C) Guenther Deschner                 2009
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "rpcclient.h"
27
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                 result = WERR_OK;
1922
1923                 /* make the call to remove the driver */
1924                 status = rpccli_spoolss_DeletePrinterDriver(cli, mem_ctx,
1925                                                             cli->srv_name_slash,
1926                                                             archi_table[i].long_archi,
1927                                                             argv[1],
1928                                                             &result);
1929                 if (!NT_STATUS_IS_OK(status)) {
1930                         if (W_ERROR_IS_OK(result)) {
1931                                 result = ntstatus_to_werror(status);
1932                         }
1933                 }
1934                 if ( !W_ERROR_IS_OK(result) ) {
1935                         if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1936                                 printf ("Failed to remove driver %s for arch [%s] - error 0x%x!\n",
1937                                         argv[1], archi_table[i].long_archi,
1938                                         W_ERROR_V(result));
1939                         }
1940                 } else {
1941                         printf ("Driver %s removed for arch [%s].\n", argv[1],
1942                                 archi_table[i].long_archi);
1943                 }
1944         }
1945
1946         return result;
1947 }
1948
1949 /****************************************************************************
1950 ****************************************************************************/
1951
1952 static WERROR cmd_spoolss_getprintprocdir(struct rpc_pipe_client *cli,
1953                                             TALLOC_CTX *mem_ctx,
1954                                             int argc, const char **argv)
1955 {
1956         WERROR result;
1957         NTSTATUS status;
1958         const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
1959         DATA_BLOB buffer;
1960         uint32_t offered;
1961         union spoolss_PrintProcessorDirectoryInfo info;
1962         uint32_t needed;
1963
1964         /* parse the command arguments */
1965         if (argc > 2) {
1966                 printf ("Usage: %s [environment]\n", argv[0]);
1967                 return WERR_OK;
1968         }
1969
1970         if (argc == 2) {
1971                 environment = argv[1];
1972         }
1973
1974         status = rpccli_spoolss_GetPrintProcessorDirectory(cli, mem_ctx,
1975                                                            cli->srv_name_slash,
1976                                                            environment,
1977                                                            1,
1978                                                            NULL, /* buffer */
1979                                                            0, /* offered */
1980                                                            NULL, /* info */
1981                                                            &needed,
1982                                                            &result);
1983         if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) {
1984                 offered = needed;
1985                 buffer = data_blob_talloc_zero(mem_ctx, needed);
1986
1987                 status = rpccli_spoolss_GetPrintProcessorDirectory(cli, mem_ctx,
1988                                                                    cli->srv_name_slash,
1989                                                                    environment,
1990                                                                    1,
1991                                                                    &buffer,
1992                                                                    offered,
1993                                                                    &info,
1994                                                                    &needed,
1995                                                                    &result);
1996         }
1997
1998         if (W_ERROR_IS_OK(result)) {
1999                 printf("%s\n", info.info1.directory_name);
2000         }
2001
2002         return result;
2003 }
2004
2005 /****************************************************************************
2006 ****************************************************************************/
2007
2008 static WERROR cmd_spoolss_addform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
2009                                     int argc, const char **argv)
2010 {
2011         struct policy_handle handle;
2012         WERROR werror;
2013         NTSTATUS status;
2014         const char *printername;
2015         union spoolss_AddFormInfo info;
2016         struct spoolss_AddFormInfo1 info1;
2017         struct spoolss_AddFormInfo2 info2;
2018         uint32_t level = 1;
2019
2020         /* Parse the command arguments */
2021
2022         if (argc < 3 || argc > 5) {
2023                 printf ("Usage: %s <printer> <formname> [level]\n", argv[0]);
2024                 return WERR_OK;
2025         }
2026
2027         /* Get a printer handle */
2028
2029         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2030
2031         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2032                                                printername,
2033                                                PRINTER_ALL_ACCESS,
2034                                                &handle);
2035         if (!W_ERROR_IS_OK(werror))
2036                 goto done;
2037
2038         /* Dummy up some values for the form data */
2039
2040         if (argc == 4) {
2041                 level = atoi(argv[3]);
2042         }
2043
2044         switch (level) {
2045         case 1:
2046                 info1.flags             = SPOOLSS_FORM_USER;
2047                 info1.form_name         = argv[2];
2048                 info1.size.width        = 100;
2049                 info1.size.height       = 100;
2050                 info1.area.left         = 0;
2051                 info1.area.top          = 10;
2052                 info1.area.right        = 20;
2053                 info1.area.bottom       = 30;
2054
2055                 info.info1 = &info1;
2056
2057                 break;
2058         case 2:
2059                 info2.flags             = SPOOLSS_FORM_USER;
2060                 info2.form_name         = argv[2];
2061                 info2.size.width        = 100;
2062                 info2.size.height       = 100;
2063                 info2.area.left         = 0;
2064                 info2.area.top          = 10;
2065                 info2.area.right        = 20;
2066                 info2.area.bottom       = 30;
2067                 info2.keyword           = argv[2];
2068                 info2.string_type       = SPOOLSS_FORM_STRING_TYPE_NONE;
2069                 info2.mui_dll           = NULL;
2070                 info2.ressource_id      = 0;
2071                 info2.display_name      = argv[2];
2072                 info2.lang_id           = 0;
2073
2074                 info.info2 = &info2;
2075
2076                 break;
2077         }
2078
2079         /* Add the form */
2080
2081
2082         status = rpccli_spoolss_AddForm(cli, mem_ctx,
2083                                         &handle,
2084                                         level,
2085                                         info,
2086                                         &werror);
2087
2088  done:
2089         if (is_valid_policy_hnd(&handle))
2090                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2091
2092         return werror;
2093 }
2094
2095 /****************************************************************************
2096 ****************************************************************************/
2097
2098 static WERROR cmd_spoolss_setform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
2099                                     int argc, const char **argv)
2100 {
2101         struct policy_handle handle;
2102         WERROR werror;
2103         NTSTATUS status;
2104         const char *printername;
2105         union spoolss_AddFormInfo info;
2106         struct spoolss_AddFormInfo1 info1;
2107
2108         /* Parse the command arguments */
2109
2110         if (argc != 3) {
2111                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
2112                 return WERR_OK;
2113         }
2114
2115         /* Get a printer handle */
2116
2117         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2118
2119         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2120                                                printername,
2121                                                SEC_FLAG_MAXIMUM_ALLOWED,
2122                                                &handle);
2123         if (!W_ERROR_IS_OK(werror))
2124                 goto done;
2125
2126         /* Dummy up some values for the form data */
2127
2128         info1.flags             = SPOOLSS_FORM_PRINTER;
2129         info1.size.width        = 100;
2130         info1.size.height       = 100;
2131         info1.area.left         = 0;
2132         info1.area.top          = 1000;
2133         info1.area.right        = 2000;
2134         info1.area.bottom       = 3000;
2135         info1.form_name         = argv[2];
2136
2137         info.info1 = &info1;
2138
2139         /* Set the form */
2140
2141         status = rpccli_spoolss_SetForm(cli, mem_ctx,
2142                                         &handle,
2143                                         argv[2],
2144                                         1,
2145                                         info,
2146                                         &werror);
2147
2148  done:
2149         if (is_valid_policy_hnd(&handle))
2150                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2151
2152         return werror;
2153 }
2154
2155 /****************************************************************************
2156 ****************************************************************************/
2157
2158 static const char *get_form_flag(int form_flag)
2159 {
2160         switch (form_flag) {
2161         case SPOOLSS_FORM_USER:
2162                 return "FORM_USER";
2163         case SPOOLSS_FORM_BUILTIN:
2164                 return "FORM_BUILTIN";
2165         case SPOOLSS_FORM_PRINTER:
2166                 return "FORM_PRINTER";
2167         default:
2168                 return "unknown";
2169         }
2170 }
2171
2172 /****************************************************************************
2173 ****************************************************************************/
2174
2175 static void display_form_info1(struct spoolss_FormInfo1 *r)
2176 {
2177         printf("%s\n" \
2178                 "\tflag: %s (%d)\n" \
2179                 "\twidth: %d, length: %d\n" \
2180                 "\tleft: %d, right: %d, top: %d, bottom: %d\n\n",
2181                 r->form_name, get_form_flag(r->flags), r->flags,
2182                 r->size.width, r->size.height,
2183                 r->area.left, r->area.right,
2184                 r->area.top, r->area.bottom);
2185 }
2186
2187 /****************************************************************************
2188 ****************************************************************************/
2189
2190 static void display_form_info2(struct spoolss_FormInfo2 *r)
2191 {
2192         printf("%s\n" \
2193                 "\tflag: %s (%d)\n" \
2194                 "\twidth: %d, length: %d\n" \
2195                 "\tleft: %d, right: %d, top: %d, bottom: %d\n",
2196                 r->form_name, get_form_flag(r->flags), r->flags,
2197                 r->size.width, r->size.height,
2198                 r->area.left, r->area.right,
2199                 r->area.top, r->area.bottom);
2200         printf("\tkeyword: %s\n", r->keyword);
2201         printf("\tstring_type: 0x%08x\n", r->string_type);
2202         printf("\tmui_dll: %s\n", r->mui_dll);
2203         printf("\tressource_id: 0x%08x\n", r->ressource_id);
2204         printf("\tdisplay_name: %s\n", r->display_name);
2205         printf("\tlang_id: %d\n", r->lang_id);
2206         printf("\n");
2207 }
2208
2209 /****************************************************************************
2210 ****************************************************************************/
2211
2212 static WERROR cmd_spoolss_getform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
2213                                     int argc, const char **argv)
2214 {
2215         struct policy_handle handle;
2216         WERROR werror;
2217         NTSTATUS status;
2218         const char *printername;
2219         DATA_BLOB buffer;
2220         uint32_t offered = 0;
2221         union spoolss_FormInfo info;
2222         uint32_t needed;
2223         uint32_t level = 1;
2224
2225         /* Parse the command arguments */
2226
2227         if (argc < 3 || argc > 5) {
2228                 printf ("Usage: %s <printer> <formname> [level]\n", argv[0]);
2229                 return WERR_OK;
2230         }
2231
2232         /* Get a printer handle */
2233
2234         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2235
2236         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2237                                                printername,
2238                                                SEC_FLAG_MAXIMUM_ALLOWED,
2239                                                &handle);
2240         if (!W_ERROR_IS_OK(werror))
2241                 goto done;
2242
2243         if (argc == 4) {
2244                 level = atoi(argv[3]);
2245         }
2246
2247         /* Get the form */
2248
2249         status = rpccli_spoolss_GetForm(cli, mem_ctx,
2250                                         &handle,
2251                                         argv[2],
2252                                         level,
2253                                         NULL,
2254                                         offered,
2255                                         &info,
2256                                         &needed,
2257                                         &werror);
2258         if (W_ERROR_EQUAL(werror, WERR_INSUFFICIENT_BUFFER)) {
2259                 buffer = data_blob_talloc_zero(mem_ctx, needed);
2260                 offered = needed;
2261                 status = rpccli_spoolss_GetForm(cli, mem_ctx,
2262                                                 &handle,
2263                                                 argv[2],
2264                                                 level,
2265                                                 &buffer,
2266                                                 offered,
2267                                                 &info,
2268                                                 &needed,
2269                                                 &werror);
2270         }
2271
2272         if (!NT_STATUS_IS_OK(status)) {
2273                 return werror;
2274         }
2275
2276         switch (level) {
2277         case 1:
2278                 display_form_info1(&info.info1);
2279                 break;
2280         case 2:
2281                 display_form_info2(&info.info2);
2282                 break;
2283         }
2284
2285  done:
2286         if (is_valid_policy_hnd(&handle))
2287                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2288
2289         return werror;
2290 }
2291
2292 /****************************************************************************
2293 ****************************************************************************/
2294
2295 static WERROR cmd_spoolss_deleteform(struct rpc_pipe_client *cli,
2296                                        TALLOC_CTX *mem_ctx, int argc,
2297                                        const char **argv)
2298 {
2299         struct policy_handle handle;
2300         WERROR werror;
2301         NTSTATUS status;
2302         const char *printername;
2303
2304         /* Parse the command arguments */
2305
2306         if (argc != 3) {
2307                 printf ("Usage: %s <printer> <formname>\n", argv[0]);
2308                 return WERR_OK;
2309         }
2310
2311         /* Get a printer handle */
2312
2313         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2314
2315         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2316                                                printername,
2317                                                SEC_FLAG_MAXIMUM_ALLOWED,
2318                                                &handle);
2319         if (!W_ERROR_IS_OK(werror))
2320                 goto done;
2321
2322         /* Delete the form */
2323
2324         status = rpccli_spoolss_DeleteForm(cli, mem_ctx,
2325                                            &handle,
2326                                            argv[2],
2327                                            &werror);
2328         if (!NT_STATUS_IS_OK(status)) {
2329                 return ntstatus_to_werror(status);
2330         }
2331
2332  done:
2333         if (is_valid_policy_hnd(&handle))
2334                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2335
2336         return werror;
2337 }
2338
2339 /****************************************************************************
2340 ****************************************************************************/
2341
2342 static WERROR cmd_spoolss_enum_forms(struct rpc_pipe_client *cli,
2343                                        TALLOC_CTX *mem_ctx, int argc,
2344                                        const char **argv)
2345 {
2346         struct policy_handle handle;
2347         WERROR werror;
2348         const char *printername;
2349         uint32_t num_forms, level = 1, i;
2350         union spoolss_FormInfo *forms;
2351
2352         /* Parse the command arguments */
2353
2354         if (argc < 2 || argc > 4) {
2355                 printf ("Usage: %s <printer> [level]\n", argv[0]);
2356                 return WERR_OK;
2357         }
2358
2359         /* Get a printer handle */
2360
2361         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2362
2363         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2364                                                printername,
2365                                                SEC_FLAG_MAXIMUM_ALLOWED,
2366                                                &handle);
2367         if (!W_ERROR_IS_OK(werror))
2368                 goto done;
2369
2370         if (argc == 3) {
2371                 level = atoi(argv[2]);
2372         }
2373
2374         /* Enumerate forms */
2375
2376         werror = rpccli_spoolss_enumforms(cli, mem_ctx,
2377                                           &handle,
2378                                           level,
2379                                           0,
2380                                           &num_forms,
2381                                           &forms);
2382
2383         if (!W_ERROR_IS_OK(werror))
2384                 goto done;
2385
2386         /* Display output */
2387
2388         for (i = 0; i < num_forms; i++) {
2389                 switch (level) {
2390                 case 1:
2391                         display_form_info1(&forms[i].info1);
2392                         break;
2393                 case 2:
2394                         display_form_info2(&forms[i].info2);
2395                         break;
2396                 }
2397         }
2398
2399  done:
2400         if (is_valid_policy_hnd(&handle))
2401                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2402
2403         return werror;
2404 }
2405
2406 /****************************************************************************
2407 ****************************************************************************/
2408
2409 static WERROR cmd_spoolss_setprinterdata(struct rpc_pipe_client *cli,
2410                                             TALLOC_CTX *mem_ctx,
2411                                             int argc, const char **argv)
2412 {
2413         WERROR result;
2414         NTSTATUS status;
2415         const char *printername;
2416         struct policy_handle pol;
2417         union spoolss_PrinterInfo info;
2418         enum winreg_Type type;
2419         union spoolss_PrinterData data;
2420         DATA_BLOB blob;
2421
2422         /* parse the command arguments */
2423         if (argc < 5) {
2424                 printf ("Usage: %s <printer> <string|binary|dword|multistring>"
2425                         " <value> <data>\n",
2426                         argv[0]);
2427                 result = WERR_INVALID_PARAM;
2428                 goto done;
2429         }
2430
2431         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2432
2433         type = REG_NONE;
2434
2435         if (strequal(argv[2], "string")) {
2436                 type = REG_SZ;
2437         }
2438
2439         if (strequal(argv[2], "binary")) {
2440                 type = REG_BINARY;
2441         }
2442
2443         if (strequal(argv[2], "dword")) {
2444                 type = REG_DWORD;
2445         }
2446
2447         if (strequal(argv[2], "multistring")) {
2448                 type = REG_MULTI_SZ;
2449         }
2450
2451         if (type == REG_NONE) {
2452                 printf("Unknown data type: %s\n", argv[2]);
2453                 result =  WERR_INVALID_PARAM;
2454                 goto done;
2455         }
2456
2457         /* get a printer handle */
2458
2459         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2460                                                printername,
2461                                                SEC_FLAG_MAXIMUM_ALLOWED,
2462                                                &pol);
2463         if (!W_ERROR_IS_OK(result)) {
2464                 goto done;
2465         }
2466
2467         result = rpccli_spoolss_getprinter(cli, mem_ctx,
2468                                            &pol,
2469                                            0,
2470                                            0,
2471                                            &info);
2472         if (!W_ERROR_IS_OK(result)) {
2473                 goto done;
2474         }
2475
2476         printf("%s\n", current_timestring(mem_ctx, true));
2477         printf("\tchange_id (before set)\t:[0x%x]\n", info.info0.change_id);
2478
2479         /* Set the printer data */
2480
2481         switch (type) {
2482         case REG_SZ:
2483                 data.string = talloc_strdup(mem_ctx, argv[4]);
2484                 W_ERROR_HAVE_NO_MEMORY(data.string);
2485                 break;
2486         case REG_DWORD:
2487                 data.value = strtoul(argv[4], NULL, 10);
2488                 break;
2489         case REG_BINARY:
2490                 data.binary = strhex_to_data_blob(mem_ctx, argv[4]);
2491                 break;
2492         case REG_MULTI_SZ: {
2493                 int i, num_strings;
2494                 const char **strings = NULL;
2495
2496                 for (i=4; i<argc; i++) {
2497                         if (strcmp(argv[i], "NULL") == 0) {
2498                                 argv[i] = "";
2499                         }
2500                         if (!add_string_to_array(mem_ctx, argv[i],
2501                                                  &strings,
2502                                                  &num_strings)) {
2503                                 result = WERR_NOMEM;
2504                                 goto done;
2505                         }
2506                 }
2507                 data.string_array = talloc_zero_array(mem_ctx, const char *, num_strings + 1);
2508                 if (!data.string_array) {
2509                         result = WERR_NOMEM;
2510                         goto done;
2511                 }
2512                 for (i=0; i < num_strings; i++) {
2513                         data.string_array[i] = strings[i];
2514                 }
2515                 break;
2516                 }
2517         default:
2518                 printf("Unknown data type: %s\n", argv[2]);
2519                 result = WERR_INVALID_PARAM;
2520                 goto done;
2521         }
2522
2523         result = push_spoolss_PrinterData(mem_ctx, &blob, type, &data);
2524         if (!W_ERROR_IS_OK(result)) {
2525                 goto done;
2526         }
2527
2528         status = rpccli_spoolss_SetPrinterData(cli, mem_ctx,
2529                                                &pol,
2530                                                argv[3], /* value_name */
2531                                                type,
2532                                                blob.data,
2533                                                blob.length,
2534                                                &result);
2535         if (!W_ERROR_IS_OK(result)) {
2536                 printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]);
2537                 goto done;
2538         }
2539         printf("\tSetPrinterData succeeded [%s: %s]\n", argv[3], argv[4]);
2540
2541         result = rpccli_spoolss_getprinter(cli, mem_ctx,
2542                                            &pol,
2543                                            0,
2544                                            0,
2545                                            &info);
2546         if (!W_ERROR_IS_OK(result)) {
2547                 goto done;
2548         }
2549
2550         printf("%s\n", current_timestring(mem_ctx, true));
2551         printf("\tchange_id (after set)\t:[0x%x]\n", info.info0.change_id);
2552
2553 done:
2554         /* cleanup */
2555         if (is_valid_policy_hnd(&pol)) {
2556                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
2557         }
2558
2559         return result;
2560 }
2561
2562 /****************************************************************************
2563 ****************************************************************************/
2564
2565 static void display_job_info1(struct spoolss_JobInfo1 *r)
2566 {
2567         printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", r->position, r->job_id,
2568                r->user_name, r->document_name, r->text_status, r->pages_printed,
2569                r->total_pages);
2570 }
2571
2572 /****************************************************************************
2573 ****************************************************************************/
2574
2575 static void display_job_info2(struct spoolss_JobInfo2 *r)
2576 {
2577         printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n",
2578                r->position, r->job_id,
2579                r->user_name, r->document_name, r->text_status, r->pages_printed,
2580                r->total_pages, r->size);
2581 }
2582
2583 /****************************************************************************
2584 ****************************************************************************/
2585
2586 static void display_job_info3(struct spoolss_JobInfo3 *r)
2587 {
2588         printf("jobid[%d], next_jobid[%d]\n",
2589                 r->job_id, r->next_job_id);
2590 }
2591
2592 /****************************************************************************
2593 ****************************************************************************/
2594
2595 static void display_job_info4(struct spoolss_JobInfo4 *r)
2596 {
2597         printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d/%d bytes\n",
2598                r->position, r->job_id,
2599                r->user_name, r->document_name, r->text_status, r->pages_printed,
2600                r->total_pages, r->size, r->size_high);
2601 }
2602
2603 /****************************************************************************
2604 ****************************************************************************/
2605
2606 static WERROR cmd_spoolss_enum_jobs(struct rpc_pipe_client *cli,
2607                                       TALLOC_CTX *mem_ctx, int argc,
2608                                       const char **argv)
2609 {
2610         WERROR result;
2611         uint32_t level = 1, count, i;
2612         const char *printername;
2613         struct policy_handle hnd;
2614         union spoolss_JobInfo *info;
2615
2616         if (argc < 2 || argc > 3) {
2617                 printf("Usage: %s printername [level]\n", argv[0]);
2618                 return WERR_OK;
2619         }
2620
2621         if (argc == 3) {
2622                 level = atoi(argv[2]);
2623         }
2624
2625         /* Open printer handle */
2626
2627         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2628
2629         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2630                                                printername,
2631                                                SEC_FLAG_MAXIMUM_ALLOWED,
2632                                                &hnd);
2633         if (!W_ERROR_IS_OK(result))
2634                 goto done;
2635
2636         /* Enumerate ports */
2637
2638         result = rpccli_spoolss_enumjobs(cli, mem_ctx,
2639                                          &hnd,
2640                                          0, /* firstjob */
2641                                          1000, /* numjobs */
2642                                          level,
2643                                          0,
2644                                          &count,
2645                                          &info);
2646         if (!W_ERROR_IS_OK(result)) {
2647                 goto done;
2648         }
2649
2650         for (i = 0; i < count; i++) {
2651                 switch (level) {
2652                 case 1:
2653                         display_job_info1(&info[i].info1);
2654                         break;
2655                 case 2:
2656                         display_job_info2(&info[i].info2);
2657                         break;
2658                 default:
2659                         d_printf("unknown info level %d\n", level);
2660                         break;
2661                 }
2662         }
2663
2664 done:
2665         if (is_valid_policy_hnd(&hnd)) {
2666                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2667         }
2668
2669         return result;
2670 }
2671
2672 /****************************************************************************
2673 ****************************************************************************/
2674
2675 static WERROR cmd_spoolss_get_job(struct rpc_pipe_client *cli,
2676                                   TALLOC_CTX *mem_ctx, int argc,
2677                                   const char **argv)
2678 {
2679         WERROR result;
2680         const char *printername;
2681         struct policy_handle hnd;
2682         uint32_t job_id;
2683         uint32_t level = 1;
2684         union spoolss_JobInfo info;
2685
2686         if (argc < 3 || argc > 4) {
2687                 printf("Usage: %s printername job_id [level]\n", argv[0]);
2688                 return WERR_OK;
2689         }
2690
2691         job_id = atoi(argv[2]);
2692
2693         if (argc == 4) {
2694                 level = atoi(argv[3]);
2695         }
2696
2697         /* Open printer handle */
2698
2699         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2700
2701         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2702                                                printername,
2703                                                SEC_FLAG_MAXIMUM_ALLOWED,
2704                                                &hnd);
2705         if (!W_ERROR_IS_OK(result)) {
2706                 goto done;
2707         }
2708
2709         /* Enumerate ports */
2710
2711         result = rpccli_spoolss_getjob(cli, mem_ctx,
2712                                        &hnd,
2713                                        job_id,
2714                                        level,
2715                                        0,
2716                                        &info);
2717
2718         if (!W_ERROR_IS_OK(result)) {
2719                 goto done;
2720         }
2721
2722         switch (level) {
2723         case 1:
2724                 display_job_info1(&info.info1);
2725                 break;
2726         case 2:
2727                 display_job_info2(&info.info2);
2728                 break;
2729         case 3:
2730                 display_job_info3(&info.info3);
2731                 break;
2732         case 4:
2733                 display_job_info4(&info.info4);
2734                 break;
2735         default:
2736                 d_printf("unknown info level %d\n", level);
2737                 break;
2738         }
2739
2740 done:
2741         if (is_valid_policy_hnd(&hnd)) {
2742                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2743         }
2744
2745         return result;
2746 }
2747
2748 /****************************************************************************
2749 ****************************************************************************/
2750
2751 static WERROR cmd_spoolss_set_job(struct rpc_pipe_client *cli,
2752                                   TALLOC_CTX *mem_ctx, int argc,
2753                                   const char **argv)
2754 {
2755         WERROR result;
2756         NTSTATUS status;
2757         const char *printername;
2758         struct policy_handle hnd;
2759         uint32_t job_id;
2760         enum spoolss_JobControl command;
2761
2762         if (argc != 4) {
2763                 printf("Usage: %s printername job_id command\n", argv[0]);
2764                 return WERR_OK;
2765         }
2766
2767         job_id = atoi(argv[2]);
2768         command = atoi(argv[3]);
2769
2770         /* Open printer handle */
2771
2772         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2773
2774         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2775                                                printername,
2776                                                SEC_FLAG_MAXIMUM_ALLOWED,
2777                                                &hnd);
2778         if (!W_ERROR_IS_OK(result)) {
2779                 goto done;
2780         }
2781
2782         /* Set Job */
2783
2784         status = rpccli_spoolss_SetJob(cli, mem_ctx,
2785                                        &hnd,
2786                                        job_id,
2787                                        NULL,
2788                                        command,
2789                                        &result);
2790
2791         if (!W_ERROR_IS_OK(result)) {
2792                 goto done;
2793         }
2794
2795 done:
2796         if (is_valid_policy_hnd(&hnd)) {
2797                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2798         }
2799
2800         return result;
2801 }
2802
2803 /****************************************************************************
2804 ****************************************************************************/
2805
2806 static WERROR cmd_spoolss_enum_data(struct rpc_pipe_client *cli,
2807                                     TALLOC_CTX *mem_ctx, int argc,
2808                                     const char **argv)
2809 {
2810         WERROR result;
2811         NTSTATUS status;
2812         uint32_t i = 0;
2813         const char *printername;
2814         struct policy_handle hnd;
2815         uint32_t value_offered = 0;
2816         const char *value_name = NULL;
2817         uint32_t value_needed;
2818         enum winreg_Type type;
2819         uint8_t *data = NULL;
2820         uint32_t data_offered = 0;
2821         uint32_t data_needed;
2822
2823         if (argc != 2) {
2824                 printf("Usage: %s printername\n", argv[0]);
2825                 return WERR_OK;
2826         }
2827
2828         /* Open printer handle */
2829
2830         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2831
2832         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2833                                                printername,
2834                                                SEC_FLAG_MAXIMUM_ALLOWED,
2835                                                &hnd);
2836         if (!W_ERROR_IS_OK(result)) {
2837                 goto done;
2838         }
2839
2840         /* Enumerate data */
2841
2842         status = rpccli_spoolss_EnumPrinterData(cli, mem_ctx,
2843                                                 &hnd,
2844                                                 i,
2845                                                 value_name,
2846                                                 value_offered,
2847                                                 &value_needed,
2848                                                 &type,
2849                                                 data,
2850                                                 data_offered,
2851                                                 &data_needed,
2852                                                 &result);
2853
2854         data_offered    = data_needed;
2855         value_offered   = value_needed;
2856         data            = talloc_zero_array(mem_ctx, uint8_t, data_needed);
2857         value_name      = talloc_zero_array(mem_ctx, char, value_needed);
2858
2859         while (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(result)) {
2860
2861                 status = rpccli_spoolss_EnumPrinterData(cli, mem_ctx,
2862                                                         &hnd,
2863                                                         i++,
2864                                                         value_name,
2865                                                         value_offered,
2866                                                         &value_needed,
2867                                                         &type,
2868                                                         data,
2869                                                         data_offered,
2870                                                         &data_needed,
2871                                                         &result);
2872                 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(result)) {
2873                         REGISTRY_VALUE v;
2874                         fstrcpy(v.valuename, value_name);
2875                         v.type = type;
2876                         v.size = data_offered;
2877                         v.data_p = data;
2878                         display_reg_value(v);
2879                 }
2880         }
2881
2882         if (W_ERROR_V(result) == ERRnomoreitems) {
2883                 result = W_ERROR(ERRsuccess);
2884         }
2885
2886 done:
2887         if (is_valid_policy_hnd(&hnd)) {
2888                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2889         }
2890
2891         return result;
2892 }
2893
2894 /****************************************************************************
2895 ****************************************************************************/
2896
2897 static WERROR cmd_spoolss_enum_data_ex( struct rpc_pipe_client *cli,
2898                                           TALLOC_CTX *mem_ctx, int argc,
2899                                           const char **argv)
2900 {
2901         WERROR result;
2902         uint32_t i;
2903         const char *printername;
2904         struct policy_handle hnd;
2905         uint32_t count;
2906         struct spoolss_PrinterEnumValues *info;
2907
2908         if (argc != 3) {
2909                 printf("Usage: %s printername <keyname>\n", argv[0]);
2910                 return WERR_OK;
2911         }
2912
2913         /* Open printer handle */
2914
2915         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2916
2917         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2918                                                printername,
2919                                                SEC_FLAG_MAXIMUM_ALLOWED,
2920                                                &hnd);
2921         if (!W_ERROR_IS_OK(result)) {
2922                 goto done;
2923         }
2924
2925         /* Enumerate subkeys */
2926
2927         result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx,
2928                                                   &hnd,
2929                                                   argv[2],
2930                                                   0,
2931                                                   &count,
2932                                                   &info);
2933         if (!W_ERROR_IS_OK(result)) {
2934                 goto done;
2935         }
2936
2937         for (i=0; i < count; i++) {
2938                 display_printer_data(info[i].value_name,
2939                                      info[i].type,
2940                                      info[i].data->data,
2941                                      info[i].data->length);
2942         }
2943
2944  done:
2945         if (is_valid_policy_hnd(&hnd)) {
2946                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2947         }
2948
2949         return result;
2950 }
2951
2952 /****************************************************************************
2953 ****************************************************************************/
2954
2955 static WERROR cmd_spoolss_enum_printerkey(struct rpc_pipe_client *cli,
2956                                           TALLOC_CTX *mem_ctx, int argc,
2957                                           const char **argv)
2958 {
2959         WERROR result;
2960         const char *printername;
2961         const char *keyname = NULL;
2962         struct policy_handle hnd;
2963         const char **key_buffer = NULL;
2964         int i;
2965
2966         if (argc < 2 || argc > 3) {
2967                 printf("Usage: %s printername [keyname]\n", argv[0]);
2968                 return WERR_OK;
2969         }
2970
2971         if (argc == 3) {
2972                 keyname = argv[2];
2973         } else {
2974                 keyname = "";
2975         }
2976
2977         /* Open printer handle */
2978
2979         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2980
2981         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2982                                                printername,
2983                                                SEC_FLAG_MAXIMUM_ALLOWED,
2984                                                &hnd);
2985         if (!W_ERROR_IS_OK(result)) {
2986                 goto done;
2987         }
2988
2989         /* Enumerate subkeys */
2990
2991         result = rpccli_spoolss_enumprinterkey(cli, mem_ctx,
2992                                                &hnd,
2993                                                keyname,
2994                                                &key_buffer,
2995                                                0);
2996
2997         if (!W_ERROR_IS_OK(result)) {
2998                 goto done;
2999         }
3000
3001         for (i=0; key_buffer && key_buffer[i]; i++) {
3002                 printf("%s\n", key_buffer[i]);
3003         }
3004
3005  done:
3006
3007         if (is_valid_policy_hnd(&hnd)) {
3008                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
3009         }
3010
3011         return result;
3012 }
3013
3014 /****************************************************************************
3015 ****************************************************************************/
3016
3017 static WERROR cmd_spoolss_rffpcnex(struct rpc_pipe_client *cli,
3018                                      TALLOC_CTX *mem_ctx, int argc,
3019                                      const char **argv)
3020 {
3021         const char *printername;
3022         const char *clientname;
3023         struct policy_handle hnd;
3024         WERROR result;
3025         NTSTATUS status;
3026         struct spoolss_NotifyOption option;
3027
3028         if (argc != 2) {
3029                 printf("Usage: %s printername\n", argv[0]);
3030                 result = WERR_OK;
3031                 goto done;
3032         }
3033
3034         /* Open printer */
3035
3036         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3037
3038         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3039                                                printername,
3040                                                SEC_FLAG_MAXIMUM_ALLOWED,
3041                                                &hnd);
3042         if (!W_ERROR_IS_OK(result)) {
3043                 printf("Error opening %s\n", argv[1]);
3044                 goto done;
3045         }
3046
3047         /* Create spool options */
3048
3049         option.version = 2;
3050         option.count = 2;
3051
3052         option.types = talloc_array(mem_ctx, struct spoolss_NotifyOptionType, 2);
3053         if (option.types == NULL) {
3054                 result = WERR_NOMEM;
3055                 goto done;
3056         }
3057
3058         option.types[0].type = PRINTER_NOTIFY_TYPE;
3059         option.types[0].count = 1;
3060         option.types[0].fields = talloc_array(mem_ctx, union spoolss_Field, 1);
3061         if (option.types[0].fields == NULL) {
3062                 result = WERR_NOMEM;
3063                 goto done;
3064         }
3065         option.types[0].fields[0].field = PRINTER_NOTIFY_FIELD_SERVER_NAME;
3066
3067         option.types[1].type = JOB_NOTIFY_TYPE;
3068         option.types[1].count = 1;
3069         option.types[1].fields = talloc_array(mem_ctx, union spoolss_Field, 1);
3070         if (option.types[1].fields == NULL) {
3071                 result = WERR_NOMEM;
3072                 goto done;
3073         }
3074         option.types[1].fields[0].field = JOB_NOTIFY_FIELD_PRINTER_NAME;
3075
3076         clientname = talloc_asprintf(mem_ctx, "\\\\%s", global_myname());
3077         if (!clientname) {
3078                 result = WERR_NOMEM;
3079                 goto done;
3080         }
3081
3082         /* Send rffpcnex */
3083
3084         status = rpccli_spoolss_RemoteFindFirstPrinterChangeNotifyEx(cli, mem_ctx,
3085                                                                      &hnd,
3086                                                                      0,
3087                                                                      0,
3088                                                                      clientname,
3089                                                                      123,
3090                                                                      &option,
3091                                                                      &result);
3092         if (!W_ERROR_IS_OK(result)) {
3093                 printf("Error rffpcnex %s\n", argv[1]);
3094                 goto done;
3095         }
3096
3097 done:
3098         if (is_valid_policy_hnd(&hnd))
3099                 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
3100
3101         return result;
3102 }
3103
3104 /****************************************************************************
3105 ****************************************************************************/
3106
3107 static bool compare_printer( struct rpc_pipe_client *cli1, struct policy_handle *hnd1,
3108                              struct rpc_pipe_client *cli2, struct policy_handle *hnd2 )
3109 {
3110         union spoolss_PrinterInfo info1, info2;
3111         WERROR werror;
3112         TALLOC_CTX *mem_ctx = talloc_init("compare_printer");
3113
3114         printf("Retrieving printer propertiesfor %s...", cli1->desthost);
3115         werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
3116                                            hnd1,
3117                                            2,
3118                                            0,
3119                                            &info1);
3120         if ( !W_ERROR_IS_OK(werror) ) {
3121                 printf("failed (%s)\n", win_errstr(werror));
3122                 talloc_destroy(mem_ctx);
3123                 return false;
3124         }
3125         printf("ok\n");
3126
3127         printf("Retrieving printer properties for %s...", cli2->desthost);
3128         werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
3129                                            hnd2,
3130                                            2,
3131                                            0,
3132                                            &info2);
3133         if ( !W_ERROR_IS_OK(werror) ) {
3134                 printf("failed (%s)\n", win_errstr(werror));
3135                 talloc_destroy(mem_ctx);
3136                 return false;
3137         }
3138         printf("ok\n");
3139
3140         talloc_destroy(mem_ctx);
3141
3142         return true;
3143 }
3144
3145 /****************************************************************************
3146 ****************************************************************************/
3147
3148 static bool compare_printer_secdesc( struct rpc_pipe_client *cli1, struct policy_handle *hnd1,
3149                                      struct rpc_pipe_client *cli2, struct policy_handle *hnd2 )
3150 {
3151         union spoolss_PrinterInfo info1, info2;
3152         WERROR werror;
3153         TALLOC_CTX *mem_ctx = talloc_init("compare_printer_secdesc");
3154         SEC_DESC *sd1, *sd2;
3155         bool result = true;
3156
3157
3158         printf("Retrieving printer security for %s...", cli1->desthost);
3159         werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
3160                                            hnd1,
3161                                            3,
3162                                            0,
3163                                            &info1);
3164         if ( !W_ERROR_IS_OK(werror) ) {
3165                 printf("failed (%s)\n", win_errstr(werror));
3166                 result = false;
3167                 goto done;
3168         }
3169         printf("ok\n");
3170
3171         printf("Retrieving printer security for %s...", cli2->desthost);
3172         werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
3173                                            hnd2,
3174                                            3,
3175                                            0,
3176                                            &info2);
3177         if ( !W_ERROR_IS_OK(werror) ) {
3178                 printf("failed (%s)\n", win_errstr(werror));
3179                 result = false;
3180                 goto done;
3181         }
3182         printf("ok\n");
3183
3184
3185         printf("++ ");
3186
3187         sd1 = info1.info3.secdesc;
3188         sd2 = info2.info3.secdesc;
3189
3190         if ( (sd1 != sd2) && ( !sd1 || !sd2 ) ) {
3191                 printf("NULL secdesc!\n");
3192                 result = false;
3193                 goto done;
3194         }
3195
3196         if (!sec_desc_equal( sd1, sd2 ) ) {
3197                 printf("Security Descriptors *not* equal!\n");
3198                 result = false;
3199                 goto done;
3200         }
3201
3202         printf("Security descriptors match\n");
3203
3204 done:
3205         talloc_destroy(mem_ctx);
3206         return result;
3207 }
3208
3209
3210 /****************************************************************************
3211 ****************************************************************************/
3212
3213 extern struct user_auth_info *rpcclient_auth_info;
3214
3215 static WERROR cmd_spoolss_printercmp(struct rpc_pipe_client *cli,
3216                                      TALLOC_CTX *mem_ctx, int argc,
3217                                      const char **argv)
3218 {
3219         const char *printername;
3220         char *printername_path = NULL;
3221         struct cli_state *cli_server2 = NULL;
3222         struct rpc_pipe_client *cli2 = NULL;
3223         struct policy_handle hPrinter1, hPrinter2;
3224         NTSTATUS nt_status;
3225         WERROR werror;
3226
3227         if ( argc != 3 )  {
3228                 printf("Usage: %s <printer> <server>\n", argv[0]);
3229                 return WERR_OK;
3230         }
3231
3232         printername = argv[1];
3233
3234         /* first get the connection to the remote server */
3235
3236         nt_status = cli_full_connection(&cli_server2, global_myname(), argv[2],
3237                                         NULL, 0,
3238                                         "IPC$", "IPC",
3239                                         get_cmdline_auth_info_username(rpcclient_auth_info),
3240                                         lp_workgroup(),
3241                                         get_cmdline_auth_info_password(rpcclient_auth_info),
3242                                         get_cmdline_auth_info_use_kerberos(rpcclient_auth_info) ? CLI_FULL_CONNECTION_USE_KERBEROS : 0,
3243                                         get_cmdline_auth_info_signing_state(rpcclient_auth_info), NULL);
3244
3245         if ( !NT_STATUS_IS_OK(nt_status) )
3246                 return WERR_GENERAL_FAILURE;
3247
3248         nt_status = cli_rpc_pipe_open_noauth(cli_server2, &ndr_table_spoolss.syntax_id,
3249                                              &cli2);
3250         if (!NT_STATUS_IS_OK(nt_status)) {
3251                 printf("failed to open spoolss pipe on server %s (%s)\n",
3252                         argv[2], nt_errstr(nt_status));
3253                 return WERR_GENERAL_FAILURE;
3254         }
3255
3256         /* now open up both printers */
3257
3258         RPCCLIENT_PRINTERNAME(printername_path, cli, printername);
3259
3260         printf("Opening %s...", printername_path);
3261
3262         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3263                                                printername_path,
3264                                                PRINTER_ALL_ACCESS,
3265                                                &hPrinter1);
3266         if ( !W_ERROR_IS_OK(werror) ) {
3267                 printf("failed (%s)\n", win_errstr(werror));
3268                 goto done;
3269         }
3270         printf("ok\n");
3271
3272         RPCCLIENT_PRINTERNAME(printername_path, cli2, printername);
3273
3274         printf("Opening %s...", printername_path);
3275         werror = rpccli_spoolss_openprinter_ex(cli2, mem_ctx,
3276                                                printername_path,
3277                                                PRINTER_ALL_ACCESS,
3278                                                &hPrinter2);
3279         if ( !W_ERROR_IS_OK(werror) ) {
3280                  printf("failed (%s)\n", win_errstr(werror));
3281                 goto done;
3282         }
3283         printf("ok\n");
3284
3285         compare_printer( cli, &hPrinter1, cli2, &hPrinter2 );
3286         compare_printer_secdesc( cli, &hPrinter1, cli2, &hPrinter2 );
3287 #if 0
3288         compare_printerdata( cli_server1, &hPrinter1, cli_server2, &hPrinter2 );
3289 #endif
3290
3291
3292 done:
3293         /* cleanup */
3294
3295         printf("Closing printers...");
3296         rpccli_spoolss_ClosePrinter( cli, mem_ctx, &hPrinter1, NULL );
3297         rpccli_spoolss_ClosePrinter( cli2, mem_ctx, &hPrinter2, NULL );
3298         printf("ok\n");
3299
3300         /* close the second remote connection */
3301
3302         cli_shutdown( cli_server2 );
3303         return WERR_OK;
3304 }
3305
3306 static void display_proc_info1(struct spoolss_PrintProcessorInfo1 *r)
3307 {
3308         printf("print_processor_name: %s\n", r->print_processor_name);
3309 }
3310
3311 static WERROR cmd_spoolss_enum_procs(struct rpc_pipe_client *cli,
3312                                      TALLOC_CTX *mem_ctx, int argc,
3313                                      const char **argv)
3314 {
3315         WERROR werror;
3316         const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
3317         uint32_t num_procs, level = 1, i;
3318         union spoolss_PrintProcessorInfo *procs;
3319
3320         /* Parse the command arguments */
3321
3322         if (argc < 1 || argc > 4) {
3323                 printf ("Usage: %s [environment] [level]\n", argv[0]);
3324                 return WERR_OK;
3325         }
3326
3327         if (argc >= 2) {
3328                 environment = argv[1];
3329         }
3330
3331         if (argc == 3) {
3332                 level = atoi(argv[2]);
3333         }
3334
3335         /* Enumerate Print Processors */
3336
3337         werror = rpccli_spoolss_enumprintprocessors(cli, mem_ctx,
3338                                                     cli->srv_name_slash,
3339                                                     environment,
3340                                                     level,
3341                                                     0,
3342                                                     &num_procs,
3343                                                     &procs);
3344         if (!W_ERROR_IS_OK(werror))
3345                 goto done;
3346
3347         /* Display output */
3348
3349         for (i = 0; i < num_procs; i++) {
3350                 switch (level) {
3351                 case 1:
3352                         display_proc_info1(&procs[i].info1);
3353                         break;
3354                 }
3355         }
3356
3357  done:
3358         return werror;
3359 }
3360
3361 static void display_proc_data_types_info1(struct spoolss_PrintProcDataTypesInfo1 *r)
3362 {
3363         printf("name_array: %s\n", r->name_array);
3364 }
3365
3366 static WERROR cmd_spoolss_enum_proc_data_types(struct rpc_pipe_client *cli,
3367                                                TALLOC_CTX *mem_ctx, int argc,
3368                                                const char **argv)
3369 {
3370         WERROR werror;
3371         const char *print_processor_name = "winprint";
3372         uint32_t num_procs, level = 1, i;
3373         union spoolss_PrintProcDataTypesInfo *procs;
3374
3375         /* Parse the command arguments */
3376
3377         if (argc < 1 || argc > 4) {
3378                 printf ("Usage: %s [environment] [level]\n", argv[0]);
3379                 return WERR_OK;
3380         }
3381
3382         if (argc >= 2) {
3383                 print_processor_name = argv[1];
3384         }
3385
3386         if (argc == 3) {
3387                 level = atoi(argv[2]);
3388         }
3389
3390         /* Enumerate Print Processor Data Types */
3391
3392         werror = rpccli_spoolss_enumprintprocessordatatypes(cli, mem_ctx,
3393                                                             cli->srv_name_slash,
3394                                                             print_processor_name,
3395                                                             level,
3396                                                             0,
3397                                                             &num_procs,
3398                                                             &procs);
3399         if (!W_ERROR_IS_OK(werror))
3400                 goto done;
3401
3402         /* Display output */
3403
3404         for (i = 0; i < num_procs; i++) {
3405                 switch (level) {
3406                 case 1:
3407                         display_proc_data_types_info1(&procs[i].info1);
3408                         break;
3409                 }
3410         }
3411
3412  done:
3413         return werror;
3414 }
3415
3416 static void display_monitor1(const struct spoolss_MonitorInfo1 *r)
3417 {
3418         printf("monitor_name: %s\n", r->monitor_name);
3419 }
3420
3421 static void display_monitor2(const struct spoolss_MonitorInfo2 *r)
3422 {
3423         printf("monitor_name: %s\n", r->monitor_name);
3424         printf("environment: %s\n", r->environment);
3425         printf("dll_name: %s\n", r->dll_name);
3426 }
3427
3428 static WERROR cmd_spoolss_enum_monitors(struct rpc_pipe_client *cli,
3429                                         TALLOC_CTX *mem_ctx, int argc,
3430                                         const char **argv)
3431 {
3432         WERROR werror;
3433         uint32_t count, level = 1, i;
3434         union spoolss_MonitorInfo *info;
3435
3436         /* Parse the command arguments */
3437
3438         if (argc > 2) {
3439                 printf("Usage: %s [level]\n", argv[0]);
3440                 return WERR_OK;
3441         }
3442
3443         if (argc == 2) {
3444                 level = atoi(argv[1]);
3445         }
3446
3447         /* Enumerate Print Monitors */
3448
3449         werror = rpccli_spoolss_enummonitors(cli, mem_ctx,
3450                                              cli->srv_name_slash,
3451                                              level,
3452                                              0,
3453                                              &count,
3454                                              &info);
3455         if (!W_ERROR_IS_OK(werror)) {
3456                 goto done;
3457         }
3458
3459         /* Display output */
3460
3461         for (i = 0; i < count; i++) {
3462                 switch (level) {
3463                 case 1:
3464                         display_monitor1(&info[i].info1);
3465                         break;
3466                 case 2:
3467                         display_monitor2(&info[i].info2);
3468                         break;
3469                 }
3470         }
3471
3472  done:
3473         return werror;
3474 }
3475
3476 /* List of commands exported by this module */
3477 struct cmd_set spoolss_commands[] = {
3478
3479         { "SPOOLSS"  },
3480
3481         { "adddriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterdriver,   &ndr_table_spoolss.syntax_id, NULL, "Add a print driver",                  "" },
3482         { "addprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterex,       &ndr_table_spoolss.syntax_id, NULL, "Add a printer",                       "" },
3483         { "deldriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriver,       &ndr_table_spoolss.syntax_id, NULL, "Delete a printer driver",             "" },
3484         { "deldriverex",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriverex,     &ndr_table_spoolss.syntax_id, NULL, "Delete a printer driver with files",  "" },
3485         { "enumdata",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data,          &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer data",              "" },
3486         { "enumdataex",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data_ex,       &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer data for a key",    "" },
3487         { "enumkey",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printerkey,    &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer keys",              "" },
3488         { "enumjobs",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_jobs,          &ndr_table_spoolss.syntax_id, NULL, "Enumerate print jobs",                "" },
3489         { "getjob",             RPC_RTYPE_WERROR, NULL, cmd_spoolss_get_job,            &ndr_table_spoolss.syntax_id, NULL, "Get print job",                       "" },
3490         { "setjob",             RPC_RTYPE_WERROR, NULL, cmd_spoolss_set_job,            &ndr_table_spoolss.syntax_id, NULL, "Set print job",                       "" },
3491         { "enumports",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_ports,         &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer ports",             "" },
3492         { "enumdrivers",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_drivers,       &ndr_table_spoolss.syntax_id, NULL, "Enumerate installed printer drivers", "" },
3493         { "enumprinters",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printers,      &ndr_table_spoolss.syntax_id, NULL, "Enumerate printers",                  "" },
3494         { "getdata",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdata,     &ndr_table_spoolss.syntax_id, NULL, "Get print driver data",               "" },
3495         { "getdataex",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdataex,   &ndr_table_spoolss.syntax_id, NULL, "Get printer driver data with keyname", ""},
3496         { "getdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriver,          &ndr_table_spoolss.syntax_id, NULL, "Get print driver information",        "" },
3497         { "getdriverdir",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriverdir,       &ndr_table_spoolss.syntax_id, NULL, "Get print driver upload directory",   "" },
3498         { "getprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinter,         &ndr_table_spoolss.syntax_id, NULL, "Get printer info",                    "" },
3499         { "openprinter",        RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer_ex,    &ndr_table_spoolss.syntax_id, NULL, "Open printer handle",                 "" },
3500         { "setdriver",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_setdriver,          &ndr_table_spoolss.syntax_id, NULL, "Set printer driver",                  "" },
3501         { "getprintprocdir",    RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprintprocdir,    &ndr_table_spoolss.syntax_id, NULL, "Get print processor directory",       "" },
3502         { "addform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_addform,            &ndr_table_spoolss.syntax_id, NULL, "Add form",                            "" },
3503         { "setform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_setform,            &ndr_table_spoolss.syntax_id, NULL, "Set form",                            "" },
3504         { "getform",            RPC_RTYPE_WERROR, NULL, cmd_spoolss_getform,            &ndr_table_spoolss.syntax_id, NULL, "Get form",                            "" },
3505         { "deleteform",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform,         &ndr_table_spoolss.syntax_id, NULL, "Delete form",                         "" },
3506         { "enumforms",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms,         &ndr_table_spoolss.syntax_id, NULL, "Enumerate forms",                     "" },
3507         { "setprinter",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter,         &ndr_table_spoolss.syntax_id, NULL, "Set printer comment",                 "" },
3508         { "setprintername",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername,     &ndr_table_spoolss.syntax_id, NULL, "Set printername",                 "" },
3509         { "setprinterdata",     RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata,     &ndr_table_spoolss.syntax_id, NULL, "Set REG_SZ printer data",             "" },
3510         { "rffpcnex",           RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex,           &ndr_table_spoolss.syntax_id, NULL, "Rffpcnex test", "" },
3511         { "printercmp",         RPC_RTYPE_WERROR, NULL, cmd_spoolss_printercmp,         &ndr_table_spoolss.syntax_id, NULL, "Printer comparison test", "" },
3512         { "enumprocs",          RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_procs,         &ndr_table_spoolss.syntax_id, NULL, "Enumerate Print Processors",          "" },
3513         { "enumprocdatatypes",  RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_proc_data_types, &ndr_table_spoolss.syntax_id, NULL, "Enumerate Print Processor Data Types", "" },
3514         { "enummonitors",       RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_monitors,      &ndr_table_spoolss.syntax_id, NULL, "Enumerate Print Monitors", "" },
3515
3516         { NULL }
3517 };