r5687: Fix for bug #2398 from Kevin Dalley <kevin@kelphead.org>.
[Samba.git] / source / passdb / lookup_sid.c
blob8a3d35defd95cc9b2e302f43b0d454497ff5e98b
1 /*
2 Unix SMB/CIFS implementation.
3 uid/user handling
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.
22 #include "includes.h"
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)
31 fstring sid;
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)) {
41 DEBUG(10,
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));
45 return True;
47 } else {
48 /* Remote */
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));
54 return True;
58 DEBUG(10, ("lookup_name: %s lookup for [%s]\\[%s] failed\n",
59 local_lookup ? "local" : "winbind", domain, name));
61 return False;
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(const DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE *name_type)
71 if (!name_type)
72 return False;
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 == 4 && sid_equal(get_global_sam_sid(), sid)) {
80 DOM_SID tmp_sid;
81 sid_copy(&tmp_sid, sid);
82 return map_domain_sid_to_name(&tmp_sid, dom_name) &&
83 local_lookup_sid(sid, name, name_type);
86 if (sid->num_auths == 5) {
87 DOM_SID tmp_sid;
88 uint32 rid;
90 sid_copy(&tmp_sid, sid);
91 sid_split_rid(&tmp_sid, &rid);
93 if (sid_equal(get_global_sam_sid(), &tmp_sid)) {
95 return map_domain_sid_to_name(&tmp_sid, dom_name) &&
96 local_lookup_sid(sid, name, name_type);
100 if (!winbind_lookup_sid(sid, dom_name, name, name_type)) {
101 fstring sid_str;
102 DOM_SID tmp_sid;
103 uint32 rid;
105 DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying local.\n", sid_to_string(sid_str, sid) ));
107 sid_copy(&tmp_sid, sid);
108 sid_split_rid(&tmp_sid, &rid);
109 return map_domain_sid_to_name(&tmp_sid, dom_name) &&
110 lookup_known_rid(&tmp_sid, rid, name, name_type);
112 return True;
116 /*****************************************************************
117 Id mapping cache. This is to avoid Winbind mappings already
118 seen by smbd to be queried too frequently, keeping winbindd
119 busy, and blocking smbd while winbindd is busy with other
120 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
121 modified to use linked lists by jra.
122 *****************************************************************/
124 #define MAX_UID_SID_CACHE_SIZE 100
125 #define TURNOVER_UID_SID_CACHE_SIZE 10
126 #define MAX_GID_SID_CACHE_SIZE 100
127 #define TURNOVER_GID_SID_CACHE_SIZE 10
129 static size_t n_uid_sid_cache = 0;
130 static size_t n_gid_sid_cache = 0;
132 static struct uid_sid_cache {
133 struct uid_sid_cache *next, *prev;
134 uid_t uid;
135 DOM_SID sid;
136 enum SID_NAME_USE sidtype;
137 } *uid_sid_cache_head;
139 static struct gid_sid_cache {
140 struct gid_sid_cache *next, *prev;
141 gid_t gid;
142 DOM_SID sid;
143 enum SID_NAME_USE sidtype;
144 } *gid_sid_cache_head;
146 /*****************************************************************
147 Find a SID given a uid.
148 *****************************************************************/
150 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
152 struct uid_sid_cache *pc;
154 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
155 if (pc->uid == uid) {
156 fstring sid;
157 *psid = pc->sid;
158 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
159 (unsigned int)uid, sid_to_string(sid, psid)));
160 DLIST_PROMOTE(uid_sid_cache_head, pc);
161 return True;
164 return False;
167 /*****************************************************************
168 Find a uid given a SID.
169 *****************************************************************/
171 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
173 struct uid_sid_cache *pc;
175 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
176 if (sid_compare(&pc->sid, psid) == 0) {
177 fstring sid;
178 *puid = pc->uid;
179 DEBUG(3,("fetch uid from cache %u -> %s\n",
180 (unsigned int)*puid, sid_to_string(sid, psid)));
181 DLIST_PROMOTE(uid_sid_cache_head, pc);
182 return True;
185 return False;
188 /*****************************************************************
189 Store uid to SID mapping in cache.
190 *****************************************************************/
192 static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
194 struct uid_sid_cache *pc;
196 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
197 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
198 struct uid_sid_cache *pc_next;
199 size_t i;
201 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
203 for(; pc; pc = pc_next) {
204 pc_next = pc->next;
205 DLIST_REMOVE(uid_sid_cache_head,pc);
206 SAFE_FREE(pc);
207 n_uid_sid_cache--;
211 pc = SMB_MALLOC_P(struct uid_sid_cache);
212 if (!pc)
213 return;
214 pc->uid = uid;
215 sid_copy(&pc->sid, psid);
216 DLIST_ADD(uid_sid_cache_head, pc);
217 n_uid_sid_cache++;
220 /*****************************************************************
221 Find a SID given a gid.
222 *****************************************************************/
224 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
226 struct gid_sid_cache *pc;
228 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
229 if (pc->gid == gid) {
230 fstring sid;
231 *psid = pc->sid;
232 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
233 (unsigned int)gid, sid_to_string(sid, psid)));
234 DLIST_PROMOTE(gid_sid_cache_head, pc);
235 return True;
238 return False;
241 /*****************************************************************
242 Find a gid given a SID.
243 *****************************************************************/
245 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
247 struct gid_sid_cache *pc;
249 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
250 if (sid_compare(&pc->sid, psid) == 0) {
251 fstring sid;
252 *pgid = pc->gid;
253 DEBUG(3,("fetch uid from cache %u -> %s\n",
254 (unsigned int)*pgid, sid_to_string(sid, psid)));
255 DLIST_PROMOTE(gid_sid_cache_head, pc);
256 return True;
259 return False;
262 /*****************************************************************
263 Store gid to SID mapping in cache.
264 *****************************************************************/
266 static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
268 struct gid_sid_cache *pc;
270 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
271 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
272 struct gid_sid_cache *pc_next;
273 size_t i;
275 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
277 for(; pc; pc = pc_next) {
278 pc_next = pc->next;
279 DLIST_REMOVE(gid_sid_cache_head,pc);
280 SAFE_FREE(pc);
281 n_gid_sid_cache--;
285 pc = SMB_MALLOC_P(struct gid_sid_cache);
286 if (!pc)
287 return;
288 pc->gid = gid;
289 sid_copy(&pc->sid, psid);
290 DLIST_ADD(gid_sid_cache_head, pc);
291 n_gid_sid_cache++;
294 /*****************************************************************
295 *THE CANONICAL* convert uid_t to SID function.
296 *****************************************************************/
298 NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid)
300 fstring sid;
301 uid_t low, high;
303 ZERO_STRUCTP(psid);
305 if (fetch_sid_from_uid_cache(psid, uid))
306 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
308 /* DC's never use winbindd to resolve users outside the
309 defined idmap range */
311 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
312 || (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) )
314 if (winbind_uid_to_sid(psid, uid)) {
316 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
317 (unsigned int)uid, sid_to_string(sid, psid)));
319 if (psid)
320 store_uid_sid_cache(psid, uid);
321 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
325 if (!local_uid_to_sid(psid, uid)) {
326 DEBUG(10,("uid_to_sid: local %u failed to map to sid\n", (unsigned int)uid ));
327 return NT_STATUS_UNSUCCESSFUL;
330 DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
332 store_uid_sid_cache(psid, uid);
333 return NT_STATUS_OK;
336 /*****************************************************************
337 *THE CANONICAL* convert gid_t to SID function.
338 *****************************************************************/
340 NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid)
342 fstring sid;
343 gid_t low, high;
345 ZERO_STRUCTP(psid);
347 if (fetch_sid_from_gid_cache(psid, gid))
348 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
350 /* DC's never use winbindd to resolve groups outside the
351 defined idmap range */
353 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
354 || (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) )
356 if (winbind_gid_to_sid(psid, gid)) {
358 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
359 (unsigned int)gid, sid_to_string(sid, psid)));
361 if (psid)
362 store_gid_sid_cache(psid, gid);
363 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
367 if (!local_gid_to_sid(psid, gid)) {
368 DEBUG(10,("gid_to_sid: local %u failed to map to sid\n", (unsigned int)gid ));
369 return NT_STATUS_UNSUCCESSFUL;
372 DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
374 store_gid_sid_cache(psid, gid);
375 return NT_STATUS_OK;
378 /*****************************************************************
379 *THE CANONICAL* convert SID to uid function.
380 *****************************************************************/
382 NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid)
384 fstring dom_name, name, sid_str;
385 enum SID_NAME_USE name_type;
387 if (fetch_uid_from_cache(puid, psid))
388 return NT_STATUS_OK;
390 /* if this is our SID then go straight to a local lookup */
392 if ( sid_compare_domain(get_global_sam_sid(), psid) == 0 ) {
393 DEBUG(10,("sid_to_uid: my domain (%s) - trying local.\n",
394 sid_string_static(psid) ));
396 if ( local_sid_to_uid(puid, psid, &name_type) )
397 goto success;
399 DEBUG(10,("sid_to_uid: local lookup failed\n"));
401 return NT_STATUS_UNSUCCESSFUL;
404 /* If it is not our local domain, only hope is winbindd */
406 if ( !winbind_lookup_sid(psid, dom_name, name, &name_type) ) {
407 DEBUG(10,("sid_to_uid: winbind lookup for non-local sid %s failed\n",
408 sid_string_static(psid) ));
410 return NT_STATUS_UNSUCCESSFUL;
413 /* If winbindd does know the SID, ensure this is a user */
415 if (name_type != SID_NAME_USER) {
416 DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a user (%u)\n",
417 (unsigned int)name_type ));
418 return NT_STATUS_INVALID_PARAMETER;
421 /* get the uid. Has to work or else we are dead in the water */
423 if ( !winbind_sid_to_uid(puid, psid) ) {
424 DEBUG(10,("sid_to_uid: winbind failed to allocate a new uid for sid %s\n",
425 sid_to_string(sid_str, psid) ));
426 return NT_STATUS_UNSUCCESSFUL;
429 success:
430 DEBUG(10,("sid_to_uid: %s -> %u\n", sid_to_string(sid_str, psid),
431 (unsigned int)*puid ));
433 store_uid_sid_cache(psid, *puid);
435 return NT_STATUS_OK;
437 /*****************************************************************
438 *THE CANONICAL* convert SID to gid function.
439 Group mapping is used for gids that maps to Wellknown SIDs
440 *****************************************************************/
442 NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid)
444 fstring dom_name, name, sid_str;
445 enum SID_NAME_USE name_type;
447 if (fetch_gid_from_cache(pgid, psid))
448 return NT_STATUS_OK;
451 * First we must look up the name and decide if this is a group sid.
452 * Group mapping can deal with foreign SIDs
455 if ( local_sid_to_gid(pgid, psid, &name_type) )
456 goto success;
458 if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
459 DEBUG(10,("sid_to_gid: no one knows the SID %s (tried local, then winbind)\n", sid_to_string(sid_str, psid)));
461 return NT_STATUS_UNSUCCESSFUL;
464 /* winbindd knows it; Ensure this is a group sid */
466 if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS)
467 && (name_type != SID_NAME_WKN_GRP))
469 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
470 (unsigned int)name_type ));
472 /* winbindd is running and knows about this SID. Just the wrong type.
473 Don't fallback to a local lookup here */
475 return NT_STATUS_INVALID_PARAMETER;
478 /* winbindd knows it and it is a type of group; sid_to_gid must succeed
479 or we are dead in the water */
481 if ( !winbind_sid_to_gid(pgid, psid) ) {
482 DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid for sid %s\n",
483 sid_to_string(sid_str, psid) ));
484 return NT_STATUS_UNSUCCESSFUL;
487 success:
488 DEBUG(10,("sid_to_gid: %s -> %u\n", sid_to_string(sid_str, psid),
489 (unsigned int)*pgid ));
491 store_gid_sid_cache(psid, *pgid);
493 return NT_STATUS_OK;