s3: auth: Move the declaration of struct dom_sid tmp_sid to function level scope.
[samba.git] / source3 / auth / token_util.c
index d86d589cc3d6ff14d6c6491fb33d79fa63bca84c..f6ce1315c0825ca8de01f9dec26079e2aabf3eaa 100644 (file)
@@ -28,7 +28,7 @@
 #include "system/passwd.h"
 #include "auth.h"
 #include "secrets.h"
-#include "memcache.h"
+#include "../lib/util/memcache.h"
 #include "../librpc/gen_ndr/netlogon.h"
 #include "../libcli/security/security.h"
 #include "../lib/util/util_pw.h"
@@ -389,12 +389,113 @@ struct security_token *create_local_nt_token(TALLOC_CTX *mem_ctx,
        return result;
 }
 
+/***************************************************
+ Merge in any groups from /etc/group.
+***************************************************/
+
+static NTSTATUS add_local_groups(struct security_token *result,
+                                bool is_guest)
+{
+       gid_t *gids = NULL;
+       uint32_t getgroups_num_group_sids = 0;
+       struct passwd *pass = NULL;
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+       int i;
+
+       if (is_guest) {
+               /*
+                * Guest is a special case. It's always
+                * a user that can be looked up, but
+                * result->sids[0] is set to DOMAIN\Guest.
+                * Lookup by account name instead.
+                */
+               pass = Get_Pwnam_alloc(tmp_ctx, lp_guest_account());
+       } else {
+               uid_t uid;
+
+               /* For non-guest result->sids[0] is always the user sid. */
+               if (!sid_to_uid(&result->sids[0], &uid)) {
+                       /*
+                        * Non-mappable SID like SYSTEM.
+                        * Can't be in any /etc/group groups.
+                        */
+                       TALLOC_FREE(tmp_ctx);
+                       return NT_STATUS_OK;
+               }
+
+               pass = getpwuid_alloc(tmp_ctx, uid);
+               if (pass == NULL) {
+                       DEBUG(1, ("SID %s -> getpwuid(%u) failed\n",
+                               sid_string_dbg(&result->sids[0]),
+                               (unsigned int)uid));
+               }
+       }
+
+       if (!pass) {
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       /*
+        * Now we must get any groups this user has been
+        * added to in /etc/group and merge them in.
+        * This has to be done in every code path
+        * that creates an NT token, as remote users
+        * may have been added to the local /etc/group
+        * database. Tokens created merely from the
+        * info3 structs (via the DC or via the krb5 PAC)
+        * won't have these local groups. Note the
+        * groups added here will only be UNIX groups
+        * (S-1-22-2-XXXX groups) as getgroups_unix_user()
+        * turns off winbindd before calling getgroups().
+        *
+        * NB. This is duplicating work already
+        * done in the 'unix_user:' case of
+        * create_token_from_sid() but won't
+        * do anything other than be inefficient
+        * in that case.
+        */
+
+       if (!getgroups_unix_user(tmp_ctx, pass->pw_name, pass->pw_gid,
+                       &gids, &getgroups_num_group_sids)) {
+               DEBUG(1, ("getgroups_unix_user for user %s failed\n",
+                       pass->pw_name));
+               TALLOC_FREE(tmp_ctx);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       for (i=0; i<getgroups_num_group_sids; i++) {
+               NTSTATUS status;
+               struct dom_sid grp_sid;
+               gid_to_sid(&grp_sid, gids[i]);
+
+               status = add_sid_to_array_unique(result,
+                                        &grp_sid,
+                                        &result->sids,
+                                        &result->num_sids);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(3, ("Failed to add UNIX SID to nt token\n"));
+                       TALLOC_FREE(tmp_ctx);
+                       return status;
+               }
+       }
+       TALLOC_FREE(tmp_ctx);
+       return NT_STATUS_OK;
+}
+
 static NTSTATUS finalize_local_nt_token(struct security_token *result,
                                        bool is_guest)
 {
        struct dom_sid dom_sid;
-       gid_t gid;
        NTSTATUS status;
+       struct acct_info *info;
+
+       /* Add any local groups. */
+
+       status = add_local_groups(result, is_guest);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
 
        /* Add in BUILTIN sids */
 
@@ -426,11 +527,18 @@ static NTSTATUS finalize_local_nt_token(struct security_token *result,
                }
        }
 
+       info = talloc_zero(talloc_tos(), struct acct_info);
+       if (info == NULL) {
+               DEBUG(0, ("talloc failed!\n"));
+               return NT_STATUS_NO_MEMORY;
+       }
+
        /* Deal with the BUILTIN\Administrators group.  If the SID can
           be resolved then assume that the add_aliasmem( S-1-5-32 )
           handled it. */
 
-       if (!sid_to_gid(&global_sid_Builtin_Administrators, &gid)) {
+       status = pdb_get_aliasinfo(&global_sid_Builtin_Administrators, info);
+       if (!NT_STATUS_IS_OK(status)) {
 
                become_root();
                if (!secrets_fetch_domain_sid(lp_workgroup(), &dom_sid)) {
@@ -461,7 +569,8 @@ static NTSTATUS finalize_local_nt_token(struct security_token *result,
           be resolved then assume that the add_aliasmem( S-1-5-32 )
           handled it. */
 
-       if (!sid_to_gid(&global_sid_Builtin_Users, &gid)) {
+       status = pdb_get_aliasinfo(&global_sid_Builtin_Users, info);
+       if (!NT_STATUS_IS_OK(status)) {
 
                become_root();
                if (!secrets_fetch_domain_sid(lp_workgroup(), &dom_sid)) {
@@ -481,6 +590,8 @@ static NTSTATUS finalize_local_nt_token(struct security_token *result,
                }
        }
 
+       TALLOC_FREE(info);
+
        /* Deal with local groups */
 
        if (lp_winbind_nested_groups()) {
@@ -562,6 +673,7 @@ static NTSTATUS create_token_from_sid(TALLOC_CTX *mem_ctx,
        gid_t *gids;
        struct dom_sid *group_sids;
        struct dom_sid unix_group_sid;
+       struct dom_sid tmp_sid;
        uint32_t num_group_sids;
        uint32_t num_gids;
        uint32_t i;
@@ -619,7 +731,7 @@ static NTSTATUS create_token_from_sid(TALLOC_CTX *mem_ctx,
 
                /*
                 * If the SID from lookup_name() was the guest sid, passdb knows
-                * about the mapping of guest sid to lp_guestaccount()
+                * about the mapping of guest sid to lp_guest_account()
                 * username and will return the unix_pw info for a guest
                 * user. Use it if it's there, else lookup the *uid details
                 * using Get_Pwnam_alloc(). See bug #6291 for details. JRA.
@@ -645,7 +757,6 @@ static NTSTATUS create_token_from_sid(TALLOC_CTX *mem_ctx,
                *uid = sam_acct->unix_pw->pw_uid;
 
        } else  if (sid_check_is_in_unix_users(user_sid)) {
-               struct dom_sid tmp_sid;
                uint32_t getgroups_num_group_sids;
                /* This is a unix user not in passdb. We need to ask nss
                 * directly, without consulting passdb */