diff options
Diffstat (limited to 'source3/printing/nt_printing_ads.c')
-rw-r--r-- | source3/printing/nt_printing_ads.c | 908 |
1 files changed, 908 insertions, 0 deletions
diff --git a/source3/printing/nt_printing_ads.c b/source3/printing/nt_printing_ads.c new file mode 100644 index 0000000..4d5991e --- /dev/null +++ b/source3/printing/nt_printing_ads.c @@ -0,0 +1,908 @@ +/* + * Unix SMB/CIFS implementation. + * RPC Pipe client / server routines + * Copyright (C) Andrew Tridgell 1992-2000, + * Copyright (C) Jean François Micouleau 1998-2000. + * Copyright (C) Gerald Carter 2002-2005. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "includes.h" +#include "../librpc/gen_ndr/spoolss.h" +#include "rpc_server/spoolss/srv_spoolss_util.h" +#include "nt_printing.h" +#include "ads.h" +#include "secrets.h" +#include "krb5_env.h" +#include "../libcli/registry/util_reg.h" +#include "auth.h" +#include "../librpc/ndr/libndr.h" +#include "rpc_client/cli_winreg_spoolss.h" + +#ifdef HAVE_ADS +/***************************************************************** + ****************************************************************/ + +WERROR nt_printer_guid_store(struct messaging_context *msg_ctx, + const char *printer, struct GUID guid) +{ + TALLOC_CTX *tmp_ctx; + const struct auth_session_info *session_info; + const char *guid_str; + DATA_BLOB blob; + WERROR result; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) { + DEBUG(0, ("Out of memory?!\n")); + return WERR_NOT_ENOUGH_MEMORY; + } + + session_info = get_session_info_system(); + if (session_info == NULL) { + DEBUG(0, ("Could not get system session_info\n")); + result = WERR_NOT_ENOUGH_MEMORY; + goto done; + } + + guid_str = GUID_string(tmp_ctx, &guid); + if (!guid_str) { + DEBUG(0, ("Out of memory?!\n")); + result = WERR_NOT_ENOUGH_MEMORY; + goto done; + } + + /* We used to store this as a REG_BINARY but that causes + Vista to whine */ + + if (!push_reg_sz(tmp_ctx, &blob, guid_str)) { + DEBUG(0, ("Could not marshall string %s for objectGUID\n", + guid_str)); + result = WERR_NOT_ENOUGH_MEMORY; + goto done; + } + + result = winreg_set_printer_dataex_internal(tmp_ctx, session_info, msg_ctx, + printer, + SPOOL_DSSPOOLER_KEY, "objectGUID", + REG_SZ, blob.data, blob.length); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("Failed to store GUID for printer %s\n", printer)); + goto done; + } + + result = WERR_OK; +done: + talloc_free(tmp_ctx); + + return result; +} + +static WERROR nt_printer_dn_lookup(TALLOC_CTX *mem_ctx, + ADS_STRUCT *ads, + const char *printer, + char **pprinter_dn) +{ + char *printer_dn = NULL; + char *srv_dn = NULL; + char *srv_cn_0 = NULL; + char *srv_cn_escaped = NULL; + char *sharename_escaped = NULL; + char *srv_dn_utf8 = NULL; + char **srv_cn_utf8 = NULL; + size_t converted_size; + ADS_STATUS ads_status; + LDAPMessage *res; + WERROR result; + bool ok; + + ads_status = ads_find_machine_acct(ads, &res, lp_netbios_name()); + if (!ADS_ERR_OK(ads_status)) { + DEBUG(2, ("Failed to find machine account for %s\n", + lp_netbios_name())); + result = WERR_NOT_FOUND; + goto err_out; + } + + /* + * We use ldap_get_dn here as we need the answer in utf8 to call + * ldap_explode_dn(). JRA. + */ + srv_dn_utf8 = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res); + ads_msgfree(ads, res); + if (srv_dn_utf8 == NULL) { + result = WERR_RPC_S_SERVER_UNAVAILABLE; + goto err_out; + } + + srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1); + if (srv_cn_utf8 == NULL) { + ldap_memfree(srv_dn_utf8); + result = WERR_RPC_S_SERVER_UNAVAILABLE; + goto err_out; + } + + /* Now convert to CH_UNIX. */ + ok = pull_utf8_talloc(mem_ctx, &srv_dn, srv_dn_utf8, &converted_size); + ldap_memfree(srv_dn_utf8); + if (!ok) { + ldap_memfree(srv_cn_utf8); + result = WERR_RPC_S_SERVER_UNAVAILABLE; + goto err_out; + } + + ok = pull_utf8_talloc(mem_ctx, &srv_cn_0, srv_cn_utf8[0], &converted_size); + ldap_memfree(srv_cn_utf8); + if (!ok) { + result = WERR_RPC_S_SERVER_UNAVAILABLE; + goto err_out; + } + + srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0); + if (srv_cn_escaped == NULL) { + result = WERR_RPC_S_SERVER_UNAVAILABLE; + goto err_out; + } + + sharename_escaped = escape_rdn_val_string_alloc(printer); + if (sharename_escaped == NULL) { + result = WERR_RPC_S_SERVER_UNAVAILABLE; + goto err_out; + } + + printer_dn = talloc_asprintf(mem_ctx, + "cn=%s-%s,%s", + srv_cn_escaped, + sharename_escaped, + srv_dn); + if (printer_dn == NULL) { + result = WERR_NOT_ENOUGH_MEMORY; + goto err_out; + } + + *pprinter_dn = printer_dn; + + result = WERR_OK; +err_out: + SAFE_FREE(sharename_escaped); + SAFE_FREE(srv_cn_escaped); + TALLOC_FREE(srv_cn_0); + TALLOC_FREE(srv_dn); + return result; +} + +static WERROR nt_printer_guid_retrieve_internal(ADS_STRUCT *ads, + const char *printer_dn, + struct GUID *pguid) +{ + ADS_STATUS ads_status; + LDAPMessage *res; + const char *attrs[] = {"objectGUID", NULL}; + struct GUID guid; + bool ok; + + ads_status = ads_search_dn(ads, &res, printer_dn, attrs); + if (!ADS_ERR_OK(ads_status)) { + DEBUG(2, ("Failed to retrieve GUID from DC - %s\n", + ads_errstr(ads_status))); + return WERR_FILE_NOT_FOUND; + } + + ZERO_STRUCT(guid); + ok = ads_pull_guid(ads, res, &guid); + ads_msgfree(ads, res); + if (!ok) { + return WERR_NOT_ENOUGH_MEMORY; + } + + *pguid = guid; + + return WERR_OK; +} + +WERROR nt_printer_guid_retrieve(TALLOC_CTX *mem_ctx, const char *printer, + struct GUID *pguid) +{ + ADS_STRUCT *ads = NULL; + char *old_krb5ccname = NULL; + char *printer_dn; + WERROR result; + ADS_STATUS ads_status; + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + char *machine_password = NULL; + + ads = ads_init(tmp_ctx, + lp_realm(), + lp_workgroup(), + NULL, + ADS_SASL_PLAIN); + if (ads == NULL) { + result = WERR_RPC_S_SERVER_UNAVAILABLE; + goto out; + } + + old_krb5ccname = getenv(KRB5_ENV_CCNAME); + setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1); + ADS_TALLOC_CONST_FREE(ads->auth.password); + machine_password = secrets_fetch_machine_password(lp_workgroup(), + NULL, NULL); + if (machine_password != NULL) { + ads->auth.password = talloc_strdup(ads, machine_password); + SAFE_FREE(machine_password); + if (ads->auth.password == NULL) { + result = WERR_NOT_ENOUGH_MEMORY; + goto out; + } + } + + ads_status = ads_connect(ads); + if (!ADS_ERR_OK(ads_status)) { + DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_status))); + result = WERR_ACCESS_DENIED; + goto out; + } + + result = nt_printer_dn_lookup(tmp_ctx, ads, printer, &printer_dn); + if (!W_ERROR_IS_OK(result)) { + goto out; + } + + result = nt_printer_guid_retrieve_internal(ads, printer_dn, pguid); +out: + TALLOC_FREE(tmp_ctx); + ads_kdestroy("MEMORY:prtpub_cache"); + unsetenv(KRB5_ENV_CCNAME); + if (old_krb5ccname != NULL) { + setenv(KRB5_ENV_CCNAME, old_krb5ccname, 0); + } + + return result; +} + +WERROR nt_printer_guid_get(TALLOC_CTX *mem_ctx, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, + const char *printer, struct GUID *guid) +{ + TALLOC_CTX *tmp_ctx; + enum winreg_Type type; + DATA_BLOB blob; + uint32_t len; + NTSTATUS status; + WERROR result; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + DEBUG(0, ("out of memory?!\n")); + return WERR_NOT_ENOUGH_MEMORY; + } + + result = winreg_get_printer_dataex_internal(tmp_ctx, session_info, + msg_ctx, printer, + SPOOL_DSSPOOLER_KEY, + "objectGUID", + &type, + &blob.data, + &len); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("Failed to get GUID for printer %s\n", printer)); + goto out_ctx_free; + } + blob.length = (size_t)len; + + /* We used to store the guid as REG_BINARY, then swapped + to REG_SZ for Vista compatibility so check for both */ + + switch (type) { + case REG_SZ: { + bool ok; + const char *guid_str; + ok = pull_reg_sz(tmp_ctx, &blob, &guid_str); + if (!ok) { + DEBUG(0, ("Failed to unmarshall GUID for printer %s\n", + printer)); + result = WERR_REGISTRY_CORRUPT; + goto out_ctx_free; + } + status = GUID_from_string(guid_str, guid); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("bad GUID for printer %s\n", printer)); + result = ntstatus_to_werror(status); + goto out_ctx_free; + } + break; + } + case REG_BINARY: + if (blob.length != sizeof(struct GUID)) { + DEBUG(0, ("bad GUID for printer %s\n", printer)); + result = WERR_REGISTRY_CORRUPT; + goto out_ctx_free; + } + memcpy(guid, blob.data, sizeof(struct GUID)); + break; + default: + DEBUG(0,("GUID value stored as invalid type (%d)\n", type)); + result = WERR_REGISTRY_CORRUPT; + goto out_ctx_free; + break; + } + result = WERR_OK; + +out_ctx_free: + talloc_free(tmp_ctx); + return result; +} + +static WERROR nt_printer_devmode_to_mods(TALLOC_CTX *ctx, + struct spoolss_DeviceMode *devmode, + ADS_MODLIST *mods) +{ + char *str = NULL; + ADS_STATUS status; + + /* + the device mode fields bits allow us to make an educated guess if a + printer feature is supported. For sure a feature must be unsupported if + the fields bit is not set. Device Mode Extra Data and FeatureOptionPairs + might help to figure out more information here. Common attributes, that + we can't handle yet: + SPOOL_REG_PRINTBINNAMES - printBinNames + SPOOL_REG_PRINTMAXXEXTENT - printMaxXExtent + SPOOL_REG_PRINTMAXYEXTENT - printMaxYExtent + SPOOL_REG_PRINTMINXEXTENT - printMinXExtent + SPOOL_REG_PRINTMINYEXTENT - printMinYExtent + SPOOL_REG_PRINTSTAPLINGSUPPORTED - printStaplingSupported + SPOOL_REG_PRINTPAGESPERMINUTE - printPagesPerMinute + SPOOL_REG_PRINTRATE - printRate + SPOOL_REG_PRINTRATEUNIT - printRateUnit + SPOOL_REG_PRINTMEDIAREADY - printMediaReady + SPOOL_REG_PRINTMEDIASUPPORTED - printMediaSupported + SPOOL_REG_PRINTNUMBERUP - printNumberUp + SPOOL_REG_PRINTMAXCOPIES - printMaxCopies + */ + if (devmode->fields & DEVMODE_COLOR) { + status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTCOLOR, "TRUE"); + } else { + status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTCOLOR, "FALSE"); + } + if (!ADS_ERR_OK(status)) { + return WERR_NOT_ENOUGH_MEMORY; + } + + if (devmode->fields & DEVMODE_DUPLEX) { + status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTDUPLEXSUPPORTED, "TRUE"); + } else { + status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTDUPLEXSUPPORTED, "FALSE"); + } + if (!ADS_ERR_OK(status)) { + return WERR_NOT_ENOUGH_MEMORY; + } + + if (devmode->fields & DEVMODE_COLLATE) { + status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTCOLLATE, "TRUE"); + } else { + status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTCOLLATE, "FALSE"); + } + if (!ADS_ERR_OK(status)) { + return WERR_NOT_ENOUGH_MEMORY; + } + + /* portrait mode is always supported, LANDSCAPE is optional */ + status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTORIENTATIONSSUPPORTED, "PORTRAIT"); + if (!ADS_ERR_OK(status)) { + return WERR_NOT_ENOUGH_MEMORY; + } + if (devmode->fields & DEVMODE_ORIENTATION) { + status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTORIENTATIONSSUPPORTED, "LANDSCAPE"); + if (!ADS_ERR_OK(status)) { + return WERR_NOT_ENOUGH_MEMORY; + } + } + + /* the driverVersion attribute in AD contains actually specversion */ + str = talloc_asprintf(ctx, "%u", devmode->specversion); + if (str == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + if (strlen(str) != 0) { + status = ads_mod_str(ctx, mods, SPOOL_REG_DRIVERVERSION, str); + if (!ADS_ERR_OK(status)) { + return WERR_NOT_ENOUGH_MEMORY; + } + } + + /* devmode->yresolution is a good candidate for printMaxResolutionSupported */ + str = talloc_asprintf(ctx, "%u", devmode->yresolution); + if (str == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + if (strlen(str) != 0) { + status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTMAXRESOLUTIONSUPPORTED, str); + if (!ADS_ERR_OK(status)) { + return WERR_NOT_ENOUGH_MEMORY; + } + } + + return WERR_OK; +} + + + +static WERROR nt_printer_info_to_mods(TALLOC_CTX *ctx, + struct spoolss_PrinterInfo2 *info2, + ADS_MODLIST *mods) +{ + char *info_str; + + ads_mod_str(ctx, mods, SPOOL_REG_PRINTERNAME, info2->sharename); + ads_mod_str(ctx, mods, SPOOL_REG_PRINTSHARENAME, info2->sharename); + ads_mod_str(ctx, mods, SPOOL_REG_SHORTSERVERNAME, lp_netbios_name()); + ads_mod_str(ctx, mods, SPOOL_REG_SERVERNAME, get_mydnsfullname()); + + info_str = talloc_asprintf(ctx, "\\\\%s\\%s", + get_mydnsfullname(), info2->sharename); + if (info_str == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + ads_mod_str(ctx, mods, SPOOL_REG_UNCNAME, info_str); + + info_str = talloc_asprintf(ctx, "%d", 4); + if (info_str == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + ads_mod_str(ctx, mods, SPOOL_REG_VERSIONNUMBER, info_str); + + /* empty strings in the mods list result in an attribute error */ + if (strlen(info2->drivername) != 0) + ads_mod_str(ctx, mods, SPOOL_REG_DRIVERNAME, info2->drivername); + if (strlen(info2->location) != 0) + ads_mod_str(ctx, mods, SPOOL_REG_LOCATION, info2->location); + if (strlen(info2->comment) != 0) + ads_mod_str(ctx, mods, SPOOL_REG_DESCRIPTION, info2->comment); + if (strlen(info2->portname) != 0) + ads_mod_str(ctx, mods, SPOOL_REG_PORTNAME, info2->portname); + if (strlen(info2->sepfile) != 0) + ads_mod_str(ctx, mods, SPOOL_REG_PRINTSEPARATORFILE, info2->sepfile); + + info_str = talloc_asprintf(ctx, "%u", info2->starttime); + if (info_str == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + ads_mod_str(ctx, mods, SPOOL_REG_PRINTSTARTTIME, info_str); + + info_str = talloc_asprintf(ctx, "%u", info2->untiltime); + if (info_str == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + ads_mod_str(ctx, mods, SPOOL_REG_PRINTENDTIME, info_str); + + info_str = talloc_asprintf(ctx, "%u", info2->priority); + if (info_str == NULL) { + return WERR_NOT_ENOUGH_MEMORY; + } + ads_mod_str(ctx, mods, SPOOL_REG_PRIORITY, info_str); + + if (info2->attributes & PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS) { + ads_mod_str(ctx, mods, SPOOL_REG_PRINTKEEPPRINTEDJOBS, "TRUE"); + } else { + ads_mod_str(ctx, mods, SPOOL_REG_PRINTKEEPPRINTEDJOBS, "FALSE"); + } + + switch (info2->attributes & 0x3) { + case 0: + ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING, + SPOOL_REGVAL_PRINTWHILESPOOLING); + break; + case 1: + ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING, + SPOOL_REGVAL_PRINTAFTERSPOOLED); + break; + case 2: + ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING, + SPOOL_REGVAL_PRINTDIRECT); + break; + default: + DEBUG(3, ("unsupported printer attributes %x\n", + info2->attributes)); + } + + if (info2->devmode != NULL) { + WERROR werr; + werr = nt_printer_devmode_to_mods(ctx, info2->devmode, mods); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + } + + return WERR_OK; +} + +static WERROR nt_printer_publish_ads(struct messaging_context *msg_ctx, + ADS_STRUCT *ads, + struct spoolss_PrinterInfo2 *pinfo2) +{ + ADS_STATUS ads_rc; + TALLOC_CTX *ctx = talloc_stackframe(); + ADS_MODLIST mods; + struct GUID guid; + WERROR win_rc = WERR_OK; + const char *printer = pinfo2->sharename; + char *printer_dn = NULL; + + /* build the ads mods */ + DEBUG(5, ("publishing printer %s\n", printer)); + + win_rc = nt_printer_dn_lookup(ctx, ads, printer, &printer_dn); + if (!W_ERROR_IS_OK(win_rc)) { + DEBUG(2, ("Failed to create printer dn\n")); + TALLOC_FREE(ctx); + return win_rc; + } + + mods = ads_init_mods(ctx); + + if (mods == NULL) { + TALLOC_FREE(ctx); + return WERR_NOT_ENOUGH_MEMORY; + } + + win_rc = nt_printer_info_to_mods(ctx, pinfo2, &mods); + if (!W_ERROR_IS_OK(win_rc)) { + TALLOC_FREE(ctx); + return win_rc; + } + + /* publish it */ + ads_rc = ads_mod_printer_entry(ads, printer_dn, ctx, &mods); + if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT) { + int i; + for (i=0; mods[i] != 0; i++) + ; + mods[i] = (LDAPMod *)-1; + ads_rc = ads_add_printer_entry(ads, printer_dn, ctx, &mods); + } + + if (!ADS_ERR_OK(ads_rc)) { + DEBUG(3, ("error publishing %s: %s\n", + printer, ads_errstr(ads_rc))); + /* XXX failed to publish, so no guid to retrieve */ + } + + win_rc = nt_printer_guid_retrieve_internal(ads, printer_dn, &guid); + if (!W_ERROR_IS_OK(win_rc)) { + TALLOC_FREE(ctx); + return win_rc; + } + + win_rc = nt_printer_guid_store(msg_ctx, printer, guid); + if (!W_ERROR_IS_OK(win_rc)) { + DEBUG(3, ("failed to store printer %s guid\n", + printer)); + /* not catastrophic, retrieve on next use */ + win_rc = WERR_OK; + } + + TALLOC_FREE(ctx); + + return win_rc; +} + +static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads, + const char *printer) +{ + ADS_STATUS ads_rc; + LDAPMessage *res = NULL; + char *prt_dn = NULL; + + DEBUG(5, ("unpublishing printer %s\n", printer)); + + /* remove the printer from the directory */ + ads_rc = ads_find_printer_on_server(ads, &res, + printer, lp_netbios_name()); + + if (ADS_ERR_OK(ads_rc) && res && ads_count_replies(ads, res)) { + prt_dn = ads_get_dn(ads, talloc_tos(), res); + if (!prt_dn) { + ads_msgfree(ads, res); + return WERR_NOT_ENOUGH_MEMORY; + } + ads_rc = ads_del_dn(ads, prt_dn); + TALLOC_FREE(prt_dn); + } + + if (res) { + ads_msgfree(ads, res); + } + return WERR_OK; +} + +/**************************************************************************** + * Publish a printer in the directory + * + * @param mem_ctx memory context + * @param session_info session_info to access winreg pipe + * @param pinfo2 printer information + * @param action publish/unpublish action + * @return WERROR indicating status of publishing + ***************************************************************************/ + +WERROR nt_printer_publish(TALLOC_CTX *mem_ctx, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, + struct spoolss_PrinterInfo2 *pinfo2, + int action) +{ + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + uint32_t info2_mask = SPOOLSS_PRINTER_INFO_ATTRIBUTES; + struct spoolss_SetPrinterInfo2 *sinfo2; + ADS_STATUS ads_rc; + ADS_STRUCT *ads = NULL; + WERROR win_rc; + char *old_krb5ccname = NULL; + char *machine_password = NULL; + + sinfo2 = talloc_zero(tmp_ctx, struct spoolss_SetPrinterInfo2); + if (!sinfo2) { + win_rc = WERR_NOT_ENOUGH_MEMORY; + goto done; + } + + switch (action) { + case DSPRINT_PUBLISH: + case DSPRINT_UPDATE: + pinfo2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED; + break; + case DSPRINT_UNPUBLISH: + pinfo2->attributes &= (~PRINTER_ATTRIBUTE_PUBLISHED); + break; + default: + win_rc = WERR_NOT_SUPPORTED; + goto done; + } + + sinfo2->attributes = pinfo2->attributes; + + win_rc = winreg_update_printer_internal(tmp_ctx, session_info, msg_ctx, + pinfo2->sharename, info2_mask, + sinfo2, NULL, NULL); + if (!W_ERROR_IS_OK(win_rc)) { + DBG_NOTICE("Failed to update data for printer [%s] - %s\n", + pinfo2->sharename, + win_errstr(win_rc)); + goto done; + } + + TALLOC_FREE(sinfo2); + + ads = ads_init(tmp_ctx, + lp_realm(), + lp_workgroup(), + NULL, + ADS_SASL_PLAIN); + if (!ads) { + DEBUG(3, ("ads_init() failed\n")); + win_rc = WERR_RPC_S_SERVER_UNAVAILABLE; + goto done; + } + old_krb5ccname = getenv(KRB5_ENV_CCNAME); + setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1); + ADS_TALLOC_CONST_FREE(ads->auth.password); + machine_password = secrets_fetch_machine_password(lp_workgroup(), + NULL, NULL); + if (machine_password != NULL) { + ads->auth.password = talloc_strdup(ads, machine_password); + SAFE_FREE(machine_password); + if (ads->auth.password == NULL) { + win_rc = WERR_NOT_ENOUGH_MEMORY; + goto done; + } + } + + /* ads_connect() will find the DC for us */ + ads_rc = ads_connect(ads); + if (!ADS_ERR_OK(ads_rc)) { + DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc))); + win_rc = WERR_ACCESS_DENIED; + goto done; + } + + switch (action) { + case DSPRINT_PUBLISH: + case DSPRINT_UPDATE: + win_rc = nt_printer_publish_ads(msg_ctx, ads, pinfo2); + break; + case DSPRINT_UNPUBLISH: + win_rc = nt_printer_unpublish_ads(ads, pinfo2->sharename); + break; + } + +done: + ads_kdestroy("MEMORY:prtpub_cache"); + unsetenv(KRB5_ENV_CCNAME); + if (old_krb5ccname) { + setenv(KRB5_ENV_CCNAME, old_krb5ccname, 0); + } + + TALLOC_FREE(tmp_ctx); + + return win_rc; +} + +WERROR check_published_printers(struct messaging_context *msg_ctx) +{ + const struct loadparm_substitution *lp_sub = + loadparm_s3_global_substitution(); + ADS_STATUS ads_rc; + ADS_STRUCT *ads = NULL; + int snum; + int n_services = lp_numservices(); + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + struct auth_session_info *session_info = NULL; + struct spoolss_PrinterInfo2 *pinfo2; + NTSTATUS status; + WERROR result; + char *old_krb5ccname = NULL; + char *machine_password = NULL; + + ads = ads_init(tmp_ctx, + lp_realm(), + lp_workgroup(), + NULL, + ADS_SASL_PLAIN); + if (!ads) { + DEBUG(3, ("ads_init() failed\n")); + TALLOC_FREE(tmp_ctx); + return WERR_RPC_S_SERVER_UNAVAILABLE; + } + old_krb5ccname = getenv(KRB5_ENV_CCNAME); + setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1); + ADS_TALLOC_CONST_FREE(ads->auth.password); + machine_password = secrets_fetch_machine_password(lp_workgroup(), + NULL, NULL); + if (machine_password != NULL) { + ads->auth.password = talloc_strdup(ads, machine_password); + SAFE_FREE(machine_password); + if (ads->auth.password == NULL) { + result = WERR_NOT_ENOUGH_MEMORY; + goto done; + } + } + /* ads_connect() will find the DC for us */ + ads_rc = ads_connect(ads); + if (!ADS_ERR_OK(ads_rc)) { + DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc))); + result = WERR_ACCESS_DENIED; + goto done; + } + + status = make_session_info_system(tmp_ctx, &session_info); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("check_published_printers: " + "Could not create system session_info\n")); + result = WERR_ACCESS_DENIED; + goto done; + } + + for (snum = 0; snum < n_services; snum++) { + if (!lp_snum_ok(snum) || !lp_printable(snum)) { + continue; + } + + result = winreg_get_printer_internal(tmp_ctx, session_info, msg_ctx, + lp_servicename(talloc_tos(), lp_sub, snum), + &pinfo2); + if (!W_ERROR_IS_OK(result)) { + continue; + } + + if (pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) { + nt_printer_publish_ads(msg_ctx, ads, pinfo2); + } + + TALLOC_FREE(pinfo2); + } + + result = WERR_OK; +done: + ads_kdestroy("MEMORY:prtpub_cache"); + unsetenv(KRB5_ENV_CCNAME); + if (old_krb5ccname) { + setenv(KRB5_ENV_CCNAME, old_krb5ccname, 0); + } + talloc_free(tmp_ctx); + return result; +} + +bool is_printer_published(TALLOC_CTX *mem_ctx, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, + const char *servername, + const char *printer, + struct spoolss_PrinterInfo2 **info2) +{ + struct spoolss_PrinterInfo2 *pinfo2 = NULL; + WERROR result; + struct dcerpc_binding_handle *b; + + result = winreg_printer_binding_handle(mem_ctx, + session_info, + msg_ctx, + &b); + if (!W_ERROR_IS_OK(result)) { + return false; + } + + result = winreg_get_printer(mem_ctx, b, + printer, &pinfo2); + if (!W_ERROR_IS_OK(result)) { + return false; + } + + if (!(pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED)) { + TALLOC_FREE(pinfo2); + return false; + } + + if (info2) { + *info2 = talloc_move(mem_ctx, &pinfo2); + } + talloc_free(pinfo2); + return true; +} +#else +WERROR nt_printer_guid_store(struct messaging_context *msg_ctx, + const char *printer, struct GUID guid) +{ + return WERR_NOT_SUPPORTED; +} + +WERROR nt_printer_guid_retrieve(TALLOC_CTX *mem_ctx, const char *printer, + struct GUID *pguid) +{ + return WERR_NOT_SUPPORTED; +} + +WERROR nt_printer_guid_get(TALLOC_CTX *mem_ctx, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, + const char *printer, struct GUID *guid) +{ + return WERR_NOT_SUPPORTED; +} + +WERROR nt_printer_publish(TALLOC_CTX *mem_ctx, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, + struct spoolss_PrinterInfo2 *pinfo2, + int action) +{ + return WERR_OK; +} + +WERROR check_published_printers(struct messaging_context *msg_ctx) +{ + return WERR_OK; +} + +bool is_printer_published(TALLOC_CTX *mem_ctx, + const struct auth_session_info *session_info, + struct messaging_context *msg_ctx, + const char *servername, + const char *printer, + struct spoolss_PrinterInfo2 **info2) +{ + return False; +} +#endif /* HAVE_ADS */ |