id.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. id.c
  5. Abstract:
  6. This module implements the id utility, which prints out the user and group
  7. identifiers for the calling process.
  8. Author:
  9. Evan Green 6-Oct-2014
  10. Environment:
  11. POSIX
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <minoca/lib/types.h>
  17. #include <assert.h>
  18. #include <errno.h>
  19. #include <getopt.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <unistd.h>
  23. #include "swlib.h"
  24. //
  25. // ---------------------------------------------------------------- Definitions
  26. //
  27. #define ID_VERSION_MAJOR 1
  28. #define ID_VERSION_MINOR 0
  29. #define ID_USAGE \
  30. "usage: id [user]\n" \
  31. " id -G[-n] [user]\n" \
  32. " id -g[-nr] [user]\n" \
  33. " id -u[-nr] [user]\n" \
  34. "The id utility prints the user and group IDs and names of the invoking \n"\
  35. "process. If the effective and real IDs do not match, both will be \n" \
  36. "printed. If a user parameter is specified, then that user's data \n" \
  37. "will be printed, assuming the effective and real IDs match." \
  38. "Options are:\n" \
  39. " -G, --groups -- Output all different group IDs (effective, real, and \n"\
  40. " supplementary) only.\n" \
  41. " -g, --group -- Output only the effective group ID.\n" \
  42. " -n, --name -- Output the name instead of a number.\n" \
  43. " -r, --real -- Output the real ID instead of the effective ID.\n" \
  44. " -u, --user -- Output only the effective user ID.\n" \
  45. " --help -- Show this help text and exit.\n" \
  46. " --version -- Print the application version information and exit.\n"
  47. #define ID_OPTIONS_STRING "Ggnruh"
  48. //
  49. // Define ID options.
  50. //
  51. //
  52. // Set this option to print only all different group IDs.
  53. //
  54. #define ID_OPTION_ONLY_GROUPS 0x00000001
  55. //
  56. // Set this option to print only the effective group ID.
  57. //
  58. #define ID_OPTION_ONLY_GROUP 0x00000002
  59. //
  60. // Set this option to print only the effective user ID.
  61. //
  62. #define ID_OPTION_ONLY_USER 0x00000004
  63. //
  64. // Set this option to print names instead of numbers.
  65. //
  66. #define ID_OPTION_PRINT_NAMES 0x00000008
  67. //
  68. // Set this option to use the real instead of the effective ID.
  69. //
  70. #define ID_OPTION_REAL_ID 0x00000010
  71. //
  72. // Define the options that are mutually exclusive.
  73. //
  74. #define ID_OPTION_EXCLUSIVE_MASK \
  75. (ID_OPTION_ONLY_GROUPS | ID_OPTION_ONLY_GROUP | ID_OPTION_ONLY_USER)
  76. //
  77. // ------------------------------------------------------ Data Type Definitions
  78. //
  79. //
  80. // ----------------------------------------------- Internal Function Prototypes
  81. //
  82. INT
  83. IdPrintGroups (
  84. uid_t UserId,
  85. gid_t GroupId,
  86. INT Options
  87. );
  88. VOID
  89. IdPrintUserId (
  90. uid_t UserId,
  91. INT Options
  92. );
  93. VOID
  94. IdPrintGroupId (
  95. gid_t GroupId,
  96. INT Options
  97. );
  98. //
  99. // -------------------------------------------------------------------- Globals
  100. //
  101. struct option IdLongOptions[] = {
  102. {"groups", no_argument, 0, 'G'},
  103. {"group", no_argument, 0, 'g'},
  104. {"name", no_argument, 0, 'n'},
  105. {"real", no_argument, 0, 'r'},
  106. {"user", no_argument, 0, 'u'},
  107. {"help", no_argument, 0, 'h'},
  108. {"version", no_argument, 0, 'V'},
  109. {NULL, 0, 0, 0},
  110. };
  111. //
  112. // ------------------------------------------------------------------ Functions
  113. //
  114. INT
  115. IdMain (
  116. INT ArgumentCount,
  117. CHAR **Arguments
  118. )
  119. /*++
  120. Routine Description:
  121. This routine is the main entry point for the id utility.
  122. Arguments:
  123. ArgumentCount - Supplies the number of command line arguments the program
  124. was invoked with.
  125. Arguments - Supplies a tokenized array of command line arguments.
  126. Return Value:
  127. Returns an integer exit code. 0 for success, nonzero otherwise.
  128. --*/
  129. {
  130. ULONG ArgumentIndex;
  131. gid_t EffectiveGroupId;
  132. uid_t EffectiveUserId;
  133. INT Option;
  134. ULONG Options;
  135. gid_t RealGroupId;
  136. uid_t RealUserId;
  137. int Status;
  138. PSWISS_USER_INFORMATION UserInformation;
  139. PSTR UserNameArgument;
  140. Options = 0;
  141. UserInformation = NULL;
  142. //
  143. // Process the control arguments.
  144. //
  145. while (TRUE) {
  146. Option = getopt_long(ArgumentCount,
  147. Arguments,
  148. ID_OPTIONS_STRING,
  149. IdLongOptions,
  150. NULL);
  151. if (Option == -1) {
  152. break;
  153. }
  154. if ((Option == '?') || (Option == ':')) {
  155. Status = 1;
  156. goto MainEnd;
  157. }
  158. switch (Option) {
  159. case 'G':
  160. if ((Options & ID_OPTION_EXCLUSIVE_MASK) != 0) {
  161. SwPrintError(0,
  162. NULL,
  163. "Multiple mutually exclusive options supplied");
  164. Status = EINVAL;
  165. goto MainEnd;
  166. }
  167. Options |= ID_OPTION_ONLY_GROUPS;
  168. break;
  169. case 'g':
  170. if ((Options & ID_OPTION_EXCLUSIVE_MASK) != 0) {
  171. SwPrintError(0,
  172. NULL,
  173. "Multiple mutually exclusive options supplied");
  174. Status = EINVAL;
  175. goto MainEnd;
  176. }
  177. Options |= ID_OPTION_ONLY_GROUP;
  178. break;
  179. case 'n':
  180. Options |= ID_OPTION_PRINT_NAMES;
  181. break;
  182. case 'r':
  183. Options |= ID_OPTION_REAL_ID;
  184. break;
  185. case 'u':
  186. if ((Options & ID_OPTION_EXCLUSIVE_MASK) != 0) {
  187. SwPrintError(0,
  188. NULL,
  189. "Multiple mutually exclusive options supplied");
  190. Status = EINVAL;
  191. goto MainEnd;
  192. }
  193. Options |= ID_OPTION_ONLY_USER;
  194. break;
  195. case 'V':
  196. SwPrintVersion(ID_VERSION_MAJOR, ID_VERSION_MINOR);
  197. return 1;
  198. case 'h':
  199. printf(ID_USAGE);
  200. return 1;
  201. default:
  202. assert(FALSE);
  203. Status = 1;
  204. goto MainEnd;
  205. }
  206. }
  207. //
  208. // The modifiers are only valid if one of the "only" options was specified.
  209. //
  210. if (((Options & (ID_OPTION_PRINT_NAMES | ID_OPTION_REAL_ID)) != 0) &&
  211. ((Options & ID_OPTION_EXCLUSIVE_MASK) == 0)) {
  212. SwPrintError(0,
  213. NULL,
  214. "Cannot print names or real IDs in the default format");
  215. Status = 1;
  216. goto MainEnd;
  217. }
  218. Status = 0;
  219. ArgumentIndex = optind;
  220. if (ArgumentIndex > ArgumentCount) {
  221. ArgumentIndex = ArgumentCount;
  222. }
  223. UserNameArgument = NULL;
  224. if (ArgumentIndex < ArgumentCount) {
  225. UserNameArgument = Arguments[ArgumentIndex];
  226. if (ArgumentIndex + 1 != ArgumentCount) {
  227. SwPrintError(0, NULL, "Only one argument expected");
  228. Status = EINVAL;
  229. goto MainEnd;
  230. }
  231. }
  232. if (UserNameArgument == NULL) {
  233. RealUserId = SwGetRealUserId();
  234. RealGroupId = SwGetRealGroupId();
  235. EffectiveUserId = SwGetEffectiveUserId();
  236. EffectiveGroupId = SwGetEffectiveGroupId();
  237. } else {
  238. Status = SwGetUserInformationByName(UserNameArgument, &UserInformation);
  239. if (Status != 0) {
  240. SwPrintError(Status,
  241. UserNameArgument,
  242. "Failed to get information for user");
  243. goto MainEnd;
  244. }
  245. RealUserId = UserInformation->UserId;
  246. RealGroupId = UserInformation->GroupId;
  247. EffectiveUserId = RealUserId;
  248. EffectiveGroupId = RealGroupId;
  249. free(UserInformation);
  250. UserInformation = NULL;
  251. }
  252. if (((Options & ID_OPTION_EXCLUSIVE_MASK) != 0) &&
  253. ((Options & ID_OPTION_REAL_ID) != 0)) {
  254. EffectiveUserId = RealUserId;
  255. EffectiveGroupId = RealGroupId;
  256. }
  257. if ((Options & ID_OPTION_ONLY_USER) != 0) {
  258. IdPrintUserId(EffectiveUserId, Options);
  259. } else if ((Options & ID_OPTION_ONLY_GROUP) != 0) {
  260. IdPrintGroupId(EffectiveGroupId, Options);
  261. } else if ((Options & ID_OPTION_ONLY_GROUPS) != 0) {
  262. Status = IdPrintGroups(EffectiveUserId, EffectiveGroupId, Options);
  263. //
  264. // Print the fancy default format.
  265. //
  266. } else {
  267. printf("uid=");
  268. IdPrintUserId(RealUserId, Options);
  269. printf(" gid=");
  270. IdPrintGroupId(RealGroupId, Options);
  271. if (RealUserId != EffectiveUserId) {
  272. printf(" euid=");
  273. IdPrintUserId(EffectiveUserId, Options);
  274. }
  275. if (RealGroupId != EffectiveGroupId) {
  276. printf(" egid=");
  277. IdPrintGroupId(EffectiveGroupId, Options);
  278. }
  279. printf(" groups=");
  280. Status = IdPrintGroups(EffectiveUserId, EffectiveGroupId, Options);
  281. }
  282. printf("\n");
  283. MainEnd:
  284. return Status;
  285. }
  286. //
  287. // --------------------------------------------------------- Internal Functions
  288. //
  289. INT
  290. IdPrintGroups (
  291. uid_t UserId,
  292. gid_t GroupId,
  293. INT Options
  294. )
  295. /*++
  296. Routine Description:
  297. This routine prints all the groups a user is a member of.
  298. Arguments:
  299. UserId - Supplies the ID of the user to print.
  300. GroupId - Supplies the primary group the user belongs to.
  301. Options - Supplies the options the utility was invoked with.
  302. Return Value:
  303. 0 on success.
  304. Returns an error code on failure.
  305. --*/
  306. {
  307. size_t GroupCount;
  308. size_t GroupIndex;
  309. gid_t *Groups;
  310. INT Result;
  311. Groups = NULL;
  312. GroupCount = 0;
  313. Result = SwGetGroupList(UserId, GroupId, &Groups, &GroupCount);
  314. if (Result != 0) {
  315. SwPrintError(Result,
  316. NULL,
  317. "Failed to get groups for user %u",
  318. (unsigned int)UserId);
  319. return Result;
  320. }
  321. for (GroupIndex = 0; GroupIndex < GroupCount; GroupIndex += 1) {
  322. IdPrintGroupId(Groups[GroupIndex], Options);
  323. if (GroupIndex != GroupCount - 1) {
  324. if ((Options & ID_OPTION_ONLY_GROUPS) != 0) {
  325. printf(" ");
  326. } else {
  327. printf(",");
  328. }
  329. }
  330. }
  331. if (Groups != NULL) {
  332. free(Groups);
  333. }
  334. return 0;
  335. }
  336. VOID
  337. IdPrintUserId (
  338. uid_t UserId,
  339. INT Options
  340. )
  341. /*++
  342. Routine Description:
  343. This routine prints a user ID (real or effective).
  344. Arguments:
  345. UserId - Supplies the ID of the user to print.
  346. Options - Supplies the options the utility was invoked with, which governs
  347. whether the id number, name or both are printed.
  348. Return Value:
  349. None.
  350. --*/
  351. {
  352. PSTR UserName;
  353. //
  354. // If there was no exclusive option or names were requested, get the name.
  355. //
  356. UserName = NULL;
  357. if (((Options & ID_OPTION_EXCLUSIVE_MASK) == 0) ||
  358. ((Options & ID_OPTION_PRINT_NAMES) != 0)) {
  359. SwGetUserNameFromId(UserId, &UserName);
  360. }
  361. //
  362. // If one of the "only" options was specified, then either the name or the
  363. // number is printed.
  364. //
  365. if ((Options & ID_OPTION_EXCLUSIVE_MASK) != 0) {
  366. if ((Options & ID_OPTION_PRINT_NAMES) != 0) {
  367. printf("%s", UserName);
  368. } else {
  369. printf("%u", (unsigned int)UserId);
  370. }
  371. //
  372. // Print both if present.
  373. //
  374. } else {
  375. printf("%u(%s)", (unsigned int)UserId, UserName);
  376. }
  377. if (UserName != NULL) {
  378. free(UserName);
  379. }
  380. return;
  381. }
  382. VOID
  383. IdPrintGroupId (
  384. gid_t GroupId,
  385. INT Options
  386. )
  387. /*++
  388. Routine Description:
  389. This routine prints a group ID.
  390. Arguments:
  391. GroupId - Supplies the ID of the group to print.
  392. Options - Supplies the options the utility was invoked with, which governs
  393. whether the id number, name or both are printed.
  394. Return Value:
  395. None.
  396. --*/
  397. {
  398. PSTR GroupName;
  399. //
  400. // If there was no exclusive option or names were requested, get the name.
  401. //
  402. GroupName = NULL;
  403. if (((Options & ID_OPTION_EXCLUSIVE_MASK) == 0) ||
  404. ((Options & ID_OPTION_PRINT_NAMES) != 0)) {
  405. SwGetGroupNameFromId(GroupId, &GroupName);
  406. }
  407. //
  408. // If one of the "only" options was specified, then either the name or the
  409. // number is printed.
  410. //
  411. if ((Options & ID_OPTION_EXCLUSIVE_MASK) != 0) {
  412. if ((Options & ID_OPTION_PRINT_NAMES) != 0) {
  413. printf("%s", GroupName);
  414. } else {
  415. printf("%u", (unsigned int)GroupId);
  416. }
  417. //
  418. // Print both if present.
  419. //
  420. } else {
  421. printf("%u(%s)", (unsigned int)GroupId, GroupName);
  422. }
  423. if (GroupName != NULL) {
  424. free(GroupName);
  425. }
  426. return;
  427. }