225 lines · 6.1 KB · C
RawDownload
/* request_key_auth.c: request key authorisation controlling key def * * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * See Documentation/keys-request-key.txt */ #include <linux/module.h>#include <linux/sched.h>#include <linux/err.h>#include <linux/seq_file.h>#include <asm/uaccess.h>#include "internal.h" static int request_key_auth_instantiate(struct key *, const void *, size_t);static void request_key_auth_describe(const struct key *, struct seq_file *);static void request_key_auth_destroy(struct key *);static long request_key_auth_read(const struct key *, char __user *, size_t); /* * the request-key authorisation key type definition */struct key_type key_type_request_key_auth = {	.name		= ".request_key_auth",	.def_datalen	= sizeof(struct request_key_auth),	.instantiate	= request_key_auth_instantiate,	.describe	= request_key_auth_describe,	.destroy	= request_key_auth_destroy,	.read		= request_key_auth_read,}; /*****************************************************************************//* * instantiate a request-key authorisation key */static int request_key_auth_instantiate(struct key *key,					const void *data,					size_t datalen){	key->payload.data = (struct request_key_auth *) data;	return 0; } /* end request_key_auth_instantiate() */ /*****************************************************************************//* * reading a request-key authorisation key retrieves the callout information */static void request_key_auth_describe(const struct key *key,				      struct seq_file *m){	struct request_key_auth *rka = key->payload.data; 	seq_puts(m, "key:");	seq_puts(m, key->description);	seq_printf(m, " pid:%d ci:%zu", rka->pid, strlen(rka->callout_info)); } /* end request_key_auth_describe() */ /*****************************************************************************//* * read the callout_info data * - the key's semaphore is read-locked */static long request_key_auth_read(const struct key *key,				  char __user *buffer, size_t buflen){	struct request_key_auth *rka = key->payload.data;	size_t datalen;	long ret; 	datalen = strlen(rka->callout_info);	ret = datalen; 	/* we can return the data as is */	if (buffer && buflen > 0) {		if (buflen > datalen)			buflen = datalen; 		if (copy_to_user(buffer, rka->callout_info, buflen) != 0)			ret = -EFAULT;	} 	return ret; } /* end request_key_auth_read() */ /*****************************************************************************//* * destroy an instantiation authorisation token key */static void request_key_auth_destroy(struct key *key){	struct request_key_auth *rka = key->payload.data; 	kenter("{%d}", key->serial); 	key_put(rka->target_key);	kfree(rka); } /* end request_key_auth_destroy() */ /*****************************************************************************//* * create an authorisation token for /sbin/request-key or whoever to gain * access to the caller's security data */struct key *request_key_auth_new(struct key *target, const char *callout_info){	struct request_key_auth *rka, *irka;	struct key *authkey = NULL;	char desc[20];	int ret; 	kenter("%d,", target->serial); 	/* allocate a auth record */	rka = kmalloc(sizeof(*rka), GFP_KERNEL);	if (!rka) {		kleave(" = -ENOMEM");		return ERR_PTR(-ENOMEM);	} 	/* see if the calling process is already servicing the key request of	 * another process */	if (current->request_key_auth) {		/* it is - use that instantiation context here too */		irka = current->request_key_auth->payload.data;		rka->context = irka->context;		rka->pid = irka->pid;	}	else {		/* it isn't - use this process as the context */		rka->context = current;		rka->pid = current->pid;	} 	rka->target_key = key_get(target);	rka->callout_info = callout_info; 	/* allocate the auth key */	sprintf(desc, "%x", target->serial); 	authkey = key_alloc(&key_type_request_key_auth, desc,			    current->fsuid, current->fsgid, current,			    KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH |			    KEY_USR_VIEW, 1);	if (IS_ERR(authkey)) {		ret = PTR_ERR(authkey);		goto error_alloc;	} 	/* construct and attach to the keyring */	ret = key_instantiate_and_link(authkey, rka, 0, NULL, NULL);	if (ret < 0)		goto error_inst; 	kleave(" = {%d})", authkey->serial);	return authkey; error_inst:	key_revoke(authkey);	key_put(authkey);error_alloc:	key_put(rka->target_key);	kfree(rka);	kleave("= %d", ret);	return ERR_PTR(ret); } /* end request_key_auth_new() */ /*****************************************************************************//* * see if an authorisation key is associated with a particular key */static int key_get_instantiation_authkey_match(const struct key *key,					       const void *_id){	struct request_key_auth *rka = key->payload.data;	key_serial_t id = (key_serial_t)(unsigned long) _id; 	return rka->target_key->serial == id; } /* end key_get_instantiation_authkey_match() */ /*****************************************************************************//* * get the authorisation key for instantiation of a specific key if attached to * the current process's keyrings * - this key is inserted into a keyring and that is set as /sbin/request-key's *   session keyring * - a target_id of zero specifies any valid token */struct key *key_get_instantiation_authkey(key_serial_t target_id){	struct key *authkey;	key_ref_t authkey_ref; 	authkey_ref = search_process_keyrings(		&key_type_request_key_auth,		(void *) (unsigned long) target_id,		key_get_instantiation_authkey_match,		current); 	if (IS_ERR(authkey_ref)) {		authkey = ERR_PTR(PTR_ERR(authkey_ref));		goto error;	} 	authkey = key_ref_to_ptr(authkey_ref);	if (test_bit(KEY_FLAG_REVOKED, &authkey->flags)) {		key_put(authkey);		authkey = ERR_PTR(-EKEYREVOKED);	} error:	return authkey; } /* end key_get_instantiation_authkey() */