r2: import HEAD into svn+ssh://svn.samba.org/home/svn/samba/trunk
[Samba.git] / source / passdb / lookup_sid.c
bloba365cba0082dcf266306ebfb0867f4735d8bdd8c
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 == 5) {
80 DOM_SID tmp_sid;
81 uint32 rid;
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)) {
94 fstring sid_str;
95 DOM_SID tmp_sid;
96 uint32 rid;
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);
105 return True;
108 BOOL sid_to_local_user_name(const DOM_SID *sid, fstring username)
110 fstring dom_name;
111 fstring name;
112 enum SID_NAME_USE type;
114 if (!sid_check_is_in_our_domain(sid))
115 return False;
117 if (!lookup_sid(sid, dom_name, name, &type))
118 return False;
120 if (type != SID_NAME_USER)
121 return False;
123 fstrcpy(username, name);
124 return True;
127 BOOL sid_to_local_dom_grp_name(const DOM_SID *sid, fstring groupname)
129 fstring dom_name;
130 fstring name;
131 enum SID_NAME_USE type;
133 if (!sid_check_is_in_our_domain(sid))
134 return False;
136 if (!lookup_sid(sid, dom_name, name, &type))
137 return False;
139 if (type != SID_NAME_DOM_GRP)
140 return False;
142 fstrcpy(groupname, name);
143 return True;
147 /*****************************************************************
148 Id mapping cache. This is to avoid Winbind mappings already
149 seen by smbd to be queried too frequently, keeping winbindd
150 busy, and blocking smbd while winbindd is busy with other
151 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
152 modified to use linked lists by jra.
153 *****************************************************************/
155 #define MAX_UID_SID_CACHE_SIZE 100
156 #define TURNOVER_UID_SID_CACHE_SIZE 10
157 #define MAX_GID_SID_CACHE_SIZE 100
158 #define TURNOVER_GID_SID_CACHE_SIZE 10
160 static size_t n_uid_sid_cache = 0;
161 static size_t n_gid_sid_cache = 0;
163 static struct uid_sid_cache {
164 struct uid_sid_cache *next, *prev;
165 uid_t uid;
166 DOM_SID sid;
167 enum SID_NAME_USE sidtype;
168 } *uid_sid_cache_head;
170 static struct gid_sid_cache {
171 struct gid_sid_cache *next, *prev;
172 gid_t gid;
173 DOM_SID sid;
174 enum SID_NAME_USE sidtype;
175 } *gid_sid_cache_head;
177 /*****************************************************************
178 Find a SID given a uid.
179 *****************************************************************/
181 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
183 struct uid_sid_cache *pc;
185 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
186 if (pc->uid == uid) {
187 fstring sid;
188 *psid = pc->sid;
189 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
190 (unsigned int)uid, sid_to_string(sid, psid)));
191 DLIST_PROMOTE(uid_sid_cache_head, pc);
192 return True;
195 return False;
198 /*****************************************************************
199 Find a uid given a SID.
200 *****************************************************************/
202 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
204 struct uid_sid_cache *pc;
206 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
207 if (sid_compare(&pc->sid, psid) == 0) {
208 fstring sid;
209 *puid = pc->uid;
210 DEBUG(3,("fetch uid from cache %u -> %s\n",
211 (unsigned int)*puid, sid_to_string(sid, psid)));
212 DLIST_PROMOTE(uid_sid_cache_head, pc);
213 return True;
216 return False;
219 /*****************************************************************
220 Store uid to SID mapping in cache.
221 *****************************************************************/
223 static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
225 struct uid_sid_cache *pc;
227 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
228 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
229 struct uid_sid_cache *pc_next;
230 size_t i;
232 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
234 for(; pc; pc = pc_next) {
235 pc_next = pc->next;
236 DLIST_REMOVE(uid_sid_cache_head,pc);
237 SAFE_FREE(pc);
238 n_uid_sid_cache--;
242 pc = (struct uid_sid_cache *)malloc(sizeof(struct uid_sid_cache));
243 if (!pc)
244 return;
245 pc->uid = uid;
246 sid_copy(&pc->sid, psid);
247 DLIST_ADD(uid_sid_cache_head, pc);
248 n_uid_sid_cache++;
251 /*****************************************************************
252 Find a SID given a gid.
253 *****************************************************************/
255 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
257 struct gid_sid_cache *pc;
259 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
260 if (pc->gid == gid) {
261 fstring sid;
262 *psid = pc->sid;
263 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
264 (unsigned int)gid, sid_to_string(sid, psid)));
265 DLIST_PROMOTE(gid_sid_cache_head, pc);
266 return True;
269 return False;
272 /*****************************************************************
273 Find a gid given a SID.
274 *****************************************************************/
276 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
278 struct gid_sid_cache *pc;
280 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
281 if (sid_compare(&pc->sid, psid) == 0) {
282 fstring sid;
283 *pgid = pc->gid;
284 DEBUG(3,("fetch uid from cache %u -> %s\n",
285 (unsigned int)*pgid, sid_to_string(sid, psid)));
286 DLIST_PROMOTE(gid_sid_cache_head, pc);
287 return True;
290 return False;
293 /*****************************************************************
294 Store gid to SID mapping in cache.
295 *****************************************************************/
297 static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
299 struct gid_sid_cache *pc;
301 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
302 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
303 struct gid_sid_cache *pc_next;
304 size_t i;
306 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
308 for(; pc; pc = pc_next) {
309 pc_next = pc->next;
310 DLIST_REMOVE(gid_sid_cache_head,pc);
311 SAFE_FREE(pc);
312 n_gid_sid_cache--;
316 pc = (struct gid_sid_cache *)malloc(sizeof(struct gid_sid_cache));
317 if (!pc)
318 return;
319 pc->gid = gid;
320 sid_copy(&pc->sid, psid);
321 DLIST_ADD(gid_sid_cache_head, pc);
322 n_gid_sid_cache++;
325 /*****************************************************************
326 *THE CANONICAL* convert uid_t to SID function.
327 *****************************************************************/
329 NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid)
331 fstring sid;
332 uid_t low, high;
334 ZERO_STRUCTP(psid);
336 if (fetch_sid_from_uid_cache(psid, uid))
337 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
339 /* DC's never use winbindd to resolve users outside the
340 defined idmap range */
342 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
343 || (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) )
345 if (winbind_uid_to_sid(psid, uid)) {
347 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
348 (unsigned int)uid, sid_to_string(sid, psid)));
350 if (psid)
351 store_uid_sid_cache(psid, uid);
352 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
356 if (!local_uid_to_sid(psid, uid)) {
357 DEBUG(10,("uid_to_sid: local %u failed to map to sid\n", (unsigned int)uid ));
358 return NT_STATUS_UNSUCCESSFUL;
361 DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
363 store_uid_sid_cache(psid, uid);
364 return NT_STATUS_OK;
367 /*****************************************************************
368 *THE CANONICAL* convert gid_t to SID function.
369 *****************************************************************/
371 NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid)
373 fstring sid;
374 gid_t low, high;
376 ZERO_STRUCTP(psid);
378 if (fetch_sid_from_gid_cache(psid, gid))
379 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
381 /* DC's never use winbindd to resolve groups outside the
382 defined idmap range */
384 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
385 || (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) )
387 if (winbind_gid_to_sid(psid, gid)) {
389 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
390 (unsigned int)gid, sid_to_string(sid, psid)));
392 if (psid)
393 store_gid_sid_cache(psid, gid);
394 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
398 if (!local_gid_to_sid(psid, gid)) {
399 DEBUG(10,("gid_to_sid: local %u failed to map to sid\n", (unsigned int)gid ));
400 return NT_STATUS_UNSUCCESSFUL;
403 DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
405 store_gid_sid_cache(psid, gid);
406 return NT_STATUS_OK;
409 /*****************************************************************
410 *THE CANONICAL* convert SID to uid function.
411 *****************************************************************/
413 NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid)
415 fstring dom_name, name, sid_str;
416 enum SID_NAME_USE name_type;
418 if (fetch_uid_from_cache(puid, psid))
419 return NT_STATUS_OK;
421 /* if this is our SID then go straight to a local lookup */
423 if ( sid_compare_domain(get_global_sam_sid(), psid) == 0 ) {
424 DEBUG(10,("sid_to_uid: my domain (%s) - trying local.\n",
425 sid_string_static(psid) ));
427 if ( local_sid_to_uid(puid, psid, &name_type) )
428 goto success;
430 DEBUG(10,("sid_to_uid: local lookup failed\n"));
432 return NT_STATUS_UNSUCCESSFUL;
435 /* If it is not our local domain, only hope is winbindd */
437 if ( !winbind_lookup_sid(psid, dom_name, name, &name_type) ) {
438 DEBUG(10,("sid_to_uid: winbind lookup for non-local sid %s failed\n",
439 sid_string_static(psid) ));
441 return NT_STATUS_UNSUCCESSFUL;
444 /* If winbindd does know the SID, ensure this is a user */
446 if (name_type != SID_NAME_USER) {
447 DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a user (%u)\n",
448 (unsigned int)name_type ));
449 return NT_STATUS_INVALID_PARAMETER;
452 /* get the uid. Has to work or else we are dead in the water */
454 if ( !winbind_sid_to_uid(puid, psid) ) {
455 DEBUG(10,("sid_to_uid: winbind failed to allocate a new uid for sid %s\n",
456 sid_to_string(sid_str, psid) ));
457 return NT_STATUS_UNSUCCESSFUL;
460 success:
461 DEBUG(10,("sid_to_uid: %s -> %u\n", sid_to_string(sid_str, psid),
462 (unsigned int)*puid ));
464 store_uid_sid_cache(psid, *puid);
466 return NT_STATUS_OK;
468 /*****************************************************************
469 *THE CANONICAL* convert SID to gid function.
470 Group mapping is used for gids that maps to Wellknown SIDs
471 *****************************************************************/
473 NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid)
475 fstring dom_name, name, sid_str;
476 enum SID_NAME_USE name_type;
478 if (fetch_gid_from_cache(pgid, psid))
479 return NT_STATUS_OK;
482 * First we must look up the name and decide if this is a group sid.
483 * Group mapping can deal with foreign SIDs
486 if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
487 DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed - trying local.\n",
488 sid_to_string(sid_str, psid) ));
490 if ( local_sid_to_gid(pgid, psid, &name_type) )
491 goto success;
493 DEBUG(10,("sid_to_gid: no one knows this SID\n"));
495 return NT_STATUS_UNSUCCESSFUL;
498 /* winbindd knows it; Ensure this is a group sid */
500 if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS)
501 && (name_type != SID_NAME_WKN_GRP))
503 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
504 (unsigned int)name_type ));
506 /* winbindd is running and knows about this SID. Just the wrong type.
507 Don't fallback to a local lookup here */
509 return NT_STATUS_INVALID_PARAMETER;
512 /* winbindd knows it and it is a type of group; sid_to_gid must succeed
513 or we are dead in the water */
515 if ( !winbind_sid_to_gid(pgid, psid) ) {
516 DEBUG(10,("sid_to_uid: winbind failed to allocate a new gid for sid %s\n",
517 sid_to_string(sid_str, psid) ));
518 return NT_STATUS_UNSUCCESSFUL;
521 success:
522 DEBUG(10,("sid_to_gid: %s -> %u\n", sid_to_string(sid_str, psid),
523 (unsigned int)*pgid ));
525 store_gid_sid_cache(psid, *pgid);
527 return NT_STATUS_OK;