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