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