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 94*454804abSSerge E. Hallyn static struct rb_node *__key_serial_next(struct rb_node *n) 95*454804abSSerge E. Hallyn { 96*454804abSSerge E. Hallyn while (n) { 97*454804abSSerge E. Hallyn struct key *key = rb_entry(n, struct key, serial_node); 98*454804abSSerge E. Hallyn if (key->user->user_ns == current_user_ns()) 99*454804abSSerge E. Hallyn break; 100*454804abSSerge E. Hallyn n = rb_next(n); 101*454804abSSerge E. Hallyn } 102*454804abSSerge E. Hallyn return n; 103*454804abSSerge E. Hallyn } 104*454804abSSerge E. Hallyn 105*454804abSSerge E. Hallyn static struct rb_node *key_serial_next(struct rb_node *n) 106*454804abSSerge E. Hallyn { 107*454804abSSerge E. Hallyn return __key_serial_next(rb_next(n)); 108*454804abSSerge E. Hallyn } 109*454804abSSerge E. Hallyn 110*454804abSSerge E. Hallyn static struct rb_node *key_serial_first(struct rb_root *r) 111*454804abSSerge E. Hallyn { 112*454804abSSerge E. Hallyn struct rb_node *n = rb_first(r); 113*454804abSSerge E. Hallyn return __key_serial_next(n); 114*454804abSSerge E. Hallyn } 115*454804abSSerge E. Hallyn 1161da177e4SLinus Torvalds static int proc_keys_open(struct inode *inode, struct file *file) 1171da177e4SLinus Torvalds { 1181da177e4SLinus Torvalds return seq_open(file, &proc_keys_ops); 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds } 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds static void *proc_keys_start(struct seq_file *p, loff_t *_pos) 1231da177e4SLinus Torvalds { 1241da177e4SLinus Torvalds struct rb_node *_p; 1251da177e4SLinus Torvalds loff_t pos = *_pos; 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds spin_lock(&key_serial_lock); 1281da177e4SLinus Torvalds 129*454804abSSerge E. Hallyn _p = key_serial_first(&key_serial_tree); 1301da177e4SLinus Torvalds while (pos > 0 && _p) { 1311da177e4SLinus Torvalds pos--; 132*454804abSSerge E. Hallyn _p = key_serial_next(_p); 1331da177e4SLinus Torvalds } 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds return _p; 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds } 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos) 1401da177e4SLinus Torvalds { 1411da177e4SLinus Torvalds (*_pos)++; 142*454804abSSerge E. Hallyn return key_serial_next((struct rb_node *) v); 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds } 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds static void proc_keys_stop(struct seq_file *p, void *v) 1471da177e4SLinus Torvalds { 1481da177e4SLinus Torvalds spin_unlock(&key_serial_lock); 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds static int proc_keys_show(struct seq_file *m, void *v) 1521da177e4SLinus Torvalds { 1531da177e4SLinus Torvalds struct rb_node *_p = v; 1541da177e4SLinus Torvalds struct key *key = rb_entry(_p, struct key, serial_node); 1551da177e4SLinus Torvalds struct timespec now; 1561da177e4SLinus Torvalds unsigned long timo; 1571da177e4SLinus Torvalds char xbuf[12]; 15806ec7be5SMichael LeMay int rc; 15906ec7be5SMichael LeMay 16006ec7be5SMichael LeMay /* check whether the current task is allowed to view the key (assuming 161d84f4f99SDavid Howells * non-possession) 162d84f4f99SDavid Howells * - the caller holds a spinlock, and thus the RCU read lock, making our 163d84f4f99SDavid Howells * access to __current_cred() safe 164d84f4f99SDavid Howells */ 165d84f4f99SDavid Howells rc = key_task_permission(make_key_ref(key, 0), current_cred(), 166d84f4f99SDavid Howells KEY_VIEW); 16706ec7be5SMichael LeMay if (rc < 0) 16806ec7be5SMichael LeMay return 0; 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds now = current_kernel_time(); 1711da177e4SLinus Torvalds 17276d8aeabSDavid Howells rcu_read_lock(); 1731da177e4SLinus Torvalds 1741da177e4SLinus Torvalds /* come up with a suitable timeout value */ 1751da177e4SLinus Torvalds if (key->expiry == 0) { 1761da177e4SLinus Torvalds memcpy(xbuf, "perm", 5); 1771da177e4SLinus Torvalds } 1781da177e4SLinus Torvalds else if (now.tv_sec >= key->expiry) { 1791da177e4SLinus Torvalds memcpy(xbuf, "expd", 5); 1801da177e4SLinus Torvalds } 1811da177e4SLinus Torvalds else { 1821da177e4SLinus Torvalds timo = key->expiry - now.tv_sec; 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds if (timo < 60) 1851da177e4SLinus Torvalds sprintf(xbuf, "%lus", timo); 1861da177e4SLinus Torvalds else if (timo < 60*60) 1871da177e4SLinus Torvalds sprintf(xbuf, "%lum", timo / 60); 1881da177e4SLinus Torvalds else if (timo < 60*60*24) 1891da177e4SLinus Torvalds sprintf(xbuf, "%luh", timo / (60*60)); 1901da177e4SLinus Torvalds else if (timo < 60*60*24*7) 1911da177e4SLinus Torvalds sprintf(xbuf, "%lud", timo / (60*60*24)); 1921da177e4SLinus Torvalds else 1931da177e4SLinus Torvalds sprintf(xbuf, "%luw", timo / (60*60*24*7)); 1941da177e4SLinus Torvalds } 1951da177e4SLinus Torvalds 19676d8aeabSDavid Howells #define showflag(KEY, LETTER, FLAG) \ 19776d8aeabSDavid Howells (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') 19876d8aeabSDavid Howells 199664cceb0SDavid Howells seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ", 2001da177e4SLinus Torvalds key->serial, 20176d8aeabSDavid Howells showflag(key, 'I', KEY_FLAG_INSTANTIATED), 20276d8aeabSDavid Howells showflag(key, 'R', KEY_FLAG_REVOKED), 20376d8aeabSDavid Howells showflag(key, 'D', KEY_FLAG_DEAD), 20476d8aeabSDavid Howells showflag(key, 'Q', KEY_FLAG_IN_QUOTA), 20576d8aeabSDavid Howells showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), 20676d8aeabSDavid Howells showflag(key, 'N', KEY_FLAG_NEGATIVE), 2071da177e4SLinus Torvalds atomic_read(&key->usage), 2081da177e4SLinus Torvalds xbuf, 2091da177e4SLinus Torvalds key->perm, 2101da177e4SLinus Torvalds key->uid, 2111da177e4SLinus Torvalds key->gid, 2121da177e4SLinus Torvalds key->type->name); 2131da177e4SLinus Torvalds 21476d8aeabSDavid Howells #undef showflag 21576d8aeabSDavid Howells 2161da177e4SLinus Torvalds if (key->type->describe) 2171da177e4SLinus Torvalds key->type->describe(key, m); 2181da177e4SLinus Torvalds seq_putc(m, '\n'); 2191da177e4SLinus Torvalds 22076d8aeabSDavid Howells rcu_read_unlock(); 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds return 0; 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds #endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */ 2271da177e4SLinus Torvalds 228*454804abSSerge E. Hallyn static struct rb_node *__key_user_next(struct rb_node *n) 229*454804abSSerge E. Hallyn { 230*454804abSSerge E. Hallyn while (n) { 231*454804abSSerge E. Hallyn struct key_user *user = rb_entry(n, struct key_user, node); 232*454804abSSerge E. Hallyn if (user->user_ns == current_user_ns()) 233*454804abSSerge E. Hallyn break; 234*454804abSSerge E. Hallyn n = rb_next(n); 235*454804abSSerge E. Hallyn } 236*454804abSSerge E. Hallyn return n; 237*454804abSSerge E. Hallyn } 238*454804abSSerge E. Hallyn 239*454804abSSerge E. Hallyn static struct rb_node *key_user_next(struct rb_node *n) 240*454804abSSerge E. Hallyn { 241*454804abSSerge E. Hallyn return __key_user_next(rb_next(n)); 242*454804abSSerge E. Hallyn } 243*454804abSSerge E. Hallyn 244*454804abSSerge E. Hallyn static struct rb_node *key_user_first(struct rb_root *r) 245*454804abSSerge E. Hallyn { 246*454804abSSerge E. Hallyn struct rb_node *n = rb_first(r); 247*454804abSSerge E. Hallyn return __key_user_next(n); 248*454804abSSerge E. Hallyn } 2491da177e4SLinus Torvalds /*****************************************************************************/ 2501da177e4SLinus Torvalds /* 2511da177e4SLinus Torvalds * implement "/proc/key-users" to provides a list of the key users 2521da177e4SLinus Torvalds */ 2531da177e4SLinus Torvalds static int proc_key_users_open(struct inode *inode, struct file *file) 2541da177e4SLinus Torvalds { 2551da177e4SLinus Torvalds return seq_open(file, &proc_key_users_ops); 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds } 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds static void *proc_key_users_start(struct seq_file *p, loff_t *_pos) 2601da177e4SLinus Torvalds { 2611da177e4SLinus Torvalds struct rb_node *_p; 2621da177e4SLinus Torvalds loff_t pos = *_pos; 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds spin_lock(&key_user_lock); 2651da177e4SLinus Torvalds 266*454804abSSerge E. Hallyn _p = key_user_first(&key_user_tree); 2671da177e4SLinus Torvalds while (pos > 0 && _p) { 2681da177e4SLinus Torvalds pos--; 269*454804abSSerge E. Hallyn _p = key_user_next(_p); 2701da177e4SLinus Torvalds } 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds return _p; 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds } 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos) 2771da177e4SLinus Torvalds { 2781da177e4SLinus Torvalds (*_pos)++; 279*454804abSSerge E. Hallyn return key_user_next((struct rb_node *) v); 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds } 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds static void proc_key_users_stop(struct seq_file *p, void *v) 2841da177e4SLinus Torvalds { 2851da177e4SLinus Torvalds spin_unlock(&key_user_lock); 2861da177e4SLinus Torvalds } 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds static int proc_key_users_show(struct seq_file *m, void *v) 2891da177e4SLinus Torvalds { 2901da177e4SLinus Torvalds struct rb_node *_p = v; 2911da177e4SLinus Torvalds struct key_user *user = rb_entry(_p, struct key_user, node); 2920b77f5bfSDavid Howells unsigned maxkeys = (user->uid == 0) ? 2930b77f5bfSDavid Howells key_quota_root_maxkeys : key_quota_maxkeys; 2940b77f5bfSDavid Howells unsigned maxbytes = (user->uid == 0) ? 2950b77f5bfSDavid Howells key_quota_root_maxbytes : key_quota_maxbytes; 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n", 2981da177e4SLinus Torvalds user->uid, 2991da177e4SLinus Torvalds atomic_read(&user->usage), 3001da177e4SLinus Torvalds atomic_read(&user->nkeys), 3011da177e4SLinus Torvalds atomic_read(&user->nikeys), 3021da177e4SLinus Torvalds user->qnkeys, 3030b77f5bfSDavid Howells maxkeys, 3041da177e4SLinus Torvalds user->qnbytes, 3050b77f5bfSDavid Howells maxbytes); 3061da177e4SLinus Torvalds 3071da177e4SLinus Torvalds return 0; 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds } 310