1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00

idmap_hash: Add the idmap/nss-info provider from Likewise Open.

* Port the Likewise Open idmap/nss_info provider (renamed to
  idmap_hash).

* uids & gids are generated based on a hashing algorithm that collapse
  the Domain SID to a 31 bit number.  The reverse mapping from the
  high order 11 bits to the originat8ing sdomain SID is stored in
  a has table initialized at start up.

* Includes support for "idmap_hash:name_map = <filename>" for the
  name aliasing layer.  The name map file consist of entries in
  the form "alias = DOMAIN\name"
This commit is contained in:
Gerald (Jerry) Carter 2008-09-15 15:51:44 -05:00 committed by Jeremy Allison
parent 544cd1b4b9
commit 63554b4078
5 changed files with 637 additions and 0 deletions

View File

@ -979,6 +979,10 @@ IDMAP_OBJ = winbindd/idmap.o winbindd/idmap_util.o @IDMAP_STATIC@
NSS_INFO_OBJ = winbindd/nss_info.o @NSS_INFO_STATIC@
IDMAP_HASH_OBJ = \
winbindd/idmap_hash/idmap_hash.o \
winbindd/idmap_hash/mapfile.o
WINBINDD_OBJ1 = \
winbindd/winbindd.o \
winbindd/winbindd_user.o \
@ -2208,6 +2212,10 @@ bin/ad.@SHLIBEXT@: $(BINARY_PREREQS) winbindd/idmap_ad.o
@echo "Building plugin $@"
@$(SHLD_MODULE) winbindd/idmap_ad.o
bin/hash.@SHLIBEXT@: $(BINARY_PREREQS) $(IDMAP_HASH_OBJ)
@echo "Building plugin $@"
@$(SHLD_MODULE) $(IDMAP_HASH_OBJ)
bin/tdb2.@SHLIBEXT@: $(BINARY_PREREQS) winbindd/idmap_tdb2.o
@echo "Building plugin $@"
@$(SHLD_MODULE) winbindd/idmap_tdb2.o

View File

@ -6057,6 +6057,7 @@ SMB_MODULE(idmap_passdb, winbindd/idmap_passdb.o, "bin/passdb.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_nss, winbindd/idmap_nss.o, "bin/nss.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_rid, winbindd/idmap_rid.o, "bin/rid.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_ad, winbindd/idmap_ad.o, "bin/ad.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_hash, \$(IDMAP_HASH_OBJ), "bin/hash.$SHLIBEXT", IDMAP)
SMB_SUBSYSTEM(IDMAP, winbindd/idmap.o)
SMB_MODULE(nss_info_template, winbindd/nss_info_template.o, "bin/template.$SHLIBEXT", NSS_INFO)

View File

@ -0,0 +1,393 @@
/*
* idmap_hash.c
*
* Copyright (C) Gerald Carter <jerry@samba.org> 2007 - 2008
*
* 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 "winbindd/winbindd.h"
#include "idmap_hash.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
struct sid_hash_table {
DOM_SID *sid;
};
struct sid_hash_table *hashed_domains = NULL;
/*********************************************************************
Hash a domain SID (S-1-5-12-aaa-bbb-ccc) to a 12bit number
********************************************************************/
static uint32_t hash_domain_sid(const DOM_SID *sid)
{
uint32_t hash;
if (sid->num_auths != 4)
return 0;
/* XOR the last three subauths */
hash = ((sid->sub_auths[1] ^ sid->sub_auths[2]) ^ sid->sub_auths[3]);
/* Take all 32-bits into account when generating the 12-bit
hash value */
hash = (((hash & 0xFFF00000) >> 20)
+ ((hash & 0x000FFF00) >> 8)
+ (hash & 0x000000FF)) & 0x0000FFF;
/* return a 12-bit hash value */
return hash;
}
/*********************************************************************
Hash a Relative ID to a 20 bit number
********************************************************************/
static uint32_t hash_rid(uint32_t rid)
{
/* 20 bits for the rid which allows us to support
the first 100K users/groups in a domain */
return (rid & 0x0007FFFF);
}
/*********************************************************************
********************************************************************/
static uint32_t combine_hashes(uint32_t h_domain,
uint32_t h_rid)
{
uint32_t return_id = 0;
/* shift the hash_domain 19 bits to the left and OR with the
hash_rid */
return_id = ((h_domain<<19) | h_rid);
return return_id;
}
/*********************************************************************
********************************************************************/
static void separate_hashes(uint32_t id,
uint32_t *h_domain,
uint32_t *h_rid)
{
*h_rid = id & 0x0007FFFF;
*h_domain = (id & 0x7FF80000) >> 19;
return;
}
/*********************************************************************
********************************************************************/
static NTSTATUS be_init(struct idmap_domain *dom,
const char *params)
{
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
struct winbindd_tdc_domain *dom_list = NULL;
size_t num_domains = 0;
int i;
/* If the domain SID hash talbe has been initialized, assume
that we completed this function previously */
if ( hashed_domains ) {
nt_status = NT_STATUS_OK;
goto done;
}
if (!wcache_tdc_fetch_list(&dom_list, &num_domains)) {
nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE;
BAIL_ON_NTSTATUS_ERROR(nt_status);
}
/* Create the hash table of domain SIDs */
hashed_domains = TALLOC_ZERO_ARRAY(NULL, struct sid_hash_table, 4096);
BAIL_ON_PTR_NT_ERROR(hashed_domains, nt_status);
/* create the hash table of domain SIDs */
for (i=0; i<num_domains; i++) {
uint32_t hash;
if (is_null_sid(&dom_list[i].sid))
continue;
if ((hash = hash_domain_sid(&dom_list[i].sid)) == 0)
continue;
DEBUG(5,("hash:be_init() Adding %s (%s) -> %d\n",
dom_list[i].domain_name,
sid_string_dbg(&dom_list[i].sid),
hash));
hashed_domains[hash].sid = talloc(hashed_domains, DOM_SID);
sid_copy(hashed_domains[hash].sid, &dom_list[i].sid);
}
done:
return nt_status;
}
/*********************************************************************
********************************************************************/
static NTSTATUS unixids_to_sids(struct idmap_domain *dom,
struct id_map **ids)
{
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
int i;
nt_status = be_init(dom, NULL);
BAIL_ON_NTSTATUS_ERROR(nt_status);
if (!ids) {
nt_status = NT_STATUS_INVALID_PARAMETER;
BAIL_ON_NTSTATUS_ERROR(nt_status);
}
for (i=0; ids[i]; i++) {
uint32_t h_domain, h_rid;
ids[i]->status = ID_UNMAPPED;
separate_hashes(ids[i]->xid.id, &h_domain, &h_rid);
/* Make sure the caller allocated memor for us */
if (!ids[i]->sid) {
nt_status = NT_STATUS_INVALID_PARAMETER;
BAIL_ON_NTSTATUS_ERROR(nt_status);
}
/* If the domain hash doesn't find a SID in the table,
skip it */
if (!hashed_domains[h_domain].sid)
continue;
sid_copy(ids[i]->sid, hashed_domains[h_domain].sid);
sid_append_rid(ids[i]->sid, h_rid);
ids[i]->status = ID_MAPPED;
}
done:
return nt_status;
}
/*********************************************************************
********************************************************************/
static NTSTATUS sids_to_unixids(struct idmap_domain *dom,
struct id_map **ids)
{
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
int i;
nt_status = be_init(dom, NULL);
BAIL_ON_NTSTATUS_ERROR(nt_status);
if (!ids) {
nt_status = NT_STATUS_INVALID_PARAMETER;
BAIL_ON_NTSTATUS_ERROR(nt_status);
}
for (i=0; ids[i]; i++) {
DOM_SID sid;
uint32_t rid;
uint32_t h_domain, h_rid;
ids[i]->status = ID_UNMAPPED;
sid_copy(&sid, ids[i]->sid);
sid_split_rid(&sid, &rid);
h_domain = hash_domain_sid(&sid);
h_rid = hash_rid(rid);
/* Check that both hashes are non-zero*/
if (h_domain && h_rid) {
ids[i]->xid.id = combine_hashes(h_domain, h_rid);
ids[i]->status = ID_MAPPED;
}
}
done:
return nt_status;
}
/*********************************************************************
********************************************************************/
static NTSTATUS be_close(struct idmap_domain *dom)
{
if (hashed_domains)
talloc_free(hashed_domains);
return NT_STATUS_OK;
}
/*********************************************************************
********************************************************************/
static NTSTATUS nss_hash_init(struct nss_domain_entry *e )
{
return be_init(NULL, NULL);
}
/**********************************************************************
*********************************************************************/
static NTSTATUS nss_hash_get_info(struct nss_domain_entry *e,
const DOM_SID *sid,
TALLOC_CTX *ctx,
ADS_STRUCT *ads,
LDAPMessage *msg,
char **homedir,
char **shell,
char **gecos,
gid_t *p_gid )
{
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
nt_status = nss_hash_init(e);
BAIL_ON_NTSTATUS_ERROR(nt_status);
if (!homedir || !shell || !gecos) {
nt_status = NT_STATUS_INVALID_PARAMETER;
BAIL_ON_NTSTATUS_ERROR(nt_status);
}
*homedir = talloc_strdup(ctx, lp_template_homedir());
BAIL_ON_PTR_NT_ERROR(*homedir, nt_status);
*shell = talloc_strdup(ctx, lp_template_shell());
BAIL_ON_PTR_NT_ERROR(*shell, nt_status);
*gecos = NULL;
/* Initialize the gid so that the upper layer fills
in the proper Windows primary group */
if (*p_gid) {
*p_gid = (gid_t)-1;
}
done:
return nt_status;
}
/**********************************************************************
*********************************************************************/
static NTSTATUS nss_hash_map_to_alias(TALLOC_CTX *mem_ctx,
const char *domain,
const char *name,
char **alias)
{
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
const char *value;
value = talloc_asprintf(mem_ctx, "%s\\%s", domain, name);
BAIL_ON_PTR_NT_ERROR(value, nt_status);
nt_status = mapfile_lookup_key(mem_ctx, value, alias);
BAIL_ON_NTSTATUS_ERROR(nt_status);
done:
return nt_status;
}
/**********************************************************************
*********************************************************************/
static NTSTATUS nss_hash_map_from_alias(TALLOC_CTX *mem_ctx,
const char *domain,
const char *alias,
char **name)
{
return mapfile_lookup_value(mem_ctx, alias, name);
}
/**********************************************************************
*********************************************************************/
static NTSTATUS nss_hash_close(void)
{
return NT_STATUS_OK;
}
/*********************************************************************
Dispatch Tables for IDMap and NssInfo Methods
********************************************************************/
static struct idmap_methods hash_idmap_methods = {
.init = be_init,
.unixids_to_sids = unixids_to_sids,
.sids_to_unixids = sids_to_unixids,
.close_fn = be_close
};
static struct nss_info_methods hash_nss_methods = {
.init = nss_hash_init,
.get_nss_info = nss_hash_get_info,
.map_to_alias = nss_hash_map_to_alias,
.map_from_alias = nss_hash_map_from_alias,
.close_fn = nss_hash_close
};
/**********************************************************************
Register with the idmap and idmap_nss subsystems. We have to protect
against the idmap and nss_info interfaces being in a half-registered
state.
**********************************************************************/
NTSTATUS idmap_hash_init(void)
{
static NTSTATUS idmap_status = NT_STATUS_UNSUCCESSFUL;
static NTSTATUS nss_status = NT_STATUS_UNSUCCESSFUL;
if ( !NT_STATUS_IS_OK(idmap_status) ) {
idmap_status = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION,
"hash", &hash_idmap_methods);
if ( !NT_STATUS_IS_OK(idmap_status) ) {
DEBUG(0,("Failed to register hash idmap plugin.\n"));
return idmap_status;
}
}
if ( !NT_STATUS_IS_OK(nss_status) ) {
nss_status = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
"hash", &hash_nss_methods);
if ( !NT_STATUS_IS_OK(nss_status) ) {
DEBUG(0,("Failed to register hash idmap nss plugin.\n"));
return nss_status;
}
}
return NT_STATUS_OK;
}

View File

@ -0,0 +1,60 @@
/*
* lwopen.h
*
* Copyright (C) Gerald Carter <jerry@samba.org>
*
* 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/>.
*
*/
#ifndef _LWOPEN_H
#define _LWOPEN_H
#define BAIL_ON_NTSTATUS_ERROR(x) \
do { \
if (!NT_STATUS_IS_OK(x)) { \
DEBUG(10,("Failed! (%s)\n", nt_errstr(x))); \
goto done; \
} \
} \
while (0); \
#define BAIL_ON_PTR_NT_ERROR(p, x) \
do { \
if ((p) == NULL ) { \
DEBUG(10,("NULL pointer!\n")); \
x = NT_STATUS_NO_MEMORY; \
goto done; \
} else { \
x = NT_STATUS_OK; \
} \
} while (0);
#define PRINT_NTSTATUS_ERROR(x, hdr, level) \
do { \
if (!NT_STATUS_IS_OK(x)) { \
DEBUG(level,("Likewise Open ("hdr"): %s\n", nt_errstr(x))); \
} \
} while(0);
NTSTATUS mapfile_lookup_key(TALLOC_CTX *ctx,
const char *value,
char **key);
NTSTATUS mapfile_lookup_value(TALLOC_CTX *ctx,
const char *key,
char **value);
#endif /* _LWOPEN_H */

View File

@ -0,0 +1,175 @@
/*
* mapfile.c
*
* Copyright (C) Gerald Carter <jerry@samba.org>
*
* 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 "winbindd/winbindd.h"
#include "idmap_hash.h"
#include <stdio.h>
XFILE *lw_map_file = NULL;
/*********************************************************************
********************************************************************/
static bool mapfile_open(void)
{
const char *mapfile_name = NULL;
/* If we have an open handle, just reset it */
if (lw_map_file) {
return (x_tseek(lw_map_file, 0, SEEK_SET) == 0);
}
mapfile_name = lp_parm_const_string(-1, "idmap_hash", "name_map", NULL);
if (!mapfile_name) {
return false;
}
lw_map_file = x_fopen(mapfile_name, O_RDONLY, 0);
if (!lw_map_file) {
DEBUG(0,("can't open idmap_hash:name_map (%s). Error %s\n",
mapfile_name, strerror(errno) ));
return false;
}
return true;
}
/*********************************************************************
********************************************************************/
static bool mapfile_read_line(fstring key, fstring value)
{
char buffer[1024];
char *p;
int len;
if (!lw_map_file)
return false;
if ((p = x_fgets(buffer, sizeof(buffer)-1, lw_map_file)) == NULL) {
return false;
}
/* Strip newlines and carriage returns */
len = strlen_m(buffer) - 1;
while ((buffer[len] == '\n') || (buffer[len] == '\r')) {
buffer[len--] = '\0';
}
if ((p = strchr_m(buffer, '=')) == NULL ) {
DEBUG(0,("idmap_hash: Bad line in name_map (%s)\n", buffer));
return false;
}
*p = '\0';
p++;
fstrcpy(key, buffer);
fstrcpy(value, p);
/* Eat whitespace */
if (!trim_char(key, ' ', ' '))
return false;
if (!trim_char(value, ' ', ' '))
return false;
return true;
}
/*********************************************************************
********************************************************************/
static bool mapfile_close(void)
{
int ret = 0;
if (lw_map_file) {
ret = x_fclose(lw_map_file);
lw_map_file = NULL;
}
return (ret == 0);
}
/*********************************************************************
********************************************************************/
NTSTATUS mapfile_lookup_key(TALLOC_CTX *ctx, const char *value, char **key)
{
fstring r_key, r_value;
NTSTATUS ret = NT_STATUS_NOT_FOUND;
if (!mapfile_open())
return NT_STATUS_OBJECT_PATH_NOT_FOUND;
while (mapfile_read_line(r_key, r_value))
{
if (strequal(r_value, value)) {
ret = NT_STATUS_OK;
/* We're done once finishing this block */
*key = talloc_strdup(ctx, r_key);
if (!*key) {
ret = NT_STATUS_NO_MEMORY;
}
break;
}
}
mapfile_close();
return ret;
}
/*********************************************************************
********************************************************************/
NTSTATUS mapfile_lookup_value(TALLOC_CTX *ctx, const char *key, char **value)
{
fstring r_key, r_value;
NTSTATUS ret = NT_STATUS_NOT_FOUND;
if (!mapfile_open())
return NT_STATUS_OBJECT_PATH_NOT_FOUND;
while (mapfile_read_line(r_key, r_value))
{
if (strequal(r_key, key)) {
ret = NT_STATUS_OK;
/* We're done once finishing this block */
*value = talloc_strdup(ctx, r_value);
if (!*key) {
ret = NT_STATUS_NO_MEMORY;
}
break;
}
}
mapfile_close();
return ret;
}