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 /*********************************************************************
37 Hash a domain SID (S-1-5-12-aaa-bbb-ccc) to a 12bit number
38 ********************************************************************/
40 static uint32_t hash_domain_sid(const struct dom_sid *sid)
44 if (sid->num_auths != 4)
47 /* XOR the last three subauths */
49 hash = ((sid->sub_auths[1] ^ sid->sub_auths[2]) ^ sid->sub_auths[3]);
51 /* Take all 32-bits into account when generating the 12-bit
53 hash = (((hash & 0xFFF00000) >> 20)
54 + ((hash & 0x000FFF00) >> 8)
55 + (hash & 0x000000FF)) & 0x0000FFF;
57 /* return a 12-bit hash value */
62 /*********************************************************************
63 Hash a Relative ID to a 20 bit number
64 ********************************************************************/
66 static uint32_t hash_rid(uint32_t rid)
68 /* 20 bits for the rid which allows us to support
69 the first 100K users/groups in a domain */
71 return (rid & 0x0007FFFF);
74 /*********************************************************************
75 ********************************************************************/
77 static uint32_t combine_hashes(uint32_t h_domain,
80 uint32_t return_id = 0;
82 /* shift the hash_domain 19 bits to the left and OR with the
85 return_id = ((h_domain<<19) | h_rid);
90 /*********************************************************************
91 ********************************************************************/
93 static void separate_hashes(uint32_t id,
97 *h_rid = id & 0x0007FFFF;
98 *h_domain = (id & 0x7FF80000) >> 19;
104 /*********************************************************************
105 ********************************************************************/
107 static NTSTATUS idmap_hash_initialize(struct idmap_domain *dom)
109 struct sid_hash_table *hashed_domains;
110 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
111 struct winbindd_tdc_domain *dom_list = NULL;
112 size_t num_domains = 0;
115 DBG_ERR("The idmap_hash module is deprecated and should not be used. "
116 "Please migrate to a different plugin. This module will be "
117 "removed in a future version of Samba\n");
119 if (!strequal(dom->name, "*")) {
120 DBG_ERR("Error: idmap_hash configured for domain '%s'. "
121 "But the hash module can only be used for the default "
122 "idmap configuration.\n", dom->name);
123 return NT_STATUS_INVALID_PARAMETER;
126 /* If the domain SID hash table has been initialized, assume
127 that we completed this function previously */
129 if (dom->private_data != NULL) {
130 nt_status = NT_STATUS_OK;
134 if (!wcache_tdc_fetch_list(&dom_list, &num_domains)) {
135 nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE;
136 BAIL_ON_NTSTATUS_ERROR(nt_status);
139 /* Create the hash table of domain SIDs */
141 hashed_domains = talloc_zero_array(dom, struct sid_hash_table, 4096);
142 BAIL_ON_PTR_NT_ERROR(hashed_domains, nt_status);
144 /* create the hash table of domain SIDs */
146 for (i=0; i<num_domains; i++) {
149 if (is_null_sid(&dom_list[i].sid))
153 * Check if the domain from the list is not already configured
154 * to use another idmap backend. Not checking this makes the
155 * idmap_hash module map IDs for *all* domains implicitly. This
156 * is quite dangerous in setups that use multiple idmap
160 if (domain_has_idmap_config(dom_list[i].domain_name)) {
164 if ((hash = hash_domain_sid(&dom_list[i].sid)) == 0)
167 DBG_INFO("Adding %s (%s) -> %d\n",
168 dom_list[i].domain_name,
169 sid_string_dbg(&dom_list[i].sid),
172 hashed_domains[hash].sid = talloc(hashed_domains, struct dom_sid);
173 sid_copy(hashed_domains[hash].sid, &dom_list[i].sid);
176 dom->private_data = hashed_domains;
182 /*********************************************************************
183 ********************************************************************/
185 static NTSTATUS unixids_to_sids(struct idmap_domain *dom,
188 struct sid_hash_table *hashed_domains = talloc_get_type_abort(
189 dom->private_data, struct sid_hash_table);
190 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
194 nt_status = NT_STATUS_INVALID_PARAMETER;
195 BAIL_ON_NTSTATUS_ERROR(nt_status);
198 /* initialize the status to avoid suprise */
199 for (i = 0; ids[i]; i++) {
200 ids[i]->status = ID_UNKNOWN;
203 nt_status = idmap_hash_initialize(dom);
204 BAIL_ON_NTSTATUS_ERROR(nt_status);
206 for (i=0; ids[i]; i++) {
207 uint32_t h_domain, h_rid;
209 ids[i]->status = ID_UNMAPPED;
211 separate_hashes(ids[i]->xid.id, &h_domain, &h_rid);
213 /* Make sure the caller allocated memor for us */
216 nt_status = NT_STATUS_INVALID_PARAMETER;
217 BAIL_ON_NTSTATUS_ERROR(nt_status);
220 /* If the domain hash doesn't find a SID in the table,
223 if (!hashed_domains[h_domain].sid)
226 sid_compose(ids[i]->sid, hashed_domains[h_domain].sid, h_rid);
227 ids[i]->status = ID_MAPPED;
234 /*********************************************************************
235 ********************************************************************/
237 static NTSTATUS sids_to_unixids(struct idmap_domain *dom,
240 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
244 nt_status = NT_STATUS_INVALID_PARAMETER;
245 BAIL_ON_NTSTATUS_ERROR(nt_status);
248 /* initialize the status to avoid suprise */
249 for (i = 0; ids[i]; i++) {
250 ids[i]->status = ID_UNKNOWN;
253 nt_status = idmap_hash_initialize(dom);
254 BAIL_ON_NTSTATUS_ERROR(nt_status);
256 for (i=0; ids[i]; i++) {
259 uint32_t h_domain, h_rid;
261 ids[i]->status = ID_UNMAPPED;
263 sid_copy(&sid, ids[i]->sid);
264 sid_split_rid(&sid, &rid);
266 h_domain = hash_domain_sid(&sid);
267 h_rid = hash_rid(rid);
269 /* Check that both hashes are non-zero*/
271 if (h_domain && h_rid) {
272 ids[i]->xid.id = combine_hashes(h_domain, h_rid);
273 ids[i]->status = ID_MAPPED;
281 /*********************************************************************
282 ********************************************************************/
284 static NTSTATUS nss_hash_init(struct nss_domain_entry *e )
289 /**********************************************************************
290 *********************************************************************/
292 static NTSTATUS nss_hash_map_to_alias(TALLOC_CTX *mem_ctx,
293 struct nss_domain_entry *e,
297 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
300 value = talloc_asprintf(mem_ctx, "%s\\%s", e->domain, name);
301 BAIL_ON_PTR_NT_ERROR(value, nt_status);
303 nt_status = mapfile_lookup_key(mem_ctx, value, alias);
304 BAIL_ON_NTSTATUS_ERROR(nt_status);
310 /**********************************************************************
311 *********************************************************************/
313 static NTSTATUS nss_hash_map_from_alias(TALLOC_CTX *mem_ctx,
314 struct nss_domain_entry *e,
318 return mapfile_lookup_value(mem_ctx, alias, name);
321 /**********************************************************************
322 *********************************************************************/
324 static NTSTATUS nss_hash_close(void)
329 /*********************************************************************
330 Dispatch Tables for IDMap and NssInfo Methods
331 ********************************************************************/
333 static struct idmap_methods hash_idmap_methods = {
334 .init = idmap_hash_initialize,
335 .unixids_to_sids = unixids_to_sids,
336 .sids_to_unixids = sids_to_unixids,
339 static struct nss_info_methods hash_nss_methods = {
340 .init = nss_hash_init,
341 .map_to_alias = nss_hash_map_to_alias,
342 .map_from_alias = nss_hash_map_from_alias,
343 .close_fn = nss_hash_close
346 /**********************************************************************
347 Register with the idmap and idmap_nss subsystems. We have to protect
348 against the idmap and nss_info interfaces being in a half-registered
350 **********************************************************************/
353 NTSTATUS idmap_hash_init(TALLOC_CTX *ctx)
355 static NTSTATUS idmap_status = NT_STATUS_UNSUCCESSFUL;
356 static NTSTATUS nss_status = NT_STATUS_UNSUCCESSFUL;
358 if ( !NT_STATUS_IS_OK(idmap_status) ) {
359 idmap_status = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION,
360 "hash", &hash_idmap_methods);
362 if ( !NT_STATUS_IS_OK(idmap_status) ) {
363 DEBUG(0,("Failed to register hash idmap plugin.\n"));
368 if ( !NT_STATUS_IS_OK(nss_status) ) {
369 nss_status = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
370 "hash", &hash_nss_methods);
371 if ( !NT_STATUS_IS_OK(nss_status) ) {
372 DEBUG(0,("Failed to register hash idmap nss plugin.\n"));