| /* |
| * libxt_owner - iptables addon for xt_owner |
| * |
| * Copyright © CC Computer Consultants GmbH, 2007 - 2008 |
| * Jan Engelhardt <jengelh@computergmbh.de> |
| */ |
| #include <getopt.h> |
| #include <grp.h> |
| #include <netdb.h> |
| #include <pwd.h> |
| #include <stdbool.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <limits.h> |
| |
| #include <xtables.h> |
| #include <linux/netfilter/xt_owner.h> |
| #include <linux/netfilter_ipv4/ipt_owner.h> |
| #include <linux/netfilter_ipv6/ip6t_owner.h> |
| |
| /* |
| * Note: "UINT32_MAX - 1" is used in the code because -1 is a reserved |
| * UID/GID value anyway. |
| */ |
| |
| enum { |
| FLAG_UID_OWNER = 1 << 0, |
| FLAG_GID_OWNER = 1 << 1, |
| FLAG_SOCKET_EXISTS = 1 << 2, |
| FLAG_PID_OWNER = 1 << 3, |
| FLAG_SID_OWNER = 1 << 4, |
| FLAG_COMM = 1 << 5, |
| }; |
| |
| static void owner_mt_help_v0(void) |
| { |
| #ifdef IPT_OWNER_COMM |
| printf( |
| "owner match options:\n" |
| "[!] --uid-owner userid Match local UID\n" |
| "[!] --gid-owner groupid Match local GID\n" |
| "[!] --pid-owner processid Match local PID\n" |
| "[!] --sid-owner sessionid Match local SID\n" |
| "[!] --cmd-owner name Match local command name\n" |
| "NOTE: PID, SID and command matching are broken on SMP\n"); |
| #else |
| printf( |
| "owner match options:\n" |
| "[!] --uid-owner userid Match local UID\n" |
| "[!] --gid-owner groupid Match local GID\n" |
| "[!] --pid-owner processid Match local PID\n" |
| "[!] --sid-owner sessionid Match local SID\n" |
| "NOTE: PID and SID matching are broken on SMP\n"); |
| #endif /* IPT_OWNER_COMM */ |
| } |
| |
| static void owner_mt6_help_v0(void) |
| { |
| printf( |
| "owner match options:\n" |
| "[!] --uid-owner userid Match local UID\n" |
| "[!] --gid-owner groupid Match local GID\n" |
| "[!] --pid-owner processid Match local PID\n" |
| "[!] --sid-owner sessionid Match local SID\n" |
| "NOTE: PID and SID matching are broken on SMP\n"); |
| } |
| |
| static void owner_mt_help(void) |
| { |
| printf( |
| "owner match options:\n" |
| "[!] --uid-owner userid[-userid] Match local UID\n" |
| "[!] --gid-owner groupid[-groupid] Match local GID\n" |
| "[!] --socket-exists Match if socket exists\n"); |
| } |
| |
| static const struct option owner_mt_opts_v0[] = { |
| {.name = "uid-owner", .has_arg = true, .val = 'u'}, |
| {.name = "gid-owner", .has_arg = true, .val = 'g'}, |
| {.name = "pid-owner", .has_arg = true, .val = 'p'}, |
| {.name = "sid-owner", .has_arg = true, .val = 's'}, |
| #ifdef IPT_OWNER_COMM |
| {.name = "cmd-owner", .has_arg = true, .val = 'c'}, |
| #endif |
| { .name = NULL } |
| }; |
| |
| static const struct option owner_mt6_opts_v0[] = { |
| {.name = "uid-owner", .has_arg = true, .val = 'u'}, |
| {.name = "gid-owner", .has_arg = true, .val = 'g'}, |
| {.name = "pid-owner", .has_arg = true, .val = 'p'}, |
| {.name = "sid-owner", .has_arg = true, .val = 's'}, |
| { .name = NULL } |
| }; |
| |
| static const struct option owner_mt_opts[] = { |
| {.name = "uid-owner", .has_arg = true, .val = 'u'}, |
| {.name = "gid-owner", .has_arg = true, .val = 'g'}, |
| {.name = "socket-exists", .has_arg = false, .val = 'k'}, |
| { .name = NULL } |
| }; |
| |
| static int |
| owner_mt_parse_v0(int c, char **argv, int invert, unsigned int *flags, |
| const void *entry, struct xt_entry_match **match) |
| { |
| struct ipt_owner_info *info = (void *)(*match)->data; |
| struct passwd *pwd; |
| struct group *grp; |
| unsigned int id; |
| |
| switch (c) { |
| case 'u': |
| xtables_param_act(XTF_ONLY_ONCE, "owner", "--uid-owner", *flags & FLAG_UID_OWNER); |
| if ((pwd = getpwnam(optarg)) != NULL) |
| id = pwd->pw_uid; |
| else if (!xtables_strtoui(optarg, NULL, &id, 0, UINT32_MAX - 1)) |
| xtables_param_act(XTF_BAD_VALUE, "owner", "--uid-owner", optarg); |
| if (invert) |
| info->invert |= IPT_OWNER_UID; |
| info->match |= IPT_OWNER_UID; |
| info->uid = id; |
| *flags |= FLAG_UID_OWNER; |
| return true; |
| |
| case 'g': |
| xtables_param_act(XTF_ONLY_ONCE, "owner", "--gid-owner", *flags & FLAG_GID_OWNER); |
| if ((grp = getgrnam(optarg)) != NULL) |
| id = grp->gr_gid; |
| else if (!xtables_strtoui(optarg, NULL, &id, 0, UINT32_MAX - 1)) |
| xtables_param_act(XTF_BAD_VALUE, "owner", "--gid-owner", optarg); |
| if (invert) |
| info->invert |= IPT_OWNER_GID; |
| info->match |= IPT_OWNER_GID; |
| info->gid = id; |
| *flags |= FLAG_GID_OWNER; |
| return true; |
| |
| case 'p': |
| xtables_param_act(XTF_ONLY_ONCE, "owner", "--pid-owner", *flags & FLAG_PID_OWNER); |
| if (!xtables_strtoui(optarg, NULL, &id, 0, INT_MAX)) |
| xtables_param_act(XTF_BAD_VALUE, "owner", "--pid-owner", optarg); |
| if (invert) |
| info->invert |= IPT_OWNER_PID; |
| info->match |= IPT_OWNER_PID; |
| info->pid = id; |
| *flags |= FLAG_PID_OWNER; |
| return true; |
| |
| case 's': |
| xtables_param_act(XTF_ONLY_ONCE, "owner", "--sid-owner", *flags & FLAG_SID_OWNER); |
| if (!xtables_strtoui(optarg, NULL, &id, 0, INT_MAX)) |
| xtables_param_act(XTF_BAD_VALUE, "owner", "--sid-value", optarg); |
| if (invert) |
| info->invert |= IPT_OWNER_SID; |
| info->match |= IPT_OWNER_SID; |
| info->sid = id; |
| *flags |= FLAG_SID_OWNER; |
| return true; |
| |
| #ifdef IPT_OWNER_COMM |
| case 'c': |
| xtables_param_act(XTF_ONLY_ONCE, "owner", "--cmd-owner", *flags & FLAG_COMM); |
| if (strlen(optarg) > sizeof(info->comm)) |
| xtables_error(PARAMETER_PROBLEM, "owner match: command " |
| "\"%s\" too long, max. %zu characters", |
| optarg, sizeof(info->comm)); |
| |
| info->comm[sizeof(info->comm)-1] = '\0'; |
| strncpy(info->comm, optarg, sizeof(info->comm)); |
| |
| if (invert) |
| info->invert |= IPT_OWNER_COMM; |
| info->match |= IPT_OWNER_COMM; |
| *flags |= FLAG_COMM; |
| return true; |
| #endif |
| } |
| return false; |
| } |
| |
| static int |
| owner_mt6_parse_v0(int c, char **argv, int invert, unsigned int *flags, |
| const void *entry, struct xt_entry_match **match) |
| { |
| struct ip6t_owner_info *info = (void *)(*match)->data; |
| struct passwd *pwd; |
| struct group *grp; |
| unsigned int id; |
| |
| switch (c) { |
| case 'u': |
| xtables_param_act(XTF_ONLY_ONCE, "owner", "--uid-owner", |
| *flags & FLAG_UID_OWNER); |
| if ((pwd = getpwnam(optarg)) != NULL) |
| id = pwd->pw_uid; |
| else if (!xtables_strtoui(optarg, NULL, &id, 0, UINT32_MAX - 1)) |
| xtables_param_act(XTF_BAD_VALUE, "owner", "--uid-owner", optarg); |
| if (invert) |
| info->invert |= IP6T_OWNER_UID; |
| info->match |= IP6T_OWNER_UID; |
| info->uid = id; |
| *flags |= FLAG_UID_OWNER; |
| return true; |
| |
| case 'g': |
| xtables_param_act(XTF_ONLY_ONCE, "owner", "--gid-owner", |
| *flags & FLAG_GID_OWNER); |
| if ((grp = getgrnam(optarg)) != NULL) |
| id = grp->gr_gid; |
| else if (!xtables_strtoui(optarg, NULL, &id, 0, UINT32_MAX - 1)) |
| xtables_param_act(XTF_BAD_VALUE, "owner", "--gid-owner", optarg); |
| if (invert) |
| info->invert |= IP6T_OWNER_GID; |
| info->match |= IP6T_OWNER_GID; |
| info->gid = id; |
| *flags |= FLAG_GID_OWNER; |
| return true; |
| |
| case 'p': |
| xtables_param_act(XTF_ONLY_ONCE, "owner", "--pid-owner", |
| *flags & FLAG_PID_OWNER); |
| if (!xtables_strtoui(optarg, NULL, &id, 0, INT_MAX)) |
| xtables_param_act(XTF_BAD_VALUE, "owner", "--pid-owner", optarg); |
| if (invert) |
| info->invert |= IP6T_OWNER_PID; |
| info->match |= IP6T_OWNER_PID; |
| info->pid = id; |
| *flags |= FLAG_PID_OWNER; |
| return true; |
| |
| case 's': |
| xtables_param_act(XTF_ONLY_ONCE, "owner", "--sid-owner", |
| *flags & FLAG_SID_OWNER); |
| if (!xtables_strtoui(optarg, NULL, &id, 0, INT_MAX)) |
| xtables_param_act(XTF_BAD_VALUE, "owner", "--sid-owner", optarg); |
| if (invert) |
| info->invert |= IP6T_OWNER_SID; |
| info->match |= IP6T_OWNER_SID; |
| info->sid = id; |
| *flags |= FLAG_SID_OWNER; |
| return true; |
| } |
| return false; |
| } |
| |
| static void owner_parse_range(const char *s, unsigned int *from, |
| unsigned int *to, const char *opt) |
| { |
| char *end; |
| |
| /* -1 is reversed, so the max is one less than that. */ |
| if (!xtables_strtoui(s, &end, from, 0, UINT32_MAX - 1)) |
| xtables_param_act(XTF_BAD_VALUE, "owner", opt, s); |
| *to = *from; |
| if (*end == '-' || *end == ':') |
| if (!xtables_strtoui(end + 1, &end, to, 0, UINT32_MAX - 1)) |
| xtables_param_act(XTF_BAD_VALUE, "owner", opt, s); |
| if (*end != '\0') |
| xtables_param_act(XTF_BAD_VALUE, "owner", opt, s); |
| } |
| |
| static int owner_mt_parse(int c, char **argv, int invert, unsigned int *flags, |
| const void *entry, struct xt_entry_match **match) |
| { |
| struct xt_owner_match_info *info = (void *)(*match)->data; |
| struct passwd *pwd; |
| struct group *grp; |
| unsigned int from, to; |
| |
| switch (c) { |
| case 'u': |
| xtables_param_act(XTF_ONLY_ONCE, "owner", "--uid-owner", |
| *flags & FLAG_UID_OWNER); |
| if ((pwd = getpwnam(optarg)) != NULL) |
| from = to = pwd->pw_uid; |
| else |
| owner_parse_range(optarg, &from, &to, "--uid-owner"); |
| if (invert) |
| info->invert |= XT_OWNER_UID; |
| info->match |= XT_OWNER_UID; |
| info->uid_min = from; |
| info->uid_max = to; |
| *flags |= FLAG_UID_OWNER; |
| return true; |
| |
| case 'g': |
| xtables_param_act(XTF_ONLY_ONCE, "owner", "--gid-owner", |
| *flags & FLAG_GID_OWNER); |
| if ((grp = getgrnam(optarg)) != NULL) |
| from = to = grp->gr_gid; |
| else |
| owner_parse_range(optarg, &from, &to, "--gid-owner"); |
| if (invert) |
| info->invert |= XT_OWNER_GID; |
| info->match |= XT_OWNER_GID; |
| info->gid_min = from; |
| info->gid_max = to; |
| *flags |= FLAG_GID_OWNER; |
| return true; |
| |
| case 'k': |
| xtables_param_act(XTF_ONLY_ONCE, "owner", "--socket-exists", |
| *flags & FLAG_SOCKET_EXISTS); |
| if (invert) |
| info->invert |= XT_OWNER_SOCKET; |
| info->match |= XT_OWNER_SOCKET; |
| *flags |= FLAG_SOCKET_EXISTS; |
| return true; |
| |
| } |
| return false; |
| } |
| |
| static void owner_mt_check(unsigned int flags) |
| { |
| if (flags == 0) |
| xtables_error(PARAMETER_PROBLEM, "owner: At least one of " |
| "--uid-owner, --gid-owner or --socket-exists " |
| "is required"); |
| } |
| |
| static void |
| owner_mt_print_item_v0(const struct ipt_owner_info *info, const char *label, |
| u_int8_t flag, bool numeric) |
| { |
| if (!(info->match & flag)) |
| return; |
| if (info->invert & flag) |
| printf("! "); |
| printf("%s ", label); |
| |
| switch (info->match & flag) { |
| case IPT_OWNER_UID: |
| if (!numeric) { |
| struct passwd *pwd = getpwuid(info->uid); |
| |
| if (pwd != NULL && pwd->pw_name != NULL) { |
| printf("%s ", pwd->pw_name); |
| break; |
| } |
| } |
| printf("%u ", (unsigned int)info->uid); |
| break; |
| |
| case IPT_OWNER_GID: |
| if (!numeric) { |
| struct group *grp = getgrgid(info->gid); |
| |
| if (grp != NULL && grp->gr_name != NULL) { |
| printf("%s ", grp->gr_name); |
| break; |
| } |
| } |
| printf("%u ", (unsigned int)info->gid); |
| break; |
| |
| case IPT_OWNER_PID: |
| printf("%u ", (unsigned int)info->pid); |
| break; |
| |
| case IPT_OWNER_SID: |
| printf("%u ", (unsigned int)info->sid); |
| break; |
| |
| #ifdef IPT_OWNER_COMM |
| case IPT_OWNER_COMM: |
| printf("%.*s ", (int)sizeof(info->comm), info->comm); |
| break; |
| #endif |
| } |
| } |
| |
| static void |
| owner_mt6_print_item_v0(const struct ip6t_owner_info *info, const char *label, |
| u_int8_t flag, bool numeric) |
| { |
| if (!(info->match & flag)) |
| return; |
| if (info->invert & flag) |
| printf("! "); |
| printf("%s ", label); |
| |
| switch (info->match & flag) { |
| case IP6T_OWNER_UID: |
| if (!numeric) { |
| struct passwd *pwd = getpwuid(info->uid); |
| |
| if (pwd != NULL && pwd->pw_name != NULL) { |
| printf("%s ", pwd->pw_name); |
| break; |
| } |
| } |
| printf("%u ", (unsigned int)info->uid); |
| break; |
| |
| case IP6T_OWNER_GID: |
| if (!numeric) { |
| struct group *grp = getgrgid(info->gid); |
| |
| if (grp != NULL && grp->gr_name != NULL) { |
| printf("%s ", grp->gr_name); |
| break; |
| } |
| } |
| printf("%u ", (unsigned int)info->gid); |
| break; |
| |
| case IP6T_OWNER_PID: |
| printf("%u ", (unsigned int)info->pid); |
| break; |
| |
| case IP6T_OWNER_SID: |
| printf("%u ", (unsigned int)info->sid); |
| break; |
| } |
| } |
| |
| static void |
| owner_mt_print_item(const struct xt_owner_match_info *info, const char *label, |
| u_int8_t flag, bool numeric) |
| { |
| if (!(info->match & flag)) |
| return; |
| if (info->invert & flag) |
| printf("! "); |
| printf("%s ", label); |
| |
| switch (info->match & flag) { |
| case XT_OWNER_UID: |
| if (info->uid_min != info->uid_max) { |
| printf("%u-%u ", (unsigned int)info->uid_min, |
| (unsigned int)info->uid_max); |
| break; |
| } else if (!numeric) { |
| const struct passwd *pwd = getpwuid(info->uid_min); |
| |
| if (pwd != NULL && pwd->pw_name != NULL) { |
| printf("%s ", pwd->pw_name); |
| break; |
| } |
| } |
| printf("%u ", (unsigned int)info->uid_min); |
| break; |
| |
| case XT_OWNER_GID: |
| if (info->gid_min != info->gid_max) { |
| printf("%u-%u ", (unsigned int)info->gid_min, |
| (unsigned int)info->gid_max); |
| break; |
| } else if (!numeric) { |
| const struct group *grp = getgrgid(info->gid_min); |
| |
| if (grp != NULL && grp->gr_name != NULL) { |
| printf("%s ", grp->gr_name); |
| break; |
| } |
| } |
| printf("%u ", (unsigned int)info->gid_min); |
| break; |
| } |
| } |
| |
| static void |
| owner_mt_print_v0(const void *ip, const struct xt_entry_match *match, |
| int numeric) |
| { |
| const struct ipt_owner_info *info = (void *)match->data; |
| |
| owner_mt_print_item_v0(info, "owner UID match", IPT_OWNER_UID, numeric); |
| owner_mt_print_item_v0(info, "owner GID match", IPT_OWNER_GID, numeric); |
| owner_mt_print_item_v0(info, "owner PID match", IPT_OWNER_PID, numeric); |
| owner_mt_print_item_v0(info, "owner SID match", IPT_OWNER_SID, numeric); |
| #ifdef IPT_OWNER_COMM |
| owner_mt_print_item_v0(info, "owner CMD match", IPT_OWNER_COMM, numeric); |
| #endif |
| } |
| |
| static void |
| owner_mt6_print_v0(const void *ip, const struct xt_entry_match *match, |
| int numeric) |
| { |
| const struct ip6t_owner_info *info = (void *)match->data; |
| |
| owner_mt6_print_item_v0(info, "owner UID match", IPT_OWNER_UID, numeric); |
| owner_mt6_print_item_v0(info, "owner GID match", IPT_OWNER_GID, numeric); |
| owner_mt6_print_item_v0(info, "owner PID match", IPT_OWNER_PID, numeric); |
| owner_mt6_print_item_v0(info, "owner SID match", IPT_OWNER_SID, numeric); |
| } |
| |
| static void owner_mt_print(const void *ip, const struct xt_entry_match *match, |
| int numeric) |
| { |
| const struct xt_owner_match_info *info = (void *)match->data; |
| |
| owner_mt_print_item(info, "owner socket exists", XT_OWNER_SOCKET, numeric); |
| owner_mt_print_item(info, "owner UID match", XT_OWNER_UID, numeric); |
| owner_mt_print_item(info, "owner GID match", XT_OWNER_GID, numeric); |
| } |
| |
| static void |
| owner_mt_save_v0(const void *ip, const struct xt_entry_match *match) |
| { |
| const struct ipt_owner_info *info = (void *)match->data; |
| |
| owner_mt_print_item_v0(info, "--uid-owner", IPT_OWNER_UID, true); |
| owner_mt_print_item_v0(info, "--gid-owner", IPT_OWNER_GID, true); |
| owner_mt_print_item_v0(info, "--pid-owner", IPT_OWNER_PID, true); |
| owner_mt_print_item_v0(info, "--sid-owner", IPT_OWNER_SID, true); |
| #ifdef IPT_OWNER_COMM |
| owner_mt_print_item_v0(info, "--cmd-owner", IPT_OWNER_COMM, true); |
| #endif |
| } |
| |
| static void |
| owner_mt6_save_v0(const void *ip, const struct xt_entry_match *match) |
| { |
| const struct ip6t_owner_info *info = (void *)match->data; |
| |
| owner_mt6_print_item_v0(info, "--uid-owner", IPT_OWNER_UID, true); |
| owner_mt6_print_item_v0(info, "--gid-owner", IPT_OWNER_GID, true); |
| owner_mt6_print_item_v0(info, "--pid-owner", IPT_OWNER_PID, true); |
| owner_mt6_print_item_v0(info, "--sid-owner", IPT_OWNER_SID, true); |
| } |
| |
| static void owner_mt_save(const void *ip, const struct xt_entry_match *match) |
| { |
| const struct xt_owner_match_info *info = (void *)match->data; |
| |
| owner_mt_print_item(info, "--socket-exists", XT_OWNER_SOCKET, false); |
| owner_mt_print_item(info, "--uid-owner", XT_OWNER_UID, false); |
| owner_mt_print_item(info, "--gid-owner", XT_OWNER_GID, false); |
| } |
| |
| static struct xtables_match owner_mt_reg_v0 = { |
| .version = XTABLES_VERSION, |
| .name = "owner", |
| .revision = 0, |
| .family = NFPROTO_IPV4, |
| .size = XT_ALIGN(sizeof(struct ipt_owner_info)), |
| .userspacesize = XT_ALIGN(sizeof(struct ipt_owner_info)), |
| .help = owner_mt_help_v0, |
| .parse = owner_mt_parse_v0, |
| .final_check = owner_mt_check, |
| .print = owner_mt_print_v0, |
| .save = owner_mt_save_v0, |
| .extra_opts = owner_mt_opts_v0, |
| }; |
| |
| static struct xtables_match owner_mt6_reg_v0 = { |
| .version = XTABLES_VERSION, |
| .name = "owner", |
| .revision = 0, |
| .family = NFPROTO_IPV6, |
| .size = XT_ALIGN(sizeof(struct ip6t_owner_info)), |
| .userspacesize = XT_ALIGN(sizeof(struct ip6t_owner_info)), |
| .help = owner_mt6_help_v0, |
| .parse = owner_mt6_parse_v0, |
| .final_check = owner_mt_check, |
| .print = owner_mt6_print_v0, |
| .save = owner_mt6_save_v0, |
| .extra_opts = owner_mt6_opts_v0, |
| }; |
| |
| static struct xtables_match owner_mt_reg = { |
| .version = XTABLES_VERSION, |
| .name = "owner", |
| .revision = 1, |
| .family = NFPROTO_IPV4, |
| .size = XT_ALIGN(sizeof(struct xt_owner_match_info)), |
| .userspacesize = XT_ALIGN(sizeof(struct xt_owner_match_info)), |
| .help = owner_mt_help, |
| .parse = owner_mt_parse, |
| .final_check = owner_mt_check, |
| .print = owner_mt_print, |
| .save = owner_mt_save, |
| .extra_opts = owner_mt_opts, |
| }; |
| |
| static struct xtables_match owner_mt6_reg = { |
| .version = XTABLES_VERSION, |
| .name = "owner", |
| .revision = 1, |
| .family = NFPROTO_IPV6, |
| .size = XT_ALIGN(sizeof(struct xt_owner_match_info)), |
| .userspacesize = XT_ALIGN(sizeof(struct xt_owner_match_info)), |
| .help = owner_mt_help, |
| .parse = owner_mt_parse, |
| .final_check = owner_mt_check, |
| .print = owner_mt_print, |
| .save = owner_mt_save, |
| .extra_opts = owner_mt_opts, |
| }; |
| |
| void _init(void) |
| { |
| xtables_register_match(&owner_mt_reg_v0); |
| xtables_register_match(&owner_mt6_reg_v0); |
| xtables_register_match(&owner_mt_reg); |
| xtables_register_match(&owner_mt6_reg); |
| } |