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