2 Unix SMB/CIFS implementation.
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/>.
26 #include "rpcclient.h"
27 #include "../librpc/gen_ndr/cli_spoolss.h"
28 #include "rpc_client/cli_spoolss.h"
29 #include "rpc_client/init_spoolss.h"
31 #include "registry/reg_objects.h"
32 #include "nt_printing.h"
34 #define RPCCLIENT_PRINTERNAME(_printername, _cli, _arg) \
36 _printername = talloc_asprintf_strupper_m(mem_ctx, "%s\\%s", \
37 _cli->srv_name_slash, _arg); \
38 W_ERROR_HAVE_NO_MEMORY(_printername); \
41 /* The version int is used by getdrivers. Note that
42 all architecture strings that support mutliple
43 versions must be grouped together since enumdrivers
44 uses this property to prevent issuing multiple
45 enumdriver calls for the same arch */
48 static const struct print_architecture_table_node archi_table
[]= {
50 {"Windows 4.0", "WIN40", 0 },
51 {"Windows NT x86", "W32X86", 2 },
52 {"Windows NT x86", "W32X86", 3 },
53 {"Windows NT R4000", "W32MIPS", 2 },
54 {"Windows NT Alpha_AXP", "W32ALPHA", 2 },
55 {"Windows NT PowerPC", "W32PPC", 2 },
56 {"Windows IA64", "IA64", 3 },
57 {"Windows x64", "x64", 3 },
64 * rpcclient module for SPOOLSS rpc pipe.
66 * This generally just parses and checks command lines, and then calls
67 * a cli_spoolss function.
70 /****************************************************************************
71 function to do the mapping between the long architecture name and
73 ****************************************************************************/
75 static const char *cmd_spoolss_get_short_archi(const char *long_archi
)
79 DEBUG(107,("Getting architecture dependant directory\n"));
82 } while ( (archi_table
[i
].long_archi
!=NULL
) &&
83 StrCaseCmp(long_archi
, archi_table
[i
].long_archi
) );
85 if (archi_table
[i
].long_archi
==NULL
) {
86 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi
));
90 /* this might be client code - but shouldn't this be an fstrcpy etc? */
93 DEBUGADD(108,("index: [%d]\n", i
));
94 DEBUGADD(108,("long architecture: [%s]\n", archi_table
[i
].long_archi
));
95 DEBUGADD(108,("short architecture: [%s]\n", archi_table
[i
].short_archi
));
97 return archi_table
[i
].short_archi
;
100 /****************************************************************************
101 ****************************************************************************/
103 static WERROR
cmd_spoolss_open_printer_ex(struct rpc_pipe_client
*cli
,
105 int argc
, const char **argv
)
108 struct policy_handle hnd
;
109 uint32_t access_mask
= PRINTER_ALL_ACCESS
;
112 printf("Usage: %s <printername> [access_mask]\n", argv
[0]);
117 sscanf(argv
[2], "%x", &access_mask
);
120 /* Open the printer handle */
122 werror
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
126 if (W_ERROR_IS_OK(werror
)) {
127 printf("Printer %s opened successfully\n", argv
[1]);
128 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &hnd
, &werror
);
130 if (!W_ERROR_IS_OK(werror
)) {
131 printf("Error closing printer handle! (%s)\n",
132 get_dos_error_msg(werror
));
140 /****************************************************************************
141 ****************************************************************************/
143 static void display_print_info0(struct spoolss_PrinterInfo0
*r
)
148 printf("\tprintername:[%s]\n", r
->printername
);
149 printf("\tservername:[%s]\n", r
->servername
);
150 printf("\tcjobs:[0x%x]\n", r
->cjobs
);
151 printf("\ttotal_jobs:[0x%x]\n", r
->total_jobs
);
152 printf("\ttotal_bytes:[0x%x]\n", r
->total_bytes
);
153 printf("\t:date: [%d]-[%d]-[%d] (%d)\n", r
->time
.year
, r
->time
.month
,
154 r
->time
.day
, r
->time
.day_of_week
);
155 printf("\t:time: [%d]-[%d]-[%d]-[%d]\n", r
->time
.hour
, r
->time
.minute
,
156 r
->time
.second
, r
->time
.millisecond
);
158 printf("\tglobal_counter:[0x%x]\n", r
->global_counter
);
159 printf("\ttotal_pages:[0x%x]\n", r
->total_pages
);
161 printf("\tversion:[0x%x]\n", r
->version
);
162 printf("\tfree_build:[0x%x]\n", r
->free_build
);
163 printf("\tspooling:[0x%x]\n", r
->spooling
);
164 printf("\tmax_spooling:[0x%x]\n", r
->max_spooling
);
165 printf("\tsession_counter:[0x%x]\n", r
->session_counter
);
166 printf("\tnum_error_out_of_paper:[0x%x]\n", r
->num_error_out_of_paper
);
167 printf("\tnum_error_not_ready:[0x%x]\n", r
->num_error_not_ready
);
168 printf("\tjob_error:[0x%x]\n", r
->job_error
);
169 printf("\tnumber_of_processors:[0x%x]\n", r
->number_of_processors
);
170 printf("\tprocessor_type:[0x%x]\n", r
->processor_type
);
171 printf("\thigh_part_total_bytes:[0x%x]\n", r
->high_part_total_bytes
);
172 printf("\tchange_id:[0x%x]\n", r
->change_id
);
173 printf("\tlast_error: %s\n", win_errstr(r
->last_error
));
174 printf("\tstatus:[0x%x]\n", r
->status
);
175 printf("\tenumerate_network_printers:[0x%x]\n", r
->enumerate_network_printers
);
176 printf("\tc_setprinter:[0x%x]\n", r
->c_setprinter
);
177 printf("\tprocessor_architecture:[0x%x]\n", r
->processor_architecture
);
178 printf("\tprocessor_level:[0x%x]\n", r
->processor_level
);
179 printf("\tref_ic:[0x%x]\n", r
->ref_ic
);
180 printf("\treserved2:[0x%x]\n", r
->reserved2
);
181 printf("\treserved3:[0x%x]\n", r
->reserved3
);
186 /****************************************************************************
187 ****************************************************************************/
189 static void display_print_info1(struct spoolss_PrinterInfo1
*r
)
191 printf("\tflags:[0x%x]\n", r
->flags
);
192 printf("\tname:[%s]\n", r
->name
);
193 printf("\tdescription:[%s]\n", r
->description
);
194 printf("\tcomment:[%s]\n", r
->comment
);
199 /****************************************************************************
200 ****************************************************************************/
202 static void display_print_info2(struct spoolss_PrinterInfo2
*r
)
204 printf("\tservername:[%s]\n", r
->servername
);
205 printf("\tprintername:[%s]\n", r
->printername
);
206 printf("\tsharename:[%s]\n", r
->sharename
);
207 printf("\tportname:[%s]\n", r
->portname
);
208 printf("\tdrivername:[%s]\n", r
->drivername
);
209 printf("\tcomment:[%s]\n", r
->comment
);
210 printf("\tlocation:[%s]\n", r
->location
);
211 printf("\tsepfile:[%s]\n", r
->sepfile
);
212 printf("\tprintprocessor:[%s]\n", r
->printprocessor
);
213 printf("\tdatatype:[%s]\n", r
->datatype
);
214 printf("\tparameters:[%s]\n", r
->parameters
);
215 printf("\tattributes:[0x%x]\n", r
->attributes
);
216 printf("\tpriority:[0x%x]\n", r
->priority
);
217 printf("\tdefaultpriority:[0x%x]\n", r
->defaultpriority
);
218 printf("\tstarttime:[0x%x]\n", r
->starttime
);
219 printf("\tuntiltime:[0x%x]\n", r
->untiltime
);
220 printf("\tstatus:[0x%x]\n", r
->status
);
221 printf("\tcjobs:[0x%x]\n", r
->cjobs
);
222 printf("\taverageppm:[0x%x]\n", r
->averageppm
);
225 display_sec_desc(r
->secdesc
);
230 /****************************************************************************
231 ****************************************************************************/
233 static void display_print_info3(struct spoolss_PrinterInfo3
*r
)
235 display_sec_desc(r
->secdesc
);
240 /****************************************************************************
241 ****************************************************************************/
243 static void display_print_info4(struct spoolss_PrinterInfo4
*r
)
245 printf("\tservername:[%s]\n", r
->servername
);
246 printf("\tprintername:[%s]\n", r
->printername
);
247 printf("\tattributes:[0x%x]\n", r
->attributes
);
251 /****************************************************************************
252 ****************************************************************************/
254 static void display_print_info5(struct spoolss_PrinterInfo5
*r
)
256 printf("\tprintername:[%s]\n", r
->printername
);
257 printf("\tportname:[%s]\n", r
->portname
);
258 printf("\tattributes:[0x%x]\n", r
->attributes
);
259 printf("\tdevice_not_selected_timeout:[0x%x]\n", r
->device_not_selected_timeout
);
260 printf("\ttransmission_retry_timeout:[0x%x]\n", r
->transmission_retry_timeout
);
264 /****************************************************************************
265 ****************************************************************************/
267 static void display_print_info6(struct spoolss_PrinterInfo6
*r
)
269 printf("\tstatus:[0x%x]\n", r
->status
);
273 /****************************************************************************
274 ****************************************************************************/
276 static void display_print_info7(struct spoolss_PrinterInfo7
*r
)
278 printf("\tguid:[%s]\n", r
->guid
);
279 printf("\taction:[0x%x]\n", r
->action
);
283 /****************************************************************************
284 ****************************************************************************/
286 static WERROR
cmd_spoolss_enum_printers(struct rpc_pipe_client
*cli
,
288 int argc
, const char **argv
)
292 union spoolss_PrinterInfo
*info
;
295 uint32_t flags
= PRINTER_ENUM_LOCAL
;
298 printf("Usage: %s [level] [name] [flags]\n", argv
[0]);
303 level
= atoi(argv
[1]);
309 name
= cli
->srv_name_slash
;
313 flags
= atoi(argv
[3]);
316 result
= rpccli_spoolss_enumprinters(cli
, mem_ctx
,
323 if (W_ERROR_IS_OK(result
)) {
326 printf ("No printers returned.\n");
330 for (i
= 0; i
< count
; i
++) {
333 display_print_info0(&info
[i
].info0
);
336 display_print_info1(&info
[i
].info1
);
339 display_print_info2(&info
[i
].info2
);
342 display_print_info3(&info
[i
].info3
);
345 display_print_info4(&info
[i
].info4
);
348 display_print_info5(&info
[i
].info5
);
351 display_print_info6(&info
[i
].info6
);
354 printf("unknown info level %d\n", level
);
364 /****************************************************************************
365 ****************************************************************************/
367 static void display_port_info_1(struct spoolss_PortInfo1
*r
)
369 printf("\tPort Name:\t[%s]\n", r
->port_name
);
372 /****************************************************************************
373 ****************************************************************************/
375 static void display_port_info_2(struct spoolss_PortInfo2
*r
)
377 printf("\tPort Name:\t[%s]\n", r
->port_name
);
378 printf("\tMonitor Name:\t[%s]\n", r
->monitor_name
);
379 printf("\tDescription:\t[%s]\n", r
->description
);
380 printf("\tPort Type:\t" );
382 int comma
= 0; /* hack */
384 if (r
->port_type
& SPOOLSS_PORT_TYPE_READ
) {
388 if (r
->port_type
& SPOOLSS_PORT_TYPE_WRITE
) {
389 printf( "%sWrite", comma
? ", " : "" );
392 /* These two have slightly different interpretations
393 on 95/98/ME but I'm disregarding that for now */
394 if (r
->port_type
& SPOOLSS_PORT_TYPE_REDIRECTED
) {
395 printf( "%sRedirected", comma
? ", " : "" );
398 if (r
->port_type
& SPOOLSS_PORT_TYPE_NET_ATTACHED
) {
399 printf( "%sNet-Attached", comma
? ", " : "" );
403 printf( "[Unset]\n" );
405 printf("\tReserved:\t[%d]\n", r
->reserved
);
409 /****************************************************************************
410 ****************************************************************************/
412 static WERROR
cmd_spoolss_enum_ports(struct rpc_pipe_client
*cli
,
413 TALLOC_CTX
*mem_ctx
, int argc
,
419 union spoolss_PortInfo
*info
;
422 printf("Usage: %s [level]\n", argv
[0]);
427 level
= atoi(argv
[1]);
430 /* Enumerate ports */
432 result
= rpccli_spoolss_enumports(cli
, mem_ctx
,
438 if (W_ERROR_IS_OK(result
)) {
441 for (i
= 0; i
< count
; i
++) {
444 display_port_info_1(&info
[i
].info1
);
447 display_port_info_2(&info
[i
].info2
);
450 printf("unknown info level %d\n", level
);
459 /****************************************************************************
460 ****************************************************************************/
462 static WERROR
cmd_spoolss_setprinter(struct rpc_pipe_client
*cli
,
464 int argc
, const char **argv
)
466 struct policy_handle pol
;
469 uint32_t info_level
= 2;
470 union spoolss_PrinterInfo info
;
471 struct spoolss_SetPrinterInfoCtr info_ctr
;
472 struct spoolss_SetPrinterInfo2 info2
;
473 const char *printername
, *comment
= NULL
;
474 struct spoolss_DevmodeContainer devmode_ctr
;
475 struct sec_desc_buf secdesc_ctr
;
477 if (argc
== 1 || argc
> 3) {
478 printf("Usage: %s printername comment\n", argv
[0]);
483 /* Open a printer handle */
488 ZERO_STRUCT(devmode_ctr
);
489 ZERO_STRUCT(secdesc_ctr
);
491 RPCCLIENT_PRINTERNAME(printername
, cli
, argv
[1]);
493 /* get a printer handle */
494 result
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
498 if (!W_ERROR_IS_OK(result
))
501 /* Get printer info */
502 result
= rpccli_spoolss_getprinter(cli
, mem_ctx
,
507 if (!W_ERROR_IS_OK(result
))
511 /* Modify the comment. */
512 spoolss_printerinfo2_to_setprinterinfo2(&info
.info2
, &info2
);
513 info2
.comment
= comment
;
516 info_ctr
.info
.info2
= &info2
;
518 status
= rpccli_spoolss_SetPrinter(cli
, mem_ctx
,
525 if (W_ERROR_IS_OK(result
))
526 printf("Success in setting comment.\n");
529 if (is_valid_policy_hnd(&pol
))
530 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &pol
, NULL
);
535 /****************************************************************************
536 ****************************************************************************/
538 static WERROR
cmd_spoolss_setprintername(struct rpc_pipe_client
*cli
,
540 int argc
, const char **argv
)
542 struct policy_handle pol
;
545 uint32_t info_level
= 2;
546 union spoolss_PrinterInfo info
;
547 const char *printername
,
548 *new_printername
= NULL
;
549 struct spoolss_SetPrinterInfoCtr info_ctr
;
550 struct spoolss_SetPrinterInfo2 info2
;
551 struct spoolss_DevmodeContainer devmode_ctr
;
552 struct sec_desc_buf secdesc_ctr
;
554 ZERO_STRUCT(devmode_ctr
);
555 ZERO_STRUCT(secdesc_ctr
);
557 if (argc
== 1 || argc
> 3) {
558 printf("Usage: %s printername new_printername\n", argv
[0]);
563 /* Open a printer handle */
565 new_printername
= argv
[2];
568 RPCCLIENT_PRINTERNAME(printername
, cli
, argv
[1]);
570 /* get a printer handle */
571 result
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
575 if (!W_ERROR_IS_OK(result
))
578 /* Get printer info */
579 result
= rpccli_spoolss_getprinter(cli
, mem_ctx
,
584 if (!W_ERROR_IS_OK(result
))
587 /* Modify the printername. */
588 spoolss_printerinfo2_to_setprinterinfo2(&info
.info2
, &info2
);
589 info2
.printername
= new_printername
;
592 info_ctr
.info
.info2
= &info2
;
594 status
= rpccli_spoolss_SetPrinter(cli
, mem_ctx
,
601 if (W_ERROR_IS_OK(result
))
602 printf("Success in setting printername.\n");
605 if (is_valid_policy_hnd(&pol
))
606 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &pol
, NULL
);
611 /****************************************************************************
612 ****************************************************************************/
614 static WERROR
cmd_spoolss_getprinter(struct rpc_pipe_client
*cli
,
616 int argc
, const char **argv
)
618 struct policy_handle pol
;
621 const char *printername
;
622 union spoolss_PrinterInfo info
;
624 if (argc
== 1 || argc
> 3) {
625 printf("Usage: %s <printername> [level]\n", argv
[0]);
629 /* Open a printer handle */
631 level
= atoi(argv
[2]);
634 RPCCLIENT_PRINTERNAME(printername
, cli
, argv
[1]);
636 /* get a printer handle */
638 result
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
640 SEC_FLAG_MAXIMUM_ALLOWED
,
642 if (!W_ERROR_IS_OK(result
)) {
646 /* Get printer info */
648 result
= rpccli_spoolss_getprinter(cli
, mem_ctx
,
653 if (!W_ERROR_IS_OK(result
)) {
657 /* Display printer info */
660 display_print_info0(&info
.info0
);
663 display_print_info1(&info
.info1
);
666 display_print_info2(&info
.info2
);
669 display_print_info3(&info
.info3
);
672 display_print_info4(&info
.info4
);
675 display_print_info5(&info
.info5
);
678 display_print_info6(&info
.info6
);
681 display_print_info7(&info
.info7
);
684 printf("unknown info level %d\n", level
);
688 if (is_valid_policy_hnd(&pol
)) {
689 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &pol
, NULL
);
695 /****************************************************************************
696 ****************************************************************************/
698 static void display_reg_value(struct regval_blob
*value
)
700 const char *text
= NULL
;
703 switch(regval_type(value
)) {
705 printf("%s: REG_DWORD: 0x%08x\n", regval_name(value
),
706 *((uint32_t *) regval_data_p(value
)));
709 blob
= data_blob_const(regval_data_p(value
), regval_size(value
));
710 pull_reg_sz(talloc_tos(), &blob
, &text
);
711 printf("%s: REG_SZ: %s\n", regval_name(value
), text
? text
: "");
714 char *hex
= hex_encode_talloc(NULL
, regval_data_p(value
), regval_size(value
));
716 printf("%s: REG_BINARY:", regval_name(value
));
718 for (i
=0; i
<len
; i
++) {
719 if (hex
[i
] == '\0') {
734 blob
= data_blob_const(regval_data_p(value
), regval_size(value
));
736 if (!pull_reg_multi_sz(NULL
, &blob
, &values
)) {
737 d_printf("pull_reg_multi_sz failed\n");
741 printf("%s: REG_MULTI_SZ: \n", regval_name(value
));
742 for (i
=0; values
[i
] != NULL
; i
++) {
743 d_printf("%s\n", values
[i
]);
749 printf("%s: unknown type %d\n", regval_name(value
), regval_type(value
));
754 /****************************************************************************
755 ****************************************************************************/
757 static void display_printer_data(const char *v
,
758 enum winreg_Type type
,
763 union spoolss_PrinterData r
;
764 DATA_BLOB blob
= data_blob_const(data
, length
);
767 result
= pull_spoolss_PrinterData(talloc_tos(), &blob
, &r
, type
);
768 if (!W_ERROR_IS_OK(result
)) {
774 printf("%s: REG_DWORD: 0x%08x\n", v
, r
.value
);
777 printf("%s: REG_SZ: %s\n", v
, r
.string
);
780 char *hex
= hex_encode_talloc(NULL
,
781 r
.binary
.data
, r
.binary
.length
);
783 printf("%s: REG_BINARY:", v
);
785 for (i
=0; i
<len
; i
++) {
786 if (hex
[i
] == '\0') {
799 printf("%s: REG_MULTI_SZ: ", v
);
800 for (i
=0; r
.string_array
[i
] != NULL
; i
++) {
801 printf("%s ", r
.string_array
[i
]);
806 printf("%s: unknown type 0x%02x:\n", v
, type
);
811 /****************************************************************************
812 ****************************************************************************/
814 static WERROR
cmd_spoolss_getprinterdata(struct rpc_pipe_client
*cli
,
816 int argc
, const char **argv
)
818 struct policy_handle pol
;
821 const char *valuename
;
822 enum winreg_Type type
;
827 printf("Usage: %s <printername> <valuename>\n", argv
[0]);
828 printf("<printername> of . queries print server\n");
833 /* Open a printer handle */
835 if (strncmp(argv
[1], ".", sizeof(".")) == 0)
836 fstrcpy(printername
, cli
->srv_name_slash
);
838 slprintf(printername
, sizeof(printername
)-1, "%s\\%s",
839 cli
->srv_name_slash
, argv
[1]);
841 /* get a printer handle */
843 result
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
845 SEC_FLAG_MAXIMUM_ALLOWED
,
847 if (!W_ERROR_IS_OK(result
))
850 /* Get printer info */
852 result
= rpccli_spoolss_getprinterdata(cli
, mem_ctx
,
859 if (!W_ERROR_IS_OK(result
))
862 /* Display printer data */
864 display_printer_data(valuename
, type
, data
, needed
);
867 if (is_valid_policy_hnd(&pol
))
868 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &pol
, NULL
);
873 /****************************************************************************
874 ****************************************************************************/
876 static WERROR
cmd_spoolss_getprinterdataex(struct rpc_pipe_client
*cli
,
878 int argc
, const char **argv
)
880 struct policy_handle pol
;
884 const char *valuename
, *keyname
;
886 enum winreg_Type type
;
887 uint8_t *data
= NULL
;
888 uint32_t offered
= 0;
892 printf("Usage: %s <printername> <keyname> <valuename>\n",
894 printf("<printername> of . queries print server\n");
900 /* Open a printer handle */
902 if (strncmp(argv
[1], ".", sizeof(".")) == 0)
903 fstrcpy(printername
, cli
->srv_name_slash
);
905 slprintf(printername
, sizeof(printername
)-1, "%s\\%s",
906 cli
->srv_name_slash
, argv
[1]);
908 /* get a printer handle */
910 result
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
912 SEC_FLAG_MAXIMUM_ALLOWED
,
914 if (!W_ERROR_IS_OK(result
))
917 /* Get printer info */
919 data
= talloc_zero_array(mem_ctx
, uint8_t, offered
);
924 status
= rpccli_spoolss_GetPrinterDataEx(cli
, mem_ctx
,
933 if (W_ERROR_EQUAL(result
, WERR_MORE_DATA
)) {
935 data
= talloc_zero_array(mem_ctx
, uint8_t, offered
);
939 status
= rpccli_spoolss_GetPrinterDataEx(cli
, mem_ctx
,
950 if (!NT_STATUS_IS_OK(status
)) {
954 if (!W_ERROR_IS_OK(result
))
957 /* Display printer data */
959 display_printer_data(valuename
, type
, data
, needed
);
963 if (is_valid_policy_hnd(&pol
))
964 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &pol
, NULL
);
969 /****************************************************************************
970 ****************************************************************************/
972 static void display_print_driver1(struct spoolss_DriverInfo1
*r
)
978 printf("Printer Driver Info 1:\n");
979 printf("\tDriver Name: [%s]\n", r
->driver_name
);
983 /****************************************************************************
984 ****************************************************************************/
986 static void display_print_driver2(struct spoolss_DriverInfo2
*r
)
992 printf("Printer Driver Info 2:\n");
993 printf("\tVersion: [%x]\n", r
->version
);
994 printf("\tDriver Name: [%s]\n", r
->driver_name
);
995 printf("\tArchitecture: [%s]\n", r
->architecture
);
996 printf("\tDriver Path: [%s]\n", r
->driver_path
);
997 printf("\tDatafile: [%s]\n", r
->data_file
);
998 printf("\tConfigfile: [%s]\n", r
->config_file
);
1002 /****************************************************************************
1003 ****************************************************************************/
1005 static void display_print_driver3(struct spoolss_DriverInfo3
*r
)
1013 printf("Printer Driver Info 3:\n");
1014 printf("\tVersion: [%x]\n", r
->version
);
1015 printf("\tDriver Name: [%s]\n", r
->driver_name
);
1016 printf("\tArchitecture: [%s]\n", r
->architecture
);
1017 printf("\tDriver Path: [%s]\n", r
->driver_path
);
1018 printf("\tDatafile: [%s]\n", r
->data_file
);
1019 printf("\tConfigfile: [%s]\n", r
->config_file
);
1020 printf("\tHelpfile: [%s]\n", r
->help_file
);
1022 for (i
=0; r
->dependent_files
&& r
->dependent_files
[i
] != NULL
; i
++) {
1023 printf("\tDependentfiles: [%s]\n", r
->dependent_files
[i
]);
1026 printf("\tMonitorname: [%s]\n", r
->monitor_name
);
1027 printf("\tDefaultdatatype: [%s]\n", r
->default_datatype
);
1031 /****************************************************************************
1032 ****************************************************************************/
1034 static void display_print_driver4(struct spoolss_DriverInfo4
*r
)
1042 printf("Printer Driver Info 4:\n");
1043 printf("\tVersion: [%x]\n", r
->version
);
1044 printf("\tDriver Name: [%s]\n", r
->driver_name
);
1045 printf("\tArchitecture: [%s]\n", r
->architecture
);
1046 printf("\tDriver Path: [%s]\n", r
->driver_path
);
1047 printf("\tDatafile: [%s]\n", r
->data_file
);
1048 printf("\tConfigfile: [%s]\n", r
->config_file
);
1049 printf("\tHelpfile: [%s]\n", r
->help_file
);
1051 for (i
=0; r
->dependent_files
&& r
->dependent_files
[i
] != NULL
; i
++) {
1052 printf("\tDependentfiles: [%s]\n", r
->dependent_files
[i
]);
1055 printf("\tMonitorname: [%s]\n", r
->monitor_name
);
1056 printf("\tDefaultdatatype: [%s]\n", r
->default_datatype
);
1058 for (i
=0; r
->previous_names
&& r
->previous_names
[i
] != NULL
; i
++) {
1059 printf("\tPrevious Names: [%s]\n", r
->previous_names
[i
]);
1064 /****************************************************************************
1065 ****************************************************************************/
1067 static void display_print_driver5(struct spoolss_DriverInfo5
*r
)
1073 printf("Printer Driver Info 5:\n");
1074 printf("\tVersion: [%x]\n", r
->version
);
1075 printf("\tDriver Name: [%s]\n", r
->driver_name
);
1076 printf("\tArchitecture: [%s]\n", r
->architecture
);
1077 printf("\tDriver Path: [%s]\n", r
->driver_path
);
1078 printf("\tDatafile: [%s]\n", r
->data_file
);
1079 printf("\tConfigfile: [%s]\n", r
->config_file
);
1080 printf("\tDriver Attributes: [0x%x]\n", r
->driver_attributes
);
1081 printf("\tConfig Version: [0x%x]\n", r
->config_version
);
1082 printf("\tDriver Version: [0x%x]\n", r
->driver_version
);
1086 /****************************************************************************
1087 ****************************************************************************/
1089 static void display_print_driver6(struct spoolss_DriverInfo6
*r
)
1097 printf("Printer Driver Info 6:\n");
1098 printf("\tVersion: [%x]\n", r
->version
);
1099 printf("\tDriver Name: [%s]\n", r
->driver_name
);
1100 printf("\tArchitecture: [%s]\n", r
->architecture
);
1101 printf("\tDriver Path: [%s]\n", r
->driver_path
);
1102 printf("\tDatafile: [%s]\n", r
->data_file
);
1103 printf("\tConfigfile: [%s]\n", r
->config_file
);
1104 printf("\tHelpfile: [%s]\n", r
->help_file
);
1106 for (i
=0; r
->dependent_files
&& r
->dependent_files
[i
] != NULL
; i
++) {
1107 printf("\tDependentfiles: [%s]\n", r
->dependent_files
[i
]);
1110 printf("\tMonitorname: [%s]\n", r
->monitor_name
);
1111 printf("\tDefaultdatatype: [%s]\n", r
->default_datatype
);
1113 for (i
=0; r
->previous_names
&& r
->previous_names
[i
] != NULL
; i
++) {
1114 printf("\tPrevious Names: [%s]\n", r
->previous_names
[i
]);
1117 printf("\tDriver Date: [%s]\n", nt_time_string(talloc_tos(), r
->driver_date
));
1118 printf("\tDriver Version: [0x%016llx]\n", (long long unsigned int)r
->driver_version
);
1119 printf("\tManufacturer Name: [%s]\n", r
->manufacturer_name
);
1120 printf("\tManufacturer Url: [%s]\n", r
->manufacturer_url
);
1121 printf("\tHardware ID: [%s]\n", r
->hardware_id
);
1122 printf("\tProvider: [%s]\n", r
->provider
);
1127 /****************************************************************************
1128 ****************************************************************************/
1130 static void display_print_driver8(struct spoolss_DriverInfo8
*r
)
1138 printf("Printer Driver Info 8:\n");
1139 printf("\tVersion: [%x]\n", r
->version
);
1140 printf("\tDriver Name: [%s]\n", r
->driver_name
);
1141 printf("\tArchitecture: [%s]\n", r
->architecture
);
1142 printf("\tDriver Path: [%s]\n", r
->driver_path
);
1143 printf("\tDatafile: [%s]\n", r
->data_file
);
1144 printf("\tConfigfile: [%s]\n", r
->config_file
);
1145 printf("\tHelpfile: [%s]\n", r
->help_file
);
1146 printf("\tMonitorname: [%s]\n", r
->monitor_name
);
1147 printf("\tDefaultdatatype: [%s]\n", r
->default_datatype
);
1149 for (i
=0; r
->dependent_files
&& r
->dependent_files
[i
] != NULL
; i
++) {
1150 printf("\tDependentfiles: [%s]\n", r
->dependent_files
[i
]);
1153 for (i
=0; r
->previous_names
&& r
->previous_names
[i
] != NULL
; i
++) {
1154 printf("\tPrevious Names: [%s]\n", r
->previous_names
[i
]);
1157 printf("\tDriver Date: [%s]\n", nt_time_string(talloc_tos(), r
->driver_date
));
1158 printf("\tDriver Version: [0x%016llx]\n", (long long unsigned int)r
->driver_version
);
1159 printf("\tManufacturer Name: [%s]\n", r
->manufacturer_name
);
1160 printf("\tManufacturer Url: [%s]\n", r
->manufacturer_url
);
1161 printf("\tHardware ID: [%s]\n", r
->hardware_id
);
1162 printf("\tProvider: [%s]\n", r
->provider
);
1163 printf("\tPrint Processor: [%s]\n", r
->print_processor
);
1164 printf("\tVendor Setup: [%s]\n", r
->vendor_setup
);
1165 for (i
=0; r
->color_profiles
&& r
->color_profiles
[i
] != NULL
; i
++) {
1166 printf("\tColor Profiles: [%s]\n", r
->color_profiles
[i
]);
1168 printf("\tInf Path: [%s]\n", r
->inf_path
);
1169 printf("\tPrinter Driver Attributes: [0x%x]\n", r
->printer_driver_attributes
);
1170 for (i
=0; r
->core_driver_dependencies
&& r
->core_driver_dependencies
[i
] != NULL
; i
++) {
1171 printf("\tCore Driver Dependencies: [%s]\n", r
->core_driver_dependencies
[i
]);
1173 printf("\tMin Driver Inbox Driver Version Date: [%s]\n", nt_time_string(talloc_tos(), r
->min_inbox_driver_ver_date
));
1174 printf("\tMin Driver Inbox Driver Version Version: [0x%016llx]\n",
1175 (long long unsigned int)r
->min_inbox_driver_ver_version
);
1180 /****************************************************************************
1181 ****************************************************************************/
1183 static WERROR
cmd_spoolss_getdriver(struct rpc_pipe_client
*cli
,
1184 TALLOC_CTX
*mem_ctx
,
1185 int argc
, const char **argv
)
1187 struct policy_handle pol
;
1190 const char *printername
;
1192 bool success
= false;
1193 union spoolss_DriverInfo info
;
1194 uint32_t server_major_version
;
1195 uint32_t server_minor_version
;
1197 if ((argc
== 1) || (argc
> 3)) {
1198 printf("Usage: %s <printername> [level]\n", argv
[0]);
1202 /* get the arguments need to open the printer handle */
1204 RPCCLIENT_PRINTERNAME(printername
, cli
, argv
[1]);
1207 level
= atoi(argv
[2]);
1210 /* Open a printer handle */
1212 werror
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
1216 if (!W_ERROR_IS_OK(werror
)) {
1217 printf("Error opening printer handle for %s!\n", printername
);
1221 /* loop through and print driver info level for each architecture */
1223 for (i
=0; archi_table
[i
].long_archi
!=NULL
; i
++) {
1225 werror
= rpccli_spoolss_getprinterdriver2(cli
, mem_ctx
,
1227 archi_table
[i
].long_archi
,
1230 archi_table
[i
].version
,
1233 &server_major_version
,
1234 &server_minor_version
);
1235 if (!W_ERROR_IS_OK(werror
)) {
1239 /* need at least one success */
1243 printf("\n[%s]\n", archi_table
[i
].long_archi
);
1247 display_print_driver1(&info
.info1
);
1250 display_print_driver2(&info
.info2
);
1253 display_print_driver3(&info
.info3
);
1256 display_print_driver4(&info
.info4
);
1259 display_print_driver5(&info
.info5
);
1262 display_print_driver6(&info
.info6
);
1265 display_print_driver8(&info
.info8
);
1268 printf("unknown info level %d\n", level
);
1275 if (is_valid_policy_hnd(&pol
)) {
1276 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &pol
, NULL
);
1286 /****************************************************************************
1287 ****************************************************************************/
1289 static WERROR
enum_driver_by_architecture(struct rpc_pipe_client
*cli
,
1290 TALLOC_CTX
*mem_ctx
,
1291 const char *architecture
,
1296 union spoolss_DriverInfo
*info
= NULL
;
1299 werror
= rpccli_spoolss_enumprinterdrivers(cli
, mem_ctx
,
1300 cli
->srv_name_slash
,
1307 if (W_ERROR_EQUAL(werror
, WERR_INVALID_ENVIRONMENT
)) {
1308 printf("Server does not support environment [%s]\n",
1317 if (!W_ERROR_IS_OK(werror
)) {
1318 printf("Error getting driver for environment [%s] - %s\n",
1319 architecture
, win_errstr(werror
));
1323 printf("\n[%s]\n", architecture
);
1327 for (j
=0; j
< count
; j
++) {
1328 display_print_driver1(&info
[j
].info1
);
1332 for (j
=0; j
< count
; j
++) {
1333 display_print_driver2(&info
[j
].info2
);
1337 for (j
=0; j
< count
; j
++) {
1338 display_print_driver3(&info
[j
].info3
);
1342 for (j
=0; j
< count
; j
++) {
1343 display_print_driver4(&info
[j
].info4
);
1347 for (j
=0; j
< count
; j
++) {
1348 display_print_driver5(&info
[j
].info5
);
1352 for (j
=0; j
< count
; j
++) {
1353 display_print_driver6(&info
[j
].info6
);
1357 for (j
=0; j
< count
; j
++) {
1358 display_print_driver8(&info
[j
].info8
);
1362 printf("unknown info level %d\n", level
);
1363 return WERR_UNKNOWN_LEVEL
;
1369 static WERROR
cmd_spoolss_enum_drivers(struct rpc_pipe_client
*cli
,
1370 TALLOC_CTX
*mem_ctx
,
1371 int argc
, const char **argv
)
1373 WERROR werror
= WERR_OK
;
1376 const char *architecture
= NULL
;
1379 printf("Usage: enumdrivers [level] [architecture]\n");
1384 level
= atoi(argv
[1]);
1388 architecture
= argv
[2];
1392 return enum_driver_by_architecture(cli
, mem_ctx
,
1397 /* loop through and print driver info level for each architecture */
1398 for (i
=0; archi_table
[i
].long_archi
!=NULL
; i
++) {
1399 /* check to see if we already asked for this architecture string */
1401 if (i
>0 && strequal(archi_table
[i
].long_archi
, archi_table
[i
-1].long_archi
)) {
1405 werror
= enum_driver_by_architecture(cli
, mem_ctx
,
1406 archi_table
[i
].long_archi
,
1408 if (!W_ERROR_IS_OK(werror
)) {
1416 /****************************************************************************
1417 ****************************************************************************/
1419 static void display_printdriverdir_1(struct spoolss_DriverDirectoryInfo1
*r
)
1421 printf("\tDirectory Name:[%s]\n", r
->directory_name
);
1424 /****************************************************************************
1425 ****************************************************************************/
1427 static WERROR
cmd_spoolss_getdriverdir(struct rpc_pipe_client
*cli
,
1428 TALLOC_CTX
*mem_ctx
,
1429 int argc
, const char **argv
)
1433 const char *env
= SPOOLSS_ARCHITECTURE_NT_X86
;
1436 union spoolss_DriverDirectoryInfo info
;
1440 printf("Usage: %s [environment]\n", argv
[0]);
1444 /* Get the arguments need to open the printer handle */
1450 /* Get the directory. Only use Info level 1 */
1452 status
= rpccli_spoolss_GetPrinterDriverDirectory(cli
, mem_ctx
,
1453 cli
->srv_name_slash
,
1461 if (W_ERROR_EQUAL(result
, WERR_INSUFFICIENT_BUFFER
)) {
1463 buffer
= data_blob_talloc_zero(mem_ctx
, needed
);
1465 status
= rpccli_spoolss_GetPrinterDriverDirectory(cli
, mem_ctx
,
1466 cli
->srv_name_slash
,
1476 if (W_ERROR_IS_OK(result
)) {
1477 display_printdriverdir_1(&info
.info1
);
1483 /****************************************************************************
1484 ****************************************************************************/
1486 static void set_drv_info_3_env(TALLOC_CTX
*mem_ctx
,
1487 struct spoolss_AddDriverInfo3
*info
,
1493 for (i
=0; archi_table
[i
].long_archi
!= NULL
; i
++)
1495 if (strcmp(arch
, archi_table
[i
].short_archi
) == 0)
1497 info
->version
= archi_table
[i
].version
;
1498 info
->architecture
= talloc_strdup(mem_ctx
, archi_table
[i
].long_archi
);
1503 if (archi_table
[i
].long_archi
== NULL
)
1505 DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch
));
1512 /**************************************************************************
1513 wrapper for strtok to get the next parameter from a delimited list.
1514 Needed to handle the empty parameter string denoted by "NULL"
1515 *************************************************************************/
1517 static char *get_driver_3_param(TALLOC_CTX
*mem_ctx
, char *str
,
1518 const char *delim
, const char **dest
,
1523 /* get the next token */
1524 ptr
= strtok_r(str
, delim
, saveptr
);
1526 /* a string of 'NULL' is used to represent an empty
1527 parameter because two consecutive delimiters
1528 will not return an empty string. See man strtok(3)
1530 if (ptr
&& (StrCaseCmp(ptr
, "NULL") == 0)) {
1535 *dest
= talloc_strdup(mem_ctx
, ptr
);
1541 /********************************************************************************
1542 fill in the members of a spoolss_AddDriverInfo3 struct using a character
1543 string in the form of
1544 <Long Printer Name>:<Driver File Name>:<Data File Name>:\
1545 <Config File Name>:<Help File Name>:<Language Monitor Name>:\
1546 <Default Data Type>:<Comma Separated list of Files>
1547 *******************************************************************************/
1549 static bool init_drv_info_3_members(TALLOC_CTX
*mem_ctx
, struct spoolss_AddDriverInfo3
*r
,
1554 char *saveptr
= NULL
;
1555 struct spoolss_StringArray
*deps
;
1556 const char **file_array
= NULL
;
1559 /* fill in the UNISTR fields */
1560 str
= get_driver_3_param(mem_ctx
, args
, ":", &r
->driver_name
, &saveptr
);
1561 str
= get_driver_3_param(mem_ctx
, NULL
, ":", &r
->driver_path
, &saveptr
);
1562 str
= get_driver_3_param(mem_ctx
, NULL
, ":", &r
->data_file
, &saveptr
);
1563 str
= get_driver_3_param(mem_ctx
, NULL
, ":", &r
->config_file
, &saveptr
);
1564 str
= get_driver_3_param(mem_ctx
, NULL
, ":", &r
->help_file
, &saveptr
);
1565 str
= get_driver_3_param(mem_ctx
, NULL
, ":", &r
->monitor_name
, &saveptr
);
1566 str
= get_driver_3_param(mem_ctx
, NULL
, ":", &r
->default_datatype
, &saveptr
);
1568 /* <Comma Separated List of Dependent Files> */
1569 /* save the beginning of the string */
1570 str2
= get_driver_3_param(mem_ctx
, NULL
, ":", NULL
, &saveptr
);
1573 /* begin to strip out each filename */
1574 str
= strtok_r(str
, ",", &saveptr
);
1576 /* no dependent files, we are done */
1581 deps
= talloc_zero(mem_ctx
, struct spoolss_StringArray
);
1586 while (str
!= NULL
) {
1587 add_string_to_array(deps
, str
, &file_array
, &count
);
1588 str
= strtok_r(NULL
, ",", &saveptr
);
1591 deps
->string
= talloc_zero_array(deps
, const char *, count
+ 1);
1592 if (!deps
->string
) {
1596 for (i
=0; i
< count
; i
++) {
1597 deps
->string
[i
] = file_array
[i
];
1600 r
->dependent_files
= deps
;
1605 /****************************************************************************
1606 ****************************************************************************/
1608 static WERROR
cmd_spoolss_addprinterdriver(struct rpc_pipe_client
*cli
,
1609 TALLOC_CTX
*mem_ctx
,
1610 int argc
, const char **argv
)
1615 struct spoolss_AddDriverInfoCtr info_ctr
;
1616 struct spoolss_AddDriverInfo3 info3
;
1620 /* parse the command arguments */
1621 if (argc
!= 3 && argc
!= 4)
1623 printf ("Usage: %s <Environment> \\\n", argv
[0]);
1624 printf ("\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n");
1625 printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
1626 printf ("\t<Default Data Type>:<Comma Separated list of Files> \\\n");
1627 printf ("\t[version]\n");
1632 /* Fill in the spoolss_AddDriverInfo3 struct */
1635 arch
= cmd_spoolss_get_short_archi(argv
[1]);
1637 printf ("Error Unknown architechture [%s]\n", argv
[1]);
1638 return WERR_INVALID_PARAM
;
1641 set_drv_info_3_env(mem_ctx
, &info3
, arch
);
1643 driver_args
= talloc_strdup( mem_ctx
, argv
[2] );
1644 if (!init_drv_info_3_members(mem_ctx
, &info3
, driver_args
))
1646 printf ("Error Invalid parameter list - %s.\n", argv
[2]);
1647 return WERR_INVALID_PARAM
;
1650 /* if printer driver version specified, override the default version
1651 * used by the architecture. This allows installation of Windows
1652 * 2000 (version 3) printer drivers. */
1655 info3
.version
= atoi(argv
[3]);
1659 info_ctr
.level
= level
;
1660 info_ctr
.info
.info3
= &info3
;
1662 status
= rpccli_spoolss_AddPrinterDriver(cli
, mem_ctx
,
1663 cli
->srv_name_slash
,
1666 if (!NT_STATUS_IS_OK(status
)) {
1667 return ntstatus_to_werror(status
);
1669 if (W_ERROR_IS_OK(result
)) {
1670 printf ("Printer Driver %s successfully installed.\n",
1678 /****************************************************************************
1679 ****************************************************************************/
1681 static WERROR
cmd_spoolss_addprinterex(struct rpc_pipe_client
*cli
,
1682 TALLOC_CTX
*mem_ctx
,
1683 int argc
, const char **argv
)
1686 struct spoolss_SetPrinterInfoCtr info_ctr
;
1687 struct spoolss_SetPrinterInfo2 info2
;
1689 /* parse the command arguments */
1692 printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv
[0]);
1696 /* Fill in the DRIVER_INFO_2 struct */
1699 info2
.printername
= argv
[1];
1700 info2
.drivername
= argv
[3];
1701 info2
.sharename
= argv
[2];
1702 info2
.portname
= argv
[4];
1703 info2
.comment
= "Created by rpcclient";
1704 info2
.printprocessor
= "winprint";
1705 info2
.datatype
= "RAW";
1706 info2
.devmode_ptr
= 0;
1707 info2
.secdesc_ptr
= 0;
1708 info2
.attributes
= PRINTER_ATTRIBUTE_SHARED
;
1710 info2
.defaultpriority
= 0;
1711 info2
.starttime
= 0;
1712 info2
.untiltime
= 0;
1714 /* These three fields must not be used by AddPrinter()
1715 as defined in the MS Platform SDK documentation..
1719 info2.averageppm = 0;
1723 info_ctr
.info
.info2
= &info2
;
1725 result
= rpccli_spoolss_addprinterex(cli
, mem_ctx
,
1727 if (W_ERROR_IS_OK(result
))
1728 printf ("Printer %s successfully installed.\n", argv
[1]);
1733 /****************************************************************************
1734 ****************************************************************************/
1736 static WERROR
cmd_spoolss_setdriver(struct rpc_pipe_client
*cli
,
1737 TALLOC_CTX
*mem_ctx
,
1738 int argc
, const char **argv
)
1740 struct policy_handle pol
;
1744 const char *printername
;
1745 union spoolss_PrinterInfo info
;
1746 struct spoolss_SetPrinterInfoCtr info_ctr
;
1747 struct spoolss_SetPrinterInfo2 info2
;
1748 struct spoolss_DevmodeContainer devmode_ctr
;
1749 struct sec_desc_buf secdesc_ctr
;
1751 ZERO_STRUCT(devmode_ctr
);
1752 ZERO_STRUCT(secdesc_ctr
);
1754 /* parse the command arguments */
1757 printf ("Usage: %s <printer> <driver>\n", argv
[0]);
1761 RPCCLIENT_PRINTERNAME(printername
, cli
, argv
[1]);
1763 /* Get a printer handle */
1765 result
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
1769 if (!W_ERROR_IS_OK(result
))
1772 /* Get printer info */
1774 result
= rpccli_spoolss_getprinter(cli
, mem_ctx
,
1779 if (!W_ERROR_IS_OK(result
)) {
1780 printf ("Unable to retrieve printer information!\n");
1784 /* Set the printer driver */
1786 spoolss_printerinfo2_to_setprinterinfo2(&info
.info2
, &info2
);
1787 info2
.drivername
= argv
[2];
1790 info_ctr
.info
.info2
= &info2
;
1792 status
= rpccli_spoolss_SetPrinter(cli
, mem_ctx
,
1799 if (!W_ERROR_IS_OK(result
)) {
1800 printf("SetPrinter call failed!\n");
1804 printf("Successfully set %s to driver %s.\n", argv
[1], argv
[2]);
1809 if (is_valid_policy_hnd(&pol
))
1810 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &pol
, NULL
);
1816 /****************************************************************************
1817 ****************************************************************************/
1819 static WERROR
cmd_spoolss_deletedriverex(struct rpc_pipe_client
*cli
,
1820 TALLOC_CTX
*mem_ctx
,
1821 int argc
, const char **argv
)
1823 WERROR result
, ret
= WERR_UNKNOWN_PRINTER_DRIVER
;
1829 const char *arch
= NULL
;
1830 uint32_t delete_flags
= 0;
1832 /* parse the command arguments */
1833 if (argc
< 2 || argc
> 4) {
1834 printf ("Usage: %s <driver> [arch] [version]\n", argv
[0]);
1841 vers
= atoi (argv
[3]);
1844 delete_flags
|= DPD_DELETE_SPECIFIC_VERSION
;
1847 /* delete the driver for all architectures */
1848 for (i
=0; archi_table
[i
].long_archi
; i
++) {
1850 if (arch
&& !strequal( archi_table
[i
].long_archi
, arch
))
1853 if (vers
>= 0 && archi_table
[i
].version
!= vers
)
1856 /* make the call to remove the driver */
1857 status
= rpccli_spoolss_DeletePrinterDriverEx(cli
, mem_ctx
,
1858 cli
->srv_name_slash
,
1859 archi_table
[i
].long_archi
,
1862 archi_table
[i
].version
,
1865 if ( !W_ERROR_IS_OK(result
) )
1867 if ( !W_ERROR_EQUAL(result
, WERR_UNKNOWN_PRINTER_DRIVER
) ) {
1868 printf ("Failed to remove driver %s for arch [%s] (version: %d): %s\n",
1869 argv
[1], archi_table
[i
].long_archi
, archi_table
[i
].version
, win_errstr(result
));
1874 printf ("Driver %s and files removed for arch [%s] (version: %d).\n", argv
[1],
1875 archi_table
[i
].long_archi
, archi_table
[i
].version
);
1884 /****************************************************************************
1885 ****************************************************************************/
1887 static WERROR
cmd_spoolss_deletedriver(struct rpc_pipe_client
*cli
,
1888 TALLOC_CTX
*mem_ctx
,
1889 int argc
, const char **argv
)
1891 WERROR result
= WERR_OK
;
1895 /* parse the command arguments */
1897 printf ("Usage: %s <driver>\n", argv
[0]);
1901 /* delete the driver for all architectures */
1902 for (i
=0; archi_table
[i
].long_archi
; i
++) {
1903 /* make the call to remove the driver */
1904 status
= rpccli_spoolss_DeletePrinterDriver(cli
, mem_ctx
,
1905 cli
->srv_name_slash
,
1906 archi_table
[i
].long_archi
,
1909 if (!NT_STATUS_IS_OK(status
)) {
1912 if ( !W_ERROR_IS_OK(result
) ) {
1913 if ( !W_ERROR_EQUAL(result
, WERR_UNKNOWN_PRINTER_DRIVER
) ) {
1914 printf ("Failed to remove driver %s for arch [%s] - error 0x%x!\n",
1915 argv
[1], archi_table
[i
].long_archi
,
1919 printf ("Driver %s removed for arch [%s].\n", argv
[1],
1920 archi_table
[i
].long_archi
);
1927 /****************************************************************************
1928 ****************************************************************************/
1930 static WERROR
cmd_spoolss_getprintprocdir(struct rpc_pipe_client
*cli
,
1931 TALLOC_CTX
*mem_ctx
,
1932 int argc
, const char **argv
)
1936 const char *environment
= SPOOLSS_ARCHITECTURE_NT_X86
;
1939 union spoolss_PrintProcessorDirectoryInfo info
;
1942 /* parse the command arguments */
1944 printf ("Usage: %s [environment]\n", argv
[0]);
1949 environment
= argv
[1];
1952 status
= rpccli_spoolss_GetPrintProcessorDirectory(cli
, mem_ctx
,
1953 cli
->srv_name_slash
,
1961 if (W_ERROR_EQUAL(result
, WERR_INSUFFICIENT_BUFFER
)) {
1963 buffer
= data_blob_talloc_zero(mem_ctx
, needed
);
1965 status
= rpccli_spoolss_GetPrintProcessorDirectory(cli
, mem_ctx
,
1966 cli
->srv_name_slash
,
1976 if (W_ERROR_IS_OK(result
)) {
1977 printf("%s\n", info
.info1
.directory_name
);
1983 /****************************************************************************
1984 ****************************************************************************/
1986 static WERROR
cmd_spoolss_addform(struct rpc_pipe_client
*cli
, TALLOC_CTX
*mem_ctx
,
1987 int argc
, const char **argv
)
1989 struct policy_handle handle
;
1992 const char *printername
;
1993 union spoolss_AddFormInfo info
;
1994 struct spoolss_AddFormInfo1 info1
;
1995 struct spoolss_AddFormInfo2 info2
;
1998 /* Parse the command arguments */
2000 if (argc
< 3 || argc
> 5) {
2001 printf ("Usage: %s <printer> <formname> [level]\n", argv
[0]);
2005 /* Get a printer handle */
2007 RPCCLIENT_PRINTERNAME(printername
, cli
, argv
[1]);
2009 werror
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
2013 if (!W_ERROR_IS_OK(werror
))
2016 /* Dummy up some values for the form data */
2019 level
= atoi(argv
[3]);
2024 info1
.flags
= SPOOLSS_FORM_USER
;
2025 info1
.form_name
= argv
[2];
2026 info1
.size
.width
= 100;
2027 info1
.size
.height
= 100;
2028 info1
.area
.left
= 0;
2029 info1
.area
.top
= 10;
2030 info1
.area
.right
= 20;
2031 info1
.area
.bottom
= 30;
2033 info
.info1
= &info1
;
2037 info2
.flags
= SPOOLSS_FORM_USER
;
2038 info2
.form_name
= argv
[2];
2039 info2
.size
.width
= 100;
2040 info2
.size
.height
= 100;
2041 info2
.area
.left
= 0;
2042 info2
.area
.top
= 10;
2043 info2
.area
.right
= 20;
2044 info2
.area
.bottom
= 30;
2045 info2
.keyword
= argv
[2];
2046 info2
.string_type
= SPOOLSS_FORM_STRING_TYPE_NONE
;
2047 info2
.mui_dll
= NULL
;
2048 info2
.ressource_id
= 0;
2049 info2
.display_name
= argv
[2];
2052 info
.info2
= &info2
;
2060 status
= rpccli_spoolss_AddForm(cli
, mem_ctx
,
2067 if (is_valid_policy_hnd(&handle
))
2068 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &handle
, NULL
);
2073 /****************************************************************************
2074 ****************************************************************************/
2076 static WERROR
cmd_spoolss_setform(struct rpc_pipe_client
*cli
, TALLOC_CTX
*mem_ctx
,
2077 int argc
, const char **argv
)
2079 struct policy_handle handle
;
2082 const char *printername
;
2083 union spoolss_AddFormInfo info
;
2084 struct spoolss_AddFormInfo1 info1
;
2086 /* Parse the command arguments */
2089 printf ("Usage: %s <printer> <formname>\n", argv
[0]);
2093 /* Get a printer handle */
2095 RPCCLIENT_PRINTERNAME(printername
, cli
, argv
[1]);
2097 werror
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
2099 SEC_FLAG_MAXIMUM_ALLOWED
,
2101 if (!W_ERROR_IS_OK(werror
))
2104 /* Dummy up some values for the form data */
2106 info1
.flags
= SPOOLSS_FORM_PRINTER
;
2107 info1
.size
.width
= 100;
2108 info1
.size
.height
= 100;
2109 info1
.area
.left
= 0;
2110 info1
.area
.top
= 1000;
2111 info1
.area
.right
= 2000;
2112 info1
.area
.bottom
= 3000;
2113 info1
.form_name
= argv
[2];
2115 info
.info1
= &info1
;
2119 status
= rpccli_spoolss_SetForm(cli
, mem_ctx
,
2127 if (is_valid_policy_hnd(&handle
))
2128 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &handle
, NULL
);
2133 /****************************************************************************
2134 ****************************************************************************/
2136 static const char *get_form_flag(int form_flag
)
2138 switch (form_flag
) {
2139 case SPOOLSS_FORM_USER
:
2141 case SPOOLSS_FORM_BUILTIN
:
2142 return "FORM_BUILTIN";
2143 case SPOOLSS_FORM_PRINTER
:
2144 return "FORM_PRINTER";
2150 /****************************************************************************
2151 ****************************************************************************/
2153 static void display_form_info1(struct spoolss_FormInfo1
*r
)
2156 "\tflag: %s (%d)\n" \
2157 "\twidth: %d, length: %d\n" \
2158 "\tleft: %d, right: %d, top: %d, bottom: %d\n\n",
2159 r
->form_name
, get_form_flag(r
->flags
), r
->flags
,
2160 r
->size
.width
, r
->size
.height
,
2161 r
->area
.left
, r
->area
.right
,
2162 r
->area
.top
, r
->area
.bottom
);
2165 /****************************************************************************
2166 ****************************************************************************/
2168 static void display_form_info2(struct spoolss_FormInfo2
*r
)
2171 "\tflag: %s (%d)\n" \
2172 "\twidth: %d, length: %d\n" \
2173 "\tleft: %d, right: %d, top: %d, bottom: %d\n",
2174 r
->form_name
, get_form_flag(r
->flags
), r
->flags
,
2175 r
->size
.width
, r
->size
.height
,
2176 r
->area
.left
, r
->area
.right
,
2177 r
->area
.top
, r
->area
.bottom
);
2178 printf("\tkeyword: %s\n", r
->keyword
);
2179 printf("\tstring_type: 0x%08x\n", r
->string_type
);
2180 printf("\tmui_dll: %s\n", r
->mui_dll
);
2181 printf("\tressource_id: 0x%08x\n", r
->ressource_id
);
2182 printf("\tdisplay_name: %s\n", r
->display_name
);
2183 printf("\tlang_id: %d\n", r
->lang_id
);
2187 /****************************************************************************
2188 ****************************************************************************/
2190 static WERROR
cmd_spoolss_getform(struct rpc_pipe_client
*cli
, TALLOC_CTX
*mem_ctx
,
2191 int argc
, const char **argv
)
2193 struct policy_handle handle
;
2196 const char *printername
;
2198 uint32_t offered
= 0;
2199 union spoolss_FormInfo info
;
2203 /* Parse the command arguments */
2205 if (argc
< 3 || argc
> 5) {
2206 printf ("Usage: %s <printer> <formname> [level]\n", argv
[0]);
2210 /* Get a printer handle */
2212 RPCCLIENT_PRINTERNAME(printername
, cli
, argv
[1]);
2214 werror
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
2216 SEC_FLAG_MAXIMUM_ALLOWED
,
2218 if (!W_ERROR_IS_OK(werror
))
2222 level
= atoi(argv
[3]);
2227 status
= rpccli_spoolss_GetForm(cli
, mem_ctx
,
2236 if (W_ERROR_EQUAL(werror
, WERR_INSUFFICIENT_BUFFER
)) {
2237 buffer
= data_blob_talloc_zero(mem_ctx
, needed
);
2239 status
= rpccli_spoolss_GetForm(cli
, mem_ctx
,
2250 if (!NT_STATUS_IS_OK(status
)) {
2256 display_form_info1(&info
.info1
);
2259 display_form_info2(&info
.info2
);
2264 if (is_valid_policy_hnd(&handle
))
2265 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &handle
, NULL
);
2270 /****************************************************************************
2271 ****************************************************************************/
2273 static WERROR
cmd_spoolss_deleteform(struct rpc_pipe_client
*cli
,
2274 TALLOC_CTX
*mem_ctx
, int argc
,
2277 struct policy_handle handle
;
2280 const char *printername
;
2282 /* Parse the command arguments */
2285 printf ("Usage: %s <printer> <formname>\n", argv
[0]);
2289 /* Get a printer handle */
2291 RPCCLIENT_PRINTERNAME(printername
, cli
, argv
[1]);
2293 werror
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
2295 SEC_FLAG_MAXIMUM_ALLOWED
,
2297 if (!W_ERROR_IS_OK(werror
))
2300 /* Delete the form */
2302 status
= rpccli_spoolss_DeleteForm(cli
, mem_ctx
,
2306 if (!NT_STATUS_IS_OK(status
)) {
2307 return ntstatus_to_werror(status
);
2311 if (is_valid_policy_hnd(&handle
))
2312 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &handle
, NULL
);
2317 /****************************************************************************
2318 ****************************************************************************/
2320 static WERROR
cmd_spoolss_enum_forms(struct rpc_pipe_client
*cli
,
2321 TALLOC_CTX
*mem_ctx
, int argc
,
2324 struct policy_handle handle
;
2326 const char *printername
;
2327 uint32_t num_forms
, level
= 1, i
;
2328 union spoolss_FormInfo
*forms
;
2330 /* Parse the command arguments */
2332 if (argc
< 2 || argc
> 4) {
2333 printf ("Usage: %s <printer> [level]\n", argv
[0]);
2337 /* Get a printer handle */
2339 RPCCLIENT_PRINTERNAME(printername
, cli
, argv
[1]);
2341 werror
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
2343 SEC_FLAG_MAXIMUM_ALLOWED
,
2345 if (!W_ERROR_IS_OK(werror
))
2349 level
= atoi(argv
[2]);
2352 /* Enumerate forms */
2354 werror
= rpccli_spoolss_enumforms(cli
, mem_ctx
,
2361 if (!W_ERROR_IS_OK(werror
))
2364 /* Display output */
2366 for (i
= 0; i
< num_forms
; i
++) {
2369 display_form_info1(&forms
[i
].info1
);
2372 display_form_info2(&forms
[i
].info2
);
2378 if (is_valid_policy_hnd(&handle
))
2379 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &handle
, NULL
);
2384 /****************************************************************************
2385 ****************************************************************************/
2387 static WERROR
cmd_spoolss_setprinterdata(struct rpc_pipe_client
*cli
,
2388 TALLOC_CTX
*mem_ctx
,
2389 int argc
, const char **argv
)
2393 const char *printername
;
2394 struct policy_handle pol
;
2395 union spoolss_PrinterInfo info
;
2396 enum winreg_Type type
;
2397 union spoolss_PrinterData data
;
2400 /* parse the command arguments */
2402 printf ("Usage: %s <printer> <string|binary|dword|multistring>"
2403 " <value> <data>\n",
2408 RPCCLIENT_PRINTERNAME(printername
, cli
, argv
[1]);
2412 if (strequal(argv
[2], "string")) {
2416 if (strequal(argv
[2], "binary")) {
2420 if (strequal(argv
[2], "dword")) {
2424 if (strequal(argv
[2], "multistring")) {
2425 type
= REG_MULTI_SZ
;
2428 if (type
== REG_NONE
) {
2429 printf("Unknown data type: %s\n", argv
[2]);
2430 result
= WERR_INVALID_PARAM
;
2434 /* get a printer handle */
2436 result
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
2438 SEC_FLAG_MAXIMUM_ALLOWED
,
2440 if (!W_ERROR_IS_OK(result
)) {
2444 result
= rpccli_spoolss_getprinter(cli
, mem_ctx
,
2449 if (!W_ERROR_IS_OK(result
)) {
2453 printf("%s\n", current_timestring(mem_ctx
, true));
2454 printf("\tchange_id (before set)\t:[0x%x]\n", info
.info0
.change_id
);
2456 /* Set the printer data */
2460 data
.string
= talloc_strdup(mem_ctx
, argv
[4]);
2461 W_ERROR_HAVE_NO_MEMORY(data
.string
);
2464 data
.value
= strtoul(argv
[4], NULL
, 10);
2467 data
.binary
= strhex_to_data_blob(mem_ctx
, argv
[4]);
2469 case REG_MULTI_SZ
: {
2471 const char **strings
= NULL
;
2473 for (i
=4; i
<argc
; i
++) {
2474 if (strcmp(argv
[i
], "NULL") == 0) {
2477 if (!add_string_to_array(mem_ctx
, argv
[i
],
2480 result
= WERR_NOMEM
;
2484 data
.string_array
= talloc_zero_array(mem_ctx
, const char *, num_strings
+ 1);
2485 if (!data
.string_array
) {
2486 result
= WERR_NOMEM
;
2489 for (i
=0; i
< num_strings
; i
++) {
2490 data
.string_array
[i
] = strings
[i
];
2495 printf("Unknown data type: %s\n", argv
[2]);
2496 result
= WERR_INVALID_PARAM
;
2500 result
= push_spoolss_PrinterData(mem_ctx
, &blob
, type
, &data
);
2501 if (!W_ERROR_IS_OK(result
)) {
2505 status
= rpccli_spoolss_SetPrinterData(cli
, mem_ctx
,
2507 argv
[3], /* value_name */
2512 if (!W_ERROR_IS_OK(result
)) {
2513 printf ("Unable to set [%s=%s]!\n", argv
[3], argv
[4]);
2516 printf("\tSetPrinterData succeeded [%s: %s]\n", argv
[3], argv
[4]);
2518 result
= rpccli_spoolss_getprinter(cli
, mem_ctx
,
2523 if (!W_ERROR_IS_OK(result
)) {
2527 printf("%s\n", current_timestring(mem_ctx
, true));
2528 printf("\tchange_id (after set)\t:[0x%x]\n", info
.info0
.change_id
);
2532 if (is_valid_policy_hnd(&pol
)) {
2533 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &pol
, NULL
);
2539 /****************************************************************************
2540 ****************************************************************************/
2542 static void display_job_info1(struct spoolss_JobInfo1
*r
)
2544 printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", r
->position
, r
->job_id
,
2545 r
->user_name
, r
->document_name
, r
->text_status
, r
->pages_printed
,
2549 /****************************************************************************
2550 ****************************************************************************/
2552 static void display_job_info2(struct spoolss_JobInfo2
*r
)
2554 printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n",
2555 r
->position
, r
->job_id
,
2556 r
->user_name
, r
->document_name
, r
->text_status
, r
->pages_printed
,
2557 r
->total_pages
, r
->size
);
2560 /****************************************************************************
2561 ****************************************************************************/
2563 static void display_job_info3(struct spoolss_JobInfo3
*r
)
2565 printf("jobid[%d], next_jobid[%d]\n",
2566 r
->job_id
, r
->next_job_id
);
2569 /****************************************************************************
2570 ****************************************************************************/
2572 static void display_job_info4(struct spoolss_JobInfo4
*r
)
2574 printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d/%d bytes\n",
2575 r
->position
, r
->job_id
,
2576 r
->user_name
, r
->document_name
, r
->text_status
, r
->pages_printed
,
2577 r
->total_pages
, r
->size
, r
->size_high
);
2580 /****************************************************************************
2581 ****************************************************************************/
2583 static WERROR
cmd_spoolss_enum_jobs(struct rpc_pipe_client
*cli
,
2584 TALLOC_CTX
*mem_ctx
, int argc
,
2588 uint32_t level
= 1, count
, i
;
2589 const char *printername
;
2590 struct policy_handle hnd
;
2591 union spoolss_JobInfo
*info
;
2593 if (argc
< 2 || argc
> 3) {
2594 printf("Usage: %s printername [level]\n", argv
[0]);
2599 level
= atoi(argv
[2]);
2602 /* Open printer handle */
2604 RPCCLIENT_PRINTERNAME(printername
, cli
, argv
[1]);
2606 result
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
2608 SEC_FLAG_MAXIMUM_ALLOWED
,
2610 if (!W_ERROR_IS_OK(result
))
2613 /* Enumerate ports */
2615 result
= rpccli_spoolss_enumjobs(cli
, mem_ctx
,
2623 if (!W_ERROR_IS_OK(result
)) {
2627 for (i
= 0; i
< count
; i
++) {
2630 display_job_info1(&info
[i
].info1
);
2633 display_job_info2(&info
[i
].info2
);
2636 d_printf("unknown info level %d\n", level
);
2642 if (is_valid_policy_hnd(&hnd
)) {
2643 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &hnd
, NULL
);
2649 /****************************************************************************
2650 ****************************************************************************/
2652 static WERROR
cmd_spoolss_get_job(struct rpc_pipe_client
*cli
,
2653 TALLOC_CTX
*mem_ctx
, int argc
,
2657 const char *printername
;
2658 struct policy_handle hnd
;
2661 union spoolss_JobInfo info
;
2663 if (argc
< 3 || argc
> 4) {
2664 printf("Usage: %s printername job_id [level]\n", argv
[0]);
2668 job_id
= atoi(argv
[2]);
2671 level
= atoi(argv
[3]);
2674 /* Open printer handle */
2676 RPCCLIENT_PRINTERNAME(printername
, cli
, argv
[1]);
2678 result
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
2680 SEC_FLAG_MAXIMUM_ALLOWED
,
2682 if (!W_ERROR_IS_OK(result
)) {
2686 /* Enumerate ports */
2688 result
= rpccli_spoolss_getjob(cli
, mem_ctx
,
2695 if (!W_ERROR_IS_OK(result
)) {
2701 display_job_info1(&info
.info1
);
2704 display_job_info2(&info
.info2
);
2707 display_job_info3(&info
.info3
);
2710 display_job_info4(&info
.info4
);
2713 d_printf("unknown info level %d\n", level
);
2718 if (is_valid_policy_hnd(&hnd
)) {
2719 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &hnd
, NULL
);
2725 /****************************************************************************
2726 ****************************************************************************/
2730 enum spoolss_JobControl val
;
2732 {"PAUSE", SPOOLSS_JOB_CONTROL_PAUSE
},
2733 {"RESUME", SPOOLSS_JOB_CONTROL_RESUME
},
2734 {"CANCEL", SPOOLSS_JOB_CONTROL_CANCEL
},
2735 {"RESTART", SPOOLSS_JOB_CONTROL_RESTART
},
2736 {"DELETE", SPOOLSS_JOB_CONTROL_DELETE
},
2737 {"SEND_TO_PRINTER", SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER
},
2738 {"EJECTED", SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED
},
2739 {"RETAIN", SPOOLSS_JOB_CONTROL_RETAIN
},
2740 {"RELEASE", SPOOLSS_JOB_CONTROL_RELEASE
}
2743 static enum spoolss_JobControl
parse_setjob_command(const char *cmd
)
2747 for (i
= 0; i
< sizeof(cmdvals
)/sizeof(cmdvals
[0]); i
++) {
2748 if (strequal(cmdvals
[i
].name
, cmd
)) {
2749 return cmdvals
[i
].val
;
2752 return (enum spoolss_JobControl
)atoi(cmd
);
2755 static WERROR
cmd_spoolss_set_job(struct rpc_pipe_client
*cli
,
2756 TALLOC_CTX
*mem_ctx
, int argc
,
2761 const char *printername
;
2762 struct policy_handle hnd
;
2764 enum spoolss_JobControl command
;
2767 printf("Usage: %s printername job_id command\n", argv
[0]);
2768 printf("command = [PAUSE|RESUME|CANCEL|RESTART|DELETE|"
2769 "SEND_TO_PRINTER|EJECTED|RETAIN|RELEASE]\n");
2773 job_id
= atoi(argv
[2]);
2774 command
= parse_setjob_command(argv
[3]);
2776 /* Open printer handle */
2778 RPCCLIENT_PRINTERNAME(printername
, cli
, argv
[1]);
2780 result
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
2782 SEC_FLAG_MAXIMUM_ALLOWED
,
2784 if (!W_ERROR_IS_OK(result
)) {
2790 status
= rpccli_spoolss_SetJob(cli
, mem_ctx
,
2797 if (!W_ERROR_IS_OK(result
)) {
2802 if (is_valid_policy_hnd(&hnd
)) {
2803 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &hnd
, NULL
);
2809 /****************************************************************************
2810 ****************************************************************************/
2812 static WERROR
cmd_spoolss_enum_data(struct rpc_pipe_client
*cli
,
2813 TALLOC_CTX
*mem_ctx
, int argc
,
2819 const char *printername
;
2820 struct policy_handle hnd
;
2821 uint32_t value_offered
= 0;
2822 const char *value_name
= NULL
;
2823 uint32_t value_needed
;
2824 enum winreg_Type type
;
2825 uint8_t *data
= NULL
;
2826 uint32_t data_offered
= 0;
2827 uint32_t data_needed
;
2830 printf("Usage: %s printername\n", argv
[0]);
2834 /* Open printer handle */
2836 RPCCLIENT_PRINTERNAME(printername
, cli
, argv
[1]);
2838 result
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
2840 SEC_FLAG_MAXIMUM_ALLOWED
,
2842 if (!W_ERROR_IS_OK(result
)) {
2846 /* Enumerate data */
2848 status
= rpccli_spoolss_EnumPrinterData(cli
, mem_ctx
,
2860 data_offered
= data_needed
;
2861 value_offered
= value_needed
;
2862 data
= talloc_zero_array(mem_ctx
, uint8_t, data_needed
);
2863 value_name
= talloc_zero_array(mem_ctx
, char, value_needed
);
2865 while (NT_STATUS_IS_OK(status
) && W_ERROR_IS_OK(result
)) {
2867 status
= rpccli_spoolss_EnumPrinterData(cli
, mem_ctx
,
2878 if (NT_STATUS_IS_OK(status
) && W_ERROR_IS_OK(result
)) {
2879 struct regval_blob
*v
;
2881 v
= regval_compose(talloc_tos(),
2887 result
= WERR_NOMEM
;
2891 display_reg_value(v
);
2896 if (W_ERROR_V(result
) == ERRnomoreitems
) {
2897 result
= W_ERROR(ERRsuccess
);
2901 if (is_valid_policy_hnd(&hnd
)) {
2902 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &hnd
, NULL
);
2908 /****************************************************************************
2909 ****************************************************************************/
2911 static WERROR
cmd_spoolss_enum_data_ex( struct rpc_pipe_client
*cli
,
2912 TALLOC_CTX
*mem_ctx
, int argc
,
2917 const char *printername
;
2918 struct policy_handle hnd
;
2920 struct spoolss_PrinterEnumValues
*info
;
2923 printf("Usage: %s printername <keyname>\n", argv
[0]);
2927 /* Open printer handle */
2929 RPCCLIENT_PRINTERNAME(printername
, cli
, argv
[1]);
2931 result
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
2933 SEC_FLAG_MAXIMUM_ALLOWED
,
2935 if (!W_ERROR_IS_OK(result
)) {
2939 /* Enumerate subkeys */
2941 result
= rpccli_spoolss_enumprinterdataex(cli
, mem_ctx
,
2947 if (!W_ERROR_IS_OK(result
)) {
2951 for (i
=0; i
< count
; i
++) {
2952 display_printer_data(info
[i
].value_name
,
2955 info
[i
].data
->length
);
2959 if (is_valid_policy_hnd(&hnd
)) {
2960 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &hnd
, NULL
);
2966 /****************************************************************************
2967 ****************************************************************************/
2969 static WERROR
cmd_spoolss_enum_printerkey(struct rpc_pipe_client
*cli
,
2970 TALLOC_CTX
*mem_ctx
, int argc
,
2974 const char *printername
;
2975 const char *keyname
= NULL
;
2976 struct policy_handle hnd
;
2977 const char **key_buffer
= NULL
;
2979 uint32_t offered
= 0;
2981 if (argc
< 2 || argc
> 4) {
2982 printf("Usage: %s printername [keyname] [offered]\n", argv
[0]);
2993 offered
= atoi(argv
[3]);
2996 /* Open printer handle */
2998 RPCCLIENT_PRINTERNAME(printername
, cli
, argv
[1]);
3000 result
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
3002 SEC_FLAG_MAXIMUM_ALLOWED
,
3004 if (!W_ERROR_IS_OK(result
)) {
3008 /* Enumerate subkeys */
3010 result
= rpccli_spoolss_enumprinterkey(cli
, mem_ctx
,
3016 if (!W_ERROR_IS_OK(result
)) {
3020 for (i
=0; key_buffer
&& key_buffer
[i
]; i
++) {
3021 printf("%s\n", key_buffer
[i
]);
3026 if (is_valid_policy_hnd(&hnd
)) {
3027 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &hnd
, NULL
);
3033 /****************************************************************************
3034 ****************************************************************************/
3036 static WERROR
cmd_spoolss_rffpcnex(struct rpc_pipe_client
*cli
,
3037 TALLOC_CTX
*mem_ctx
, int argc
,
3040 const char *printername
;
3041 const char *clientname
;
3042 struct policy_handle hnd
;
3045 struct spoolss_NotifyOption option
;
3048 printf("Usage: %s printername\n", argv
[0]);
3055 RPCCLIENT_PRINTERNAME(printername
, cli
, argv
[1]);
3057 result
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
3059 SEC_FLAG_MAXIMUM_ALLOWED
,
3061 if (!W_ERROR_IS_OK(result
)) {
3062 printf("Error opening %s\n", argv
[1]);
3066 /* Create spool options */
3071 option
.types
= talloc_array(mem_ctx
, struct spoolss_NotifyOptionType
, 2);
3072 if (option
.types
== NULL
) {
3073 result
= WERR_NOMEM
;
3077 option
.types
[0].type
= PRINTER_NOTIFY_TYPE
;
3078 option
.types
[0].count
= 1;
3079 option
.types
[0].fields
= talloc_array(mem_ctx
, union spoolss_Field
, 1);
3080 if (option
.types
[0].fields
== NULL
) {
3081 result
= WERR_NOMEM
;
3084 option
.types
[0].fields
[0].field
= PRINTER_NOTIFY_FIELD_SERVER_NAME
;
3086 option
.types
[1].type
= JOB_NOTIFY_TYPE
;
3087 option
.types
[1].count
= 1;
3088 option
.types
[1].fields
= talloc_array(mem_ctx
, union spoolss_Field
, 1);
3089 if (option
.types
[1].fields
== NULL
) {
3090 result
= WERR_NOMEM
;
3093 option
.types
[1].fields
[0].field
= JOB_NOTIFY_FIELD_PRINTER_NAME
;
3095 clientname
= talloc_asprintf(mem_ctx
, "\\\\%s", global_myname());
3097 result
= WERR_NOMEM
;
3103 status
= rpccli_spoolss_RemoteFindFirstPrinterChangeNotifyEx(cli
, mem_ctx
,
3111 if (!W_ERROR_IS_OK(result
)) {
3112 printf("Error rffpcnex %s\n", argv
[1]);
3117 if (is_valid_policy_hnd(&hnd
))
3118 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &hnd
, NULL
);
3123 /****************************************************************************
3124 ****************************************************************************/
3126 static bool compare_printer( struct rpc_pipe_client
*cli1
, struct policy_handle
*hnd1
,
3127 struct rpc_pipe_client
*cli2
, struct policy_handle
*hnd2
)
3129 union spoolss_PrinterInfo info1
, info2
;
3131 TALLOC_CTX
*mem_ctx
= talloc_init("compare_printer");
3133 printf("Retrieving printer propertiesfor %s...", cli1
->desthost
);
3134 werror
= rpccli_spoolss_getprinter(cli1
, mem_ctx
,
3139 if ( !W_ERROR_IS_OK(werror
) ) {
3140 printf("failed (%s)\n", win_errstr(werror
));
3141 talloc_destroy(mem_ctx
);
3146 printf("Retrieving printer properties for %s...", cli2
->desthost
);
3147 werror
= rpccli_spoolss_getprinter(cli2
, mem_ctx
,
3152 if ( !W_ERROR_IS_OK(werror
) ) {
3153 printf("failed (%s)\n", win_errstr(werror
));
3154 talloc_destroy(mem_ctx
);
3159 talloc_destroy(mem_ctx
);
3164 /****************************************************************************
3165 ****************************************************************************/
3167 static bool compare_printer_secdesc( struct rpc_pipe_client
*cli1
, struct policy_handle
*hnd1
,
3168 struct rpc_pipe_client
*cli2
, struct policy_handle
*hnd2
)
3170 union spoolss_PrinterInfo info1
, info2
;
3172 TALLOC_CTX
*mem_ctx
= talloc_init("compare_printer_secdesc");
3173 struct security_descriptor
*sd1
, *sd2
;
3177 printf("Retrieving printer security for %s...", cli1
->desthost
);
3178 werror
= rpccli_spoolss_getprinter(cli1
, mem_ctx
,
3183 if ( !W_ERROR_IS_OK(werror
) ) {
3184 printf("failed (%s)\n", win_errstr(werror
));
3190 printf("Retrieving printer security for %s...", cli2
->desthost
);
3191 werror
= rpccli_spoolss_getprinter(cli2
, mem_ctx
,
3196 if ( !W_ERROR_IS_OK(werror
) ) {
3197 printf("failed (%s)\n", win_errstr(werror
));
3206 sd1
= info1
.info3
.secdesc
;
3207 sd2
= info2
.info3
.secdesc
;
3209 if ( (sd1
!= sd2
) && ( !sd1
|| !sd2
) ) {
3210 printf("NULL secdesc!\n");
3215 if (!security_descriptor_equal( sd1
, sd2
) ) {
3216 printf("Security Descriptors *not* equal!\n");
3221 printf("Security descriptors match\n");
3224 talloc_destroy(mem_ctx
);
3229 /****************************************************************************
3230 ****************************************************************************/
3232 extern struct user_auth_info
*rpcclient_auth_info
;
3234 static WERROR
cmd_spoolss_printercmp(struct rpc_pipe_client
*cli
,
3235 TALLOC_CTX
*mem_ctx
, int argc
,
3238 const char *printername
;
3239 char *printername_path
= NULL
;
3240 struct cli_state
*cli_server2
= NULL
;
3241 struct rpc_pipe_client
*cli2
= NULL
;
3242 struct policy_handle hPrinter1
, hPrinter2
;
3247 printf("Usage: %s <printer> <server>\n", argv
[0]);
3251 printername
= argv
[1];
3253 /* first get the connection to the remote server */
3255 nt_status
= cli_full_connection(&cli_server2
, global_myname(), argv
[2],
3258 get_cmdline_auth_info_username(rpcclient_auth_info
),
3260 get_cmdline_auth_info_password(rpcclient_auth_info
),
3261 get_cmdline_auth_info_use_kerberos(rpcclient_auth_info
) ? CLI_FULL_CONNECTION_USE_KERBEROS
: 0,
3262 get_cmdline_auth_info_signing_state(rpcclient_auth_info
), NULL
);
3264 if ( !NT_STATUS_IS_OK(nt_status
) )
3265 return WERR_GENERAL_FAILURE
;
3267 nt_status
= cli_rpc_pipe_open_noauth(cli_server2
, &ndr_table_spoolss
.syntax_id
,
3269 if (!NT_STATUS_IS_OK(nt_status
)) {
3270 printf("failed to open spoolss pipe on server %s (%s)\n",
3271 argv
[2], nt_errstr(nt_status
));
3272 return WERR_GENERAL_FAILURE
;
3275 /* now open up both printers */
3277 RPCCLIENT_PRINTERNAME(printername_path
, cli
, printername
);
3279 printf("Opening %s...", printername_path
);
3281 werror
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
3285 if ( !W_ERROR_IS_OK(werror
) ) {
3286 printf("failed (%s)\n", win_errstr(werror
));
3291 RPCCLIENT_PRINTERNAME(printername_path
, cli2
, printername
);
3293 printf("Opening %s...", printername_path
);
3294 werror
= rpccli_spoolss_openprinter_ex(cli2
, mem_ctx
,
3298 if ( !W_ERROR_IS_OK(werror
) ) {
3299 printf("failed (%s)\n", win_errstr(werror
));
3304 compare_printer( cli
, &hPrinter1
, cli2
, &hPrinter2
);
3305 compare_printer_secdesc( cli
, &hPrinter1
, cli2
, &hPrinter2
);
3307 compare_printerdata( cli_server1
, &hPrinter1
, cli_server2
, &hPrinter2
);
3314 printf("Closing printers...");
3315 rpccli_spoolss_ClosePrinter( cli
, mem_ctx
, &hPrinter1
, NULL
);
3316 rpccli_spoolss_ClosePrinter( cli2
, mem_ctx
, &hPrinter2
, NULL
);
3319 /* close the second remote connection */
3321 cli_shutdown( cli_server2
);
3325 static void display_proc_info1(struct spoolss_PrintProcessorInfo1
*r
)
3327 printf("print_processor_name: %s\n", r
->print_processor_name
);
3330 static WERROR
cmd_spoolss_enum_procs(struct rpc_pipe_client
*cli
,
3331 TALLOC_CTX
*mem_ctx
, int argc
,
3335 const char *environment
= SPOOLSS_ARCHITECTURE_NT_X86
;
3336 uint32_t num_procs
, level
= 1, i
;
3337 union spoolss_PrintProcessorInfo
*procs
;
3339 /* Parse the command arguments */
3341 if (argc
< 1 || argc
> 4) {
3342 printf ("Usage: %s [environment] [level]\n", argv
[0]);
3347 environment
= argv
[1];
3351 level
= atoi(argv
[2]);
3354 /* Enumerate Print Processors */
3356 werror
= rpccli_spoolss_enumprintprocessors(cli
, mem_ctx
,
3357 cli
->srv_name_slash
,
3363 if (!W_ERROR_IS_OK(werror
))
3366 /* Display output */
3368 for (i
= 0; i
< num_procs
; i
++) {
3371 display_proc_info1(&procs
[i
].info1
);
3380 static void display_proc_data_types_info1(struct spoolss_PrintProcDataTypesInfo1
*r
)
3382 printf("name_array: %s\n", r
->name_array
);
3385 static WERROR
cmd_spoolss_enum_proc_data_types(struct rpc_pipe_client
*cli
,
3386 TALLOC_CTX
*mem_ctx
, int argc
,
3390 const char *print_processor_name
= "winprint";
3391 uint32_t num_procs
, level
= 1, i
;
3392 union spoolss_PrintProcDataTypesInfo
*procs
;
3394 /* Parse the command arguments */
3396 if (argc
< 1 || argc
> 4) {
3397 printf ("Usage: %s [environment] [level]\n", argv
[0]);
3402 print_processor_name
= argv
[1];
3406 level
= atoi(argv
[2]);
3409 /* Enumerate Print Processor Data Types */
3411 werror
= rpccli_spoolss_enumprintprocessordatatypes(cli
, mem_ctx
,
3412 cli
->srv_name_slash
,
3413 print_processor_name
,
3418 if (!W_ERROR_IS_OK(werror
))
3421 /* Display output */
3423 for (i
= 0; i
< num_procs
; i
++) {
3426 display_proc_data_types_info1(&procs
[i
].info1
);
3435 static void display_monitor1(const struct spoolss_MonitorInfo1
*r
)
3437 printf("monitor_name: %s\n", r
->monitor_name
);
3440 static void display_monitor2(const struct spoolss_MonitorInfo2
*r
)
3442 printf("monitor_name: %s\n", r
->monitor_name
);
3443 printf("environment: %s\n", r
->environment
);
3444 printf("dll_name: %s\n", r
->dll_name
);
3447 static WERROR
cmd_spoolss_enum_monitors(struct rpc_pipe_client
*cli
,
3448 TALLOC_CTX
*mem_ctx
, int argc
,
3452 uint32_t count
, level
= 1, i
;
3453 union spoolss_MonitorInfo
*info
;
3455 /* Parse the command arguments */
3458 printf("Usage: %s [level]\n", argv
[0]);
3463 level
= atoi(argv
[1]);
3466 /* Enumerate Print Monitors */
3468 werror
= rpccli_spoolss_enummonitors(cli
, mem_ctx
,
3469 cli
->srv_name_slash
,
3474 if (!W_ERROR_IS_OK(werror
)) {
3478 /* Display output */
3480 for (i
= 0; i
< count
; i
++) {
3483 display_monitor1(&info
[i
].info1
);
3486 display_monitor2(&info
[i
].info2
);
3495 static WERROR
cmd_spoolss_create_printer_ic(struct rpc_pipe_client
*cli
,
3496 TALLOC_CTX
*mem_ctx
, int argc
,
3501 struct policy_handle handle
, gdi_handle
;
3502 const char *printername
;
3503 struct spoolss_DevmodeContainer devmode_ctr
;
3505 RPCCLIENT_PRINTERNAME(printername
, cli
, argv
[1]);
3507 result
= rpccli_spoolss_openprinter_ex(cli
, mem_ctx
,
3509 SEC_FLAG_MAXIMUM_ALLOWED
,
3511 if (!W_ERROR_IS_OK(result
)) {
3515 ZERO_STRUCT(devmode_ctr
);
3517 status
= rpccli_spoolss_CreatePrinterIC(cli
, mem_ctx
,
3522 if (!W_ERROR_IS_OK(result
)) {
3527 if (is_valid_policy_hnd(&gdi_handle
)) {
3528 rpccli_spoolss_DeletePrinterIC(cli
, mem_ctx
, &gdi_handle
, NULL
);
3530 if (is_valid_policy_hnd(&handle
)) {
3531 rpccli_spoolss_ClosePrinter(cli
, mem_ctx
, &handle
, NULL
);
3537 /* List of commands exported by this module */
3538 struct cmd_set spoolss_commands
[] = {
3542 { "adddriver", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_addprinterdriver
, &ndr_table_spoolss
.syntax_id
, NULL
, "Add a print driver", "" },
3543 { "addprinter", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_addprinterex
, &ndr_table_spoolss
.syntax_id
, NULL
, "Add a printer", "" },
3544 { "deldriver", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_deletedriver
, &ndr_table_spoolss
.syntax_id
, NULL
, "Delete a printer driver", "" },
3545 { "deldriverex", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_deletedriverex
, &ndr_table_spoolss
.syntax_id
, NULL
, "Delete a printer driver with files", "" },
3546 { "enumdata", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_enum_data
, &ndr_table_spoolss
.syntax_id
, NULL
, "Enumerate printer data", "" },
3547 { "enumdataex", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_enum_data_ex
, &ndr_table_spoolss
.syntax_id
, NULL
, "Enumerate printer data for a key", "" },
3548 { "enumkey", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_enum_printerkey
, &ndr_table_spoolss
.syntax_id
, NULL
, "Enumerate printer keys", "" },
3549 { "enumjobs", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_enum_jobs
, &ndr_table_spoolss
.syntax_id
, NULL
, "Enumerate print jobs", "" },
3550 { "getjob", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_get_job
, &ndr_table_spoolss
.syntax_id
, NULL
, "Get print job", "" },
3551 { "setjob", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_set_job
, &ndr_table_spoolss
.syntax_id
, NULL
, "Set print job", "" },
3552 { "enumports", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_enum_ports
, &ndr_table_spoolss
.syntax_id
, NULL
, "Enumerate printer ports", "" },
3553 { "enumdrivers", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_enum_drivers
, &ndr_table_spoolss
.syntax_id
, NULL
, "Enumerate installed printer drivers", "" },
3554 { "enumprinters", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_enum_printers
, &ndr_table_spoolss
.syntax_id
, NULL
, "Enumerate printers", "" },
3555 { "getdata", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_getprinterdata
, &ndr_table_spoolss
.syntax_id
, NULL
, "Get print driver data", "" },
3556 { "getdataex", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_getprinterdataex
, &ndr_table_spoolss
.syntax_id
, NULL
, "Get printer driver data with keyname", ""},
3557 { "getdriver", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_getdriver
, &ndr_table_spoolss
.syntax_id
, NULL
, "Get print driver information", "" },
3558 { "getdriverdir", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_getdriverdir
, &ndr_table_spoolss
.syntax_id
, NULL
, "Get print driver upload directory", "" },
3559 { "getprinter", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_getprinter
, &ndr_table_spoolss
.syntax_id
, NULL
, "Get printer info", "" },
3560 { "openprinter", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_open_printer_ex
, &ndr_table_spoolss
.syntax_id
, NULL
, "Open printer handle", "" },
3561 { "setdriver", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_setdriver
, &ndr_table_spoolss
.syntax_id
, NULL
, "Set printer driver", "" },
3562 { "getprintprocdir", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_getprintprocdir
, &ndr_table_spoolss
.syntax_id
, NULL
, "Get print processor directory", "" },
3563 { "addform", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_addform
, &ndr_table_spoolss
.syntax_id
, NULL
, "Add form", "" },
3564 { "setform", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_setform
, &ndr_table_spoolss
.syntax_id
, NULL
, "Set form", "" },
3565 { "getform", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_getform
, &ndr_table_spoolss
.syntax_id
, NULL
, "Get form", "" },
3566 { "deleteform", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_deleteform
, &ndr_table_spoolss
.syntax_id
, NULL
, "Delete form", "" },
3567 { "enumforms", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_enum_forms
, &ndr_table_spoolss
.syntax_id
, NULL
, "Enumerate forms", "" },
3568 { "setprinter", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_setprinter
, &ndr_table_spoolss
.syntax_id
, NULL
, "Set printer comment", "" },
3569 { "setprintername", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_setprintername
, &ndr_table_spoolss
.syntax_id
, NULL
, "Set printername", "" },
3570 { "setprinterdata", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_setprinterdata
, &ndr_table_spoolss
.syntax_id
, NULL
, "Set REG_SZ printer data", "" },
3571 { "rffpcnex", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_rffpcnex
, &ndr_table_spoolss
.syntax_id
, NULL
, "Rffpcnex test", "" },
3572 { "printercmp", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_printercmp
, &ndr_table_spoolss
.syntax_id
, NULL
, "Printer comparison test", "" },
3573 { "enumprocs", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_enum_procs
, &ndr_table_spoolss
.syntax_id
, NULL
, "Enumerate Print Processors", "" },
3574 { "enumprocdatatypes", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_enum_proc_data_types
, &ndr_table_spoolss
.syntax_id
, NULL
, "Enumerate Print Processor Data Types", "" },
3575 { "enummonitors", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_enum_monitors
, &ndr_table_spoolss
.syntax_id
, NULL
, "Enumerate Print Monitors", "" },
3576 { "createprinteric", RPC_RTYPE_WERROR
, NULL
, cmd_spoolss_create_printer_ic
, &ndr_table_spoolss
.syntax_id
, NULL
, "Create Printer IC", "" },