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