s3:passdb Export function to calculate the proper primary group sid
authorSimo Sorce <ssorce@redhat.com>
Sat, 29 May 2010 14:51:40 +0000 (10:51 -0400)
committerSimo Sorce <ssorce@redhat.com>
Mon, 31 May 2010 15:14:41 +0000 (11:14 -0400)
Don't keep it buried in passdb, this function need to be available
for use in places where we do not want to construct an artificial
samu struct just to play tricks.

source3/include/proto.h
source3/passdb/lookup_sid.c
source3/passdb/pdb_get_set.c

index deb836579704750b7980a11a333ebf7e9dc3a87c..8120ed20c9aabe20fe63c4c09ddfc0088136fe9a 100644 (file)
@@ -4351,6 +4351,10 @@ void uid_to_sid(struct dom_sid *psid, uid_t uid);
 void gid_to_sid(struct dom_sid *psid, gid_t gid);
 bool sid_to_uid(const struct dom_sid *psid, uid_t *puid);
 bool sid_to_gid(const struct dom_sid *psid, gid_t *pgid);
+NTSTATUS get_primary_group_sid(TALLOC_CTX *mem_ctx,
+                               const char *username,
+                               struct passwd **_pwd,
+                               struct dom_sid **_group_sid);
 
 /* The following definitions come from passdb/machine_sid.c  */
 
index 14494cbeec20ca58bf6577fb35bf859d5497c8ab..d523055b9dd3dd3fb07583fbec0b88deaf8c78b5 100644 (file)
@@ -1514,3 +1514,127 @@ bool sid_to_gid(const struct dom_sid *psid, gid_t *pgid)
        store_gid_sid_cache(psid, *pgid);
        return true;
 }
+
+/**
+ * @brief This function gets the primary group SID mapping the primary
+ *        GID of the user as obtained by an actual getpwnam() call.
+ *        This is necessary to avoid issues with arbitrary group SIDs
+ *        stored in passdb. We try as hard as we can to get the SID
+ *        corresponding to the GID, including trying group mapping.
+ *        If nothing else works, we will force "Domain Users" as the
+ *        primary group.
+ *        This is needed because we must always be able to lookup the
+ *        primary group SID, so we cannot settle for an arbitrary SID.
+ *
+ *        This call can be expensive. Use with moderation.
+ *        If you have a "samu" struct around use pdb_get_group_sid()
+ *        instead as it does properly cache results.
+ *
+ * @param mem_ctx[in]     The memory context iused to allocate the result.
+ * @param username[in]    The user's name
+ * @param _pwd[in|out]    If available, pass in user's passwd struct.
+ *                        It will contain a tallocated passwd if NULL was
+ *                        passed in.
+ * @param _group_sid[out] The user's Primary Group SID
+ *
+ * @return NTSTATUS error code.
+ */
+NTSTATUS get_primary_group_sid(TALLOC_CTX *mem_ctx,
+                               const char *username,
+                               struct passwd **_pwd,
+                               struct dom_sid **_group_sid)
+{
+       TALLOC_CTX *tmp_ctx;
+       bool need_lookup_sid = false;
+       struct dom_sid *group_sid;
+       struct passwd *pwd = *_pwd;
+
+       tmp_ctx = talloc_new(mem_ctx);
+       if (!tmp_ctx) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (!pwd) {
+               pwd = Get_Pwnam_alloc(mem_ctx, username);
+               if (!pwd) {
+                       DEBUG(0, ("Failed to find a Unix account for %s",
+                                 username));
+                       TALLOC_FREE(tmp_ctx);
+                       return NT_STATUS_NO_SUCH_USER;
+               }
+       }
+
+       group_sid = talloc_zero(mem_ctx, struct dom_sid);
+       if (!group_sid) {
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       gid_to_sid(group_sid, pwd->pw_gid);
+       if (!is_null_sid(group_sid)) {
+               struct dom_sid domain_sid;
+               uint32_t rid;
+
+               /* We need a sid within our domain */
+               sid_copy(&domain_sid, group_sid);
+               sid_split_rid(&domain_sid, &rid);
+               if (sid_equal(&domain_sid, get_global_sam_sid())) {
+                       /*
+                        * As shortcut for the expensive lookup_sid call
+                        * compare the domain sid part
+                        */
+                       switch (rid) {
+                       case DOMAIN_RID_ADMINS:
+                       case DOMAIN_RID_USERS:
+                               goto done;
+                       default:
+                               need_lookup_sid = true;
+                               break;
+                       }
+               } else {
+                       /* Try group mapping */
+                       ZERO_STRUCTP(group_sid);
+                       if (pdb_gid_to_sid(pwd->pw_gid, group_sid)) {
+                               need_lookup_sid = true;
+                       }
+               }
+       }
+
+       /* We must verify that this is a valid SID that resolves to a
+        * group of the correct type */
+       if (need_lookup_sid) {
+               enum lsa_SidType type = SID_NAME_UNKNOWN;
+               bool lookup_ret;
+
+               DEBUG(10, ("do lookup_sid(%s) for group of user %s\n",
+                          sid_string_dbg(group_sid), username));
+
+               /* Now check that it's actually a domain group and
+                * not something else */
+               lookup_ret = lookup_sid(tmp_ctx, group_sid,
+                                       NULL, NULL, &type);
+
+               if (lookup_ret && (type == SID_NAME_DOM_GRP)) {
+                       goto done;
+               }
+
+               DEBUG(3, ("Primary group %s for user %s is"
+                         " a %s and not a domain group\n",
+                         sid_string_dbg(group_sid), username,
+                         sid_type_lookup(type)));
+       }
+
+       /* Everything else, failed.
+        * Just set it to the 'Domain Users' RID of 513 which will
+          always resolve to a name */
+       DEBUG(3, ("Forcing Primary Group to 'Domain Users' for %s\n",
+                 username));
+
+       sid_compose(group_sid, get_global_sam_sid(), DOMAIN_RID_USERS);
+
+done:
+       *_pwd = talloc_move(mem_ctx, &pwd);
+       *_group_sid = talloc_move(mem_ctx, &group_sid);
+       TALLOC_FREE(tmp_ctx);
+       return NT_STATUS_OK;
+}
index 57d95138e3ea99b4c969324afdd853d50bd8a38d..3e2510e74c89c2e1ae9404f46ab3b20239b298e4 100644 (file)
@@ -182,105 +182,27 @@ const struct dom_sid *pdb_get_user_sid(const struct samu *sampass)
 
 const struct dom_sid *pdb_get_group_sid(struct samu *sampass)
 {
-       struct dom_sid *gsid;
-       struct passwd *pwd;
-       bool need_lookup_sid = false;
+       NTSTATUS status;
 
        /* Return the cached group SID if we have that */
-       if ( sampass->group_sid ) {
+       if (sampass->group_sid) {
                return sampass->group_sid;
        }
 
-       /* generate the group SID from the user's primary Unix group */
-
-       if ( !(gsid  = TALLOC_ZERO_P( sampass, struct dom_sid )) ) {
-               return NULL;
-       }
-
        /* No algorithmic mapping, meaning that we have to figure out the
           primary group SID according to group mapping and the user SID must
           be a newly allocated one.  We rely on the user's Unix primary gid.
           We have no choice but to fail if we can't find it. */
-
-       if ( sampass->unix_pw ) {
-               pwd = sampass->unix_pw;
-       } else {
-               pwd = Get_Pwnam_alloc( sampass, pdb_get_username(sampass) );
-               sampass->unix_pw = pwd;
-       }
-
-       if ( !pwd ) {
-               DEBUG(0,("pdb_get_group_sid: Failed to find Unix account for %s\n", pdb_get_username(sampass) ));
+       status = get_primary_group_sid(sampass,
+                                       pdb_get_username(sampass),
+                                       &sampass->unix_pw,
+                                       &sampass->group_sid);
+       if (!NT_STATUS_IS_OK(status)) {
                return NULL;
        }
 
-       gid_to_sid(gsid, pwd->pw_gid);
-       if (!is_null_sid(gsid)) {
-               struct dom_sid dgsid;
-               uint32_t rid;
-
-               sid_copy(&dgsid, gsid);
-               sid_split_rid(&dgsid, &rid);
-               if (sid_equal(&dgsid, get_global_sam_sid())) {
-                       /*
-                        * As shortcut for the expensive lookup_sid call
-                        * compare the domain sid part
-                        */
-                       switch (rid) {
-                       case DOMAIN_RID_ADMINS:
-                       case DOMAIN_RID_USERS:
-                               sampass->group_sid = gsid;
-                               return sampass->group_sid;
-                       default:
-                               need_lookup_sid = true;
-                               break;
-                       }
-               } else {
-                       ZERO_STRUCTP(gsid);
-                       if (pdb_gid_to_sid(pwd->pw_gid, gsid)) {
-                               need_lookup_sid = true;
-                       }
-               }
-       }
-
-       if (need_lookup_sid) {
-               enum lsa_SidType type = SID_NAME_UNKNOWN;
-               TALLOC_CTX *mem_ctx;
-               bool lookup_ret;
-               const struct dom_sid *usid = pdb_get_user_sid(sampass);
-
-               mem_ctx = talloc_init("pdb_get_group_sid");
-               if (!mem_ctx) {
-                       return NULL;
-               }
-
-               DEBUG(10,("do lookup_sid(%s) for group of user %s\n",
-                         sid_string_dbg(gsid), sid_string_dbg(usid)));
-
-               /* Now check that it's actually a domain group and not something else */
-
-               lookup_ret = lookup_sid(mem_ctx, gsid, NULL, NULL, &type);
-
-               TALLOC_FREE( mem_ctx );
-
-               if ( lookup_ret && (type == SID_NAME_DOM_GRP) ) {
-                       sampass->group_sid = gsid;
-                       return sampass->group_sid;
-               }
-
-               DEBUG(3, ("Primary group %s for user %s is a %s and not a domain group\n",
-                       sid_string_dbg(gsid), pwd->pw_name, sid_type_lookup(type)));
-       }
-
-       /* Just set it to the 'Domain Users' RID of 513 which will
-          always resolve to a name */
-
-       sid_compose(gsid, get_global_sam_sid(), DOMAIN_RID_USERS);
-
-       sampass->group_sid = gsid;
-
        return sampass->group_sid;
-}      
+}
 
 /**
  * Get flags showing what is initalised in the struct samu