1/*
2   Unix SMB/CIFS implementation.
3   ads (active directory) printer utility library
4   Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21#include "includes.h"
22
23#ifdef HAVE_ADS
24
25/*
26  find a printer given the name and the hostname
27    Note that results "res" may be allocated on return so that the
28    results can be used.  It should be freed using ads_msgfree.
29*/
30ADS_STATUS ads_find_printer_on_server(ADS_STRUCT *ads, void **res,
31				      const char *printer, const char *servername)
32{
33	ADS_STATUS status;
34	char *srv_dn, **srv_cn, *s;
35	const char *attrs[] = {"*", "nTSecurityDescriptor", NULL};
36
37	status = ads_find_machine_acct(ads, res, servername);
38	if (!ADS_ERR_OK(status)) {
39		DEBUG(1, ("ads_add_printer: cannot find host %s in ads\n",
40			  servername));
41		return status;
42	}
43	srv_dn = ldap_get_dn(ads->ld, *res);
44	srv_cn = ldap_explode_dn(srv_dn, 1);
45	ads_msgfree(ads, *res);
46
47	asprintf(&s, "(cn=%s-%s)", srv_cn[0], printer);
48	status = ads_search(ads, res, s, attrs);
49
50	ldap_memfree(srv_dn);
51	ldap_value_free(srv_cn);
52	free(s);
53	return status;
54}
55
56ADS_STATUS ads_find_printers(ADS_STRUCT *ads, void **res)
57{
58	char *ldap_expr;
59	const char *attrs[] = { "objectClass", "printerName", "location", "driverName",
60				"serverName", "description", NULL };
61
62	/* For the moment only display all printers */
63
64	ldap_expr = "(&(!(showInAdvancedViewOnly=TRUE))(uncName=*)"
65		"(objectCategory=printQueue))";
66
67	return ads_search(ads, res, ldap_expr, attrs);
68}
69
70/*
71  modify a printer entry in the directory
72*/
73ADS_STATUS ads_mod_printer_entry(ADS_STRUCT *ads, char *prt_dn,
74				 TALLOC_CTX *ctx, const ADS_MODLIST *mods)
75{
76	return ads_gen_mod(ads, prt_dn, *mods);
77}
78
79/*
80  add a printer to the directory
81*/
82ADS_STATUS ads_add_printer_entry(ADS_STRUCT *ads, char *prt_dn,
83					TALLOC_CTX *ctx, ADS_MODLIST *mods)
84{
85	ads_mod_str(ctx, mods, "objectClass", "printQueue");
86	return ads_gen_add(ads, prt_dn, *mods);
87}
88
89/*
90  map a REG_SZ to an ldap mod
91*/
92static BOOL map_sz(TALLOC_CTX *ctx, ADS_MODLIST *mods,
93			    const REGISTRY_VALUE *value)
94{
95	char *str_value = NULL;
96	ADS_STATUS status;
97
98	if (value->type != REG_SZ)
99		return False;
100
101	if (value->size && *((smb_ucs2_t *) value->data_p)) {
102		pull_ucs2_talloc(ctx, &str_value, (const smb_ucs2_t *) value->data_p);
103		status = ads_mod_str(ctx, mods, value->valuename, str_value);
104		return ADS_ERR_OK(status);
105	}
106	return True;
107
108}
109
110/*
111  map a REG_DWORD to an ldap mod
112*/
113static BOOL map_dword(TALLOC_CTX *ctx, ADS_MODLIST *mods,
114		      const REGISTRY_VALUE *value)
115{
116	char *str_value = NULL;
117	ADS_STATUS status;
118
119	if (value->type != REG_DWORD)
120		return False;
121	str_value = talloc_asprintf(ctx, "%d", *((uint32 *) value->data_p));
122	status = ads_mod_str(ctx, mods, value->valuename, str_value);
123	return ADS_ERR_OK(status);
124}
125
126/*
127  map a boolean REG_BINARY to an ldap mod
128*/
129static BOOL map_bool(TALLOC_CTX *ctx, ADS_MODLIST *mods,
130		     const REGISTRY_VALUE *value)
131{
132	char *str_value;
133	ADS_STATUS status;
134
135	if ((value->type != REG_BINARY) || (value->size != 1))
136		return False;
137	str_value =  talloc_asprintf(ctx, "%s",
138				     *(value->data_p) ? "TRUE" : "FALSE");
139	status = ads_mod_str(ctx, mods, value->valuename, str_value);
140	return ADS_ERR_OK(status);
141}
142
143/*
144  map a REG_MULTI_SZ to an ldap mod
145*/
146static BOOL map_multi_sz(TALLOC_CTX *ctx, ADS_MODLIST *mods,
147			 const REGISTRY_VALUE *value)
148{
149	char **str_values = NULL;
150	smb_ucs2_t *cur_str = (smb_ucs2_t *) value->data_p;
151        uint32 size = 0, num_vals = 0, i=0;
152	ADS_STATUS status;
153
154	if (value->type != REG_MULTI_SZ)
155		return False;
156
157	while(cur_str && *cur_str && (size < value->size)) {
158		size += 2 * (strlen_w(cur_str) + 1);
159		cur_str += strlen_w(cur_str) + 1;
160		num_vals++;
161	};
162
163	if (num_vals) {
164		str_values = talloc(ctx,
165				    (num_vals + 1) * sizeof(smb_ucs2_t *));
166		memset(str_values, '\0',
167		       (num_vals + 1) * sizeof(smb_ucs2_t *));
168
169		cur_str = (smb_ucs2_t *) value->data_p;
170		for (i=0; i < num_vals; i++)
171			cur_str += pull_ucs2_talloc(ctx, &str_values[i],
172			                            cur_str);
173
174		status = ads_mod_strlist(ctx, mods, value->valuename,
175					 (const char **) str_values);
176		return ADS_ERR_OK(status);
177	}
178	return True;
179}
180
181struct valmap_to_ads {
182	const char *valname;
183	BOOL (*fn)(TALLOC_CTX *, ADS_MODLIST *, const REGISTRY_VALUE *);
184};
185
186/*
187  map a REG_SZ to an ldap mod
188*/
189static void map_regval_to_ads(TALLOC_CTX *ctx, ADS_MODLIST *mods,
190			      REGISTRY_VALUE *value)
191{
192	const struct valmap_to_ads map[] = {
193		{SPOOL_REG_ASSETNUMBER, map_sz},
194		{SPOOL_REG_BYTESPERMINUTE, map_dword},
195		{SPOOL_REG_DEFAULTPRIORITY, map_dword},
196		{SPOOL_REG_DESCRIPTION, map_sz},
197		{SPOOL_REG_DRIVERNAME, map_sz},
198		{SPOOL_REG_DRIVERVERSION, map_dword},
199		{SPOOL_REG_FLAGS, map_dword},
200		{SPOOL_REG_LOCATION, map_sz},
201		{SPOOL_REG_OPERATINGSYSTEM, map_sz},
202		{SPOOL_REG_OPERATINGSYSTEMHOTFIX, map_sz},
203		{SPOOL_REG_OPERATINGSYSTEMSERVICEPACK, map_sz},
204		{SPOOL_REG_OPERATINGSYSTEMVERSION, map_sz},
205		{SPOOL_REG_PORTNAME, map_multi_sz},
206		{SPOOL_REG_PRINTATTRIBUTES, map_dword},
207		{SPOOL_REG_PRINTBINNAMES, map_multi_sz},
208		{SPOOL_REG_PRINTCOLLATE, map_bool},
209		{SPOOL_REG_PRINTCOLOR, map_bool},
210		{SPOOL_REG_PRINTDUPLEXSUPPORTED, map_bool},
211		{SPOOL_REG_PRINTENDTIME, map_dword},
212		{SPOOL_REG_PRINTFORMNAME, map_sz},
213		{SPOOL_REG_PRINTKEEPPRINTEDJOBS, map_bool},
214		{SPOOL_REG_PRINTLANGUAGE, map_multi_sz},
215		{SPOOL_REG_PRINTMACADDRESS, map_sz},
216		{SPOOL_REG_PRINTMAXCOPIES, map_sz},
217		{SPOOL_REG_PRINTMAXRESOLUTIONSUPPORTED, map_dword},
218		{SPOOL_REG_PRINTMAXXEXTENT, map_dword},
219		{SPOOL_REG_PRINTMAXYEXTENT, map_dword},
220		{SPOOL_REG_PRINTMEDIAREADY, map_multi_sz},
221		{SPOOL_REG_PRINTMEDIASUPPORTED, map_multi_sz},
222		{SPOOL_REG_PRINTMEMORY, map_dword},
223		{SPOOL_REG_PRINTMINXEXTENT, map_dword},
224		{SPOOL_REG_PRINTMINYEXTENT, map_dword},
225		{SPOOL_REG_PRINTNETWORKADDRESS, map_sz},
226		{SPOOL_REG_PRINTNOTIFY, map_sz},
227		{SPOOL_REG_PRINTNUMBERUP, map_dword},
228		{SPOOL_REG_PRINTORIENTATIONSSUPPORTED, map_multi_sz},
229		{SPOOL_REG_PRINTOWNER, map_sz},
230		{SPOOL_REG_PRINTPAGESPERMINUTE, map_dword},
231		{SPOOL_REG_PRINTRATE, map_dword},
232		{SPOOL_REG_PRINTRATEUNIT, map_sz},
233		{SPOOL_REG_PRINTSEPARATORFILE, map_sz},
234		{SPOOL_REG_PRINTSHARENAME, map_sz},
235		{SPOOL_REG_PRINTSPOOLING, map_sz},
236		{SPOOL_REG_PRINTSTAPLINGSUPPORTED, map_bool},
237		{SPOOL_REG_PRINTSTARTTIME, map_dword},
238		{SPOOL_REG_PRINTSTATUS, map_sz},
239		{SPOOL_REG_PRIORITY, map_dword},
240		{SPOOL_REG_SERVERNAME, map_sz},
241		{SPOOL_REG_SHORTSERVERNAME, map_sz},
242		{SPOOL_REG_UNCNAME, map_sz},
243		{SPOOL_REG_URL, map_sz},
244		{SPOOL_REG_VERSIONNUMBER, map_dword},
245		{NULL, NULL}
246	};
247	int i;
248
249	for (i=0; map[i].valname; i++) {
250		if (StrCaseCmp(map[i].valname, value->valuename) == 0) {
251			if (!map[i].fn(ctx, mods, value)) {
252				DEBUG(5, ("Add of value %s to modlist failed\n", value->valuename));
253			} else {
254				DEBUG(7, ("Mapped value %s\n", value->valuename));
255			}
256
257		}
258	}
259}
260
261
262WERROR get_remote_printer_publishing_data(struct cli_state *cli,
263					  TALLOC_CTX *mem_ctx,
264					  ADS_MODLIST *mods,
265					  const char *printer)
266{
267	WERROR result;
268	char *printername, *servername;
269	REGVAL_CTR dsdriver_ctr, dsspooler_ctr;
270	BOOL got_dsdriver = False, got_dsspooler = False;
271	uint32 needed, i;
272	POLICY_HND pol;
273
274	asprintf(&servername, "\\\\%s", cli->desthost);
275	asprintf(&printername, "%s\\%s", servername, printer);
276	if (!servername || !printername) {
277		DEBUG(3, ("Insufficient memory\n"));
278		return WERR_NOMEM;
279	}
280
281	result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername,
282					     "", MAXIMUM_ALLOWED_ACCESS,
283					     servername, cli->user_name, &pol);
284	if (!W_ERROR_IS_OK(result)) {
285		DEBUG(3, ("Unable to open printer %s, error is %s.\n",
286			  printername, dos_errstr(result)));
287		return result;
288	}
289
290	result = cli_spoolss_enumprinterdataex(cli, mem_ctx, 0, &needed,
291					       &pol, SPOOL_DSDRIVER_KEY, NULL);
292
293	if (W_ERROR_V(result) == ERRmoredata)
294		result = cli_spoolss_enumprinterdataex(cli, mem_ctx, needed,
295						       NULL, &pol,
296						       SPOOL_DSDRIVER_KEY,
297						       &dsdriver_ctr);
298
299	if (!W_ERROR_IS_OK(result)) {
300		DEBUG(3, ("Unable to do enumdataex on %s, error is %s.\n",
301			  printername, dos_errstr(result)));
302	} else {
303
304		/* Have the data we need now, so start building */
305		got_dsdriver = True;
306		for (i=0; i < dsdriver_ctr.num_values; i++)
307			map_regval_to_ads(mem_ctx, mods,
308					  dsdriver_ctr.values[i]);
309	}
310
311	result = cli_spoolss_enumprinterdataex(cli, mem_ctx, 0, &needed,
312					       &pol, SPOOL_DSSPOOLER_KEY,
313					       NULL);
314
315	if (W_ERROR_V(result) == ERRmoredata)
316		result = cli_spoolss_enumprinterdataex(cli, mem_ctx, needed,
317						       NULL, &pol,
318						       SPOOL_DSSPOOLER_KEY,
319						       &dsspooler_ctr);
320
321	if (!W_ERROR_IS_OK(result)) {
322		DEBUG(3, ("Unable to do enumdataex on %s, error is %s.\n",
323			  printername, dos_errstr(result)));
324	} else {
325		got_dsspooler = True;
326		for (i=0; i < dsspooler_ctr.num_values; i++)
327			map_regval_to_ads(mem_ctx, mods,
328					  dsspooler_ctr.values[i]);
329	}
330
331	ads_mod_str(mem_ctx, mods, SPOOL_REG_PRINTERNAME, printer);
332
333	if (got_dsdriver) regval_ctr_destroy(&dsdriver_ctr);
334	if (got_dsspooler) regval_ctr_destroy(&dsspooler_ctr);
335	cli_spoolss_close_printer(cli, mem_ctx, &pol);
336
337	return result;
338}
339
340BOOL get_local_printer_publishing_data(TALLOC_CTX *mem_ctx,
341				       ADS_MODLIST *mods,
342				       NT_PRINTER_DATA *data)
343{
344	uint32 key,val;
345
346	for (key=0; key < data->num_keys; key++) {
347		REGVAL_CTR ctr = data->keys[key].values;
348		for (val=0; val < ctr.num_values; val++)
349			map_regval_to_ads(mem_ctx, mods, ctr.values[val]);
350	}
351	return True;
352}
353
354#endif
355