2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Gerald (Jerry) Carter 2003
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 /*****************************************************************
25 *THE CANONICAL* convert name to SID function.
26 Tries local lookup first - for local domains - then uses winbind.
27 *****************************************************************/
29 BOOL lookup_name(const char *domain, const char *name, DOM_SID *psid, enum SID_NAME_USE *name_type)
32 BOOL local_lookup = False;
34 *name_type = SID_NAME_UNKNOWN;
36 /* If we are looking up a domain user, make sure it is
37 for the local machine only */
39 if (strequal(domain, get_global_sam_name())) {
40 if (local_lookup_name(name, psid, name_type)) {
42 ("lookup_name: (local) [%s]\\[%s] -> SID %s (type %s: %u)\n",
43 domain, name, sid_to_string(sid,psid),
44 sid_type_lookup(*name_type), (unsigned int)*name_type));
49 if (winbind_lookup_name(domain, name, psid, name_type)) {
51 DEBUG(10,("lookup_name (winbindd): [%s]\\[%s] -> SID %s (type %u)\n",
52 domain, name, sid_to_string(sid, psid),
53 (unsigned int)*name_type));
58 DEBUG(10, ("lookup_name: %s lookup for [%s]\\[%s] failed\n",
59 local_lookup ? "local" : "winbind", domain, name));
64 /*****************************************************************
65 *THE CANONICAL* convert SID to name function.
66 Tries local lookup first - for local sids, then tries winbind.
67 *****************************************************************/
69 BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE *name_type)
74 *name_type = SID_NAME_UNKNOWN;
76 /* Check if this is our own sid. This should perhaps be done by
77 winbind? For the moment handle it here. */
79 if (sid->num_auths == 5) {
83 sid_copy(&tmp_sid, sid);
84 sid_split_rid(&tmp_sid, &rid);
86 if (sid_equal(get_global_sam_sid(), &tmp_sid)) {
88 return map_domain_sid_to_name(&tmp_sid, dom_name) &&
89 local_lookup_sid(sid, name, name_type);
93 if (!winbind_lookup_sid(sid, dom_name, name, name_type)) {
98 DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying local.\n", sid_to_string(sid_str, sid) ));
100 sid_copy(&tmp_sid, sid);
101 sid_split_rid(&tmp_sid, &rid);
102 return map_domain_sid_to_name(&tmp_sid, dom_name) &&
103 lookup_known_rid(&tmp_sid, rid, name, name_type);
109 /*****************************************************************
110 Id mapping cache. This is to avoid Winbind mappings already
111 seen by smbd to be queried too frequently, keeping winbindd
112 busy, and blocking smbd while winbindd is busy with other
113 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
114 modified to use linked lists by jra.
115 *****************************************************************/
117 #define MAX_UID_SID_CACHE_SIZE 100
118 #define TURNOVER_UID_SID_CACHE_SIZE 10
119 #define MAX_GID_SID_CACHE_SIZE 100
120 #define TURNOVER_GID_SID_CACHE_SIZE 10
122 static size_t n_uid_sid_cache = 0;
123 static size_t n_gid_sid_cache = 0;
125 static struct uid_sid_cache {
126 struct uid_sid_cache *next, *prev;
129 enum SID_NAME_USE sidtype;
130 } *uid_sid_cache_head;
132 static struct gid_sid_cache {
133 struct gid_sid_cache *next, *prev;
136 enum SID_NAME_USE sidtype;
137 } *gid_sid_cache_head;
139 /*****************************************************************
140 Find a SID given a uid.
141 *****************************************************************/
143 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
145 struct uid_sid_cache *pc;
147 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
148 if (pc->uid == uid) {
151 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
152 (unsigned int)uid, sid_to_string(sid, psid)));
153 DLIST_PROMOTE(uid_sid_cache_head, pc);
160 /*****************************************************************
161 Find a uid given a SID.
162 *****************************************************************/
164 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
166 struct uid_sid_cache *pc;
168 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
169 if (sid_compare(&pc->sid, psid) == 0) {
172 DEBUG(3,("fetch uid from cache %u -> %s\n",
173 (unsigned int)*puid, sid_to_string(sid, psid)));
174 DLIST_PROMOTE(uid_sid_cache_head, pc);
181 /*****************************************************************
182 Store uid to SID mapping in cache.
183 *****************************************************************/
185 static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
187 struct uid_sid_cache *pc;
189 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
190 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
191 struct uid_sid_cache *pc_next;
194 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
196 for(; pc; pc = pc_next) {
198 DLIST_REMOVE(uid_sid_cache_head,pc);
204 pc = (struct uid_sid_cache *)malloc(sizeof(struct uid_sid_cache));
208 sid_copy(&pc->sid, psid);
209 DLIST_ADD(uid_sid_cache_head, pc);
213 /*****************************************************************
214 Find a SID given a gid.
215 *****************************************************************/
217 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
219 struct gid_sid_cache *pc;
221 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
222 if (pc->gid == gid) {
225 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
226 (unsigned int)gid, sid_to_string(sid, psid)));
227 DLIST_PROMOTE(gid_sid_cache_head, pc);
234 /*****************************************************************
235 Find a gid given a SID.
236 *****************************************************************/
238 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
240 struct gid_sid_cache *pc;
242 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
243 if (sid_compare(&pc->sid, psid) == 0) {
246 DEBUG(3,("fetch uid from cache %u -> %s\n",
247 (unsigned int)*pgid, sid_to_string(sid, psid)));
248 DLIST_PROMOTE(gid_sid_cache_head, pc);
255 /*****************************************************************
256 Store gid to SID mapping in cache.
257 *****************************************************************/
259 static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
261 struct gid_sid_cache *pc;
263 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
264 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
265 struct gid_sid_cache *pc_next;
268 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
270 for(; pc; pc = pc_next) {
272 DLIST_REMOVE(gid_sid_cache_head,pc);
278 pc = (struct gid_sid_cache *)malloc(sizeof(struct gid_sid_cache));
282 sid_copy(&pc->sid, psid);
283 DLIST_ADD(gid_sid_cache_head, pc);
287 /*****************************************************************
288 *THE CANONICAL* convert uid_t to SID function.
289 *****************************************************************/
291 NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid)
298 if (fetch_sid_from_uid_cache(psid, uid))
299 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
301 /* DC's never use winbindd to resolve users outside the
302 defined idmap range */
304 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
305 || (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) )
307 if (winbind_uid_to_sid(psid, uid)) {
309 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
310 (unsigned int)uid, sid_to_string(sid, psid)));
313 store_uid_sid_cache(psid, uid);
314 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
318 if (!local_uid_to_sid(psid, uid)) {
319 DEBUG(10,("uid_to_sid: local %u failed to map to sid\n", (unsigned int)uid ));
320 return NT_STATUS_UNSUCCESSFUL;
323 DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
325 store_uid_sid_cache(psid, uid);
329 /*****************************************************************
330 *THE CANONICAL* convert gid_t to SID function.
331 *****************************************************************/
333 NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid)
340 if (fetch_sid_from_gid_cache(psid, gid))
341 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
343 /* DC's never use winbindd to resolve groups outside the
344 defined idmap range */
346 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
347 || (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) )
349 if (winbind_gid_to_sid(psid, gid)) {
351 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
352 (unsigned int)gid, sid_to_string(sid, psid)));
355 store_gid_sid_cache(psid, gid);
356 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
360 if (!local_gid_to_sid(psid, gid)) {
361 DEBUG(10,("gid_to_sid: local %u failed to map to sid\n", (unsigned int)gid ));
362 return NT_STATUS_UNSUCCESSFUL;
365 DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
367 store_gid_sid_cache(psid, gid);
371 /*****************************************************************
372 *THE CANONICAL* convert SID to uid function.
373 *****************************************************************/
375 NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid)
377 fstring dom_name, name, sid_str;
378 enum SID_NAME_USE name_type;
380 if (fetch_uid_from_cache(puid, psid))
383 /* if this is our SID then go straight to a local lookup */
385 if ( sid_compare_domain(get_global_sam_sid(), psid) == 0 ) {
386 DEBUG(10,("sid_to_uid: my domain (%s) - trying local.\n",
387 sid_string_static(psid) ));
389 if ( local_sid_to_uid(puid, psid, &name_type) )
392 DEBUG(10,("sid_to_uid: local lookup failed\n"));
394 return NT_STATUS_UNSUCCESSFUL;
397 /* If it is not our local domain, only hope is winbindd */
399 if ( !winbind_lookup_sid(psid, dom_name, name, &name_type) ) {
400 DEBUG(10,("sid_to_uid: winbind lookup for non-local sid %s failed\n",
401 sid_string_static(psid) ));
403 return NT_STATUS_UNSUCCESSFUL;
406 /* If winbindd does know the SID, ensure this is a user */
408 if (name_type != SID_NAME_USER) {
409 DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a user (%u)\n",
410 (unsigned int)name_type ));
411 return NT_STATUS_INVALID_PARAMETER;
414 /* get the uid. Has to work or else we are dead in the water */
416 if ( !winbind_sid_to_uid(puid, psid) ) {
417 DEBUG(10,("sid_to_uid: winbind failed to allocate a new uid for sid %s\n",
418 sid_to_string(sid_str, psid) ));
419 return NT_STATUS_UNSUCCESSFUL;
423 DEBUG(10,("sid_to_uid: %s -> %u\n", sid_to_string(sid_str, psid),
424 (unsigned int)*puid ));
426 store_uid_sid_cache(psid, *puid);
430 /*****************************************************************
431 *THE CANONICAL* convert SID to gid function.
432 Group mapping is used for gids that maps to Wellknown SIDs
433 *****************************************************************/
435 NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid)
437 fstring dom_name, name, sid_str;
438 enum SID_NAME_USE name_type;
440 if (fetch_gid_from_cache(pgid, psid))
444 * First we must look up the name and decide if this is a group sid.
445 * Group mapping can deal with foreign SIDs
448 if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
449 DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed - trying local.\n",
450 sid_to_string(sid_str, psid) ));
452 if ( local_sid_to_gid(pgid, psid, &name_type) )
455 DEBUG(10,("sid_to_gid: no one knows this SID\n"));
457 return NT_STATUS_UNSUCCESSFUL;
460 /* winbindd knows it; Ensure this is a group sid */
462 if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS)
463 && (name_type != SID_NAME_WKN_GRP))
465 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
466 (unsigned int)name_type ));
468 /* winbindd is running and knows about this SID. Just the wrong type.
469 Don't fallback to a local lookup here */
471 return NT_STATUS_INVALID_PARAMETER;
474 /* winbindd knows it and it is a type of group; sid_to_gid must succeed
475 or we are dead in the water */
477 if ( !winbind_sid_to_gid(pgid, psid) ) {
478 DEBUG(10,("sid_to_uid: winbind failed to allocate a new gid for sid %s\n",
479 sid_to_string(sid_str, psid) ));
480 return NT_STATUS_UNSUCCESSFUL;
484 DEBUG(10,("sid_to_gid: %s -> %u\n", sid_to_string(sid_str, psid),
485 (unsigned int)*pgid ));
487 store_gid_sid_cache(psid, *pgid);