manpages: do not include v4-only modules in ip6tables manpage
[jleu-iptables.git] / extensions / libxt_owner.c
blobd27b3ae5768634857d7084f536002607bf0edfe5
1 /*
2 * libxt_owner - iptables addon for xt_owner
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 #include <limits.h>
17 #include <xtables.h>
18 #include <linux/netfilter/xt_owner.h>
19 #include <linux/netfilter_ipv4/ipt_owner.h>
20 #include <linux/netfilter_ipv6/ip6t_owner.h>
23 * Note: "UINT32_MAX - 1" is used in the code because -1 is a reserved
24 * UID/GID value anyway.
27 enum {
28 FLAG_UID_OWNER = 1 << 0,
29 FLAG_GID_OWNER = 1 << 1,
30 FLAG_SOCKET_EXISTS = 1 << 2,
31 FLAG_PID_OWNER = 1 << 3,
32 FLAG_SID_OWNER = 1 << 4,
33 FLAG_COMM = 1 << 5,
36 static void owner_mt_help_v0(void)
38 #ifdef IPT_OWNER_COMM
39 printf(
40 "owner match options:\n"
41 "[!] --uid-owner userid Match local UID\n"
42 "[!] --gid-owner groupid Match local GID\n"
43 "[!] --pid-owner processid Match local PID\n"
44 "[!] --sid-owner sessionid Match local SID\n"
45 "[!] --cmd-owner name Match local command name\n"
46 "NOTE: PID, SID and command matching are broken on SMP\n");
47 #else
48 printf(
49 "owner match options:\n"
50 "[!] --uid-owner userid Match local UID\n"
51 "[!] --gid-owner groupid Match local GID\n"
52 "[!] --pid-owner processid Match local PID\n"
53 "[!] --sid-owner sessionid Match local SID\n"
54 "NOTE: PID and SID matching are broken on SMP\n");
55 #endif /* IPT_OWNER_COMM */
58 static void owner_mt6_help_v0(void)
60 printf(
61 "owner match options:\n"
62 "[!] --uid-owner userid Match local UID\n"
63 "[!] --gid-owner groupid Match local GID\n"
64 "[!] --pid-owner processid Match local PID\n"
65 "[!] --sid-owner sessionid Match local SID\n"
66 "NOTE: PID and SID matching are broken on SMP\n");
69 static void owner_mt_help(void)
71 printf(
72 "owner match options:\n"
73 "[!] --uid-owner userid[-userid] Match local UID\n"
74 "[!] --gid-owner groupid[-groupid] Match local GID\n"
75 "[!] --socket-exists Match if socket exists\n");
78 static const struct option owner_mt_opts_v0[] = {
79 {.name = "uid-owner", .has_arg = true, .val = 'u'},
80 {.name = "gid-owner", .has_arg = true, .val = 'g'},
81 {.name = "pid-owner", .has_arg = true, .val = 'p'},
82 {.name = "sid-owner", .has_arg = true, .val = 's'},
83 #ifdef IPT_OWNER_COMM
84 {.name = "cmd-owner", .has_arg = true, .val = 'c'},
85 #endif
86 { .name = NULL }
89 static const struct option owner_mt6_opts_v0[] = {
90 {.name = "uid-owner", .has_arg = true, .val = 'u'},
91 {.name = "gid-owner", .has_arg = true, .val = 'g'},
92 {.name = "pid-owner", .has_arg = true, .val = 'p'},
93 {.name = "sid-owner", .has_arg = true, .val = 's'},
94 { .name = NULL }
97 static const struct option owner_mt_opts[] = {
98 {.name = "uid-owner", .has_arg = true, .val = 'u'},
99 {.name = "gid-owner", .has_arg = true, .val = 'g'},
100 {.name = "socket-exists", .has_arg = false, .val = 'k'},
101 { .name = NULL }
104 static int
105 owner_mt_parse_v0(int c, char **argv, int invert, unsigned int *flags,
106 const void *entry, struct xt_entry_match **match)
108 struct ipt_owner_info *info = (void *)(*match)->data;
109 struct passwd *pwd;
110 struct group *grp;
111 unsigned int id;
113 switch (c) {
114 case 'u':
115 xtables_param_act(XTF_ONLY_ONCE, "owner", "--uid-owner", *flags & FLAG_UID_OWNER);
116 if ((pwd = getpwnam(optarg)) != NULL)
117 id = pwd->pw_uid;
118 else if (!xtables_strtoui(optarg, NULL, &id, 0, UINT32_MAX - 1))
119 xtables_param_act(XTF_BAD_VALUE, "owner", "--uid-owner", optarg);
120 if (invert)
121 info->invert |= IPT_OWNER_UID;
122 info->match |= IPT_OWNER_UID;
123 info->uid = id;
124 *flags |= FLAG_UID_OWNER;
125 return true;
127 case 'g':
128 xtables_param_act(XTF_ONLY_ONCE, "owner", "--gid-owner", *flags & FLAG_GID_OWNER);
129 if ((grp = getgrnam(optarg)) != NULL)
130 id = grp->gr_gid;
131 else if (!xtables_strtoui(optarg, NULL, &id, 0, UINT32_MAX - 1))
132 xtables_param_act(XTF_BAD_VALUE, "owner", "--gid-owner", optarg);
133 if (invert)
134 info->invert |= IPT_OWNER_GID;
135 info->match |= IPT_OWNER_GID;
136 info->gid = id;
137 *flags |= FLAG_GID_OWNER;
138 return true;
140 case 'p':
141 xtables_param_act(XTF_ONLY_ONCE, "owner", "--pid-owner", *flags & FLAG_PID_OWNER);
142 if (!xtables_strtoui(optarg, NULL, &id, 0, INT_MAX))
143 xtables_param_act(XTF_BAD_VALUE, "owner", "--pid-owner", optarg);
144 if (invert)
145 info->invert |= IPT_OWNER_PID;
146 info->match |= IPT_OWNER_PID;
147 info->pid = id;
148 *flags |= FLAG_PID_OWNER;
149 return true;
151 case 's':
152 xtables_param_act(XTF_ONLY_ONCE, "owner", "--sid-owner", *flags & FLAG_SID_OWNER);
153 if (!xtables_strtoui(optarg, NULL, &id, 0, INT_MAX))
154 xtables_param_act(XTF_BAD_VALUE, "owner", "--sid-value", optarg);
155 if (invert)
156 info->invert |= IPT_OWNER_SID;
157 info->match |= IPT_OWNER_SID;
158 info->sid = id;
159 *flags |= FLAG_SID_OWNER;
160 return true;
162 #ifdef IPT_OWNER_COMM
163 case 'c':
164 xtables_param_act(XTF_ONLY_ONCE, "owner", "--cmd-owner", *flags & FLAG_COMM);
165 if (strlen(optarg) > sizeof(info->comm))
166 xtables_error(PARAMETER_PROBLEM, "owner match: command "
167 "\"%s\" too long, max. %zu characters",
168 optarg, sizeof(info->comm));
170 info->comm[sizeof(info->comm)-1] = '\0';
171 strncpy(info->comm, optarg, sizeof(info->comm));
173 if (invert)
174 info->invert |= IPT_OWNER_COMM;
175 info->match |= IPT_OWNER_COMM;
176 *flags |= FLAG_COMM;
177 return true;
178 #endif
180 return false;
183 static int
184 owner_mt6_parse_v0(int c, char **argv, int invert, unsigned int *flags,
185 const void *entry, struct xt_entry_match **match)
187 struct ip6t_owner_info *info = (void *)(*match)->data;
188 struct passwd *pwd;
189 struct group *grp;
190 unsigned int id;
192 switch (c) {
193 case 'u':
194 xtables_param_act(XTF_ONLY_ONCE, "owner", "--uid-owner",
195 *flags & FLAG_UID_OWNER);
196 if ((pwd = getpwnam(optarg)) != NULL)
197 id = pwd->pw_uid;
198 else if (!xtables_strtoui(optarg, NULL, &id, 0, UINT32_MAX - 1))
199 xtables_param_act(XTF_BAD_VALUE, "owner", "--uid-owner", optarg);
200 if (invert)
201 info->invert |= IP6T_OWNER_UID;
202 info->match |= IP6T_OWNER_UID;
203 info->uid = id;
204 *flags |= FLAG_UID_OWNER;
205 return true;
207 case 'g':
208 xtables_param_act(XTF_ONLY_ONCE, "owner", "--gid-owner",
209 *flags & FLAG_GID_OWNER);
210 if ((grp = getgrnam(optarg)) != NULL)
211 id = grp->gr_gid;
212 else if (!xtables_strtoui(optarg, NULL, &id, 0, UINT32_MAX - 1))
213 xtables_param_act(XTF_BAD_VALUE, "owner", "--gid-owner", optarg);
214 if (invert)
215 info->invert |= IP6T_OWNER_GID;
216 info->match |= IP6T_OWNER_GID;
217 info->gid = id;
218 *flags |= FLAG_GID_OWNER;
219 return true;
221 case 'p':
222 xtables_param_act(XTF_ONLY_ONCE, "owner", "--pid-owner",
223 *flags & FLAG_PID_OWNER);
224 if (!xtables_strtoui(optarg, NULL, &id, 0, INT_MAX))
225 xtables_param_act(XTF_BAD_VALUE, "owner", "--pid-owner", optarg);
226 if (invert)
227 info->invert |= IP6T_OWNER_PID;
228 info->match |= IP6T_OWNER_PID;
229 info->pid = id;
230 *flags |= FLAG_PID_OWNER;
231 return true;
233 case 's':
234 xtables_param_act(XTF_ONLY_ONCE, "owner", "--sid-owner",
235 *flags & FLAG_SID_OWNER);
236 if (!xtables_strtoui(optarg, NULL, &id, 0, INT_MAX))
237 xtables_param_act(XTF_BAD_VALUE, "owner", "--sid-owner", optarg);
238 if (invert)
239 info->invert |= IP6T_OWNER_SID;
240 info->match |= IP6T_OWNER_SID;
241 info->sid = id;
242 *flags |= FLAG_SID_OWNER;
243 return true;
245 return false;
248 static void owner_parse_range(const char *s, unsigned int *from,
249 unsigned int *to, const char *opt)
251 char *end;
253 /* -1 is reversed, so the max is one less than that. */
254 if (!xtables_strtoui(s, &end, from, 0, UINT32_MAX - 1))
255 xtables_param_act(XTF_BAD_VALUE, "owner", opt, s);
256 *to = *from;
257 if (*end == '-' || *end == ':')
258 if (!xtables_strtoui(end + 1, &end, to, 0, UINT32_MAX - 1))
259 xtables_param_act(XTF_BAD_VALUE, "owner", opt, s);
260 if (*end != '\0')
261 xtables_param_act(XTF_BAD_VALUE, "owner", opt, s);
264 static int owner_mt_parse(int c, char **argv, int invert, unsigned int *flags,
265 const void *entry, struct xt_entry_match **match)
267 struct xt_owner_match_info *info = (void *)(*match)->data;
268 struct passwd *pwd;
269 struct group *grp;
270 unsigned int from, to;
272 switch (c) {
273 case 'u':
274 xtables_param_act(XTF_ONLY_ONCE, "owner", "--uid-owner",
275 *flags & FLAG_UID_OWNER);
276 if ((pwd = getpwnam(optarg)) != NULL)
277 from = to = pwd->pw_uid;
278 else
279 owner_parse_range(optarg, &from, &to, "--uid-owner");
280 if (invert)
281 info->invert |= XT_OWNER_UID;
282 info->match |= XT_OWNER_UID;
283 info->uid_min = from;
284 info->uid_max = to;
285 *flags |= FLAG_UID_OWNER;
286 return true;
288 case 'g':
289 xtables_param_act(XTF_ONLY_ONCE, "owner", "--gid-owner",
290 *flags & FLAG_GID_OWNER);
291 if ((grp = getgrnam(optarg)) != NULL)
292 from = to = grp->gr_gid;
293 else
294 owner_parse_range(optarg, &from, &to, "--gid-owner");
295 if (invert)
296 info->invert |= XT_OWNER_GID;
297 info->match |= XT_OWNER_GID;
298 info->gid_min = from;
299 info->gid_max = to;
300 *flags |= FLAG_GID_OWNER;
301 return true;
303 case 'k':
304 xtables_param_act(XTF_ONLY_ONCE, "owner", "--socket-exists",
305 *flags & FLAG_SOCKET_EXISTS);
306 if (invert)
307 info->invert |= XT_OWNER_SOCKET;
308 info->match |= XT_OWNER_SOCKET;
309 *flags |= FLAG_SOCKET_EXISTS;
310 return true;
313 return false;
316 static void owner_mt_check(unsigned int flags)
318 if (flags == 0)
319 xtables_error(PARAMETER_PROBLEM, "owner: At least one of "
320 "--uid-owner, --gid-owner or --socket-exists "
321 "is required");
324 static void
325 owner_mt_print_item_v0(const struct ipt_owner_info *info, const char *label,
326 u_int8_t flag, bool numeric)
328 if (!(info->match & flag))
329 return;
330 if (info->invert & flag)
331 printf("! ");
332 printf("%s ", label);
334 switch (info->match & flag) {
335 case IPT_OWNER_UID:
336 if (!numeric) {
337 struct passwd *pwd = getpwuid(info->uid);
339 if (pwd != NULL && pwd->pw_name != NULL) {
340 printf("%s ", pwd->pw_name);
341 break;
344 printf("%u ", (unsigned int)info->uid);
345 break;
347 case IPT_OWNER_GID:
348 if (!numeric) {
349 struct group *grp = getgrgid(info->gid);
351 if (grp != NULL && grp->gr_name != NULL) {
352 printf("%s ", grp->gr_name);
353 break;
356 printf("%u ", (unsigned int)info->gid);
357 break;
359 case IPT_OWNER_PID:
360 printf("%u ", (unsigned int)info->pid);
361 break;
363 case IPT_OWNER_SID:
364 printf("%u ", (unsigned int)info->sid);
365 break;
367 #ifdef IPT_OWNER_COMM
368 case IPT_OWNER_COMM:
369 printf("%.*s ", (int)sizeof(info->comm), info->comm);
370 break;
371 #endif
375 static void
376 owner_mt6_print_item_v0(const struct ip6t_owner_info *info, const char *label,
377 u_int8_t flag, bool numeric)
379 if (!(info->match & flag))
380 return;
381 if (info->invert & flag)
382 printf("! ");
383 printf("%s ", label);
385 switch (info->match & flag) {
386 case IP6T_OWNER_UID:
387 if (!numeric) {
388 struct passwd *pwd = getpwuid(info->uid);
390 if (pwd != NULL && pwd->pw_name != NULL) {
391 printf("%s ", pwd->pw_name);
392 break;
395 printf("%u ", (unsigned int)info->uid);
396 break;
398 case IP6T_OWNER_GID:
399 if (!numeric) {
400 struct group *grp = getgrgid(info->gid);
402 if (grp != NULL && grp->gr_name != NULL) {
403 printf("%s ", grp->gr_name);
404 break;
407 printf("%u ", (unsigned int)info->gid);
408 break;
410 case IP6T_OWNER_PID:
411 printf("%u ", (unsigned int)info->pid);
412 break;
414 case IP6T_OWNER_SID:
415 printf("%u ", (unsigned int)info->sid);
416 break;
420 static void
421 owner_mt_print_item(const struct xt_owner_match_info *info, const char *label,
422 u_int8_t flag, bool numeric)
424 if (!(info->match & flag))
425 return;
426 if (info->invert & flag)
427 printf("! ");
428 printf("%s ", label);
430 switch (info->match & flag) {
431 case XT_OWNER_UID:
432 if (info->uid_min != info->uid_max) {
433 printf("%u-%u ", (unsigned int)info->uid_min,
434 (unsigned int)info->uid_max);
435 break;
436 } else if (!numeric) {
437 const struct passwd *pwd = getpwuid(info->uid_min);
439 if (pwd != NULL && pwd->pw_name != NULL) {
440 printf("%s ", pwd->pw_name);
441 break;
444 printf("%u ", (unsigned int)info->uid_min);
445 break;
447 case XT_OWNER_GID:
448 if (info->gid_min != info->gid_max) {
449 printf("%u-%u ", (unsigned int)info->gid_min,
450 (unsigned int)info->gid_max);
451 break;
452 } else if (!numeric) {
453 const struct group *grp = getgrgid(info->gid_min);
455 if (grp != NULL && grp->gr_name != NULL) {
456 printf("%s ", grp->gr_name);
457 break;
460 printf("%u ", (unsigned int)info->gid_min);
461 break;
465 static void
466 owner_mt_print_v0(const void *ip, const struct xt_entry_match *match,
467 int numeric)
469 const struct ipt_owner_info *info = (void *)match->data;
471 owner_mt_print_item_v0(info, "owner UID match", IPT_OWNER_UID, numeric);
472 owner_mt_print_item_v0(info, "owner GID match", IPT_OWNER_GID, numeric);
473 owner_mt_print_item_v0(info, "owner PID match", IPT_OWNER_PID, numeric);
474 owner_mt_print_item_v0(info, "owner SID match", IPT_OWNER_SID, numeric);
475 #ifdef IPT_OWNER_COMM
476 owner_mt_print_item_v0(info, "owner CMD match", IPT_OWNER_COMM, numeric);
477 #endif
480 static void
481 owner_mt6_print_v0(const void *ip, const struct xt_entry_match *match,
482 int numeric)
484 const struct ip6t_owner_info *info = (void *)match->data;
486 owner_mt6_print_item_v0(info, "owner UID match", IPT_OWNER_UID, numeric);
487 owner_mt6_print_item_v0(info, "owner GID match", IPT_OWNER_GID, numeric);
488 owner_mt6_print_item_v0(info, "owner PID match", IPT_OWNER_PID, numeric);
489 owner_mt6_print_item_v0(info, "owner SID match", IPT_OWNER_SID, numeric);
492 static void owner_mt_print(const void *ip, const struct xt_entry_match *match,
493 int numeric)
495 const struct xt_owner_match_info *info = (void *)match->data;
497 owner_mt_print_item(info, "owner socket exists", XT_OWNER_SOCKET, numeric);
498 owner_mt_print_item(info, "owner UID match", XT_OWNER_UID, numeric);
499 owner_mt_print_item(info, "owner GID match", XT_OWNER_GID, numeric);
502 static void
503 owner_mt_save_v0(const void *ip, const struct xt_entry_match *match)
505 const struct ipt_owner_info *info = (void *)match->data;
507 owner_mt_print_item_v0(info, "--uid-owner", IPT_OWNER_UID, true);
508 owner_mt_print_item_v0(info, "--gid-owner", IPT_OWNER_GID, true);
509 owner_mt_print_item_v0(info, "--pid-owner", IPT_OWNER_PID, true);
510 owner_mt_print_item_v0(info, "--sid-owner", IPT_OWNER_SID, true);
511 #ifdef IPT_OWNER_COMM
512 owner_mt_print_item_v0(info, "--cmd-owner", IPT_OWNER_COMM, true);
513 #endif
516 static void
517 owner_mt6_save_v0(const void *ip, const struct xt_entry_match *match)
519 const struct ip6t_owner_info *info = (void *)match->data;
521 owner_mt6_print_item_v0(info, "--uid-owner", IPT_OWNER_UID, true);
522 owner_mt6_print_item_v0(info, "--gid-owner", IPT_OWNER_GID, true);
523 owner_mt6_print_item_v0(info, "--pid-owner", IPT_OWNER_PID, true);
524 owner_mt6_print_item_v0(info, "--sid-owner", IPT_OWNER_SID, true);
527 static void owner_mt_save(const void *ip, const struct xt_entry_match *match)
529 const struct xt_owner_match_info *info = (void *)match->data;
531 owner_mt_print_item(info, "--socket-exists", XT_OWNER_SOCKET, false);
532 owner_mt_print_item(info, "--uid-owner", XT_OWNER_UID, false);
533 owner_mt_print_item(info, "--gid-owner", XT_OWNER_GID, false);
536 static struct xtables_match owner_mt_reg_v0 = {
537 .version = XTABLES_VERSION,
538 .name = "owner",
539 .revision = 0,
540 .family = NFPROTO_IPV4,
541 .size = XT_ALIGN(sizeof(struct ipt_owner_info)),
542 .userspacesize = XT_ALIGN(sizeof(struct ipt_owner_info)),
543 .help = owner_mt_help_v0,
544 .parse = owner_mt_parse_v0,
545 .final_check = owner_mt_check,
546 .print = owner_mt_print_v0,
547 .save = owner_mt_save_v0,
548 .extra_opts = owner_mt_opts_v0,
551 static struct xtables_match owner_mt6_reg_v0 = {
552 .version = XTABLES_VERSION,
553 .name = "owner",
554 .revision = 0,
555 .family = NFPROTO_IPV6,
556 .size = XT_ALIGN(sizeof(struct ip6t_owner_info)),
557 .userspacesize = XT_ALIGN(sizeof(struct ip6t_owner_info)),
558 .help = owner_mt6_help_v0,
559 .parse = owner_mt6_parse_v0,
560 .final_check = owner_mt_check,
561 .print = owner_mt6_print_v0,
562 .save = owner_mt6_save_v0,
563 .extra_opts = owner_mt6_opts_v0,
566 static struct xtables_match owner_mt_reg = {
567 .version = XTABLES_VERSION,
568 .name = "owner",
569 .revision = 1,
570 .family = NFPROTO_IPV4,
571 .size = XT_ALIGN(sizeof(struct xt_owner_match_info)),
572 .userspacesize = XT_ALIGN(sizeof(struct xt_owner_match_info)),
573 .help = owner_mt_help,
574 .parse = owner_mt_parse,
575 .final_check = owner_mt_check,
576 .print = owner_mt_print,
577 .save = owner_mt_save,
578 .extra_opts = owner_mt_opts,
581 static struct xtables_match owner_mt6_reg = {
582 .version = XTABLES_VERSION,
583 .name = "owner",
584 .revision = 1,
585 .family = NFPROTO_IPV6,
586 .size = XT_ALIGN(sizeof(struct xt_owner_match_info)),
587 .userspacesize = XT_ALIGN(sizeof(struct xt_owner_match_info)),
588 .help = owner_mt_help,
589 .parse = owner_mt_parse,
590 .final_check = owner_mt_check,
591 .print = owner_mt_print,
592 .save = owner_mt_save,
593 .extra_opts = owner_mt_opts,
596 void _init(void)
598 xtables_register_match(&owner_mt_reg_v0);
599 xtables_register_match(&owner_mt6_reg_v0);
600 xtables_register_match(&owner_mt_reg);
601 xtables_register_match(&owner_mt6_reg);