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(kuid_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 (uid_eq(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 = from_kuid_munged(current_user_ns(), ax25_uid->uid);
  88                                break;
  89                        }
  90                }
  91                read_unlock(&ax25_uid_lock);
  92
  93                return res;
  94
  95        case SIOCAX25ADDUID:
  96        {
  97                kuid_t sax25_kuid;
  98                if (!capable(CAP_NET_ADMIN))
  99                        return -EPERM;
 100                sax25_kuid = make_kuid(current_user_ns(), sax->sax25_uid);
 101                if (!uid_valid(sax25_kuid))
 102                        return -EINVAL;
 103                user = ax25_findbyuid(sax25_kuid);
 104                if (user) {
 105                        ax25_uid_put(user);
 106                        return -EEXIST;
 107                }
 108                if (sax->sax25_uid == 0)
 109                        return -EINVAL;
 110                if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL)
 111                        return -ENOMEM;
 112
 113                atomic_set(&ax25_uid->refcount, 1);
 114                ax25_uid->uid  = sax25_kuid;
 115                ax25_uid->call = sax->sax25_call;
 116
 117                write_lock(&ax25_uid_lock);
 118                hlist_add_head(&ax25_uid->uid_node, &ax25_uid_list);
 119                write_unlock(&ax25_uid_lock);
 120
 121                return 0;
 122        }
 123        case SIOCAX25DELUID:
 124                if (!capable(CAP_NET_ADMIN))
 125                        return -EPERM;
 126
 127                ax25_uid = NULL;
 128                write_lock(&ax25_uid_lock);
 129                ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) {
 130                        if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0)
 131                                break;
 132                }
 133                if (ax25_uid == NULL) {
 134                        write_unlock(&ax25_uid_lock);
 135                        return -ENOENT;
 136                }
 137                hlist_del_init(&ax25_uid->uid_node);
 138                ax25_uid_put(ax25_uid);
 139                write_unlock(&ax25_uid_lock);
 140
 141                return 0;
 142
 143        default:
 144                return -EINVAL;
 145        }
 146
 147        return -EINVAL; /*NOTREACHED */
 148}
 149
 150#ifdef CONFIG_PROC_FS
 151
 152static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos)
 153        __acquires(ax25_uid_lock)
 154{
 155        read_lock(&ax25_uid_lock);
 156        return seq_hlist_start_head(&ax25_uid_list, *pos);
 157}
 158
 159static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 160{
 161        return seq_hlist_next(v, &ax25_uid_list, pos);
 162}
 163
 164static void ax25_uid_seq_stop(struct seq_file *seq, void *v)
 165        __releases(ax25_uid_lock)
 166{
 167        read_unlock(&ax25_uid_lock);
 168}
 169
 170static int ax25_uid_seq_show(struct seq_file *seq, void *v)
 171{
 172        char buf[11];
 173
 174        if (v == SEQ_START_TOKEN)
 175                seq_printf(seq, "Policy: %d\n", ax25_uid_policy);
 176        else {
 177                struct ax25_uid_assoc *pt;
 178
 179                pt = hlist_entry(v, struct ax25_uid_assoc, uid_node);
 180                seq_printf(seq, "%6d %s\n",
 181                        from_kuid_munged(seq_user_ns(seq), pt->uid),
 182                        ax2asc(buf, &pt->call));
 183        }
 184        return 0;
 185}
 186
 187static const struct seq_operations ax25_uid_seqops = {
 188        .start = ax25_uid_seq_start,
 189        .next = ax25_uid_seq_next,
 190        .stop = ax25_uid_seq_stop,
 191        .show = ax25_uid_seq_show,
 192};
 193
 194static int ax25_uid_info_open(struct inode *inode, struct file *file)
 195{
 196        return seq_open(file, &ax25_uid_seqops);
 197}
 198
 199const struct file_operations ax25_uid_fops = {
 200        .owner = THIS_MODULE,
 201        .open = ax25_uid_info_open,
 202        .read = seq_read,
 203        .llseek = seq_lseek,
 204        .release = seq_release,
 205};
 206
 207#endif
 208
 209/*
 210 *      Free all memory associated with UID/Callsign structures.
 211 */
 212void __exit ax25_uid_free(void)
 213{
 214        ax25_uid_assoc *ax25_uid;
 215        struct hlist_node *node;
 216
 217        write_lock(&ax25_uid_lock);
 218again:
 219        ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) {
 220                hlist_del_init(&ax25_uid->uid_node);
 221                ax25_uid_put(ax25_uid);
 222                goto again;
 223        }
 224        write_unlock(&ax25_uid_lock);
 225}
 226
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.