• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *	libxt_owner - iptables addon for xt_owner
3  *
4  *	Copyright © CC Computer Consultants GmbH, 2007 - 2008
5  *	Jan Engelhardt <jengelh@computergmbh.de>
6  */
7 #include <grp.h>
8 #include <pwd.h>
9 #include <stdbool.h>
10 #include <stdio.h>
11 #include <limits.h>
12 #include <xtables.h>
13 #include <linux/netfilter/xt_owner.h>
14 
15 /* match and invert flags */
16 enum {
17 	IPT_OWNER_UID   = 0x01,
18 	IPT_OWNER_GID   = 0x02,
19 	IPT_OWNER_PID   = 0x04,
20 	IPT_OWNER_SID   = 0x08,
21 	IPT_OWNER_COMM  = 0x10,
22 	IP6T_OWNER_UID  = IPT_OWNER_UID,
23 	IP6T_OWNER_GID  = IPT_OWNER_GID,
24 	IP6T_OWNER_PID  = IPT_OWNER_PID,
25 	IP6T_OWNER_SID  = IPT_OWNER_SID,
26 	IP6T_OWNER_COMM = IPT_OWNER_COMM,
27 };
28 
29 struct ipt_owner_info {
30 	uid_t uid;
31 	gid_t gid;
32 	pid_t pid;
33 	pid_t sid;
34 	char comm[16];
35 	uint8_t match, invert;	/* flags */
36 };
37 
38 struct ip6t_owner_info {
39 	uid_t uid;
40 	gid_t gid;
41 	pid_t pid;
42 	pid_t sid;
43 	char comm[16];
44 	uint8_t match, invert;	/* flags */
45 };
46 
47 /*
48  *	Note: "UINT32_MAX - 1" is used in the code because -1 is a reserved
49  *	UID/GID value anyway.
50  */
51 
52 enum {
53 	O_USER = 0,
54 	O_GROUP,
55 	O_SOCK_EXISTS,
56 	O_PROCESS,
57 	O_SESSION,
58 	O_COMM,
59 };
60 
owner_mt_help_v0(void)61 static void owner_mt_help_v0(void)
62 {
63 	printf(
64 "owner match options:\n"
65 "[!] --uid-owner userid       Match local UID\n"
66 "[!] --gid-owner groupid      Match local GID\n"
67 "[!] --pid-owner processid    Match local PID\n"
68 "[!] --sid-owner sessionid    Match local SID\n"
69 "[!] --cmd-owner name         Match local command name\n"
70 "NOTE: PID, SID and command matching are broken on SMP\n");
71 }
72 
owner_mt6_help_v0(void)73 static void owner_mt6_help_v0(void)
74 {
75 	printf(
76 "owner match options:\n"
77 "[!] --uid-owner userid       Match local UID\n"
78 "[!] --gid-owner groupid      Match local GID\n"
79 "[!] --pid-owner processid    Match local PID\n"
80 "[!] --sid-owner sessionid    Match local SID\n"
81 "NOTE: PID and SID matching are broken on SMP\n");
82 }
83 
owner_mt_help(void)84 static void owner_mt_help(void)
85 {
86 	printf(
87 "owner match options:\n"
88 "[!] --uid-owner userid[-userid]      Match local UID\n"
89 "[!] --gid-owner groupid[-groupid]    Match local GID\n"
90 "[!] --socket-exists                  Match if socket exists\n");
91 }
92 
93 #define s struct ipt_owner_info
94 static const struct xt_option_entry owner_mt_opts_v0[] = {
95 	{.name = "uid-owner", .id = O_USER, .type = XTTYPE_STRING,
96 	 .flags = XTOPT_INVERT},
97 	{.name = "gid-owner", .id = O_GROUP, .type = XTTYPE_STRING,
98 	 .flags = XTOPT_INVERT},
99 	{.name = "pid-owner", .id = O_PROCESS, .type = XTTYPE_UINT32,
100 	 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, pid),
101 	 .max = INT_MAX},
102 	{.name = "sid-owner", .id = O_SESSION, .type = XTTYPE_UINT32,
103 	 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, sid),
104 	 .max = INT_MAX},
105 	{.name = "cmd-owner", .id = O_COMM, .type = XTTYPE_STRING,
106 	 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, comm)},
107 	XTOPT_TABLEEND,
108 };
109 #undef s
110 
111 #define s struct ip6t_owner_info
112 static const struct xt_option_entry owner_mt6_opts_v0[] = {
113 	{.name = "uid-owner", .id = O_USER, .type = XTTYPE_STRING,
114 	 .flags = XTOPT_INVERT},
115 	{.name = "gid-owner", .id = O_GROUP, .type = XTTYPE_STRING,
116 	 .flags = XTOPT_INVERT},
117 	{.name = "pid-owner", .id = O_PROCESS, .type = XTTYPE_UINT32,
118 	 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, pid),
119 	 .max = INT_MAX},
120 	{.name = "sid-owner", .id = O_SESSION, .type = XTTYPE_UINT32,
121 	 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, sid),
122 	 .max = INT_MAX},
123 	XTOPT_TABLEEND,
124 };
125 #undef s
126 
127 static const struct xt_option_entry owner_mt_opts[] = {
128 	{.name = "uid-owner", .id = O_USER, .type = XTTYPE_STRING,
129 	 .flags = XTOPT_INVERT},
130 	{.name = "gid-owner", .id = O_GROUP, .type = XTTYPE_STRING,
131 	 .flags = XTOPT_INVERT},
132 	{.name = "socket-exists", .id = O_SOCK_EXISTS, .type = XTTYPE_NONE},
133 	XTOPT_TABLEEND,
134 };
135 
owner_mt_parse_v0(struct xt_option_call * cb)136 static void owner_mt_parse_v0(struct xt_option_call *cb)
137 {
138 	struct ipt_owner_info *info = cb->data;
139 	struct passwd *pwd;
140 	struct group *grp;
141 	unsigned int id;
142 
143 	xtables_option_parse(cb);
144 	switch (cb->entry->id) {
145 	case O_USER:
146 		if ((pwd = getpwnam(cb->arg)) != NULL)
147 			id = pwd->pw_uid;
148 		else if (!xtables_strtoui(cb->arg, NULL, &id, 0, UINT32_MAX - 1))
149 			xtables_param_act(XTF_BAD_VALUE, "owner", "--uid-owner", cb->arg);
150 		if (cb->invert)
151 			info->invert |= IPT_OWNER_UID;
152 		info->match |= IPT_OWNER_UID;
153 		info->uid    = id;
154 		break;
155 	case O_GROUP:
156 		if ((grp = getgrnam(cb->arg)) != NULL)
157 			id = grp->gr_gid;
158 		else if (!xtables_strtoui(cb->arg, NULL, &id, 0, UINT32_MAX - 1))
159 			xtables_param_act(XTF_BAD_VALUE, "owner", "--gid-owner", cb->arg);
160 		if (cb->invert)
161 			info->invert |= IPT_OWNER_GID;
162 		info->match |= IPT_OWNER_GID;
163 		info->gid    = id;
164 		break;
165 	case O_PROCESS:
166 		if (cb->invert)
167 			info->invert |= IPT_OWNER_PID;
168 		info->match |= IPT_OWNER_PID;
169 		break;
170 	case O_SESSION:
171 		if (cb->invert)
172 			info->invert |= IPT_OWNER_SID;
173 		info->match |= IPT_OWNER_SID;
174 		break;
175 	case O_COMM:
176 		if (cb->invert)
177 			info->invert |= IPT_OWNER_COMM;
178 		info->match |= IPT_OWNER_COMM;
179 		break;
180 	}
181 }
182 
owner_mt6_parse_v0(struct xt_option_call * cb)183 static void owner_mt6_parse_v0(struct xt_option_call *cb)
184 {
185 	struct ip6t_owner_info *info = cb->data;
186 	struct passwd *pwd;
187 	struct group *grp;
188 	unsigned int id;
189 
190 	xtables_option_parse(cb);
191 	switch (cb->entry->id) {
192 	case O_USER:
193 		if ((pwd = getpwnam(cb->arg)) != NULL)
194 			id = pwd->pw_uid;
195 		else if (!xtables_strtoui(cb->arg, NULL, &id, 0, UINT32_MAX - 1))
196 			xtables_param_act(XTF_BAD_VALUE, "owner", "--uid-owner", cb->arg);
197 		if (cb->invert)
198 			info->invert |= IP6T_OWNER_UID;
199 		info->match |= IP6T_OWNER_UID;
200 		info->uid    = id;
201 		break;
202 	case O_GROUP:
203 		if ((grp = getgrnam(cb->arg)) != NULL)
204 			id = grp->gr_gid;
205 		else if (!xtables_strtoui(cb->arg, NULL, &id, 0, UINT32_MAX - 1))
206 			xtables_param_act(XTF_BAD_VALUE, "owner", "--gid-owner", cb->arg);
207 		if (cb->invert)
208 			info->invert |= IP6T_OWNER_GID;
209 		info->match |= IP6T_OWNER_GID;
210 		info->gid    = id;
211 		break;
212 	case O_PROCESS:
213 		if (cb->invert)
214 			info->invert |= IP6T_OWNER_PID;
215 		info->match |= IP6T_OWNER_PID;
216 		break;
217 	case O_SESSION:
218 		if (cb->invert)
219 			info->invert |= IP6T_OWNER_SID;
220 		info->match |= IP6T_OWNER_SID;
221 		break;
222 	}
223 }
224 
owner_parse_range(const char * s,unsigned int * from,unsigned int * to,const char * opt)225 static void owner_parse_range(const char *s, unsigned int *from,
226                               unsigned int *to, const char *opt)
227 {
228 	char *end;
229 
230 	/* -1 is reversed, so the max is one less than that. */
231 	if (!xtables_strtoui(s, &end, from, 0, UINT32_MAX - 1))
232 		xtables_param_act(XTF_BAD_VALUE, "owner", opt, s);
233 	*to = *from;
234 	if (*end == '-' || *end == ':')
235 		if (!xtables_strtoui(end + 1, &end, to, 0, UINT32_MAX - 1))
236 			xtables_param_act(XTF_BAD_VALUE, "owner", opt, s);
237 	if (*end != '\0')
238 		xtables_param_act(XTF_BAD_VALUE, "owner", opt, s);
239 }
240 
owner_mt_parse(struct xt_option_call * cb)241 static void owner_mt_parse(struct xt_option_call *cb)
242 {
243 	struct xt_owner_match_info *info = cb->data;
244 	struct passwd *pwd;
245 	struct group *grp;
246 	unsigned int from, to;
247 
248 	xtables_option_parse(cb);
249 	switch (cb->entry->id) {
250 	case O_USER:
251 		if ((pwd = getpwnam(cb->arg)) != NULL)
252 			from = to = pwd->pw_uid;
253 		else
254 			owner_parse_range(cb->arg, &from, &to, "--uid-owner");
255 		if (cb->invert)
256 			info->invert |= XT_OWNER_UID;
257 		info->match  |= XT_OWNER_UID;
258 		info->uid_min = from;
259 		info->uid_max = to;
260 		break;
261 	case O_GROUP:
262 		if ((grp = getgrnam(cb->arg)) != NULL)
263 			from = to = grp->gr_gid;
264 		else
265 			owner_parse_range(cb->arg, &from, &to, "--gid-owner");
266 		if (cb->invert)
267 			info->invert |= XT_OWNER_GID;
268 		info->match  |= XT_OWNER_GID;
269 		info->gid_min = from;
270 		info->gid_max = to;
271 		break;
272 	case O_SOCK_EXISTS:
273 		if (cb->invert)
274 			info->invert |= XT_OWNER_SOCKET;
275 		info->match |= XT_OWNER_SOCKET;
276 		break;
277 	}
278 }
279 
owner_mt_check(struct xt_fcheck_call * cb)280 static void owner_mt_check(struct xt_fcheck_call *cb)
281 {
282 	if (cb->xflags == 0)
283 		xtables_error(PARAMETER_PROBLEM, "owner: At least one of "
284 		           "--uid-owner, --gid-owner or --socket-exists "
285 		           "is required");
286 }
287 
288 static void
owner_mt_print_item_v0(const struct ipt_owner_info * info,const char * label,uint8_t flag,bool numeric)289 owner_mt_print_item_v0(const struct ipt_owner_info *info, const char *label,
290                        uint8_t flag, bool numeric)
291 {
292 	if (!(info->match & flag))
293 		return;
294 	if (info->invert & flag)
295 		printf(" !");
296 	printf(" %s", label);
297 
298 	switch (info->match & flag) {
299 	case IPT_OWNER_UID:
300 		if (!numeric) {
301 			struct passwd *pwd = getpwuid(info->uid);
302 
303 			if (pwd != NULL && pwd->pw_name != NULL) {
304 				printf(" %s", pwd->pw_name);
305 				break;
306 			}
307 		}
308 		printf(" %u", (unsigned int)info->uid);
309 		break;
310 
311 	case IPT_OWNER_GID:
312 		if (!numeric) {
313 			struct group *grp = getgrgid(info->gid);
314 
315 			if (grp != NULL && grp->gr_name != NULL) {
316 				printf(" %s", grp->gr_name);
317 				break;
318 			}
319 		}
320 		printf(" %u", (unsigned int)info->gid);
321 		break;
322 
323 	case IPT_OWNER_PID:
324 		printf(" %u", (unsigned int)info->pid);
325 		break;
326 
327 	case IPT_OWNER_SID:
328 		printf(" %u", (unsigned int)info->sid);
329 		break;
330 
331 	case IPT_OWNER_COMM:
332 		printf(" %.*s", (int)sizeof(info->comm), info->comm);
333 		break;
334 	}
335 }
336 
337 static void
owner_mt6_print_item_v0(const struct ip6t_owner_info * info,const char * label,uint8_t flag,bool numeric)338 owner_mt6_print_item_v0(const struct ip6t_owner_info *info, const char *label,
339                         uint8_t flag, bool numeric)
340 {
341 	if (!(info->match & flag))
342 		return;
343 	if (info->invert & flag)
344 		printf(" !");
345 	printf(" %s", label);
346 
347 	switch (info->match & flag) {
348 	case IP6T_OWNER_UID:
349 		if (!numeric) {
350 			struct passwd *pwd = getpwuid(info->uid);
351 
352 			if (pwd != NULL && pwd->pw_name != NULL) {
353 				printf(" %s", pwd->pw_name);
354 				break;
355 			}
356 		}
357 		printf(" %u", (unsigned int)info->uid);
358 		break;
359 
360 	case IP6T_OWNER_GID:
361 		if (!numeric) {
362 			struct group *grp = getgrgid(info->gid);
363 
364 			if (grp != NULL && grp->gr_name != NULL) {
365 				printf(" %s", grp->gr_name);
366 				break;
367 			}
368 		}
369 		printf(" %u", (unsigned int)info->gid);
370 		break;
371 
372 	case IP6T_OWNER_PID:
373 		printf(" %u", (unsigned int)info->pid);
374 		break;
375 
376 	case IP6T_OWNER_SID:
377 		printf(" %u", (unsigned int)info->sid);
378 		break;
379 	}
380 }
381 
382 static void
owner_mt_print_item(const struct xt_owner_match_info * info,const char * label,uint8_t flag,bool numeric)383 owner_mt_print_item(const struct xt_owner_match_info *info, const char *label,
384                     uint8_t flag, bool numeric)
385 {
386 	if (!(info->match & flag))
387 		return;
388 	if (info->invert & flag)
389 		printf(" !");
390 	printf(" %s", label);
391 
392 	switch (info->match & flag) {
393 	case XT_OWNER_UID:
394 		if (info->uid_min != info->uid_max) {
395 			printf(" %u-%u", (unsigned int)info->uid_min,
396 			       (unsigned int)info->uid_max);
397 			break;
398 		} else if (!numeric) {
399 			const struct passwd *pwd = getpwuid(info->uid_min);
400 
401 			if (pwd != NULL && pwd->pw_name != NULL) {
402 				printf(" %s", pwd->pw_name);
403 				break;
404 			}
405 		}
406 		printf(" %u", (unsigned int)info->uid_min);
407 		break;
408 
409 	case XT_OWNER_GID:
410 		if (info->gid_min != info->gid_max) {
411 			printf(" %u-%u", (unsigned int)info->gid_min,
412 			       (unsigned int)info->gid_max);
413 			break;
414 		} else if (!numeric) {
415 			const struct group *grp = getgrgid(info->gid_min);
416 
417 			if (grp != NULL && grp->gr_name != NULL) {
418 				printf(" %s", grp->gr_name);
419 				break;
420 			}
421 		}
422 		printf(" %u", (unsigned int)info->gid_min);
423 		break;
424 	}
425 }
426 
427 static void
owner_mt_print_v0(const void * ip,const struct xt_entry_match * match,int numeric)428 owner_mt_print_v0(const void *ip, const struct xt_entry_match *match,
429                   int numeric)
430 {
431 	const struct ipt_owner_info *info = (void *)match->data;
432 
433 	owner_mt_print_item_v0(info, "owner UID match", IPT_OWNER_UID, numeric);
434 	owner_mt_print_item_v0(info, "owner GID match", IPT_OWNER_GID, numeric);
435 	owner_mt_print_item_v0(info, "owner PID match", IPT_OWNER_PID, numeric);
436 	owner_mt_print_item_v0(info, "owner SID match", IPT_OWNER_SID, numeric);
437 	owner_mt_print_item_v0(info, "owner CMD match", IPT_OWNER_COMM, numeric);
438 }
439 
440 static void
owner_mt6_print_v0(const void * ip,const struct xt_entry_match * match,int numeric)441 owner_mt6_print_v0(const void *ip, const struct xt_entry_match *match,
442                    int numeric)
443 {
444 	const struct ip6t_owner_info *info = (void *)match->data;
445 
446 	owner_mt6_print_item_v0(info, "owner UID match", IPT_OWNER_UID, numeric);
447 	owner_mt6_print_item_v0(info, "owner GID match", IPT_OWNER_GID, numeric);
448 	owner_mt6_print_item_v0(info, "owner PID match", IPT_OWNER_PID, numeric);
449 	owner_mt6_print_item_v0(info, "owner SID match", IPT_OWNER_SID, numeric);
450 }
451 
owner_mt_print(const void * ip,const struct xt_entry_match * match,int numeric)452 static void owner_mt_print(const void *ip, const struct xt_entry_match *match,
453                            int numeric)
454 {
455 	const struct xt_owner_match_info *info = (void *)match->data;
456 
457 	owner_mt_print_item(info, "owner socket exists", XT_OWNER_SOCKET, numeric);
458 	owner_mt_print_item(info, "owner UID match",     XT_OWNER_UID,    numeric);
459 	owner_mt_print_item(info, "owner GID match",     XT_OWNER_GID,    numeric);
460 }
461 
462 static void
owner_mt_save_v0(const void * ip,const struct xt_entry_match * match)463 owner_mt_save_v0(const void *ip, const struct xt_entry_match *match)
464 {
465 	const struct ipt_owner_info *info = (void *)match->data;
466 
467 	owner_mt_print_item_v0(info, "--uid-owner", IPT_OWNER_UID, true);
468 	owner_mt_print_item_v0(info, "--gid-owner", IPT_OWNER_GID, true);
469 	owner_mt_print_item_v0(info, "--pid-owner", IPT_OWNER_PID, true);
470 	owner_mt_print_item_v0(info, "--sid-owner", IPT_OWNER_SID, true);
471 	owner_mt_print_item_v0(info, "--cmd-owner", IPT_OWNER_COMM, true);
472 }
473 
474 static void
owner_mt6_save_v0(const void * ip,const struct xt_entry_match * match)475 owner_mt6_save_v0(const void *ip, const struct xt_entry_match *match)
476 {
477 	const struct ip6t_owner_info *info = (void *)match->data;
478 
479 	owner_mt6_print_item_v0(info, "--uid-owner", IPT_OWNER_UID, true);
480 	owner_mt6_print_item_v0(info, "--gid-owner", IPT_OWNER_GID, true);
481 	owner_mt6_print_item_v0(info, "--pid-owner", IPT_OWNER_PID, true);
482 	owner_mt6_print_item_v0(info, "--sid-owner", IPT_OWNER_SID, true);
483 }
484 
owner_mt_save(const void * ip,const struct xt_entry_match * match)485 static void owner_mt_save(const void *ip, const struct xt_entry_match *match)
486 {
487 	const struct xt_owner_match_info *info = (void *)match->data;
488 
489 	owner_mt_print_item(info, "--socket-exists",  XT_OWNER_SOCKET, true);
490 	owner_mt_print_item(info, "--uid-owner",      XT_OWNER_UID,    true);
491 	owner_mt_print_item(info, "--gid-owner",      XT_OWNER_GID,    true);
492 }
493 
494 static struct xtables_match owner_mt_reg[] = {
495 	{
496 		.version       = XTABLES_VERSION,
497 		.name          = "owner",
498 		.revision      = 0,
499 		.family        = NFPROTO_IPV4,
500 		.size          = XT_ALIGN(sizeof(struct ipt_owner_info)),
501 		.userspacesize = XT_ALIGN(sizeof(struct ipt_owner_info)),
502 		.help          = owner_mt_help_v0,
503 		.x6_parse      = owner_mt_parse_v0,
504 		.x6_fcheck     = owner_mt_check,
505 		.print         = owner_mt_print_v0,
506 		.save          = owner_mt_save_v0,
507 		.x6_options    = owner_mt_opts_v0,
508 	},
509 	{
510 		.version       = XTABLES_VERSION,
511 		.name          = "owner",
512 		.revision      = 0,
513 		.family        = NFPROTO_IPV6,
514 		.size          = XT_ALIGN(sizeof(struct ip6t_owner_info)),
515 		.userspacesize = XT_ALIGN(sizeof(struct ip6t_owner_info)),
516 		.help          = owner_mt6_help_v0,
517 		.x6_parse      = owner_mt6_parse_v0,
518 		.x6_fcheck     = owner_mt_check,
519 		.print         = owner_mt6_print_v0,
520 		.save          = owner_mt6_save_v0,
521 		.x6_options    = owner_mt6_opts_v0,
522 	},
523 	{
524 		.version       = XTABLES_VERSION,
525 		.name          = "owner",
526 		.revision      = 1,
527 		.family        = NFPROTO_UNSPEC,
528 		.size          = XT_ALIGN(sizeof(struct xt_owner_match_info)),
529 		.userspacesize = XT_ALIGN(sizeof(struct xt_owner_match_info)),
530 		.help          = owner_mt_help,
531 		.x6_parse      = owner_mt_parse,
532 		.x6_fcheck     = owner_mt_check,
533 		.print         = owner_mt_print,
534 		.save          = owner_mt_save,
535 		.x6_options    = owner_mt_opts,
536 	},
537 };
538 
_init(void)539 void _init(void)
540 {
541 	xtables_register_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg));
542 }
543