11da177e4SLinus Torvalds /* proc.c: proc files for key database enumeration 21da177e4SLinus Torvalds * 31da177e4SLinus Torvalds * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. 41da177e4SLinus Torvalds * Written by David Howells (dhowells@redhat.com) 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 71da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 81da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 91da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/module.h> 131da177e4SLinus Torvalds #include <linux/init.h> 141da177e4SLinus Torvalds #include <linux/sched.h> 151da177e4SLinus Torvalds #include <linux/slab.h> 161da177e4SLinus Torvalds #include <linux/fs.h> 171da177e4SLinus Torvalds #include <linux/proc_fs.h> 181da177e4SLinus Torvalds #include <linux/seq_file.h> 191da177e4SLinus Torvalds #include <asm/errno.h> 201da177e4SLinus Torvalds #include "internal.h" 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS 231da177e4SLinus Torvalds static int proc_keys_open(struct inode *inode, struct file *file); 241da177e4SLinus Torvalds static void *proc_keys_start(struct seq_file *p, loff_t *_pos); 251da177e4SLinus Torvalds static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos); 261da177e4SLinus Torvalds static void proc_keys_stop(struct seq_file *p, void *v); 271da177e4SLinus Torvalds static int proc_keys_show(struct seq_file *m, void *v); 281da177e4SLinus Torvalds 291996a109SJan Engelhardt static const struct seq_operations proc_keys_ops = { 301da177e4SLinus Torvalds .start = proc_keys_start, 311da177e4SLinus Torvalds .next = proc_keys_next, 321da177e4SLinus Torvalds .stop = proc_keys_stop, 331da177e4SLinus Torvalds .show = proc_keys_show, 341da177e4SLinus Torvalds }; 351da177e4SLinus Torvalds 369c2e08c5SArjan van de Ven static const struct file_operations proc_keys_fops = { 371da177e4SLinus Torvalds .open = proc_keys_open, 381da177e4SLinus Torvalds .read = seq_read, 391da177e4SLinus Torvalds .llseek = seq_lseek, 401da177e4SLinus Torvalds .release = seq_release, 411da177e4SLinus Torvalds }; 421da177e4SLinus Torvalds #endif 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds static int proc_key_users_open(struct inode *inode, struct file *file); 451da177e4SLinus Torvalds static void *proc_key_users_start(struct seq_file *p, loff_t *_pos); 461da177e4SLinus Torvalds static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos); 471da177e4SLinus Torvalds static void proc_key_users_stop(struct seq_file *p, void *v); 481da177e4SLinus Torvalds static int proc_key_users_show(struct seq_file *m, void *v); 491da177e4SLinus Torvalds 501996a109SJan Engelhardt static const struct seq_operations proc_key_users_ops = { 511da177e4SLinus Torvalds .start = proc_key_users_start, 521da177e4SLinus Torvalds .next = proc_key_users_next, 531da177e4SLinus Torvalds .stop = proc_key_users_stop, 541da177e4SLinus Torvalds .show = proc_key_users_show, 551da177e4SLinus Torvalds }; 561da177e4SLinus Torvalds 579c2e08c5SArjan van de Ven static const struct file_operations proc_key_users_fops = { 581da177e4SLinus Torvalds .open = proc_key_users_open, 591da177e4SLinus Torvalds .read = seq_read, 601da177e4SLinus Torvalds .llseek = seq_lseek, 611da177e4SLinus Torvalds .release = seq_release, 621da177e4SLinus Torvalds }; 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds /*****************************************************************************/ 651da177e4SLinus Torvalds /* 661da177e4SLinus Torvalds * declare the /proc files 671da177e4SLinus Torvalds */ 681da177e4SLinus Torvalds static int __init key_proc_init(void) 691da177e4SLinus Torvalds { 701da177e4SLinus Torvalds struct proc_dir_entry *p; 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS 73da91d2efSAlexey Dobriyan p = proc_create("keys", 0, NULL, &proc_keys_fops); 741da177e4SLinus Torvalds if (!p) 751da177e4SLinus Torvalds panic("Cannot create /proc/keys\n"); 761da177e4SLinus Torvalds #endif 771da177e4SLinus Torvalds 78da91d2efSAlexey Dobriyan p = proc_create("key-users", 0, NULL, &proc_key_users_fops); 791da177e4SLinus Torvalds if (!p) 801da177e4SLinus Torvalds panic("Cannot create /proc/key-users\n"); 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds return 0; 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds } /* end key_proc_init() */ 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds __initcall(key_proc_init); 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds /*****************************************************************************/ 891da177e4SLinus Torvalds /* 901da177e4SLinus Torvalds * implement "/proc/keys" to provides a list of the keys on the system 911da177e4SLinus Torvalds */ 921da177e4SLinus Torvalds #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds static int proc_keys_open(struct inode *inode, struct file *file) 951da177e4SLinus Torvalds { 961da177e4SLinus Torvalds return seq_open(file, &proc_keys_ops); 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds } 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds static void *proc_keys_start(struct seq_file *p, loff_t *_pos) 1011da177e4SLinus Torvalds { 1021da177e4SLinus Torvalds struct rb_node *_p; 1031da177e4SLinus Torvalds loff_t pos = *_pos; 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds spin_lock(&key_serial_lock); 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds _p = rb_first(&key_serial_tree); 1081da177e4SLinus Torvalds while (pos > 0 && _p) { 1091da177e4SLinus Torvalds pos--; 1101da177e4SLinus Torvalds _p = rb_next(_p); 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds return _p; 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds } 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos) 1181da177e4SLinus Torvalds { 1191da177e4SLinus Torvalds (*_pos)++; 1201da177e4SLinus Torvalds return rb_next((struct rb_node *) v); 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds } 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds static void proc_keys_stop(struct seq_file *p, void *v) 1251da177e4SLinus Torvalds { 1261da177e4SLinus Torvalds spin_unlock(&key_serial_lock); 1271da177e4SLinus Torvalds } 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds static int proc_keys_show(struct seq_file *m, void *v) 1301da177e4SLinus Torvalds { 1311da177e4SLinus Torvalds struct rb_node *_p = v; 1321da177e4SLinus Torvalds struct key *key = rb_entry(_p, struct key, serial_node); 1331da177e4SLinus Torvalds struct timespec now; 1341da177e4SLinus Torvalds unsigned long timo; 1351da177e4SLinus Torvalds char xbuf[12]; 13606ec7be5SMichael LeMay int rc; 13706ec7be5SMichael LeMay 13806ec7be5SMichael LeMay /* check whether the current task is allowed to view the key (assuming 13906ec7be5SMichael LeMay * non-possession) */ 14006ec7be5SMichael LeMay rc = key_task_permission(make_key_ref(key, 0), current, KEY_VIEW); 14106ec7be5SMichael LeMay if (rc < 0) 14206ec7be5SMichael LeMay return 0; 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds now = current_kernel_time(); 1451da177e4SLinus Torvalds 14676d8aeabSDavid Howells rcu_read_lock(); 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds /* come up with a suitable timeout value */ 1491da177e4SLinus Torvalds if (key->expiry == 0) { 1501da177e4SLinus Torvalds memcpy(xbuf, "perm", 5); 1511da177e4SLinus Torvalds } 1521da177e4SLinus Torvalds else if (now.tv_sec >= key->expiry) { 1531da177e4SLinus Torvalds memcpy(xbuf, "expd", 5); 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds else { 1561da177e4SLinus Torvalds timo = key->expiry - now.tv_sec; 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds if (timo < 60) 1591da177e4SLinus Torvalds sprintf(xbuf, "%lus", timo); 1601da177e4SLinus Torvalds else if (timo < 60*60) 1611da177e4SLinus Torvalds sprintf(xbuf, "%lum", timo / 60); 1621da177e4SLinus Torvalds else if (timo < 60*60*24) 1631da177e4SLinus Torvalds sprintf(xbuf, "%luh", timo / (60*60)); 1641da177e4SLinus Torvalds else if (timo < 60*60*24*7) 1651da177e4SLinus Torvalds sprintf(xbuf, "%lud", timo / (60*60*24)); 1661da177e4SLinus Torvalds else 1671da177e4SLinus Torvalds sprintf(xbuf, "%luw", timo / (60*60*24*7)); 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds 17076d8aeabSDavid Howells #define showflag(KEY, LETTER, FLAG) \ 17176d8aeabSDavid Howells (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') 17276d8aeabSDavid Howells 173664cceb0SDavid Howells seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ", 1741da177e4SLinus Torvalds key->serial, 17576d8aeabSDavid Howells showflag(key, 'I', KEY_FLAG_INSTANTIATED), 17676d8aeabSDavid Howells showflag(key, 'R', KEY_FLAG_REVOKED), 17776d8aeabSDavid Howells showflag(key, 'D', KEY_FLAG_DEAD), 17876d8aeabSDavid Howells showflag(key, 'Q', KEY_FLAG_IN_QUOTA), 17976d8aeabSDavid Howells showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), 18076d8aeabSDavid Howells showflag(key, 'N', KEY_FLAG_NEGATIVE), 1811da177e4SLinus Torvalds atomic_read(&key->usage), 1821da177e4SLinus Torvalds xbuf, 1831da177e4SLinus Torvalds key->perm, 1841da177e4SLinus Torvalds key->uid, 1851da177e4SLinus Torvalds key->gid, 1861da177e4SLinus Torvalds key->type->name); 1871da177e4SLinus Torvalds 18876d8aeabSDavid Howells #undef showflag 18976d8aeabSDavid Howells 1901da177e4SLinus Torvalds if (key->type->describe) 1911da177e4SLinus Torvalds key->type->describe(key, m); 1921da177e4SLinus Torvalds seq_putc(m, '\n'); 1931da177e4SLinus Torvalds 19476d8aeabSDavid Howells rcu_read_unlock(); 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds return 0; 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds #endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */ 2011da177e4SLinus Torvalds 2021da177e4SLinus Torvalds /*****************************************************************************/ 2031da177e4SLinus Torvalds /* 2041da177e4SLinus Torvalds * implement "/proc/key-users" to provides a list of the key users 2051da177e4SLinus Torvalds */ 2061da177e4SLinus Torvalds static int proc_key_users_open(struct inode *inode, struct file *file) 2071da177e4SLinus Torvalds { 2081da177e4SLinus Torvalds return seq_open(file, &proc_key_users_ops); 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds } 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds static void *proc_key_users_start(struct seq_file *p, loff_t *_pos) 2131da177e4SLinus Torvalds { 2141da177e4SLinus Torvalds struct rb_node *_p; 2151da177e4SLinus Torvalds loff_t pos = *_pos; 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds spin_lock(&key_user_lock); 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds _p = rb_first(&key_user_tree); 2201da177e4SLinus Torvalds while (pos > 0 && _p) { 2211da177e4SLinus Torvalds pos--; 2221da177e4SLinus Torvalds _p = rb_next(_p); 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds return _p; 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos) 2301da177e4SLinus Torvalds { 2311da177e4SLinus Torvalds (*_pos)++; 2321da177e4SLinus Torvalds return rb_next((struct rb_node *) v); 2331da177e4SLinus Torvalds 2341da177e4SLinus Torvalds } 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds static void proc_key_users_stop(struct seq_file *p, void *v) 2371da177e4SLinus Torvalds { 2381da177e4SLinus Torvalds spin_unlock(&key_user_lock); 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds static int proc_key_users_show(struct seq_file *m, void *v) 2421da177e4SLinus Torvalds { 2431da177e4SLinus Torvalds struct rb_node *_p = v; 2441da177e4SLinus Torvalds struct key_user *user = rb_entry(_p, struct key_user, node); 245*0b77f5bfSDavid Howells unsigned maxkeys = (user->uid == 0) ? 246*0b77f5bfSDavid Howells key_quota_root_maxkeys : key_quota_maxkeys; 247*0b77f5bfSDavid Howells unsigned maxbytes = (user->uid == 0) ? 248*0b77f5bfSDavid Howells key_quota_root_maxbytes : key_quota_maxbytes; 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n", 2511da177e4SLinus Torvalds user->uid, 2521da177e4SLinus Torvalds atomic_read(&user->usage), 2531da177e4SLinus Torvalds atomic_read(&user->nkeys), 2541da177e4SLinus Torvalds atomic_read(&user->nikeys), 2551da177e4SLinus Torvalds user->qnkeys, 256*0b77f5bfSDavid Howells maxkeys, 2571da177e4SLinus Torvalds user->qnbytes, 258*0b77f5bfSDavid Howells maxbytes); 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds return 0; 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds } 263