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