linux/net/ax25/ax25_uid.c
<<
>>
Prefs
   1/*
   2 * This program is free software; you can redistribute it and/or modify
   3 * it under the terms of the GNU General Public License as published by
   4 * the Free Software Foundation; either version 2 of the License, or
   5 * (at your option) any later version.
   6 *
   7 * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
   8 */
   9
  10#include <linux/capability.h>
  11#include <linux/errno.h>
  12#include <linux/types.h>
  13#include <linux/socket.h>
  14#include <linux/in.h>
  15#include <linux/kernel.h>
  16#include <linux/timer.h>
  17#include <linux/string.h>
  18#include <linux/sockios.h>
  19#include <linux/net.h>
  20#include <linux/spinlock.h>
  21#include <linux/slab.h>
  22#include <net/ax25.h>
  23#include <linux/inet.h>
  24#include <linux/netdevice.h>
  25#include <linux/if_arp.h>
  26#include <linux/skbuff.h>
  27#include <net/sock.h>
  28#include <asm/uaccess.h>
  29#include <linux/fcntl.h>
  30#include <linux/mm.h>
  31#include <linux/interrupt.h>
  32#include <linux/list.h>
  33#include <linux/notifier.h>
  34#include <linux/proc_fs.h>
  35#include <linux/seq_file.h>
  36#include <linux/stat.h>
  37#include <linux/netfilter.h>
  38#include <linux/sysctl.h>
  39#include <linux/export.h>
  40#include <net/ip.h>
  41#include <net/arp.h>
  42
  43/*
  44 *      Callsign/UID mapper. This is in kernel space for security on multi-amateur machines.
  45 */
  46
  47static HLIST_HEAD(ax25_uid_list);
  48static DEFINE_RWLOCK(ax25_uid_lock);
  49
  50int ax25_uid_policy;
  51
  52EXPORT_SYMBOL(ax25_uid_policy);
  53
  54ax25_uid_assoc *ax25_findbyuid(uid_t uid)
  55{
  56        ax25_uid_assoc *ax25_uid, *res = NULL;
  57        struct hlist_node *node;
  58
  59        read_lock(&ax25_uid_lock);
  60        ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) {
  61                if (ax25_uid->uid == uid) {
  62                        ax25_uid_hold(ax25_uid);
  63                        res = ax25_uid;
  64                        break;
  65                }
  66        }
  67        read_unlock(&ax25_uid_lock);
  68
  69        return res;
  70}
  71
  72EXPORT_SYMBOL(ax25_findbyuid);
  73
  74int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
  75{
  76        ax25_uid_assoc *ax25_uid;
  77        struct hlist_node *node;
  78        ax25_uid_assoc *user;
  79        unsigned long res;
  80
  81        switch (cmd) {
  82        case SIOCAX25GETUID:
  83                res = -ENOENT;
  84                read_lock(&ax25_uid_lock);
  85                ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) {
  86                        if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) {
  87                                res = ax25_uid->uid;
  88                                break;
  89                        }
  90                }
  91                read_unlock(&ax25_uid_lock);
  92
  93                return res;
  94
  95        case SIOCAX25ADDUID:
  96                if (!capable(CAP_NET_ADMIN))
  97                        return -EPERM;
  98                user = ax25_findbyuid(sax->sax25_uid);
  99                if (user) {
 100                        ax25_uid_put(user);
 101                        return -EEXIST;
 102                }
 103                if (sax->sax25_uid == 0)
 104                        return -EINVAL;
 105                if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL)
 106                        return -ENOMEM;
 107
 108                atomic_set(&ax25_uid->refcount, 1);
 109                ax25_uid->uid  = sax->sax25_uid;
 110                ax25_uid->call = sax->sax25_call;
 111
 112                write_lock(&ax25_uid_lock);
 113                hlist_add_head(&ax25_uid->uid_node, &ax25_uid_list);
 114                write_unlock(&ax25_uid_lock);
 115
 116                return 0;
 117
 118        case SIOCAX25DELUID:
 119                if (!capable(CAP_NET_ADMIN))
 120                        return -EPERM;
 121
 122                ax25_uid = NULL;
 123                write_lock(&ax25_uid_lock);
 124                ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) {
 125                        if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0)
 126                                break;
 127                }
 128                if (ax25_uid == NULL) {
 129                        write_unlock(&ax25_uid_lock);
 130                        return -ENOENT;
 131                }
 132                hlist_del_init(&ax25_uid->uid_node);
 133                ax25_uid_put(ax25_uid);
 134                write_unlock(&ax25_uid_lock);
 135
 136                return 0;
 137
 138        default:
 139                return -EINVAL;
 140        }
 141
 142        return -EINVAL; /*NOTREACHED */
 143}
 144
 145#ifdef CONFIG_PROC_FS
 146
 147static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos)
 148        __acquires(ax25_uid_lock)
 149{
 150        read_lock(&ax25_uid_lock);
 151        return seq_hlist_start_head(&ax25_uid_list, *pos);
 152}
 153
 154static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 155{
 156        return seq_hlist_next(v, &ax25_uid_list, pos);
 157}
 158
 159static void ax25_uid_seq_stop(struct seq_file *seq, void *v)
 160        __releases(ax25_uid_lock)
 161{
 162        read_unlock(&ax25_uid_lock);
 163}
 164
 165static int ax25_uid_seq_show(struct seq_file *seq, void *v)
 166{
 167        char buf[11];
 168
 169        if (v == SEQ_START_TOKEN)
 170                seq_printf(seq, "Policy: %d\n", ax25_uid_policy);
 171        else {
 172                struct ax25_uid_assoc *pt;
 173
 174                pt = hlist_entry(v, struct ax25_uid_assoc, uid_node);
 175                seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(buf, &pt->call));
 176        }
 177        return 0;
 178}
 179
 180static const struct seq_operations ax25_uid_seqops = {
 181        .start = ax25_uid_seq_start,
 182        .next = ax25_uid_seq_next,
 183        .stop = ax25_uid_seq_stop,
 184        .show = ax25_uid_seq_show,
 185};
 186
 187static int ax25_uid_info_open(struct inode *inode, struct file *file)
 188{
 189        return seq_open(file, &ax25_uid_seqops);
 190}
 191
 192const struct file_operations ax25_uid_fops = {
 193        .owner = THIS_MODULE,
 194        .open = ax25_uid_info_open,
 195        .read = seq_read,
 196        .llseek = seq_lseek,
 197        .release = seq_release,
 198};
 199
 200#endif
 201
 202/*
 203 *      Free all memory associated with UID/Callsign structures.
 204 */
 205void __exit ax25_uid_free(void)
 206{
 207        ax25_uid_assoc *ax25_uid;
 208        struct hlist_node *node;
 209
 210        write_lock(&ax25_uid_lock);
 211again:
 212        ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) {
 213                hlist_del_init(&ax25_uid->uid_node);
 214                ax25_uid_put(ax25_uid);
 215                goto again;
 216        }
 217        write_unlock(&ax25_uid_lock);
 218}
 219