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