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