r12224: adding more characters to the invalid share name string
[Samba.git] / source / passdb / lookup_sid.c
blobb397e084c3382174cb92b27d1fbe2109d8763382
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,
70 enum SID_NAME_USE *name_type)
72 if (!name_type)
73 return False;
75 *name_type = SID_NAME_UNKNOWN;
77 /* Check if this is our own sid. This should perhaps be done by
78 winbind? For the moment handle it here. */
80 if (sid_check_is_domain(sid)) {
81 fstrcpy(dom_name, get_global_sam_name());
82 fstrcpy(name, "");
83 *name_type = SID_NAME_DOMAIN;
84 return True;
87 if (sid_check_is_in_our_domain(sid)) {
88 uint32 rid;
89 SMB_ASSERT(sid_peek_rid(sid, &rid));
91 /* For our own domain passdb is responsible */
92 fstrcpy(dom_name, get_global_sam_name());
93 return lookup_global_sam_rid(rid, name, name_type);
96 if (sid_check_is_builtin(sid)) {
98 /* Got through map_domain_sid_to_name here so that the mapping
99 * of S-1-5-32 to the name "BUILTIN" in as few places as
100 * possible. We might add i18n... */
101 SMB_ASSERT(map_domain_sid_to_name(sid, dom_name));
103 /* Yes, W2k3 returns "BUILTIN" both as domain and name here */
104 fstrcpy(name, dom_name);
106 *name_type = SID_NAME_DOMAIN;
107 return True;
110 if (sid_check_is_in_builtin(sid)) {
111 uint32 rid;
113 SMB_ASSERT(sid_peek_rid(sid, &rid));
115 /* Got through map_domain_sid_to_name here so that the mapping
116 * of S-1-5-32 to the name "BUILTIN" in as few places as
117 * possible. We might add i18n... */
118 SMB_ASSERT(map_domain_sid_to_name(&global_sid_Builtin,
119 dom_name));
121 /* There's only aliases in S-1-5-32 */
122 *name_type = SID_NAME_ALIAS;
124 return lookup_builtin_rid(rid, name);
127 if (winbind_lookup_sid(sid, dom_name, name, name_type)) {
128 return True;
131 DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying "
132 "special SIDs.\n", sid_string_static(sid)));
135 const char *dom, *obj_name;
137 if (lookup_special_sid(sid, &dom, &obj_name, name_type)) {
138 DEBUG(10, ("found %s\\%s\n", dom, obj_name));
139 fstrcpy(dom_name, dom);
140 fstrcpy(name, obj_name);
141 return True;
145 DEBUG(10, ("lookup_sid failed\n"));
147 return False;
150 /*****************************************************************
151 Id mapping cache. This is to avoid Winbind mappings already
152 seen by smbd to be queried too frequently, keeping winbindd
153 busy, and blocking smbd while winbindd is busy with other
154 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
155 modified to use linked lists by jra.
156 *****************************************************************/
158 #define MAX_UID_SID_CACHE_SIZE 100
159 #define TURNOVER_UID_SID_CACHE_SIZE 10
160 #define MAX_GID_SID_CACHE_SIZE 100
161 #define TURNOVER_GID_SID_CACHE_SIZE 10
163 static size_t n_uid_sid_cache = 0;
164 static size_t n_gid_sid_cache = 0;
166 static struct uid_sid_cache {
167 struct uid_sid_cache *next, *prev;
168 uid_t uid;
169 DOM_SID sid;
170 enum SID_NAME_USE sidtype;
171 } *uid_sid_cache_head;
173 static struct gid_sid_cache {
174 struct gid_sid_cache *next, *prev;
175 gid_t gid;
176 DOM_SID sid;
177 enum SID_NAME_USE sidtype;
178 } *gid_sid_cache_head;
180 /*****************************************************************
181 Find a SID given a uid.
182 *****************************************************************/
184 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
186 struct uid_sid_cache *pc;
188 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
189 if (pc->uid == uid) {
190 fstring sid;
191 *psid = pc->sid;
192 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
193 (unsigned int)uid, sid_to_string(sid, psid)));
194 DLIST_PROMOTE(uid_sid_cache_head, pc);
195 return True;
198 return False;
201 /*****************************************************************
202 Find a uid given a SID.
203 *****************************************************************/
205 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
207 struct uid_sid_cache *pc;
209 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
210 if (sid_compare(&pc->sid, psid) == 0) {
211 fstring sid;
212 *puid = pc->uid;
213 DEBUG(3,("fetch uid from cache %u -> %s\n",
214 (unsigned int)*puid, sid_to_string(sid, psid)));
215 DLIST_PROMOTE(uid_sid_cache_head, pc);
216 return True;
219 return False;
222 /*****************************************************************
223 Store uid to SID mapping in cache.
224 *****************************************************************/
226 static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
228 struct uid_sid_cache *pc;
230 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
231 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
232 struct uid_sid_cache *pc_next;
233 size_t i;
235 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
237 for(; pc; pc = pc_next) {
238 pc_next = pc->next;
239 DLIST_REMOVE(uid_sid_cache_head,pc);
240 SAFE_FREE(pc);
241 n_uid_sid_cache--;
245 pc = SMB_MALLOC_P(struct uid_sid_cache);
246 if (!pc)
247 return;
248 pc->uid = uid;
249 sid_copy(&pc->sid, psid);
250 DLIST_ADD(uid_sid_cache_head, pc);
251 n_uid_sid_cache++;
254 /*****************************************************************
255 Find a SID given a gid.
256 *****************************************************************/
258 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
260 struct gid_sid_cache *pc;
262 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
263 if (pc->gid == gid) {
264 fstring sid;
265 *psid = pc->sid;
266 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
267 (unsigned int)gid, sid_to_string(sid, psid)));
268 DLIST_PROMOTE(gid_sid_cache_head, pc);
269 return True;
272 return False;
275 /*****************************************************************
276 Find a gid given a SID.
277 *****************************************************************/
279 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
281 struct gid_sid_cache *pc;
283 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
284 if (sid_compare(&pc->sid, psid) == 0) {
285 fstring sid;
286 *pgid = pc->gid;
287 DEBUG(3,("fetch gid from cache %u -> %s\n",
288 (unsigned int)*pgid, sid_to_string(sid, psid)));
289 DLIST_PROMOTE(gid_sid_cache_head, pc);
290 return True;
293 return False;
296 /*****************************************************************
297 Store gid to SID mapping in cache.
298 *****************************************************************/
300 static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
302 struct gid_sid_cache *pc;
304 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
305 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
306 struct gid_sid_cache *pc_next;
307 size_t i;
309 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
311 for(; pc; pc = pc_next) {
312 pc_next = pc->next;
313 DLIST_REMOVE(gid_sid_cache_head,pc);
314 SAFE_FREE(pc);
315 n_gid_sid_cache--;
319 pc = SMB_MALLOC_P(struct gid_sid_cache);
320 if (!pc)
321 return;
322 pc->gid = gid;
323 sid_copy(&pc->sid, psid);
324 DLIST_ADD(gid_sid_cache_head, pc);
325 n_gid_sid_cache++;
328 /*****************************************************************
329 *THE CANONICAL* convert uid_t to SID function.
330 *****************************************************************/
332 NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid)
334 fstring sid;
335 uid_t low, high;
337 ZERO_STRUCTP(psid);
339 if (fetch_sid_from_uid_cache(psid, uid))
340 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
342 /* DC's never use winbindd to resolve users outside the
343 defined idmap range */
345 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
346 || (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) )
348 if (winbind_uid_to_sid(psid, uid)) {
350 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
351 (unsigned int)uid, sid_to_string(sid, psid)));
353 if (psid)
354 store_uid_sid_cache(psid, uid);
355 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
359 if (!local_uid_to_sid(psid, uid)) {
360 DEBUG(10,("uid_to_sid: local %u failed to map to sid\n", (unsigned int)uid ));
361 return NT_STATUS_UNSUCCESSFUL;
364 DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
366 store_uid_sid_cache(psid, uid);
367 return NT_STATUS_OK;
370 /*****************************************************************
371 *THE CANONICAL* convert gid_t to SID function.
372 *****************************************************************/
374 NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid)
376 fstring sid;
377 gid_t low, high;
379 ZERO_STRUCTP(psid);
381 if (fetch_sid_from_gid_cache(psid, gid))
382 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
384 /* DC's never use winbindd to resolve groups outside the
385 defined idmap range */
387 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
388 || (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) )
390 if (winbind_gid_to_sid(psid, gid)) {
392 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
393 (unsigned int)gid, sid_to_string(sid, psid)));
395 if (psid)
396 store_gid_sid_cache(psid, gid);
397 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
401 if (!local_gid_to_sid(psid, gid)) {
402 DEBUG(10,("gid_to_sid: local %u failed to map to sid\n", (unsigned int)gid ));
403 return NT_STATUS_UNSUCCESSFUL;
406 DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
408 store_gid_sid_cache(psid, gid);
409 return NT_STATUS_OK;
412 /*****************************************************************
413 *THE CANONICAL* convert SID to uid function.
414 *****************************************************************/
416 NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid)
418 fstring dom_name, name, sid_str;
419 enum SID_NAME_USE name_type;
421 if (fetch_uid_from_cache(puid, psid))
422 return NT_STATUS_OK;
424 /* if this is our SID then go straight to a local lookup */
426 if ( sid_compare_domain(get_global_sam_sid(), psid) == 0 ) {
427 DEBUG(10,("sid_to_uid: my domain (%s) - trying local.\n",
428 sid_string_static(psid) ));
430 if ( local_sid_to_uid(puid, psid, &name_type) )
431 goto success;
433 DEBUG(10,("sid_to_uid: local lookup failed\n"));
435 return NT_STATUS_UNSUCCESSFUL;
438 /* If it is not our local domain, only hope is winbindd */
440 if ( !winbind_lookup_sid(psid, dom_name, name, &name_type) ) {
441 DEBUG(10,("sid_to_uid: winbind lookup for non-local sid %s failed\n",
442 sid_string_static(psid) ));
444 return NT_STATUS_UNSUCCESSFUL;
447 /* If winbindd does know the SID, ensure this is a user */
449 if (name_type != SID_NAME_USER) {
450 DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a user (%u)\n",
451 (unsigned int)name_type ));
452 return NT_STATUS_INVALID_PARAMETER;
455 /* get the uid. Has to work or else we are dead in the water */
457 if ( !winbind_sid_to_uid(puid, psid) ) {
458 DEBUG(10,("sid_to_uid: winbind failed to allocate a new uid for sid %s\n",
459 sid_to_string(sid_str, psid) ));
460 return NT_STATUS_UNSUCCESSFUL;
463 success:
464 DEBUG(10,("sid_to_uid: %s -> %u\n", sid_to_string(sid_str, psid),
465 (unsigned int)*puid ));
467 store_uid_sid_cache(psid, *puid);
469 return NT_STATUS_OK;
471 /*****************************************************************
472 *THE CANONICAL* convert SID to gid function.
473 Group mapping is used for gids that maps to Wellknown SIDs
474 *****************************************************************/
476 NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid)
478 fstring dom_name, name, sid_str;
479 enum SID_NAME_USE name_type;
481 if (fetch_gid_from_cache(pgid, psid))
482 return NT_STATUS_OK;
485 * First we must look up the name and decide if this is a group sid.
486 * Group mapping can deal with foreign SIDs
489 if ( local_sid_to_gid(pgid, psid, &name_type) )
490 goto success;
492 if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
493 DEBUG(10,("sid_to_gid: no one knows the SID %s (tried local, then winbind)\n", sid_to_string(sid_str, psid)));
495 return NT_STATUS_UNSUCCESSFUL;
498 /* winbindd knows it; Ensure this is a group sid */
500 if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS)
501 && (name_type != SID_NAME_WKN_GRP))
503 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
504 (unsigned int)name_type ));
506 /* winbindd is running and knows about this SID. Just the wrong type.
507 Don't fallback to a local lookup here */
509 return NT_STATUS_INVALID_PARAMETER;
512 /* winbindd knows it and it is a type of group; sid_to_gid must succeed
513 or we are dead in the water */
515 if ( !winbind_sid_to_gid(pgid, psid) ) {
516 DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid for sid %s\n",
517 sid_to_string(sid_str, psid) ));
518 return NT_STATUS_UNSUCCESSFUL;
521 success:
522 DEBUG(10,("sid_to_gid: %s -> %u\n", sid_to_string(sid_str, psid),
523 (unsigned int)*pgid ));
525 store_gid_sid_cache(psid, *pgid);
527 return NT_STATUS_OK;