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
10   This program is free software; you can redistribute it and/or modify
11   it under the terms of the GNU General Public License as published by
12   the Free Software Foundation; either version 2 of the License, or
13   (at your option) any later version.
14
15   This program is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   GNU General Public License for more details.
19
20   You should have received a copy of the GNU General Public License
21   along with this program; if not, write to the Free Software
22   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23*/
24
25#include "includes.h"
26#include "rpcclient.h"
27
28struct table_node {
29	const char 	*long_archi;
30	const char 	*short_archi;
31	int	version;
32};
33
34/* The version int is used by getdrivers.  Note that
35   all architecture strings that support mutliple
36   versions must be grouped together since enumdrivers
37   uses this property to prevent issuing multiple
38   enumdriver calls for the same arch */
39
40
41static const struct table_node archi_table[]= {
42
43	{"Windows 4.0",          "WIN40",	0 },
44	{"Windows NT x86",       "W32X86",	2 },
45	{"Windows NT x86",       "W32X86",	3 },
46	{"Windows NT R4000",     "W32MIPS",	2 },
47	{"Windows NT Alpha_AXP", "W32ALPHA",	2 },
48	{"Windows NT PowerPC",   "W32PPC",	2 },
49	{"Windows IA64",         "IA64",        3 },
50	{"Windows x64",          "x64",         3 },
51	{NULL,                   "",		-1 }
52};
53
54/**
55 * @file
56 *
57 * rpcclient module for SPOOLSS rpc pipe.
58 *
59 * This generally just parses and checks command lines, and then calls
60 * a cli_spoolss function.
61 **/
62
63/****************************************************************************
64 function to do the mapping between the long architecture name and
65 the short one.
66****************************************************************************/
67
68static const char *cmd_spoolss_get_short_archi(const char *long_archi)
69{
70        int i=-1;
71
72        DEBUG(107,("Getting architecture dependant directory\n"));
73        do {
74                i++;
75        } while ( (archi_table[i].long_archi!=NULL ) &&
76                  StrCaseCmp(long_archi, archi_table[i].long_archi) );
77
78        if (archi_table[i].long_archi==NULL) {
79                DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
80                return NULL;
81        }
82
83	/* this might be client code - but shouldn't this be an fstrcpy etc? */
84
85
86        DEBUGADD(108,("index: [%d]\n", i));
87        DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
88        DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
89
90	return archi_table[i].short_archi;
91}
92
93/****************************************************************************
94****************************************************************************/
95
96static WERROR cmd_spoolss_open_printer_ex(struct rpc_pipe_client *cli,
97                                            TALLOC_CTX *mem_ctx,
98                                            int argc, const char **argv)
99{
100	WERROR 	        werror;
101	fstring		printername;
102	fstring		servername, user;
103	POLICY_HND	hnd;
104
105	if (argc != 2) {
106		printf("Usage: %s <printername>\n", argv[0]);
107		return WERR_OK;
108	}
109
110	if (!cli)
111            return WERR_GENERAL_FAILURE;
112
113	slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
114	strupper_m(servername);
115	fstrcpy(user, cli->user_name);
116	fstrcpy(printername, argv[1]);
117
118	/* Open the printer handle */
119
120	werror = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername,
121					     "", PRINTER_ALL_ACCESS,
122					     servername, user, &hnd);
123
124	if (W_ERROR_IS_OK(werror)) {
125		printf("Printer %s opened successfully\n", printername);
126		werror = rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
127
128		if (!W_ERROR_IS_OK(werror)) {
129			printf("Error closing printer handle! (%s)\n",
130				get_dos_error_msg(werror));
131		}
132	}
133
134	return werror;
135}
136
137
138/****************************************************************************
139****************************************************************************/
140
141static void display_print_info_0(PRINTER_INFO_0 *i0)
142{
143	fstring name = "";
144	fstring servername = "";
145
146	if (!i0)
147		return;
148
149	rpcstr_pull(name, i0->printername.buffer, sizeof(name), -1, STR_TERMINATE);
150
151	rpcstr_pull(servername, i0->servername.buffer, sizeof(servername), -1,STR_TERMINATE);
152
153	printf("\tprintername:[%s]\n", name);
154	printf("\tservername:[%s]\n", servername);
155	printf("\tcjobs:[0x%x]\n", i0->cjobs);
156	printf("\ttotal_jobs:[0x%x]\n", i0->total_jobs);
157
158	printf("\t:date: [%d]-[%d]-[%d] (%d)\n", i0->year, i0->month,
159	       i0->day, i0->dayofweek);
160	printf("\t:time: [%d]-[%d]-[%d]-[%d]\n", i0->hour, i0->minute,
161	       i0->second, i0->milliseconds);
162
163	printf("\tglobal_counter:[0x%x]\n", i0->global_counter);
164	printf("\ttotal_pages:[0x%x]\n", i0->total_pages);
165
166	printf("\tmajorversion:[0x%x]\n", i0->major_version);
167	printf("\tbuildversion:[0x%x]\n", i0->build_version);
168
169	printf("\tunknown7:[0x%x]\n", i0->unknown7);
170	printf("\tunknown8:[0x%x]\n", i0->unknown8);
171	printf("\tunknown9:[0x%x]\n", i0->unknown9);
172	printf("\tsession_counter:[0x%x]\n", i0->session_counter);
173	printf("\tunknown11:[0x%x]\n", i0->unknown11);
174	printf("\tprinter_errors:[0x%x]\n", i0->printer_errors);
175	printf("\tunknown13:[0x%x]\n", i0->unknown13);
176	printf("\tunknown14:[0x%x]\n", i0->unknown14);
177	printf("\tunknown15:[0x%x]\n", i0->unknown15);
178	printf("\tunknown16:[0x%x]\n", i0->unknown16);
179	printf("\tchange_id:[0x%x]\n", i0->change_id);
180	printf("\tunknown18:[0x%x]\n", i0->unknown18);
181	printf("\tstatus:[0x%x]\n", i0->status);
182	printf("\tunknown20:[0x%x]\n", i0->unknown20);
183	printf("\tc_setprinter:[0x%x]\n", i0->c_setprinter);
184	printf("\tunknown22:[0x%x]\n", i0->unknown22);
185	printf("\tunknown23:[0x%x]\n", i0->unknown23);
186	printf("\tunknown24:[0x%x]\n", i0->unknown24);
187	printf("\tunknown25:[0x%x]\n", i0->unknown25);
188	printf("\tunknown26:[0x%x]\n", i0->unknown26);
189	printf("\tunknown27:[0x%x]\n", i0->unknown27);
190	printf("\tunknown28:[0x%x]\n", i0->unknown28);
191	printf("\tunknown29:[0x%x]\n", i0->unknown29);
192
193	printf("\n");
194}
195
196/****************************************************************************
197****************************************************************************/
198
199static void display_print_info_1(PRINTER_INFO_1 *i1)
200{
201	fstring desc = "";
202	fstring name = "";
203	fstring comm = "";
204
205	rpcstr_pull(desc, i1->description.buffer, sizeof(desc), -1,
206		    STR_TERMINATE);
207
208	rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
209	rpcstr_pull(comm, i1->comment.buffer, sizeof(comm), -1, STR_TERMINATE);
210
211	printf("\tflags:[0x%x]\n", i1->flags);
212	printf("\tname:[%s]\n", name);
213	printf("\tdescription:[%s]\n", desc);
214	printf("\tcomment:[%s]\n", comm);
215
216	printf("\n");
217}
218
219/****************************************************************************
220****************************************************************************/
221
222static void display_print_info_2(PRINTER_INFO_2 *i2)
223{
224	fstring servername = "";
225	fstring printername = "";
226	fstring sharename = "";
227	fstring portname = "";
228	fstring drivername = "";
229	fstring comment = "";
230	fstring location = "";
231	fstring sepfile = "";
232	fstring printprocessor = "";
233	fstring datatype = "";
234	fstring parameters = "";
235
236	rpcstr_pull(servername, i2->servername.buffer,sizeof(servername), -1, STR_TERMINATE);
237	rpcstr_pull(printername, i2->printername.buffer,sizeof(printername), -1, STR_TERMINATE);
238	rpcstr_pull(sharename, i2->sharename.buffer,sizeof(sharename), -1, STR_TERMINATE);
239	rpcstr_pull(portname, i2->portname.buffer,sizeof(portname), -1, STR_TERMINATE);
240	rpcstr_pull(drivername, i2->drivername.buffer,sizeof(drivername), -1, STR_TERMINATE);
241	rpcstr_pull(comment, i2->comment.buffer,sizeof(comment), -1, STR_TERMINATE);
242	rpcstr_pull(location, i2->location.buffer,sizeof(location), -1, STR_TERMINATE);
243	rpcstr_pull(sepfile, i2->sepfile.buffer,sizeof(sepfile), -1, STR_TERMINATE);
244	rpcstr_pull(printprocessor, i2->printprocessor.buffer,sizeof(printprocessor), -1, STR_TERMINATE);
245	rpcstr_pull(datatype, i2->datatype.buffer,sizeof(datatype), -1, STR_TERMINATE);
246	rpcstr_pull(parameters, i2->parameters.buffer,sizeof(parameters), -1, STR_TERMINATE);
247
248	printf("\tservername:[%s]\n", servername);
249	printf("\tprintername:[%s]\n", printername);
250	printf("\tsharename:[%s]\n", sharename);
251	printf("\tportname:[%s]\n", portname);
252	printf("\tdrivername:[%s]\n", drivername);
253	printf("\tcomment:[%s]\n", comment);
254	printf("\tlocation:[%s]\n", location);
255	printf("\tsepfile:[%s]\n", sepfile);
256	printf("\tprintprocessor:[%s]\n", printprocessor);
257	printf("\tdatatype:[%s]\n", datatype);
258	printf("\tparameters:[%s]\n", parameters);
259	printf("\tattributes:[0x%x]\n", i2->attributes);
260	printf("\tpriority:[0x%x]\n", i2->priority);
261	printf("\tdefaultpriority:[0x%x]\n", i2->defaultpriority);
262	printf("\tstarttime:[0x%x]\n", i2->starttime);
263	printf("\tuntiltime:[0x%x]\n", i2->untiltime);
264	printf("\tstatus:[0x%x]\n", i2->status);
265	printf("\tcjobs:[0x%x]\n", i2->cjobs);
266	printf("\taverageppm:[0x%x]\n", i2->averageppm);
267
268	if (i2->secdesc)
269		display_sec_desc(i2->secdesc);
270
271	printf("\n");
272}
273
274/****************************************************************************
275****************************************************************************/
276
277static void display_print_info_3(PRINTER_INFO_3 *i3)
278{
279	display_sec_desc(i3->secdesc);
280
281	printf("\n");
282}
283
284/****************************************************************************
285****************************************************************************/
286
287static void display_print_info_7(PRINTER_INFO_7 *i7)
288{
289	fstring guid = "";
290	rpcstr_pull(guid, i7->guid.buffer,sizeof(guid), -1, STR_TERMINATE);
291	printf("\tguid:[%s]\n", guid);
292	printf("\taction:[0x%x]\n", i7->action);
293}
294
295
296/****************************************************************************
297****************************************************************************/
298
299static WERROR cmd_spoolss_enum_printers(struct rpc_pipe_client *cli,
300                                          TALLOC_CTX *mem_ctx,
301                                          int argc, const char **argv)
302{
303	WERROR                  result;
304	uint32			info_level = 1;
305	PRINTER_INFO_CTR	ctr;
306	uint32			i = 0, num_printers;
307	fstring name;
308
309	if (argc > 3)
310	{
311		printf("Usage: %s [level] [name]\n", argv[0]);
312		return WERR_OK;
313	}
314
315	if (argc >= 2)
316		info_level = atoi(argv[1]);
317
318	if (argc == 3)
319		fstrcpy(name, argv[2]);
320	else {
321		slprintf(name, sizeof(name)-1, "\\\\%s", cli->cli->desthost);
322		strupper_m(name);
323	}
324
325	ZERO_STRUCT(ctr);
326
327	result = rpccli_spoolss_enum_printers(cli, mem_ctx, name, PRINTER_ENUM_LOCAL,
328		info_level, &num_printers, &ctr);
329
330	if (W_ERROR_IS_OK(result)) {
331
332		if (!num_printers) {
333			printf ("No printers returned.\n");
334			goto done;
335		}
336
337		for (i = 0; i < num_printers; i++) {
338			switch(info_level) {
339			case 0:
340				display_print_info_0(&ctr.printers_0[i]);
341				break;
342			case 1:
343				display_print_info_1(&ctr.printers_1[i]);
344				break;
345			case 2:
346				display_print_info_2(&ctr.printers_2[i]);
347				break;
348			case 3:
349				display_print_info_3(&ctr.printers_3[i]);
350				break;
351			default:
352				printf("unknown info level %d\n", info_level);
353				goto done;
354			}
355		}
356	}
357	done:
358
359	return result;
360}
361
362/****************************************************************************
363****************************************************************************/
364
365static void display_port_info_1(PORT_INFO_1 *i1)
366{
367	fstring buffer;
368
369	rpcstr_pull(buffer, i1->port_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
370	printf("\tPort Name:\t[%s]\n", buffer);
371}
372
373/****************************************************************************
374****************************************************************************/
375
376static void display_port_info_2(PORT_INFO_2 *i2)
377{
378	fstring buffer;
379
380	rpcstr_pull(buffer, i2->port_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
381	printf("\tPort Name:\t[%s]\n", buffer);
382	rpcstr_pull(buffer, i2->monitor_name.buffer, sizeof(buffer), -1, STR_TERMINATE);
383
384	printf("\tMonitor Name:\t[%s]\n", buffer);
385	rpcstr_pull(buffer, i2->description.buffer, sizeof(buffer), -1, STR_TERMINATE);
386
387	printf("\tDescription:\t[%s]\n", buffer);
388	printf("\tPort Type:\t" );
389	if ( i2->port_type ) {
390		int comma = 0; /* hack */
391		printf( "[" );
392		if ( i2->port_type & PORT_TYPE_READ ) {
393			printf( "Read" );
394			comma = 1;
395		}
396		if ( i2->port_type & PORT_TYPE_WRITE ) {
397			printf( "%sWrite", comma ? ", " : "" );
398			comma = 1;
399		}
400		/* These two have slightly different interpretations
401		 on 95/98/ME but I'm disregarding that for now */
402		if ( i2->port_type & PORT_TYPE_REDIRECTED ) {
403			printf( "%sRedirected", comma ? ", " : "" );
404			comma = 1;
405		}
406		if ( i2->port_type & PORT_TYPE_NET_ATTACHED ) {
407			printf( "%sNet-Attached", comma ? ", " : "" );
408		}
409		printf( "]\n" );
410	} else {
411		printf( "[Unset]\n" );
412	}
413	printf("\tReserved:\t[%d]\n", i2->reserved);
414	printf("\n");
415}
416
417/****************************************************************************
418****************************************************************************/
419
420static WERROR cmd_spoolss_enum_ports(struct rpc_pipe_client *cli,
421				       TALLOC_CTX *mem_ctx, int argc,
422				       const char **argv)
423{
424	WERROR         		result;
425	uint32                  info_level = 1;
426	PORT_INFO_CTR 		ctr;
427	uint32 			returned;
428
429	if (argc > 2) {
430		printf("Usage: %s [level]\n", argv[0]);
431		return WERR_OK;
432	}
433
434	if (argc == 2)
435		info_level = atoi(argv[1]);
436
437	/* Enumerate ports */
438
439	ZERO_STRUCT(ctr);
440
441	result = rpccli_spoolss_enum_ports(cli, mem_ctx, info_level, &returned, &ctr);
442
443	if (W_ERROR_IS_OK(result)) {
444		int i;
445
446		for (i = 0; i < returned; i++) {
447			switch (info_level) {
448			case 1:
449				display_port_info_1(&ctr.port.info_1[i]);
450				break;
451			case 2:
452				display_port_info_2(&ctr.port.info_2[i]);
453				break;
454			default:
455				printf("unknown info level %d\n", info_level);
456				break;
457			}
458		}
459	}
460
461	return result;
462}
463
464/****************************************************************************
465****************************************************************************/
466
467static WERROR cmd_spoolss_setprinter(struct rpc_pipe_client *cli,
468                                       TALLOC_CTX *mem_ctx,
469                                       int argc, const char **argv)
470{
471	POLICY_HND 	pol;
472	WERROR		result;
473	uint32 		info_level = 2;
474	BOOL 		opened_hnd = False;
475	PRINTER_INFO_CTR ctr;
476	fstring 	printername,
477			servername,
478			user,
479			comment;
480
481	if (argc == 1 || argc > 3) {
482		printf("Usage: %s printername comment\n", argv[0]);
483
484		return WERR_OK;
485	}
486
487	/* Open a printer handle */
488	if (argc == 3) {
489		fstrcpy(comment, argv[2]);
490	}
491
492	slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
493	strupper_m(servername);
494	slprintf(printername, sizeof(servername)-1, "%s\\%s", servername, argv[1]);
495	fstrcpy(user, cli->user_name);
496
497	/* get a printer handle */
498	result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
499				PRINTER_ALL_ACCESS, servername,
500				user, &pol);
501
502	if (!W_ERROR_IS_OK(result))
503		goto done;
504
505	opened_hnd = True;
506
507	/* Get printer info */
508        result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, info_level, &ctr);
509
510        if (!W_ERROR_IS_OK(result))
511                goto done;
512
513
514	/* Modify the comment. */
515	init_unistr(&ctr.printers_2->comment, comment);
516	ctr.printers_2->devmode = NULL;
517	ctr.printers_2->secdesc = NULL;
518
519	result = rpccli_spoolss_setprinter(cli, mem_ctx, &pol, info_level, &ctr, 0);
520	if (W_ERROR_IS_OK(result))
521		printf("Success in setting comment.\n");
522
523 done:
524	if (opened_hnd)
525		rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
526
527	return result;
528}
529
530/****************************************************************************
531****************************************************************************/
532
533static WERROR cmd_spoolss_setprintername(struct rpc_pipe_client *cli,
534                                       TALLOC_CTX *mem_ctx,
535                                       int argc, const char **argv)
536{
537	POLICY_HND 	pol;
538	WERROR		result;
539	uint32 		info_level = 2;
540	BOOL 		opened_hnd = False;
541	PRINTER_INFO_CTR ctr;
542	fstring 	printername,
543			servername,
544			user,
545			new_printername;
546
547	if (argc == 1 || argc > 3) {
548		printf("Usage: %s printername new_printername\n", argv[0]);
549
550		return WERR_OK;
551	}
552
553	/* Open a printer handle */
554	if (argc == 3) {
555		fstrcpy(new_printername, argv[2]);
556	}
557
558	slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
559	strupper_m(servername);
560	slprintf(printername, sizeof(printername)-1, "%s\\%s", servername, argv[1]);
561	fstrcpy(user, cli->user_name);
562
563	/* get a printer handle */
564	result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
565				PRINTER_ALL_ACCESS, servername,
566				user, &pol);
567
568	if (!W_ERROR_IS_OK(result))
569		goto done;
570
571	opened_hnd = True;
572
573	/* Get printer info */
574        result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, info_level, &ctr);
575
576        if (!W_ERROR_IS_OK(result))
577                goto done;
578
579	/* Modify the printername. */
580	init_unistr(&ctr.printers_2->printername, new_printername);
581	ctr.printers_2->devmode = NULL;
582	ctr.printers_2->secdesc = NULL;
583
584	result = rpccli_spoolss_setprinter(cli, mem_ctx, &pol, info_level, &ctr, 0);
585	if (W_ERROR_IS_OK(result))
586		printf("Success in setting printername.\n");
587
588 done:
589	if (opened_hnd)
590		rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
591
592	return result;
593}
594
595/****************************************************************************
596****************************************************************************/
597
598static WERROR cmd_spoolss_getprinter(struct rpc_pipe_client *cli,
599                                       TALLOC_CTX *mem_ctx,
600                                       int argc, const char **argv)
601{
602	POLICY_HND 	pol;
603	WERROR          result;
604	uint32 		info_level = 1;
605	BOOL 		opened_hnd = False;
606	PRINTER_INFO_CTR ctr;
607	fstring 	printername,
608			servername,
609			user;
610
611	if (argc == 1 || argc > 3) {
612		printf("Usage: %s <printername> [level]\n", argv[0]);
613		return WERR_OK;
614	}
615
616	/* Open a printer handle */
617	if (argc == 3) {
618		info_level = atoi(argv[2]);
619	}
620
621	slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
622	strupper_m(servername);
623	slprintf(printername, sizeof(printername)-1, "%s\\%s", servername, argv[1]);
624	fstrcpy(user, cli->user_name);
625
626	/* get a printer handle */
627
628	result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername,
629					     "", MAXIMUM_ALLOWED_ACCESS,
630					     servername, user, &pol);
631
632	if (!W_ERROR_IS_OK(result))
633		goto done;
634
635	opened_hnd = True;
636
637	/* Get printer info */
638
639	result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, info_level, &ctr);
640
641	if (!W_ERROR_IS_OK(result))
642		goto done;
643
644	/* Display printer info */
645
646	switch (info_level) {
647	case 0:
648		display_print_info_0(ctr.printers_0);
649		break;
650	case 1:
651		display_print_info_1(ctr.printers_1);
652		break;
653	case 2:
654		display_print_info_2(ctr.printers_2);
655		break;
656	case 3:
657		display_print_info_3(ctr.printers_3);
658		break;
659	case 7:
660		display_print_info_7(ctr.printers_7);
661		break;
662	default:
663		printf("unknown info level %d\n", info_level);
664		break;
665	}
666
667 done:
668	if (opened_hnd)
669		rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
670
671	return result;
672}
673
674/****************************************************************************
675****************************************************************************/
676
677static void display_reg_value(REGISTRY_VALUE value)
678{
679	pstring text;
680
681	switch(value.type) {
682	case REG_DWORD:
683		printf("%s: REG_DWORD: 0x%08x\n", value.valuename,
684		       *((uint32 *) value.data_p));
685		break;
686	case REG_SZ:
687		rpcstr_pull(text, value.data_p, sizeof(text), value.size,
688			    STR_TERMINATE);
689		printf("%s: REG_SZ: %s\n", value.valuename, text);
690		break;
691	case REG_BINARY: {
692		char *hex = hex_encode(NULL, value.data_p, value.size);
693		size_t i, len;
694		printf("%s: REG_BINARY:", value.valuename);
695		len = strlen(hex);
696		for (i=0; i<len; i++) {
697			if (hex[i] == '\0') {
698				break;
699			}
700			if (i%40 == 0) {
701				putchar('\n');
702			}
703			putchar(hex[i]);
704		}
705		TALLOC_FREE(hex);
706		putchar('\n');
707		break;
708	}
709	case REG_MULTI_SZ: {
710		uint16 *curstr = (uint16 *) value.data_p;
711		uint8 *start = value.data_p;
712		printf("%s: REG_MULTI_SZ:\n", value.valuename);
713		while (((uint8 *) curstr < start + value.size)) {
714			rpcstr_pull(text, curstr, sizeof(text), -1,
715				    STR_TERMINATE);
716			printf("  %s\n", *text != 0 ? text : "NULL");
717			curstr += strlen(text) + 1;
718		}
719	}
720	break;
721	default:
722		printf("%s: unknown type %d\n", value.valuename, value.type);
723	}
724
725}
726
727/****************************************************************************
728****************************************************************************/
729
730static WERROR cmd_spoolss_getprinterdata(struct rpc_pipe_client *cli,
731					   TALLOC_CTX *mem_ctx,
732					   int argc, const char **argv)
733{
734	POLICY_HND 	pol;
735	WERROR          result;
736	BOOL 		opened_hnd = False;
737	fstring 	printername,
738			servername,
739			user;
740	const char *valuename;
741	REGISTRY_VALUE value;
742
743	if (argc != 3) {
744		printf("Usage: %s <printername> <valuename>\n", argv[0]);
745		printf("<printername> of . queries print server\n");
746		return WERR_OK;
747	}
748	valuename = argv[2];
749
750	/* Open a printer handle */
751
752	slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
753	strupper_m(servername);
754	if (strncmp(argv[1], ".", sizeof(".")) == 0)
755		fstrcpy(printername, servername);
756	else
757		slprintf(printername, sizeof(servername)-1, "%s\\%s",
758			  servername, argv[1]);
759	fstrcpy(user, cli->user_name);
760
761	/* get a printer handle */
762
763	result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername,
764					     "", MAXIMUM_ALLOWED_ACCESS,
765					     servername, user, &pol);
766
767	if (!W_ERROR_IS_OK(result))
768		goto done;
769
770	opened_hnd = True;
771
772	/* Get printer info */
773
774	result = rpccli_spoolss_getprinterdata(cli, mem_ctx, &pol, valuename, &value);
775
776	if (!W_ERROR_IS_OK(result))
777		goto done;
778
779	/* Display printer data */
780
781	fstrcpy(value.valuename, valuename);
782	display_reg_value(value);
783
784
785 done:
786	if (opened_hnd)
787		rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
788
789	return result;
790}
791
792/****************************************************************************
793****************************************************************************/
794
795static WERROR cmd_spoolss_getprinterdataex(struct rpc_pipe_client *cli,
796					     TALLOC_CTX *mem_ctx,
797					     int argc, const char **argv)
798{
799	POLICY_HND 	pol;
800	WERROR          result;
801	BOOL 		opened_hnd = False;
802	fstring 	printername,
803			servername,
804			user;
805	const char *valuename, *keyname;
806	REGISTRY_VALUE value;
807
808	if (argc != 4) {
809		printf("Usage: %s <printername> <keyname> <valuename>\n",
810		       argv[0]);
811		printf("<printername> of . queries print server\n");
812		return WERR_OK;
813	}
814	valuename = argv[3];
815	keyname = argv[2];
816
817	/* Open a printer handle */
818
819	slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
820	strupper_m(servername);
821	if (strncmp(argv[1], ".", sizeof(".")) == 0)
822		fstrcpy(printername, servername);
823	else
824		slprintf(printername, sizeof(printername)-1, "%s\\%s",
825			  servername, argv[1]);
826	fstrcpy(user, cli->user_name);
827
828	/* get a printer handle */
829
830	result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername,
831					     "", MAXIMUM_ALLOWED_ACCESS,
832					     servername, user, &pol);
833
834	if (!W_ERROR_IS_OK(result))
835		goto done;
836
837	opened_hnd = True;
838
839	/* Get printer info */
840
841	result = rpccli_spoolss_getprinterdataex(cli, mem_ctx, &pol, keyname,
842		valuename, &value);
843
844	if (!W_ERROR_IS_OK(result))
845		goto done;
846
847	/* Display printer data */
848
849	fstrcpy(value.valuename, valuename);
850	display_reg_value(value);
851
852
853 done:
854	if (opened_hnd)
855		rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
856
857	return result;
858}
859
860/****************************************************************************
861****************************************************************************/
862
863static void display_print_driver_1(DRIVER_INFO_1 *i1)
864{
865	fstring name;
866	if (i1 == NULL)
867		return;
868
869	rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
870
871	printf ("Printer Driver Info 1:\n");
872	printf ("\tDriver Name: [%s]\n\n", name);
873
874	return;
875}
876
877/****************************************************************************
878****************************************************************************/
879
880static void display_print_driver_2(DRIVER_INFO_2 *i1)
881{
882	fstring name;
883	fstring architecture;
884	fstring driverpath;
885	fstring datafile;
886	fstring configfile;
887	if (i1 == NULL)
888		return;
889
890	rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
891	rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), -1, STR_TERMINATE);
892	rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), -1, STR_TERMINATE);
893	rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), -1, STR_TERMINATE);
894	rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), -1, STR_TERMINATE);
895
896	printf ("Printer Driver Info 2:\n");
897	printf ("\tVersion: [%x]\n", i1->version);
898	printf ("\tDriver Name: [%s]\n", name);
899	printf ("\tArchitecture: [%s]\n", architecture);
900	printf ("\tDriver Path: [%s]\n", driverpath);
901	printf ("\tDatafile: [%s]\n", datafile);
902	printf ("\tConfigfile: [%s]\n\n", configfile);
903
904	return;
905}
906
907/****************************************************************************
908****************************************************************************/
909
910static void display_print_driver_3(DRIVER_INFO_3 *i1)
911{
912	fstring name = "";
913	fstring architecture = "";
914	fstring driverpath = "";
915	fstring datafile = "";
916	fstring configfile = "";
917	fstring helpfile = "";
918	fstring dependentfiles = "";
919	fstring monitorname = "";
920	fstring defaultdatatype = "";
921
922	int length=0;
923	BOOL valid = True;
924
925	if (i1 == NULL)
926		return;
927
928	rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
929	rpcstr_pull(architecture, i1->architecture.buffer, sizeof(architecture), -1, STR_TERMINATE);
930	rpcstr_pull(driverpath, i1->driverpath.buffer, sizeof(driverpath), -1, STR_TERMINATE);
931	rpcstr_pull(datafile, i1->datafile.buffer, sizeof(datafile), -1, STR_TERMINATE);
932	rpcstr_pull(configfile, i1->configfile.buffer, sizeof(configfile), -1, STR_TERMINATE);
933	rpcstr_pull(helpfile, i1->helpfile.buffer, sizeof(helpfile), -1, STR_TERMINATE);
934	rpcstr_pull(monitorname, i1->monitorname.buffer, sizeof(monitorname), -1, STR_TERMINATE);
935	rpcstr_pull(defaultdatatype, i1->defaultdatatype.buffer, sizeof(defaultdatatype), -1, STR_TERMINATE);
936
937	printf ("Printer Driver Info 3:\n");
938	printf ("\tVersion: [%x]\n", i1->version);
939	printf ("\tDriver Name: [%s]\n",name);
940	printf ("\tArchitecture: [%s]\n", architecture);
941	printf ("\tDriver Path: [%s]\n", driverpath);
942	printf ("\tDatafile: [%s]\n", datafile);
943	printf ("\tConfigfile: [%s]\n", configfile);
944	printf ("\tHelpfile: [%s]\n\n", helpfile);
945
946	while (valid)
947	{
948		rpcstr_pull(dependentfiles, i1->dependentfiles+length, sizeof(dependentfiles), -1, STR_TERMINATE);
949
950		length+=strlen(dependentfiles)+1;
951
952		if (strlen(dependentfiles) > 0)
953		{
954			printf ("\tDependentfiles: [%s]\n", dependentfiles);
955		}
956		else
957		{
958			valid = False;
959		}
960	}
961
962	printf ("\n");
963
964	printf ("\tMonitorname: [%s]\n", monitorname);
965	printf ("\tDefaultdatatype: [%s]\n\n", defaultdatatype);
966
967	return;
968}
969
970/****************************************************************************
971****************************************************************************/
972
973static WERROR cmd_spoolss_getdriver(struct rpc_pipe_client *cli,
974                                      TALLOC_CTX *mem_ctx,
975                                      int argc, const char **argv)
976{
977	POLICY_HND 	pol;
978	WERROR          werror;
979	uint32		info_level = 3;
980	BOOL 		opened_hnd = False;
981	PRINTER_DRIVER_CTR 	ctr;
982	fstring 	printername,
983			servername,
984			user;
985	uint32		i;
986	BOOL		success = False;
987
988	if ((argc == 1) || (argc > 3))
989	{
990		printf("Usage: %s <printername> [level]\n", argv[0]);
991		return WERR_OK;
992	}
993
994	/* get the arguments need to open the printer handle */
995	slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
996	strupper_m(servername);
997	fstrcpy(user, cli->user_name);
998	slprintf(printername, sizeof(servername)-1, "%s\\%s", servername, argv[1]);
999	if (argc == 3)
1000		info_level = atoi(argv[2]);
1001
1002	/* Open a printer handle */
1003
1004	werror = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
1005					     PRINTER_ACCESS_USE,
1006					     servername, user, &pol);
1007
1008	if (!W_ERROR_IS_OK(werror)) {
1009		printf("Error opening printer handle for %s!\n", printername);
1010		return werror;
1011	}
1012
1013	opened_hnd = True;
1014
1015	/* loop through and print driver info level for each architecture */
1016
1017	for (i=0; archi_table[i].long_archi!=NULL; i++) {
1018
1019		werror = rpccli_spoolss_getprinterdriver( cli, mem_ctx, &pol, info_level,
1020			archi_table[i].long_archi, archi_table[i].version,
1021			&ctr);
1022
1023		if (!W_ERROR_IS_OK(werror))
1024			continue;
1025
1026		/* need at least one success */
1027
1028		success = True;
1029
1030		printf ("\n[%s]\n", archi_table[i].long_archi);
1031
1032		switch (info_level) {
1033		case 1:
1034			display_print_driver_1 (ctr.info1);
1035			break;
1036		case 2:
1037			display_print_driver_2 (ctr.info2);
1038			break;
1039		case 3:
1040			display_print_driver_3 (ctr.info3);
1041			break;
1042		default:
1043			printf("unknown info level %d\n", info_level);
1044			break;
1045		}
1046	}
1047
1048	/* Cleanup */
1049
1050	if (opened_hnd)
1051		rpccli_spoolss_close_printer (cli, mem_ctx, &pol);
1052
1053	if ( success )
1054		werror = WERR_OK;
1055
1056	return werror;
1057}
1058
1059/****************************************************************************
1060****************************************************************************/
1061
1062static WERROR cmd_spoolss_enum_drivers(struct rpc_pipe_client *cli,
1063                                         TALLOC_CTX *mem_ctx,
1064                                         int argc, const char **argv)
1065{
1066	WERROR werror = WERR_OK;
1067	uint32          info_level = 1;
1068	PRINTER_DRIVER_CTR 	ctr;
1069	uint32		i, j,
1070			returned;
1071
1072	if (argc > 2) {
1073		printf("Usage: enumdrivers [level]\n");
1074		return WERR_OK;
1075	}
1076
1077	if (argc == 2)
1078		info_level = atoi(argv[1]);
1079
1080
1081	/* loop through and print driver info level for each architecture */
1082	for (i=0; archi_table[i].long_archi!=NULL; i++) {
1083		/* check to see if we already asked for this architecture string */
1084
1085		if ( i>0 && strequal(archi_table[i].long_archi, archi_table[i-1].long_archi) )
1086			continue;
1087
1088		werror = rpccli_spoolss_enumprinterdrivers(
1089			cli, mem_ctx, info_level,
1090			archi_table[i].long_archi, &returned, &ctr);
1091
1092		if (W_ERROR_V(werror) == W_ERROR_V(WERR_INVALID_ENVIRONMENT)) {
1093			printf ("Server does not support environment [%s]\n",
1094				archi_table[i].long_archi);
1095			werror = WERR_OK;
1096			continue;
1097		}
1098
1099		if (returned == 0)
1100			continue;
1101
1102		if (!W_ERROR_IS_OK(werror)) {
1103			printf ("Error getting driver for environment [%s] - %d\n",
1104				archi_table[i].long_archi, W_ERROR_V(werror));
1105			continue;
1106		}
1107
1108		printf ("\n[%s]\n", archi_table[i].long_archi);
1109		switch (info_level)
1110		{
1111
1112		case 1:
1113			for (j=0; j < returned; j++) {
1114				display_print_driver_1 (&ctr.info1[j]);
1115			}
1116			break;
1117		case 2:
1118			for (j=0; j < returned; j++) {
1119				display_print_driver_2 (&ctr.info2[j]);
1120			}
1121			break;
1122		case 3:
1123			for (j=0; j < returned; j++) {
1124				display_print_driver_3 (&ctr.info3[j]);
1125			}
1126			break;
1127		default:
1128			printf("unknown info level %d\n", info_level);
1129			return WERR_UNKNOWN_LEVEL;
1130		}
1131	}
1132
1133	return werror;
1134}
1135
1136/****************************************************************************
1137****************************************************************************/
1138
1139static void display_printdriverdir_1(DRIVER_DIRECTORY_1 *i1)
1140{
1141        fstring name;
1142        if (i1 == NULL)
1143                return;
1144
1145	rpcstr_pull(name, i1->name.buffer, sizeof(name), -1, STR_TERMINATE);
1146
1147	printf ("\tDirectory Name:[%s]\n", name);
1148}
1149
1150/****************************************************************************
1151****************************************************************************/
1152
1153static WERROR cmd_spoolss_getdriverdir(struct rpc_pipe_client *cli,
1154                                         TALLOC_CTX *mem_ctx,
1155                                         int argc, const char **argv)
1156{
1157	WERROR result;
1158	fstring			env;
1159	DRIVER_DIRECTORY_CTR	ctr;
1160
1161	if (argc > 2) {
1162		printf("Usage: %s [environment]\n", argv[0]);
1163		return WERR_OK;
1164	}
1165
1166	/* Get the arguments need to open the printer handle */
1167
1168	if (argc == 2)
1169		fstrcpy (env, argv[1]);
1170	else
1171		fstrcpy (env, "Windows NT x86");
1172
1173	/* Get the directory.  Only use Info level 1 */
1174
1175	result = rpccli_spoolss_getprinterdriverdir(cli, mem_ctx, 1, env, &ctr);
1176
1177	if (W_ERROR_IS_OK(result))
1178		display_printdriverdir_1(ctr.info1);
1179
1180	return result;
1181}
1182
1183/****************************************************************************
1184****************************************************************************/
1185
1186void set_drv_info_3_env (DRIVER_INFO_3 *info, const char *arch)
1187{
1188
1189	int i;
1190
1191	for (i=0; archi_table[i].long_archi != NULL; i++)
1192	{
1193		if (strcmp(arch, archi_table[i].short_archi) == 0)
1194		{
1195			info->version = archi_table[i].version;
1196			init_unistr (&info->architecture, archi_table[i].long_archi);
1197			break;
1198		}
1199	}
1200
1201	if (archi_table[i].long_archi == NULL)
1202	{
1203		DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch));
1204	}
1205
1206	return;
1207}
1208
1209
1210/**************************************************************************
1211 wrapper for strtok to get the next parameter from a delimited list.
1212 Needed to handle the empty parameter string denoted by "NULL"
1213 *************************************************************************/
1214
1215static char* get_driver_3_param (char* str, const char* delim, UNISTR* dest)
1216{
1217	char	*ptr;
1218
1219	/* get the next token */
1220	ptr = strtok(str, delim);
1221
1222	/* a string of 'NULL' is used to represent an empty
1223	   parameter because two consecutive delimiters
1224	   will not return an empty string.  See man strtok(3)
1225	   for details */
1226	if (ptr && (StrCaseCmp(ptr, "NULL") == 0))
1227		ptr = NULL;
1228
1229	if (dest != NULL)
1230		init_unistr(dest, ptr);
1231
1232	return ptr;
1233}
1234
1235/********************************************************************************
1236 fill in the members of a DRIVER_INFO_3 struct using a character
1237 string in the form of
1238 	 <Long Printer Name>:<Driver File Name>:<Data File Name>:\
1239	     <Config File Name>:<Help File Name>:<Language Monitor Name>:\
1240	     <Default Data Type>:<Comma Separated list of Files>
1241 *******************************************************************************/
1242static BOOL init_drv_info_3_members ( TALLOC_CTX *mem_ctx, DRIVER_INFO_3 *info,
1243                                      char *args )
1244{
1245	char	*str, *str2;
1246	uint32	len, i;
1247
1248	/* fill in the UNISTR fields */
1249	str = get_driver_3_param (args, ":", &info->name);
1250	str = get_driver_3_param (NULL, ":", &info->driverpath);
1251	str = get_driver_3_param (NULL, ":", &info->datafile);
1252	str = get_driver_3_param (NULL, ":", &info->configfile);
1253	str = get_driver_3_param (NULL, ":", &info->helpfile);
1254	str = get_driver_3_param (NULL, ":", &info->monitorname);
1255	str = get_driver_3_param (NULL, ":", &info->defaultdatatype);
1256
1257	/* <Comma Separated List of Dependent Files> */
1258	str2 = get_driver_3_param (NULL, ":", NULL); /* save the beginning of the string */
1259	str = str2;
1260
1261	/* begin to strip out each filename */
1262	str = strtok(str, ",");
1263	len = 0;
1264	while (str != NULL)
1265	{
1266		/* keep a cumlative count of the str lengths */
1267		len += strlen(str)+1;
1268		str = strtok(NULL, ",");
1269	}
1270
1271	/* allocate the space; add one extra slot for a terminating NULL.
1272	   Each filename is NULL terminated and the end contains a double
1273	   NULL */
1274	if ((info->dependentfiles=TALLOC_ARRAY(mem_ctx, uint16, len+1)) == NULL)
1275	{
1276		DEBUG(0,("init_drv_info_3_members: Unable to malloc memory for dependenfiles\n"));
1277		return False;
1278	}
1279	for (i=0; i<len; i++)
1280	{
1281		SSVAL(&info->dependentfiles[i], 0, str2[i]);
1282	}
1283	info->dependentfiles[len] = '\0';
1284
1285	return True;
1286}
1287
1288
1289/****************************************************************************
1290****************************************************************************/
1291
1292static WERROR cmd_spoolss_addprinterdriver(struct rpc_pipe_client *cli,
1293                                             TALLOC_CTX *mem_ctx,
1294                                             int argc, const char **argv)
1295{
1296	WERROR result;
1297	uint32                  level = 3;
1298	PRINTER_DRIVER_CTR	ctr;
1299	DRIVER_INFO_3		info3;
1300	const char		*arch;
1301	fstring			driver_name;
1302	char 			*driver_args;
1303
1304	/* parse the command arguements */
1305	if (argc != 3 && argc != 4)
1306	{
1307		printf ("Usage: %s <Environment> \\\n", argv[0]);
1308		printf ("\t<Long Printer Name>:<Driver File Name>:<Data File Name>:\\\n");
1309    		printf ("\t<Config File Name>:<Help File Name>:<Language Monitor Name>:\\\n");
1310	    	printf ("\t<Default Data Type>:<Comma Separated list of Files> \\\n");
1311		printf ("\t[version]\n");
1312
1313            return WERR_OK;
1314        }
1315
1316	/* Fill in the DRIVER_INFO_3 struct */
1317	ZERO_STRUCT(info3);
1318	if (!(arch = cmd_spoolss_get_short_archi(argv[1])))
1319	{
1320		printf ("Error Unknown architechture [%s]\n", argv[1]);
1321		return WERR_INVALID_PARAM;
1322	}
1323	else
1324		set_drv_info_3_env(&info3, arch);
1325
1326	driver_args = talloc_strdup( mem_ctx, argv[2] );
1327	if (!init_drv_info_3_members(mem_ctx, &info3, driver_args ))
1328	{
1329		printf ("Error Invalid parameter list - %s.\n", argv[2]);
1330		return WERR_INVALID_PARAM;
1331	}
1332
1333	/* if printer driver version specified, override the default version
1334	 * used by the architecture.  This allows installation of Windows
1335	 * 2000 (version 3) printer drivers. */
1336	if (argc == 4)
1337	{
1338		info3.version = atoi(argv[3]);
1339	}
1340
1341
1342	ctr.info3 = &info3;
1343	result = rpccli_spoolss_addprinterdriver (cli, mem_ctx, level, &ctr);
1344
1345	if (W_ERROR_IS_OK(result)) {
1346		rpcstr_pull(driver_name, info3.name.buffer,
1347			    sizeof(driver_name), -1, STR_TERMINATE);
1348		printf ("Printer Driver %s successfully installed.\n",
1349			driver_name);
1350	}
1351
1352	return result;
1353}
1354
1355
1356/****************************************************************************
1357****************************************************************************/
1358
1359static WERROR cmd_spoolss_addprinterex(struct rpc_pipe_client *cli,
1360                                         TALLOC_CTX *mem_ctx,
1361                                         int argc, const char **argv)
1362{
1363	WERROR result;
1364	uint32			level = 2;
1365	PRINTER_INFO_CTR	ctr;
1366	PRINTER_INFO_2		info2;
1367	fstring			servername;
1368
1369	/* parse the command arguements */
1370	if (argc != 5)
1371	{
1372		printf ("Usage: %s <name> <shared name> <driver> <port>\n", argv[0]);
1373		return WERR_OK;
1374        }
1375
1376        slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
1377        strupper_m(servername);
1378
1379	/* Fill in the DRIVER_INFO_2 struct */
1380	ZERO_STRUCT(info2);
1381
1382	init_unistr( &info2.printername,	argv[1]);
1383	init_unistr( &info2.sharename, 		argv[2]);
1384	init_unistr( &info2.drivername,		argv[3]);
1385	init_unistr( &info2.portname,		argv[4]);
1386	init_unistr( &info2.comment,		"Created by rpcclient");
1387	init_unistr( &info2.printprocessor, 	"winprint");
1388	init_unistr( &info2.datatype,		"RAW");
1389	info2.devmode = 	NULL;
1390	info2.secdesc = 	NULL;
1391	info2.attributes 	= PRINTER_ATTRIBUTE_SHARED;
1392	info2.priority 		= 0;
1393	info2.defaultpriority	= 0;
1394	info2.starttime		= 0;
1395	info2.untiltime		= 0;
1396
1397	/* These three fields must not be used by AddPrinter()
1398	   as defined in the MS Platform SDK documentation..
1399	   --jerry
1400	info2.status		= 0;
1401	info2.cjobs		= 0;
1402	info2.averageppm	= 0;
1403	*/
1404
1405	ctr.printers_2 = &info2;
1406	result = rpccli_spoolss_addprinterex (cli, mem_ctx, level, &ctr);
1407
1408	if (W_ERROR_IS_OK(result))
1409		printf ("Printer %s successfully installed.\n", argv[1]);
1410
1411	return result;
1412}
1413
1414/****************************************************************************
1415****************************************************************************/
1416
1417static WERROR cmd_spoolss_setdriver(struct rpc_pipe_client *cli,
1418                                      TALLOC_CTX *mem_ctx,
1419                                      int argc, const char **argv)
1420{
1421	POLICY_HND		pol;
1422	WERROR                  result;
1423	uint32			level = 2;
1424	BOOL			opened_hnd = False;
1425	PRINTER_INFO_CTR	ctr;
1426	PRINTER_INFO_2		info2;
1427	fstring			servername,
1428				printername,
1429				user;
1430
1431	/* parse the command arguements */
1432	if (argc != 3)
1433	{
1434		printf ("Usage: %s <printer> <driver>\n", argv[0]);
1435		return WERR_OK;
1436        }
1437
1438	slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
1439	strupper_m(servername);
1440	slprintf(printername, sizeof(printername)-1, "%s\\%s", servername, argv[1]);
1441	fstrcpy(user, cli->user_name);
1442
1443	/* Get a printer handle */
1444
1445	result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
1446					     PRINTER_ALL_ACCESS,
1447					     servername, user, &pol);
1448
1449	if (!W_ERROR_IS_OK(result))
1450		goto done;
1451
1452	opened_hnd = True;
1453
1454	/* Get printer info */
1455
1456	ZERO_STRUCT (info2);
1457	ctr.printers_2 = &info2;
1458
1459	result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, level, &ctr);
1460
1461	if (!W_ERROR_IS_OK(result)) {
1462		printf ("Unable to retrieve printer information!\n");
1463		goto done;
1464	}
1465
1466	/* Set the printer driver */
1467
1468	init_unistr(&ctr.printers_2->drivername, argv[2]);
1469
1470	result = rpccli_spoolss_setprinter(cli, mem_ctx, &pol, level, &ctr, 0);
1471
1472	if (!W_ERROR_IS_OK(result)) {
1473		printf("SetPrinter call failed!\n");
1474		goto done;;
1475	}
1476
1477	printf("Succesfully set %s to driver %s.\n", argv[1], argv[2]);
1478
1479done:
1480	/* Cleanup */
1481
1482	if (opened_hnd)
1483		rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
1484
1485	return result;
1486}
1487
1488
1489/****************************************************************************
1490****************************************************************************/
1491
1492static WERROR cmd_spoolss_deletedriverex(struct rpc_pipe_client *cli,
1493                                         TALLOC_CTX *mem_ctx,
1494                                         int argc, const char **argv)
1495{
1496	WERROR result, ret = WERR_UNKNOWN_PRINTER_DRIVER;
1497
1498	int   i;
1499	int vers = -1;
1500
1501	const char *arch = NULL;
1502
1503	/* parse the command arguements */
1504	if (argc < 2 || argc > 4) {
1505		printf ("Usage: %s <driver> [arch] [version]\n", argv[0]);
1506		return WERR_OK;
1507	}
1508
1509	if (argc >= 3)
1510		arch = argv[2];
1511	if (argc == 4)
1512		vers = atoi (argv[3]);
1513
1514
1515	/* delete the driver for all architectures */
1516	for (i=0; archi_table[i].long_archi; i++) {
1517
1518		if (arch &&  !strequal( archi_table[i].long_archi, arch))
1519			continue;
1520
1521		if (vers >= 0 && archi_table[i].version != vers)
1522			continue;
1523
1524		/* make the call to remove the driver */
1525		result = rpccli_spoolss_deleteprinterdriverex(
1526			cli, mem_ctx, archi_table[i].long_archi, argv[1], archi_table[i].version);
1527
1528		if ( !W_ERROR_IS_OK(result) )
1529		{
1530			if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1531				printf ("Failed to remove driver %s for arch [%s] (version: %d): %s\n",
1532					argv[1], archi_table[i].long_archi, archi_table[i].version, dos_errstr(result));
1533			}
1534		}
1535		else
1536		{
1537			printf ("Driver %s and files removed for arch [%s] (version: %d).\n", argv[1],
1538			archi_table[i].long_archi, archi_table[i].version);
1539			ret = WERR_OK;
1540		}
1541	}
1542
1543	return ret;
1544}
1545
1546
1547/****************************************************************************
1548****************************************************************************/
1549
1550static WERROR cmd_spoolss_deletedriver(struct rpc_pipe_client *cli,
1551                                         TALLOC_CTX *mem_ctx,
1552                                         int argc, const char **argv)
1553{
1554	WERROR result = WERR_OK;
1555	fstring			servername;
1556	int			i;
1557
1558	/* parse the command arguements */
1559	if (argc != 2) {
1560		printf ("Usage: %s <driver>\n", argv[0]);
1561		return WERR_OK;
1562        }
1563
1564	slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
1565	strupper_m(servername);
1566
1567	/* delete the driver for all architectures */
1568	for (i=0; archi_table[i].long_archi; i++) {
1569		/* make the call to remove the driver */
1570		result = rpccli_spoolss_deleteprinterdriver(
1571			cli, mem_ctx, archi_table[i].long_archi, argv[1]);
1572
1573		if ( !W_ERROR_IS_OK(result) ) {
1574			if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) {
1575				printf ("Failed to remove driver %s for arch [%s] - error 0x%x!\n",
1576					argv[1], archi_table[i].long_archi,
1577					W_ERROR_V(result));
1578			}
1579		} else {
1580			printf ("Driver %s removed for arch [%s].\n", argv[1],
1581				archi_table[i].long_archi);
1582		}
1583	}
1584
1585	return result;
1586}
1587
1588/****************************************************************************
1589****************************************************************************/
1590
1591static WERROR cmd_spoolss_getprintprocdir(struct rpc_pipe_client *cli,
1592					    TALLOC_CTX *mem_ctx,
1593					    int argc, const char **argv)
1594{
1595	WERROR result;
1596	char *servername = NULL, *environment = NULL;
1597	fstring procdir;
1598
1599	/* parse the command arguements */
1600	if (argc > 2) {
1601		printf ("Usage: %s [environment]\n", argv[0]);
1602		return WERR_OK;
1603        }
1604
1605	if (asprintf(&servername, "\\\\%s", cli->cli->desthost) < 0)
1606		return WERR_NOMEM;
1607	strupper_m(servername);
1608
1609	if (asprintf(&environment, "%s", (argc == 2) ? argv[1] :
1610		     PRINTER_DRIVER_ARCHITECTURE) < 0) {
1611		SAFE_FREE(servername);
1612		return WERR_NOMEM;
1613	}
1614
1615	result = rpccli_spoolss_getprintprocessordirectory(
1616		cli, mem_ctx, servername, environment, procdir);
1617
1618	if (W_ERROR_IS_OK(result))
1619		printf("%s\n", procdir);
1620
1621	SAFE_FREE(servername);
1622	SAFE_FREE(environment);
1623
1624	return result;
1625}
1626
1627/****************************************************************************
1628****************************************************************************/
1629
1630static WERROR cmd_spoolss_addform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1631				    int argc, const char **argv)
1632{
1633	POLICY_HND handle;
1634	WERROR werror;
1635	char *servername = NULL, *printername = NULL;
1636	FORM form;
1637	BOOL got_handle = False;
1638
1639	/* Parse the command arguements */
1640
1641	if (argc != 3) {
1642		printf ("Usage: %s <printer> <formname>\n", argv[0]);
1643		return WERR_OK;
1644        }
1645
1646	/* Get a printer handle */
1647
1648	asprintf(&servername, "\\\\%s", cli->cli->desthost);
1649	strupper_m(servername);
1650	asprintf(&printername, "%s\\%s", servername, argv[1]);
1651
1652	werror = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
1653					     PRINTER_ALL_ACCESS,
1654					     servername, cli->user_name, &handle);
1655
1656	if (!W_ERROR_IS_OK(werror))
1657		goto done;
1658
1659	got_handle = True;
1660
1661	/* Dummy up some values for the form data */
1662
1663	form.flags = FORM_USER;
1664	form.size_x = form.size_y = 100;
1665	form.left = 0;
1666	form.top = 10;
1667	form.right = 20;
1668	form.bottom = 30;
1669
1670	init_unistr2(&form.name, argv[2], UNI_STR_TERMINATE);
1671
1672	/* Add the form */
1673
1674
1675	werror = rpccli_spoolss_addform(cli, mem_ctx, &handle, 1, &form);
1676
1677 done:
1678	if (got_handle)
1679		rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
1680
1681	SAFE_FREE(servername);
1682	SAFE_FREE(printername);
1683
1684	return werror;
1685}
1686
1687/****************************************************************************
1688****************************************************************************/
1689
1690static WERROR cmd_spoolss_setform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1691				    int argc, const char **argv)
1692{
1693	POLICY_HND handle;
1694	WERROR werror;
1695	char *servername = NULL, *printername = NULL;
1696	FORM form;
1697	BOOL got_handle = False;
1698
1699	/* Parse the command arguements */
1700
1701	if (argc != 3) {
1702		printf ("Usage: %s <printer> <formname>\n", argv[0]);
1703		return WERR_OK;
1704        }
1705
1706	/* Get a printer handle */
1707
1708	asprintf(&servername, "\\\\%s", cli->cli->desthost);
1709	strupper_m(servername);
1710	asprintf(&printername, "%s\\%s", servername, argv[1]);
1711
1712	werror = rpccli_spoolss_open_printer_ex(
1713		cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS,
1714		servername, cli->user_name, &handle);
1715
1716	if (!W_ERROR_IS_OK(werror))
1717		goto done;
1718
1719	got_handle = True;
1720
1721	/* Dummy up some values for the form data */
1722
1723	form.flags = FORM_PRINTER;
1724	form.size_x = form.size_y = 100;
1725	form.left = 0;
1726	form.top = 1000;
1727	form.right = 2000;
1728	form.bottom = 3000;
1729
1730	init_unistr2(&form.name, argv[2], UNI_STR_TERMINATE);
1731
1732	/* Set the form */
1733
1734	werror = rpccli_spoolss_setform(cli, mem_ctx, &handle, 1, argv[2], &form);
1735
1736 done:
1737	if (got_handle)
1738		rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
1739
1740	SAFE_FREE(servername);
1741	SAFE_FREE(printername);
1742
1743	return werror;
1744}
1745
1746/****************************************************************************
1747****************************************************************************/
1748
1749static const char *get_form_flag(int form_flag)
1750{
1751	switch (form_flag) {
1752	case FORM_USER:
1753		return "FORM_USER";
1754	case FORM_BUILTIN:
1755		return "FORM_BUILTIN";
1756	case FORM_PRINTER:
1757		return "FORM_PRINTER";
1758	default:
1759		return "unknown";
1760	}
1761}
1762
1763/****************************************************************************
1764****************************************************************************/
1765
1766static void display_form(FORM_1 *form)
1767{
1768	fstring form_name = "";
1769
1770	if (form->name.buffer)
1771		rpcstr_pull(form_name, form->name.buffer,
1772			    sizeof(form_name), -1, STR_TERMINATE);
1773
1774	printf("%s\n" \
1775		"\tflag: %s (%d)\n" \
1776		"\twidth: %d, length: %d\n" \
1777		"\tleft: %d, right: %d, top: %d, bottom: %d\n\n",
1778		form_name, get_form_flag(form->flag), form->flag,
1779		form->width, form->length,
1780		form->left, form->right,
1781		form->top, form->bottom);
1782}
1783
1784/****************************************************************************
1785****************************************************************************/
1786
1787static WERROR cmd_spoolss_getform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1788				    int argc, const char **argv)
1789{
1790	POLICY_HND handle;
1791	WERROR werror;
1792	char *servername = NULL, *printername = NULL;
1793	FORM_1 form;
1794	BOOL got_handle = False;
1795
1796	/* Parse the command arguements */
1797
1798	if (argc != 3) {
1799		printf ("Usage: %s <printer> <formname>\n", argv[0]);
1800		return WERR_OK;
1801        }
1802
1803	/* Get a printer handle */
1804
1805	asprintf(&servername, "\\\\%s", cli->cli->desthost);
1806	strupper_m(servername);
1807	asprintf(&printername, "%s\\%s", servername, argv[1]);
1808
1809	werror = rpccli_spoolss_open_printer_ex(
1810		cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS,
1811		servername, cli->user_name, &handle);
1812
1813	if (!W_ERROR_IS_OK(werror))
1814		goto done;
1815
1816	got_handle = True;
1817
1818	/* Get the form */
1819
1820	werror = rpccli_spoolss_getform(cli, mem_ctx, &handle, argv[2], 1, &form);
1821
1822	if (!W_ERROR_IS_OK(werror))
1823		goto done;
1824
1825	display_form(&form);
1826
1827 done:
1828	if (got_handle)
1829		rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
1830
1831	SAFE_FREE(servername);
1832	SAFE_FREE(printername);
1833
1834	return werror;
1835}
1836
1837/****************************************************************************
1838****************************************************************************/
1839
1840static WERROR cmd_spoolss_deleteform(struct rpc_pipe_client *cli,
1841				       TALLOC_CTX *mem_ctx, int argc,
1842				       const char **argv)
1843{
1844	POLICY_HND handle;
1845	WERROR werror;
1846	char *servername = NULL, *printername = NULL;
1847	BOOL got_handle = False;
1848
1849	/* Parse the command arguements */
1850
1851	if (argc != 3) {
1852		printf ("Usage: %s <printer> <formname>\n", argv[0]);
1853		return WERR_OK;
1854        }
1855
1856	/* Get a printer handle */
1857
1858	asprintf(&servername, "\\\\%s", cli->cli->desthost);
1859	strupper_m(servername);
1860	asprintf(&printername, "%s\\%s", servername, argv[1]);
1861
1862	werror = rpccli_spoolss_open_printer_ex(
1863		cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS,
1864		servername, cli->user_name, &handle);
1865
1866	if (!W_ERROR_IS_OK(werror))
1867		goto done;
1868
1869	got_handle = True;
1870
1871	/* Delete the form */
1872
1873	werror = rpccli_spoolss_deleteform(cli, mem_ctx, &handle, argv[2]);
1874
1875 done:
1876	if (got_handle)
1877		rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
1878
1879	SAFE_FREE(servername);
1880	SAFE_FREE(printername);
1881
1882	return werror;
1883}
1884
1885/****************************************************************************
1886****************************************************************************/
1887
1888static WERROR cmd_spoolss_enum_forms(struct rpc_pipe_client *cli,
1889				       TALLOC_CTX *mem_ctx, int argc,
1890				       const char **argv)
1891{
1892	POLICY_HND handle;
1893	WERROR werror;
1894	char *servername = NULL, *printername = NULL;
1895	BOOL got_handle = False;
1896	uint32 num_forms, level = 1, i;
1897	FORM_1 *forms;
1898
1899	/* Parse the command arguements */
1900
1901	if (argc != 2) {
1902		printf ("Usage: %s <printer>\n", argv[0]);
1903		return WERR_OK;
1904        }
1905
1906	/* Get a printer handle */
1907
1908	asprintf(&servername, "\\\\%s", cli->cli->desthost);
1909	strupper_m(servername);
1910	asprintf(&printername, "%s\\%s", servername, argv[1]);
1911
1912	werror = rpccli_spoolss_open_printer_ex(
1913		cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS,
1914		servername, cli->user_name, &handle);
1915
1916	if (!W_ERROR_IS_OK(werror))
1917		goto done;
1918
1919	got_handle = True;
1920
1921	/* Enumerate forms */
1922
1923	werror = rpccli_spoolss_enumforms(cli, mem_ctx, &handle, level, &num_forms, &forms);
1924
1925	if (!W_ERROR_IS_OK(werror))
1926		goto done;
1927
1928	/* Display output */
1929
1930	for (i = 0; i < num_forms; i++) {
1931
1932		display_form(&forms[i]);
1933
1934	}
1935
1936 done:
1937	if (got_handle)
1938		rpccli_spoolss_close_printer(cli, mem_ctx, &handle);
1939
1940	SAFE_FREE(servername);
1941	SAFE_FREE(printername);
1942
1943	return werror;
1944}
1945
1946/****************************************************************************
1947****************************************************************************/
1948
1949static WERROR cmd_spoolss_setprinterdata(struct rpc_pipe_client *cli,
1950					    TALLOC_CTX *mem_ctx,
1951					    int argc, const char **argv)
1952{
1953	WERROR result;
1954	fstring servername, printername, user;
1955	POLICY_HND pol;
1956	BOOL opened_hnd = False;
1957	PRINTER_INFO_CTR ctr;
1958	PRINTER_INFO_0 info;
1959	REGISTRY_VALUE value;
1960
1961	/* parse the command arguements */
1962	if (argc < 5) {
1963		printf ("Usage: %s <printer> <string|binary|dword|multistring>"
1964			" <value> <data>\n",
1965			argv[0]);
1966		return WERR_INVALID_PARAM;
1967	}
1968
1969	slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
1970	strupper_m(servername);
1971	slprintf(printername, sizeof(servername)-1, "%s\\%s", servername, argv[1]);
1972	fstrcpy(user, cli->user_name);
1973
1974	value.type = REG_NONE;
1975
1976	if (strequal(argv[2], "string")) {
1977		value.type = REG_SZ;
1978	}
1979
1980	if (strequal(argv[2], "binary")) {
1981		value.type = REG_BINARY;
1982	}
1983
1984	if (strequal(argv[2], "dword")) {
1985		value.type = REG_DWORD;
1986	}
1987
1988	if (strequal(argv[2], "multistring")) {
1989		value.type = REG_MULTI_SZ;
1990	}
1991
1992	if (value.type == REG_NONE) {
1993		printf("Unknown data type: %s\n", argv[2]);
1994		return WERR_INVALID_PARAM;
1995	}
1996
1997	/* get a printer handle */
1998	result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "",
1999					     MAXIMUM_ALLOWED_ACCESS, servername,
2000					     user, &pol);
2001	if (!W_ERROR_IS_OK(result))
2002		goto done;
2003
2004	opened_hnd = True;
2005
2006	ctr.printers_0 = &info;
2007
2008        result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, 0, &ctr);
2009
2010        if (!W_ERROR_IS_OK(result))
2011                goto done;
2012
2013	printf("%s\n", current_timestring(True));
2014	printf("\tchange_id (before set)\t:[0x%x]\n", info.change_id);
2015
2016	/* Set the printer data */
2017
2018	fstrcpy(value.valuename, argv[3]);
2019
2020	switch (value.type) {
2021	case REG_SZ: {
2022		UNISTR2 data;
2023		init_unistr2(&data, argv[4], UNI_STR_TERMINATE);
2024		value.size = data.uni_str_len * 2;
2025		if (value.size) {
2026			value.data_p = (uint8 *)TALLOC_MEMDUP(mem_ctx, data.buffer,
2027						      value.size);
2028		} else {
2029			value.data_p = NULL;
2030		}
2031		break;
2032	}
2033	case REG_DWORD: {
2034		uint32 data = strtoul(argv[4], NULL, 10);
2035		value.size = sizeof(data);
2036		if (sizeof(data)) {
2037			value.data_p = (uint8 *)TALLOC_MEMDUP(mem_ctx, &data,
2038						      sizeof(data));
2039		} else {
2040			value.data_p = NULL;
2041		}
2042		break;
2043	}
2044	case REG_BINARY: {
2045		DATA_BLOB data = strhex_to_data_blob(mem_ctx, argv[4]);
2046		value.data_p = data.data;
2047		value.size = data.length;
2048		break;
2049	}
2050	case REG_MULTI_SZ: {
2051		int i;
2052		size_t len = 0;
2053		char *p;
2054
2055		for (i=4; i<argc; i++) {
2056			if (strcmp(argv[i], "NULL") == 0) {
2057				argv[i] = "";
2058			}
2059			len += strlen(argv[i])+1;
2060		}
2061
2062		value.size = len*2;
2063		value.data_p = TALLOC_ARRAY(mem_ctx, unsigned char, value.size);
2064		if (value.data_p == NULL) {
2065			result = WERR_NOMEM;
2066			goto done;
2067		}
2068
2069		p = (char *)value.data_p;
2070		len = value.size;
2071		for (i=4; i<argc; i++) {
2072			size_t l = (strlen(argv[i])+1)*2;
2073			rpcstr_push(p, argv[i], len, STR_TERMINATE);
2074			p += l;
2075			len -= l;
2076		}
2077		SMB_ASSERT(len == 0);
2078		break;
2079	}
2080	default:
2081		printf("Unknown data type: %s\n", argv[2]);
2082		result = WERR_INVALID_PARAM;
2083		goto done;
2084	}
2085
2086	result = rpccli_spoolss_setprinterdata(cli, mem_ctx, &pol, &value);
2087
2088	if (!W_ERROR_IS_OK(result)) {
2089		printf ("Unable to set [%s=%s]!\n", argv[3], argv[4]);
2090		goto done;
2091	}
2092	printf("\tSetPrinterData succeeded [%s: %s]\n", argv[3], argv[4]);
2093
2094        result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, 0, &ctr);
2095
2096        if (!W_ERROR_IS_OK(result))
2097                goto done;
2098
2099	printf("%s\n", current_timestring(True));
2100	printf("\tchange_id (after set)\t:[0x%x]\n", info.change_id);
2101
2102done:
2103	/* cleanup */
2104	if (opened_hnd)
2105		rpccli_spoolss_close_printer(cli, mem_ctx, &pol);
2106
2107	return result;
2108}
2109
2110/****************************************************************************
2111****************************************************************************/
2112
2113static void display_job_info_1(JOB_INFO_1 *job)
2114{
2115	fstring username = "", document = "", text_status = "";
2116
2117	rpcstr_pull(username, job->username.buffer,
2118		    sizeof(username), -1, STR_TERMINATE);
2119
2120	rpcstr_pull(document, job->document.buffer,
2121		    sizeof(document), -1, STR_TERMINATE);
2122
2123	rpcstr_pull(text_status, job->text_status.buffer,
2124		    sizeof(text_status), -1, STR_TERMINATE);
2125
2126	printf("%d: jobid[%d]: %s %s %s %d/%d pages\n", job->position, job->jobid,
2127	       username, document, text_status, job->pagesprinted,
2128	       job->totalpages);
2129}
2130
2131/****************************************************************************
2132****************************************************************************/
2133
2134static void display_job_info_2(JOB_INFO_2 *job)
2135{
2136	fstring username = "", document = "", text_status = "";
2137
2138	rpcstr_pull(username, job->username.buffer,
2139		    sizeof(username), -1, STR_TERMINATE);
2140
2141	rpcstr_pull(document, job->document.buffer,
2142		    sizeof(document), -1, STR_TERMINATE);
2143
2144	rpcstr_pull(text_status, job->text_status.buffer,
2145		    sizeof(text_status), -1, STR_TERMINATE);
2146
2147	printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n", job->position, job->jobid,
2148	       username, document, text_status, job->pagesprinted,
2149	       job->totalpages, job->size);
2150}
2151
2152/****************************************************************************
2153****************************************************************************/
2154
2155static WERROR cmd_spoolss_enum_jobs(struct rpc_pipe_client *cli,
2156				      TALLOC_CTX *mem_ctx, int argc,
2157				      const char **argv)
2158{
2159	WERROR result;
2160	uint32 level = 1, num_jobs, i;
2161	BOOL got_hnd = False;
2162	pstring printername;
2163	fstring servername, user;
2164	POLICY_HND hnd;
2165	JOB_INFO_CTR ctr;
2166
2167	if (argc < 2 || argc > 3) {
2168		printf("Usage: %s printername [level]\n", argv[0]);
2169		return WERR_OK;
2170	}
2171
2172	if (argc == 3)
2173		level = atoi(argv[2]);
2174
2175	/* Open printer handle */
2176
2177	slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
2178	strupper_m(servername);
2179	fstrcpy(user, cli->user_name);
2180	slprintf(printername, sizeof(servername)-1, "\\\\%s\\", cli->cli->desthost);
2181	strupper_m(printername);
2182	pstrcat(printername, argv[1]);
2183
2184	result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername,
2185					     "", MAXIMUM_ALLOWED_ACCESS,
2186					     servername, user, &hnd);
2187
2188	if (!W_ERROR_IS_OK(result))
2189		goto done;
2190
2191	got_hnd = True;
2192
2193	/* Enumerate ports */
2194
2195	result = rpccli_spoolss_enumjobs(cli, mem_ctx, &hnd, level, 0, 1000,
2196		&num_jobs, &ctr);
2197
2198	if (!W_ERROR_IS_OK(result))
2199		goto done;
2200
2201	for (i = 0; i < num_jobs; i++) {
2202		switch(level) {
2203		case 1:
2204			display_job_info_1(&ctr.job.job_info_1[i]);
2205			break;
2206		case 2:
2207			display_job_info_2(&ctr.job.job_info_2[i]);
2208			break;
2209		default:
2210			d_printf("unknown info level %d\n", level);
2211			break;
2212		}
2213	}
2214
2215done:
2216	if (got_hnd)
2217		rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
2218
2219	return result;
2220}
2221
2222/****************************************************************************
2223****************************************************************************/
2224
2225static WERROR cmd_spoolss_enum_data( struct rpc_pipe_client *cli,
2226				       TALLOC_CTX *mem_ctx, int argc,
2227				       const char **argv)
2228{
2229	WERROR result;
2230	uint32 i=0, val_needed, data_needed;
2231	BOOL got_hnd = False;
2232	pstring printername;
2233	fstring servername, user;
2234	POLICY_HND hnd;
2235
2236	if (argc != 2) {
2237		printf("Usage: %s printername\n", argv[0]);
2238		return WERR_OK;
2239	}
2240
2241	/* Open printer handle */
2242
2243	slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
2244	strupper_m(servername);
2245	fstrcpy(user, cli->user_name);
2246	slprintf(printername, sizeof(printername)-1, "\\\\%s\\", cli->cli->desthost);
2247	strupper_m(printername);
2248	pstrcat(printername, argv[1]);
2249
2250	result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername,
2251					     "", MAXIMUM_ALLOWED_ACCESS,
2252					     servername, user, &hnd);
2253
2254	if (!W_ERROR_IS_OK(result))
2255		goto done;
2256
2257	got_hnd = True;
2258
2259	/* Enumerate data */
2260
2261	result = rpccli_spoolss_enumprinterdata(cli, mem_ctx, &hnd, i, 0, 0,
2262					     &val_needed, &data_needed,
2263					     NULL);
2264	while (W_ERROR_IS_OK(result)) {
2265		REGISTRY_VALUE value;
2266		result = rpccli_spoolss_enumprinterdata(
2267			cli, mem_ctx, &hnd, i++, val_needed,
2268			data_needed, 0, 0, &value);
2269		if (W_ERROR_IS_OK(result))
2270			display_reg_value(value);
2271	}
2272	if (W_ERROR_V(result) == ERRnomoreitems)
2273		result = W_ERROR(ERRsuccess);
2274
2275done:
2276	if (got_hnd)
2277		rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
2278
2279	return result;
2280}
2281
2282/****************************************************************************
2283****************************************************************************/
2284
2285static WERROR cmd_spoolss_enum_data_ex( struct rpc_pipe_client *cli,
2286					  TALLOC_CTX *mem_ctx, int argc,
2287					  const char **argv)
2288{
2289	WERROR result;
2290	uint32 i;
2291	BOOL got_hnd = False;
2292	pstring printername;
2293	fstring servername, user;
2294	const char *keyname = NULL;
2295	POLICY_HND hnd;
2296	REGVAL_CTR *ctr = NULL;
2297
2298	if (argc != 3) {
2299		printf("Usage: %s printername <keyname>\n", argv[0]);
2300		return WERR_OK;
2301	}
2302
2303	keyname = argv[2];
2304
2305	/* Open printer handle */
2306
2307	slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
2308	strupper_m(servername);
2309	fstrcpy(user, cli->user_name);
2310	slprintf(printername, sizeof(printername)-1, "\\\\%s\\", cli->cli->desthost);
2311	strupper_m(printername);
2312	pstrcat(printername, argv[1]);
2313
2314	result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername,
2315					     "", MAXIMUM_ALLOWED_ACCESS,
2316					     servername, user, &hnd);
2317
2318	if (!W_ERROR_IS_OK(result))
2319		goto done;
2320
2321	got_hnd = True;
2322
2323	/* Enumerate subkeys */
2324
2325	if ( !(ctr = TALLOC_ZERO_P( mem_ctx, REGVAL_CTR )) )
2326		return WERR_NOMEM;
2327
2328	result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx, &hnd, keyname, ctr);
2329
2330	if (!W_ERROR_IS_OK(result))
2331		goto done;
2332
2333	for (i=0; i < ctr->num_values; i++) {
2334		display_reg_value(*(ctr->values[i]));
2335	}
2336
2337	TALLOC_FREE( ctr );
2338
2339done:
2340	if (got_hnd)
2341		rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
2342
2343	return result;
2344}
2345
2346/****************************************************************************
2347****************************************************************************/
2348
2349static WERROR cmd_spoolss_enum_printerkey( struct rpc_pipe_client *cli,
2350					     TALLOC_CTX *mem_ctx, int argc,
2351					     const char **argv)
2352{
2353	WERROR result;
2354	BOOL got_hnd = False;
2355	pstring printername;
2356	fstring servername, user;
2357	const char *keyname = NULL;
2358	POLICY_HND hnd;
2359	uint16 *keylist = NULL, *curkey;
2360
2361	if (argc < 2 || argc > 3) {
2362		printf("Usage: %s printername [keyname]\n", argv[0]);
2363		return WERR_OK;
2364	}
2365
2366	if (argc == 3)
2367		keyname = argv[2];
2368	else
2369		keyname = "";
2370
2371	/* Open printer handle */
2372
2373	slprintf(servername, sizeof(servername)-1, "\\\\%s", cli->cli->desthost);
2374	strupper_m(servername);
2375	fstrcpy(user, cli->user_name);
2376	slprintf(printername, sizeof(printername)-1, "\\\\%s\\", cli->cli->desthost);
2377	strupper_m(printername);
2378	pstrcat(printername, argv[1]);
2379
2380	result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername,
2381					     "", MAXIMUM_ALLOWED_ACCESS,
2382					     servername, user, &hnd);
2383
2384	if (!W_ERROR_IS_OK(result))
2385		goto done;
2386
2387	got_hnd = True;
2388
2389	/* Enumerate subkeys */
2390
2391	result = rpccli_spoolss_enumprinterkey(cli, mem_ctx, &hnd, keyname, &keylist, NULL);
2392
2393	if (!W_ERROR_IS_OK(result))
2394		goto done;
2395
2396	curkey = keylist;
2397	while (*curkey != 0) {
2398		pstring subkey;
2399		rpcstr_pull(subkey, curkey, sizeof(subkey), -1,
2400			    STR_TERMINATE);
2401		printf("%s\n", subkey);
2402		curkey += strlen(subkey) + 1;
2403	}
2404
2405done:
2406
2407	SAFE_FREE(keylist);
2408
2409	if (got_hnd)
2410		rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
2411
2412	return result;
2413}
2414
2415/****************************************************************************
2416****************************************************************************/
2417
2418static WERROR cmd_spoolss_rffpcnex(struct rpc_pipe_client *cli,
2419				     TALLOC_CTX *mem_ctx, int argc,
2420				     const char **argv)
2421{
2422	fstring servername, printername;
2423	POLICY_HND hnd;
2424	BOOL got_hnd = False;
2425	WERROR result;
2426	SPOOL_NOTIFY_OPTION option;
2427
2428	if (argc != 2) {
2429		printf("Usage: %s printername\n", argv[0]);
2430		result = WERR_OK;
2431		goto done;
2432	}
2433
2434	/* Open printer */
2435
2436	slprintf(servername, sizeof(servername) - 1, "\\\\%s", cli->cli->desthost);
2437	strupper_m(servername);
2438
2439	slprintf(printername, sizeof(printername) - 1, "\\\\%s\\%s", cli->cli->desthost,
2440		 argv[1]);
2441	strupper_m(printername);
2442
2443	result = rpccli_spoolss_open_printer_ex(
2444		cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS,
2445		servername, cli->user_name, &hnd);
2446
2447	if (!W_ERROR_IS_OK(result)) {
2448		printf("Error opening %s\n", argv[1]);
2449		goto done;
2450	}
2451
2452	got_hnd = True;
2453
2454	/* Create spool options */
2455
2456	ZERO_STRUCT(option);
2457
2458	option.version = 2;
2459	option.option_type_ptr = 1;
2460	option.count = option.ctr.count = 2;
2461
2462	option.ctr.type = TALLOC_ARRAY(mem_ctx, SPOOL_NOTIFY_OPTION_TYPE, 2);
2463	if (option.ctr.type == NULL) {
2464		result = WERR_NOMEM;
2465		goto done;
2466	}
2467
2468	ZERO_STRUCT(option.ctr.type[0]);
2469	option.ctr.type[0].type = PRINTER_NOTIFY_TYPE;
2470	option.ctr.type[0].count = option.ctr.type[0].count2 = 1;
2471	option.ctr.type[0].fields_ptr = 1;
2472	option.ctr.type[0].fields[0] = PRINTER_NOTIFY_SERVER_NAME;
2473
2474	ZERO_STRUCT(option.ctr.type[1]);
2475	option.ctr.type[1].type = JOB_NOTIFY_TYPE;
2476	option.ctr.type[1].count = option.ctr.type[1].count2 = 1;
2477	option.ctr.type[1].fields_ptr = 1;
2478	option.ctr.type[1].fields[0] = JOB_NOTIFY_PRINTER_NAME;
2479
2480	/* Send rffpcnex */
2481
2482	slprintf(servername, sizeof(servername) - 1, "\\\\%s", myhostname());
2483	strupper_m(servername);
2484
2485	result = rpccli_spoolss_rffpcnex(
2486		cli, mem_ctx, &hnd, 0, 0, servername, 123, &option);
2487
2488	if (!W_ERROR_IS_OK(result)) {
2489		printf("Error rffpcnex %s\n", argv[1]);
2490		goto done;
2491	}
2492
2493done:
2494	if (got_hnd)
2495		rpccli_spoolss_close_printer(cli, mem_ctx, &hnd);
2496
2497	return result;
2498}
2499
2500/****************************************************************************
2501****************************************************************************/
2502
2503static BOOL compare_printer( struct rpc_pipe_client *cli1, POLICY_HND *hnd1,
2504                             struct rpc_pipe_client *cli2, POLICY_HND *hnd2 )
2505{
2506	PRINTER_INFO_CTR ctr1, ctr2;
2507	WERROR werror;
2508	TALLOC_CTX *mem_ctx = talloc_init("compare_printer");
2509
2510	printf("Retrieving printer propertiesfor %s...", cli1->cli->desthost);
2511	werror = rpccli_spoolss_getprinter( cli1, mem_ctx, hnd1, 2, &ctr1);
2512	if ( !W_ERROR_IS_OK(werror) ) {
2513		printf("failed (%s)\n", dos_errstr(werror));
2514		talloc_destroy(mem_ctx);
2515		return False;
2516	}
2517	printf("ok\n");
2518
2519	printf("Retrieving printer properties for %s...", cli2->cli->desthost);
2520	werror = rpccli_spoolss_getprinter( cli2, mem_ctx, hnd2, 2, &ctr2);
2521	if ( !W_ERROR_IS_OK(werror) ) {
2522		printf("failed (%s)\n", dos_errstr(werror));
2523		talloc_destroy(mem_ctx);
2524		return False;
2525	}
2526	printf("ok\n");
2527
2528	talloc_destroy(mem_ctx);
2529
2530	return True;
2531}
2532
2533/****************************************************************************
2534****************************************************************************/
2535
2536static BOOL compare_printer_secdesc( struct rpc_pipe_client *cli1, POLICY_HND *hnd1,
2537                                     struct rpc_pipe_client *cli2, POLICY_HND *hnd2 )
2538{
2539	PRINTER_INFO_CTR ctr1, ctr2;
2540	WERROR werror;
2541	TALLOC_CTX *mem_ctx = talloc_init("compare_printer_secdesc");
2542	SEC_DESC *sd1, *sd2;
2543	BOOL result = True;
2544
2545
2546	printf("Retreiving printer security for %s...", cli1->cli->desthost);
2547	werror = rpccli_spoolss_getprinter( cli1, mem_ctx, hnd1, 3, &ctr1);
2548	if ( !W_ERROR_IS_OK(werror) ) {
2549		printf("failed (%s)\n", dos_errstr(werror));
2550		result = False;
2551		goto done;
2552	}
2553	printf("ok\n");
2554
2555	printf("Retrieving printer security for %s...", cli2->cli->desthost);
2556	werror = rpccli_spoolss_getprinter( cli2, mem_ctx, hnd2, 3, &ctr2);
2557	if ( !W_ERROR_IS_OK(werror) ) {
2558		printf("failed (%s)\n", dos_errstr(werror));
2559		result = False;
2560		goto done;
2561	}
2562	printf("ok\n");
2563
2564
2565	printf("++ ");
2566
2567	if ( (ctr1.printers_3 != ctr2.printers_3) && (!ctr1.printers_3 || !ctr2.printers_3) ) {
2568		printf("NULL PRINTER_INFO_3!\n");
2569		result = False;
2570		goto done;
2571	}
2572
2573	sd1 = ctr1.printers_3->secdesc;
2574	sd2 = ctr2.printers_3->secdesc;
2575
2576	if ( (sd1 != sd2) && ( !sd1 || !sd2 ) ) {
2577		printf("NULL secdesc!\n");
2578		result = False;
2579		goto done;
2580	}
2581
2582	if (!sec_desc_equal( sd1, sd2 ) ) {
2583		printf("Security Descriptors *not* equal!\n");
2584		result = False;
2585		goto done;
2586	}
2587
2588	printf("Security descriptors match\n");
2589
2590done:
2591	talloc_destroy(mem_ctx);
2592	return result;
2593}
2594
2595
2596/****************************************************************************
2597****************************************************************************/
2598
2599static WERROR cmd_spoolss_printercmp(struct rpc_pipe_client *cli,
2600				     TALLOC_CTX *mem_ctx, int argc,
2601				     const char **argv)
2602{
2603	fstring printername, servername1, servername2;
2604	pstring printername_path;
2605	struct cli_state *cli_server1 = cli->cli;
2606	struct cli_state *cli_server2 = NULL;
2607	struct rpc_pipe_client *cli2 = NULL;
2608	POLICY_HND hPrinter1, hPrinter2;
2609	NTSTATUS nt_status;
2610	WERROR werror;
2611
2612	if ( argc != 3 )  {
2613		printf("Usage: %s <printer> <server>\n", argv[0]);
2614		return WERR_OK;
2615	}
2616
2617	fstrcpy( printername, argv[1] );
2618
2619	fstr_sprintf( servername1, cli->cli->desthost );
2620	fstrcpy( servername2, argv[2] );
2621	strupper_m( servername1 );
2622	strupper_m( servername2 );
2623
2624
2625	/* first get the connection to the remote server */
2626
2627	nt_status = cli_full_connection(&cli_server2, global_myname(), servername2,
2628					NULL, 0,
2629					"IPC$", "IPC",
2630					cmdline_auth_info.username,
2631					lp_workgroup(),
2632					cmdline_auth_info.password,
2633					cmdline_auth_info.use_kerberos ? CLI_FULL_CONNECTION_USE_KERBEROS : 0,
2634					cmdline_auth_info.signing_state, NULL);
2635
2636	if ( !NT_STATUS_IS_OK(nt_status) )
2637		return WERR_GENERAL_FAILURE;
2638
2639	cli2 = cli_rpc_pipe_open_noauth(cli_server2, PI_SPOOLSS, &nt_status);
2640	if (!cli2) {
2641		printf("failed to open spoolss pipe on server %s (%s)\n",
2642			servername2, nt_errstr(nt_status));
2643		return WERR_GENERAL_FAILURE;
2644	}
2645
2646	/* now open up both printers */
2647
2648	pstr_sprintf( printername_path, "\\\\%s\\%s", servername1, printername );
2649	printf("Opening %s...", printername_path);
2650	werror = rpccli_spoolss_open_printer_ex( cli, mem_ctx, printername_path,
2651		"", PRINTER_ALL_ACCESS, servername1, cli_server1->user_name, &hPrinter1);
2652	if ( !W_ERROR_IS_OK(werror) ) {
2653		printf("failed (%s)\n", dos_errstr(werror));
2654		goto done;
2655	}
2656	printf("ok\n");
2657
2658	pstr_sprintf( printername_path, "\\\\%s\\%s", servername2, printername );
2659	printf("Opening %s...", printername_path);
2660	werror = rpccli_spoolss_open_printer_ex( cli2, mem_ctx, printername_path,
2661		"", PRINTER_ALL_ACCESS, servername2, cli_server2->user_name, &hPrinter2 );
2662	if ( !W_ERROR_IS_OK(werror) ) {
2663		 printf("failed (%s)\n", dos_errstr(werror));
2664		goto done;
2665	}
2666	printf("ok\n");
2667
2668
2669	compare_printer( cli, &hPrinter1, cli2, &hPrinter2 );
2670	compare_printer_secdesc( cli, &hPrinter1, cli2, &hPrinter2 );
2671#if 0
2672	compare_printerdata( cli_server1, &hPrinter1, cli_server2, &hPrinter2 );
2673#endif
2674
2675
2676done:
2677	/* cleanup */
2678
2679	printf("Closing printers...");
2680	rpccli_spoolss_close_printer( cli, mem_ctx, &hPrinter1 );
2681	rpccli_spoolss_close_printer( cli2, mem_ctx, &hPrinter2 );
2682	printf("ok\n");
2683
2684	/* close the second remote connection */
2685
2686	cli_shutdown( cli_server2 );
2687
2688	return WERR_OK;
2689}
2690
2691/* List of commands exported by this module */
2692struct cmd_set spoolss_commands[] = {
2693
2694	{ "SPOOLSS"  },
2695
2696	{ "adddriver",		RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterdriver,	PI_SPOOLSS, NULL, "Add a print driver",                  "" },
2697	{ "addprinter",		RPC_RTYPE_WERROR, NULL, cmd_spoolss_addprinterex,	PI_SPOOLSS, NULL, "Add a printer",                       "" },
2698	{ "deldriver",		RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriver,	PI_SPOOLSS, NULL, "Delete a printer driver",             "" },
2699	{ "deldriverex",	RPC_RTYPE_WERROR, NULL, cmd_spoolss_deletedriverex,	PI_SPOOLSS, NULL, "Delete a printer driver with files",  "" },
2700	{ "enumdata",		RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data,		PI_SPOOLSS, NULL, "Enumerate printer data",              "" },
2701	{ "enumdataex",		RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_data_ex,	PI_SPOOLSS, NULL, "Enumerate printer data for a key",    "" },
2702	{ "enumkey",		RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printerkey,	PI_SPOOLSS, NULL, "Enumerate printer keys",              "" },
2703	{ "enumjobs",		RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_jobs,          PI_SPOOLSS, NULL, "Enumerate print jobs",                "" },
2704	{ "enumports", 		RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_ports, 	PI_SPOOLSS, NULL, "Enumerate printer ports",             "" },
2705	{ "enumdrivers", 	RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_drivers, 	PI_SPOOLSS, NULL, "Enumerate installed printer drivers", "" },
2706	{ "enumprinters", 	RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_printers, 	PI_SPOOLSS, NULL, "Enumerate printers",                  "" },
2707	{ "getdata",		RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdata,	PI_SPOOLSS, NULL, "Get print driver data",               "" },
2708	{ "getdataex",		RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinterdataex,	PI_SPOOLSS, NULL, "Get printer driver data with keyname", ""},
2709	{ "getdriver",		RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriver,		PI_SPOOLSS, NULL, "Get print driver information",        "" },
2710	{ "getdriverdir",	RPC_RTYPE_WERROR, NULL, cmd_spoolss_getdriverdir,	PI_SPOOLSS, NULL, "Get print driver upload directory",   "" },
2711	{ "getprinter", 	RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprinter, 	PI_SPOOLSS, NULL, "Get printer info",                    "" },
2712	{ "openprinter",	RPC_RTYPE_WERROR, NULL, cmd_spoolss_open_printer_ex,	PI_SPOOLSS, NULL, "Open printer handle",                 "" },
2713	{ "setdriver", 		RPC_RTYPE_WERROR, NULL, cmd_spoolss_setdriver,		PI_SPOOLSS, NULL, "Set printer driver",                  "" },
2714	{ "getprintprocdir",	RPC_RTYPE_WERROR, NULL, cmd_spoolss_getprintprocdir,    PI_SPOOLSS, NULL, "Get print processor directory",       "" },
2715	{ "addform",		RPC_RTYPE_WERROR, NULL, cmd_spoolss_addform,            PI_SPOOLSS, NULL, "Add form",                            "" },
2716	{ "setform",		RPC_RTYPE_WERROR, NULL, cmd_spoolss_setform,            PI_SPOOLSS, NULL, "Set form",                            "" },
2717	{ "getform",		RPC_RTYPE_WERROR, NULL, cmd_spoolss_getform,            PI_SPOOLSS, NULL, "Get form",                            "" },
2718	{ "deleteform",		RPC_RTYPE_WERROR, NULL, cmd_spoolss_deleteform,         PI_SPOOLSS, NULL, "Delete form",                         "" },
2719	{ "enumforms",		RPC_RTYPE_WERROR, NULL, cmd_spoolss_enum_forms,         PI_SPOOLSS, NULL, "Enumerate forms",                     "" },
2720	{ "setprinter",		RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinter,         PI_SPOOLSS, NULL, "Set printer comment",                 "" },
2721	{ "setprintername",	RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprintername,	PI_SPOOLSS, NULL, "Set printername",                 "" },
2722	{ "setprinterdata",	RPC_RTYPE_WERROR, NULL, cmd_spoolss_setprinterdata,     PI_SPOOLSS, NULL, "Set REG_SZ printer data",             "" },
2723	{ "rffpcnex",		RPC_RTYPE_WERROR, NULL, cmd_spoolss_rffpcnex,           PI_SPOOLSS, NULL, "Rffpcnex test", "" },
2724	{ "printercmp",		RPC_RTYPE_WERROR, NULL, cmd_spoolss_printercmp,         PI_SPOOLSS, NULL, "Printer comparison test", "" },
2725
2726	{ NULL }
2727};
2728