Initial public busybox upstream commit
[busybox4maemo] / loginutils / addgroup.c
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
13 #include "libbb.h"
14
15 static void xgroup_study(struct group *g)
16 {
17         /* Make sure gr_name is unused */
18         if (getgrnam(g->gr_name)) {
19                 goto error;
20         }
21
22         /* Check if the desired gid is free
23          * or find the first free one */
24         while (1) {
25                 if (!getgrgid(g->gr_gid)) {
26                         return; /* found free group: return */
27                 }
28                 if (option_mask32) {
29                         /* -g N, cannot pick gid other than N: error */
30                         g->gr_name = itoa(g->gr_gid);
31                         goto error;
32                 }
33                 g->gr_gid++;
34                 if (g->gr_gid <= 0) {
35                         /* overflowed: error */
36                         bb_error_msg_and_die("no gids left");
37                 }
38         }
39
40  error:
41         /* exit */
42         bb_error_msg_and_die("group %s already exists", g->gr_name);
43 }
44
45 /* append a new user to the passwd file */
46 static void new_group(char *group, gid_t gid)
47 {
48         FILE *file;
49         struct group gr;
50
51         /* make sure gid and group haven't already been allocated */
52         gr.gr_gid = gid;
53         gr.gr_name = group;
54         xgroup_study(&gr);
55
56         /* add entry to group */
57         file = xfopen(bb_path_group_file, "a");
58         /* group:passwd:gid:userlist */
59         fprintf(file, "%s:x:%u:\n", group, (unsigned)gr.gr_gid);
60         if (ENABLE_FEATURE_CLEAN_UP)
61                 fclose(file);
62 #if ENABLE_FEATURE_SHADOWPASSWDS
63         file = fopen_or_warn(bb_path_gshadow_file, "a");
64         if (file) {
65                 fprintf(file, "%s:!::\n", group);
66                 if (ENABLE_FEATURE_CLEAN_UP)
67                         fclose(file);
68         }
69 #endif
70 }
71
72 #if ENABLE_FEATURE_ADDUSER_TO_GROUP
73 static void add_user_to_group(char **args,
74                 const char *path,
75                 FILE *(*fopen_func)(const char *fileName, const char *mode))
76 {
77         char *line;
78         int len = strlen(args[1]);
79         llist_t *plist = NULL;
80         FILE *group_file;
81
82         group_file = fopen_func(path, "r");
83
84         if (!group_file) return;
85
86         while ((line = xmalloc_getline(group_file))) {
87                 /* Find the group */
88                 if (!strncmp(line, args[1], len)
89                  && line[len] == ':'
90                 ) {
91                         /* Add the new user */
92                         line = xasprintf("%s%s%s", line,
93                                                 last_char_is(line, ':') ? "" : ",",
94                                                 args[0]);
95                 }
96                 llist_add_to_end(&plist, line);
97         }
98
99         if (ENABLE_FEATURE_CLEAN_UP) {
100                 fclose(group_file);
101                 group_file = fopen_func(path, "w");
102                 while ((line = llist_pop(&plist))) {
103                         if (group_file)
104                                 fprintf(group_file, "%s\n", line);
105                         free(line);
106                 }
107                 if (group_file)
108                         fclose(group_file);
109         } else {
110                 group_file = fopen_func(path, "w");
111                 if (group_file)
112                         while ((line = llist_pop(&plist)))
113                                 fprintf(group_file, "%s\n", line);
114         }
115 }
116 #endif
117
118 /*
119  * addgroup will take a login_name as its first parameter.
120  *
121  * gid can be customized via command-line parameters.
122  * If called with two non-option arguments, addgroup
123  * will add an existing user to an existing group.
124  */
125 int addgroup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
126 int addgroup_main(int argc ATTRIBUTE_UNUSED, char **argv)
127 {
128         char *group;
129         gid_t gid = 0;
130
131         /* need to be root */
132         if (geteuid()) {
133                 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
134         }
135
136         /* Syntax:
137          *  addgroup group
138          *  addgroup -g num group
139          *  addgroup user group
140          * Check for min, max and missing args */
141         opt_complementary = "-1:?2";
142         if (getopt32(argv, "g:", &group)) {
143                 gid = xatoul_range(group, 0, ((unsigned long)(gid_t)ULONG_MAX) >> 1);
144         }
145         /* move past the commandline options */
146         argv += optind;
147         //argc -= optind;
148
149 #if ENABLE_FEATURE_ADDUSER_TO_GROUP
150         if (argv[1]) {
151                 struct group *gr;
152
153                 if (option_mask32) {
154                         /* -g was there, but "addgroup -g num user group"
155                          * is a no-no */
156                         bb_show_usage();
157                 }
158
159                 /* check if group and user exist */
160                 xuname2uid(argv[0]); /* unknown user: exit */
161                 xgroup2gid(argv[1]); /* unknown group: exit */
162                 /* check if user is already in this group */
163                 gr = getgrnam(argv[1]);
164                 for (; *(gr->gr_mem) != NULL; (gr->gr_mem)++) {
165                         if (!strcmp(argv[0], *(gr->gr_mem))) {
166                                 /* user is already in group: do nothing */
167                                 return EXIT_SUCCESS;
168                         }
169                 }
170                 add_user_to_group(argv, bb_path_group_file, xfopen);
171 #if ENABLE_FEATURE_SHADOWPASSWDS
172                 add_user_to_group(argv, bb_path_gshadow_file, fopen_or_warn);
173 #endif
174         } else
175 #endif /* ENABLE_FEATURE_ADDUSER_TO_GROUP */
176         {
177                 die_if_bad_username(argv[0]);
178                 new_group(argv[0], gid);
179
180         }
181         /* Reached only on success */
182         return EXIT_SUCCESS;
183 }