Linux: Use the kernel's credentials structure
authorMarc Dionne <marc.c.dionne@gmail.com>
Thu, 29 Oct 2009 23:58:00 +0000 (19:58 -0400)
committerDerrick Brashear <shadow|account-1000005@unknown>
Wed, 11 Nov 2009 21:33:28 +0000 (13:33 -0800)
Recent kernels (2.6.29 and above) have a separate ref-counted
structure for holding credentials.  Use it directly instead of
keeping a separate afs specific structure that shadows the same
information.

Also adapt Linux for the change from cr_xxx to afs_cr_xxx wrappers.

Reference counting is done with the appropriate get/put calls.

Change-Id: I1135bb5a66cda51cee4fa9f3f3e63eaa9af28f61
Reviewed-on: http://gerrit.openafs.org/797
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Tested-by: Derrick Brashear <shadow@dementia.org>

src/afs/LINUX/osi_cred.c
src/afs/LINUX/osi_groups.c
src/afs/LINUX/osi_machdep.h
src/afs/afs.h
src/afs/afs_osi.c
src/afs/afs_osi_pag.c

index 76bc98d..69b2614 100644 (file)
 #include "afs/sysincludes.h"
 #include "afsincludes.h"
 
+/* Copy one credential structure to another, being careful about references */
+static inline void
+afs_copy_creds(cred_t *to_cred, const cred_t *from_cred) {
+    afs_set_cr_uid(to_cred, afs_cr_uid(from_cred));
+    afs_set_cr_gid(to_cred, afs_cr_gid(from_cred));
+    afs_set_cr_ruid(to_cred, afs_cr_ruid(from_cred));
+    afs_set_cr_rgid(to_cred, afs_cr_rgid(from_cred));
+    get_group_info(afs_cr_group_info(from_cred));
+    afs_set_cr_group_info(to_cred, afs_cr_group_info(from_cred));
+}
+
 cred_t *
 crget(void)
 {
@@ -27,24 +38,31 @@ crget(void)
 #define GFP_NOFS GFP_KERNEL
 #endif
     tmp = kmalloc(sizeof(cred_t), GFP_NOFS);
+    memset(tmp, 0, sizeof(cred_t));
     if (!tmp)
-       osi_Panic("crget: No more memory for creds!\n");
-    
+        osi_Panic("crget: No more memory for creds!\n");
+
+#if defined(STRUCT_TASK_HAS_CRED)
+    get_cred(tmp);
+#else
     tmp->cr_ref = 1;
+#endif
     return tmp;
 }
 
 void
 crfree(cred_t * cr)
 {
+#if defined(STRUCT_TASK_HAS_CRED)
+    put_cred(cr);
+#else
     if (cr->cr_ref > 1) {
        cr->cr_ref--;
        return;
     }
-
-    put_group_info(cr_group_info(cr));
-
+    put_group_info(afs_cr_group_info(cr));
     kfree(cr);
+#endif
 }
 
 
@@ -53,21 +71,26 @@ cred_t *
 crdup(cred_t * cr)
 {
     cred_t *tmp = crget();
-
+#if defined(STRUCT_TASK_HAS_CRED)
+    afs_copy_creds(tmp, cr);
+#else
     afs_set_cr_uid(tmp, afs_cr_uid(cr));
     afs_set_cr_ruid(tmp, afs_cr_ruid(cr));
     afs_set_cr_gid(tmp, afs_cr_gid(cr));
     afs_set_cr_rgid(tmp, afs_cr_rgid(cr));
 
-    get_group_info(cr_group_info(cr));
-    set_cr_group_info(tmp, cr_group_info(cr));
-
+    get_group_info(afs_cr_group_info(cr));
+    afs_set_cr_group_info(tmp, afs_cr_group_info(cr));
+#endif
     return tmp;
 }
 
 cred_t *
 crref(void)
 {
+#if defined(STRUCT_TASK_HAS_CRED)
+    return (cred_t *)get_current_cred();
+#else
     cred_t *cr = crget();
 
     afs_set_cr_uid(cr, current_fsuid());
@@ -77,17 +100,17 @@ crref(void)
 
     task_lock(current);
     get_group_info(current_group_info());
-    set_cr_group_info(cr, current_group_info());
+    afs_set_cr_group_info(cr, current_group_info());
     task_unlock(current);
 
     return cr;
+#endif
 }
 
 /* Set the cred info into the current task */
 void
 crset(cred_t * cr)
 {
-    struct group_info *old_info;
 #if defined(STRUCT_TASK_HAS_CRED)
     struct cred *new_creds;
 
@@ -98,30 +121,24 @@ crset(cred_t * cr)
     if (current->cred != current->real_cred)
         return;
     new_creds = prepare_creds();
-    new_creds->fsuid = afs_cr_uid(cr);
-    new_creds->uid = afs_cr_ruid(cr);
-    new_creds->fsgid = afs_cr_gid(cr);
-    new_creds->gid = afs_cr_rgid(cr);
+    /* Drop the reference to group_info - we'll overwrite it in afs_copy_creds */
+    put_group_info(new_creds->group_info);
+    afs_copy_creds(new_creds, current_cred());
+
+    commit_creds(new_creds);
 #else
+    struct group_info *old_info;
+
     current->fsuid = afs_cr_uid(cr);
     current->uid = afs_cr_ruid(cr);
     current->fsgid = afs_cr_gid(cr);
     current->gid = afs_cr_rgid(cr);
-#endif
-
-    /* using set_current_groups() will sort the groups */
-    get_group_info(cr_group_info(cr));
 
+    get_group_info(afs_cr_group_info(cr));
     task_lock(current);
-#if defined(STRUCT_TASK_HAS_CRED)
-    old_info = current->cred->group_info;
-    new_creds->group_info = cr_group_info(cr);
-    commit_creds(new_creds);
-#else
     old_info = current->group_info;
-    current->group_info = cr_group_info(cr);
-#endif
+    current->group_info = afs_cr_group_info(cr);
     task_unlock(current);
-
     put_group_info(old_info);
+#endif
 }
index d8dc83f..c9efc75 100644 (file)
@@ -39,9 +39,9 @@ afs_setgroups(cred_t **cr, struct group_info *group_info, int change_parent)
 
     AFS_STATCNT(afs_setgroups);
 
-    old_info = cr_group_info(*cr);
+    old_info = afs_cr_group_info(*cr);
     get_group_info(group_info);
-    set_cr_group_info(*cr, group_info);
+    afs_set_cr_group_info(*cr, group_info);
     put_group_info(old_info);
 
     crset(*cr);
@@ -65,8 +65,8 @@ afs_getgroups(cred_t * cr)
 {
     AFS_STATCNT(afs_getgroups);
 
-    get_group_info(cr_group_info(cr));
-    return cr_group_info(cr);
+    get_group_info(afs_cr_group_info(cr));
+    return afs_cr_group_info(cr);
 }
 
 int
index 2ff0896..52d4ea2 100644 (file)
@@ -153,38 +153,65 @@ static inline long copyinstr(char *from, char *to, int count, int *length) {
 #define NGROUPS NGROUPS_SMALL
 #endif
 
-/* cred struct */
-typedef struct afs_cred {              /* maps to task field: */
-    int cr_ref;
-    uid_t cr_uid;              /* euid */
-    uid_t cr_ruid;             /* uid */
-    gid_t cr_gid;              /* egid */
-    gid_t cr_rgid;             /* gid */
-    struct group_info *cr_group_info;
-} cred_t;
-
-typedef struct afs_cred afs_ucred_t;
 typedef struct task_struct afs_proc_t;
 
-#define cr_group_info(cred) ((cred)->cr_group_info)
+/* Credentials.  For newer kernels we use the kernel structure directly. */
+#if defined(STRUCT_TASK_HAS_CRED)
+
+typedef struct cred afs_ucred_t;
+typedef struct cred cred_t;
+
+#define afs_cr_uid(cred) ((cred)->fsuid)
+#define afs_cr_gid(cred) ((cred)->fsgid)
+#define afs_cr_ruid(cred) ((cred)->uid)
+#define afs_cr_rgid(cred) ((cred)->gid)
+#define afs_cr_group_info(cred) ((cred)->group_info)
+#define crhold(c) (get_cred(c))
 static inline void
-set_cr_group_info(afs_ucred_t *cred, struct group_info *group_info) {
-    cred->cr_group_info = group_info;
+afs_set_cr_uid(cred_t *cred, uid_t uid) {
+    cred->fsuid = uid;
+}
+static inline void
+afs_set_cr_gid(cred_t *cred, gid_t gid) {
+    cred->fsgid = gid;
+}
+static inline void
+afs_set_cr_ruid(cred_t *cred, uid_t uid) {
+    cred->uid = uid;
+}
+static inline void
+afs_set_cr_rgid(cred_t *cred, gid_t gid) {
+    cred->gid = gid;
+}
+static inline void
+afs_set_cr_group_info(cred_t *cred, struct group_info *group_info) {
+    cred->group_info = group_info;
 }
 
-#if !defined(current_cred)
-#define current_gid() (current->gid)
-#define current_uid() (current->uid)
-#define current_fsgid() (current->fsgid)
-#define current_fsuid() (current->fsuid)
-#endif
-#if defined(STRUCT_TASK_HAS_CRED)
 #define current_group_info() (current->cred->group_info)
 #define task_gid(task) (task->cred->gid)
 #define task_user(task) (task->cred->user)
 #define task_session_keyring(task) (task->cred->tgcred->session_keyring)
 #define current_session_keyring() (current->cred->tgcred->session_keyring)
+
 #else
+
+typedef struct afs_cred {
+    int cr_ref;
+    uid_t cr_uid;
+    uid_t cr_ruid;
+    gid_t cr_gid;
+    gid_t cr_rgid;
+    struct group_info *cr_group_info;
+} cred_t;
+
+typedef struct afs_cred afs_ucred_t;
+#define afs_cr_group_info(cred) ((cred)->cr_group_info)
+static inline void
+afs_set_cr_group_info(cred_t *cred, struct group_info *group_info) {
+    cred->cr_group_info = group_info;
+}
+
 #define current_group_info() (current->group_info)
 #if !defined(task_gid)
 #define task_gid(task) (task->gid)
@@ -195,9 +222,17 @@ set_cr_group_info(afs_ucred_t *cred, struct group_info *group_info) {
 #define task_user(task) (task->user)
 #define task_session_keyring(task) (task->signal->session_keyring)
 #define current_session_keyring() (current->signal->session_keyring)
-#endif
 #define crhold(c) (c)->cr_ref++
 
+#endif /* defined(STRUCT_TASK_HAS_CRED) */
+
+#if !defined(current_cred)
+#define current_gid() (current->gid)
+#define current_uid() (current->uid)
+#define current_fsgid() (current->fsgid)
+#define current_fsuid() (current->fsuid)
+#endif
+
 /* UIO manipulation */
 typedef enum { AFS_UIOSYS, AFS_UIOUSER } uio_seg_t;
 typedef enum { UIO_READ, UIO_WRITE } uio_flag_t;
index c03c9ca..4f45c38 100644 (file)
@@ -1399,7 +1399,12 @@ extern int afsd_dynamic_vcaches;
 #define afsd_dynamic_vcaches 0
 #endif
 
-/* Wrappers for access to credentials structure members */
+/*
+ * Wrappers for access to credentials structure members
+ * Linux uses the kernel cred structure if available, with the
+ * wrappers defined in LINUX/osi_machdep.h
+ */
+#if !(defined(AFS_LINUX26_ENV) && defined(STRUCT_TASK_HAS_CRED))
 #define afs_cr_uid(cred) ((cred)->cr_uid)
 #define afs_cr_gid(cred) ((cred)->cr_gid)
 #define afs_cr_ruid(cred) ((cred)->cr_ruid)
@@ -1421,4 +1426,5 @@ static_inline void
 afs_set_cr_rgid(afs_ucred_t *cred, gid_t gid) {
     cred->cr_rgid = gid;
 }
+#endif
 #endif /* _AFS_H_ */
index f075ef2..1257902 100644 (file)
@@ -115,7 +115,7 @@ osi_Init(void)
 #else
        memset(&afs_osi_cred, 0, sizeof(afs_ucred_t));
 #if defined(AFS_LINUX26_ENV)
-        set_cr_group_info(&afs_osi_cred, groups_alloc(0));
+        afs_set_cr_group_info(&afs_osi_cred, groups_alloc(0));
 #endif
 #if defined(AFS_DARWIN80_ENV)
         afs_osi_cred.cr_ref = 1; /* kauth_cred_get_ref needs 1 existing ref */
index b1d715f..740d460 100644 (file)
@@ -571,7 +571,7 @@ PagInCred(afs_ucred_t *cred)
        return NOPAG;
     }
 #elif defined(AFS_LINUX26_ENV)
-    if (cr_group_info(cred)->ngroups < NUMPAGGROUPS) {
+    if (afs_cr_group_info(cred)->ngroups < NUMPAGGROUPS) {
        pag = NOPAG;
        goto out;
     }
@@ -590,8 +590,8 @@ PagInCred(afs_ucred_t *cred)
     g1 = cred->cr_groupset.gs_union.un_groups[1];
 #elif defined(AFS_LINUX26_ONEGROUP_ENV)
 #elif defined(AFS_LINUX26_ENV)
-    g0 = GROUP_AT(cr_group_info(cred), 0);
-    g1 = GROUP_AT(cr_group_info(cred), 1);
+    g0 = GROUP_AT(afs_cr_group_info(cred), 0);
+    g1 = GROUP_AT(afs_cr_group_info(cred), 1);
 #elif defined(AFS_SUN510_ENV)
     g0 = gids[0];
     g1 = gids[1];
@@ -601,7 +601,7 @@ PagInCred(afs_ucred_t *cred)
 #endif
 #endif
 #if defined(AFS_LINUX26_ONEGROUP_ENV)
-    pag = (afs_int32) afs_get_pag_from_groups(cr_group_info(cred));
+    pag = (afs_int32) afs_get_pag_from_groups(afs_cr_group_info(cred));
 #else
     pag = (afs_int32) afs_get_pag_from_groups(g0, g1);
 #endif