2005-04-16 15:20:36 -07:00
/* proc.c: proc files for key database enumeration
*
* 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/sched.h>
# include <linux/slab.h>
# include <linux/fs.h>
# include <linux/proc_fs.h>
# include <linux/seq_file.h>
# include <asm/errno.h>
# include "internal.h"
# ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
static int proc_keys_open ( struct inode * inode , struct file * file ) ;
static void * proc_keys_start ( struct seq_file * p , loff_t * _pos ) ;
static void * proc_keys_next ( struct seq_file * p , void * v , loff_t * _pos ) ;
static void proc_keys_stop ( struct seq_file * p , void * v ) ;
static int proc_keys_show ( struct seq_file * m , void * v ) ;
2008-01-23 00:02:58 +01:00
static const struct seq_operations proc_keys_ops = {
2005-04-16 15:20:36 -07:00
. start = proc_keys_start ,
. next = proc_keys_next ,
. stop = proc_keys_stop ,
. show = proc_keys_show ,
} ;
2007-02-12 00:55:37 -08:00
static const struct file_operations proc_keys_fops = {
2005-04-16 15:20:36 -07:00
. open = proc_keys_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = seq_release ,
} ;
# endif
static int proc_key_users_open ( struct inode * inode , struct file * file ) ;
static void * proc_key_users_start ( struct seq_file * p , loff_t * _pos ) ;
static void * proc_key_users_next ( struct seq_file * p , void * v , loff_t * _pos ) ;
static void proc_key_users_stop ( struct seq_file * p , void * v ) ;
static int proc_key_users_show ( struct seq_file * m , void * v ) ;
2008-01-23 00:02:58 +01:00
static const struct seq_operations proc_key_users_ops = {
2005-04-16 15:20:36 -07:00
. start = proc_key_users_start ,
. next = proc_key_users_next ,
. stop = proc_key_users_stop ,
. show = proc_key_users_show ,
} ;
2007-02-12 00:55:37 -08:00
static const struct file_operations proc_key_users_fops = {
2005-04-16 15:20:36 -07:00
. open = proc_key_users_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = seq_release ,
} ;
/*****************************************************************************/
/*
* declare the / proc files
*/
static int __init key_proc_init ( void )
{
struct proc_dir_entry * p ;
# ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
2008-04-29 01:01:27 -07:00
p = proc_create ( " keys " , 0 , NULL , & proc_keys_fops ) ;
2005-04-16 15:20:36 -07:00
if ( ! p )
panic ( " Cannot create /proc/keys \n " ) ;
# endif
2008-04-29 01:01:27 -07:00
p = proc_create ( " key-users " , 0 , NULL , & proc_key_users_fops ) ;
2005-04-16 15:20:36 -07:00
if ( ! p )
panic ( " Cannot create /proc/key-users \n " ) ;
return 0 ;
} /* end key_proc_init() */
__initcall ( key_proc_init ) ;
/*****************************************************************************/
/*
* implement " /proc/keys " to provides a list of the keys on the system
*/
# ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
static int proc_keys_open ( struct inode * inode , struct file * file )
{
return seq_open ( file , & proc_keys_ops ) ;
}
static void * proc_keys_start ( struct seq_file * p , loff_t * _pos )
{
struct rb_node * _p ;
loff_t pos = * _pos ;
spin_lock ( & key_serial_lock ) ;
_p = rb_first ( & key_serial_tree ) ;
while ( pos > 0 & & _p ) {
pos - - ;
_p = rb_next ( _p ) ;
}
return _p ;
}
static void * proc_keys_next ( struct seq_file * p , void * v , loff_t * _pos )
{
( * _pos ) + + ;
return rb_next ( ( struct rb_node * ) v ) ;
}
static void proc_keys_stop ( struct seq_file * p , void * v )
{
spin_unlock ( & key_serial_lock ) ;
}
static int proc_keys_show ( struct seq_file * m , void * v )
{
struct rb_node * _p = v ;
struct key * key = rb_entry ( _p , struct key , serial_node ) ;
struct timespec now ;
unsigned long timo ;
char xbuf [ 12 ] ;
2006-06-26 00:24:56 -07:00
int rc ;
/* check whether the current task is allowed to view the key (assuming
* non - possession ) */
rc = key_task_permission ( make_key_ref ( key , 0 ) , current , KEY_VIEW ) ;
if ( rc < 0 )
return 0 ;
2005-04-16 15:20:36 -07:00
now = current_kernel_time ( ) ;
2005-06-23 22:00:49 -07:00
rcu_read_lock ( ) ;
2005-04-16 15:20:36 -07:00
/* come up with a suitable timeout value */
if ( key - > expiry = = 0 ) {
memcpy ( xbuf , " perm " , 5 ) ;
}
else if ( now . tv_sec > = key - > expiry ) {
memcpy ( xbuf , " expd " , 5 ) ;
}
else {
timo = key - > expiry - now . tv_sec ;
if ( timo < 60 )
sprintf ( xbuf , " %lus " , timo ) ;
else if ( timo < 60 * 60 )
sprintf ( xbuf , " %lum " , timo / 60 ) ;
else if ( timo < 60 * 60 * 24 )
sprintf ( xbuf , " %luh " , timo / ( 60 * 60 ) ) ;
else if ( timo < 60 * 60 * 24 * 7 )
sprintf ( xbuf , " %lud " , timo / ( 60 * 60 * 24 ) ) ;
else
sprintf ( xbuf , " %luw " , timo / ( 60 * 60 * 24 * 7 ) ) ;
}
2005-06-23 22:00:49 -07:00
# define showflag(KEY, LETTER, FLAG) \
( test_bit ( FLAG , & ( KEY ) - > flags ) ? LETTER : ' - ' )
2005-09-28 17:03:15 +01:00
seq_printf ( m , " %08x %c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s " ,
2005-04-16 15:20:36 -07:00
key - > serial ,
2005-06-23 22:00:49 -07:00
showflag ( key , ' I ' , KEY_FLAG_INSTANTIATED ) ,
showflag ( key , ' R ' , KEY_FLAG_REVOKED ) ,
showflag ( key , ' D ' , KEY_FLAG_DEAD ) ,
showflag ( key , ' Q ' , KEY_FLAG_IN_QUOTA ) ,
showflag ( key , ' U ' , KEY_FLAG_USER_CONSTRUCT ) ,
showflag ( key , ' N ' , KEY_FLAG_NEGATIVE ) ,
2005-04-16 15:20:36 -07:00
atomic_read ( & key - > usage ) ,
xbuf ,
key - > perm ,
key - > uid ,
key - > gid ,
key - > type - > name ) ;
2005-06-23 22:00:49 -07:00
# undef showflag
2005-04-16 15:20:36 -07:00
if ( key - > type - > describe )
key - > type - > describe ( key , m ) ;
seq_putc ( m , ' \n ' ) ;
2005-06-23 22:00:49 -07:00
rcu_read_unlock ( ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
# endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */
/*****************************************************************************/
/*
* implement " /proc/key-users " to provides a list of the key users
*/
static int proc_key_users_open ( struct inode * inode , struct file * file )
{
return seq_open ( file , & proc_key_users_ops ) ;
}
static void * proc_key_users_start ( struct seq_file * p , loff_t * _pos )
{
struct rb_node * _p ;
loff_t pos = * _pos ;
spin_lock ( & key_user_lock ) ;
_p = rb_first ( & key_user_tree ) ;
while ( pos > 0 & & _p ) {
pos - - ;
_p = rb_next ( _p ) ;
}
return _p ;
}
static void * proc_key_users_next ( struct seq_file * p , void * v , loff_t * _pos )
{
( * _pos ) + + ;
return rb_next ( ( struct rb_node * ) v ) ;
}
static void proc_key_users_stop ( struct seq_file * p , void * v )
{
spin_unlock ( & key_user_lock ) ;
}
static int proc_key_users_show ( struct seq_file * m , void * v )
{
struct rb_node * _p = v ;
struct key_user * user = rb_entry ( _p , struct key_user , node ) ;
2008-04-29 01:01:32 -07:00
unsigned maxkeys = ( user - > uid = = 0 ) ?
key_quota_root_maxkeys : key_quota_maxkeys ;
unsigned maxbytes = ( user - > uid = = 0 ) ?
key_quota_root_maxbytes : key_quota_maxbytes ;
2005-04-16 15:20:36 -07:00
seq_printf ( m , " %5u: %5d %d/%d %d/%d %d/%d \n " ,
user - > uid ,
atomic_read ( & user - > usage ) ,
atomic_read ( & user - > nkeys ) ,
atomic_read ( & user - > nikeys ) ,
user - > qnkeys ,
2008-04-29 01:01:32 -07:00
maxkeys ,
2005-04-16 15:20:36 -07:00
user - > qnbytes ,
2008-04-29 01:01:32 -07:00
maxbytes ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}