r85: Update the winbind interface version, as I just extended the struct.
[Samba/gebeck_regimport.git] / source3 / passdb / lookup_sid.c
blob842db8de5dc7529d1947b5ccd91732c8fa9ce97e
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;
109 /*****************************************************************
110 Id mapping cache. This is to avoid Winbind mappings already
111 seen by smbd to be queried too frequently, keeping winbindd
112 busy, and blocking smbd while winbindd is busy with other
113 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
114 modified to use linked lists by jra.
115 *****************************************************************/
117 #define MAX_UID_SID_CACHE_SIZE 100
118 #define TURNOVER_UID_SID_CACHE_SIZE 10
119 #define MAX_GID_SID_CACHE_SIZE 100
120 #define TURNOVER_GID_SID_CACHE_SIZE 10
122 static size_t n_uid_sid_cache = 0;
123 static size_t n_gid_sid_cache = 0;
125 static struct uid_sid_cache {
126 struct uid_sid_cache *next, *prev;
127 uid_t uid;
128 DOM_SID sid;
129 enum SID_NAME_USE sidtype;
130 } *uid_sid_cache_head;
132 static struct gid_sid_cache {
133 struct gid_sid_cache *next, *prev;
134 gid_t gid;
135 DOM_SID sid;
136 enum SID_NAME_USE sidtype;
137 } *gid_sid_cache_head;
139 /*****************************************************************
140 Find a SID given a uid.
141 *****************************************************************/
143 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
145 struct uid_sid_cache *pc;
147 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
148 if (pc->uid == uid) {
149 fstring sid;
150 *psid = pc->sid;
151 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
152 (unsigned int)uid, sid_to_string(sid, psid)));
153 DLIST_PROMOTE(uid_sid_cache_head, pc);
154 return True;
157 return False;
160 /*****************************************************************
161 Find a uid given a SID.
162 *****************************************************************/
164 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
166 struct uid_sid_cache *pc;
168 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
169 if (sid_compare(&pc->sid, psid) == 0) {
170 fstring sid;
171 *puid = pc->uid;
172 DEBUG(3,("fetch uid from cache %u -> %s\n",
173 (unsigned int)*puid, sid_to_string(sid, psid)));
174 DLIST_PROMOTE(uid_sid_cache_head, pc);
175 return True;
178 return False;
181 /*****************************************************************
182 Store uid to SID mapping in cache.
183 *****************************************************************/
185 static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
187 struct uid_sid_cache *pc;
189 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
190 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
191 struct uid_sid_cache *pc_next;
192 size_t i;
194 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
196 for(; pc; pc = pc_next) {
197 pc_next = pc->next;
198 DLIST_REMOVE(uid_sid_cache_head,pc);
199 SAFE_FREE(pc);
200 n_uid_sid_cache--;
204 pc = (struct uid_sid_cache *)malloc(sizeof(struct uid_sid_cache));
205 if (!pc)
206 return;
207 pc->uid = uid;
208 sid_copy(&pc->sid, psid);
209 DLIST_ADD(uid_sid_cache_head, pc);
210 n_uid_sid_cache++;
213 /*****************************************************************
214 Find a SID given a gid.
215 *****************************************************************/
217 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
219 struct gid_sid_cache *pc;
221 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
222 if (pc->gid == gid) {
223 fstring sid;
224 *psid = pc->sid;
225 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
226 (unsigned int)gid, sid_to_string(sid, psid)));
227 DLIST_PROMOTE(gid_sid_cache_head, pc);
228 return True;
231 return False;
234 /*****************************************************************
235 Find a gid given a SID.
236 *****************************************************************/
238 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
240 struct gid_sid_cache *pc;
242 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
243 if (sid_compare(&pc->sid, psid) == 0) {
244 fstring sid;
245 *pgid = pc->gid;
246 DEBUG(3,("fetch uid from cache %u -> %s\n",
247 (unsigned int)*pgid, sid_to_string(sid, psid)));
248 DLIST_PROMOTE(gid_sid_cache_head, pc);
249 return True;
252 return False;
255 /*****************************************************************
256 Store gid to SID mapping in cache.
257 *****************************************************************/
259 static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
261 struct gid_sid_cache *pc;
263 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
264 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
265 struct gid_sid_cache *pc_next;
266 size_t i;
268 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
270 for(; pc; pc = pc_next) {
271 pc_next = pc->next;
272 DLIST_REMOVE(gid_sid_cache_head,pc);
273 SAFE_FREE(pc);
274 n_gid_sid_cache--;
278 pc = (struct gid_sid_cache *)malloc(sizeof(struct gid_sid_cache));
279 if (!pc)
280 return;
281 pc->gid = gid;
282 sid_copy(&pc->sid, psid);
283 DLIST_ADD(gid_sid_cache_head, pc);
284 n_gid_sid_cache++;
287 /*****************************************************************
288 *THE CANONICAL* convert uid_t to SID function.
289 *****************************************************************/
291 NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid)
293 fstring sid;
294 uid_t low, high;
296 ZERO_STRUCTP(psid);
298 if (fetch_sid_from_uid_cache(psid, uid))
299 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
301 /* DC's never use winbindd to resolve users outside the
302 defined idmap range */
304 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
305 || (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) )
307 if (winbind_uid_to_sid(psid, uid)) {
309 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
310 (unsigned int)uid, sid_to_string(sid, psid)));
312 if (psid)
313 store_uid_sid_cache(psid, uid);
314 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
318 if (!local_uid_to_sid(psid, uid)) {
319 DEBUG(10,("uid_to_sid: local %u failed to map to sid\n", (unsigned int)uid ));
320 return NT_STATUS_UNSUCCESSFUL;
323 DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
325 store_uid_sid_cache(psid, uid);
326 return NT_STATUS_OK;
329 /*****************************************************************
330 *THE CANONICAL* convert gid_t to SID function.
331 *****************************************************************/
333 NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid)
335 fstring sid;
336 gid_t low, high;
338 ZERO_STRUCTP(psid);
340 if (fetch_sid_from_gid_cache(psid, gid))
341 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
343 /* DC's never use winbindd to resolve groups outside the
344 defined idmap range */
346 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
347 || (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) )
349 if (winbind_gid_to_sid(psid, gid)) {
351 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
352 (unsigned int)gid, sid_to_string(sid, psid)));
354 if (psid)
355 store_gid_sid_cache(psid, gid);
356 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
360 if (!local_gid_to_sid(psid, gid)) {
361 DEBUG(10,("gid_to_sid: local %u failed to map to sid\n", (unsigned int)gid ));
362 return NT_STATUS_UNSUCCESSFUL;
365 DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
367 store_gid_sid_cache(psid, gid);
368 return NT_STATUS_OK;
371 /*****************************************************************
372 *THE CANONICAL* convert SID to uid function.
373 *****************************************************************/
375 NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid)
377 fstring dom_name, name, sid_str;
378 enum SID_NAME_USE name_type;
380 if (fetch_uid_from_cache(puid, psid))
381 return NT_STATUS_OK;
383 /* if this is our SID then go straight to a local lookup */
385 if ( sid_compare_domain(get_global_sam_sid(), psid) == 0 ) {
386 DEBUG(10,("sid_to_uid: my domain (%s) - trying local.\n",
387 sid_string_static(psid) ));
389 if ( local_sid_to_uid(puid, psid, &name_type) )
390 goto success;
392 DEBUG(10,("sid_to_uid: local lookup failed\n"));
394 return NT_STATUS_UNSUCCESSFUL;
397 /* If it is not our local domain, only hope is winbindd */
399 if ( !winbind_lookup_sid(psid, dom_name, name, &name_type) ) {
400 DEBUG(10,("sid_to_uid: winbind lookup for non-local sid %s failed\n",
401 sid_string_static(psid) ));
403 return NT_STATUS_UNSUCCESSFUL;
406 /* If winbindd does know the SID, ensure this is a user */
408 if (name_type != SID_NAME_USER) {
409 DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a user (%u)\n",
410 (unsigned int)name_type ));
411 return NT_STATUS_INVALID_PARAMETER;
414 /* get the uid. Has to work or else we are dead in the water */
416 if ( !winbind_sid_to_uid(puid, psid) ) {
417 DEBUG(10,("sid_to_uid: winbind failed to allocate a new uid for sid %s\n",
418 sid_to_string(sid_str, psid) ));
419 return NT_STATUS_UNSUCCESSFUL;
422 success:
423 DEBUG(10,("sid_to_uid: %s -> %u\n", sid_to_string(sid_str, psid),
424 (unsigned int)*puid ));
426 store_uid_sid_cache(psid, *puid);
428 return NT_STATUS_OK;
430 /*****************************************************************
431 *THE CANONICAL* convert SID to gid function.
432 Group mapping is used for gids that maps to Wellknown SIDs
433 *****************************************************************/
435 NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid)
437 fstring dom_name, name, sid_str;
438 enum SID_NAME_USE name_type;
440 if (fetch_gid_from_cache(pgid, psid))
441 return NT_STATUS_OK;
444 * First we must look up the name and decide if this is a group sid.
445 * Group mapping can deal with foreign SIDs
448 if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
449 DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed - trying local.\n",
450 sid_to_string(sid_str, psid) ));
452 if ( local_sid_to_gid(pgid, psid, &name_type) )
453 goto success;
455 DEBUG(10,("sid_to_gid: no one knows this SID\n"));
457 return NT_STATUS_UNSUCCESSFUL;
460 /* winbindd knows it; Ensure this is a group sid */
462 if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS)
463 && (name_type != SID_NAME_WKN_GRP))
465 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
466 (unsigned int)name_type ));
468 /* winbindd is running and knows about this SID. Just the wrong type.
469 Don't fallback to a local lookup here */
471 return NT_STATUS_INVALID_PARAMETER;
474 /* winbindd knows it and it is a type of group; sid_to_gid must succeed
475 or we are dead in the water */
477 if ( !winbind_sid_to_gid(pgid, psid) ) {
478 DEBUG(10,("sid_to_uid: winbind failed to allocate a new gid for sid %s\n",
479 sid_to_string(sid_str, psid) ));
480 return NT_STATUS_UNSUCCESSFUL;
483 success:
484 DEBUG(10,("sid_to_gid: %s -> %u\n", sid_to_string(sid_str, psid),
485 (unsigned int)*pgid ));
487 store_gid_sid_cache(psid, *pgid);
489 return NT_STATUS_OK;