1/* Shared library add-on to iptables to add OWNER matching support. */
2#include <stdio.h>
3#include <netdb.h>
4#include <string.h>
5#include <stdlib.h>
6#include <getopt.h>
7#include <pwd.h>
8#include <grp.h>
9
10#include <iptables.h>
11#include <linux/netfilter_ipv4/ipt_owner.h>
12
13/* Function which prints out usage message. */
14static void
15help(void)
16{
17#ifdef IPT_OWNER_COMM
18	printf(
19"OWNER match v%s options:\n"
20"[!] --uid-owner userid     Match local uid\n"
21"[!] --gid-owner groupid    Match local gid\n"
22"[!] --pid-owner processid  Match local pid\n"
23"[!] --sid-owner sessionid  Match local sid\n"
24"[!] --cmd-owner name       Match local command name\n"
25"NOTE: pid, sid and command matching are broken on SMP\n"
26"\n",
27IPTABLES_VERSION);
28#else
29	printf(
30"OWNER match v%s options:\n"
31"[!] --uid-owner userid     Match local uid\n"
32"[!] --gid-owner groupid    Match local gid\n"
33"[!] --pid-owner processid  Match local pid\n"
34"[!] --sid-owner sessionid  Match local sid\n"
35"NOTE: pid and sid matching are broken on SMP\n"
36"\n",
37IPTABLES_VERSION);
38#endif /* IPT_OWNER_COMM */
39}
40
41static struct option opts[] = {
42	{ "uid-owner", 1, 0, '1' },
43	{ "gid-owner", 1, 0, '2' },
44	{ "pid-owner", 1, 0, '3' },
45	{ "sid-owner", 1, 0, '4' },
46#ifdef IPT_OWNER_COMM
47	{ "cmd-owner", 1, 0, '5' },
48#endif
49	{0}
50};
51
52/* Function which parses command options; returns true if it
53   ate an option */
54static int
55parse(int c, char **argv, int invert, unsigned int *flags,
56      const struct ipt_entry *entry,
57      unsigned int *nfcache,
58      struct ipt_entry_match **match)
59{
60	struct ipt_owner_info *ownerinfo = (struct ipt_owner_info *)(*match)->data;
61
62	switch (c) {
63		char *end;
64		struct passwd *pwd;
65		struct group *grp;
66	case '1':
67		check_inverse(optarg, &invert, &optind, 0);
68		if ((pwd = getpwnam(optarg)))
69			ownerinfo->uid = pwd->pw_uid;
70		else {
71			ownerinfo->uid = strtoul(optarg, &end, 0);
72			if (*end != '\0' || end == optarg)
73				exit_error(PARAMETER_PROBLEM, "Bad OWNER UID value `%s'", optarg);
74		}
75		if (invert)
76			ownerinfo->invert |= IPT_OWNER_UID;
77		ownerinfo->match |= IPT_OWNER_UID;
78		*flags = 1;
79		break;
80
81	case '2':
82		check_inverse(optarg, &invert, &optind, 0);
83		if ((grp = getgrnam(optarg)))
84			ownerinfo->gid = grp->gr_gid;
85		else {
86			ownerinfo->gid = strtoul(optarg, &end, 0);
87			if (*end != '\0' || end == optarg)
88				exit_error(PARAMETER_PROBLEM, "Bad OWNER GID value `%s'", optarg);
89		}
90		if (invert)
91			ownerinfo->invert |= IPT_OWNER_GID;
92		ownerinfo->match |= IPT_OWNER_GID;
93		*flags = 1;
94		break;
95
96	case '3':
97		check_inverse(optarg, &invert, &optind, 0);
98		ownerinfo->pid = strtoul(optarg, &end, 0);
99		if (*end != '\0' || end == optarg)
100			exit_error(PARAMETER_PROBLEM, "Bad OWNER PID value `%s'", optarg);
101		if (invert)
102			ownerinfo->invert |= IPT_OWNER_PID;
103		ownerinfo->match |= IPT_OWNER_PID;
104		*flags = 1;
105		break;
106
107	case '4':
108		check_inverse(optarg, &invert, &optind, 0);
109		ownerinfo->sid = strtoul(optarg, &end, 0);
110		if (*end != '\0' || end == optarg)
111			exit_error(PARAMETER_PROBLEM, "Bad OWNER SID value `%s'", optarg);
112		if (invert)
113			ownerinfo->invert |= IPT_OWNER_SID;
114		ownerinfo->match |= IPT_OWNER_SID;
115		*flags = 1;
116		break;
117
118#ifdef IPT_OWNER_COMM
119	case '5':
120		check_inverse(optarg, &invert, &optind, 0);
121		if(strlen(optarg) > sizeof(ownerinfo->comm))
122			exit_error(PARAMETER_PROBLEM, "OWNER CMD `%s' too long, max %u characters", optarg, (unsigned int)sizeof(ownerinfo->comm));
123
124		strncpy(ownerinfo->comm, optarg, sizeof(ownerinfo->comm));
125		ownerinfo->comm[sizeof(ownerinfo->comm)-1] = '\0';
126
127		if (invert)
128			ownerinfo->invert |= IPT_OWNER_COMM;
129		ownerinfo->match |= IPT_OWNER_COMM;
130		*flags = 1;
131		break;
132#endif
133
134	default:
135		return 0;
136	}
137	return 1;
138}
139
140static void
141print_item(struct ipt_owner_info *info, u_int8_t flag, int numeric, char *label)
142{
143	if(info->match & flag) {
144
145		if (info->invert & flag)
146			printf("! ");
147
148		printf(label);
149
150		switch(info->match & flag) {
151		case IPT_OWNER_UID:
152			if(!numeric) {
153				struct passwd *pwd = getpwuid(info->uid);
154
155				if(pwd && pwd->pw_name) {
156					printf("%s ", pwd->pw_name);
157					break;
158				}
159				/* FALLTHROUGH */
160			}
161			printf("%u ", info->uid);
162			break;
163		case IPT_OWNER_GID:
164			if(!numeric) {
165				struct group *grp = getgrgid(info->gid);
166
167				if(grp && grp->gr_name) {
168					printf("%s ", grp->gr_name);
169					break;
170				}
171				/* FALLTHROUGH */
172			}
173			printf("%u ", info->gid);
174			break;
175		case IPT_OWNER_PID:
176			printf("%u ", info->pid);
177			break;
178		case IPT_OWNER_SID:
179			printf("%u ", info->sid);
180			break;
181#ifdef IPT_OWNER_COMM
182		case IPT_OWNER_COMM:
183			printf("%.*s ", (int)sizeof(info->comm), info->comm);
184			break;
185#endif
186		default:
187			break;
188		}
189	}
190}
191
192/* Final check; must have specified --own. */
193static void
194final_check(unsigned int flags)
195{
196	if (!flags)
197		exit_error(PARAMETER_PROBLEM,
198			   "OWNER match: You must specify one or more options");
199}
200
201/* Prints out the matchinfo. */
202static void
203print(const struct ipt_ip *ip,
204      const struct ipt_entry_match *match,
205      int numeric)
206{
207	struct ipt_owner_info *info = (struct ipt_owner_info *)match->data;
208
209	print_item(info, IPT_OWNER_UID, numeric, "OWNER UID match ");
210	print_item(info, IPT_OWNER_GID, numeric, "OWNER GID match ");
211	print_item(info, IPT_OWNER_PID, numeric, "OWNER PID match ");
212	print_item(info, IPT_OWNER_SID, numeric, "OWNER SID match ");
213#ifdef IPT_OWNER_COMM
214	print_item(info, IPT_OWNER_COMM, numeric, "OWNER CMD match ");
215#endif
216}
217
218/* Saves the union ipt_matchinfo in parsable form to stdout. */
219static void
220save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
221{
222	struct ipt_owner_info *info = (struct ipt_owner_info *)match->data;
223
224	print_item(info, IPT_OWNER_UID, 0, "--uid-owner ");
225	print_item(info, IPT_OWNER_GID, 0, "--gid-owner ");
226	print_item(info, IPT_OWNER_PID, 0, "--pid-owner ");
227	print_item(info, IPT_OWNER_SID, 0, "--sid-owner ");
228#ifdef IPT_OWNER_COMM
229	print_item(info, IPT_OWNER_COMM, 0, "--cmd-owner ");
230#endif
231}
232
233static struct iptables_match owner = {
234	.next		= NULL,
235	.name		= "owner",
236	.version	= IPTABLES_VERSION,
237	.size		= IPT_ALIGN(sizeof(struct ipt_owner_info)),
238	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_owner_info)),
239	.help		= &help,
240	.parse		= &parse,
241	.final_check	= &final_check,
242	.print		= &print,
243	.save		= &save,
244	.extra_opts	= opts
245};
246
247void _init(void)
248{
249	register_match(&owner);
250}
251