fix for bug 680 (heads up). This gist is to map the
[Samba.git] / source / passdb / lookup_sid.c
blob425c9b87f10d2a9ef435961c2c62a6828de4e2c5
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(global_myname(), domain)) {
40 local_lookup = True;
41 } else if (lp_server_role() == ROLE_DOMAIN_PDC ||
42 lp_server_role() == ROLE_DOMAIN_BDC) {
43 if (strequal(domain, lp_workgroup())) {
44 local_lookup = True;
48 if (local_lookup) {
49 if (local_lookup_name(name, psid, name_type)) {
50 DEBUG(10,
51 ("lookup_name: (local) [%s]\\[%s] -> SID %s (type %s: %u)\n",
52 domain, name, sid_to_string(sid,psid),
53 sid_type_lookup(*name_type), (unsigned int)*name_type));
54 return True;
56 } else {
57 /* Remote */
58 if (winbind_lookup_name(domain, name, psid, name_type)) {
60 DEBUG(10,("lookup_name (winbindd): [%s]\\[%s] -> SID %s (type %u)\n",
61 domain, name, sid_to_string(sid, psid),
62 (unsigned int)*name_type));
63 return True;
67 DEBUG(10, ("lookup_name: %s lookup for [%s]\\[%s] failed\n",
68 local_lookup ? "local" : "winbind", domain, name));
70 return False;
73 /*****************************************************************
74 *THE CANONICAL* convert SID to name function.
75 Tries local lookup first - for local sids, then tries winbind.
76 *****************************************************************/
78 BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE *name_type)
80 if (!name_type)
81 return False;
83 *name_type = SID_NAME_UNKNOWN;
85 /* Check if this is our own sid. This should perhaps be done by
86 winbind? For the moment handle it here. */
88 if (sid->num_auths == 5) {
89 DOM_SID tmp_sid;
90 uint32 rid;
92 sid_copy(&tmp_sid, sid);
93 sid_split_rid(&tmp_sid, &rid);
95 if (sid_equal(get_global_sam_sid(), &tmp_sid)) {
97 return map_domain_sid_to_name(&tmp_sid, dom_name) &&
98 local_lookup_sid(sid, name, name_type);
102 if (!winbind_lookup_sid(sid, dom_name, name, name_type)) {
103 fstring sid_str;
104 DOM_SID tmp_sid;
105 uint32 rid;
107 DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying local.\n", sid_to_string(sid_str, sid) ));
109 sid_copy(&tmp_sid, sid);
110 sid_split_rid(&tmp_sid, &rid);
111 return map_domain_sid_to_name(&tmp_sid, dom_name) &&
112 lookup_known_rid(&tmp_sid, rid, name, name_type);
114 return True;
118 /*****************************************************************
119 Id mapping cache. This is to avoid Winbind mappings already
120 seen by smbd to be queried too frequently, keeping winbindd
121 busy, and blocking smbd while winbindd is busy with other
122 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
123 modified to use linked lists by jra.
124 *****************************************************************/
126 #define MAX_UID_SID_CACHE_SIZE 100
127 #define TURNOVER_UID_SID_CACHE_SIZE 10
128 #define MAX_GID_SID_CACHE_SIZE 100
129 #define TURNOVER_GID_SID_CACHE_SIZE 10
131 static size_t n_uid_sid_cache = 0;
132 static size_t n_gid_sid_cache = 0;
134 static struct uid_sid_cache {
135 struct uid_sid_cache *next, *prev;
136 uid_t uid;
137 DOM_SID sid;
138 enum SID_NAME_USE sidtype;
139 } *uid_sid_cache_head;
141 static struct gid_sid_cache {
142 struct gid_sid_cache *next, *prev;
143 gid_t gid;
144 DOM_SID sid;
145 enum SID_NAME_USE sidtype;
146 } *gid_sid_cache_head;
148 /*****************************************************************
149 Find a SID given a uid.
150 *****************************************************************/
152 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
154 struct uid_sid_cache *pc;
156 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
157 if (pc->uid == uid) {
158 fstring sid;
159 *psid = pc->sid;
160 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
161 (unsigned int)uid, sid_to_string(sid, psid)));
162 DLIST_PROMOTE(uid_sid_cache_head, pc);
163 return True;
166 return False;
169 /*****************************************************************
170 Find a uid given a SID.
171 *****************************************************************/
173 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
175 struct uid_sid_cache *pc;
177 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
178 if (sid_compare(&pc->sid, psid) == 0) {
179 fstring sid;
180 *puid = pc->uid;
181 DEBUG(3,("fetch uid from cache %u -> %s\n",
182 (unsigned int)*puid, sid_to_string(sid, psid)));
183 DLIST_PROMOTE(uid_sid_cache_head, pc);
184 return True;
187 return False;
190 /*****************************************************************
191 Store uid to SID mapping in cache.
192 *****************************************************************/
194 static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
196 struct uid_sid_cache *pc;
198 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
199 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
200 struct uid_sid_cache *pc_next;
201 size_t i;
203 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
205 for(; pc; pc = pc_next) {
206 pc_next = pc->next;
207 DLIST_REMOVE(uid_sid_cache_head,pc);
208 SAFE_FREE(pc);
209 n_uid_sid_cache--;
213 pc = (struct uid_sid_cache *)malloc(sizeof(struct uid_sid_cache));
214 if (!pc)
215 return;
216 pc->uid = uid;
217 sid_copy(&pc->sid, psid);
218 DLIST_ADD(uid_sid_cache_head, pc);
219 n_uid_sid_cache++;
222 /*****************************************************************
223 Find a SID given a gid.
224 *****************************************************************/
226 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
228 struct gid_sid_cache *pc;
230 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
231 if (pc->gid == gid) {
232 fstring sid;
233 *psid = pc->sid;
234 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
235 (unsigned int)gid, sid_to_string(sid, psid)));
236 DLIST_PROMOTE(gid_sid_cache_head, pc);
237 return True;
240 return False;
243 /*****************************************************************
244 Find a gid given a SID.
245 *****************************************************************/
247 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
249 struct gid_sid_cache *pc;
251 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
252 if (sid_compare(&pc->sid, psid) == 0) {
253 fstring sid;
254 *pgid = pc->gid;
255 DEBUG(3,("fetch uid from cache %u -> %s\n",
256 (unsigned int)*pgid, sid_to_string(sid, psid)));
257 DLIST_PROMOTE(gid_sid_cache_head, pc);
258 return True;
261 return False;
264 /*****************************************************************
265 Store gid to SID mapping in cache.
266 *****************************************************************/
268 static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
270 struct gid_sid_cache *pc;
272 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
273 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
274 struct gid_sid_cache *pc_next;
275 size_t i;
277 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
279 for(; pc; pc = pc_next) {
280 pc_next = pc->next;
281 DLIST_REMOVE(gid_sid_cache_head,pc);
282 SAFE_FREE(pc);
283 n_gid_sid_cache--;
287 pc = (struct gid_sid_cache *)malloc(sizeof(struct gid_sid_cache));
288 if (!pc)
289 return;
290 pc->gid = gid;
291 sid_copy(&pc->sid, psid);
292 DLIST_ADD(gid_sid_cache_head, pc);
293 n_gid_sid_cache++;
296 /*****************************************************************
297 *THE CANONICAL* convert uid_t to SID function.
298 *****************************************************************/
300 NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid)
302 fstring sid;
303 uid_t low, high;
305 ZERO_STRUCTP(psid);
307 if (fetch_sid_from_uid_cache(psid, uid))
308 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
310 /* DC's never use winbindd to resolve users outside the
311 defined idmap range */
313 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
314 || (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) )
316 if (winbind_uid_to_sid(psid, uid)) {
318 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
319 (unsigned int)uid, sid_to_string(sid, psid)));
321 if (psid)
322 store_uid_sid_cache(psid, uid);
323 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
327 if (!local_uid_to_sid(psid, uid)) {
328 DEBUG(10,("uid_to_sid: local %u failed to map to sid\n", (unsigned int)uid ));
329 return NT_STATUS_UNSUCCESSFUL;
332 DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
334 store_uid_sid_cache(psid, uid);
335 return NT_STATUS_OK;
338 /*****************************************************************
339 *THE CANONICAL* convert gid_t to SID function.
340 *****************************************************************/
342 NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid)
344 fstring sid;
345 gid_t low, high;
347 ZERO_STRUCTP(psid);
349 if (fetch_sid_from_gid_cache(psid, gid))
350 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
352 /* DC's never use winbindd to resolve groups outside the
353 defined idmap range */
355 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
356 || (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) )
358 if (winbind_gid_to_sid(psid, gid)) {
360 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
361 (unsigned int)gid, sid_to_string(sid, psid)));
363 if (psid)
364 store_gid_sid_cache(psid, gid);
365 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
369 if (!local_gid_to_sid(psid, gid)) {
370 DEBUG(10,("gid_to_sid: local %u failed to map to sid\n", (unsigned int)gid ));
371 return NT_STATUS_UNSUCCESSFUL;
374 DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
376 store_gid_sid_cache(psid, gid);
377 return NT_STATUS_OK;
380 /*****************************************************************
381 *THE CANONICAL* convert SID to uid function.
382 *****************************************************************/
384 NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid)
386 fstring dom_name, name, sid_str;
387 enum SID_NAME_USE name_type;
389 if (fetch_uid_from_cache(puid, psid))
390 return NT_STATUS_OK;
392 /* if this is our SID then go straight to a local lookup */
394 if ( sid_compare_domain(get_global_sam_sid(), psid) == 0 ) {
395 DEBUG(10,("sid_to_uid: my domain (%s) - trying local.\n",
396 sid_string_static(psid) ));
398 if ( local_sid_to_uid(puid, psid, &name_type) )
399 goto success;
401 DEBUG(10,("sid_to_uid: local lookup failed\n"));
403 return NT_STATUS_UNSUCCESSFUL;
406 /* If it is not our local domain, only hope is winbindd */
408 if ( !winbind_lookup_sid(psid, dom_name, name, &name_type) ) {
409 DEBUG(10,("sid_to_uid: winbind lookup for non-local sid %s failed\n",
410 sid_string_static(psid) ));
412 return NT_STATUS_UNSUCCESSFUL;
415 /* If winbindd does know the SID, ensure this is a user */
417 if (name_type != SID_NAME_USER) {
418 DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a user (%u)\n",
419 (unsigned int)name_type ));
420 return NT_STATUS_INVALID_PARAMETER;
423 /* get the uid. Has to work or else we are dead in the water */
425 if ( !winbind_sid_to_uid(puid, psid) ) {
426 DEBUG(10,("sid_to_uid: winbind failed to allocate a new uid for sid %s\n",
427 sid_to_string(sid_str, psid) ));
428 return NT_STATUS_UNSUCCESSFUL;
431 success:
432 DEBUG(10,("sid_to_uid: %s -> %u\n", sid_to_string(sid_str, psid),
433 (unsigned int)*puid ));
435 store_uid_sid_cache(psid, *puid);
437 return NT_STATUS_OK;
439 /*****************************************************************
440 *THE CANONICAL* convert SID to gid function.
441 Group mapping is used for gids that maps to Wellknown SIDs
442 *****************************************************************/
444 NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid)
446 fstring dom_name, name, sid_str;
447 enum SID_NAME_USE name_type;
449 if (fetch_gid_from_cache(pgid, psid))
450 return NT_STATUS_OK;
453 * First we must look up the name and decide if this is a group sid.
454 * Group mapping can deal with foreign SIDs
457 if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
458 DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed - trying local.\n",
459 sid_to_string(sid_str, psid) ));
461 if ( local_sid_to_gid(pgid, psid, &name_type) )
462 goto success;
464 DEBUG(10,("sid_to_gid: no one knows this SID\n"));
466 return NT_STATUS_UNSUCCESSFUL;
469 /* winbindd knows it; Ensure this is a group sid */
471 if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS)
472 && (name_type != SID_NAME_WKN_GRP))
474 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
475 (unsigned int)name_type ));
477 /* winbindd is running and knows about this SID. Just the wrong type.
478 Don't fallback to a local lookup here */
480 return NT_STATUS_INVALID_PARAMETER;
483 /* winbindd knows it and it is a type of group; sid_to_gid must succeed
484 or we are dead in the water */
486 if ( !winbind_sid_to_gid(pgid, psid) ) {
487 DEBUG(10,("sid_to_uid: winbind failed to allocate a new gid for sid %s\n",
488 sid_to_string(sid_str, psid) ));
489 return NT_STATUS_UNSUCCESSFUL;
492 success:
493 DEBUG(10,("sid_to_gid: %s -> %u\n", sid_to_string(sid_str, psid),
494 (unsigned int)*pgid ));
496 store_gid_sid_cache(psid, *pgid);
498 return NT_STATUS_OK;