4
* Copyright (C) Gerald Carter <jerry@samba.org> 2007 - 2008
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 3 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, see <http://www.gnu.org/licenses/>.
22
#include "winbindd/winbindd.h"
23
#include "idmap_hash.h"
26
#define DBGC_CLASS DBGC_IDMAP
28
struct sid_hash_table {
32
struct sid_hash_table *hashed_domains = NULL;
34
/*********************************************************************
35
Hash a domain SID (S-1-5-12-aaa-bbb-ccc) to a 12bit number
36
********************************************************************/
38
static uint32_t hash_domain_sid(const DOM_SID *sid)
42
if (sid->num_auths != 4)
45
/* XOR the last three subauths */
47
hash = ((sid->sub_auths[1] ^ sid->sub_auths[2]) ^ sid->sub_auths[3]);
49
/* Take all 32-bits into account when generating the 12-bit
51
hash = (((hash & 0xFFF00000) >> 20)
52
+ ((hash & 0x000FFF00) >> 8)
53
+ (hash & 0x000000FF)) & 0x0000FFF;
55
/* return a 12-bit hash value */
60
/*********************************************************************
61
Hash a Relative ID to a 20 bit number
62
********************************************************************/
64
static uint32_t hash_rid(uint32_t rid)
66
/* 20 bits for the rid which allows us to support
67
the first 100K users/groups in a domain */
69
return (rid & 0x0007FFFF);
72
/*********************************************************************
73
********************************************************************/
75
static uint32_t combine_hashes(uint32_t h_domain,
78
uint32_t return_id = 0;
80
/* shift the hash_domain 19 bits to the left and OR with the
83
return_id = ((h_domain<<19) | h_rid);
88
/*********************************************************************
89
********************************************************************/
91
static void separate_hashes(uint32_t id,
95
*h_rid = id & 0x0007FFFF;
96
*h_domain = (id & 0x7FF80000) >> 19;
102
/*********************************************************************
103
********************************************************************/
105
static NTSTATUS be_init(struct idmap_domain *dom,
108
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
109
struct winbindd_tdc_domain *dom_list = NULL;
110
size_t num_domains = 0;
113
/* If the domain SID hash talbe has been initialized, assume
114
that we completed this function previously */
116
if ( hashed_domains ) {
117
nt_status = NT_STATUS_OK;
121
if (!wcache_tdc_fetch_list(&dom_list, &num_domains)) {
122
nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE;
123
BAIL_ON_NTSTATUS_ERROR(nt_status);
126
/* Create the hash table of domain SIDs */
128
hashed_domains = TALLOC_ZERO_ARRAY(NULL, struct sid_hash_table, 4096);
129
BAIL_ON_PTR_NT_ERROR(hashed_domains, nt_status);
131
/* create the hash table of domain SIDs */
133
for (i=0; i<num_domains; i++) {
136
if (is_null_sid(&dom_list[i].sid))
138
if ((hash = hash_domain_sid(&dom_list[i].sid)) == 0)
141
DEBUG(5,("hash:be_init() Adding %s (%s) -> %d\n",
142
dom_list[i].domain_name,
143
sid_string_dbg(&dom_list[i].sid),
146
hashed_domains[hash].sid = talloc(hashed_domains, DOM_SID);
147
sid_copy(hashed_domains[hash].sid, &dom_list[i].sid);
154
/*********************************************************************
155
********************************************************************/
157
static NTSTATUS unixids_to_sids(struct idmap_domain *dom,
160
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
163
/* initialize the status to avoid suprise */
164
for (i = 0; ids[i]; i++) {
165
ids[i]->status = ID_UNKNOWN;
168
nt_status = be_init(dom, NULL);
169
BAIL_ON_NTSTATUS_ERROR(nt_status);
172
nt_status = NT_STATUS_INVALID_PARAMETER;
173
BAIL_ON_NTSTATUS_ERROR(nt_status);
176
for (i=0; ids[i]; i++) {
177
uint32_t h_domain, h_rid;
179
ids[i]->status = ID_UNMAPPED;
181
separate_hashes(ids[i]->xid.id, &h_domain, &h_rid);
183
/* Make sure the caller allocated memor for us */
186
nt_status = NT_STATUS_INVALID_PARAMETER;
187
BAIL_ON_NTSTATUS_ERROR(nt_status);
190
/* If the domain hash doesn't find a SID in the table,
193
if (!hashed_domains[h_domain].sid)
196
sid_copy(ids[i]->sid, hashed_domains[h_domain].sid);
197
sid_append_rid(ids[i]->sid, h_rid);
198
ids[i]->status = ID_MAPPED;
205
/*********************************************************************
206
********************************************************************/
208
static NTSTATUS sids_to_unixids(struct idmap_domain *dom,
211
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
214
/* initialize the status to avoid suprise */
215
for (i = 0; ids[i]; i++) {
216
ids[i]->status = ID_UNKNOWN;
219
nt_status = be_init(dom, NULL);
220
BAIL_ON_NTSTATUS_ERROR(nt_status);
223
nt_status = NT_STATUS_INVALID_PARAMETER;
224
BAIL_ON_NTSTATUS_ERROR(nt_status);
227
for (i=0; ids[i]; i++) {
230
uint32_t h_domain, h_rid;
232
ids[i]->status = ID_UNMAPPED;
234
sid_copy(&sid, ids[i]->sid);
235
sid_split_rid(&sid, &rid);
237
h_domain = hash_domain_sid(&sid);
238
h_rid = hash_rid(rid);
240
/* Check that both hashes are non-zero*/
242
if (h_domain && h_rid) {
243
ids[i]->xid.id = combine_hashes(h_domain, h_rid);
244
ids[i]->status = ID_MAPPED;
252
/*********************************************************************
253
********************************************************************/
255
static NTSTATUS be_close(struct idmap_domain *dom)
258
talloc_free(hashed_domains);
263
/*********************************************************************
264
********************************************************************/
266
static NTSTATUS nss_hash_init(struct nss_domain_entry *e )
268
return be_init(NULL, NULL);
271
/**********************************************************************
272
*********************************************************************/
274
static NTSTATUS nss_hash_get_info(struct nss_domain_entry *e,
284
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
286
nt_status = nss_hash_init(e);
287
BAIL_ON_NTSTATUS_ERROR(nt_status);
289
if (!homedir || !shell || !gecos) {
290
nt_status = NT_STATUS_INVALID_PARAMETER;
291
BAIL_ON_NTSTATUS_ERROR(nt_status);
294
*homedir = talloc_strdup(ctx, lp_template_homedir());
295
BAIL_ON_PTR_NT_ERROR(*homedir, nt_status);
297
*shell = talloc_strdup(ctx, lp_template_shell());
298
BAIL_ON_PTR_NT_ERROR(*shell, nt_status);
302
/* Initialize the gid so that the upper layer fills
303
in the proper Windows primary group */
313
/**********************************************************************
314
*********************************************************************/
316
static NTSTATUS nss_hash_map_to_alias(TALLOC_CTX *mem_ctx,
317
struct nss_domain_entry *e,
321
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
324
value = talloc_asprintf(mem_ctx, "%s\\%s", e->domain, name);
325
BAIL_ON_PTR_NT_ERROR(value, nt_status);
327
nt_status = mapfile_lookup_key(mem_ctx, value, alias);
328
BAIL_ON_NTSTATUS_ERROR(nt_status);
334
/**********************************************************************
335
*********************************************************************/
337
static NTSTATUS nss_hash_map_from_alias(TALLOC_CTX *mem_ctx,
338
struct nss_domain_entry *e,
342
return mapfile_lookup_value(mem_ctx, alias, name);
345
/**********************************************************************
346
*********************************************************************/
348
static NTSTATUS nss_hash_close(void)
353
/*********************************************************************
354
Dispatch Tables for IDMap and NssInfo Methods
355
********************************************************************/
357
static struct idmap_methods hash_idmap_methods = {
359
.unixids_to_sids = unixids_to_sids,
360
.sids_to_unixids = sids_to_unixids,
364
static struct nss_info_methods hash_nss_methods = {
365
.init = nss_hash_init,
366
.get_nss_info = nss_hash_get_info,
367
.map_to_alias = nss_hash_map_to_alias,
368
.map_from_alias = nss_hash_map_from_alias,
369
.close_fn = nss_hash_close
372
/**********************************************************************
373
Register with the idmap and idmap_nss subsystems. We have to protect
374
against the idmap and nss_info interfaces being in a half-registered
376
**********************************************************************/
378
NTSTATUS idmap_hash_init(void)
380
static NTSTATUS idmap_status = NT_STATUS_UNSUCCESSFUL;
381
static NTSTATUS nss_status = NT_STATUS_UNSUCCESSFUL;
383
if ( !NT_STATUS_IS_OK(idmap_status) ) {
384
idmap_status = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION,
385
"hash", &hash_idmap_methods);
387
if ( !NT_STATUS_IS_OK(idmap_status) ) {
388
DEBUG(0,("Failed to register hash idmap plugin.\n"));
393
if ( !NT_STATUS_IS_OK(nss_status) ) {
394
nss_status = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
395
"hash", &hash_nss_methods);
396
if ( !NT_STATUS_IS_OK(nss_status) ) {
397
DEBUG(0,("Failed to register hash idmap nss plugin.\n"));