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_find_printer_on_server: 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_ARRAY(ctx, char *, num_vals + 1);
165		memset(str_values, '\0',
166		       (num_vals + 1) * sizeof(char *));
167
168		cur_str = (smb_ucs2_t *) value->data_p;
169		for (i=0; i < num_vals; i++)
170			cur_str += pull_ucs2_talloc(ctx, &str_values[i],
171			                            cur_str);
172
173		status = ads_mod_strlist(ctx, mods, value->valuename,
174					 (const char **) str_values);
175		return ADS_ERR_OK(status);
176	}
177	return True;
178}
179
180struct valmap_to_ads {
181	const char *valname;
182	BOOL (*fn)(TALLOC_CTX *, ADS_MODLIST *, const REGISTRY_VALUE *);
183};
184
185/*
186  map a REG_SZ to an ldap mod
187*/
188static void map_regval_to_ads(TALLOC_CTX *ctx, ADS_MODLIST *mods,
189			      REGISTRY_VALUE *value)
190{
191	const struct valmap_to_ads map[] = {
192		{SPOOL_REG_ASSETNUMBER, map_sz},
193		{SPOOL_REG_BYTESPERMINUTE, map_dword},
194		{SPOOL_REG_DEFAULTPRIORITY, map_dword},
195		{SPOOL_REG_DESCRIPTION, map_sz},
196		{SPOOL_REG_DRIVERNAME, map_sz},
197		{SPOOL_REG_DRIVERVERSION, map_dword},
198		{SPOOL_REG_FLAGS, map_dword},
199		{SPOOL_REG_LOCATION, map_sz},
200		{SPOOL_REG_OPERATINGSYSTEM, map_sz},
201		{SPOOL_REG_OPERATINGSYSTEMHOTFIX, map_sz},
202		{SPOOL_REG_OPERATINGSYSTEMSERVICEPACK, map_sz},
203		{SPOOL_REG_OPERATINGSYSTEMVERSION, map_sz},
204		{SPOOL_REG_PORTNAME, map_multi_sz},
205		{SPOOL_REG_PRINTATTRIBUTES, map_dword},
206		{SPOOL_REG_PRINTBINNAMES, map_multi_sz},
207		{SPOOL_REG_PRINTCOLLATE, map_bool},
208		{SPOOL_REG_PRINTCOLOR, map_bool},
209		{SPOOL_REG_PRINTDUPLEXSUPPORTED, map_bool},
210		{SPOOL_REG_PRINTENDTIME, map_dword},
211		{SPOOL_REG_PRINTFORMNAME, map_sz},
212		{SPOOL_REG_PRINTKEEPPRINTEDJOBS, map_bool},
213		{SPOOL_REG_PRINTLANGUAGE, map_multi_sz},
214		{SPOOL_REG_PRINTMACADDRESS, map_sz},
215		{SPOOL_REG_PRINTMAXCOPIES, map_sz},
216		{SPOOL_REG_PRINTMAXRESOLUTIONSUPPORTED, map_dword},
217		{SPOOL_REG_PRINTMAXXEXTENT, map_dword},
218		{SPOOL_REG_PRINTMAXYEXTENT, map_dword},
219		{SPOOL_REG_PRINTMEDIAREADY, map_multi_sz},
220		{SPOOL_REG_PRINTMEDIASUPPORTED, map_multi_sz},
221		{SPOOL_REG_PRINTMEMORY, map_dword},
222		{SPOOL_REG_PRINTMINXEXTENT, map_dword},
223		{SPOOL_REG_PRINTMINYEXTENT, map_dword},
224		{SPOOL_REG_PRINTNETWORKADDRESS, map_sz},
225		{SPOOL_REG_PRINTNOTIFY, map_sz},
226		{SPOOL_REG_PRINTNUMBERUP, map_dword},
227		{SPOOL_REG_PRINTORIENTATIONSSUPPORTED, map_multi_sz},
228		{SPOOL_REG_PRINTOWNER, map_sz},
229		{SPOOL_REG_PRINTPAGESPERMINUTE, map_dword},
230		{SPOOL_REG_PRINTRATE, map_dword},
231		{SPOOL_REG_PRINTRATEUNIT, map_sz},
232		{SPOOL_REG_PRINTSEPARATORFILE, map_sz},
233		{SPOOL_REG_PRINTSHARENAME, map_sz},
234		{SPOOL_REG_PRINTSPOOLING, map_sz},
235		{SPOOL_REG_PRINTSTAPLINGSUPPORTED, map_bool},
236		{SPOOL_REG_PRINTSTARTTIME, map_dword},
237		{SPOOL_REG_PRINTSTATUS, map_sz},
238		{SPOOL_REG_PRIORITY, map_dword},
239		{SPOOL_REG_SERVERNAME, map_sz},
240		{SPOOL_REG_SHORTSERVERNAME, map_sz},
241		{SPOOL_REG_UNCNAME, map_sz},
242		{SPOOL_REG_URL, map_sz},
243		{SPOOL_REG_VERSIONNUMBER, map_dword},
244		{NULL, NULL}
245	};
246	int i;
247
248	for (i=0; map[i].valname; i++) {
249		if (StrCaseCmp(map[i].valname, value->valuename) == 0) {
250			if (!map[i].fn(ctx, mods, value)) {
251				DEBUG(5, ("Add of value %s to modlist failed\n", value->valuename));
252			} else {
253				DEBUG(7, ("Mapped value %s\n", value->valuename));
254			}
255
256		}
257	}
258}
259
260
261WERROR get_remote_printer_publishing_data(struct cli_state *cli,
262					  TALLOC_CTX *mem_ctx,
263					  ADS_MODLIST *mods,
264					  const char *printer)
265{
266	WERROR result;
267	char *printername, *servername;
268	REGVAL_CTR dsdriver_ctr, dsspooler_ctr;
269	BOOL got_dsdriver = False, got_dsspooler = False;
270	uint32 needed, i;
271	POLICY_HND pol;
272
273	asprintf(&servername, "\\\\%s", cli->desthost);
274	asprintf(&printername, "%s\\%s", servername, printer);
275	if (!servername || !printername) {
276		DEBUG(3, ("Insufficient memory\n"));
277		return WERR_NOMEM;
278	}
279
280	result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername,
281					     "", MAXIMUM_ALLOWED_ACCESS,
282					     servername, cli->user_name, &pol);
283	if (!W_ERROR_IS_OK(result)) {
284		DEBUG(3, ("Unable to open printer %s, error is %s.\n",
285			  printername, dos_errstr(result)));
286		return result;
287	}
288
289	result = cli_spoolss_enumprinterdataex(cli, mem_ctx, 0, &needed,
290					       &pol, SPOOL_DSDRIVER_KEY, NULL);
291
292	if (W_ERROR_V(result) == ERRmoredata)
293		result = cli_spoolss_enumprinterdataex(cli, mem_ctx, needed,
294						       NULL, &pol,
295						       SPOOL_DSDRIVER_KEY,
296						       &dsdriver_ctr);
297
298	if (!W_ERROR_IS_OK(result)) {
299		DEBUG(3, ("Unable to do enumdataex on %s, error is %s.\n",
300			  printername, dos_errstr(result)));
301	} else {
302
303		/* Have the data we need now, so start building */
304		got_dsdriver = True;
305		for (i=0; i < dsdriver_ctr.num_values; i++)
306			map_regval_to_ads(mem_ctx, mods,
307					  dsdriver_ctr.values[i]);
308	}
309
310	result = cli_spoolss_enumprinterdataex(cli, mem_ctx, 0, &needed,
311					       &pol, SPOOL_DSSPOOLER_KEY,
312					       NULL);
313
314	if (W_ERROR_V(result) == ERRmoredata)
315		result = cli_spoolss_enumprinterdataex(cli, mem_ctx, needed,
316						       NULL, &pol,
317						       SPOOL_DSSPOOLER_KEY,
318						       &dsspooler_ctr);
319
320	if (!W_ERROR_IS_OK(result)) {
321		DEBUG(3, ("Unable to do enumdataex on %s, error is %s.\n",
322			  printername, dos_errstr(result)));
323	} else {
324		got_dsspooler = True;
325		for (i=0; i < dsspooler_ctr.num_values; i++)
326			map_regval_to_ads(mem_ctx, mods,
327					  dsspooler_ctr.values[i]);
328	}
329
330	ads_mod_str(mem_ctx, mods, SPOOL_REG_PRINTERNAME, printer);
331
332	if (got_dsdriver) regval_ctr_destroy(&dsdriver_ctr);
333	if (got_dsspooler) regval_ctr_destroy(&dsspooler_ctr);
334	cli_spoolss_close_printer(cli, mem_ctx, &pol);
335
336	return result;
337}
338
339BOOL get_local_printer_publishing_data(TALLOC_CTX *mem_ctx,
340				       ADS_MODLIST *mods,
341				       NT_PRINTER_DATA *data)
342{
343	uint32 key,val;
344
345	for (key=0; key < data->num_keys; key++) {
346		REGVAL_CTR ctr = data->keys[key].values;
347		for (val=0; val < ctr.num_values; val++)
348			map_regval_to_ads(mem_ctx, mods, ctr.values[val]);
349	}
350	return True;
351}
352
353#endif
354