Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * RPC Pipe client / server routines
4 : * Copyright (C) Andrew Tridgell 1992-2000,
5 : * Copyright (C) Jean François Micouleau 1998-2000.
6 : * Copyright (C) Gerald Carter 2002-2005.
7 : *
8 : * This program is free software; you can redistribute it and/or modify
9 : * it under the terms of the GNU General Public License as published by
10 : * the Free Software Foundation; either version 3 of the License, or
11 : * (at your option) any later version.
12 : *
13 : * This program is distributed in the hope that it will be useful,
14 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : * GNU General Public License for more details.
17 : *
18 : * You should have received a copy of the GNU General Public License
19 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include "../librpc/gen_ndr/spoolss.h"
24 : #include "rpc_server/spoolss/srv_spoolss_util.h"
25 : #include "nt_printing.h"
26 : #include "ads.h"
27 : #include "secrets.h"
28 : #include "krb5_env.h"
29 : #include "../libcli/registry/util_reg.h"
30 : #include "auth.h"
31 : #include "../librpc/ndr/libndr.h"
32 : #include "rpc_client/cli_winreg_spoolss.h"
33 :
34 : #ifdef HAVE_ADS
35 : /*****************************************************************
36 : ****************************************************************/
37 :
38 0 : WERROR nt_printer_guid_store(struct messaging_context *msg_ctx,
39 : const char *printer, struct GUID guid)
40 : {
41 0 : TALLOC_CTX *tmp_ctx;
42 0 : const struct auth_session_info *session_info;
43 0 : const char *guid_str;
44 0 : DATA_BLOB blob;
45 0 : WERROR result;
46 :
47 0 : tmp_ctx = talloc_new(NULL);
48 0 : if (!tmp_ctx) {
49 0 : DEBUG(0, ("Out of memory?!\n"));
50 0 : return WERR_NOT_ENOUGH_MEMORY;
51 : }
52 :
53 0 : session_info = get_session_info_system();
54 0 : if (session_info == NULL) {
55 0 : DEBUG(0, ("Could not get system session_info\n"));
56 0 : result = WERR_NOT_ENOUGH_MEMORY;
57 0 : goto done;
58 : }
59 :
60 0 : guid_str = GUID_string(tmp_ctx, &guid);
61 0 : if (!guid_str) {
62 0 : DEBUG(0, ("Out of memory?!\n"));
63 0 : result = WERR_NOT_ENOUGH_MEMORY;
64 0 : goto done;
65 : }
66 :
67 : /* We used to store this as a REG_BINARY but that causes
68 : Vista to whine */
69 :
70 0 : if (!push_reg_sz(tmp_ctx, &blob, guid_str)) {
71 0 : DEBUG(0, ("Could not marshall string %s for objectGUID\n",
72 : guid_str));
73 0 : result = WERR_NOT_ENOUGH_MEMORY;
74 0 : goto done;
75 : }
76 :
77 0 : result = winreg_set_printer_dataex_internal(tmp_ctx, session_info, msg_ctx,
78 : printer,
79 : SPOOL_DSSPOOLER_KEY, "objectGUID",
80 0 : REG_SZ, blob.data, blob.length);
81 0 : if (!W_ERROR_IS_OK(result)) {
82 0 : DEBUG(0, ("Failed to store GUID for printer %s\n", printer));
83 0 : goto done;
84 : }
85 :
86 0 : result = WERR_OK;
87 0 : done:
88 0 : talloc_free(tmp_ctx);
89 :
90 0 : return result;
91 : }
92 :
93 0 : static WERROR nt_printer_dn_lookup(TALLOC_CTX *mem_ctx,
94 : ADS_STRUCT *ads,
95 : const char *printer,
96 : char **pprinter_dn)
97 : {
98 0 : char *printer_dn = NULL;
99 0 : char *srv_dn = NULL;
100 0 : char *srv_cn_0 = NULL;
101 0 : char *srv_cn_escaped = NULL;
102 0 : char *sharename_escaped = NULL;
103 0 : char *srv_dn_utf8 = NULL;
104 0 : char **srv_cn_utf8 = NULL;
105 0 : size_t converted_size;
106 0 : ADS_STATUS ads_status;
107 0 : LDAPMessage *res;
108 0 : WERROR result;
109 0 : bool ok;
110 :
111 0 : ads_status = ads_find_machine_acct(ads, &res, lp_netbios_name());
112 0 : if (!ADS_ERR_OK(ads_status)) {
113 0 : DEBUG(2, ("Failed to find machine account for %s\n",
114 : lp_netbios_name()));
115 0 : result = WERR_NOT_FOUND;
116 0 : goto err_out;
117 : }
118 :
119 : /*
120 : * We use ldap_get_dn here as we need the answer in utf8 to call
121 : * ldap_explode_dn(). JRA.
122 : */
123 0 : srv_dn_utf8 = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
124 0 : ads_msgfree(ads, res);
125 0 : if (srv_dn_utf8 == NULL) {
126 0 : result = WERR_RPC_S_SERVER_UNAVAILABLE;
127 0 : goto err_out;
128 : }
129 :
130 0 : srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
131 0 : if (srv_cn_utf8 == NULL) {
132 0 : ldap_memfree(srv_dn_utf8);
133 0 : result = WERR_RPC_S_SERVER_UNAVAILABLE;
134 0 : goto err_out;
135 : }
136 :
137 : /* Now convert to CH_UNIX. */
138 0 : ok = pull_utf8_talloc(mem_ctx, &srv_dn, srv_dn_utf8, &converted_size);
139 0 : ldap_memfree(srv_dn_utf8);
140 0 : if (!ok) {
141 0 : ldap_memfree(srv_cn_utf8);
142 0 : result = WERR_RPC_S_SERVER_UNAVAILABLE;
143 0 : goto err_out;
144 : }
145 :
146 0 : ok = pull_utf8_talloc(mem_ctx, &srv_cn_0, srv_cn_utf8[0], &converted_size);
147 0 : ldap_memfree(srv_cn_utf8);
148 0 : if (!ok) {
149 0 : result = WERR_RPC_S_SERVER_UNAVAILABLE;
150 0 : goto err_out;
151 : }
152 :
153 0 : srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0);
154 0 : if (srv_cn_escaped == NULL) {
155 0 : result = WERR_RPC_S_SERVER_UNAVAILABLE;
156 0 : goto err_out;
157 : }
158 :
159 0 : sharename_escaped = escape_rdn_val_string_alloc(printer);
160 0 : if (sharename_escaped == NULL) {
161 0 : result = WERR_RPC_S_SERVER_UNAVAILABLE;
162 0 : goto err_out;
163 : }
164 :
165 0 : printer_dn = talloc_asprintf(mem_ctx,
166 : "cn=%s-%s,%s",
167 : srv_cn_escaped,
168 : sharename_escaped,
169 : srv_dn);
170 0 : if (printer_dn == NULL) {
171 0 : result = WERR_NOT_ENOUGH_MEMORY;
172 0 : goto err_out;
173 : }
174 :
175 0 : *pprinter_dn = printer_dn;
176 :
177 0 : result = WERR_OK;
178 0 : err_out:
179 0 : SAFE_FREE(sharename_escaped);
180 0 : SAFE_FREE(srv_cn_escaped);
181 0 : TALLOC_FREE(srv_cn_0);
182 0 : TALLOC_FREE(srv_dn);
183 0 : return result;
184 : }
185 :
186 0 : static WERROR nt_printer_guid_retrieve_internal(ADS_STRUCT *ads,
187 : const char *printer_dn,
188 : struct GUID *pguid)
189 : {
190 0 : ADS_STATUS ads_status;
191 0 : LDAPMessage *res;
192 0 : const char *attrs[] = {"objectGUID", NULL};
193 0 : struct GUID guid;
194 0 : bool ok;
195 :
196 0 : ads_status = ads_search_dn(ads, &res, printer_dn, attrs);
197 0 : if (!ADS_ERR_OK(ads_status)) {
198 0 : DEBUG(2, ("Failed to retrieve GUID from DC - %s\n",
199 : ads_errstr(ads_status)));
200 0 : return WERR_FILE_NOT_FOUND;
201 : }
202 :
203 0 : ZERO_STRUCT(guid);
204 0 : ok = ads_pull_guid(ads, res, &guid);
205 0 : ads_msgfree(ads, res);
206 0 : if (!ok) {
207 0 : return WERR_NOT_ENOUGH_MEMORY;
208 : }
209 :
210 0 : *pguid = guid;
211 :
212 0 : return WERR_OK;
213 : }
214 :
215 0 : WERROR nt_printer_guid_retrieve(TALLOC_CTX *mem_ctx, const char *printer,
216 : struct GUID *pguid)
217 : {
218 0 : ADS_STRUCT *ads = NULL;
219 0 : char *old_krb5ccname = NULL;
220 0 : char *printer_dn;
221 0 : WERROR result;
222 0 : ADS_STATUS ads_status;
223 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
224 0 : char *machine_password = NULL;
225 :
226 0 : ads = ads_init(tmp_ctx,
227 : lp_realm(),
228 : lp_workgroup(),
229 : NULL,
230 : ADS_SASL_PLAIN);
231 0 : if (ads == NULL) {
232 0 : result = WERR_RPC_S_SERVER_UNAVAILABLE;
233 0 : goto out;
234 : }
235 :
236 0 : old_krb5ccname = getenv(KRB5_ENV_CCNAME);
237 0 : setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
238 0 : ADS_TALLOC_CONST_FREE(ads->auth.password);
239 0 : machine_password = secrets_fetch_machine_password(lp_workgroup(),
240 : NULL, NULL);
241 0 : if (machine_password != NULL) {
242 0 : ads->auth.password = talloc_strdup(ads, machine_password);
243 0 : SAFE_FREE(machine_password);
244 0 : if (ads->auth.password == NULL) {
245 0 : result = WERR_NOT_ENOUGH_MEMORY;
246 0 : goto out;
247 : }
248 : }
249 :
250 0 : ads_status = ads_connect(ads);
251 0 : if (!ADS_ERR_OK(ads_status)) {
252 0 : DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_status)));
253 0 : result = WERR_ACCESS_DENIED;
254 0 : goto out;
255 : }
256 :
257 0 : result = nt_printer_dn_lookup(tmp_ctx, ads, printer, &printer_dn);
258 0 : if (!W_ERROR_IS_OK(result)) {
259 0 : goto out;
260 : }
261 :
262 0 : result = nt_printer_guid_retrieve_internal(ads, printer_dn, pguid);
263 0 : out:
264 0 : TALLOC_FREE(tmp_ctx);
265 0 : ads_kdestroy("MEMORY:prtpub_cache");
266 0 : unsetenv(KRB5_ENV_CCNAME);
267 0 : if (old_krb5ccname != NULL) {
268 0 : setenv(KRB5_ENV_CCNAME, old_krb5ccname, 0);
269 : }
270 :
271 0 : return result;
272 : }
273 :
274 0 : WERROR nt_printer_guid_get(TALLOC_CTX *mem_ctx,
275 : const struct auth_session_info *session_info,
276 : struct messaging_context *msg_ctx,
277 : const char *printer, struct GUID *guid)
278 : {
279 0 : TALLOC_CTX *tmp_ctx;
280 0 : enum winreg_Type type;
281 0 : DATA_BLOB blob;
282 0 : uint32_t len;
283 0 : NTSTATUS status;
284 0 : WERROR result;
285 :
286 0 : tmp_ctx = talloc_new(mem_ctx);
287 0 : if (tmp_ctx == NULL) {
288 0 : DEBUG(0, ("out of memory?!\n"));
289 0 : return WERR_NOT_ENOUGH_MEMORY;
290 : }
291 :
292 0 : result = winreg_get_printer_dataex_internal(tmp_ctx, session_info,
293 : msg_ctx, printer,
294 : SPOOL_DSSPOOLER_KEY,
295 : "objectGUID",
296 : &type,
297 : &blob.data,
298 : &len);
299 0 : if (!W_ERROR_IS_OK(result)) {
300 0 : DEBUG(0, ("Failed to get GUID for printer %s\n", printer));
301 0 : goto out_ctx_free;
302 : }
303 0 : blob.length = (size_t)len;
304 :
305 : /* We used to store the guid as REG_BINARY, then swapped
306 : to REG_SZ for Vista compatibility so check for both */
307 :
308 0 : switch (type) {
309 0 : case REG_SZ: {
310 0 : bool ok;
311 0 : const char *guid_str;
312 0 : ok = pull_reg_sz(tmp_ctx, &blob, &guid_str);
313 0 : if (!ok) {
314 0 : DEBUG(0, ("Failed to unmarshall GUID for printer %s\n",
315 : printer));
316 0 : result = WERR_REGISTRY_CORRUPT;
317 0 : goto out_ctx_free;
318 : }
319 0 : status = GUID_from_string(guid_str, guid);
320 0 : if (!NT_STATUS_IS_OK(status)) {
321 0 : DEBUG(0, ("bad GUID for printer %s\n", printer));
322 0 : result = ntstatus_to_werror(status);
323 0 : goto out_ctx_free;
324 : }
325 0 : break;
326 : }
327 0 : case REG_BINARY:
328 0 : if (blob.length != sizeof(struct GUID)) {
329 0 : DEBUG(0, ("bad GUID for printer %s\n", printer));
330 0 : result = WERR_REGISTRY_CORRUPT;
331 0 : goto out_ctx_free;
332 : }
333 0 : memcpy(guid, blob.data, sizeof(struct GUID));
334 0 : break;
335 0 : default:
336 0 : DEBUG(0,("GUID value stored as invalid type (%d)\n", type));
337 0 : result = WERR_REGISTRY_CORRUPT;
338 0 : goto out_ctx_free;
339 : break;
340 : }
341 0 : result = WERR_OK;
342 :
343 0 : out_ctx_free:
344 0 : talloc_free(tmp_ctx);
345 0 : return result;
346 : }
347 :
348 0 : static WERROR nt_printer_devmode_to_mods(TALLOC_CTX *ctx,
349 : struct spoolss_DeviceMode *devmode,
350 : ADS_MODLIST *mods)
351 : {
352 0 : char *str = NULL;
353 0 : ADS_STATUS status;
354 :
355 : /*
356 : the device mode fields bits allow us to make an educated guess if a
357 : printer feature is supported. For sure a feature must be unsupported if
358 : the fields bit is not set. Device Mode Extra Data and FeatureOptionPairs
359 : might help to figure out more information here. Common attributes, that
360 : we can't handle yet:
361 : SPOOL_REG_PRINTBINNAMES - printBinNames
362 : SPOOL_REG_PRINTMAXXEXTENT - printMaxXExtent
363 : SPOOL_REG_PRINTMAXYEXTENT - printMaxYExtent
364 : SPOOL_REG_PRINTMINXEXTENT - printMinXExtent
365 : SPOOL_REG_PRINTMINYEXTENT - printMinYExtent
366 : SPOOL_REG_PRINTSTAPLINGSUPPORTED - printStaplingSupported
367 : SPOOL_REG_PRINTPAGESPERMINUTE - printPagesPerMinute
368 : SPOOL_REG_PRINTRATE - printRate
369 : SPOOL_REG_PRINTRATEUNIT - printRateUnit
370 : SPOOL_REG_PRINTMEDIAREADY - printMediaReady
371 : SPOOL_REG_PRINTMEDIASUPPORTED - printMediaSupported
372 : SPOOL_REG_PRINTNUMBERUP - printNumberUp
373 : SPOOL_REG_PRINTMAXCOPIES - printMaxCopies
374 : */
375 0 : if (devmode->fields & DEVMODE_COLOR) {
376 0 : status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTCOLOR, "TRUE");
377 : } else {
378 0 : status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTCOLOR, "FALSE");
379 : }
380 0 : if (!ADS_ERR_OK(status)) {
381 0 : return WERR_NOT_ENOUGH_MEMORY;
382 : }
383 :
384 0 : if (devmode->fields & DEVMODE_DUPLEX) {
385 0 : status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTDUPLEXSUPPORTED, "TRUE");
386 : } else {
387 0 : status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTDUPLEXSUPPORTED, "FALSE");
388 : }
389 0 : if (!ADS_ERR_OK(status)) {
390 0 : return WERR_NOT_ENOUGH_MEMORY;
391 : }
392 :
393 0 : if (devmode->fields & DEVMODE_COLLATE) {
394 0 : status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTCOLLATE, "TRUE");
395 : } else {
396 0 : status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTCOLLATE, "FALSE");
397 : }
398 0 : if (!ADS_ERR_OK(status)) {
399 0 : return WERR_NOT_ENOUGH_MEMORY;
400 : }
401 :
402 : /* portrait mode is always supported, LANDSCAPE is optional */
403 0 : status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTORIENTATIONSSUPPORTED, "PORTRAIT");
404 0 : if (!ADS_ERR_OK(status)) {
405 0 : return WERR_NOT_ENOUGH_MEMORY;
406 : }
407 0 : if (devmode->fields & DEVMODE_ORIENTATION) {
408 0 : status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTORIENTATIONSSUPPORTED, "LANDSCAPE");
409 0 : if (!ADS_ERR_OK(status)) {
410 0 : return WERR_NOT_ENOUGH_MEMORY;
411 : }
412 : }
413 :
414 : /* the driverVersion attribute in AD contains actually specversion */
415 0 : str = talloc_asprintf(ctx, "%u", devmode->specversion);
416 0 : if (str == NULL) {
417 0 : return WERR_NOT_ENOUGH_MEMORY;
418 : }
419 0 : if (strlen(str) != 0) {
420 0 : status = ads_mod_str(ctx, mods, SPOOL_REG_DRIVERVERSION, str);
421 0 : if (!ADS_ERR_OK(status)) {
422 0 : return WERR_NOT_ENOUGH_MEMORY;
423 : }
424 : }
425 :
426 : /* devmode->yresolution is a good candidate for printMaxResolutionSupported */
427 0 : str = talloc_asprintf(ctx, "%u", devmode->yresolution);
428 0 : if (str == NULL) {
429 0 : return WERR_NOT_ENOUGH_MEMORY;
430 : }
431 0 : if (strlen(str) != 0) {
432 0 : status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTMAXRESOLUTIONSUPPORTED, str);
433 0 : if (!ADS_ERR_OK(status)) {
434 0 : return WERR_NOT_ENOUGH_MEMORY;
435 : }
436 : }
437 :
438 0 : return WERR_OK;
439 : }
440 :
441 :
442 :
443 0 : static WERROR nt_printer_info_to_mods(TALLOC_CTX *ctx,
444 : struct spoolss_PrinterInfo2 *info2,
445 : ADS_MODLIST *mods)
446 : {
447 0 : char *info_str;
448 :
449 0 : ads_mod_str(ctx, mods, SPOOL_REG_PRINTERNAME, info2->sharename);
450 0 : ads_mod_str(ctx, mods, SPOOL_REG_PRINTSHARENAME, info2->sharename);
451 0 : ads_mod_str(ctx, mods, SPOOL_REG_SHORTSERVERNAME, lp_netbios_name());
452 0 : ads_mod_str(ctx, mods, SPOOL_REG_SERVERNAME, get_mydnsfullname());
453 :
454 0 : info_str = talloc_asprintf(ctx, "\\\\%s\\%s",
455 : get_mydnsfullname(), info2->sharename);
456 0 : if (info_str == NULL) {
457 0 : return WERR_NOT_ENOUGH_MEMORY;
458 : }
459 0 : ads_mod_str(ctx, mods, SPOOL_REG_UNCNAME, info_str);
460 :
461 0 : info_str = talloc_asprintf(ctx, "%d", 4);
462 0 : if (info_str == NULL) {
463 0 : return WERR_NOT_ENOUGH_MEMORY;
464 : }
465 0 : ads_mod_str(ctx, mods, SPOOL_REG_VERSIONNUMBER, info_str);
466 :
467 : /* empty strings in the mods list result in an attribute error */
468 0 : if (strlen(info2->drivername) != 0)
469 0 : ads_mod_str(ctx, mods, SPOOL_REG_DRIVERNAME, info2->drivername);
470 0 : if (strlen(info2->location) != 0)
471 0 : ads_mod_str(ctx, mods, SPOOL_REG_LOCATION, info2->location);
472 0 : if (strlen(info2->comment) != 0)
473 0 : ads_mod_str(ctx, mods, SPOOL_REG_DESCRIPTION, info2->comment);
474 0 : if (strlen(info2->portname) != 0)
475 0 : ads_mod_str(ctx, mods, SPOOL_REG_PORTNAME, info2->portname);
476 0 : if (strlen(info2->sepfile) != 0)
477 0 : ads_mod_str(ctx, mods, SPOOL_REG_PRINTSEPARATORFILE, info2->sepfile);
478 :
479 0 : info_str = talloc_asprintf(ctx, "%u", info2->starttime);
480 0 : if (info_str == NULL) {
481 0 : return WERR_NOT_ENOUGH_MEMORY;
482 : }
483 0 : ads_mod_str(ctx, mods, SPOOL_REG_PRINTSTARTTIME, info_str);
484 :
485 0 : info_str = talloc_asprintf(ctx, "%u", info2->untiltime);
486 0 : if (info_str == NULL) {
487 0 : return WERR_NOT_ENOUGH_MEMORY;
488 : }
489 0 : ads_mod_str(ctx, mods, SPOOL_REG_PRINTENDTIME, info_str);
490 :
491 0 : info_str = talloc_asprintf(ctx, "%u", info2->priority);
492 0 : if (info_str == NULL) {
493 0 : return WERR_NOT_ENOUGH_MEMORY;
494 : }
495 0 : ads_mod_str(ctx, mods, SPOOL_REG_PRIORITY, info_str);
496 :
497 0 : if (info2->attributes & PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS) {
498 0 : ads_mod_str(ctx, mods, SPOOL_REG_PRINTKEEPPRINTEDJOBS, "TRUE");
499 : } else {
500 0 : ads_mod_str(ctx, mods, SPOOL_REG_PRINTKEEPPRINTEDJOBS, "FALSE");
501 : }
502 :
503 0 : switch (info2->attributes & 0x3) {
504 0 : case 0:
505 0 : ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
506 : SPOOL_REGVAL_PRINTWHILESPOOLING);
507 0 : break;
508 0 : case 1:
509 0 : ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
510 : SPOOL_REGVAL_PRINTAFTERSPOOLED);
511 0 : break;
512 0 : case 2:
513 0 : ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
514 : SPOOL_REGVAL_PRINTDIRECT);
515 0 : break;
516 0 : default:
517 0 : DEBUG(3, ("unsupported printer attributes %x\n",
518 : info2->attributes));
519 : }
520 :
521 0 : if (info2->devmode != NULL) {
522 0 : WERROR werr;
523 0 : werr = nt_printer_devmode_to_mods(ctx, info2->devmode, mods);
524 0 : if (!W_ERROR_IS_OK(werr)) {
525 0 : return werr;
526 : }
527 : }
528 :
529 0 : return WERR_OK;
530 : }
531 :
532 0 : static WERROR nt_printer_publish_ads(struct messaging_context *msg_ctx,
533 : ADS_STRUCT *ads,
534 : struct spoolss_PrinterInfo2 *pinfo2)
535 : {
536 0 : ADS_STATUS ads_rc;
537 0 : TALLOC_CTX *ctx = talloc_stackframe();
538 0 : ADS_MODLIST mods;
539 0 : struct GUID guid;
540 0 : WERROR win_rc = WERR_OK;
541 0 : const char *printer = pinfo2->sharename;
542 0 : char *printer_dn = NULL;
543 :
544 : /* build the ads mods */
545 0 : DEBUG(5, ("publishing printer %s\n", printer));
546 :
547 0 : win_rc = nt_printer_dn_lookup(ctx, ads, printer, &printer_dn);
548 0 : if (!W_ERROR_IS_OK(win_rc)) {
549 0 : DEBUG(2, ("Failed to create printer dn\n"));
550 0 : TALLOC_FREE(ctx);
551 0 : return win_rc;
552 : }
553 :
554 0 : mods = ads_init_mods(ctx);
555 :
556 0 : if (mods == NULL) {
557 0 : TALLOC_FREE(ctx);
558 0 : return WERR_NOT_ENOUGH_MEMORY;
559 : }
560 :
561 0 : win_rc = nt_printer_info_to_mods(ctx, pinfo2, &mods);
562 0 : if (!W_ERROR_IS_OK(win_rc)) {
563 0 : TALLOC_FREE(ctx);
564 0 : return win_rc;
565 : }
566 :
567 : /* publish it */
568 0 : ads_rc = ads_mod_printer_entry(ads, printer_dn, ctx, &mods);
569 0 : if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT) {
570 : int i;
571 0 : for (i=0; mods[i] != 0; i++)
572 : ;
573 0 : mods[i] = (LDAPMod *)-1;
574 0 : ads_rc = ads_add_printer_entry(ads, printer_dn, ctx, &mods);
575 : }
576 :
577 0 : if (!ADS_ERR_OK(ads_rc)) {
578 0 : DEBUG(3, ("error publishing %s: %s\n",
579 : printer, ads_errstr(ads_rc)));
580 : /* XXX failed to publish, so no guid to retrieve */
581 : }
582 :
583 0 : win_rc = nt_printer_guid_retrieve_internal(ads, printer_dn, &guid);
584 0 : if (!W_ERROR_IS_OK(win_rc)) {
585 0 : TALLOC_FREE(ctx);
586 0 : return win_rc;
587 : }
588 :
589 0 : win_rc = nt_printer_guid_store(msg_ctx, printer, guid);
590 0 : if (!W_ERROR_IS_OK(win_rc)) {
591 0 : DEBUG(3, ("failed to store printer %s guid\n",
592 : printer));
593 : /* not catastrophic, retrieve on next use */
594 0 : win_rc = WERR_OK;
595 : }
596 :
597 0 : TALLOC_FREE(ctx);
598 :
599 0 : return win_rc;
600 : }
601 :
602 0 : static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
603 : const char *printer)
604 : {
605 0 : ADS_STATUS ads_rc;
606 0 : LDAPMessage *res = NULL;
607 0 : char *prt_dn = NULL;
608 :
609 0 : DEBUG(5, ("unpublishing printer %s\n", printer));
610 :
611 : /* remove the printer from the directory */
612 0 : ads_rc = ads_find_printer_on_server(ads, &res,
613 : printer, lp_netbios_name());
614 :
615 0 : if (ADS_ERR_OK(ads_rc) && res && ads_count_replies(ads, res)) {
616 0 : prt_dn = ads_get_dn(ads, talloc_tos(), res);
617 0 : if (!prt_dn) {
618 0 : ads_msgfree(ads, res);
619 0 : return WERR_NOT_ENOUGH_MEMORY;
620 : }
621 0 : ads_rc = ads_del_dn(ads, prt_dn);
622 0 : TALLOC_FREE(prt_dn);
623 : }
624 :
625 0 : if (res) {
626 0 : ads_msgfree(ads, res);
627 : }
628 0 : return WERR_OK;
629 : }
630 :
631 : /****************************************************************************
632 : * Publish a printer in the directory
633 : *
634 : * @param mem_ctx memory context
635 : * @param session_info session_info to access winreg pipe
636 : * @param pinfo2 printer information
637 : * @param action publish/unpublish action
638 : * @return WERROR indicating status of publishing
639 : ***************************************************************************/
640 :
641 0 : WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
642 : const struct auth_session_info *session_info,
643 : struct messaging_context *msg_ctx,
644 : struct spoolss_PrinterInfo2 *pinfo2,
645 : int action)
646 : {
647 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
648 0 : uint32_t info2_mask = SPOOLSS_PRINTER_INFO_ATTRIBUTES;
649 0 : struct spoolss_SetPrinterInfo2 *sinfo2;
650 0 : ADS_STATUS ads_rc;
651 0 : ADS_STRUCT *ads = NULL;
652 0 : WERROR win_rc;
653 0 : char *old_krb5ccname = NULL;
654 0 : char *machine_password = NULL;
655 :
656 0 : sinfo2 = talloc_zero(tmp_ctx, struct spoolss_SetPrinterInfo2);
657 0 : if (!sinfo2) {
658 0 : win_rc = WERR_NOT_ENOUGH_MEMORY;
659 0 : goto done;
660 : }
661 :
662 0 : switch (action) {
663 0 : case DSPRINT_PUBLISH:
664 : case DSPRINT_UPDATE:
665 0 : pinfo2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
666 0 : break;
667 0 : case DSPRINT_UNPUBLISH:
668 0 : pinfo2->attributes &= (~PRINTER_ATTRIBUTE_PUBLISHED);
669 0 : break;
670 0 : default:
671 0 : win_rc = WERR_NOT_SUPPORTED;
672 0 : goto done;
673 : }
674 :
675 0 : sinfo2->attributes = pinfo2->attributes;
676 :
677 0 : win_rc = winreg_update_printer_internal(tmp_ctx, session_info, msg_ctx,
678 : pinfo2->sharename, info2_mask,
679 : sinfo2, NULL, NULL);
680 0 : if (!W_ERROR_IS_OK(win_rc)) {
681 0 : DBG_NOTICE("Failed to update data for printer [%s] - %s\n",
682 : pinfo2->sharename,
683 : win_errstr(win_rc));
684 0 : goto done;
685 : }
686 :
687 0 : TALLOC_FREE(sinfo2);
688 :
689 0 : ads = ads_init(tmp_ctx,
690 : lp_realm(),
691 : lp_workgroup(),
692 : NULL,
693 : ADS_SASL_PLAIN);
694 0 : if (!ads) {
695 0 : DEBUG(3, ("ads_init() failed\n"));
696 0 : win_rc = WERR_RPC_S_SERVER_UNAVAILABLE;
697 0 : goto done;
698 : }
699 0 : old_krb5ccname = getenv(KRB5_ENV_CCNAME);
700 0 : setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
701 0 : ADS_TALLOC_CONST_FREE(ads->auth.password);
702 0 : machine_password = secrets_fetch_machine_password(lp_workgroup(),
703 : NULL, NULL);
704 0 : if (machine_password != NULL) {
705 0 : ads->auth.password = talloc_strdup(ads, machine_password);
706 0 : SAFE_FREE(machine_password);
707 0 : if (ads->auth.password == NULL) {
708 0 : win_rc = WERR_NOT_ENOUGH_MEMORY;
709 0 : goto done;
710 : }
711 : }
712 :
713 : /* ads_connect() will find the DC for us */
714 0 : ads_rc = ads_connect(ads);
715 0 : if (!ADS_ERR_OK(ads_rc)) {
716 0 : DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
717 0 : win_rc = WERR_ACCESS_DENIED;
718 0 : goto done;
719 : }
720 :
721 0 : switch (action) {
722 0 : case DSPRINT_PUBLISH:
723 : case DSPRINT_UPDATE:
724 0 : win_rc = nt_printer_publish_ads(msg_ctx, ads, pinfo2);
725 0 : break;
726 0 : case DSPRINT_UNPUBLISH:
727 0 : win_rc = nt_printer_unpublish_ads(ads, pinfo2->sharename);
728 0 : break;
729 : }
730 :
731 0 : done:
732 0 : ads_kdestroy("MEMORY:prtpub_cache");
733 0 : unsetenv(KRB5_ENV_CCNAME);
734 0 : if (old_krb5ccname) {
735 0 : setenv(KRB5_ENV_CCNAME, old_krb5ccname, 0);
736 : }
737 :
738 0 : TALLOC_FREE(tmp_ctx);
739 :
740 0 : return win_rc;
741 : }
742 :
743 2 : WERROR check_published_printers(struct messaging_context *msg_ctx)
744 : {
745 0 : const struct loadparm_substitution *lp_sub =
746 2 : loadparm_s3_global_substitution();
747 0 : ADS_STATUS ads_rc;
748 2 : ADS_STRUCT *ads = NULL;
749 0 : int snum;
750 2 : int n_services = lp_numservices();
751 2 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
752 2 : struct auth_session_info *session_info = NULL;
753 0 : struct spoolss_PrinterInfo2 *pinfo2;
754 0 : NTSTATUS status;
755 0 : WERROR result;
756 2 : char *old_krb5ccname = NULL;
757 2 : char *machine_password = NULL;
758 :
759 2 : ads = ads_init(tmp_ctx,
760 : lp_realm(),
761 : lp_workgroup(),
762 : NULL,
763 : ADS_SASL_PLAIN);
764 2 : if (!ads) {
765 0 : DEBUG(3, ("ads_init() failed\n"));
766 0 : TALLOC_FREE(tmp_ctx);
767 0 : return WERR_RPC_S_SERVER_UNAVAILABLE;
768 : }
769 2 : old_krb5ccname = getenv(KRB5_ENV_CCNAME);
770 2 : setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
771 2 : ADS_TALLOC_CONST_FREE(ads->auth.password);
772 2 : machine_password = secrets_fetch_machine_password(lp_workgroup(),
773 : NULL, NULL);
774 2 : if (machine_password != NULL) {
775 2 : ads->auth.password = talloc_strdup(ads, machine_password);
776 2 : SAFE_FREE(machine_password);
777 2 : if (ads->auth.password == NULL) {
778 0 : result = WERR_NOT_ENOUGH_MEMORY;
779 0 : goto done;
780 : }
781 : }
782 : /* ads_connect() will find the DC for us */
783 2 : ads_rc = ads_connect(ads);
784 2 : if (!ADS_ERR_OK(ads_rc)) {
785 0 : DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
786 0 : result = WERR_ACCESS_DENIED;
787 0 : goto done;
788 : }
789 :
790 2 : status = make_session_info_system(tmp_ctx, &session_info);
791 2 : if (!NT_STATUS_IS_OK(status)) {
792 0 : DEBUG(0, ("check_published_printers: "
793 : "Could not create system session_info\n"));
794 0 : result = WERR_ACCESS_DENIED;
795 0 : goto done;
796 : }
797 :
798 246 : for (snum = 0; snum < n_services; snum++) {
799 244 : if (!lp_snum_ok(snum) || !lp_printable(snum)) {
800 234 : continue;
801 : }
802 :
803 10 : result = winreg_get_printer_internal(tmp_ctx, session_info, msg_ctx,
804 10 : lp_servicename(talloc_tos(), lp_sub, snum),
805 : &pinfo2);
806 10 : if (!W_ERROR_IS_OK(result)) {
807 10 : continue;
808 : }
809 :
810 0 : if (pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
811 0 : nt_printer_publish_ads(msg_ctx, ads, pinfo2);
812 : }
813 :
814 0 : TALLOC_FREE(pinfo2);
815 : }
816 :
817 2 : result = WERR_OK;
818 2 : done:
819 2 : ads_kdestroy("MEMORY:prtpub_cache");
820 2 : unsetenv(KRB5_ENV_CCNAME);
821 2 : if (old_krb5ccname) {
822 2 : setenv(KRB5_ENV_CCNAME, old_krb5ccname, 0);
823 : }
824 2 : talloc_free(tmp_ctx);
825 2 : return result;
826 : }
827 :
828 84 : bool is_printer_published(TALLOC_CTX *mem_ctx,
829 : const struct auth_session_info *session_info,
830 : struct messaging_context *msg_ctx,
831 : const char *servername,
832 : const char *printer,
833 : struct spoolss_PrinterInfo2 **info2)
834 : {
835 84 : struct spoolss_PrinterInfo2 *pinfo2 = NULL;
836 0 : WERROR result;
837 0 : struct dcerpc_binding_handle *b;
838 :
839 84 : result = winreg_printer_binding_handle(mem_ctx,
840 : session_info,
841 : msg_ctx,
842 : &b);
843 84 : if (!W_ERROR_IS_OK(result)) {
844 0 : return false;
845 : }
846 :
847 84 : result = winreg_get_printer(mem_ctx, b,
848 : printer, &pinfo2);
849 84 : if (!W_ERROR_IS_OK(result)) {
850 0 : return false;
851 : }
852 :
853 84 : if (!(pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
854 84 : TALLOC_FREE(pinfo2);
855 84 : return false;
856 : }
857 :
858 0 : if (info2) {
859 0 : *info2 = talloc_move(mem_ctx, &pinfo2);
860 : }
861 0 : talloc_free(pinfo2);
862 0 : return true;
863 : }
864 : #else
865 0 : WERROR nt_printer_guid_store(struct messaging_context *msg_ctx,
866 : const char *printer, struct GUID guid)
867 : {
868 0 : return WERR_NOT_SUPPORTED;
869 : }
870 :
871 0 : WERROR nt_printer_guid_retrieve(TALLOC_CTX *mem_ctx, const char *printer,
872 : struct GUID *pguid)
873 : {
874 0 : return WERR_NOT_SUPPORTED;
875 : }
876 :
877 0 : WERROR nt_printer_guid_get(TALLOC_CTX *mem_ctx,
878 : const struct auth_session_info *session_info,
879 : struct messaging_context *msg_ctx,
880 : const char *printer, struct GUID *guid)
881 : {
882 0 : return WERR_NOT_SUPPORTED;
883 : }
884 :
885 0 : WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
886 : const struct auth_session_info *session_info,
887 : struct messaging_context *msg_ctx,
888 : struct spoolss_PrinterInfo2 *pinfo2,
889 : int action)
890 : {
891 0 : return WERR_OK;
892 : }
893 :
894 0 : WERROR check_published_printers(struct messaging_context *msg_ctx)
895 : {
896 0 : return WERR_OK;
897 : }
898 :
899 28 : bool is_printer_published(TALLOC_CTX *mem_ctx,
900 : const struct auth_session_info *session_info,
901 : struct messaging_context *msg_ctx,
902 : const char *servername,
903 : const char *printer,
904 : struct spoolss_PrinterInfo2 **info2)
905 : {
906 28 : return False;
907 : }
908 : #endif /* HAVE_ADS */
|