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"));