ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / 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       const void *hdr,
96       u_int16_t datalen,
97       int *hotdrop)
98 {
99         const struct ip6t_owner_info *info = matchinfo;
100
101         if (!skb->sk || !skb->sk->sk_socket || !skb->sk->sk_socket->file)
102                 return 0;
103
104         if(info->match & IP6T_OWNER_UID) {
105                 if((skb->sk->sk_socket->file->f_uid != info->uid) ^
106                     !!(info->invert & IP6T_OWNER_UID))
107                         return 0;
108         }
109
110         if(info->match & IP6T_OWNER_GID) {
111                 if((skb->sk->sk_socket->file->f_gid != info->gid) ^
112                     !!(info->invert & IP6T_OWNER_GID))
113                         return 0;
114         }
115
116         if(info->match & IP6T_OWNER_PID) {
117                 if (!match_pid(skb, info->pid) ^
118                     !!(info->invert & IP6T_OWNER_PID))
119                         return 0;
120         }
121
122         if(info->match & IP6T_OWNER_SID) {
123                 if (!match_sid(skb, info->sid) ^
124                     !!(info->invert & IP6T_OWNER_SID))
125                         return 0;
126         }
127
128         return 1;
129 }
130
131 static int
132 checkentry(const char *tablename,
133            const struct ip6t_ip6 *ip,
134            void *matchinfo,
135            unsigned int matchsize,
136            unsigned int hook_mask)
137 {
138         if (hook_mask
139             & ~((1 << NF_IP6_LOCAL_OUT) | (1 << NF_IP6_POST_ROUTING))) {
140                 printk("ip6t_owner: only valid for LOCAL_OUT or POST_ROUTING.\n");
141                 return 0;
142         }
143
144         if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_owner_info)))
145                 return 0;
146
147         return 1;
148 }
149
150 static struct ip6t_match owner_match = {
151         .name           = "owner",
152         .match          = &match,
153         .checkentry     = &checkentry,
154         .me             = THIS_MODULE,
155 };
156
157 static int __init init(void)
158 {
159         return ip6t_register_match(&owner_match);
160 }
161
162 static void __exit fini(void)
163 {
164         ip6t_unregister_match(&owner_match);
165 }
166
167 module_init(init);
168 module_exit(fini);