r10656: BIG merge from trunk. Features not copied over
[Samba/nascimento.git] / source3 / passdb / lookup_sid.c
blob6b58210919a0a9c77310cfe896f45dc762436f6f
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 return True;
104 DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying "
105 "special SIDs.\n", sid_string_static(sid)));
108 const char *dom, *obj_name;
110 if (lookup_special_sid(sid, &dom, &obj_name, name_type)) {
111 DEBUG(10, ("found %s\\%s\n", dom, obj_name));
112 fstrcpy(dom_name, dom);
113 fstrcpy(name, obj_name);
114 return True;
118 DEBUG(10, ("lookup_sid failed\n"));
120 return False;
123 /*****************************************************************
124 Id mapping cache. This is to avoid Winbind mappings already
125 seen by smbd to be queried too frequently, keeping winbindd
126 busy, and blocking smbd while winbindd is busy with other
127 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
128 modified to use linked lists by jra.
129 *****************************************************************/
131 #define MAX_UID_SID_CACHE_SIZE 100
132 #define TURNOVER_UID_SID_CACHE_SIZE 10
133 #define MAX_GID_SID_CACHE_SIZE 100
134 #define TURNOVER_GID_SID_CACHE_SIZE 10
136 static size_t n_uid_sid_cache = 0;
137 static size_t n_gid_sid_cache = 0;
139 static struct uid_sid_cache {
140 struct uid_sid_cache *next, *prev;
141 uid_t uid;
142 DOM_SID sid;
143 enum SID_NAME_USE sidtype;
144 } *uid_sid_cache_head;
146 static struct gid_sid_cache {
147 struct gid_sid_cache *next, *prev;
148 gid_t gid;
149 DOM_SID sid;
150 enum SID_NAME_USE sidtype;
151 } *gid_sid_cache_head;
153 /*****************************************************************
154 Find a SID given a uid.
155 *****************************************************************/
157 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
159 struct uid_sid_cache *pc;
161 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
162 if (pc->uid == uid) {
163 fstring sid;
164 *psid = pc->sid;
165 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
166 (unsigned int)uid, sid_to_string(sid, psid)));
167 DLIST_PROMOTE(uid_sid_cache_head, pc);
168 return True;
171 return False;
174 /*****************************************************************
175 Find a uid given a SID.
176 *****************************************************************/
178 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
180 struct uid_sid_cache *pc;
182 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
183 if (sid_compare(&pc->sid, psid) == 0) {
184 fstring sid;
185 *puid = pc->uid;
186 DEBUG(3,("fetch uid from cache %u -> %s\n",
187 (unsigned int)*puid, sid_to_string(sid, psid)));
188 DLIST_PROMOTE(uid_sid_cache_head, pc);
189 return True;
192 return False;
195 /*****************************************************************
196 Store uid to SID mapping in cache.
197 *****************************************************************/
199 static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
201 struct uid_sid_cache *pc;
203 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
204 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
205 struct uid_sid_cache *pc_next;
206 size_t i;
208 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
210 for(; pc; pc = pc_next) {
211 pc_next = pc->next;
212 DLIST_REMOVE(uid_sid_cache_head,pc);
213 SAFE_FREE(pc);
214 n_uid_sid_cache--;
218 pc = SMB_MALLOC_P(struct uid_sid_cache);
219 if (!pc)
220 return;
221 pc->uid = uid;
222 sid_copy(&pc->sid, psid);
223 DLIST_ADD(uid_sid_cache_head, pc);
224 n_uid_sid_cache++;
227 /*****************************************************************
228 Find a SID given a gid.
229 *****************************************************************/
231 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
233 struct gid_sid_cache *pc;
235 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
236 if (pc->gid == gid) {
237 fstring sid;
238 *psid = pc->sid;
239 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
240 (unsigned int)gid, sid_to_string(sid, psid)));
241 DLIST_PROMOTE(gid_sid_cache_head, pc);
242 return True;
245 return False;
248 /*****************************************************************
249 Find a gid given a SID.
250 *****************************************************************/
252 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
254 struct gid_sid_cache *pc;
256 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
257 if (sid_compare(&pc->sid, psid) == 0) {
258 fstring sid;
259 *pgid = pc->gid;
260 DEBUG(3,("fetch gid from cache %u -> %s\n",
261 (unsigned int)*pgid, sid_to_string(sid, psid)));
262 DLIST_PROMOTE(gid_sid_cache_head, pc);
263 return True;
266 return False;
269 /*****************************************************************
270 Store gid to SID mapping in cache.
271 *****************************************************************/
273 static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
275 struct gid_sid_cache *pc;
277 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
278 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
279 struct gid_sid_cache *pc_next;
280 size_t i;
282 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
284 for(; pc; pc = pc_next) {
285 pc_next = pc->next;
286 DLIST_REMOVE(gid_sid_cache_head,pc);
287 SAFE_FREE(pc);
288 n_gid_sid_cache--;
292 pc = SMB_MALLOC_P(struct gid_sid_cache);
293 if (!pc)
294 return;
295 pc->gid = gid;
296 sid_copy(&pc->sid, psid);
297 DLIST_ADD(gid_sid_cache_head, pc);
298 n_gid_sid_cache++;
301 /*****************************************************************
302 *THE CANONICAL* convert uid_t to SID function.
303 *****************************************************************/
305 NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid)
307 fstring sid;
308 uid_t low, high;
310 ZERO_STRUCTP(psid);
312 if (fetch_sid_from_uid_cache(psid, uid))
313 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
315 /* DC's never use winbindd to resolve users outside the
316 defined idmap range */
318 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
319 || (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) )
321 if (winbind_uid_to_sid(psid, uid)) {
323 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
324 (unsigned int)uid, sid_to_string(sid, psid)));
326 if (psid)
327 store_uid_sid_cache(psid, uid);
328 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
332 if (!local_uid_to_sid(psid, uid)) {
333 DEBUG(10,("uid_to_sid: local %u failed to map to sid\n", (unsigned int)uid ));
334 return NT_STATUS_UNSUCCESSFUL;
337 DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
339 store_uid_sid_cache(psid, uid);
340 return NT_STATUS_OK;
343 /*****************************************************************
344 *THE CANONICAL* convert gid_t to SID function.
345 *****************************************************************/
347 NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid)
349 fstring sid;
350 gid_t low, high;
352 ZERO_STRUCTP(psid);
354 if (fetch_sid_from_gid_cache(psid, gid))
355 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
357 /* DC's never use winbindd to resolve groups outside the
358 defined idmap range */
360 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
361 || (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) )
363 if (winbind_gid_to_sid(psid, gid)) {
365 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
366 (unsigned int)gid, sid_to_string(sid, psid)));
368 if (psid)
369 store_gid_sid_cache(psid, gid);
370 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
374 if (!local_gid_to_sid(psid, gid)) {
375 DEBUG(10,("gid_to_sid: local %u failed to map to sid\n", (unsigned int)gid ));
376 return NT_STATUS_UNSUCCESSFUL;
379 DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
381 store_gid_sid_cache(psid, gid);
382 return NT_STATUS_OK;
385 /*****************************************************************
386 *THE CANONICAL* convert SID to uid function.
387 *****************************************************************/
389 NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid)
391 fstring dom_name, name, sid_str;
392 enum SID_NAME_USE name_type;
394 if (fetch_uid_from_cache(puid, psid))
395 return NT_STATUS_OK;
397 /* if this is our SID then go straight to a local lookup */
399 if ( sid_compare_domain(get_global_sam_sid(), psid) == 0 ) {
400 DEBUG(10,("sid_to_uid: my domain (%s) - trying local.\n",
401 sid_string_static(psid) ));
403 if ( local_sid_to_uid(puid, psid, &name_type) )
404 goto success;
406 DEBUG(10,("sid_to_uid: local lookup failed\n"));
408 return NT_STATUS_UNSUCCESSFUL;
411 /* If it is not our local domain, only hope is winbindd */
413 if ( !winbind_lookup_sid(psid, dom_name, name, &name_type) ) {
414 DEBUG(10,("sid_to_uid: winbind lookup for non-local sid %s failed\n",
415 sid_string_static(psid) ));
417 return NT_STATUS_UNSUCCESSFUL;
420 /* If winbindd does know the SID, ensure this is a user */
422 if (name_type != SID_NAME_USER) {
423 DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a user (%u)\n",
424 (unsigned int)name_type ));
425 return NT_STATUS_INVALID_PARAMETER;
428 /* get the uid. Has to work or else we are dead in the water */
430 if ( !winbind_sid_to_uid(puid, psid) ) {
431 DEBUG(10,("sid_to_uid: winbind failed to allocate a new uid for sid %s\n",
432 sid_to_string(sid_str, psid) ));
433 return NT_STATUS_UNSUCCESSFUL;
436 success:
437 DEBUG(10,("sid_to_uid: %s -> %u\n", sid_to_string(sid_str, psid),
438 (unsigned int)*puid ));
440 store_uid_sid_cache(psid, *puid);
442 return NT_STATUS_OK;
444 /*****************************************************************
445 *THE CANONICAL* convert SID to gid function.
446 Group mapping is used for gids that maps to Wellknown SIDs
447 *****************************************************************/
449 NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid)
451 fstring dom_name, name, sid_str;
452 enum SID_NAME_USE name_type;
454 if (fetch_gid_from_cache(pgid, psid))
455 return NT_STATUS_OK;
458 * First we must look up the name and decide if this is a group sid.
459 * Group mapping can deal with foreign SIDs
462 if ( local_sid_to_gid(pgid, psid, &name_type) )
463 goto success;
465 if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
466 DEBUG(10,("sid_to_gid: no one knows the SID %s (tried local, then winbind)\n", sid_to_string(sid_str, psid)));
468 return NT_STATUS_UNSUCCESSFUL;
471 /* winbindd knows it; Ensure this is a group sid */
473 if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS)
474 && (name_type != SID_NAME_WKN_GRP))
476 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
477 (unsigned int)name_type ));
479 /* winbindd is running and knows about this SID. Just the wrong type.
480 Don't fallback to a local lookup here */
482 return NT_STATUS_INVALID_PARAMETER;
485 /* winbindd knows it and it is a type of group; sid_to_gid must succeed
486 or we are dead in the water */
488 if ( !winbind_sid_to_gid(pgid, psid) ) {
489 DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid for sid %s\n",
490 sid_to_string(sid_str, psid) ));
491 return NT_STATUS_UNSUCCESSFUL;
494 success:
495 DEBUG(10,("sid_to_gid: %s -> %u\n", sid_to_string(sid_str, psid),
496 (unsigned int)*pgid ));
498 store_gid_sid_cache(psid, *pgid);
500 return NT_STATUS_OK;