xref: /linux/net/ax25/ax25_uid.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
51da177e4SLinus Torvalds  */
64fc268d2SRandy Dunlap 
74fc268d2SRandy Dunlap #include <linux/capability.h>
81da177e4SLinus Torvalds #include <linux/errno.h>
91da177e4SLinus Torvalds #include <linux/types.h>
101da177e4SLinus Torvalds #include <linux/socket.h>
111da177e4SLinus Torvalds #include <linux/in.h>
121da177e4SLinus Torvalds #include <linux/kernel.h>
131da177e4SLinus Torvalds #include <linux/timer.h>
141da177e4SLinus Torvalds #include <linux/string.h>
151da177e4SLinus Torvalds #include <linux/sockios.h>
161da177e4SLinus Torvalds #include <linux/net.h>
171da177e4SLinus Torvalds #include <linux/spinlock.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
191da177e4SLinus Torvalds #include <net/ax25.h>
201da177e4SLinus Torvalds #include <linux/inet.h>
211da177e4SLinus Torvalds #include <linux/netdevice.h>
221da177e4SLinus Torvalds #include <linux/if_arp.h>
231da177e4SLinus Torvalds #include <linux/skbuff.h>
241da177e4SLinus Torvalds #include <net/sock.h>
257c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
261da177e4SLinus Torvalds #include <linux/fcntl.h>
271da177e4SLinus Torvalds #include <linux/mm.h>
281da177e4SLinus Torvalds #include <linux/interrupt.h>
2901d7dd0eSRalf Baechle #include <linux/list.h>
301da177e4SLinus Torvalds #include <linux/notifier.h>
311da177e4SLinus Torvalds #include <linux/proc_fs.h>
321da177e4SLinus Torvalds #include <linux/seq_file.h>
331da177e4SLinus Torvalds #include <linux/stat.h>
341da177e4SLinus Torvalds #include <linux/sysctl.h>
35bc3b2d7fSPaul Gortmaker #include <linux/export.h>
361da177e4SLinus Torvalds #include <net/ip.h>
371da177e4SLinus Torvalds #include <net/arp.h>
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds /*
401da177e4SLinus Torvalds  *	Callsign/UID mapper. This is in kernel space for security on multi-amateur machines.
411da177e4SLinus Torvalds  */
421da177e4SLinus Torvalds 
43f16f3026SEric Dumazet static HLIST_HEAD(ax25_uid_list);
441da177e4SLinus Torvalds static DEFINE_RWLOCK(ax25_uid_lock);
451da177e4SLinus Torvalds 
46f16f3026SEric Dumazet int ax25_uid_policy;
471da177e4SLinus Torvalds 
4870868eacSRalf Baechle EXPORT_SYMBOL(ax25_uid_policy);
4970868eacSRalf Baechle 
ax25_findbyuid(kuid_t uid)50d13fda85SEric W. Biederman ax25_uid_assoc *ax25_findbyuid(kuid_t uid)
511da177e4SLinus Torvalds {
5201d7dd0eSRalf Baechle 	ax25_uid_assoc *ax25_uid, *res = NULL;
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds 	read_lock(&ax25_uid_lock);
55b67bfe0dSSasha Levin 	ax25_uid_for_each(ax25_uid, &ax25_uid_list) {
56d13fda85SEric W. Biederman 		if (uid_eq(ax25_uid->uid, uid)) {
5701d7dd0eSRalf Baechle 			ax25_uid_hold(ax25_uid);
5801d7dd0eSRalf Baechle 			res = ax25_uid;
591da177e4SLinus Torvalds 			break;
601da177e4SLinus Torvalds 		}
611da177e4SLinus Torvalds 	}
621da177e4SLinus Torvalds 	read_unlock(&ax25_uid_lock);
631da177e4SLinus Torvalds 
6401d7dd0eSRalf Baechle 	return res;
651da177e4SLinus Torvalds }
661da177e4SLinus Torvalds 
6770868eacSRalf Baechle EXPORT_SYMBOL(ax25_findbyuid);
6870868eacSRalf Baechle 
ax25_uid_ioctl(int cmd,struct sockaddr_ax25 * sax)691da177e4SLinus Torvalds int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
701da177e4SLinus Torvalds {
7101d7dd0eSRalf Baechle 	ax25_uid_assoc *ax25_uid;
7201d7dd0eSRalf Baechle 	ax25_uid_assoc *user;
731da177e4SLinus Torvalds 	unsigned long res;
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds 	switch (cmd) {
761da177e4SLinus Torvalds 	case SIOCAX25GETUID:
771da177e4SLinus Torvalds 		res = -ENOENT;
781da177e4SLinus Torvalds 		read_lock(&ax25_uid_lock);
79b67bfe0dSSasha Levin 		ax25_uid_for_each(ax25_uid, &ax25_uid_list) {
801da177e4SLinus Torvalds 			if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) {
81d13fda85SEric W. Biederman 				res = from_kuid_munged(current_user_ns(), ax25_uid->uid);
821da177e4SLinus Torvalds 				break;
831da177e4SLinus Torvalds 			}
841da177e4SLinus Torvalds 		}
851da177e4SLinus Torvalds 		read_unlock(&ax25_uid_lock);
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds 		return res;
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds 	case SIOCAX25ADDUID:
90d13fda85SEric W. Biederman 	{
91d13fda85SEric W. Biederman 		kuid_t sax25_kuid;
921da177e4SLinus Torvalds 		if (!capable(CAP_NET_ADMIN))
931da177e4SLinus Torvalds 			return -EPERM;
94d13fda85SEric W. Biederman 		sax25_kuid = make_kuid(current_user_ns(), sax->sax25_uid);
95d13fda85SEric W. Biederman 		if (!uid_valid(sax25_kuid))
96d13fda85SEric W. Biederman 			return -EINVAL;
97d13fda85SEric W. Biederman 		user = ax25_findbyuid(sax25_kuid);
9801d7dd0eSRalf Baechle 		if (user) {
9901d7dd0eSRalf Baechle 			ax25_uid_put(user);
1001da177e4SLinus Torvalds 			return -EEXIST;
10101d7dd0eSRalf Baechle 		}
1021da177e4SLinus Torvalds 		if (sax->sax25_uid == 0)
1031da177e4SLinus Torvalds 			return -EINVAL;
1041da177e4SLinus Torvalds 		if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL)
1051da177e4SLinus Torvalds 			return -ENOMEM;
1061da177e4SLinus Torvalds 
10707f2282fSReshetova, Elena 		refcount_set(&ax25_uid->refcount, 1);
108d13fda85SEric W. Biederman 		ax25_uid->uid  = sax25_kuid;
1091da177e4SLinus Torvalds 		ax25_uid->call = sax->sax25_call;
1101da177e4SLinus Torvalds 
1111da177e4SLinus Torvalds 		write_lock(&ax25_uid_lock);
11201d7dd0eSRalf Baechle 		hlist_add_head(&ax25_uid->uid_node, &ax25_uid_list);
1131da177e4SLinus Torvalds 		write_unlock(&ax25_uid_lock);
1141da177e4SLinus Torvalds 
1151da177e4SLinus Torvalds 		return 0;
116d13fda85SEric W. Biederman 	}
1171da177e4SLinus Torvalds 	case SIOCAX25DELUID:
1181da177e4SLinus Torvalds 		if (!capable(CAP_NET_ADMIN))
1191da177e4SLinus Torvalds 			return -EPERM;
1201da177e4SLinus Torvalds 
12101d7dd0eSRalf Baechle 		ax25_uid = NULL;
1221da177e4SLinus Torvalds 		write_lock(&ax25_uid_lock);
123b67bfe0dSSasha Levin 		ax25_uid_for_each(ax25_uid, &ax25_uid_list) {
12401d7dd0eSRalf Baechle 			if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0)
1251da177e4SLinus Torvalds 				break;
1261da177e4SLinus Torvalds 		}
1271da177e4SLinus Torvalds 		if (ax25_uid == NULL) {
1281da177e4SLinus Torvalds 			write_unlock(&ax25_uid_lock);
1291da177e4SLinus Torvalds 			return -ENOENT;
1301da177e4SLinus Torvalds 		}
13101d7dd0eSRalf Baechle 		hlist_del_init(&ax25_uid->uid_node);
13201d7dd0eSRalf Baechle 		ax25_uid_put(ax25_uid);
1331da177e4SLinus Torvalds 		write_unlock(&ax25_uid_lock);
1341da177e4SLinus Torvalds 
13501d7dd0eSRalf Baechle 		return 0;
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds 	default:
1381da177e4SLinus Torvalds 		return -EINVAL;
1391da177e4SLinus Torvalds 	}
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds 	return -EINVAL;	/*NOTREACHED */
1421da177e4SLinus Torvalds }
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
1451da177e4SLinus Torvalds 
ax25_uid_seq_start(struct seq_file * seq,loff_t * pos)1461da177e4SLinus Torvalds static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos)
147f16f3026SEric Dumazet 	__acquires(ax25_uid_lock)
1481da177e4SLinus Torvalds {
1491da177e4SLinus Torvalds 	read_lock(&ax25_uid_lock);
150b512f3d8SLi Zefan 	return seq_hlist_start_head(&ax25_uid_list, *pos);
1511da177e4SLinus Torvalds }
1521da177e4SLinus Torvalds 
ax25_uid_seq_next(struct seq_file * seq,void * v,loff_t * pos)1531da177e4SLinus Torvalds static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1541da177e4SLinus Torvalds {
155b512f3d8SLi Zefan 	return seq_hlist_next(v, &ax25_uid_list, pos);
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds 
ax25_uid_seq_stop(struct seq_file * seq,void * v)1581da177e4SLinus Torvalds static void ax25_uid_seq_stop(struct seq_file *seq, void *v)
159f16f3026SEric Dumazet 	__releases(ax25_uid_lock)
1601da177e4SLinus Torvalds {
1611da177e4SLinus Torvalds 	read_unlock(&ax25_uid_lock);
1621da177e4SLinus Torvalds }
1631da177e4SLinus Torvalds 
ax25_uid_seq_show(struct seq_file * seq,void * v)1641da177e4SLinus Torvalds static int ax25_uid_seq_show(struct seq_file *seq, void *v)
1651da177e4SLinus Torvalds {
166f75268cdSRalf Baechle 	char buf[11];
167f75268cdSRalf Baechle 
1681da177e4SLinus Torvalds 	if (v == SEQ_START_TOKEN)
1691da177e4SLinus Torvalds 		seq_printf(seq, "Policy: %d\n", ax25_uid_policy);
1701da177e4SLinus Torvalds 	else {
171b512f3d8SLi Zefan 		struct ax25_uid_assoc *pt;
1721da177e4SLinus Torvalds 
173b512f3d8SLi Zefan 		pt = hlist_entry(v, struct ax25_uid_assoc, uid_node);
174d13fda85SEric W. Biederman 		seq_printf(seq, "%6d %s\n",
175d13fda85SEric W. Biederman 			from_kuid_munged(seq_user_ns(seq), pt->uid),
176d13fda85SEric W. Biederman 			ax2asc(buf, &pt->call));
1771da177e4SLinus Torvalds 	}
1781da177e4SLinus Torvalds 	return 0;
1791da177e4SLinus Torvalds }
1801da177e4SLinus Torvalds 
181fddda2b7SChristoph Hellwig const struct seq_operations ax25_uid_seqops = {
1821da177e4SLinus Torvalds 	.start = ax25_uid_seq_start,
1831da177e4SLinus Torvalds 	.next = ax25_uid_seq_next,
1841da177e4SLinus Torvalds 	.stop = ax25_uid_seq_stop,
1851da177e4SLinus Torvalds 	.show = ax25_uid_seq_show,
1861da177e4SLinus Torvalds };
1871da177e4SLinus Torvalds #endif
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds /*
1901da177e4SLinus Torvalds  *	Free all memory associated with UID/Callsign structures.
1911da177e4SLinus Torvalds  */
ax25_uid_free(void)1921da177e4SLinus Torvalds void __exit ax25_uid_free(void)
1931da177e4SLinus Torvalds {
19401d7dd0eSRalf Baechle 	ax25_uid_assoc *ax25_uid;
1951da177e4SLinus Torvalds 
1961da177e4SLinus Torvalds 	write_lock(&ax25_uid_lock);
197ae1b6a31SPavel Emelyanov again:
198b67bfe0dSSasha Levin 	ax25_uid_for_each(ax25_uid, &ax25_uid_list) {
19901d7dd0eSRalf Baechle 		hlist_del_init(&ax25_uid->uid_node);
20001d7dd0eSRalf Baechle 		ax25_uid_put(ax25_uid);
201ae1b6a31SPavel Emelyanov 		goto again;
2021da177e4SLinus Torvalds 	}
2031da177e4SLinus Torvalds 	write_unlock(&ax25_uid_lock);
2041da177e4SLinus Torvalds }
205