logo

utils

~/.local/bin tools and git-hooks git clone https://hacktivis.me/git/utils.git

id.c (6093B)


  1. // Collection of Unix tools, comparable to coreutils
  2. // SPDX-FileCopyrightText: 2017-2022 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
  3. // SPDX-License-Identifier: MPL-2.0
  4. #define _DEFAULT_SOURCE // getgrouplist (4.4BSD+)
  5. #include <grp.h> // getgrgid, getgroups, getgrouplist(glibc)
  6. #include <pwd.h> // getpwuid
  7. #include <stdbool.h> // bool
  8. #include <stdio.h> // printf, perror
  9. #include <stdlib.h> // malloc, free
  10. #include <sys/types.h> // uid_t
  11. #include <unistd.h> // getuid, getgid, getopt, opt*, getgrouplist(FreeBSD, NetBSD)
  12. bool name_flag = false;
  13. static int
  14. simple_list_groups(struct passwd *pw, int ngroups, gid_t *groups)
  15. {
  16. for(int i = 0; i < ngroups; i++)
  17. {
  18. if(name_flag)
  19. {
  20. struct group *lgr = getgrgid(groups[i]);
  21. if(lgr == NULL)
  22. {
  23. return 1;
  24. }
  25. int sep = ' ';
  26. if(i == ngroups - 1)
  27. {
  28. sep = '\n';
  29. }
  30. int ret = printf("%s%c", lgr->gr_name, sep);
  31. if(ret < 0)
  32. {
  33. return 1;
  34. }
  35. }
  36. else
  37. {
  38. int sep = ' ';
  39. if(i == ngroups - 1)
  40. {
  41. sep = '\n';
  42. }
  43. int ret = printf("%u%c", groups[i], sep);
  44. if(ret < 0)
  45. {
  46. return 1;
  47. }
  48. }
  49. }
  50. return 0;
  51. }
  52. static int
  53. list_groups(struct passwd *pw, int ngroups, gid_t *groups)
  54. {
  55. printf(" groups=");
  56. for(int i = 0; i < ngroups; i++)
  57. {
  58. struct group *lgr = getgrgid(groups[i]);
  59. if(name_flag)
  60. {
  61. if(lgr == NULL)
  62. {
  63. return 1;
  64. }
  65. int sep = ' ';
  66. if(i == ngroups - 1)
  67. {
  68. sep = '\0';
  69. }
  70. int ret = printf("%s%c", lgr->gr_name, sep);
  71. if(ret < 0)
  72. {
  73. return 1;
  74. }
  75. }
  76. else
  77. {
  78. int ret = printf("%u", groups[i]);
  79. if(ret < 0)
  80. {
  81. return 1;
  82. }
  83. if(lgr != NULL)
  84. {
  85. int ret = printf("(%s)", lgr->gr_name);
  86. if(ret < 0)
  87. {
  88. return 1;
  89. }
  90. }
  91. if(i != ngroups - 1)
  92. {
  93. printf(",");
  94. }
  95. }
  96. }
  97. return 0;
  98. }
  99. int
  100. print_gid(char *field, struct group *gr, gid_t gid)
  101. {
  102. if(gr && gr->gr_name)
  103. {
  104. if(name_flag)
  105. {
  106. return printf("%s=%s", field, gr->gr_name);
  107. }
  108. return printf("%s=%u(%s)", field, gid, gr->gr_name);
  109. }
  110. else
  111. {
  112. if(name_flag)
  113. {
  114. return -1;
  115. }
  116. return printf("%s=%u", field, gid);
  117. }
  118. }
  119. int
  120. print_uid(char *field, struct passwd *pw, uid_t uid)
  121. {
  122. if(pw && pw->pw_name)
  123. {
  124. if(name_flag)
  125. {
  126. return printf("%s=%s", field, pw->pw_name);
  127. }
  128. return printf("%s=%u(%s)", field, uid, pw->pw_name);
  129. }
  130. else
  131. {
  132. if(name_flag)
  133. {
  134. return -1;
  135. }
  136. return printf("%s=%u", field, uid);
  137. }
  138. }
  139. void
  140. safe_getpwuid(uid_t uid, struct passwd *res)
  141. {
  142. struct passwd *pw = getpwuid(uid);
  143. if(pw != NULL)
  144. {
  145. *res = *pw;
  146. }
  147. }
  148. enum id_modes
  149. {
  150. ID_NORMAL,
  151. ID_GROUPS,
  152. ID_GID,
  153. ID_UID,
  154. };
  155. void
  156. usage()
  157. {
  158. fprintf(stderr, "Usage: id [-Ggu] [-nr] [user]\n");
  159. }
  160. int
  161. main(int argc, char *argv[])
  162. {
  163. int ret = 0, c = 0;
  164. enum id_modes mode = ID_NORMAL;
  165. bool real_flag = false;
  166. int ngroups = 0;
  167. int ngroups_max = (int)sysconf(_SC_NGROUPS_MAX) + 1;
  168. gid_t *groups = malloc(sizeof(gid_t) * ngroups_max);
  169. if(groups == NULL)
  170. {
  171. perror("groups malloc");
  172. return 1;
  173. }
  174. // geteuid, getuid, getegid, getgid shall always be successful
  175. uid_t uid = getuid();
  176. uid_t euid = geteuid();
  177. gid_t gid = getgid();
  178. gid_t egid = getegid();
  179. struct passwd pw = {.pw_uid = uid, .pw_gid = gid};
  180. struct passwd epw = {.pw_uid = euid, .pw_gid = egid};
  181. /* flawfinder: ignore. Old implementations of getopt should fix themselves */
  182. while((c = getopt(argc, argv, ":Ggunr")) != EOF)
  183. {
  184. switch(c)
  185. {
  186. case 'G':
  187. mode = ID_GROUPS;
  188. break;
  189. case 'u':
  190. mode = ID_UID;
  191. break;
  192. case 'g':
  193. mode = ID_GID;
  194. break;
  195. case 'n':
  196. name_flag = true;
  197. break;
  198. case 'r':
  199. real_flag = true;
  200. break;
  201. default:
  202. usage();
  203. free(groups);
  204. return 1;
  205. }
  206. }
  207. argc -= optind;
  208. argv += optind;
  209. if(argc == 0)
  210. {
  211. safe_getpwuid(uid, &pw);
  212. safe_getpwuid(euid, &epw);
  213. // Get groups from currently running process instead of configuration
  214. ngroups = getgroups(ngroups_max, groups);
  215. if(ngroups < 0)
  216. {
  217. perror("getgroups");
  218. goto failure;
  219. }
  220. }
  221. else if(argc == 1)
  222. {
  223. struct passwd *pw_n = getpwnam(argv[0]);
  224. if(pw_n == NULL)
  225. {
  226. goto failure;
  227. }
  228. pw = *pw_n;
  229. epw = *pw_n;
  230. uid = pw.pw_uid;
  231. euid = epw.pw_uid;
  232. gid = pw.pw_gid;
  233. egid = epw.pw_gid;
  234. // Can only get groups from configuration
  235. ngroups = getgrouplist(pw.pw_name, pw.pw_gid, groups, &ngroups_max);
  236. if(ngroups < 0)
  237. {
  238. perror("getgrouplist");
  239. goto failure;
  240. }
  241. }
  242. else
  243. {
  244. usage();
  245. }
  246. struct group *gr = getgrgid(gid);
  247. struct group *egr = getgrgid(egid);
  248. if(mode == ID_GID)
  249. {
  250. if(!real_flag)
  251. {
  252. gid = egid;
  253. }
  254. if(!name_flag)
  255. {
  256. ret = printf("%u\n", gid);
  257. }
  258. else
  259. {
  260. if(gr == NULL || gr->gr_name == NULL)
  261. {
  262. ret--;
  263. fprintf(stderr, "id: cannot find name for group ID %u\n", gid);
  264. printf("%u\n", gid);
  265. }
  266. else
  267. {
  268. ret = printf("%s\n", gr->gr_name);
  269. }
  270. }
  271. if(ret < 0)
  272. {
  273. goto failure;
  274. }
  275. goto done;
  276. }
  277. if(mode == ID_UID)
  278. {
  279. if(!real_flag)
  280. {
  281. uid = euid;
  282. }
  283. if(!name_flag)
  284. {
  285. ret = printf("%u\n", uid);
  286. }
  287. else
  288. {
  289. if(pw.pw_name == NULL)
  290. {
  291. ret--;
  292. fprintf(stderr, "id: cannot find name for user ID %u\n", uid);
  293. printf("%u\n", uid);
  294. }
  295. else
  296. {
  297. ret = printf("%s\n", pw.pw_name);
  298. }
  299. }
  300. if(ret < 0)
  301. {
  302. goto failure;
  303. }
  304. goto done;
  305. }
  306. if(mode == ID_GROUPS)
  307. {
  308. if(real_flag)
  309. {
  310. ret = simple_list_groups(&pw, ngroups, groups);
  311. }
  312. else
  313. {
  314. ret = simple_list_groups(&epw, ngroups, groups);
  315. }
  316. if(ret != 0)
  317. {
  318. goto failure;
  319. }
  320. goto done;
  321. }
  322. ret = print_uid("uid", &pw, uid);
  323. if(ret < 0)
  324. {
  325. goto failure;
  326. }
  327. if(euid != uid)
  328. {
  329. ret = print_uid(" euid", &epw, euid);
  330. if(ret < 0)
  331. {
  332. goto failure;
  333. }
  334. }
  335. ret = print_gid(" gid", gr, gid);
  336. if(ret < 0)
  337. {
  338. goto failure;
  339. }
  340. if(egid != gid)
  341. {
  342. ret = print_gid(" egid", egr, egid);
  343. if(ret < 0)
  344. {
  345. goto failure;
  346. }
  347. }
  348. if(list_groups(&pw, ngroups, groups) != 0)
  349. {
  350. goto failure;
  351. }
  352. ret = printf("\n");
  353. if(ret < 0)
  354. {
  355. goto failure;
  356. }
  357. done:
  358. free(groups);
  359. return 0;
  360. failure:
  361. free(groups);
  362. return 1;
  363. }