1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-12 09:18:10 +03:00
samba-mirror/source3/printing/nt_printing_ads.c
Andrew Bartlett 2e69e89456 s3-auth Rename auth_serversupplied_info varaiables: server_info -> session_info
These variables, of type struct auth_serversupplied_info were poorly
named when added into 2001, and in good consistant practice, this has
extended all over the codebase in the years since.

The structure is also not ideal for it's current purpose.  Originally
intended to convey the results of the authentication modules, it
really describes all the essential attributes of a session.  This
rename will reduce the volume of a future patch to replaced these with
a struct auth_session_info, with auth_serversupplied_info confined to
the lower levels of the auth subsystem, and then eliminated.

(The new structure will be the output of create_local_token(), and the
change in struct definition will ensure that this is always run, populating
local groups and privileges).

Andrew Bartlett

Signed-off-by: Stefan Metzmacher <metze@samba.org>
2011-02-22 16:20:10 +11:00

481 lines
12 KiB
C

/*
* 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"
#ifdef HAVE_ADS
/*****************************************************************
****************************************************************/
static void store_printer_guid(struct messaging_context *msg_ctx,
const char *printer, struct GUID guid)
{
TALLOC_CTX *tmp_ctx;
struct auth_serversupplied_info *session_info = NULL;
const char *guid_str;
DATA_BLOB blob;
NTSTATUS status;
WERROR result;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
return;
}
status = make_session_info_system(tmp_ctx, &session_info);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("store_printer_guid: "
"Could not create system session_info\n"));
goto done;
}
guid_str = GUID_string(tmp_ctx, &guid);
if (!guid_str) {
DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
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, ("store_printer_guid: "
"Could not marshall string %s for objectGUID\n",
guid_str));
goto done;
}
result = winreg_set_printer_dataex(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, ("store_printer_guid: "
"Failed to store GUID for printer %s\n", printer));
}
done:
talloc_free(tmp_ctx);
}
static WERROR nt_printer_publish_ads(struct messaging_context *msg_ctx,
ADS_STRUCT *ads,
struct spoolss_PrinterInfo2 *pinfo2)
{
ADS_STATUS ads_rc;
LDAPMessage *res;
char *prt_dn = NULL, *srv_dn, *srv_cn_0, *srv_cn_escaped, *sharename_escaped;
char *srv_dn_utf8, **srv_cn_utf8;
TALLOC_CTX *ctx;
ADS_MODLIST mods;
const char *attrs[] = {"objectGUID", NULL};
struct GUID guid;
WERROR win_rc = WERR_OK;
size_t converted_size;
const char *printer = pinfo2->sharename;
/* build the ads mods */
ctx = talloc_init("nt_printer_publish_ads");
if (ctx == NULL) {
return WERR_NOMEM;
}
DEBUG(5, ("publishing printer %s\n", printer));
/* figure out where to publish */
ads_find_machine_acct(ads, &res, global_myname());
/* 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);
if (!srv_dn_utf8) {
TALLOC_FREE(ctx);
return WERR_SERVER_UNAVAILABLE;
}
ads_msgfree(ads, res);
srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
if (!srv_cn_utf8) {
TALLOC_FREE(ctx);
ldap_memfree(srv_dn_utf8);
return WERR_SERVER_UNAVAILABLE;
}
/* Now convert to CH_UNIX. */
if (!pull_utf8_talloc(ctx, &srv_dn, srv_dn_utf8, &converted_size)) {
TALLOC_FREE(ctx);
ldap_memfree(srv_dn_utf8);
ldap_memfree(srv_cn_utf8);
return WERR_SERVER_UNAVAILABLE;
}
if (!pull_utf8_talloc(ctx, &srv_cn_0, srv_cn_utf8[0], &converted_size)) {
TALLOC_FREE(ctx);
ldap_memfree(srv_dn_utf8);
ldap_memfree(srv_cn_utf8);
TALLOC_FREE(srv_dn);
return WERR_SERVER_UNAVAILABLE;
}
ldap_memfree(srv_dn_utf8);
ldap_memfree(srv_cn_utf8);
srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0);
if (!srv_cn_escaped) {
TALLOC_FREE(ctx);
return WERR_SERVER_UNAVAILABLE;
}
sharename_escaped = escape_rdn_val_string_alloc(printer);
if (!sharename_escaped) {
SAFE_FREE(srv_cn_escaped);
TALLOC_FREE(ctx);
return WERR_SERVER_UNAVAILABLE;
}
prt_dn = talloc_asprintf(ctx, "cn=%s-%s,%s", srv_cn_escaped, sharename_escaped, srv_dn);
SAFE_FREE(srv_cn_escaped);
SAFE_FREE(sharename_escaped);
mods = ads_init_mods(ctx);
if (mods == NULL) {
SAFE_FREE(prt_dn);
TALLOC_FREE(ctx);
return WERR_NOMEM;
}
ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME, printer);
/* publish it */
ads_rc = ads_mod_printer_entry(ads, prt_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, prt_dn, ctx, &mods);
}
if (!ADS_ERR_OK(ads_rc)) {
DEBUG(3, ("error publishing %s: %s\n",
printer, ads_errstr(ads_rc)));
}
/* retreive the guid and store it locally */
if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
bool guid_ok;
ZERO_STRUCT(guid);
guid_ok = ads_pull_guid(ads, res, &guid);
ads_msgfree(ads, res);
if (guid_ok) {
store_printer_guid(msg_ctx, printer, guid);
}
}
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, global_myname());
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_NOMEM;
}
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_serversupplied_info *session_info,
struct messaging_context *msg_ctx,
struct spoolss_PrinterInfo2 *pinfo2,
int action)
{
uint32_t info2_mask = SPOOLSS_PRINTER_INFO_ATTRIBUTES;
struct spoolss_SetPrinterInfo2 *sinfo2;
ADS_STATUS ads_rc;
ADS_STRUCT *ads = NULL;
WERROR win_rc;
sinfo2 = talloc_zero(mem_ctx, struct spoolss_SetPrinterInfo2);
if (!sinfo2) {
return WERR_NOMEM;
}
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(mem_ctx, session_info, msg_ctx,
pinfo2->sharename, info2_mask,
sinfo2, NULL, NULL);
if (!W_ERROR_IS_OK(win_rc)) {
DEBUG(3, ("err %d saving data\n", W_ERROR_V(win_rc)));
goto done;
}
TALLOC_FREE(sinfo2);
ads = ads_init(lp_realm(), lp_workgroup(), NULL);
if (!ads) {
DEBUG(3, ("ads_init() failed\n"));
win_rc = WERR_SERVER_UNAVAILABLE;
goto done;
}
setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
SAFE_FREE(ads->auth.password);
ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
NULL, NULL);
/* 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_destroy(&ads);
return win_rc;
}
WERROR check_published_printers(struct messaging_context *msg_ctx)
{
ADS_STATUS ads_rc;
ADS_STRUCT *ads = NULL;
int snum;
int n_services = lp_numservices();
TALLOC_CTX *tmp_ctx = NULL;
struct auth_serversupplied_info *session_info = NULL;
struct spoolss_PrinterInfo2 *pinfo2;
NTSTATUS status;
WERROR result;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) return WERR_NOMEM;
ads = ads_init(lp_realm(), lp_workgroup(), NULL);
if (!ads) {
DEBUG(3, ("ads_init() failed\n"));
return WERR_SERVER_UNAVAILABLE;
}
setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
SAFE_FREE(ads->auth.password);
ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
NULL, NULL);
/* 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_print_ok(snum)) {
continue;
}
result = winreg_get_printer(tmp_ctx, session_info, msg_ctx,
lp_servicename(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_destroy(&ads);
ads_kdestroy("MEMORY:prtpub_cache");
talloc_free(tmp_ctx);
return result;
}
bool is_printer_published(TALLOC_CTX *mem_ctx,
const struct auth_serversupplied_info *session_info,
struct messaging_context *msg_ctx,
const char *servername, char *printer, struct GUID *guid,
struct spoolss_PrinterInfo2 **info2)
{
struct spoolss_PrinterInfo2 *pinfo2 = NULL;
enum winreg_Type type;
uint8_t *data;
uint32_t data_size;
WERROR result;
NTSTATUS status;
result = winreg_get_printer(mem_ctx, session_info, msg_ctx,
printer, &pinfo2);
if (!W_ERROR_IS_OK(result)) {
return false;
}
if (!(pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
TALLOC_FREE(pinfo2);
return false;
}
if (!guid) {
goto done;
}
/* fetching printer guids really ought to be a separate function. */
result = winreg_get_printer_dataex(mem_ctx, session_info, msg_ctx,
printer,
SPOOL_DSSPOOLER_KEY, "objectGUID",
&type, &data, &data_size);
if (!W_ERROR_IS_OK(result)) {
TALLOC_FREE(pinfo2);
return false;
}
/* 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:
status = GUID_from_string((char *)data, guid);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(pinfo2);
return false;
}
break;
case REG_BINARY:
if (data_size != sizeof(struct GUID)) {
TALLOC_FREE(pinfo2);
return false;
}
memcpy(guid, data, sizeof(struct GUID));
break;
default:
DEBUG(0,("is_printer_published: GUID value stored as "
"invaluid type (%d)\n", type));
break;
}
done:
if (info2) {
*info2 = talloc_move(mem_ctx, &pinfo2);
}
talloc_free(pinfo2);
return true;
}
#else
WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
const struct auth_serversupplied_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_serversupplied_info *session_info,
struct messaging_context *msg_ctx,
const char *servername, char *printer, struct GUID *guid,
struct spoolss_PrinterInfo2 **info2)
{
return False;
}
#endif /* HAVE_ADS */