Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-for-linus-2.6
[linux-2.6] / net / ipv6 / netfilter / ip6t_owner.c
1 /* Kernel module to match various things tied to sockets associated with
2    locally generated outgoing packets. */
3
4 /* (C) 2000-2001 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_ipv6/ip6t_owner.h>
17 #include <linux/netfilter_ipv6/ip6_tables.h>
18
19 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
20 MODULE_DESCRIPTION("IP6 tables owner matching module");
21 MODULE_LICENSE("GPL");
22
23 static int
24 match_pid(const struct sk_buff *skb, pid_t pid)
25 {
26         struct task_struct *p;
27         struct files_struct *files;
28         int i;
29
30         read_lock(&tasklist_lock);
31         p = find_task_by_pid(pid);
32         if (!p)
33                 goto out;
34         task_lock(p);
35         files = p->files;
36         if(files) {
37                 spin_lock(&files->file_lock);
38                 for (i=0; i < files->max_fds; i++) {
39                         if (fcheck_files(files, i) == skb->sk->sk_socket->file) {
40                                 spin_unlock(&files->file_lock);
41                                 task_unlock(p);
42                                 read_unlock(&tasklist_lock);
43                                 return 1;
44                         }
45                 }
46                 spin_unlock(&files->file_lock);
47         }
48         task_unlock(p);
49 out:
50         read_unlock(&tasklist_lock);
51         return 0;
52 }
53
54 static int
55 match_sid(const struct sk_buff *skb, pid_t sid)
56 {
57         struct task_struct *g, *p;
58         struct file *file = skb->sk->sk_socket->file;
59         int i, found=0;
60
61         read_lock(&tasklist_lock);
62         do_each_thread(g, p) {
63                 struct files_struct *files;
64                 if (p->signal->session != sid)
65                         continue;
66
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) == file) {
73                                         found = 1;
74                                         break;
75                                 }
76                         }
77                         spin_unlock(&files->file_lock);
78                 }
79                 task_unlock(p);
80                 if (found)
81                         goto out;
82         } while_each_thread(g, p);
83 out:
84         read_unlock(&tasklist_lock);
85
86         return found;
87 }
88
89 static int
90 match(const struct sk_buff *skb,
91       const struct net_device *in,
92       const struct net_device *out,
93       const void *matchinfo,
94       int offset,
95       unsigned int protoff,
96       int *hotdrop)
97 {
98         const struct ip6t_owner_info *info = matchinfo;
99
100         if (!skb->sk || !skb->sk->sk_socket || !skb->sk->sk_socket->file)
101                 return 0;
102
103         if(info->match & IP6T_OWNER_UID) {
104                 if((skb->sk->sk_socket->file->f_uid != info->uid) ^
105                     !!(info->invert & IP6T_OWNER_UID))
106                         return 0;
107         }
108
109         if(info->match & IP6T_OWNER_GID) {
110                 if((skb->sk->sk_socket->file->f_gid != info->gid) ^
111                     !!(info->invert & IP6T_OWNER_GID))
112                         return 0;
113         }
114
115         if(info->match & IP6T_OWNER_PID) {
116                 if (!match_pid(skb, info->pid) ^
117                     !!(info->invert & IP6T_OWNER_PID))
118                         return 0;
119         }
120
121         if(info->match & IP6T_OWNER_SID) {
122                 if (!match_sid(skb, info->sid) ^
123                     !!(info->invert & IP6T_OWNER_SID))
124                         return 0;
125         }
126
127         return 1;
128 }
129
130 static int
131 checkentry(const char *tablename,
132            const struct ip6t_ip6 *ip,
133            void *matchinfo,
134            unsigned int matchsize,
135            unsigned int hook_mask)
136 {
137         if (hook_mask
138             & ~((1 << NF_IP6_LOCAL_OUT) | (1 << NF_IP6_POST_ROUTING))) {
139                 printk("ip6t_owner: only valid for LOCAL_OUT or POST_ROUTING.\n");
140                 return 0;
141         }
142
143         if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_owner_info)))
144                 return 0;
145 #ifdef CONFIG_SMP
146         /* files->file_lock can not be used in a BH */
147         if (((struct ip6t_owner_info *)matchinfo)->match
148             & (IP6T_OWNER_PID|IP6T_OWNER_SID)) {
149                 printk("ip6t_owner: pid and sid matching is broken on SMP.\n");
150                 return 0;
151         }
152 #endif
153         return 1;
154 }
155
156 static struct ip6t_match owner_match = {
157         .name           = "owner",
158         .match          = &match,
159         .checkentry     = &checkentry,
160         .me             = THIS_MODULE,
161 };
162
163 static int __init init(void)
164 {
165         return ip6t_register_match(&owner_match);
166 }
167
168 static void __exit fini(void)
169 {
170         ip6t_unregister_match(&owner_match);
171 }
172
173 module_init(init);
174 module_exit(fini);