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