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