]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 | #include <linux/errno.h> | |
10 | #include <linux/types.h> | |
11 | #include <linux/socket.h> | |
12 | #include <linux/in.h> | |
13 | #include <linux/kernel.h> | |
14 | #include <linux/sched.h> | |
15 | #include <linux/timer.h> | |
16 | #include <linux/string.h> | |
17 | #include <linux/sockios.h> | |
18 | #include <linux/net.h> | |
19 | #include <linux/spinlock.h> | |
20 | #include <net/ax25.h> | |
21 | #include <linux/inet.h> | |
22 | #include <linux/netdevice.h> | |
23 | #include <linux/if_arp.h> | |
24 | #include <linux/skbuff.h> | |
25 | #include <net/sock.h> | |
26 | #include <asm/uaccess.h> | |
27 | #include <asm/system.h> | |
28 | #include <linux/fcntl.h> | |
29 | #include <linux/mm.h> | |
30 | #include <linux/interrupt.h> | |
31 | #include <linux/notifier.h> | |
32 | #include <linux/proc_fs.h> | |
33 | #include <linux/seq_file.h> | |
34 | #include <linux/stat.h> | |
35 | #include <linux/netfilter.h> | |
36 | #include <linux/sysctl.h> | |
37 | #include <net/ip.h> | |
38 | #include <net/arp.h> | |
39 | ||
40 | /* | |
41 | * Callsign/UID mapper. This is in kernel space for security on multi-amateur machines. | |
42 | */ | |
43 | ||
44 | static ax25_uid_assoc *ax25_uid_list; | |
45 | static DEFINE_RWLOCK(ax25_uid_lock); | |
46 | ||
47 | int ax25_uid_policy = 0; | |
48 | ||
49 | ax25_address *ax25_findbyuid(uid_t uid) | |
50 | { | |
51 | ax25_uid_assoc *ax25_uid; | |
52 | ax25_address *res = NULL; | |
53 | ||
54 | read_lock(&ax25_uid_lock); | |
55 | for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { | |
56 | if (ax25_uid->uid == uid) { | |
57 | res = &ax25_uid->call; | |
58 | break; | |
59 | } | |
60 | } | |
61 | read_unlock(&ax25_uid_lock); | |
62 | ||
63 | return NULL; | |
64 | } | |
65 | ||
66 | int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) | |
67 | { | |
68 | ax25_uid_assoc *s, *ax25_uid; | |
69 | unsigned long res; | |
70 | ||
71 | switch (cmd) { | |
72 | case SIOCAX25GETUID: | |
73 | res = -ENOENT; | |
74 | read_lock(&ax25_uid_lock); | |
75 | for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { | |
76 | if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) { | |
77 | res = ax25_uid->uid; | |
78 | break; | |
79 | } | |
80 | } | |
81 | read_unlock(&ax25_uid_lock); | |
82 | ||
83 | return res; | |
84 | ||
85 | case SIOCAX25ADDUID: | |
86 | if (!capable(CAP_NET_ADMIN)) | |
87 | return -EPERM; | |
88 | if (ax25_findbyuid(sax->sax25_uid)) | |
89 | return -EEXIST; | |
90 | if (sax->sax25_uid == 0) | |
91 | return -EINVAL; | |
92 | if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL) | |
93 | return -ENOMEM; | |
94 | ||
95 | ax25_uid->uid = sax->sax25_uid; | |
96 | ax25_uid->call = sax->sax25_call; | |
97 | ||
98 | write_lock(&ax25_uid_lock); | |
99 | ax25_uid->next = ax25_uid_list; | |
100 | ax25_uid_list = ax25_uid; | |
101 | write_unlock(&ax25_uid_lock); | |
102 | ||
103 | return 0; | |
104 | ||
105 | case SIOCAX25DELUID: | |
106 | if (!capable(CAP_NET_ADMIN)) | |
107 | return -EPERM; | |
108 | ||
109 | write_lock(&ax25_uid_lock); | |
110 | for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { | |
111 | if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) { | |
112 | break; | |
113 | } | |
114 | } | |
115 | if (ax25_uid == NULL) { | |
116 | write_unlock(&ax25_uid_lock); | |
117 | return -ENOENT; | |
118 | } | |
119 | if ((s = ax25_uid_list) == ax25_uid) { | |
120 | ax25_uid_list = s->next; | |
121 | write_unlock(&ax25_uid_lock); | |
122 | kfree(ax25_uid); | |
123 | return 0; | |
124 | } | |
125 | while (s != NULL && s->next != NULL) { | |
126 | if (s->next == ax25_uid) { | |
127 | s->next = ax25_uid->next; | |
128 | write_unlock(&ax25_uid_lock); | |
129 | kfree(ax25_uid); | |
130 | return 0; | |
131 | } | |
132 | s = s->next; | |
133 | } | |
134 | write_unlock(&ax25_uid_lock); | |
135 | ||
136 | return -ENOENT; | |
137 | ||
138 | default: | |
139 | return -EINVAL; | |
140 | } | |
141 | ||
142 | return -EINVAL; /*NOTREACHED */ | |
143 | } | |
144 | ||
145 | #ifdef CONFIG_PROC_FS | |
146 | ||
147 | static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos) | |
148 | { | |
149 | struct ax25_uid_assoc *pt; | |
150 | int i = 1; | |
151 | ||
152 | read_lock(&ax25_uid_lock); | |
153 | if (*pos == 0) | |
154 | return SEQ_START_TOKEN; | |
155 | ||
156 | for (pt = ax25_uid_list; pt != NULL; pt = pt->next) { | |
157 | if (i == *pos) | |
158 | return pt; | |
159 | ++i; | |
160 | } | |
161 | return NULL; | |
162 | } | |
163 | ||
164 | static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |
165 | { | |
166 | ++*pos; | |
167 | return (v == SEQ_START_TOKEN) ? ax25_uid_list : | |
168 | ((struct ax25_uid_assoc *) v)->next; | |
169 | } | |
170 | ||
171 | static void ax25_uid_seq_stop(struct seq_file *seq, void *v) | |
172 | { | |
173 | read_unlock(&ax25_uid_lock); | |
174 | } | |
175 | ||
176 | static int ax25_uid_seq_show(struct seq_file *seq, void *v) | |
177 | { | |
178 | if (v == SEQ_START_TOKEN) | |
179 | seq_printf(seq, "Policy: %d\n", ax25_uid_policy); | |
180 | else { | |
181 | struct ax25_uid_assoc *pt = v; | |
182 | ||
183 | ||
184 | seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(&pt->call)); | |
185 | } | |
186 | return 0; | |
187 | } | |
188 | ||
189 | static struct seq_operations ax25_uid_seqops = { | |
190 | .start = ax25_uid_seq_start, | |
191 | .next = ax25_uid_seq_next, | |
192 | .stop = ax25_uid_seq_stop, | |
193 | .show = ax25_uid_seq_show, | |
194 | }; | |
195 | ||
196 | static int ax25_uid_info_open(struct inode *inode, struct file *file) | |
197 | { | |
198 | return seq_open(file, &ax25_uid_seqops); | |
199 | } | |
200 | ||
201 | struct file_operations ax25_uid_fops = { | |
202 | .owner = THIS_MODULE, | |
203 | .open = ax25_uid_info_open, | |
204 | .read = seq_read, | |
205 | .llseek = seq_lseek, | |
206 | .release = seq_release, | |
207 | }; | |
208 | ||
209 | #endif | |
210 | ||
211 | /* | |
212 | * Free all memory associated with UID/Callsign structures. | |
213 | */ | |
214 | void __exit ax25_uid_free(void) | |
215 | { | |
216 | ax25_uid_assoc *s, *ax25_uid; | |
217 | ||
218 | write_lock(&ax25_uid_lock); | |
219 | ax25_uid = ax25_uid_list; | |
220 | while (ax25_uid != NULL) { | |
221 | s = ax25_uid; | |
222 | ax25_uid = ax25_uid->next; | |
223 | ||
224 | kfree(s); | |
225 | } | |
226 | ax25_uid_list = NULL; | |
227 | write_unlock(&ax25_uid_lock); | |
228 | } |