[PATCH 17/17] AFS: Implement the PGetTokens pioctl

David Howells dhowells at redhat.com
Tue Jun 16 16:40:13 EDT 2009


Implement the PGetTokens pioctl for AFS.  This will get the security tokens
cached for a user for security index 2 tokens.

This can be tested with the OpenAFS userspace tools by doing:

	tokens

which should return something like:

	[root at andromeda ~]# echo password | klog admin -pipe
	[root at andromeda ~]# keyctl show
	Session Keyring
	       -3 --alswrv      0     0  keyring: _ses
	237984081 --alswrv      0    -1   \_ keyring: _uid.0
	978861311 --als--v      0     0   \_ rxrpc: cambridge.redhat.com
	[root at andromeda ~]# tokens

	Tokens held by the Cache Manager:

	User's (AFS ID 10143) tokens for afs at cambridge.redhat.com [Expires Jun 16 16:10]
	   --End of list--

Signed-off-by: David Howells <dhowells at redhat.com>
---

 fs/afs/pioctl.c         |  174 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/afscall.h |    1 
 include/linux/venus.h   |    1 
 3 files changed, 176 insertions(+), 0 deletions(-)


diff --git a/fs/afs/pioctl.c b/fs/afs/pioctl.c
index e6ea69f..d097745 100644
--- a/fs/afs/pioctl.c
+++ b/fs/afs/pioctl.c
@@ -392,6 +392,175 @@ invalid:
 }
 
 /*
+ * filter tickets by security index when enumerating
+ */
+bool afs_enum_filter(const struct key *key, void *data)
+{
+	unsigned long security_index = (unsigned long) data;
+
+	return key->type == &key_type_rxrpc &&
+		key->type_data.x[0] == security_index &&
+		memcmp(key->description, "afs@", 4) == 0;
+}
+
+/*
+ * Get a user's authentication rxkad tokens
+ */
+static long afs_PGetTokens(struct vice_ioctl *arg)
+{
+	struct rxrpc_key_payload *upayload;
+	struct clear_token details;
+	struct afs_cell *root_cell;
+	struct key *key;
+	key_ref_t keyring_r, key_r = NULL;
+	size_t out_size;
+	void *out, *out_next;
+	long ret;
+	int skip;
+	u32 tmp, ticket_len;
+
+	_enter("");
+
+	/* find out which key we're being asked for */
+	if (arg->in_size == 0) {
+		skip = -1;
+	} else if (arg->in_size == sizeof(skip)) {
+		memcpy(&skip, arg->in, sizeof(skip));
+		if (skip < 0) {
+			_leave(" = -EINVAL [inval iter]");
+			return -EINVAL;
+		}
+	} else {
+		_leave(" = -EINVAL [bad arg size]");
+		return -EINVAL;
+	}
+
+	_debug("iterator: %d", skip);
+
+	/* we're going to look through the session keyring */
+	keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 1, 0,
+				    WANT_KEY_SEARCH);
+	if (IS_ERR(keyring_r)) {
+		_leave(" = %ld [keyring]", PTR_ERR(keyring_r));
+		return PTR_ERR(keyring_r);
+	}
+
+	root_cell = afs_get_root_cell();
+	ASSERT(root_cell != NULL);
+
+	/* if there's no input argument, then we return the tokens for the root
+	 * cell; if there is an argument, then we're being asked for the nth
+	 * key belonging to this session */
+	if (skip >= 0) {
+		key_r = keyring_enum(keyring_r, skip,
+				     afs_enum_filter,
+				     (void *) RXRPC_SECURITY_RXKAD,
+				     WANT_KEY_SEARCH);
+		if (key_r == ERR_PTR(-ENOKEY)) {
+			ret = -EDOM;
+			goto error_no_key;
+		}
+	} else {
+		/* find key for the root cell */
+		key_r = keyring_search(keyring_r, &key_type_rxrpc,
+				       root_cell->anonymous_key->description);
+		if (key_r == ERR_PTR(-ENOKEY)) {
+			ret = -ENOTCONN;
+			goto error_no_key;
+		}
+	}
+
+	key_ref_put(keyring_r);
+	keyring_r = NULL;
+
+	if (IS_ERR(key_r)) {
+		if (key_r == ERR_PTR(-EACCES))
+			ret = -EACCES;
+		else
+			ret = -EIO;
+		goto error_no_key;
+	}
+
+	key = key_ref_to_ptr(key_r);
+	upayload = key->payload.data;
+
+	_debug("key serial: %x", key->serial);
+
+	/* pass the contents of the key back to userspace */
+#define CHECK(n)				\
+	do {					\
+		if (out_size < (n)) {		\
+			ret = -EINVAL;		\
+			goto error;		\
+		}				\
+		out = out_next;			\
+		out_size -= (n);		\
+		out_next += (n);		\
+	} while(0)
+
+#define ENCODE(from)					\
+	do {						\
+		CHECK(sizeof(*(from)));			\
+		memcpy(out, from, sizeof(*(from)));	\
+	} while(0)
+
+	out_next = arg->out;
+	out_size = arg->out_size;
+
+	/* pass the ticket in at least 56 bytes of space */
+	ticket_len = upayload->k.ticket_len;
+	tmp = min(ticket_len, 56U);
+	ENCODE(&tmp);
+	CHECK(tmp);
+	memcpy(out, upayload->k.ticket, ticket_len);
+	if (ticket_len < tmp)
+		memset(out + ticket_len, 0, tmp - ticket_len);
+
+	tmp = sizeof(details);
+	ENCODE(&tmp);
+	details.vice_id		= upayload->k.vice_id;
+	details.begin_timestamp	= upayload->k.start;
+	details.end_timestamp	= upayload->k.expiry;
+	details.auth_handle	= upayload->k.kvno;
+	memcpy(details.session_key, upayload->k.session_key, 8);
+	ENCODE(&details);
+
+	/* if we were given an iterator, then there's more stuff we must
+	 * return */
+	if (arg->in_size > 0) {
+		struct afs_cell *cell;
+		size_t cellname_size;
+
+		cellname_size = strlen(key->description + 4);
+		cell = afs_cell_lookup(key->description + 4, cellname_size);
+		tmp = (cell == root_cell) ? 1 : 0;
+		if (!IS_ERR(cell))
+			afs_put_cell(cell);
+		ENCODE(&tmp);
+		CHECK(cellname_size + 1);
+		memcpy(out, key->description + 4, cellname_size + 1);
+	}
+
+#undef ENCODE
+#undef CHECK
+
+	arg->out_size = (char *) out_next - arg->out;
+
+	key_ref_put(key_r);
+	afs_put_cell(root_cell);
+	_leave(" = 0");
+	return 0;
+
+error:
+	key_ref_put(key_r);
+error_no_key:
+	key_ref_put(keyring_r);
+	afs_put_cell(root_cell);
+	_leave(" = %ld", ret);
+	return ret;
+}
+
+/*
  * The AFS pathless pioctl handler
  */
 long afs_pathless_pioctl(int cmd, struct vice_ioctl *arg)
@@ -408,6 +577,11 @@ long afs_pathless_pioctl(int cmd, struct vice_ioctl *arg)
 		ret = afs_PSetTokens(arg);
 		break;
 
+
+	case VIOC_COMMAND(PGetTokens):
+		ret = afs_PGetTokens(arg);
+		break;
+
 	default:
 		printk(KERN_DEBUG "AFS: Unsupported pioctl command %x\n", cmd);
 		ret = -EOPNOTSUPP;
diff --git a/include/linux/afscall.h b/include/linux/afscall.h
index 7635aab..bdff9a0 100644
--- a/include/linux/afscall.h
+++ b/include/linux/afscall.h
@@ -18,6 +18,7 @@
 /* pioctl commands */
 #define PSetTokens	3		/* get authentication tokens for user */
 #define PGetVolStat	4		/* get volume status */
+#define PGetTokens	8		/* get authentication tokens for user */
 #define PWhereIs	14		/* find out where a volume is located */
 #define PGetFID		22		/* get file ID */
 #define PFlushCB	25		/* flush callback only */
diff --git a/include/linux/venus.h b/include/linux/venus.h
index b90e5f2..7a3ae08 100644
--- a/include/linux/venus.h
+++ b/include/linux/venus.h
@@ -19,6 +19,7 @@
  */
 #define VIOCSETTOK		_VICEIOCTL(PSetTokens)
 #define VIOCGETVOLSTAT		_VICEIOCTL(PGetVolStat)
+#define VIOCGETTOK		_VICEIOCTL(PGetTokens)
 #define VIOCWHEREIS		_VICEIOCTL(PWhereIs)
 #define VIOCGETFID		_VICEIOCTL(PGetFID)
 #define VIOCFLUSHCB		_VICEIOCTL(PFlushCB)




More information about the linux-afs mailing list