2005-04-17 02:20:36 +04:00
/* user_defined.c: user defined key type
*
* Copyright ( C ) 2004 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 .
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/seq_file.h>
# include <linux/err.h>
2005-10-31 02:02:42 +03:00
# include <keys/user-type.h>
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
# include "internal.h"
/*
* user defined keys take an arbitrary string as the description and an
* arbitrary blob of data as the payload
*/
struct key_type key_type_user = {
. name = " user " ,
. instantiate = user_instantiate ,
. update = user_update ,
. match = user_match ,
2006-06-26 11:24:51 +04:00
. revoke = user_revoke ,
2005-04-17 02:20:36 +04:00
. destroy = user_destroy ,
. describe = user_describe ,
. read = user_read ,
} ;
2005-06-24 09:00:58 +04:00
EXPORT_SYMBOL_GPL ( key_type_user ) ;
2005-04-17 02:20:36 +04:00
/*
* instantiate a user defined key
*/
2005-10-31 02:02:42 +03:00
int user_instantiate ( struct key * key , const void * data , size_t datalen )
2005-04-17 02:20:36 +04:00
{
2005-06-24 09:00:49 +04:00
struct user_key_payload * upayload ;
2005-04-17 02:20:36 +04:00
int ret ;
ret = - EINVAL ;
if ( datalen < = 0 | | datalen > 32767 | | ! data )
goto error ;
ret = key_payload_reserve ( key , datalen ) ;
if ( ret < 0 )
goto error ;
ret = - ENOMEM ;
2005-06-24 09:00:49 +04:00
upayload = kmalloc ( sizeof ( * upayload ) + datalen , GFP_KERNEL ) ;
if ( ! upayload )
2005-04-17 02:20:36 +04:00
goto error ;
2005-06-24 09:00:49 +04:00
/* attach the data */
upayload - > datalen = datalen ;
memcpy ( upayload - > data , data , datalen ) ;
rcu_assign_pointer ( key - > payload . data , upayload ) ;
2005-04-17 02:20:36 +04:00
ret = 0 ;
2005-10-31 02:02:42 +03:00
error :
2005-04-17 02:20:36 +04:00
return ret ;
2011-01-20 19:38:27 +03:00
}
2006-06-26 11:24:51 +04:00
2005-10-31 02:02:42 +03:00
EXPORT_SYMBOL_GPL ( user_instantiate ) ;
2005-06-24 09:00:49 +04:00
/*
* dispose of the old data from an updated user defined key
*/
static void user_update_rcu_disposal ( struct rcu_head * rcu )
{
struct user_key_payload * upayload ;
upayload = container_of ( rcu , struct user_key_payload , rcu ) ;
kfree ( upayload ) ;
2011-01-20 19:38:27 +03:00
}
2005-06-24 09:00:49 +04:00
2005-04-17 02:20:36 +04:00
/*
* update a user defined key
2005-06-24 09:00:49 +04:00
* - the key ' s semaphore is write - locked
2005-04-17 02:20:36 +04:00
*/
2005-10-31 02:02:42 +03:00
int user_update ( struct key * key , const void * data , size_t datalen )
2005-04-17 02:20:36 +04:00
{
2005-06-24 09:00:49 +04:00
struct user_key_payload * upayload , * zap ;
2005-04-17 02:20:36 +04:00
int ret ;
ret = - EINVAL ;
if ( datalen < = 0 | | datalen > 32767 | | ! data )
goto error ;
2005-06-24 09:00:49 +04:00
/* construct a replacement payload */
2005-04-17 02:20:36 +04:00
ret = - ENOMEM ;
2005-06-24 09:00:49 +04:00
upayload = kmalloc ( sizeof ( * upayload ) + datalen , GFP_KERNEL ) ;
if ( ! upayload )
2005-04-17 02:20:36 +04:00
goto error ;
2005-06-24 09:00:49 +04:00
upayload - > datalen = datalen ;
memcpy ( upayload - > data , data , datalen ) ;
2005-04-17 02:20:36 +04:00
/* check the quota and attach the new data */
2005-06-24 09:00:49 +04:00
zap = upayload ;
2005-04-17 02:20:36 +04:00
ret = key_payload_reserve ( key , datalen ) ;
if ( ret = = 0 ) {
/* attach the new data, displacing the old */
zap = key - > payload . data ;
2005-06-24 09:00:49 +04:00
rcu_assign_pointer ( key - > payload . data , upayload ) ;
2005-04-17 02:20:36 +04:00
key - > expiry = 0 ;
}
2005-06-24 09:00:49 +04:00
call_rcu ( & zap - > rcu , user_update_rcu_disposal ) ;
2005-04-17 02:20:36 +04:00
2005-10-31 02:02:42 +03:00
error :
2005-04-17 02:20:36 +04:00
return ret ;
2011-01-20 19:38:27 +03:00
}
2005-04-17 02:20:36 +04:00
2005-10-31 02:02:42 +03:00
EXPORT_SYMBOL_GPL ( user_update ) ;
2005-04-17 02:20:36 +04:00
/*
* match users on their name
*/
2005-10-31 02:02:42 +03:00
int user_match ( const struct key * key , const void * description )
2005-04-17 02:20:36 +04:00
{
return strcmp ( key - > description , description ) = = 0 ;
2011-01-20 19:38:27 +03:00
}
2005-04-17 02:20:36 +04:00
2005-10-31 02:02:42 +03:00
EXPORT_SYMBOL_GPL ( user_match ) ;
2005-04-17 02:20:36 +04:00
/*
2006-06-26 11:24:51 +04:00
* dispose of the links from a revoked keyring
* - called with the key sem write - locked
*/
void user_revoke ( struct key * key )
{
struct user_key_payload * upayload = key - > payload . data ;
/* clear the quota */
key_payload_reserve ( key , 0 ) ;
if ( upayload ) {
rcu_assign_pointer ( key - > payload . data , NULL ) ;
call_rcu ( & upayload - > rcu , user_update_rcu_disposal ) ;
}
2011-01-20 19:38:27 +03:00
}
2006-06-26 11:24:51 +04:00
EXPORT_SYMBOL ( user_revoke ) ;
/*
* dispose of the data dangling from the corpse of a user key
2005-04-17 02:20:36 +04:00
*/
2005-10-31 02:02:42 +03:00
void user_destroy ( struct key * key )
2005-04-17 02:20:36 +04:00
{
2005-06-24 09:00:49 +04:00
struct user_key_payload * upayload = key - > payload . data ;
kfree ( upayload ) ;
2011-01-20 19:38:27 +03:00
}
2005-04-17 02:20:36 +04:00
2005-10-31 02:02:42 +03:00
EXPORT_SYMBOL_GPL ( user_destroy ) ;
2005-04-17 02:20:36 +04:00
/*
2005-06-24 09:00:49 +04:00
* describe the user key
2005-04-17 02:20:36 +04:00
*/
2005-10-31 02:02:42 +03:00
void user_describe ( const struct key * key , struct seq_file * m )
2005-04-17 02:20:36 +04:00
{
seq_puts ( m , key - > description ) ;
seq_printf ( m , " : %u " , key - > datalen ) ;
2011-01-20 19:38:27 +03:00
}
2005-04-17 02:20:36 +04:00
2005-10-31 02:02:42 +03:00
EXPORT_SYMBOL_GPL ( user_describe ) ;
2005-04-17 02:20:36 +04:00
/*
* read the key data
2005-06-24 09:00:49 +04:00
* - the key ' s semaphore is read - locked
2005-04-17 02:20:36 +04:00
*/
2005-10-31 02:02:42 +03:00
long user_read ( const struct key * key , char __user * buffer , size_t buflen )
2005-04-17 02:20:36 +04:00
{
2005-06-24 09:00:49 +04:00
struct user_key_payload * upayload ;
long ret ;
2010-04-30 17:32:08 +04:00
upayload = rcu_dereference_protected (
key - > payload . data , rwsem_is_locked ( & ( ( struct key * ) key ) - > sem ) ) ;
2005-06-24 09:00:49 +04:00
ret = upayload - > datalen ;
2005-04-17 02:20:36 +04:00
/* we can return the data as is */
if ( buffer & & buflen > 0 ) {
2005-06-24 09:00:49 +04:00
if ( buflen > upayload - > datalen )
buflen = upayload - > datalen ;
2005-04-17 02:20:36 +04:00
2005-06-24 09:00:49 +04:00
if ( copy_to_user ( buffer , upayload - > data , buflen ) ! = 0 )
2005-04-17 02:20:36 +04:00
ret = - EFAULT ;
}
return ret ;
2011-01-20 19:38:27 +03:00
}
2005-10-31 02:02:42 +03:00
EXPORT_SYMBOL_GPL ( user_read ) ;