r7415: * big change -- volker's new async winbindd from trunk
[Samba/gbeck.git] / source / passdb / lookup_sid.c
blob6fcd4582f2dce244b8992c35d6f97bf000692365
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;
115 BOOL sid_to_local_user_name(const DOM_SID *sid, fstring username)
117 fstring dom_name;
118 fstring name;
119 enum SID_NAME_USE type;
121 if (!sid_check_is_in_our_domain(sid))
122 return False;
124 if (!lookup_sid(sid, dom_name, name, &type))
125 return False;
127 if (type != SID_NAME_USER)
128 return False;
130 fstrcpy(username, name);
131 return True;
134 BOOL sid_to_local_dom_grp_name(const DOM_SID *sid, fstring groupname)
136 fstring dom_name;
137 fstring name;
138 enum SID_NAME_USE type;
140 if (!sid_check_is_in_our_domain(sid))
141 return False;
143 if (!lookup_sid(sid, dom_name, name, &type))
144 return False;
146 if (type != SID_NAME_DOM_GRP)
147 return False;
149 fstrcpy(groupname, name);
150 return True;
154 /*****************************************************************
155 Id mapping cache. This is to avoid Winbind mappings already
156 seen by smbd to be queried too frequently, keeping winbindd
157 busy, and blocking smbd while winbindd is busy with other
158 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
159 modified to use linked lists by jra.
160 *****************************************************************/
162 #define MAX_UID_SID_CACHE_SIZE 100
163 #define TURNOVER_UID_SID_CACHE_SIZE 10
164 #define MAX_GID_SID_CACHE_SIZE 100
165 #define TURNOVER_GID_SID_CACHE_SIZE 10
167 static size_t n_uid_sid_cache = 0;
168 static size_t n_gid_sid_cache = 0;
170 static struct uid_sid_cache {
171 struct uid_sid_cache *next, *prev;
172 uid_t uid;
173 DOM_SID sid;
174 enum SID_NAME_USE sidtype;
175 } *uid_sid_cache_head;
177 static struct gid_sid_cache {
178 struct gid_sid_cache *next, *prev;
179 gid_t gid;
180 DOM_SID sid;
181 enum SID_NAME_USE sidtype;
182 } *gid_sid_cache_head;
184 /*****************************************************************
185 Find a SID given a uid.
186 *****************************************************************/
188 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
190 struct uid_sid_cache *pc;
192 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
193 if (pc->uid == uid) {
194 fstring sid;
195 *psid = pc->sid;
196 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
197 (unsigned int)uid, sid_to_string(sid, psid)));
198 DLIST_PROMOTE(uid_sid_cache_head, pc);
199 return True;
202 return False;
205 /*****************************************************************
206 Find a uid given a SID.
207 *****************************************************************/
209 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
211 struct uid_sid_cache *pc;
213 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
214 if (sid_compare(&pc->sid, psid) == 0) {
215 fstring sid;
216 *puid = pc->uid;
217 DEBUG(3,("fetch uid from cache %u -> %s\n",
218 (unsigned int)*puid, sid_to_string(sid, psid)));
219 DLIST_PROMOTE(uid_sid_cache_head, pc);
220 return True;
223 return False;
226 /*****************************************************************
227 Store uid to SID mapping in cache.
228 *****************************************************************/
230 static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
232 struct uid_sid_cache *pc;
234 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
235 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
236 struct uid_sid_cache *pc_next;
237 size_t i;
239 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
241 for(; pc; pc = pc_next) {
242 pc_next = pc->next;
243 DLIST_REMOVE(uid_sid_cache_head,pc);
244 SAFE_FREE(pc);
245 n_uid_sid_cache--;
249 pc = SMB_MALLOC_P(struct uid_sid_cache);
250 if (!pc)
251 return;
252 pc->uid = uid;
253 sid_copy(&pc->sid, psid);
254 DLIST_ADD(uid_sid_cache_head, pc);
255 n_uid_sid_cache++;
258 /*****************************************************************
259 Find a SID given a gid.
260 *****************************************************************/
262 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
264 struct gid_sid_cache *pc;
266 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
267 if (pc->gid == gid) {
268 fstring sid;
269 *psid = pc->sid;
270 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
271 (unsigned int)gid, sid_to_string(sid, psid)));
272 DLIST_PROMOTE(gid_sid_cache_head, pc);
273 return True;
276 return False;
279 /*****************************************************************
280 Find a gid given a SID.
281 *****************************************************************/
283 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
285 struct gid_sid_cache *pc;
287 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
288 if (sid_compare(&pc->sid, psid) == 0) {
289 fstring sid;
290 *pgid = pc->gid;
291 DEBUG(3,("fetch gid from cache %u -> %s\n",
292 (unsigned int)*pgid, sid_to_string(sid, psid)));
293 DLIST_PROMOTE(gid_sid_cache_head, pc);
294 return True;
297 return False;
300 /*****************************************************************
301 Store gid to SID mapping in cache.
302 *****************************************************************/
304 static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
306 struct gid_sid_cache *pc;
308 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
309 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
310 struct gid_sid_cache *pc_next;
311 size_t i;
313 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
315 for(; pc; pc = pc_next) {
316 pc_next = pc->next;
317 DLIST_REMOVE(gid_sid_cache_head,pc);
318 SAFE_FREE(pc);
319 n_gid_sid_cache--;
323 pc = SMB_MALLOC_P(struct gid_sid_cache);
324 if (!pc)
325 return;
326 pc->gid = gid;
327 sid_copy(&pc->sid, psid);
328 DLIST_ADD(gid_sid_cache_head, pc);
329 n_gid_sid_cache++;
332 /*****************************************************************
333 *THE CANONICAL* convert uid_t to SID function.
334 *****************************************************************/
336 NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid)
338 fstring sid;
339 uid_t low, high;
341 ZERO_STRUCTP(psid);
343 if (fetch_sid_from_uid_cache(psid, uid))
344 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
346 /* DC's never use winbindd to resolve users outside the
347 defined idmap range */
349 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
350 || (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) )
352 if (winbind_uid_to_sid(psid, uid)) {
354 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
355 (unsigned int)uid, sid_to_string(sid, psid)));
357 if (psid)
358 store_uid_sid_cache(psid, uid);
359 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
363 if (!local_uid_to_sid(psid, uid)) {
364 DEBUG(10,("uid_to_sid: local %u failed to map to sid\n", (unsigned int)uid ));
365 return NT_STATUS_UNSUCCESSFUL;
368 DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
370 store_uid_sid_cache(psid, uid);
371 return NT_STATUS_OK;
374 /*****************************************************************
375 *THE CANONICAL* convert gid_t to SID function.
376 *****************************************************************/
378 NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid)
380 fstring sid;
381 gid_t low, high;
383 ZERO_STRUCTP(psid);
385 if (fetch_sid_from_gid_cache(psid, gid))
386 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
388 /* DC's never use winbindd to resolve groups outside the
389 defined idmap range */
391 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
392 || (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) )
394 if (winbind_gid_to_sid(psid, gid)) {
396 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
397 (unsigned int)gid, sid_to_string(sid, psid)));
399 if (psid)
400 store_gid_sid_cache(psid, gid);
401 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
405 if (!local_gid_to_sid(psid, gid)) {
406 DEBUG(10,("gid_to_sid: local %u failed to map to sid\n", (unsigned int)gid ));
407 return NT_STATUS_UNSUCCESSFUL;
410 DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
412 store_gid_sid_cache(psid, gid);
413 return NT_STATUS_OK;
416 /*****************************************************************
417 *THE CANONICAL* convert SID to uid function.
418 *****************************************************************/
420 NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid)
422 fstring dom_name, name, sid_str;
423 enum SID_NAME_USE name_type;
425 if (fetch_uid_from_cache(puid, psid))
426 return NT_STATUS_OK;
428 /* if this is our SID then go straight to a local lookup */
430 if ( sid_compare_domain(get_global_sam_sid(), psid) == 0 ) {
431 DEBUG(10,("sid_to_uid: my domain (%s) - trying local.\n",
432 sid_string_static(psid) ));
434 if ( local_sid_to_uid(puid, psid, &name_type) )
435 goto success;
437 DEBUG(10,("sid_to_uid: local lookup failed\n"));
439 return NT_STATUS_UNSUCCESSFUL;
442 /* If it is not our local domain, only hope is winbindd */
444 if ( !winbind_lookup_sid(psid, dom_name, name, &name_type) ) {
445 DEBUG(10,("sid_to_uid: winbind lookup for non-local sid %s failed\n",
446 sid_string_static(psid) ));
448 return NT_STATUS_UNSUCCESSFUL;
451 /* If winbindd does know the SID, ensure this is a user */
453 if (name_type != SID_NAME_USER) {
454 DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a user (%u)\n",
455 (unsigned int)name_type ));
456 return NT_STATUS_INVALID_PARAMETER;
459 /* get the uid. Has to work or else we are dead in the water */
461 if ( !winbind_sid_to_uid(puid, psid) ) {
462 DEBUG(10,("sid_to_uid: winbind failed to allocate a new uid for sid %s\n",
463 sid_to_string(sid_str, psid) ));
464 return NT_STATUS_UNSUCCESSFUL;
467 success:
468 DEBUG(10,("sid_to_uid: %s -> %u\n", sid_to_string(sid_str, psid),
469 (unsigned int)*puid ));
471 store_uid_sid_cache(psid, *puid);
473 return NT_STATUS_OK;
475 /*****************************************************************
476 *THE CANONICAL* convert SID to gid function.
477 Group mapping is used for gids that maps to Wellknown SIDs
478 *****************************************************************/
480 NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid)
482 fstring dom_name, name, sid_str;
483 enum SID_NAME_USE name_type;
485 if (fetch_gid_from_cache(pgid, psid))
486 return NT_STATUS_OK;
489 * First we must look up the name and decide if this is a group sid.
490 * Group mapping can deal with foreign SIDs
493 if ( local_sid_to_gid(pgid, psid, &name_type) )
494 goto success;
496 if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
497 DEBUG(10,("sid_to_gid: no one knows the SID %s (tried local, then winbind)\n", sid_to_string(sid_str, psid)));
499 return NT_STATUS_UNSUCCESSFUL;
502 /* winbindd knows it; Ensure this is a group sid */
504 if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS)
505 && (name_type != SID_NAME_WKN_GRP))
507 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
508 (unsigned int)name_type ));
510 /* winbindd is running and knows about this SID. Just the wrong type.
511 Don't fallback to a local lookup here */
513 return NT_STATUS_INVALID_PARAMETER;
516 /* winbindd knows it and it is a type of group; sid_to_gid must succeed
517 or we are dead in the water */
519 if ( !winbind_sid_to_gid(pgid, psid) ) {
520 DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid for sid %s\n",
521 sid_to_string(sid_str, psid) ));
522 return NT_STATUS_UNSUCCESSFUL;
525 success:
526 DEBUG(10,("sid_to_gid: %s -> %u\n", sid_to_string(sid_str, psid),
527 (unsigned int)*pgid ));
529 store_gid_sid_cache(psid, *pgid);
531 return NT_STATUS_OK;