*/
#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
/* 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;
}