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 Dissect a user-provided name into domain, name, sid and type.
27 If an explicit domain name was given in the form domain\user, it
28 has to try that. If no explicit domain name was given, we have
30 *****************************************************************/
32 BOOL lookup_name(TALLOC_CTX *mem_ctx,
33 const char *full_name, int flags,
34 const char **ret_domain, const char **ret_name,
35 DOM_SID *ret_sid, enum SID_NAME_USE *ret_type)
39 const char *domain = NULL;
40 const char *name = NULL;
43 enum SID_NAME_USE type;
44 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
46 if (tmp_ctx == NULL) {
47 DEBUG(0, ("talloc_new failed\n"));
51 p = strchr_m(full_name, '\\');
54 domain = talloc_strndup(tmp_ctx, full_name,
55 PTR_DIFF(p, full_name));
56 name = talloc_strdup(tmp_ctx, p+1);
58 domain = talloc_strdup(tmp_ctx, "");
59 name = talloc_strdup(tmp_ctx, full_name);
62 if ((domain == NULL) || (name == NULL)) {
63 DEBUG(0, ("talloc failed\n"));
67 if (strequal(domain, get_global_sam_name())) {
69 /* It's our own domain, lookup the name in passdb */
70 if (lookup_global_sam_name(name, &rid, &type)) {
71 sid_copy(&sid, get_global_sam_sid());
72 sid_append_rid(&sid, rid);
78 if (strequal(domain, builtin_domain_name())) {
80 /* Explicit request for a name in BUILTIN */
81 if (lookup_builtin_name(name, &rid)) {
82 sid_copy(&sid, &global_sid_Builtin);
83 sid_append_rid(&sid, rid);
84 type = SID_NAME_ALIAS;
90 if (domain[0] != '\0') {
91 /* An explicit domain name was given, here our last resort is
93 if (winbind_lookup_name(domain, name, &sid, &type)) {
99 if (!(flags & LOOKUP_NAME_ISOLATED)) {
103 /* Now the guesswork begins, we haven't been given an explicit
104 * domain. Try the sequence as documented on
105 * http://msdn.microsoft.com/library/en-us/secmgmt/security/lsalookupnames.asp
106 * November 27, 2005 */
108 /* 1. well-known names */
111 if (lookup_wellknown_name(tmp_ctx, name, &sid, &domain)) {
112 type = SID_NAME_WKN_GRP;
117 /* 2. Builtin domain as such */
119 if (strequal(name, builtin_domain_name())) {
120 /* Swap domain and name */
121 tmp = name; name = domain; domain = tmp;
122 sid_copy(&sid, &global_sid_Builtin);
123 type = SID_NAME_DOMAIN;
127 /* 3. Account domain */
129 if (strequal(name, get_global_sam_name())) {
130 if (!secrets_fetch_domain_sid(name, &sid)) {
131 DEBUG(3, ("Could not fetch my SID\n"));
134 /* Swap domain and name */
135 tmp = name; name = domain; domain = tmp;
136 type = SID_NAME_DOMAIN;
140 /* 4. Primary domain */
142 if (!IS_DC && strequal(name, lp_workgroup())) {
143 if (!secrets_fetch_domain_sid(name, &sid)) {
144 DEBUG(3, ("Could not fetch the domain SID\n"));
147 /* Swap domain and name */
148 tmp = name; name = domain; domain = tmp;
149 type = SID_NAME_DOMAIN;
153 /* 5. Trusted domains as such, to me it looks as if members don't do
154 this, tested an XP workstation in a NT domain -- vl */
156 if (IS_DC && (secrets_fetch_trusted_domain_password(name, NULL,
158 /* Swap domain and name */
159 tmp = name; name = domain; domain = tmp;
160 type = SID_NAME_DOMAIN;
164 /* 6. Builtin aliases */
166 if (lookup_builtin_name(name, &rid)) {
167 domain = talloc_strdup(tmp_ctx, builtin_domain_name());
168 sid_copy(&sid, &global_sid_Builtin);
169 sid_append_rid(&sid, rid);
170 type = SID_NAME_ALIAS;
174 /* 7. Local systems' SAM (DCs don't have a local SAM) */
175 /* 8. Primary SAM (On members, this is the domain) */
177 /* Both cases are done by looking at our passdb */
179 if (lookup_global_sam_name(name, &rid, &type)) {
180 domain = talloc_strdup(tmp_ctx, get_global_sam_name());
181 sid_copy(&sid, get_global_sam_sid());
182 sid_append_rid(&sid, rid);
186 /* Now our local possibilities are exhausted. */
188 if (!(flags & LOOKUP_NAME_REMOTE)) {
192 /* If we are not a DC, we have to ask in our primary domain. Let
193 * winbind do that. */
196 (winbind_lookup_name(lp_workgroup(), name, &sid, &type))) {
197 domain = talloc_strdup(tmp_ctx, lp_workgroup());
201 /* 9. Trusted domains */
203 /* If we're a DC we have to ask all trusted DC's. Winbind does not do
204 * that (yet), but give it a chance. */
206 if (IS_DC && winbind_lookup_name("", name, &sid, &type)) {
209 enum SID_NAME_USE domain_type;
211 if (type == SID_NAME_DOMAIN) {
212 /* Swap name and type */
213 tmp = name; name = domain; domain = tmp;
217 /* Here we have to cope with a little deficiency in the
218 * winbind API: We have to ask it again for the name of the
219 * domain it figured out itself. Maybe fix that later... */
221 sid_copy(&dom_sid, &sid);
222 sid_split_rid(&dom_sid, &tmp_rid);
224 if (!winbind_lookup_sid(tmp_ctx, &dom_sid, &domain, NULL,
226 (domain_type != SID_NAME_DOMAIN)) {
227 DEBUG(2, ("winbind could not find the domain's name "
228 "it just looked up for us\n"));
234 /* 10. Don't translate */
236 talloc_free(tmp_ctx);
240 if ((domain == NULL) || (name == NULL)) {
241 DEBUG(0, ("talloc failed\n"));
242 talloc_free(tmp_ctx);
246 if (ret_name != NULL) {
247 *ret_name = talloc_steal(mem_ctx, name);
250 if (ret_domain != NULL) {
251 char *tmp_dom = talloc_strdup(tmp_ctx, domain);
253 *ret_domain = talloc_steal(mem_ctx, tmp_dom);
256 if (ret_sid != NULL) {
257 sid_copy(ret_sid, &sid);
260 if (ret_type != NULL) {
264 talloc_free(tmp_ctx);
268 /*****************************************************************
269 *THE CANONICAL* convert SID to name function.
270 Tries local lookup first - for local sids, then tries winbind.
271 *****************************************************************/
273 BOOL lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
274 const char **ret_domain, const char **ret_name,
275 enum SID_NAME_USE *ret_type)
277 const char *domain = NULL;
278 const char *name = NULL;
279 enum SID_NAME_USE type;
280 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
282 /* Check if this is our own sid. This should perhaps be done by
283 winbind? For the moment handle it here. */
285 if (tmp_ctx == NULL) {
286 DEBUG(0, ("talloc_new failed\n"));
290 if (sid_check_is_domain(sid)) {
291 domain = talloc_strdup(tmp_ctx, get_global_sam_name());
292 name = talloc_strdup(tmp_ctx, "");
293 type = SID_NAME_DOMAIN;
297 if (sid_check_is_in_our_domain(sid)) {
299 SMB_ASSERT(sid_peek_rid(sid, &rid));
301 /* For our own domain passdb is responsible */
302 if (!lookup_global_sam_rid(tmp_ctx, rid, &name, &type)) {
306 domain = talloc_strdup(tmp_ctx, get_global_sam_name());
310 if (sid_check_is_builtin(sid)) {
312 domain = talloc_strdup(tmp_ctx, builtin_domain_name());
314 /* Yes, W2k3 returns "BUILTIN" both as domain and name here */
315 name = talloc_strdup(tmp_ctx, builtin_domain_name());
316 type = SID_NAME_DOMAIN;
320 if (sid_check_is_in_builtin(sid)) {
323 SMB_ASSERT(sid_peek_rid(sid, &rid));
325 if (!lookup_builtin_rid(tmp_ctx, rid, &name)) {
329 /* There's only aliases in S-1-5-32 */
330 type = SID_NAME_ALIAS;
331 domain = talloc_strdup(tmp_ctx, builtin_domain_name());
336 if (winbind_lookup_sid(tmp_ctx, sid, &domain, &name, &type)) {
340 DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying "
341 "special SIDs.\n", sid_string_static(sid)));
343 if (lookup_wellknown_sid(tmp_ctx, sid, &domain, &name)) {
344 type = SID_NAME_WKN_GRP;
349 DEBUG(10, ("Failed to lookup sid %s\n", sid_string_static(sid)));
350 talloc_free(tmp_ctx);
355 if ((domain == NULL) || (name == NULL)) {
356 DEBUG(0, ("talloc failed\n"));
357 talloc_free(tmp_ctx);
361 if (ret_domain != NULL) {
362 *ret_domain = talloc_steal(mem_ctx, domain);
365 if (ret_name != NULL) {
366 *ret_name = talloc_steal(mem_ctx, name);
369 if (ret_type != NULL) {
373 talloc_free(tmp_ctx);
377 /*****************************************************************
378 Id mapping cache. This is to avoid Winbind mappings already
379 seen by smbd to be queried too frequently, keeping winbindd
380 busy, and blocking smbd while winbindd is busy with other
381 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
382 modified to use linked lists by jra.
383 *****************************************************************/
385 #define MAX_UID_SID_CACHE_SIZE 100
386 #define TURNOVER_UID_SID_CACHE_SIZE 10
387 #define MAX_GID_SID_CACHE_SIZE 100
388 #define TURNOVER_GID_SID_CACHE_SIZE 10
390 static size_t n_uid_sid_cache = 0;
391 static size_t n_gid_sid_cache = 0;
393 static struct uid_sid_cache {
394 struct uid_sid_cache *next, *prev;
397 enum SID_NAME_USE sidtype;
398 } *uid_sid_cache_head;
400 static struct gid_sid_cache {
401 struct gid_sid_cache *next, *prev;
404 enum SID_NAME_USE sidtype;
405 } *gid_sid_cache_head;
407 /*****************************************************************
408 Find a SID given a uid.
409 *****************************************************************/
411 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
413 struct uid_sid_cache *pc;
415 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
416 if (pc->uid == uid) {
418 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
419 (unsigned int)uid, sid_string_static(psid)));
420 DLIST_PROMOTE(uid_sid_cache_head, pc);
427 /*****************************************************************
428 Find a uid given a SID.
429 *****************************************************************/
431 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
433 struct uid_sid_cache *pc;
435 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
436 if (sid_compare(&pc->sid, psid) == 0) {
438 DEBUG(3,("fetch uid from cache %u -> %s\n",
439 (unsigned int)*puid, sid_string_static(psid)));
440 DLIST_PROMOTE(uid_sid_cache_head, pc);
447 /*****************************************************************
448 Store uid to SID mapping in cache.
449 *****************************************************************/
451 static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
453 struct uid_sid_cache *pc;
455 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
456 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
457 struct uid_sid_cache *pc_next;
460 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
462 for(; pc; pc = pc_next) {
464 DLIST_REMOVE(uid_sid_cache_head,pc);
470 pc = SMB_MALLOC_P(struct uid_sid_cache);
474 sid_copy(&pc->sid, psid);
475 DLIST_ADD(uid_sid_cache_head, pc);
479 /*****************************************************************
480 Find a SID given a gid.
481 *****************************************************************/
483 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
485 struct gid_sid_cache *pc;
487 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
488 if (pc->gid == gid) {
490 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
491 (unsigned int)gid, sid_string_static(psid)));
492 DLIST_PROMOTE(gid_sid_cache_head, pc);
499 /*****************************************************************
500 Find a gid given a SID.
501 *****************************************************************/
503 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
505 struct gid_sid_cache *pc;
507 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
508 if (sid_compare(&pc->sid, psid) == 0) {
510 DEBUG(3,("fetch gid from cache %u -> %s\n",
511 (unsigned int)*pgid, sid_string_static(psid)));
512 DLIST_PROMOTE(gid_sid_cache_head, pc);
519 /*****************************************************************
520 Store gid to SID mapping in cache.
521 *****************************************************************/
523 static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
525 struct gid_sid_cache *pc;
527 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
528 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
529 struct gid_sid_cache *pc_next;
532 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
534 for(; pc; pc = pc_next) {
536 DLIST_REMOVE(gid_sid_cache_head,pc);
542 pc = SMB_MALLOC_P(struct gid_sid_cache);
546 sid_copy(&pc->sid, psid);
547 DLIST_ADD(gid_sid_cache_head, pc);
551 /*****************************************************************
552 *THE CANONICAL* convert uid_t to SID function.
553 *****************************************************************/
555 NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid)
561 if (fetch_sid_from_uid_cache(psid, uid))
562 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
564 /* DC's never use winbindd to resolve users outside the
565 defined idmap range */
567 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
568 || (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) )
570 if (winbind_uid_to_sid(psid, uid)) {
572 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
573 (unsigned int)uid, sid_string_static(psid)));
576 store_uid_sid_cache(psid, uid);
577 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
581 if (!local_uid_to_sid(psid, uid)) {
582 DEBUG(10,("uid_to_sid: local %u failed to map to sid\n", (unsigned int)uid ));
583 return NT_STATUS_UNSUCCESSFUL;
586 DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid,
587 sid_string_static(psid)));
589 store_uid_sid_cache(psid, uid);
593 /*****************************************************************
594 *THE CANONICAL* convert gid_t to SID function.
595 *****************************************************************/
597 NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid)
603 if (fetch_sid_from_gid_cache(psid, gid))
604 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
606 /* DC's never use winbindd to resolve groups outside the
607 defined idmap range */
609 if ( lp_server_role()==ROLE_DOMAIN_MEMBER
610 || (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) )
612 if (winbind_gid_to_sid(psid, gid)) {
614 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
615 (unsigned int)gid, sid_string_static(psid)));
618 store_gid_sid_cache(psid, gid);
619 return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
623 if (!local_gid_to_sid(psid, gid)) {
624 DEBUG(10,("gid_to_sid: local %u failed to map to sid\n", (unsigned int)gid ));
625 return NT_STATUS_UNSUCCESSFUL;
628 DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid,
629 sid_string_static(psid)));
631 store_gid_sid_cache(psid, gid);
635 /*****************************************************************
636 *THE CANONICAL* convert SID to uid function.
637 *****************************************************************/
639 NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid)
641 enum SID_NAME_USE name_type;
643 if (fetch_uid_from_cache(puid, psid))
646 /* if this is our SID then go straight to a local lookup */
648 if ( sid_compare_domain(get_global_sam_sid(), psid) == 0 ) {
649 DEBUG(10,("sid_to_uid: my domain (%s) - trying local.\n",
650 sid_string_static(psid) ));
652 if ( local_sid_to_uid(puid, psid, &name_type) )
655 DEBUG(10,("sid_to_uid: local lookup failed\n"));
657 return NT_STATUS_UNSUCCESSFUL;
660 /* If it is not our local domain, only hope is winbindd */
662 if ( !winbind_lookup_sid(NULL, psid, NULL, NULL, &name_type) ) {
663 DEBUG(10,("sid_to_uid: winbind lookup for non-local sid %s failed\n",
664 sid_string_static(psid) ));
666 return NT_STATUS_UNSUCCESSFUL;
669 /* If winbindd does know the SID, ensure this is a user */
671 if (name_type != SID_NAME_USER) {
672 DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a user (%u)\n",
673 (unsigned int)name_type ));
674 return NT_STATUS_INVALID_PARAMETER;
677 /* get the uid. Has to work or else we are dead in the water */
679 if ( !winbind_sid_to_uid(puid, psid) ) {
680 DEBUG(10,("sid_to_uid: winbind failed to allocate a new uid for sid %s\n",
681 sid_string_static(psid)));
682 return NT_STATUS_UNSUCCESSFUL;
686 DEBUG(10,("sid_to_uid: %s -> %u\n", sid_string_static(psid),
687 (unsigned int)*puid ));
689 store_uid_sid_cache(psid, *puid);
693 /*****************************************************************
694 *THE CANONICAL* convert SID to gid function.
695 Group mapping is used for gids that maps to Wellknown SIDs
696 *****************************************************************/
698 NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid)
700 enum SID_NAME_USE name_type;
702 if (fetch_gid_from_cache(pgid, psid))
706 * First we must look up the name and decide if this is a group sid.
707 * Group mapping can deal with foreign SIDs
710 if ( local_sid_to_gid(pgid, psid, &name_type) )
713 if (!winbind_lookup_sid(NULL, psid, NULL, NULL, &name_type)) {
714 DEBUG(10,("sid_to_gid: no one knows the SID %s (tried local, then "
715 "winbind)\n", sid_string_static(psid)));
717 return NT_STATUS_UNSUCCESSFUL;
720 /* winbindd knows it; Ensure this is a group sid */
722 if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS)
723 && (name_type != SID_NAME_WKN_GRP))
725 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
726 (unsigned int)name_type ));
728 /* winbindd is running and knows about this SID. Just the wrong type.
729 Don't fallback to a local lookup here */
731 return NT_STATUS_INVALID_PARAMETER;
734 /* winbindd knows it and it is a type of group; sid_to_gid must succeed
735 or we are dead in the water */
737 if ( !winbind_sid_to_gid(pgid, psid) ) {
738 DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid for sid %s\n",
739 sid_string_static(psid)));
740 return NT_STATUS_UNSUCCESSFUL;
744 DEBUG(10,("sid_to_gid: %s -> %u\n", sid_string_static(psid),
745 (unsigned int)*pgid ));
747 store_gid_sid_cache(psid, *pgid);