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