ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / net / ipv4 / netfilter / ipt_owner.c
1 /* Kernel module to match various things tied to sockets associated with
2    locally generated outgoing packets. */
3
4 /* (C) 2000 Marc Boucher <marc@mbsi.ca>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10
11 #include <linux/module.h>
12 #include <linux/skbuff.h>
13 #include <linux/file.h>
14 #include <net/sock.h>
15
16 #include <linux/netfilter_ipv4/ipt_owner.h>
17 #include <linux/netfilter_ipv4/ip_tables.h>
18
19 MODULE_LICENSE("GPL");
20 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
21 MODULE_DESCRIPTION("iptables owner match");
22
23 static int
24 match_comm(const struct sk_buff *skb, const char *comm)
25 {
26         struct task_struct *g, *p;
27         struct files_struct *files;
28         int i;
29
30         read_lock(&tasklist_lock);
31         do_each_thread(g, p) {
32                 if(strncmp(p->comm, comm, sizeof(p->comm)))
33                         continue;
34
35                 task_lock(p);
36                 files = p->files;
37                 if(files) {
38                         spin_lock(&files->file_lock);
39                         for (i=0; i < files->max_fds; i++) {
40                                 if (fcheck_files(files, i) ==
41                                     skb->sk->sk_socket->file) {
42                                         spin_unlock(&files->file_lock);
43                                         task_unlock(p);
44                                         read_unlock(&tasklist_lock);
45                                         return 1;
46                                 }
47                         }
48                         spin_unlock(&files->file_lock);
49                 }
50                 task_unlock(p);
51         } while_each_thread(g, p);
52         read_unlock(&tasklist_lock);
53         return 0;
54 }
55
56 static int
57 match_pid(const struct sk_buff *skb, pid_t pid)
58 {
59         struct task_struct *p;
60         struct files_struct *files;
61         int i;
62
63         read_lock(&tasklist_lock);
64         p = find_task_by_pid(pid);
65         if (!p)
66                 goto out;
67         task_lock(p);
68         files = p->files;
69         if(files) {
70                 spin_lock(&files->file_lock);
71                 for (i=0; i < files->max_fds; i++) {
72                         if (fcheck_files(files, i) ==
73                             skb->sk->sk_socket->file) {
74                                 spin_unlock(&files->file_lock);
75                                 task_unlock(p);
76                                 read_unlock(&tasklist_lock);
77                                 return 1;
78                         }
79                 }
80                 spin_unlock(&files->file_lock);
81         }
82         task_unlock(p);
83 out:
84         read_unlock(&tasklist_lock);
85         return 0;
86 }
87
88 static int
89 match_sid(const struct sk_buff *skb, pid_t sid)
90 {
91         struct task_struct *g, *p;
92         struct file *file = skb->sk->sk_socket->file;
93         int i, found=0;
94
95         read_lock(&tasklist_lock);
96         do_each_thread(g, p) {
97                 struct files_struct *files;
98                 if (p->signal->session != sid)
99                         continue;
100
101                 task_lock(p);
102                 files = p->files;
103                 if (files) {
104                         spin_lock(&files->file_lock);
105                         for (i=0; i < files->max_fds; i++) {
106                                 if (fcheck_files(files, i) == file) {
107                                         found = 1;
108                                         break;
109                                 }
110                         }
111                         spin_unlock(&files->file_lock);
112                 }
113                 task_unlock(p);
114                 if (found)
115                         goto out;
116         } while_each_thread(g, p);
117 out:
118         read_unlock(&tasklist_lock);
119
120         return found;
121 }
122
123 static int
124 match(const struct sk_buff *skb,
125       const struct net_device *in,
126       const struct net_device *out,
127       const void *matchinfo,
128       int offset,
129       int *hotdrop)
130 {
131         const struct ipt_owner_info *info = matchinfo;
132
133         if (!skb->sk || !skb->sk->sk_socket || !skb->sk->sk_socket->file)
134                 return 0;
135
136         if(info->match & IPT_OWNER_UID) {
137                 if ((skb->sk->sk_socket->file->f_uid != info->uid) ^
138                     !!(info->invert & IPT_OWNER_UID))
139                         return 0;
140         }
141
142         if(info->match & IPT_OWNER_GID) {
143                 if ((skb->sk->sk_socket->file->f_gid != info->gid) ^
144                     !!(info->invert & IPT_OWNER_GID))
145                         return 0;
146         }
147
148         if(info->match & IPT_OWNER_PID) {
149                 if (!match_pid(skb, info->pid) ^
150                     !!(info->invert & IPT_OWNER_PID))
151                         return 0;
152         }
153
154         if(info->match & IPT_OWNER_SID) {
155                 if (!match_sid(skb, info->sid) ^
156                     !!(info->invert & IPT_OWNER_SID))
157                         return 0;
158         }
159
160         if(info->match & IPT_OWNER_COMM) {
161                 if (!match_comm(skb, info->comm) ^
162                     !!(info->invert & IPT_OWNER_COMM))
163                         return 0;
164         }
165
166         return 1;
167 }
168
169 static int
170 checkentry(const char *tablename,
171            const struct ipt_ip *ip,
172            void *matchinfo,
173            unsigned int matchsize,
174            unsigned int hook_mask)
175 {
176         if (hook_mask
177             & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING))) {
178                 printk("ipt_owner: only valid for LOCAL_OUT or POST_ROUTING.\n");
179                 return 0;
180         }
181
182         if (matchsize != IPT_ALIGN(sizeof(struct ipt_owner_info))) {
183                 printk("Matchsize %u != %Zu\n", matchsize,
184                        IPT_ALIGN(sizeof(struct ipt_owner_info)));
185                 return 0;
186         }
187
188         return 1;
189 }
190
191 static struct ipt_match owner_match = {
192         .name           = "owner",
193         .match          = &match,
194         .checkentry     = &checkentry,
195         .me             = THIS_MODULE,
196 };
197
198 static int __init init(void)
199 {
200         return ipt_register_match(&owner_match);
201 }
202
203 static void __exit fini(void)
204 {
205         ipt_unregister_match(&owner_match);
206 }
207
208 module_init(init);
209 module_exit(fini);