dsdb/netlogon: make use of dsdb_dc_functional_level() in fill_netlogon_samlogon_respo...
[Samba.git] / source3 / printing / nt_printing_ads.c
blob0ec13d1bf1af8d2b985bf93dc8a289bd1a4a41be
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.
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.
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.
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/>.
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"
34 #ifdef HAVE_ADS
35 /*****************************************************************
36 ****************************************************************/
38 WERROR nt_printer_guid_store(struct messaging_context *msg_ctx,
39 const char *printer, struct GUID guid)
41 TALLOC_CTX *tmp_ctx;
42 const struct auth_session_info *session_info;
43 const char *guid_str;
44 DATA_BLOB blob;
45 WERROR result;
47 tmp_ctx = talloc_new(NULL);
48 if (!tmp_ctx) {
49 DEBUG(0, ("Out of memory?!\n"));
50 return WERR_NOT_ENOUGH_MEMORY;
53 session_info = get_session_info_system();
54 if (session_info == NULL) {
55 DEBUG(0, ("Could not get system session_info\n"));
56 result = WERR_NOT_ENOUGH_MEMORY;
57 goto done;
60 guid_str = GUID_string(tmp_ctx, &guid);
61 if (!guid_str) {
62 DEBUG(0, ("Out of memory?!\n"));
63 result = WERR_NOT_ENOUGH_MEMORY;
64 goto done;
67 /* We used to store this as a REG_BINARY but that causes
68 Vista to whine */
70 if (!push_reg_sz(tmp_ctx, &blob, guid_str)) {
71 DEBUG(0, ("Could not marshall string %s for objectGUID\n",
72 guid_str));
73 result = WERR_NOT_ENOUGH_MEMORY;
74 goto done;
77 result = winreg_set_printer_dataex_internal(tmp_ctx, session_info, msg_ctx,
78 printer,
79 SPOOL_DSSPOOLER_KEY, "objectGUID",
80 REG_SZ, blob.data, blob.length);
81 if (!W_ERROR_IS_OK(result)) {
82 DEBUG(0, ("Failed to store GUID for printer %s\n", printer));
83 goto done;
86 result = WERR_OK;
87 done:
88 talloc_free(tmp_ctx);
90 return result;
93 static WERROR nt_printer_dn_lookup(TALLOC_CTX *mem_ctx,
94 ADS_STRUCT *ads,
95 const char *printer,
96 char **pprinter_dn)
98 char *printer_dn = NULL;
99 char *srv_dn = NULL;
100 char *srv_cn_0 = NULL;
101 char *srv_cn_escaped = NULL;
102 char *sharename_escaped = NULL;
103 char *srv_dn_utf8 = NULL;
104 char **srv_cn_utf8 = NULL;
105 size_t converted_size;
106 ADS_STATUS ads_status;
107 LDAPMessage *res;
108 WERROR result;
109 bool ok;
111 ads_status = ads_find_machine_acct(ads, &res, lp_netbios_name());
112 if (!ADS_ERR_OK(ads_status)) {
113 DEBUG(2, ("Failed to find machine account for %s\n",
114 lp_netbios_name()));
115 result = WERR_NOT_FOUND;
116 goto err_out;
120 * We use ldap_get_dn here as we need the answer in utf8 to call
121 * ldap_explode_dn(). JRA.
123 srv_dn_utf8 = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
124 ads_msgfree(ads, res);
125 if (srv_dn_utf8 == NULL) {
126 result = WERR_RPC_S_SERVER_UNAVAILABLE;
127 goto err_out;
130 srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
131 if (srv_cn_utf8 == NULL) {
132 ldap_memfree(srv_dn_utf8);
133 result = WERR_RPC_S_SERVER_UNAVAILABLE;
134 goto err_out;
137 /* Now convert to CH_UNIX. */
138 ok = pull_utf8_talloc(mem_ctx, &srv_dn, srv_dn_utf8, &converted_size);
139 ldap_memfree(srv_dn_utf8);
140 if (!ok) {
141 ldap_memfree(srv_cn_utf8);
142 result = WERR_RPC_S_SERVER_UNAVAILABLE;
143 goto err_out;
146 ok = pull_utf8_talloc(mem_ctx, &srv_cn_0, srv_cn_utf8[0], &converted_size);
147 ldap_memfree(srv_cn_utf8);
148 if (!ok) {
149 result = WERR_RPC_S_SERVER_UNAVAILABLE;
150 goto err_out;
153 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0);
154 if (srv_cn_escaped == NULL) {
155 result = WERR_RPC_S_SERVER_UNAVAILABLE;
156 goto err_out;
159 sharename_escaped = escape_rdn_val_string_alloc(printer);
160 if (sharename_escaped == NULL) {
161 result = WERR_RPC_S_SERVER_UNAVAILABLE;
162 goto err_out;
165 printer_dn = talloc_asprintf(mem_ctx,
166 "cn=%s-%s,%s",
167 srv_cn_escaped,
168 sharename_escaped,
169 srv_dn);
170 if (printer_dn == NULL) {
171 result = WERR_NOT_ENOUGH_MEMORY;
172 goto err_out;
175 *pprinter_dn = printer_dn;
177 result = WERR_OK;
178 err_out:
179 SAFE_FREE(sharename_escaped);
180 SAFE_FREE(srv_cn_escaped);
181 TALLOC_FREE(srv_cn_0);
182 TALLOC_FREE(srv_dn);
183 return result;
186 static WERROR nt_printer_guid_retrieve_internal(ADS_STRUCT *ads,
187 const char *printer_dn,
188 struct GUID *pguid)
190 ADS_STATUS ads_status;
191 LDAPMessage *res;
192 const char *attrs[] = {"objectGUID", NULL};
193 struct GUID guid;
194 bool ok;
196 ads_status = ads_search_dn(ads, &res, printer_dn, attrs);
197 if (!ADS_ERR_OK(ads_status)) {
198 DEBUG(2, ("Failed to retrieve GUID from DC - %s\n",
199 ads_errstr(ads_status)));
200 return WERR_FILE_NOT_FOUND;
203 ZERO_STRUCT(guid);
204 ok = ads_pull_guid(ads, res, &guid);
205 ads_msgfree(ads, res);
206 if (!ok) {
207 return WERR_NOT_ENOUGH_MEMORY;
210 *pguid = guid;
212 return WERR_OK;
215 WERROR nt_printer_guid_retrieve(TALLOC_CTX *mem_ctx, const char *printer,
216 struct GUID *pguid)
218 ADS_STRUCT *ads = NULL;
219 char *old_krb5ccname = NULL;
220 char *printer_dn;
221 WERROR result;
222 ADS_STATUS ads_status;
223 TALLOC_CTX *tmp_ctx;
225 tmp_ctx = talloc_new(mem_ctx);
226 if (tmp_ctx == NULL) {
227 return WERR_NOT_ENOUGH_MEMORY;
230 ads = ads_init(lp_realm(), lp_workgroup(), NULL, ADS_SASL_PLAIN);
231 if (ads == NULL) {
232 result = WERR_RPC_S_SERVER_UNAVAILABLE;
233 goto out;
236 old_krb5ccname = getenv(KRB5_ENV_CCNAME);
237 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
238 SAFE_FREE(ads->auth.password);
239 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
240 NULL, NULL);
242 ads_status = ads_connect(ads);
243 if (!ADS_ERR_OK(ads_status)) {
244 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_status)));
245 result = WERR_ACCESS_DENIED;
246 goto out;
249 result = nt_printer_dn_lookup(tmp_ctx, ads, printer, &printer_dn);
250 if (!W_ERROR_IS_OK(result)) {
251 goto out;
254 result = nt_printer_guid_retrieve_internal(ads, printer_dn, pguid);
255 out:
256 TALLOC_FREE(tmp_ctx);
257 ads_destroy(&ads);
258 ads_kdestroy("MEMORY:prtpub_cache");
259 unsetenv(KRB5_ENV_CCNAME);
260 if (old_krb5ccname != NULL) {
261 setenv(KRB5_ENV_CCNAME, old_krb5ccname, 0);
264 return result;
267 WERROR nt_printer_guid_get(TALLOC_CTX *mem_ctx,
268 const struct auth_session_info *session_info,
269 struct messaging_context *msg_ctx,
270 const char *printer, struct GUID *guid)
272 TALLOC_CTX *tmp_ctx;
273 enum winreg_Type type;
274 DATA_BLOB blob;
275 uint32_t len;
276 NTSTATUS status;
277 WERROR result;
279 tmp_ctx = talloc_new(mem_ctx);
280 if (tmp_ctx == NULL) {
281 DEBUG(0, ("out of memory?!\n"));
282 return WERR_NOT_ENOUGH_MEMORY;
285 result = winreg_get_printer_dataex_internal(tmp_ctx, session_info,
286 msg_ctx, printer,
287 SPOOL_DSSPOOLER_KEY,
288 "objectGUID",
289 &type,
290 &blob.data,
291 &len);
292 if (!W_ERROR_IS_OK(result)) {
293 DEBUG(0, ("Failed to get GUID for printer %s\n", printer));
294 goto out_ctx_free;
296 blob.length = (size_t)len;
298 /* We used to store the guid as REG_BINARY, then swapped
299 to REG_SZ for Vista compatibility so check for both */
301 switch (type) {
302 case REG_SZ: {
303 bool ok;
304 const char *guid_str;
305 ok = pull_reg_sz(tmp_ctx, &blob, &guid_str);
306 if (!ok) {
307 DEBUG(0, ("Failed to unmarshall GUID for printer %s\n",
308 printer));
309 result = WERR_REGISTRY_CORRUPT;
310 goto out_ctx_free;
312 status = GUID_from_string(guid_str, guid);
313 if (!NT_STATUS_IS_OK(status)) {
314 DEBUG(0, ("bad GUID for printer %s\n", printer));
315 result = ntstatus_to_werror(status);
316 goto out_ctx_free;
318 break;
320 case REG_BINARY:
321 if (blob.length != sizeof(struct GUID)) {
322 DEBUG(0, ("bad GUID for printer %s\n", printer));
323 result = WERR_REGISTRY_CORRUPT;
324 goto out_ctx_free;
326 memcpy(guid, blob.data, sizeof(struct GUID));
327 break;
328 default:
329 DEBUG(0,("GUID value stored as invalid type (%d)\n", type));
330 result = WERR_REGISTRY_CORRUPT;
331 goto out_ctx_free;
332 break;
334 result = WERR_OK;
336 out_ctx_free:
337 talloc_free(tmp_ctx);
338 return result;
341 static WERROR nt_printer_devmode_to_mods(TALLOC_CTX *ctx,
342 struct spoolss_DeviceMode *devmode,
343 ADS_MODLIST *mods)
345 char *str = NULL;
346 ADS_STATUS status;
349 the device mode fields bits allow us to make an educated guess if a
350 printer feature is supported. For sure a feature must be unsupported if
351 the fields bit is not set. Device Mode Extra Data and FeatureOptionPairs
352 might help to figure out more information here. Common attributes, that
353 we can't handle yet:
354 SPOOL_REG_PRINTBINNAMES - printBinNames
355 SPOOL_REG_PRINTMAXXEXTENT - printMaxXExtent
356 SPOOL_REG_PRINTMAXYEXTENT - printMaxYExtent
357 SPOOL_REG_PRINTMINXEXTENT - printMinXExtent
358 SPOOL_REG_PRINTMINYEXTENT - printMinYExtent
359 SPOOL_REG_PRINTSTAPLINGSUPPORTED - printStaplingSupported
360 SPOOL_REG_PRINTPAGESPERMINUTE - printPagesPerMinute
361 SPOOL_REG_PRINTRATE - printRate
362 SPOOL_REG_PRINTRATEUNIT - printRateUnit
363 SPOOL_REG_PRINTMEDIAREADY - printMediaReady
364 SPOOL_REG_PRINTMEDIASUPPORTED - printMediaSupported
365 SPOOL_REG_PRINTNUMBERUP - printNumberUp
366 SPOOL_REG_PRINTMAXCOPIES - printMaxCopies
368 if (devmode->fields & DEVMODE_COLOR) {
369 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTCOLOR, "TRUE");
370 } else {
371 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTCOLOR, "FALSE");
373 if (!ADS_ERR_OK(status)) {
374 return WERR_NOT_ENOUGH_MEMORY;
377 if (devmode->fields & DEVMODE_DUPLEX) {
378 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTDUPLEXSUPPORTED, "TRUE");
379 } else {
380 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTDUPLEXSUPPORTED, "FALSE");
382 if (!ADS_ERR_OK(status)) {
383 return WERR_NOT_ENOUGH_MEMORY;
386 if (devmode->fields & DEVMODE_COLLATE) {
387 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTCOLLATE, "TRUE");
388 } else {
389 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTCOLLATE, "FALSE");
391 if (!ADS_ERR_OK(status)) {
392 return WERR_NOT_ENOUGH_MEMORY;
395 /* portrait mode is always supported, LANDSCAPE is optional */
396 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTORIENTATIONSSUPPORTED, "PORTRAIT");
397 if (!ADS_ERR_OK(status)) {
398 return WERR_NOT_ENOUGH_MEMORY;
400 if (devmode->fields & DEVMODE_ORIENTATION) {
401 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTORIENTATIONSSUPPORTED, "LANDSCAPE");
402 if (!ADS_ERR_OK(status)) {
403 return WERR_NOT_ENOUGH_MEMORY;
407 /* the driverVersion attribute in AD contains actually specversion */
408 str = talloc_asprintf(ctx, "%u", devmode->specversion);
409 if (str == NULL) {
410 return WERR_NOT_ENOUGH_MEMORY;
412 if (strlen(str) != 0) {
413 status = ads_mod_str(ctx, mods, SPOOL_REG_DRIVERVERSION, str);
414 if (!ADS_ERR_OK(status)) {
415 return WERR_NOT_ENOUGH_MEMORY;
419 /* devmode->yresolution is a good candidate for printMaxResolutionSupported */
420 str = talloc_asprintf(ctx, "%u", devmode->yresolution);
421 if (str == NULL) {
422 return WERR_NOT_ENOUGH_MEMORY;
424 if (strlen(str) != 0) {
425 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTMAXRESOLUTIONSUPPORTED, str);
426 if (!ADS_ERR_OK(status)) {
427 return WERR_NOT_ENOUGH_MEMORY;
431 return WERR_OK;
436 static WERROR nt_printer_info_to_mods(TALLOC_CTX *ctx,
437 struct spoolss_PrinterInfo2 *info2,
438 ADS_MODLIST *mods)
440 char *info_str;
442 ads_mod_str(ctx, mods, SPOOL_REG_PRINTERNAME, info2->sharename);
443 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSHARENAME, info2->sharename);
444 ads_mod_str(ctx, mods, SPOOL_REG_SHORTSERVERNAME, lp_netbios_name());
445 ads_mod_str(ctx, mods, SPOOL_REG_SERVERNAME, get_mydnsfullname());
447 info_str = talloc_asprintf(ctx, "\\\\%s\\%s",
448 get_mydnsfullname(), info2->sharename);
449 if (info_str == NULL) {
450 return WERR_NOT_ENOUGH_MEMORY;
452 ads_mod_str(ctx, mods, SPOOL_REG_UNCNAME, info_str);
454 info_str = talloc_asprintf(ctx, "%d", 4);
455 if (info_str == NULL) {
456 return WERR_NOT_ENOUGH_MEMORY;
458 ads_mod_str(ctx, mods, SPOOL_REG_VERSIONNUMBER, info_str);
460 /* empty strings in the mods list result in an attrubute error */
461 if (strlen(info2->drivername) != 0)
462 ads_mod_str(ctx, mods, SPOOL_REG_DRIVERNAME, info2->drivername);
463 if (strlen(info2->location) != 0)
464 ads_mod_str(ctx, mods, SPOOL_REG_LOCATION, info2->location);
465 if (strlen(info2->comment) != 0)
466 ads_mod_str(ctx, mods, SPOOL_REG_DESCRIPTION, info2->comment);
467 if (strlen(info2->portname) != 0)
468 ads_mod_str(ctx, mods, SPOOL_REG_PORTNAME, info2->portname);
469 if (strlen(info2->sepfile) != 0)
470 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSEPARATORFILE, info2->sepfile);
472 info_str = talloc_asprintf(ctx, "%u", info2->starttime);
473 if (info_str == NULL) {
474 return WERR_NOT_ENOUGH_MEMORY;
476 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSTARTTIME, info_str);
478 info_str = talloc_asprintf(ctx, "%u", info2->untiltime);
479 if (info_str == NULL) {
480 return WERR_NOT_ENOUGH_MEMORY;
482 ads_mod_str(ctx, mods, SPOOL_REG_PRINTENDTIME, info_str);
484 info_str = talloc_asprintf(ctx, "%u", info2->priority);
485 if (info_str == NULL) {
486 return WERR_NOT_ENOUGH_MEMORY;
488 ads_mod_str(ctx, mods, SPOOL_REG_PRIORITY, info_str);
490 if (info2->attributes & PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS) {
491 ads_mod_str(ctx, mods, SPOOL_REG_PRINTKEEPPRINTEDJOBS, "TRUE");
492 } else {
493 ads_mod_str(ctx, mods, SPOOL_REG_PRINTKEEPPRINTEDJOBS, "FALSE");
496 switch (info2->attributes & 0x3) {
497 case 0:
498 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
499 SPOOL_REGVAL_PRINTWHILESPOOLING);
500 break;
501 case 1:
502 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
503 SPOOL_REGVAL_PRINTAFTERSPOOLED);
504 break;
505 case 2:
506 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
507 SPOOL_REGVAL_PRINTDIRECT);
508 break;
509 default:
510 DEBUG(3, ("unsupported printer attributes %x\n",
511 info2->attributes));
514 if (info2->devmode != NULL) {
515 WERROR werr;
516 werr = nt_printer_devmode_to_mods(ctx, info2->devmode, mods);
517 if (!W_ERROR_IS_OK(werr)) {
518 return werr;
522 return WERR_OK;
525 static WERROR nt_printer_publish_ads(struct messaging_context *msg_ctx,
526 ADS_STRUCT *ads,
527 struct spoolss_PrinterInfo2 *pinfo2)
529 ADS_STATUS ads_rc;
530 TALLOC_CTX *ctx;
531 ADS_MODLIST mods;
532 struct GUID guid;
533 WERROR win_rc = WERR_OK;
534 const char *printer = pinfo2->sharename;
535 char *printer_dn = NULL;
537 /* build the ads mods */
538 ctx = talloc_init("nt_printer_publish_ads");
539 if (ctx == NULL) {
540 return WERR_NOT_ENOUGH_MEMORY;
543 DEBUG(5, ("publishing printer %s\n", printer));
545 win_rc = nt_printer_dn_lookup(ctx, ads, printer, &printer_dn);
546 if (!W_ERROR_IS_OK(win_rc)) {
547 DEBUG(2, ("Failed to create printer dn\n"));
548 TALLOC_FREE(ctx);
549 return win_rc;
552 mods = ads_init_mods(ctx);
554 if (mods == NULL) {
555 TALLOC_FREE(ctx);
556 return WERR_NOT_ENOUGH_MEMORY;
559 win_rc = nt_printer_info_to_mods(ctx, pinfo2, &mods);
560 if (!W_ERROR_IS_OK(win_rc)) {
561 TALLOC_FREE(ctx);
562 return win_rc;
565 /* publish it */
566 ads_rc = ads_mod_printer_entry(ads, printer_dn, ctx, &mods);
567 if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT) {
568 int i;
569 for (i=0; mods[i] != 0; i++)
571 mods[i] = (LDAPMod *)-1;
572 ads_rc = ads_add_printer_entry(ads, printer_dn, ctx, &mods);
575 if (!ADS_ERR_OK(ads_rc)) {
576 DEBUG(3, ("error publishing %s: %s\n",
577 printer, ads_errstr(ads_rc)));
578 /* XXX failed to publish, so no guid to retrieve */
581 win_rc = nt_printer_guid_retrieve_internal(ads, printer_dn, &guid);
582 if (!W_ERROR_IS_OK(win_rc)) {
583 TALLOC_FREE(ctx);
584 return win_rc;
587 win_rc = nt_printer_guid_store(msg_ctx, printer, guid);
588 if (!W_ERROR_IS_OK(win_rc)) {
589 DEBUG(3, ("failed to store printer %s guid\n",
590 printer));
591 /* not catastrophic, retrieve on next use */
592 win_rc = WERR_OK;
595 TALLOC_FREE(ctx);
597 return win_rc;
600 static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
601 const char *printer)
603 ADS_STATUS ads_rc;
604 LDAPMessage *res = NULL;
605 char *prt_dn = NULL;
607 DEBUG(5, ("unpublishing printer %s\n", printer));
609 /* remove the printer from the directory */
610 ads_rc = ads_find_printer_on_server(ads, &res,
611 printer, lp_netbios_name());
613 if (ADS_ERR_OK(ads_rc) && res && ads_count_replies(ads, res)) {
614 prt_dn = ads_get_dn(ads, talloc_tos(), res);
615 if (!prt_dn) {
616 ads_msgfree(ads, res);
617 return WERR_NOT_ENOUGH_MEMORY;
619 ads_rc = ads_del_dn(ads, prt_dn);
620 TALLOC_FREE(prt_dn);
623 if (res) {
624 ads_msgfree(ads, res);
626 return WERR_OK;
629 /****************************************************************************
630 * Publish a printer in the directory
632 * @param mem_ctx memory context
633 * @param session_info session_info to access winreg pipe
634 * @param pinfo2 printer information
635 * @param action publish/unpublish action
636 * @return WERROR indicating status of publishing
637 ***************************************************************************/
639 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
640 const struct auth_session_info *session_info,
641 struct messaging_context *msg_ctx,
642 struct spoolss_PrinterInfo2 *pinfo2,
643 int action)
645 uint32_t info2_mask = SPOOLSS_PRINTER_INFO_ATTRIBUTES;
646 struct spoolss_SetPrinterInfo2 *sinfo2;
647 ADS_STATUS ads_rc;
648 ADS_STRUCT *ads = NULL;
649 WERROR win_rc;
650 char *old_krb5ccname = NULL;
652 sinfo2 = talloc_zero(mem_ctx, struct spoolss_SetPrinterInfo2);
653 if (!sinfo2) {
654 return WERR_NOT_ENOUGH_MEMORY;
657 switch (action) {
658 case DSPRINT_PUBLISH:
659 case DSPRINT_UPDATE:
660 pinfo2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
661 break;
662 case DSPRINT_UNPUBLISH:
663 pinfo2->attributes &= (~PRINTER_ATTRIBUTE_PUBLISHED);
664 break;
665 default:
666 win_rc = WERR_NOT_SUPPORTED;
667 goto done;
670 sinfo2->attributes = pinfo2->attributes;
672 win_rc = winreg_update_printer_internal(mem_ctx, session_info, msg_ctx,
673 pinfo2->sharename, info2_mask,
674 sinfo2, NULL, NULL);
675 if (!W_ERROR_IS_OK(win_rc)) {
676 DBG_NOTICE("Failed to update data for printer [%s] - %s\n",
677 pinfo2->sharename,
678 win_errstr(win_rc));
679 goto done;
682 TALLOC_FREE(sinfo2);
684 ads = ads_init(lp_realm(), lp_workgroup(), NULL, ADS_SASL_PLAIN);
685 if (!ads) {
686 DEBUG(3, ("ads_init() failed\n"));
687 win_rc = WERR_RPC_S_SERVER_UNAVAILABLE;
688 goto done;
690 old_krb5ccname = getenv(KRB5_ENV_CCNAME);
691 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
692 SAFE_FREE(ads->auth.password);
693 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
694 NULL, NULL);
696 /* ads_connect() will find the DC for us */
697 ads_rc = ads_connect(ads);
698 if (!ADS_ERR_OK(ads_rc)) {
699 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
700 win_rc = WERR_ACCESS_DENIED;
701 goto done;
704 switch (action) {
705 case DSPRINT_PUBLISH:
706 case DSPRINT_UPDATE:
707 win_rc = nt_printer_publish_ads(msg_ctx, ads, pinfo2);
708 break;
709 case DSPRINT_UNPUBLISH:
710 win_rc = nt_printer_unpublish_ads(ads, pinfo2->sharename);
711 break;
714 done:
715 ads_destroy(&ads);
716 ads_kdestroy("MEMORY:prtpub_cache");
717 unsetenv(KRB5_ENV_CCNAME);
718 if (old_krb5ccname) {
719 setenv(KRB5_ENV_CCNAME, old_krb5ccname, 0);
721 return win_rc;
724 WERROR check_published_printers(struct messaging_context *msg_ctx)
726 const struct loadparm_substitution *lp_sub =
727 loadparm_s3_global_substitution();
728 ADS_STATUS ads_rc;
729 ADS_STRUCT *ads = NULL;
730 int snum;
731 int n_services = lp_numservices();
732 TALLOC_CTX *tmp_ctx = NULL;
733 struct auth_session_info *session_info = NULL;
734 struct spoolss_PrinterInfo2 *pinfo2;
735 NTSTATUS status;
736 WERROR result;
737 char *old_krb5ccname = NULL;
739 tmp_ctx = talloc_new(NULL);
740 if (!tmp_ctx) return WERR_NOT_ENOUGH_MEMORY;
742 ads = ads_init(lp_realm(), lp_workgroup(), NULL, ADS_SASL_PLAIN);
743 if (!ads) {
744 DEBUG(3, ("ads_init() failed\n"));
745 return WERR_RPC_S_SERVER_UNAVAILABLE;
747 old_krb5ccname = getenv(KRB5_ENV_CCNAME);
748 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
749 SAFE_FREE(ads->auth.password);
750 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
751 NULL, NULL);
753 /* ads_connect() will find the DC for us */
754 ads_rc = ads_connect(ads);
755 if (!ADS_ERR_OK(ads_rc)) {
756 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
757 result = WERR_ACCESS_DENIED;
758 goto done;
761 status = make_session_info_system(tmp_ctx, &session_info);
762 if (!NT_STATUS_IS_OK(status)) {
763 DEBUG(0, ("check_published_printers: "
764 "Could not create system session_info\n"));
765 result = WERR_ACCESS_DENIED;
766 goto done;
769 for (snum = 0; snum < n_services; snum++) {
770 if (!lp_snum_ok(snum) || !lp_printable(snum)) {
771 continue;
774 result = winreg_get_printer_internal(tmp_ctx, session_info, msg_ctx,
775 lp_servicename(talloc_tos(), lp_sub, snum),
776 &pinfo2);
777 if (!W_ERROR_IS_OK(result)) {
778 continue;
781 if (pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
782 nt_printer_publish_ads(msg_ctx, ads, pinfo2);
785 TALLOC_FREE(pinfo2);
788 result = WERR_OK;
789 done:
790 ads_destroy(&ads);
791 ads_kdestroy("MEMORY:prtpub_cache");
792 unsetenv(KRB5_ENV_CCNAME);
793 if (old_krb5ccname) {
794 setenv(KRB5_ENV_CCNAME, old_krb5ccname, 0);
796 talloc_free(tmp_ctx);
797 return result;
800 bool is_printer_published(TALLOC_CTX *mem_ctx,
801 const struct auth_session_info *session_info,
802 struct messaging_context *msg_ctx,
803 const char *servername,
804 const char *printer,
805 struct spoolss_PrinterInfo2 **info2)
807 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
808 WERROR result;
809 struct dcerpc_binding_handle *b;
811 result = winreg_printer_binding_handle(mem_ctx,
812 session_info,
813 msg_ctx,
814 &b);
815 if (!W_ERROR_IS_OK(result)) {
816 return false;
819 result = winreg_get_printer(mem_ctx, b,
820 printer, &pinfo2);
821 if (!W_ERROR_IS_OK(result)) {
822 return false;
825 if (!(pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
826 TALLOC_FREE(pinfo2);
827 return false;
830 if (info2) {
831 *info2 = talloc_move(mem_ctx, &pinfo2);
833 talloc_free(pinfo2);
834 return true;
836 #else
837 WERROR nt_printer_guid_store(struct messaging_context *msg_ctx,
838 const char *printer, struct GUID guid)
840 return WERR_NOT_SUPPORTED;
843 WERROR nt_printer_guid_retrieve(TALLOC_CTX *mem_ctx, const char *printer,
844 struct GUID *pguid)
846 return WERR_NOT_SUPPORTED;
849 WERROR nt_printer_guid_get(TALLOC_CTX *mem_ctx,
850 const struct auth_session_info *session_info,
851 struct messaging_context *msg_ctx,
852 const char *printer, struct GUID *guid)
854 return WERR_NOT_SUPPORTED;
857 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
858 const struct auth_session_info *session_info,
859 struct messaging_context *msg_ctx,
860 struct spoolss_PrinterInfo2 *pinfo2,
861 int action)
863 return WERR_OK;
866 WERROR check_published_printers(struct messaging_context *msg_ctx)
868 return WERR_OK;
871 bool is_printer_published(TALLOC_CTX *mem_ctx,
872 const struct auth_session_info *session_info,
873 struct messaging_context *msg_ctx,
874 const char *servername,
875 const char *printer,
876 struct spoolss_PrinterInfo2 **info2)
878 return False;
880 #endif /* HAVE_ADS */