s3-libnet: Improve error message.
[Samba.git] / source3 / rpcclient / cmd_spoolss.c
blobfb011f8478d9c28214ff04fb5383b73a1fa33abc
1 /*
2 Unix SMB/CIFS implementation.
3 RPC pipe client
5 Copyright (C) Gerald Carter 2001-2005
6 Copyright (C) Tim Potter 2000
7 Copyright (C) Andrew Tridgell 1992-1999
8 Copyright (C) Luke Kenneth Casson Leighton 1996-1999
9 Copyright (C) Guenther Deschner 2009
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "rpcclient.h"
27 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
28 #include "../librpc/gen_ndr/ndr_spoolss.h"
29 #include "rpc_client/cli_spoolss.h"
30 #include "rpc_client/init_spoolss.h"
31 #include "nt_printing.h"
32 #include "../libcli/security/display_sec.h"
33 #include "../libcli/security/security_descriptor.h"
34 #include "../libcli/registry/util_reg.h"
35 #include "libsmb/libsmb.h"
37 #define RPCCLIENT_PRINTERNAME(_printername, _cli, _arg) \
38 { \
39 _printername = talloc_asprintf_strupper_m(mem_ctx, "%s\\%s", \
40 _cli->srv_name_slash, _arg); \
41 W_ERROR_HAVE_NO_MEMORY(_printername); \
44 /* The version int is used by getdrivers. Note that
45 all architecture strings that support mutliple
46 versions must be grouped together since enumdrivers
47 uses this property to prevent issuing multiple
48 enumdriver calls for the same arch */
51 static const struct print_architecture_table_node archi_table[]= {
53 {"Windows 4.0", "WIN40", 0 },
54 {"Windows NT x86", "W32X86", 2 },
55 {"Windows NT x86", "W32X86", 3 },
56 {"Windows NT R4000", "W32MIPS", 2 },
57 {"Windows NT Alpha_AXP", "W32ALPHA", 2 },
58 {"Windows NT PowerPC", "W32PPC", 2 },
59 {"Windows IA64", "IA64", 3 },
60 {"Windows x64", "x64", 3 },
61 {NULL, "", -1 }
64 /**
65 * @file
67 * rpcclient module for SPOOLSS rpc pipe.
69 * This generally just parses and checks command lines, and then calls
70 * a cli_spoolss function.
71 **/
73 /****************************************************************************
74 function to do the mapping between the long architecture name and
75 the short one.
76 ****************************************************************************/
78 static const char *cmd_spoolss_get_short_archi(const char *long_archi)
80 int i=-1;
82 DEBUG(107,("Getting architecture dependent directory\n"));
83 do {
84 i++;
85 } while ( (archi_table[i].long_archi!=NULL ) &&
86 strcasecmp_m(long_archi, archi_table[i].long_archi) );
88 if (archi_table[i].long_archi==NULL) {
89 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
90 return NULL;
93 /* this might be client code - but shouldn't this be an fstrcpy etc? */
96 DEBUGADD(108,("index: [%d]\n", i));
97 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
98 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
100 return archi_table[i].short_archi;
103 /****************************************************************************
104 ****************************************************************************/
106 static WERROR cmd_spoolss_open_printer_ex(struct rpc_pipe_client *cli,
107 TALLOC_CTX *mem_ctx,
108 int argc, const char **argv)
110 WERROR werror;
111 struct policy_handle hnd;
112 uint32_t access_mask = PRINTER_ALL_ACCESS;
113 struct dcerpc_binding_handle *b = cli->binding_handle;
115 if (argc < 2) {
116 printf("Usage: %s <printername> [access_mask]\n", argv[0]);
117 return WERR_OK;
120 if (argc >= 3) {
121 sscanf(argv[2], "%x", &access_mask);
124 /* Open the printer handle */
126 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
127 argv[1],
128 access_mask,
129 &hnd);
130 if (W_ERROR_IS_OK(werror)) {
131 printf("Printer %s opened successfully\n", argv[1]);
132 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &werror);
134 if (!W_ERROR_IS_OK(werror)) {
135 printf("Error closing printer handle! (%s)\n",
136 get_dos_error_msg(werror));
140 return werror;
143 /****************************************************************************
144 ****************************************************************************/
146 static WERROR cmd_spoolss_open_printer(struct rpc_pipe_client *cli,
147 TALLOC_CTX *mem_ctx,
148 int argc, const char **argv)
150 WERROR werror;
151 struct policy_handle hnd;
152 uint32_t access_mask = PRINTER_ALL_ACCESS;
153 NTSTATUS status;
154 struct spoolss_DevmodeContainer devmode_ctr;
155 struct dcerpc_binding_handle *b = cli->binding_handle;
157 ZERO_STRUCT(devmode_ctr);
159 if (argc < 2) {
160 printf("Usage: %s <printername> [access_mask]\n", argv[0]);
161 return WERR_OK;
164 if (argc >= 3) {
165 sscanf(argv[2], "%x", &access_mask);
168 /* Open the printer handle */
170 status = dcerpc_spoolss_OpenPrinter(b, mem_ctx,
171 argv[1],
172 NULL,
173 devmode_ctr,
174 access_mask,
175 &hnd,
176 &werror);
177 if (!NT_STATUS_IS_OK(status)) {
178 return ntstatus_to_werror(status);
180 if (W_ERROR_IS_OK(werror)) {
181 printf("Printer %s opened successfully\n", argv[1]);
182 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &werror);
184 if (!W_ERROR_IS_OK(werror)) {
185 printf("Error closing printer handle! (%s)\n",
186 get_dos_error_msg(werror));
190 return werror;
193 /****************************************************************************
194 ****************************************************************************/
196 static void display_print_info0(struct spoolss_PrinterInfo0 *r)
198 if (!r)
199 return;
201 printf("\tprintername:[%s]\n", r->printername);
202 printf("\tservername:[%s]\n", r->servername);
203 printf("\tcjobs:[0x%x]\n", r->cjobs);
204 printf("\ttotal_jobs:[0x%x]\n", r->total_jobs);
205 printf("\ttotal_bytes:[0x%x]\n", r->total_bytes);
206 printf("\t:date: [%d]-[%d]-[%d] (%d)\n", r->time.year, r->time.month,
207 r->time.day, r->time.day_of_week);
208 printf("\t:time: [%d]-[%d]-[%d]-[%d]\n", r->time.hour, r->time.minute,
209 r->time.second, r->time.millisecond);
211 printf("\tglobal_counter:[0x%x]\n", r->global_counter);
212 printf("\ttotal_pages:[0x%x]\n", r->total_pages);
214 printf("\tversion:[0x%x]\n", r->version);
215 printf("\tfree_build:[0x%x]\n", r->free_build);
216 printf("\tspooling:[0x%x]\n", r->spooling);
217 printf("\tmax_spooling:[0x%x]\n", r->max_spooling);
218 printf("\tsession_counter:[0x%x]\n", r->session_counter);
219 printf("\tnum_error_out_of_paper:[0x%x]\n", r->num_error_out_of_paper);
220 printf("\tnum_error_not_ready:[0x%x]\n", r->num_error_not_ready);
221 printf("\tjob_error:[0x%x]\n", r->job_error);
222 printf("\tnumber_of_processors:[0x%x]\n", r->number_of_processors);
223 printf("\tprocessor_type:[0x%x]\n", r->processor_type);
224 printf("\thigh_part_total_bytes:[0x%x]\n", r->high_part_total_bytes);
225 printf("\tchange_id:[0x%x]\n", r->change_id);
226 printf("\tlast_error: %s\n", win_errstr(r->last_error));
227 printf("\tstatus:[0x%x]\n", r->status);
228 printf("\tenumerate_network_printers:[0x%x]\n", r->enumerate_network_printers);
229 printf("\tc_setprinter:[0x%x]\n", r->c_setprinter);
230 printf("\tprocessor_architecture:[0x%x]\n", r->processor_architecture);
231 printf("\tprocessor_level:[0x%x]\n", r->processor_level);
232 printf("\tref_ic:[0x%x]\n", r->ref_ic);
233 printf("\treserved2:[0x%x]\n", r->reserved2);
234 printf("\treserved3:[0x%x]\n", r->reserved3);
236 printf("\n");
239 /****************************************************************************
240 ****************************************************************************/
242 static void display_print_info1(struct spoolss_PrinterInfo1 *r)
244 printf("\tflags:[0x%x]\n", r->flags);
245 printf("\tname:[%s]\n", r->name);
246 printf("\tdescription:[%s]\n", r->description);
247 printf("\tcomment:[%s]\n", r->comment);
249 printf("\n");
252 /****************************************************************************
253 ****************************************************************************/
255 static void display_print_info2(struct spoolss_PrinterInfo2 *r)
257 printf("\tservername:[%s]\n", r->servername);
258 printf("\tprintername:[%s]\n", r->printername);
259 printf("\tsharename:[%s]\n", r->sharename);
260 printf("\tportname:[%s]\n", r->portname);
261 printf("\tdrivername:[%s]\n", r->drivername);
262 printf("\tcomment:[%s]\n", r->comment);
263 printf("\tlocation:[%s]\n", r->location);
264 printf("\tsepfile:[%s]\n", r->sepfile);
265 printf("\tprintprocessor:[%s]\n", r->printprocessor);
266 printf("\tdatatype:[%s]\n", r->datatype);
267 printf("\tparameters:[%s]\n", r->parameters);
268 printf("\tattributes:[0x%x]\n", r->attributes);
269 printf("\tpriority:[0x%x]\n", r->priority);
270 printf("\tdefaultpriority:[0x%x]\n", r->defaultpriority);
271 printf("\tstarttime:[0x%x]\n", r->starttime);
272 printf("\tuntiltime:[0x%x]\n", r->untiltime);
273 printf("\tstatus:[0x%x]\n", r->status);
274 printf("\tcjobs:[0x%x]\n", r->cjobs);
275 printf("\taverageppm:[0x%x]\n", r->averageppm);
277 if (r->secdesc)
278 display_sec_desc(r->secdesc);
280 printf("\n");
283 /****************************************************************************
284 ****************************************************************************/
286 static void display_print_info3(struct spoolss_PrinterInfo3 *r)
288 display_sec_desc(r->secdesc);
290 printf("\n");
293 /****************************************************************************
294 ****************************************************************************/
296 static void display_print_info4(struct spoolss_PrinterInfo4 *r)
298 printf("\tservername:[%s]\n", r->servername);
299 printf("\tprintername:[%s]\n", r->printername);
300 printf("\tattributes:[0x%x]\n", r->attributes);
301 printf("\n");
304 /****************************************************************************
305 ****************************************************************************/
307 static void display_print_info5(struct spoolss_PrinterInfo5 *r)
309 printf("\tprintername:[%s]\n", r->printername);
310 printf("\tportname:[%s]\n", r->portname);
311 printf("\tattributes:[0x%x]\n", r->attributes);
312 printf("\tdevice_not_selected_timeout:[0x%x]\n", r->device_not_selected_timeout);
313 printf("\ttransmission_retry_timeout:[0x%x]\n", r->transmission_retry_timeout);
314 printf("\n");
317 /****************************************************************************
318 ****************************************************************************/
320 static void display_print_info6(struct spoolss_PrinterInfo6 *r)
322 printf("\tstatus:[0x%x]\n", r->status);
323 printf("\n");
326 /****************************************************************************
327 ****************************************************************************/
329 static void display_print_info7(struct spoolss_PrinterInfo7 *r)
331 printf("\tguid:[%s]\n", r->guid);
332 printf("\taction:[0x%x]\n", r->action);
333 printf("\n");
336 /****************************************************************************
337 ****************************************************************************/
339 static WERROR cmd_spoolss_enum_printers(struct rpc_pipe_client *cli,
340 TALLOC_CTX *mem_ctx,
341 int argc, const char **argv)
343 WERROR result;
344 uint32_t level = 1;
345 union spoolss_PrinterInfo *info;
346 uint32_t i, count;
347 const char *name;
348 uint32_t flags = PRINTER_ENUM_LOCAL;
350 if (argc > 4) {
351 printf("Usage: %s [level] [name] [flags]\n", argv[0]);
352 return WERR_OK;
355 if (argc >= 2) {
356 level = atoi(argv[1]);
359 if (argc >= 3) {
360 name = argv[2];
361 } else {
362 name = cli->srv_name_slash;
365 if (argc == 4) {
366 flags = atoi(argv[3]);
369 result = rpccli_spoolss_enumprinters(cli, mem_ctx,
370 flags,
371 name,
372 level,
374 &count,
375 &info);
376 if (W_ERROR_IS_OK(result)) {
378 if (!count) {
379 printf ("No printers returned.\n");
380 goto done;
383 for (i = 0; i < count; i++) {
384 switch (level) {
385 case 0:
386 display_print_info0(&info[i].info0);
387 break;
388 case 1:
389 display_print_info1(&info[i].info1);
390 break;
391 case 2:
392 display_print_info2(&info[i].info2);
393 break;
394 case 3:
395 display_print_info3(&info[i].info3);
396 break;
397 case 4:
398 display_print_info4(&info[i].info4);
399 break;
400 case 5:
401 display_print_info5(&info[i].info5);
402 break;
403 case 6:
404 display_print_info6(&info[i].info6);
405 break;
406 default:
407 printf("unknown info level %d\n", level);
408 goto done;
412 done:
414 return result;
417 /****************************************************************************
418 ****************************************************************************/
420 static void display_port_info_1(struct spoolss_PortInfo1 *r)
422 printf("\tPort Name:\t[%s]\n", r->port_name);
425 /****************************************************************************
426 ****************************************************************************/
428 static void display_port_info_2(struct spoolss_PortInfo2 *r)
430 printf("\tPort Name:\t[%s]\n", r->port_name);
431 printf("\tMonitor Name:\t[%s]\n", r->monitor_name);
432 printf("\tDescription:\t[%s]\n", r->description);
433 printf("\tPort Type:\t" );
434 if (r->port_type) {
435 int comma = 0; /* hack */
436 printf( "[" );
437 if (r->port_type & SPOOLSS_PORT_TYPE_READ) {
438 printf( "Read" );
439 comma = 1;
441 if (r->port_type & SPOOLSS_PORT_TYPE_WRITE) {
442 printf( "%sWrite", comma ? ", " : "" );
443 comma = 1;
445 /* These two have slightly different interpretations
446 on 95/98/ME but I'm disregarding that for now */
447 if (r->port_type & SPOOLSS_PORT_TYPE_REDIRECTED) {
448 printf( "%sRedirected", comma ? ", " : "" );
449 comma = 1;
451 if (r->port_type & SPOOLSS_PORT_TYPE_NET_ATTACHED) {
452 printf( "%sNet-Attached", comma ? ", " : "" );
454 printf( "]\n" );
455 } else {
456 printf( "[Unset]\n" );
458 printf("\tReserved:\t[%d]\n", r->reserved);
459 printf("\n");
462 /****************************************************************************
463 ****************************************************************************/
465 static WERROR cmd_spoolss_enum_ports(struct rpc_pipe_client *cli,
466 TALLOC_CTX *mem_ctx, int argc,
467 const char **argv)
469 WERROR result;
470 uint32_t level = 1;
471 uint32_t count;
472 union spoolss_PortInfo *info;
474 if (argc > 2) {
475 printf("Usage: %s [level]\n", argv[0]);
476 return WERR_OK;
479 if (argc == 2) {
480 level = atoi(argv[1]);
483 /* Enumerate ports */
485 result = rpccli_spoolss_enumports(cli, mem_ctx,
486 cli->srv_name_slash,
487 level,
489 &count,
490 &info);
491 if (W_ERROR_IS_OK(result)) {
492 int i;
494 for (i = 0; i < count; i++) {
495 switch (level) {
496 case 1:
497 display_port_info_1(&info[i].info1);
498 break;
499 case 2:
500 display_port_info_2(&info[i].info2);
501 break;
502 default:
503 printf("unknown info level %d\n", level);
504 break;
509 return result;
512 /****************************************************************************
513 ****************************************************************************/
515 static WERROR cmd_spoolss_setprinter(struct rpc_pipe_client *cli,
516 TALLOC_CTX *mem_ctx,
517 int argc, const char **argv)
519 struct policy_handle pol;
520 WERROR result;
521 NTSTATUS status;
522 uint32_t info_level = 2;
523 union spoolss_PrinterInfo info;
524 struct spoolss_SetPrinterInfoCtr info_ctr;
525 struct spoolss_SetPrinterInfo2 info2;
526 const char *printername, *comment = NULL;
527 struct spoolss_DevmodeContainer devmode_ctr;
528 struct sec_desc_buf secdesc_ctr;
529 struct dcerpc_binding_handle *b = cli->binding_handle;
531 if (argc == 1 || argc > 3) {
532 printf("Usage: %s printername comment\n", argv[0]);
534 return WERR_OK;
537 /* Open a printer handle */
538 if (argc == 3) {
539 comment = argv[2];
542 ZERO_STRUCT(devmode_ctr);
543 ZERO_STRUCT(secdesc_ctr);
545 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
547 /* get a printer handle */
548 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
549 printername,
550 PRINTER_ALL_ACCESS,
551 &pol);
552 if (!W_ERROR_IS_OK(result))
553 goto done;
555 /* Get printer info */
556 result = rpccli_spoolss_getprinter(cli, mem_ctx,
557 &pol,
558 info_level,
560 &info);
561 if (!W_ERROR_IS_OK(result))
562 goto done;
565 /* Modify the comment. */
566 spoolss_printerinfo2_to_setprinterinfo2(&info.info2, &info2);
567 info2.comment = comment;
569 info_ctr.level = 2;
570 info_ctr.info.info2 = &info2;
572 status = dcerpc_spoolss_SetPrinter(b, mem_ctx,
573 &pol,
574 &info_ctr,
575 &devmode_ctr,
576 &secdesc_ctr,
577 0, /* command */
578 &result);
579 if (!NT_STATUS_IS_OK(status)) {
580 result = ntstatus_to_werror(status);
581 goto done;
583 if (W_ERROR_IS_OK(result))
584 printf("Success in setting comment.\n");
586 done:
587 if (is_valid_policy_hnd(&pol)) {
588 WERROR _result;
589 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result);
592 return result;
595 /****************************************************************************
596 ****************************************************************************/
598 static WERROR cmd_spoolss_setprintername(struct rpc_pipe_client *cli,
599 TALLOC_CTX *mem_ctx,
600 int argc, const char **argv)
602 struct policy_handle pol;
603 WERROR result;
604 NTSTATUS status;
605 uint32_t info_level = 2;
606 union spoolss_PrinterInfo info;
607 const char *printername,
608 *new_printername = NULL;
609 struct spoolss_SetPrinterInfoCtr info_ctr;
610 struct spoolss_SetPrinterInfo2 info2;
611 struct spoolss_DevmodeContainer devmode_ctr;
612 struct sec_desc_buf secdesc_ctr;
613 struct dcerpc_binding_handle *b = cli->binding_handle;
615 ZERO_STRUCT(devmode_ctr);
616 ZERO_STRUCT(secdesc_ctr);
618 if (argc == 1 || argc > 3) {
619 printf("Usage: %s printername new_printername\n", argv[0]);
621 return WERR_OK;
624 /* Open a printer handle */
625 if (argc == 3) {
626 new_printername = argv[2];
629 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
631 /* get a printer handle */
632 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
633 printername,
634 PRINTER_ALL_ACCESS,
635 &pol);
636 if (!W_ERROR_IS_OK(result))
637 goto done;
639 /* Get printer info */
640 result = rpccli_spoolss_getprinter(cli, mem_ctx,
641 &pol,
642 info_level,
644 &info);
645 if (!W_ERROR_IS_OK(result))
646 goto done;
648 /* Modify the printername. */
649 spoolss_printerinfo2_to_setprinterinfo2(&info.info2, &info2);
650 info2.printername = new_printername;
652 info_ctr.level = 2;
653 info_ctr.info.info2 = &info2;
655 status = dcerpc_spoolss_SetPrinter(b, mem_ctx,
656 &pol,
657 &info_ctr,
658 &devmode_ctr,
659 &secdesc_ctr,
660 0, /* command */
661 &result);
662 if (!NT_STATUS_IS_OK(status)) {
663 result = ntstatus_to_werror(status);
664 goto done;
666 if (W_ERROR_IS_OK(result))
667 printf("Success in setting printername.\n");
669 done:
670 if (is_valid_policy_hnd(&pol)) {
671 WERROR _result;
672 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result);
675 return result;
678 /****************************************************************************
679 ****************************************************************************/
681 static WERROR cmd_spoolss_getprinter(struct rpc_pipe_client *cli,
682 TALLOC_CTX *mem_ctx,
683 int argc, const char **argv)
685 struct policy_handle pol;
686 WERROR result;
687 uint32_t level = 1;
688 const char *printername;
689 union spoolss_PrinterInfo info;
690 struct dcerpc_binding_handle *b = cli->binding_handle;
692 if (argc == 1 || argc > 3) {
693 printf("Usage: %s <printername> [level]\n", argv[0]);
694 return WERR_OK;
697 /* Open a printer handle */
698 if (argc == 3) {
699 level = atoi(argv[2]);
702 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
704 /* get a printer handle */
706 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
707 printername,
708 SEC_FLAG_MAXIMUM_ALLOWED,
709 &pol);
710 if (!W_ERROR_IS_OK(result)) {
711 goto done;
714 /* Get printer info */
716 result = rpccli_spoolss_getprinter(cli, mem_ctx,
717 &pol,
718 level,
720 &info);
721 if (!W_ERROR_IS_OK(result)) {
722 goto done;
725 /* Display printer info */
726 switch (level) {
727 case 0:
728 display_print_info0(&info.info0);
729 break;
730 case 1:
731 display_print_info1(&info.info1);
732 break;
733 case 2:
734 display_print_info2(&info.info2);
735 break;
736 case 3:
737 display_print_info3(&info.info3);
738 break;
739 case 4:
740 display_print_info4(&info.info4);
741 break;
742 case 5:
743 display_print_info5(&info.info5);
744 break;
745 case 6:
746 display_print_info6(&info.info6);
747 break;
748 case 7:
749 display_print_info7(&info.info7);
750 break;
751 default:
752 printf("unknown info level %d\n", level);
753 break;
755 done:
756 if (is_valid_policy_hnd(&pol)) {
757 WERROR _result;
758 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result);
761 return result;
764 /****************************************************************************
765 ****************************************************************************/
767 static void display_reg_value(const char *name, enum winreg_Type type, DATA_BLOB blob)
769 const char *text = NULL;
771 switch(type) {
772 case REG_DWORD:
773 if (blob.length == sizeof(uint32)) {
774 printf("%s: REG_DWORD: 0x%08x\n", name, IVAL(blob.data,0));
775 } else {
776 printf("%s: REG_DWORD: <invalid>\n", name);
778 break;
779 case REG_SZ:
780 pull_reg_sz(talloc_tos(), &blob, &text);
781 printf("%s: REG_SZ: %s\n", name, text ? text : "");
782 break;
783 case REG_BINARY: {
784 char *hex = hex_encode_talloc(NULL, blob.data, blob.length);
785 size_t i, len;
786 printf("%s: REG_BINARY:", name);
787 len = strlen(hex);
788 for (i=0; i<len; i++) {
789 if (hex[i] == '\0') {
790 break;
792 if (i%40 == 0) {
793 putchar('\n');
795 putchar(hex[i]);
797 TALLOC_FREE(hex);
798 putchar('\n');
799 break;
801 case REG_MULTI_SZ: {
802 uint32_t i;
803 const char **values;
805 if (!pull_reg_multi_sz(NULL, &blob, &values)) {
806 d_printf("pull_reg_multi_sz failed\n");
807 break;
810 printf("%s: REG_MULTI_SZ: \n", name);
811 for (i=0; values[i] != NULL; i++) {
812 d_printf("%s\n", values[i]);
814 TALLOC_FREE(values);
815 break;
817 default:
818 printf("%s: unknown type %d\n", name, type);
823 /****************************************************************************
824 ****************************************************************************/
826 static void display_printer_data(const char *v,
827 enum winreg_Type type,
828 uint8_t *data,
829 uint32_t length)
831 int i;
832 union spoolss_PrinterData r;
833 DATA_BLOB blob = data_blob_const(data, length);
834 WERROR result;
835 enum ndr_err_code ndr_err;
837 result = pull_spoolss_PrinterData(talloc_tos(), &blob, &r, type);
838 if (!W_ERROR_IS_OK(result)) {
839 return;
842 switch (type) {
843 case REG_DWORD:
844 printf("%s: REG_DWORD: 0x%08x\n", v, r.value);
845 break;
846 case REG_SZ:
847 printf("%s: REG_SZ: %s\n", v, r.string);
848 break;
849 case REG_BINARY: {
850 char *hex = hex_encode_talloc(NULL,
851 r.binary.data, r.binary.length);
852 size_t len;
853 printf("%s: REG_BINARY:", v);
854 len = strlen(hex);
855 for (i=0; i<len; i++) {
856 if (hex[i] == '\0') {
857 break;
859 if (i%40 == 0) {
860 putchar('\n');
862 putchar(hex[i]);
864 TALLOC_FREE(hex);
865 putchar('\n');
867 if (strequal(v, "OsVersion")) {
868 struct spoolss_OSVersion os;
869 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &os,
870 (ndr_pull_flags_fn_t)ndr_pull_spoolss_OSVersion);
871 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
872 printf("%s: OsVersion:\n", v);
873 NDR_PRINT_DEBUG(spoolss_OSVersion, &os);
876 if (strequal(v, "OsVersionEx")) {
877 struct spoolss_OSVersionEx os;
878 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &os,
879 (ndr_pull_flags_fn_t)ndr_pull_spoolss_OSVersionEx);
880 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
881 printf("%s: OsVersionEx:\n", v);
882 NDR_PRINT_DEBUG(spoolss_OSVersionEx, &os);
885 break;
887 case REG_MULTI_SZ:
888 printf("%s: REG_MULTI_SZ: ", v);
889 for (i=0; r.string_array[i] != NULL; i++) {
890 printf("%s ", r.string_array[i]);
892 printf("\n");
893 break;
894 default:
895 printf("%s: unknown type 0x%02x:\n", v, type);
896 break;
900 /****************************************************************************
901 ****************************************************************************/
903 static WERROR cmd_spoolss_getprinterdata(struct rpc_pipe_client *cli,
904 TALLOC_CTX *mem_ctx,
905 int argc, const char **argv)
907 struct policy_handle pol;
908 WERROR result;
909 fstring printername;
910 const char *valuename;
911 enum winreg_Type type;
912 uint8_t *data;
913 uint32_t needed;
914 struct dcerpc_binding_handle *b = cli->binding_handle;
916 if (argc != 3) {
917 printf("Usage: %s <printername> <valuename>\n", argv[0]);
918 printf("<printername> of . queries print server\n");
919 return WERR_OK;
921 valuename = argv[2];
923 /* Open a printer handle */
925 if (strncmp(argv[1], ".", sizeof(".")) == 0)
926 fstrcpy(printername, cli->srv_name_slash);
927 else
928 slprintf(printername, sizeof(printername)-1, "%s\\%s",
929 cli->srv_name_slash, argv[1]);
931 /* get a printer handle */
933 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
934 printername,
935 SEC_FLAG_MAXIMUM_ALLOWED,
936 &pol);
937 if (!W_ERROR_IS_OK(result))
938 goto done;
940 /* Get printer info */
942 result = rpccli_spoolss_getprinterdata(cli, mem_ctx,
943 &pol,
944 valuename,
946 &type,
947 &needed,
948 &data);
949 if (!W_ERROR_IS_OK(result))
950 goto done;
952 /* Display printer data */
954 display_printer_data(valuename, type, data, needed);
956 done:
957 if (is_valid_policy_hnd(&pol)) {
958 WERROR _result;
959 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result);
962 return result;
965 /****************************************************************************
966 ****************************************************************************/
968 static WERROR cmd_spoolss_getprinterdataex(struct rpc_pipe_client *cli,
969 TALLOC_CTX *mem_ctx,
970 int argc, const char **argv)
972 struct policy_handle pol;
973 WERROR result;
974 NTSTATUS status;
975 fstring printername;
976 const char *valuename, *keyname;
978 enum winreg_Type type;
979 uint8_t *data = NULL;
980 uint32_t offered = 0;
981 uint32_t needed;
982 struct dcerpc_binding_handle *b = cli->binding_handle;
984 if (argc != 4) {
985 printf("Usage: %s <printername> <keyname> <valuename>\n",
986 argv[0]);
987 printf("<printername> of . queries print server\n");
988 return WERR_OK;
990 valuename = argv[3];
991 keyname = argv[2];
993 /* Open a printer handle */
995 if (strncmp(argv[1], ".", sizeof(".")) == 0)
996 fstrcpy(printername, cli->srv_name_slash);
997 else
998 slprintf(printername, sizeof(printername)-1, "%s\\%s",
999 cli->srv_name_slash, argv[1]);
1001 /* get a printer handle */
1003 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1004 printername,
1005 SEC_FLAG_MAXIMUM_ALLOWED,
1006 &pol);
1007 if (!W_ERROR_IS_OK(result))
1008 goto done;
1010 /* Get printer info */
1012 data = talloc_zero_array(mem_ctx, uint8_t, offered);
1013 if (!data) {
1014 goto done;
1017 status = dcerpc_spoolss_GetPrinterDataEx(b, mem_ctx,
1018 &pol,
1019 keyname,
1020 valuename,
1021 &type,
1022 data,
1023 offered,
1024 &needed,
1025 &result);
1026 if (!NT_STATUS_IS_OK(status)) {
1027 result = ntstatus_to_werror(status);
1028 goto done;
1030 if (W_ERROR_EQUAL(result, WERR_MORE_DATA)) {
1031 offered = needed;
1032 data = talloc_zero_array(mem_ctx, uint8_t, offered);
1033 if (!data) {
1034 goto done;
1036 status = dcerpc_spoolss_GetPrinterDataEx(b, mem_ctx,
1037 &pol,
1038 keyname,
1039 valuename,
1040 &type,
1041 data,
1042 offered,
1043 &needed,
1044 &result);
1047 if (!NT_STATUS_IS_OK(status)) {
1048 result = ntstatus_to_werror(status);
1049 goto done;
1052 if (!W_ERROR_IS_OK(result))
1053 goto done;
1055 /* Display printer data */
1057 display_printer_data(valuename, type, data, needed);
1060 done:
1061 if (is_valid_policy_hnd(&pol)) {
1062 WERROR _result;
1063 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result);
1066 return result;
1069 /****************************************************************************
1070 ****************************************************************************/
1072 static void display_print_driver1(struct spoolss_DriverInfo1 *r)
1074 if (!r) {
1075 return;
1078 printf("Printer Driver Info 1:\n");
1079 printf("\tDriver Name: [%s]\n", r->driver_name);
1080 printf("\n");
1083 /****************************************************************************
1084 ****************************************************************************/
1086 static void display_print_driver2(struct spoolss_DriverInfo2 *r)
1088 if (!r) {
1089 return;
1092 printf("Printer Driver Info 2:\n");
1093 printf("\tVersion: [%x]\n", r->version);
1094 printf("\tDriver Name: [%s]\n", r->driver_name);
1095 printf("\tArchitecture: [%s]\n", r->architecture);
1096 printf("\tDriver Path: [%s]\n", r->driver_path);
1097 printf("\tDatafile: [%s]\n", r->data_file);
1098 printf("\tConfigfile: [%s]\n", r->config_file);
1099 printf("\n");
1102 /****************************************************************************
1103 ****************************************************************************/
1105 static void display_print_driver3(struct spoolss_DriverInfo3 *r)
1107 int i;
1109 if (!r) {
1110 return;
1113 printf("Printer Driver Info 3:\n");
1114 printf("\tVersion: [%x]\n", r->version);
1115 printf("\tDriver Name: [%s]\n", r->driver_name);
1116 printf("\tArchitecture: [%s]\n", r->architecture);
1117 printf("\tDriver Path: [%s]\n", r->driver_path);
1118 printf("\tDatafile: [%s]\n", r->data_file);
1119 printf("\tConfigfile: [%s]\n", r->config_file);
1120 printf("\tHelpfile: [%s]\n", r->help_file);
1122 for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1123 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1126 printf("\tMonitorname: [%s]\n", r->monitor_name);
1127 printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1128 printf("\n");
1131 /****************************************************************************
1132 ****************************************************************************/
1134 static void display_print_driver4(struct spoolss_DriverInfo4 *r)
1136 int i;
1138 if (!r) {
1139 return;
1142 printf("Printer Driver Info 4:\n");
1143 printf("\tVersion: [%x]\n", r->version);
1144 printf("\tDriver Name: [%s]\n", r->driver_name);
1145 printf("\tArchitecture: [%s]\n", r->architecture);
1146 printf("\tDriver Path: [%s]\n", r->driver_path);
1147 printf("\tDatafile: [%s]\n", r->data_file);
1148 printf("\tConfigfile: [%s]\n", r->config_file);
1149 printf("\tHelpfile: [%s]\n", r->help_file);
1151 for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1152 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1155 printf("\tMonitorname: [%s]\n", r->monitor_name);
1156 printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1158 for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) {
1159 printf("\tPrevious Names: [%s]\n", r->previous_names[i]);
1161 printf("\n");
1164 /****************************************************************************
1165 ****************************************************************************/
1167 static void display_print_driver5(struct spoolss_DriverInfo5 *r)
1169 if (!r) {
1170 return;
1173 printf("Printer Driver Info 5:\n");
1174 printf("\tVersion: [%x]\n", r->version);
1175 printf("\tDriver Name: [%s]\n", r->driver_name);
1176 printf("\tArchitecture: [%s]\n", r->architecture);
1177 printf("\tDriver Path: [%s]\n", r->driver_path);
1178 printf("\tDatafile: [%s]\n", r->data_file);
1179 printf("\tConfigfile: [%s]\n", r->config_file);
1180 printf("\tDriver Attributes: [0x%x]\n", r->driver_attributes);
1181 printf("\tConfig Version: [0x%x]\n", r->config_version);
1182 printf("\tDriver Version: [0x%x]\n", r->driver_version);
1183 printf("\n");
1186 /****************************************************************************
1187 ****************************************************************************/
1189 static void display_print_driver6(struct spoolss_DriverInfo6 *r)
1191 int i;
1193 if (!r) {
1194 return;
1197 printf("Printer Driver Info 6:\n");
1198 printf("\tVersion: [%x]\n", r->version);
1199 printf("\tDriver Name: [%s]\n", r->driver_name);
1200 printf("\tArchitecture: [%s]\n", r->architecture);
1201 printf("\tDriver Path: [%s]\n", r->driver_path);
1202 printf("\tDatafile: [%s]\n", r->data_file);
1203 printf("\tConfigfile: [%s]\n", r->config_file);
1204 printf("\tHelpfile: [%s]\n", r->help_file);
1206 for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1207 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1210 printf("\tMonitorname: [%s]\n", r->monitor_name);
1211 printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1213 for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) {
1214 printf("\tPrevious Names: [%s]\n", r->previous_names[i]);
1217 printf("\tDriver Date: [%s]\n", nt_time_string(talloc_tos(), r->driver_date));
1218 printf("\tDriver Version: [0x%016llx]\n", (long long unsigned int)r->driver_version);
1219 printf("\tManufacturer Name: [%s]\n", r->manufacturer_name);
1220 printf("\tManufacturer Url: [%s]\n", r->manufacturer_url);
1221 printf("\tHardware ID: [%s]\n", r->hardware_id);
1222 printf("\tProvider: [%s]\n", r->provider);
1224 printf("\n");
1227 /****************************************************************************
1228 ****************************************************************************/
1230 static void display_print_driver8(struct spoolss_DriverInfo8 *r)
1232 int i;
1234 if (!r) {
1235 return;
1238 printf("Printer Driver Info 8:\n");
1239 printf("\tVersion: [%x]\n", r->version);
1240 printf("\tDriver Name: [%s]\n", r->driver_name);
1241 printf("\tArchitecture: [%s]\n", r->architecture);
1242 printf("\tDriver Path: [%s]\n", r->driver_path);
1243 printf("\tDatafile: [%s]\n", r->data_file);
1244 printf("\tConfigfile: [%s]\n", r->config_file);
1245 printf("\tHelpfile: [%s]\n", r->help_file);
1246 printf("\tMonitorname: [%s]\n", r->monitor_name);
1247 printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1249 for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1250 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1253 for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) {
1254 printf("\tPrevious Names: [%s]\n", r->previous_names[i]);
1257 printf("\tDriver Date: [%s]\n", nt_time_string(talloc_tos(), r->driver_date));
1258 printf("\tDriver Version: [0x%016llx]\n", (long long unsigned int)r->driver_version);
1259 printf("\tManufacturer Name: [%s]\n", r->manufacturer_name);
1260 printf("\tManufacturer Url: [%s]\n", r->manufacturer_url);
1261 printf("\tHardware ID: [%s]\n", r->hardware_id);
1262 printf("\tProvider: [%s]\n", r->provider);
1263 printf("\tPrint Processor: [%s]\n", r->print_processor);
1264 printf("\tVendor Setup: [%s]\n", r->vendor_setup);
1265 for (i=0; r->color_profiles && r->color_profiles[i] != NULL; i++) {
1266 printf("\tColor Profiles: [%s]\n", r->color_profiles[i]);
1268 printf("\tInf Path: [%s]\n", r->inf_path);
1269 printf("\tPrinter Driver Attributes: [0x%x]\n", r->printer_driver_attributes);
1270 for (i=0; r->core_driver_dependencies && r->core_driver_dependencies[i] != NULL; i++) {
1271 printf("\tCore Driver Dependencies: [%s]\n", r->core_driver_dependencies[i]);
1273 printf("\tMin Driver Inbox Driver Version Date: [%s]\n", nt_time_string(talloc_tos(), r->min_inbox_driver_ver_date));
1274 printf("\tMin Driver Inbox Driver Version Version: [0x%016llx]\n",
1275 (long long unsigned int)r->min_inbox_driver_ver_version);
1277 printf("\n");
1280 /****************************************************************************
1281 ****************************************************************************/
1283 static WERROR cmd_spoolss_getdriver(struct rpc_pipe_client *cli,
1284 TALLOC_CTX *mem_ctx,
1285 int argc, const char **argv)
1287 struct policy_handle pol;
1288 WERROR werror;
1289 uint32_t level = 3;
1290 const char *printername;
1291 uint32_t i;
1292 bool success = false;
1293 union spoolss_DriverInfo info;
1294 uint32_t server_major_version;
1295 uint32_t server_minor_version;
1296 struct dcerpc_binding_handle *b = cli->binding_handle;
1298 if ((argc == 1) || (argc > 3)) {
1299 printf("Usage: %s <printername> [level]\n", argv[0]);
1300 return WERR_OK;
1303 /* get the arguments need to open the printer handle */
1305 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1307 if (argc == 3) {
1308 level = atoi(argv[2]);
1311 /* Open a printer handle */
1313 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1314 printername,
1315 PRINTER_ACCESS_USE,
1316 &pol);
1317 if (!W_ERROR_IS_OK(werror)) {
1318 printf("Error opening printer handle for %s!\n", printername);
1319 return werror;
1322 /* loop through and print driver info level for each architecture */
1324 for (i=0; archi_table[i].long_archi!=NULL; i++) {
1326 werror = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1327 &pol,
1328 archi_table[i].long_archi,
1329 level,
1330 0, /* offered */
1331 archi_table[i].version,
1333 &info,
1334 &server_major_version,
1335 &server_minor_version);
1336 if (!W_ERROR_IS_OK(werror)) {
1337 continue;
1340 /* need at least one success */
1342 success = true;
1344 printf("\n[%s]\n", archi_table[i].long_archi);
1346 switch (level) {
1347 case 1:
1348 display_print_driver1(&info.info1);
1349 break;
1350 case 2:
1351 display_print_driver2(&info.info2);
1352 break;
1353 case 3:
1354 display_print_driver3(&info.info3);
1355 break;
1356 case 4:
1357 display_print_driver4(&info.info4);
1358 break;
1359 case 5:
1360 display_print_driver5(&info.info5);
1361 break;
1362 case 6:
1363 display_print_driver6(&info.info6);
1364 break;
1365 case 8:
1366 display_print_driver8(&info.info8);
1367 break;
1368 default:
1369 printf("unknown info level %d\n", level);
1370 break;
1374 /* Cleanup */
1376 if (is_valid_policy_hnd(&pol)) {
1377 WERROR _result;
1378 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result);
1381 if (success) {
1382 werror = WERR_OK;
1385 return werror;
1388 /****************************************************************************
1389 ****************************************************************************/
1391 static WERROR enum_driver_by_architecture(struct rpc_pipe_client *cli,
1392 TALLOC_CTX *mem_ctx,
1393 const char *architecture,
1394 uint32_t level)
1396 WERROR werror;
1397 uint32_t count = 0;
1398 union spoolss_DriverInfo *info = NULL;
1399 uint32_t j;
1401 werror = rpccli_spoolss_enumprinterdrivers(cli, mem_ctx,
1402 cli->srv_name_slash,
1403 architecture,
1404 level,
1406 &count,
1407 &info);
1409 if (W_ERROR_EQUAL(werror, WERR_INVALID_ENVIRONMENT)) {
1410 printf("Server does not support environment [%s]\n",
1411 architecture);
1412 return WERR_OK;
1415 if (count == 0) {
1416 return WERR_OK;
1419 if (!W_ERROR_IS_OK(werror)) {
1420 printf("Error getting driver for environment [%s] - %s\n",
1421 architecture, win_errstr(werror));
1422 return werror;
1425 printf("\n[%s]\n", architecture);
1427 switch (level) {
1428 case 1:
1429 for (j=0; j < count; j++) {
1430 display_print_driver1(&info[j].info1);
1432 break;
1433 case 2:
1434 for (j=0; j < count; j++) {
1435 display_print_driver2(&info[j].info2);
1437 break;
1438 case 3:
1439 for (j=0; j < count; j++) {
1440 display_print_driver3(&info[j].info3);
1442 break;
1443 case 4:
1444 for (j=0; j < count; j++) {
1445 display_print_driver4(&info[j].info4);
1447 break;
1448 case 5:
1449 for (j=0; j < count; j++) {
1450 display_print_driver5(&info[j].info5);
1452 break;
1453 case 6:
1454 for (j=0; j < count; j++) {
1455 display_print_driver6(&info[j].info6);
1457 break;
1458 case 8:
1459 for (j=0; j < count; j++) {
1460 display_print_driver8(&info[j].info8);
1462 break;
1463 default:
1464 printf("unknown info level %d\n", level);
1465 return WERR_UNKNOWN_LEVEL;
1468 return werror;
1471 static WERROR cmd_spoolss_enum_drivers(struct rpc_pipe_client *cli,
1472 TALLOC_CTX *mem_ctx,
1473 int argc, const char **argv)
1475 WERROR werror = WERR_OK;
1476 uint32_t level = 1;
1477 uint32_t i;
1478 const char *architecture = NULL;
1480 if (argc > 3) {
1481 printf("Usage: enumdrivers [level] [architecture]\n");
1482 return WERR_OK;
1485 if (argc >= 2) {
1486 level = atoi(argv[1]);
1489 if (argc == 3) {
1490 architecture = argv[2];
1493 if (architecture) {
1494 return enum_driver_by_architecture(cli, mem_ctx,
1495 architecture,
1496 level);
1499 /* loop through and print driver info level for each architecture */
1500 for (i=0; archi_table[i].long_archi!=NULL; i++) {
1501 /* check to see if we already asked for this architecture string */
1503 if (i>0 && strequal(archi_table[i].long_archi, archi_table[i-1].long_archi)) {
1504 continue;
1507 werror = enum_driver_by_architecture(cli, mem_ctx,
1508 archi_table[i].long_archi,
1509 level);
1510 if (!W_ERROR_IS_OK(werror)) {
1511 break;
1515 return werror;
1518 /****************************************************************************
1519 ****************************************************************************/
1521 static void display_printdriverdir_1(struct spoolss_DriverDirectoryInfo1 *r)
1523 printf("\tDirectory Name:[%s]\n", r->directory_name);
1526 /****************************************************************************
1527 ****************************************************************************/
1529 static WERROR cmd_spoolss_getdriverdir(struct rpc_pipe_client *cli,
1530 TALLOC_CTX *mem_ctx,
1531 int argc, const char **argv)
1533 WERROR result;
1534 NTSTATUS status;
1535 const char *env = SPOOLSS_ARCHITECTURE_NT_X86;
1536 DATA_BLOB buffer;
1537 uint32_t offered;
1538 union spoolss_DriverDirectoryInfo info;
1539 uint32_t needed;
1540 struct dcerpc_binding_handle *b = cli->binding_handle;
1542 if (argc > 2) {
1543 printf("Usage: %s [environment]\n", argv[0]);
1544 return WERR_OK;
1547 /* Get the arguments need to open the printer handle */
1549 if (argc == 2) {
1550 env = argv[1];
1553 /* Get the directory. Only use Info level 1 */
1555 status = dcerpc_spoolss_GetPrinterDriverDirectory(b, mem_ctx,
1556 cli->srv_name_slash,
1557 env,
1559 NULL, /* buffer */
1560 0, /* offered */
1561 NULL, /* info */
1562 &needed,
1563 &result);
1564 if (!NT_STATUS_IS_OK(status)) {
1565 return ntstatus_to_werror(status);
1567 if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) {
1568 offered = needed;
1569 buffer = data_blob_talloc_zero(mem_ctx, needed);
1571 status = dcerpc_spoolss_GetPrinterDriverDirectory(b, mem_ctx,
1572 cli->srv_name_slash,
1573 env,
1575 &buffer,
1576 offered,
1577 &info,
1578 &needed,
1579 &result);
1580 if (!NT_STATUS_IS_OK(status)) {
1581 return ntstatus_to_werror(status);
1585 if (W_ERROR_IS_OK(result)) {
1586 display_printdriverdir_1(&info.info1);
1589 return result;
1592 /****************************************************************************
1593 ****************************************************************************/
1595 static void set_drv_info_3_env(TALLOC_CTX *mem_ctx,
1596 struct spoolss_AddDriverInfo3 *info,
1597 const char *arch)
1600 int i;
1602 for (i=0; archi_table[i].long_archi != NULL; i++)
1604 if (strcmp(arch, archi_table[i].short_archi) == 0)
1606 info->version = archi_table[i].version;
1607 info->architecture = talloc_strdup(mem_ctx, archi_table[i].long_archi);
1608 break;
1612 if (archi_table[i].long_archi == NULL)
1614 DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch));
1617 return;
1621 /**************************************************************************
1622 wrapper for strtok to get the next parameter from a delimited list.
1623 Needed to handle the empty parameter string denoted by "NULL"
1624 *************************************************************************/
1626 static char *get_driver_3_param(TALLOC_CTX *mem_ctx, char *str,
1627 const char *delim, const char **dest,
1628 char **saveptr)
1630 char *ptr;
1632 /* get the next token */
1633 ptr = strtok_r(str, delim, saveptr);
1635 /* a string of 'NULL' is used to represent an empty
1636 parameter because two consecutive delimiters
1637 will not return an empty string. See man strtok(3)
1638 for details */
1639 if (ptr && (strcasecmp_m(ptr, "NULL") == 0)) {
1640 ptr = NULL;
1643 if (dest != NULL) {
1644 *dest = talloc_strdup(mem_ctx, ptr);
1647 return ptr;
1650 /********************************************************************************
1651 fill in the members of a spoolss_AddDriverInfo3 struct using a character
1652 string in the form of
1653 <Long Driver Name>:<Driver File Name>:<Data File Name>:\
1654 <Config File Name>:<Help File Name>:<Language Monitor Name>:\
1655 <Default Data Type>:<Comma Separated list of Files>
1656 *******************************************************************************/
1658 static bool init_drv_info_3_members(TALLOC_CTX *mem_ctx, struct spoolss_AddDriverInfo3 *r,
1659 char *args)
1661 char *str, *str2;
1662 int count = 0;
1663 char *saveptr = NULL;
1664 struct spoolss_StringArray *deps;
1665 const char **file_array = NULL;
1666 int i;
1668 /* fill in the UNISTR fields */
1669 str = get_driver_3_param(mem_ctx, args, ":", &r->driver_name, &saveptr);
1670 str = get_driver_3_param(mem_ctx, NULL, ":", &r->driver_path, &saveptr);
1671 str = get_driver_3_param(mem_ctx, NULL, ":", &r->data_file, &saveptr);
1672 str = get_driver_3_param(mem_ctx, NULL, ":", &r->config_file, &saveptr);
1673 str = get_driver_3_param(mem_ctx, NULL, ":", &r->help_file, &saveptr);
1674 str = get_driver_3_param(mem_ctx, NULL, ":", &r->monitor_name, &saveptr);
1675 str = get_driver_3_param(mem_ctx, NULL, ":", &r->default_datatype, &saveptr);
1677 /* <Comma Separated List of Dependent Files> */
1678 /* save the beginning of the string */
1679 str2 = get_driver_3_param(mem_ctx, NULL, ":", NULL, &saveptr);
1680 str = str2;
1682 /* begin to strip out each filename */
1683 str = strtok_r(str, ",", &saveptr);
1685 /* no dependent files, we are done */
1686 if (!str) {
1687 return true;
1690 deps = talloc_zero(mem_ctx, struct spoolss_StringArray);
1691 if (!deps) {
1692 return false;
1695 while (str != NULL) {
1696 bool ok;
1697 ok = add_string_to_array(deps, str, &file_array, &count);
1698 if (!ok) {
1699 return false;
1701 str = strtok_r(NULL, ",", &saveptr);
1704 deps->string = talloc_zero_array(deps, const char *, count + 1);
1705 if (!deps->string) {
1706 return false;
1709 for (i=0; i < count; i++) {
1710 deps->string[i] = file_array[i];
1713 r->dependent_files = deps;
1715 return true;
1718 /****************************************************************************
1719 ****************************************************************************/
1721 static WERROR cmd_spoolss_addprinterdriver(struct rpc_pipe_client *cli,
1722 TALLOC_CTX *mem_ctx,
1723 int argc, const char **argv)
1725 WERROR result;
1726 NTSTATUS status;
1727 uint32_t level = 3;
1728 struct spoolss_AddDriverInfoCtr info_ctr;
1729 struct spoolss_AddDriverInfo3 info3;
1730 const char *arch;
1731 char *driver_args;
1732 struct dcerpc_binding_handle *b = cli->binding_handle;
1734 /* parse the command arguments */
1735 if (argc != 3 && argc != 4)
1737 printf ("Usage: %s <Environment> \\\n", argv[0]);
1738 printf ("\t<Long Driver Name>:<Driver File Name>:<Data File Name>:\\\n");
1739 printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
1740 printf ("\t<Default Data Type>:<Comma Separated list of Files> \\\n");
1741 printf ("\t[version]\n");
1743 return WERR_OK;
1746 /* Fill in the spoolss_AddDriverInfo3 struct */
1747 ZERO_STRUCT(info3);
1749 arch = cmd_spoolss_get_short_archi(argv[1]);
1750 if (!arch) {
1751 printf ("Error Unknown architecture [%s]\n", argv[1]);
1752 return WERR_INVALID_PARAM;
1755 set_drv_info_3_env(mem_ctx, &info3, arch);
1757 driver_args = talloc_strdup( mem_ctx, argv[2] );
1758 if (!init_drv_info_3_members(mem_ctx, &info3, driver_args ))
1760 printf ("Error Invalid parameter list - %s.\n", argv[2]);
1761 return WERR_INVALID_PARAM;
1764 /* if printer driver version specified, override the default version
1765 * used by the architecture. This allows installation of Windows
1766 * 2000 (version 3) printer drivers. */
1767 if (argc == 4)
1769 info3.version = atoi(argv[3]);
1773 info_ctr.level = level;
1774 info_ctr.info.info3 = &info3;
1776 status = dcerpc_spoolss_AddPrinterDriver(b, mem_ctx,
1777 cli->srv_name_slash,
1778 &info_ctr,
1779 &result);
1780 if (!NT_STATUS_IS_OK(status)) {
1781 return ntstatus_to_werror(status);
1783 if (W_ERROR_IS_OK(result)) {
1784 printf ("Printer Driver %s successfully installed.\n",
1785 info3.driver_name);
1788 return result;
1792 /****************************************************************************
1793 ****************************************************************************/
1795 static WERROR cmd_spoolss_addprinterex(struct rpc_pipe_client *cli,
1796 TALLOC_CTX *mem_ctx,
1797 int argc, const char **argv)
1799 WERROR result;
1800 struct spoolss_SetPrinterInfoCtr info_ctr;
1801 struct spoolss_SetPrinterInfo2 info2;
1803 /* parse the command arguments */
1804 if (argc != 5)
1806 printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]);
1807 return WERR_OK;
1810 /* Fill in the DRIVER_INFO_2 struct */
1811 ZERO_STRUCT(info2);
1813 info2.printername = argv[1];
1814 info2.drivername = argv[3];
1815 info2.sharename = argv[2];
1816 info2.portname = argv[4];
1817 info2.comment = "Created by rpcclient";
1818 info2.printprocessor = "winprint";
1819 info2.datatype = "RAW";
1820 info2.devmode_ptr = NULL;
1821 info2.secdesc_ptr = NULL;
1822 info2.attributes = PRINTER_ATTRIBUTE_SHARED;
1823 info2.priority = 0;
1824 info2.defaultpriority = 0;
1825 info2.starttime = 0;
1826 info2.untiltime = 0;
1828 /* These three fields must not be used by AddPrinter()
1829 as defined in the MS Platform SDK documentation..
1830 --jerry
1831 info2.status = 0;
1832 info2.cjobs = 0;
1833 info2.averageppm = 0;
1836 info_ctr.level = 2;
1837 info_ctr.info.info2 = &info2;
1839 result = rpccli_spoolss_addprinterex(cli, mem_ctx,
1840 &info_ctr);
1841 if (W_ERROR_IS_OK(result))
1842 printf ("Printer %s successfully installed.\n", argv[1]);
1844 return result;
1847 /****************************************************************************
1848 ****************************************************************************/
1850 static WERROR cmd_spoolss_setdriver(struct rpc_pipe_client *cli,
1851 TALLOC_CTX *mem_ctx,
1852 int argc, const char **argv)
1854 struct policy_handle pol;
1855 WERROR result;
1856 NTSTATUS status;
1857 uint32_t level = 2;
1858 const char *printername;
1859 union spoolss_PrinterInfo info;
1860 struct spoolss_SetPrinterInfoCtr info_ctr;
1861 struct spoolss_SetPrinterInfo2 info2;
1862 struct spoolss_DevmodeContainer devmode_ctr;
1863 struct sec_desc_buf secdesc_ctr;
1864 struct dcerpc_binding_handle *b = cli->binding_handle;
1866 ZERO_STRUCT(devmode_ctr);
1867 ZERO_STRUCT(secdesc_ctr);
1869 /* parse the command arguments */
1870 if (argc != 3)
1872 printf ("Usage: %s <printer> <driver>\n", argv[0]);
1873 return WERR_OK;
1876 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1878 /* Get a printer handle */
1880 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1881 printername,
1882 PRINTER_ALL_ACCESS,
1883 &pol);
1884 if (!W_ERROR_IS_OK(result))
1885 goto done;
1887 /* Get printer info */
1889 result = rpccli_spoolss_getprinter(cli, mem_ctx,
1890 &pol,
1891 level,
1893 &info);
1894 if (!W_ERROR_IS_OK(result)) {
1895 printf ("Unable to retrieve printer information!\n");
1896 goto done;
1899 /* Set the printer driver */
1901 spoolss_printerinfo2_to_setprinterinfo2(&info.info2, &info2);
1902 info2.drivername = argv[2];
1904 info_ctr.level = 2;
1905 info_ctr.info.info2 = &info2;
1907 status = dcerpc_spoolss_SetPrinter(b, mem_ctx,
1908 &pol,
1909 &info_ctr,
1910 &devmode_ctr,
1911 &secdesc_ctr,
1912 0, /* command */
1913 &result);
1914 if (!NT_STATUS_IS_OK(status)) {
1915 result = ntstatus_to_werror(status);
1916 goto done;
1918 if (!W_ERROR_IS_OK(result)) {
1919 printf("SetPrinter call failed!\n");
1920 goto done;
1923 printf("Successfully set %s to driver %s.\n", argv[1], argv[2]);
1925 done:
1926 /* Cleanup */
1928 if (is_valid_policy_hnd(&pol)) {
1929 WERROR _result;
1930 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result);
1933 return result;
1937 /****************************************************************************
1938 ****************************************************************************/
1940 static WERROR cmd_spoolss_deletedriverex(struct rpc_pipe_client *cli,
1941 TALLOC_CTX *mem_ctx,
1942 int argc, const char **argv)
1944 WERROR result, ret = WERR_UNKNOWN_PRINTER_DRIVER;
1945 NTSTATUS status;
1946 struct dcerpc_binding_handle *b = cli->binding_handle;
1948 int i;
1949 int vers = -1;
1951 const char *arch = NULL;
1952 uint32_t delete_flags = 0;
1954 /* parse the command arguments */
1955 if (argc < 2 || argc > 5) {
1956 printf("Usage: %s <driver> [arch] [version] [flags]\n", argv[0]);
1957 return WERR_OK;
1960 if (argc >= 3)
1961 arch = argv[2];
1962 if (argc >= 4) {
1963 vers = atoi(argv[3]);
1964 delete_flags |= DPD_DELETE_SPECIFIC_VERSION;
1966 if (argc == 5)
1967 delete_flags = atoi(argv[4]);
1969 /* delete the driver for all architectures */
1970 for (i=0; archi_table[i].long_archi; i++) {
1972 if (arch && !strequal(archi_table[i].long_archi, arch))
1973 continue;
1975 if (vers >= 0 && archi_table[i].version != vers)
1976 continue;
1978 /* make the call to remove the driver */
1979 status = dcerpc_spoolss_DeletePrinterDriverEx(b, mem_ctx,
1980 cli->srv_name_slash,
1981 archi_table[i].long_archi,
1982 argv[1],
1983 delete_flags,
1984 archi_table[i].version,
1985 &result);
1986 if (!NT_STATUS_IS_OK(status)) {
1987 return ntstatus_to_werror(status);
1989 if ( !W_ERROR_IS_OK(result) )
1991 if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1992 printf ("Failed to remove driver %s for arch [%s] (version: %d): %s\n",
1993 argv[1], archi_table[i].long_archi, archi_table[i].version, win_errstr(result));
1996 else
1998 printf ("Driver %s and files removed for arch [%s] (version: %d).\n", argv[1],
1999 archi_table[i].long_archi, archi_table[i].version);
2000 ret = WERR_OK;
2004 return ret;
2008 /****************************************************************************
2009 ****************************************************************************/
2011 static WERROR cmd_spoolss_deletedriver(struct rpc_pipe_client *cli,
2012 TALLOC_CTX *mem_ctx,
2013 int argc, const char **argv)
2015 WERROR result = WERR_OK;
2016 NTSTATUS status;
2017 int i;
2018 struct dcerpc_binding_handle *b = cli->binding_handle;
2020 /* parse the command arguments */
2021 if (argc != 2) {
2022 printf ("Usage: %s <driver>\n", argv[0]);
2023 return WERR_OK;
2026 /* delete the driver for all architectures */
2027 for (i=0; archi_table[i].long_archi; i++) {
2028 result = WERR_OK;
2030 /* make the call to remove the driver */
2031 status = dcerpc_spoolss_DeletePrinterDriver(b, mem_ctx,
2032 cli->srv_name_slash,
2033 archi_table[i].long_archi,
2034 argv[1],
2035 &result);
2036 if (!NT_STATUS_IS_OK(status)) {
2037 result = ntstatus_to_werror(status);
2038 continue;
2040 if ( !W_ERROR_IS_OK(result) ) {
2041 if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
2042 printf ("Failed to remove driver %s for arch [%s] - error %s!\n",
2043 argv[1], archi_table[i].long_archi,
2044 win_errstr(result));
2046 } else {
2047 printf ("Driver %s removed for arch [%s].\n", argv[1],
2048 archi_table[i].long_archi);
2052 return result;
2055 /****************************************************************************
2056 ****************************************************************************/
2058 static WERROR cmd_spoolss_getprintprocdir(struct rpc_pipe_client *cli,
2059 TALLOC_CTX *mem_ctx,
2060 int argc, const char **argv)
2062 WERROR result;
2063 NTSTATUS status;
2064 const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
2065 DATA_BLOB buffer;
2066 uint32_t offered;
2067 union spoolss_PrintProcessorDirectoryInfo info;
2068 uint32_t needed;
2069 struct dcerpc_binding_handle *b = cli->binding_handle;
2071 /* parse the command arguments */
2072 if (argc > 2) {
2073 printf ("Usage: %s [environment]\n", argv[0]);
2074 return WERR_OK;
2077 if (argc == 2) {
2078 environment = argv[1];
2081 status = dcerpc_spoolss_GetPrintProcessorDirectory(b, mem_ctx,
2082 cli->srv_name_slash,
2083 environment,
2085 NULL, /* buffer */
2086 0, /* offered */
2087 NULL, /* info */
2088 &needed,
2089 &result);
2090 if (!NT_STATUS_IS_OK(status)) {
2091 return ntstatus_to_werror(status);
2093 if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) {
2094 offered = needed;
2095 buffer = data_blob_talloc_zero(mem_ctx, needed);
2097 status = dcerpc_spoolss_GetPrintProcessorDirectory(b, mem_ctx,
2098 cli->srv_name_slash,
2099 environment,
2101 &buffer,
2102 offered,
2103 &info,
2104 &needed,
2105 &result);
2106 if (!NT_STATUS_IS_OK(status)) {
2107 return ntstatus_to_werror(status);
2111 if (W_ERROR_IS_OK(result)) {
2112 printf("%s\n", info.info1.directory_name);
2115 return result;
2118 /****************************************************************************
2119 ****************************************************************************/
2121 static WERROR cmd_spoolss_addform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
2122 int argc, const char **argv)
2124 struct policy_handle handle;
2125 WERROR werror;
2126 NTSTATUS status;
2127 const char *printername;
2128 struct spoolss_AddFormInfoCtr info_ctr;
2129 struct spoolss_AddFormInfo1 info1;
2130 struct spoolss_AddFormInfo2 info2;
2131 uint32_t level = 1;
2132 struct dcerpc_binding_handle *b = cli->binding_handle;
2134 /* Parse the command arguments */
2136 if (argc < 3 || argc > 5) {
2137 printf ("Usage: %s <printer> <formname> [level]\n", argv[0]);
2138 return WERR_OK;
2141 /* Get a printer handle */
2143 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2145 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2146 printername,
2147 PRINTER_ALL_ACCESS,
2148 &handle);
2149 if (!W_ERROR_IS_OK(werror))
2150 goto done;
2152 /* Dummy up some values for the form data */
2154 if (argc == 4) {
2155 level = atoi(argv[3]);
2158 switch (level) {
2159 case 1:
2160 info1.flags = SPOOLSS_FORM_USER;
2161 info1.form_name = argv[2];
2162 info1.size.width = 100;
2163 info1.size.height = 100;
2164 info1.area.left = 0;
2165 info1.area.top = 10;
2166 info1.area.right = 20;
2167 info1.area.bottom = 30;
2169 info_ctr.level = 1;
2170 info_ctr.info.info1 = &info1;
2172 break;
2173 case 2:
2174 info2.flags = SPOOLSS_FORM_USER;
2175 info2.form_name = argv[2];
2176 info2.size.width = 100;
2177 info2.size.height = 100;
2178 info2.area.left = 0;
2179 info2.area.top = 10;
2180 info2.area.right = 20;
2181 info2.area.bottom = 30;
2182 info2.keyword = argv[2];
2183 info2.string_type = SPOOLSS_FORM_STRING_TYPE_NONE;
2184 info2.mui_dll = NULL;
2185 info2.ressource_id = 0;
2186 info2.display_name = argv[2];
2187 info2.lang_id = 0;
2189 info_ctr.level = 2;
2190 info_ctr.info.info2 = &info2;
2192 break;
2193 default:
2194 werror = WERR_INVALID_PARAM;
2195 goto done;
2198 /* Add the form */
2200 status = dcerpc_spoolss_AddForm(b, mem_ctx,
2201 &handle,
2202 &info_ctr,
2203 &werror);
2204 if (!NT_STATUS_IS_OK(status)) {
2205 werror = ntstatus_to_werror(status);
2206 goto done;
2208 done:
2209 if (is_valid_policy_hnd(&handle)) {
2210 WERROR _result;
2211 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result);
2214 return werror;
2217 /****************************************************************************
2218 ****************************************************************************/
2220 static WERROR cmd_spoolss_setform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
2221 int argc, const char **argv)
2223 struct policy_handle handle;
2224 WERROR werror;
2225 NTSTATUS status;
2226 const char *printername;
2227 struct spoolss_AddFormInfoCtr info_ctr;
2228 struct spoolss_AddFormInfo1 info1;
2229 struct dcerpc_binding_handle *b = cli->binding_handle;
2231 /* Parse the command arguments */
2233 if (argc != 3) {
2234 printf ("Usage: %s <printer> <formname>\n", argv[0]);
2235 return WERR_OK;
2238 /* Get a printer handle */
2240 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2242 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2243 printername,
2244 SEC_FLAG_MAXIMUM_ALLOWED,
2245 &handle);
2246 if (!W_ERROR_IS_OK(werror))
2247 goto done;
2249 /* Dummy up some values for the form data */
2251 info1.flags = SPOOLSS_FORM_PRINTER;
2252 info1.size.width = 100;
2253 info1.size.height = 100;
2254 info1.area.left = 0;
2255 info1.area.top = 1000;
2256 info1.area.right = 2000;
2257 info1.area.bottom = 3000;
2258 info1.form_name = argv[2];
2260 info_ctr.info.info1 = &info1;
2261 info_ctr.level = 1;
2263 /* Set the form */
2265 status = dcerpc_spoolss_SetForm(b, mem_ctx,
2266 &handle,
2267 argv[2],
2268 &info_ctr,
2269 &werror);
2270 if (!NT_STATUS_IS_OK(status)) {
2271 werror = ntstatus_to_werror(status);
2272 goto done;
2274 done:
2275 if (is_valid_policy_hnd(&handle)) {
2276 WERROR _result;
2277 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result);
2280 return werror;
2283 /****************************************************************************
2284 ****************************************************************************/
2286 static const char *get_form_flag(int form_flag)
2288 switch (form_flag) {
2289 case SPOOLSS_FORM_USER:
2290 return "FORM_USER";
2291 case SPOOLSS_FORM_BUILTIN:
2292 return "FORM_BUILTIN";
2293 case SPOOLSS_FORM_PRINTER:
2294 return "FORM_PRINTER";
2295 default:
2296 return "unknown";
2300 /****************************************************************************
2301 ****************************************************************************/
2303 static void display_form_info1(struct spoolss_FormInfo1 *r)
2305 printf("%s\n" \
2306 "\tflag: %s (%d)\n" \
2307 "\twidth: %d, length: %d\n" \
2308 "\tleft: %d, right: %d, top: %d, bottom: %d\n\n",
2309 r->form_name, get_form_flag(r->flags), r->flags,
2310 r->size.width, r->size.height,
2311 r->area.left, r->area.right,
2312 r->area.top, r->area.bottom);
2315 /****************************************************************************
2316 ****************************************************************************/
2318 static void display_form_info2(struct spoolss_FormInfo2 *r)
2320 printf("%s\n" \
2321 "\tflag: %s (%d)\n" \
2322 "\twidth: %d, length: %d\n" \
2323 "\tleft: %d, right: %d, top: %d, bottom: %d\n",
2324 r->form_name, get_form_flag(r->flags), r->flags,
2325 r->size.width, r->size.height,
2326 r->area.left, r->area.right,
2327 r->area.top, r->area.bottom);
2328 printf("\tkeyword: %s\n", r->keyword);
2329 printf("\tstring_type: 0x%08x\n", r->string_type);
2330 printf("\tmui_dll: %s\n", r->mui_dll);
2331 printf("\tressource_id: 0x%08x\n", r->ressource_id);
2332 printf("\tdisplay_name: %s\n", r->display_name);
2333 printf("\tlang_id: %d\n", r->lang_id);
2334 printf("\n");
2337 /****************************************************************************
2338 ****************************************************************************/
2340 static WERROR cmd_spoolss_getform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
2341 int argc, const char **argv)
2343 struct policy_handle handle;
2344 WERROR werror;
2345 NTSTATUS status;
2346 const char *printername;
2347 DATA_BLOB buffer;
2348 uint32_t offered = 0;
2349 union spoolss_FormInfo info;
2350 uint32_t needed;
2351 uint32_t level = 1;
2352 struct dcerpc_binding_handle *b = cli->binding_handle;
2354 /* Parse the command arguments */
2356 if (argc < 3 || argc > 5) {
2357 printf ("Usage: %s <printer> <formname> [level]\n", argv[0]);
2358 return WERR_OK;
2361 /* Get a printer handle */
2363 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2365 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2366 printername,
2367 SEC_FLAG_MAXIMUM_ALLOWED,
2368 &handle);
2369 if (!W_ERROR_IS_OK(werror))
2370 goto done;
2372 if (argc == 4) {
2373 level = atoi(argv[3]);
2376 /* Get the form */
2378 status = dcerpc_spoolss_GetForm(b, mem_ctx,
2379 &handle,
2380 argv[2],
2381 level,
2382 NULL,
2383 offered,
2384 &info,
2385 &needed,
2386 &werror);
2387 if (!NT_STATUS_IS_OK(status)) {
2388 werror = ntstatus_to_werror(status);
2389 goto done;
2391 if (W_ERROR_EQUAL(werror, WERR_INSUFFICIENT_BUFFER)) {
2392 buffer = data_blob_talloc_zero(mem_ctx, needed);
2393 offered = needed;
2394 status = dcerpc_spoolss_GetForm(b, mem_ctx,
2395 &handle,
2396 argv[2],
2397 level,
2398 &buffer,
2399 offered,
2400 &info,
2401 &needed,
2402 &werror);
2403 if (!NT_STATUS_IS_OK(status)) {
2404 werror = ntstatus_to_werror(status);
2405 goto done;
2409 if (!W_ERROR_IS_OK(werror)) {
2410 goto done;
2413 switch (level) {
2414 case 1:
2415 display_form_info1(&info.info1);
2416 break;
2417 case 2:
2418 display_form_info2(&info.info2);
2419 break;
2422 done:
2423 if (is_valid_policy_hnd(&handle)) {
2424 WERROR _result;
2425 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result);
2428 return werror;
2431 /****************************************************************************
2432 ****************************************************************************/
2434 static WERROR cmd_spoolss_deleteform(struct rpc_pipe_client *cli,
2435 TALLOC_CTX *mem_ctx, int argc,
2436 const char **argv)
2438 struct policy_handle handle;
2439 WERROR werror;
2440 NTSTATUS status;
2441 const char *printername;
2442 struct dcerpc_binding_handle *b = cli->binding_handle;
2444 /* Parse the command arguments */
2446 if (argc != 3) {
2447 printf ("Usage: %s <printer> <formname>\n", argv[0]);
2448 return WERR_OK;
2451 /* Get a printer handle */
2453 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2455 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2456 printername,
2457 SEC_FLAG_MAXIMUM_ALLOWED,
2458 &handle);
2459 if (!W_ERROR_IS_OK(werror))
2460 goto done;
2462 /* Delete the form */
2464 status = dcerpc_spoolss_DeleteForm(b, mem_ctx,
2465 &handle,
2466 argv[2],
2467 &werror);
2468 if (!NT_STATUS_IS_OK(status)) {
2469 werror = ntstatus_to_werror(status);
2470 goto done;
2473 done:
2474 if (is_valid_policy_hnd(&handle)) {
2475 WERROR _result;
2476 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result);
2479 return werror;
2482 /****************************************************************************
2483 ****************************************************************************/
2485 static WERROR cmd_spoolss_enum_forms(struct rpc_pipe_client *cli,
2486 TALLOC_CTX *mem_ctx, int argc,
2487 const char **argv)
2489 struct policy_handle handle;
2490 WERROR werror;
2491 const char *printername;
2492 uint32_t num_forms, level = 1, i;
2493 union spoolss_FormInfo *forms;
2494 struct dcerpc_binding_handle *b = cli->binding_handle;
2496 /* Parse the command arguments */
2498 if (argc < 2 || argc > 4) {
2499 printf ("Usage: %s <printer> [level]\n", argv[0]);
2500 return WERR_OK;
2503 /* Get a printer handle */
2505 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2507 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2508 printername,
2509 SEC_FLAG_MAXIMUM_ALLOWED,
2510 &handle);
2511 if (!W_ERROR_IS_OK(werror))
2512 goto done;
2514 if (argc == 3) {
2515 level = atoi(argv[2]);
2518 /* Enumerate forms */
2520 werror = rpccli_spoolss_enumforms(cli, mem_ctx,
2521 &handle,
2522 level,
2524 &num_forms,
2525 &forms);
2527 if (!W_ERROR_IS_OK(werror))
2528 goto done;
2530 /* Display output */
2532 for (i = 0; i < num_forms; i++) {
2533 switch (level) {
2534 case 1:
2535 display_form_info1(&forms[i].info1);
2536 break;
2537 case 2:
2538 display_form_info2(&forms[i].info2);
2539 break;
2543 done:
2544 if (is_valid_policy_hnd(&handle)) {
2545 WERROR _result;
2546 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result);
2549 return werror;
2552 /****************************************************************************
2553 ****************************************************************************/
2555 static WERROR cmd_spoolss_setprinterdata(struct rpc_pipe_client *cli,
2556 TALLOC_CTX *mem_ctx,
2557 int argc, const char **argv)
2559 WERROR result;
2560 NTSTATUS status;
2561 const char *printername;
2562 struct policy_handle pol = { 0, };
2563 union spoolss_PrinterInfo info;
2564 enum winreg_Type type;
2565 union spoolss_PrinterData data;
2566 DATA_BLOB blob;
2567 struct dcerpc_binding_handle *b = cli->binding_handle;
2569 /* parse the command arguments */
2570 if (argc < 5) {
2571 printf ("Usage: %s <printer> <string|binary|dword|multistring>"
2572 " <value> <data>\n",
2573 argv[0]);
2574 return WERR_OK;
2577 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2579 type = REG_NONE;
2581 if (strequal(argv[2], "string")) {
2582 type = REG_SZ;
2585 if (strequal(argv[2], "binary")) {
2586 type = REG_BINARY;
2589 if (strequal(argv[2], "dword")) {
2590 type = REG_DWORD;
2593 if (strequal(argv[2], "multistring")) {
2594 type = REG_MULTI_SZ;
2597 if (type == REG_NONE) {
2598 printf("Unknown data type: %s\n", argv[2]);
2599 result = WERR_INVALID_PARAM;
2600 goto done;
2603 /* get a printer handle */
2605 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2606 printername,
2607 SEC_FLAG_MAXIMUM_ALLOWED,
2608 &pol);
2609 if (!W_ERROR_IS_OK(result)) {
2610 goto done;
2613 result = rpccli_spoolss_getprinter(cli, mem_ctx,
2614 &pol,
2617 &info);
2618 if (!W_ERROR_IS_OK(result)) {
2619 goto done;
2622 printf("%s\n", current_timestring(mem_ctx, true));
2623 printf("\tchange_id (before set)\t:[0x%x]\n", info.info0.change_id);
2625 /* Set the printer data */
2627 switch (type) {
2628 case REG_SZ:
2629 data.string = talloc_strdup(mem_ctx, argv[4]);
2630 W_ERROR_HAVE_NO_MEMORY(data.string);
2631 break;
2632 case REG_DWORD:
2633 data.value = strtoul(argv[4], NULL, 10);
2634 break;
2635 case REG_BINARY:
2636 data.binary = strhex_to_data_blob(mem_ctx, argv[4]);
2637 break;
2638 case REG_MULTI_SZ: {
2639 int i, num_strings;
2640 const char **strings = NULL;
2642 num_strings = 0;
2644 for (i=4; i<argc; i++) {
2645 if (strcmp(argv[i], "NULL") == 0) {
2646 argv[i] = "";
2648 if (!add_string_to_array(mem_ctx, argv[i],
2649 &strings,
2650 &num_strings)) {
2651 result = WERR_NOMEM;
2652 goto done;
2655 data.string_array = talloc_zero_array(mem_ctx, const char *, num_strings + 1);
2656 if (!data.string_array) {
2657 result = WERR_NOMEM;
2658 goto done;
2660 for (i=0; i < num_strings; i++) {
2661 data.string_array[i] = strings[i];
2663 break;
2665 default:
2666 printf("Unknown data type: %s\n", argv[2]);
2667 result = WERR_INVALID_PARAM;
2668 goto done;
2671 result = push_spoolss_PrinterData(mem_ctx, &blob, type, &data);
2672 if (!W_ERROR_IS_OK(result)) {
2673 goto done;
2676 status = dcerpc_spoolss_SetPrinterData(b, mem_ctx,
2677 &pol,
2678 argv[3], /* value_name */
2679 type,
2680 blob.data,
2681 blob.length,
2682 &result);
2683 if (!NT_STATUS_IS_OK(status)) {
2684 printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]);
2685 result = ntstatus_to_werror(status);
2686 goto done;
2688 if (!W_ERROR_IS_OK(result)) {
2689 printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]);
2690 goto done;
2692 printf("\tSetPrinterData succeeded [%s: %s]\n", argv[3], argv[4]);
2694 result = rpccli_spoolss_getprinter(cli, mem_ctx,
2695 &pol,
2698 &info);
2699 if (!W_ERROR_IS_OK(result)) {
2700 goto done;
2703 printf("%s\n", current_timestring(mem_ctx, true));
2704 printf("\tchange_id (after set)\t:[0x%x]\n", info.info0.change_id);
2706 done:
2707 /* cleanup */
2708 if (is_valid_policy_hnd(&pol)) {
2709 WERROR _result;
2710 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result);
2713 return result;
2716 /****************************************************************************
2717 ****************************************************************************/
2719 static void display_job_info1(struct spoolss_JobInfo1 *r)
2721 printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", r->position, r->job_id,
2722 r->user_name, r->document_name, r->text_status, r->pages_printed,
2723 r->total_pages);
2726 /****************************************************************************
2727 ****************************************************************************/
2729 static void display_job_info2(struct spoolss_JobInfo2 *r)
2731 printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n",
2732 r->position, r->job_id,
2733 r->user_name, r->document_name, r->text_status, r->pages_printed,
2734 r->total_pages, r->size);
2737 /****************************************************************************
2738 ****************************************************************************/
2740 static void display_job_info3(struct spoolss_JobInfo3 *r)
2742 printf("jobid[%d], next_jobid[%d]\n",
2743 r->job_id, r->next_job_id);
2746 /****************************************************************************
2747 ****************************************************************************/
2749 static void display_job_info4(struct spoolss_JobInfo4 *r)
2751 printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d/%d bytes\n",
2752 r->position, r->job_id,
2753 r->user_name, r->document_name, r->text_status, r->pages_printed,
2754 r->total_pages, r->size, r->size_high);
2757 /****************************************************************************
2758 ****************************************************************************/
2760 static WERROR cmd_spoolss_enum_jobs(struct rpc_pipe_client *cli,
2761 TALLOC_CTX *mem_ctx, int argc,
2762 const char **argv)
2764 WERROR result;
2765 uint32_t level = 1, count, i;
2766 const char *printername;
2767 struct policy_handle hnd;
2768 union spoolss_JobInfo *info;
2769 struct dcerpc_binding_handle *b = cli->binding_handle;
2771 if (argc < 2 || argc > 3) {
2772 printf("Usage: %s printername [level]\n", argv[0]);
2773 return WERR_OK;
2776 if (argc == 3) {
2777 level = atoi(argv[2]);
2780 /* Open printer handle */
2782 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2784 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2785 printername,
2786 SEC_FLAG_MAXIMUM_ALLOWED,
2787 &hnd);
2788 if (!W_ERROR_IS_OK(result))
2789 goto done;
2791 /* Enumerate ports */
2793 result = rpccli_spoolss_enumjobs(cli, mem_ctx,
2794 &hnd,
2795 0, /* firstjob */
2796 1000, /* numjobs */
2797 level,
2799 &count,
2800 &info);
2801 if (!W_ERROR_IS_OK(result)) {
2802 goto done;
2805 for (i = 0; i < count; i++) {
2806 switch (level) {
2807 case 1:
2808 display_job_info1(&info[i].info1);
2809 break;
2810 case 2:
2811 display_job_info2(&info[i].info2);
2812 break;
2813 default:
2814 d_printf("unknown info level %d\n", level);
2815 break;
2819 done:
2820 if (is_valid_policy_hnd(&hnd)) {
2821 WERROR _result;
2822 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
2825 return result;
2828 /****************************************************************************
2829 ****************************************************************************/
2831 static WERROR cmd_spoolss_get_job(struct rpc_pipe_client *cli,
2832 TALLOC_CTX *mem_ctx, int argc,
2833 const char **argv)
2835 WERROR result;
2836 const char *printername;
2837 struct policy_handle hnd;
2838 uint32_t job_id;
2839 uint32_t level = 1;
2840 union spoolss_JobInfo info;
2841 struct dcerpc_binding_handle *b = cli->binding_handle;
2843 if (argc < 3 || argc > 4) {
2844 printf("Usage: %s printername job_id [level]\n", argv[0]);
2845 return WERR_OK;
2848 job_id = atoi(argv[2]);
2850 if (argc == 4) {
2851 level = atoi(argv[3]);
2854 /* Open printer handle */
2856 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2858 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2859 printername,
2860 SEC_FLAG_MAXIMUM_ALLOWED,
2861 &hnd);
2862 if (!W_ERROR_IS_OK(result)) {
2863 goto done;
2866 /* Enumerate ports */
2868 result = rpccli_spoolss_getjob(cli, mem_ctx,
2869 &hnd,
2870 job_id,
2871 level,
2873 &info);
2875 if (!W_ERROR_IS_OK(result)) {
2876 goto done;
2879 switch (level) {
2880 case 1:
2881 display_job_info1(&info.info1);
2882 break;
2883 case 2:
2884 display_job_info2(&info.info2);
2885 break;
2886 case 3:
2887 display_job_info3(&info.info3);
2888 break;
2889 case 4:
2890 display_job_info4(&info.info4);
2891 break;
2892 default:
2893 d_printf("unknown info level %d\n", level);
2894 break;
2897 done:
2898 if (is_valid_policy_hnd(&hnd)) {
2899 WERROR _result;
2900 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
2903 return result;
2906 /****************************************************************************
2907 ****************************************************************************/
2909 static struct {
2910 const char *name;
2911 enum spoolss_JobControl val;
2912 } cmdvals[] = {
2913 {"PAUSE", SPOOLSS_JOB_CONTROL_PAUSE},
2914 {"RESUME", SPOOLSS_JOB_CONTROL_RESUME},
2915 {"CANCEL", SPOOLSS_JOB_CONTROL_CANCEL},
2916 {"RESTART", SPOOLSS_JOB_CONTROL_RESTART},
2917 {"DELETE", SPOOLSS_JOB_CONTROL_DELETE},
2918 {"SEND_TO_PRINTER", SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER},
2919 {"EJECTED", SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED},
2920 {"RETAIN", SPOOLSS_JOB_CONTROL_RETAIN},
2921 {"RELEASE", SPOOLSS_JOB_CONTROL_RELEASE}
2924 static enum spoolss_JobControl parse_setjob_command(const char *cmd)
2926 int i;
2928 for (i = 0; i < sizeof(cmdvals)/sizeof(cmdvals[0]); i++) {
2929 if (strequal(cmdvals[i].name, cmd)) {
2930 return cmdvals[i].val;
2933 return (enum spoolss_JobControl)atoi(cmd);
2936 static WERROR cmd_spoolss_set_job(struct rpc_pipe_client *cli,
2937 TALLOC_CTX *mem_ctx, int argc,
2938 const char **argv)
2940 WERROR result;
2941 NTSTATUS status;
2942 const char *printername;
2943 struct policy_handle hnd;
2944 uint32_t job_id;
2945 enum spoolss_JobControl command;
2946 struct dcerpc_binding_handle *b = cli->binding_handle;
2948 if (argc != 4) {
2949 printf("Usage: %s printername job_id command\n", argv[0]);
2950 printf("command = [PAUSE|RESUME|CANCEL|RESTART|DELETE|"
2951 "SEND_TO_PRINTER|EJECTED|RETAIN|RELEASE]\n");
2952 return WERR_OK;
2955 job_id = atoi(argv[2]);
2956 command = parse_setjob_command(argv[3]);
2958 /* Open printer handle */
2960 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2962 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2963 printername,
2964 SEC_FLAG_MAXIMUM_ALLOWED,
2965 &hnd);
2966 if (!W_ERROR_IS_OK(result)) {
2967 goto done;
2970 /* Set Job */
2972 status = dcerpc_spoolss_SetJob(b, mem_ctx,
2973 &hnd,
2974 job_id,
2975 NULL,
2976 command,
2977 &result);
2978 if (!NT_STATUS_IS_OK(status)) {
2979 result = ntstatus_to_werror(status);
2980 goto done;
2982 if (!W_ERROR_IS_OK(result)) {
2983 goto done;
2986 done:
2987 if (is_valid_policy_hnd(&hnd)) {
2988 WERROR _result;
2989 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
2992 return result;
2995 /****************************************************************************
2996 ****************************************************************************/
2998 static WERROR cmd_spoolss_enum_data(struct rpc_pipe_client *cli,
2999 TALLOC_CTX *mem_ctx, int argc,
3000 const char **argv)
3002 WERROR result;
3003 NTSTATUS status;
3004 const char *printername;
3005 struct policy_handle hnd;
3006 uint32_t value_needed;
3007 enum winreg_Type type;
3008 uint32_t data_needed;
3009 struct dcerpc_binding_handle *b = cli->binding_handle;
3010 struct spoolss_EnumPrinterData r;
3012 if (argc != 2) {
3013 printf("Usage: %s printername\n", argv[0]);
3014 return WERR_OK;
3017 /* Open printer handle */
3019 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3021 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3022 printername,
3023 SEC_FLAG_MAXIMUM_ALLOWED,
3024 &hnd);
3025 if (!W_ERROR_IS_OK(result)) {
3026 goto done;
3029 /* Enumerate data */
3031 r.in.handle = &hnd;
3032 r.in.enum_index = 0;
3033 r.in.value_offered = 0;
3034 r.in.data_offered = 0;
3035 r.out.value_name = NULL;
3036 r.out.value_needed = &value_needed;
3037 r.out.type = &type;
3038 r.out.data = NULL;
3039 r.out.data_needed = &data_needed;
3041 status = dcerpc_spoolss_EnumPrinterData_r(b, mem_ctx, &r);
3042 if (!NT_STATUS_IS_OK(status)) {
3043 result = ntstatus_to_werror(status);
3044 goto done;
3047 if (!W_ERROR_IS_OK(r.out.result)) {
3048 result = r.out.result;
3049 goto done;
3052 r.in.data_offered = *r.out.data_needed;
3053 r.in.value_offered = *r.out.value_needed;
3054 r.out.data = talloc_zero_array(mem_ctx, uint8_t, r.in.data_offered);
3055 r.out.value_name = talloc_zero_array(mem_ctx, char, r.in.value_offered);
3057 do {
3059 status = dcerpc_spoolss_EnumPrinterData_r(b, mem_ctx, &r);
3060 if (!NT_STATUS_IS_OK(status)) {
3061 result = ntstatus_to_werror(status);
3062 goto done;
3065 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
3066 result = WERR_OK;
3067 break;
3070 r.in.enum_index++;
3072 display_reg_value(r.out.value_name, *r.out.type,
3073 data_blob_const(r.out.data, r.in.data_offered));
3075 } while (W_ERROR_IS_OK(r.out.result));
3077 done:
3078 if (is_valid_policy_hnd(&hnd)) {
3079 WERROR _result;
3080 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
3083 return result;
3086 /****************************************************************************
3087 ****************************************************************************/
3089 static WERROR cmd_spoolss_enum_data_ex( struct rpc_pipe_client *cli,
3090 TALLOC_CTX *mem_ctx, int argc,
3091 const char **argv)
3093 WERROR result;
3094 uint32_t i;
3095 const char *printername;
3096 struct policy_handle hnd;
3097 uint32_t count;
3098 struct spoolss_PrinterEnumValues *info;
3099 struct dcerpc_binding_handle *b = cli->binding_handle;
3101 if (argc != 3) {
3102 printf("Usage: %s printername <keyname>\n", argv[0]);
3103 return WERR_OK;
3106 /* Open printer handle */
3108 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3110 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3111 printername,
3112 SEC_FLAG_MAXIMUM_ALLOWED,
3113 &hnd);
3114 if (!W_ERROR_IS_OK(result)) {
3115 goto done;
3118 /* Enumerate subkeys */
3120 result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx,
3121 &hnd,
3122 argv[2],
3124 &count,
3125 &info);
3126 if (!W_ERROR_IS_OK(result)) {
3127 goto done;
3130 for (i=0; i < count; i++) {
3131 display_printer_data(info[i].value_name,
3132 info[i].type,
3133 info[i].data->data,
3134 info[i].data->length);
3137 done:
3138 if (is_valid_policy_hnd(&hnd)) {
3139 WERROR _result;
3140 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
3143 return result;
3146 /****************************************************************************
3147 ****************************************************************************/
3149 static WERROR cmd_spoolss_enum_printerkey(struct rpc_pipe_client *cli,
3150 TALLOC_CTX *mem_ctx, int argc,
3151 const char **argv)
3153 WERROR result;
3154 const char *printername;
3155 const char *keyname = NULL;
3156 struct policy_handle hnd;
3157 const char **key_buffer = NULL;
3158 int i;
3159 uint32_t offered = 0;
3160 struct dcerpc_binding_handle *b = cli->binding_handle;
3162 if (argc < 2 || argc > 4) {
3163 printf("Usage: %s printername [keyname] [offered]\n", argv[0]);
3164 return WERR_OK;
3167 if (argc >= 3) {
3168 keyname = argv[2];
3169 } else {
3170 keyname = "";
3173 if (argc == 4) {
3174 offered = atoi(argv[3]);
3177 /* Open printer handle */
3179 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3181 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3182 printername,
3183 SEC_FLAG_MAXIMUM_ALLOWED,
3184 &hnd);
3185 if (!W_ERROR_IS_OK(result)) {
3186 goto done;
3189 /* Enumerate subkeys */
3191 result = rpccli_spoolss_enumprinterkey(cli, mem_ctx,
3192 &hnd,
3193 keyname,
3194 &key_buffer,
3195 offered);
3197 if (!W_ERROR_IS_OK(result)) {
3198 goto done;
3201 for (i=0; key_buffer && key_buffer[i]; i++) {
3202 printf("%s\n", key_buffer[i]);
3205 done:
3207 if (is_valid_policy_hnd(&hnd)) {
3208 WERROR _result;
3209 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
3212 return result;
3215 /****************************************************************************
3216 ****************************************************************************/
3218 static WERROR cmd_spoolss_rffpcnex(struct rpc_pipe_client *cli,
3219 TALLOC_CTX *mem_ctx, int argc,
3220 const char **argv)
3222 const char *printername;
3223 const char *clientname;
3224 struct policy_handle hnd = { 0, };
3225 WERROR result;
3226 NTSTATUS status;
3227 struct spoolss_NotifyOption option;
3228 struct dcerpc_binding_handle *b = cli->binding_handle;
3230 if (argc != 2) {
3231 printf("Usage: %s printername\n", argv[0]);
3232 result = WERR_OK;
3233 goto done;
3236 /* Open printer */
3238 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3240 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3241 printername,
3242 SEC_FLAG_MAXIMUM_ALLOWED,
3243 &hnd);
3244 if (!W_ERROR_IS_OK(result)) {
3245 printf("Error opening %s\n", argv[1]);
3246 goto done;
3249 /* Create spool options */
3251 option.version = 2;
3252 option.count = 2;
3254 option.types = talloc_array(mem_ctx, struct spoolss_NotifyOptionType, 2);
3255 if (option.types == NULL) {
3256 result = WERR_NOMEM;
3257 goto done;
3260 option.types[0].type = PRINTER_NOTIFY_TYPE;
3261 option.types[0].count = 1;
3262 option.types[0].fields = talloc_array(mem_ctx, union spoolss_Field, 1);
3263 if (option.types[0].fields == NULL) {
3264 result = WERR_NOMEM;
3265 goto done;
3267 option.types[0].fields[0].field = PRINTER_NOTIFY_FIELD_SERVER_NAME;
3269 option.types[1].type = JOB_NOTIFY_TYPE;
3270 option.types[1].count = 1;
3271 option.types[1].fields = talloc_array(mem_ctx, union spoolss_Field, 1);
3272 if (option.types[1].fields == NULL) {
3273 result = WERR_NOMEM;
3274 goto done;
3276 option.types[1].fields[0].field = JOB_NOTIFY_FIELD_PRINTER_NAME;
3278 clientname = talloc_asprintf(mem_ctx, "\\\\%s", lp_netbios_name());
3279 if (!clientname) {
3280 result = WERR_NOMEM;
3281 goto done;
3284 /* Send rffpcnex */
3286 status = dcerpc_spoolss_RemoteFindFirstPrinterChangeNotifyEx(b, mem_ctx,
3287 &hnd,
3290 clientname,
3291 123,
3292 &option,
3293 &result);
3294 if (!NT_STATUS_IS_OK(status)) {
3295 result = ntstatus_to_werror(status);
3296 goto done;
3298 if (!W_ERROR_IS_OK(result)) {
3299 printf("Error rffpcnex %s\n", argv[1]);
3300 goto done;
3303 done:
3304 if (is_valid_policy_hnd(&hnd)) {
3305 WERROR _result;
3306 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
3309 return result;
3312 /****************************************************************************
3313 ****************************************************************************/
3315 static bool compare_printer( struct rpc_pipe_client *cli1, struct policy_handle *hnd1,
3316 struct rpc_pipe_client *cli2, struct policy_handle *hnd2 )
3318 union spoolss_PrinterInfo info1, info2;
3319 WERROR werror;
3320 TALLOC_CTX *mem_ctx = talloc_init("compare_printer");
3322 printf("Retrieving printer propertiesfor %s...", cli1->desthost);
3323 werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
3324 hnd1,
3327 &info1);
3328 if ( !W_ERROR_IS_OK(werror) ) {
3329 printf("failed (%s)\n", win_errstr(werror));
3330 talloc_destroy(mem_ctx);
3331 return false;
3333 printf("ok\n");
3335 printf("Retrieving printer properties for %s...", cli2->desthost);
3336 werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
3337 hnd2,
3340 &info2);
3341 if ( !W_ERROR_IS_OK(werror) ) {
3342 printf("failed (%s)\n", win_errstr(werror));
3343 talloc_destroy(mem_ctx);
3344 return false;
3346 printf("ok\n");
3348 talloc_destroy(mem_ctx);
3350 return true;
3353 /****************************************************************************
3354 ****************************************************************************/
3356 static bool compare_printer_secdesc( struct rpc_pipe_client *cli1, struct policy_handle *hnd1,
3357 struct rpc_pipe_client *cli2, struct policy_handle *hnd2 )
3359 union spoolss_PrinterInfo info1, info2;
3360 WERROR werror;
3361 TALLOC_CTX *mem_ctx = talloc_init("compare_printer_secdesc");
3362 struct security_descriptor *sd1, *sd2;
3363 bool result = true;
3366 printf("Retrieving printer security for %s...", cli1->desthost);
3367 werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
3368 hnd1,
3371 &info1);
3372 if ( !W_ERROR_IS_OK(werror) ) {
3373 printf("failed (%s)\n", win_errstr(werror));
3374 result = false;
3375 goto done;
3377 printf("ok\n");
3379 printf("Retrieving printer security for %s...", cli2->desthost);
3380 werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
3381 hnd2,
3384 &info2);
3385 if ( !W_ERROR_IS_OK(werror) ) {
3386 printf("failed (%s)\n", win_errstr(werror));
3387 result = false;
3388 goto done;
3390 printf("ok\n");
3393 printf("++ ");
3395 sd1 = info1.info3.secdesc;
3396 sd2 = info2.info3.secdesc;
3398 if ( (sd1 != sd2) && ( !sd1 || !sd2 ) ) {
3399 printf("NULL secdesc!\n");
3400 result = false;
3401 goto done;
3404 if (!security_descriptor_equal( sd1, sd2 ) ) {
3405 printf("Security Descriptors *not* equal!\n");
3406 result = false;
3407 goto done;
3410 printf("Security descriptors match\n");
3412 done:
3413 talloc_destroy(mem_ctx);
3414 return result;
3418 /****************************************************************************
3419 ****************************************************************************/
3421 extern struct user_auth_info *rpcclient_auth_info;
3423 static WERROR cmd_spoolss_printercmp(struct rpc_pipe_client *cli,
3424 TALLOC_CTX *mem_ctx, int argc,
3425 const char **argv)
3427 const char *printername;
3428 char *printername_path = NULL;
3429 struct cli_state *cli_server2 = NULL;
3430 struct rpc_pipe_client *cli2 = NULL;
3431 struct policy_handle hPrinter1, hPrinter2;
3432 NTSTATUS nt_status;
3433 WERROR werror;
3435 if ( argc != 3 ) {
3436 printf("Usage: %s <printer> <server>\n", argv[0]);
3437 return WERR_OK;
3440 printername = argv[1];
3442 /* first get the connection to the remote server */
3444 nt_status = cli_full_connection(&cli_server2, lp_netbios_name(), argv[2],
3445 NULL, 0,
3446 "IPC$", "IPC",
3447 get_cmdline_auth_info_username(rpcclient_auth_info),
3448 lp_workgroup(),
3449 get_cmdline_auth_info_password(rpcclient_auth_info),
3450 get_cmdline_auth_info_use_kerberos(rpcclient_auth_info) ? CLI_FULL_CONNECTION_USE_KERBEROS : 0,
3451 get_cmdline_auth_info_signing_state(rpcclient_auth_info));
3453 if ( !NT_STATUS_IS_OK(nt_status) )
3454 return WERR_GENERAL_FAILURE;
3456 nt_status = cli_rpc_pipe_open_noauth(cli_server2, &ndr_table_spoolss,
3457 &cli2);
3458 if (!NT_STATUS_IS_OK(nt_status)) {
3459 printf("failed to open spoolss pipe on server %s (%s)\n",
3460 argv[2], nt_errstr(nt_status));
3461 return WERR_GENERAL_FAILURE;
3464 /* now open up both printers */
3466 RPCCLIENT_PRINTERNAME(printername_path, cli, printername);
3468 printf("Opening %s...", printername_path);
3470 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3471 printername_path,
3472 PRINTER_ALL_ACCESS,
3473 &hPrinter1);
3474 if ( !W_ERROR_IS_OK(werror) ) {
3475 printf("failed (%s)\n", win_errstr(werror));
3476 goto done;
3478 printf("ok\n");
3480 RPCCLIENT_PRINTERNAME(printername_path, cli2, printername);
3482 printf("Opening %s...", printername_path);
3483 werror = rpccli_spoolss_openprinter_ex(cli2, mem_ctx,
3484 printername_path,
3485 PRINTER_ALL_ACCESS,
3486 &hPrinter2);
3487 if ( !W_ERROR_IS_OK(werror) ) {
3488 printf("failed (%s)\n", win_errstr(werror));
3489 goto done;
3491 printf("ok\n");
3493 compare_printer( cli, &hPrinter1, cli2, &hPrinter2 );
3494 compare_printer_secdesc( cli, &hPrinter1, cli2, &hPrinter2 );
3495 #if 0
3496 compare_printerdata( cli_server1, &hPrinter1, cli_server2, &hPrinter2 );
3497 #endif
3500 done:
3501 /* cleanup */
3503 printf("Closing printers...");
3505 WERROR _result;
3506 dcerpc_spoolss_ClosePrinter(cli->binding_handle, mem_ctx, &hPrinter1, &_result);
3507 dcerpc_spoolss_ClosePrinter(cli2->binding_handle, mem_ctx, &hPrinter2, &_result);
3509 printf("ok\n");
3511 /* close the second remote connection */
3513 cli_shutdown( cli_server2 );
3514 return WERR_OK;
3517 static void display_proc_info1(struct spoolss_PrintProcessorInfo1 *r)
3519 printf("print_processor_name: %s\n", r->print_processor_name);
3522 static WERROR cmd_spoolss_enum_procs(struct rpc_pipe_client *cli,
3523 TALLOC_CTX *mem_ctx, int argc,
3524 const char **argv)
3526 WERROR werror;
3527 const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
3528 uint32_t num_procs, level = 1, i;
3529 union spoolss_PrintProcessorInfo *procs;
3531 /* Parse the command arguments */
3533 if (argc < 1 || argc > 4) {
3534 printf ("Usage: %s [environment] [level]\n", argv[0]);
3535 return WERR_OK;
3538 if (argc >= 2) {
3539 environment = argv[1];
3542 if (argc == 3) {
3543 level = atoi(argv[2]);
3546 /* Enumerate Print Processors */
3548 werror = rpccli_spoolss_enumprintprocessors(cli, mem_ctx,
3549 cli->srv_name_slash,
3550 environment,
3551 level,
3553 &num_procs,
3554 &procs);
3555 if (!W_ERROR_IS_OK(werror))
3556 goto done;
3558 /* Display output */
3560 for (i = 0; i < num_procs; i++) {
3561 switch (level) {
3562 case 1:
3563 display_proc_info1(&procs[i].info1);
3564 break;
3568 done:
3569 return werror;
3572 static void display_proc_data_types_info1(struct spoolss_PrintProcDataTypesInfo1 *r)
3574 printf("name_array: %s\n", r->name_array);
3577 static WERROR cmd_spoolss_enum_proc_data_types(struct rpc_pipe_client *cli,
3578 TALLOC_CTX *mem_ctx, int argc,
3579 const char **argv)
3581 WERROR werror;
3582 const char *print_processor_name = "winprint";
3583 uint32_t num_procs, level = 1, i;
3584 union spoolss_PrintProcDataTypesInfo *procs;
3586 /* Parse the command arguments */
3588 if (argc < 1 || argc > 4) {
3589 printf ("Usage: %s [environment] [level]\n", argv[0]);
3590 return WERR_OK;
3593 if (argc >= 2) {
3594 print_processor_name = argv[1];
3597 if (argc == 3) {
3598 level = atoi(argv[2]);
3601 /* Enumerate Print Processor Data Types */
3603 werror = rpccli_spoolss_enumprintprocessordatatypes(cli, mem_ctx,
3604 cli->srv_name_slash,
3605 print_processor_name,
3606 level,
3608 &num_procs,
3609 &procs);
3610 if (!W_ERROR_IS_OK(werror))
3611 goto done;
3613 /* Display output */
3615 for (i = 0; i < num_procs; i++) {
3616 switch (level) {
3617 case 1:
3618 display_proc_data_types_info1(&procs[i].info1);
3619 break;
3623 done:
3624 return werror;
3627 static void display_monitor1(const struct spoolss_MonitorInfo1 *r)
3629 printf("monitor_name: %s\n", r->monitor_name);
3632 static void display_monitor2(const struct spoolss_MonitorInfo2 *r)
3634 printf("monitor_name: %s\n", r->monitor_name);
3635 printf("environment: %s\n", r->environment);
3636 printf("dll_name: %s\n", r->dll_name);
3639 static WERROR cmd_spoolss_enum_monitors(struct rpc_pipe_client *cli,
3640 TALLOC_CTX *mem_ctx, int argc,
3641 const char **argv)
3643 WERROR werror;
3644 uint32_t count, level = 1, i;
3645 union spoolss_MonitorInfo *info;
3647 /* Parse the command arguments */
3649 if (argc > 2) {
3650 printf("Usage: %s [level]\n", argv[0]);
3651 return WERR_OK;
3654 if (argc == 2) {
3655 level = atoi(argv[1]);
3658 /* Enumerate Print Monitors */
3660 werror = rpccli_spoolss_enummonitors(cli, mem_ctx,
3661 cli->srv_name_slash,
3662 level,
3664 &count,
3665 &info);
3666 if (!W_ERROR_IS_OK(werror)) {
3667 goto done;
3670 /* Display output */
3672 for (i = 0; i < count; i++) {
3673 switch (level) {
3674 case 1:
3675 display_monitor1(&info[i].info1);
3676 break;
3677 case 2:
3678 display_monitor2(&info[i].info2);
3679 break;
3683 done:
3684 return werror;
3687 static WERROR cmd_spoolss_create_printer_ic(struct rpc_pipe_client *cli,
3688 TALLOC_CTX *mem_ctx, int argc,
3689 const char **argv)
3691 WERROR result;
3692 NTSTATUS status;
3693 struct policy_handle handle, gdi_handle;
3694 const char *printername;
3695 struct spoolss_DevmodeContainer devmode_ctr;
3696 struct dcerpc_binding_handle *b = cli->binding_handle;
3698 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3700 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3701 printername,
3702 SEC_FLAG_MAXIMUM_ALLOWED,
3703 &handle);
3704 if (!W_ERROR_IS_OK(result)) {
3705 return result;
3708 ZERO_STRUCT(devmode_ctr);
3710 status = dcerpc_spoolss_CreatePrinterIC(b, mem_ctx,
3711 &handle,
3712 &gdi_handle,
3713 &devmode_ctr,
3714 &result);
3715 if (!NT_STATUS_IS_OK(status)) {
3716 result = ntstatus_to_werror(status);
3717 goto done;
3719 if (!W_ERROR_IS_OK(result)) {
3720 goto done;
3723 done:
3724 if (is_valid_policy_hnd(&gdi_handle)) {
3725 WERROR _result;
3726 dcerpc_spoolss_DeletePrinterIC(b, mem_ctx, &gdi_handle, &_result);
3728 if (is_valid_policy_hnd(&handle)) {
3729 WERROR _result;
3730 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result);
3733 return result;
3736 static WERROR cmd_spoolss_play_gdi_script_on_printer_ic(struct rpc_pipe_client *cli,
3737 TALLOC_CTX *mem_ctx, int argc,
3738 const char **argv)
3740 WERROR result;
3741 NTSTATUS status;
3742 struct policy_handle handle, gdi_handle;
3743 const char *printername;
3744 struct spoolss_DevmodeContainer devmode_ctr;
3745 struct dcerpc_binding_handle *b = cli->binding_handle;
3746 DATA_BLOB in,out;
3747 uint32_t count = 0;
3749 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3751 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3752 printername,
3753 SEC_FLAG_MAXIMUM_ALLOWED,
3754 &handle);
3755 if (!W_ERROR_IS_OK(result)) {
3756 return result;
3759 ZERO_STRUCT(devmode_ctr);
3761 status = dcerpc_spoolss_CreatePrinterIC(b, mem_ctx,
3762 &handle,
3763 &gdi_handle,
3764 &devmode_ctr,
3765 &result);
3766 if (!NT_STATUS_IS_OK(status)) {
3767 result = ntstatus_to_werror(status);
3768 goto done;
3770 if (!W_ERROR_IS_OK(result)) {
3771 goto done;
3774 in = data_blob_string_const("");
3775 out = data_blob_talloc_zero(mem_ctx, 4);
3777 status = dcerpc_spoolss_PlayGDIScriptOnPrinterIC(b, mem_ctx,
3778 &gdi_handle,
3779 in.data,
3780 in.length,
3781 out.data,
3782 out.length,
3783 0, /* ul */
3784 &result);
3785 if (!NT_STATUS_IS_OK(status)) {
3786 result = ntstatus_to_werror(status);
3787 goto done;
3789 if (!W_ERROR_IS_OK(result)) {
3790 goto done;
3793 count = IVAL(out.data, 0);
3795 out = data_blob_talloc_zero(mem_ctx,
3796 count * sizeof(struct UNIVERSAL_FONT_ID) + 4);
3798 status = dcerpc_spoolss_PlayGDIScriptOnPrinterIC(b, mem_ctx,
3799 &gdi_handle,
3800 in.data,
3801 in.length,
3802 out.data,
3803 out.length,
3804 0, /* ul */
3805 &result);
3806 if (!NT_STATUS_IS_OK(status)) {
3807 result = ntstatus_to_werror(status);
3808 goto done;
3810 if (!W_ERROR_IS_OK(result)) {
3811 goto done;
3815 enum ndr_err_code ndr_err;
3816 struct UNIVERSAL_FONT_ID_ctr r;
3818 ndr_err = ndr_pull_struct_blob(&out, mem_ctx, &r,
3819 (ndr_pull_flags_fn_t)ndr_pull_UNIVERSAL_FONT_ID_ctr);
3820 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3821 NDR_PRINT_DEBUG(UNIVERSAL_FONT_ID_ctr, &r);
3825 done:
3826 if (is_valid_policy_hnd(&gdi_handle)) {
3827 WERROR _result;
3828 dcerpc_spoolss_DeletePrinterIC(b, mem_ctx, &gdi_handle, &_result);
3830 if (is_valid_policy_hnd(&handle)) {
3831 WERROR _result;
3832 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result);
3835 return result;
3838 /* List of commands exported by this module */
3839 struct cmd_set spoolss_commands[] = {
3841 { "SPOOLSS" },
3843 { "adddriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterdriver, &ndr_table_spoolss, NULL, "Add a print driver", "" },
3844 { "addprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterex, &ndr_table_spoolss, NULL, "Add a printer", "" },
3845 { "deldriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriver, &ndr_table_spoolss, NULL, "Delete a printer driver", "" },
3846 { "deldriverex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriverex, &ndr_table_spoolss, NULL, "Delete a printer driver with files", "" },
3847 { "enumdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data, &ndr_table_spoolss, NULL, "Enumerate printer data", "" },
3848 { "enumdataex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data_ex, &ndr_table_spoolss, NULL, "Enumerate printer data for a key", "" },
3849 { "enumkey", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printerkey, &ndr_table_spoolss, NULL, "Enumerate printer keys", "" },
3850 { "enumjobs", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_jobs, &ndr_table_spoolss, NULL, "Enumerate print jobs", "" },
3851 { "getjob", RPC_RTYPE_WERROR, NULL, cmd_spoolss_get_job, &ndr_table_spoolss, NULL, "Get print job", "" },
3852 { "setjob", RPC_RTYPE_WERROR, NULL, cmd_spoolss_set_job, &ndr_table_spoolss, NULL, "Set print job", "" },
3853 { "enumports", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_ports, &ndr_table_spoolss, NULL, "Enumerate printer ports", "" },
3854 { "enumdrivers", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_drivers, &ndr_table_spoolss, NULL, "Enumerate installed printer drivers", "" },
3855 { "enumprinters", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printers, &ndr_table_spoolss, NULL, "Enumerate printers", "" },
3856 { "getdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdata, &ndr_table_spoolss, NULL, "Get print driver data", "" },
3857 { "getdataex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdataex, &ndr_table_spoolss, NULL, "Get printer driver data with keyname", ""},
3858 { "getdriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriver, &ndr_table_spoolss, NULL, "Get print driver information", "" },
3859 { "getdriverdir", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriverdir, &ndr_table_spoolss, NULL, "Get print driver upload directory", "" },
3860 { "getprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinter, &ndr_table_spoolss, NULL, "Get printer info", "" },
3861 { "openprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer, &ndr_table_spoolss, NULL, "Open printer handle", "" },
3862 { "openprinter_ex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer_ex, &ndr_table_spoolss, NULL, "Open printer handle", "" },
3863 { "setdriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setdriver, &ndr_table_spoolss, NULL, "Set printer driver", "" },
3864 { "getprintprocdir", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprintprocdir, &ndr_table_spoolss, NULL, "Get print processor directory", "" },
3865 { "addform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addform, &ndr_table_spoolss, NULL, "Add form", "" },
3866 { "setform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setform, &ndr_table_spoolss, NULL, "Set form", "" },
3867 { "getform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getform, &ndr_table_spoolss, NULL, "Get form", "" },
3868 { "deleteform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform, &ndr_table_spoolss, NULL, "Delete form", "" },
3869 { "enumforms", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms, &ndr_table_spoolss, NULL, "Enumerate forms", "" },
3870 { "setprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter, &ndr_table_spoolss, NULL, "Set printer comment", "" },
3871 { "setprintername", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername, &ndr_table_spoolss, NULL, "Set printername", "" },
3872 { "setprinterdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata, &ndr_table_spoolss, NULL, "Set REG_SZ printer data", "" },
3873 { "rffpcnex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex, &ndr_table_spoolss, NULL, "Rffpcnex test", "" },
3874 { "printercmp", RPC_RTYPE_WERROR, NULL, cmd_spoolss_printercmp, &ndr_table_spoolss, NULL, "Printer comparison test", "" },
3875 { "enumprocs", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_procs, &ndr_table_spoolss, NULL, "Enumerate Print Processors", "" },
3876 { "enumprocdatatypes", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_proc_data_types, &ndr_table_spoolss, NULL, "Enumerate Print Processor Data Types", "" },
3877 { "enummonitors", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_monitors, &ndr_table_spoolss, NULL, "Enumerate Print Monitors", "" },
3878 { "createprinteric", RPC_RTYPE_WERROR, NULL, cmd_spoolss_create_printer_ic, &ndr_table_spoolss, NULL, "Create Printer IC", "" },
3879 { "playgdiscriptonprinteric", RPC_RTYPE_WERROR, NULL, cmd_spoolss_play_gdi_script_on_printer_ic, &ndr_table_spoolss, NULL, "Create Printer IC", "" },
3881 { NULL }