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"
24 #include "idmap_hash.h"
27 #include "../libcli/security/dom_sid.h"
30 #define DBGC_CLASS DBGC_IDMAP
32 struct sid_hash_table {
36 struct sid_hash_table *hashed_domains = NULL;
38 /*********************************************************************
39 Hash a domain SID (S-1-5-12-aaa-bbb-ccc) to a 12bit number
40 ********************************************************************/
42 static uint32_t hash_domain_sid(const struct dom_sid *sid)
46 if (sid->num_auths != 4)
49 /* XOR the last three subauths */
51 hash = ((sid->sub_auths[1] ^ sid->sub_auths[2]) ^ sid->sub_auths[3]);
53 /* Take all 32-bits into account when generating the 12-bit
55 hash = (((hash & 0xFFF00000) >> 20)
56 + ((hash & 0x000FFF00) >> 8)
57 + (hash & 0x000000FF)) & 0x0000FFF;
59 /* return a 12-bit hash value */
64 /*********************************************************************
65 Hash a Relative ID to a 20 bit number
66 ********************************************************************/
68 static uint32_t hash_rid(uint32_t rid)
70 /* 20 bits for the rid which allows us to support
71 the first 100K users/groups in a domain */
73 return (rid & 0x0007FFFF);
76 /*********************************************************************
77 ********************************************************************/
79 static uint32_t combine_hashes(uint32_t h_domain,
82 uint32_t return_id = 0;
84 /* shift the hash_domain 19 bits to the left and OR with the
87 return_id = ((h_domain<<19) | h_rid);
92 /*********************************************************************
93 ********************************************************************/
95 static void separate_hashes(uint32_t id,
99 *h_rid = id & 0x0007FFFF;
100 *h_domain = (id & 0x7FF80000) >> 19;
106 /*********************************************************************
107 ********************************************************************/
109 static NTSTATUS be_init(struct idmap_domain *dom,
112 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
113 struct winbindd_tdc_domain *dom_list = NULL;
114 size_t num_domains = 0;
117 /* If the domain SID hash table has been initialized, assume
118 that we completed this function previously */
120 if ( hashed_domains ) {
121 nt_status = NT_STATUS_OK;
125 if (!wcache_tdc_fetch_list(&dom_list, &num_domains)) {
126 nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE;
127 BAIL_ON_NTSTATUS_ERROR(nt_status);
130 /* Create the hash table of domain SIDs */
132 hashed_domains = TALLOC_ZERO_ARRAY(NULL, struct sid_hash_table, 4096);
133 BAIL_ON_PTR_NT_ERROR(hashed_domains, nt_status);
135 /* create the hash table of domain SIDs */
137 for (i=0; i<num_domains; i++) {
140 if (is_null_sid(&dom_list[i].sid))
142 if ((hash = hash_domain_sid(&dom_list[i].sid)) == 0)
145 DEBUG(5,("hash:be_init() Adding %s (%s) -> %d\n",
146 dom_list[i].domain_name,
147 sid_string_dbg(&dom_list[i].sid),
150 hashed_domains[hash].sid = talloc(hashed_domains, struct dom_sid);
151 sid_copy(hashed_domains[hash].sid, &dom_list[i].sid);
158 /*********************************************************************
159 ********************************************************************/
161 static NTSTATUS unixids_to_sids(struct idmap_domain *dom,
164 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
167 /* initialize the status to avoid suprise */
168 for (i = 0; ids[i]; i++) {
169 ids[i]->status = ID_UNKNOWN;
172 nt_status = be_init(dom, NULL);
173 BAIL_ON_NTSTATUS_ERROR(nt_status);
176 nt_status = NT_STATUS_INVALID_PARAMETER;
177 BAIL_ON_NTSTATUS_ERROR(nt_status);
180 for (i=0; ids[i]; i++) {
181 uint32_t h_domain, h_rid;
183 ids[i]->status = ID_UNMAPPED;
185 separate_hashes(ids[i]->xid.id, &h_domain, &h_rid);
187 /* Make sure the caller allocated memor for us */
190 nt_status = NT_STATUS_INVALID_PARAMETER;
191 BAIL_ON_NTSTATUS_ERROR(nt_status);
194 /* If the domain hash doesn't find a SID in the table,
197 if (!hashed_domains[h_domain].sid)
200 sid_compose(ids[i]->sid, hashed_domains[h_domain].sid, h_rid);
201 ids[i]->status = ID_MAPPED;
208 /*********************************************************************
209 ********************************************************************/
211 static NTSTATUS sids_to_unixids(struct idmap_domain *dom,
214 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
217 /* initialize the status to avoid suprise */
218 for (i = 0; ids[i]; i++) {
219 ids[i]->status = ID_UNKNOWN;
222 nt_status = be_init(dom, NULL);
223 BAIL_ON_NTSTATUS_ERROR(nt_status);
226 nt_status = NT_STATUS_INVALID_PARAMETER;
227 BAIL_ON_NTSTATUS_ERROR(nt_status);
230 for (i=0; ids[i]; i++) {
233 uint32_t h_domain, h_rid;
235 ids[i]->status = ID_UNMAPPED;
237 sid_copy(&sid, ids[i]->sid);
238 sid_split_rid(&sid, &rid);
240 h_domain = hash_domain_sid(&sid);
241 h_rid = hash_rid(rid);
243 /* Check that both hashes are non-zero*/
245 if (h_domain && h_rid) {
246 ids[i]->xid.id = combine_hashes(h_domain, h_rid);
247 ids[i]->status = ID_MAPPED;
255 /*********************************************************************
256 ********************************************************************/
258 static NTSTATUS be_close(struct idmap_domain *dom)
261 talloc_free(hashed_domains);
266 /*********************************************************************
267 ********************************************************************/
269 static NTSTATUS nss_hash_init(struct nss_domain_entry *e )
271 return be_init(NULL, NULL);
274 /**********************************************************************
275 *********************************************************************/
277 static NTSTATUS nss_hash_get_info(struct nss_domain_entry *e,
278 const struct dom_sid *sid,
282 const char **homedir,
287 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
289 nt_status = nss_hash_init(e);
290 BAIL_ON_NTSTATUS_ERROR(nt_status);
292 if (!homedir || !shell || !gecos) {
293 nt_status = NT_STATUS_INVALID_PARAMETER;
294 BAIL_ON_NTSTATUS_ERROR(nt_status);
297 *homedir = talloc_strdup(ctx, lp_template_homedir());
298 BAIL_ON_PTR_NT_ERROR(*homedir, nt_status);
300 *shell = talloc_strdup(ctx, lp_template_shell());
301 BAIL_ON_PTR_NT_ERROR(*shell, nt_status);
305 /* Initialize the gid so that the upper layer fills
306 in the proper Windows primary group */
316 /**********************************************************************
317 *********************************************************************/
319 static NTSTATUS nss_hash_map_to_alias(TALLOC_CTX *mem_ctx,
320 struct nss_domain_entry *e,
324 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
327 value = talloc_asprintf(mem_ctx, "%s\\%s", e->domain, name);
328 BAIL_ON_PTR_NT_ERROR(value, nt_status);
330 nt_status = mapfile_lookup_key(mem_ctx, value, alias);
331 BAIL_ON_NTSTATUS_ERROR(nt_status);
337 /**********************************************************************
338 *********************************************************************/
340 static NTSTATUS nss_hash_map_from_alias(TALLOC_CTX *mem_ctx,
341 struct nss_domain_entry *e,
345 return mapfile_lookup_value(mem_ctx, alias, name);
348 /**********************************************************************
349 *********************************************************************/
351 static NTSTATUS nss_hash_close(void)
356 /*********************************************************************
357 Dispatch Tables for IDMap and NssInfo Methods
358 ********************************************************************/
360 static struct idmap_methods hash_idmap_methods = {
362 .unixids_to_sids = unixids_to_sids,
363 .sids_to_unixids = sids_to_unixids,
367 static struct nss_info_methods hash_nss_methods = {
368 .init = nss_hash_init,
369 .get_nss_info = nss_hash_get_info,
370 .map_to_alias = nss_hash_map_to_alias,
371 .map_from_alias = nss_hash_map_from_alias,
372 .close_fn = nss_hash_close
375 /**********************************************************************
376 Register with the idmap and idmap_nss subsystems. We have to protect
377 against the idmap and nss_info interfaces being in a half-registered
379 **********************************************************************/
381 NTSTATUS idmap_hash_init(void)
383 static NTSTATUS idmap_status = NT_STATUS_UNSUCCESSFUL;
384 static NTSTATUS nss_status = NT_STATUS_UNSUCCESSFUL;
386 if ( !NT_STATUS_IS_OK(idmap_status) ) {
387 idmap_status = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION,
388 "hash", &hash_idmap_methods);
390 if ( !NT_STATUS_IS_OK(idmap_status) ) {
391 DEBUG(0,("Failed to register hash idmap plugin.\n"));
396 if ( !NT_STATUS_IS_OK(nss_status) ) {
397 nss_status = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
398 "hash", &hash_nss_methods);
399 if ( !NT_STATUS_IS_OK(nss_status) ) {
400 DEBUG(0,("Failed to register hash idmap nss plugin.\n"));