s3:winbindd: make use of samba_tevent_context_init()
[Samba/gebeck_regimport.git] / source3 / winbindd / idmap_hash / idmap_hash.c
blobbff1e9e3fad336674201b032d22690cb889d5e75
1 /*
2 * idmap_hash.c
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/>.
21 #include "includes.h"
22 #include "winbindd/winbindd.h"
23 #include "idmap.h"
24 #include "idmap_hash.h"
25 #include "ads.h"
26 #include "nss_info.h"
27 #include "../libcli/security/dom_sid.h"
29 #undef DBGC_CLASS
30 #define DBGC_CLASS DBGC_IDMAP
32 struct sid_hash_table {
33 struct dom_sid *sid;
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)
42 uint32_t hash;
44 if (sid->num_auths != 4)
45 return 0;
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
52 hash value */
53 hash = (((hash & 0xFFF00000) >> 20)
54 + ((hash & 0x000FFF00) >> 8)
55 + (hash & 0x000000FF)) & 0x0000FFF;
57 /* return a 12-bit hash value */
59 return hash;
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,
78 uint32_t h_rid)
80 uint32_t return_id = 0;
82 /* shift the hash_domain 19 bits to the left and OR with the
83 hash_rid */
85 return_id = ((h_domain<<19) | h_rid);
87 return return_id;
90 /*********************************************************************
91 ********************************************************************/
93 static void separate_hashes(uint32_t id,
94 uint32_t *h_domain,
95 uint32_t *h_rid)
97 *h_rid = id & 0x0007FFFF;
98 *h_domain = (id & 0x7FF80000) >> 19;
100 return;
104 /*********************************************************************
105 ********************************************************************/
107 static NTSTATUS be_init(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;
113 int i;
115 /* If the domain SID hash table has been initialized, assume
116 that we completed this function previously */
118 if (dom->private_data != NULL) {
119 nt_status = NT_STATUS_OK;
120 goto done;
123 if (!wcache_tdc_fetch_list(&dom_list, &num_domains)) {
124 nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE;
125 BAIL_ON_NTSTATUS_ERROR(nt_status);
128 /* Create the hash table of domain SIDs */
130 hashed_domains = talloc_zero_array(dom, struct sid_hash_table, 4096);
131 BAIL_ON_PTR_NT_ERROR(hashed_domains, nt_status);
133 /* create the hash table of domain SIDs */
135 for (i=0; i<num_domains; i++) {
136 uint32_t hash;
138 if (is_null_sid(&dom_list[i].sid))
139 continue;
140 if ((hash = hash_domain_sid(&dom_list[i].sid)) == 0)
141 continue;
143 DEBUG(5,("hash:be_init() Adding %s (%s) -> %d\n",
144 dom_list[i].domain_name,
145 sid_string_dbg(&dom_list[i].sid),
146 hash));
148 hashed_domains[hash].sid = talloc(hashed_domains, struct dom_sid);
149 sid_copy(hashed_domains[hash].sid, &dom_list[i].sid);
152 dom->private_data = hashed_domains;
154 done:
155 return nt_status;
158 /*********************************************************************
159 ********************************************************************/
161 static NTSTATUS unixids_to_sids(struct idmap_domain *dom,
162 struct id_map **ids)
164 struct sid_hash_table *hashed_domains = talloc_get_type_abort(
165 dom->private_data, struct sid_hash_table);
166 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
167 int i;
169 if (!ids) {
170 nt_status = NT_STATUS_INVALID_PARAMETER;
171 BAIL_ON_NTSTATUS_ERROR(nt_status);
174 /* initialize the status to avoid suprise */
175 for (i = 0; ids[i]; i++) {
176 ids[i]->status = ID_UNKNOWN;
179 nt_status = be_init(dom);
180 BAIL_ON_NTSTATUS_ERROR(nt_status);
182 for (i=0; ids[i]; i++) {
183 uint32_t h_domain, h_rid;
185 ids[i]->status = ID_UNMAPPED;
187 separate_hashes(ids[i]->xid.id, &h_domain, &h_rid);
189 /* Make sure the caller allocated memor for us */
191 if (!ids[i]->sid) {
192 nt_status = NT_STATUS_INVALID_PARAMETER;
193 BAIL_ON_NTSTATUS_ERROR(nt_status);
196 /* If the domain hash doesn't find a SID in the table,
197 skip it */
199 if (!hashed_domains[h_domain].sid)
200 continue;
202 sid_compose(ids[i]->sid, hashed_domains[h_domain].sid, h_rid);
203 ids[i]->status = ID_MAPPED;
206 done:
207 return nt_status;
210 /*********************************************************************
211 ********************************************************************/
213 static NTSTATUS sids_to_unixids(struct idmap_domain *dom,
214 struct id_map **ids)
216 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
217 int i;
219 if (!ids) {
220 nt_status = NT_STATUS_INVALID_PARAMETER;
221 BAIL_ON_NTSTATUS_ERROR(nt_status);
224 /* initialize the status to avoid suprise */
225 for (i = 0; ids[i]; i++) {
226 ids[i]->status = ID_UNKNOWN;
229 nt_status = be_init(dom);
230 BAIL_ON_NTSTATUS_ERROR(nt_status);
232 for (i=0; ids[i]; i++) {
233 struct dom_sid sid;
234 uint32_t rid;
235 uint32_t h_domain, h_rid;
237 ids[i]->status = ID_UNMAPPED;
239 sid_copy(&sid, ids[i]->sid);
240 sid_split_rid(&sid, &rid);
242 h_domain = hash_domain_sid(&sid);
243 h_rid = hash_rid(rid);
245 /* Check that both hashes are non-zero*/
247 if (h_domain && h_rid) {
248 ids[i]->xid.id = combine_hashes(h_domain, h_rid);
249 ids[i]->status = ID_MAPPED;
253 done:
254 return nt_status;
257 /*********************************************************************
258 ********************************************************************/
260 static NTSTATUS nss_hash_init(struct nss_domain_entry *e )
262 return NT_STATUS_OK;
265 /**********************************************************************
266 *********************************************************************/
268 static NTSTATUS nss_hash_get_info(struct nss_domain_entry *e,
269 const struct dom_sid *sid,
270 TALLOC_CTX *ctx,
271 const char **homedir,
272 const char **shell,
273 const char **gecos,
274 gid_t *p_gid )
276 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
278 nt_status = nss_hash_init(e);
279 BAIL_ON_NTSTATUS_ERROR(nt_status);
281 if (!homedir || !shell || !gecos) {
282 nt_status = NT_STATUS_INVALID_PARAMETER;
283 BAIL_ON_NTSTATUS_ERROR(nt_status);
286 *homedir = talloc_strdup(ctx, lp_template_homedir());
287 BAIL_ON_PTR_NT_ERROR(*homedir, nt_status);
289 *shell = talloc_strdup(ctx, lp_template_shell());
290 BAIL_ON_PTR_NT_ERROR(*shell, nt_status);
292 *gecos = NULL;
294 /* Initialize the gid so that the upper layer fills
295 in the proper Windows primary group */
297 if (*p_gid) {
298 *p_gid = (gid_t)-1;
301 done:
302 return nt_status;
305 /**********************************************************************
306 *********************************************************************/
308 static NTSTATUS nss_hash_map_to_alias(TALLOC_CTX *mem_ctx,
309 struct nss_domain_entry *e,
310 const char *name,
311 char **alias)
313 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
314 const char *value;
316 value = talloc_asprintf(mem_ctx, "%s\\%s", e->domain, name);
317 BAIL_ON_PTR_NT_ERROR(value, nt_status);
319 nt_status = mapfile_lookup_key(mem_ctx, value, alias);
320 BAIL_ON_NTSTATUS_ERROR(nt_status);
322 done:
323 return nt_status;
326 /**********************************************************************
327 *********************************************************************/
329 static NTSTATUS nss_hash_map_from_alias(TALLOC_CTX *mem_ctx,
330 struct nss_domain_entry *e,
331 const char *alias,
332 char **name)
334 return mapfile_lookup_value(mem_ctx, alias, name);
337 /**********************************************************************
338 *********************************************************************/
340 static NTSTATUS nss_hash_close(void)
342 return NT_STATUS_OK;
345 /*********************************************************************
346 Dispatch Tables for IDMap and NssInfo Methods
347 ********************************************************************/
349 static struct idmap_methods hash_idmap_methods = {
350 .init = be_init,
351 .unixids_to_sids = unixids_to_sids,
352 .sids_to_unixids = sids_to_unixids,
355 static struct nss_info_methods hash_nss_methods = {
356 .init = nss_hash_init,
357 .get_nss_info = nss_hash_get_info,
358 .map_to_alias = nss_hash_map_to_alias,
359 .map_from_alias = nss_hash_map_from_alias,
360 .close_fn = nss_hash_close
363 /**********************************************************************
364 Register with the idmap and idmap_nss subsystems. We have to protect
365 against the idmap and nss_info interfaces being in a half-registered
366 state.
367 **********************************************************************/
369 NTSTATUS samba_init_module(void)
371 static NTSTATUS idmap_status = NT_STATUS_UNSUCCESSFUL;
372 static NTSTATUS nss_status = NT_STATUS_UNSUCCESSFUL;
374 if ( !NT_STATUS_IS_OK(idmap_status) ) {
375 idmap_status = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION,
376 "hash", &hash_idmap_methods);
378 if ( !NT_STATUS_IS_OK(idmap_status) ) {
379 DEBUG(0,("Failed to register hash idmap plugin.\n"));
380 return idmap_status;
384 if ( !NT_STATUS_IS_OK(nss_status) ) {
385 nss_status = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
386 "hash", &hash_nss_methods);
387 if ( !NT_STATUS_IS_OK(nss_status) ) {
388 DEBUG(0,("Failed to register hash idmap nss plugin.\n"));
389 return nss_status;
393 return NT_STATUS_OK;