libxt_owner.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  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 <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. /* match and invert flags */
  15. enum {
  16. IPT_OWNER_UID = 0x01,
  17. IPT_OWNER_GID = 0x02,
  18. IPT_OWNER_PID = 0x04,
  19. IPT_OWNER_SID = 0x08,
  20. IPT_OWNER_COMM = 0x10,
  21. IP6T_OWNER_UID = IPT_OWNER_UID,
  22. IP6T_OWNER_GID = IPT_OWNER_GID,
  23. IP6T_OWNER_PID = IPT_OWNER_PID,
  24. IP6T_OWNER_SID = IPT_OWNER_SID,
  25. IP6T_OWNER_COMM = IPT_OWNER_COMM,
  26. };
  27. struct ipt_owner_info {
  28. uid_t uid;
  29. gid_t gid;
  30. pid_t pid;
  31. pid_t sid;
  32. char comm[16];
  33. uint8_t match, invert; /* flags */
  34. };
  35. struct ip6t_owner_info {
  36. uid_t uid;
  37. gid_t gid;
  38. pid_t pid;
  39. pid_t sid;
  40. char comm[16];
  41. uint8_t match, invert; /* flags */
  42. };
  43. /*
  44. * Note: "UINT32_MAX - 1" is used in the code because -1 is a reserved
  45. * UID/GID value anyway.
  46. */
  47. enum {
  48. O_USER = 0,
  49. O_GROUP,
  50. O_SOCK_EXISTS,
  51. O_PROCESS,
  52. O_SESSION,
  53. O_COMM,
  54. };
  55. static void owner_mt_help_v0(void)
  56. {
  57. printf(
  58. "owner match options:\n"
  59. "[!] --uid-owner userid Match local UID\n"
  60. "[!] --gid-owner groupid Match local GID\n"
  61. "[!] --pid-owner processid Match local PID\n"
  62. "[!] --sid-owner sessionid Match local SID\n"
  63. "[!] --cmd-owner name Match local command name\n"
  64. "NOTE: PID, SID and command matching are broken on SMP\n");
  65. }
  66. static void owner_mt6_help_v0(void)
  67. {
  68. printf(
  69. "owner match options:\n"
  70. "[!] --uid-owner userid Match local UID\n"
  71. "[!] --gid-owner groupid Match local GID\n"
  72. "[!] --pid-owner processid Match local PID\n"
  73. "[!] --sid-owner sessionid Match local SID\n"
  74. "NOTE: PID and SID matching are broken on SMP\n");
  75. }
  76. static void owner_mt_help(void)
  77. {
  78. printf(
  79. "owner match options:\n"
  80. "[!] --uid-owner userid[-userid] Match local UID\n"
  81. "[!] --gid-owner groupid[-groupid] Match local GID\n"
  82. "[!] --socket-exists Match if socket exists\n");
  83. }
  84. #define s struct ipt_owner_info
  85. static const struct xt_option_entry owner_mt_opts_v0[] = {
  86. {.name = "uid-owner", .id = O_USER, .type = XTTYPE_STRING,
  87. .flags = XTOPT_INVERT},
  88. {.name = "gid-owner", .id = O_GROUP, .type = XTTYPE_STRING,
  89. .flags = XTOPT_INVERT},
  90. {.name = "pid-owner", .id = O_PROCESS, .type = XTTYPE_UINT32,
  91. .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, pid),
  92. .max = INT_MAX},
  93. {.name = "sid-owner", .id = O_SESSION, .type = XTTYPE_UINT32,
  94. .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, sid),
  95. .max = INT_MAX},
  96. {.name = "cmd-owner", .id = O_COMM, .type = XTTYPE_STRING,
  97. .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, comm)},
  98. XTOPT_TABLEEND,
  99. };
  100. #undef s
  101. #define s struct ip6t_owner_info
  102. static const struct xt_option_entry owner_mt6_opts_v0[] = {
  103. {.name = "uid-owner", .id = O_USER, .type = XTTYPE_STRING,
  104. .flags = XTOPT_INVERT},
  105. {.name = "gid-owner", .id = O_GROUP, .type = XTTYPE_STRING,
  106. .flags = XTOPT_INVERT},
  107. {.name = "pid-owner", .id = O_PROCESS, .type = XTTYPE_UINT32,
  108. .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, pid),
  109. .max = INT_MAX},
  110. {.name = "sid-owner", .id = O_SESSION, .type = XTTYPE_UINT32,
  111. .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, sid),
  112. .max = INT_MAX},
  113. XTOPT_TABLEEND,
  114. };
  115. #undef s
  116. static const struct xt_option_entry owner_mt_opts[] = {
  117. {.name = "uid-owner", .id = O_USER, .type = XTTYPE_STRING,
  118. .flags = XTOPT_INVERT},
  119. {.name = "gid-owner", .id = O_GROUP, .type = XTTYPE_STRING,
  120. .flags = XTOPT_INVERT},
  121. {.name = "socket-exists", .id = O_SOCK_EXISTS, .type = XTTYPE_NONE,
  122. .flags = XTOPT_INVERT},
  123. XTOPT_TABLEEND,
  124. };
  125. static void owner_mt_parse_v0(struct xt_option_call *cb)
  126. {
  127. struct ipt_owner_info *info = cb->data;
  128. struct passwd *pwd;
  129. struct group *grp;
  130. unsigned int id;
  131. xtables_option_parse(cb);
  132. switch (cb->entry->id) {
  133. case O_USER:
  134. if ((pwd = getpwnam(cb->arg)) != NULL)
  135. id = pwd->pw_uid;
  136. else if (!xtables_strtoui(cb->arg, NULL, &id, 0, UINT32_MAX - 1))
  137. xtables_param_act(XTF_BAD_VALUE, "owner", "--uid-owner", cb->arg);
  138. if (cb->invert)
  139. info->invert |= IPT_OWNER_UID;
  140. info->match |= IPT_OWNER_UID;
  141. info->uid = id;
  142. break;
  143. case O_GROUP:
  144. if ((grp = getgrnam(cb->arg)) != NULL)
  145. id = grp->gr_gid;
  146. else if (!xtables_strtoui(cb->arg, NULL, &id, 0, UINT32_MAX - 1))
  147. xtables_param_act(XTF_BAD_VALUE, "owner", "--gid-owner", cb->arg);
  148. if (cb->invert)
  149. info->invert |= IPT_OWNER_GID;
  150. info->match |= IPT_OWNER_GID;
  151. info->gid = id;
  152. break;
  153. case O_PROCESS:
  154. if (cb->invert)
  155. info->invert |= IPT_OWNER_PID;
  156. info->match |= IPT_OWNER_PID;
  157. break;
  158. case O_SESSION:
  159. if (cb->invert)
  160. info->invert |= IPT_OWNER_SID;
  161. info->match |= IPT_OWNER_SID;
  162. break;
  163. case O_COMM:
  164. if (cb->invert)
  165. info->invert |= IPT_OWNER_COMM;
  166. info->match |= IPT_OWNER_COMM;
  167. break;
  168. }
  169. }
  170. static void owner_mt6_parse_v0(struct xt_option_call *cb)
  171. {
  172. struct ip6t_owner_info *info = cb->data;
  173. struct passwd *pwd;
  174. struct group *grp;
  175. unsigned int id;
  176. xtables_option_parse(cb);
  177. switch (cb->entry->id) {
  178. case O_USER:
  179. if ((pwd = getpwnam(cb->arg)) != NULL)
  180. id = pwd->pw_uid;
  181. else if (!xtables_strtoui(cb->arg, NULL, &id, 0, UINT32_MAX - 1))
  182. xtables_param_act(XTF_BAD_VALUE, "owner", "--uid-owner", cb->arg);
  183. if (cb->invert)
  184. info->invert |= IP6T_OWNER_UID;
  185. info->match |= IP6T_OWNER_UID;
  186. info->uid = id;
  187. break;
  188. case O_GROUP:
  189. if ((grp = getgrnam(cb->arg)) != NULL)
  190. id = grp->gr_gid;
  191. else if (!xtables_strtoui(cb->arg, NULL, &id, 0, UINT32_MAX - 1))
  192. xtables_param_act(XTF_BAD_VALUE, "owner", "--gid-owner", cb->arg);
  193. if (cb->invert)
  194. info->invert |= IP6T_OWNER_GID;
  195. info->match |= IP6T_OWNER_GID;
  196. info->gid = id;
  197. break;
  198. case O_PROCESS:
  199. if (cb->invert)
  200. info->invert |= IP6T_OWNER_PID;
  201. info->match |= IP6T_OWNER_PID;
  202. break;
  203. case O_SESSION:
  204. if (cb->invert)
  205. info->invert |= IP6T_OWNER_SID;
  206. info->match |= IP6T_OWNER_SID;
  207. break;
  208. }
  209. }
  210. static void owner_parse_range(const char *s, unsigned int *from,
  211. unsigned int *to, const char *opt)
  212. {
  213. char *end;
  214. /* -1 is reversed, so the max is one less than that. */
  215. if (!xtables_strtoui(s, &end, from, 0, UINT32_MAX - 1))
  216. xtables_param_act(XTF_BAD_VALUE, "owner", opt, s);
  217. *to = *from;
  218. if (*end == '-' || *end == ':')
  219. if (!xtables_strtoui(end + 1, &end, to, 0, UINT32_MAX - 1))
  220. xtables_param_act(XTF_BAD_VALUE, "owner", opt, s);
  221. if (*end != '\0')
  222. xtables_param_act(XTF_BAD_VALUE, "owner", opt, s);
  223. }
  224. static void owner_mt_parse(struct xt_option_call *cb)
  225. {
  226. struct xt_owner_match_info *info = cb->data;
  227. struct passwd *pwd;
  228. struct group *grp;
  229. unsigned int from, to;
  230. xtables_option_parse(cb);
  231. switch (cb->entry->id) {
  232. case O_USER:
  233. if ((pwd = getpwnam(cb->arg)) != NULL)
  234. from = to = pwd->pw_uid;
  235. else
  236. owner_parse_range(cb->arg, &from, &to, "--uid-owner");
  237. if (cb->invert)
  238. info->invert |= XT_OWNER_UID;
  239. info->match |= XT_OWNER_UID;
  240. info->uid_min = from;
  241. info->uid_max = to;
  242. break;
  243. case O_GROUP:
  244. if ((grp = getgrnam(cb->arg)) != NULL)
  245. from = to = grp->gr_gid;
  246. else
  247. owner_parse_range(cb->arg, &from, &to, "--gid-owner");
  248. if (cb->invert)
  249. info->invert |= XT_OWNER_GID;
  250. info->match |= XT_OWNER_GID;
  251. info->gid_min = from;
  252. info->gid_max = to;
  253. break;
  254. case O_SOCK_EXISTS:
  255. if (cb->invert)
  256. info->invert |= XT_OWNER_SOCKET;
  257. info->match |= XT_OWNER_SOCKET;
  258. break;
  259. }
  260. }
  261. static void owner_mt_check(struct xt_fcheck_call *cb)
  262. {
  263. if (cb->xflags == 0)
  264. xtables_error(PARAMETER_PROBLEM, "owner: At least one of "
  265. "--uid-owner, --gid-owner or --socket-exists "
  266. "is required");
  267. }
  268. static void
  269. owner_mt_print_item_v0(const struct ipt_owner_info *info, const char *label,
  270. uint8_t flag, bool numeric)
  271. {
  272. if (!(info->match & flag))
  273. return;
  274. if (info->invert & flag)
  275. printf(" !");
  276. printf(" %s", label);
  277. switch (info->match & flag) {
  278. case IPT_OWNER_UID:
  279. if (!numeric) {
  280. struct passwd *pwd = getpwuid(info->uid);
  281. if (pwd != NULL && pwd->pw_name != NULL) {
  282. printf(" %s", pwd->pw_name);
  283. break;
  284. }
  285. }
  286. printf(" %u", (unsigned int)info->uid);
  287. break;
  288. case IPT_OWNER_GID:
  289. if (!numeric) {
  290. struct group *grp = getgrgid(info->gid);
  291. if (grp != NULL && grp->gr_name != NULL) {
  292. printf(" %s", grp->gr_name);
  293. break;
  294. }
  295. }
  296. printf(" %u", (unsigned int)info->gid);
  297. break;
  298. case IPT_OWNER_PID:
  299. printf(" %u", (unsigned int)info->pid);
  300. break;
  301. case IPT_OWNER_SID:
  302. printf(" %u", (unsigned int)info->sid);
  303. break;
  304. case IPT_OWNER_COMM:
  305. printf(" %.*s", (int)sizeof(info->comm), info->comm);
  306. break;
  307. }
  308. }
  309. static void
  310. owner_mt6_print_item_v0(const struct ip6t_owner_info *info, const char *label,
  311. uint8_t flag, bool numeric)
  312. {
  313. if (!(info->match & flag))
  314. return;
  315. if (info->invert & flag)
  316. printf(" !");
  317. printf(" %s", label);
  318. switch (info->match & flag) {
  319. case IP6T_OWNER_UID:
  320. if (!numeric) {
  321. struct passwd *pwd = getpwuid(info->uid);
  322. if (pwd != NULL && pwd->pw_name != NULL) {
  323. printf(" %s", pwd->pw_name);
  324. break;
  325. }
  326. }
  327. printf(" %u", (unsigned int)info->uid);
  328. break;
  329. case IP6T_OWNER_GID:
  330. if (!numeric) {
  331. struct group *grp = getgrgid(info->gid);
  332. if (grp != NULL && grp->gr_name != NULL) {
  333. printf(" %s", grp->gr_name);
  334. break;
  335. }
  336. }
  337. printf(" %u", (unsigned int)info->gid);
  338. break;
  339. case IP6T_OWNER_PID:
  340. printf(" %u", (unsigned int)info->pid);
  341. break;
  342. case IP6T_OWNER_SID:
  343. printf(" %u", (unsigned int)info->sid);
  344. break;
  345. }
  346. }
  347. static void
  348. owner_mt_print_item(const struct xt_owner_match_info *info, const char *label,
  349. uint8_t flag, bool numeric)
  350. {
  351. if (!(info->match & flag))
  352. return;
  353. if (info->invert & flag)
  354. printf(" !");
  355. printf(" %s", label);
  356. switch (info->match & flag) {
  357. case XT_OWNER_UID:
  358. if (info->uid_min != info->uid_max) {
  359. printf(" %u-%u", (unsigned int)info->uid_min,
  360. (unsigned int)info->uid_max);
  361. break;
  362. } else if (!numeric) {
  363. const struct passwd *pwd = getpwuid(info->uid_min);
  364. if (pwd != NULL && pwd->pw_name != NULL) {
  365. printf(" %s", pwd->pw_name);
  366. break;
  367. }
  368. }
  369. printf(" %u", (unsigned int)info->uid_min);
  370. break;
  371. case XT_OWNER_GID:
  372. if (info->gid_min != info->gid_max) {
  373. printf(" %u-%u", (unsigned int)info->gid_min,
  374. (unsigned int)info->gid_max);
  375. break;
  376. } else if (!numeric) {
  377. const struct group *grp = getgrgid(info->gid_min);
  378. if (grp != NULL && grp->gr_name != NULL) {
  379. printf(" %s", grp->gr_name);
  380. break;
  381. }
  382. }
  383. printf(" %u", (unsigned int)info->gid_min);
  384. break;
  385. }
  386. }
  387. static void
  388. owner_mt_print_v0(const void *ip, const struct xt_entry_match *match,
  389. int numeric)
  390. {
  391. const struct ipt_owner_info *info = (void *)match->data;
  392. owner_mt_print_item_v0(info, "owner UID match", IPT_OWNER_UID, numeric);
  393. owner_mt_print_item_v0(info, "owner GID match", IPT_OWNER_GID, numeric);
  394. owner_mt_print_item_v0(info, "owner PID match", IPT_OWNER_PID, numeric);
  395. owner_mt_print_item_v0(info, "owner SID match", IPT_OWNER_SID, numeric);
  396. owner_mt_print_item_v0(info, "owner CMD match", IPT_OWNER_COMM, numeric);
  397. }
  398. static void
  399. owner_mt6_print_v0(const void *ip, const struct xt_entry_match *match,
  400. int numeric)
  401. {
  402. const struct ip6t_owner_info *info = (void *)match->data;
  403. owner_mt6_print_item_v0(info, "owner UID match", IPT_OWNER_UID, numeric);
  404. owner_mt6_print_item_v0(info, "owner GID match", IPT_OWNER_GID, numeric);
  405. owner_mt6_print_item_v0(info, "owner PID match", IPT_OWNER_PID, numeric);
  406. owner_mt6_print_item_v0(info, "owner SID match", IPT_OWNER_SID, numeric);
  407. }
  408. static void owner_mt_print(const void *ip, const struct xt_entry_match *match,
  409. int numeric)
  410. {
  411. const struct xt_owner_match_info *info = (void *)match->data;
  412. owner_mt_print_item(info, "owner socket exists", XT_OWNER_SOCKET, numeric);
  413. owner_mt_print_item(info, "owner UID match", XT_OWNER_UID, numeric);
  414. owner_mt_print_item(info, "owner GID match", XT_OWNER_GID, numeric);
  415. }
  416. static void
  417. owner_mt_save_v0(const void *ip, const struct xt_entry_match *match)
  418. {
  419. const struct ipt_owner_info *info = (void *)match->data;
  420. owner_mt_print_item_v0(info, "--uid-owner", IPT_OWNER_UID, true);
  421. owner_mt_print_item_v0(info, "--gid-owner", IPT_OWNER_GID, true);
  422. owner_mt_print_item_v0(info, "--pid-owner", IPT_OWNER_PID, true);
  423. owner_mt_print_item_v0(info, "--sid-owner", IPT_OWNER_SID, true);
  424. owner_mt_print_item_v0(info, "--cmd-owner", IPT_OWNER_COMM, true);
  425. }
  426. static void
  427. owner_mt6_save_v0(const void *ip, const struct xt_entry_match *match)
  428. {
  429. const struct ip6t_owner_info *info = (void *)match->data;
  430. owner_mt6_print_item_v0(info, "--uid-owner", IPT_OWNER_UID, true);
  431. owner_mt6_print_item_v0(info, "--gid-owner", IPT_OWNER_GID, true);
  432. owner_mt6_print_item_v0(info, "--pid-owner", IPT_OWNER_PID, true);
  433. owner_mt6_print_item_v0(info, "--sid-owner", IPT_OWNER_SID, true);
  434. }
  435. static void owner_mt_save(const void *ip, const struct xt_entry_match *match)
  436. {
  437. const struct xt_owner_match_info *info = (void *)match->data;
  438. owner_mt_print_item(info, "--socket-exists", XT_OWNER_SOCKET, true);
  439. owner_mt_print_item(info, "--uid-owner", XT_OWNER_UID, true);
  440. owner_mt_print_item(info, "--gid-owner", XT_OWNER_GID, true);
  441. }
  442. static struct xtables_match owner_mt_reg[] = {
  443. {
  444. .version = XTABLES_VERSION,
  445. .name = "owner",
  446. .revision = 0,
  447. .family = NFPROTO_IPV4,
  448. .size = XT_ALIGN(sizeof(struct ipt_owner_info)),
  449. .userspacesize = XT_ALIGN(sizeof(struct ipt_owner_info)),
  450. .help = owner_mt_help_v0,
  451. .x6_parse = owner_mt_parse_v0,
  452. .x6_fcheck = owner_mt_check,
  453. .print = owner_mt_print_v0,
  454. .save = owner_mt_save_v0,
  455. .x6_options = owner_mt_opts_v0,
  456. },
  457. {
  458. .version = XTABLES_VERSION,
  459. .name = "owner",
  460. .revision = 0,
  461. .family = NFPROTO_IPV6,
  462. .size = XT_ALIGN(sizeof(struct ip6t_owner_info)),
  463. .userspacesize = XT_ALIGN(sizeof(struct ip6t_owner_info)),
  464. .help = owner_mt6_help_v0,
  465. .x6_parse = owner_mt6_parse_v0,
  466. .x6_fcheck = owner_mt_check,
  467. .print = owner_mt6_print_v0,
  468. .save = owner_mt6_save_v0,
  469. .x6_options = owner_mt6_opts_v0,
  470. },
  471. {
  472. .version = XTABLES_VERSION,
  473. .name = "owner",
  474. .revision = 1,
  475. .family = NFPROTO_UNSPEC,
  476. .size = XT_ALIGN(sizeof(struct xt_owner_match_info)),
  477. .userspacesize = XT_ALIGN(sizeof(struct xt_owner_match_info)),
  478. .help = owner_mt_help,
  479. .x6_parse = owner_mt_parse,
  480. .x6_fcheck = owner_mt_check,
  481. .print = owner_mt_print,
  482. .save = owner_mt_save,
  483. .x6_options = owner_mt_opts,
  484. },
  485. };
  486. void _init(void)
  487. {
  488. xtables_register_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg));
  489. }