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