1 |
/* vi: set sw=4 ts=4: */ |
/* vi: set sw=4 ts=4: */ |
2 |
/* |
/* |
3 |
* addgroup - add users to /etc/passwd and /etc/shadow |
* addgroup - add groups to /etc/group and /etc/gshadow |
4 |
* |
* |
5 |
* Copyright (C) 1999 by Lineo, inc. and John Beppu |
* Copyright (C) 1999 by Lineo, inc. and John Beppu |
6 |
* Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org> |
* 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. |
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
10 |
* |
* |
11 |
*/ |
*/ |
12 |
|
|
13 |
#include "busybox.h" |
#include "libbb.h" |
14 |
|
|
15 |
/* make sure gr_name isn't taken, make sure gid is kosher |
static void xgroup_study(struct group *g) |
|
* return 1 on failure */ |
|
|
static int group_study(struct group *g) |
|
16 |
{ |
{ |
17 |
FILE *etc_group; |
/* Make sure gr_name is unused */ |
18 |
gid_t desired; |
if (getgrnam(g->gr_name)) { |
19 |
|
goto error; |
20 |
struct group *grp; |
} |
|
const int max = 65000; |
|
|
|
|
|
etc_group = xfopen(bb_path_group_file, "r"); |
|
21 |
|
|
22 |
/* make sure gr_name isn't taken, make sure gid is kosher */ |
/* Check if the desired gid is free |
23 |
desired = g->gr_gid; |
* or find the first free one */ |
24 |
while ((grp = fgetgrent(etc_group))) { |
while (1) { |
25 |
if ((strcmp(grp->gr_name, g->gr_name)) == 0) { |
if (!getgrgid(g->gr_gid)) { |
26 |
bb_error_msg_and_die("%s: group already in use", g->gr_name); |
return; /* found free group: return */ |
27 |
} |
} |
28 |
if ((desired) && grp->gr_gid == desired) { |
if (option_mask32) { |
29 |
bb_error_msg_and_die("%d: gid already in use", |
/* -g N, cannot pick gid other than N: error */ |
30 |
desired); |
g->gr_name = itoa(g->gr_gid); |
31 |
|
goto error; |
32 |
} |
} |
33 |
if ((grp->gr_gid > g->gr_gid) && (grp->gr_gid < max)) { |
g->gr_gid++; |
34 |
g->gr_gid = grp->gr_gid; |
if (g->gr_gid <= 0) { |
35 |
|
/* overflowed: error */ |
36 |
|
bb_error_msg_and_die("no gids left"); |
37 |
} |
} |
38 |
} |
} |
|
fclose(etc_group); |
|
39 |
|
|
40 |
/* gid */ |
error: |
41 |
if (desired) { |
/* exit */ |
42 |
g->gr_gid = desired; |
bb_error_msg_and_die("group %s already exists", g->gr_name); |
|
} else { |
|
|
g->gr_gid++; |
|
|
} |
|
|
/* return 1; */ |
|
|
return 0; |
|
43 |
} |
} |
44 |
|
|
45 |
/* append a new user to the passwd file */ |
/* append a new user to the passwd file */ |
46 |
static int addgroup(char *group, gid_t gid, const char *user) |
static void new_group(char *group, gid_t gid) |
47 |
{ |
{ |
48 |
FILE *file; |
FILE *file; |
49 |
struct group gr; |
struct group gr; |
51 |
/* make sure gid and group haven't already been allocated */ |
/* make sure gid and group haven't already been allocated */ |
52 |
gr.gr_gid = gid; |
gr.gr_gid = gid; |
53 |
gr.gr_name = group; |
gr.gr_name = group; |
54 |
if (group_study(&gr)) |
xgroup_study(&gr); |
|
return 1; |
|
55 |
|
|
56 |
/* add entry to group */ |
/* add entry to group */ |
57 |
file = xfopen(bb_path_group_file, "a"); |
file = xfopen(bb_path_group_file, "a"); |
58 |
/* group:passwd:gid:userlist */ |
/* group:passwd:gid:userlist */ |
59 |
fprintf(file, "%s:%s:%d:%s\n", group, "x", gr.gr_gid, user); |
fprintf(file, "%s:x:%u:\n", group, (unsigned)gr.gr_gid); |
60 |
fclose(file); |
if (ENABLE_FEATURE_CLEAN_UP) |
61 |
|
fclose(file); |
62 |
#if ENABLE_FEATURE_SHADOWPASSWDS |
#if ENABLE_FEATURE_SHADOWPASSWDS |
63 |
file = xfopen(bb_path_gshadow_file, "a"); |
file = fopen_or_warn(bb_path_gshadow_file, "a"); |
64 |
fprintf(file, "%s:!::\n", group); |
if (file) { |
65 |
fclose(file); |
fprintf(file, "%s:!::\n", group); |
66 |
|
if (ENABLE_FEATURE_CLEAN_UP) |
67 |
|
fclose(file); |
68 |
|
} |
69 |
#endif |
#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* FAST_FUNC (*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_fgetline(group_file)) != NULL) { |
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 |
/* return 1; */ |
if (ENABLE_FEATURE_CLEAN_UP) { |
100 |
return 0; |
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. |
* addgroup will take a login_name as its first parameter. |
120 |
* |
* |
121 |
* gid |
* gid can be customized via command-line parameters. |
122 |
* |
* If called with two non-option arguments, addgroup |
123 |
* can be customized via command-line parameters. |
* will add an existing user to an existing group. |
124 |
* ________________________________________________________________________ */ |
*/ |
125 |
int addgroup_main(int argc, char **argv) |
int addgroup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
126 |
|
int addgroup_main(int argc UNUSED_PARAM, char **argv) |
127 |
{ |
{ |
128 |
char *group; |
char *group; |
129 |
gid_t gid = 0; |
gid_t gid = 0; |
130 |
|
|
|
/* check for min, max and missing args and exit on error */ |
|
|
opt_complementary = "-1:?2:?"; |
|
|
if (getopt32(argc, argv, "g:", &group)) { |
|
|
gid = xatoul_range(group, 0, (gid_t)ULONG_MAX); |
|
|
} |
|
|
/* move past the commandline options */ |
|
|
argv += optind; |
|
|
|
|
131 |
/* need to be root */ |
/* need to be root */ |
132 |
if (geteuid()) { |
if (geteuid()) { |
133 |
bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); |
bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); |
134 |
} |
} |
135 |
|
|
136 |
/* werk */ |
/* Syntax: |
137 |
return addgroup(argv[0], gid, (argv[1]) ? argv[1] : ""); |
* 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 |
} |
} |