1/* Kernel module to match various things tied to sockets associated with
2   locally generated outgoing packets.
3
4   Copyright (C) 2000,2001 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_ipv6/ip6t_owner.h>
12#include <linux/netfilter_ipv6/ip6_tables.h>
13
14MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
15MODULE_DESCRIPTION("IP6 tables owner matching module");
16MODULE_LICENSE("GPL");
17
18static int
19match_pid(const struct sk_buff *skb, pid_t pid)
20{
21	struct task_struct *p;
22	struct files_struct *files;
23	int i;
24
25	read_lock(&tasklist_lock);
26	p = find_task_by_pid(pid);
27	if (!p)
28		goto out;
29	task_lock(p);
30	files = p->files;
31	if(files) {
32		read_lock(&files->file_lock);
33		for (i=0; i < files->max_fds; i++) {
34			if (fcheck_files(files, i) == skb->sk->socket->file) {
35				read_unlock(&files->file_lock);
36				task_unlock(p);
37				read_unlock(&tasklist_lock);
38				return 1;
39			}
40		}
41		read_unlock(&files->file_lock);
42	}
43	task_unlock(p);
44out:
45	read_unlock(&tasklist_lock);
46	return 0;
47}
48
49static int
50match_sid(const struct sk_buff *skb, pid_t sid)
51{
52	struct task_struct *p;
53	struct file *file = skb->sk->socket->file;
54	int i, found=0;
55
56	read_lock(&tasklist_lock);
57	for_each_task(p) {
58		struct files_struct *files;
59		if (p->session != sid)
60			continue;
61
62		task_lock(p);
63		files = p->files;
64		if (files) {
65			read_lock(&files->file_lock);
66			for (i=0; i < files->max_fds; i++) {
67				if (fcheck_files(files, i) == file) {
68					found = 1;
69					break;
70				}
71			}
72			read_unlock(&files->file_lock);
73		}
74		task_unlock(p);
75		if(found)
76			break;
77	}
78	read_unlock(&tasklist_lock);
79
80	return found;
81}
82
83static int
84match(const struct sk_buff *skb,
85      const struct net_device *in,
86      const struct net_device *out,
87      const void *matchinfo,
88      int offset,
89      const void *hdr,
90      u_int16_t datalen,
91      int *hotdrop)
92{
93	const struct ip6t_owner_info *info = matchinfo;
94
95	if (!skb->sk || !skb->sk->socket || !skb->sk->socket->file)
96		return 0;
97
98	if(info->match & IP6T_OWNER_UID) {
99		if((skb->sk->socket->file->f_uid != info->uid) ^
100		    !!(info->invert & IP6T_OWNER_UID))
101			return 0;
102	}
103
104	if(info->match & IP6T_OWNER_GID) {
105		if((skb->sk->socket->file->f_gid != info->gid) ^
106		    !!(info->invert & IP6T_OWNER_GID))
107			return 0;
108	}
109
110	if(info->match & IP6T_OWNER_PID) {
111		if (!match_pid(skb, info->pid) ^
112		    !!(info->invert & IP6T_OWNER_PID))
113			return 0;
114	}
115
116	if(info->match & IP6T_OWNER_SID) {
117		if (!match_sid(skb, info->sid) ^
118		    !!(info->invert & IP6T_OWNER_SID))
119			return 0;
120	}
121
122	return 1;
123}
124
125static int
126checkentry(const char *tablename,
127           const struct ip6t_ip6 *ip,
128           void *matchinfo,
129           unsigned int matchsize,
130           unsigned int hook_mask)
131{
132        if (hook_mask
133            & ~((1 << NF_IP6_LOCAL_OUT) | (1 << NF_IP6_POST_ROUTING))) {
134                printk("ip6t_owner: only valid for LOCAL_OUT or POST_ROUTING.\n");
135                return 0;
136        }
137
138	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_owner_info)))
139		return 0;
140
141	return 1;
142}
143
144static struct ip6t_match owner_match
145= { { NULL, NULL }, "owner", &match, &checkentry, NULL, THIS_MODULE };
146
147static int __init init(void)
148{
149	return ip6t_register_match(&owner_match);
150}
151
152static void __exit fini(void)
153{
154	ip6t_unregister_match(&owner_match);
155}
156
157module_init(init);
158module_exit(fini);
159