logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git

id.c (5970B)


  1. // utils-std: Collection of commonly available Unix tools
  2. // SPDX-FileCopyrightText: 2017 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> // calloc, 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. bool first = true;
  17. // Don't print basegid twice when present in pw and grouplist
  18. bool basegid_done = false;
  19. for(int i = 0; i < ngroups; i++)
  20. {
  21. if(groups[i] == pw->pw_gid)
  22. {
  23. if(basegid_done)
  24. continue;
  25. else
  26. basegid_done = true;
  27. }
  28. if(name_flag)
  29. {
  30. struct group *lgr = getgrgid(groups[i]);
  31. if(lgr == NULL) return 1;
  32. if(!first) putchar(' ');
  33. printf("%s", lgr->gr_name);
  34. }
  35. else
  36. {
  37. if(!first) putchar(' ');
  38. printf("%u", groups[i]);
  39. }
  40. first = false;
  41. }
  42. putchar('\n');
  43. return 0;
  44. }
  45. static int
  46. list_groups(struct passwd *pw, int ngroups, gid_t *groups)
  47. {
  48. bool first = true;
  49. // Don't print basegid twice when present in pw and grouplist
  50. bool basegid_done = false;
  51. printf(" groups=");
  52. for(int i = 0; i < ngroups; i++)
  53. {
  54. struct group *lgr = getgrgid(groups[i]);
  55. if(groups[i] == pw->pw_gid)
  56. {
  57. if(basegid_done)
  58. continue;
  59. else
  60. basegid_done = true;
  61. }
  62. if(name_flag)
  63. {
  64. if(lgr == NULL) return 1;
  65. if(!first) putchar(' ');
  66. printf("%s", lgr->gr_name);
  67. }
  68. else
  69. {
  70. if(!first) putchar(',');
  71. printf("%u", groups[i]);
  72. if(lgr != NULL) printf("(%s)", lgr->gr_name);
  73. }
  74. first = false;
  75. }
  76. putchar('\n');
  77. return 0;
  78. }
  79. static int
  80. print_gid(const char *field, struct group *gr, gid_t gid)
  81. {
  82. if(gr && gr->gr_name)
  83. {
  84. if(name_flag) return printf("%s=%s", field, gr->gr_name);
  85. return printf("%s=%u(%s)", field, gid, gr->gr_name);
  86. }
  87. else
  88. {
  89. if(name_flag) return -1;
  90. return printf("%s=%u", field, gid);
  91. }
  92. }
  93. static int
  94. print_uid(const char *field, struct passwd *pw, uid_t uid)
  95. {
  96. if(pw && pw->pw_name)
  97. {
  98. if(name_flag) return printf("%s=%s", field, pw->pw_name);
  99. return printf("%s=%u(%s)", field, uid, pw->pw_name);
  100. }
  101. else
  102. {
  103. if(name_flag) return -1;
  104. return printf("%s=%u", field, uid);
  105. }
  106. }
  107. static void
  108. safe_getpwuid(uid_t uid, struct passwd *res)
  109. {
  110. struct passwd *pw = getpwuid(uid);
  111. if(pw != NULL) *res = *pw;
  112. }
  113. enum id_modes
  114. {
  115. ID_NORMAL,
  116. ID_GROUPS,
  117. ID_GID,
  118. ID_UID,
  119. };
  120. static void
  121. usage(void)
  122. {
  123. fprintf(stderr, "Usage: id [-Ggu] [-nr] [user]\n");
  124. }
  125. int
  126. main(int argc, char *argv[])
  127. {
  128. int ret = 0;
  129. enum id_modes mode = ID_NORMAL;
  130. bool real_flag = false;
  131. int ngroups = 0;
  132. int ngroups_max = (int)sysconf(_SC_NGROUPS_MAX) + 1;
  133. gid_t *groups = NULL;
  134. groups = calloc(ngroups_max, sizeof(*groups));
  135. if(groups == NULL)
  136. {
  137. perror("id: calloc(groups)");
  138. return 1;
  139. }
  140. // geteuid, getuid, getegid, getgid shall always be successful
  141. uid_t uid = getuid();
  142. uid_t euid = geteuid();
  143. gid_t gid = getgid();
  144. gid_t egid = getegid();
  145. struct passwd pw = {.pw_uid = uid, .pw_gid = gid};
  146. struct passwd epw = {.pw_uid = euid, .pw_gid = egid};
  147. int c = -1;
  148. while((c = getopt(argc, argv, ":Ggunr")) != -1)
  149. {
  150. switch(c)
  151. {
  152. case 'G':
  153. mode = ID_GROUPS;
  154. break;
  155. case 'u':
  156. mode = ID_UID;
  157. break;
  158. case 'g':
  159. mode = ID_GID;
  160. break;
  161. case 'n':
  162. name_flag = true;
  163. break;
  164. case 'r':
  165. real_flag = true;
  166. break;
  167. default:
  168. usage();
  169. free(groups);
  170. return 1;
  171. }
  172. }
  173. argc -= optind;
  174. argv += optind;
  175. if(argc == 0)
  176. {
  177. safe_getpwuid(uid, &pw);
  178. safe_getpwuid(euid, &epw);
  179. // Get groups from currently running process instead of configuration
  180. ngroups = getgroups(ngroups_max, groups);
  181. if(ngroups < 0)
  182. {
  183. perror("id: getgroups");
  184. goto failure;
  185. }
  186. }
  187. else if(argc == 1)
  188. {
  189. struct passwd *pw_n = getpwnam(argv[0]);
  190. if(pw_n == NULL)
  191. {
  192. goto failure;
  193. }
  194. pw = *pw_n;
  195. epw = *pw_n;
  196. uid = pw.pw_uid;
  197. euid = epw.pw_uid;
  198. gid = pw.pw_gid;
  199. egid = epw.pw_gid;
  200. // Can only get groups from configuration
  201. if(getgrouplist(pw.pw_name, pw.pw_gid, groups, &ngroups_max) < 0)
  202. {
  203. perror("id: getgrouplist");
  204. goto failure;
  205. }
  206. ngroups = ngroups_max;
  207. }
  208. else
  209. {
  210. usage();
  211. }
  212. struct group *gr = getgrgid(gid);
  213. struct group *egr = getgrgid(egid);
  214. if(mode == ID_GID)
  215. {
  216. if(!real_flag) gid = egid;
  217. if(!name_flag)
  218. {
  219. ret = printf("%u\n", gid);
  220. }
  221. else
  222. {
  223. if(gr == NULL || gr->gr_name == NULL)
  224. {
  225. ret--;
  226. fprintf(stderr, "id: cannot find name for group ID %u\n", gid);
  227. printf("%u\n", gid);
  228. }
  229. else
  230. {
  231. ret = printf("%s\n", gr->gr_name);
  232. }
  233. }
  234. if(ret < 0) goto failure;
  235. goto done;
  236. }
  237. if(mode == ID_UID)
  238. {
  239. if(!real_flag) uid = euid;
  240. if(!name_flag)
  241. {
  242. ret = printf("%u\n", uid);
  243. }
  244. else
  245. {
  246. if(pw.pw_name == NULL)
  247. {
  248. ret--;
  249. fprintf(stderr, "id: cannot find name for user ID %u\n", uid);
  250. printf("%u\n", uid);
  251. }
  252. else
  253. {
  254. ret = printf("%s\n", pw.pw_name);
  255. }
  256. }
  257. if(ret < 0) goto failure;
  258. goto done;
  259. }
  260. if(mode == ID_GROUPS)
  261. {
  262. if(real_flag)
  263. {
  264. ret = simple_list_groups(&pw, ngroups, groups);
  265. }
  266. else
  267. {
  268. ret = simple_list_groups(&epw, ngroups, groups);
  269. }
  270. if(ret != 0) goto failure;
  271. goto done;
  272. }
  273. ret = print_uid("uid", &pw, uid);
  274. if(ret < 0) goto failure;
  275. if(euid != uid)
  276. {
  277. ret = print_uid(" euid", &epw, euid);
  278. if(ret < 0) goto failure;
  279. }
  280. ret = print_gid(" gid", gr, gid);
  281. if(ret < 0) goto failure;
  282. if(egid != gid)
  283. {
  284. ret = print_gid(" egid", egr, egid);
  285. if(ret < 0) goto failure;
  286. }
  287. if(list_groups(&pw, ngroups, groups) != 0) goto failure;
  288. ret = printf("\n");
  289. if(ret < 0) goto failure;
  290. done:
  291. free(groups);
  292. return 0;
  293. failure:
  294. free(groups);
  295. return 1;
  296. }