s4-auth: Make sure error_string is correctly initialized
[Samba.git] / source3 / rpcclient / cmd_spoolss.c
blob3191e80ffac59e4bcf320ff29491c8d2bcc129e7
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_t)) {
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');
866 putchar('\n');
868 if (strequal(v, "OsVersion")) {
869 struct spoolss_OSVersion os;
870 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &os,
871 (ndr_pull_flags_fn_t)ndr_pull_spoolss_OSVersion);
872 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
873 // add output here;
874 printf("OsMajor: %u\n", os.major);
875 printf("OsMinor: %u\n", os.minor);
876 printf("OsBuild: %u\n", os.build);
877 NDR_PRINT_DEBUG(spoolss_OSVersion, &os);
880 if (strequal(v, "OsVersionEx")) {
881 struct spoolss_OSVersionEx os;
882 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &os,
883 (ndr_pull_flags_fn_t)ndr_pull_spoolss_OSVersionEx);
884 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
885 printf("OsMajor: %u\n", os.major);
886 printf("OsMinor: %u\n", os.minor);
887 printf("OsBuild: %u\n", os.build);
888 printf("ServicePackMajor: %u\n", os.service_pack_major);
889 printf("ServicePackMinor: %u\n", os.service_pack_minor);
890 NDR_PRINT_DEBUG(spoolss_OSVersionEx, &os);
893 break;
895 case REG_MULTI_SZ:
896 printf("%s: REG_MULTI_SZ: ", v);
897 for (i=0; r.string_array[i] != NULL; i++) {
898 printf("%s ", r.string_array[i]);
900 printf("\n");
901 break;
902 default:
903 printf("%s: unknown type 0x%02x:\n", v, type);
904 break;
908 /****************************************************************************
909 ****************************************************************************/
911 static WERROR cmd_spoolss_getprinterdata(struct rpc_pipe_client *cli,
912 TALLOC_CTX *mem_ctx,
913 int argc, const char **argv)
915 struct policy_handle pol;
916 WERROR result;
917 fstring printername;
918 const char *valuename;
919 enum winreg_Type type;
920 uint8_t *data;
921 uint32_t needed;
922 struct dcerpc_binding_handle *b = cli->binding_handle;
924 if (argc != 3) {
925 printf("Usage: %s <printername> <valuename>\n", argv[0]);
926 printf("<printername> of . queries print server\n");
927 return WERR_OK;
929 valuename = argv[2];
931 /* Open a printer handle */
933 if (strncmp(argv[1], ".", sizeof(".")) == 0)
934 fstrcpy(printername, cli->srv_name_slash);
935 else
936 slprintf(printername, sizeof(printername)-1, "%s\\%s",
937 cli->srv_name_slash, argv[1]);
939 /* get a printer handle */
941 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
942 printername,
943 SEC_FLAG_MAXIMUM_ALLOWED,
944 &pol);
945 if (!W_ERROR_IS_OK(result))
946 goto done;
948 /* Get printer info */
950 result = rpccli_spoolss_getprinterdata(cli, mem_ctx,
951 &pol,
952 valuename,
954 &type,
955 &needed,
956 &data);
957 if (!W_ERROR_IS_OK(result))
958 goto done;
960 /* Display printer data */
962 display_printer_data(valuename, type, data, needed);
964 done:
965 if (is_valid_policy_hnd(&pol)) {
966 WERROR _result;
967 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result);
970 return result;
973 /****************************************************************************
974 ****************************************************************************/
976 static WERROR cmd_spoolss_getprinterdataex(struct rpc_pipe_client *cli,
977 TALLOC_CTX *mem_ctx,
978 int argc, const char **argv)
980 struct policy_handle pol;
981 WERROR result;
982 NTSTATUS status;
983 fstring printername;
984 const char *valuename, *keyname;
986 enum winreg_Type type;
987 uint8_t *data = NULL;
988 uint32_t offered = 0;
989 uint32_t needed;
990 struct dcerpc_binding_handle *b = cli->binding_handle;
992 if (argc != 4) {
993 printf("Usage: %s <printername> <keyname> <valuename>\n",
994 argv[0]);
995 printf("<printername> of . queries print server\n");
996 return WERR_OK;
998 valuename = argv[3];
999 keyname = argv[2];
1001 /* Open a printer handle */
1003 if (strncmp(argv[1], ".", sizeof(".")) == 0)
1004 fstrcpy(printername, cli->srv_name_slash);
1005 else
1006 slprintf(printername, sizeof(printername)-1, "%s\\%s",
1007 cli->srv_name_slash, argv[1]);
1009 /* get a printer handle */
1011 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1012 printername,
1013 SEC_FLAG_MAXIMUM_ALLOWED,
1014 &pol);
1015 if (!W_ERROR_IS_OK(result))
1016 goto done;
1018 /* Get printer info */
1020 data = talloc_zero_array(mem_ctx, uint8_t, offered);
1021 if (!data) {
1022 goto done;
1025 status = dcerpc_spoolss_GetPrinterDataEx(b, mem_ctx,
1026 &pol,
1027 keyname,
1028 valuename,
1029 &type,
1030 data,
1031 offered,
1032 &needed,
1033 &result);
1034 if (!NT_STATUS_IS_OK(status)) {
1035 result = ntstatus_to_werror(status);
1036 goto done;
1038 if (W_ERROR_EQUAL(result, WERR_MORE_DATA)) {
1039 offered = needed;
1040 data = talloc_zero_array(mem_ctx, uint8_t, offered);
1041 if (!data) {
1042 goto done;
1044 status = dcerpc_spoolss_GetPrinterDataEx(b, mem_ctx,
1045 &pol,
1046 keyname,
1047 valuename,
1048 &type,
1049 data,
1050 offered,
1051 &needed,
1052 &result);
1055 if (!NT_STATUS_IS_OK(status)) {
1056 result = ntstatus_to_werror(status);
1057 goto done;
1060 if (!W_ERROR_IS_OK(result))
1061 goto done;
1063 /* Display printer data */
1065 display_printer_data(valuename, type, data, needed);
1068 done:
1069 if (is_valid_policy_hnd(&pol)) {
1070 WERROR _result;
1071 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result);
1074 return result;
1077 /****************************************************************************
1078 ****************************************************************************/
1080 static void display_print_driver1(struct spoolss_DriverInfo1 *r)
1082 if (!r) {
1083 return;
1086 printf("Printer Driver Info 1:\n");
1087 printf("\tDriver Name: [%s]\n", r->driver_name);
1088 printf("\n");
1091 /****************************************************************************
1092 ****************************************************************************/
1094 static void display_print_driver2(struct spoolss_DriverInfo2 *r)
1096 if (!r) {
1097 return;
1100 printf("Printer Driver Info 2:\n");
1101 printf("\tVersion: [%x]\n", r->version);
1102 printf("\tDriver Name: [%s]\n", r->driver_name);
1103 printf("\tArchitecture: [%s]\n", r->architecture);
1104 printf("\tDriver Path: [%s]\n", r->driver_path);
1105 printf("\tDatafile: [%s]\n", r->data_file);
1106 printf("\tConfigfile: [%s]\n", r->config_file);
1107 printf("\n");
1110 /****************************************************************************
1111 ****************************************************************************/
1113 static void display_print_driver3(struct spoolss_DriverInfo3 *r)
1115 int i;
1117 if (!r) {
1118 return;
1121 printf("Printer Driver Info 3:\n");
1122 printf("\tVersion: [%x]\n", r->version);
1123 printf("\tDriver Name: [%s]\n", r->driver_name);
1124 printf("\tArchitecture: [%s]\n", r->architecture);
1125 printf("\tDriver Path: [%s]\n", r->driver_path);
1126 printf("\tDatafile: [%s]\n", r->data_file);
1127 printf("\tConfigfile: [%s]\n", r->config_file);
1128 printf("\tHelpfile: [%s]\n", r->help_file);
1130 for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1131 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1134 printf("\tMonitorname: [%s]\n", r->monitor_name);
1135 printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1136 printf("\n");
1139 /****************************************************************************
1140 ****************************************************************************/
1142 static void display_print_driver4(struct spoolss_DriverInfo4 *r)
1144 int i;
1146 if (!r) {
1147 return;
1150 printf("Printer Driver Info 4:\n");
1151 printf("\tVersion: [%x]\n", r->version);
1152 printf("\tDriver Name: [%s]\n", r->driver_name);
1153 printf("\tArchitecture: [%s]\n", r->architecture);
1154 printf("\tDriver Path: [%s]\n", r->driver_path);
1155 printf("\tDatafile: [%s]\n", r->data_file);
1156 printf("\tConfigfile: [%s]\n", r->config_file);
1157 printf("\tHelpfile: [%s]\n", r->help_file);
1159 for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1160 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1163 printf("\tMonitorname: [%s]\n", r->monitor_name);
1164 printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1166 for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) {
1167 printf("\tPrevious Names: [%s]\n", r->previous_names[i]);
1169 printf("\n");
1172 /****************************************************************************
1173 ****************************************************************************/
1175 static void display_print_driver5(struct spoolss_DriverInfo5 *r)
1177 if (!r) {
1178 return;
1181 printf("Printer Driver Info 5:\n");
1182 printf("\tVersion: [%x]\n", r->version);
1183 printf("\tDriver Name: [%s]\n", r->driver_name);
1184 printf("\tArchitecture: [%s]\n", r->architecture);
1185 printf("\tDriver Path: [%s]\n", r->driver_path);
1186 printf("\tDatafile: [%s]\n", r->data_file);
1187 printf("\tConfigfile: [%s]\n", r->config_file);
1188 printf("\tDriver Attributes: [0x%x]\n", r->driver_attributes);
1189 printf("\tConfig Version: [0x%x]\n", r->config_version);
1190 printf("\tDriver Version: [0x%x]\n", r->driver_version);
1191 printf("\n");
1194 /****************************************************************************
1195 ****************************************************************************/
1197 static void display_print_driver6(struct spoolss_DriverInfo6 *r)
1199 int i;
1201 if (!r) {
1202 return;
1205 printf("Printer Driver Info 6:\n");
1206 printf("\tVersion: [%x]\n", r->version);
1207 printf("\tDriver Name: [%s]\n", r->driver_name);
1208 printf("\tArchitecture: [%s]\n", r->architecture);
1209 printf("\tDriver Path: [%s]\n", r->driver_path);
1210 printf("\tDatafile: [%s]\n", r->data_file);
1211 printf("\tConfigfile: [%s]\n", r->config_file);
1212 printf("\tHelpfile: [%s]\n", r->help_file);
1214 for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1215 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1218 printf("\tMonitorname: [%s]\n", r->monitor_name);
1219 printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1221 for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) {
1222 printf("\tPrevious Names: [%s]\n", r->previous_names[i]);
1225 printf("\tDriver Date: [%s]\n", nt_time_string(talloc_tos(), r->driver_date));
1226 printf("\tDriver Version: [0x%016llx]\n", (long long unsigned int)r->driver_version);
1227 printf("\tManufacturer Name: [%s]\n", r->manufacturer_name);
1228 printf("\tManufacturer Url: [%s]\n", r->manufacturer_url);
1229 printf("\tHardware ID: [%s]\n", r->hardware_id);
1230 printf("\tProvider: [%s]\n", r->provider);
1232 printf("\n");
1235 /****************************************************************************
1236 ****************************************************************************/
1238 static void display_print_driver8(struct spoolss_DriverInfo8 *r)
1240 int i;
1242 if (!r) {
1243 return;
1246 printf("Printer Driver Info 8:\n");
1247 printf("\tVersion: [%x]\n", r->version);
1248 printf("\tDriver Name: [%s]\n", r->driver_name);
1249 printf("\tArchitecture: [%s]\n", r->architecture);
1250 printf("\tDriver Path: [%s]\n", r->driver_path);
1251 printf("\tDatafile: [%s]\n", r->data_file);
1252 printf("\tConfigfile: [%s]\n", r->config_file);
1253 printf("\tHelpfile: [%s]\n", r->help_file);
1254 printf("\tMonitorname: [%s]\n", r->monitor_name);
1255 printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1257 for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1258 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1261 for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) {
1262 printf("\tPrevious Names: [%s]\n", r->previous_names[i]);
1265 printf("\tDriver Date: [%s]\n", nt_time_string(talloc_tos(), r->driver_date));
1266 printf("\tDriver Version: [0x%016llx]\n", (long long unsigned int)r->driver_version);
1267 printf("\tManufacturer Name: [%s]\n", r->manufacturer_name);
1268 printf("\tManufacturer Url: [%s]\n", r->manufacturer_url);
1269 printf("\tHardware ID: [%s]\n", r->hardware_id);
1270 printf("\tProvider: [%s]\n", r->provider);
1271 printf("\tPrint Processor: [%s]\n", r->print_processor);
1272 printf("\tVendor Setup: [%s]\n", r->vendor_setup);
1273 for (i=0; r->color_profiles && r->color_profiles[i] != NULL; i++) {
1274 printf("\tColor Profiles: [%s]\n", r->color_profiles[i]);
1276 printf("\tInf Path: [%s]\n", r->inf_path);
1277 printf("\tPrinter Driver Attributes: [0x%x]\n", r->printer_driver_attributes);
1278 for (i=0; r->core_driver_dependencies && r->core_driver_dependencies[i] != NULL; i++) {
1279 printf("\tCore Driver Dependencies: [%s]\n", r->core_driver_dependencies[i]);
1281 printf("\tMin Driver Inbox Driver Version Date: [%s]\n", nt_time_string(talloc_tos(), r->min_inbox_driver_ver_date));
1282 printf("\tMin Driver Inbox Driver Version Version: [0x%016llx]\n",
1283 (long long unsigned int)r->min_inbox_driver_ver_version);
1285 printf("\n");
1288 /****************************************************************************
1289 ****************************************************************************/
1291 static WERROR cmd_spoolss_getdriver(struct rpc_pipe_client *cli,
1292 TALLOC_CTX *mem_ctx,
1293 int argc, const char **argv)
1295 struct policy_handle pol;
1296 WERROR werror;
1297 uint32_t level = 3;
1298 const char *printername;
1299 uint32_t i;
1300 bool success = false;
1301 union spoolss_DriverInfo info;
1302 uint32_t server_major_version;
1303 uint32_t server_minor_version;
1304 struct dcerpc_binding_handle *b = cli->binding_handle;
1306 if ((argc == 1) || (argc > 3)) {
1307 printf("Usage: %s <printername> [level]\n", argv[0]);
1308 return WERR_OK;
1311 /* get the arguments need to open the printer handle */
1313 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1315 if (argc == 3) {
1316 level = atoi(argv[2]);
1319 /* Open a printer handle */
1321 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1322 printername,
1323 PRINTER_ACCESS_USE,
1324 &pol);
1325 if (!W_ERROR_IS_OK(werror)) {
1326 printf("Error opening printer handle for %s!\n", printername);
1327 return werror;
1330 /* loop through and print driver info level for each architecture */
1332 for (i=0; archi_table[i].long_archi!=NULL; i++) {
1334 werror = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1335 &pol,
1336 archi_table[i].long_archi,
1337 level,
1338 0, /* offered */
1339 archi_table[i].version,
1341 &info,
1342 &server_major_version,
1343 &server_minor_version);
1344 if (!W_ERROR_IS_OK(werror)) {
1345 continue;
1348 /* need at least one success */
1350 success = true;
1352 printf("\n[%s]\n", archi_table[i].long_archi);
1354 switch (level) {
1355 case 1:
1356 display_print_driver1(&info.info1);
1357 break;
1358 case 2:
1359 display_print_driver2(&info.info2);
1360 break;
1361 case 3:
1362 display_print_driver3(&info.info3);
1363 break;
1364 case 4:
1365 display_print_driver4(&info.info4);
1366 break;
1367 case 5:
1368 display_print_driver5(&info.info5);
1369 break;
1370 case 6:
1371 display_print_driver6(&info.info6);
1372 break;
1373 case 8:
1374 display_print_driver8(&info.info8);
1375 break;
1376 default:
1377 printf("unknown info level %d\n", level);
1378 break;
1382 /* Cleanup */
1384 if (is_valid_policy_hnd(&pol)) {
1385 WERROR _result;
1386 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result);
1389 if (success) {
1390 werror = WERR_OK;
1393 return werror;
1396 /****************************************************************************
1397 ****************************************************************************/
1399 static WERROR enum_driver_by_architecture(struct rpc_pipe_client *cli,
1400 TALLOC_CTX *mem_ctx,
1401 const char *architecture,
1402 uint32_t level)
1404 WERROR werror;
1405 uint32_t count = 0;
1406 union spoolss_DriverInfo *info = NULL;
1407 uint32_t j;
1409 werror = rpccli_spoolss_enumprinterdrivers(cli, mem_ctx,
1410 cli->srv_name_slash,
1411 architecture,
1412 level,
1414 &count,
1415 &info);
1417 if (W_ERROR_EQUAL(werror, WERR_INVALID_ENVIRONMENT)) {
1418 printf("Server does not support environment [%s]\n",
1419 architecture);
1420 return WERR_OK;
1423 if (count == 0) {
1424 return WERR_OK;
1427 if (!W_ERROR_IS_OK(werror)) {
1428 printf("Error getting driver for environment [%s] - %s\n",
1429 architecture, win_errstr(werror));
1430 return werror;
1433 printf("\n[%s]\n", architecture);
1435 switch (level) {
1436 case 1:
1437 for (j=0; j < count; j++) {
1438 display_print_driver1(&info[j].info1);
1440 break;
1441 case 2:
1442 for (j=0; j < count; j++) {
1443 display_print_driver2(&info[j].info2);
1445 break;
1446 case 3:
1447 for (j=0; j < count; j++) {
1448 display_print_driver3(&info[j].info3);
1450 break;
1451 case 4:
1452 for (j=0; j < count; j++) {
1453 display_print_driver4(&info[j].info4);
1455 break;
1456 case 5:
1457 for (j=0; j < count; j++) {
1458 display_print_driver5(&info[j].info5);
1460 break;
1461 case 6:
1462 for (j=0; j < count; j++) {
1463 display_print_driver6(&info[j].info6);
1465 break;
1466 case 8:
1467 for (j=0; j < count; j++) {
1468 display_print_driver8(&info[j].info8);
1470 break;
1471 default:
1472 printf("unknown info level %d\n", level);
1473 return WERR_UNKNOWN_LEVEL;
1476 return werror;
1479 static WERROR cmd_spoolss_enum_drivers(struct rpc_pipe_client *cli,
1480 TALLOC_CTX *mem_ctx,
1481 int argc, const char **argv)
1483 WERROR werror = WERR_OK;
1484 uint32_t level = 1;
1485 uint32_t i;
1486 const char *architecture = NULL;
1488 if (argc > 3) {
1489 printf("Usage: enumdrivers [level] [architecture]\n");
1490 return WERR_OK;
1493 if (argc >= 2) {
1494 level = atoi(argv[1]);
1497 if (argc == 3) {
1498 architecture = argv[2];
1501 if (architecture) {
1502 return enum_driver_by_architecture(cli, mem_ctx,
1503 architecture,
1504 level);
1507 /* loop through and print driver info level for each architecture */
1508 for (i=0; archi_table[i].long_archi!=NULL; i++) {
1509 /* check to see if we already asked for this architecture string */
1511 if (i>0 && strequal(archi_table[i].long_archi, archi_table[i-1].long_archi)) {
1512 continue;
1515 werror = enum_driver_by_architecture(cli, mem_ctx,
1516 archi_table[i].long_archi,
1517 level);
1518 if (!W_ERROR_IS_OK(werror)) {
1519 break;
1523 return werror;
1526 /****************************************************************************
1527 ****************************************************************************/
1529 static void display_printdriverdir_1(struct spoolss_DriverDirectoryInfo1 *r)
1531 printf("\tDirectory Name:[%s]\n", r->directory_name);
1534 /****************************************************************************
1535 ****************************************************************************/
1537 static WERROR cmd_spoolss_getdriverdir(struct rpc_pipe_client *cli,
1538 TALLOC_CTX *mem_ctx,
1539 int argc, const char **argv)
1541 WERROR result;
1542 NTSTATUS status;
1543 const char *env = SPOOLSS_ARCHITECTURE_NT_X86;
1544 DATA_BLOB buffer;
1545 uint32_t offered;
1546 union spoolss_DriverDirectoryInfo info;
1547 uint32_t needed;
1548 struct dcerpc_binding_handle *b = cli->binding_handle;
1550 if (argc > 2) {
1551 printf("Usage: %s [environment]\n", argv[0]);
1552 return WERR_OK;
1555 /* Get the arguments need to open the printer handle */
1557 if (argc == 2) {
1558 env = argv[1];
1561 /* Get the directory. Only use Info level 1 */
1563 status = dcerpc_spoolss_GetPrinterDriverDirectory(b, mem_ctx,
1564 cli->srv_name_slash,
1565 env,
1567 NULL, /* buffer */
1568 0, /* offered */
1569 NULL, /* info */
1570 &needed,
1571 &result);
1572 if (!NT_STATUS_IS_OK(status)) {
1573 return ntstatus_to_werror(status);
1575 if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) {
1576 offered = needed;
1577 buffer = data_blob_talloc_zero(mem_ctx, needed);
1579 status = dcerpc_spoolss_GetPrinterDriverDirectory(b, mem_ctx,
1580 cli->srv_name_slash,
1581 env,
1583 &buffer,
1584 offered,
1585 &info,
1586 &needed,
1587 &result);
1588 if (!NT_STATUS_IS_OK(status)) {
1589 return ntstatus_to_werror(status);
1593 if (W_ERROR_IS_OK(result)) {
1594 display_printdriverdir_1(&info.info1);
1597 return result;
1600 /****************************************************************************
1601 ****************************************************************************/
1603 static void set_drv_info_3_env(TALLOC_CTX *mem_ctx,
1604 struct spoolss_AddDriverInfo3 *info,
1605 const char *arch)
1608 int i;
1610 for (i=0; archi_table[i].long_archi != NULL; i++)
1612 if (strcmp(arch, archi_table[i].short_archi) == 0)
1614 info->version = archi_table[i].version;
1615 info->architecture = talloc_strdup(mem_ctx, archi_table[i].long_archi);
1616 break;
1620 if (archi_table[i].long_archi == NULL)
1622 DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch));
1625 return;
1629 /**************************************************************************
1630 wrapper for strtok to get the next parameter from a delimited list.
1631 Needed to handle the empty parameter string denoted by "NULL"
1632 *************************************************************************/
1634 static char *get_driver_3_param(TALLOC_CTX *mem_ctx, char *str,
1635 const char *delim, const char **dest,
1636 char **saveptr)
1638 char *ptr;
1640 /* get the next token */
1641 ptr = strtok_r(str, delim, saveptr);
1643 /* a string of 'NULL' is used to represent an empty
1644 parameter because two consecutive delimiters
1645 will not return an empty string. See man strtok(3)
1646 for details */
1647 if (ptr && (strcasecmp_m(ptr, "NULL") == 0)) {
1648 ptr = NULL;
1651 if (dest != NULL) {
1652 *dest = talloc_strdup(mem_ctx, ptr);
1655 return ptr;
1658 /********************************************************************************
1659 fill in the members of a spoolss_AddDriverInfo3 struct using a character
1660 string in the form of
1661 <Long Driver Name>:<Driver File Name>:<Data File Name>:\
1662 <Config File Name>:<Help File Name>:<Language Monitor Name>:\
1663 <Default Data Type>:<Comma Separated list of Files>
1664 *******************************************************************************/
1666 static bool init_drv_info_3_members(TALLOC_CTX *mem_ctx, struct spoolss_AddDriverInfo3 *r,
1667 char *args)
1669 char *str, *str2;
1670 size_t count = 0;
1671 char *saveptr = NULL;
1672 struct spoolss_StringArray *deps;
1673 const char **file_array = NULL;
1674 int i;
1676 /* fill in the UNISTR fields */
1677 str = get_driver_3_param(mem_ctx, args, ":", &r->driver_name, &saveptr);
1678 str = get_driver_3_param(mem_ctx, NULL, ":", &r->driver_path, &saveptr);
1679 str = get_driver_3_param(mem_ctx, NULL, ":", &r->data_file, &saveptr);
1680 str = get_driver_3_param(mem_ctx, NULL, ":", &r->config_file, &saveptr);
1681 str = get_driver_3_param(mem_ctx, NULL, ":", &r->help_file, &saveptr);
1682 str = get_driver_3_param(mem_ctx, NULL, ":", &r->monitor_name, &saveptr);
1683 str = get_driver_3_param(mem_ctx, NULL, ":", &r->default_datatype, &saveptr);
1685 /* <Comma Separated List of Dependent Files> */
1686 /* save the beginning of the string */
1687 str2 = get_driver_3_param(mem_ctx, NULL, ":", NULL, &saveptr);
1688 str = str2;
1690 /* begin to strip out each filename */
1691 str = strtok_r(str, ",", &saveptr);
1693 /* no dependent files, we are done */
1694 if (!str) {
1695 return true;
1698 deps = talloc_zero(mem_ctx, struct spoolss_StringArray);
1699 if (!deps) {
1700 return false;
1703 while (str != NULL) {
1704 bool ok;
1705 ok = add_string_to_array(deps, str, &file_array, &count);
1706 if (!ok) {
1707 return false;
1709 str = strtok_r(NULL, ",", &saveptr);
1712 deps->string = talloc_zero_array(deps, const char *, count + 1);
1713 if (!deps->string) {
1714 return false;
1717 for (i=0; i < count; i++) {
1718 deps->string[i] = file_array[i];
1721 r->dependent_files = deps;
1723 return true;
1726 /****************************************************************************
1727 ****************************************************************************/
1729 static WERROR cmd_spoolss_addprinterdriver(struct rpc_pipe_client *cli,
1730 TALLOC_CTX *mem_ctx,
1731 int argc, const char **argv)
1733 WERROR result;
1734 NTSTATUS status;
1735 uint32_t level = 3;
1736 struct spoolss_AddDriverInfoCtr info_ctr;
1737 struct spoolss_AddDriverInfo3 info3;
1738 const char *arch;
1739 char *driver_args;
1740 struct dcerpc_binding_handle *b = cli->binding_handle;
1742 /* parse the command arguments */
1743 if (argc != 3 && argc != 4)
1745 printf ("Usage: %s <Environment> \\\n", argv[0]);
1746 printf ("\t<Long Driver Name>:<Driver File Name>:<Data File Name>:\\\n");
1747 printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
1748 printf ("\t<Default Data Type>:<Comma Separated list of Files> \\\n");
1749 printf ("\t[version]\n");
1751 return WERR_OK;
1754 /* Fill in the spoolss_AddDriverInfo3 struct */
1755 ZERO_STRUCT(info3);
1757 arch = cmd_spoolss_get_short_archi(argv[1]);
1758 if (!arch) {
1759 printf ("Error Unknown architecture [%s]\n", argv[1]);
1760 return WERR_INVALID_PARAM;
1763 set_drv_info_3_env(mem_ctx, &info3, arch);
1765 driver_args = talloc_strdup( mem_ctx, argv[2] );
1766 if (!init_drv_info_3_members(mem_ctx, &info3, driver_args ))
1768 printf ("Error Invalid parameter list - %s.\n", argv[2]);
1769 return WERR_INVALID_PARAM;
1772 /* if printer driver version specified, override the default version
1773 * used by the architecture. This allows installation of Windows
1774 * 2000 (version 3) printer drivers. */
1775 if (argc == 4)
1777 info3.version = atoi(argv[3]);
1781 info_ctr.level = level;
1782 info_ctr.info.info3 = &info3;
1784 status = dcerpc_spoolss_AddPrinterDriver(b, mem_ctx,
1785 cli->srv_name_slash,
1786 &info_ctr,
1787 &result);
1788 if (!NT_STATUS_IS_OK(status)) {
1789 return ntstatus_to_werror(status);
1791 if (W_ERROR_IS_OK(result)) {
1792 printf ("Printer Driver %s successfully installed.\n",
1793 info3.driver_name);
1796 return result;
1800 /****************************************************************************
1801 ****************************************************************************/
1803 static WERROR cmd_spoolss_addprinterex(struct rpc_pipe_client *cli,
1804 TALLOC_CTX *mem_ctx,
1805 int argc, const char **argv)
1807 WERROR result;
1808 struct spoolss_SetPrinterInfoCtr info_ctr;
1809 struct spoolss_SetPrinterInfo2 info2;
1811 /* parse the command arguments */
1812 if (argc != 5)
1814 printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]);
1815 return WERR_OK;
1818 /* Fill in the DRIVER_INFO_2 struct */
1819 ZERO_STRUCT(info2);
1821 info2.printername = argv[1];
1822 info2.drivername = argv[3];
1823 info2.sharename = argv[2];
1824 info2.portname = argv[4];
1825 info2.comment = "Created by rpcclient";
1826 info2.printprocessor = "winprint";
1827 info2.datatype = "RAW";
1828 info2.devmode_ptr = NULL;
1829 info2.secdesc_ptr = NULL;
1830 info2.attributes = PRINTER_ATTRIBUTE_SHARED;
1831 info2.priority = 0;
1832 info2.defaultpriority = 0;
1833 info2.starttime = 0;
1834 info2.untiltime = 0;
1836 /* These three fields must not be used by AddPrinter()
1837 as defined in the MS Platform SDK documentation..
1838 --jerry
1839 info2.status = 0;
1840 info2.cjobs = 0;
1841 info2.averageppm = 0;
1844 info_ctr.level = 2;
1845 info_ctr.info.info2 = &info2;
1847 result = rpccli_spoolss_addprinterex(cli, mem_ctx,
1848 &info_ctr);
1849 if (W_ERROR_IS_OK(result))
1850 printf ("Printer %s successfully installed.\n", argv[1]);
1852 return result;
1855 /****************************************************************************
1856 ****************************************************************************/
1858 static WERROR cmd_spoolss_setdriver(struct rpc_pipe_client *cli,
1859 TALLOC_CTX *mem_ctx,
1860 int argc, const char **argv)
1862 struct policy_handle pol;
1863 WERROR result;
1864 NTSTATUS status;
1865 uint32_t level = 2;
1866 const char *printername;
1867 union spoolss_PrinterInfo info;
1868 struct spoolss_SetPrinterInfoCtr info_ctr;
1869 struct spoolss_SetPrinterInfo2 info2;
1870 struct spoolss_DevmodeContainer devmode_ctr;
1871 struct sec_desc_buf secdesc_ctr;
1872 struct dcerpc_binding_handle *b = cli->binding_handle;
1874 ZERO_STRUCT(devmode_ctr);
1875 ZERO_STRUCT(secdesc_ctr);
1877 /* parse the command arguments */
1878 if (argc != 3)
1880 printf ("Usage: %s <printer> <driver>\n", argv[0]);
1881 return WERR_OK;
1884 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1886 /* Get a printer handle */
1888 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1889 printername,
1890 PRINTER_ALL_ACCESS,
1891 &pol);
1892 if (!W_ERROR_IS_OK(result))
1893 goto done;
1895 /* Get printer info */
1897 result = rpccli_spoolss_getprinter(cli, mem_ctx,
1898 &pol,
1899 level,
1901 &info);
1902 if (!W_ERROR_IS_OK(result)) {
1903 printf ("Unable to retrieve printer information!\n");
1904 goto done;
1907 /* Set the printer driver */
1909 spoolss_printerinfo2_to_setprinterinfo2(&info.info2, &info2);
1910 info2.drivername = argv[2];
1912 info_ctr.level = 2;
1913 info_ctr.info.info2 = &info2;
1915 status = dcerpc_spoolss_SetPrinter(b, mem_ctx,
1916 &pol,
1917 &info_ctr,
1918 &devmode_ctr,
1919 &secdesc_ctr,
1920 0, /* command */
1921 &result);
1922 if (!NT_STATUS_IS_OK(status)) {
1923 result = ntstatus_to_werror(status);
1924 goto done;
1926 if (!W_ERROR_IS_OK(result)) {
1927 printf("SetPrinter call failed!\n");
1928 goto done;
1931 printf("Successfully set %s to driver %s.\n", argv[1], argv[2]);
1933 done:
1934 /* Cleanup */
1936 if (is_valid_policy_hnd(&pol)) {
1937 WERROR _result;
1938 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result);
1941 return result;
1945 /****************************************************************************
1946 ****************************************************************************/
1948 static WERROR cmd_spoolss_deletedriverex(struct rpc_pipe_client *cli,
1949 TALLOC_CTX *mem_ctx,
1950 int argc, const char **argv)
1952 WERROR result, ret = WERR_UNKNOWN_PRINTER_DRIVER;
1953 NTSTATUS status;
1954 struct dcerpc_binding_handle *b = cli->binding_handle;
1956 int i;
1957 int vers = -1;
1959 const char *arch = NULL;
1960 uint32_t delete_flags = 0;
1962 /* parse the command arguments */
1963 if (argc < 2 || argc > 5) {
1964 printf("Usage: %s <driver> [arch] [version] [flags]\n", argv[0]);
1965 return WERR_OK;
1968 if (argc >= 3)
1969 arch = argv[2];
1970 if (argc >= 4) {
1971 vers = atoi(argv[3]);
1972 delete_flags |= DPD_DELETE_SPECIFIC_VERSION;
1974 if (argc == 5)
1975 delete_flags = atoi(argv[4]);
1977 /* delete the driver for all architectures */
1978 for (i=0; archi_table[i].long_archi; i++) {
1980 if (arch && !strequal(archi_table[i].long_archi, arch))
1981 continue;
1983 if (vers >= 0 && archi_table[i].version != vers)
1984 continue;
1986 /* make the call to remove the driver */
1987 status = dcerpc_spoolss_DeletePrinterDriverEx(b, mem_ctx,
1988 cli->srv_name_slash,
1989 archi_table[i].long_archi,
1990 argv[1],
1991 delete_flags,
1992 archi_table[i].version,
1993 &result);
1994 if (!NT_STATUS_IS_OK(status)) {
1995 return ntstatus_to_werror(status);
1997 if ( !W_ERROR_IS_OK(result) )
1999 if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
2000 printf ("Failed to remove driver %s for arch [%s] (version: %d): %s\n",
2001 argv[1], archi_table[i].long_archi, archi_table[i].version, win_errstr(result));
2004 else
2006 printf ("Driver %s and files removed for arch [%s] (version: %d).\n", argv[1],
2007 archi_table[i].long_archi, archi_table[i].version);
2008 ret = WERR_OK;
2012 return ret;
2016 /****************************************************************************
2017 ****************************************************************************/
2019 static WERROR cmd_spoolss_deletedriver(struct rpc_pipe_client *cli,
2020 TALLOC_CTX *mem_ctx,
2021 int argc, const char **argv)
2023 WERROR result = WERR_OK;
2024 NTSTATUS status;
2025 int i;
2026 struct dcerpc_binding_handle *b = cli->binding_handle;
2028 /* parse the command arguments */
2029 if (argc != 2) {
2030 printf ("Usage: %s <driver>\n", argv[0]);
2031 return WERR_OK;
2034 /* delete the driver for all architectures */
2035 for (i=0; archi_table[i].long_archi; i++) {
2036 result = WERR_OK;
2038 /* make the call to remove the driver */
2039 status = dcerpc_spoolss_DeletePrinterDriver(b, mem_ctx,
2040 cli->srv_name_slash,
2041 archi_table[i].long_archi,
2042 argv[1],
2043 &result);
2044 if (!NT_STATUS_IS_OK(status)) {
2045 result = ntstatus_to_werror(status);
2046 continue;
2048 if ( !W_ERROR_IS_OK(result) ) {
2049 if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
2050 printf ("Failed to remove driver %s for arch [%s] - error %s!\n",
2051 argv[1], archi_table[i].long_archi,
2052 win_errstr(result));
2054 } else {
2055 printf ("Driver %s removed for arch [%s].\n", argv[1],
2056 archi_table[i].long_archi);
2060 return result;
2063 /****************************************************************************
2064 ****************************************************************************/
2066 static WERROR cmd_spoolss_getprintprocdir(struct rpc_pipe_client *cli,
2067 TALLOC_CTX *mem_ctx,
2068 int argc, const char **argv)
2070 WERROR result;
2071 NTSTATUS status;
2072 const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
2073 DATA_BLOB buffer;
2074 uint32_t offered;
2075 union spoolss_PrintProcessorDirectoryInfo info;
2076 uint32_t needed;
2077 struct dcerpc_binding_handle *b = cli->binding_handle;
2079 /* parse the command arguments */
2080 if (argc > 2) {
2081 printf ("Usage: %s [environment]\n", argv[0]);
2082 return WERR_OK;
2085 if (argc == 2) {
2086 environment = argv[1];
2089 status = dcerpc_spoolss_GetPrintProcessorDirectory(b, mem_ctx,
2090 cli->srv_name_slash,
2091 environment,
2093 NULL, /* buffer */
2094 0, /* offered */
2095 NULL, /* info */
2096 &needed,
2097 &result);
2098 if (!NT_STATUS_IS_OK(status)) {
2099 return ntstatus_to_werror(status);
2101 if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) {
2102 offered = needed;
2103 buffer = data_blob_talloc_zero(mem_ctx, needed);
2105 status = dcerpc_spoolss_GetPrintProcessorDirectory(b, mem_ctx,
2106 cli->srv_name_slash,
2107 environment,
2109 &buffer,
2110 offered,
2111 &info,
2112 &needed,
2113 &result);
2114 if (!NT_STATUS_IS_OK(status)) {
2115 return ntstatus_to_werror(status);
2119 if (W_ERROR_IS_OK(result)) {
2120 printf("%s\n", info.info1.directory_name);
2123 return result;
2126 /****************************************************************************
2127 ****************************************************************************/
2129 static WERROR cmd_spoolss_addform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
2130 int argc, const char **argv)
2132 struct policy_handle handle;
2133 WERROR werror;
2134 NTSTATUS status;
2135 const char *printername;
2136 struct spoolss_AddFormInfoCtr info_ctr;
2137 struct spoolss_AddFormInfo1 info1;
2138 struct spoolss_AddFormInfo2 info2;
2139 uint32_t level = 1;
2140 struct dcerpc_binding_handle *b = cli->binding_handle;
2142 /* Parse the command arguments */
2144 if (argc < 3 || argc > 5) {
2145 printf ("Usage: %s <printer> <formname> [level]\n", argv[0]);
2146 return WERR_OK;
2149 /* Get a printer handle */
2151 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2153 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2154 printername,
2155 PRINTER_ALL_ACCESS,
2156 &handle);
2157 if (!W_ERROR_IS_OK(werror))
2158 goto done;
2160 /* Dummy up some values for the form data */
2162 if (argc == 4) {
2163 level = atoi(argv[3]);
2166 switch (level) {
2167 case 1:
2168 info1.flags = SPOOLSS_FORM_USER;
2169 info1.form_name = argv[2];
2170 info1.size.width = 100;
2171 info1.size.height = 100;
2172 info1.area.left = 0;
2173 info1.area.top = 10;
2174 info1.area.right = 20;
2175 info1.area.bottom = 30;
2177 info_ctr.level = 1;
2178 info_ctr.info.info1 = &info1;
2180 break;
2181 case 2:
2182 info2.flags = SPOOLSS_FORM_USER;
2183 info2.form_name = argv[2];
2184 info2.size.width = 100;
2185 info2.size.height = 100;
2186 info2.area.left = 0;
2187 info2.area.top = 10;
2188 info2.area.right = 20;
2189 info2.area.bottom = 30;
2190 info2.keyword = argv[2];
2191 info2.string_type = SPOOLSS_FORM_STRING_TYPE_NONE;
2192 info2.mui_dll = NULL;
2193 info2.ressource_id = 0;
2194 info2.display_name = argv[2];
2195 info2.lang_id = 0;
2197 info_ctr.level = 2;
2198 info_ctr.info.info2 = &info2;
2200 break;
2201 default:
2202 werror = WERR_INVALID_PARAM;
2203 goto done;
2206 /* Add the form */
2208 status = dcerpc_spoolss_AddForm(b, mem_ctx,
2209 &handle,
2210 &info_ctr,
2211 &werror);
2212 if (!NT_STATUS_IS_OK(status)) {
2213 werror = ntstatus_to_werror(status);
2214 goto done;
2216 done:
2217 if (is_valid_policy_hnd(&handle)) {
2218 WERROR _result;
2219 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result);
2222 return werror;
2225 /****************************************************************************
2226 ****************************************************************************/
2228 static WERROR cmd_spoolss_setform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
2229 int argc, const char **argv)
2231 struct policy_handle handle;
2232 WERROR werror;
2233 NTSTATUS status;
2234 const char *printername;
2235 struct spoolss_AddFormInfoCtr info_ctr;
2236 struct spoolss_AddFormInfo1 info1;
2237 struct dcerpc_binding_handle *b = cli->binding_handle;
2239 /* Parse the command arguments */
2241 if (argc != 3) {
2242 printf ("Usage: %s <printer> <formname>\n", argv[0]);
2243 return WERR_OK;
2246 /* Get a printer handle */
2248 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2250 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2251 printername,
2252 SEC_FLAG_MAXIMUM_ALLOWED,
2253 &handle);
2254 if (!W_ERROR_IS_OK(werror))
2255 goto done;
2257 /* Dummy up some values for the form data */
2259 info1.flags = SPOOLSS_FORM_PRINTER;
2260 info1.size.width = 100;
2261 info1.size.height = 100;
2262 info1.area.left = 0;
2263 info1.area.top = 1000;
2264 info1.area.right = 2000;
2265 info1.area.bottom = 3000;
2266 info1.form_name = argv[2];
2268 info_ctr.info.info1 = &info1;
2269 info_ctr.level = 1;
2271 /* Set the form */
2273 status = dcerpc_spoolss_SetForm(b, mem_ctx,
2274 &handle,
2275 argv[2],
2276 &info_ctr,
2277 &werror);
2278 if (!NT_STATUS_IS_OK(status)) {
2279 werror = ntstatus_to_werror(status);
2280 goto done;
2282 done:
2283 if (is_valid_policy_hnd(&handle)) {
2284 WERROR _result;
2285 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result);
2288 return werror;
2291 /****************************************************************************
2292 ****************************************************************************/
2294 static const char *get_form_flag(int form_flag)
2296 switch (form_flag) {
2297 case SPOOLSS_FORM_USER:
2298 return "FORM_USER";
2299 case SPOOLSS_FORM_BUILTIN:
2300 return "FORM_BUILTIN";
2301 case SPOOLSS_FORM_PRINTER:
2302 return "FORM_PRINTER";
2303 default:
2304 return "unknown";
2308 /****************************************************************************
2309 ****************************************************************************/
2311 static void display_form_info1(struct spoolss_FormInfo1 *r)
2313 printf("%s\n" \
2314 "\tflag: %s (%d)\n" \
2315 "\twidth: %d, length: %d\n" \
2316 "\tleft: %d, right: %d, top: %d, bottom: %d\n\n",
2317 r->form_name, get_form_flag(r->flags), r->flags,
2318 r->size.width, r->size.height,
2319 r->area.left, r->area.right,
2320 r->area.top, r->area.bottom);
2323 /****************************************************************************
2324 ****************************************************************************/
2326 static void display_form_info2(struct spoolss_FormInfo2 *r)
2328 printf("%s\n" \
2329 "\tflag: %s (%d)\n" \
2330 "\twidth: %d, length: %d\n" \
2331 "\tleft: %d, right: %d, top: %d, bottom: %d\n",
2332 r->form_name, get_form_flag(r->flags), r->flags,
2333 r->size.width, r->size.height,
2334 r->area.left, r->area.right,
2335 r->area.top, r->area.bottom);
2336 printf("\tkeyword: %s\n", r->keyword);
2337 printf("\tstring_type: 0x%08x\n", r->string_type);
2338 printf("\tmui_dll: %s\n", r->mui_dll);
2339 printf("\tressource_id: 0x%08x\n", r->ressource_id);
2340 printf("\tdisplay_name: %s\n", r->display_name);
2341 printf("\tlang_id: %d\n", r->lang_id);
2342 printf("\n");
2345 /****************************************************************************
2346 ****************************************************************************/
2348 static WERROR cmd_spoolss_getform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
2349 int argc, const char **argv)
2351 struct policy_handle handle;
2352 WERROR werror;
2353 NTSTATUS status;
2354 const char *printername;
2355 DATA_BLOB buffer;
2356 uint32_t offered = 0;
2357 union spoolss_FormInfo info;
2358 uint32_t needed;
2359 uint32_t level = 1;
2360 struct dcerpc_binding_handle *b = cli->binding_handle;
2362 /* Parse the command arguments */
2364 if (argc < 3 || argc > 5) {
2365 printf ("Usage: %s <printer> <formname> [level]\n", argv[0]);
2366 return WERR_OK;
2369 /* Get a printer handle */
2371 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2373 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2374 printername,
2375 SEC_FLAG_MAXIMUM_ALLOWED,
2376 &handle);
2377 if (!W_ERROR_IS_OK(werror))
2378 goto done;
2380 if (argc == 4) {
2381 level = atoi(argv[3]);
2384 /* Get the form */
2386 status = dcerpc_spoolss_GetForm(b, mem_ctx,
2387 &handle,
2388 argv[2],
2389 level,
2390 NULL,
2391 offered,
2392 &info,
2393 &needed,
2394 &werror);
2395 if (!NT_STATUS_IS_OK(status)) {
2396 werror = ntstatus_to_werror(status);
2397 goto done;
2399 if (W_ERROR_EQUAL(werror, WERR_INSUFFICIENT_BUFFER)) {
2400 buffer = data_blob_talloc_zero(mem_ctx, needed);
2401 offered = needed;
2402 status = dcerpc_spoolss_GetForm(b, mem_ctx,
2403 &handle,
2404 argv[2],
2405 level,
2406 &buffer,
2407 offered,
2408 &info,
2409 &needed,
2410 &werror);
2411 if (!NT_STATUS_IS_OK(status)) {
2412 werror = ntstatus_to_werror(status);
2413 goto done;
2417 if (!W_ERROR_IS_OK(werror)) {
2418 goto done;
2421 switch (level) {
2422 case 1:
2423 display_form_info1(&info.info1);
2424 break;
2425 case 2:
2426 display_form_info2(&info.info2);
2427 break;
2430 done:
2431 if (is_valid_policy_hnd(&handle)) {
2432 WERROR _result;
2433 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result);
2436 return werror;
2439 /****************************************************************************
2440 ****************************************************************************/
2442 static WERROR cmd_spoolss_deleteform(struct rpc_pipe_client *cli,
2443 TALLOC_CTX *mem_ctx, int argc,
2444 const char **argv)
2446 struct policy_handle handle;
2447 WERROR werror;
2448 NTSTATUS status;
2449 const char *printername;
2450 struct dcerpc_binding_handle *b = cli->binding_handle;
2452 /* Parse the command arguments */
2454 if (argc != 3) {
2455 printf ("Usage: %s <printer> <formname>\n", argv[0]);
2456 return WERR_OK;
2459 /* Get a printer handle */
2461 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2463 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2464 printername,
2465 SEC_FLAG_MAXIMUM_ALLOWED,
2466 &handle);
2467 if (!W_ERROR_IS_OK(werror))
2468 goto done;
2470 /* Delete the form */
2472 status = dcerpc_spoolss_DeleteForm(b, mem_ctx,
2473 &handle,
2474 argv[2],
2475 &werror);
2476 if (!NT_STATUS_IS_OK(status)) {
2477 werror = ntstatus_to_werror(status);
2478 goto done;
2481 done:
2482 if (is_valid_policy_hnd(&handle)) {
2483 WERROR _result;
2484 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result);
2487 return werror;
2490 /****************************************************************************
2491 ****************************************************************************/
2493 static WERROR cmd_spoolss_enum_forms(struct rpc_pipe_client *cli,
2494 TALLOC_CTX *mem_ctx, int argc,
2495 const char **argv)
2497 struct policy_handle handle;
2498 WERROR werror;
2499 const char *printername;
2500 uint32_t num_forms, level = 1, i;
2501 union spoolss_FormInfo *forms;
2502 struct dcerpc_binding_handle *b = cli->binding_handle;
2504 /* Parse the command arguments */
2506 if (argc < 2 || argc > 4) {
2507 printf ("Usage: %s <printer> [level]\n", argv[0]);
2508 return WERR_OK;
2511 /* Get a printer handle */
2513 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2515 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2516 printername,
2517 SEC_FLAG_MAXIMUM_ALLOWED,
2518 &handle);
2519 if (!W_ERROR_IS_OK(werror))
2520 goto done;
2522 if (argc == 3) {
2523 level = atoi(argv[2]);
2526 /* Enumerate forms */
2528 werror = rpccli_spoolss_enumforms(cli, mem_ctx,
2529 &handle,
2530 level,
2532 &num_forms,
2533 &forms);
2535 if (!W_ERROR_IS_OK(werror))
2536 goto done;
2538 /* Display output */
2540 for (i = 0; i < num_forms; i++) {
2541 switch (level) {
2542 case 1:
2543 display_form_info1(&forms[i].info1);
2544 break;
2545 case 2:
2546 display_form_info2(&forms[i].info2);
2547 break;
2551 done:
2552 if (is_valid_policy_hnd(&handle)) {
2553 WERROR _result;
2554 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result);
2557 return werror;
2560 /****************************************************************************
2561 ****************************************************************************/
2563 static WERROR cmd_spoolss_setprinterdata(struct rpc_pipe_client *cli,
2564 TALLOC_CTX *mem_ctx,
2565 int argc, const char **argv)
2567 WERROR result;
2568 NTSTATUS status;
2569 const char *printername;
2570 struct policy_handle pol = { 0, };
2571 union spoolss_PrinterInfo info;
2572 enum winreg_Type type;
2573 union spoolss_PrinterData data;
2574 DATA_BLOB blob;
2575 struct dcerpc_binding_handle *b = cli->binding_handle;
2577 /* parse the command arguments */
2578 if (argc < 5) {
2579 printf ("Usage: %s <printer> <string|binary|dword|multistring>"
2580 " <value> <data>\n",
2581 argv[0]);
2582 return WERR_OK;
2585 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2587 type = REG_NONE;
2589 if (strequal(argv[2], "string")) {
2590 type = REG_SZ;
2593 if (strequal(argv[2], "binary")) {
2594 type = REG_BINARY;
2597 if (strequal(argv[2], "dword")) {
2598 type = REG_DWORD;
2601 if (strequal(argv[2], "multistring")) {
2602 type = REG_MULTI_SZ;
2605 if (type == REG_NONE) {
2606 printf("Unknown data type: %s\n", argv[2]);
2607 result = WERR_INVALID_PARAM;
2608 goto done;
2611 /* get a printer handle */
2613 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2614 printername,
2615 SEC_FLAG_MAXIMUM_ALLOWED,
2616 &pol);
2617 if (!W_ERROR_IS_OK(result)) {
2618 goto done;
2621 result = rpccli_spoolss_getprinter(cli, mem_ctx,
2622 &pol,
2625 &info);
2626 if (!W_ERROR_IS_OK(result)) {
2627 goto done;
2630 printf("%s\n", current_timestring(mem_ctx, true));
2631 printf("\tchange_id (before set)\t:[0x%x]\n", info.info0.change_id);
2633 /* Set the printer data */
2635 switch (type) {
2636 case REG_SZ:
2637 data.string = talloc_strdup(mem_ctx, argv[4]);
2638 W_ERROR_HAVE_NO_MEMORY(data.string);
2639 break;
2640 case REG_DWORD:
2641 data.value = strtoul(argv[4], NULL, 10);
2642 break;
2643 case REG_BINARY:
2644 data.binary = strhex_to_data_blob(mem_ctx, argv[4]);
2645 break;
2646 case REG_MULTI_SZ: {
2647 int i;
2648 size_t num_strings;
2649 const char **strings = NULL;
2651 num_strings = 0;
2653 for (i=4; i<argc; i++) {
2654 if (strcmp(argv[i], "NULL") == 0) {
2655 argv[i] = "";
2657 if (!add_string_to_array(mem_ctx, argv[i],
2658 &strings,
2659 &num_strings)) {
2660 result = WERR_NOMEM;
2661 goto done;
2664 data.string_array = talloc_zero_array(mem_ctx, const char *, num_strings + 1);
2665 if (!data.string_array) {
2666 result = WERR_NOMEM;
2667 goto done;
2669 for (i=0; i < num_strings; i++) {
2670 data.string_array[i] = strings[i];
2672 break;
2674 default:
2675 printf("Unknown data type: %s\n", argv[2]);
2676 result = WERR_INVALID_PARAM;
2677 goto done;
2680 result = push_spoolss_PrinterData(mem_ctx, &blob, type, &data);
2681 if (!W_ERROR_IS_OK(result)) {
2682 goto done;
2685 status = dcerpc_spoolss_SetPrinterData(b, mem_ctx,
2686 &pol,
2687 argv[3], /* value_name */
2688 type,
2689 blob.data,
2690 blob.length,
2691 &result);
2692 if (!NT_STATUS_IS_OK(status)) {
2693 printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]);
2694 result = ntstatus_to_werror(status);
2695 goto done;
2697 if (!W_ERROR_IS_OK(result)) {
2698 printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]);
2699 goto done;
2701 printf("\tSetPrinterData succeeded [%s: %s]\n", argv[3], argv[4]);
2703 result = rpccli_spoolss_getprinter(cli, mem_ctx,
2704 &pol,
2707 &info);
2708 if (!W_ERROR_IS_OK(result)) {
2709 goto done;
2712 printf("%s\n", current_timestring(mem_ctx, true));
2713 printf("\tchange_id (after set)\t:[0x%x]\n", info.info0.change_id);
2715 done:
2716 /* cleanup */
2717 if (is_valid_policy_hnd(&pol)) {
2718 WERROR _result;
2719 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result);
2722 return result;
2725 /****************************************************************************
2726 ****************************************************************************/
2728 static void display_job_info1(struct spoolss_JobInfo1 *r)
2730 printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", r->position, r->job_id,
2731 r->user_name, r->document_name, r->text_status, r->pages_printed,
2732 r->total_pages);
2735 /****************************************************************************
2736 ****************************************************************************/
2738 static void display_job_info2(struct spoolss_JobInfo2 *r)
2740 printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n",
2741 r->position, r->job_id,
2742 r->user_name, r->document_name, r->text_status, r->pages_printed,
2743 r->total_pages, r->size);
2746 /****************************************************************************
2747 ****************************************************************************/
2749 static void display_job_info3(struct spoolss_JobInfo3 *r)
2751 printf("jobid[%d], next_jobid[%d]\n",
2752 r->job_id, r->next_job_id);
2755 /****************************************************************************
2756 ****************************************************************************/
2758 static void display_job_info4(struct spoolss_JobInfo4 *r)
2760 printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d/%d bytes\n",
2761 r->position, r->job_id,
2762 r->user_name, r->document_name, r->text_status, r->pages_printed,
2763 r->total_pages, r->size, r->size_high);
2766 /****************************************************************************
2767 ****************************************************************************/
2769 static WERROR cmd_spoolss_enum_jobs(struct rpc_pipe_client *cli,
2770 TALLOC_CTX *mem_ctx, int argc,
2771 const char **argv)
2773 WERROR result;
2774 uint32_t level = 1, count, i;
2775 const char *printername;
2776 struct policy_handle hnd;
2777 union spoolss_JobInfo *info;
2778 struct dcerpc_binding_handle *b = cli->binding_handle;
2780 if (argc < 2 || argc > 3) {
2781 printf("Usage: %s printername [level]\n", argv[0]);
2782 return WERR_OK;
2785 if (argc == 3) {
2786 level = atoi(argv[2]);
2789 /* Open printer handle */
2791 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2793 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2794 printername,
2795 SEC_FLAG_MAXIMUM_ALLOWED,
2796 &hnd);
2797 if (!W_ERROR_IS_OK(result))
2798 goto done;
2800 /* Enumerate ports */
2802 result = rpccli_spoolss_enumjobs(cli, mem_ctx,
2803 &hnd,
2804 0, /* firstjob */
2805 1000, /* numjobs */
2806 level,
2808 &count,
2809 &info);
2810 if (!W_ERROR_IS_OK(result)) {
2811 goto done;
2814 for (i = 0; i < count; i++) {
2815 switch (level) {
2816 case 1:
2817 display_job_info1(&info[i].info1);
2818 break;
2819 case 2:
2820 display_job_info2(&info[i].info2);
2821 break;
2822 default:
2823 d_printf("unknown info level %d\n", level);
2824 break;
2828 done:
2829 if (is_valid_policy_hnd(&hnd)) {
2830 WERROR _result;
2831 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
2834 return result;
2837 /****************************************************************************
2838 ****************************************************************************/
2840 static WERROR cmd_spoolss_get_job(struct rpc_pipe_client *cli,
2841 TALLOC_CTX *mem_ctx, int argc,
2842 const char **argv)
2844 WERROR result;
2845 const char *printername;
2846 struct policy_handle hnd;
2847 uint32_t job_id;
2848 uint32_t level = 1;
2849 union spoolss_JobInfo info;
2850 struct dcerpc_binding_handle *b = cli->binding_handle;
2852 if (argc < 3 || argc > 4) {
2853 printf("Usage: %s printername job_id [level]\n", argv[0]);
2854 return WERR_OK;
2857 job_id = atoi(argv[2]);
2859 if (argc == 4) {
2860 level = atoi(argv[3]);
2863 /* Open printer handle */
2865 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2867 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2868 printername,
2869 SEC_FLAG_MAXIMUM_ALLOWED,
2870 &hnd);
2871 if (!W_ERROR_IS_OK(result)) {
2872 goto done;
2875 /* Enumerate ports */
2877 result = rpccli_spoolss_getjob(cli, mem_ctx,
2878 &hnd,
2879 job_id,
2880 level,
2882 &info);
2884 if (!W_ERROR_IS_OK(result)) {
2885 goto done;
2888 switch (level) {
2889 case 1:
2890 display_job_info1(&info.info1);
2891 break;
2892 case 2:
2893 display_job_info2(&info.info2);
2894 break;
2895 case 3:
2896 display_job_info3(&info.info3);
2897 break;
2898 case 4:
2899 display_job_info4(&info.info4);
2900 break;
2901 default:
2902 d_printf("unknown info level %d\n", level);
2903 break;
2906 done:
2907 if (is_valid_policy_hnd(&hnd)) {
2908 WERROR _result;
2909 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
2912 return result;
2915 /****************************************************************************
2916 ****************************************************************************/
2918 static struct {
2919 const char *name;
2920 enum spoolss_JobControl val;
2921 } cmdvals[] = {
2922 {"PAUSE", SPOOLSS_JOB_CONTROL_PAUSE},
2923 {"RESUME", SPOOLSS_JOB_CONTROL_RESUME},
2924 {"CANCEL", SPOOLSS_JOB_CONTROL_CANCEL},
2925 {"RESTART", SPOOLSS_JOB_CONTROL_RESTART},
2926 {"DELETE", SPOOLSS_JOB_CONTROL_DELETE},
2927 {"SEND_TO_PRINTER", SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER},
2928 {"EJECTED", SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED},
2929 {"RETAIN", SPOOLSS_JOB_CONTROL_RETAIN},
2930 {"RELEASE", SPOOLSS_JOB_CONTROL_RELEASE}
2933 static enum spoolss_JobControl parse_setjob_command(const char *cmd)
2935 int i;
2937 for (i = 0; i < sizeof(cmdvals)/sizeof(cmdvals[0]); i++) {
2938 if (strequal(cmdvals[i].name, cmd)) {
2939 return cmdvals[i].val;
2942 return (enum spoolss_JobControl)atoi(cmd);
2945 static WERROR cmd_spoolss_set_job(struct rpc_pipe_client *cli,
2946 TALLOC_CTX *mem_ctx, int argc,
2947 const char **argv)
2949 WERROR result;
2950 NTSTATUS status;
2951 const char *printername;
2952 struct policy_handle hnd;
2953 uint32_t job_id;
2954 enum spoolss_JobControl command;
2955 struct dcerpc_binding_handle *b = cli->binding_handle;
2957 if (argc != 4) {
2958 printf("Usage: %s printername job_id command\n", argv[0]);
2959 printf("command = [PAUSE|RESUME|CANCEL|RESTART|DELETE|"
2960 "SEND_TO_PRINTER|EJECTED|RETAIN|RELEASE]\n");
2961 return WERR_OK;
2964 job_id = atoi(argv[2]);
2965 command = parse_setjob_command(argv[3]);
2967 /* Open printer handle */
2969 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2971 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2972 printername,
2973 SEC_FLAG_MAXIMUM_ALLOWED,
2974 &hnd);
2975 if (!W_ERROR_IS_OK(result)) {
2976 goto done;
2979 /* Set Job */
2981 status = dcerpc_spoolss_SetJob(b, mem_ctx,
2982 &hnd,
2983 job_id,
2984 NULL,
2985 command,
2986 &result);
2987 if (!NT_STATUS_IS_OK(status)) {
2988 result = ntstatus_to_werror(status);
2989 goto done;
2991 if (!W_ERROR_IS_OK(result)) {
2992 goto done;
2995 done:
2996 if (is_valid_policy_hnd(&hnd)) {
2997 WERROR _result;
2998 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
3001 return result;
3004 /****************************************************************************
3005 ****************************************************************************/
3007 static WERROR cmd_spoolss_enum_data(struct rpc_pipe_client *cli,
3008 TALLOC_CTX *mem_ctx, int argc,
3009 const char **argv)
3011 WERROR result;
3012 NTSTATUS status;
3013 const char *printername;
3014 struct policy_handle hnd;
3015 uint32_t value_needed;
3016 enum winreg_Type type;
3017 uint32_t data_needed;
3018 struct dcerpc_binding_handle *b = cli->binding_handle;
3019 struct spoolss_EnumPrinterData r;
3021 if (argc != 2) {
3022 printf("Usage: %s printername\n", argv[0]);
3023 return WERR_OK;
3026 /* Open printer handle */
3028 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3030 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3031 printername,
3032 SEC_FLAG_MAXIMUM_ALLOWED,
3033 &hnd);
3034 if (!W_ERROR_IS_OK(result)) {
3035 goto done;
3038 /* Enumerate data */
3040 r.in.handle = &hnd;
3041 r.in.enum_index = 0;
3042 r.in.value_offered = 0;
3043 r.in.data_offered = 0;
3044 r.out.value_name = NULL;
3045 r.out.value_needed = &value_needed;
3046 r.out.type = &type;
3047 r.out.data = NULL;
3048 r.out.data_needed = &data_needed;
3050 status = dcerpc_spoolss_EnumPrinterData_r(b, mem_ctx, &r);
3051 if (!NT_STATUS_IS_OK(status)) {
3052 result = ntstatus_to_werror(status);
3053 goto done;
3056 if (!W_ERROR_IS_OK(r.out.result)) {
3057 result = r.out.result;
3058 goto done;
3061 r.in.data_offered = *r.out.data_needed;
3062 r.in.value_offered = *r.out.value_needed;
3063 r.out.data = talloc_zero_array(mem_ctx, uint8_t, r.in.data_offered);
3064 r.out.value_name = talloc_zero_array(mem_ctx, char, r.in.value_offered);
3066 do {
3068 status = dcerpc_spoolss_EnumPrinterData_r(b, mem_ctx, &r);
3069 if (!NT_STATUS_IS_OK(status)) {
3070 result = ntstatus_to_werror(status);
3071 goto done;
3074 if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
3075 result = WERR_OK;
3076 break;
3079 r.in.enum_index++;
3081 display_reg_value(r.out.value_name, *r.out.type,
3082 data_blob_const(r.out.data, r.in.data_offered));
3084 } while (W_ERROR_IS_OK(r.out.result));
3086 done:
3087 if (is_valid_policy_hnd(&hnd)) {
3088 WERROR _result;
3089 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
3092 return result;
3095 /****************************************************************************
3096 ****************************************************************************/
3098 static WERROR cmd_spoolss_enum_data_ex( struct rpc_pipe_client *cli,
3099 TALLOC_CTX *mem_ctx, int argc,
3100 const char **argv)
3102 WERROR result;
3103 uint32_t i;
3104 const char *printername;
3105 struct policy_handle hnd;
3106 uint32_t count;
3107 struct spoolss_PrinterEnumValues *info;
3108 struct dcerpc_binding_handle *b = cli->binding_handle;
3110 if (argc != 3) {
3111 printf("Usage: %s printername <keyname>\n", argv[0]);
3112 return WERR_OK;
3115 /* Open printer handle */
3117 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3119 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3120 printername,
3121 SEC_FLAG_MAXIMUM_ALLOWED,
3122 &hnd);
3123 if (!W_ERROR_IS_OK(result)) {
3124 goto done;
3127 /* Enumerate subkeys */
3129 result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx,
3130 &hnd,
3131 argv[2],
3133 &count,
3134 &info);
3135 if (!W_ERROR_IS_OK(result)) {
3136 goto done;
3139 for (i=0; i < count; i++) {
3140 display_printer_data(info[i].value_name,
3141 info[i].type,
3142 info[i].data->data,
3143 info[i].data->length);
3146 done:
3147 if (is_valid_policy_hnd(&hnd)) {
3148 WERROR _result;
3149 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
3152 return result;
3155 /****************************************************************************
3156 ****************************************************************************/
3158 static WERROR cmd_spoolss_enum_printerkey(struct rpc_pipe_client *cli,
3159 TALLOC_CTX *mem_ctx, int argc,
3160 const char **argv)
3162 WERROR result;
3163 const char *printername;
3164 const char *keyname = NULL;
3165 struct policy_handle hnd;
3166 const char **key_buffer = NULL;
3167 int i;
3168 uint32_t offered = 0;
3169 struct dcerpc_binding_handle *b = cli->binding_handle;
3171 if (argc < 2 || argc > 4) {
3172 printf("Usage: %s printername [keyname] [offered]\n", argv[0]);
3173 return WERR_OK;
3176 if (argc >= 3) {
3177 keyname = argv[2];
3178 } else {
3179 keyname = "";
3182 if (argc == 4) {
3183 offered = atoi(argv[3]);
3186 /* Open printer handle */
3188 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3190 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3191 printername,
3192 SEC_FLAG_MAXIMUM_ALLOWED,
3193 &hnd);
3194 if (!W_ERROR_IS_OK(result)) {
3195 goto done;
3198 /* Enumerate subkeys */
3200 result = rpccli_spoolss_enumprinterkey(cli, mem_ctx,
3201 &hnd,
3202 keyname,
3203 &key_buffer,
3204 offered);
3206 if (!W_ERROR_IS_OK(result)) {
3207 goto done;
3210 for (i=0; key_buffer && key_buffer[i]; i++) {
3211 printf("%s\n", key_buffer[i]);
3214 done:
3216 if (is_valid_policy_hnd(&hnd)) {
3217 WERROR _result;
3218 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
3221 return result;
3224 /****************************************************************************
3225 ****************************************************************************/
3227 static WERROR cmd_spoolss_rffpcnex(struct rpc_pipe_client *cli,
3228 TALLOC_CTX *mem_ctx, int argc,
3229 const char **argv)
3231 const char *printername;
3232 const char *clientname;
3233 struct policy_handle hnd = { 0, };
3234 WERROR result;
3235 NTSTATUS status;
3236 struct spoolss_NotifyOption option;
3237 struct dcerpc_binding_handle *b = cli->binding_handle;
3239 if (argc != 2) {
3240 printf("Usage: %s printername\n", argv[0]);
3241 result = WERR_OK;
3242 goto done;
3245 /* Open printer */
3247 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3249 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3250 printername,
3251 SEC_FLAG_MAXIMUM_ALLOWED,
3252 &hnd);
3253 if (!W_ERROR_IS_OK(result)) {
3254 printf("Error opening %s\n", argv[1]);
3255 goto done;
3258 /* Create spool options */
3260 option.version = 2;
3261 option.count = 2;
3263 option.types = talloc_array(mem_ctx, struct spoolss_NotifyOptionType, 2);
3264 if (option.types == NULL) {
3265 result = WERR_NOMEM;
3266 goto done;
3269 option.types[0].type = PRINTER_NOTIFY_TYPE;
3270 option.types[0].count = 1;
3271 option.types[0].fields = talloc_array(mem_ctx, union spoolss_Field, 1);
3272 if (option.types[0].fields == NULL) {
3273 result = WERR_NOMEM;
3274 goto done;
3276 option.types[0].fields[0].field = PRINTER_NOTIFY_FIELD_SERVER_NAME;
3278 option.types[1].type = JOB_NOTIFY_TYPE;
3279 option.types[1].count = 1;
3280 option.types[1].fields = talloc_array(mem_ctx, union spoolss_Field, 1);
3281 if (option.types[1].fields == NULL) {
3282 result = WERR_NOMEM;
3283 goto done;
3285 option.types[1].fields[0].field = JOB_NOTIFY_FIELD_PRINTER_NAME;
3287 clientname = talloc_asprintf(mem_ctx, "\\\\%s", lp_netbios_name());
3288 if (!clientname) {
3289 result = WERR_NOMEM;
3290 goto done;
3293 /* Send rffpcnex */
3295 status = dcerpc_spoolss_RemoteFindFirstPrinterChangeNotifyEx(b, mem_ctx,
3296 &hnd,
3299 clientname,
3300 123,
3301 &option,
3302 &result);
3303 if (!NT_STATUS_IS_OK(status)) {
3304 result = ntstatus_to_werror(status);
3305 goto done;
3307 if (!W_ERROR_IS_OK(result)) {
3308 printf("Error rffpcnex %s\n", argv[1]);
3309 goto done;
3312 done:
3313 if (is_valid_policy_hnd(&hnd)) {
3314 WERROR _result;
3315 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result);
3318 return result;
3321 /****************************************************************************
3322 ****************************************************************************/
3324 static bool compare_printer( struct rpc_pipe_client *cli1, struct policy_handle *hnd1,
3325 struct rpc_pipe_client *cli2, struct policy_handle *hnd2 )
3327 union spoolss_PrinterInfo info1, info2;
3328 WERROR werror;
3329 TALLOC_CTX *mem_ctx = talloc_init("compare_printer");
3331 printf("Retrieving printer propertiesfor %s...", cli1->desthost);
3332 werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
3333 hnd1,
3336 &info1);
3337 if ( !W_ERROR_IS_OK(werror) ) {
3338 printf("failed (%s)\n", win_errstr(werror));
3339 talloc_destroy(mem_ctx);
3340 return false;
3342 printf("ok\n");
3344 printf("Retrieving printer properties for %s...", cli2->desthost);
3345 werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
3346 hnd2,
3349 &info2);
3350 if ( !W_ERROR_IS_OK(werror) ) {
3351 printf("failed (%s)\n", win_errstr(werror));
3352 talloc_destroy(mem_ctx);
3353 return false;
3355 printf("ok\n");
3357 talloc_destroy(mem_ctx);
3359 return true;
3362 /****************************************************************************
3363 ****************************************************************************/
3365 static bool compare_printer_secdesc( struct rpc_pipe_client *cli1, struct policy_handle *hnd1,
3366 struct rpc_pipe_client *cli2, struct policy_handle *hnd2 )
3368 union spoolss_PrinterInfo info1, info2;
3369 WERROR werror;
3370 TALLOC_CTX *mem_ctx = talloc_init("compare_printer_secdesc");
3371 struct security_descriptor *sd1, *sd2;
3372 bool result = true;
3375 printf("Retrieving printer security for %s...", cli1->desthost);
3376 werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
3377 hnd1,
3380 &info1);
3381 if ( !W_ERROR_IS_OK(werror) ) {
3382 printf("failed (%s)\n", win_errstr(werror));
3383 result = false;
3384 goto done;
3386 printf("ok\n");
3388 printf("Retrieving printer security for %s...", cli2->desthost);
3389 werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
3390 hnd2,
3393 &info2);
3394 if ( !W_ERROR_IS_OK(werror) ) {
3395 printf("failed (%s)\n", win_errstr(werror));
3396 result = false;
3397 goto done;
3399 printf("ok\n");
3402 printf("++ ");
3404 sd1 = info1.info3.secdesc;
3405 sd2 = info2.info3.secdesc;
3407 if ( (sd1 != sd2) && ( !sd1 || !sd2 ) ) {
3408 printf("NULL secdesc!\n");
3409 result = false;
3410 goto done;
3413 if (!security_descriptor_equal( sd1, sd2 ) ) {
3414 printf("Security Descriptors *not* equal!\n");
3415 result = false;
3416 goto done;
3419 printf("Security descriptors match\n");
3421 done:
3422 talloc_destroy(mem_ctx);
3423 return result;
3427 /****************************************************************************
3428 ****************************************************************************/
3430 extern struct user_auth_info *rpcclient_auth_info;
3432 static WERROR cmd_spoolss_printercmp(struct rpc_pipe_client *cli,
3433 TALLOC_CTX *mem_ctx, int argc,
3434 const char **argv)
3436 const char *printername;
3437 char *printername_path = NULL;
3438 struct cli_state *cli_server2 = NULL;
3439 struct rpc_pipe_client *cli2 = NULL;
3440 struct policy_handle hPrinter1, hPrinter2;
3441 NTSTATUS nt_status;
3442 WERROR werror;
3444 if ( argc != 3 ) {
3445 printf("Usage: %s <printer> <server>\n", argv[0]);
3446 return WERR_OK;
3449 printername = argv[1];
3451 /* first get the connection to the remote server */
3453 nt_status = cli_full_connection(&cli_server2, lp_netbios_name(), argv[2],
3454 NULL, 0,
3455 "IPC$", "IPC",
3456 get_cmdline_auth_info_username(rpcclient_auth_info),
3457 lp_workgroup(),
3458 get_cmdline_auth_info_password(rpcclient_auth_info),
3459 get_cmdline_auth_info_use_kerberos(rpcclient_auth_info) ? CLI_FULL_CONNECTION_USE_KERBEROS : 0,
3460 get_cmdline_auth_info_signing_state(rpcclient_auth_info));
3462 if ( !NT_STATUS_IS_OK(nt_status) )
3463 return WERR_GENERAL_FAILURE;
3465 nt_status = cli_rpc_pipe_open_noauth(cli_server2, &ndr_table_spoolss,
3466 &cli2);
3467 if (!NT_STATUS_IS_OK(nt_status)) {
3468 printf("failed to open spoolss pipe on server %s (%s)\n",
3469 argv[2], nt_errstr(nt_status));
3470 return WERR_GENERAL_FAILURE;
3473 /* now open up both printers */
3475 RPCCLIENT_PRINTERNAME(printername_path, cli, printername);
3477 printf("Opening %s...", printername_path);
3479 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3480 printername_path,
3481 PRINTER_ALL_ACCESS,
3482 &hPrinter1);
3483 if ( !W_ERROR_IS_OK(werror) ) {
3484 printf("failed (%s)\n", win_errstr(werror));
3485 goto done;
3487 printf("ok\n");
3489 RPCCLIENT_PRINTERNAME(printername_path, cli2, printername);
3491 printf("Opening %s...", printername_path);
3492 werror = rpccli_spoolss_openprinter_ex(cli2, mem_ctx,
3493 printername_path,
3494 PRINTER_ALL_ACCESS,
3495 &hPrinter2);
3496 if ( !W_ERROR_IS_OK(werror) ) {
3497 printf("failed (%s)\n", win_errstr(werror));
3498 goto done;
3500 printf("ok\n");
3502 compare_printer( cli, &hPrinter1, cli2, &hPrinter2 );
3503 compare_printer_secdesc( cli, &hPrinter1, cli2, &hPrinter2 );
3504 #if 0
3505 compare_printerdata( cli_server1, &hPrinter1, cli_server2, &hPrinter2 );
3506 #endif
3509 done:
3510 /* cleanup */
3512 printf("Closing printers...");
3514 WERROR _result;
3515 dcerpc_spoolss_ClosePrinter(cli->binding_handle, mem_ctx, &hPrinter1, &_result);
3516 dcerpc_spoolss_ClosePrinter(cli2->binding_handle, mem_ctx, &hPrinter2, &_result);
3518 printf("ok\n");
3520 /* close the second remote connection */
3522 cli_shutdown( cli_server2 );
3523 return WERR_OK;
3526 static void display_proc_info1(struct spoolss_PrintProcessorInfo1 *r)
3528 printf("print_processor_name: %s\n", r->print_processor_name);
3531 static WERROR cmd_spoolss_enum_procs(struct rpc_pipe_client *cli,
3532 TALLOC_CTX *mem_ctx, int argc,
3533 const char **argv)
3535 WERROR werror;
3536 const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
3537 uint32_t num_procs, level = 1, i;
3538 union spoolss_PrintProcessorInfo *procs;
3540 /* Parse the command arguments */
3542 if (argc < 1 || argc > 4) {
3543 printf ("Usage: %s [environment] [level]\n", argv[0]);
3544 return WERR_OK;
3547 if (argc >= 2) {
3548 environment = argv[1];
3551 if (argc == 3) {
3552 level = atoi(argv[2]);
3555 /* Enumerate Print Processors */
3557 werror = rpccli_spoolss_enumprintprocessors(cli, mem_ctx,
3558 cli->srv_name_slash,
3559 environment,
3560 level,
3562 &num_procs,
3563 &procs);
3564 if (!W_ERROR_IS_OK(werror))
3565 goto done;
3567 /* Display output */
3569 for (i = 0; i < num_procs; i++) {
3570 switch (level) {
3571 case 1:
3572 display_proc_info1(&procs[i].info1);
3573 break;
3577 done:
3578 return werror;
3581 static void display_proc_data_types_info1(struct spoolss_PrintProcDataTypesInfo1 *r)
3583 printf("name_array: %s\n", r->name_array);
3586 static WERROR cmd_spoolss_enum_proc_data_types(struct rpc_pipe_client *cli,
3587 TALLOC_CTX *mem_ctx, int argc,
3588 const char **argv)
3590 WERROR werror;
3591 const char *print_processor_name = "winprint";
3592 uint32_t num_procs, level = 1, i;
3593 union spoolss_PrintProcDataTypesInfo *procs;
3595 /* Parse the command arguments */
3597 if (argc < 1 || argc > 4) {
3598 printf ("Usage: %s [environment] [level]\n", argv[0]);
3599 return WERR_OK;
3602 if (argc >= 2) {
3603 print_processor_name = argv[1];
3606 if (argc == 3) {
3607 level = atoi(argv[2]);
3610 /* Enumerate Print Processor Data Types */
3612 werror = rpccli_spoolss_enumprintprocessordatatypes(cli, mem_ctx,
3613 cli->srv_name_slash,
3614 print_processor_name,
3615 level,
3617 &num_procs,
3618 &procs);
3619 if (!W_ERROR_IS_OK(werror))
3620 goto done;
3622 /* Display output */
3624 for (i = 0; i < num_procs; i++) {
3625 switch (level) {
3626 case 1:
3627 display_proc_data_types_info1(&procs[i].info1);
3628 break;
3632 done:
3633 return werror;
3636 static void display_monitor1(const struct spoolss_MonitorInfo1 *r)
3638 printf("monitor_name: %s\n", r->monitor_name);
3641 static void display_monitor2(const struct spoolss_MonitorInfo2 *r)
3643 printf("monitor_name: %s\n", r->monitor_name);
3644 printf("environment: %s\n", r->environment);
3645 printf("dll_name: %s\n", r->dll_name);
3648 static WERROR cmd_spoolss_enum_monitors(struct rpc_pipe_client *cli,
3649 TALLOC_CTX *mem_ctx, int argc,
3650 const char **argv)
3652 WERROR werror;
3653 uint32_t count, level = 1, i;
3654 union spoolss_MonitorInfo *info;
3656 /* Parse the command arguments */
3658 if (argc > 2) {
3659 printf("Usage: %s [level]\n", argv[0]);
3660 return WERR_OK;
3663 if (argc == 2) {
3664 level = atoi(argv[1]);
3667 /* Enumerate Print Monitors */
3669 werror = rpccli_spoolss_enummonitors(cli, mem_ctx,
3670 cli->srv_name_slash,
3671 level,
3673 &count,
3674 &info);
3675 if (!W_ERROR_IS_OK(werror)) {
3676 goto done;
3679 /* Display output */
3681 for (i = 0; i < count; i++) {
3682 switch (level) {
3683 case 1:
3684 display_monitor1(&info[i].info1);
3685 break;
3686 case 2:
3687 display_monitor2(&info[i].info2);
3688 break;
3692 done:
3693 return werror;
3696 static WERROR cmd_spoolss_create_printer_ic(struct rpc_pipe_client *cli,
3697 TALLOC_CTX *mem_ctx, int argc,
3698 const char **argv)
3700 WERROR result;
3701 NTSTATUS status;
3702 struct policy_handle handle, gdi_handle;
3703 const char *printername;
3704 struct spoolss_DevmodeContainer devmode_ctr;
3705 struct dcerpc_binding_handle *b = cli->binding_handle;
3707 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3709 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3710 printername,
3711 SEC_FLAG_MAXIMUM_ALLOWED,
3712 &handle);
3713 if (!W_ERROR_IS_OK(result)) {
3714 return result;
3717 ZERO_STRUCT(devmode_ctr);
3719 status = dcerpc_spoolss_CreatePrinterIC(b, mem_ctx,
3720 &handle,
3721 &gdi_handle,
3722 &devmode_ctr,
3723 &result);
3724 if (!NT_STATUS_IS_OK(status)) {
3725 result = ntstatus_to_werror(status);
3726 goto done;
3728 if (!W_ERROR_IS_OK(result)) {
3729 goto done;
3732 done:
3733 if (is_valid_policy_hnd(&gdi_handle)) {
3734 WERROR _result;
3735 dcerpc_spoolss_DeletePrinterIC(b, mem_ctx, &gdi_handle, &_result);
3737 if (is_valid_policy_hnd(&handle)) {
3738 WERROR _result;
3739 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result);
3742 return result;
3745 static WERROR cmd_spoolss_play_gdi_script_on_printer_ic(struct rpc_pipe_client *cli,
3746 TALLOC_CTX *mem_ctx, int argc,
3747 const char **argv)
3749 WERROR result;
3750 NTSTATUS status;
3751 struct policy_handle handle, gdi_handle;
3752 const char *printername;
3753 struct spoolss_DevmodeContainer devmode_ctr;
3754 struct dcerpc_binding_handle *b = cli->binding_handle;
3755 DATA_BLOB in,out;
3756 uint32_t count = 0;
3758 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
3760 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3761 printername,
3762 SEC_FLAG_MAXIMUM_ALLOWED,
3763 &handle);
3764 if (!W_ERROR_IS_OK(result)) {
3765 return result;
3768 ZERO_STRUCT(devmode_ctr);
3770 status = dcerpc_spoolss_CreatePrinterIC(b, mem_ctx,
3771 &handle,
3772 &gdi_handle,
3773 &devmode_ctr,
3774 &result);
3775 if (!NT_STATUS_IS_OK(status)) {
3776 result = ntstatus_to_werror(status);
3777 goto done;
3779 if (!W_ERROR_IS_OK(result)) {
3780 goto done;
3783 in = data_blob_string_const("");
3784 out = data_blob_talloc_zero(mem_ctx, 4);
3786 status = dcerpc_spoolss_PlayGDIScriptOnPrinterIC(b, mem_ctx,
3787 &gdi_handle,
3788 in.data,
3789 in.length,
3790 out.data,
3791 out.length,
3792 0, /* ul */
3793 &result);
3794 if (!NT_STATUS_IS_OK(status)) {
3795 result = ntstatus_to_werror(status);
3796 goto done;
3798 if (!W_ERROR_IS_OK(result)) {
3799 goto done;
3802 count = IVAL(out.data, 0);
3804 out = data_blob_talloc_zero(mem_ctx,
3805 count * sizeof(struct UNIVERSAL_FONT_ID) + 4);
3807 status = dcerpc_spoolss_PlayGDIScriptOnPrinterIC(b, mem_ctx,
3808 &gdi_handle,
3809 in.data,
3810 in.length,
3811 out.data,
3812 out.length,
3813 0, /* ul */
3814 &result);
3815 if (!NT_STATUS_IS_OK(status)) {
3816 result = ntstatus_to_werror(status);
3817 goto done;
3819 if (!W_ERROR_IS_OK(result)) {
3820 goto done;
3824 enum ndr_err_code ndr_err;
3825 struct UNIVERSAL_FONT_ID_ctr r;
3827 ndr_err = ndr_pull_struct_blob(&out, mem_ctx, &r,
3828 (ndr_pull_flags_fn_t)ndr_pull_UNIVERSAL_FONT_ID_ctr);
3829 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3830 NDR_PRINT_DEBUG(UNIVERSAL_FONT_ID_ctr, &r);
3834 done:
3835 if (is_valid_policy_hnd(&gdi_handle)) {
3836 WERROR _result;
3837 dcerpc_spoolss_DeletePrinterIC(b, mem_ctx, &gdi_handle, &_result);
3839 if (is_valid_policy_hnd(&handle)) {
3840 WERROR _result;
3841 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result);
3844 return result;
3847 /* List of commands exported by this module */
3848 struct cmd_set spoolss_commands[] = {
3850 { "SPOOLSS" },
3852 { "adddriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterdriver, &ndr_table_spoolss, NULL, "Add a print driver", "" },
3853 { "addprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterex, &ndr_table_spoolss, NULL, "Add a printer", "" },
3854 { "deldriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriver, &ndr_table_spoolss, NULL, "Delete a printer driver", "" },
3855 { "deldriverex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriverex, &ndr_table_spoolss, NULL, "Delete a printer driver with files", "" },
3856 { "enumdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data, &ndr_table_spoolss, NULL, "Enumerate printer data", "" },
3857 { "enumdataex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data_ex, &ndr_table_spoolss, NULL, "Enumerate printer data for a key", "" },
3858 { "enumkey", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printerkey, &ndr_table_spoolss, NULL, "Enumerate printer keys", "" },
3859 { "enumjobs", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_jobs, &ndr_table_spoolss, NULL, "Enumerate print jobs", "" },
3860 { "getjob", RPC_RTYPE_WERROR, NULL, cmd_spoolss_get_job, &ndr_table_spoolss, NULL, "Get print job", "" },
3861 { "setjob", RPC_RTYPE_WERROR, NULL, cmd_spoolss_set_job, &ndr_table_spoolss, NULL, "Set print job", "" },
3862 { "enumports", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_ports, &ndr_table_spoolss, NULL, "Enumerate printer ports", "" },
3863 { "enumdrivers", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_drivers, &ndr_table_spoolss, NULL, "Enumerate installed printer drivers", "" },
3864 { "enumprinters", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printers, &ndr_table_spoolss, NULL, "Enumerate printers", "" },
3865 { "getdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdata, &ndr_table_spoolss, NULL, "Get print driver data", "" },
3866 { "getdataex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdataex, &ndr_table_spoolss, NULL, "Get printer driver data with keyname", ""},
3867 { "getdriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriver, &ndr_table_spoolss, NULL, "Get print driver information", "" },
3868 { "getdriverdir", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriverdir, &ndr_table_spoolss, NULL, "Get print driver upload directory", "" },
3869 { "getprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinter, &ndr_table_spoolss, NULL, "Get printer info", "" },
3870 { "openprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer, &ndr_table_spoolss, NULL, "Open printer handle", "" },
3871 { "openprinter_ex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer_ex, &ndr_table_spoolss, NULL, "Open printer handle", "" },
3872 { "setdriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setdriver, &ndr_table_spoolss, NULL, "Set printer driver", "" },
3873 { "getprintprocdir", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprintprocdir, &ndr_table_spoolss, NULL, "Get print processor directory", "" },
3874 { "addform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addform, &ndr_table_spoolss, NULL, "Add form", "" },
3875 { "setform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setform, &ndr_table_spoolss, NULL, "Set form", "" },
3876 { "getform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getform, &ndr_table_spoolss, NULL, "Get form", "" },
3877 { "deleteform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform, &ndr_table_spoolss, NULL, "Delete form", "" },
3878 { "enumforms", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms, &ndr_table_spoolss, NULL, "Enumerate forms", "" },
3879 { "setprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter, &ndr_table_spoolss, NULL, "Set printer comment", "" },
3880 { "setprintername", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername, &ndr_table_spoolss, NULL, "Set printername", "" },
3881 { "setprinterdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata, &ndr_table_spoolss, NULL, "Set REG_SZ printer data", "" },
3882 { "rffpcnex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex, &ndr_table_spoolss, NULL, "Rffpcnex test", "" },
3883 { "printercmp", RPC_RTYPE_WERROR, NULL, cmd_spoolss_printercmp, &ndr_table_spoolss, NULL, "Printer comparison test", "" },
3884 { "enumprocs", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_procs, &ndr_table_spoolss, NULL, "Enumerate Print Processors", "" },
3885 { "enumprocdatatypes", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_proc_data_types, &ndr_table_spoolss, NULL, "Enumerate Print Processor Data Types", "" },
3886 { "enummonitors", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_monitors, &ndr_table_spoolss, NULL, "Enumerate Print Monitors", "" },
3887 { "createprinteric", RPC_RTYPE_WERROR, NULL, cmd_spoolss_create_printer_ic, &ndr_table_spoolss, NULL, "Create Printer IC", "" },
3888 { "playgdiscriptonprinteric", RPC_RTYPE_WERROR, NULL, cmd_spoolss_play_gdi_script_on_printer_ic, &ndr_table_spoolss, NULL, "Create Printer IC", "" },
3890 { NULL }