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])
*/
#include <afsconfig.h>
#include "afs/param.h"
+#ifdef LINUX_KEYRING_SUPPORT
+#include <linux/seq_file.h>
+#endif
RCSID
("$Header$");
}
#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;
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;
osi_Free((char *)gidset, NGROUPS * sizeof(int));
return code;
-#endif
}
+#endif
/* Intercept the standard system call. */
#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
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();
cleanup_module(void)
#endif
{
+ osi_keyring_shutdown();
osi_sysctl_clean();
osi_syscall_clean();
unregister_filesystem(&afs_fs_type);
/* 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_ */
/* Additional testing */
if (((ret >> 24) & 0xff) == 'A')
return ret;
- else
- return NOPAG;
#endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
}
return NOPAG;
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)
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];
#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;
}
#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.
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])