import of upstream 2.4.34.4 from kernel.org
[linux-2.4.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    Copyright (C) 2000 Marc Boucher
5  */
6 #include <linux/module.h>
7 #include <linux/skbuff.h>
8 #include <linux/file.h>
9 #include <net/sock.h>
10
11 #include <linux/netfilter_ipv4/ipt_owner.h>
12 #include <linux/netfilter_ipv4/ip_tables.h>
13
14 static int
15 match_comm(const struct sk_buff *skb, const char *comm)
16 {
17         struct task_struct *p;
18         struct files_struct *files;
19         int i;
20
21         read_lock(&tasklist_lock);
22         for_each_task(p) {
23                 if(strncmp(p->comm, comm, sizeof(p->comm)))
24                         continue;
25
26                 task_lock(p);
27                 files = p->files;
28                 if(files) {
29                         read_lock(&files->file_lock);
30                         for (i=0; i < files->max_fds; i++) {
31                                 if (fcheck_files(files, i) == skb->sk->socket->file) {
32                                         read_unlock(&files->file_lock);
33                                         task_unlock(p);
34                                         read_unlock(&tasklist_lock);
35                                         return 1;
36                                 }
37                         }
38                         read_unlock(&files->file_lock);
39                 }
40                 task_unlock(p);
41         }
42         read_unlock(&tasklist_lock);
43         return 0;
44 }
45
46 static int
47 match_pid(const struct sk_buff *skb, pid_t pid)
48 {
49         struct task_struct *p;
50         struct files_struct *files;
51         int i;
52
53         read_lock(&tasklist_lock);
54         p = find_task_by_pid(pid);
55         if (!p)
56                 goto out;
57         task_lock(p);
58         files = p->files;
59         if(files) {
60                 read_lock(&files->file_lock);
61                 for (i=0; i < files->max_fds; i++) {
62                         if (fcheck_files(files, i) == skb->sk->socket->file) {
63                                 read_unlock(&files->file_lock);
64                                 task_unlock(p);
65                                 read_unlock(&tasklist_lock);
66                                 return 1;
67                         }
68                 }
69                 read_unlock(&files->file_lock);
70         }
71         task_unlock(p);
72 out:
73         read_unlock(&tasklist_lock);
74         return 0;
75 }
76
77 static int
78 match_sid(const struct sk_buff *skb, pid_t sid)
79 {
80         struct task_struct *p;
81         struct file *file = skb->sk->socket->file;
82         int i, found=0;
83
84         read_lock(&tasklist_lock);
85         for_each_task(p) {
86                 struct files_struct *files;
87                 if (p->session != sid)
88                         continue;
89
90                 task_lock(p);
91                 files = p->files;
92                 if (files) {
93                         read_lock(&files->file_lock);
94                         for (i=0; i < files->max_fds; i++) {
95                                 if (fcheck_files(files, i) == file) {
96                                         found = 1;
97                                         break;
98                                 }
99                         }
100                         read_unlock(&files->file_lock);
101                 }
102                 task_unlock(p);
103                 if(found)
104                         break;
105         }
106         read_unlock(&tasklist_lock);
107
108         return found;
109 }
110
111 static int
112 match(const struct sk_buff *skb,
113       const struct net_device *in,
114       const struct net_device *out,
115       const void *matchinfo,
116       int offset,
117       const void *hdr,
118       u_int16_t datalen,
119       int *hotdrop)
120 {
121         const struct ipt_owner_info *info = matchinfo;
122
123         if (!skb->sk || !skb->sk->socket || !skb->sk->socket->file)
124                 return 0;
125
126         if(info->match & IPT_OWNER_UID) {
127                 if((skb->sk->socket->file->f_uid != info->uid) ^
128                     !!(info->invert & IPT_OWNER_UID))
129                         return 0;
130         }
131
132         if(info->match & IPT_OWNER_GID) {
133                 if((skb->sk->socket->file->f_gid != info->gid) ^
134                     !!(info->invert & IPT_OWNER_GID))
135                         return 0;
136         }
137
138         if(info->match & IPT_OWNER_PID) {
139                 if (!match_pid(skb, info->pid) ^
140                     !!(info->invert & IPT_OWNER_PID))
141                         return 0;
142         }
143
144         if(info->match & IPT_OWNER_SID) {
145                 if (!match_sid(skb, info->sid) ^
146                     !!(info->invert & IPT_OWNER_SID))
147                         return 0;
148         }
149
150         if(info->match & IPT_OWNER_COMM) {
151                 if (!match_comm(skb, info->comm) ^
152                     !!(info->invert & IPT_OWNER_COMM))
153                         return 0;
154         }
155
156         return 1;
157 }
158
159 static int
160 checkentry(const char *tablename,
161            const struct ipt_ip *ip,
162            void *matchinfo,
163            unsigned int matchsize,
164            unsigned int hook_mask)
165 {
166         if (hook_mask
167             & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING))) {
168                 printk("ipt_owner: only valid for LOCAL_OUT or POST_ROUTING.\n");
169                 return 0;
170         }
171
172         if (matchsize != IPT_ALIGN(sizeof(struct ipt_owner_info)))
173                 return 0;
174 #ifdef CONFIG_SMP
175         /* files->file_lock can not be used in a BH */
176         if (((struct ipt_owner_info *)matchinfo)->match
177             & (IPT_OWNER_PID|IPT_OWNER_SID|IPT_OWNER_COMM)) {
178                 printk("ipt_owner: pid, sid and command matching is broken "
179                        "on SMP.\n");
180                 return 0;
181         }
182 #endif
183         return 1;
184 }
185
186 static struct ipt_match owner_match
187 = { { NULL, NULL }, "owner", &match, &checkentry, NULL, THIS_MODULE };
188
189 static int __init init(void)
190 {
191         return ipt_register_match(&owner_match);
192 }
193
194 static void __exit fini(void)
195 {
196         ipt_unregister_match(&owner_match);
197 }
198
199 module_init(init);
200 module_exit(fini);
201 MODULE_LICENSE("GPL");