blob: 62b8b8852e8681daf2db266b7b7f5bd99b317a10 [file] [log] [blame]
Jan Engelhardt5c5cd882008-01-20 13:21:38 +00001/*
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 <getopt.h>
8#include <grp.h>
9#include <netdb.h>
10#include <pwd.h>
11#include <stdbool.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15
16#include <xtables.h>
17#include <linux/netfilter/xt_owner.h>
18#include <linux/netfilter_ipv4/ipt_owner.h>
19#include <linux/netfilter_ipv6/ip6t_owner.h>
20
21enum {
22 FLAG_UID_OWNER = 1 << 0,
23 FLAG_GID_OWNER = 1 << 1,
24 FLAG_SOCKET_EXISTS = 1 << 2,
25 FLAG_PID_OWNER = 1 << 3,
26 FLAG_SID_OWNER = 1 << 4,
27 FLAG_COMM = 1 << 5,
28};
29
30static void owner_mt_help_v0(void)
31{
32#ifdef IPT_OWNER_COMM
33 printf(
34"owner match options:\n"
35"[!] --uid-owner userid Match local UID\n"
36"[!] --gid-owner groupid Match local GID\n"
37"[!] --pid-owner processid Match local PID\n"
38"[!] --sid-owner sessionid Match local SID\n"
39"[!] --cmd-owner name Match local command name\n"
40"NOTE: PID, SID and command matching are broken on SMP\n"
41"\n");
42#else
43 printf(
44"owner match options:\n"
45"[!] --uid-owner userid Match local UID\n"
46"[!] --gid-owner groupid Match local GID\n"
47"[!] --pid-owner processid Match local PID\n"
48"[!] --sid-owner sessionid Match local SID\n"
49"NOTE: PID and SID matching are broken on SMP\n"
50"\n");
51#endif /* IPT_OWNER_COMM */
52}
53
54static void owner_mt6_help_v0(void)
55{
56 printf(
57"owner match options:\n"
58"[!] --uid-owner userid Match local UID\n"
59"[!] --gid-owner groupid Match local GID\n"
60"[!] --pid-owner processid Match local PID\n"
61"[!] --sid-owner sessionid Match local SID\n"
62"NOTE: PID and SID matching are broken on SMP\n"
63"\n");
64}
65
66static void owner_mt_help(void)
67{
68 printf(
69"owner match options:\n"
Jan Engelhardtca1da702008-01-29 13:38:05 +000070"[!] --uid-owner userid[-userid] Match local UID\n"
71"[!] --gid-owner groupid[-groupid] Match local GID\n"
72"[!] --socket-exists Match if socket exists\n"
Jan Engelhardt5c5cd882008-01-20 13:21:38 +000073"\n");
74}
75
76static const struct option owner_mt_opts_v0[] = {
77 {.name = "uid-owner", .has_arg = true, .val = 'u'},
78 {.name = "gid-owner", .has_arg = true, .val = 'g'},
79 {.name = "pid-owner", .has_arg = true, .val = 'p'},
80 {.name = "sid-owner", .has_arg = true, .val = 's'},
81#ifdef IPT_OWNER_COMM
82 {.name = "cmd-owner", .has_arg = true, .val = 'c'},
83#endif
84 {},
85};
86
87static const struct option owner_mt6_opts_v0[] = {
88 {.name = "uid-owner", .has_arg = true, .val = 'u'},
89 {.name = "gid-owner", .has_arg = true, .val = 'g'},
90 {.name = "pid-owner", .has_arg = true, .val = 'p'},
91 {.name = "sid-owner", .has_arg = true, .val = 's'},
92 {},
93};
94
95static const struct option owner_mt_opts[] = {
96 {.name = "uid-owner", .has_arg = true, .val = 'u'},
97 {.name = "gid-owner", .has_arg = true, .val = 'g'},
98 {.name = "socket-exists", .has_arg = false, .val = 'k'},
99 {},
100};
101
102static int
103owner_mt_parse_v0(int c, char **argv, int invert, unsigned int *flags,
104 const void *entry, struct xt_entry_match **match)
105{
106 struct ipt_owner_info *info = (void *)(*match)->data;
107 struct passwd *pwd;
108 struct group *grp;
109 unsigned int id;
110
111 switch (c) {
112 case 'u':
113 param_act(P_ONLY_ONCE, "owner", "--uid-owner", *flags & FLAG_UID_OWNER);
114 if ((pwd = getpwnam(optarg)) != NULL)
115 id = pwd->pw_uid;
116 else if (!strtonum(optarg, NULL, &id, 0, ~(uid_t)0))
117 param_act(P_BAD_VALUE, "owner", "--uid-owner", optarg);
118 if (invert)
119 info->invert |= IPT_OWNER_UID;
120 info->match |= IPT_OWNER_UID;
121 info->uid = id;
122 *flags |= FLAG_UID_OWNER;
123 return true;
124
125 case 'g':
126 param_act(P_ONLY_ONCE, "owner", "--gid-owner", *flags & FLAG_GID_OWNER);
127 if ((grp = getgrnam(optarg)) != NULL)
128 id = grp->gr_gid;
129 else if (!strtonum(optarg, NULL, &id, 0, ~(gid_t)0))
130 param_act(P_BAD_VALUE, "owner", "--gid-owner", optarg);
131 if (invert)
132 info->invert |= IPT_OWNER_GID;
133 info->match |= IPT_OWNER_GID;
134 info->gid = id;
135 *flags |= FLAG_GID_OWNER;
136 return true;
137
138 case 'p':
139 param_act(P_ONLY_ONCE, "owner", "--pid-owner", *flags & FLAG_PID_OWNER);
140 if (!strtonum(optarg, NULL, &id, 0, INT_MAX))
141 param_act(P_BAD_VALUE, "owner", "--pid-owner", optarg);
142 if (invert)
143 info->invert |= IPT_OWNER_PID;
144 info->match |= IPT_OWNER_PID;
145 info->pid = id;
146 *flags |= FLAG_PID_OWNER;
147 return true;
148
149 case 's':
150 param_act(P_ONLY_ONCE, "owner", "--sid-owner", *flags & FLAG_SID_OWNER);
151 if (!strtonum(optarg, NULL, &id, 0, INT_MAX))
152 param_act(P_BAD_VALUE, "owner", "--sid-value", optarg);
153 if (invert)
154 info->invert |= IPT_OWNER_SID;
155 info->match |= IPT_OWNER_SID;
156 info->sid = id;
157 *flags |= FLAG_SID_OWNER;
158 return true;
159
160#ifdef IPT_OWNER_COMM
161 case 'c':
162 param_act(P_ONLY_ONCE, "owner", "--cmd-owner", *flags & FLAG_COMM);
163 if (strlen(optarg) > sizeof(info->comm))
164 exit_error(PARAMETER_PROBLEM, "owner match: command "
165 "\"%s\" too long, max. %zu characters",
166 optarg, sizeof(info->comm));
167
168 info->comm[sizeof(info->comm)-1] = '\0';
169 strncpy(info->comm, optarg, sizeof(info->comm));
170
171 if (invert)
172 info->invert |= IPT_OWNER_COMM;
173 info->match |= IPT_OWNER_COMM;
174 *flags |= FLAG_COMM;
175 return true;
176#endif
177 }
178 return false;
179}
180
181static int
182owner_mt6_parse_v0(int c, char **argv, int invert, unsigned int *flags,
183 const void *entry, struct xt_entry_match **match)
184{
185 struct ip6t_owner_info *info = (void *)(*match)->data;
186 struct passwd *pwd;
187 struct group *grp;
188 unsigned int id;
189
190 switch (c) {
191 case 'u':
192 param_act(P_ONLY_ONCE, "owner", "--uid-owner",
193 *flags & FLAG_UID_OWNER);
194 if ((pwd = getpwnam(optarg)) != NULL)
195 id = pwd->pw_uid;
196 else if (!strtonum(optarg, NULL, &id, 0, ~(uid_t)0))
197 param_act(P_BAD_VALUE, "owner", "--uid-owner", optarg);
198 if (invert)
199 info->invert |= IP6T_OWNER_UID;
200 info->match |= IP6T_OWNER_UID;
201 info->uid = id;
202 *flags |= FLAG_UID_OWNER;
203 return true;
204
205 case 'g':
206 param_act(P_ONLY_ONCE, "owner", "--gid-owner",
207 *flags & FLAG_GID_OWNER);
208 if ((grp = getgrnam(optarg)) != NULL)
209 id = grp->gr_gid;
210 else if (!strtonum(optarg, NULL, &id, 0, ~(gid_t)0))
211 param_act(P_BAD_VALUE, "owner", "--gid-owner", optarg);
212 if (invert)
213 info->invert |= IP6T_OWNER_GID;
214 info->match |= IP6T_OWNER_GID;
215 info->gid = id;
216 *flags |= FLAG_GID_OWNER;
217 return true;
218
219 case 'p':
220 param_act(P_ONLY_ONCE, "owner", "--pid-owner",
221 *flags & FLAG_PID_OWNER);
222 if (!strtonum(optarg, NULL, &id, 0, INT_MAX))
223 param_act(P_BAD_VALUE, "owner", "--pid-owner", optarg);
224 if (invert)
225 info->invert |= IP6T_OWNER_PID;
226 info->match |= IP6T_OWNER_PID;
227 info->pid = id;
228 *flags |= FLAG_PID_OWNER;
229 return true;
230
231 case 's':
232 param_act(P_ONLY_ONCE, "owner", "--sid-owner",
233 *flags & FLAG_SID_OWNER);
234 if (!strtonum(optarg, NULL, &id, 0, INT_MAX))
235 param_act(P_BAD_VALUE, "owner", "--sid-owner", optarg);
236 if (invert)
237 info->invert |= IP6T_OWNER_SID;
238 info->match |= IP6T_OWNER_SID;
239 info->sid = id;
240 *flags |= FLAG_SID_OWNER;
241 return true;
242 }
243 return false;
244}
245
Jan Engelhardtca1da702008-01-29 13:38:05 +0000246static void owner_parse_range(const char *s, unsigned int *from,
247 unsigned int *to, const char *opt)
248{
249 char *end;
250
251 /* 4294967295 is reserved, so subtract one from ~0 */
252 if (!strtonum(s, &end, from, 0, (~(uid_t)0) - 1))
253 param_act(P_BAD_VALUE, "owner", opt, s);
254 *to = *from;
255 if (*end == '-' || *end == ':')
256 if (!strtonum(end + 1, &end, to, 0, (~(uid_t)0) - 1))
257 param_act(P_BAD_VALUE, "owner", opt, s);
258 if (*end != '\0')
259 param_act(P_BAD_VALUE, "owner", opt, s);
260}
261
Jan Engelhardt5c5cd882008-01-20 13:21:38 +0000262static int owner_mt_parse(int c, char **argv, int invert, unsigned int *flags,
263 const void *entry, struct xt_entry_match **match)
264{
265 struct xt_owner_match_info *info = (void *)(*match)->data;
266 struct passwd *pwd;
267 struct group *grp;
Jan Engelhardtca1da702008-01-29 13:38:05 +0000268 unsigned int from, to;
Jan Engelhardt5c5cd882008-01-20 13:21:38 +0000269
270 switch (c) {
271 case 'u':
272 param_act(P_ONLY_ONCE, "owner", "--uid-owner",
273 *flags & FLAG_UID_OWNER);
274 if ((pwd = getpwnam(optarg)) != NULL)
Jan Engelhardtca1da702008-01-29 13:38:05 +0000275 from = to = pwd->pw_uid;
276 else
277 owner_parse_range(optarg, &from, &to, "--uid-owner");
Jan Engelhardt5c5cd882008-01-20 13:21:38 +0000278 if (invert)
279 info->invert |= XT_OWNER_UID;
Jan Engelhardtca1da702008-01-29 13:38:05 +0000280 info->match |= XT_OWNER_UID;
281 info->uid_min = from;
282 info->uid_max = to;
283 *flags |= FLAG_UID_OWNER;
Jan Engelhardt5c5cd882008-01-20 13:21:38 +0000284 return true;
285
286 case 'g':
287 param_act(P_ONLY_ONCE, "owner", "--gid-owner",
288 *flags & FLAG_GID_OWNER);
289 if ((grp = getgrnam(optarg)) != NULL)
Jan Engelhardtca1da702008-01-29 13:38:05 +0000290 from = to = grp->gr_gid;
291 else
292 owner_parse_range(optarg, &from, &to, "--gid-owner");
Jan Engelhardt5c5cd882008-01-20 13:21:38 +0000293 if (invert)
294 info->invert |= XT_OWNER_GID;
Jan Engelhardtca1da702008-01-29 13:38:05 +0000295 info->match |= XT_OWNER_GID;
296 info->gid_min = from;
297 info->gid_max = to;
Jan Engelhardt5c5cd882008-01-20 13:21:38 +0000298 *flags |= FLAG_GID_OWNER;
299 return true;
300
301 case 'k':
302 param_act(P_ONLY_ONCE, "owner", "--socket-exists",
303 *flags & FLAG_SOCKET_EXISTS);
304 if (invert)
305 info->invert |= XT_OWNER_SOCKET;
306 info->match |= XT_OWNER_SOCKET;
307 *flags |= FLAG_SOCKET_EXISTS;
308 return true;
309
310 }
311 return false;
312}
313
314static void owner_mt_check(unsigned int flags)
315{
316 if (flags == 0)
317 exit_error(PARAMETER_PROBLEM, "owner: At least one of "
318 "--uid-owner, --gid-owner or --socket-exists "
319 "is required");
320}
321
322static void
323owner_mt_print_item_v0(const struct ipt_owner_info *info, const char *label,
324 u_int8_t flag, bool numeric)
325{
326 if (!(info->match & flag))
327 return;
328 if (info->invert & flag)
329 printf("! ");
330 printf(label);
331
332 switch (info->match & flag) {
333 case IPT_OWNER_UID:
334 if (!numeric) {
335 struct passwd *pwd = getpwuid(info->uid);
336
337 if (pwd != NULL && pwd->pw_name != NULL) {
338 printf("%s ", pwd->pw_name);
339 break;
340 }
341 }
342 printf("%u ", (unsigned int)info->uid);
343 break;
344
345 case IPT_OWNER_GID:
346 if (!numeric) {
347 struct group *grp = getgrgid(info->gid);
348
349 if (grp != NULL && grp->gr_name != NULL) {
350 printf("%s ", grp->gr_name);
351 break;
352 }
353 }
354 printf("%u ", (unsigned int)info->gid);
355 break;
356
357 case IPT_OWNER_PID:
358 printf("%u ", (unsigned int)info->pid);
359 break;
360
361 case IPT_OWNER_SID:
362 printf("%u ", (unsigned int)info->sid);
363 break;
364
365#ifdef IPT_OWNER_COMM
366 case IPT_OWNER_COMM:
367 printf("%.*s ", (int)sizeof(info->comm), info->comm);
368 break;
369#endif
370 }
371}
372
373static void
374owner_mt6_print_item_v0(const struct ip6t_owner_info *info, const char *label,
375 u_int8_t flag, bool numeric)
376{
377 if (!(info->match & flag))
378 return;
379 if (info->invert & flag)
380 printf("! ");
381 printf(label);
382
383 switch (info->match & flag) {
384 case IP6T_OWNER_UID:
385 if (!numeric) {
386 struct passwd *pwd = getpwuid(info->uid);
387
388 if (pwd != NULL && pwd->pw_name != NULL) {
389 printf("%s ", pwd->pw_name);
390 break;
391 }
392 }
393 printf("%u ", (unsigned int)info->uid);
394 break;
395
396 case IP6T_OWNER_GID:
397 if (!numeric) {
398 struct group *grp = getgrgid(info->gid);
399
400 if (grp != NULL && grp->gr_name != NULL) {
401 printf("%s ", grp->gr_name);
402 break;
403 }
404 }
405 printf("%u ", (unsigned int)info->gid);
406 break;
407
408 case IP6T_OWNER_PID:
409 printf("%u ", (unsigned int)info->pid);
410 break;
411
412 case IP6T_OWNER_SID:
413 printf("%u ", (unsigned int)info->sid);
414 break;
415 }
416}
417
418static void
419owner_mt_print_item(const struct xt_owner_match_info *info, const char *label,
420 u_int8_t flag, bool numeric)
421{
422 if (!(info->match & flag))
423 return;
424 if (info->invert & flag)
425 printf("! ");
426 printf(label);
427
428 switch (info->match & flag) {
429 case XT_OWNER_UID:
Jan Engelhardtca1da702008-01-29 13:38:05 +0000430 if (info->uid_min != info->uid_max) {
431 printf("%u-%u ", (unsigned int)info->uid_min,
432 (unsigned int)info->uid_max);
433 break;
434 } else if (!numeric) {
435 const struct passwd *pwd = getpwuid(info->uid_min);
Jan Engelhardt5c5cd882008-01-20 13:21:38 +0000436
437 if (pwd != NULL && pwd->pw_name != NULL) {
438 printf("%s ", pwd->pw_name);
439 break;
440 }
441 }
Jan Engelhardtca1da702008-01-29 13:38:05 +0000442 printf("%u ", (unsigned int)info->uid_min);
Jan Engelhardt5c5cd882008-01-20 13:21:38 +0000443 break;
444
445 case XT_OWNER_GID:
Jan Engelhardtca1da702008-01-29 13:38:05 +0000446 if (info->gid_min != info->gid_max) {
447 printf("%u-%u ", (unsigned int)info->gid_min,
448 (unsigned int)info->gid_max);
449 break;
450 } else if (!numeric) {
451 const struct group *grp = getgrgid(info->gid_min);
Jan Engelhardt5c5cd882008-01-20 13:21:38 +0000452
453 if (grp != NULL && grp->gr_name != NULL) {
454 printf("%s ", grp->gr_name);
455 break;
456 }
457 }
Jan Engelhardtca1da702008-01-29 13:38:05 +0000458 printf("%u ", (unsigned int)info->gid_min);
Jan Engelhardt5c5cd882008-01-20 13:21:38 +0000459 break;
460 }
461}
462
463static void
464owner_mt_print_v0(const void *ip, const struct xt_entry_match *match,
465 int numeric)
466{
467 const struct ipt_owner_info *info = (void *)match->data;
468
469 owner_mt_print_item_v0(info, "owner UID match ", IPT_OWNER_UID, numeric);
470 owner_mt_print_item_v0(info, "owner GID match ", IPT_OWNER_GID, numeric);
471 owner_mt_print_item_v0(info, "owner PID match ", IPT_OWNER_PID, numeric);
472 owner_mt_print_item_v0(info, "owner SID match ", IPT_OWNER_SID, numeric);
473#ifdef IPT_OWNER_COMM
474 owner_mt_print_item_v0(info, "owner CMD match ", IPT_OWNER_COMM, numeric);
475#endif
476}
477
478static void
479owner_mt6_print_v0(const void *ip, const struct xt_entry_match *match,
480 int numeric)
481{
482 const struct ip6t_owner_info *info = (void *)match->data;
483
484 owner_mt6_print_item_v0(info, "owner UID match ", IPT_OWNER_UID, numeric);
485 owner_mt6_print_item_v0(info, "owner GID match ", IPT_OWNER_GID, numeric);
486 owner_mt6_print_item_v0(info, "owner PID match ", IPT_OWNER_PID, numeric);
487 owner_mt6_print_item_v0(info, "owner SID match ", IPT_OWNER_SID, numeric);
488}
489
490static void owner_mt_print(const void *ip, const struct xt_entry_match *match,
491 int numeric)
492{
493 const struct xt_owner_match_info *info = (void *)match->data;
494
495 owner_mt_print_item(info, "owner socket exists ", XT_OWNER_SOCKET, numeric);
496 owner_mt_print_item(info, "owner UID match ", XT_OWNER_UID, numeric);
497 owner_mt_print_item(info, "owner GID match ", XT_OWNER_GID, numeric);
498}
499
500static void
501owner_mt_save_v0(const void *ip, const struct xt_entry_match *match)
502{
503 const struct ipt_owner_info *info = (void *)match->data;
504
505 owner_mt_print_item_v0(info, "owner UID match ", IPT_OWNER_UID, true);
506 owner_mt_print_item_v0(info, "owner GID match ", IPT_OWNER_GID, true);
507 owner_mt_print_item_v0(info, "owner PID match ", IPT_OWNER_PID, true);
508 owner_mt_print_item_v0(info, "owner SID match ", IPT_OWNER_SID, true);
509#ifdef IPT_OWNER_COMM
510 owner_mt_print_item_v0(info, "owner CMD match ", IPT_OWNER_COMM, true);
511#endif
512}
513
514static void
515owner_mt6_save_v0(const void *ip, const struct xt_entry_match *match)
516{
517 const struct ip6t_owner_info *info = (void *)match->data;
518
519 owner_mt6_print_item_v0(info, "owner UID match ", IPT_OWNER_UID, true);
520 owner_mt6_print_item_v0(info, "owner GID match ", IPT_OWNER_GID, true);
521 owner_mt6_print_item_v0(info, "owner PID match ", IPT_OWNER_PID, true);
522 owner_mt6_print_item_v0(info, "owner SID match ", IPT_OWNER_SID, true);
523}
524
525static void owner_mt_save(const void *ip, const struct xt_entry_match *match)
526{
527 const struct xt_owner_match_info *info = (void *)match->data;
528
529 owner_mt_print_item(info, "--socket-exists ", XT_OWNER_SOCKET, false);
530 owner_mt_print_item(info, "--uid-owner", XT_OWNER_UID, false);
531 owner_mt_print_item(info, "--gid-owner", XT_OWNER_GID, false);
532}
533
534static struct xtables_match owner_mt_reg_v0 = {
535 .version = IPTABLES_VERSION,
536 .name = "owner",
537 .revision = 0,
538 .family = AF_INET,
539 .size = XT_ALIGN(sizeof(struct ipt_owner_info)),
540 .userspacesize = XT_ALIGN(sizeof(struct ipt_owner_info)),
541 .help = owner_mt_help_v0,
542 .parse = owner_mt_parse_v0,
543 .final_check = owner_mt_check,
544 .print = owner_mt_print_v0,
545 .save = owner_mt_save_v0,
546 .extra_opts = owner_mt_opts_v0,
547};
548
549static struct xtables_match owner_mt6_reg_v0 = {
550 .version = IPTABLES_VERSION,
551 .name = "owner",
552 .revision = 0,
553 .family = AF_INET6,
554 .size = XT_ALIGN(sizeof(struct ip6t_owner_info)),
555 .userspacesize = XT_ALIGN(sizeof(struct ip6t_owner_info)),
556 .help = owner_mt6_help_v0,
557 .parse = owner_mt6_parse_v0,
558 .final_check = owner_mt_check,
559 .print = owner_mt6_print_v0,
560 .save = owner_mt6_save_v0,
561 .extra_opts = owner_mt6_opts_v0,
562};
563
564static struct xtables_match owner_mt_reg = {
565 .version = IPTABLES_VERSION,
566 .name = "owner",
567 .revision = 1,
568 .family = AF_INET,
569 .size = XT_ALIGN(sizeof(struct xt_owner_match_info)),
570 .userspacesize = XT_ALIGN(sizeof(struct xt_owner_match_info)),
571 .help = owner_mt_help,
572 .parse = owner_mt_parse,
573 .final_check = owner_mt_check,
574 .print = owner_mt_print,
575 .save = owner_mt_save,
576 .extra_opts = owner_mt_opts,
577};
578
579static struct xtables_match owner_mt6_reg = {
580 .version = IPTABLES_VERSION,
581 .name = "owner",
582 .revision = 1,
583 .family = AF_INET6,
584 .size = XT_ALIGN(sizeof(struct xt_owner_match_info)),
585 .userspacesize = XT_ALIGN(sizeof(struct xt_owner_match_info)),
586 .help = owner_mt_help,
587 .parse = owner_mt_parse,
588 .final_check = owner_mt_check,
589 .print = owner_mt_print,
590 .save = owner_mt_save,
591 .extra_opts = owner_mt_opts,
592};
593
594void _init(void)
595{
596 xtables_register_match(&owner_mt_reg_v0);
597 xtables_register_match(&owner_mt6_reg_v0);
598 xtables_register_match(&owner_mt_reg);
599 xtables_register_match(&owner_mt6_reg);
600}