linux-keyring-pags-20060804
authorChas Williams <chas@cmf.nrl.navy.mil>
Fri, 4 Aug 2006 16:55:21 +0000 (16:55 +0000)
committerDerrick Brashear <shadow@dementia.org>
Fri, 4 Aug 2006 16:55:21 +0000 (16:55 +0000)
ok, well, first try

acinclude.m4
src/afs/LINUX/osi_groups.c
src/afs/LINUX/osi_module.c
src/afs/LINUX/osi_prototypes.h
src/afs/afs_osi_pag.c
src/afs/sysincludes.h
src/cf/linux-test4.m4

index 2a3d6d9..5ecb94f 100644 (file)
@@ -603,6 +603,8 @@ case $AFS_SYSNAME in *_linux* | *_umlinux*)
                 LINUX_SCHED_STRUCT_TASK_STRUCT_HAS_SIGNAL_RLIM
                 LINUX_SCHED_STRUCT_TASK_STRUCT_HAS_EXIT_STATE
                 LINUX_REFRIGERATOR
+                LINUX_LINUX_KEYRING_SUPPORT
+                LINUX_KEY_ALLOC_NEEDS_STRUCT_TASK
                 LINUX_WHICH_MODULES
                  if test "x$ac_cv_linux_config_modversions" = "xno" -o $AFS_SYSKVERS -ge 26; then
                    AC_MSG_WARN([Cannot determine sys_call_table status. assuming it isn't exported])
index 8a4e2d2..bf21172 100644 (file)
@@ -15,6 +15,9 @@
  */
 #include <afsconfig.h>
 #include "afs/param.h"
+#ifdef LINUX_KEYRING_SUPPORT
+#include <linux/seq_file.h>
+#endif
 
 RCSID
     ("$Header$");
@@ -148,11 +151,11 @@ set_pag_in_parent(int pag, int g0, int g1)
 }
 #endif
 
+#if defined(AFS_LINUX26_ENV)
 int
-setpag(cred_t ** cr, afs_uint32 pagvalue, afs_uint32 * newpag,
-       int change_parent)
+__setpag(cred_t ** cr, afs_uint32 pagvalue, afs_uint32 * newpag,
+         int change_parent)
 {
-#if defined(AFS_LINUX26_ENV)
     struct group_info *group_info;
     gid_t g0, g1;
     struct group_info *tmp;
@@ -185,7 +188,64 @@ setpag(cred_t ** cr, afs_uint32 pagvalue, afs_uint32 * newpag,
     put_group_info(group_info);
 
     return 0;
+}
+
+#ifdef LINUX_KEYRING_SUPPORT
+#include <asm/unistd.h>
+#include <linux/keyctl.h>
+
+static int errno;
+static inline _syscall2(long, keyctl, int, option, void*, arg2);
+
+static long
+__join_session_keyring(char *name)
+{
+       return keyctl(KEYCTL_JOIN_SESSION_KEYRING, name);
+}
+#endif /* LINUX_KEYRING_SUPPORT */
+
+int
+setpag(cred_t ** cr, afs_uint32 pagvalue, afs_uint32 * newpag,
+         int change_parent)
+{
+    int code;
+
+    code = __setpag(cr, pagvalue, newpag, change_parent);
+
+#ifdef LINUX_KEYRING_SUPPORT
+    if (code == 0) {
+
+       (void) __join_session_keyring(NULL);
+
+       if (current->signal->session_keyring) {
+           struct key *key;
+           key_perm_t perm;
+
+           perm = KEY_POS_VIEW | KEY_POS_SEARCH;
+           perm |= KEY_USR_VIEW | KEY_USR_SEARCH;
+
+#ifdef KEY_ALLOC_NEEDS_STRUCT_TASK
+           key = key_alloc(&key_type_afs_pag, "_pag", 0, 0, current, perm, 1);
+#else
+           key = key_alloc(&key_type_afs_pag, "_pag", 0, 0, perm, 1);
+#endif
+
+           if (!IS_ERR(key)) {
+               key_instantiate_and_link(key, (void *) newpag, sizeof(afs_uint32),
+                                        current->signal->session_keyring, NULL);
+               key_put(key);
+           }
+       }
+    }
+#endif /* LINUX_KEYRING_SUPPORT */
+
+    return code;
+}
 #else
+int
+setpag(cred_t ** cr, afs_uint32 pagvalue, afs_uint32 * newpag,
+       int change_parent)
+{
     gid_t *gidset;
     afs_int32 ngroups, code = 0;
     int j;
@@ -219,8 +279,8 @@ setpag(cred_t ** cr, afs_uint32 pagvalue, afs_uint32 * newpag,
 
     osi_Free((char *)gidset, NGROUPS * sizeof(int));
     return code;
-#endif
 }
+#endif
 
 
 /* Intercept the standard system call. */
@@ -396,3 +456,86 @@ afs32_xsetgroups32(int gidsetsize, gid_t * grouplist)
 #endif
 #endif
 
+
+#ifdef LINUX_KEYRING_SUPPORT
+static void afs_pag_describe(const struct key *key, struct seq_file *m)
+{
+    seq_puts(m, key->description);
+
+    seq_printf(m, ": %u", key->datalen);
+}
+
+static int afs_pag_instantiate(struct key *key, const void *data, size_t datalen)
+{
+    int code;
+    afs_uint32 *userpag, pag = NOPAG;
+    int g0, g1;
+
+    if (key->uid != 0 || key->gid != 0)
+       return -EPERM;
+
+    code = -EINVAL;
+    get_group_info(current->group_info);
+
+    if (datalen != sizeof(afs_uint32) || !data)
+       goto error;
+
+    if (current->group_info->ngroups < 2)
+       goto error;
+
+    /* ensure key being set matches current pag */
+
+    g0 = GROUP_AT(current->group_info, 0);
+    g1 = GROUP_AT(current->group_info, 1);
+
+    pag = afs_get_pag_from_groups(g0, g1);
+    if (pag == NOPAG)
+       goto error;
+
+    userpag = (afs_uint32 *) data;
+    if (*userpag != pag)
+       goto error;
+
+    key->payload.value = (unsigned long) *userpag;
+    key->datalen = sizeof(afs_uint32);
+    code = 0;
+
+error:
+    put_group_info(current->group_info);
+    return code;
+}
+
+static int afs_pag_match(const struct key *key, const void *description)
+{
+       return strcmp(key->description, description) == 0;
+}
+
+struct key_type key_type_afs_pag =
+{
+    .name        = "afs_pag",
+    .describe    = afs_pag_describe,
+    .instantiate = afs_pag_instantiate,
+    .match       = afs_pag_match,
+};
+
+void osi_keyring_init(void)
+{
+    register_key_type(&key_type_afs_pag);
+}
+
+void osi_keyring_shutdown(void)
+{
+    unregister_key_type(&key_type_afs_pag);
+}
+
+#else
+void osi_keyring_init(void)
+{
+       return;
+}
+
+void osi_keyring_shutdown(void)
+{
+       return;
+}
+#endif
index 33c3327..6ba552c 100644 (file)
@@ -86,14 +86,19 @@ init_module(void)
     osi_linux_nfssrv_init();
 #endif
 
+#ifndef LINUX_KEYRING_SUPPORT
     err = osi_syscall_init();
     if (err)
        return err;
+#endif
     err = afs_init_inodecache();
     if (err)
        return err;
     register_filesystem(&afs_fs_type);
     osi_sysctl_init();
+#ifdef LINUX_KEYRING_SUPPORT
+    osi_keyring_init();
+#endif
 #ifdef AFS_LINUX24_ENV
     osi_proc_init();
     osi_ioctl_init();
@@ -110,6 +115,7 @@ void
 cleanup_module(void)
 #endif
 {
+    osi_keyring_shutdown();
     osi_sysctl_clean();
     osi_syscall_clean();
     unregister_filesystem(&afs_fs_type);
index 7f97c75..149274c 100644 (file)
@@ -87,4 +87,14 @@ extern void osi_linux_free_inode_pages(void);
 /* osi_vnodeops.c */
 extern void afs_fill_inode(struct inode *ip, struct vattr *vattr);
 
+/* osi_groups.c */
+extern void osi_keyring_init(void);
+extern void osi_keyring_shutdown(void);
+extern int __setpag(cred_t **cr, afs_uint32 pagvalue, afs_uint32 *newpag,
+                    int change_parent);
+#ifdef LINUX_KEYRING_SUPPORT
+extern struct key_type key_type_afs_pag;
+#endif /* LINUX_KEYRING_SUPPORT */
+
+
 #endif /* _OSI_PROTO_H_ */
index 53b4739..a7fda77 100644 (file)
@@ -462,8 +462,6 @@ afs_get_pag_from_groups(gid_t g0a, gid_t g1a)
        /* Additional testing */
        if (((ret >> 24) & 0xff) == 'A')
            return ret;
-       else
-           return NOPAG;
 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
     }
     return NOPAG;
@@ -496,7 +494,7 @@ PagInCred(const struct AFS_UCRED *cred)
     gid_t g0, g1;
 
     AFS_STATCNT(PagInCred);
-    if (cred == NULL) {
+    if (cred == NULL || cred == afs_osi_credp) {
        return NOPAG;
     }
 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
@@ -518,11 +516,15 @@ PagInCred(const struct AFS_UCRED *cred)
        return NOPAG;
     }
 #elif defined(AFS_LINUX26_ENV)
-    if (cred->cr_group_info->ngroups < 2)
-       return NOPAG;
+    if (cred->cr_group_info->ngroups < 2) {
+       pag = NOPAG;
+       goto out;
+    }
 #elif defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_DUX40_ENV) || defined(AFS_LINUX20_ENV) || defined(AFS_XBSD_ENV)
-    if (cred->cr_ngroups < 2)
-       return NOPAG;
+    if (cred->cr_ngroups < 2) {
+       pag = NOPAG;
+       goto out;
+    }
 #endif
 #if defined(AFS_AIX51_ENV)
     g0 = cred->cr_groupset.gs_union.un_groups[0];
@@ -536,5 +538,23 @@ PagInCred(const struct AFS_UCRED *cred)
 #endif
 #endif
     pag = (afs_int32) afs_get_pag_from_groups(g0, g1);
+out:
+#ifdef LINUX_KEYRING_SUPPORT
+    if (pag == NOPAG) {
+       struct key *key;
+       afs_uint32 pag, newpag;
+
+       key = request_key(&key_type_afs_pag, "_pag", NULL);
+       if (!IS_ERR(key)) {
+           if (key_validate(key) == 0 && key->uid == 0) {      /* also verify in the session keyring? */
+
+               pag = (afs_uint32) key->payload.value;
+               if (((pag >> 24) & 0xff) == 'A')
+                   __setpag(&cred, pag, &newpag, 0);
+           }
+           key_put(key);
+       } 
+    }
+#endif
     return pag;
 }
index 787bcd3..ed7117b 100644 (file)
 #include <linux/security.h>
 #endif
 #include <linux/suspend.h>
+#if defined(LINUX_KEYRING_SUPPORT)
+#include <linux/rwsem.h>
+#include <linux/key.h>
+#endif
 #endif
 /* Avoid conflicts with coda overloading AFS type namespace. Must precede
  * inclusion of uaccess.h.
index aa3e10f..7391891 100644 (file)
@@ -587,3 +587,41 @@ AC_DEFUN([LINUX_GET_SB_HAS_STRUCT_VFSMOUNT], [
       ac_cv_linux_get_sb_has_struct_vfsmount=yes,
       ac_cv_linux_get_sb_has_struct_vfsmount=no)])
   AC_MSG_RESULT($ac_cv_linux_get_sb_has_struct_vfsmount)])
+
+AC_DEFUN([LINUX_LINUX_KEYRING_SUPPORT], [
+  AC_MSG_CHECKING([for linux kernel keyring support])
+  AC_CACHE_VAL([ac_cv_linux_keyring_support], [
+    AC_TRY_KBUILD(
+[#include <linux/rwsem.h>
+#include <linux/key.h>
+#include <linux/keyctl.h>
+#include <asm/unistd.h>
+static int errno;
+static inline _syscall2(long, keyctl, int, option, void*, arg2);],
+[#ifdef CONFIG_KEYS
+keyctl(KEYCTL_JOIN_SESSION_KEYRING, NULL);
+request_key(NULL, NULL, NULL);
+#else
+#error rebuild your kernel with CONFIG_KEYS
+#endif],
+      ac_cv_linux_keyring_support=yes,
+      ac_cv_linux_keyring_support=no)])
+  AC_MSG_RESULT($ac_cv_linux_keyring_support)
+  if test "x$ac_cv_linux_keyring_support" = "xyes"; then
+    AC_DEFINE([LINUX_KEYRING_SUPPORT], 1, [define if your kernel has keyring support])
+  fi])
+
+AC_DEFUN([LINUX_KEY_ALLOC_NEEDS_STRUCT_TASK], [
+  AC_MSG_CHECKING([if key_alloc() takes a struct task *])
+  AC_CACHE_VAL([ac_cv_key_alloc_needs_struct_task], [
+    AC_TRY_KBUILD(
+[#include <linux/rwsem.h>
+#include <linux/key.h>
+],
+[(void) key_alloc(NULL, NULL, 0, 0, NULL, 0, 0);],
+      ac_cv_key_alloc_needs_struct_task=yes,
+      ac_cv_key_alloc_needs_struct_task=no)])
+  AC_MSG_RESULT($ac_cv_key_alloc_needs_struct_task)
+  if test "x$ac_cv_key_alloc_needs_struct_task" = "xyes"; then
+    AC_DEFINE([KEY_ALLOC_NEEDS_STRUCT_TASK], 1, [define if key_alloc takes a struct task *])
+  fi])