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>
2016-12-24 22:46:01 +03:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
# include "internal.h"
2012-01-18 01:09:11 +04:00
static int logon_vet_description ( const char * desc ) ;
2005-04-17 02:20:36 +04:00
/*
* 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 = {
2013-09-24 13:35:15 +04:00
. name = " user " ,
2014-07-18 21:56:35 +04:00
. preparse = user_preparse ,
. free_preparse = user_free_preparse ,
. instantiate = generic_key_instantiate ,
2013-09-24 13:35:15 +04:00
. update = user_update ,
. revoke = user_revoke ,
. destroy = user_destroy ,
. describe = user_describe ,
. read = user_read ,
2005-04-17 02:20:36 +04:00
} ;
2005-06-24 09:00:58 +04:00
EXPORT_SYMBOL_GPL ( key_type_user ) ;
2012-01-18 01:09:11 +04:00
/*
* This key type is essentially the same as key_type_user , but it does
* not define a . read op . This is suitable for storing username and
* password pairs in the keyring that you do not want to be readable
* from userspace .
*/
struct key_type key_type_logon = {
. name = " logon " ,
2014-07-18 21:56:35 +04:00
. preparse = user_preparse ,
. free_preparse = user_free_preparse ,
. instantiate = generic_key_instantiate ,
2012-01-18 01:09:11 +04:00
. update = user_update ,
. revoke = user_revoke ,
. destroy = user_destroy ,
. describe = user_describe ,
. vet_description = logon_vet_description ,
} ;
EXPORT_SYMBOL_GPL ( key_type_logon ) ;
2005-04-17 02:20:36 +04:00
/*
2014-07-18 21:56:35 +04:00
* Preparse a user defined key payload
2005-04-17 02:20:36 +04:00
*/
2014-07-18 21:56:35 +04:00
int user_preparse ( struct key_preparsed_payload * prep )
2005-04-17 02:20:36 +04:00
{
2005-06-24 09:00:49 +04:00
struct user_key_payload * upayload ;
2012-09-13 16:06:29 +04:00
size_t datalen = prep - > datalen ;
2005-04-17 02:20:36 +04:00
2012-09-13 16:06:29 +04:00
if ( datalen < = 0 | | datalen > 32767 | | ! prep - > data )
2014-07-18 21:56:35 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2005-06-24 09:00:49 +04:00
upayload = kmalloc ( sizeof ( * upayload ) + datalen , GFP_KERNEL ) ;
if ( ! upayload )
2014-07-18 21:56:35 +04:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
2005-06-24 09:00:49 +04:00
/* attach the data */
2014-07-18 21:56:35 +04:00
prep - > quotalen = datalen ;
2015-10-21 16:04:48 +03:00
prep - > payload . data [ 0 ] = upayload ;
2005-06-24 09:00:49 +04:00
upayload - > datalen = datalen ;
2012-09-13 16:06:29 +04:00
memcpy ( upayload - > data , prep - > data , datalen ) ;
2014-07-18 21:56:35 +04:00
return 0 ;
2011-01-20 19:38:27 +03:00
}
2014-07-18 21:56:35 +04:00
EXPORT_SYMBOL_GPL ( user_preparse ) ;
2006-06-26 11:24:51 +04:00
2014-07-18 21:56:35 +04:00
/*
* Free a preparse of a user defined key payload
*/
void user_free_preparse ( struct key_preparsed_payload * prep )
{
2017-06-08 16:49:04 +03:00
kzfree ( prep - > payload . data [ 0 ] ) ;
2014-07-18 21:56:35 +04:00
}
EXPORT_SYMBOL_GPL ( user_free_preparse ) ;
2005-10-31 02:02:42 +03:00
2017-06-08 16:49:04 +03:00
static void user_free_payload_rcu ( struct rcu_head * head )
{
struct user_key_payload * payload ;
payload = container_of ( head , struct user_key_payload , rcu ) ;
kzfree ( payload ) ;
}
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
*/
2012-09-13 16:06:29 +04:00
int user_update ( struct key * key , struct key_preparsed_payload * prep )
2005-04-17 02:20:36 +04:00
{
2016-04-12 21:54:58 +03:00
struct user_key_payload * zap = NULL ;
2005-04-17 02:20:36 +04:00
int ret ;
/* check the quota and attach the new data */
2016-04-12 21:54:58 +03:00
ret = key_payload_reserve ( key , prep - > datalen ) ;
if ( ret < 0 )
return ret ;
/* attach the new data, displacing the old */
key - > expiry = prep - > expiry ;
2017-10-04 18:43:25 +03:00
if ( key_is_positive ( key ) )
2017-03-01 18:11:23 +03:00
zap = dereference_key_locked ( key ) ;
2016-04-12 21:54:58 +03:00
rcu_assign_keypointer ( key , prep - > payload . data [ 0 ] ) ;
prep - > payload . data [ 0 ] = NULL ;
2005-04-17 02:20:36 +04:00
2011-11-16 02:09:45 +04:00
if ( zap )
2017-06-08 16:49:04 +03:00
call_rcu ( & zap - > rcu , user_free_payload_rcu ) ;
2005-04-17 02:20:36 +04:00
return ret ;
2011-01-20 19:38:27 +03:00
}
2005-10-31 02:02:42 +03:00
EXPORT_SYMBOL_GPL ( user_update ) ;
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 )
{
2017-03-01 18:11:23 +03:00
struct user_key_payload * upayload = user_key_payload_locked ( key ) ;
2006-06-26 11:24:51 +04:00
/* clear the quota */
key_payload_reserve ( key , 0 ) ;
if ( upayload ) {
2012-01-18 14:03:14 +04:00
rcu_assign_keypointer ( key , NULL ) ;
2017-06-08 16:49:04 +03:00
call_rcu ( & upayload - > rcu , user_free_payload_rcu ) ;
2006-06-26 11:24:51 +04:00
}
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
{
2015-10-21 16:04:48 +03:00
struct user_key_payload * upayload = key - > payload . data [ 0 ] ;
2005-06-24 09:00:49 +04:00
2017-06-08 16:49:04 +03:00
kzfree ( 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 ) ;
2017-10-04 18:43:25 +03:00
if ( key_is_positive ( key ) )
2011-03-11 20:57:23 +03:00
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
{
2015-10-21 16:04:48 +03:00
const struct user_key_payload * upayload ;
2005-06-24 09:00:49 +04:00
long ret ;
2017-03-01 18:11:23 +03:00
upayload = user_key_payload_locked ( key ) ;
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 ) ;
2012-01-18 01:09:11 +04:00
/* Vet the description for a "logon" key */
static int logon_vet_description ( const char * desc )
{
char * p ;
/* require a "qualified" description string */
p = strchr ( desc , ' : ' ) ;
if ( ! p )
return - EINVAL ;
/* also reject description with ':' as first char */
if ( p = = desc )
return - EINVAL ;
return 0 ;
}