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->num_auths == 4 && sid_equal(get_global_sam_sid(), 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) {
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)) {
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);
115 /*****************************************************************
116 Id mapping cache. This is to avoid Winbind mappings already
117 seen by smbd to be queried too frequently, keeping winbindd
118 busy, and blocking smbd while winbindd is busy with other
119 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
120 modified to use linked lists by jra.
121 *****************************************************************/
123 #define MAX_UID_SID_CACHE_SIZE 100
124 #define TURNOVER_UID_SID_CACHE_SIZE 10
125 #define MAX_GID_SID_CACHE_SIZE 100
126 #define TURNOVER_GID_SID_CACHE_SIZE 10
128 static size_t n_uid_sid_cache = 0;
129 static size_t n_gid_sid_cache = 0;
131 static struct uid_sid_cache {
132 struct uid_sid_cache *next, *prev;
135 enum SID_NAME_USE sidtype;
136 } *uid_sid_cache_head;
138 static struct gid_sid_cache {
139 struct gid_sid_cache *next, *prev;
142 enum SID_NAME_USE sidtype;
143 } *gid_sid_cache_head;
145 /*****************************************************************
146 Find a SID given a uid.
147 *****************************************************************/
149 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
151 struct uid_sid_cache *pc;
153 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
154 if (pc->uid == uid) {
157 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
158 (unsigned int)uid, sid_to_string(sid, psid)));
159 DLIST_PROMOTE(uid_sid_cache_head, pc);
166 /*****************************************************************
167 Find a uid given a SID.
168 *****************************************************************/
170 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
172 struct uid_sid_cache *pc;
174 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
175 if (sid_compare(&pc->sid, psid) == 0) {
178 DEBUG(3,("fetch uid from cache %u -> %s\n",
179 (unsigned int)*puid, sid_to_string(sid, psid)));
180 DLIST_PROMOTE(uid_sid_cache_head, pc);
187 /*****************************************************************
188 Store uid to SID mapping in cache.
189 *****************************************************************/
191 static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
193 struct uid_sid_cache *pc;
195 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
196 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
197 struct uid_sid_cache *pc_next;
200 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
202 for(; pc; pc = pc_next) {
204 DLIST_REMOVE(uid_sid_cache_head,pc);
210 pc = SMB_MALLOC_P(struct uid_sid_cache);
214 sid_copy(&pc->sid, psid);
215 DLIST_ADD(uid_sid_cache_head, pc);
219 /*****************************************************************
220 Find a SID given a gid.
221 *****************************************************************/
223 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
225 struct gid_sid_cache *pc;
227 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
228 if (pc->gid == gid) {
231 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
232 (unsigned int)gid, sid_to_string(sid, psid)));
233 DLIST_PROMOTE(gid_sid_cache_head, pc);
240 /*****************************************************************
241 Find a gid given a SID.
242 *****************************************************************/
244 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
246 struct gid_sid_cache *pc;
248 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
249 if (sid_compare(&pc->sid, psid) == 0) {
252 DEBUG(3,("fetch gid from cache %u -> %s\n",
253 (unsigned int)*pgid, sid_to_string(sid, psid)));
254 DLIST_PROMOTE(gid_sid_cache_head, pc);
261 /*****************************************************************
262 Store gid to SID mapping in cache.
263 *****************************************************************/
265 static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
267 struct gid_sid_cache *pc;
269 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
270 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
271 struct gid_sid_cache *pc_next;
274 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
276 for(; pc; pc = pc_next) {
278 DLIST_REMOVE(gid_sid_cache_head,pc);
284 pc = SMB_MALLOC_P(struct gid_sid_cache);
288 sid_copy(&pc->sid, psid);
289 DLIST_ADD(gid_sid_cache_head, pc);
293 /*****************************************************************
294 *THE CANONICAL* convert uid_t to SID function.
295 *****************************************************************/
297 NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid)
304 if (fetch_sid_from_uid_cache(psid, uid))
305 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
307 /* DC's never use winbindd to resolve users outside the
308 defined idmap range */
310 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
311 || (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) )
313 if (winbind_uid_to_sid(psid, uid)) {
315 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
316 (unsigned int)uid, sid_to_string(sid, psid)));
319 store_uid_sid_cache(psid, uid);
320 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
324 if (!local_uid_to_sid(psid, uid)) {
325 DEBUG(10,("uid_to_sid: local %u failed to map to sid\n", (unsigned int)uid ));
326 return NT_STATUS_UNSUCCESSFUL;
329 DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
331 store_uid_sid_cache(psid, uid);
335 /*****************************************************************
336 *THE CANONICAL* convert gid_t to SID function.
337 *****************************************************************/
339 NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid)
346 if (fetch_sid_from_gid_cache(psid, gid))
347 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
349 /* DC's never use winbindd to resolve groups outside the
350 defined idmap range */
352 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
353 || (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) )
355 if (winbind_gid_to_sid(psid, gid)) {
357 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
358 (unsigned int)gid, sid_to_string(sid, psid)));
361 store_gid_sid_cache(psid, gid);
362 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
366 if (!local_gid_to_sid(psid, gid)) {
367 DEBUG(10,("gid_to_sid: local %u failed to map to sid\n", (unsigned int)gid ));
368 return NT_STATUS_UNSUCCESSFUL;
371 DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
373 store_gid_sid_cache(psid, gid);
377 /*****************************************************************
378 *THE CANONICAL* convert SID to uid function.
379 *****************************************************************/
381 NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid)
383 fstring dom_name, name, sid_str;
384 enum SID_NAME_USE name_type;
386 if (fetch_uid_from_cache(puid, psid))
389 /* if this is our SID then go straight to a local lookup */
391 if ( sid_compare_domain(get_global_sam_sid(), psid) == 0 ) {
392 DEBUG(10,("sid_to_uid: my domain (%s) - trying local.\n",
393 sid_string_static(psid) ));
395 if ( local_sid_to_uid(puid, psid, &name_type) )
398 DEBUG(10,("sid_to_uid: local lookup failed\n"));
400 return NT_STATUS_UNSUCCESSFUL;
403 /* If it is not our local domain, only hope is winbindd */
405 if ( !winbind_lookup_sid(psid, dom_name, name, &name_type) ) {
406 DEBUG(10,("sid_to_uid: winbind lookup for non-local sid %s failed\n",
407 sid_string_static(psid) ));
409 return NT_STATUS_UNSUCCESSFUL;
412 /* If winbindd does know the SID, ensure this is a user */
414 if (name_type != SID_NAME_USER) {
415 DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a user (%u)\n",
416 (unsigned int)name_type ));
417 return NT_STATUS_INVALID_PARAMETER;
420 /* get the uid. Has to work or else we are dead in the water */
422 if ( !winbind_sid_to_uid(puid, psid) ) {
423 DEBUG(10,("sid_to_uid: winbind failed to allocate a new uid for sid %s\n",
424 sid_to_string(sid_str, psid) ));
425 return NT_STATUS_UNSUCCESSFUL;
429 DEBUG(10,("sid_to_uid: %s -> %u\n", sid_to_string(sid_str, psid),
430 (unsigned int)*puid ));
432 store_uid_sid_cache(psid, *puid);
436 /*****************************************************************
437 *THE CANONICAL* convert SID to gid function.
438 Group mapping is used for gids that maps to Wellknown SIDs
439 *****************************************************************/
441 NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid)
443 fstring dom_name, name, sid_str;
444 enum SID_NAME_USE name_type;
446 if (fetch_gid_from_cache(pgid, psid))
450 * First we must look up the name and decide if this is a group sid.
451 * Group mapping can deal with foreign SIDs
454 if ( local_sid_to_gid(pgid, psid, &name_type) )
457 if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
458 DEBUG(10,("sid_to_gid: no one knows the SID %s (tried local, then winbind)\n", sid_to_string(sid_str, psid)));
460 return NT_STATUS_UNSUCCESSFUL;
463 /* winbindd knows it; Ensure this is a group sid */
465 if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS)
466 && (name_type != SID_NAME_WKN_GRP))
468 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
469 (unsigned int)name_type ));
471 /* winbindd is running and knows about this SID. Just the wrong type.
472 Don't fallback to a local lookup here */
474 return NT_STATUS_INVALID_PARAMETER;
477 /* winbindd knows it and it is a type of group; sid_to_gid must succeed
478 or we are dead in the water */
480 if ( !winbind_sid_to_gid(pgid, psid) ) {
481 DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid for sid %s\n",
482 sid_to_string(sid_str, psid) ));
483 return NT_STATUS_UNSUCCESSFUL;
487 DEBUG(10,("sid_to_gid: %s -> %u\n", sid_to_string(sid_str, psid),
488 (unsigned int)*pgid ));
490 store_gid_sid_cache(psid, *pgid);