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"\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 /* IPT_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 IPT_OWNER_COMM
45	{ "cmd-owner", 1, 0, '5' },
46#endif
47	{0}
48};
49
50/* Initialize the match. */
51static void
52init(struct ipt_entry_match *m, unsigned int *nfcache)
53{
54	/* Can't cache this. */
55	*nfcache |= NFC_UNKNOWN;
56}
57
58/* Function which parses command options; returns true if it
59   ate an option */
60static int
61parse(int c, char **argv, int invert, unsigned int *flags,
62      const struct ipt_entry *entry,
63      unsigned int *nfcache,
64      struct ipt_entry_match **match)
65{
66	struct ipt_owner_info *ownerinfo = (struct ipt_owner_info *)(*match)->data;
67
68	switch (c) {
69		char *end;
70		struct passwd *pwd;
71		struct group *grp;
72	case '1':
73		check_inverse(optarg, &invert, &optind, 0);
74		if ((pwd = getpwnam(optarg)))
75			ownerinfo->uid = pwd->pw_uid;
76		else {
77			ownerinfo->uid = strtoul(optarg, &end, 0);
78			if (*end != '\0' || end == optarg)
79				exit_error(PARAMETER_PROBLEM, "Bad OWNER UID value `%s'", optarg);
80		}
81		if (invert)
82			ownerinfo->invert |= IPT_OWNER_UID;
83		ownerinfo->match |= IPT_OWNER_UID;
84		*flags = 1;
85		break;
86
87	case '2':
88		check_inverse(optarg, &invert, &optind, 0);
89		if ((grp = getgrnam(optarg)))
90			ownerinfo->gid = grp->gr_gid;
91		else {
92			ownerinfo->gid = strtoul(optarg, &end, 0);
93			if (*end != '\0' || end == optarg)
94				exit_error(PARAMETER_PROBLEM, "Bad OWNER GID value `%s'", optarg);
95		}
96		if (invert)
97			ownerinfo->invert |= IPT_OWNER_GID;
98		ownerinfo->match |= IPT_OWNER_GID;
99		*flags = 1;
100		break;
101
102	case '3':
103		check_inverse(optarg, &invert, &optind, 0);
104		ownerinfo->pid = strtoul(optarg, &end, 0);
105		if (*end != '\0' || end == optarg)
106			exit_error(PARAMETER_PROBLEM, "Bad OWNER PID value `%s'", optarg);
107		if (invert)
108			ownerinfo->invert |= IPT_OWNER_PID;
109		ownerinfo->match |= IPT_OWNER_PID;
110		*flags = 1;
111		break;
112
113	case '4':
114		check_inverse(optarg, &invert, &optind, 0);
115		ownerinfo->sid = strtoul(optarg, &end, 0);
116		if (*end != '\0' || end == optarg)
117			exit_error(PARAMETER_PROBLEM, "Bad OWNER SID value `%s'", optarg);
118		if (invert)
119			ownerinfo->invert |= IPT_OWNER_SID;
120		ownerinfo->match |= IPT_OWNER_SID;
121		*flags = 1;
122		break;
123
124#ifdef IPT_OWNER_COMM
125	case '5':
126		check_inverse(optarg, &invert, &optind, 0);
127		if(strlen(optarg) > sizeof(ownerinfo->comm))
128			exit_error(PARAMETER_PROBLEM, "OWNER CMD `%s' too long, max %d characters", optarg, sizeof(ownerinfo->comm));
129
130		strncpy(ownerinfo->comm, optarg, sizeof(ownerinfo->comm));
131
132		if (invert)
133			ownerinfo->invert |= IPT_OWNER_COMM;
134		ownerinfo->match |= IPT_OWNER_COMM;
135		*flags = 1;
136		break;
137#endif
138
139	default:
140		return 0;
141	}
142	return 1;
143}
144
145static void
146print_item(struct ipt_owner_info *info, u_int8_t flag, int numeric, char *label)
147{
148	if(info->match & flag) {
149
150		printf(label);
151
152		if (info->invert & flag)
153			fputc('!', stdout);
154
155		switch(info->match & flag) {
156		case IPT_OWNER_UID:
157			if(!numeric) {
158				struct passwd *pwd = getpwuid(info->uid);
159
160				if(pwd && pwd->pw_name) {
161					printf("%s ", pwd->pw_name);
162					break;
163				}
164				/* FALLTHROUGH */
165			}
166			printf("%u ", info->uid);
167			break;
168		case IPT_OWNER_GID:
169			if(!numeric) {
170				struct group *grp = getgrgid(info->gid);
171
172				if(grp && grp->gr_name) {
173					printf("%s ", grp->gr_name);
174					break;
175				}
176				/* FALLTHROUGH */
177			}
178			printf("%u ", info->gid);
179			break;
180		case IPT_OWNER_PID:
181			printf("%u ", info->pid);
182			break;
183		case IPT_OWNER_SID:
184			printf("%u ", info->sid);
185			break;
186#ifdef IPT_OWNER_COMM
187		case IPT_OWNER_COMM:
188			printf("%.*s ", (int)sizeof(info->comm), info->comm);
189			break;
190#endif
191		default:
192			break;
193		}
194	}
195}
196
197/* Final check; must have specified --own. */
198static void
199final_check(unsigned int flags)
200{
201	if (!flags)
202		exit_error(PARAMETER_PROBLEM,
203			   "OWNER match: You must specify one or more options");
204}
205
206/* Prints out the matchinfo. */
207static void
208print(const struct ipt_ip *ip,
209      const struct ipt_entry_match *match,
210      int numeric)
211{
212	struct ipt_owner_info *info = (struct ipt_owner_info *)match->data;
213
214	print_item(info, IPT_OWNER_UID, numeric, "OWNER UID match ");
215	print_item(info, IPT_OWNER_GID, numeric, "OWNER GID match ");
216	print_item(info, IPT_OWNER_PID, numeric, "OWNER PID match ");
217	print_item(info, IPT_OWNER_SID, numeric, "OWNER SID match ");
218#ifdef IPT_OWNER_COMM
219	print_item(info, IPT_OWNER_COMM, numeric, "OWNER CMD match ");
220#endif
221}
222
223/* Saves the union ipt_matchinfo in parsable form to stdout. */
224static void
225save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
226{
227	struct ipt_owner_info *info = (struct ipt_owner_info *)match->data;
228
229	print_item(info, IPT_OWNER_UID, 0, "--uid-owner ");
230	print_item(info, IPT_OWNER_GID, 0, "--gid-owner ");
231	print_item(info, IPT_OWNER_PID, 0, "--pid-owner ");
232	print_item(info, IPT_OWNER_SID, 0, "--sid-owner ");
233#ifdef IPT_OWNER_COMM
234	print_item(info, IPT_OWNER_COMM, 0, "--cmd-owner ");
235#endif
236}
237
238static
239struct iptables_match owner
240= { NULL,
241    "owner",
242    IPTABLES_VERSION,
243    IPT_ALIGN(sizeof(struct ipt_owner_info)),
244    IPT_ALIGN(sizeof(struct ipt_owner_info)),
245    &help,
246    &init,
247    &parse,
248    &final_check,
249    &print,
250    &save,
251    opts
252};
253
254void _init(void)
255{
256	register_match(&owner);
257}
258