libsmb: Use clistr_smb2_extract_snapshot_token() in cli_smb2_create_fnum_send()
[Samba.git] / source3 / printing / nt_printing_ads.c
blobff41baad5a2d111fd7af3cea56316664e353438d
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 = talloc_stackframe();
224 char *machine_password = NULL;
226 ads = ads_init(tmp_ctx,
227 lp_realm(),
228 lp_workgroup(),
229 NULL,
230 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 TALLOC_FREE(ads->auth.password);
239 machine_password = secrets_fetch_machine_password(lp_workgroup(),
240 NULL, NULL);
241 if (machine_password != NULL) {
242 ads->auth.password = talloc_strdup(ads, machine_password);
243 SAFE_FREE(machine_password);
244 if (ads->auth.password == NULL) {
245 result = WERR_NOT_ENOUGH_MEMORY;
246 goto out;
250 ads_status = ads_connect(ads);
251 if (!ADS_ERR_OK(ads_status)) {
252 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_status)));
253 result = WERR_ACCESS_DENIED;
254 goto out;
257 result = nt_printer_dn_lookup(tmp_ctx, ads, printer, &printer_dn);
258 if (!W_ERROR_IS_OK(result)) {
259 goto out;
262 result = nt_printer_guid_retrieve_internal(ads, printer_dn, pguid);
263 out:
264 TALLOC_FREE(tmp_ctx);
265 ads_kdestroy("MEMORY:prtpub_cache");
266 unsetenv(KRB5_ENV_CCNAME);
267 if (old_krb5ccname != NULL) {
268 setenv(KRB5_ENV_CCNAME, old_krb5ccname, 0);
271 return result;
274 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)
279 TALLOC_CTX *tmp_ctx;
280 enum winreg_Type type;
281 DATA_BLOB blob;
282 uint32_t len;
283 NTSTATUS status;
284 WERROR result;
286 tmp_ctx = talloc_new(mem_ctx);
287 if (tmp_ctx == NULL) {
288 DEBUG(0, ("out of memory?!\n"));
289 return WERR_NOT_ENOUGH_MEMORY;
292 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 if (!W_ERROR_IS_OK(result)) {
300 DEBUG(0, ("Failed to get GUID for printer %s\n", printer));
301 goto out_ctx_free;
303 blob.length = (size_t)len;
305 /* We used to store the guid as REG_BINARY, then swapped
306 to REG_SZ for Vista compatibility so check for both */
308 switch (type) {
309 case REG_SZ: {
310 bool ok;
311 const char *guid_str;
312 ok = pull_reg_sz(tmp_ctx, &blob, &guid_str);
313 if (!ok) {
314 DEBUG(0, ("Failed to unmarshall GUID for printer %s\n",
315 printer));
316 result = WERR_REGISTRY_CORRUPT;
317 goto out_ctx_free;
319 status = GUID_from_string(guid_str, guid);
320 if (!NT_STATUS_IS_OK(status)) {
321 DEBUG(0, ("bad GUID for printer %s\n", printer));
322 result = ntstatus_to_werror(status);
323 goto out_ctx_free;
325 break;
327 case REG_BINARY:
328 if (blob.length != sizeof(struct GUID)) {
329 DEBUG(0, ("bad GUID for printer %s\n", printer));
330 result = WERR_REGISTRY_CORRUPT;
331 goto out_ctx_free;
333 memcpy(guid, blob.data, sizeof(struct GUID));
334 break;
335 default:
336 DEBUG(0,("GUID value stored as invalid type (%d)\n", type));
337 result = WERR_REGISTRY_CORRUPT;
338 goto out_ctx_free;
339 break;
341 result = WERR_OK;
343 out_ctx_free:
344 talloc_free(tmp_ctx);
345 return result;
348 static WERROR nt_printer_devmode_to_mods(TALLOC_CTX *ctx,
349 struct spoolss_DeviceMode *devmode,
350 ADS_MODLIST *mods)
352 char *str = NULL;
353 ADS_STATUS status;
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
375 if (devmode->fields & DEVMODE_COLOR) {
376 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTCOLOR, "TRUE");
377 } else {
378 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTCOLOR, "FALSE");
380 if (!ADS_ERR_OK(status)) {
381 return WERR_NOT_ENOUGH_MEMORY;
384 if (devmode->fields & DEVMODE_DUPLEX) {
385 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTDUPLEXSUPPORTED, "TRUE");
386 } else {
387 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTDUPLEXSUPPORTED, "FALSE");
389 if (!ADS_ERR_OK(status)) {
390 return WERR_NOT_ENOUGH_MEMORY;
393 if (devmode->fields & DEVMODE_COLLATE) {
394 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTCOLLATE, "TRUE");
395 } else {
396 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTCOLLATE, "FALSE");
398 if (!ADS_ERR_OK(status)) {
399 return WERR_NOT_ENOUGH_MEMORY;
402 /* portrait mode is always supported, LANDSCAPE is optional */
403 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTORIENTATIONSSUPPORTED, "PORTRAIT");
404 if (!ADS_ERR_OK(status)) {
405 return WERR_NOT_ENOUGH_MEMORY;
407 if (devmode->fields & DEVMODE_ORIENTATION) {
408 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTORIENTATIONSSUPPORTED, "LANDSCAPE");
409 if (!ADS_ERR_OK(status)) {
410 return WERR_NOT_ENOUGH_MEMORY;
414 /* the driverVersion attribute in AD contains actually specversion */
415 str = talloc_asprintf(ctx, "%u", devmode->specversion);
416 if (str == NULL) {
417 return WERR_NOT_ENOUGH_MEMORY;
419 if (strlen(str) != 0) {
420 status = ads_mod_str(ctx, mods, SPOOL_REG_DRIVERVERSION, str);
421 if (!ADS_ERR_OK(status)) {
422 return WERR_NOT_ENOUGH_MEMORY;
426 /* devmode->yresolution is a good candidate for printMaxResolutionSupported */
427 str = talloc_asprintf(ctx, "%u", devmode->yresolution);
428 if (str == NULL) {
429 return WERR_NOT_ENOUGH_MEMORY;
431 if (strlen(str) != 0) {
432 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTMAXRESOLUTIONSUPPORTED, str);
433 if (!ADS_ERR_OK(status)) {
434 return WERR_NOT_ENOUGH_MEMORY;
438 return WERR_OK;
443 static WERROR nt_printer_info_to_mods(TALLOC_CTX *ctx,
444 struct spoolss_PrinterInfo2 *info2,
445 ADS_MODLIST *mods)
447 char *info_str;
449 ads_mod_str(ctx, mods, SPOOL_REG_PRINTERNAME, info2->sharename);
450 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSHARENAME, info2->sharename);
451 ads_mod_str(ctx, mods, SPOOL_REG_SHORTSERVERNAME, lp_netbios_name());
452 ads_mod_str(ctx, mods, SPOOL_REG_SERVERNAME, get_mydnsfullname());
454 info_str = talloc_asprintf(ctx, "\\\\%s\\%s",
455 get_mydnsfullname(), info2->sharename);
456 if (info_str == NULL) {
457 return WERR_NOT_ENOUGH_MEMORY;
459 ads_mod_str(ctx, mods, SPOOL_REG_UNCNAME, info_str);
461 info_str = talloc_asprintf(ctx, "%d", 4);
462 if (info_str == NULL) {
463 return WERR_NOT_ENOUGH_MEMORY;
465 ads_mod_str(ctx, mods, SPOOL_REG_VERSIONNUMBER, info_str);
467 /* empty strings in the mods list result in an attrubute error */
468 if (strlen(info2->drivername) != 0)
469 ads_mod_str(ctx, mods, SPOOL_REG_DRIVERNAME, info2->drivername);
470 if (strlen(info2->location) != 0)
471 ads_mod_str(ctx, mods, SPOOL_REG_LOCATION, info2->location);
472 if (strlen(info2->comment) != 0)
473 ads_mod_str(ctx, mods, SPOOL_REG_DESCRIPTION, info2->comment);
474 if (strlen(info2->portname) != 0)
475 ads_mod_str(ctx, mods, SPOOL_REG_PORTNAME, info2->portname);
476 if (strlen(info2->sepfile) != 0)
477 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSEPARATORFILE, info2->sepfile);
479 info_str = talloc_asprintf(ctx, "%u", info2->starttime);
480 if (info_str == NULL) {
481 return WERR_NOT_ENOUGH_MEMORY;
483 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSTARTTIME, info_str);
485 info_str = talloc_asprintf(ctx, "%u", info2->untiltime);
486 if (info_str == NULL) {
487 return WERR_NOT_ENOUGH_MEMORY;
489 ads_mod_str(ctx, mods, SPOOL_REG_PRINTENDTIME, info_str);
491 info_str = talloc_asprintf(ctx, "%u", info2->priority);
492 if (info_str == NULL) {
493 return WERR_NOT_ENOUGH_MEMORY;
495 ads_mod_str(ctx, mods, SPOOL_REG_PRIORITY, info_str);
497 if (info2->attributes & PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS) {
498 ads_mod_str(ctx, mods, SPOOL_REG_PRINTKEEPPRINTEDJOBS, "TRUE");
499 } else {
500 ads_mod_str(ctx, mods, SPOOL_REG_PRINTKEEPPRINTEDJOBS, "FALSE");
503 switch (info2->attributes & 0x3) {
504 case 0:
505 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
506 SPOOL_REGVAL_PRINTWHILESPOOLING);
507 break;
508 case 1:
509 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
510 SPOOL_REGVAL_PRINTAFTERSPOOLED);
511 break;
512 case 2:
513 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
514 SPOOL_REGVAL_PRINTDIRECT);
515 break;
516 default:
517 DEBUG(3, ("unsupported printer attributes %x\n",
518 info2->attributes));
521 if (info2->devmode != NULL) {
522 WERROR werr;
523 werr = nt_printer_devmode_to_mods(ctx, info2->devmode, mods);
524 if (!W_ERROR_IS_OK(werr)) {
525 return werr;
529 return WERR_OK;
532 static WERROR nt_printer_publish_ads(struct messaging_context *msg_ctx,
533 ADS_STRUCT *ads,
534 struct spoolss_PrinterInfo2 *pinfo2)
536 ADS_STATUS ads_rc;
537 TALLOC_CTX *ctx = talloc_stackframe();
538 ADS_MODLIST mods;
539 struct GUID guid;
540 WERROR win_rc = WERR_OK;
541 const char *printer = pinfo2->sharename;
542 char *printer_dn = NULL;
544 /* build the ads mods */
545 DEBUG(5, ("publishing printer %s\n", printer));
547 win_rc = nt_printer_dn_lookup(ctx, ads, printer, &printer_dn);
548 if (!W_ERROR_IS_OK(win_rc)) {
549 DEBUG(2, ("Failed to create printer dn\n"));
550 TALLOC_FREE(ctx);
551 return win_rc;
554 mods = ads_init_mods(ctx);
556 if (mods == NULL) {
557 TALLOC_FREE(ctx);
558 return WERR_NOT_ENOUGH_MEMORY;
561 win_rc = nt_printer_info_to_mods(ctx, pinfo2, &mods);
562 if (!W_ERROR_IS_OK(win_rc)) {
563 TALLOC_FREE(ctx);
564 return win_rc;
567 /* publish it */
568 ads_rc = ads_mod_printer_entry(ads, printer_dn, ctx, &mods);
569 if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT) {
570 int i;
571 for (i=0; mods[i] != 0; i++)
573 mods[i] = (LDAPMod *)-1;
574 ads_rc = ads_add_printer_entry(ads, printer_dn, ctx, &mods);
577 if (!ADS_ERR_OK(ads_rc)) {
578 DEBUG(3, ("error publishing %s: %s\n",
579 printer, ads_errstr(ads_rc)));
580 /* XXX failed to publish, so no guid to retrieve */
583 win_rc = nt_printer_guid_retrieve_internal(ads, printer_dn, &guid);
584 if (!W_ERROR_IS_OK(win_rc)) {
585 TALLOC_FREE(ctx);
586 return win_rc;
589 win_rc = nt_printer_guid_store(msg_ctx, printer, guid);
590 if (!W_ERROR_IS_OK(win_rc)) {
591 DEBUG(3, ("failed to store printer %s guid\n",
592 printer));
593 /* not catastrophic, retrieve on next use */
594 win_rc = WERR_OK;
597 TALLOC_FREE(ctx);
599 return win_rc;
602 static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
603 const char *printer)
605 ADS_STATUS ads_rc;
606 LDAPMessage *res = NULL;
607 char *prt_dn = NULL;
609 DEBUG(5, ("unpublishing printer %s\n", printer));
611 /* remove the printer from the directory */
612 ads_rc = ads_find_printer_on_server(ads, &res,
613 printer, lp_netbios_name());
615 if (ADS_ERR_OK(ads_rc) && res && ads_count_replies(ads, res)) {
616 prt_dn = ads_get_dn(ads, talloc_tos(), res);
617 if (!prt_dn) {
618 ads_msgfree(ads, res);
619 return WERR_NOT_ENOUGH_MEMORY;
621 ads_rc = ads_del_dn(ads, prt_dn);
622 TALLOC_FREE(prt_dn);
625 if (res) {
626 ads_msgfree(ads, res);
628 return WERR_OK;
631 /****************************************************************************
632 * Publish a printer in the directory
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 ***************************************************************************/
641 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)
647 TALLOC_CTX *tmp_ctx = talloc_stackframe();
648 uint32_t info2_mask = SPOOLSS_PRINTER_INFO_ATTRIBUTES;
649 struct spoolss_SetPrinterInfo2 *sinfo2;
650 ADS_STATUS ads_rc;
651 ADS_STRUCT *ads = NULL;
652 WERROR win_rc;
653 char *old_krb5ccname = NULL;
654 char *machine_password = NULL;
656 sinfo2 = talloc_zero(tmp_ctx, struct spoolss_SetPrinterInfo2);
657 if (!sinfo2) {
658 win_rc = WERR_NOT_ENOUGH_MEMORY;
659 goto done;
662 switch (action) {
663 case DSPRINT_PUBLISH:
664 case DSPRINT_UPDATE:
665 pinfo2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
666 break;
667 case DSPRINT_UNPUBLISH:
668 pinfo2->attributes &= (~PRINTER_ATTRIBUTE_PUBLISHED);
669 break;
670 default:
671 win_rc = WERR_NOT_SUPPORTED;
672 goto done;
675 sinfo2->attributes = pinfo2->attributes;
677 win_rc = winreg_update_printer_internal(tmp_ctx, session_info, msg_ctx,
678 pinfo2->sharename, info2_mask,
679 sinfo2, NULL, NULL);
680 if (!W_ERROR_IS_OK(win_rc)) {
681 DBG_NOTICE("Failed to update data for printer [%s] - %s\n",
682 pinfo2->sharename,
683 win_errstr(win_rc));
684 goto done;
687 TALLOC_FREE(sinfo2);
689 ads = ads_init(tmp_ctx,
690 lp_realm(),
691 lp_workgroup(),
692 NULL,
693 ADS_SASL_PLAIN);
694 if (!ads) {
695 DEBUG(3, ("ads_init() failed\n"));
696 win_rc = WERR_RPC_S_SERVER_UNAVAILABLE;
697 goto done;
699 old_krb5ccname = getenv(KRB5_ENV_CCNAME);
700 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
701 TALLOC_FREE(ads->auth.password);
702 machine_password = secrets_fetch_machine_password(lp_workgroup(),
703 NULL, NULL);
704 if (machine_password != NULL) {
705 ads->auth.password = talloc_strdup(ads, machine_password);
706 SAFE_FREE(machine_password);
707 if (ads->auth.password == NULL) {
708 win_rc = WERR_NOT_ENOUGH_MEMORY;
709 goto done;
713 /* ads_connect() will find the DC for us */
714 ads_rc = ads_connect(ads);
715 if (!ADS_ERR_OK(ads_rc)) {
716 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
717 win_rc = WERR_ACCESS_DENIED;
718 goto done;
721 switch (action) {
722 case DSPRINT_PUBLISH:
723 case DSPRINT_UPDATE:
724 win_rc = nt_printer_publish_ads(msg_ctx, ads, pinfo2);
725 break;
726 case DSPRINT_UNPUBLISH:
727 win_rc = nt_printer_unpublish_ads(ads, pinfo2->sharename);
728 break;
731 done:
732 ads_kdestroy("MEMORY:prtpub_cache");
733 unsetenv(KRB5_ENV_CCNAME);
734 if (old_krb5ccname) {
735 setenv(KRB5_ENV_CCNAME, old_krb5ccname, 0);
738 TALLOC_FREE(tmp_ctx);
740 return win_rc;
743 WERROR check_published_printers(struct messaging_context *msg_ctx)
745 const struct loadparm_substitution *lp_sub =
746 loadparm_s3_global_substitution();
747 ADS_STATUS ads_rc;
748 ADS_STRUCT *ads = NULL;
749 int snum;
750 int n_services = lp_numservices();
751 TALLOC_CTX *tmp_ctx = talloc_stackframe();
752 struct auth_session_info *session_info = NULL;
753 struct spoolss_PrinterInfo2 *pinfo2;
754 NTSTATUS status;
755 WERROR result;
756 char *old_krb5ccname = NULL;
757 char *machine_password = NULL;
759 ads = ads_init(tmp_ctx,
760 lp_realm(),
761 lp_workgroup(),
762 NULL,
763 ADS_SASL_PLAIN);
764 if (!ads) {
765 DEBUG(3, ("ads_init() failed\n"));
766 TALLOC_FREE(tmp_ctx);
767 return WERR_RPC_S_SERVER_UNAVAILABLE;
769 old_krb5ccname = getenv(KRB5_ENV_CCNAME);
770 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
771 TALLOC_FREE(ads->auth.password);
772 machine_password = secrets_fetch_machine_password(lp_workgroup(),
773 NULL, NULL);
774 if (machine_password != NULL) {
775 ads->auth.password = talloc_strdup(ads, machine_password);
776 SAFE_FREE(machine_password);
777 if (ads->auth.password == NULL) {
778 result = WERR_NOT_ENOUGH_MEMORY;
779 goto done;
782 /* ads_connect() will find the DC for us */
783 ads_rc = ads_connect(ads);
784 if (!ADS_ERR_OK(ads_rc)) {
785 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
786 result = WERR_ACCESS_DENIED;
787 goto done;
790 status = make_session_info_system(tmp_ctx, &session_info);
791 if (!NT_STATUS_IS_OK(status)) {
792 DEBUG(0, ("check_published_printers: "
793 "Could not create system session_info\n"));
794 result = WERR_ACCESS_DENIED;
795 goto done;
798 for (snum = 0; snum < n_services; snum++) {
799 if (!lp_snum_ok(snum) || !lp_printable(snum)) {
800 continue;
803 result = winreg_get_printer_internal(tmp_ctx, session_info, msg_ctx,
804 lp_servicename(talloc_tos(), lp_sub, snum),
805 &pinfo2);
806 if (!W_ERROR_IS_OK(result)) {
807 continue;
810 if (pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
811 nt_printer_publish_ads(msg_ctx, ads, pinfo2);
814 TALLOC_FREE(pinfo2);
817 result = WERR_OK;
818 done:
819 ads_kdestroy("MEMORY:prtpub_cache");
820 unsetenv(KRB5_ENV_CCNAME);
821 if (old_krb5ccname) {
822 setenv(KRB5_ENV_CCNAME, old_krb5ccname, 0);
824 talloc_free(tmp_ctx);
825 return result;
828 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)
835 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
836 WERROR result;
837 struct dcerpc_binding_handle *b;
839 result = winreg_printer_binding_handle(mem_ctx,
840 session_info,
841 msg_ctx,
842 &b);
843 if (!W_ERROR_IS_OK(result)) {
844 return false;
847 result = winreg_get_printer(mem_ctx, b,
848 printer, &pinfo2);
849 if (!W_ERROR_IS_OK(result)) {
850 return false;
853 if (!(pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
854 TALLOC_FREE(pinfo2);
855 return false;
858 if (info2) {
859 *info2 = talloc_move(mem_ctx, &pinfo2);
861 talloc_free(pinfo2);
862 return true;
864 #else
865 WERROR nt_printer_guid_store(struct messaging_context *msg_ctx,
866 const char *printer, struct GUID guid)
868 return WERR_NOT_SUPPORTED;
871 WERROR nt_printer_guid_retrieve(TALLOC_CTX *mem_ctx, const char *printer,
872 struct GUID *pguid)
874 return WERR_NOT_SUPPORTED;
877 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)
882 return WERR_NOT_SUPPORTED;
885 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)
891 return WERR_OK;
894 WERROR check_published_printers(struct messaging_context *msg_ctx)
896 return WERR_OK;
899 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)
906 return False;
908 #endif /* HAVE_ADS */