2 Unix SMB/CIFS implementation.
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.
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)
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)) {
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));
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));
58 DEBUG(10, ("lookup_name: %s lookup for [%s]\\[%s] failed\n",
59 local_lookup ? "local" : "winbind", domain, name));
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)
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_check_is_domain(sid)) {
80 fstrcpy(dom_name, get_global_sam_name());
82 *name_type = SID_NAME_DOMAIN;
86 if (sid_check_is_builtin(sid)) {
88 /* Got through map_domain_sid_to_name here so that the mapping
89 * of S-1-5-32 to the name "BUILTIN" in as few places as
90 * possible. We might add i18n... */
91 SMB_ASSERT(map_domain_sid_to_name(sid, dom_name));
93 /* Yes, W2k3 returns "BUILTIN" both as domain and name here */
94 fstrcpy(name, dom_name);
96 *name_type = SID_NAME_DOMAIN;
100 if (sid_check_is_in_our_domain(sid)) {
102 SMB_ASSERT(sid_peek_rid(sid, &rid));
104 /* For our own domain passdb is responsible */
105 fstrcpy(dom_name, get_global_sam_name());
106 return local_lookup_rid(rid, name, name_type);
109 if (winbind_lookup_sid(sid, dom_name, name, name_type)) {
113 DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying "
114 "special SIDs.\n", sid_string_static(sid)));
117 const char *dom, *obj_name;
119 if (lookup_special_sid(sid, &dom, &obj_name, name_type)) {
120 DEBUG(10, ("found %s\\%s\n", dom, obj_name));
121 fstrcpy(dom_name, dom);
122 fstrcpy(name, obj_name);
127 DEBUG(10, ("lookup_sid failed\n"));
132 /*****************************************************************
133 Id mapping cache. This is to avoid Winbind mappings already
134 seen by smbd to be queried too frequently, keeping winbindd
135 busy, and blocking smbd while winbindd is busy with other
136 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
137 modified to use linked lists by jra.
138 *****************************************************************/
140 #define MAX_UID_SID_CACHE_SIZE 100
141 #define TURNOVER_UID_SID_CACHE_SIZE 10
142 #define MAX_GID_SID_CACHE_SIZE 100
143 #define TURNOVER_GID_SID_CACHE_SIZE 10
145 static size_t n_uid_sid_cache = 0;
146 static size_t n_gid_sid_cache = 0;
148 static struct uid_sid_cache {
149 struct uid_sid_cache *next, *prev;
152 enum SID_NAME_USE sidtype;
153 } *uid_sid_cache_head;
155 static struct gid_sid_cache {
156 struct gid_sid_cache *next, *prev;
159 enum SID_NAME_USE sidtype;
160 } *gid_sid_cache_head;
162 /*****************************************************************
163 Find a SID given a uid.
164 *****************************************************************/
166 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
168 struct uid_sid_cache *pc;
170 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
171 if (pc->uid == uid) {
174 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
175 (unsigned int)uid, sid_to_string(sid, psid)));
176 DLIST_PROMOTE(uid_sid_cache_head, pc);
183 /*****************************************************************
184 Find a uid given a SID.
185 *****************************************************************/
187 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
189 struct uid_sid_cache *pc;
191 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
192 if (sid_compare(&pc->sid, psid) == 0) {
195 DEBUG(3,("fetch uid from cache %u -> %s\n",
196 (unsigned int)*puid, sid_to_string(sid, psid)));
197 DLIST_PROMOTE(uid_sid_cache_head, pc);
204 /*****************************************************************
205 Store uid to SID mapping in cache.
206 *****************************************************************/
208 static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
210 struct uid_sid_cache *pc;
212 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
213 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
214 struct uid_sid_cache *pc_next;
217 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
219 for(; pc; pc = pc_next) {
221 DLIST_REMOVE(uid_sid_cache_head,pc);
227 pc = SMB_MALLOC_P(struct uid_sid_cache);
231 sid_copy(&pc->sid, psid);
232 DLIST_ADD(uid_sid_cache_head, pc);
236 /*****************************************************************
237 Find a SID given a gid.
238 *****************************************************************/
240 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
242 struct gid_sid_cache *pc;
244 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
245 if (pc->gid == gid) {
248 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
249 (unsigned int)gid, sid_to_string(sid, psid)));
250 DLIST_PROMOTE(gid_sid_cache_head, pc);
257 /*****************************************************************
258 Find a gid given a SID.
259 *****************************************************************/
261 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
263 struct gid_sid_cache *pc;
265 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
266 if (sid_compare(&pc->sid, psid) == 0) {
269 DEBUG(3,("fetch gid from cache %u -> %s\n",
270 (unsigned int)*pgid, sid_to_string(sid, psid)));
271 DLIST_PROMOTE(gid_sid_cache_head, pc);
278 /*****************************************************************
279 Store gid to SID mapping in cache.
280 *****************************************************************/
282 static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
284 struct gid_sid_cache *pc;
286 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
287 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
288 struct gid_sid_cache *pc_next;
291 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
293 for(; pc; pc = pc_next) {
295 DLIST_REMOVE(gid_sid_cache_head,pc);
301 pc = SMB_MALLOC_P(struct gid_sid_cache);
305 sid_copy(&pc->sid, psid);
306 DLIST_ADD(gid_sid_cache_head, pc);
310 /*****************************************************************
311 *THE CANONICAL* convert uid_t to SID function.
312 *****************************************************************/
314 NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid)
321 if (fetch_sid_from_uid_cache(psid, uid))
322 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
324 /* DC's never use winbindd to resolve users outside the
325 defined idmap range */
327 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
328 || (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) )
330 if (winbind_uid_to_sid(psid, uid)) {
332 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
333 (unsigned int)uid, sid_to_string(sid, psid)));
336 store_uid_sid_cache(psid, uid);
337 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
341 if (!local_uid_to_sid(psid, uid)) {
342 DEBUG(10,("uid_to_sid: local %u failed to map to sid\n", (unsigned int)uid ));
343 return NT_STATUS_UNSUCCESSFUL;
346 DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
348 store_uid_sid_cache(psid, uid);
352 /*****************************************************************
353 *THE CANONICAL* convert gid_t to SID function.
354 *****************************************************************/
356 NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid)
363 if (fetch_sid_from_gid_cache(psid, gid))
364 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
366 /* DC's never use winbindd to resolve groups outside the
367 defined idmap range */
369 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
370 || (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) )
372 if (winbind_gid_to_sid(psid, gid)) {
374 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
375 (unsigned int)gid, sid_to_string(sid, psid)));
378 store_gid_sid_cache(psid, gid);
379 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
383 if (!local_gid_to_sid(psid, gid)) {
384 DEBUG(10,("gid_to_sid: local %u failed to map to sid\n", (unsigned int)gid ));
385 return NT_STATUS_UNSUCCESSFUL;
388 DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
390 store_gid_sid_cache(psid, gid);
394 /*****************************************************************
395 *THE CANONICAL* convert SID to uid function.
396 *****************************************************************/
398 NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid)
400 fstring dom_name, name, sid_str;
401 enum SID_NAME_USE name_type;
403 if (fetch_uid_from_cache(puid, psid))
406 /* if this is our SID then go straight to a local lookup */
408 if ( sid_compare_domain(get_global_sam_sid(), psid) == 0 ) {
409 DEBUG(10,("sid_to_uid: my domain (%s) - trying local.\n",
410 sid_string_static(psid) ));
412 if ( local_sid_to_uid(puid, psid, &name_type) )
415 DEBUG(10,("sid_to_uid: local lookup failed\n"));
417 return NT_STATUS_UNSUCCESSFUL;
420 /* If it is not our local domain, only hope is winbindd */
422 if ( !winbind_lookup_sid(psid, dom_name, name, &name_type) ) {
423 DEBUG(10,("sid_to_uid: winbind lookup for non-local sid %s failed\n",
424 sid_string_static(psid) ));
426 return NT_STATUS_UNSUCCESSFUL;
429 /* If winbindd does know the SID, ensure this is a user */
431 if (name_type != SID_NAME_USER) {
432 DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a user (%u)\n",
433 (unsigned int)name_type ));
434 return NT_STATUS_INVALID_PARAMETER;
437 /* get the uid. Has to work or else we are dead in the water */
439 if ( !winbind_sid_to_uid(puid, psid) ) {
440 DEBUG(10,("sid_to_uid: winbind failed to allocate a new uid for sid %s\n",
441 sid_to_string(sid_str, psid) ));
442 return NT_STATUS_UNSUCCESSFUL;
446 DEBUG(10,("sid_to_uid: %s -> %u\n", sid_to_string(sid_str, psid),
447 (unsigned int)*puid ));
449 store_uid_sid_cache(psid, *puid);
453 /*****************************************************************
454 *THE CANONICAL* convert SID to gid function.
455 Group mapping is used for gids that maps to Wellknown SIDs
456 *****************************************************************/
458 NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid)
460 fstring dom_name, name, sid_str;
461 enum SID_NAME_USE name_type;
463 if (fetch_gid_from_cache(pgid, psid))
467 * First we must look up the name and decide if this is a group sid.
468 * Group mapping can deal with foreign SIDs
471 if ( local_sid_to_gid(pgid, psid, &name_type) )
474 if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
475 DEBUG(10,("sid_to_gid: no one knows the SID %s (tried local, then winbind)\n", sid_to_string(sid_str, psid)));
477 return NT_STATUS_UNSUCCESSFUL;
480 /* winbindd knows it; Ensure this is a group sid */
482 if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS)
483 && (name_type != SID_NAME_WKN_GRP))
485 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
486 (unsigned int)name_type ));
488 /* winbindd is running and knows about this SID. Just the wrong type.
489 Don't fallback to a local lookup here */
491 return NT_STATUS_INVALID_PARAMETER;
494 /* winbindd knows it and it is a type of group; sid_to_gid must succeed
495 or we are dead in the water */
497 if ( !winbind_sid_to_gid(pgid, psid) ) {
498 DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid for sid %s\n",
499 sid_to_string(sid_str, psid) ));
500 return NT_STATUS_UNSUCCESSFUL;
504 DEBUG(10,("sid_to_gid: %s -> %u\n", sid_to_string(sid_str, psid),
505 (unsigned int)*pgid ));
507 store_gid_sid_cache(psid, *pgid);