addgroup.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * addgroup - add groups to /etc/group and /etc/gshadow
  4. *
  5. * Copyright (C) 1999 by Lineo, inc. and John Beppu
  6. * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
  7. * Copyright (C) 2007 by Tito Ragusa <farmatito@tiscali.it>
  8. *
  9. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  10. *
  11. */
  12. #include "libbb.h"
  13. #if CONFIG_LAST_SYSTEM_ID < CONFIG_FIRST_SYSTEM_ID
  14. #error Bad LAST_SYSTEM_ID or FIRST_SYSTEM_ID in .config
  15. #endif
  16. #define OPT_GID (1 << 0)
  17. #define OPT_SYSTEM_ACCOUNT (1 << 1)
  18. /* We assume GID_T_MAX == INT_MAX */
  19. static void xgroup_study(struct group *g)
  20. {
  21. unsigned max = INT_MAX;
  22. /* Make sure gr_name is unused */
  23. if (getgrnam(g->gr_name)) {
  24. bb_error_msg_and_die("%s '%s' in use", "group", g->gr_name);
  25. /* these format strings are reused in adduser and addgroup */
  26. }
  27. /* if a specific gid is requested, the --system switch and */
  28. /* min and max values are overridden, and the range of valid */
  29. /* gid values is set to [0, INT_MAX] */
  30. if (!(option_mask32 & OPT_GID)) {
  31. if (option_mask32 & OPT_SYSTEM_ACCOUNT) {
  32. g->gr_gid = CONFIG_FIRST_SYSTEM_ID;
  33. max = CONFIG_LAST_SYSTEM_ID;
  34. } else {
  35. g->gr_gid = CONFIG_LAST_SYSTEM_ID + 1;
  36. max = 64999;
  37. }
  38. }
  39. /* Check if the desired gid is free
  40. * or find the first free one */
  41. while (1) {
  42. if (!getgrgid(g->gr_gid)) {
  43. return; /* found free group: return */
  44. }
  45. if (option_mask32 & OPT_GID) {
  46. /* -g N, cannot pick gid other than N: error */
  47. bb_error_msg_and_die("%s '%s' in use", "gid", itoa(g->gr_gid));
  48. /* this format strings is reused in adduser and addgroup */
  49. }
  50. if (g->gr_gid == max) {
  51. /* overflowed: error */
  52. bb_error_msg_and_die("no %cids left", 'g');
  53. /* this format string is reused in adduser and addgroup */
  54. }
  55. g->gr_gid++;
  56. }
  57. }
  58. /* append a new user to the passwd file */
  59. static void new_group(char *group, gid_t gid)
  60. {
  61. struct group gr;
  62. char *p;
  63. /* make sure gid and group haven't already been allocated */
  64. gr.gr_gid = gid;
  65. gr.gr_name = group;
  66. xgroup_study(&gr);
  67. /* add entry to group */
  68. p = xasprintf("x:%u:", (unsigned) gr.gr_gid);
  69. if (update_passwd(bb_path_group_file, group, p, NULL) < 0)
  70. exit(EXIT_FAILURE);
  71. if (ENABLE_FEATURE_CLEAN_UP)
  72. free(p);
  73. #if ENABLE_FEATURE_SHADOWPASSWDS
  74. /* /etc/gshadow fields:
  75. * 1. Group name.
  76. * 2. Encrypted password.
  77. * If set, non-members of the group can join the group
  78. * by typing the password for that group using the newgrp command.
  79. * If the value is of this field ! then no user is allowed
  80. * to access the group using the newgrp command. A value of !!
  81. * is treated the same as a value of ! only it indicates
  82. * that a password has never been set before. If the value is null,
  83. * only group members can log into the group.
  84. * 3. Group administrators (comma delimited list).
  85. * Group members listed here can add or remove group members
  86. * using the gpasswd command.
  87. * 4. Group members (comma delimited list).
  88. */
  89. /* Ignore errors: if file is missing we assume admin doesn't want it */
  90. update_passwd(bb_path_gshadow_file, group, "!::", NULL);
  91. #endif
  92. }
  93. #if ENABLE_FEATURE_ADDGROUP_LONG_OPTIONS
  94. static const char addgroup_longopts[] ALIGN1 =
  95. "gid\0" Required_argument "g"
  96. "system\0" No_argument "S"
  97. ;
  98. #endif
  99. /*
  100. * addgroup will take a login_name as its first parameter.
  101. *
  102. * gid can be customized via command-line parameters.
  103. * If called with two non-option arguments, addgroup
  104. * will add an existing user to an existing group.
  105. */
  106. int addgroup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  107. int addgroup_main(int argc UNUSED_PARAM, char **argv)
  108. {
  109. unsigned opts;
  110. unsigned gid = 0;
  111. /* need to be root */
  112. if (geteuid()) {
  113. bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
  114. }
  115. #if ENABLE_FEATURE_ADDGROUP_LONG_OPTIONS
  116. applet_long_options = addgroup_longopts;
  117. #endif
  118. /* Syntax:
  119. * addgroup group
  120. * addgroup -g num group
  121. * addgroup user group
  122. * Check for min, max and missing args */
  123. opt_complementary = "-1:?2:g+";
  124. opts = getopt32(argv, "g:S", &gid);
  125. /* move past the commandline options */
  126. argv += optind;
  127. //argc -= optind;
  128. #if ENABLE_FEATURE_ADDUSER_TO_GROUP
  129. if (argv[1]) {
  130. struct group *gr;
  131. if (opts & OPT_GID) {
  132. /* -g was there, but "addgroup -g num user group"
  133. * is a no-no */
  134. bb_show_usage();
  135. }
  136. /* check if group and user exist */
  137. xuname2uid(argv[0]); /* unknown user: exit */
  138. gr = xgetgrnam(argv[1]); /* unknown group: exit */
  139. /* check if user is already in this group */
  140. for (; *(gr->gr_mem) != NULL; (gr->gr_mem)++) {
  141. if (!strcmp(argv[0], *(gr->gr_mem))) {
  142. /* user is already in group: do nothing */
  143. return EXIT_SUCCESS;
  144. }
  145. }
  146. if (update_passwd(bb_path_group_file, argv[1], NULL, argv[0]) < 0) {
  147. return EXIT_FAILURE;
  148. }
  149. # if ENABLE_FEATURE_SHADOWPASSWDS
  150. update_passwd(bb_path_gshadow_file, argv[1], NULL, argv[0]);
  151. # endif
  152. } else
  153. #endif /* ENABLE_FEATURE_ADDUSER_TO_GROUP */
  154. {
  155. die_if_bad_username(argv[0]);
  156. new_group(argv[0], gid);
  157. }
  158. /* Reached only on success */
  159. return EXIT_SUCCESS;
  160. }