pyldb: avoid segfault when adding an element with no name
[sfrench/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         int error = 0;
2646
2647         /* parse the command arguments */
2648         if (argc < 5) {
2649                 printf ("Usage: %s <printer> <string|binary|dword|multistring>"
2650                         " <value> <data>\n",
2651                         argv[0]);
2652                 return WERR_OK;
2653         }
2654
2655         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2656
2657         type = REG_NONE;
2658
2659         if (strequal(argv[2], "string")) {
2660                 type = REG_SZ;
2661         }
2662
2663         if (strequal(argv[2], "binary")) {
2664                 type = REG_BINARY;
2665         }
2666
2667         if (strequal(argv[2], "dword")) {
2668                 type = REG_DWORD;
2669         }
2670
2671         if (strequal(argv[2], "multistring")) {
2672                 type = REG_MULTI_SZ;
2673         }
2674
2675         if (type == REG_NONE) {
2676                 printf("Unknown data type: %s\n", argv[2]);
2677                 result =  WERR_INVALID_PARAMETER;
2678                 goto done;
2679         }
2680
2681         /* get a printer handle */
2682
2683         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2684                                                printername,
2685                                                SEC_FLAG_MAXIMUM_ALLOWED,
2686                                                &pol);
2687         if (!W_ERROR_IS_OK(result)) {
2688                 goto done;
2689         }
2690
2691         result = rpccli_spoolss_getprinter(cli, mem_ctx,
2692                                            &pol,
2693                                            0,
2694                                            0,
2695                                            &info);
2696         if (!W_ERROR_IS_OK(result)) {
2697                 goto done;
2698         }
2699
2700         printf("%s\n", current_timestring(mem_ctx, true));
2701         printf("\tchange_id (before set)\t:[0x%x]\n", info.info0.change_id);
2702
2703         /* Set the printer data */
2704
2705         switch (type) {
2706         case REG_SZ:
2707                 data.string = talloc_strdup(mem_ctx, argv[4]);
2708                 W_ERROR_HAVE_NO_MEMORY(data.string);
2709                 break;
2710         case REG_DWORD:
2711                 data.value = strtoul_err(argv[4], NULL, 10, &error);
2712                 if (error != 0) {
2713                         result = WERR_INVALID_PARAMETER;
2714                         goto done;
2715                 }
2716
2717                 break;
2718         case REG_BINARY:
2719                 data.binary = strhex_to_data_blob(mem_ctx, argv[4]);
2720                 break;
2721         case REG_MULTI_SZ: {
2722                 int i;
2723                 size_t num_strings;
2724                 const char **strings = NULL;
2725
2726                 num_strings = 0;
2727
2728                 for (i=4; i<argc; i++) {
2729                         if (strcmp(argv[i], "NULL") == 0) {
2730                                 argv[i] = "";
2731                         }
2732                         if (!add_string_to_array(mem_ctx, argv[i],
2733                                                  &strings,
2734                                                  &num_strings)) {
2735                                 result = WERR_NOT_ENOUGH_MEMORY;
2736                                 goto done;
2737                         }
2738                 }
2739                 data.string_array = talloc_zero_array(mem_ctx, const char *, num_strings + 1);
2740                 if (!data.string_array) {
2741                         result = WERR_NOT_ENOUGH_MEMORY;
2742                         goto done;
2743                 }
2744                 for (i=0; i < num_strings; i++) {
2745                         data.string_array[i] = strings[i];
2746                 }
2747                 break;
2748                 }
2749         default:
2750                 printf("Unknown data type: %s\n", argv[2]);
2751                 result = WERR_INVALID_PARAMETER;
2752                 goto done;
2753         }
2754
2755         result = push_spoolss_PrinterData(mem_ctx, &blob, type, &data);
2756         if (!W_ERROR_IS_OK(result)) {
2757                 goto done;
2758         }
2759
2760         status = dcerpc_spoolss_SetPrinterData(b, mem_ctx,
2761                                                &pol,
2762                                                argv[3], /* value_name */
2763                                                type,
2764                                                blob.data,
2765                                                blob.length,
2766                                                &result);
2767         if (!NT_STATUS_IS_OK(status)) {
2768                 printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]);
2769                 result = ntstatus_to_werror(status);
2770                 goto done;
2771         }
2772         if (!W_ERROR_IS_OK(result)) {
2773                 printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]);
2774                 goto done;
2775         }
2776         printf("\tSetPrinterData succeeded [%s: %s]\n", argv[3], argv[4]);
2777
2778         result = rpccli_spoolss_getprinter(cli, mem_ctx,
2779                                            &pol,
2780                                            0,
2781                                            0,
2782                                            &info);
2783         if (!W_ERROR_IS_OK(result)) {
2784                 goto done;
2785         }
2786
2787         printf("%s\n", current_timestring(mem_ctx, true));
2788         printf("\tchange_id (after set)\t:[0x%x]\n", info.info0.change_id);
2789
2790 done:
2791         /* cleanup */
2792         if (is_valid_policy_hnd(&pol)) {
2793                 WERROR _result;
2794                 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result);
2795         }
2796
2797         return result;
2798 }
2799
2800 /****************************************************************************
2801 ****************************************************************************/
2802
2803 static void display_job_info1(struct spoolss_JobInfo1 *r)
2804 {
2805         printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", r->position, r->job_id,
2806                r->user_name, r->document_name, r->text_status, r->pages_printed,
2807                r->total_pages);
2808 }
2809
2810 /****************************************************************************
2811 ****************************************************************************/
2812
2813 static void display_job_info2(struct spoolss_JobInfo2 *r)
2814 {
2815         printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n",
2816                r->position, r->job_id,
2817                r->user_name, r->document_name, r->text_status, r->pages_printed,
2818                r->total_pages, r->size);
2819 }
2820
2821 /****************************************************************************
2822 ****************************************************************************/
2823
2824 static void display_job_info3(struct spoolss_JobInfo3 *r)
2825 {
2826         printf("jobid[%d], next_jobid[%d]\n",
2827                 r->job_id, r->next_job_id);
2828 }
2829
2830 /****************************************************************************
2831 ****************************************************************************/
2832
2833 static void display_job_info4(struct spoolss_JobInfo4 *r)
2834 {
2835         printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d/%d bytes\n",
2836                r->position, r->job_id,
2837                r->user_name, r->document_name, r->text_status, r->pages_printed,
2838                r->total_pages, r->size, r->size_high);
2839 }
2840
2841 /****************************************************************************
2842 ****************************************************************************/
2843
2844 static WERROR cmd_spoolss_enum_jobs(struct rpc_pipe_client *cli,
2845                                       TALLOC_CTX *mem_ctx, int argc,
2846                                       const char **argv)
2847 {
2848         WERROR result;
2849         uint32_t level = 1, count, i;
2850         const char *printername;
2851         struct policy_handle hnd;
2852         union spoolss_JobInfo *info;
2853         struct dcerpc_binding_handle *b = cli->binding_handle;
2854
2855         if (argc < 2 || argc > 3) {
2856                 printf("Usage: %s printername [level]\n", argv[0]);
2857                 return WERR_OK;
2858         }
2859
2860         if (argc == 3) {
2861                 level = atoi(argv[2]);
2862         }
2863
2864         /* Open printer handle */
2865
2866         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2867
2868         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2869                                                printername,
2870                                                SEC_FLAG_MAXIMUM_ALLOWED,
2871                                                &hnd);
2872         if (!W_ERROR_IS_OK(result))
2873                 goto done;
2874
2875         /* Enumerate ports */
2876
2877         result = rpccli_spoolss_enumjobs(cli, mem_ctx,
2878                                          &hnd,
2879                                          0, /* firstjob */
2880                                          1000, /* numjobs */
2881                                          level,
2882                                          0,
2883                                          &count,
2884                                          &info);
2885         if (!W_ERROR_IS_OK(result)) {
2886                 goto done;
2887         }
2888
2889         for (i = 0; i < count; i++) {
2890                 switch (level) {
2891                 case 1:
2892                         display_job_info1(&info[i].info1);
2893                         break;
2894                 case 2:
2895                         display_job_info2(&info[i].info2);
2896                         break;
2897                 default:
2898                         d_printf("unknown info level %d\n", level);
2899                         break;
2900                 }
2901         }
2902
2903 done:
2904         if (is_valid_policy_hnd(&hnd)) {
2905                 WERROR _result;
2906                 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
2907         }
2908
2909         return result;
2910 }
2911
2912 /****************************************************************************
2913 ****************************************************************************/
2914
2915 static WERROR cmd_spoolss_get_job(struct rpc_pipe_client *cli,
2916                                   TALLOC_CTX *mem_ctx, int argc,
2917                                   const char **argv)
2918 {
2919         WERROR result;
2920         const char *printername;
2921         struct policy_handle hnd;
2922         uint32_t job_id;
2923         uint32_t level = 1;
2924         union spoolss_JobInfo info;
2925         struct dcerpc_binding_handle *b = cli->binding_handle;
2926
2927         if (argc < 3 || argc > 4) {
2928                 printf("Usage: %s printername job_id [level]\n", argv[0]);
2929                 return WERR_OK;
2930         }
2931
2932         job_id = atoi(argv[2]);
2933
2934         if (argc == 4) {
2935                 level = atoi(argv[3]);
2936         }
2937
2938         /* Open printer handle */
2939
2940         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2941
2942         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2943                                                printername,
2944                                                SEC_FLAG_MAXIMUM_ALLOWED,
2945                                                &hnd);
2946         if (!W_ERROR_IS_OK(result)) {
2947                 goto done;
2948         }
2949
2950         /* Enumerate ports */
2951
2952         result = rpccli_spoolss_getjob(cli, mem_ctx,
2953                                        &hnd,
2954                                        job_id,
2955                                        level,
2956                                        0,
2957                                        &info);
2958
2959         if (!W_ERROR_IS_OK(result)) {
2960                 goto done;
2961         }
2962
2963         switch (level) {
2964         case 1:
2965                 display_job_info1(&info.info1);
2966                 break;
2967         case 2:
2968                 display_job_info2(&info.info2);
2969                 break;
2970         case 3:
2971                 display_job_info3(&info.info3);
2972                 break;
2973         case 4:
2974                 display_job_info4(&info.info4);
2975                 break;
2976         default:
2977                 d_printf("unknown info level %d\n", level);
2978                 break;
2979         }
2980
2981 done:
2982         if (is_valid_policy_hnd(&hnd)) {
2983                 WERROR _result;
2984                 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
2985         }
2986
2987         return result;
2988 }
2989
2990 /****************************************************************************
2991 ****************************************************************************/
2992
2993 static struct {
2994         const char *name;
2995         enum spoolss_JobControl val;
2996 } cmdvals[] = {
2997         {"PAUSE", SPOOLSS_JOB_CONTROL_PAUSE},
2998         {"RESUME", SPOOLSS_JOB_CONTROL_RESUME},
2999         {"CANCEL", SPOOLSS_JOB_CONTROL_CANCEL},
3000         {"RESTART", SPOOLSS_JOB_CONTROL_RESTART},
3001         {"DELETE", SPOOLSS_JOB_CONTROL_DELETE},
3002         {"SEND_TO_PRINTER", SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER},
3003         {"EJECTED", SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED},
3004         {"RETAIN", SPOOLSS_JOB_CONTROL_RETAIN},
3005         {"RELEASE", SPOOLSS_JOB_CONTROL_RELEASE}
3006 };
3007
3008 static enum spoolss_JobControl parse_setjob_command(const char *cmd)
3009 {
3010         int i;
3011
3012         for (i = 0; i < sizeof(cmdvals)/sizeof(cmdvals[0]); i++) {
3013                 if (strequal(cmdvals[i].name, cmd)) {
3014                         return cmdvals[i].val;
3015                 }
3016         }
3017         return (enum spoolss_JobControl)atoi(cmd);
3018 }
3019
3020 static WERROR cmd_spoolss_set_job(struct rpc_pipe_client *cli,
3021                                   TALLOC_CTX *mem_ctx, int argc,
3022                                   const char **argv)
3023 {
3024         WERROR result;
3025         NTSTATUS status;
3026         const char *printername;
3027         struct policy_handle hnd;
3028         uint32_t job_id;
3029         enum spoolss_JobControl command;
3030         struct dcerpc_binding_handle *b = cli->binding_handle;
3031
3032         if (argc != 4) {
3033                 printf("Usage: %s printername job_id command\n", argv[0]);
3034                 printf("command = [PAUSE|RESUME|CANCEL|RESTART|DELETE|"
3035                         "SEND_TO_PRINTER|EJECTED|RETAIN|RELEASE]\n");
3036                 return WERR_OK;
3037         }
3038
3039         job_id = atoi(argv[2]);
3040         command = parse_setjob_command(argv[3]);
3041
3042         /* Open printer handle */
3043
3044         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3045
3046         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3047                                                printername,
3048                                                SEC_FLAG_MAXIMUM_ALLOWED,
3049                                                &hnd);
3050         if (!W_ERROR_IS_OK(result)) {
3051                 goto done;
3052         }
3053
3054         /* Set Job */
3055
3056         status = dcerpc_spoolss_SetJob(b, mem_ctx,
3057                                        &hnd,
3058                                        job_id,
3059                                        NULL,
3060                                        command,
3061                                        &result);
3062         if (!NT_STATUS_IS_OK(status)) {
3063                 result = ntstatus_to_werror(status);
3064                 goto done;
3065         }
3066         if (!W_ERROR_IS_OK(result)) {
3067                 goto done;
3068         }
3069
3070 done:
3071         if (is_valid_policy_hnd(&hnd)) {
3072                 WERROR _result;
3073                 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
3074         }
3075
3076         return result;
3077 }
3078
3079 /****************************************************************************
3080 ****************************************************************************/
3081
3082 static WERROR cmd_spoolss_enum_data(struct rpc_pipe_client *cli,
3083                                     TALLOC_CTX *mem_ctx, int argc,
3084                                     const char **argv)
3085 {
3086         WERROR result;
3087         NTSTATUS status;
3088         const char *printername;
3089         struct policy_handle hnd;
3090         uint32_t value_needed;
3091         enum winreg_Type type;
3092         uint32_t data_needed;
3093         struct dcerpc_binding_handle *b = cli->binding_handle;
3094         struct spoolss_EnumPrinterData r;
3095
3096         if (argc != 2) {
3097                 printf("Usage: %s printername\n", argv[0]);
3098                 return WERR_OK;
3099         }
3100
3101         /* Open printer handle */
3102
3103         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3104
3105         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3106                                                printername,
3107                                                SEC_FLAG_MAXIMUM_ALLOWED,
3108                                                &hnd);
3109         if (!W_ERROR_IS_OK(result)) {
3110                 goto done;
3111         }
3112
3113         /* Enumerate data */
3114
3115         r.in.handle = &hnd;
3116         r.in.enum_index = 0;
3117         r.in.value_offered = 0;
3118         r.in.data_offered = 0;
3119         r.out.value_name = NULL;
3120         r.out.value_needed = &value_needed;
3121         r.out.type = &type;
3122         r.out.data = NULL;
3123         r.out.data_needed = &data_needed;
3124
3125         status = dcerpc_spoolss_EnumPrinterData_r(b, mem_ctx, &r);
3126         if (!NT_STATUS_IS_OK(status)) {
3127                 result = ntstatus_to_werror(status);
3128                 goto done;
3129         }
3130
3131         if (!W_ERROR_IS_OK(r.out.result)) {
3132                 result = r.out.result;
3133                 goto done;
3134         }
3135
3136         r.in.data_offered       = *r.out.data_needed;
3137         r.in.value_offered      = *r.out.value_needed;
3138         r.out.data              = talloc_zero_array(mem_ctx, uint8_t, r.in.data_offered);
3139         r.out.value_name        = talloc_zero_array(mem_ctx, char, r.in.value_offered);
3140
3141         do {
3142
3143                 status = dcerpc_spoolss_EnumPrinterData_r(b, mem_ctx, &r);
3144                 if (!NT_STATUS_IS_OK(status)) {
3145                         result = ntstatus_to_werror(status);
3146                         goto done;
3147                 }
3148
3149                 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
3150                         result = WERR_OK;
3151                         break;
3152                 }
3153
3154                 r.in.enum_index++;
3155
3156                 display_reg_value(r.out.value_name, *r.out.type,
3157                                   data_blob_const(r.out.data, r.in.data_offered));
3158
3159         } while (W_ERROR_IS_OK(r.out.result));
3160
3161 done:
3162         if (is_valid_policy_hnd(&hnd)) {
3163                 WERROR _result;
3164                 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
3165         }
3166
3167         return result;
3168 }
3169
3170 /****************************************************************************
3171 ****************************************************************************/
3172
3173 static WERROR cmd_spoolss_enum_data_ex( struct rpc_pipe_client *cli,
3174                                           TALLOC_CTX *mem_ctx, int argc,
3175                                           const char **argv)
3176 {
3177         WERROR result;
3178         uint32_t i;
3179         const char *printername;
3180         struct policy_handle hnd;
3181         uint32_t count;
3182         struct spoolss_PrinterEnumValues *info;
3183         struct dcerpc_binding_handle *b = cli->binding_handle;
3184
3185         if (argc != 3) {
3186                 printf("Usage: %s printername <keyname>\n", argv[0]);
3187                 return WERR_OK;
3188         }
3189
3190         /* Open printer handle */
3191
3192         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3193
3194         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3195                                                printername,
3196                                                SEC_FLAG_MAXIMUM_ALLOWED,
3197                                                &hnd);
3198         if (!W_ERROR_IS_OK(result)) {
3199                 goto done;
3200         }
3201
3202         /* Enumerate subkeys */
3203
3204         result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx,
3205                                                   &hnd,
3206                                                   argv[2],
3207                                                   0,
3208                                                   &count,
3209                                                   &info);
3210         if (!W_ERROR_IS_OK(result)) {
3211                 goto done;
3212         }
3213
3214         for (i=0; i < count; i++) {
3215                 display_printer_data(info[i].value_name,
3216                                      info[i].type,
3217                                      info[i].data->data,
3218                                      info[i].data->length);
3219         }
3220
3221  done:
3222         if (is_valid_policy_hnd(&hnd)) {
3223                 WERROR _result;
3224                 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
3225         }
3226
3227         return result;
3228 }
3229
3230 /****************************************************************************
3231 ****************************************************************************/
3232
3233 static WERROR cmd_spoolss_enum_printerkey(struct rpc_pipe_client *cli,
3234                                           TALLOC_CTX *mem_ctx, int argc,
3235                                           const char **argv)
3236 {
3237         WERROR result;
3238         const char *printername;
3239         const char *keyname = NULL;
3240         struct policy_handle hnd;
3241         const char **key_buffer = NULL;
3242         int i;
3243         uint32_t offered = 0;
3244         struct dcerpc_binding_handle *b = cli->binding_handle;
3245
3246         if (argc < 2 || argc > 4) {
3247                 printf("Usage: %s printername [keyname] [offered]\n", argv[0]);
3248                 return WERR_OK;
3249         }
3250
3251         if (argc >= 3) {
3252                 keyname = argv[2];
3253         } else {
3254                 keyname = "";
3255         }
3256
3257         if (argc == 4) {
3258                 offered = atoi(argv[3]);
3259         }
3260
3261         /* Open printer handle */
3262
3263         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3264
3265         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3266                                                printername,
3267                                                SEC_FLAG_MAXIMUM_ALLOWED,
3268                                                &hnd);
3269         if (!W_ERROR_IS_OK(result)) {
3270                 goto done;
3271         }
3272
3273         /* Enumerate subkeys */
3274
3275         result = rpccli_spoolss_enumprinterkey(cli, mem_ctx,
3276                                                &hnd,
3277                                                keyname,
3278                                                &key_buffer,
3279                                                offered);
3280
3281         if (!W_ERROR_IS_OK(result)) {
3282                 goto done;
3283         }
3284
3285         for (i=0; key_buffer && key_buffer[i]; i++) {
3286                 printf("%s\n", key_buffer[i]);
3287         }
3288
3289  done:
3290
3291         if (is_valid_policy_hnd(&hnd)) {
3292                 WERROR _result;
3293                 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
3294         }
3295
3296         return result;
3297 }
3298
3299 /****************************************************************************
3300 ****************************************************************************/
3301
3302 static WERROR cmd_spoolss_rffpcnex(struct rpc_pipe_client *cli,
3303                                      TALLOC_CTX *mem_ctx, int argc,
3304                                      const char **argv)
3305 {
3306         const char *printername;
3307         const char *clientname;
3308         struct policy_handle hnd = { 0, };
3309         WERROR result;
3310         NTSTATUS status;
3311         struct spoolss_NotifyOption option;
3312         struct dcerpc_binding_handle *b = cli->binding_handle;
3313
3314         if (argc != 2) {
3315                 printf("Usage: %s printername\n", argv[0]);
3316                 result = WERR_OK;
3317                 goto done;
3318         }
3319
3320         /* Open printer */
3321
3322         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3323
3324         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3325                                                printername,
3326                                                SEC_FLAG_MAXIMUM_ALLOWED,
3327                                                &hnd);
3328         if (!W_ERROR_IS_OK(result)) {
3329                 printf("Error opening %s\n", argv[1]);
3330                 goto done;
3331         }
3332
3333         /* Create spool options */
3334
3335         option.version = 2;
3336         option.count = 2;
3337
3338         option.types = talloc_array(mem_ctx, struct spoolss_NotifyOptionType, 2);
3339         if (option.types == NULL) {
3340                 result = WERR_NOT_ENOUGH_MEMORY;
3341                 goto done;
3342         }
3343
3344         option.types[0].type = PRINTER_NOTIFY_TYPE;
3345         option.types[0].count = 1;
3346         option.types[0].fields = talloc_array(mem_ctx, union spoolss_Field, 1);
3347         if (option.types[0].fields == NULL) {
3348                 result = WERR_NOT_ENOUGH_MEMORY;
3349                 goto done;
3350         }
3351         option.types[0].fields[0].field = PRINTER_NOTIFY_FIELD_SERVER_NAME;
3352
3353         option.types[1].type = JOB_NOTIFY_TYPE;
3354         option.types[1].count = 1;
3355         option.types[1].fields = talloc_array(mem_ctx, union spoolss_Field, 1);
3356         if (option.types[1].fields == NULL) {
3357                 result = WERR_NOT_ENOUGH_MEMORY;
3358                 goto done;
3359         }
3360         option.types[1].fields[0].field = JOB_NOTIFY_FIELD_PRINTER_NAME;
3361
3362         clientname = talloc_asprintf(mem_ctx, "\\\\%s", lp_netbios_name());
3363         if (!clientname) {
3364                 result = WERR_NOT_ENOUGH_MEMORY;
3365                 goto done;
3366         }
3367
3368         /* Send rffpcnex */
3369
3370         status = dcerpc_spoolss_RemoteFindFirstPrinterChangeNotifyEx(b, mem_ctx,
3371                                                                      &hnd,
3372                                                                      0,
3373                                                                      0,
3374                                                                      clientname,
3375                                                                      123,
3376                                                                      &option,
3377                                                                      &result);
3378         if (!NT_STATUS_IS_OK(status)) {
3379                 result = ntstatus_to_werror(status);
3380                 goto done;
3381         }
3382         if (!W_ERROR_IS_OK(result)) {
3383                 printf("Error rffpcnex %s\n", argv[1]);
3384                 goto done;
3385         }
3386
3387 done:
3388         if (is_valid_policy_hnd(&hnd)) {
3389                 WERROR _result;
3390                 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
3391         }
3392
3393         return result;
3394 }
3395
3396 /****************************************************************************
3397 ****************************************************************************/
3398
3399 static bool compare_printer( struct rpc_pipe_client *cli1, struct policy_handle *hnd1,
3400                              struct rpc_pipe_client *cli2, struct policy_handle *hnd2 )
3401 {
3402         union spoolss_PrinterInfo info1, info2;
3403         WERROR werror;
3404         TALLOC_CTX *mem_ctx = talloc_init("compare_printer");
3405
3406         printf("Retrieving printer propertiesfor %s...", cli1->desthost);
3407         werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
3408                                            hnd1,
3409                                            2,
3410                                            0,
3411                                            &info1);
3412         if ( !W_ERROR_IS_OK(werror) ) {
3413                 printf("failed (%s)\n", win_errstr(werror));
3414                 talloc_destroy(mem_ctx);
3415                 return false;
3416         }
3417         printf("ok\n");
3418
3419         printf("Retrieving printer properties for %s...", cli2->desthost);
3420         werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
3421                                            hnd2,
3422                                            2,
3423                                            0,
3424                                            &info2);
3425         if ( !W_ERROR_IS_OK(werror) ) {
3426                 printf("failed (%s)\n", win_errstr(werror));
3427                 talloc_destroy(mem_ctx);
3428                 return false;
3429         }
3430         printf("ok\n");
3431
3432         talloc_destroy(mem_ctx);
3433
3434         return true;
3435 }
3436
3437 /****************************************************************************
3438 ****************************************************************************/
3439
3440 static bool compare_printer_secdesc( struct rpc_pipe_client *cli1, struct policy_handle *hnd1,
3441                                      struct rpc_pipe_client *cli2, struct policy_handle *hnd2 )
3442 {
3443         union spoolss_PrinterInfo info1, info2;
3444         WERROR werror;
3445         TALLOC_CTX *mem_ctx = talloc_init("compare_printer_secdesc");
3446         struct security_descriptor *sd1, *sd2;
3447         bool result = true;
3448
3449
3450         printf("Retrieving printer security for %s...", cli1->desthost);
3451         werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
3452                                            hnd1,
3453                                            3,
3454                                            0,
3455                                            &info1);
3456         if ( !W_ERROR_IS_OK(werror) ) {
3457                 printf("failed (%s)\n", win_errstr(werror));
3458                 result = false;
3459                 goto done;
3460         }
3461         printf("ok\n");
3462
3463         printf("Retrieving printer security for %s...", cli2->desthost);
3464         werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
3465                                            hnd2,
3466                                            3,
3467                                            0,
3468                                            &info2);
3469         if ( !W_ERROR_IS_OK(werror) ) {
3470                 printf("failed (%s)\n", win_errstr(werror));
3471                 result = false;
3472                 goto done;
3473         }
3474         printf("ok\n");
3475
3476
3477         printf("++ ");
3478
3479         sd1 = info1.info3.secdesc;
3480         sd2 = info2.info3.secdesc;
3481
3482         if ( (sd1 != sd2) && ( !sd1 || !sd2 ) ) {
3483                 printf("NULL secdesc!\n");
3484                 result = false;
3485                 goto done;
3486         }
3487
3488         if (!security_descriptor_equal( sd1, sd2 ) ) {
3489                 printf("Security Descriptors *not* equal!\n");
3490                 result = false;
3491                 goto done;
3492         }
3493
3494         printf("Security descriptors match\n");
3495
3496 done:
3497         talloc_destroy(mem_ctx);
3498         return result;
3499 }
3500
3501
3502 /****************************************************************************
3503 ****************************************************************************/
3504
3505 static WERROR cmd_spoolss_printercmp(struct rpc_pipe_client *cli,
3506                                      TALLOC_CTX *mem_ctx, int argc,
3507                                      const char **argv)
3508 {
3509         const char *printername;
3510         char *printername_path = NULL;
3511         struct cli_state *cli_server2 = NULL;
3512         struct rpc_pipe_client *cli2 = NULL;
3513         struct policy_handle hPrinter1, hPrinter2;
3514         NTSTATUS nt_status;
3515         WERROR werror;
3516
3517         if ( argc != 3 )  {
3518                 printf("Usage: %s <printer> <server>\n", argv[0]);
3519                 return WERR_OK;
3520         }
3521
3522         printername = argv[1];
3523
3524         /* first get the connection to the remote server */
3525
3526         nt_status = cli_full_connection(&cli_server2, lp_netbios_name(), argv[2],
3527                                 NULL, 0,
3528                                 "IPC$", "IPC",
3529                                 get_cmdline_auth_info_username(
3530                                         popt_get_cmdline_auth_info()),
3531                                 lp_workgroup(),
3532                                 get_cmdline_auth_info_password(
3533                                         popt_get_cmdline_auth_info()),
3534                                 get_cmdline_auth_info_use_kerberos(
3535                                         popt_get_cmdline_auth_info()) ?
3536                                         CLI_FULL_CONNECTION_USE_KERBEROS : 0,
3537                                 get_cmdline_auth_info_signing_state(
3538                                         popt_get_cmdline_auth_info()));
3539
3540         if ( !NT_STATUS_IS_OK(nt_status) )
3541                 return WERR_GEN_FAILURE;
3542
3543         nt_status = cli_rpc_pipe_open_noauth(cli_server2, &ndr_table_spoolss,
3544                                              &cli2);
3545         if (!NT_STATUS_IS_OK(nt_status)) {
3546                 printf("failed to open spoolss pipe on server %s (%s)\n",
3547                         argv[2], nt_errstr(nt_status));
3548                 return WERR_GEN_FAILURE;
3549         }
3550
3551         /* now open up both printers */
3552
3553         RPCCLIENT_PRINTERNAME(printername_path, cli, printername);
3554
3555         printf("Opening %s...", printername_path);
3556
3557         werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3558                                                printername_path,
3559                                                PRINTER_ALL_ACCESS,
3560                                                &hPrinter1);
3561         if ( !W_ERROR_IS_OK(werror) ) {
3562                 printf("failed (%s)\n", win_errstr(werror));
3563                 goto done;
3564         }
3565         printf("ok\n");
3566
3567         RPCCLIENT_PRINTERNAME(printername_path, cli2, printername);
3568
3569         printf("Opening %s...", printername_path);
3570         werror = rpccli_spoolss_openprinter_ex(cli2, mem_ctx,
3571                                                printername_path,
3572                                                PRINTER_ALL_ACCESS,
3573                                                &hPrinter2);
3574         if ( !W_ERROR_IS_OK(werror) ) {
3575                  printf("failed (%s)\n", win_errstr(werror));
3576                 goto done;
3577         }
3578         printf("ok\n");
3579
3580         compare_printer( cli, &hPrinter1, cli2, &hPrinter2 );
3581         compare_printer_secdesc( cli, &hPrinter1, cli2, &hPrinter2 );
3582 #if 0
3583         compare_printerdata( cli_server1, &hPrinter1, cli_server2, &hPrinter2 );
3584 #endif
3585
3586
3587 done:
3588         /* cleanup */
3589
3590         printf("Closing printers...");
3591         {
3592                 WERROR _result;
3593                 dcerpc_spoolss_ClosePrinter(cli->binding_handle, mem_ctx, &hPrinter1, &_result);
3594                 dcerpc_spoolss_ClosePrinter(cli2->binding_handle, mem_ctx, &hPrinter2, &_result);
3595         }
3596         printf("ok\n");
3597
3598         /* close the second remote connection */
3599
3600         cli_shutdown( cli_server2 );
3601         return WERR_OK;
3602 }
3603
3604 static void display_proc_info1(struct spoolss_PrintProcessorInfo1 *r)
3605 {
3606         printf("print_processor_name: %s\n", r->print_processor_name);
3607 }
3608
3609 static WERROR cmd_spoolss_enum_procs(struct rpc_pipe_client *cli,
3610                                      TALLOC_CTX *mem_ctx, int argc,
3611                                      const char **argv)
3612 {
3613         WERROR werror;
3614         const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
3615         uint32_t num_procs, level = 1, i;
3616         union spoolss_PrintProcessorInfo *procs;
3617
3618         /* Parse the command arguments */
3619
3620         if (argc < 1 || argc > 4) {
3621                 printf ("Usage: %s [environment] [level]\n", argv[0]);
3622                 return WERR_OK;
3623         }
3624
3625         if (argc >= 2) {
3626                 environment = argv[1];
3627         }
3628
3629         if (argc == 3) {
3630                 level = atoi(argv[2]);
3631         }
3632
3633         /* Enumerate Print Processors */
3634
3635         werror = rpccli_spoolss_enumprintprocessors(cli, mem_ctx,
3636                                                     cli->srv_name_slash,
3637                                                     environment,
3638                                                     level,
3639                                                     0,
3640                                                     &num_procs,
3641                                                     &procs);
3642         if (!W_ERROR_IS_OK(werror))
3643                 goto done;
3644
3645         /* Display output */
3646
3647         for (i = 0; i < num_procs; i++) {
3648                 switch (level) {
3649                 case 1:
3650                         display_proc_info1(&procs[i].info1);
3651                         break;
3652                 }
3653         }
3654
3655  done:
3656         return werror;
3657 }
3658
3659 static void display_proc_data_types_info1(struct spoolss_PrintProcDataTypesInfo1 *r)
3660 {
3661         printf("name_array: %s\n", r->name_array);
3662 }
3663
3664 static WERROR cmd_spoolss_enum_proc_data_types(struct rpc_pipe_client *cli,
3665                                                TALLOC_CTX *mem_ctx, int argc,
3666                                                const char **argv)
3667 {
3668         WERROR werror;
3669         const char *print_processor_name = "winprint";
3670         uint32_t num_procs, level = 1, i;
3671         union spoolss_PrintProcDataTypesInfo *procs;
3672
3673         /* Parse the command arguments */
3674
3675         if (argc < 1 || argc > 4) {
3676                 printf ("Usage: %s [environment] [level]\n", argv[0]);
3677                 return WERR_OK;
3678         }
3679
3680         if (argc >= 2) {
3681                 print_processor_name = argv[1];
3682         }
3683
3684         if (argc == 3) {
3685                 level = atoi(argv[2]);
3686         }
3687
3688         /* Enumerate Print Processor Data Types */
3689
3690         werror = rpccli_spoolss_enumprintprocessordatatypes(cli, mem_ctx,
3691                                                             cli->srv_name_slash,
3692                                                             print_processor_name,
3693                                                             level,
3694                                                             0,
3695                                                             &num_procs,
3696                                                             &procs);
3697         if (!W_ERROR_IS_OK(werror))
3698                 goto done;
3699
3700         /* Display output */
3701
3702         for (i = 0; i < num_procs; i++) {
3703                 switch (level) {
3704                 case 1:
3705                         display_proc_data_types_info1(&procs[i].info1);
3706                         break;
3707                 }
3708         }
3709
3710  done:
3711         return werror;
3712 }
3713
3714 static void display_monitor1(const struct spoolss_MonitorInfo1 *r)
3715 {
3716         printf("monitor_name: %s\n", r->monitor_name);
3717 }
3718
3719 static void display_monitor2(const struct spoolss_MonitorInfo2 *r)
3720 {
3721         printf("monitor_name: %s\n", r->monitor_name);
3722         printf("environment: %s\n", r->environment);
3723         printf("dll_name: %s\n", r->dll_name);
3724 }
3725
3726 static WERROR cmd_spoolss_enum_monitors(struct rpc_pipe_client *cli,
3727                                         TALLOC_CTX *mem_ctx, int argc,
3728                                         const char **argv)
3729 {
3730         WERROR werror;
3731         uint32_t count, level = 1, i;
3732         union spoolss_MonitorInfo *info;
3733
3734         /* Parse the command arguments */
3735
3736         if (argc > 2) {
3737                 printf("Usage: %s [level]\n", argv[0]);
3738                 return WERR_OK;
3739         }
3740
3741         if (argc == 2) {
3742                 level = atoi(argv[1]);
3743         }
3744
3745         /* Enumerate Print Monitors */
3746
3747         werror = rpccli_spoolss_enummonitors(cli, mem_ctx,
3748                                              cli->srv_name_slash,
3749                                              level,
3750                                              0,
3751                                              &count,
3752                                              &info);
3753         if (!W_ERROR_IS_OK(werror)) {
3754                 goto done;
3755         }
3756
3757         /* Display output */
3758
3759         for (i = 0; i < count; i++) {
3760                 switch (level) {
3761                 case 1:
3762                         display_monitor1(&info[i].info1);
3763                         break;
3764                 case 2:
3765                         display_monitor2(&info[i].info2);
3766                         break;
3767                 }
3768         }
3769
3770  done:
3771         return werror;
3772 }
3773
3774 static WERROR cmd_spoolss_create_printer_ic(struct rpc_pipe_client *cli,
3775                                             TALLOC_CTX *mem_ctx, int argc,
3776                                             const char **argv)
3777 {
3778         WERROR result;
3779         NTSTATUS status;
3780         struct policy_handle handle, gdi_handle;
3781         const char *printername;
3782         struct spoolss_DevmodeContainer devmode_ctr;
3783         struct dcerpc_binding_handle *b = cli->binding_handle;
3784
3785         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3786
3787         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3788                                                printername,
3789                                                SEC_FLAG_MAXIMUM_ALLOWED,
3790                                                &handle);
3791         if (!W_ERROR_IS_OK(result)) {
3792                 return result;
3793         }
3794
3795         ZERO_STRUCT(devmode_ctr);
3796
3797         status = dcerpc_spoolss_CreatePrinterIC(b, mem_ctx,
3798                                                 &handle,
3799                                                 &gdi_handle,
3800                                                 &devmode_ctr,
3801                                                 &result);
3802         if (!NT_STATUS_IS_OK(status)) {
3803                 result = ntstatus_to_werror(status);
3804                 goto done;
3805         }
3806         if (!W_ERROR_IS_OK(result)) {
3807                 goto done;
3808         }
3809
3810  done:
3811         if (is_valid_policy_hnd(&gdi_handle)) {
3812                 WERROR _result;
3813                 dcerpc_spoolss_DeletePrinterIC(b, mem_ctx, &gdi_handle, &_result);
3814         }
3815         if (is_valid_policy_hnd(&handle)) {
3816                 WERROR _result;
3817                 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result);
3818         }
3819
3820         return result;
3821 }
3822
3823 static WERROR cmd_spoolss_play_gdi_script_on_printer_ic(struct rpc_pipe_client *cli,
3824                                                         TALLOC_CTX *mem_ctx, int argc,
3825                                                         const char **argv)
3826 {
3827         WERROR result;
3828         NTSTATUS status;
3829         struct policy_handle handle, gdi_handle;
3830         const char *printername;
3831         struct spoolss_DevmodeContainer devmode_ctr;
3832         struct dcerpc_binding_handle *b = cli->binding_handle;
3833         DATA_BLOB in,out;
3834         uint32_t count = 0;
3835
3836         RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3837
3838         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3839                                                printername,
3840                                                SEC_FLAG_MAXIMUM_ALLOWED,
3841                                                &handle);
3842         if (!W_ERROR_IS_OK(result)) {
3843                 return result;
3844         }
3845
3846         ZERO_STRUCT(devmode_ctr);
3847
3848         status = dcerpc_spoolss_CreatePrinterIC(b, mem_ctx,
3849                                                 &handle,
3850                                                 &gdi_handle,
3851                                                 &devmode_ctr,
3852                                                 &result);
3853         if (!NT_STATUS_IS_OK(status)) {
3854                 result = ntstatus_to_werror(status);
3855                 goto done;
3856         }
3857         if (!W_ERROR_IS_OK(result)) {
3858                 goto done;
3859         }
3860
3861         in = data_blob_string_const("");
3862         out = data_blob_talloc_zero(mem_ctx, 4);
3863
3864         status = dcerpc_spoolss_PlayGDIScriptOnPrinterIC(b, mem_ctx,
3865                                                          &gdi_handle,
3866                                                          in.data,
3867                                                          in.length,
3868                                                          out.data,
3869                                                          out.length,
3870                                                          0, /* ul */
3871                                                          &result);
3872         if (!NT_STATUS_IS_OK(status)) {
3873                 result = ntstatus_to_werror(status);
3874                 goto done;
3875         }
3876         if (!W_ERROR_IS_OK(result)) {
3877                 goto done;
3878         }
3879
3880         count = IVAL(out.data, 0);
3881
3882         out = data_blob_talloc_zero(mem_ctx,
3883                                     count * sizeof(struct UNIVERSAL_FONT_ID) + 4);
3884
3885         status = dcerpc_spoolss_PlayGDIScriptOnPrinterIC(b, mem_ctx,
3886                                                          &gdi_handle,
3887                                                          in.data,
3888                                                          in.length,
3889                                                          out.data,
3890                                                          out.length,
3891                                                          0, /* ul */
3892                                                          &result);
3893         if (!NT_STATUS_IS_OK(status)) {
3894                 result = ntstatus_to_werror(status);
3895                 goto done;
3896         }
3897         if (!W_ERROR_IS_OK(result)) {
3898                 goto done;
3899         }
3900
3901         {
3902                 enum ndr_err_code ndr_err;
3903                 struct UNIVERSAL_FONT_ID_ctr r;
3904
3905                 ndr_err = ndr_pull_struct_blob(&out, mem_ctx, &r,
3906                         (ndr_pull_flags_fn_t)ndr_pull_UNIVERSAL_FONT_ID_ctr);
3907                 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3908                         NDR_PRINT_DEBUG(UNIVERSAL_FONT_ID_ctr, &r);
3909                 }
3910         }
3911
3912  done:
3913         if (is_valid_policy_hnd(&gdi_handle)) {
3914                 WERROR _result;
3915                 dcerpc_spoolss_DeletePrinterIC(b, mem_ctx, &gdi_handle, &_result);
3916         }
3917         if (is_valid_policy_hnd(&handle)) {
3918                 WERROR _result;
3919                 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result);
3920         }
3921
3922         return result;
3923 }
3924
3925 /* List of commands exported by this module */
3926 struct cmd_set spoolss_commands[] = {
3927
3928         {
3929                 .name = "SPOOLSS",
3930         },
3931
3932         {
3933                 .name               = "adddriver",
3934                 .returntype         = RPC_RTYPE_WERROR,
3935                 .ntfn               = NULL,
3936                 .wfn                = cmd_spoolss_addprinterdriver,
3937                 .table              = &ndr_table_spoolss,
3938                 .rpc_pipe           = NULL,
3939                 .description        = "Add a print driver",
3940                 .usage              = "",
3941                 .use_netlogon_creds = false,
3942         },
3943         {
3944                 .name               = "addprinter",
3945                 .returntype         = RPC_RTYPE_WERROR,
3946                 .ntfn               = NULL,
3947                 .wfn                = cmd_spoolss_addprinterex,
3948                 .table              = &ndr_table_spoolss,
3949                 .rpc_pipe           = NULL,
3950                 .description        = "Add a printer",
3951                 .usage              = "",
3952         },
3953         {
3954                 .name               = "deldriver",
3955                 .returntype         = RPC_RTYPE_WERROR,
3956                 .ntfn               = NULL,
3957                 .wfn                = cmd_spoolss_deletedriver,
3958                 .table              = &ndr_table_spoolss,
3959                 .rpc_pipe           = NULL,
3960                 .description        = "Delete a printer driver",
3961                 .usage              = "",
3962         },
3963         {
3964                 .name               = "deldriverex",
3965                 .returntype         = RPC_RTYPE_WERROR,
3966                 .ntfn               = NULL,
3967                 .wfn                = cmd_spoolss_deletedriverex,
3968                 .table              = &ndr_table_spoolss,
3969                 .rpc_pipe           = NULL,
3970                 .description        = "Delete a printer driver with files",
3971                 .usage              = "",
3972         },
3973         {
3974                 .name               = "enumdata",
3975                 .returntype         = RPC_RTYPE_WERROR,
3976                 .ntfn               = NULL,
3977                 .wfn                = cmd_spoolss_enum_data,
3978                 .table              = &ndr_table_spoolss,
3979                 .rpc_pipe           = NULL,
3980                 .description        = "Enumerate printer data",
3981                 .usage              = "",
3982         },
3983         {
3984                 .name               = "enumdataex",
3985                 .returntype         = RPC_RTYPE_WERROR,
3986                 .ntfn               = NULL,
3987                 .wfn                = cmd_spoolss_enum_data_ex,
3988                 .table              = &ndr_table_spoolss,
3989                 .rpc_pipe           = NULL,
3990                 .description        = "Enumerate printer data for a key",
3991                 .usage              = "",
3992         },
3993         {
3994                 .name               = "enumkey",
3995                 .returntype         = RPC_RTYPE_WERROR,
3996                 .ntfn               = NULL,
3997                 .wfn                = cmd_spoolss_enum_printerkey,
3998                 .table              = &ndr_table_spoolss,
3999                 .rpc_pipe           = NULL,
4000                 .description        = "Enumerate printer keys",
4001                 .usage              = "",
4002         },
4003         {
4004                 .name               = "enumjobs",
4005                 .returntype         = RPC_RTYPE_WERROR,
4006                 .ntfn               = NULL,
4007                 .wfn                = cmd_spoolss_enum_jobs,
4008                 .table              = &ndr_table_spoolss,
4009                 .rpc_pipe           = NULL,
4010                 .description        = "Enumerate print jobs",
4011                 .usage              = "",
4012         },
4013         {
4014                 .name               = "getjob",
4015                 .returntype         = RPC_RTYPE_WERROR,
4016                 .ntfn               = NULL,
4017                 .wfn                = cmd_spoolss_get_job,
4018                 .table              = &ndr_table_spoolss,
4019                 .rpc_pipe           = NULL,
4020                 .description        = "Get print job",
4021                 .usage              = "",
4022         },
4023         {
4024                 .name               = "setjob",
4025                 .returntype         = RPC_RTYPE_WERROR,
4026                 .ntfn               = NULL,
4027                 .wfn                = cmd_spoolss_set_job,
4028                 .table              = &ndr_table_spoolss,
4029                 .rpc_pipe           = NULL,
4030                 .description        = "Set print job",
4031                 .usage              = "",
4032         },
4033         {
4034                 .name               = "enumports",
4035                 .returntype         = RPC_RTYPE_WERROR,
4036                 .ntfn               = NULL,
4037                 .wfn                = cmd_spoolss_enum_ports,
4038                 .table              = &ndr_table_spoolss,
4039                 .rpc_pipe           = NULL,
4040                 .description        = "Enumerate printer ports",
4041                 .usage              = "",
4042         },
4043         {
4044                 .name               = "enumdrivers",
4045                 .returntype         = RPC_RTYPE_WERROR,
4046                 .ntfn               = NULL,
4047                 .wfn                = cmd_spoolss_enum_drivers,
4048                 .table              = &ndr_table_spoolss,
4049                 .rpc_pipe           = NULL,
4050                 .description        = "Enumerate installed printer drivers",
4051                 .usage              = "",
4052         },
4053         {
4054                 .name               = "enumprinters",
4055                 .returntype         = RPC_RTYPE_WERROR,
4056                 .ntfn               = NULL,
4057                 .wfn                = cmd_spoolss_enum_printers,
4058                 .table              = &ndr_table_spoolss,
4059                 .rpc_pipe           = NULL,
4060                 .description        = "Enumerate printers",
4061                 .usage              = "",
4062         },
4063         {
4064                 .name               = "getdata",
4065                 .returntype         = RPC_RTYPE_WERROR,
4066                 .ntfn               = NULL,
4067                 .wfn                = cmd_spoolss_getprinterdata,
4068                 .table              = &ndr_table_spoolss,
4069                 .rpc_pipe           = NULL,
4070                 .description        = "Get print driver data",
4071                 .usage              = "",
4072         },
4073         {
4074                 .name               = "getdataex",
4075                 .returntype         = RPC_RTYPE_WERROR,
4076                 .ntfn               = NULL,
4077                 .wfn                = cmd_spoolss_getprinterdataex,
4078                 .table              = &ndr_table_spoolss,
4079                 .rpc_pipe           = NULL,
4080                 .description        = "Get printer driver data with keyname",
4081                 .usage              = "",
4082         },
4083         {
4084                 .name               = "getdriver",
4085                 .returntype         = RPC_RTYPE_WERROR,
4086                 .ntfn               = NULL,
4087                 .wfn                = cmd_spoolss_getdriver,
4088                 .table              = &ndr_table_spoolss,
4089                 .rpc_pipe           = NULL,
4090                 .description        = "Get print driver information",
4091                 .usage              = "",
4092         },
4093         {
4094                 .name               = "getdriverdir",
4095                 .returntype         = RPC_RTYPE_WERROR,
4096                 .ntfn               = NULL,
4097                 .wfn                = cmd_spoolss_getdriverdir,
4098                 .table              = &ndr_table_spoolss,
4099                 .rpc_pipe           = NULL,
4100                 .description        = "Get print driver upload directory",
4101                 .usage              = "",
4102         },
4103         {
4104                 .name               = "getdriverpackagepath",
4105                 .returntype         = RPC_RTYPE_WERROR,
4106                 .ntfn               = NULL,
4107                 .wfn                = cmd_spoolss_getdriverpackagepath,
4108                 .table              = &ndr_table_spoolss,
4109                 .rpc_pipe           = NULL,
4110                 .description        = "Get print driver package download directory",
4111                 .usage              = "",
4112         },
4113         {
4114                 .name               = "getprinter",
4115                 .returntype         = RPC_RTYPE_WERROR,
4116                 .ntfn               = NULL,
4117                 .wfn                = cmd_spoolss_getprinter,
4118                 .table              = &ndr_table_spoolss,
4119                 .rpc_pipe           = NULL,
4120                 .description        = "Get printer info",
4121                 .usage              = "",
4122         },
4123         {
4124                 .name               = "openprinter",
4125                 .returntype         = RPC_RTYPE_WERROR,
4126                 .ntfn               = NULL,
4127                 .wfn                = cmd_spoolss_open_printer,
4128                 .table              = &ndr_table_spoolss,
4129                 .rpc_pipe           = NULL,
4130                 .description        = "Open printer handle",
4131                 .usage              = "",
4132         },
4133         {
4134                 .name               = "openprinter_ex",
4135                 .returntype         = RPC_RTYPE_WERROR,
4136                 .ntfn               = NULL,
4137                 .wfn                = cmd_spoolss_open_printer_ex,
4138                 .table              = &ndr_table_spoolss,
4139                 .rpc_pipe           = NULL,
4140                 .description        = "Open printer handle",
4141                 .usage              = "",
4142         },
4143         {
4144                 .name               = "setdriver",
4145                 .returntype         = RPC_RTYPE_WERROR,
4146                 .ntfn               = NULL,
4147                 .wfn                = cmd_spoolss_setdriver,
4148                 .table              = &ndr_table_spoolss,
4149                 .rpc_pipe           = NULL,
4150                 .description        = "Set printer driver",
4151                 .usage              = "",
4152         },
4153         {
4154                 .name               = "getprintprocdir",
4155                 .returntype         = RPC_RTYPE_WERROR,
4156                 .ntfn               = NULL,
4157                 .wfn                = cmd_spoolss_getprintprocdir,
4158                 .table              = &ndr_table_spoolss,
4159                 .rpc_pipe           = NULL,
4160                 .description        = "Get print processor directory",
4161                 .usage              = "",
4162         },
4163         {
4164                 .name               = "addform",
4165                 .returntype         = RPC_RTYPE_WERROR,
4166                 .ntfn               = NULL,
4167                 .wfn                = cmd_spoolss_addform,
4168                 .table              = &ndr_table_spoolss,
4169                 .rpc_pipe           = NULL,
4170                 .description        = "Add form",
4171                 .usage              = "",
4172         },
4173         {
4174                 .name               = "setform",
4175                 .returntype         = RPC_RTYPE_WERROR,
4176                 .ntfn               = NULL,
4177                 .wfn                = cmd_spoolss_setform,
4178                 .table              = &ndr_table_spoolss,
4179                 .rpc_pipe           = NULL,
4180                 .description        = "Set form",
4181                 .usage              = "",
4182         },
4183         {
4184                 .name               = "getform",
4185                 .returntype         = RPC_RTYPE_WERROR,
4186                 .ntfn               = NULL,
4187                 .wfn                = cmd_spoolss_getform,
4188                 .table              = &ndr_table_spoolss,
4189                 .rpc_pipe           = NULL,
4190                 .description        = "Get form",
4191                 .usage              = "",
4192         },
4193         {
4194                 .name               = "deleteform",
4195                 .returntype         = RPC_RTYPE_WERROR,
4196                 .ntfn               = NULL,
4197                 .wfn                = cmd_spoolss_deleteform,
4198                 .table              = &ndr_table_spoolss,
4199                 .rpc_pipe           = NULL,
4200                 .description        = "Delete form",
4201                 .usage              = "",
4202         },
4203         {
4204                 .name               = "enumforms",
4205                 .returntype         = RPC_RTYPE_WERROR,
4206                 .ntfn               = NULL,
4207                 .wfn                = cmd_spoolss_enum_forms,
4208                 .table              = &ndr_table_spoolss,
4209                 .rpc_pipe           = NULL,
4210                 .description        = "Enumerate forms",
4211                 .usage              = "",
4212         },
4213         {
4214                 .name               = "setprinter",
4215                 .returntype         = RPC_RTYPE_WERROR,
4216                 .ntfn               = NULL,
4217                 .wfn                = cmd_spoolss_setprinter,
4218                 .table              = &ndr_table_spoolss,
4219                 .rpc_pipe           = NULL,
4220                 .description        = "Set printer comment",
4221                 .usage              = "",
4222         },
4223         {
4224                 .name               = "setprintername",
4225                 .returntype         = RPC_RTYPE_WERROR,
4226                 .ntfn               = NULL,
4227                 .wfn                = cmd_spoolss_setprintername,
4228                 .table              = &ndr_table_spoolss,
4229                 .rpc_pipe           = NULL,
4230                 .description        = "Set printername",
4231                 .usage              = "",
4232         },
4233         {
4234                 .name               = "setprinterdata",
4235                 .returntype         = RPC_RTYPE_WERROR,
4236                 .ntfn               = NULL,
4237                 .wfn                = cmd_spoolss_setprinterdata,
4238                 .table              = &ndr_table_spoolss,
4239                 .rpc_pipe           = NULL,
4240                 .description        = "Set REG_SZ printer data",
4241                 .usage              = "",
4242         },
4243         {
4244                 .name               = "rffpcnex",
4245                 .returntype         = RPC_RTYPE_WERROR,
4246                 .ntfn               = NULL,
4247                 .wfn                = cmd_spoolss_rffpcnex,
4248                 .table              = &ndr_table_spoolss,
4249                 .rpc_pipe           = NULL,
4250                 .description        = "Rffpcnex test",
4251                 .usage              = "",
4252         },
4253         {
4254                 .name               = "printercmp",
4255                 .returntype         = RPC_RTYPE_WERROR,
4256                 .ntfn               = NULL,
4257                 .wfn                = cmd_spoolss_printercmp,
4258                 .table              = &ndr_table_spoolss,
4259                 .rpc_pipe           = NULL,
4260                 .description        = "Printer comparison test",
4261                 .usage              = "",
4262         },
4263         {
4264                 .name               = "enumprocs",
4265                 .returntype         = RPC_RTYPE_WERROR,
4266                 .ntfn               = NULL,
4267                 .wfn                = cmd_spoolss_enum_procs,
4268                 .table              = &ndr_table_spoolss,
4269                 .rpc_pipe           = NULL,
4270                 .description        = "Enumerate Print Processors",
4271                 .usage              = "",
4272         },
4273         {
4274                 .name               = "enumprocdatatypes",
4275                 .returntype         = RPC_RTYPE_WERROR,
4276                 .ntfn               = NULL,
4277                 .wfn                = cmd_spoolss_enum_proc_data_types,
4278                 .table              = &ndr_table_spoolss,
4279                 .rpc_pipe           = NULL,
4280                 .description        = "Enumerate Print Processor Data Types",
4281                 .usage              = "",
4282         },
4283         {
4284                 .name               = "enummonitors",
4285                 .returntype         = RPC_RTYPE_WERROR,
4286                 .ntfn               = NULL,
4287                 .wfn                = cmd_spoolss_enum_monitors,
4288                 .table              = &ndr_table_spoolss,
4289                 .rpc_pipe           = NULL,
4290                 .description        = "Enumerate Print Monitors",
4291                 .usage              = "",
4292         },
4293         {
4294                 .name               = "createprinteric",
4295                 .returntype         = RPC_RTYPE_WERROR,
4296                 .ntfn               = NULL,
4297                 .wfn                = cmd_spoolss_create_printer_ic,
4298                 .table              = &ndr_table_spoolss,
4299                 .rpc_pipe           = NULL,
4300                 .description        = "Create Printer IC",
4301                 .usage              = "",
4302         },
4303         {
4304                 .name               = "playgdiscriptonprinteric",
4305                 .returntype         = RPC_RTYPE_WERROR,
4306                 .ntfn               = NULL,
4307                 .wfn                = cmd_spoolss_play_gdi_script_on_printer_ic,
4308                 .table              = &ndr_table_spoolss,
4309                 .rpc_pipe           = NULL,
4310                 .description        = "Create Printer IC",
4311                 .usage              = "",
4312         },
4313
4314         {
4315                 .name = NULL,
4316         },
4317 };