/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- cmd_spoolss_get_short_archi
- cmd_spoolss_open_printer_ex
- display_print_info0
- display_print_info1
- display_print_info2
- display_print_info3
- display_print_info4
- display_print_info5
- display_print_info6
- display_print_info7
- cmd_spoolss_enum_printers
- display_port_info_1
- display_port_info_2
- cmd_spoolss_enum_ports
- cmd_spoolss_setprinter
- cmd_spoolss_setprintername
- cmd_spoolss_getprinter
- display_reg_value
- display_printer_data
- cmd_spoolss_getprinterdata
- cmd_spoolss_getprinterdataex
- display_print_driver1
- display_print_driver2
- display_print_driver3
- display_print_driver4
- display_print_driver5
- display_print_driver6
- display_print_driver8
- cmd_spoolss_getdriver
- enum_driver_by_architecture
- cmd_spoolss_enum_drivers
- display_printdriverdir_1
- cmd_spoolss_getdriverdir
- set_drv_info_3_env
- get_driver_3_param
- init_drv_info_3_members
- cmd_spoolss_addprinterdriver
- cmd_spoolss_addprinterex
- cmd_spoolss_setdriver
- cmd_spoolss_deletedriverex
- cmd_spoolss_deletedriver
- cmd_spoolss_getprintprocdir
- cmd_spoolss_addform
- cmd_spoolss_setform
- get_form_flag
- display_form_info1
- display_form_info2
- cmd_spoolss_getform
- cmd_spoolss_deleteform
- cmd_spoolss_enum_forms
- cmd_spoolss_setprinterdata
- display_job_info1
- display_job_info2
- display_job_info3
- display_job_info4
- cmd_spoolss_enum_jobs
- cmd_spoolss_get_job
- cmd_spoolss_set_job
- cmd_spoolss_enum_data
- cmd_spoolss_enum_data_ex
- cmd_spoolss_enum_printerkey
- cmd_spoolss_rffpcnex
- compare_printer
- compare_printer_secdesc
- cmd_spoolss_printercmp
- display_proc_info1
- cmd_spoolss_enum_procs
- display_proc_data_types_info1
- cmd_spoolss_enum_proc_data_types
- display_monitor1
- display_monitor2
- cmd_spoolss_enum_monitors
1 /*
2 Unix SMB/CIFS implementation.
3 RPC pipe client
4
5 Copyright (C) Gerald Carter 2001-2005
6 Copyright (C) Tim Potter 2000
7 Copyright (C) Andrew Tridgell 1992-1999
8 Copyright (C) Luke Kenneth Casson Leighton 1996-1999
9 Copyright (C) Guenther Deschner 2009
10
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.
15
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.
20
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/>.
23 */
24
25 #include "includes.h"
26 #include "rpcclient.h"
27
28 #define RPCCLIENT_PRINTERNAME(_printername, _cli, _arg) \
29 { \
30 _printername = talloc_asprintf_strupper_m(mem_ctx, "%s\\%s", \
31 _cli->srv_name_slash, _arg); \
32 W_ERROR_HAVE_NO_MEMORY(_printername); \
33 }
34
35 /* The version int is used by getdrivers. Note that
36 all architecture strings that support mutliple
37 versions must be grouped together since enumdrivers
38 uses this property to prevent issuing multiple
39 enumdriver calls for the same arch */
40
41
42 static const struct print_architecture_table_node archi_table[]= {
43
44 {"Windows 4.0", "WIN40", 0 },
45 {"Windows NT x86", "W32X86", 2 },
46 {"Windows NT x86", "W32X86", 3 },
47 {"Windows NT R4000", "W32MIPS", 2 },
48 {"Windows NT Alpha_AXP", "W32ALPHA", 2 },
49 {"Windows NT PowerPC", "W32PPC", 2 },
50 {"Windows IA64", "IA64", 3 },
51 {"Windows x64", "x64", 3 },
52 {NULL, "", -1 }
53 };
54
55 /**
56 * @file
57 *
58 * rpcclient module for SPOOLSS rpc pipe.
59 *
60 * This generally just parses and checks command lines, and then calls
61 * a cli_spoolss function.
62 **/
63
64 /****************************************************************************
65 function to do the mapping between the long architecture name and
66 the short one.
67 ****************************************************************************/
68
69 static const char *cmd_spoolss_get_short_archi(const char *long_archi)
/* [<][>][^][v][top][bottom][index][help] */
70 {
71 int i=-1;
72
73 DEBUG(107,("Getting architecture dependant directory\n"));
74 do {
75 i++;
76 } while ( (archi_table[i].long_archi!=NULL ) &&
77 StrCaseCmp(long_archi, archi_table[i].long_archi) );
78
79 if (archi_table[i].long_archi==NULL) {
80 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
81 return NULL;
82 }
83
84 /* this might be client code - but shouldn't this be an fstrcpy etc? */
85
86
87 DEBUGADD(108,("index: [%d]\n", i));
88 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
89 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
90
91 return archi_table[i].short_archi;
92 }
93
94 /****************************************************************************
95 ****************************************************************************/
96
97 static WERROR cmd_spoolss_open_printer_ex(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
98 TALLOC_CTX *mem_ctx,
99 int argc, const char **argv)
100 {
101 WERROR werror;
102 struct policy_handle hnd;
103
104 if (argc != 2) {
105 printf("Usage: %s <printername>\n", argv[0]);
106 return WERR_OK;
107 }
108
109 if (!cli)
110 return WERR_GENERAL_FAILURE;
111
112 /* Open the printer handle */
113
114 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
115 argv[1],
116 PRINTER_ALL_ACCESS,
117 &hnd);
118 if (W_ERROR_IS_OK(werror)) {
119 printf("Printer %s opened successfully\n", argv[1]);
120 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, &werror);
121
122 if (!W_ERROR_IS_OK(werror)) {
123 printf("Error closing printer handle! (%s)\n",
124 get_dos_error_msg(werror));
125 }
126 }
127
128 return werror;
129 }
130
131
132 /****************************************************************************
133 ****************************************************************************/
134
135 static void display_print_info0(struct spoolss_PrinterInfo0 *r)
/* [<][>][^][v][top][bottom][index][help] */
136 {
137 if (!r)
138 return;
139
140 printf("\tprintername:[%s]\n", r->printername);
141 printf("\tservername:[%s]\n", r->servername);
142 printf("\tcjobs:[0x%x]\n", r->cjobs);
143 printf("\ttotal_jobs:[0x%x]\n", r->total_jobs);
144 printf("\ttotal_bytes:[0x%x]\n", r->total_bytes);
145 printf("\t:date: [%d]-[%d]-[%d] (%d)\n", r->time.year, r->time.month,
146 r->time.day, r->time.day_of_week);
147 printf("\t:time: [%d]-[%d]-[%d]-[%d]\n", r->time.hour, r->time.minute,
148 r->time.second, r->time.millisecond);
149
150 printf("\tglobal_counter:[0x%x]\n", r->global_counter);
151 printf("\ttotal_pages:[0x%x]\n", r->total_pages);
152
153 printf("\tversion:[0x%x]\n", r->version);
154 printf("\tfree_build:[0x%x]\n", r->free_build);
155 printf("\tspooling:[0x%x]\n", r->spooling);
156 printf("\tmax_spooling:[0x%x]\n", r->max_spooling);
157 printf("\tsession_counter:[0x%x]\n", r->session_counter);
158 printf("\tnum_error_out_of_paper:[0x%x]\n", r->num_error_out_of_paper);
159 printf("\tnum_error_not_ready:[0x%x]\n", r->num_error_not_ready);
160 printf("\tjob_error:[0x%x]\n", r->job_error);
161 printf("\tnumber_of_processors:[0x%x]\n", r->number_of_processors);
162 printf("\tprocessor_type:[0x%x]\n", r->processor_type);
163 printf("\thigh_part_total_bytes:[0x%x]\n", r->high_part_total_bytes);
164 printf("\tchange_id:[0x%x]\n", r->change_id);
165 printf("\tlast_error: %s\n", win_errstr(r->last_error));
166 printf("\tstatus:[0x%x]\n", r->status);
167 printf("\tenumerate_network_printers:[0x%x]\n", r->enumerate_network_printers);
168 printf("\tc_setprinter:[0x%x]\n", r->c_setprinter);
169 printf("\tprocessor_architecture:[0x%x]\n", r->processor_architecture);
170 printf("\tprocessor_level:[0x%x]\n", r->processor_level);
171 printf("\tref_ic:[0x%x]\n", r->ref_ic);
172 printf("\treserved2:[0x%x]\n", r->reserved2);
173 printf("\treserved3:[0x%x]\n", r->reserved3);
174
175 printf("\n");
176 }
177
178 /****************************************************************************
179 ****************************************************************************/
180
181 static void display_print_info1(struct spoolss_PrinterInfo1 *r)
/* [<][>][^][v][top][bottom][index][help] */
182 {
183 printf("\tflags:[0x%x]\n", r->flags);
184 printf("\tname:[%s]\n", r->name);
185 printf("\tdescription:[%s]\n", r->description);
186 printf("\tcomment:[%s]\n", r->comment);
187
188 printf("\n");
189 }
190
191 /****************************************************************************
192 ****************************************************************************/
193
194 static void display_print_info2(struct spoolss_PrinterInfo2 *r)
/* [<][>][^][v][top][bottom][index][help] */
195 {
196 printf("\tservername:[%s]\n", r->servername);
197 printf("\tprintername:[%s]\n", r->printername);
198 printf("\tsharename:[%s]\n", r->sharename);
199 printf("\tportname:[%s]\n", r->portname);
200 printf("\tdrivername:[%s]\n", r->drivername);
201 printf("\tcomment:[%s]\n", r->comment);
202 printf("\tlocation:[%s]\n", r->location);
203 printf("\tsepfile:[%s]\n", r->sepfile);
204 printf("\tprintprocessor:[%s]\n", r->printprocessor);
205 printf("\tdatatype:[%s]\n", r->datatype);
206 printf("\tparameters:[%s]\n", r->parameters);
207 printf("\tattributes:[0x%x]\n", r->attributes);
208 printf("\tpriority:[0x%x]\n", r->priority);
209 printf("\tdefaultpriority:[0x%x]\n", r->defaultpriority);
210 printf("\tstarttime:[0x%x]\n", r->starttime);
211 printf("\tuntiltime:[0x%x]\n", r->untiltime);
212 printf("\tstatus:[0x%x]\n", r->status);
213 printf("\tcjobs:[0x%x]\n", r->cjobs);
214 printf("\taverageppm:[0x%x]\n", r->averageppm);
215
216 if (r->secdesc)
217 display_sec_desc(r->secdesc);
218
219 printf("\n");
220 }
221
222 /****************************************************************************
223 ****************************************************************************/
224
225 static void display_print_info3(struct spoolss_PrinterInfo3 *r)
/* [<][>][^][v][top][bottom][index][help] */
226 {
227 display_sec_desc(r->secdesc);
228
229 printf("\n");
230 }
231
232 /****************************************************************************
233 ****************************************************************************/
234
235 static void display_print_info4(struct spoolss_PrinterInfo4 *r)
/* [<][>][^][v][top][bottom][index][help] */
236 {
237 printf("\tservername:[%s]\n", r->servername);
238 printf("\tprintername:[%s]\n", r->printername);
239 printf("\tattributes:[0x%x]\n", r->attributes);
240 printf("\n");
241 }
242
243 /****************************************************************************
244 ****************************************************************************/
245
246 static void display_print_info5(struct spoolss_PrinterInfo5 *r)
/* [<][>][^][v][top][bottom][index][help] */
247 {
248 printf("\tprintername:[%s]\n", r->printername);
249 printf("\tportname:[%s]\n", r->portname);
250 printf("\tattributes:[0x%x]\n", r->attributes);
251 printf("\tdevice_not_selected_timeout:[0x%x]\n", r->device_not_selected_timeout);
252 printf("\ttransmission_retry_timeout:[0x%x]\n", r->transmission_retry_timeout);
253 printf("\n");
254 }
255
256 /****************************************************************************
257 ****************************************************************************/
258
259 static void display_print_info6(struct spoolss_PrinterInfo6 *r)
/* [<][>][^][v][top][bottom][index][help] */
260 {
261 printf("\tstatus:[0x%x]\n", r->status);
262 printf("\n");
263 }
264
265 /****************************************************************************
266 ****************************************************************************/
267
268 static void display_print_info7(struct spoolss_PrinterInfo7 *r)
/* [<][>][^][v][top][bottom][index][help] */
269 {
270 printf("\tguid:[%s]\n", r->guid);
271 printf("\taction:[0x%x]\n", r->action);
272 printf("\n");
273 }
274
275 /****************************************************************************
276 ****************************************************************************/
277
278 static WERROR cmd_spoolss_enum_printers(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
279 TALLOC_CTX *mem_ctx,
280 int argc, const char **argv)
281 {
282 WERROR result;
283 uint32_t level = 1;
284 union spoolss_PrinterInfo *info;
285 uint32_t i, count;
286 const char *name;
287 uint32_t flags = PRINTER_ENUM_LOCAL;
288
289 if (argc > 4) {
290 printf("Usage: %s [level] [name] [flags]\n", argv[0]);
291 return WERR_OK;
292 }
293
294 if (argc >= 2) {
295 level = atoi(argv[1]);
296 }
297
298 if (argc >= 3) {
299 name = argv[2];
300 } else {
301 name = cli->srv_name_slash;
302 }
303
304 if (argc == 4) {
305 flags = atoi(argv[3]);
306 }
307
308 result = rpccli_spoolss_enumprinters(cli, mem_ctx,
309 flags,
310 name,
311 level,
312 0,
313 &count,
314 &info);
315 if (W_ERROR_IS_OK(result)) {
316
317 if (!count) {
318 printf ("No printers returned.\n");
319 goto done;
320 }
321
322 for (i = 0; i < count; i++) {
323 switch (level) {
324 case 0:
325 display_print_info0(&info[i].info0);
326 break;
327 case 1:
328 display_print_info1(&info[i].info1);
329 break;
330 case 2:
331 display_print_info2(&info[i].info2);
332 break;
333 case 3:
334 display_print_info3(&info[i].info3);
335 break;
336 case 4:
337 display_print_info4(&info[i].info4);
338 break;
339 case 5:
340 display_print_info5(&info[i].info5);
341 break;
342 case 6:
343 display_print_info6(&info[i].info6);
344 break;
345 default:
346 printf("unknown info level %d\n", level);
347 goto done;
348 }
349 }
350 }
351 done:
352
353 return result;
354 }
355
356 /****************************************************************************
357 ****************************************************************************/
358
359 static void display_port_info_1(struct spoolss_PortInfo1 *r)
/* [<][>][^][v][top][bottom][index][help] */
360 {
361 printf("\tPort Name:\t[%s]\n", r->port_name);
362 }
363
364 /****************************************************************************
365 ****************************************************************************/
366
367 static void display_port_info_2(struct spoolss_PortInfo2 *r)
/* [<][>][^][v][top][bottom][index][help] */
368 {
369 printf("\tPort Name:\t[%s]\n", r->port_name);
370 printf("\tMonitor Name:\t[%s]\n", r->monitor_name);
371 printf("\tDescription:\t[%s]\n", r->description);
372 printf("\tPort Type:\t" );
373 if (r->port_type) {
374 int comma = 0; /* hack */
375 printf( "[" );
376 if (r->port_type & SPOOLSS_PORT_TYPE_READ) {
377 printf( "Read" );
378 comma = 1;
379 }
380 if (r->port_type & SPOOLSS_PORT_TYPE_WRITE) {
381 printf( "%sWrite", comma ? ", " : "" );
382 comma = 1;
383 }
384 /* These two have slightly different interpretations
385 on 95/98/ME but I'm disregarding that for now */
386 if (r->port_type & SPOOLSS_PORT_TYPE_REDIRECTED) {
387 printf( "%sRedirected", comma ? ", " : "" );
388 comma = 1;
389 }
390 if (r->port_type & SPOOLSS_PORT_TYPE_NET_ATTACHED) {
391 printf( "%sNet-Attached", comma ? ", " : "" );
392 }
393 printf( "]\n" );
394 } else {
395 printf( "[Unset]\n" );
396 }
397 printf("\tReserved:\t[%d]\n", r->reserved);
398 printf("\n");
399 }
400
401 /****************************************************************************
402 ****************************************************************************/
403
404 static WERROR cmd_spoolss_enum_ports(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
405 TALLOC_CTX *mem_ctx, int argc,
406 const char **argv)
407 {
408 WERROR result;
409 uint32_t level = 1;
410 uint32_t count;
411 union spoolss_PortInfo *info;
412
413 if (argc > 2) {
414 printf("Usage: %s [level]\n", argv[0]);
415 return WERR_OK;
416 }
417
418 if (argc == 2) {
419 level = atoi(argv[1]);
420 }
421
422 /* Enumerate ports */
423
424 result = rpccli_spoolss_enumports(cli, mem_ctx,
425 cli->srv_name_slash,
426 level,
427 0,
428 &count,
429 &info);
430 if (W_ERROR_IS_OK(result)) {
431 int i;
432
433 for (i = 0; i < count; i++) {
434 switch (level) {
435 case 1:
436 display_port_info_1(&info[i].info1);
437 break;
438 case 2:
439 display_port_info_2(&info[i].info2);
440 break;
441 default:
442 printf("unknown info level %d\n", level);
443 break;
444 }
445 }
446 }
447
448 return result;
449 }
450
451 /****************************************************************************
452 ****************************************************************************/
453
454 static WERROR cmd_spoolss_setprinter(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
455 TALLOC_CTX *mem_ctx,
456 int argc, const char **argv)
457 {
458 struct policy_handle pol;
459 WERROR result;
460 NTSTATUS status;
461 uint32_t info_level = 2;
462 union spoolss_PrinterInfo info;
463 struct spoolss_SetPrinterInfoCtr info_ctr;
464 const char *printername, *comment = NULL;
465 struct spoolss_DevmodeContainer devmode_ctr;
466 struct sec_desc_buf secdesc_ctr;
467
468 if (argc == 1 || argc > 3) {
469 printf("Usage: %s printername comment\n", argv[0]);
470
471 return WERR_OK;
472 }
473
474 /* Open a printer handle */
475 if (argc == 3) {
476 comment = argv[2];
477 }
478
479 ZERO_STRUCT(devmode_ctr);
480 ZERO_STRUCT(secdesc_ctr);
481
482 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
483
484 /* get a printer handle */
485 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
486 printername,
487 PRINTER_ALL_ACCESS,
488 &pol);
489 if (!W_ERROR_IS_OK(result))
490 goto done;
491
492 /* Get printer info */
493 result = rpccli_spoolss_getprinter(cli, mem_ctx,
494 &pol,
495 info_level,
496 0,
497 &info);
498 if (!W_ERROR_IS_OK(result))
499 goto done;
500
501
502 /* Modify the comment. */
503 info.info2.comment = comment;
504 info.info2.secdesc = NULL;
505 info.info2.devmode = NULL;
506
507 info_ctr.level = 2;
508 info_ctr.info.info2 = (struct spoolss_SetPrinterInfo2 *)&info.info2;
509
510 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
511 &pol,
512 &info_ctr,
513 &devmode_ctr,
514 &secdesc_ctr,
515 0, /* command */
516 &result);
517 if (W_ERROR_IS_OK(result))
518 printf("Success in setting comment.\n");
519
520 done:
521 if (is_valid_policy_hnd(&pol))
522 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
523
524 return result;
525 }
526
527 /****************************************************************************
528 ****************************************************************************/
529
530 static WERROR cmd_spoolss_setprintername(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
531 TALLOC_CTX *mem_ctx,
532 int argc, const char **argv)
533 {
534 struct policy_handle pol;
535 WERROR result;
536 NTSTATUS status;
537 uint32_t info_level = 2;
538 union spoolss_PrinterInfo info;
539 const char *printername,
540 *new_printername = NULL;
541 struct spoolss_SetPrinterInfoCtr info_ctr;
542 struct spoolss_DevmodeContainer devmode_ctr;
543 struct sec_desc_buf secdesc_ctr;
544
545 ZERO_STRUCT(devmode_ctr);
546 ZERO_STRUCT(secdesc_ctr);
547
548 if (argc == 1 || argc > 3) {
549 printf("Usage: %s printername new_printername\n", argv[0]);
550
551 return WERR_OK;
552 }
553
554 /* Open a printer handle */
555 if (argc == 3) {
556 new_printername = argv[2];
557 }
558
559 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
560
561 /* get a printer handle */
562 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
563 printername,
564 PRINTER_ALL_ACCESS,
565 &pol);
566 if (!W_ERROR_IS_OK(result))
567 goto done;
568
569 /* Get printer info */
570 result = rpccli_spoolss_getprinter(cli, mem_ctx,
571 &pol,
572 info_level,
573 0,
574 &info);
575 if (!W_ERROR_IS_OK(result))
576 goto done;
577
578 /* Modify the printername. */
579 info.info2.printername = new_printername;
580 info.info2.devmode = NULL;
581 info.info2.secdesc = NULL;
582
583 info_ctr.level = info_level;
584 info_ctr.info.info2 = (struct spoolss_SetPrinterInfo2 *)&info.info2;
585
586 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
587 &pol,
588 &info_ctr,
589 &devmode_ctr,
590 &secdesc_ctr,
591 0, /* command */
592 &result);
593 if (W_ERROR_IS_OK(result))
594 printf("Success in setting printername.\n");
595
596 done:
597 if (is_valid_policy_hnd(&pol))
598 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
599
600 return result;
601 }
602
603 /****************************************************************************
604 ****************************************************************************/
605
606 static WERROR cmd_spoolss_getprinter(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
607 TALLOC_CTX *mem_ctx,
608 int argc, const char **argv)
609 {
610 struct policy_handle pol;
611 WERROR result;
612 uint32_t level = 1;
613 const char *printername;
614 union spoolss_PrinterInfo info;
615
616 if (argc == 1 || argc > 3) {
617 printf("Usage: %s <printername> [level]\n", argv[0]);
618 return WERR_OK;
619 }
620
621 /* Open a printer handle */
622 if (argc == 3) {
623 level = atoi(argv[2]);
624 }
625
626 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
627
628 /* get a printer handle */
629
630 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
631 printername,
632 SEC_FLAG_MAXIMUM_ALLOWED,
633 &pol);
634 if (!W_ERROR_IS_OK(result)) {
635 goto done;
636 }
637
638 /* Get printer info */
639
640 result = rpccli_spoolss_getprinter(cli, mem_ctx,
641 &pol,
642 level,
643 0,
644 &info);
645 if (!W_ERROR_IS_OK(result)) {
646 goto done;
647 }
648
649 /* Display printer info */
650 switch (level) {
651 case 0:
652 display_print_info0(&info.info0);
653 break;
654 case 1:
655 display_print_info1(&info.info1);
656 break;
657 case 2:
658 display_print_info2(&info.info2);
659 break;
660 case 3:
661 display_print_info3(&info.info3);
662 break;
663 case 4:
664 display_print_info4(&info.info4);
665 break;
666 case 5:
667 display_print_info5(&info.info5);
668 break;
669 case 6:
670 display_print_info6(&info.info6);
671 break;
672 case 7:
673 display_print_info7(&info.info7);
674 break;
675 default:
676 printf("unknown info level %d\n", level);
677 break;
678 }
679 done:
680 if (is_valid_policy_hnd(&pol)) {
681 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
682 }
683
684 return result;
685 }
686
687 /****************************************************************************
688 ****************************************************************************/
689
690 static void display_reg_value(REGISTRY_VALUE value)
/* [<][>][^][v][top][bottom][index][help] */
691 {
692 char *text = NULL;
693
694 switch(value.type) {
695 case REG_DWORD:
696 printf("%s: REG_DWORD: 0x%08x\n", value.valuename,
697 *((uint32_t *) value.data_p));
698 break;
699 case REG_SZ:
700 rpcstr_pull_talloc(talloc_tos(),
701 &text,
702 value.data_p,
703 value.size,
704 STR_TERMINATE);
705 printf("%s: REG_SZ: %s\n", value.valuename, text ? text : "");
706 break;
707 case REG_BINARY: {
708 char *hex = hex_encode_talloc(NULL, value.data_p, value.size);
709 size_t i, len;
710 printf("%s: REG_BINARY:", value.valuename);
711 len = strlen(hex);
712 for (i=0; i<len; i++) {
713 if (hex[i] == '\0') {
714 break;
715 }
716 if (i%40 == 0) {
717 putchar('\n');
718 }
719 putchar(hex[i]);
720 }
721 TALLOC_FREE(hex);
722 putchar('\n');
723 break;
724 }
725 case REG_MULTI_SZ: {
726 uint32_t i, num_values;
727 char **values;
728
729 if (!W_ERROR_IS_OK(reg_pull_multi_sz(NULL, value.data_p,
730 value.size, &num_values,
731 &values))) {
732 d_printf("reg_pull_multi_sz failed\n");
733 break;
734 }
735
736 printf("%s: REG_MULTI_SZ: \n", value.valuename);
737 for (i=0; i<num_values; i++) {
738 d_printf("%s\n", values[i]);
739 }
740 TALLOC_FREE(values);
741 break;
742 }
743 default:
744 printf("%s: unknown type %d\n", value.valuename, value.type);
745 }
746
747 }
748
749 /****************************************************************************
750 ****************************************************************************/
751
752 static void display_printer_data(const char *v,
/* [<][>][^][v][top][bottom][index][help] */
753 enum winreg_Type type,
754 union spoolss_PrinterData *r)
755 {
756 int i;
757
758 switch (type) {
759 case REG_DWORD:
760 printf("%s: REG_DWORD: 0x%08x\n", v, r->value);
761 break;
762 case REG_SZ:
763 printf("%s: REG_SZ: %s\n", v, r->string);
764 break;
765 case REG_BINARY: {
766 char *hex = hex_encode_talloc(NULL,
767 r->binary.data, r->binary.length);
768 size_t len;
769 printf("%s: REG_BINARY:", v);
770 len = strlen(hex);
771 for (i=0; i<len; i++) {
772 if (hex[i] == '\0') {
773 break;
774 }
775 if (i%40 == 0) {
776 putchar('\n');
777 }
778 putchar(hex[i]);
779 }
780 TALLOC_FREE(hex);
781 putchar('\n');
782 break;
783 }
784 case REG_MULTI_SZ:
785 printf("%s: REG_MULTI_SZ: ", v);
786 for (i=0; r->string_array[i] != NULL; i++) {
787 printf("%s ", r->string_array[i]);
788 }
789 printf("\n");
790 break;
791 default:
792 printf("%s: unknown type 0x%02x:\n", v, type);
793 break;
794 }
795 }
796
797 /****************************************************************************
798 ****************************************************************************/
799
800 static WERROR cmd_spoolss_getprinterdata(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
801 TALLOC_CTX *mem_ctx,
802 int argc, const char **argv)
803 {
804 struct policy_handle pol;
805 WERROR result;
806 fstring printername;
807 const char *valuename;
808 enum winreg_Type type;
809 union spoolss_PrinterData data;
810
811 if (argc != 3) {
812 printf("Usage: %s <printername> <valuename>\n", argv[0]);
813 printf("<printername> of . queries print server\n");
814 return WERR_OK;
815 }
816 valuename = argv[2];
817
818 /* Open a printer handle */
819
820 if (strncmp(argv[1], ".", sizeof(".")) == 0)
821 fstrcpy(printername, cli->srv_name_slash);
822 else
823 slprintf(printername, sizeof(printername)-1, "%s\\%s",
824 cli->srv_name_slash, argv[1]);
825
826 /* get a printer handle */
827
828 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
829 printername,
830 SEC_FLAG_MAXIMUM_ALLOWED,
831 &pol);
832 if (!W_ERROR_IS_OK(result))
833 goto done;
834
835 /* Get printer info */
836
837 result = rpccli_spoolss_getprinterdata(cli, mem_ctx,
838 &pol,
839 valuename,
840 0,
841 &type,
842 &data);
843 if (!W_ERROR_IS_OK(result))
844 goto done;
845
846 /* Display printer data */
847
848 display_printer_data(valuename, type, &data);
849
850 done:
851 if (is_valid_policy_hnd(&pol))
852 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
853
854 return result;
855 }
856
857 /****************************************************************************
858 ****************************************************************************/
859
860 static WERROR cmd_spoolss_getprinterdataex(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
861 TALLOC_CTX *mem_ctx,
862 int argc, const char **argv)
863 {
864 struct policy_handle pol;
865 WERROR result;
866 NTSTATUS status;
867 fstring printername;
868 const char *valuename, *keyname;
869 REGISTRY_VALUE value;
870
871 enum winreg_Type type;
872 uint8_t *buffer = NULL;
873 uint32_t offered = 0;
874 uint32_t needed;
875
876 if (argc != 4) {
877 printf("Usage: %s <printername> <keyname> <valuename>\n",
878 argv[0]);
879 printf("<printername> of . queries print server\n");
880 return WERR_OK;
881 }
882 valuename = argv[3];
883 keyname = argv[2];
884
885 /* Open a printer handle */
886
887 if (strncmp(argv[1], ".", sizeof(".")) == 0)
888 fstrcpy(printername, cli->srv_name_slash);
889 else
890 slprintf(printername, sizeof(printername)-1, "%s\\%s",
891 cli->srv_name_slash, argv[1]);
892
893 /* get a printer handle */
894
895 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
896 printername,
897 SEC_FLAG_MAXIMUM_ALLOWED,
898 &pol);
899 if (!W_ERROR_IS_OK(result))
900 goto done;
901
902 /* Get printer info */
903
904 status = rpccli_spoolss_GetPrinterDataEx(cli, mem_ctx,
905 &pol,
906 keyname,
907 valuename,
908 &type,
909 buffer,
910 offered,
911 &needed,
912 &result);
913 if (W_ERROR_EQUAL(result, WERR_MORE_DATA)) {
914 offered = needed;
915 buffer = talloc_array(mem_ctx, uint8_t, needed);
916 status = rpccli_spoolss_GetPrinterDataEx(cli, mem_ctx,
917 &pol,
918 keyname,
919 valuename,
920 &type,
921 buffer,
922 offered,
923 &needed,
924 &result);
925 }
926
927 if (!NT_STATUS_IS_OK(status)) {
928 goto done;
929 }
930
931 if (!W_ERROR_IS_OK(result)) {
932 goto done;
933 }
934
935
936 if (!W_ERROR_IS_OK(result))
937 goto done;
938
939 /* Display printer data */
940
941 fstrcpy(value.valuename, valuename);
942 value.type = type;
943 value.size = needed;
944 value.data_p = buffer;
945
946 display_reg_value(value);
947
948 done:
949 if (is_valid_policy_hnd(&pol))
950 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
951
952 return result;
953 }
954
955 /****************************************************************************
956 ****************************************************************************/
957
958 static void display_print_driver1(struct spoolss_DriverInfo1 *r)
/* [<][>][^][v][top][bottom][index][help] */
959 {
960 if (!r) {
961 return;
962 }
963
964 printf("Printer Driver Info 1:\n");
965 printf("\tDriver Name: [%s]\n", r->driver_name);
966 printf("\n");
967 }
968
969 /****************************************************************************
970 ****************************************************************************/
971
972 static void display_print_driver2(struct spoolss_DriverInfo2 *r)
/* [<][>][^][v][top][bottom][index][help] */
973 {
974 if (!r) {
975 return;
976 }
977
978 printf("Printer Driver Info 2:\n");
979 printf("\tVersion: [%x]\n", r->version);
980 printf("\tDriver Name: [%s]\n", r->driver_name);
981 printf("\tArchitecture: [%s]\n", r->architecture);
982 printf("\tDriver Path: [%s]\n", r->driver_path);
983 printf("\tDatafile: [%s]\n", r->data_file);
984 printf("\tConfigfile: [%s]\n", r->config_file);
985 printf("\n");
986 }
987
988 /****************************************************************************
989 ****************************************************************************/
990
991 static void display_print_driver3(struct spoolss_DriverInfo3 *r)
/* [<][>][^][v][top][bottom][index][help] */
992 {
993 int i;
994
995 if (!r) {
996 return;
997 }
998
999 printf("Printer Driver Info 3:\n");
1000 printf("\tVersion: [%x]\n", r->version);
1001 printf("\tDriver Name: [%s]\n", r->driver_name);
1002 printf("\tArchitecture: [%s]\n", r->architecture);
1003 printf("\tDriver Path: [%s]\n", r->driver_path);
1004 printf("\tDatafile: [%s]\n", r->data_file);
1005 printf("\tConfigfile: [%s]\n", r->config_file);
1006 printf("\tHelpfile: [%s]\n", r->help_file);
1007
1008 for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1009 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1010 }
1011
1012 printf("\tMonitorname: [%s]\n", r->monitor_name);
1013 printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1014 printf("\n");
1015 }
1016
1017 /****************************************************************************
1018 ****************************************************************************/
1019
1020 static void display_print_driver4(struct spoolss_DriverInfo4 *r)
/* [<][>][^][v][top][bottom][index][help] */
1021 {
1022 int i;
1023
1024 if (!r) {
1025 return;
1026 }
1027
1028 printf("Printer Driver Info 4:\n");
1029 printf("\tVersion: [%x]\n", r->version);
1030 printf("\tDriver Name: [%s]\n", r->driver_name);
1031 printf("\tArchitecture: [%s]\n", r->architecture);
1032 printf("\tDriver Path: [%s]\n", r->driver_path);
1033 printf("\tDatafile: [%s]\n", r->data_file);
1034 printf("\tConfigfile: [%s]\n", r->config_file);
1035 printf("\tHelpfile: [%s]\n", r->help_file);
1036
1037 for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1038 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1039 }
1040
1041 printf("\tMonitorname: [%s]\n", r->monitor_name);
1042 printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1043
1044 for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) {
1045 printf("\tPrevious Names: [%s]\n", r->previous_names[i]);
1046 }
1047 printf("\n");
1048 }
1049
1050 /****************************************************************************
1051 ****************************************************************************/
1052
1053 static void display_print_driver5(struct spoolss_DriverInfo5 *r)
/* [<][>][^][v][top][bottom][index][help] */
1054 {
1055 if (!r) {
1056 return;
1057 }
1058
1059 printf("Printer Driver Info 5:\n");
1060 printf("\tVersion: [%x]\n", r->version);
1061 printf("\tDriver Name: [%s]\n", r->driver_name);
1062 printf("\tArchitecture: [%s]\n", r->architecture);
1063 printf("\tDriver Path: [%s]\n", r->driver_path);
1064 printf("\tDatafile: [%s]\n", r->data_file);
1065 printf("\tConfigfile: [%s]\n", r->config_file);
1066 printf("\tDriver Attributes: [0x%x]\n", r->driver_attributes);
1067 printf("\tConfig Version: [0x%x]\n", r->config_version);
1068 printf("\tDriver Version: [0x%x]\n", r->driver_version);
1069 printf("\n");
1070 }
1071
1072 /****************************************************************************
1073 ****************************************************************************/
1074
1075 static void display_print_driver6(struct spoolss_DriverInfo6 *r)
/* [<][>][^][v][top][bottom][index][help] */
1076 {
1077 int i;
1078
1079 if (!r) {
1080 return;
1081 }
1082
1083 printf("Printer Driver Info 6:\n");
1084 printf("\tVersion: [%x]\n", r->version);
1085 printf("\tDriver Name: [%s]\n", r->driver_name);
1086 printf("\tArchitecture: [%s]\n", r->architecture);
1087 printf("\tDriver Path: [%s]\n", r->driver_path);
1088 printf("\tDatafile: [%s]\n", r->data_file);
1089 printf("\tConfigfile: [%s]\n", r->config_file);
1090 printf("\tHelpfile: [%s]\n", r->help_file);
1091
1092 for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1093 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1094 }
1095
1096 printf("\tMonitorname: [%s]\n", r->monitor_name);
1097 printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1098
1099 for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) {
1100 printf("\tPrevious Names: [%s]\n", r->previous_names[i]);
1101 }
1102
1103 printf("\tDriver Date: [%s]\n", nt_time_string(talloc_tos(), r->driver_date));
1104 printf("\tDriver Version: [0x%016llx]\n", (long long unsigned int)r->driver_version);
1105 printf("\tManufacturer Name: [%s]\n", r->manufacturer_name);
1106 printf("\tManufacturer Url: [%s]\n", r->manufacturer_url);
1107 printf("\tHardware ID: [%s]\n", r->hardware_id);
1108 printf("\tProvider: [%s]\n", r->provider);
1109
1110 printf("\n");
1111 }
1112
1113 /****************************************************************************
1114 ****************************************************************************/
1115
1116 static void display_print_driver8(struct spoolss_DriverInfo8 *r)
/* [<][>][^][v][top][bottom][index][help] */
1117 {
1118 int i;
1119
1120 if (!r) {
1121 return;
1122 }
1123
1124 printf("Printer Driver Info 8:\n");
1125 printf("\tVersion: [%x]\n", r->version);
1126 printf("\tDriver Name: [%s]\n", r->driver_name);
1127 printf("\tArchitecture: [%s]\n", r->architecture);
1128 printf("\tDriver Path: [%s]\n", r->driver_path);
1129 printf("\tDatafile: [%s]\n", r->data_file);
1130 printf("\tConfigfile: [%s]\n", r->config_file);
1131 printf("\tHelpfile: [%s]\n", r->help_file);
1132 printf("\tMonitorname: [%s]\n", r->monitor_name);
1133 printf("\tDefaultdatatype: [%s]\n", r->default_datatype);
1134
1135 for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) {
1136 printf("\tDependentfiles: [%s]\n", r->dependent_files[i]);
1137 }
1138
1139 for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) {
1140 printf("\tPrevious Names: [%s]\n", r->previous_names[i]);
1141 }
1142
1143 printf("\tDriver Date: [%s]\n", nt_time_string(talloc_tos(), r->driver_date));
1144 printf("\tDriver Version: [0x%016llx]\n", (long long unsigned int)r->driver_version);
1145 printf("\tManufacturer Name: [%s]\n", r->manufacturer_name);
1146 printf("\tManufacturer Url: [%s]\n", r->manufacturer_url);
1147 printf("\tHardware ID: [%s]\n", r->hardware_id);
1148 printf("\tProvider: [%s]\n", r->provider);
1149 printf("\tPrint Processor: [%s]\n", r->print_processor);
1150 printf("\tVendor Setup: [%s]\n", r->vendor_setup);
1151 for (i=0; r->color_profiles && r->color_profiles[i] != NULL; i++) {
1152 printf("\tColor Profiles: [%s]\n", r->color_profiles[i]);
1153 }
1154 printf("\tInf Path: [%s]\n", r->inf_path);
1155 printf("\tPrinter Driver Attributes: [0x%x]\n", r->printer_driver_attributes);
1156 for (i=0; r->core_driver_dependencies && r->core_driver_dependencies[i] != NULL; i++) {
1157 printf("\tCore Driver Dependencies: [%s]\n", r->core_driver_dependencies[i]);
1158 }
1159 printf("\tMin Driver Inbox Driver Version Date: [%s]\n", nt_time_string(talloc_tos(), r->min_inbox_driver_ver_date));
1160 printf("\tMin Driver Inbox Driver Version Version: [0x%016llx]\n",
1161 (long long unsigned int)r->min_inbox_driver_ver_version);
1162
1163 printf("\n");
1164 }
1165
1166 /****************************************************************************
1167 ****************************************************************************/
1168
1169 static WERROR cmd_spoolss_getdriver(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
1170 TALLOC_CTX *mem_ctx,
1171 int argc, const char **argv)
1172 {
1173 struct policy_handle pol;
1174 WERROR werror;
1175 uint32_t level = 3;
1176 const char *printername;
1177 uint32_t i;
1178 bool success = false;
1179 union spoolss_DriverInfo info;
1180 uint32_t server_major_version;
1181 uint32_t server_minor_version;
1182
1183 if ((argc == 1) || (argc > 3)) {
1184 printf("Usage: %s <printername> [level]\n", argv[0]);
1185 return WERR_OK;
1186 }
1187
1188 /* get the arguments need to open the printer handle */
1189
1190 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1191
1192 if (argc == 3) {
1193 level = atoi(argv[2]);
1194 }
1195
1196 /* Open a printer handle */
1197
1198 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1199 printername,
1200 PRINTER_ACCESS_USE,
1201 &pol);
1202 if (!W_ERROR_IS_OK(werror)) {
1203 printf("Error opening printer handle for %s!\n", printername);
1204 return werror;
1205 }
1206
1207 /* loop through and print driver info level for each architecture */
1208
1209 for (i=0; archi_table[i].long_archi!=NULL; i++) {
1210
1211 werror = rpccli_spoolss_getprinterdriver2(cli, mem_ctx,
1212 &pol,
1213 archi_table[i].long_archi,
1214 level,
1215 0, /* offered */
1216 archi_table[i].version,
1217 2,
1218 &info,
1219 &server_major_version,
1220 &server_minor_version);
1221 if (!W_ERROR_IS_OK(werror)) {
1222 continue;
1223 }
1224
1225 /* need at least one success */
1226
1227 success = true;
1228
1229 printf("\n[%s]\n", archi_table[i].long_archi);
1230
1231 switch (level) {
1232 case 1:
1233 display_print_driver1(&info.info1);
1234 break;
1235 case 2:
1236 display_print_driver2(&info.info2);
1237 break;
1238 case 3:
1239 display_print_driver3(&info.info3);
1240 break;
1241 case 4:
1242 display_print_driver4(&info.info4);
1243 break;
1244 case 5:
1245 display_print_driver5(&info.info5);
1246 break;
1247 case 6:
1248 display_print_driver6(&info.info6);
1249 break;
1250 case 8:
1251 display_print_driver8(&info.info8);
1252 break;
1253 default:
1254 printf("unknown info level %d\n", level);
1255 break;
1256 }
1257 }
1258
1259 /* Cleanup */
1260
1261 if (is_valid_policy_hnd(&pol)) {
1262 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
1263 }
1264
1265 if (success) {
1266 werror = WERR_OK;
1267 }
1268
1269 return werror;
1270 }
1271
1272 /****************************************************************************
1273 ****************************************************************************/
1274
1275 static WERROR enum_driver_by_architecture(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
1276 TALLOC_CTX *mem_ctx,
1277 const char *architecture,
1278 uint32_t level)
1279 {
1280 WERROR werror;
1281 uint32_t count = 0;
1282 union spoolss_DriverInfo *info = NULL;
1283 uint32_t j;
1284
1285 werror = rpccli_spoolss_enumprinterdrivers(cli, mem_ctx,
1286 cli->srv_name_slash,
1287 architecture,
1288 level,
1289 0,
1290 &count,
1291 &info);
1292
1293 if (W_ERROR_EQUAL(werror, WERR_INVALID_ENVIRONMENT)) {
1294 printf("Server does not support environment [%s]\n",
1295 architecture);
1296 return WERR_OK;
1297 }
1298
1299 if (count == 0) {
1300 return WERR_OK;
1301 }
1302
1303 if (!W_ERROR_IS_OK(werror)) {
1304 printf("Error getting driver for environment [%s] - %s\n",
1305 architecture, win_errstr(werror));
1306 return werror;
1307 }
1308
1309 printf("\n[%s]\n", architecture);
1310
1311 switch (level) {
1312 case 1:
1313 for (j=0; j < count; j++) {
1314 display_print_driver1(&info[j].info1);
1315 }
1316 break;
1317 case 2:
1318 for (j=0; j < count; j++) {
1319 display_print_driver2(&info[j].info2);
1320 }
1321 break;
1322 case 3:
1323 for (j=0; j < count; j++) {
1324 display_print_driver3(&info[j].info3);
1325 }
1326 break;
1327 case 4:
1328 for (j=0; j < count; j++) {
1329 display_print_driver4(&info[j].info4);
1330 }
1331 break;
1332 case 5:
1333 for (j=0; j < count; j++) {
1334 display_print_driver5(&info[j].info5);
1335 }
1336 break;
1337 case 6:
1338 for (j=0; j < count; j++) {
1339 display_print_driver6(&info[j].info6);
1340 }
1341 break;
1342 case 8:
1343 for (j=0; j < count; j++) {
1344 display_print_driver8(&info[j].info8);
1345 }
1346 break;
1347 default:
1348 printf("unknown info level %d\n", level);
1349 return WERR_UNKNOWN_LEVEL;
1350 }
1351
1352 return werror;
1353 }
1354
1355 static WERROR cmd_spoolss_enum_drivers(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
1356 TALLOC_CTX *mem_ctx,
1357 int argc, const char **argv)
1358 {
1359 WERROR werror = WERR_OK;
1360 uint32_t level = 1;
1361 uint32_t i;
1362 const char *architecture = NULL;
1363
1364 if (argc > 3) {
1365 printf("Usage: enumdrivers [level] [architecture]\n");
1366 return WERR_OK;
1367 }
1368
1369 if (argc >= 2) {
1370 level = atoi(argv[1]);
1371 }
1372
1373 if (argc == 3) {
1374 architecture = argv[2];
1375 }
1376
1377 if (architecture) {
1378 return enum_driver_by_architecture(cli, mem_ctx,
1379 architecture,
1380 level);
1381 }
1382
1383 /* loop through and print driver info level for each architecture */
1384 for (i=0; archi_table[i].long_archi!=NULL; i++) {
1385 /* check to see if we already asked for this architecture string */
1386
1387 if (i>0 && strequal(archi_table[i].long_archi, archi_table[i-1].long_archi)) {
1388 continue;
1389 }
1390
1391 werror = enum_driver_by_architecture(cli, mem_ctx,
1392 archi_table[i].long_archi,
1393 level);
1394 if (!W_ERROR_IS_OK(werror)) {
1395 break;
1396 }
1397 }
1398
1399 return werror;
1400 }
1401
1402 /****************************************************************************
1403 ****************************************************************************/
1404
1405 static void display_printdriverdir_1(struct spoolss_DriverDirectoryInfo1 *r)
/* [<][>][^][v][top][bottom][index][help] */
1406 {
1407 printf("\tDirectory Name:[%s]\n", r->directory_name);
1408 }
1409
1410 /****************************************************************************
1411 ****************************************************************************/
1412
1413 static WERROR cmd_spoolss_getdriverdir(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
1414 TALLOC_CTX *mem_ctx,
1415 int argc, const char **argv)
1416 {
1417 WERROR result;
1418 NTSTATUS status;
1419 const char *env = SPOOLSS_ARCHITECTURE_NT_X86;
1420 DATA_BLOB buffer;
1421 uint32_t offered;
1422 union spoolss_DriverDirectoryInfo info;
1423 uint32_t needed;
1424
1425 if (argc > 2) {
1426 printf("Usage: %s [environment]\n", argv[0]);
1427 return WERR_OK;
1428 }
1429
1430 /* Get the arguments need to open the printer handle */
1431
1432 if (argc == 2) {
1433 env = argv[1];
1434 }
1435
1436 /* Get the directory. Only use Info level 1 */
1437
1438 status = rpccli_spoolss_GetPrinterDriverDirectory(cli, mem_ctx,
1439 cli->srv_name_slash,
1440 env,
1441 1,
1442 NULL, /* buffer */
1443 0, /* offered */
1444 NULL, /* info */
1445 &needed,
1446 &result);
1447 if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) {
1448 offered = needed;
1449 buffer = data_blob_talloc_zero(mem_ctx, needed);
1450
1451 status = rpccli_spoolss_GetPrinterDriverDirectory(cli, mem_ctx,
1452 cli->srv_name_slash,
1453 env,
1454 1,
1455 &buffer,
1456 offered,
1457 &info,
1458 &needed,
1459 &result);
1460 }
1461
1462 if (W_ERROR_IS_OK(result)) {
1463 display_printdriverdir_1(&info.info1);
1464 }
1465
1466 return result;
1467 }
1468
1469 /****************************************************************************
1470 ****************************************************************************/
1471
1472 static void set_drv_info_3_env(TALLOC_CTX *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
1473 struct spoolss_AddDriverInfo3 *info,
1474 const char *arch)
1475 {
1476
1477 int i;
1478
1479 for (i=0; archi_table[i].long_archi != NULL; i++)
1480 {
1481 if (strcmp(arch, archi_table[i].short_archi) == 0)
1482 {
1483 info->version = archi_table[i].version;
1484 info->architecture = talloc_strdup(mem_ctx, archi_table[i].long_archi);
1485 break;
1486 }
1487 }
1488
1489 if (archi_table[i].long_archi == NULL)
1490 {
1491 DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch));
1492 }
1493
1494 return;
1495 }
1496
1497
1498 /**************************************************************************
1499 wrapper for strtok to get the next parameter from a delimited list.
1500 Needed to handle the empty parameter string denoted by "NULL"
1501 *************************************************************************/
1502
1503 static char *get_driver_3_param(TALLOC_CTX *mem_ctx, char *str,
/* [<][>][^][v][top][bottom][index][help] */
1504 const char *delim, const char **dest,
1505 char **saveptr)
1506 {
1507 char *ptr;
1508
1509 /* get the next token */
1510 ptr = strtok_r(str, delim, saveptr);
1511
1512 /* a string of 'NULL' is used to represent an empty
1513 parameter because two consecutive delimiters
1514 will not return an empty string. See man strtok(3)
1515 for details */
1516 if (ptr && (StrCaseCmp(ptr, "NULL") == 0)) {
1517 ptr = NULL;
1518 }
1519
1520 if (dest != NULL) {
1521 *dest = talloc_strdup(mem_ctx, ptr);
1522 }
1523
1524 return ptr;
1525 }
1526
1527 /********************************************************************************
1528 fill in the members of a spoolss_AddDriverInfo3 struct using a character
1529 string in the form of
1530 <Long Printer Name>:<Driver File Name>:<Data File Name>:\
1531 <Config File Name>:<Help File Name>:<Language Monitor Name>:\
1532 <Default Data Type>:<Comma Separated list of Files>
1533 *******************************************************************************/
1534
1535 static bool init_drv_info_3_members(TALLOC_CTX *mem_ctx, struct spoolss_AddDriverInfo3 *r,
/* [<][>][^][v][top][bottom][index][help] */
1536 char *args)
1537 {
1538 char *str, *str2;
1539 int count = 0;
1540 char *saveptr = NULL;
1541 struct spoolss_StringArray *deps;
1542 const char **file_array = NULL;
1543 int i;
1544
1545 /* fill in the UNISTR fields */
1546 str = get_driver_3_param(mem_ctx, args, ":", &r->driver_name, &saveptr);
1547 str = get_driver_3_param(mem_ctx, NULL, ":", &r->driver_path, &saveptr);
1548 str = get_driver_3_param(mem_ctx, NULL, ":", &r->data_file, &saveptr);
1549 str = get_driver_3_param(mem_ctx, NULL, ":", &r->config_file, &saveptr);
1550 str = get_driver_3_param(mem_ctx, NULL, ":", &r->help_file, &saveptr);
1551 str = get_driver_3_param(mem_ctx, NULL, ":", &r->monitor_name, &saveptr);
1552 str = get_driver_3_param(mem_ctx, NULL, ":", &r->default_datatype, &saveptr);
1553
1554 /* <Comma Separated List of Dependent Files> */
1555 /* save the beginning of the string */
1556 str2 = get_driver_3_param(mem_ctx, NULL, ":", NULL, &saveptr);
1557 str = str2;
1558
1559 /* begin to strip out each filename */
1560 str = strtok_r(str, ",", &saveptr);
1561
1562 /* no dependent files, we are done */
1563 if (!str) {
1564 return true;
1565 }
1566
1567 deps = talloc_zero(mem_ctx, struct spoolss_StringArray);
1568 if (!deps) {
1569 return false;
1570 }
1571
1572 while (str != NULL) {
1573 add_string_to_array(deps, str, &file_array, &count);
1574 str = strtok_r(NULL, ",", &saveptr);
1575 }
1576
1577 deps->string = talloc_zero_array(deps, const char *, count + 1);
1578 if (!deps->string) {
1579 return false;
1580 }
1581
1582 for (i=0; i < count; i++) {
1583 deps->string[i] = file_array[i];
1584 }
1585
1586 r->dependent_files = deps;
1587
1588 return true;
1589 }
1590
1591 /****************************************************************************
1592 ****************************************************************************/
1593
1594 static WERROR cmd_spoolss_addprinterdriver(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
1595 TALLOC_CTX *mem_ctx,
1596 int argc, const char **argv)
1597 {
1598 WERROR result;
1599 NTSTATUS status;
1600 uint32_t level = 3;
1601 struct spoolss_AddDriverInfoCtr info_ctr;
1602 struct spoolss_AddDriverInfo3 info3;
1603 const char *arch;
1604 char *driver_args;
1605
1606 /* parse the command arguments */
1607 if (argc != 3 && argc != 4)
1608 {
1609 printf ("Usage: %s <Environment> \\\n", argv[0]);
1610 printf ("\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n");
1611 printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
1612 printf ("\t<Default Data Type>:<Comma Separated list of Files> \\\n");
1613 printf ("\t[version]\n");
1614
1615 return WERR_OK;
1616 }
1617
1618 /* Fill in the spoolss_AddDriverInfo3 struct */
1619 ZERO_STRUCT(info3);
1620
1621 arch = cmd_spoolss_get_short_archi(argv[1]);
1622 if (!arch) {
1623 printf ("Error Unknown architechture [%s]\n", argv[1]);
1624 return WERR_INVALID_PARAM;
1625 }
1626
1627 set_drv_info_3_env(mem_ctx, &info3, arch);
1628
1629 driver_args = talloc_strdup( mem_ctx, argv[2] );
1630 if (!init_drv_info_3_members(mem_ctx, &info3, driver_args ))
1631 {
1632 printf ("Error Invalid parameter list - %s.\n", argv[2]);
1633 return WERR_INVALID_PARAM;
1634 }
1635
1636 /* if printer driver version specified, override the default version
1637 * used by the architecture. This allows installation of Windows
1638 * 2000 (version 3) printer drivers. */
1639 if (argc == 4)
1640 {
1641 info3.version = atoi(argv[3]);
1642 }
1643
1644
1645 info_ctr.level = level;
1646 info_ctr.info.info3 = &info3;
1647
1648 status = rpccli_spoolss_AddPrinterDriver(cli, mem_ctx,
1649 cli->srv_name_slash,
1650 &info_ctr,
1651 &result);
1652 if (!NT_STATUS_IS_OK(status)) {
1653 return ntstatus_to_werror(status);
1654 }
1655 if (W_ERROR_IS_OK(result)) {
1656 printf ("Printer Driver %s successfully installed.\n",
1657 info3.driver_name);
1658 }
1659
1660 return result;
1661 }
1662
1663
1664 /****************************************************************************
1665 ****************************************************************************/
1666
1667 static WERROR cmd_spoolss_addprinterex(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
1668 TALLOC_CTX *mem_ctx,
1669 int argc, const char **argv)
1670 {
1671 WERROR result;
1672 struct spoolss_SetPrinterInfoCtr info_ctr;
1673 struct spoolss_SetPrinterInfo2 info2;
1674
1675 /* parse the command arguments */
1676 if (argc != 5)
1677 {
1678 printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]);
1679 return WERR_OK;
1680 }
1681
1682 /* Fill in the DRIVER_INFO_2 struct */
1683 ZERO_STRUCT(info2);
1684
1685 info2.printername = argv[1];
1686 info2.drivername = argv[3];
1687 info2.sharename = argv[2];
1688 info2.portname = argv[4];
1689 info2.comment = "Created by rpcclient";
1690 info2.printprocessor = "winprint";
1691 info2.datatype = "RAW";
1692 info2.devmode = NULL;
1693 info2.secdesc = NULL;
1694 info2.attributes = PRINTER_ATTRIBUTE_SHARED;
1695 info2.priority = 0;
1696 info2.defaultpriority = 0;
1697 info2.starttime = 0;
1698 info2.untiltime = 0;
1699
1700 /* These three fields must not be used by AddPrinter()
1701 as defined in the MS Platform SDK documentation..
1702 --jerry
1703 info2.status = 0;
1704 info2.cjobs = 0;
1705 info2.averageppm = 0;
1706 */
1707
1708 info_ctr.level = 2;
1709 info_ctr.info.info2 = &info2;
1710
1711 result = rpccli_spoolss_addprinterex(cli, mem_ctx,
1712 &info_ctr);
1713 if (W_ERROR_IS_OK(result))
1714 printf ("Printer %s successfully installed.\n", argv[1]);
1715
1716 return result;
1717 }
1718
1719 /****************************************************************************
1720 ****************************************************************************/
1721
1722 static WERROR cmd_spoolss_setdriver(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
1723 TALLOC_CTX *mem_ctx,
1724 int argc, const char **argv)
1725 {
1726 struct policy_handle pol;
1727 WERROR result;
1728 NTSTATUS status;
1729 uint32_t level = 2;
1730 const char *printername;
1731 union spoolss_PrinterInfo info;
1732 struct spoolss_SetPrinterInfoCtr info_ctr;
1733 struct spoolss_DevmodeContainer devmode_ctr;
1734 struct sec_desc_buf secdesc_ctr;
1735
1736 ZERO_STRUCT(devmode_ctr);
1737 ZERO_STRUCT(secdesc_ctr);
1738
1739 /* parse the command arguments */
1740 if (argc != 3)
1741 {
1742 printf ("Usage: %s <printer> <driver>\n", argv[0]);
1743 return WERR_OK;
1744 }
1745
1746 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1747
1748 /* Get a printer handle */
1749
1750 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1751 printername,
1752 PRINTER_ALL_ACCESS,
1753 &pol);
1754 if (!W_ERROR_IS_OK(result))
1755 goto done;
1756
1757 /* Get printer info */
1758
1759 result = rpccli_spoolss_getprinter(cli, mem_ctx,
1760 &pol,
1761 level,
1762 0,
1763 &info);
1764 if (!W_ERROR_IS_OK(result)) {
1765 printf ("Unable to retrieve printer information!\n");
1766 goto done;
1767 }
1768
1769 /* Set the printer driver */
1770
1771 info.info2.drivername = argv[2];
1772 info.info2.devmode = NULL;
1773 info.info2.secdesc = NULL;
1774
1775 info_ctr.level = 2;
1776 info_ctr.info.info2 = (struct spoolss_SetPrinterInfo2 *)&info.info2;
1777
1778 status = rpccli_spoolss_SetPrinter(cli, mem_ctx,
1779 &pol,
1780 &info_ctr,
1781 &devmode_ctr,
1782 &secdesc_ctr,
1783 0, /* command */
1784 &result);
1785 if (!W_ERROR_IS_OK(result)) {
1786 printf("SetPrinter call failed!\n");
1787 goto done;;
1788 }
1789
1790 printf("Successfully set %s to driver %s.\n", argv[1], argv[2]);
1791
1792 done:
1793 /* Cleanup */
1794
1795 if (is_valid_policy_hnd(&pol))
1796 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
1797
1798 return result;
1799 }
1800
1801
1802 /****************************************************************************
1803 ****************************************************************************/
1804
1805 static WERROR cmd_spoolss_deletedriverex(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
1806 TALLOC_CTX *mem_ctx,
1807 int argc, const char **argv)
1808 {
1809 WERROR result, ret = WERR_UNKNOWN_PRINTER_DRIVER;
1810 NTSTATUS status;
1811
1812 int i;
1813 int vers = -1;
1814
1815 const char *arch = NULL;
1816 uint32_t delete_flags = 0;
1817
1818 /* parse the command arguments */
1819 if (argc < 2 || argc > 4) {
1820 printf ("Usage: %s <driver> [arch] [version]\n", argv[0]);
1821 return WERR_OK;
1822 }
1823
1824 if (argc >= 3)
1825 arch = argv[2];
1826 if (argc == 4)
1827 vers = atoi (argv[3]);
1828
1829 if (vers >= 0) {
1830 delete_flags |= DPD_DELETE_SPECIFIC_VERSION;
1831 }
1832
1833 /* delete the driver for all architectures */
1834 for (i=0; archi_table[i].long_archi; i++) {
1835
1836 if (arch && !strequal( archi_table[i].long_archi, arch))
1837 continue;
1838
1839 if (vers >= 0 && archi_table[i].version != vers)
1840 continue;
1841
1842 /* make the call to remove the driver */
1843 status = rpccli_spoolss_DeletePrinterDriverEx(cli, mem_ctx,
1844 cli->srv_name_slash,
1845 archi_table[i].long_archi,
1846 argv[1],
1847 delete_flags,
1848 archi_table[i].version,
1849 &result);
1850
1851 if ( !W_ERROR_IS_OK(result) )
1852 {
1853 if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1854 printf ("Failed to remove driver %s for arch [%s] (version: %d): %s\n",
1855 argv[1], archi_table[i].long_archi, archi_table[i].version, win_errstr(result));
1856 }
1857 }
1858 else
1859 {
1860 printf ("Driver %s and files removed for arch [%s] (version: %d).\n", argv[1],
1861 archi_table[i].long_archi, archi_table[i].version);
1862 ret = WERR_OK;
1863 }
1864 }
1865
1866 return ret;
1867 }
1868
1869
1870 /****************************************************************************
1871 ****************************************************************************/
1872
1873 static WERROR cmd_spoolss_deletedriver(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
1874 TALLOC_CTX *mem_ctx,
1875 int argc, const char **argv)
1876 {
1877 WERROR result = WERR_OK;
1878 NTSTATUS status;
1879 int i;
1880
1881 /* parse the command arguments */
1882 if (argc != 2) {
1883 printf ("Usage: %s <driver>\n", argv[0]);
1884 return WERR_OK;
1885 }
1886
1887 /* delete the driver for all architectures */
1888 for (i=0; archi_table[i].long_archi; i++) {
1889 /* make the call to remove the driver */
1890 status = rpccli_spoolss_DeletePrinterDriver(cli, mem_ctx,
1891 cli->srv_name_slash,
1892 archi_table[i].long_archi,
1893 argv[1],
1894 &result);
1895 if (!NT_STATUS_IS_OK(status)) {
1896 return result;
1897 }
1898 if ( !W_ERROR_IS_OK(result) ) {
1899 if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1900 printf ("Failed to remove driver %s for arch [%s] - error 0x%x!\n",
1901 argv[1], archi_table[i].long_archi,
1902 W_ERROR_V(result));
1903 }
1904 } else {
1905 printf ("Driver %s removed for arch [%s].\n", argv[1],
1906 archi_table[i].long_archi);
1907 }
1908 }
1909
1910 return result;
1911 }
1912
1913 /****************************************************************************
1914 ****************************************************************************/
1915
1916 static WERROR cmd_spoolss_getprintprocdir(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
1917 TALLOC_CTX *mem_ctx,
1918 int argc, const char **argv)
1919 {
1920 WERROR result;
1921 NTSTATUS status;
1922 const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
1923 DATA_BLOB buffer;
1924 uint32_t offered;
1925 union spoolss_PrintProcessorDirectoryInfo info;
1926 uint32_t needed;
1927
1928 /* parse the command arguments */
1929 if (argc > 2) {
1930 printf ("Usage: %s [environment]\n", argv[0]);
1931 return WERR_OK;
1932 }
1933
1934 if (argc == 2) {
1935 environment = argv[1];
1936 }
1937
1938 status = rpccli_spoolss_GetPrintProcessorDirectory(cli, mem_ctx,
1939 cli->srv_name_slash,
1940 environment,
1941 1,
1942 NULL, /* buffer */
1943 0, /* offered */
1944 NULL, /* info */
1945 &needed,
1946 &result);
1947 if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) {
1948 offered = needed;
1949 buffer = data_blob_talloc_zero(mem_ctx, needed);
1950
1951 status = rpccli_spoolss_GetPrintProcessorDirectory(cli, mem_ctx,
1952 cli->srv_name_slash,
1953 environment,
1954 1,
1955 &buffer,
1956 offered,
1957 &info,
1958 &needed,
1959 &result);
1960 }
1961
1962 if (W_ERROR_IS_OK(result)) {
1963 printf("%s\n", info.info1.directory_name);
1964 }
1965
1966 return result;
1967 }
1968
1969 /****************************************************************************
1970 ****************************************************************************/
1971
1972 static WERROR cmd_spoolss_addform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
1973 int argc, const char **argv)
1974 {
1975 struct policy_handle handle;
1976 WERROR werror;
1977 NTSTATUS status;
1978 const char *printername;
1979 union spoolss_AddFormInfo info;
1980 struct spoolss_AddFormInfo1 info1;
1981 struct spoolss_AddFormInfo2 info2;
1982 uint32_t level = 1;
1983
1984 /* Parse the command arguments */
1985
1986 if (argc < 3 || argc > 5) {
1987 printf ("Usage: %s <printer> <formname> [level]\n", argv[0]);
1988 return WERR_OK;
1989 }
1990
1991 /* Get a printer handle */
1992
1993 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
1994
1995 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
1996 printername,
1997 PRINTER_ALL_ACCESS,
1998 &handle);
1999 if (!W_ERROR_IS_OK(werror))
2000 goto done;
2001
2002 /* Dummy up some values for the form data */
2003
2004 if (argc == 4) {
2005 level = atoi(argv[3]);
2006 }
2007
2008 switch (level) {
2009 case 1:
2010 info1.flags = SPOOLSS_FORM_USER;
2011 info1.form_name = argv[2];
2012 info1.size.width = 100;
2013 info1.size.height = 100;
2014 info1.area.left = 0;
2015 info1.area.top = 10;
2016 info1.area.right = 20;
2017 info1.area.bottom = 30;
2018
2019 info.info1 = &info1;
2020
2021 break;
2022 case 2:
2023 info2.flags = SPOOLSS_FORM_USER;
2024 info2.form_name = argv[2];
2025 info2.size.width = 100;
2026 info2.size.height = 100;
2027 info2.area.left = 0;
2028 info2.area.top = 10;
2029 info2.area.right = 20;
2030 info2.area.bottom = 30;
2031 info2.keyword = argv[2];
2032 info2.string_type = SPOOLSS_FORM_STRING_TYPE_NONE;
2033 info2.mui_dll = NULL;
2034 info2.ressource_id = 0;
2035 info2.display_name = argv[2];
2036 info2.lang_id = 0;
2037
2038 info.info2 = &info2;
2039
2040 break;
2041 }
2042
2043 /* Add the form */
2044
2045
2046 status = rpccli_spoolss_AddForm(cli, mem_ctx,
2047 &handle,
2048 level,
2049 info,
2050 &werror);
2051
2052 done:
2053 if (is_valid_policy_hnd(&handle))
2054 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2055
2056 return werror;
2057 }
2058
2059 /****************************************************************************
2060 ****************************************************************************/
2061
2062 static WERROR cmd_spoolss_setform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
2063 int argc, const char **argv)
2064 {
2065 struct policy_handle handle;
2066 WERROR werror;
2067 NTSTATUS status;
2068 const char *printername;
2069 union spoolss_AddFormInfo info;
2070 struct spoolss_AddFormInfo1 info1;
2071
2072 /* Parse the command arguments */
2073
2074 if (argc != 3) {
2075 printf ("Usage: %s <printer> <formname>\n", argv[0]);
2076 return WERR_OK;
2077 }
2078
2079 /* Get a printer handle */
2080
2081 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2082
2083 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2084 printername,
2085 SEC_FLAG_MAXIMUM_ALLOWED,
2086 &handle);
2087 if (!W_ERROR_IS_OK(werror))
2088 goto done;
2089
2090 /* Dummy up some values for the form data */
2091
2092 info1.flags = SPOOLSS_FORM_PRINTER;
2093 info1.size.width = 100;
2094 info1.size.height = 100;
2095 info1.area.left = 0;
2096 info1.area.top = 1000;
2097 info1.area.right = 2000;
2098 info1.area.bottom = 3000;
2099 info1.form_name = argv[2];
2100
2101 info.info1 = &info1;
2102
2103 /* Set the form */
2104
2105 status = rpccli_spoolss_SetForm(cli, mem_ctx,
2106 &handle,
2107 argv[2],
2108 1,
2109 info,
2110 &werror);
2111
2112 done:
2113 if (is_valid_policy_hnd(&handle))
2114 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2115
2116 return werror;
2117 }
2118
2119 /****************************************************************************
2120 ****************************************************************************/
2121
2122 static const char *get_form_flag(int form_flag)
/* [<][>][^][v][top][bottom][index][help] */
2123 {
2124 switch (form_flag) {
2125 case SPOOLSS_FORM_USER:
2126 return "FORM_USER";
2127 case SPOOLSS_FORM_BUILTIN:
2128 return "FORM_BUILTIN";
2129 case SPOOLSS_FORM_PRINTER:
2130 return "FORM_PRINTER";
2131 default:
2132 return "unknown";
2133 }
2134 }
2135
2136 /****************************************************************************
2137 ****************************************************************************/
2138
2139 static void display_form_info1(struct spoolss_FormInfo1 *r)
/* [<][>][^][v][top][bottom][index][help] */
2140 {
2141 printf("%s\n" \
2142 "\tflag: %s (%d)\n" \
2143 "\twidth: %d, length: %d\n" \
2144 "\tleft: %d, right: %d, top: %d, bottom: %d\n\n",
2145 r->form_name, get_form_flag(r->flags), r->flags,
2146 r->size.width, r->size.height,
2147 r->area.left, r->area.right,
2148 r->area.top, r->area.bottom);
2149 }
2150
2151 /****************************************************************************
2152 ****************************************************************************/
2153
2154 static void display_form_info2(struct spoolss_FormInfo2 *r)
/* [<][>][^][v][top][bottom][index][help] */
2155 {
2156 printf("%s\n" \
2157 "\tflag: %s (%d)\n" \
2158 "\twidth: %d, length: %d\n" \
2159 "\tleft: %d, right: %d, top: %d, bottom: %d\n",
2160 r->form_name, get_form_flag(r->flags), r->flags,
2161 r->size.width, r->size.height,
2162 r->area.left, r->area.right,
2163 r->area.top, r->area.bottom);
2164 printf("\tkeyword: %s\n", r->keyword);
2165 printf("\tstring_type: 0x%08x\n", r->string_type);
2166 printf("\tmui_dll: %s\n", r->mui_dll);
2167 printf("\tressource_id: 0x%08x\n", r->ressource_id);
2168 printf("\tdisplay_name: %s\n", r->display_name);
2169 printf("\tlang_id: %d\n", r->lang_id);
2170 printf("\n");
2171 }
2172
2173 /****************************************************************************
2174 ****************************************************************************/
2175
2176 static WERROR cmd_spoolss_getform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
2177 int argc, const char **argv)
2178 {
2179 struct policy_handle handle;
2180 WERROR werror;
2181 NTSTATUS status;
2182 const char *printername;
2183 DATA_BLOB buffer;
2184 uint32_t offered = 0;
2185 union spoolss_FormInfo info;
2186 uint32_t needed;
2187 uint32_t level = 1;
2188
2189 /* Parse the command arguments */
2190
2191 if (argc < 3 || argc > 5) {
2192 printf ("Usage: %s <printer> <formname> [level]\n", argv[0]);
2193 return WERR_OK;
2194 }
2195
2196 /* Get a printer handle */
2197
2198 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2199
2200 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2201 printername,
2202 SEC_FLAG_MAXIMUM_ALLOWED,
2203 &handle);
2204 if (!W_ERROR_IS_OK(werror))
2205 goto done;
2206
2207 if (argc == 4) {
2208 level = atoi(argv[3]);
2209 }
2210
2211 /* Get the form */
2212
2213 status = rpccli_spoolss_GetForm(cli, mem_ctx,
2214 &handle,
2215 argv[2],
2216 level,
2217 NULL,
2218 offered,
2219 &info,
2220 &needed,
2221 &werror);
2222 if (W_ERROR_EQUAL(werror, WERR_INSUFFICIENT_BUFFER)) {
2223 buffer = data_blob_talloc_zero(mem_ctx, needed);
2224 offered = needed;
2225 status = rpccli_spoolss_GetForm(cli, mem_ctx,
2226 &handle,
2227 argv[2],
2228 level,
2229 &buffer,
2230 offered,
2231 &info,
2232 &needed,
2233 &werror);
2234 }
2235
2236 if (!NT_STATUS_IS_OK(status)) {
2237 return werror;
2238 }
2239
2240 switch (level) {
2241 case 1:
2242 display_form_info1(&info.info1);
2243 break;
2244 case 2:
2245 display_form_info2(&info.info2);
2246 break;
2247 }
2248
2249 done:
2250 if (is_valid_policy_hnd(&handle))
2251 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2252
2253 return werror;
2254 }
2255
2256 /****************************************************************************
2257 ****************************************************************************/
2258
2259 static WERROR cmd_spoolss_deleteform(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
2260 TALLOC_CTX *mem_ctx, int argc,
2261 const char **argv)
2262 {
2263 struct policy_handle handle;
2264 WERROR werror;
2265 NTSTATUS status;
2266 const char *printername;
2267
2268 /* Parse the command arguments */
2269
2270 if (argc != 3) {
2271 printf ("Usage: %s <printer> <formname>\n", argv[0]);
2272 return WERR_OK;
2273 }
2274
2275 /* Get a printer handle */
2276
2277 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2278
2279 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2280 printername,
2281 SEC_FLAG_MAXIMUM_ALLOWED,
2282 &handle);
2283 if (!W_ERROR_IS_OK(werror))
2284 goto done;
2285
2286 /* Delete the form */
2287
2288 status = rpccli_spoolss_DeleteForm(cli, mem_ctx,
2289 &handle,
2290 argv[2],
2291 &werror);
2292 if (!NT_STATUS_IS_OK(status)) {
2293 return ntstatus_to_werror(status);
2294 }
2295
2296 done:
2297 if (is_valid_policy_hnd(&handle))
2298 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2299
2300 return werror;
2301 }
2302
2303 /****************************************************************************
2304 ****************************************************************************/
2305
2306 static WERROR cmd_spoolss_enum_forms(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
2307 TALLOC_CTX *mem_ctx, int argc,
2308 const char **argv)
2309 {
2310 struct policy_handle handle;
2311 WERROR werror;
2312 const char *printername;
2313 uint32_t num_forms, level = 1, i;
2314 union spoolss_FormInfo *forms;
2315
2316 /* Parse the command arguments */
2317
2318 if (argc < 2 || argc > 4) {
2319 printf ("Usage: %s <printer> [level]\n", argv[0]);
2320 return WERR_OK;
2321 }
2322
2323 /* Get a printer handle */
2324
2325 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2326
2327 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2328 printername,
2329 SEC_FLAG_MAXIMUM_ALLOWED,
2330 &handle);
2331 if (!W_ERROR_IS_OK(werror))
2332 goto done;
2333
2334 if (argc == 3) {
2335 level = atoi(argv[2]);
2336 }
2337
2338 /* Enumerate forms */
2339
2340 werror = rpccli_spoolss_enumforms(cli, mem_ctx,
2341 &handle,
2342 level,
2343 0,
2344 &num_forms,
2345 &forms);
2346
2347 if (!W_ERROR_IS_OK(werror))
2348 goto done;
2349
2350 /* Display output */
2351
2352 for (i = 0; i < num_forms; i++) {
2353 switch (level) {
2354 case 1:
2355 display_form_info1(&forms[i].info1);
2356 break;
2357 case 2:
2358 display_form_info2(&forms[i].info2);
2359 break;
2360 }
2361 }
2362
2363 done:
2364 if (is_valid_policy_hnd(&handle))
2365 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &handle, NULL);
2366
2367 return werror;
2368 }
2369
2370 /****************************************************************************
2371 ****************************************************************************/
2372
2373 static WERROR cmd_spoolss_setprinterdata(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
2374 TALLOC_CTX *mem_ctx,
2375 int argc, const char **argv)
2376 {
2377 WERROR result;
2378 NTSTATUS status;
2379 const char *printername;
2380 struct policy_handle pol;
2381 union spoolss_PrinterInfo info;
2382 enum winreg_Type type;
2383 union spoolss_PrinterData data;
2384
2385 /* parse the command arguments */
2386 if (argc < 5) {
2387 printf ("Usage: %s <printer> <string|binary|dword|multistring>"
2388 " <value> <data>\n",
2389 argv[0]);
2390 result = WERR_INVALID_PARAM;
2391 goto done;
2392 }
2393
2394 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2395
2396 type = REG_NONE;
2397
2398 if (strequal(argv[2], "string")) {
2399 type = REG_SZ;
2400 }
2401
2402 if (strequal(argv[2], "binary")) {
2403 type = REG_BINARY;
2404 }
2405
2406 if (strequal(argv[2], "dword")) {
2407 type = REG_DWORD;
2408 }
2409
2410 if (strequal(argv[2], "multistring")) {
2411 type = REG_MULTI_SZ;
2412 }
2413
2414 if (type == REG_NONE) {
2415 printf("Unknown data type: %s\n", argv[2]);
2416 result = WERR_INVALID_PARAM;
2417 goto done;
2418 }
2419
2420 /* get a printer handle */
2421
2422 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2423 printername,
2424 SEC_FLAG_MAXIMUM_ALLOWED,
2425 &pol);
2426 if (!W_ERROR_IS_OK(result)) {
2427 goto done;
2428 }
2429
2430 result = rpccli_spoolss_getprinter(cli, mem_ctx,
2431 &pol,
2432 0,
2433 0,
2434 &info);
2435 if (!W_ERROR_IS_OK(result)) {
2436 goto done;
2437 }
2438
2439 printf("%s\n", current_timestring(mem_ctx, true));
2440 printf("\tchange_id (before set)\t:[0x%x]\n", info.info0.change_id);
2441
2442 /* Set the printer data */
2443
2444 switch (type) {
2445 case REG_SZ:
2446 data.string = talloc_strdup(mem_ctx, argv[4]);
2447 W_ERROR_HAVE_NO_MEMORY(data.string);
2448 break;
2449 case REG_DWORD:
2450 data.value = strtoul(argv[4], NULL, 10);
2451 break;
2452 case REG_BINARY:
2453 data.binary = strhex_to_data_blob(mem_ctx, argv[4]);
2454 break;
2455 case REG_MULTI_SZ: {
2456 int i, num_strings;
2457 const char **strings = NULL;
2458
2459 for (i=4; i<argc; i++) {
2460 if (strcmp(argv[i], "NULL") == 0) {
2461 argv[i] = "";
2462 }
2463 if (!add_string_to_array(mem_ctx, argv[i],
2464 &strings,
2465 &num_strings)) {
2466 result = WERR_NOMEM;
2467 goto done;
2468 }
2469 }
2470 data.string_array = talloc_zero_array(mem_ctx, const char *, num_strings + 1);
2471 if (!data.string_array) {
2472 result = WERR_NOMEM;
2473 goto done;
2474 }
2475 for (i=0; i < num_strings; i++) {
2476 data.string_array[i] = strings[i];
2477 }
2478 break;
2479 }
2480 default:
2481 printf("Unknown data type: %s\n", argv[2]);
2482 result = WERR_INVALID_PARAM;
2483 goto done;
2484 }
2485
2486 status = rpccli_spoolss_SetPrinterData(cli, mem_ctx,
2487 &pol,
2488 argv[3], /* value_name */
2489 type,
2490 data,
2491 0, /* autocalculated size */
2492 &result);
2493 if (!W_ERROR_IS_OK(result)) {
2494 printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]);
2495 goto done;
2496 }
2497 printf("\tSetPrinterData succeeded [%s: %s]\n", argv[3], argv[4]);
2498
2499 result = rpccli_spoolss_getprinter(cli, mem_ctx,
2500 &pol,
2501 0,
2502 0,
2503 &info);
2504 if (!W_ERROR_IS_OK(result)) {
2505 goto done;
2506 }
2507
2508 printf("%s\n", current_timestring(mem_ctx, true));
2509 printf("\tchange_id (after set)\t:[0x%x]\n", info.info0.change_id);
2510
2511 done:
2512 /* cleanup */
2513 if (is_valid_policy_hnd(&pol)) {
2514 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
2515 }
2516
2517 return result;
2518 }
2519
2520 /****************************************************************************
2521 ****************************************************************************/
2522
2523 static void display_job_info1(struct spoolss_JobInfo1 *r)
/* [<][>][^][v][top][bottom][index][help] */
2524 {
2525 printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", r->position, r->job_id,
2526 r->user_name, r->document_name, r->text_status, r->pages_printed,
2527 r->total_pages);
2528 }
2529
2530 /****************************************************************************
2531 ****************************************************************************/
2532
2533 static void display_job_info2(struct spoolss_JobInfo2 *r)
/* [<][>][^][v][top][bottom][index][help] */
2534 {
2535 printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n",
2536 r->position, r->job_id,
2537 r->user_name, r->document_name, r->text_status, r->pages_printed,
2538 r->total_pages, r->size);
2539 }
2540
2541 /****************************************************************************
2542 ****************************************************************************/
2543
2544 static void display_job_info3(struct spoolss_JobInfo3 *r)
/* [<][>][^][v][top][bottom][index][help] */
2545 {
2546 printf("jobid[%d], next_jobid[%d]\n",
2547 r->job_id, r->next_job_id);
2548 }
2549
2550 /****************************************************************************
2551 ****************************************************************************/
2552
2553 static void display_job_info4(struct spoolss_JobInfo4 *r)
/* [<][>][^][v][top][bottom][index][help] */
2554 {
2555 printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d/%d bytes\n",
2556 r->position, r->job_id,
2557 r->user_name, r->document_name, r->text_status, r->pages_printed,
2558 r->total_pages, r->size, r->size_high);
2559 }
2560
2561 /****************************************************************************
2562 ****************************************************************************/
2563
2564 static WERROR cmd_spoolss_enum_jobs(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
2565 TALLOC_CTX *mem_ctx, int argc,
2566 const char **argv)
2567 {
2568 WERROR result;
2569 uint32_t level = 1, count, i;
2570 const char *printername;
2571 struct policy_handle hnd;
2572 union spoolss_JobInfo *info;
2573
2574 if (argc < 2 || argc > 3) {
2575 printf("Usage: %s printername [level]\n", argv[0]);
2576 return WERR_OK;
2577 }
2578
2579 if (argc == 3) {
2580 level = atoi(argv[2]);
2581 }
2582
2583 /* Open printer handle */
2584
2585 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2586
2587 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2588 printername,
2589 SEC_FLAG_MAXIMUM_ALLOWED,
2590 &hnd);
2591 if (!W_ERROR_IS_OK(result))
2592 goto done;
2593
2594 /* Enumerate ports */
2595
2596 result = rpccli_spoolss_enumjobs(cli, mem_ctx,
2597 &hnd,
2598 0, /* firstjob */
2599 1000, /* numjobs */
2600 level,
2601 0,
2602 &count,
2603 &info);
2604 if (!W_ERROR_IS_OK(result)) {
2605 goto done;
2606 }
2607
2608 for (i = 0; i < count; i++) {
2609 switch (level) {
2610 case 1:
2611 display_job_info1(&info[i].info1);
2612 break;
2613 case 2:
2614 display_job_info2(&info[i].info2);
2615 break;
2616 default:
2617 d_printf("unknown info level %d\n", level);
2618 break;
2619 }
2620 }
2621
2622 done:
2623 if (is_valid_policy_hnd(&hnd)) {
2624 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2625 }
2626
2627 return result;
2628 }
2629
2630 /****************************************************************************
2631 ****************************************************************************/
2632
2633 static WERROR cmd_spoolss_get_job(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
2634 TALLOC_CTX *mem_ctx, int argc,
2635 const char **argv)
2636 {
2637 WERROR result;
2638 const char *printername;
2639 struct policy_handle hnd;
2640 uint32_t job_id;
2641 uint32_t level = 1;
2642 union spoolss_JobInfo info;
2643
2644 if (argc < 3 || argc > 4) {
2645 printf("Usage: %s printername job_id [level]\n", argv[0]);
2646 return WERR_OK;
2647 }
2648
2649 job_id = atoi(argv[2]);
2650
2651 if (argc == 4) {
2652 level = atoi(argv[3]);
2653 }
2654
2655 /* Open printer handle */
2656
2657 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2658
2659 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2660 printername,
2661 SEC_FLAG_MAXIMUM_ALLOWED,
2662 &hnd);
2663 if (!W_ERROR_IS_OK(result)) {
2664 goto done;
2665 }
2666
2667 /* Enumerate ports */
2668
2669 result = rpccli_spoolss_getjob(cli, mem_ctx,
2670 &hnd,
2671 job_id,
2672 level,
2673 0,
2674 &info);
2675
2676 if (!W_ERROR_IS_OK(result)) {
2677 goto done;
2678 }
2679
2680 switch (level) {
2681 case 1:
2682 display_job_info1(&info.info1);
2683 break;
2684 case 2:
2685 display_job_info2(&info.info2);
2686 break;
2687 case 3:
2688 display_job_info3(&info.info3);
2689 break;
2690 case 4:
2691 display_job_info4(&info.info4);
2692 break;
2693 default:
2694 d_printf("unknown info level %d\n", level);
2695 break;
2696 }
2697
2698 done:
2699 if (is_valid_policy_hnd(&hnd)) {
2700 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2701 }
2702
2703 return result;
2704 }
2705
2706 /****************************************************************************
2707 ****************************************************************************/
2708
2709 static WERROR cmd_spoolss_set_job(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
2710 TALLOC_CTX *mem_ctx, int argc,
2711 const char **argv)
2712 {
2713 WERROR result;
2714 NTSTATUS status;
2715 const char *printername;
2716 struct policy_handle hnd;
2717 uint32_t job_id;
2718 enum spoolss_JobControl command;
2719
2720 if (argc != 4) {
2721 printf("Usage: %s printername job_id command\n", argv[0]);
2722 return WERR_OK;
2723 }
2724
2725 job_id = atoi(argv[2]);
2726 command = atoi(argv[3]);
2727
2728 /* Open printer handle */
2729
2730 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2731
2732 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2733 printername,
2734 SEC_FLAG_MAXIMUM_ALLOWED,
2735 &hnd);
2736 if (!W_ERROR_IS_OK(result)) {
2737 goto done;
2738 }
2739
2740 /* Set Job */
2741
2742 status = rpccli_spoolss_SetJob(cli, mem_ctx,
2743 &hnd,
2744 job_id,
2745 NULL,
2746 command,
2747 &result);
2748
2749 if (!W_ERROR_IS_OK(result)) {
2750 goto done;
2751 }
2752
2753 done:
2754 if (is_valid_policy_hnd(&hnd)) {
2755 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2756 }
2757
2758 return result;
2759 }
2760
2761 /****************************************************************************
2762 ****************************************************************************/
2763
2764 static WERROR cmd_spoolss_enum_data(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
2765 TALLOC_CTX *mem_ctx, int argc,
2766 const char **argv)
2767 {
2768 WERROR result;
2769 NTSTATUS status;
2770 uint32_t i = 0;
2771 const char *printername;
2772 struct policy_handle hnd;
2773 uint32_t value_offered = 0;
2774 const char *value_name = NULL;
2775 uint32_t value_needed;
2776 enum winreg_Type type;
2777 uint8_t *data = NULL;
2778 uint32_t data_offered = 0;
2779 uint32_t data_needed;
2780
2781 if (argc != 2) {
2782 printf("Usage: %s printername\n", argv[0]);
2783 return WERR_OK;
2784 }
2785
2786 /* Open printer handle */
2787
2788 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2789
2790 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2791 printername,
2792 SEC_FLAG_MAXIMUM_ALLOWED,
2793 &hnd);
2794 if (!W_ERROR_IS_OK(result)) {
2795 goto done;
2796 }
2797
2798 /* Enumerate data */
2799
2800 status = rpccli_spoolss_EnumPrinterData(cli, mem_ctx,
2801 &hnd,
2802 i,
2803 value_name,
2804 value_offered,
2805 &value_needed,
2806 &type,
2807 data,
2808 data_offered,
2809 &data_needed,
2810 &result);
2811
2812 data_offered = data_needed;
2813 value_offered = value_needed;
2814 data = talloc_zero_array(mem_ctx, uint8_t, data_needed);
2815 value_name = talloc_zero_array(mem_ctx, char, value_needed);
2816
2817 while (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(result)) {
2818
2819 status = rpccli_spoolss_EnumPrinterData(cli, mem_ctx,
2820 &hnd,
2821 i++,
2822 value_name,
2823 value_offered,
2824 &value_needed,
2825 &type,
2826 data,
2827 data_offered,
2828 &data_needed,
2829 &result);
2830 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(result)) {
2831 REGISTRY_VALUE v;
2832 fstrcpy(v.valuename, value_name);
2833 v.type = type;
2834 v.size = data_offered;
2835 v.data_p = data;
2836 display_reg_value(v);
2837 }
2838 }
2839
2840 if (W_ERROR_V(result) == ERRnomoreitems) {
2841 result = W_ERROR(ERRsuccess);
2842 }
2843
2844 done:
2845 if (is_valid_policy_hnd(&hnd)) {
2846 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2847 }
2848
2849 return result;
2850 }
2851
2852 /****************************************************************************
2853 ****************************************************************************/
2854
2855 static WERROR cmd_spoolss_enum_data_ex( struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
2856 TALLOC_CTX *mem_ctx, int argc,
2857 const char **argv)
2858 {
2859 WERROR result;
2860 uint32_t i;
2861 const char *printername;
2862 struct policy_handle hnd;
2863 uint32_t count;
2864 struct spoolss_PrinterEnumValues *info;
2865
2866 if (argc != 3) {
2867 printf("Usage: %s printername <keyname>\n", argv[0]);
2868 return WERR_OK;
2869 }
2870
2871 /* Open printer handle */
2872
2873 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2874
2875 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2876 printername,
2877 SEC_FLAG_MAXIMUM_ALLOWED,
2878 &hnd);
2879 if (!W_ERROR_IS_OK(result)) {
2880 goto done;
2881 }
2882
2883 /* Enumerate subkeys */
2884
2885 result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx,
2886 &hnd,
2887 argv[2],
2888 0,
2889 &count,
2890 &info);
2891 if (!W_ERROR_IS_OK(result)) {
2892 goto done;
2893 }
2894
2895 for (i=0; i < count; i++) {
2896 display_printer_data(info[i].value_name,
2897 info[i].type,
2898 info[i].data);
2899 }
2900
2901 done:
2902 if (is_valid_policy_hnd(&hnd)) {
2903 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2904 }
2905
2906 return result;
2907 }
2908
2909 /****************************************************************************
2910 ****************************************************************************/
2911
2912 static WERROR cmd_spoolss_enum_printerkey(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
2913 TALLOC_CTX *mem_ctx, int argc,
2914 const char **argv)
2915 {
2916 WERROR result;
2917 const char *printername;
2918 const char *keyname = NULL;
2919 struct policy_handle hnd;
2920 const char **key_buffer = NULL;
2921 int i;
2922
2923 if (argc < 2 || argc > 3) {
2924 printf("Usage: %s printername [keyname]\n", argv[0]);
2925 return WERR_OK;
2926 }
2927
2928 if (argc == 3) {
2929 keyname = argv[2];
2930 } else {
2931 keyname = "";
2932 }
2933
2934 /* Open printer handle */
2935
2936 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2937
2938 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2939 printername,
2940 SEC_FLAG_MAXIMUM_ALLOWED,
2941 &hnd);
2942 if (!W_ERROR_IS_OK(result)) {
2943 goto done;
2944 }
2945
2946 /* Enumerate subkeys */
2947
2948 result = rpccli_spoolss_enumprinterkey(cli, mem_ctx,
2949 &hnd,
2950 keyname,
2951 &key_buffer,
2952 0);
2953
2954 if (!W_ERROR_IS_OK(result)) {
2955 goto done;
2956 }
2957
2958 for (i=0; key_buffer && key_buffer[i]; i++) {
2959 printf("%s\n", key_buffer[i]);
2960 }
2961
2962 done:
2963
2964 if (is_valid_policy_hnd(&hnd)) {
2965 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
2966 }
2967
2968 return result;
2969 }
2970
2971 /****************************************************************************
2972 ****************************************************************************/
2973
2974 static WERROR cmd_spoolss_rffpcnex(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
2975 TALLOC_CTX *mem_ctx, int argc,
2976 const char **argv)
2977 {
2978 const char *printername;
2979 const char *clientname;
2980 struct policy_handle hnd;
2981 WERROR result;
2982 NTSTATUS status;
2983 struct spoolss_NotifyOption option;
2984
2985 if (argc != 2) {
2986 printf("Usage: %s printername\n", argv[0]);
2987 result = WERR_OK;
2988 goto done;
2989 }
2990
2991 /* Open printer */
2992
2993 RPCCLIENT_PRINTERNAME(printername, cli, argv[1]);
2994
2995 result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
2996 printername,
2997 SEC_FLAG_MAXIMUM_ALLOWED,
2998 &hnd);
2999 if (!W_ERROR_IS_OK(result)) {
3000 printf("Error opening %s\n", argv[1]);
3001 goto done;
3002 }
3003
3004 /* Create spool options */
3005
3006 option.version = 2;
3007 option.count = 2;
3008
3009 option.types = talloc_array(mem_ctx, struct spoolss_NotifyOptionType, 2);
3010 if (option.types == NULL) {
3011 result = WERR_NOMEM;
3012 goto done;
3013 }
3014
3015 option.types[0].type = PRINTER_NOTIFY_TYPE;
3016 option.types[0].count = 1;
3017 option.types[0].fields = talloc_array(mem_ctx, union spoolss_Field, 1);
3018 if (option.types[0].fields == NULL) {
3019 result = WERR_NOMEM;
3020 goto done;
3021 }
3022 option.types[0].fields[0].field = PRINTER_NOTIFY_FIELD_SERVER_NAME;
3023
3024 option.types[1].type = JOB_NOTIFY_TYPE;
3025 option.types[1].count = 1;
3026 option.types[1].fields = talloc_array(mem_ctx, union spoolss_Field, 1);
3027 if (option.types[1].fields == NULL) {
3028 result = WERR_NOMEM;
3029 goto done;
3030 }
3031 option.types[1].fields[0].field = JOB_NOTIFY_FIELD_PRINTER_NAME;
3032
3033 clientname = talloc_asprintf(mem_ctx, "\\\\%s", global_myname());
3034 if (!clientname) {
3035 result = WERR_NOMEM;
3036 goto done;
3037 }
3038
3039 /* Send rffpcnex */
3040
3041 status = rpccli_spoolss_RemoteFindFirstPrinterChangeNotifyEx(cli, mem_ctx,
3042 &hnd,
3043 0,
3044 0,
3045 clientname,
3046 123,
3047 &option,
3048 &result);
3049 if (!W_ERROR_IS_OK(result)) {
3050 printf("Error rffpcnex %s\n", argv[1]);
3051 goto done;
3052 }
3053
3054 done:
3055 if (is_valid_policy_hnd(&hnd))
3056 rpccli_spoolss_ClosePrinter(cli, mem_ctx, &hnd, NULL);
3057
3058 return result;
3059 }
3060
3061 /****************************************************************************
3062 ****************************************************************************/
3063
3064 static bool compare_printer( struct rpc_pipe_client *cli1, struct policy_handle *hnd1,
/* [<][>][^][v][top][bottom][index][help] */
3065 struct rpc_pipe_client *cli2, struct policy_handle *hnd2 )
3066 {
3067 union spoolss_PrinterInfo info1, info2;
3068 WERROR werror;
3069 TALLOC_CTX *mem_ctx = talloc_init("compare_printer");
3070
3071 printf("Retrieving printer propertiesfor %s...", cli1->desthost);
3072 werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
3073 hnd1,
3074 2,
3075 0,
3076 &info1);
3077 if ( !W_ERROR_IS_OK(werror) ) {
3078 printf("failed (%s)\n", win_errstr(werror));
3079 talloc_destroy(mem_ctx);
3080 return false;
3081 }
3082 printf("ok\n");
3083
3084 printf("Retrieving printer properties for %s...", cli2->desthost);
3085 werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
3086 hnd2,
3087 2,
3088 0,
3089 &info2);
3090 if ( !W_ERROR_IS_OK(werror) ) {
3091 printf("failed (%s)\n", win_errstr(werror));
3092 talloc_destroy(mem_ctx);
3093 return false;
3094 }
3095 printf("ok\n");
3096
3097 talloc_destroy(mem_ctx);
3098
3099 return true;
3100 }
3101
3102 /****************************************************************************
3103 ****************************************************************************/
3104
3105 static bool compare_printer_secdesc( struct rpc_pipe_client *cli1, struct policy_handle *hnd1,
/* [<][>][^][v][top][bottom][index][help] */
3106 struct rpc_pipe_client *cli2, struct policy_handle *hnd2 )
3107 {
3108 union spoolss_PrinterInfo info1, info2;
3109 WERROR werror;
3110 TALLOC_CTX *mem_ctx = talloc_init("compare_printer_secdesc");
3111 SEC_DESC *sd1, *sd2;
3112 bool result = true;
3113
3114
3115 printf("Retrieving printer security for %s...", cli1->desthost);
3116 werror = rpccli_spoolss_getprinter(cli1, mem_ctx,
3117 hnd1,
3118 3,
3119 0,
3120 &info1);
3121 if ( !W_ERROR_IS_OK(werror) ) {
3122 printf("failed (%s)\n", win_errstr(werror));
3123 result = false;
3124 goto done;
3125 }
3126 printf("ok\n");
3127
3128 printf("Retrieving printer security for %s...", cli2->desthost);
3129 werror = rpccli_spoolss_getprinter(cli2, mem_ctx,
3130 hnd2,
3131 3,
3132 0,
3133 &info2);
3134 if ( !W_ERROR_IS_OK(werror) ) {
3135 printf("failed (%s)\n", win_errstr(werror));
3136 result = false;
3137 goto done;
3138 }
3139 printf("ok\n");
3140
3141
3142 printf("++ ");
3143
3144 sd1 = info1.info3.secdesc;
3145 sd2 = info2.info3.secdesc;
3146
3147 if ( (sd1 != sd2) && ( !sd1 || !sd2 ) ) {
3148 printf("NULL secdesc!\n");
3149 result = false;
3150 goto done;
3151 }
3152
3153 if (!sec_desc_equal( sd1, sd2 ) ) {
3154 printf("Security Descriptors *not* equal!\n");
3155 result = false;
3156 goto done;
3157 }
3158
3159 printf("Security descriptors match\n");
3160
3161 done:
3162 talloc_destroy(mem_ctx);
3163 return result;
3164 }
3165
3166
3167 /****************************************************************************
3168 ****************************************************************************/
3169
3170 extern struct user_auth_info *rpcclient_auth_info;
3171
3172 static WERROR cmd_spoolss_printercmp(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
3173 TALLOC_CTX *mem_ctx, int argc,
3174 const char **argv)
3175 {
3176 const char *printername;
3177 char *printername_path = NULL;
3178 struct cli_state *cli_server2 = NULL;
3179 struct rpc_pipe_client *cli2 = NULL;
3180 struct policy_handle hPrinter1, hPrinter2;
3181 NTSTATUS nt_status;
3182 WERROR werror;
3183
3184 if ( argc != 3 ) {
3185 printf("Usage: %s <printer> <server>\n", argv[0]);
3186 return WERR_OK;
3187 }
3188
3189 printername = argv[1];
3190
3191 /* first get the connection to the remote server */
3192
3193 nt_status = cli_full_connection(&cli_server2, global_myname(), argv[2],
3194 NULL, 0,
3195 "IPC$", "IPC",
3196 get_cmdline_auth_info_username(rpcclient_auth_info),
3197 lp_workgroup(),
3198 get_cmdline_auth_info_password(rpcclient_auth_info),
3199 get_cmdline_auth_info_use_kerberos(rpcclient_auth_info) ? CLI_FULL_CONNECTION_USE_KERBEROS : 0,
3200 get_cmdline_auth_info_signing_state(rpcclient_auth_info), NULL);
3201
3202 if ( !NT_STATUS_IS_OK(nt_status) )
3203 return WERR_GENERAL_FAILURE;
3204
3205 nt_status = cli_rpc_pipe_open_noauth(cli_server2, &ndr_table_spoolss.syntax_id,
3206 &cli2);
3207 if (!NT_STATUS_IS_OK(nt_status)) {
3208 printf("failed to open spoolss pipe on server %s (%s)\n",
3209 argv[2], nt_errstr(nt_status));
3210 return WERR_GENERAL_FAILURE;
3211 }
3212
3213 /* now open up both printers */
3214
3215 RPCCLIENT_PRINTERNAME(printername_path, cli, printername);
3216
3217 printf("Opening %s...", printername_path);
3218
3219 werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
3220 printername_path,
3221 PRINTER_ALL_ACCESS,
3222 &hPrinter1);
3223 if ( !W_ERROR_IS_OK(werror) ) {
3224 printf("failed (%s)\n", win_errstr(werror));
3225 goto done;
3226 }
3227 printf("ok\n");
3228
3229 RPCCLIENT_PRINTERNAME(printername_path, cli2, printername);
3230
3231 printf("Opening %s...", printername_path);
3232 werror = rpccli_spoolss_openprinter_ex(cli2, mem_ctx,
3233 printername_path,
3234 PRINTER_ALL_ACCESS,
3235 &hPrinter2);
3236 if ( !W_ERROR_IS_OK(werror) ) {
3237 printf("failed (%s)\n", win_errstr(werror));
3238 goto done;
3239 }
3240 printf("ok\n");
3241
3242 compare_printer( cli, &hPrinter1, cli2, &hPrinter2 );
3243 compare_printer_secdesc( cli, &hPrinter1, cli2, &hPrinter2 );
3244 #if 0
3245 compare_printerdata( cli_server1, &hPrinter1, cli_server2, &hPrinter2 );
3246 #endif
3247
3248
3249 done:
3250 /* cleanup */
3251
3252 printf("Closing printers...");
3253 rpccli_spoolss_ClosePrinter( cli, mem_ctx, &hPrinter1, NULL );
3254 rpccli_spoolss_ClosePrinter( cli2, mem_ctx, &hPrinter2, NULL );
3255 printf("ok\n");
3256
3257 /* close the second remote connection */
3258
3259 cli_shutdown( cli_server2 );
3260 return WERR_OK;
3261 }
3262
3263 static void display_proc_info1(struct spoolss_PrintProcessorInfo1 *r)
/* [<][>][^][v][top][bottom][index][help] */
3264 {
3265 printf("print_processor_name: %s\n", r->print_processor_name);
3266 }
3267
3268 static WERROR cmd_spoolss_enum_procs(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
3269 TALLOC_CTX *mem_ctx, int argc,
3270 const char **argv)
3271 {
3272 WERROR werror;
3273 const char *environment = SPOOLSS_ARCHITECTURE_NT_X86;
3274 uint32_t num_procs, level = 1, i;
3275 union spoolss_PrintProcessorInfo *procs;
3276
3277 /* Parse the command arguments */
3278
3279 if (argc < 1 || argc > 4) {
3280 printf ("Usage: %s [environment] [level]\n", argv[0]);
3281 return WERR_OK;
3282 }
3283
3284 if (argc >= 2) {
3285 environment = argv[1];
3286 }
3287
3288 if (argc == 3) {
3289 level = atoi(argv[2]);
3290 }
3291
3292 /* Enumerate Print Processors */
3293
3294 werror = rpccli_spoolss_enumprintprocessors(cli, mem_ctx,
3295 cli->srv_name_slash,
3296 environment,
3297 level,
3298 0,
3299 &num_procs,
3300 &procs);
3301 if (!W_ERROR_IS_OK(werror))
3302 goto done;
3303
3304 /* Display output */
3305
3306 for (i = 0; i < num_procs; i++) {
3307 switch (level) {
3308 case 1:
3309 display_proc_info1(&procs[i].info1);
3310 break;
3311 }
3312 }
3313
3314 done:
3315 return werror;
3316 }
3317
3318 static void display_proc_data_types_info1(struct spoolss_PrintProcDataTypesInfo1 *r)
/* [<][>][^][v][top][bottom][index][help] */
3319 {
3320 printf("name_array: %s\n", r->name_array);
3321 }
3322
3323 static WERROR cmd_spoolss_enum_proc_data_types(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
3324 TALLOC_CTX *mem_ctx, int argc,
3325 const char **argv)
3326 {
3327 WERROR werror;
3328 const char *print_processor_name = "winprint";
3329 uint32_t num_procs, level = 1, i;
3330 union spoolss_PrintProcDataTypesInfo *procs;
3331
3332 /* Parse the command arguments */
3333
3334 if (argc < 1 || argc > 4) {
3335 printf ("Usage: %s [environment] [level]\n", argv[0]);
3336 return WERR_OK;
3337 }
3338
3339 if (argc >= 2) {
3340 print_processor_name = argv[1];
3341 }
3342
3343 if (argc == 3) {
3344 level = atoi(argv[2]);
3345 }
3346
3347 /* Enumerate Print Processor Data Types */
3348
3349 werror = rpccli_spoolss_enumprintprocessordatatypes(cli, mem_ctx,
3350 cli->srv_name_slash,
3351 print_processor_name,
3352 level,
3353 0,
3354 &num_procs,
3355 &procs);
3356 if (!W_ERROR_IS_OK(werror))
3357 goto done;
3358
3359 /* Display output */
3360
3361 for (i = 0; i < num_procs; i++) {
3362 switch (level) {
3363 case 1:
3364 display_proc_data_types_info1(&procs[i].info1);
3365 break;
3366 }
3367 }
3368
3369 done:
3370 return werror;
3371 }
3372
3373 static void display_monitor1(const struct spoolss_MonitorInfo1 *r)
/* [<][>][^][v][top][bottom][index][help] */
3374 {
3375 printf("monitor_name: %s\n", r->monitor_name);
3376 }
3377
3378 static void display_monitor2(const struct spoolss_MonitorInfo2 *r)
/* [<][>][^][v][top][bottom][index][help] */
3379 {
3380 printf("monitor_name: %s\n", r->monitor_name);
3381 printf("environment: %s\n", r->environment);
3382 printf("dll_name: %s\n", r->dll_name);
3383 }
3384
3385 static WERROR cmd_spoolss_enum_monitors(struct rpc_pipe_client *cli,
/* [<][>][^][v][top][bottom][index][help] */
3386 TALLOC_CTX *mem_ctx, int argc,
3387 const char **argv)
3388 {
3389 WERROR werror;
3390 uint32_t count, level = 1, i;
3391 union spoolss_MonitorInfo *info;
3392
3393 /* Parse the command arguments */
3394
3395 if (argc > 2) {
3396 printf("Usage: %s [level]\n", argv[0]);
3397 return WERR_OK;
3398 }
3399
3400 if (argc == 2) {
3401 level = atoi(argv[1]);
3402 }
3403
3404 /* Enumerate Print Monitors */
3405
3406 werror = rpccli_spoolss_enummonitors(cli, mem_ctx,
3407 cli->srv_name_slash,
3408 level,
3409 0,
3410 &count,
3411 &info);
3412 if (!W_ERROR_IS_OK(werror)) {
3413 goto done;
3414 }
3415
3416 /* Display output */
3417
3418 for (i = 0; i < count; i++) {
3419 switch (level) {
3420 case 1:
3421 display_monitor1(&info[i].info1);
3422 break;
3423 case 2:
3424 display_monitor2(&info[i].info2);
3425 break;
3426 }
3427 }
3428
3429 done:
3430 return werror;
3431 }
3432
3433 /* List of commands exported by this module */
3434 struct cmd_set spoolss_commands[] = {
3435
3436 { "SPOOLSS" },
3437
3438 { "adddriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterdriver, &ndr_table_spoolss.syntax_id, NULL, "Add a print driver", "" },
3439 { "addprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterex, &ndr_table_spoolss.syntax_id, NULL, "Add a printer", "" },
3440 { "deldriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriver, &ndr_table_spoolss.syntax_id, NULL, "Delete a printer driver", "" },
3441 { "deldriverex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriverex, &ndr_table_spoolss.syntax_id, NULL, "Delete a printer driver with files", "" },
3442 { "enumdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data, &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer data", "" },
3443 { "enumdataex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data_ex, &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer data for a key", "" },
3444 { "enumkey", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printerkey, &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer keys", "" },
3445 { "enumjobs", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_jobs, &ndr_table_spoolss.syntax_id, NULL, "Enumerate print jobs", "" },
3446 { "getjob", RPC_RTYPE_WERROR, NULL, cmd_spoolss_get_job, &ndr_table_spoolss.syntax_id, NULL, "Get print job", "" },
3447 { "setjob", RPC_RTYPE_WERROR, NULL, cmd_spoolss_set_job, &ndr_table_spoolss.syntax_id, NULL, "Set print job", "" },
3448 { "enumports", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_ports, &ndr_table_spoolss.syntax_id, NULL, "Enumerate printer ports", "" },
3449 { "enumdrivers", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_drivers, &ndr_table_spoolss.syntax_id, NULL, "Enumerate installed printer drivers", "" },
3450 { "enumprinters", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printers, &ndr_table_spoolss.syntax_id, NULL, "Enumerate printers", "" },
3451 { "getdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdata, &ndr_table_spoolss.syntax_id, NULL, "Get print driver data", "" },
3452 { "getdataex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdataex, &ndr_table_spoolss.syntax_id, NULL, "Get printer driver data with keyname", ""},
3453 { "getdriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriver, &ndr_table_spoolss.syntax_id, NULL, "Get print driver information", "" },
3454 { "getdriverdir", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriverdir, &ndr_table_spoolss.syntax_id, NULL, "Get print driver upload directory", "" },
3455 { "getprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinter, &ndr_table_spoolss.syntax_id, NULL, "Get printer info", "" },
3456 { "openprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer_ex, &ndr_table_spoolss.syntax_id, NULL, "Open printer handle", "" },
3457 { "setdriver", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setdriver, &ndr_table_spoolss.syntax_id, NULL, "Set printer driver", "" },
3458 { "getprintprocdir", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprintprocdir, &ndr_table_spoolss.syntax_id, NULL, "Get print processor directory", "" },
3459 { "addform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_addform, &ndr_table_spoolss.syntax_id, NULL, "Add form", "" },
3460 { "setform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setform, &ndr_table_spoolss.syntax_id, NULL, "Set form", "" },
3461 { "getform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_getform, &ndr_table_spoolss.syntax_id, NULL, "Get form", "" },
3462 { "deleteform", RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform, &ndr_table_spoolss.syntax_id, NULL, "Delete form", "" },
3463 { "enumforms", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms, &ndr_table_spoolss.syntax_id, NULL, "Enumerate forms", "" },
3464 { "setprinter", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter, &ndr_table_spoolss.syntax_id, NULL, "Set printer comment", "" },
3465 { "setprintername", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername, &ndr_table_spoolss.syntax_id, NULL, "Set printername", "" },
3466 { "setprinterdata", RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata, &ndr_table_spoolss.syntax_id, NULL, "Set REG_SZ printer data", "" },
3467 { "rffpcnex", RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex, &ndr_table_spoolss.syntax_id, NULL, "Rffpcnex test", "" },
3468 { "printercmp", RPC_RTYPE_WERROR, NULL, cmd_spoolss_printercmp, &ndr_table_spoolss.syntax_id, NULL, "Printer comparison test", "" },
3469 { "enumprocs", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_procs, &ndr_table_spoolss.syntax_id, NULL, "Enumerate Print Processors", "" },
3470 { "enumprocdatatypes", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_proc_data_types, &ndr_table_spoolss.syntax_id, NULL, "Enumerate Print Processor Data Types", "" },
3471 { "enummonitors", RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_monitors, &ndr_table_spoolss.syntax_id, NULL, "Enumerate Print Monitors", "" },
3472
3473 { NULL }
3474 };