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
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "rpcclient.h"
27 #define RPCCLIENT_PRINTERNAME(_printername, _cli, _arg) \
29 _printername = talloc_asprintf_strupper_m(mem_ctx, "%s\\%s", \
30 _cli->srv_name_slash, _arg); \
31 W_ERROR_HAVE_NO_MEMORY(_printername); \
35 const char *long_archi;
36 const char *short_archi;
40 /* The version int is used by getdrivers. Note that
41 all architecture strings that support mutliple
42 versions must be grouped together since enumdrivers
43 uses this property to prevent issuing multiple
44 enumdriver calls for the same arch */
47 static const struct table_node archi_table[]= {
49 {"Windows 4.0", "WIN40", 0 },
50 {"Windows NT x86", "W32X86", 2 },
51 {"Windows NT x86", "W32X86", 3 },
52 {"Windows NT R4000", "W32MIPS", 2 },
53 {"Windows NT Alpha_AXP", "W32ALPHA", 2 },
54 {"Windows NT PowerPC", "W32PPC", 2 },
55 {"Windows IA64", "IA64", 3 },
56 {"Windows x64", "x64", 3 },
63 * rpcclient module for SPOOLSS rpc pipe.
65 * This generally just parses and checks command lines, and then calls
66 * a cli_spoolss function.
69 /****************************************************************************
70 function to do the mapping between the long architecture name and
72 ****************************************************************************/
74 static const char *cmd_spoolss_get_short_archi(const char *long_archi)
78 DEBUG(107,("Getting architecture dependant directory\n"));
81 } while ( (archi_table[i].long_archi!=NULL ) &&
82 StrCaseCmp(long_archi, archi_table[i].long_archi) );
84 if (archi_table[i].long_archi==NULL) {
85 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
89 /* this might be client code - but shouldn't this be an fstrcpy etc? */
92 DEBUGADD(108,("index: [%d]\n", i));
93 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
94 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
96 return archi_table[i].short_archi;
99 /****************************************************************************
100 ****************************************************************************/
102 static WERROR cmd_spoolss_open_printer_ex(struct rpc_pipe_client *cli,
104 int argc, const char **argv)
110 printf("Usage: %s <printername>\n", argv[0]);
115 return WERR_GENERAL_FAILURE;
117 /* Open the printer handle */
119 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
123 if (W_ERROR_IS_OK(werror)) {
124 printf("Printer %s opened successfully\n", argv[1]);
125 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, &werror);
127 if (!W_ERROR_IS_OK(werror)) {
128 printf("Error closing printer handle! (%s)\n",
129 get_dos_error_msg(werror));
137 /****************************************************************************
138 ****************************************************************************/
140 static void display_print_info0(struct spoolss_PrinterInfo0 *r)
145 printf("\tprintername:[%s]\n", r->printername);
146 printf("\tservername:[%s]\n", r->servername);
147 printf("\tcjobs:[0x%x]\n", r->cjobs);
148 printf("\ttotal_jobs:[0x%x]\n", r->total_jobs);
149 printf("\ttotal_bytes:[0x%x]\n", r->total_bytes);
150 printf("\t:date: [%d]-[%d]-[%d] (%d)\n", r->time.year, r->time.month,
151 r->time.day, r->time.day_of_week);
152 printf("\t:time: [%d]-[%d]-[%d]-[%d]\n", r->time.hour, r->time.minute,
153 r->time.second, r->time.millisecond);
155 printf("\tglobal_counter:[0x%x]\n", r->global_counter);
156 printf("\ttotal_pages:[0x%x]\n", r->total_pages);
158 printf("\tversion:[0x%x]\n", r->version);
159 printf("\tfree_build:[0x%x]\n", r->free_build);
160 printf("\tspooling:[0x%x]\n", r->spooling);
161 printf("\tmax_spooling:[0x%x]\n", r->max_spooling);
162 printf("\tsession_counter:[0x%x]\n", r->session_counter);
163 printf("\tnum_error_out_of_paper:[0x%x]\n", r->num_error_out_of_paper);
164 printf("\tnum_error_not_ready:[0x%x]\n", r->num_error_not_ready);
165 printf("\tjob_error:[0x%x]\n", r->job_error);
166 printf("\tnumber_of_processors:[0x%x]\n", r->number_of_processors);
167 printf("\tprocessor_type:[0x%x]\n", r->processor_type);
168 printf("\thigh_part_total_bytes:[0x%x]\n", r->high_part_total_bytes);
169 printf("\tchange_id:[0x%x]\n", r->change_id);
170 printf("\tlast_error: %s\n", win_errstr(r->last_error));
171 printf("\tstatus:[0x%x]\n", r->status);
172 printf("\tenumerate_network_printers:[0x%x]\n", r->enumerate_network_printers);
173 printf("\tc_setprinter:[0x%x]\n", r->c_setprinter);
174 printf("\tprocessor_architecture:[0x%x]\n", r->processor_architecture);
175 printf("\tprocessor_level:[0x%x]\n", r->processor_level);
176 printf("\tref_ic:[0x%x]\n", r->ref_ic);
177 printf("\treserved2:[0x%x]\n", r->reserved2);
178 printf("\treserved3:[0x%x]\n", r->reserved3);
183 /****************************************************************************
184 ****************************************************************************/
186 static void display_print_info1(struct spoolss_PrinterInfo1 *r)
188 printf("\tflags:[0x%x]\n", r->flags);
189 printf("\tname:[%s]\n", r->name);
190 printf("\tdescription:[%s]\n", r->description);
191 printf("\tcomment:[%s]\n", r->comment);
196 /****************************************************************************
197 ****************************************************************************/
199 static void display_print_info2(struct spoolss_PrinterInfo2 *r)
201 printf("\tservername:[%s]\n", r->servername);
202 printf("\tprintername:[%s]\n", r->printername);
203 printf("\tsharename:[%s]\n", r->sharename);
204 printf("\tportname:[%s]\n", r->portname);
205 printf("\tdrivername:[%s]\n", r->drivername);
206 printf("\tcomment:[%s]\n", r->comment);
207 printf("\tlocation:[%s]\n", r->location);
208 printf("\tsepfile:[%s]\n", r->sepfile);
209 printf("\tprintprocessor:[%s]\n", r->printprocessor);
210 printf("\tdatatype:[%s]\n", r->datatype);
211 printf("\tparameters:[%s]\n", r->parameters);
212 printf("\tattributes:[0x%x]\n", r->attributes);
213 printf("\tpriority:[0x%x]\n", r->priority);
214 printf("\tdefaultpriority:[0x%x]\n", r->defaultpriority);
215 printf("\tstarttime:[0x%x]\n", r->starttime);
216 printf("\tuntiltime:[0x%x]\n", r->untiltime);
217 printf("\tstatus:[0x%x]\n", r->status);
218 printf("\tcjobs:[0x%x]\n", r->cjobs);
219 printf("\taverageppm:[0x%x]\n", r->averageppm);
222 display_sec_desc(r->secdesc);
227 /****************************************************************************
228 ****************************************************************************/
230 static void display_print_info3(struct spoolss_PrinterInfo3 *r)
232 display_sec_desc(r->secdesc);
237 /****************************************************************************
238 ****************************************************************************/
240 static void display_print_info7(struct spoolss_PrinterInfo7 *r)
242 printf("\tguid:[%s]\n", r->guid);
243 printf("\taction:[0x%x]\n", r->action);
247 /****************************************************************************
248 ****************************************************************************/
250 static WERROR cmd_spoolss_enum_printers(struct rpc_pipe_client *cli,
252 int argc, const char **argv)
256 union spoolss_PrinterInfo *info;
261 printf("Usage: %s [level] [name]\n", argv[0]);
266 level = atoi(argv[1]);
272 name = cli->srv_name_slash;
275 result = rpccli_spoolss_enumprinters(cli, mem_ctx,
282 if (W_ERROR_IS_OK(result)) {
285 printf ("No printers returned.\n");
289 for (i = 0; i < count; i++) {
292 display_print_info0(&info[i].info0);
295 display_print_info1(&info[i].info1);
298 display_print_info2(&info[i].info2);
301 display_print_info3(&info[i].info3);
304 printf("unknown info level %d\n", level);
314 /****************************************************************************
315 ****************************************************************************/
317 static void display_port_info_1(struct spoolss_PortInfo1 *r)
319 printf("\tPort Name:\t[%s]\n", r->port_name);
322 /****************************************************************************
323 ****************************************************************************/
325 static void display_port_info_2(struct spoolss_PortInfo2 *r)
327 printf("\tPort Name:\t[%s]\n", r->port_name);
328 printf("\tMonitor Name:\t[%s]\n", r->monitor_name);
329 printf("\tDescription:\t[%s]\n", r->description);
330 printf("\tPort Type:\t" );
332 int comma = 0; /* hack */
334 if (r->port_type & SPOOLSS_PORT_TYPE_READ) {
338 if (r->port_type & SPOOLSS_PORT_TYPE_WRITE) {
339 printf( "%sWrite", comma ? ", " : "" );
342 /* These two have slightly different interpretations
343 on 95/98/ME but I'm disregarding that for now */
344 if (r->port_type & SPOOLSS_PORT_TYPE_REDIRECTED) {
345 printf( "%sRedirected", comma ? ", " : "" );
348 if (r->port_type & SPOOLSS_PORT_TYPE_NET_ATTACHED) {
349 printf( "%sNet-Attached", comma ? ", " : "" );
353 printf( "[Unset]\n" );
355 printf("\tReserved:\t[%d]\n", r->reserved);
359 /****************************************************************************
360 ****************************************************************************/
362 static WERROR cmd_spoolss_enum_ports(struct rpc_pipe_client *cli,
363 TALLOC_CTX *mem_ctx, int argc,
369 union spoolss_PortInfo *info;
372 printf("Usage: %s [level]\n", argv[0]);
377 level = atoi(argv[1]);
380 /* Enumerate ports */
382 result = rpccli_spoolss_enumports(cli, mem_ctx,
388 if (W_ERROR_IS_OK(result)) {
391 for (i = 0; i < count; i++) {
394 display_port_info_1(&info[i].info1);
397 display_port_info_2(&info[i].info2);
400 printf("unknown info level %d\n", level);
409 /****************************************************************************
410 ****************************************************************************/
412 static WERROR cmd_spoolss_setprinter(struct rpc_pipe_client *cli,
414 int argc, const char **argv)
419 uint32 info_level = 2;
420 union spoolss_PrinterInfo info;
421 struct spoolss_SetPrinterInfoCtr info_ctr;
422 const char *printername, *comment = NULL;
423 struct spoolss_DevmodeContainer devmode_ctr;
424 struct sec_desc_buf secdesc_ctr;
426 if (argc == 1 || argc > 3) {
427 printf("Usage: %s printername comment\n", argv[0]);
432 /* Open a printer handle */
437 ZERO_STRUCT(devmode_ctr);
438 ZERO_STRUCT(secdesc_ctr);
440 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
442 /* get a printer handle */
443 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
447 if (!W_ERROR_IS_OK(result))
450 /* Get printer info */
451 result = rpccli_spoolss_getprinter(cli, mem_ctx,
456 if (!W_ERROR_IS_OK(result))
460 /* Modify the comment. */
461 info.info2.comment = comment;
462 info.info2.secdesc = NULL;
463 info.info2.devmode = NULL;
466 info_ctr.info.info2 = (struct spoolss_SetPrinterInfo2 *)&info.info2;
468 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
475 if (W_ERROR_IS_OK(result))
476 printf("Success in setting comment.\n");
479 if (is_valid_policy_hnd(&pol))
480 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
485 /****************************************************************************
486 ****************************************************************************/
488 static WERROR cmd_spoolss_setprintername(struct rpc_pipe_client *cli,
490 int argc, const char **argv)
495 uint32 info_level = 2;
496 union spoolss_PrinterInfo info;
497 const char *printername,
498 *new_printername = NULL;
499 struct spoolss_SetPrinterInfoCtr info_ctr;
500 struct spoolss_DevmodeContainer devmode_ctr;
501 struct sec_desc_buf secdesc_ctr;
503 ZERO_STRUCT(devmode_ctr);
504 ZERO_STRUCT(secdesc_ctr);
506 if (argc == 1 || argc > 3) {
507 printf("Usage: %s printername new_printername\n", argv[0]);
512 /* Open a printer handle */
514 new_printername = argv[2];
517 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
519 /* get a printer handle */
520 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
524 if (!W_ERROR_IS_OK(result))
527 /* Get printer info */
528 result = rpccli_spoolss_getprinter(cli, mem_ctx,
533 if (!W_ERROR_IS_OK(result))
536 /* Modify the printername. */
537 info.info2.printername = new_printername;
538 info.info2.devmode = NULL;
539 info.info2.secdesc = NULL;
541 info_ctr.level = info_level;
542 info_ctr.info.info2 = (struct spoolss_SetPrinterInfo2 *)&info.info2;
544 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
551 if (W_ERROR_IS_OK(result))
552 printf("Success in setting printername.\n");
555 if (is_valid_policy_hnd(&pol))
556 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
561 /****************************************************************************
562 ****************************************************************************/
564 static WERROR cmd_spoolss_getprinter(struct rpc_pipe_client *cli,
566 int argc, const char **argv)
571 const char *printername;
572 union spoolss_PrinterInfo info;
574 if (argc == 1 || argc > 3) {
575 printf("Usage: %s <printername> [level]\n", argv[0]);
579 /* Open a printer handle */
581 level = atoi(argv[2]);
584 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
586 /* get a printer handle */
588 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
590 SEC_FLAG_MAXIMUM_ALLOWED,
592 if (!W_ERROR_IS_OK(result)) {
596 /* Get printer info */
598 result = rpccli_spoolss_getprinter(cli, mem_ctx,
603 if (!W_ERROR_IS_OK(result)) {
607 /* Display printer info */
610 display_print_info0(&info.info0);
613 display_print_info1(&info.info1);
616 display_print_info2(&info.info2);
619 display_print_info3(&info.info3);
622 display_print_info7(&info.info7);
625 printf("unknown info level %d\n", level);
629 if (is_valid_policy_hnd(&pol)) {
630 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
636 /****************************************************************************
637 ****************************************************************************/
639 static void display_reg_value(REGISTRY_VALUE value)
645 printf("%s: REG_DWORD: 0x%08x\n", value.valuename,
646 *((uint32 *) value.data_p));
649 rpcstr_pull_talloc(talloc_tos(),
654 printf("%s: REG_SZ: %s\n", value.valuename, text ? text : "");
657 char *hex = hex_encode_talloc(NULL, value.data_p, value.size);
659 printf("%s: REG_BINARY:", value.valuename);
661 for (i=0; i<len; i++) {
662 if (hex[i] == '\0') {
675 uint32 i, num_values;
678 if (!W_ERROR_IS_OK(reg_pull_multi_sz(NULL, value.data_p,
679 value.size, &num_values,
681 d_printf("reg_pull_multi_sz failed\n");
685 printf("%s: REG_MULTI_SZ: \n", value.valuename);
686 for (i=0; i<num_values; i++) {
687 d_printf("%s\n", values[i]);
693 printf("%s: unknown type %d\n", value.valuename, value.type);
698 /****************************************************************************
699 ****************************************************************************/
701 static void display_printer_data(const char *v,
702 enum winreg_Type type,
703 union spoolss_PrinterData *r)
709 printf("%s: REG_DWORD: 0x%08x\n", v, r->value);
712 printf("%s: REG_SZ: %s\n", v, r->string);
715 char *hex = hex_encode_talloc(NULL,
716 r->binary.data, r->binary.length);
718 printf("%s: REG_BINARY:", v);
720 for (i=0; i<len; i++) {
721 if (hex[i] == '\0') {
734 printf("%s: REG_MULTI_SZ: ", v);
735 for (i=0; r->string_array[i] != NULL; i++) {
736 printf("%s ", r->string_array[i]);
741 printf("%s: unknown type 0x%02x:\n", v, type);
746 /****************************************************************************
747 ****************************************************************************/
749 static WERROR cmd_spoolss_getprinterdata(struct rpc_pipe_client *cli,
751 int argc, const char **argv)
756 const char *valuename;
757 enum winreg_Type type;
758 union spoolss_PrinterData data;
761 printf("Usage: %s <printername> <valuename>\n", argv[0]);
762 printf("<printername> of . queries print server\n");
767 /* Open a printer handle */
769 if (strncmp(argv[1], ".", sizeof(".")) == 0)
770 fstrcpy(printername, cli->srv_name_slash);
772 slprintf(printername, sizeof(printername)-1, "%s\\%s",
773 cli->srv_name_slash, argv[1]);
775 /* get a printer handle */
777 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
779 SEC_FLAG_MAXIMUM_ALLOWED,
781 if (!W_ERROR_IS_OK(result))
784 /* Get printer info */
786 result = rpccli_spoolss_getprinterdata(cli, mem_ctx,
792 if (!W_ERROR_IS_OK(result))
795 /* Display printer data */
797 display_printer_data(valuename, type, &data);
800 if (is_valid_policy_hnd(&pol))
801 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
806 /****************************************************************************
807 ****************************************************************************/
809 static WERROR cmd_spoolss_getprinterdataex(struct rpc_pipe_client *cli,
811 int argc, const char **argv)
817 const char *valuename, *keyname;
818 REGISTRY_VALUE value;
820 enum winreg_Type type;
821 uint8_t *buffer = NULL;
822 uint32_t offered = 0;
826 printf("Usage: %s <printername> <keyname> <valuename>\n",
828 printf("<printername> of . queries print server\n");
834 /* Open a printer handle */
836 if (strncmp(argv[1], ".", sizeof(".")) == 0)
837 fstrcpy(printername, cli->srv_name_slash);
839 slprintf(printername, sizeof(printername)-1, "%s\\%s",
840 cli->srv_name_slash, argv[1]);
842 /* get a printer handle */
844 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
846 SEC_FLAG_MAXIMUM_ALLOWED,
848 if (!W_ERROR_IS_OK(result))
851 /* Get printer info */
853 status = rpccli_spoolss_GetPrinterDataEx(cli, mem_ctx,
862 if (W_ERROR_EQUAL(result, WERR_MORE_DATA)) {
864 buffer = talloc_array(mem_ctx, uint8_t, needed);
865 status = rpccli_spoolss_GetPrinterDataEx(cli, mem_ctx,
876 if (!NT_STATUS_IS_OK(status)) {
880 if (!W_ERROR_IS_OK(result)) {
885 if (!W_ERROR_IS_OK(result))
888 /* Display printer data */
890 fstrcpy(value.valuename, valuename);
893 value.data_p = buffer;
895 display_reg_value(value);
898 if (is_valid_policy_hnd(&pol))
899 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
904 /****************************************************************************
905 ****************************************************************************/
907 static void display_print_driver1(struct spoolss_DriverInfo1 *r)
913 printf("Printer Driver Info 1:\n");
914 printf("\tDriver Name: [%s]\n\n", r->driver_name);
917 /****************************************************************************
918 ****************************************************************************/
920 static void display_print_driver2(struct spoolss_DriverInfo2 *r)
926 printf("Printer Driver Info 2:\n");
927 printf("\tVersion: [%x]\n", r->version);
928 printf("\tDriver Name: [%s]\n", r->driver_name);
929 printf("\tArchitecture: [%s]\n", r->architecture);
930 printf("\tDriver Path: [%s]\n", r->driver_path);
931 printf("\tDatafile: [%s]\n", r->data_file);
932 printf("\tConfigfile: [%s]\n\n", r->config_file);
935 /****************************************************************************
936 ****************************************************************************/
938 static void display_print_driver3(struct spoolss_DriverInfo3 *r)
946 printf("Printer Driver Info 3:\n");
947 printf("\tVersion: [%x]\n", r->version);
948 printf("\tDriver Name: [%s]\n", r->driver_name);
949 printf("\tArchitecture: [%s]\n", r->architecture);
950 printf("\tDriver Path: [%s]\n", r->driver_path);
951 printf("\tDatafile: [%s]\n", r->data_file);
952 printf("\tConfigfile: [%s]\n\n", r->config_file);
953 printf("\tHelpfile: [%s]\n\n", r->help_file);
955 for (i=0; r->dependent_files[i] != NULL; i++) {
956 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
961 printf("\tMonitorname: [%s]\n", r->monitor_name);
962 printf("\tDefaultdatatype: [%s]\n\n", r->default_datatype);
966 /****************************************************************************
967 ****************************************************************************/
969 static WERROR cmd_spoolss_getdriver(struct rpc_pipe_client *cli,
971 int argc, const char **argv)
976 const char *printername;
978 bool success = false;
979 union spoolss_DriverInfo info;
980 uint32_t server_major_version;
981 uint32_t server_minor_version;
983 if ((argc == 1) || (argc > 3)) {
984 printf("Usage: %s <printername> [level]\n", argv[0]);
988 /* get the arguments need to open the printer handle */
990 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
993 level = atoi(argv[2]);
996 /* Open a printer handle */
998 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1002 if (!W_ERROR_IS_OK(werror)) {
1003 printf("Error opening printer handle for %s!\n", printername);
1007 /* loop through and print driver info level for each architecture */
1009 for (i=0; archi_table[i].long_archi!=NULL; i++) {
1011 werror = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1013 archi_table[i].long_archi,
1016 archi_table[i].version,
1019 &server_major_version,
1020 &server_minor_version);
1021 if (!W_ERROR_IS_OK(werror)) {
1025 /* need at least one success */
1029 printf("\n[%s]\n", archi_table[i].long_archi);
1033 display_print_driver1(&info.info1);
1036 display_print_driver2(&info.info2);
1039 display_print_driver3(&info.info3);
1042 printf("unknown info level %d\n", level);
1049 if (is_valid_policy_hnd(&pol)) {
1050 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
1060 /****************************************************************************
1061 ****************************************************************************/
1063 static WERROR cmd_spoolss_enum_drivers(struct rpc_pipe_client *cli,
1064 TALLOC_CTX *mem_ctx,
1065 int argc, const char **argv)
1067 WERROR werror = WERR_OK;
1069 union spoolss_DriverInfo *info;
1070 uint32_t i, j, count;
1073 printf("Usage: enumdrivers [level]\n");
1078 level = atoi(argv[1]);
1082 /* loop through and print driver info level for each architecture */
1083 for (i=0; archi_table[i].long_archi!=NULL; i++) {
1084 /* check to see if we already asked for this architecture string */
1086 if (i>0 && strequal(archi_table[i].long_archi, archi_table[i-1].long_archi)) {
1090 werror = rpccli_spoolss_enumprinterdrivers(cli, mem_ctx,
1091 cli->srv_name_slash,
1092 archi_table[i].long_archi,
1098 if (W_ERROR_V(werror) == W_ERROR_V(WERR_INVALID_ENVIRONMENT)) {
1099 printf("Server does not support environment [%s]\n",
1100 archi_table[i].long_archi);
1109 if (!W_ERROR_IS_OK(werror)) {
1110 printf("Error getting driver for environment [%s] - %d\n",
1111 archi_table[i].long_archi, W_ERROR_V(werror));
1115 printf("\n[%s]\n", archi_table[i].long_archi);
1119 for (j=0; j < count; j++) {
1120 display_print_driver1(&info[j].info1);
1124 for (j=0; j < count; j++) {
1125 display_print_driver2(&info[j].info2);
1129 for (j=0; j < count; j++) {
1130 display_print_driver3(&info[j].info3);
1134 printf("unknown info level %d\n", level);
1135 return WERR_UNKNOWN_LEVEL;
1142 /****************************************************************************
1143 ****************************************************************************/
1145 static void display_printdriverdir_1(struct spoolss_DriverDirectoryInfo1 *r)
1147 printf("\tDirectory Name:[%s]\n", r->directory_name);
1150 /****************************************************************************
1151 ****************************************************************************/
1153 static WERROR cmd_spoolss_getdriverdir(struct rpc_pipe_client *cli,
1154 TALLOC_CTX *mem_ctx,
1155 int argc, const char **argv)
1159 const char *env = SPOOLSS_ARCHITECTURE_NT_X86;
1162 union spoolss_DriverDirectoryInfo info;
1166 printf("Usage: %s [environment]\n", argv[0]);
1170 /* Get the arguments need to open the printer handle */
1176 /* Get the directory. Only use Info level 1 */
1178 status = rpccli_spoolss_GetPrinterDriverDirectory(cli, mem_ctx,
1179 cli->srv_name_slash,
1187 if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) {
1189 buffer = data_blob_talloc_zero(mem_ctx, needed);
1191 status = rpccli_spoolss_GetPrinterDriverDirectory(cli, mem_ctx,
1192 cli->srv_name_slash,
1202 if (W_ERROR_IS_OK(result)) {
1203 display_printdriverdir_1(&info.info1);
1209 /****************************************************************************
1210 ****************************************************************************/
1212 static void set_drv_info_3_env(TALLOC_CTX *mem_ctx,
1213 struct spoolss_AddDriverInfo3 *info,
1219 for (i=0; archi_table[i].long_archi != NULL; i++)
1221 if (strcmp(arch, archi_table[i].short_archi) == 0)
1223 info->version = archi_table[i].version;
1224 info->architecture = talloc_strdup(mem_ctx, archi_table[i].long_archi);
1229 if (archi_table[i].long_archi == NULL)
1231 DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch));
1238 /**************************************************************************
1239 wrapper for strtok to get the next parameter from a delimited list.
1240 Needed to handle the empty parameter string denoted by "NULL"
1241 *************************************************************************/
1243 static char *get_driver_3_param(TALLOC_CTX *mem_ctx, char *str,
1244 const char *delim, const char **dest,
1249 /* get the next token */
1250 ptr = strtok_r(str, delim, saveptr);
1252 /* a string of 'NULL' is used to represent an empty
1253 parameter because two consecutive delimiters
1254 will not return an empty string. See man strtok(3)
1256 if (ptr && (StrCaseCmp(ptr, "NULL") == 0)) {
1261 *dest = talloc_strdup(mem_ctx, ptr);
1267 /********************************************************************************
1268 fill in the members of a spoolss_AddDriverInfo3 struct using a character
1269 string in the form of
1270 <Long Printer Name>:<Driver File Name>:<Data File Name>:\
1271 <Config File Name>:<Help File Name>:<Language Monitor Name>:\
1272 <Default Data Type>:<Comma Separated list of Files>
1273 *******************************************************************************/
1275 static bool init_drv_info_3_members(TALLOC_CTX *mem_ctx, struct spoolss_AddDriverInfo3 *r,
1280 char *saveptr = NULL;
1281 struct spoolss_StringArray *deps;
1282 const char **file_array = NULL;
1285 /* fill in the UNISTR fields */
1286 str = get_driver_3_param(mem_ctx, args, ":", &r->driver_name, &saveptr);
1287 str = get_driver_3_param(mem_ctx, NULL, ":", &r->driver_path, &saveptr);
1288 str = get_driver_3_param(mem_ctx, NULL, ":", &r->data_file, &saveptr);
1289 str = get_driver_3_param(mem_ctx, NULL, ":", &r->config_file, &saveptr);
1290 str = get_driver_3_param(mem_ctx, NULL, ":", &r->help_file, &saveptr);
1291 str = get_driver_3_param(mem_ctx, NULL, ":", &r->monitor_name, &saveptr);
1292 str = get_driver_3_param(mem_ctx, NULL, ":", &r->default_datatype, &saveptr);
1294 /* <Comma Separated List of Dependent Files> */
1295 /* save the beginning of the string */
1296 str2 = get_driver_3_param(mem_ctx, NULL, ":", NULL, &saveptr);
1299 /* begin to strip out each filename */
1300 str = strtok_r(str, ",", &saveptr);
1302 /* no dependent files, we are done */
1307 deps = talloc_zero(mem_ctx, struct spoolss_StringArray);
1312 while (str != NULL) {
1313 add_string_to_array(deps, str, &file_array, &count);
1314 str = strtok_r(NULL, ",", &saveptr);
1317 deps->string = talloc_zero_array(deps, const char *, count + 1);
1318 if (!deps->string) {
1322 for (i=0; i < count; i++) {
1323 deps->string[i] = file_array[i];
1326 r->dependent_files = deps;
1331 /****************************************************************************
1332 ****************************************************************************/
1334 static WERROR cmd_spoolss_addprinterdriver(struct rpc_pipe_client *cli,
1335 TALLOC_CTX *mem_ctx,
1336 int argc, const char **argv)
1341 struct spoolss_AddDriverInfoCtr info_ctr;
1342 struct spoolss_AddDriverInfo3 info3;
1346 /* parse the command arguments */
1347 if (argc != 3 && argc != 4)
1349 printf ("Usage: %s <Environment> \\\n", argv[0]);
1350 printf ("\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n");
1351 printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
1352 printf ("\t<Default Data Type>:<Comma Separated list of Files> \\\n");
1353 printf ("\t[version]\n");
1358 /* Fill in the spoolss_AddDriverInfo3 struct */
1361 arch = cmd_spoolss_get_short_archi(argv[1]);
1363 printf ("Error Unknown architechture [%s]\n", argv[1]);
1364 return WERR_INVALID_PARAM;
1367 set_drv_info_3_env(mem_ctx, &info3, arch);
1369 driver_args = talloc_strdup( mem_ctx, argv[2] );
1370 if (!init_drv_info_3_members(mem_ctx, &info3, driver_args ))
1372 printf ("Error Invalid parameter list - %s.\n", argv[2]);
1373 return WERR_INVALID_PARAM;
1376 /* if printer driver version specified, override the default version
1377 * used by the architecture. This allows installation of Windows
1378 * 2000 (version 3) printer drivers. */
1381 info3.version = atoi(argv[3]);
1385 info_ctr.level = level;
1386 info_ctr.info.info3 = &info3;
1388 status = rpccli_spoolss_AddPrinterDriver(cli, mem_ctx,
1389 cli->srv_name_slash,
1392 if (!NT_STATUS_IS_OK(status)) {
1393 return ntstatus_to_werror(status);
1395 if (W_ERROR_IS_OK(result)) {
1396 printf ("Printer Driver %s successfully installed.\n",
1404 /****************************************************************************
1405 ****************************************************************************/
1407 static WERROR cmd_spoolss_addprinterex(struct rpc_pipe_client *cli,
1408 TALLOC_CTX *mem_ctx,
1409 int argc, const char **argv)
1412 struct spoolss_SetPrinterInfoCtr info_ctr;
1413 struct spoolss_SetPrinterInfo2 info2;
1415 /* parse the command arguments */
1418 printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]);
1422 /* Fill in the DRIVER_INFO_2 struct */
1425 info2.printername = argv[1];
1426 info2.drivername = argv[3];
1427 info2.sharename = argv[2];
1428 info2.portname = argv[4];
1429 info2.comment = "Created by rpcclient";
1430 info2.printprocessor = "winprint";
1431 info2.datatype = "RAW";
1432 info2.devmode = NULL;
1433 info2.secdesc = NULL;
1434 info2.attributes = PRINTER_ATTRIBUTE_SHARED;
1436 info2.defaultpriority = 0;
1437 info2.starttime = 0;
1438 info2.untiltime = 0;
1440 /* These three fields must not be used by AddPrinter()
1441 as defined in the MS Platform SDK documentation..
1445 info2.averageppm = 0;
1449 info_ctr.info.info2 = &info2;
1451 result = rpccli_spoolss_addprinterex(cli, mem_ctx,
1453 if (W_ERROR_IS_OK(result))
1454 printf ("Printer %s successfully installed.\n", argv[1]);
1459 /****************************************************************************
1460 ****************************************************************************/
1462 static WERROR cmd_spoolss_setdriver(struct rpc_pipe_client *cli,
1463 TALLOC_CTX *mem_ctx,
1464 int argc, const char **argv)
1470 const char *printername;
1471 union spoolss_PrinterInfo info;
1472 struct spoolss_SetPrinterInfoCtr info_ctr;
1473 struct spoolss_DevmodeContainer devmode_ctr;
1474 struct sec_desc_buf secdesc_ctr;
1476 ZERO_STRUCT(devmode_ctr);
1477 ZERO_STRUCT(secdesc_ctr);
1479 /* parse the command arguments */
1482 printf ("Usage: %s <printer> <driver>\n", argv[0]);
1486 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1488 /* Get a printer handle */
1490 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1494 if (!W_ERROR_IS_OK(result))
1497 /* Get printer info */
1499 result = rpccli_spoolss_getprinter(cli, mem_ctx,
1504 if (!W_ERROR_IS_OK(result)) {
1505 printf ("Unable to retrieve printer information!\n");
1509 /* Set the printer driver */
1511 info.info2.drivername = argv[2];
1512 info.info2.devmode = NULL;
1513 info.info2.secdesc = NULL;
1516 info_ctr.info.info2 = (struct spoolss_SetPrinterInfo2 *)&info.info2;
1518 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
1525 if (!W_ERROR_IS_OK(result)) {
1526 printf("SetPrinter call failed!\n");
1530 printf("Successfully set %s to driver %s.\n", argv[1], argv[2]);
1535 if (is_valid_policy_hnd(&pol))
1536 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
1542 /****************************************************************************
1543 ****************************************************************************/
1545 static WERROR cmd_spoolss_deletedriverex(struct rpc_pipe_client *cli,
1546 TALLOC_CTX *mem_ctx,
1547 int argc, const char **argv)
1549 WERROR result, ret = WERR_UNKNOWN_PRINTER_DRIVER;
1555 const char *arch = NULL;
1556 uint32_t delete_flags = 0;
1558 /* parse the command arguments */
1559 if (argc < 2 || argc > 4) {
1560 printf ("Usage: %s <driver> [arch] [version]\n", argv[0]);
1567 vers = atoi (argv[3]);
1570 delete_flags |= DPD_DELETE_SPECIFIC_VERSION;
1573 /* delete the driver for all architectures */
1574 for (i=0; archi_table[i].long_archi; i++) {
1576 if (arch && !strequal( archi_table[i].long_archi, arch))
1579 if (vers >= 0 && archi_table[i].version != vers)
1582 /* make the call to remove the driver */
1583 status = rpccli_spoolss_DeletePrinterDriverEx(cli, mem_ctx,
1584 cli->srv_name_slash,
1585 archi_table[i].long_archi,
1588 archi_table[i].version,
1591 if ( !W_ERROR_IS_OK(result) )
1593 if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1594 printf ("Failed to remove driver %s for arch [%s] (version: %d): %s\n",
1595 argv[1], archi_table[i].long_archi, archi_table[i].version, win_errstr(result));
1600 printf ("Driver %s and files removed for arch [%s] (version: %d).\n", argv[1],
1601 archi_table[i].long_archi, archi_table[i].version);
1610 /****************************************************************************
1611 ****************************************************************************/
1613 static WERROR cmd_spoolss_deletedriver(struct rpc_pipe_client *cli,
1614 TALLOC_CTX *mem_ctx,
1615 int argc, const char **argv)
1617 WERROR result = WERR_OK;
1621 /* parse the command arguments */
1623 printf ("Usage: %s <driver>\n", argv[0]);
1627 /* delete the driver for all architectures */
1628 for (i=0; archi_table[i].long_archi; i++) {
1629 /* make the call to remove the driver */
1630 status = rpccli_spoolss_DeletePrinterDriver(cli, mem_ctx,
1631 cli->srv_name_slash,
1632 archi_table[i].long_archi,
1635 if (!NT_STATUS_IS_OK(status)) {
1638 if ( !W_ERROR_IS_OK(result) ) {
1639 if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1640 printf ("Failed to remove driver %s for arch [%s] - error 0x%x!\n",
1641 argv[1], archi_table[i].long_archi,
1645 printf ("Driver %s removed for arch [%s].\n", argv[1],
1646 archi_table[i].long_archi);
1653 /****************************************************************************
1654 ****************************************************************************/
1656 static WERROR cmd_spoolss_getprintprocdir(struct rpc_pipe_client *cli,
1657 TALLOC_CTX *mem_ctx,
1658 int argc, const char **argv)
1662 const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
1665 union spoolss_PrintProcessorDirectoryInfo info;
1668 /* parse the command arguments */
1670 printf ("Usage: %s [environment]\n", argv[0]);
1675 environment = argv[1];
1678 status = rpccli_spoolss_GetPrintProcessorDirectory(cli, mem_ctx,
1679 cli->srv_name_slash,
1687 if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) {
1689 buffer = data_blob_talloc_zero(mem_ctx, needed);
1691 status = rpccli_spoolss_GetPrintProcessorDirectory(cli, mem_ctx,
1692 cli->srv_name_slash,
1702 if (W_ERROR_IS_OK(result)) {
1703 printf("%s\n", info.info1.directory_name);
1709 /****************************************************************************
1710 ****************************************************************************/
1712 static WERROR cmd_spoolss_addform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1713 int argc, const char **argv)
1718 const char *printername;
1719 union spoolss_AddFormInfo info;
1720 struct spoolss_AddFormInfo1 info1;
1721 struct spoolss_AddFormInfo2 info2;
1724 /* Parse the command arguments */
1726 if (argc < 3 || argc > 5) {
1727 printf ("Usage: %s <printer> <formname> [level]\n", argv[0]);
1731 /* Get a printer handle */
1733 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1735 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1739 if (!W_ERROR_IS_OK(werror))
1742 /* Dummy up some values for the form data */
1745 level = atoi(argv[3]);
1750 info1.flags = SPOOLSS_FORM_USER;
1751 info1.form_name = argv[2];
1752 info1.size.width = 100;
1753 info1.size.height = 100;
1754 info1.area.left = 0;
1755 info1.area.top = 10;
1756 info1.area.right = 20;
1757 info1.area.bottom = 30;
1759 info.info1 = &info1;
1763 info2.flags = SPOOLSS_FORM_USER;
1764 info2.form_name = argv[2];
1765 info2.size.width = 100;
1766 info2.size.height = 100;
1767 info2.area.left = 0;
1768 info2.area.top = 10;
1769 info2.area.right = 20;
1770 info2.area.bottom = 30;
1771 info2.keyword = argv[2];
1772 info2.string_type = SPOOLSS_FORM_STRING_TYPE_NONE;
1773 info2.mui_dll = NULL;
1774 info2.ressource_id = 0;
1775 info2.display_name = argv[2];
1778 info.info2 = &info2;
1786 status = rpccli_spoolss_AddForm(cli, mem_ctx,
1793 if (is_valid_policy_hnd(&handle))
1794 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1799 /****************************************************************************
1800 ****************************************************************************/
1802 static WERROR cmd_spoolss_setform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1803 int argc, const char **argv)
1808 const char *printername;
1809 union spoolss_AddFormInfo info;
1810 struct spoolss_AddFormInfo1 info1;
1812 /* Parse the command arguments */
1815 printf ("Usage: %s <printer> <formname>\n", argv[0]);
1819 /* Get a printer handle */
1821 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1823 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1825 SEC_FLAG_MAXIMUM_ALLOWED,
1827 if (!W_ERROR_IS_OK(werror))
1830 /* Dummy up some values for the form data */
1832 info1.flags = SPOOLSS_FORM_PRINTER;
1833 info1.size.width = 100;
1834 info1.size.height = 100;
1835 info1.area.left = 0;
1836 info1.area.top = 1000;
1837 info1.area.right = 2000;
1838 info1.area.bottom = 3000;
1839 info1.form_name = argv[2];
1841 info.info1 = &info1;
1845 status = rpccli_spoolss_SetForm(cli, mem_ctx,
1853 if (is_valid_policy_hnd(&handle))
1854 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1859 /****************************************************************************
1860 ****************************************************************************/
1862 static const char *get_form_flag(int form_flag)
1864 switch (form_flag) {
1865 case SPOOLSS_FORM_USER:
1867 case SPOOLSS_FORM_BUILTIN:
1868 return "FORM_BUILTIN";
1869 case SPOOLSS_FORM_PRINTER:
1870 return "FORM_PRINTER";
1876 /****************************************************************************
1877 ****************************************************************************/
1879 static void display_form_info1(struct spoolss_FormInfo1 *r)
1882 "\tflag: %s (%d)\n" \
1883 "\twidth: %d, length: %d\n" \
1884 "\tleft: %d, right: %d, top: %d, bottom: %d\n\n",
1885 r->form_name, get_form_flag(r->flags), r->flags,
1886 r->size.width, r->size.height,
1887 r->area.left, r->area.right,
1888 r->area.top, r->area.bottom);
1891 /****************************************************************************
1892 ****************************************************************************/
1894 static void display_form_info2(struct spoolss_FormInfo2 *r)
1897 "\tflag: %s (%d)\n" \
1898 "\twidth: %d, length: %d\n" \
1899 "\tleft: %d, right: %d, top: %d, bottom: %d\n",
1900 r->form_name, get_form_flag(r->flags), r->flags,
1901 r->size.width, r->size.height,
1902 r->area.left, r->area.right,
1903 r->area.top, r->area.bottom);
1904 printf("\tkeyword: %s\n", r->keyword);
1905 printf("\tstring_type: 0x%08x\n", r->string_type);
1906 printf("\tmui_dll: %s\n", r->mui_dll);
1907 printf("\tressource_id: 0x%08x\n", r->ressource_id);
1908 printf("\tdisplay_name: %s\n", r->display_name);
1909 printf("\tlang_id: %d\n", r->lang_id);
1913 /****************************************************************************
1914 ****************************************************************************/
1916 static WERROR cmd_spoolss_getform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1917 int argc, const char **argv)
1922 const char *printername;
1924 uint32_t offered = 0;
1925 union spoolss_FormInfo info;
1929 /* Parse the command arguments */
1931 if (argc < 3 || argc > 5) {
1932 printf ("Usage: %s <printer> <formname> [level]\n", argv[0]);
1936 /* Get a printer handle */
1938 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1940 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1942 SEC_FLAG_MAXIMUM_ALLOWED,
1944 if (!W_ERROR_IS_OK(werror))
1948 level = atoi(argv[3]);
1953 status = rpccli_spoolss_GetForm(cli, mem_ctx,
1962 if (W_ERROR_EQUAL(werror, WERR_INSUFFICIENT_BUFFER)) {
1963 buffer = data_blob_talloc_zero(mem_ctx, needed);
1965 status = rpccli_spoolss_GetForm(cli, mem_ctx,
1976 if (!NT_STATUS_IS_OK(status)) {
1982 display_form_info1(&info.info1);
1985 display_form_info2(&info.info2);
1990 if (is_valid_policy_hnd(&handle))
1991 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
1996 /****************************************************************************
1997 ****************************************************************************/
1999 static WERROR cmd_spoolss_deleteform(struct rpc_pipe_client *cli,
2000 TALLOC_CTX *mem_ctx, int argc,
2006 const char *printername;
2008 /* Parse the command arguments */
2011 printf ("Usage: %s <printer> <formname>\n", argv[0]);
2015 /* Get a printer handle */
2017 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2019 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2021 SEC_FLAG_MAXIMUM_ALLOWED,
2023 if (!W_ERROR_IS_OK(werror))
2026 /* Delete the form */
2028 status = rpccli_spoolss_DeleteForm(cli, mem_ctx,
2032 if (!NT_STATUS_IS_OK(status)) {
2033 return ntstatus_to_werror(status);
2037 if (is_valid_policy_hnd(&handle))
2038 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2043 /****************************************************************************
2044 ****************************************************************************/
2046 static WERROR cmd_spoolss_enum_forms(struct rpc_pipe_client *cli,
2047 TALLOC_CTX *mem_ctx, int argc,
2052 const char *printername;
2053 uint32 num_forms, level = 1, i;
2054 union spoolss_FormInfo *forms;
2056 /* Parse the command arguments */
2058 if (argc < 2 || argc > 4) {
2059 printf ("Usage: %s <printer> [level]\n", argv[0]);
2063 /* Get a printer handle */
2065 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2067 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2069 SEC_FLAG_MAXIMUM_ALLOWED,
2071 if (!W_ERROR_IS_OK(werror))
2075 level = atoi(argv[2]);
2078 /* Enumerate forms */
2080 werror = rpccli_spoolss_enumforms(cli, mem_ctx,
2087 if (!W_ERROR_IS_OK(werror))
2090 /* Display output */
2092 for (i = 0; i < num_forms; i++) {
2095 display_form_info1(&forms[i].info1);
2098 display_form_info2(&forms[i].info2);
2104 if (is_valid_policy_hnd(&handle))
2105 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2110 /****************************************************************************
2111 ****************************************************************************/
2113 static WERROR cmd_spoolss_setprinterdata(struct rpc_pipe_client *cli,
2114 TALLOC_CTX *mem_ctx,
2115 int argc, const char **argv)
2119 const char *printername;
2121 union spoolss_PrinterInfo info;
2122 enum winreg_Type type;
2123 union spoolss_PrinterData data;
2125 /* parse the command arguments */
2127 printf ("Usage: %s <printer> <string|binary|dword|multistring>"
2128 " <value> <data>\n",
2130 result = WERR_INVALID_PARAM;
2134 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2138 if (strequal(argv[2], "string")) {
2142 if (strequal(argv[2], "binary")) {
2146 if (strequal(argv[2], "dword")) {
2150 if (strequal(argv[2], "multistring")) {
2151 type = REG_MULTI_SZ;
2154 if (type == REG_NONE) {
2155 printf("Unknown data type: %s\n", argv[2]);
2156 result = WERR_INVALID_PARAM;
2160 /* get a printer handle */
2162 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2164 SEC_FLAG_MAXIMUM_ALLOWED,
2166 if (!W_ERROR_IS_OK(result)) {
2170 result = rpccli_spoolss_getprinter(cli, mem_ctx,
2175 if (!W_ERROR_IS_OK(result)) {
2179 printf("%s\n", current_timestring(mem_ctx, true));
2180 printf("\tchange_id (before set)\t:[0x%x]\n", info.info0.change_id);
2182 /* Set the printer data */
2186 data.string = talloc_strdup(mem_ctx, argv[4]);
2187 W_ERROR_HAVE_NO_MEMORY(data.string);
2190 data.value = strtoul(argv[4], NULL, 10);
2193 data.binary = strhex_to_data_blob(mem_ctx, argv[4]);
2195 case REG_MULTI_SZ: {
2197 const char **strings = NULL;
2199 for (i=4; i<argc; i++) {
2200 if (strcmp(argv[i], "NULL") == 0) {
2203 if (!add_string_to_array(mem_ctx, argv[i],
2206 result = WERR_NOMEM;
2210 data.string_array = talloc_zero_array(mem_ctx, const char *, num_strings + 1);
2211 if (!data.string_array) {
2212 result = WERR_NOMEM;
2215 for (i=0; i < num_strings; i++) {
2216 data.string_array[i] = strings[i];
2221 printf("Unknown data type: %s\n", argv[2]);
2222 result = WERR_INVALID_PARAM;
2226 status = rpccli_spoolss_SetPrinterData(cli, mem_ctx,
2228 argv[3], /* value_name */
2231 0, /* autocalculated size */
2233 if (!W_ERROR_IS_OK(result)) {
2234 printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]);
2237 printf("\tSetPrinterData succeeded [%s: %s]\n", argv[3], argv[4]);
2239 result = rpccli_spoolss_getprinter(cli, mem_ctx,
2244 if (!W_ERROR_IS_OK(result)) {
2248 printf("%s\n", current_timestring(mem_ctx, true));
2249 printf("\tchange_id (after set)\t:[0x%x]\n", info.info0.change_id);
2253 if (is_valid_policy_hnd(&pol)) {
2254 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
2260 /****************************************************************************
2261 ****************************************************************************/
2263 static void display_job_info1(struct spoolss_JobInfo1 *r)
2265 printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", r->position, r->job_id,
2266 r->user_name, r->document_name, r->text_status, r->pages_printed,
2270 /****************************************************************************
2271 ****************************************************************************/
2273 static void display_job_info2(struct spoolss_JobInfo2 *r)
2275 printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n",
2276 r->position, r->job_id,
2277 r->user_name, r->document_name, r->text_status, r->pages_printed,
2278 r->total_pages, r->size);
2281 /****************************************************************************
2282 ****************************************************************************/
2284 static void display_job_info3(struct spoolss_JobInfo3 *r)
2286 printf("jobid[%d], next_jobid[%d]\n",
2287 r->job_id, r->next_job_id);
2290 /****************************************************************************
2291 ****************************************************************************/
2293 static void display_job_info4(struct spoolss_JobInfo4 *r)
2295 printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d/%d bytes\n",
2296 r->position, r->job_id,
2297 r->user_name, r->document_name, r->text_status, r->pages_printed,
2298 r->total_pages, r->size, r->size_high);
2301 /****************************************************************************
2302 ****************************************************************************/
2304 static WERROR cmd_spoolss_enum_jobs(struct rpc_pipe_client *cli,
2305 TALLOC_CTX *mem_ctx, int argc,
2309 uint32_t level = 1, count, i;
2310 const char *printername;
2312 union spoolss_JobInfo *info;
2314 if (argc < 2 || argc > 3) {
2315 printf("Usage: %s printername [level]\n", argv[0]);
2320 level = atoi(argv[2]);
2323 /* Open printer handle */
2325 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2327 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2329 SEC_FLAG_MAXIMUM_ALLOWED,
2331 if (!W_ERROR_IS_OK(result))
2334 /* Enumerate ports */
2336 result = rpccli_spoolss_enumjobs(cli, mem_ctx,
2344 if (!W_ERROR_IS_OK(result)) {
2348 for (i = 0; i < count; i++) {
2351 display_job_info1(&info[i].info1);
2354 display_job_info2(&info[i].info2);
2357 d_printf("unknown info level %d\n", level);
2363 if (is_valid_policy_hnd(&hnd)) {
2364 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2370 /****************************************************************************
2371 ****************************************************************************/
2373 static WERROR cmd_spoolss_get_job(struct rpc_pipe_client *cli,
2374 TALLOC_CTX *mem_ctx, int argc,
2378 const char *printername;
2379 struct policy_handle hnd;
2382 union spoolss_JobInfo info;
2384 if (argc < 3 || argc > 4) {
2385 printf("Usage: %s printername job_id [level]\n", argv[0]);
2389 job_id = atoi(argv[2]);
2392 level = atoi(argv[3]);
2395 /* Open printer handle */
2397 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2399 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2401 SEC_FLAG_MAXIMUM_ALLOWED,
2403 if (!W_ERROR_IS_OK(result)) {
2407 /* Enumerate ports */
2409 result = rpccli_spoolss_getjob(cli, mem_ctx,
2416 if (!W_ERROR_IS_OK(result)) {
2422 display_job_info1(&info.info1);
2425 display_job_info2(&info.info2);
2428 display_job_info3(&info.info3);
2431 display_job_info4(&info.info4);
2434 d_printf("unknown info level %d\n", level);
2439 if (is_valid_policy_hnd(&hnd)) {
2440 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2447 /****************************************************************************
2448 ****************************************************************************/
2450 static WERROR cmd_spoolss_enum_data(struct rpc_pipe_client *cli,
2451 TALLOC_CTX *mem_ctx, int argc,
2457 const char *printername;
2459 uint32_t value_offered = 0;
2460 const char *value_name = NULL;
2461 uint32_t value_needed;
2462 enum winreg_Type type;
2463 uint8_t *data = NULL;
2464 uint32_t data_offered = 0;
2465 uint32_t data_needed;
2468 printf("Usage: %s printername\n", argv[0]);
2472 /* Open printer handle */
2474 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2476 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2478 SEC_FLAG_MAXIMUM_ALLOWED,
2480 if (!W_ERROR_IS_OK(result)) {
2484 /* Enumerate data */
2486 status = rpccli_spoolss_EnumPrinterData(cli, mem_ctx,
2498 data_offered = data_needed;
2499 value_offered = value_needed;
2500 data = talloc_zero_array(mem_ctx, uint8_t, data_needed);
2501 value_name = talloc_zero_array(mem_ctx, char, value_needed);
2503 while (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(result)) {
2505 status = rpccli_spoolss_EnumPrinterData(cli, mem_ctx,
2516 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(result)) {
2518 fstrcpy(v.valuename, value_name);
2520 v.size = data_offered;
2522 display_reg_value(v);
2526 if (W_ERROR_V(result) == ERRnomoreitems) {
2527 result = W_ERROR(ERRsuccess);
2531 if (is_valid_policy_hnd(&hnd)) {
2532 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2538 /****************************************************************************
2539 ****************************************************************************/
2541 static WERROR cmd_spoolss_enum_data_ex( struct rpc_pipe_client *cli,
2542 TALLOC_CTX *mem_ctx, int argc,
2547 const char *printername;
2550 struct spoolss_PrinterEnumValues *info;
2553 printf("Usage: %s printername <keyname>\n", argv[0]);
2557 /* Open printer handle */
2559 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2561 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2563 SEC_FLAG_MAXIMUM_ALLOWED,
2565 if (!W_ERROR_IS_OK(result)) {
2569 /* Enumerate subkeys */
2571 result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx,
2577 if (!W_ERROR_IS_OK(result)) {
2581 for (i=0; i < count; i++) {
2582 display_printer_data(info[i].value_name,
2588 if (is_valid_policy_hnd(&hnd)) {
2589 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2595 /****************************************************************************
2596 ****************************************************************************/
2598 static WERROR cmd_spoolss_enum_printerkey(struct rpc_pipe_client *cli,
2599 TALLOC_CTX *mem_ctx, int argc,
2603 const char *printername;
2604 const char *keyname = NULL;
2606 const char **key_buffer = NULL;
2609 if (argc < 2 || argc > 3) {
2610 printf("Usage: %s printername [keyname]\n", argv[0]);
2620 /* Open printer handle */
2622 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2624 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2626 SEC_FLAG_MAXIMUM_ALLOWED,
2628 if (!W_ERROR_IS_OK(result)) {
2632 /* Enumerate subkeys */
2634 result = rpccli_spoolss_enumprinterkey(cli, mem_ctx,
2640 if (!W_ERROR_IS_OK(result)) {
2644 for (i=0; key_buffer && key_buffer[i]; i++) {
2645 printf("%s\n", key_buffer[i]);
2650 if (is_valid_policy_hnd(&hnd)) {
2651 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2657 /****************************************************************************
2658 ****************************************************************************/
2660 static WERROR cmd_spoolss_rffpcnex(struct rpc_pipe_client *cli,
2661 TALLOC_CTX *mem_ctx, int argc,
2664 const char *printername;
2665 const char *clientname;
2669 struct spoolss_NotifyOption option;
2672 printf("Usage: %s printername\n", argv[0]);
2679 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2681 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2683 SEC_FLAG_MAXIMUM_ALLOWED,
2685 if (!W_ERROR_IS_OK(result)) {
2686 printf("Error opening %s\n", argv[1]);
2690 /* Create spool options */
2695 option.types = talloc_array(mem_ctx, struct spoolss_NotifyOptionType, 2);
2696 if (option.types == NULL) {
2697 result = WERR_NOMEM;
2701 option.types[0].type = PRINTER_NOTIFY_TYPE;
2702 option.types[0].count = 1;
2703 option.types[0].fields = talloc_array(mem_ctx, enum spoolss_Field, 1);
2704 if (option.types[0].fields == NULL) {
2705 result = WERR_NOMEM;
2708 option.types[0].fields[0] = PRINTER_NOTIFY_SERVER_NAME;
2710 option.types[1].type = JOB_NOTIFY_TYPE;
2711 option.types[1].count = 1;
2712 option.types[1].fields = talloc_array(mem_ctx, enum spoolss_Field, 1);
2713 if (option.types[1].fields == NULL) {
2714 result = WERR_NOMEM;
2717 option.types[1].fields[0] = JOB_NOTIFY_PRINTER_NAME;
2719 clientname = talloc_asprintf(mem_ctx, "\\\\%s", global_myname());
2721 result = WERR_NOMEM;
2727 status = rpccli_spoolss_RemoteFindFirstPrinterChangeNotifyEx(cli, mem_ctx,
2735 if (!W_ERROR_IS_OK(result)) {
2736 printf("Error rffpcnex %s\n", argv[1]);
2741 if (is_valid_policy_hnd(&hnd))
2742 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2747 /****************************************************************************
2748 ****************************************************************************/
2750 static bool compare_printer( struct rpc_pipe_client *cli1, POLICY_HND *hnd1,
2751 struct rpc_pipe_client *cli2, POLICY_HND *hnd2 )
2753 union spoolss_PrinterInfo info1, info2;
2755 TALLOC_CTX *mem_ctx = talloc_init("compare_printer");
2757 printf("Retrieving printer propertiesfor %s...", cli1->desthost);
2758 werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
2763 if ( !W_ERROR_IS_OK(werror) ) {
2764 printf("failed (%s)\n", win_errstr(werror));
2765 talloc_destroy(mem_ctx);
2770 printf("Retrieving printer properties for %s...", cli2->desthost);
2771 werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
2776 if ( !W_ERROR_IS_OK(werror) ) {
2777 printf("failed (%s)\n", win_errstr(werror));
2778 talloc_destroy(mem_ctx);
2783 talloc_destroy(mem_ctx);
2788 /****************************************************************************
2789 ****************************************************************************/
2791 static bool compare_printer_secdesc( struct rpc_pipe_client *cli1, POLICY_HND *hnd1,
2792 struct rpc_pipe_client *cli2, POLICY_HND *hnd2 )
2794 union spoolss_PrinterInfo info1, info2;
2796 TALLOC_CTX *mem_ctx = talloc_init("compare_printer_secdesc");
2797 SEC_DESC *sd1, *sd2;
2801 printf("Retrieving printer security for %s...", cli1->desthost);
2802 werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
2807 if ( !W_ERROR_IS_OK(werror) ) {
2808 printf("failed (%s)\n", win_errstr(werror));
2814 printf("Retrieving printer security for %s...", cli2->desthost);
2815 werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
2820 if ( !W_ERROR_IS_OK(werror) ) {
2821 printf("failed (%s)\n", win_errstr(werror));
2830 sd1 = info1.info3.secdesc;
2831 sd2 = info2.info3.secdesc;
2833 if ( (sd1 != sd2) && ( !sd1 || !sd2 ) ) {
2834 printf("NULL secdesc!\n");
2839 if (!sec_desc_equal( sd1, sd2 ) ) {
2840 printf("Security Descriptors *not* equal!\n");
2845 printf("Security descriptors match\n");
2848 talloc_destroy(mem_ctx);
2853 /****************************************************************************
2854 ****************************************************************************/
2856 extern struct user_auth_info *rpcclient_auth_info;
2858 static WERROR cmd_spoolss_printercmp(struct rpc_pipe_client *cli,
2859 TALLOC_CTX *mem_ctx, int argc,
2862 const char *printername;
2863 char *printername_path = NULL;
2864 struct cli_state *cli_server2 = NULL;
2865 struct rpc_pipe_client *cli2 = NULL;
2866 POLICY_HND hPrinter1, hPrinter2;
2871 printf("Usage: %s <printer> <server>\n", argv[0]);
2875 printername = argv[1];
2877 /* first get the connection to the remote server */
2879 nt_status = cli_full_connection(&cli_server2, global_myname(), argv[2],
2882 get_cmdline_auth_info_username(rpcclient_auth_info),
2884 get_cmdline_auth_info_password(rpcclient_auth_info),
2885 get_cmdline_auth_info_use_kerberos(rpcclient_auth_info) ? CLI_FULL_CONNECTION_USE_KERBEROS : 0,
2886 get_cmdline_auth_info_signing_state(rpcclient_auth_info), NULL);
2888 if ( !NT_STATUS_IS_OK(nt_status) )
2889 return WERR_GENERAL_FAILURE;
2891 nt_status = cli_rpc_pipe_open_noauth(cli_server2, &syntax_spoolss,
2893 if (!NT_STATUS_IS_OK(nt_status)) {
2894 printf("failed to open spoolss pipe on server %s (%s)\n",
2895 argv[2], nt_errstr(nt_status));
2896 return WERR_GENERAL_FAILURE;
2899 /* now open up both printers */
2901 RPCCLIENT_PRINTERNAME(printername_path, cli, printername);
2903 printf("Opening %s...", printername_path);
2905 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2909 if ( !W_ERROR_IS_OK(werror) ) {
2910 printf("failed (%s)\n", win_errstr(werror));
2915 RPCCLIENT_PRINTERNAME(printername_path, cli2, printername);
2917 printf("Opening %s...", printername_path);
2918 werror = rpccli_spoolss_openprinter_ex(cli2, mem_ctx,
2922 if ( !W_ERROR_IS_OK(werror) ) {
2923 printf("failed (%s)\n", win_errstr(werror));
2928 compare_printer( cli, &hPrinter1, cli2, &hPrinter2 );
2929 compare_printer_secdesc( cli, &hPrinter1, cli2, &hPrinter2 );
2931 compare_printerdata( cli_server1, &hPrinter1, cli_server2, &hPrinter2 );
2938 printf("Closing printers...");
2939 rpccli_spoolss_ClosePrinter( cli, mem_ctx, &hPrinter1, NULL );
2940 rpccli_spoolss_ClosePrinter( cli2, mem_ctx, &hPrinter2, NULL );
2943 /* close the second remote connection */
2945 cli_shutdown( cli_server2 );
2949 static void display_proc_info1(struct spoolss_PrintProcessorInfo1 *r)
2951 printf("print_processor_name: %s\n", r->print_processor_name);
2954 static WERROR cmd_spoolss_enum_procs(struct rpc_pipe_client *cli,
2955 TALLOC_CTX *mem_ctx, int argc,
2959 const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
2960 uint32_t num_procs, level = 1, i;
2961 union spoolss_PrintProcessorInfo *procs;
2963 /* Parse the command arguments */
2965 if (argc < 1 || argc > 4) {
2966 printf ("Usage: %s [environment] [level]\n", argv[0]);
2971 environment = argv[1];
2975 level = atoi(argv[2]);
2978 /* Enumerate Print Processors */
2980 werror = rpccli_spoolss_enumprintprocessors(cli, mem_ctx,
2981 cli->srv_name_slash,
2987 if (!W_ERROR_IS_OK(werror))
2990 /* Display output */
2992 for (i = 0; i < num_procs; i++) {
2995 display_proc_info1(&procs[i].info1);
3004 static void display_proc_data_types_info1(struct spoolss_PrintProcDataTypesInfo1 *r)
3006 printf("name_array: %s\n", r->name_array);
3009 static WERROR cmd_spoolss_enum_proc_data_types(struct rpc_pipe_client *cli,
3010 TALLOC_CTX *mem_ctx, int argc,
3014 const char *print_processor_name = "winprint";
3015 uint32_t num_procs, level = 1, i;
3016 union spoolss_PrintProcDataTypesInfo *procs;
3018 /* Parse the command arguments */
3020 if (argc < 1 || argc > 4) {
3021 printf ("Usage: %s [environment] [level]\n", argv[0]);
3026 print_processor_name = argv[1];
3030 level = atoi(argv[2]);
3033 /* Enumerate Print Processor Data Types */
3035 werror = rpccli_spoolss_enumprintprocessordatatypes(cli, mem_ctx,
3036 cli->srv_name_slash,
3037 print_processor_name,
3042 if (!W_ERROR_IS_OK(werror))
3045 /* Display output */
3047 for (i = 0; i < num_procs; i++) {
3050 display_proc_data_types_info1(&procs[i].info1);
3059 static void display_monitor1(const struct spoolss_MonitorInfo1 *r)
3061 printf("monitor_name: %s\n", r->monitor_name);
3064 static void display_monitor2(const struct spoolss_MonitorInfo2 *r)
3066 printf("monitor_name: %s\n", r->monitor_name);
3067 printf("environment: %s\n", r->environment);
3068 printf("dll_name: %s\n", r->dll_name);
3071 static WERROR cmd_spoolss_enum_monitors(struct rpc_pipe_client *cli,
3072 TALLOC_CTX *mem_ctx, int argc,
3076 uint32_t count, level = 1, i;
3077 union spoolss_MonitorInfo *info;
3079 /* Parse the command arguments */
3082 printf("Usage: %s [level]\n", argv[0]);
3087 level = atoi(argv[1]);
3090 /* Enumerate Print Monitors */
3092 werror = rpccli_spoolss_enummonitors(cli, mem_ctx,
3093 cli->srv_name_slash,
3098 if (!W_ERROR_IS_OK(werror)) {
3102 /* Display output */
3104 for (i = 0; i < count; i++) {
3107 display_monitor1(&info[i].info1);
3110 display_monitor2(&info[i].info2);
3119 /* List of commands exported by this module */
3120 struct cmd_set spoolss_commands[] = {
3124 { "adddriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterdriver, &syntax_spoolss, NULL, "Add a print driver", "" },
3125 { "addprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterex, &syntax_spoolss, NULL, "Add a printer", "" },
3126 { "deldriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriver, &syntax_spoolss, NULL, "Delete a printer driver", "" },
3127 { "deldriverex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriverex, &syntax_spoolss, NULL, "Delete a printer driver with files", "" },
3128 { "enumdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data, &syntax_spoolss, NULL, "Enumerate printer data", "" },
3129 { "enumdataex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data_ex, &syntax_spoolss, NULL, "Enumerate printer data for a key", "" },
3130 { "enumkey", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printerkey, &syntax_spoolss, NULL, "Enumerate printer keys", "" },
3131 { "enumjobs", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_jobs, &syntax_spoolss, NULL, "Enumerate print jobs", "" },
3132 { "getjob", RPC_RTYPE_WERROR, NULL, cmd_spoolss_get_job, &syntax_spoolss, NULL, "Get print job", "" },
3133 { "enumports", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_ports, &syntax_spoolss, NULL, "Enumerate printer ports", "" },
3134 { "enumdrivers", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_drivers, &syntax_spoolss, NULL, "Enumerate installed printer drivers", "" },
3135 { "enumprinters", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printers, &syntax_spoolss, NULL, "Enumerate printers", "" },
3136 { "getdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdata, &syntax_spoolss, NULL, "Get print driver data", "" },
3137 { "getdataex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdataex, &syntax_spoolss, NULL, "Get printer driver data with keyname", ""},
3138 { "getdriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriver, &syntax_spoolss, NULL, "Get print driver information", "" },
3139 { "getdriverdir", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriverdir, &syntax_spoolss, NULL, "Get print driver upload directory", "" },
3140 { "getprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinter, &syntax_spoolss, NULL, "Get printer info", "" },
3141 { "openprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer_ex, &syntax_spoolss, NULL, "Open printer handle", "" },
3142 { "setdriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setdriver, &syntax_spoolss, NULL, "Set printer driver", "" },
3143 { "getprintprocdir", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprintprocdir, &syntax_spoolss, NULL, "Get print processor directory", "" },
3144 { "addform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addform, &syntax_spoolss, NULL, "Add form", "" },
3145 { "setform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setform, &syntax_spoolss, NULL, "Set form", "" },
3146 { "getform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getform, &syntax_spoolss, NULL, "Get form", "" },
3147 { "deleteform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform, &syntax_spoolss, NULL, "Delete form", "" },
3148 { "enumforms", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms, &syntax_spoolss, NULL, "Enumerate forms", "" },
3149 { "setprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter, &syntax_spoolss, NULL, "Set printer comment", "" },
3150 { "setprintername", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername, &syntax_spoolss, NULL, "Set printername", "" },
3151 { "setprinterdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata, &syntax_spoolss, NULL, "Set REG_SZ printer data", "" },
3152 { "rffpcnex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex, &syntax_spoolss, NULL, "Rffpcnex test", "" },
3153 { "printercmp", RPC_RTYPE_WERROR, NULL, cmd_spoolss_printercmp, &syntax_spoolss, NULL, "Printer comparison test", "" },
3154 { "enumprocs", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_procs, &syntax_spoolss, NULL, "Enumerate Print Processors", "" },
3155 { "enumprocdatatypes", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_proc_data_types, &syntax_spoolss, NULL, "Enumerate Print Processor Data Types", "" },
3156 { "enummonitors", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_monitors, &syntax_spoolss, NULL, "Enumerate Print Monitors", "" },