summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/proto.h4
-rw-r--r--source3/passdb/lookup_sid.c124
-rw-r--r--source3/passdb/pdb_get_set.c94
3 files changed, 136 insertions, 86 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 393e7e277c..dc6b555fd2 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -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 */
diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c
index 14494cbeec..d523055b9d 100644
--- a/source3/passdb/lookup_sid.c
+++ b/source3/passdb/lookup_sid.c
@@ -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;
+}
diff --git a/source3/passdb/pdb_get_set.c b/source3/passdb/pdb_get_set.c
index 57d95138e3..3e2510e74c 100644
--- a/source3/passdb/pdb_get_set.c
+++ b/source3/passdb/pdb_get_set.c
@@ -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