logo

utils-std

Collection of commonly available Unix tools

id.c (5720B)


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