pw_user.c (5e779680a9ad885a3d749047f205b08e4506bf23) pw_user.c (1dcc6ec750ce84c42fee6fb29a88c20b3b91f4ed)
1/*-
2 * Copyright (C) 1996
3 * David L. Nugent. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 8 unchanged lines hidden (view full) ---

17 * ARE DISCLAIMED. IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
1/*-
2 * Copyright (C) 1996
3 * David L. Nugent. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 8 unchanged lines hidden (view full) ---

17 * ARE DISCLAIMED. IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $Id: pw_user.c,v 1.21 1997/06/14 00:23:49 ache Exp $
27 */
28
25 */
26
29#include <unistd.h>
30#include <fcntl.h>
27#ifndef lint
28static const char rcsid[] =
29 "$Id$";
30#endif /* not lint */
31
31#include <ctype.h>
32#include <ctype.h>
32#include <paths.h>
33#include <err.h>
34#include <fcntl.h>
33#include <sys/param.h>
34#include <dirent.h>
35#include <sys/param.h>
36#include <dirent.h>
37#include <paths.h>
35#include <termios.h>
36#include <sys/types.h>
37#include <sys/time.h>
38#include <sys/resource.h>
38#include <termios.h>
39#include <sys/types.h>
40#include <sys/time.h>
41#include <sys/resource.h>
42#include <unistd.h>
39#include <utmp.h>
40#if defined(USE_MD5RAND)
41#include <md5.h>
42#endif
43#include "pw.h"
44#include "bitmap.h"
45#include "pwupd.h"
46

--- 103 unchanged lines hidden (view full) ---

150 */
151 if (arg != NULL || getarg(args, 'm') != NULL) {
152 int l = strlen(cnf->home);
153
154 if (l > 1 && cnf->home[l-1] == '/') /* Shave off any trailing path delimiter */
155 cnf->home[--l] = '\0';
156
157 if (l < 2 || *cnf->home != '/') /* Check for absolute path name */
43#include <utmp.h>
44#if defined(USE_MD5RAND)
45#include <md5.h>
46#endif
47#include "pw.h"
48#include "bitmap.h"
49#include "pwupd.h"
50

--- 103 unchanged lines hidden (view full) ---

154 */
155 if (arg != NULL || getarg(args, 'm') != NULL) {
156 int l = strlen(cnf->home);
157
158 if (l > 1 && cnf->home[l-1] == '/') /* Shave off any trailing path delimiter */
159 cnf->home[--l] = '\0';
160
161 if (l < 2 || *cnf->home != '/') /* Check for absolute path name */
158 cmderr(EX_DATAERR, "invalid base directory for home '%s'\n", cnf->home);
162 errx(EX_DATAERR, "invalid base directory for home '%s'", cnf->home);
159
160 if (stat(cnf->home, &st) == -1) {
161 char dbuf[MAXPATHLEN];
162
163 /*
164 * This is a kludge especially for Joerg :)
165 * If the home directory would be created in the root partition, then
166 * we really create it under /usr which is likely to have more space.

--- 13 unchanged lines hidden (view full) ---

180 if (stat(dbuf, &st) == -1) {
181 while ((p = strchr(++p, '/')) != NULL) {
182 *p = '\0';
183 if (stat(dbuf, &st) == -1) {
184 if (mkdir(dbuf, 0755) == -1)
185 goto direrr;
186 chown(dbuf, 0, 0);
187 } else if (!S_ISDIR(st.st_mode))
163
164 if (stat(cnf->home, &st) == -1) {
165 char dbuf[MAXPATHLEN];
166
167 /*
168 * This is a kludge especially for Joerg :)
169 * If the home directory would be created in the root partition, then
170 * we really create it under /usr which is likely to have more space.

--- 13 unchanged lines hidden (view full) ---

184 if (stat(dbuf, &st) == -1) {
185 while ((p = strchr(++p, '/')) != NULL) {
186 *p = '\0';
187 if (stat(dbuf, &st) == -1) {
188 if (mkdir(dbuf, 0755) == -1)
189 goto direrr;
190 chown(dbuf, 0, 0);
191 } else if (!S_ISDIR(st.st_mode))
188 cmderr(EX_OSFILE, "'%s' (root home parent) is not a directory\n", dbuf);
192 errx(EX_OSFILE, "'%s' (root home parent) is not a directory", dbuf);
189 *p = '/';
190 }
191 }
192 if (stat(dbuf, &st) == -1) {
193 if (mkdir(dbuf, 0755) == -1) {
193 *p = '/';
194 }
195 }
196 if (stat(dbuf, &st) == -1) {
197 if (mkdir(dbuf, 0755) == -1) {
194 direrr: cmderr(EX_OSFILE, "mkdir '%s': %s\n", dbuf, strerror(errno));
198 direrr: err(EX_OSFILE, "mkdir '%s'", dbuf);
195 }
196 chown(dbuf, 0, 0);
197 }
198 } else if (!S_ISDIR(st.st_mode))
199 }
200 chown(dbuf, 0, 0);
201 }
202 } else if (!S_ISDIR(st.st_mode))
199 cmderr(EX_OSFILE, "root home `%s' is not a directory\n", cnf->home);
203 errx(EX_OSFILE, "root home `%s' is not a directory", cnf->home);
200 }
201
202
203 if ((arg = getarg(args, 'e')) != NULL)
204 cnf->expire_days = atoi(arg->val);
205
206 if ((arg = getarg(args, 'y')) != NULL)
207 cnf->nispasswd = arg->val;
208
209 if ((arg = getarg(args, 'p')) != NULL && arg->val)
210 cnf->password_days = atoi(arg->val);
211
212 if ((arg = getarg(args, 'g')) != NULL) {
213 p = arg->val;
214 if ((grp = getgrnam(p)) == NULL) {
215 if (!isdigit(*p) || (grp = getgrgid((gid_t) atoi(p))) == NULL)
204 }
205
206
207 if ((arg = getarg(args, 'e')) != NULL)
208 cnf->expire_days = atoi(arg->val);
209
210 if ((arg = getarg(args, 'y')) != NULL)
211 cnf->nispasswd = arg->val;
212
213 if ((arg = getarg(args, 'p')) != NULL && arg->val)
214 cnf->password_days = atoi(arg->val);
215
216 if ((arg = getarg(args, 'g')) != NULL) {
217 p = arg->val;
218 if ((grp = getgrnam(p)) == NULL) {
219 if (!isdigit(*p) || (grp = getgrgid((gid_t) atoi(p))) == NULL)
216 cmderr(EX_NOUSER, "group `%s' does not exist\n", p);
220 errx(EX_NOUSER, "group `%s' does not exist", p);
217 }
218 cnf->default_group = newstr(grp->gr_name);
219 }
220 if ((arg = getarg(args, 'L')) != NULL)
221 cnf->default_class = pw_checkname((u_char *)arg->val, 0);
222
223 if ((arg = getarg(args, 'G')) != NULL && arg->val) {
224 int i = 0;
225
226 for (p = strtok(arg->val, ", \t"); p != NULL; p = strtok(NULL, ", \t")) {
227 if ((grp = getgrnam(p)) == NULL) {
228 if (!isdigit(*p) || (grp = getgrgid((gid_t) atoi(p))) == NULL)
221 }
222 cnf->default_group = newstr(grp->gr_name);
223 }
224 if ((arg = getarg(args, 'L')) != NULL)
225 cnf->default_class = pw_checkname((u_char *)arg->val, 0);
226
227 if ((arg = getarg(args, 'G')) != NULL && arg->val) {
228 int i = 0;
229
230 for (p = strtok(arg->val, ", \t"); p != NULL; p = strtok(NULL, ", \t")) {
231 if ((grp = getgrnam(p)) == NULL) {
232 if (!isdigit(*p) || (grp = getgrgid((gid_t) atoi(p))) == NULL)
229 cmderr(EX_NOUSER, "group `%s' does not exist\n", p);
233 errx(EX_NOUSER, "group `%s' does not exist", p);
230 }
231 if (extendarray(&cnf->groups, &cnf->numgroups, i + 2) != -1)
232 cnf->groups[i++] = newstr(grp->gr_name);
233 }
234 while (i < cnf->numgroups)
235 cnf->groups[i++] = NULL;
236 }
237 if ((arg = getarg(args, 'k')) != NULL) {
238 if (stat(cnf->dotdir = arg->val, &st) == -1 || !S_ISDIR(st.st_mode))
234 }
235 if (extendarray(&cnf->groups, &cnf->numgroups, i + 2) != -1)
236 cnf->groups[i++] = newstr(grp->gr_name);
237 }
238 while (i < cnf->numgroups)
239 cnf->groups[i++] = NULL;
240 }
241 if ((arg = getarg(args, 'k')) != NULL) {
242 if (stat(cnf->dotdir = arg->val, &st) == -1 || !S_ISDIR(st.st_mode))
239 cmderr(EX_OSFILE, "skeleton `%s' is not a directory or does not exist\n", cnf->dotdir);
243 errx(EX_OSFILE, "skeleton `%s' is not a directory or does not exist", cnf->dotdir);
240 }
241 if ((arg = getarg(args, 's')) != NULL)
242 cnf->shell_default = arg->val;
243
244 if (mode == M_ADD && getarg(args, 'D')) {
245 if (getarg(args, 'n') != NULL)
244 }
245 if ((arg = getarg(args, 's')) != NULL)
246 cnf->shell_default = arg->val;
247
248 if (mode == M_ADD && getarg(args, 'D')) {
249 if (getarg(args, 'n') != NULL)
246 cmderr(EX_DATAERR, "can't combine `-D' with `-n name'\n");
250 errx(EX_DATAERR, "can't combine `-D' with `-n name'");
247 if ((arg = getarg(args, 'u')) != NULL && (p = strtok(arg->val, ", \t")) != NULL) {
248 if ((cnf->min_uid = (uid_t) atoi(p)) == 0)
249 cnf->min_uid = 1000;
250 if ((p = strtok(NULL, " ,\t")) == NULL || (cnf->max_uid = (uid_t) atoi(p)) < cnf->min_uid)
251 cnf->max_uid = 32000;
252 }
253 if ((arg = getarg(args, 'i')) != NULL && (p = strtok(arg->val, ", \t")) != NULL) {
254 if ((cnf->min_gid = (gid_t) atoi(p)) == 0)
255 cnf->min_gid = 1000;
256 if ((p = strtok(NULL, " ,\t")) == NULL || (cnf->max_gid = (gid_t) atoi(p)) < cnf->min_gid)
257 cnf->max_gid = 32000;
258 }
259 if ((arg = getarg(args, 'w')) != NULL)
260 cnf->default_password = boolean_val(arg->val, cnf->default_password);
261
262 arg = getarg(args, 'C');
263 if (write_userconfig(arg ? arg->val : NULL))
264 return EXIT_SUCCESS;
251 if ((arg = getarg(args, 'u')) != NULL && (p = strtok(arg->val, ", \t")) != NULL) {
252 if ((cnf->min_uid = (uid_t) atoi(p)) == 0)
253 cnf->min_uid = 1000;
254 if ((p = strtok(NULL, " ,\t")) == NULL || (cnf->max_uid = (uid_t) atoi(p)) < cnf->min_uid)
255 cnf->max_uid = 32000;
256 }
257 if ((arg = getarg(args, 'i')) != NULL && (p = strtok(arg->val, ", \t")) != NULL) {
258 if ((cnf->min_gid = (gid_t) atoi(p)) == 0)
259 cnf->min_gid = 1000;
260 if ((p = strtok(NULL, " ,\t")) == NULL || (cnf->max_gid = (gid_t) atoi(p)) < cnf->min_gid)
261 cnf->max_gid = 32000;
262 }
263 if ((arg = getarg(args, 'w')) != NULL)
264 cnf->default_password = boolean_val(arg->val, cnf->default_password);
265
266 arg = getarg(args, 'C');
267 if (write_userconfig(arg ? arg->val : NULL))
268 return EXIT_SUCCESS;
265 perror("config update");
269 warn("config update");
266 return EX_IOERR;
267 }
268 if (mode == M_PRINT && getarg(args, 'a')) {
269 int pretty = getarg(args, 'P') != NULL;
270
271 setpwent();
272 while ((pwd = getpwent()) != NULL)
273 print_user(pwd, pretty);
274 endpwent();
275 return EXIT_SUCCESS;
276 }
277 if ((a_name = getarg(args, 'n')) != NULL)
278 pwd = getpwnam(pw_checkname((u_char *)a_name->val, 0));
279 a_uid = getarg(args, 'u');
280
281 if (a_uid == NULL) {
282 if (a_name == NULL)
270 return EX_IOERR;
271 }
272 if (mode == M_PRINT && getarg(args, 'a')) {
273 int pretty = getarg(args, 'P') != NULL;
274
275 setpwent();
276 while ((pwd = getpwent()) != NULL)
277 print_user(pwd, pretty);
278 endpwent();
279 return EXIT_SUCCESS;
280 }
281 if ((a_name = getarg(args, 'n')) != NULL)
282 pwd = getpwnam(pw_checkname((u_char *)a_name->val, 0));
283 a_uid = getarg(args, 'u');
284
285 if (a_uid == NULL) {
286 if (a_name == NULL)
283 cmderr(EX_DATAERR, "user name or id required\n");
287 errx(EX_DATAERR, "user name or id required");
284
285 /*
286 * Determine whether 'n' switch is name or uid - we don't
287 * really don't really care which we have, but we need to
288 * know.
289 */
290 if (mode != M_ADD && pwd == NULL && isdigit(*a_name->val) && atoi(a_name->val) > 0) { /* Assume uid */
291 (a_uid = a_name)->ch = 'u';

--- 9 unchanged lines hidden (view full) ---

301
302 if (pwd == NULL) {
303 if (mode == M_PRINT && getarg(args, 'F')) {
304 fakeuser.pw_name = a_name ? a_name->val : "nouser";
305 fakeuser.pw_uid = a_uid ? (uid_t) atol(a_uid->val) : -1;
306 return print_user(&fakeuser, getarg(args, 'P') != NULL);
307 }
308 if (a_name == NULL)
288
289 /*
290 * Determine whether 'n' switch is name or uid - we don't
291 * really don't really care which we have, but we need to
292 * know.
293 */
294 if (mode != M_ADD && pwd == NULL && isdigit(*a_name->val) && atoi(a_name->val) > 0) { /* Assume uid */
295 (a_uid = a_name)->ch = 'u';

--- 9 unchanged lines hidden (view full) ---

305
306 if (pwd == NULL) {
307 if (mode == M_PRINT && getarg(args, 'F')) {
308 fakeuser.pw_name = a_name ? a_name->val : "nouser";
309 fakeuser.pw_uid = a_uid ? (uid_t) atol(a_uid->val) : -1;
310 return print_user(&fakeuser, getarg(args, 'P') != NULL);
311 }
312 if (a_name == NULL)
309 cmderr(EX_NOUSER, "no such uid `%s'\n", a_uid->val);
310 cmderr(EX_NOUSER, "no such user `%s'\n", a_name->val);
313 errx(EX_NOUSER, "no such uid `%s'", a_uid->val);
314 errx(EX_NOUSER, "no such user `%s'", a_name->val);
311 }
312 if (a_name == NULL) /* May be needed later */
313 a_name = addarg(args, 'n', newstr(pwd->pw_name));
314
315 /*
316 * Handle deletions now
317 */
318 if (mode == M_DELETE) {
319 char file[MAXPATHLEN];
320 char home[MAXPATHLEN];
321 uid_t uid = pwd->pw_uid;
322
323 if (strcmp(pwd->pw_name, "root") == 0)
315 }
316 if (a_name == NULL) /* May be needed later */
317 a_name = addarg(args, 'n', newstr(pwd->pw_name));
318
319 /*
320 * Handle deletions now
321 */
322 if (mode == M_DELETE) {
323 char file[MAXPATHLEN];
324 char home[MAXPATHLEN];
325 uid_t uid = pwd->pw_uid;
326
327 if (strcmp(pwd->pw_name, "root") == 0)
324 cmderr(EX_DATAERR, "cannot remove user 'root'\n");
328 errx(EX_DATAERR, "cannot remove user 'root'");
325
326 /*
327 * Remove skey record from /etc/skeykeys
328 */
329
330 rmskey(pwd->pw_name);
331
332 /*

--- 8 unchanged lines hidden (view full) ---

341 * Save these for later, since contents of pwd may be
342 * invalidated by deletion
343 */
344 sprintf(file, "%s/%s", _PATH_MAILDIR, pwd->pw_name);
345 strncpy(home, pwd->pw_dir, sizeof home);
346 home[sizeof home - 1] = '\0';
347
348 if (!delpwent(pwd))
329
330 /*
331 * Remove skey record from /etc/skeykeys
332 */
333
334 rmskey(pwd->pw_name);
335
336 /*

--- 8 unchanged lines hidden (view full) ---

345 * Save these for later, since contents of pwd may be
346 * invalidated by deletion
347 */
348 sprintf(file, "%s/%s", _PATH_MAILDIR, pwd->pw_name);
349 strncpy(home, pwd->pw_dir, sizeof home);
350 home[sizeof home - 1] = '\0';
351
352 if (!delpwent(pwd))
349 cmderr(EX_IOERR, "Error updating passwd file: %s\n", strerror(errno));
353 err(EX_IOERR, "error updating passwd file");
350
351 if (cnf->nispasswd && *cnf->nispasswd=='/' && !delnispwent(cnf->nispasswd, a_name->val))
354
355 if (cnf->nispasswd && *cnf->nispasswd=='/' && !delnispwent(cnf->nispasswd, a_name->val))
352 perror("WARNING: NIS passwd update");
356 warn("WARNING: NIS passwd update");
353
354 editgroups(a_name->val, NULL);
355
356 pw_log(cnf, mode, W_USER, "%s(%ld) account removed", a_name->val, (long) uid);
357
358 /*
359 * Remove mail file
360 */

--- 20 unchanged lines hidden (view full) ---

381 } else if (mode == M_PRINT)
382 return print_user(pwd, getarg(args, 'P') != NULL);
383
384 /*
385 * The rest is edit code
386 */
387 if ((arg = getarg(args, 'l')) != NULL) {
388 if (strcmp(pwd->pw_name, "root") == 0)
357
358 editgroups(a_name->val, NULL);
359
360 pw_log(cnf, mode, W_USER, "%s(%ld) account removed", a_name->val, (long) uid);
361
362 /*
363 * Remove mail file
364 */

--- 20 unchanged lines hidden (view full) ---

385 } else if (mode == M_PRINT)
386 return print_user(pwd, getarg(args, 'P') != NULL);
387
388 /*
389 * The rest is edit code
390 */
391 if ((arg = getarg(args, 'l')) != NULL) {
392 if (strcmp(pwd->pw_name, "root") == 0)
389 cmderr(EX_DATAERR, "can't rename `root' account\n");
393 errx(EX_DATAERR, "can't rename `root' account");
390 pwd->pw_name = pw_checkname((u_char *)arg->val, 0);
391 }
392 if ((arg = getarg(args, 'u')) != NULL && isdigit(*arg->val)) {
393 pwd->pw_uid = (uid_t) atol(arg->val);
394 if (pwd->pw_uid != 0 && strcmp(pwd->pw_name, "root") == 0)
394 pwd->pw_name = pw_checkname((u_char *)arg->val, 0);
395 }
396 if ((arg = getarg(args, 'u')) != NULL && isdigit(*arg->val)) {
397 pwd->pw_uid = (uid_t) atol(arg->val);
398 if (pwd->pw_uid != 0 && strcmp(pwd->pw_name, "root") == 0)
395 cmderr(EX_DATAERR, "can't change uid of `root' account\n");
399 errx(EX_DATAERR, "can't change uid of `root' account");
396 if (pwd->pw_uid == 0 && strcmp(pwd->pw_name, "root") != 0)
400 if (pwd->pw_uid == 0 && strcmp(pwd->pw_name, "root") != 0)
397 fprintf(stderr, "WARNING: account `%s' will have a uid of 0 (superuser access!)\n", pwd->pw_name);
401 warnx("WARNING: account `%s' will have a uid of 0 (superuser access!)", pwd->pw_name);
398 }
399 if ((arg = getarg(args, 'g')) != NULL && pwd->pw_uid != 0) /* Already checked this */
400 pwd->pw_gid = (gid_t) getgrnam(cnf->default_group)->gr_gid;
401
402 if ((arg = getarg(args, 'p')) != NULL) {
403 if (*arg->val == '\0' || strcmp(arg->val, "0") == 0)
404 pwd->pw_change = 0;
405 else {
406 time_t now = time(NULL);
407 time_t expire = parse_date(now, arg->val);
408
409 if (now == expire)
402 }
403 if ((arg = getarg(args, 'g')) != NULL && pwd->pw_uid != 0) /* Already checked this */
404 pwd->pw_gid = (gid_t) getgrnam(cnf->default_group)->gr_gid;
405
406 if ((arg = getarg(args, 'p')) != NULL) {
407 if (*arg->val == '\0' || strcmp(arg->val, "0") == 0)
408 pwd->pw_change = 0;
409 else {
410 time_t now = time(NULL);
411 time_t expire = parse_date(now, arg->val);
412
413 if (now == expire)
410 cmderr(EX_DATAERR, "Invalid password change date `%s'\n", arg->val);
414 errx(EX_DATAERR, "invalid password change date `%s'", arg->val);
411 pwd->pw_change = expire;
412 }
413 }
414 if ((arg = getarg(args, 'e')) != NULL) {
415 if (*arg->val == '\0' || strcmp(arg->val, "0") == 0)
416 pwd->pw_expire = 0;
417 else {
418 time_t now = time(NULL);
419 time_t expire = parse_date(now, arg->val);
420
421 if (now == expire)
415 pwd->pw_change = expire;
416 }
417 }
418 if ((arg = getarg(args, 'e')) != NULL) {
419 if (*arg->val == '\0' || strcmp(arg->val, "0") == 0)
420 pwd->pw_expire = 0;
421 else {
422 time_t now = time(NULL);
423 time_t expire = parse_date(now, arg->val);
424
425 if (now == expire)
422 cmderr(EX_DATAERR, "Invalid account expiry date `%s'\n", arg->val);
426 errx(EX_DATAERR, "invalid account expiry date `%s'", arg->val);
423 pwd->pw_expire = expire;
424 }
425 }
426 if ((arg = getarg(args, 's')) != NULL)
427 pwd->pw_shell = shell_path(cnf->shelldir, cnf->shells, arg->val);
428
429 if (getarg(args, 'L'))
430 pwd->pw_class = cnf->default_class;
431
432 if ((arg = getarg(args, 'd')) != NULL) {
433 if (stat(pwd->pw_dir = arg->val, &st) == -1) {
434 if (getarg(args, 'm') == NULL && strcmp(pwd->pw_dir, "/nonexistent") != 0)
427 pwd->pw_expire = expire;
428 }
429 }
430 if ((arg = getarg(args, 's')) != NULL)
431 pwd->pw_shell = shell_path(cnf->shelldir, cnf->shells, arg->val);
432
433 if (getarg(args, 'L'))
434 pwd->pw_class = cnf->default_class;
435
436 if ((arg = getarg(args, 'd')) != NULL) {
437 if (stat(pwd->pw_dir = arg->val, &st) == -1) {
438 if (getarg(args, 'm') == NULL && strcmp(pwd->pw_dir, "/nonexistent") != 0)
435 fprintf(stderr, "WARNING: home `%s' does not exist\n", pwd->pw_dir);
439 warnx("WARNING: home `%s' does not exist", pwd->pw_dir);
436 } else if (!S_ISDIR(st.st_mode))
440 } else if (!S_ISDIR(st.st_mode))
437 fprintf(stderr, "WARNING: home `%s' is not a directory\n", pwd->pw_dir);
441 warnx("WARNING: home `%s' is not a directory", pwd->pw_dir);
438 }
439
440 if ((arg = getarg(args, 'w')) != NULL && getarg(args, 'h') == NULL)
441 pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name);
442
443 } else {
444 if (a_name == NULL) /* Required */
442 }
443
444 if ((arg = getarg(args, 'w')) != NULL && getarg(args, 'h') == NULL)
445 pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name);
446
447 } else {
448 if (a_name == NULL) /* Required */
445 cmderr(EX_DATAERR, "login name required\n");
449 errx(EX_DATAERR, "login name required");
446 else if ((pwd = getpwnam(a_name->val)) != NULL) /* Exists */
450 else if ((pwd = getpwnam(a_name->val)) != NULL) /* Exists */
447 cmderr(EX_DATAERR, "login name `%s' already exists\n", a_name->val);
451 errx(EX_DATAERR, "login name `%s' already exists", a_name->val);
448
449 /*
450 * Now, set up defaults for a new user
451 */
452 pwd = &fakeuser;
453 pwd->pw_name = a_name->val;
454 pwd->pw_class = cnf->default_class ? cnf->default_class : "";
455 pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name);
456 pwd->pw_uid = pw_uidpolicy(cnf, args);
457 pwd->pw_gid = pw_gidpolicy(cnf, args, pwd->pw_name, (gid_t) pwd->pw_uid);
458 pwd->pw_change = pw_pwdpolicy(cnf, args);
459 pwd->pw_expire = pw_exppolicy(cnf, args);
460 pwd->pw_dir = pw_homepolicy(cnf, args, pwd->pw_name);
461 pwd->pw_shell = pw_shellpolicy(cnf, args, NULL);
462
463 if (pwd->pw_uid == 0 && strcmp(pwd->pw_name, "root") != 0)
452
453 /*
454 * Now, set up defaults for a new user
455 */
456 pwd = &fakeuser;
457 pwd->pw_name = a_name->val;
458 pwd->pw_class = cnf->default_class ? cnf->default_class : "";
459 pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name);
460 pwd->pw_uid = pw_uidpolicy(cnf, args);
461 pwd->pw_gid = pw_gidpolicy(cnf, args, pwd->pw_name, (gid_t) pwd->pw_uid);
462 pwd->pw_change = pw_pwdpolicy(cnf, args);
463 pwd->pw_expire = pw_exppolicy(cnf, args);
464 pwd->pw_dir = pw_homepolicy(cnf, args, pwd->pw_name);
465 pwd->pw_shell = pw_shellpolicy(cnf, args, NULL);
466
467 if (pwd->pw_uid == 0 && strcmp(pwd->pw_name, "root") != 0)
464 fprintf(stderr, "WARNING: new account `%s' has a uid of 0 (superuser access!)\n", pwd->pw_name);
468 warnx("WARNING: new account `%s' has a uid of 0 (superuser access!)", pwd->pw_name);
465 }
466
467 /*
468 * Shared add/edit code
469 */
470 if ((arg = getarg(args, 'c')) != NULL)
471 pwd->pw_gecos = pw_checkname((u_char *)arg->val, 1);
472

--- 21 unchanged lines hidden (view full) ---

494 }
495 b = read(fd, line, sizeof(line) - 1);
496 if (istty) { /* Restore state */
497 tcsetattr(fd, TCSANOW, &t);
498 fputc('\n', stdout);
499 fflush(stdout);
500 }
501 if (b < 0) {
469 }
470
471 /*
472 * Shared add/edit code
473 */
474 if ((arg = getarg(args, 'c')) != NULL)
475 pwd->pw_gecos = pw_checkname((u_char *)arg->val, 1);
476

--- 21 unchanged lines hidden (view full) ---

498 }
499 b = read(fd, line, sizeof(line) - 1);
500 if (istty) { /* Restore state */
501 tcsetattr(fd, TCSANOW, &t);
502 fputc('\n', stdout);
503 fflush(stdout);
504 }
505 if (b < 0) {
502 perror("-h file descriptor");
506 warn("-h file descriptor");
503 return EX_IOERR;
504 }
505 line[b] = '\0';
506 if ((p = strpbrk(line, " \t\r\n")) != NULL)
507 *p = '\0';
508 if (!*line)
507 return EX_IOERR;
508 }
509 line[b] = '\0';
510 if ((p = strpbrk(line, " \t\r\n")) != NULL)
511 *p = '\0';
512 if (!*line)
509 cmderr(EX_DATAERR, "empty password read on file descriptor %d\n", fd);
513 errx(EX_DATAERR, "empty password read on file descriptor %d", fd);
510 pwd->pw_passwd = pw_pwcrypt(line);
511 }
512 }
513
514 /*
515 * Special case: -N only displays & exits
516 */
517 if (getarg(args, 'N') != NULL)

--- 6 unchanged lines hidden (view full) ---

524 r1 = addnispwent(cnf->nispasswd, pwd);
525 } else if (mode == M_UPDATE) {
526 r = chgpwent(a_name->val, pwd);
527 if (r && cnf->nispasswd && *cnf->nispasswd=='/')
528 r1 = chgnispwent(cnf->nispasswd, a_name->val, pwd);
529 }
530
531 if (!r) {
514 pwd->pw_passwd = pw_pwcrypt(line);
515 }
516 }
517
518 /*
519 * Special case: -N only displays & exits
520 */
521 if (getarg(args, 'N') != NULL)

--- 6 unchanged lines hidden (view full) ---

528 r1 = addnispwent(cnf->nispasswd, pwd);
529 } else if (mode == M_UPDATE) {
530 r = chgpwent(a_name->val, pwd);
531 if (r && cnf->nispasswd && *cnf->nispasswd=='/')
532 r1 = chgnispwent(cnf->nispasswd, a_name->val, pwd);
533 }
534
535 if (!r) {
532 perror("password update");
536 warn("password update");
533 return EX_IOERR;
534 } else if (!r1) {
537 return EX_IOERR;
538 } else if (!r1) {
535 perror("WARNING: NIS password update");
539 warn("WARNING: NIS password update");
536 /* Keep on trucking */
537 }
538
539 /*
540 * Ok, user is created or changed - now edit group file
541 */
542
543 if (mode == M_ADD || getarg(args, 'G') != NULL)
544 editgroups(pwd->pw_name, cnf->groups);
545
546 /* pwd may have been invalidated */
547 if ((pwd = getpwnam(a_name->val)) == NULL)
540 /* Keep on trucking */
541 }
542
543 /*
544 * Ok, user is created or changed - now edit group file
545 */
546
547 if (mode == M_ADD || getarg(args, 'G') != NULL)
548 editgroups(pwd->pw_name, cnf->groups);
549
550 /* pwd may have been invalidated */
551 if ((pwd = getpwnam(a_name->val)) == NULL)
548 cmderr(EX_NOUSER, "user '%s' disappeared during update\n", a_name->val);
552 errx(EX_NOUSER, "user '%s' disappeared during update", a_name->val);
549
550 grp = getgrgid(pwd->pw_gid);
551 pw_log(cnf, mode, W_USER, "%s(%ld):%s(%d):%s:%s:%s",
552 pwd->pw_name, (long) pwd->pw_uid,
553 grp ? grp->gr_name : "unknown", (long) (grp ? grp->gr_gid : -1),
554 pwd->pw_gecos, pwd->pw_dir, pwd->pw_shell);
555
556 /*

--- 11 unchanged lines hidden (view full) ---

568
569 /*
570 * Send mail to the new user as well, if we are asked to
571 */
572 if (cnf->newmail && *cnf->newmail && (fp = fopen(cnf->newmail, "r")) != NULL) {
573 FILE *pfp = popen(_PATH_SENDMAIL " -t", "w");
574
575 if (pfp == NULL)
553
554 grp = getgrgid(pwd->pw_gid);
555 pw_log(cnf, mode, W_USER, "%s(%ld):%s(%d):%s:%s:%s",
556 pwd->pw_name, (long) pwd->pw_uid,
557 grp ? grp->gr_name : "unknown", (long) (grp ? grp->gr_gid : -1),
558 pwd->pw_gecos, pwd->pw_dir, pwd->pw_shell);
559
560 /*

--- 11 unchanged lines hidden (view full) ---

572
573 /*
574 * Send mail to the new user as well, if we are asked to
575 */
576 if (cnf->newmail && *cnf->newmail && (fp = fopen(cnf->newmail, "r")) != NULL) {
577 FILE *pfp = popen(_PATH_SENDMAIL " -t", "w");
578
579 if (pfp == NULL)
576 perror("sendmail");
580 warn("sendmail");
577 else {
578 fprintf(pfp, "From: root\n" "To: %s\n" "Subject: Welcome!\n\n", pwd->pw_name);
579 while (fgets(line, sizeof(line), fp) != NULL) {
580 /* Do substitutions? */
581 fputs(line, pfp);
582 }
583 pclose(pfp);
584 pw_log(cnf, mode, W_USER, "%s(%ld) new user mail sent",

--- 25 unchanged lines hidden (view full) ---

610
611 /*
612 * Check the given uid, if any
613 */
614 if (a_uid != NULL) {
615 uid = (uid_t) atol(a_uid->val);
616
617 if ((pwd = getpwuid(uid)) != NULL && getarg(args, 'o') == NULL)
581 else {
582 fprintf(pfp, "From: root\n" "To: %s\n" "Subject: Welcome!\n\n", pwd->pw_name);
583 while (fgets(line, sizeof(line), fp) != NULL) {
584 /* Do substitutions? */
585 fputs(line, pfp);
586 }
587 pclose(pfp);
588 pw_log(cnf, mode, W_USER, "%s(%ld) new user mail sent",

--- 25 unchanged lines hidden (view full) ---

614
615 /*
616 * Check the given uid, if any
617 */
618 if (a_uid != NULL) {
619 uid = (uid_t) atol(a_uid->val);
620
621 if ((pwd = getpwuid(uid)) != NULL && getarg(args, 'o') == NULL)
618 cmderr(EX_DATAERR, "uid `%ld' has already been allocated\n", (long) pwd->pw_uid);
622 errx(EX_DATAERR, "uid `%ld' has already been allocated", (long) pwd->pw_uid);
619 } else {
620 struct bitmap bm;
621
622 /*
623 * We need to allocate the next available uid under one of
624 * two policies a) Grab the first unused uid b) Grab the
625 * highest possible unused uid
626 */

--- 18 unchanged lines hidden (view full) ---

645 */
646 if (cnf->reuse_uids || (uid = (uid_t) (bm_lastset(&bm) + cnf->min_uid + 1)) > cnf->max_uid)
647 uid = (uid_t) (bm_firstunset(&bm) + cnf->min_uid);
648
649 /*
650 * Another sanity check
651 */
652 if (uid < cnf->min_uid || uid > cnf->max_uid)
623 } else {
624 struct bitmap bm;
625
626 /*
627 * We need to allocate the next available uid under one of
628 * two policies a) Grab the first unused uid b) Grab the
629 * highest possible unused uid
630 */

--- 18 unchanged lines hidden (view full) ---

649 */
650 if (cnf->reuse_uids || (uid = (uid_t) (bm_lastset(&bm) + cnf->min_uid + 1)) > cnf->max_uid)
651 uid = (uid_t) (bm_firstunset(&bm) + cnf->min_uid);
652
653 /*
654 * Another sanity check
655 */
656 if (uid < cnf->min_uid || uid > cnf->max_uid)
653 cmderr(EX_SOFTWARE, "unable to allocate a new uid - range fully used\n");
657 errx(EX_SOFTWARE, "unable to allocate a new uid - range fully used");
654 bm_dealloc(&bm);
655 }
656 return uid;
657}
658
659
660static uid_t
661pw_gidpolicy(struct userconf * cnf, struct cargs * args, char *nam, gid_t prefer)

--- 11 unchanged lines hidden (view full) ---

673 /*
674 * Check the given gid, if any
675 */
676 setgrent();
677 if (a_gid != NULL) {
678 if ((grp = getgrnam(a_gid->val)) == NULL) {
679 gid = (gid_t) atol(a_gid->val);
680 if ((gid == 0 && !isdigit(*a_gid->val)) || (grp = getgrgid(gid)) == NULL)
658 bm_dealloc(&bm);
659 }
660 return uid;
661}
662
663
664static uid_t
665pw_gidpolicy(struct userconf * cnf, struct cargs * args, char *nam, gid_t prefer)

--- 11 unchanged lines hidden (view full) ---

677 /*
678 * Check the given gid, if any
679 */
680 setgrent();
681 if (a_gid != NULL) {
682 if ((grp = getgrnam(a_gid->val)) == NULL) {
683 gid = (gid_t) atol(a_gid->val);
684 if ((gid == 0 && !isdigit(*a_gid->val)) || (grp = getgrgid(gid)) == NULL)
681 cmderr(EX_NOUSER, "group `%s' is not defined\n", a_gid->val);
685 errx(EX_NOUSER, "group `%s' is not defined", a_gid->val);
682 }
683 gid = grp->gr_gid;
684 } else if ((grp = getgrnam(nam)) != NULL && grp->gr_mem[0] == NULL) {
685 gid = grp->gr_gid; /* Already created? Use it anyway... */
686 } else {
687 struct cargs grpargs;
688 char tmp[32];
689

--- 41 unchanged lines hidden (view full) ---

731pw_pwdpolicy(struct userconf * cnf, struct cargs * args)
732{
733 time_t result = 0;
734 time_t now = time(NULL);
735 struct carg *arg = getarg(args, 'p');
736
737 if (arg != NULL) {
738 if ((result = parse_date(now, arg->val)) == now)
686 }
687 gid = grp->gr_gid;
688 } else if ((grp = getgrnam(nam)) != NULL && grp->gr_mem[0] == NULL) {
689 gid = grp->gr_gid; /* Already created? Use it anyway... */
690 } else {
691 struct cargs grpargs;
692 char tmp[32];
693

--- 41 unchanged lines hidden (view full) ---

735pw_pwdpolicy(struct userconf * cnf, struct cargs * args)
736{
737 time_t result = 0;
738 time_t now = time(NULL);
739 struct carg *arg = getarg(args, 'p');
740
741 if (arg != NULL) {
742 if ((result = parse_date(now, arg->val)) == now)
739 cmderr(EX_DATAERR, "invalid date/time `%s'\n", arg->val);
743 errx(EX_DATAERR, "invalid date/time `%s'", arg->val);
740 } else if (cnf->password_days > 0)
741 result = now + ((long) cnf->password_days * 86400L);
742 return result;
743}
744
745
746static time_t
747pw_exppolicy(struct userconf * cnf, struct cargs * args)
748{
749 time_t result = 0;
750 time_t now = time(NULL);
751 struct carg *arg = getarg(args, 'e');
752
753 if (arg != NULL) {
754 if ((result = parse_date(now, arg->val)) == now)
744 } else if (cnf->password_days > 0)
745 result = now + ((long) cnf->password_days * 86400L);
746 return result;
747}
748
749
750static time_t
751pw_exppolicy(struct userconf * cnf, struct cargs * args)
752{
753 time_t result = 0;
754 time_t now = time(NULL);
755 struct carg *arg = getarg(args, 'e');
756
757 if (arg != NULL) {
758 if ((result = parse_date(now, arg->val)) == now)
755 cmderr(EX_DATAERR, "invalid date/time `%s'\n", arg->val);
759 errx(EX_DATAERR, "invalid date/time `%s'", arg->val);
756 } else if (cnf->expire_days > 0)
757 result = now + ((long) cnf->expire_days * 86400L);
758 return result;
759}
760
761
762static char *
763pw_homepolicy(struct userconf * cnf, struct cargs * args, char const * user)
764{
765 struct carg *arg = getarg(args, 'd');
766
767 if (arg)
768 return arg->val;
769 else {
770 static char home[128];
771
772 if (cnf->home == NULL || *cnf->home == '\0')
760 } else if (cnf->expire_days > 0)
761 result = now + ((long) cnf->expire_days * 86400L);
762 return result;
763}
764
765
766static char *
767pw_homepolicy(struct userconf * cnf, struct cargs * args, char const * user)
768{
769 struct carg *arg = getarg(args, 'd');
770
771 if (arg)
772 return arg->val;
773 else {
774 static char home[128];
775
776 if (cnf->home == NULL || *cnf->home == '\0')
773 cmderr(EX_CONFIG, "no base home directory set\n");
777 errx(EX_CONFIG, "no base home directory set");
774 sprintf(home, "%s/%s", cnf->home, user);
775 return home;
776 }
777}
778
779static char *
780shell_path(char const * path, char *shells[], char *sh)
781{

--- 19 unchanged lines hidden (view full) ---

801 } else
802 for (i = 0; i < _UC_MAXSHELLS && shells[i] != NULL; i++) {
803 sprintf(shellpath, "%s/%s", p, shells[i]);
804 if (access(shellpath, X_OK) == 0)
805 return shellpath;
806 }
807 }
808 if (sh == NULL)
778 sprintf(home, "%s/%s", cnf->home, user);
779 return home;
780 }
781}
782
783static char *
784shell_path(char const * path, char *shells[], char *sh)
785{

--- 19 unchanged lines hidden (view full) ---

805 } else
806 for (i = 0; i < _UC_MAXSHELLS && shells[i] != NULL; i++) {
807 sprintf(shellpath, "%s/%s", p, shells[i]);
808 if (access(shellpath, X_OK) == 0)
809 return shellpath;
810 }
811 }
812 if (sh == NULL)
809 cmderr(EX_OSFILE, "can't find shell `%s' in shell paths\n", sh);
810 cmderr(EX_CONFIG, "no default shell available or defined\n");
813 errx(EX_OSFILE, "can't find shell `%s' in shell paths", sh);
814 errx(EX_CONFIG, "no default shell available or defined");
811 return NULL;
812 }
813}
814
815
816static char *
817pw_shellpolicy(struct userconf * cnf, struct cargs * args, char *newshell)
818{

--- 217 unchanged lines hidden (view full) ---

1036{
1037 int l = 0;
1038 char const *notch = gecos ? ":!@" : " ,\t:+&#%$^()!@~*?<>=|\\/\"";
1039
1040 while (name[l]) {
1041 if (strchr(notch, name[l]) != NULL || name[l] < ' ' || name[l] == 127 ||
1042 (!gecos && l==0 && name[l] == '-') || /* leading '-' */
1043 (!gecos && name[l] & 0x80)) /* 8-bit */
815 return NULL;
816 }
817}
818
819
820static char *
821pw_shellpolicy(struct userconf * cnf, struct cargs * args, char *newshell)
822{

--- 217 unchanged lines hidden (view full) ---

1040{
1041 int l = 0;
1042 char const *notch = gecos ? ":!@" : " ,\t:+&#%$^()!@~*?<>=|\\/\"";
1043
1044 while (name[l]) {
1045 if (strchr(notch, name[l]) != NULL || name[l] < ' ' || name[l] == 127 ||
1046 (!gecos && l==0 && name[l] == '-') || /* leading '-' */
1047 (!gecos && name[l] & 0x80)) /* 8-bit */
1044 cmderr(EX_DATAERR, (name[l] >= ' ' && name[l] < 127)
1045 ? "invalid character `%c' in field\n"
1046 : "invalid character 0x%02x in field\n",
1048 errx(EX_DATAERR, (name[l] >= ' ' && name[l] < 127)
1049 ? "invalid character `%c' in field"
1050 : "invalid character 0x%02x in field",
1047 name[l]);
1048 ++l;
1049 }
1050 if (!gecos && l > LOGNAMESIZE)
1051 name[l]);
1052 ++l;
1053 }
1054 if (!gecos && l > LOGNAMESIZE)
1051 cmderr(EX_DATAERR, "name too long `%s'\n", name);
1055 errx(EX_DATAERR, "name too long `%s'", name);
1052 return (char *)name;
1053}
1054
1055
1056static void
1057rmat(uid_t uid)
1058{
1059 DIR *d = opendir("/var/at/jobs");

--- 48 unchanged lines hidden ---
1056 return (char *)name;
1057}
1058
1059
1060static void
1061rmat(uid_t uid)
1062{
1063 DIR *d = opendir("/var/at/jobs");

--- 48 unchanged lines hidden ---