pw_user.c (286156) | pw_user.c (286196) |
---|---|
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 --- 13 unchanged lines hidden (view full) --- 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 */ 27 28#ifndef lint 29static const char rcsid[] = | 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 --- 13 unchanged lines hidden (view full) --- 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 */ 27 28#ifndef lint 29static const char rcsid[] = |
30 "$FreeBSD: head/usr.sbin/pw/pw_user.c 286156 2015-08-01 12:18:48Z bapt $"; | 30 "$FreeBSD: head/usr.sbin/pw/pw_user.c 286196 2015-08-02 12:47:50Z bapt $"; |
31#endif /* not lint */ 32 33#include <ctype.h> 34#include <err.h> 35#include <fcntl.h> 36#include <inttypes.h> 37#include <sys/param.h> 38#include <dirent.h> --- 8 unchanged lines hidden (view full) --- 47#include <libutil.h> 48#include "pw.h" 49#include "bitmap.h" 50 51#define LOGNAMESIZE (MAXLOGNAME-1) 52 53static char locked_str[] = "*LOCKED*"; 54 | 31#endif /* not lint */ 32 33#include <ctype.h> 34#include <err.h> 35#include <fcntl.h> 36#include <inttypes.h> 37#include <sys/param.h> 38#include <dirent.h> --- 8 unchanged lines hidden (view full) --- 47#include <libutil.h> 48#include "pw.h" 49#include "bitmap.h" 50 51#define LOGNAMESIZE (MAXLOGNAME-1) 52 53static char locked_str[] = "*LOCKED*"; 54 |
55static int pw_userdel(char *name, long id); 56static int print_user(struct passwd * pwd); 57static uid_t pw_uidpolicy(struct userconf * cnf, long id); 58static uid_t pw_gidpolicy(struct cargs * args, char *nam, gid_t prefer); 59static time_t pw_pwdpolicy(struct userconf * cnf, struct cargs * args); 60static time_t pw_exppolicy(struct userconf * cnf, struct cargs * args); 61static char *pw_homepolicy(struct userconf * cnf, struct cargs * args, char const * user); 62static char *pw_shellpolicy(struct userconf * cnf, struct cargs * args, char *newshell); 63static char *pw_password(struct userconf * cnf, char const * user); 64static char *shell_path(char const * path, char *shells[], char *sh); 65static void rmat(uid_t uid); 66static void rmopie(char const * name); | 55static struct passwd fakeuser = { 56 "nouser", 57 "*", 58 -1, 59 -1, 60 0, 61 "", 62 "User &", 63 "/nonexistent", 64 "/bin/sh", 65 0, 66 0 67}; |
67 | 68 |
69static int print_user(struct passwd *pwd, bool pretty, bool v7); 70static uid_t pw_uidpolicy(struct userconf *cnf, intmax_t id); 71static uid_t pw_gidpolicy(struct userconf *cnf, char *grname, char *nam, 72 gid_t prefer, bool dryrun); 73static char *pw_homepolicy(struct userconf * cnf, char *homedir, 74 const char *user); 75static char *pw_shellpolicy(struct userconf * cnf); 76static char *pw_password(struct userconf * cnf, char const * user, 77 bool dryrun); 78static char *shell_path(char const * path, char *shells[], char *sh); 79static void rmat(uid_t uid); 80static void rmopie(char const * name); 81 |
|
68static void | 82static void |
69create_and_populate_homedir(struct passwd *pwd) | 83create_and_populate_homedir(struct userconf *cnf, struct passwd *pwd, 84 const char *skeldir, mode_t homemode, bool update) |
70{ | 85{ |
71 struct userconf *cnf = conf.userconf; 72 const char *skeldir; | |
73 int skelfd = -1; 74 | 86 int skelfd = -1; 87 |
75 skeldir = cnf->dotdir; 76 | |
77 if (skeldir != NULL && *skeldir != '\0') { 78 if (*skeldir == '/') 79 skeldir++; 80 skelfd = openat(conf.rootfd, skeldir, O_DIRECTORY|O_CLOEXEC); 81 } 82 | 88 if (skeldir != NULL && *skeldir != '\0') { 89 if (*skeldir == '/') 90 skeldir++; 91 skelfd = openat(conf.rootfd, skeldir, O_DIRECTORY|O_CLOEXEC); 92 } 93 |
83 copymkdir(conf.rootfd, pwd->pw_dir, skelfd, cnf->homemode, pwd->pw_uid, | 94 copymkdir(conf.rootfd, pwd->pw_dir, skelfd, homemode, pwd->pw_uid, |
84 pwd->pw_gid, 0); | 95 pwd->pw_gid, 0); |
85 pw_log(cnf, M_ADD, W_USER, "%s(%ju) home %s made", pwd->pw_name, 86 (uintmax_t)pwd->pw_uid, pwd->pw_dir); | 96 pw_log(cnf, update ? M_UPDATE : M_ADD, W_USER, "%s(%ju) home %s made", 97 pwd->pw_name, (uintmax_t)pwd->pw_uid, pwd->pw_dir); |
87} 88 89static int | 98} 99 100static int |
90set_passwd(struct passwd *pwd, bool update) | 101pw_set_passwd(struct passwd *pwd, int fd, bool precrypted, bool update) |
91{ 92 int b, istty; 93 struct termios t, n; 94 login_cap_t *lc; 95 char line[_PASSWORD_LEN+1]; 96 char *p; 97 | 102{ 103 int b, istty; 104 struct termios t, n; 105 login_cap_t *lc; 106 char line[_PASSWORD_LEN+1]; 107 char *p; 108 |
98 if (conf.fd == '-') { | 109 if (fd == '-') { |
99 if (!pwd->pw_passwd || *pwd->pw_passwd != '*') { 100 pwd->pw_passwd = "*"; /* No access */ 101 return (1); 102 } 103 return (0); 104 } 105 | 110 if (!pwd->pw_passwd || *pwd->pw_passwd != '*') { 111 pwd->pw_passwd = "*"; /* No access */ 112 return (1); 113 } 114 return (0); 115 } 116 |
106 if ((istty = isatty(conf.fd))) { 107 if (tcgetattr(conf.fd, &t) == -1) | 117 if ((istty = isatty(fd))) { 118 if (tcgetattr(fd, &t) == -1) |
108 istty = 0; 109 else { 110 n = t; 111 n.c_lflag &= ~(ECHO); | 119 istty = 0; 120 else { 121 n = t; 122 n.c_lflag &= ~(ECHO); |
112 tcsetattr(conf.fd, TCSANOW, &n); | 123 tcsetattr(fd, TCSANOW, &n); |
113 printf("%s%spassword for user %s:", 114 update ? "new " : "", | 124 printf("%s%spassword for user %s:", 125 update ? "new " : "", |
115 conf.precrypted ? "encrypted " : "", | 126 precrypted ? "encrypted " : "", |
116 pwd->pw_name); 117 fflush(stdout); 118 } 119 } | 127 pwd->pw_name); 128 fflush(stdout); 129 } 130 } |
120 b = read(conf.fd, line, sizeof(line) - 1); | 131 b = read(fd, line, sizeof(line) - 1); |
121 if (istty) { /* Restore state */ | 132 if (istty) { /* Restore state */ |
122 tcsetattr(conf.fd, TCSANOW, &t); | 133 tcsetattr(fd, TCSANOW, &t); |
123 fputc('\n', stdout); 124 fflush(stdout); 125 } 126 127 if (b < 0) 128 err(EX_IOERR, "-%c file descriptor", | 134 fputc('\n', stdout); 135 fflush(stdout); 136 } 137 138 if (b < 0) 139 err(EX_IOERR, "-%c file descriptor", |
129 conf.precrypted ? 'H' : 'h'); | 140 precrypted ? 'H' : 'h'); |
130 line[b] = '\0'; 131 if ((p = strpbrk(line, "\r\n")) != NULL) 132 *p = '\0'; 133 if (!*line) 134 errx(EX_DATAERR, "empty password read on file descriptor %d", | 141 line[b] = '\0'; 142 if ((p = strpbrk(line, "\r\n")) != NULL) 143 *p = '\0'; 144 if (!*line) 145 errx(EX_DATAERR, "empty password read on file descriptor %d", |
135 conf.fd); 136 if (conf.precrypted) { | 146 fd); 147 if (precrypted) { |
137 if (strchr(line, ':') != NULL) 138 errx(EX_DATAERR, "bad encrypted password"); | 148 if (strchr(line, ':') != NULL) 149 errx(EX_DATAERR, "bad encrypted password"); |
139 pwd->pw_passwd = line; | 150 pwd->pw_passwd = strdup(line); |
140 } else { 141 lc = login_getpwclass(pwd); 142 if (lc == NULL || 143 login_setcryptfmt(lc, "sha512", NULL) == NULL) 144 warn("setting crypt(3) format"); 145 login_close(lc); 146 pwd->pw_passwd = pw_pwcrypt(line); 147 } 148 return (1); 149} 150 | 151 } else { 152 lc = login_getpwclass(pwd); 153 if (lc == NULL || 154 login_setcryptfmt(lc, "sha512", NULL) == NULL) 155 warn("setting crypt(3) format"); 156 login_close(lc); 157 pwd->pw_passwd = pw_pwcrypt(line); 158 } 159 return (1); 160} 161 |
151int 152pw_usernext(struct userconf *cnf, bool quiet) 153{ 154 uid_t next = pw_uidpolicy(cnf, -1); 155 156 if (quiet) 157 return (next); 158 159 printf("%ju:", (uintmax_t)next); 160 pw_groupnext(cnf, quiet); 161 162 return (EXIT_SUCCESS); 163} 164 165static int 166pw_usershow(char *name, long id, struct passwd *fakeuser) 167{ 168 struct passwd *pwd = NULL; 169 170 if (id < 0 && name == NULL && !conf.all) 171 errx(EX_DATAERR, "username or id or '-a' required"); 172 173 if (conf.all) { 174 SETPWENT(); 175 while ((pwd = GETPWENT()) != NULL) 176 print_user(pwd); 177 ENDPWENT(); 178 return (EXIT_SUCCESS); 179 } 180 181 pwd = (name != NULL) ? GETPWNAM(pw_checkname(name, 0)) : GETPWUID(id); 182 if (pwd == NULL) { 183 if (conf.force) { 184 pwd = fakeuser; 185 } else { 186 if (name == NULL) 187 errx(EX_NOUSER, "no such uid `%ld'", id); 188 errx(EX_NOUSER, "no such user `%s'", name); 189 } 190 } 191 192 return (print_user(pwd)); 193} 194 | |
195static void | 162static void |
196perform_chgpwent(const char *name, struct passwd *pwd) | 163perform_chgpwent(const char *name, struct passwd *pwd, char *nispasswd) |
197{ 198 int rc; | 164{ 165 int rc; |
166 struct passwd *nispwd; |
|
199 | 167 |
168 /* duplicate for nis so that chgpwent is not modifying before NIS */ 169 if (nispasswd && *nispasswd == '/') 170 nispwd = pw_dup(pwd); 171 |
|
200 rc = chgpwent(name, pwd); 201 if (rc == -1) 202 errx(EX_IOERR, "user '%s' does not exist (NIS?)", pwd->pw_name); 203 else if (rc != 0) 204 err(EX_IOERR, "passwd file update"); 205 | 172 rc = chgpwent(name, pwd); 173 if (rc == -1) 174 errx(EX_IOERR, "user '%s' does not exist (NIS?)", pwd->pw_name); 175 else if (rc != 0) 176 err(EX_IOERR, "passwd file update"); 177 |
206 if (conf.userconf->nispasswd && *conf.userconf->nispasswd == '/') { 207 rc = chgnispwent(conf.userconf->nispasswd, name, pwd); | 178 if (nispasswd && *nispasswd == '/') { 179 rc = chgnispwent(nispasswd, name, nispwd); |
208 if (rc == -1) 209 warn("User '%s' not found in NIS passwd", pwd->pw_name); 210 else if (rc != 0) 211 warn("NIS passwd update"); 212 /* NOTE: NIS-only update errors are not fatal */ 213 } 214} 215 216/* 217 * The M_LOCK and M_UNLOCK functions simply add or remove 218 * a "*LOCKED*" prefix from in front of the password to 219 * prevent it decoding correctly, and therefore prevents 220 * access. Of course, this only prevents access via 221 * password authentication (not ssh, kerberos or any 222 * other method that does not use the UNIX password) but 223 * that is a known limitation. 224 */ 225static int | 180 if (rc == -1) 181 warn("User '%s' not found in NIS passwd", pwd->pw_name); 182 else if (rc != 0) 183 warn("NIS passwd update"); 184 /* NOTE: NIS-only update errors are not fatal */ 185 } 186} 187 188/* 189 * The M_LOCK and M_UNLOCK functions simply add or remove 190 * a "*LOCKED*" prefix from in front of the password to 191 * prevent it decoding correctly, and therefore prevents 192 * access. Of course, this only prevents access via 193 * password authentication (not ssh, kerberos or any 194 * other method that does not use the UNIX password) but 195 * that is a known limitation. 196 */ 197static int |
226pw_userlock(char *name, long id, int mode) | 198pw_userlock(char *arg1, int mode) |
227{ 228 struct passwd *pwd = NULL; 229 char *passtmp = NULL; | 199{ 200 struct passwd *pwd = NULL; 201 char *passtmp = NULL; |
202 char *name; |
|
230 bool locked = false; | 203 bool locked = false; |
204 uid_t id; |
|
231 | 205 |
232 if (id < 0 && name == NULL) | 206 if (geteuid() != 0) 207 errx(EX_NOPERM, "you must be root"); 208 209 if (arg1 == NULL) |
233 errx(EX_DATAERR, "username or id required"); 234 | 210 errx(EX_DATAERR, "username or id required"); 211 |
212 if (strspn(arg1, "0123456789") == strlen(arg1)) 213 id = pw_checkid(arg1, UID_MAX); 214 else 215 name = arg1; 216 |
|
235 pwd = (name != NULL) ? GETPWNAM(pw_checkname(name, 0)) : GETPWUID(id); 236 if (pwd == NULL) { 237 if (name == NULL) | 217 pwd = (name != NULL) ? GETPWNAM(pw_checkname(name, 0)) : GETPWUID(id); 218 if (pwd == NULL) { 219 if (name == NULL) |
238 errx(EX_NOUSER, "no such uid `%ld'", id); | 220 errx(EX_NOUSER, "no such uid `%ju'", (uintmax_t) id); |
239 errx(EX_NOUSER, "no such user `%s'", name); 240 } 241 242 if (name == NULL) 243 name = pwd->pw_name; 244 245 if (strncmp(pwd->pw_passwd, locked_str, sizeof(locked_str) -1) == 0) 246 locked = true; --- 6 unchanged lines hidden (view full) --- 253 asprintf(&passtmp, "%s%s", locked_str, pwd->pw_passwd); 254 if (passtmp == NULL) /* disaster */ 255 errx(EX_UNAVAILABLE, "out of memory"); 256 pwd->pw_passwd = passtmp; 257 } else { 258 pwd->pw_passwd += sizeof(locked_str)-1; 259 } 260 | 221 errx(EX_NOUSER, "no such user `%s'", name); 222 } 223 224 if (name == NULL) 225 name = pwd->pw_name; 226 227 if (strncmp(pwd->pw_passwd, locked_str, sizeof(locked_str) -1) == 0) 228 locked = true; --- 6 unchanged lines hidden (view full) --- 235 asprintf(&passtmp, "%s%s", locked_str, pwd->pw_passwd); 236 if (passtmp == NULL) /* disaster */ 237 errx(EX_UNAVAILABLE, "out of memory"); 238 pwd->pw_passwd = passtmp; 239 } else { 240 pwd->pw_passwd += sizeof(locked_str)-1; 241 } 242 |
261 perform_chgpwent(name, pwd); | 243 perform_chgpwent(name, pwd, NULL); |
262 free(passtmp); 263 264 return (EXIT_SUCCESS); 265} 266 | 244 free(passtmp); 245 246 return (EXIT_SUCCESS); 247} 248 |
267/*- 268 * -C config configuration file 269 * -q quiet operation 270 * -n name login name 271 * -u uid user id 272 * -c comment user name/comment 273 * -d directory home directory 274 * -e date account expiry date 275 * -p date password expiry date 276 * -g grp primary group 277 * -G grp1,grp2 additional groups 278 * -m [ -k dir ] create and set up home 279 * -s shell name of login shell 280 * -o duplicate uid ok 281 * -L class user class 282 * -l name new login name 283 * -h fd password filehandle 284 * -H fd encrypted password filehandle 285 * -F force print or add 286 * Setting defaults: 287 * -D set user defaults 288 * -b dir default home root dir 289 * -e period default expiry period 290 * -p period default password change period 291 * -g group default group 292 * -G grp1,grp2.. default additional groups 293 * -L class default login class 294 * -k dir default home skeleton 295 * -s shell default shell 296 * -w method default password method 297 */ 298 299int 300pw_user(int mode, char *name, long id, struct cargs * args) | 249static uid_t 250pw_uidpolicy(struct userconf * cnf, intmax_t id) |
301{ | 251{ |
302 int rc, edited = 0; 303 char *p = NULL; 304 struct carg *arg; 305 struct passwd *pwd = NULL; 306 struct group *grp; 307 struct stat st; 308 struct userconf *cnf; 309 char line[_PASSWORD_LEN+1]; 310 char path[MAXPATHLEN]; 311 FILE *fp; 312 char *dmode_c; 313 void *set = NULL; 314 int valid_type = _PWF_FILES; | 252 struct passwd *pwd; 253 struct bitmap bm; 254 uid_t uid = (uid_t) - 1; |
315 | 255 |
316 static struct passwd fakeuser = 317 { 318 "nouser", 319 "*", 320 -1, 321 -1, 322 0, 323 "", 324 "User &", 325 "/nonexistent", 326 "/bin/sh", 327 0 328#if defined(__FreeBSD__) 329 ,0 330#endif 331 }; 332 333 cnf = conf.userconf; 334 335 if (mode == M_NEXT) 336 return (pw_usernext(cnf, conf.quiet)); 337 338 if (mode == M_PRINT) 339 return (pw_usershow(name, id, &fakeuser)); 340 341 if (mode == M_DELETE) 342 return (pw_userdel(name, id)); 343 344 if (mode == M_LOCK || mode == M_UNLOCK) 345 return (pw_userlock(name, id, mode)); 346 | |
347 /* | 256 /* |
348 * We can do all of the common legwork here | 257 * Check the given uid, if any |
349 */ | 258 */ |
259 if (id >= 0) { 260 uid = (uid_t) id; |
|
350 | 261 |
351 if ((arg = getarg(args, 'b')) != NULL) { 352 cnf->home = arg->val; | 262 if ((pwd = GETPWUID(uid)) != NULL && conf.checkduplicate) 263 errx(EX_DATAERR, "uid `%ju' has already been allocated", 264 (uintmax_t)pwd->pw_uid); 265 return (uid); |
353 } | 266 } |
354 355 if ((arg = getarg(args, 'M')) != NULL) { 356 dmode_c = arg->val; 357 if ((set = setmode(dmode_c)) == NULL) 358 errx(EX_DATAERR, "invalid directory creation mode '%s'", 359 dmode_c); 360 cnf->homemode = getmode(set, _DEF_DIRMODE); 361 free(set); 362 } 363 | |
364 /* | 267 /* |
365 * If we'll need to use it or we're updating it, 366 * then create the base home directory if necessary | 268 * We need to allocate the next available uid under one of 269 * two policies a) Grab the first unused uid b) Grab the 270 * highest possible unused uid |
367 */ | 271 */ |
368 if (arg != NULL || getarg(args, 'm') != NULL) { 369 int l = strlen(cnf->home); 370 371 if (l > 1 && cnf->home[l-1] == '/') /* Shave off any trailing path delimiter */ 372 cnf->home[--l] = '\0'; 373 374 if (l < 2 || *cnf->home != '/') /* Check for absolute path name */ 375 errx(EX_DATAERR, "invalid base directory for home '%s'", cnf->home); 376 377 if (stat(cnf->home, &st) == -1) { 378 char dbuf[MAXPATHLEN]; 379 380 /* 381 * This is a kludge especially for Joerg :) 382 * If the home directory would be created in the root partition, then 383 * we really create it under /usr which is likely to have more space. 384 * But we create a symlink from cnf->home -> "/usr" -> cnf->home 385 */ 386 if (strchr(cnf->home+1, '/') == NULL) { 387 snprintf(dbuf, MAXPATHLEN, "/usr%s", cnf->home); 388 if (mkdir(dbuf, _DEF_DIRMODE) != -1 || errno == EEXIST) { 389 chown(dbuf, 0, 0); 390 /* 391 * Skip first "/" and create symlink: 392 * /home -> usr/home 393 */ 394 symlink(dbuf+1, cnf->home); 395 } 396 /* If this falls, fall back to old method */ 397 } 398 strlcpy(dbuf, cnf->home, sizeof(dbuf)); 399 p = dbuf; 400 if (stat(dbuf, &st) == -1) { 401 while ((p = strchr(p + 1, '/')) != NULL) { 402 *p = '\0'; 403 if (stat(dbuf, &st) == -1) { 404 if (mkdir(dbuf, _DEF_DIRMODE) == -1) 405 err(EX_OSFILE, "mkdir '%s'", dbuf); 406 chown(dbuf, 0, 0); 407 } else if (!S_ISDIR(st.st_mode)) 408 errx(EX_OSFILE, "'%s' (root home parent) is not a directory", dbuf); 409 *p = '/'; 410 } 411 } 412 if (stat(dbuf, &st) == -1) { 413 if (mkdir(dbuf, _DEF_DIRMODE) == -1) 414 err(EX_OSFILE, "mkdir '%s'", dbuf); 415 chown(dbuf, 0, 0); 416 } 417 } else if (!S_ISDIR(st.st_mode)) 418 errx(EX_OSFILE, "root home `%s' is not a directory", cnf->home); | 272 if (cnf->min_uid >= cnf->max_uid) { /* Sanity 273 * claus^H^H^H^Hheck */ 274 cnf->min_uid = 1000; 275 cnf->max_uid = 32000; |
419 } | 276 } |
277 bm = bm_alloc(cnf->max_uid - cnf->min_uid + 1); |
|
420 | 278 |
421 if ((arg = getarg(args, 'e')) != NULL) 422 cnf->expire_days = atoi(arg->val); 423 424 if ((arg = getarg(args, 'y')) != NULL) 425 cnf->nispasswd = arg->val; 426 427 if ((arg = getarg(args, 'p')) != NULL && arg->val) 428 cnf->password_days = atoi(arg->val); 429 430 if ((arg = getarg(args, 'g')) != NULL) { 431 if (!*(p = arg->val)) /* Handle empty group list specially */ 432 cnf->default_group = ""; 433 else { 434 if ((grp = GETGRNAM(p)) == NULL) { 435 if (!isdigit((unsigned char)*p) || (grp = GETGRGID((gid_t) atoi(p))) == NULL) 436 errx(EX_NOUSER, "group `%s' does not exist", p); 437 } 438 cnf->default_group = newstr(grp->gr_name); 439 } 440 } 441 if ((arg = getarg(args, 'L')) != NULL) 442 cnf->default_class = pw_checkname(arg->val, 0); 443 444 if ((arg = getarg(args, 'G')) != NULL && arg->val) { 445 for (p = strtok(arg->val, ", \t"); p != NULL; p = strtok(NULL, ", \t")) { 446 if ((grp = GETGRNAM(p)) == NULL) { 447 if (!isdigit((unsigned char)*p) || (grp = GETGRGID((gid_t) atoi(p))) == NULL) 448 errx(EX_NOUSER, "group `%s' does not exist", p); 449 } 450 sl_add(cnf->groups, newstr(grp->gr_name)); 451 } 452 } 453 454 if ((arg = getarg(args, 'k')) != NULL) { 455 char *tmp = cnf->dotdir = arg->val; 456 if (*tmp == '/') 457 tmp++; 458 if ((fstatat(conf.rootfd, tmp, &st, 0) == -1) || 459 !S_ISDIR(st.st_mode)) 460 errx(EX_OSFILE, "skeleton `%s' is not a directory or " 461 "does not exist", cnf->dotdir); 462 } 463 464 if ((arg = getarg(args, 's')) != NULL) 465 cnf->shell_default = arg->val; 466 467 if ((arg = getarg(args, 'w')) != NULL) 468 cnf->default_password = boolean_val(arg->val, cnf->default_password); 469 if (mode == M_ADD && getarg(args, 'D')) { 470 if (name != NULL) 471 errx(EX_DATAERR, "can't combine `-D' with `-n name'"); 472 if ((arg = getarg(args, 'u')) != NULL && (p = strtok(arg->val, ", \t")) != NULL) { 473 if ((cnf->min_uid = (uid_t) atoi(p)) == 0) 474 cnf->min_uid = 1000; 475 if ((p = strtok(NULL, " ,\t")) == NULL || (cnf->max_uid = (uid_t) atoi(p)) < cnf->min_uid) 476 cnf->max_uid = 32000; 477 } 478 if ((arg = getarg(args, 'i')) != NULL && (p = strtok(arg->val, ", \t")) != NULL) { 479 if ((cnf->min_gid = (gid_t) atoi(p)) == 0) 480 cnf->min_gid = 1000; 481 if ((p = strtok(NULL, " ,\t")) == NULL || (cnf->max_gid = (gid_t) atoi(p)) < cnf->min_gid) 482 cnf->max_gid = 32000; 483 } 484 485 if (write_userconfig(conf.config)) 486 return (EXIT_SUCCESS); 487 err(EX_IOERR, "config udpate"); 488 } 489 490 if (name != NULL) 491 pwd = GETPWNAM(pw_checkname(name, 0)); 492 493 if (id < 0 && name == NULL) 494 errx(EX_DATAERR, "user name or id required"); 495 | |
496 /* | 279 /* |
497 * Update require that the user exists | 280 * Now, let's fill the bitmap from the password file |
498 */ | 281 */ |
499 if (mode == M_UPDATE) { | 282 SETPWENT(); 283 while ((pwd = GETPWENT()) != NULL) 284 if (pwd->pw_uid >= (uid_t) cnf->min_uid && pwd->pw_uid <= (uid_t) cnf->max_uid) 285 bm_setbit(&bm, pwd->pw_uid - cnf->min_uid); 286 ENDPWENT(); |
500 | 287 |
501 if (name == NULL && pwd == NULL) /* Try harder */ 502 pwd = GETPWUID(id); 503 504 if (pwd == NULL) { 505 if (name == NULL) 506 errx(EX_NOUSER, "no such uid `%ld'", id); 507 errx(EX_NOUSER, "no such user `%s'", name); 508 } 509 510 if (conf.userconf->nispasswd && *conf.userconf->nispasswd == '/') 511 valid_type = _PWF_NIS; 512 513 if (PWF._altdir == PWF_REGULAR && 514 ((pwd->pw_fields & _PWF_SOURCE) != valid_type)) 515 errx(EX_NOUSER, "no such %s user `%s'", 516 valid_type == _PWF_FILES ? "local" : "NIS" , name); 517 518 if (name == NULL) 519 name = pwd->pw_name; 520 521 /* 522 * The rest is edit code 523 */ 524 if (conf.newname != NULL) { 525 if (strcmp(pwd->pw_name, "root") == 0) 526 errx(EX_DATAERR, "can't rename `root' account"); 527 pwd->pw_name = pw_checkname(conf.newname, 0); 528 edited = 1; 529 } 530 531 if (id > 0 && isdigit((unsigned char)*arg->val)) { 532 pwd->pw_uid = (uid_t)id; 533 edited = 1; 534 if (pwd->pw_uid != 0 && strcmp(pwd->pw_name, "root") == 0) 535 errx(EX_DATAERR, "can't change uid of `root' account"); 536 if (pwd->pw_uid == 0 && strcmp(pwd->pw_name, "root") != 0) 537 warnx("WARNING: account `%s' will have a uid of 0 (superuser access!)", pwd->pw_name); 538 } 539 540 if ((arg = getarg(args, 'g')) != NULL && pwd->pw_uid != 0) { /* Already checked this */ 541 gid_t newgid = (gid_t) GETGRNAM(cnf->default_group)->gr_gid; 542 if (newgid != pwd->pw_gid) { 543 edited = 1; 544 pwd->pw_gid = newgid; 545 } 546 } 547 548 if ((arg = getarg(args, 'p')) != NULL) { 549 if (*arg->val == '\0' || strcmp(arg->val, "0") == 0) { 550 if (pwd->pw_change != 0) { 551 pwd->pw_change = 0; 552 edited = 1; 553 } 554 } 555 else { 556 time_t now = time(NULL); 557 time_t expire = parse_date(now, arg->val); 558 559 if (pwd->pw_change != expire) { 560 pwd->pw_change = expire; 561 edited = 1; 562 } 563 } 564 } 565 566 if ((arg = getarg(args, 'e')) != NULL) { 567 if (*arg->val == '\0' || strcmp(arg->val, "0") == 0) { 568 if (pwd->pw_expire != 0) { 569 pwd->pw_expire = 0; 570 edited = 1; 571 } 572 } 573 else { 574 time_t now = time(NULL); 575 time_t expire = parse_date(now, arg->val); 576 577 if (pwd->pw_expire != expire) { 578 pwd->pw_expire = expire; 579 edited = 1; 580 } 581 } 582 } 583 584 if ((arg = getarg(args, 's')) != NULL) { 585 char *shell = shell_path(cnf->shelldir, cnf->shells, arg->val); 586 if (shell == NULL) 587 shell = ""; 588 if (strcmp(shell, pwd->pw_shell) != 0) { 589 pwd->pw_shell = shell; 590 edited = 1; 591 } 592 } 593 594 if (getarg(args, 'L')) { 595 if (cnf->default_class == NULL) 596 cnf->default_class = ""; 597 if (strcmp(pwd->pw_class, cnf->default_class) != 0) { 598 pwd->pw_class = cnf->default_class; 599 edited = 1; 600 } 601 } 602 603 if ((arg = getarg(args, 'd')) != NULL) { 604 if (strcmp(pwd->pw_dir, arg->val)) 605 edited = 1; 606 if (stat(pwd->pw_dir = arg->val, &st) == -1) { 607 if (getarg(args, 'm') == NULL && strcmp(pwd->pw_dir, "/nonexistent") != 0) 608 warnx("WARNING: home `%s' does not exist", pwd->pw_dir); 609 } else if (!S_ISDIR(st.st_mode)) 610 warnx("WARNING: home `%s' is not a directory", pwd->pw_dir); 611 } 612 613 if ((arg = getarg(args, 'w')) != NULL && conf.fd == -1) { 614 login_cap_t *lc; 615 616 lc = login_getpwclass(pwd); 617 if (lc == NULL || 618 login_setcryptfmt(lc, "sha512", NULL) == NULL) 619 warn("setting crypt(3) format"); 620 login_close(lc); 621 pwd->pw_passwd = pw_password(cnf, pwd->pw_name); 622 edited = 1; 623 } 624 625 } else { 626 login_cap_t *lc; 627 628 /* 629 * Add code 630 */ 631 632 if (name == NULL) /* Required */ 633 errx(EX_DATAERR, "login name required"); 634 else if ((pwd = GETPWNAM(name)) != NULL) /* Exists */ 635 errx(EX_DATAERR, "login name `%s' already exists", name); 636 637 /* 638 * Now, set up defaults for a new user 639 */ 640 pwd = &fakeuser; 641 pwd->pw_name = name; 642 pwd->pw_class = cnf->default_class ? cnf->default_class : ""; 643 pwd->pw_uid = pw_uidpolicy(cnf, id); 644 pwd->pw_gid = pw_gidpolicy(args, pwd->pw_name, (gid_t) pwd->pw_uid); 645 pwd->pw_change = pw_pwdpolicy(cnf, args); 646 pwd->pw_expire = pw_exppolicy(cnf, args); 647 pwd->pw_dir = pw_homepolicy(cnf, args, pwd->pw_name); 648 pwd->pw_shell = pw_shellpolicy(cnf, args, NULL); 649 lc = login_getpwclass(pwd); 650 if (lc == NULL || login_setcryptfmt(lc, "sha512", NULL) == NULL) 651 warn("setting crypt(3) format"); 652 login_close(lc); 653 pwd->pw_passwd = pw_password(cnf, pwd->pw_name); 654 edited = 1; 655 656 if (pwd->pw_uid == 0 && strcmp(pwd->pw_name, "root") != 0) 657 warnx("WARNING: new account `%s' has a uid of 0 (superuser access!)", pwd->pw_name); 658 } 659 | |
660 /* | 288 /* |
661 * Shared add/edit code | 289 * Then apply the policy, with fallback to reuse if necessary |
662 */ | 290 */ |
663 if (conf.gecos != NULL) { 664 if (strcmp(pwd->pw_gecos, conf.gecos) != 0) { 665 pwd->pw_gecos = conf.gecos; 666 edited = 1; 667 } 668 } | 291 if (cnf->reuse_uids || (uid = (uid_t) (bm_lastset(&bm) + cnf->min_uid + 1)) > cnf->max_uid) 292 uid = (uid_t) (bm_firstunset(&bm) + cnf->min_uid); |
669 | 293 |
670 if (conf.fd != -1) 671 edited = set_passwd(pwd, mode == M_UPDATE); 672 | |
673 /* | 294 /* |
674 * Special case: -N only displays & exits | 295 * Another sanity check |
675 */ | 296 */ |
676 if (conf.dryrun) 677 return print_user(pwd); 678 679 if (mode == M_ADD) { 680 edited = 1; /* Always */ 681 rc = addpwent(pwd); 682 if (rc == -1) 683 errx(EX_IOERR, "user '%s' already exists", 684 pwd->pw_name); 685 else if (rc != 0) 686 err(EX_IOERR, "passwd file update"); 687 if (cnf->nispasswd && *cnf->nispasswd=='/') { 688 rc = addnispwent(cnf->nispasswd, pwd); 689 if (rc == -1) 690 warnx("User '%s' already exists in NIS passwd", pwd->pw_name); 691 else if (rc != 0) 692 warn("NIS passwd update"); 693 /* NOTE: we treat NIS-only update errors as non-fatal */ 694 } 695 } else if (mode == M_UPDATE && edited) /* Only updated this if required */ 696 perform_chgpwent(name, pwd); 697 698 /* 699 * Ok, user is created or changed - now edit group file 700 */ 701 702 if (mode == M_ADD || getarg(args, 'G') != NULL) { 703 int j; 704 size_t i; 705 /* First remove the user from all group */ 706 SETGRENT(); 707 while ((grp = GETGRENT()) != NULL) { 708 char group[MAXLOGNAME]; 709 if (grp->gr_mem == NULL) 710 continue; 711 for (i = 0; grp->gr_mem[i] != NULL; i++) { 712 if (strcmp(grp->gr_mem[i] , pwd->pw_name) != 0) 713 continue; 714 for (j = i; grp->gr_mem[j] != NULL ; j++) 715 grp->gr_mem[j] = grp->gr_mem[j+1]; 716 strlcpy(group, grp->gr_name, MAXLOGNAME); 717 chggrent(group, grp); 718 } 719 } 720 ENDGRENT(); 721 722 /* now add to group where needed */ 723 for (i = 0; i < cnf->groups->sl_cur; i++) { 724 grp = GETGRNAM(cnf->groups->sl_str[i]); 725 grp = gr_add(grp, pwd->pw_name); 726 /* 727 * grp can only be NULL in 2 cases: 728 * - the new member is already a member 729 * - a problem with memory occurs 730 * in both cases we want to skip now. 731 */ 732 if (grp == NULL) 733 continue; 734 chggrent(grp->gr_name, grp); 735 free(grp); 736 } 737 } 738 739 740 /* go get a current version of pwd */ 741 pwd = GETPWNAM(name); 742 if (pwd == NULL) { 743 /* This will fail when we rename, so special case that */ 744 if (mode == M_UPDATE && conf.newname != NULL) { 745 name = conf.newname; /* update new name */ 746 pwd = GETPWNAM(name); /* refetch renamed rec */ 747 } 748 } 749 if (pwd == NULL) /* can't go on without this */ 750 errx(EX_NOUSER, "user '%s' disappeared during update", name); 751 752 grp = GETGRGID(pwd->pw_gid); 753 pw_log(cnf, mode, W_USER, "%s(%ju):%s(%ju):%s:%s:%s", 754 pwd->pw_name, (uintmax_t)pwd->pw_uid, 755 grp ? grp->gr_name : "unknown", (uintmax_t)(grp ? grp->gr_gid : (uid_t)-1), 756 pwd->pw_gecos, pwd->pw_dir, pwd->pw_shell); 757 758 /* 759 * If adding, let's touch and chown the user's mail file. This is not 760 * strictly necessary under BSD with a 0755 maildir but it also 761 * doesn't hurt anything to create the empty mailfile 762 */ 763 if (mode == M_ADD) { 764 if (PWALTDIR() != PWF_ALT) { 765 snprintf(path, sizeof(path), "%s/%s", _PATH_MAILDIR, 766 pwd->pw_name); 767 close(openat(conf.rootfd, path +1, O_RDWR | O_CREAT, 768 0600)); /* Preserve contents & mtime */ 769 fchownat(conf.rootfd, path + 1, pwd->pw_uid, 770 pwd->pw_gid, AT_SYMLINK_NOFOLLOW); 771 } 772 } 773 774 /* 775 * Let's create and populate the user's home directory. Note 776 * that this also `works' for editing users if -m is used, but 777 * existing files will *not* be overwritten. 778 */ 779 if (PWALTDIR() != PWF_ALT && getarg(args, 'm') != NULL && pwd->pw_dir && 780 *pwd->pw_dir == '/' && pwd->pw_dir[1]) 781 create_and_populate_homedir(pwd); 782 783 /* 784 * Finally, send mail to the new user as well, if we are asked to 785 */ 786 if (mode == M_ADD && !PWALTDIR() && cnf->newmail && *cnf->newmail && (fp = fopen(cnf->newmail, "r")) != NULL) { 787 FILE *pfp = popen(_PATH_SENDMAIL " -t", "w"); 788 789 if (pfp == NULL) 790 warn("sendmail"); 791 else { 792 fprintf(pfp, "From: root\n" "To: %s\n" "Subject: Welcome!\n\n", pwd->pw_name); 793 while (fgets(line, sizeof(line), fp) != NULL) { 794 /* Do substitutions? */ 795 fputs(line, pfp); 796 } 797 pclose(pfp); 798 pw_log(cnf, mode, W_USER, "%s(%ju) new user mail sent", 799 pwd->pw_name, (uintmax_t)pwd->pw_uid); 800 } 801 fclose(fp); 802 } 803 804 return EXIT_SUCCESS; | 297 if (uid < cnf->min_uid || uid > cnf->max_uid) 298 errx(EX_SOFTWARE, "unable to allocate a new uid - range fully used"); 299 bm_dealloc(&bm); 300 return (uid); |
805} 806 | 301} 302 |
807 808static uid_t 809pw_uidpolicy(struct userconf * cnf, long id) | 303static uid_t 304pw_gidpolicy(struct userconf *cnf, char *grname, char *nam, gid_t prefer, bool dryrun) |
810{ | 305{ |
811 struct passwd *pwd; 812 uid_t uid = (uid_t) - 1; 813 814 /* 815 * Check the given uid, if any 816 */ 817 if (id >= 0) { 818 uid = (uid_t) id; 819 820 if ((pwd = GETPWUID(uid)) != NULL && conf.checkduplicate) 821 errx(EX_DATAERR, "uid `%ju' has already been allocated", 822 (uintmax_t)pwd->pw_uid); 823 } else { 824 struct bitmap bm; 825 826 /* 827 * We need to allocate the next available uid under one of 828 * two policies a) Grab the first unused uid b) Grab the 829 * highest possible unused uid 830 */ 831 if (cnf->min_uid >= cnf->max_uid) { /* Sanity 832 * claus^H^H^H^Hheck */ 833 cnf->min_uid = 1000; 834 cnf->max_uid = 32000; 835 } 836 bm = bm_alloc(cnf->max_uid - cnf->min_uid + 1); 837 838 /* 839 * Now, let's fill the bitmap from the password file 840 */ 841 SETPWENT(); 842 while ((pwd = GETPWENT()) != NULL) 843 if (pwd->pw_uid >= (uid_t) cnf->min_uid && pwd->pw_uid <= (uid_t) cnf->max_uid) 844 bm_setbit(&bm, pwd->pw_uid - cnf->min_uid); 845 ENDPWENT(); 846 847 /* 848 * Then apply the policy, with fallback to reuse if necessary 849 */ 850 if (cnf->reuse_uids || (uid = (uid_t) (bm_lastset(&bm) + cnf->min_uid + 1)) > cnf->max_uid) 851 uid = (uid_t) (bm_firstunset(&bm) + cnf->min_uid); 852 853 /* 854 * Another sanity check 855 */ 856 if (uid < cnf->min_uid || uid > cnf->max_uid) 857 errx(EX_SOFTWARE, "unable to allocate a new uid - range fully used"); 858 bm_dealloc(&bm); 859 } 860 return uid; 861} 862 863 864static uid_t 865pw_gidpolicy(struct cargs * args, char *nam, gid_t prefer) 866{ | |
867 struct group *grp; 868 gid_t gid = (uid_t) - 1; | 306 struct group *grp; 307 gid_t gid = (uid_t) - 1; |
869 struct carg *a_gid = getarg(args, 'g'); 870 struct userconf *cnf = conf.userconf; | |
871 872 /* | 308 309 /* |
873 * If no arg given, see if default can help out 874 */ 875 if (a_gid == NULL && cnf->default_group && *cnf->default_group) 876 a_gid = addarg(args, 'g', cnf->default_group); 877 878 /* | |
879 * Check the given gid, if any 880 */ 881 SETGRENT(); | 310 * Check the given gid, if any 311 */ 312 SETGRENT(); |
882 if (a_gid != NULL) { 883 if ((grp = GETGRNAM(a_gid->val)) == NULL) { 884 gid = (gid_t) atol(a_gid->val); 885 if ((gid == 0 && !isdigit((unsigned char)*a_gid->val)) || (grp = GETGRGID(gid)) == NULL) 886 errx(EX_NOUSER, "group `%s' is not defined", a_gid->val); | 313 if (grname) { 314 if ((grp = GETGRNAM(grname)) == NULL) { 315 gid = pw_checkid(grname, GID_MAX); 316 grp = GETGRGID(gid); |
887 } 888 gid = grp->gr_gid; 889 } else if ((grp = GETGRNAM(nam)) != NULL && 890 (grp->gr_mem == NULL || grp->gr_mem[0] == NULL)) { 891 gid = grp->gr_gid; /* Already created? Use it anyway... */ 892 } else { | 317 } 318 gid = grp->gr_gid; 319 } else if ((grp = GETGRNAM(nam)) != NULL && 320 (grp->gr_mem == NULL || grp->gr_mem[0] == NULL)) { 321 gid = grp->gr_gid; /* Already created? Use it anyway... */ 322 } else { |
893 gid_t grid = -1; | 323 intmax_t grid = -1; |
894 895 /* 896 * We need to auto-create a group with the user's name. We 897 * can send all the appropriate output to our sister routine 898 * bit first see if we can create a group with gid==uid so we 899 * can keep the user and group ids in sync. We purposely do 900 * NOT check the gid range if we can force the sync. If the 901 * user's name dups an existing group, then the group add 902 * function will happily handle that case for us and exit. 903 */ 904 if (GETGRGID(prefer) == NULL) 905 grid = prefer; | 324 325 /* 326 * We need to auto-create a group with the user's name. We 327 * can send all the appropriate output to our sister routine 328 * bit first see if we can create a group with gid==uid so we 329 * can keep the user and group ids in sync. We purposely do 330 * NOT check the gid range if we can force the sync. If the 331 * user's name dups an existing group, then the group add 332 * function will happily handle that case for us and exit. 333 */ 334 if (GETGRGID(prefer) == NULL) 335 grid = prefer; |
906 if (conf.dryrun) { | 336 if (dryrun) { |
907 gid = pw_groupnext(cnf, true); 908 } else { | 337 gid = pw_groupnext(cnf, true); 338 } else { |
909 pw_group(M_ADD, nam, grid, NULL); | 339 if (grid == -1) 340 grid = pw_groupnext(cnf, true); 341 groupadd(cnf, nam, grid, NULL, -1, false, false, false); |
910 if ((grp = GETGRNAM(nam)) != NULL) 911 gid = grp->gr_gid; 912 } 913 } 914 ENDGRENT(); | 342 if ((grp = GETGRNAM(nam)) != NULL) 343 gid = grp->gr_gid; 344 } 345 } 346 ENDGRENT(); |
915 return gid; | 347 return (gid); |
916} 917 | 348} 349 |
918 919static time_t 920pw_pwdpolicy(struct userconf * cnf, struct cargs * args) | 350static char * 351pw_homepolicy(struct userconf * cnf, char *homedir, const char *user) |
921{ | 352{ |
922 time_t result = 0; 923 time_t now = time(NULL); 924 struct carg *arg = getarg(args, 'p'); 925 926 if (arg != NULL) { 927 if ((result = parse_date(now, arg->val)) == now) 928 errx(EX_DATAERR, "invalid date/time `%s'", arg->val); 929 } else if (cnf->password_days > 0) 930 result = now + ((long) cnf->password_days * 86400L); 931 return result; 932} 933 934 935static time_t 936pw_exppolicy(struct userconf * cnf, struct cargs * args) 937{ 938 time_t result = 0; 939 time_t now = time(NULL); 940 struct carg *arg = getarg(args, 'e'); 941 942 if (arg != NULL) { 943 if ((result = parse_date(now, arg->val)) == now) 944 errx(EX_DATAERR, "invalid date/time `%s'", arg->val); 945 } else if (cnf->expire_days > 0) 946 result = now + ((long) cnf->expire_days * 86400L); 947 return result; 948} 949 950 951static char * 952pw_homepolicy(struct userconf * cnf, struct cargs * args, char const * user) 953{ 954 struct carg *arg = getarg(args, 'd'); | |
955 static char home[128]; 956 | 353 static char home[128]; 354 |
957 if (arg) 958 return (arg->val); | 355 if (homedir) 356 return (homedir); |
959 960 if (cnf->home == NULL || *cnf->home == '\0') 961 errx(EX_CONFIG, "no base home directory set"); 962 snprintf(home, sizeof(home), "%s/%s", cnf->home, user); 963 964 return (home); 965} 966 | 357 358 if (cnf->home == NULL || *cnf->home == '\0') 359 errx(EX_CONFIG, "no base home directory set"); 360 snprintf(home, sizeof(home), "%s/%s", cnf->home, user); 361 362 return (home); 363} 364 |
967static char * | 365static char * |
968shell_path(char const * path, char *shells[], char *sh) 969{ 970 if (sh != NULL && (*sh == '/' || *sh == '\0')) 971 return sh; /* specified full path or forced none */ 972 else { 973 char *p; 974 char paths[_UC_MAXLINE]; 975 --- 18 unchanged lines hidden (view full) --- 994 } 995 if (sh == NULL) 996 errx(EX_OSFILE, "can't find shell `%s' in shell paths", sh); 997 errx(EX_CONFIG, "no default shell available or defined"); 998 return NULL; 999 } 1000} 1001 | 366shell_path(char const * path, char *shells[], char *sh) 367{ 368 if (sh != NULL && (*sh == '/' || *sh == '\0')) 369 return sh; /* specified full path or forced none */ 370 else { 371 char *p; 372 char paths[_UC_MAXLINE]; 373 --- 18 unchanged lines hidden (view full) --- 392 } 393 if (sh == NULL) 394 errx(EX_OSFILE, "can't find shell `%s' in shell paths", sh); 395 errx(EX_CONFIG, "no default shell available or defined"); 396 return NULL; 397 } 398} 399 |
1002 1003static char * 1004pw_shellpolicy(struct userconf * cnf, struct cargs * args, char *newshell) | 400static char * 401pw_shellpolicy(struct userconf * cnf) |
1005{ | 402{ |
1006 char *sh = newshell; 1007 struct carg *arg = getarg(args, 's'); | |
1008 | 403 |
1009 if (newshell == NULL && arg != NULL) 1010 sh = arg->val; 1011 return shell_path(cnf->shelldir, cnf->shells, sh ? sh : cnf->shell_default); | 404 return shell_path(cnf->shelldir, cnf->shells, cnf->shell_default); |
1012} 1013 1014#define SALTSIZE 32 1015 1016static char const chars[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./"; 1017 | 405} 406 407#define SALTSIZE 32 408 409static char const chars[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./"; 410 |
1018char * | 411char * |
1019pw_pwcrypt(char *password) 1020{ 1021 int i; 1022 char salt[SALTSIZE + 1]; 1023 char *cryptpw; | 412pw_pwcrypt(char *password) 413{ 414 int i; 415 char salt[SALTSIZE + 1]; 416 char *cryptpw; |
1024 | |
1025 static char buf[256]; 1026 1027 /* 1028 * Calculate a salt value 1029 */ 1030 for (i = 0; i < SALTSIZE; i++) 1031 salt[i] = chars[arc4random_uniform(sizeof(chars) - 1)]; 1032 salt[SALTSIZE] = '\0'; 1033 1034 cryptpw = crypt(password, salt); 1035 if (cryptpw == NULL) 1036 errx(EX_CONFIG, "crypt(3) failure"); 1037 return strcpy(buf, cryptpw); 1038} 1039 | 417 static char buf[256]; 418 419 /* 420 * Calculate a salt value 421 */ 422 for (i = 0; i < SALTSIZE; i++) 423 salt[i] = chars[arc4random_uniform(sizeof(chars) - 1)]; 424 salt[SALTSIZE] = '\0'; 425 426 cryptpw = crypt(password, salt); 427 if (cryptpw == NULL) 428 errx(EX_CONFIG, "crypt(3) failure"); 429 return strcpy(buf, cryptpw); 430} 431 |
1040 1041static char * 1042pw_password(struct userconf * cnf, char const * user) | 432static char * 433pw_password(struct userconf * cnf, char const * user, bool dryrun) |
1043{ 1044 int i, l; 1045 char pwbuf[32]; 1046 1047 switch (cnf->default_password) { 1048 case -1: /* Random password */ 1049 l = (arc4random() % 8 + 8); /* 8 - 16 chars */ 1050 for (i = 0; i < l; i++) 1051 pwbuf[i] = chars[arc4random_uniform(sizeof(chars)-1)]; 1052 pwbuf[i] = '\0'; 1053 1054 /* 1055 * We give this information back to the user 1056 */ | 434{ 435 int i, l; 436 char pwbuf[32]; 437 438 switch (cnf->default_password) { 439 case -1: /* Random password */ 440 l = (arc4random() % 8 + 8); /* 8 - 16 chars */ 441 for (i = 0; i < l; i++) 442 pwbuf[i] = chars[arc4random_uniform(sizeof(chars)-1)]; 443 pwbuf[i] = '\0'; 444 445 /* 446 * We give this information back to the user 447 */ |
1057 if (conf.fd == -1 && !conf.dryrun) { | 448 if (conf.fd == -1 && !dryrun) { |
1058 if (isatty(STDOUT_FILENO)) 1059 printf("Password for '%s' is: ", user); 1060 printf("%s\n", pwbuf); 1061 fflush(stdout); 1062 } 1063 break; 1064 1065 case -2: /* No password at all! */ --- 6 unchanged lines hidden (view full) --- 1072 case 1: /* user's name */ 1073 strlcpy(pwbuf, user, sizeof(pwbuf)); 1074 break; 1075 } 1076 return pw_pwcrypt(pwbuf); 1077} 1078 1079static int | 449 if (isatty(STDOUT_FILENO)) 450 printf("Password for '%s' is: ", user); 451 printf("%s\n", pwbuf); 452 fflush(stdout); 453 } 454 break; 455 456 case -2: /* No password at all! */ --- 6 unchanged lines hidden (view full) --- 463 case 1: /* user's name */ 464 strlcpy(pwbuf, user, sizeof(pwbuf)); 465 break; 466 } 467 return pw_pwcrypt(pwbuf); 468} 469 470static int |
1080pw_userdel(char *name, long id) | 471print_user(struct passwd * pwd, bool pretty, bool v7) |
1081{ | 472{ |
473 int j; 474 char *p; 475 struct group *grp = GETGRGID(pwd->pw_gid); 476 char uname[60] = "User &", office[60] = "[None]", 477 wphone[60] = "[None]", hphone[60] = "[None]"; 478 char acexpire[32] = "[None]", pwexpire[32] = "[None]"; 479 struct tm * tptr; 480 481 if (!pretty) { 482 p = v7 ? pw_make_v7(pwd) : pw_make(pwd); 483 printf("%s\n", p); 484 free(p); 485 return (EXIT_SUCCESS); 486 } 487 488 if ((p = strtok(pwd->pw_gecos, ",")) != NULL) { 489 strlcpy(uname, p, sizeof(uname)); 490 if ((p = strtok(NULL, ",")) != NULL) { 491 strlcpy(office, p, sizeof(office)); 492 if ((p = strtok(NULL, ",")) != NULL) { 493 strlcpy(wphone, p, sizeof(wphone)); 494 if ((p = strtok(NULL, "")) != NULL) { 495 strlcpy(hphone, p, sizeof(hphone)); 496 } 497 } 498 } 499 } 500 /* 501 * Handle '&' in gecos field 502 */ 503 if ((p = strchr(uname, '&')) != NULL) { 504 int l = strlen(pwd->pw_name); 505 int m = strlen(p); 506 507 memmove(p + l, p + 1, m); 508 memmove(p, pwd->pw_name, l); 509 *p = (char) toupper((unsigned char)*p); 510 } 511 if (pwd->pw_expire > (time_t)0 && (tptr = localtime(&pwd->pw_expire)) != NULL) 512 strftime(acexpire, sizeof acexpire, "%c", tptr); 513 if (pwd->pw_change > (time_t)0 && (tptr = localtime(&pwd->pw_change)) != NULL) 514 strftime(pwexpire, sizeof pwexpire, "%c", tptr); 515 printf("Login Name: %-15s #%-12ju Group: %-15s #%ju\n" 516 " Full Name: %s\n" 517 " Home: %-26.26s Class: %s\n" 518 " Shell: %-26.26s Office: %s\n" 519 "Work Phone: %-26.26s Home Phone: %s\n" 520 "Acc Expire: %-26.26s Pwd Expire: %s\n", 521 pwd->pw_name, (uintmax_t)pwd->pw_uid, 522 grp ? grp->gr_name : "(invalid)", (uintmax_t)pwd->pw_gid, 523 uname, pwd->pw_dir, pwd->pw_class, 524 pwd->pw_shell, office, wphone, hphone, 525 acexpire, pwexpire); 526 SETGRENT(); 527 j = 0; 528 while ((grp=GETGRENT()) != NULL) { 529 int i = 0; 530 if (grp->gr_mem != NULL) { 531 while (grp->gr_mem[i] != NULL) { 532 if (strcmp(grp->gr_mem[i], pwd->pw_name)==0) { 533 printf(j++ == 0 ? " Groups: %s" : ",%s", grp->gr_name); 534 break; 535 } 536 ++i; 537 } 538 } 539 } 540 ENDGRENT(); 541 printf("%s", j ? "\n" : ""); 542 return (EXIT_SUCCESS); 543} 544 545char * 546pw_checkname(char *name, int gecos) 547{ 548 char showch[8]; 549 const char *badchars, *ch, *showtype; 550 int reject; 551 552 ch = name; 553 reject = 0; 554 if (gecos) { 555 /* See if the name is valid as a gecos (comment) field. */ 556 badchars = ":!@"; 557 showtype = "gecos field"; 558 } else { 559 /* See if the name is valid as a userid or group. */ 560 badchars = " ,\t:+&#%$^()!@~*?<>=|\\/\""; 561 showtype = "userid/group name"; 562 /* Userids and groups can not have a leading '-'. */ 563 if (*ch == '-') 564 reject = 1; 565 } 566 if (!reject) { 567 while (*ch) { 568 if (strchr(badchars, *ch) != NULL || *ch < ' ' || 569 *ch == 127) { 570 reject = 1; 571 break; 572 } 573 /* 8-bit characters are only allowed in GECOS fields */ 574 if (!gecos && (*ch & 0x80)) { 575 reject = 1; 576 break; 577 } 578 ch++; 579 } 580 } 581 /* 582 * A `$' is allowed as the final character for userids and groups, 583 * mainly for the benefit of samba. 584 */ 585 if (reject && !gecos) { 586 if (*ch == '$' && *(ch + 1) == '\0') { 587 reject = 0; 588 ch++; 589 } 590 } 591 if (reject) { 592 snprintf(showch, sizeof(showch), (*ch >= ' ' && *ch < 127) 593 ? "`%c'" : "0x%02x", *ch); 594 errx(EX_DATAERR, "invalid character %s at position %td in %s", 595 showch, (ch - name), showtype); 596 } 597 if (!gecos && (ch - name) > LOGNAMESIZE) 598 errx(EX_USAGE, "name too long `%s' (max is %d)", name, 599 LOGNAMESIZE); 600 601 return (name); 602} 603 604static void 605rmat(uid_t uid) 606{ 607 DIR *d = opendir("/var/at/jobs"); 608 609 if (d != NULL) { 610 struct dirent *e; 611 612 while ((e = readdir(d)) != NULL) { 613 struct stat st; 614 615 if (strncmp(e->d_name, ".lock", 5) != 0 && 616 stat(e->d_name, &st) == 0 && 617 !S_ISDIR(st.st_mode) && 618 st.st_uid == uid) { 619 char tmp[MAXPATHLEN]; 620 621 snprintf(tmp, sizeof(tmp), "/usr/bin/atrm %s", e->d_name); 622 system(tmp); 623 } 624 } 625 closedir(d); 626 } 627} 628 629static void 630rmopie(char const * name) 631{ 632 char tmp[1014]; 633 FILE *fp; 634 int fd; 635 size_t len; 636 off_t atofs = 0; 637 638 if ((fd = openat(conf.rootfd, "etc/opiekeys", O_RDWR)) == -1) 639 return; 640 641 fp = fdopen(fd, "r+"); 642 len = strlen(name); 643 644 while (fgets(tmp, sizeof(tmp), fp) != NULL) { 645 if (strncmp(name, tmp, len) == 0 && tmp[len]==' ') { 646 /* Comment username out */ 647 if (fseek(fp, atofs, SEEK_SET) == 0) 648 fwrite("#", 1, 1, fp); 649 break; 650 } 651 atofs = ftell(fp); 652 } 653 /* 654 * If we got an error of any sort, don't update! 655 */ 656 fclose(fp); 657} 658 659int 660pw_user_next(int argc, char **argv, char *name __unused) 661{ 662 struct userconf *cnf = NULL; 663 const char *cfg = NULL; 664 int ch; 665 bool quiet = false; 666 uid_t next; 667 668 while ((ch = getopt(argc, argv, "Cq")) != -1) { 669 switch (ch) { 670 case 'C': 671 cfg = optarg; 672 break; 673 case 'q': 674 quiet; 675 break; 676 } 677 } 678 679 if (quiet) 680 freopen(_PATH_DEVNULL, "w", stderr); 681 682 cnf = get_userconfig(cfg); 683 684 next = pw_uidpolicy(cnf, -1); 685 686 printf("%ju:", (uintmax_t)next); 687 pw_groupnext(cnf, quiet); 688 689 return (EXIT_SUCCESS); 690} 691 692int 693pw_user_show(int argc, char **argv, char *arg1) 694{ |
|
1082 struct passwd *pwd = NULL; | 695 struct passwd *pwd = NULL; |
1083 char file[MAXPATHLEN]; 1084 char home[MAXPATHLEN]; 1085 uid_t uid; 1086 struct group *gr, *grp; 1087 char grname[LOGNAMESIZE]; 1088 int rc; 1089 struct stat st; 1090 int valid_type = _PWF_FILES; | 696 char *name = NULL; 697 uid_t id = -1; 698 int ch; 699 bool all = false; 700 bool pretty = false; 701 bool force = false; 702 bool v7 = false; 703 bool quiet = false; |
1091 | 704 |
705 if (arg1 != NULL) { 706 if (strspn(arg1, "0123456789") == strlen(arg1)) 707 id = pw_checkid(arg1, UID_MAX); 708 else 709 name = arg1; 710 } 711 712 while ((ch = getopt(argc, argv, "C:qn:u:FPa7")) != -1) { 713 switch (ch) { 714 case 'C': 715 /* ignore compatibility */ 716 break; 717 case 'q': 718 quiet = true; 719 break; 720 case 'n': 721 name = optarg; 722 break; 723 case 'u': 724 id = pw_checkid(optarg, UID_MAX); 725 break; 726 case 'F': 727 force = true; 728 break; 729 case 'P': 730 pretty = true; 731 break; 732 case 'a': 733 all = true; 734 break; 735 case 7: 736 v7 = true; 737 break; 738 } 739 } 740 741 if (quiet) 742 freopen(_PATH_DEVNULL, "w", stderr); 743 744 if (all) { 745 SETPWENT(); 746 while ((pwd = GETPWENT()) != NULL) 747 print_user(pwd, pretty, v7); 748 ENDPWENT(); 749 return (EXIT_SUCCESS); 750 } 751 |
|
1092 if (id < 0 && name == NULL) 1093 errx(EX_DATAERR, "username or id required"); 1094 1095 pwd = (name != NULL) ? GETPWNAM(pw_checkname(name, 0)) : GETPWUID(id); 1096 if (pwd == NULL) { | 752 if (id < 0 && name == NULL) 753 errx(EX_DATAERR, "username or id required"); 754 755 pwd = (name != NULL) ? GETPWNAM(pw_checkname(name, 0)) : GETPWUID(id); 756 if (pwd == NULL) { |
757 if (force) { 758 pwd = &fakeuser; 759 } else { 760 if (name == NULL) 761 errx(EX_NOUSER, "no such uid `%ju'", 762 (uintmax_t) id); 763 errx(EX_NOUSER, "no such user `%s'", name); 764 } 765 } 766 767 return (print_user(pwd, pretty, v7)); 768} 769 770int 771pw_user_del(int argc, char **argv, char *arg1) 772{ 773 struct userconf *cnf = NULL; 774 struct passwd *pwd = NULL; 775 struct group *gr, *grp; 776 char *name = NULL; 777 char grname[MAXLOGNAME]; 778 char *nispasswd = NULL; 779 char file[MAXPATHLEN]; 780 char home[MAXPATHLEN]; 781 const char *cfg = NULL; 782 struct stat st; 783 uid_t id; 784 int ch, rc; 785 bool nis = false; 786 bool deletehome = false; 787 bool quiet = false; 788 789 if (arg1 != NULL) { 790 if (strspn(arg1, "0123456789") == strlen(arg1)) 791 id = pw_checkid(arg1, UID_MAX); 792 else 793 name = arg1; 794 } 795 796 while ((ch = getopt(argc, argv, "C:qn:u:rYy:")) != -1) { 797 switch (ch) { 798 case 'C': 799 cfg = optarg; 800 break; 801 case 'q': 802 quiet = true; 803 break; 804 case 'n': 805 name = optarg; 806 break; 807 case 'u': 808 id = pw_checkid(optarg, UID_MAX); 809 break; 810 case 'r': 811 deletehome = true; 812 break; 813 case 'y': 814 nispasswd = optarg; 815 break; 816 case 'Y': 817 nis = true; 818 break; 819 } 820 } 821 822 if (quiet) 823 freopen(_PATH_DEVNULL, "w", stderr); 824 825 if (id < 0 && name == NULL) 826 errx(EX_DATAERR, "username or id required"); 827 828 cnf = get_userconfig(cfg); 829 830 if (nispasswd == NULL) 831 nispasswd = cnf->nispasswd; 832 833 pwd = (name != NULL) ? GETPWNAM(pw_checkname(name, 0)) : GETPWUID(id); 834 if (pwd == NULL) { |
|
1097 if (name == NULL) | 835 if (name == NULL) |
1098 errx(EX_NOUSER, "no such uid `%ld'", id); | 836 errx(EX_NOUSER, "no such uid `%ju'", (uintmax_t) id); |
1099 errx(EX_NOUSER, "no such user `%s'", name); 1100 } 1101 | 837 errx(EX_NOUSER, "no such user `%s'", name); 838 } 839 |
1102 if (conf.userconf->nispasswd && *conf.userconf->nispasswd == '/') 1103 valid_type = _PWF_NIS; 1104 | |
1105 if (PWF._altdir == PWF_REGULAR && | 840 if (PWF._altdir == PWF_REGULAR && |
1106 ((pwd->pw_fields & _PWF_SOURCE) != valid_type)) 1107 errx(EX_NOUSER, "no such %s user `%s'", 1108 valid_type == _PWF_FILES ? "local" : "NIS" , name); | 841 ((pwd->pw_fields & _PWF_SOURCE) != _PWF_FILES)) { 842 if ((pwd->pw_fields & _PWF_SOURCE) == _PWF_NIS) { 843 if (!nis && nispasswd && *nispasswd != '/') 844 errx(EX_NOUSER, "Cannot remove NIS user `%s'", 845 name); 846 } else { 847 errx(EX_NOUSER, "Cannot remove non local user `%s'", 848 name); 849 } 850 } |
1109 | 851 |
1110 uid = pwd->pw_uid; | 852 id = pwd->pw_uid; |
1111 if (name == NULL) 1112 name = pwd->pw_name; 1113 1114 if (strcmp(pwd->pw_name, "root") == 0) 1115 errx(EX_DATAERR, "cannot remove user 'root'"); 1116 | 853 if (name == NULL) 854 name = pwd->pw_name; 855 856 if (strcmp(pwd->pw_name, "root") == 0) 857 errx(EX_DATAERR, "cannot remove user 'root'"); 858 |
1117 /* Remove opie record from /etc/opiekeys */ 1118 | 859 /* Remove opie record from /etc/opiekeys */ |
1119 if (PWALTDIR() != PWF_ALT) 1120 rmopie(pwd->pw_name); 1121 1122 if (!PWALTDIR()) { 1123 /* Remove crontabs */ 1124 snprintf(file, sizeof(file), "/var/cron/tabs/%s", pwd->pw_name); 1125 if (access(file, F_OK) == 0) { 1126 snprintf(file, sizeof(file), "crontab -u %s -r", pwd->pw_name); 1127 system(file); 1128 } 1129 } | 860 if (PWALTDIR() != PWF_ALT) 861 rmopie(pwd->pw_name); 862 863 if (!PWALTDIR()) { 864 /* Remove crontabs */ 865 snprintf(file, sizeof(file), "/var/cron/tabs/%s", pwd->pw_name); 866 if (access(file, F_OK) == 0) { 867 snprintf(file, sizeof(file), "crontab -u %s -r", pwd->pw_name); 868 system(file); 869 } 870 } |
871 |
|
1130 /* 1131 * Save these for later, since contents of pwd may be 1132 * invalidated by deletion 1133 */ 1134 snprintf(file, sizeof(file), "%s/%s", _PATH_MAILDIR, pwd->pw_name); 1135 strlcpy(home, pwd->pw_dir, sizeof(home)); 1136 gr = GETGRGID(pwd->pw_gid); 1137 if (gr != NULL) 1138 strlcpy(grname, gr->gr_name, LOGNAMESIZE); 1139 else 1140 grname[0] = '\0'; 1141 1142 rc = delpwent(pwd); 1143 if (rc == -1) 1144 err(EX_IOERR, "user '%s' does not exist", pwd->pw_name); 1145 else if (rc != 0) 1146 err(EX_IOERR, "passwd update"); 1147 | 872 /* 873 * Save these for later, since contents of pwd may be 874 * invalidated by deletion 875 */ 876 snprintf(file, sizeof(file), "%s/%s", _PATH_MAILDIR, pwd->pw_name); 877 strlcpy(home, pwd->pw_dir, sizeof(home)); 878 gr = GETGRGID(pwd->pw_gid); 879 if (gr != NULL) 880 strlcpy(grname, gr->gr_name, LOGNAMESIZE); 881 else 882 grname[0] = '\0'; 883 884 rc = delpwent(pwd); 885 if (rc == -1) 886 err(EX_IOERR, "user '%s' does not exist", pwd->pw_name); 887 else if (rc != 0) 888 err(EX_IOERR, "passwd update"); 889 |
1148 if (conf.userconf->nispasswd && *conf.userconf->nispasswd=='/') { 1149 rc = delnispwent(conf.userconf->nispasswd, name); | 890 if (nis && nispasswd && *nispasswd=='/') { 891 rc = delnispwent(nispasswd, name); |
1150 if (rc == -1) 1151 warnx("WARNING: user '%s' does not exist in NIS passwd", 1152 pwd->pw_name); 1153 else if (rc != 0) 1154 warn("WARNING: NIS passwd update"); | 892 if (rc == -1) 893 warnx("WARNING: user '%s' does not exist in NIS passwd", 894 pwd->pw_name); 895 else if (rc != 0) 896 warn("WARNING: NIS passwd update"); |
1155 /* non-fatal */ | |
1156 } 1157 1158 grp = GETGRNAM(name); 1159 if (grp != NULL && 1160 (grp->gr_mem == NULL || *grp->gr_mem == NULL) && 1161 strcmp(name, grname) == 0) 1162 delgrent(GETGRNAM(name)); 1163 SETGRENT(); --- 10 unchanged lines hidden (view full) --- 1174 for (j = i; grp->gr_mem[j] != NULL; j++) 1175 grp->gr_mem[j] = grp->gr_mem[j+1]; 1176 strlcpy(group, grp->gr_name, MAXLOGNAME); 1177 chggrent(group, grp); 1178 } 1179 } 1180 ENDGRENT(); 1181 | 897 } 898 899 grp = GETGRNAM(name); 900 if (grp != NULL && 901 (grp->gr_mem == NULL || *grp->gr_mem == NULL) && 902 strcmp(name, grname) == 0) 903 delgrent(GETGRNAM(name)); 904 SETGRENT(); --- 10 unchanged lines hidden (view full) --- 915 for (j = i; grp->gr_mem[j] != NULL; j++) 916 grp->gr_mem[j] = grp->gr_mem[j+1]; 917 strlcpy(group, grp->gr_name, MAXLOGNAME); 918 chggrent(group, grp); 919 } 920 } 921 ENDGRENT(); 922 |
1182 pw_log(conf.userconf, M_DELETE, W_USER, "%s(%ju) account removed", name, 1183 (uintmax_t)uid); | 923 pw_log(cnf, M_DELETE, W_USER, "%s(%ju) account removed", name, 924 (uintmax_t)id); |
1184 1185 /* Remove mail file */ 1186 if (PWALTDIR() != PWF_ALT) 1187 unlinkat(conf.rootfd, file + 1, 0); 1188 | 925 926 /* Remove mail file */ 927 if (PWALTDIR() != PWF_ALT) 928 unlinkat(conf.rootfd, file + 1, 0); 929 |
1189 /* Remove at jobs */ 1190 if (!PWALTDIR() && getpwuid(uid) == NULL) 1191 rmat(uid); | 930 /* Remove at jobs */ 931 if (!PWALTDIR() && getpwuid(id) == NULL) 932 rmat(id); |
1192 1193 /* Remove home directory and contents */ | 933 934 /* Remove home directory and contents */ |
1194 if (PWALTDIR() != PWF_ALT && conf.deletehome && *home == '/' && 1195 getpwuid(uid) == NULL && | 935 if (PWALTDIR() != PWF_ALT && deletehome && *home == '/' && 936 GETPWUID(id) == NULL && |
1196 fstatat(conf.rootfd, home + 1, &st, 0) != -1) { | 937 fstatat(conf.rootfd, home + 1, &st, 0) != -1) { |
1197 rm_r(conf.rootfd, home, uid); 1198 pw_log(conf.userconf, M_DELETE, W_USER, "%s(%ju) home '%s' %s" 1199 "removed", name, (uintmax_t)uid, home, | 938 rm_r(conf.rootfd, home, id); 939 pw_log(cnf, M_DELETE, W_USER, "%s(%ju) home '%s' %s" 940 "removed", name, (uintmax_t)id, home, |
1200 fstatat(conf.rootfd, home + 1, &st, 0) == -1 ? "" : "not " 1201 "completely "); 1202 } 1203 1204 return (EXIT_SUCCESS); 1205} 1206 | 941 fstatat(conf.rootfd, home + 1, &st, 0) == -1 ? "" : "not " 942 "completely "); 943 } 944 945 return (EXIT_SUCCESS); 946} 947 |
1207static int 1208print_user(struct passwd * pwd) | 948int 949pw_user_lock(int argc, char **argv, char *arg1) |
1209{ | 950{ |
1210 if (!conf.pretty) { 1211 char *buf; | 951 int ch; |
1212 | 952 |
1213 buf = conf.v7 ? pw_make_v7(pwd) : pw_make(pwd); 1214 printf("%s\n", buf); 1215 free(buf); 1216 } else { 1217 int j; 1218 char *p; 1219 struct group *grp = GETGRGID(pwd->pw_gid); 1220 char uname[60] = "User &", office[60] = "[None]", 1221 wphone[60] = "[None]", hphone[60] = "[None]"; 1222 char acexpire[32] = "[None]", pwexpire[32] = "[None]"; 1223 struct tm * tptr; 1224 1225 if ((p = strtok(pwd->pw_gecos, ",")) != NULL) { 1226 strlcpy(uname, p, sizeof(uname)); 1227 if ((p = strtok(NULL, ",")) != NULL) { 1228 strlcpy(office, p, sizeof(office)); 1229 if ((p = strtok(NULL, ",")) != NULL) { 1230 strlcpy(wphone, p, sizeof(wphone)); 1231 if ((p = strtok(NULL, "")) != NULL) { 1232 strlcpy(hphone, p, 1233 sizeof(hphone)); 1234 } 1235 } 1236 } | 953 while ((ch = getopt(argc, argv, "Cq")) != -1) { 954 switch (ch) { 955 case 'C': 956 case 'q': 957 /* compatibility */ 958 break; |
1237 } | 959 } |
1238 /* 1239 * Handle '&' in gecos field 1240 */ 1241 if ((p = strchr(uname, '&')) != NULL) { 1242 int l = strlen(pwd->pw_name); 1243 int m = strlen(p); | 960 } |
1244 | 961 |
1245 memmove(p + l, p + 1, m); 1246 memmove(p, pwd->pw_name, l); 1247 *p = (char) toupper((unsigned char)*p); | 962 return (pw_userlock(arg1, M_LOCK)); 963} 964 965int 966pw_user_unlock(int argc, char **argv, char *arg1) 967{ 968 int ch; 969 970 while ((ch = getopt(argc, argv, "Cq")) != -1) { 971 switch (ch) { 972 case 'C': 973 case 'q': 974 /* compatibility */ 975 break; |
1248 } | 976 } |
1249 if (pwd->pw_expire > (time_t)0 && (tptr = localtime(&pwd->pw_expire)) != NULL) 1250 strftime(acexpire, sizeof acexpire, "%c", tptr); 1251 if (pwd->pw_change > (time_t)0 && (tptr = localtime(&pwd->pw_change)) != NULL) 1252 strftime(pwexpire, sizeof pwexpire, "%c", tptr); 1253 printf("Login Name: %-15s #%-12ju Group: %-15s #%ju\n" 1254 " Full Name: %s\n" 1255 " Home: %-26.26s Class: %s\n" 1256 " Shell: %-26.26s Office: %s\n" 1257 "Work Phone: %-26.26s Home Phone: %s\n" 1258 "Acc Expire: %-26.26s Pwd Expire: %s\n", 1259 pwd->pw_name, (uintmax_t)pwd->pw_uid, 1260 grp ? grp->gr_name : "(invalid)", (uintmax_t)pwd->pw_gid, 1261 uname, pwd->pw_dir, pwd->pw_class, 1262 pwd->pw_shell, office, wphone, hphone, 1263 acexpire, pwexpire); 1264 SETGRENT(); 1265 j = 0; 1266 while ((grp=GETGRENT()) != NULL) 1267 { 1268 int i = 0; 1269 if (grp->gr_mem != NULL) { 1270 while (grp->gr_mem[i] != NULL) 1271 { 1272 if (strcmp(grp->gr_mem[i], pwd->pw_name)==0) 1273 { 1274 printf(j++ == 0 ? " Groups: %s" : ",%s", grp->gr_name); 1275 break; 1276 } 1277 ++i; 1278 } 1279 } 1280 } 1281 ENDGRENT(); 1282 printf("%s", j ? "\n" : ""); | |
1283 } | 977 } |
1284 return EXIT_SUCCESS; | 978 979 return (pw_userlock(arg1, M_UNLOCK)); |
1285} 1286 | 980} 981 |
1287char * 1288pw_checkname(char *name, int gecos) | 982static struct group * 983group_from_name_or_id(char *name) |
1289{ | 984{ |
1290 char showch[8]; 1291 const char *badchars, *ch, *showtype; 1292 int reject; | 985 const char *errstr = NULL; 986 struct group *grp; 987 uintmax_t id; |
1293 | 988 |
1294 ch = name; 1295 reject = 0; 1296 if (gecos) { 1297 /* See if the name is valid as a gecos (comment) field. */ 1298 badchars = ":!@"; 1299 showtype = "gecos field"; 1300 } else { 1301 /* See if the name is valid as a userid or group. */ 1302 badchars = " ,\t:+&#%$^()!@~*?<>=|\\/\""; 1303 showtype = "userid/group name"; 1304 /* Userids and groups can not have a leading '-'. */ 1305 if (*ch == '-') 1306 reject = 1; | 989 if ((grp = GETGRNAM(name)) == NULL) { 990 id = strtounum(name, 0, GID_MAX, &errstr); 991 if (errstr) 992 errx(EX_NOUSER, "group `%s' does not exist", name); 993 grp = GETGRGID(id); 994 if (grp == NULL) 995 errx(EX_NOUSER, "group `%s' does not exist", name); |
1307 } | 996 } |
1308 if (!reject) { 1309 while (*ch) { 1310 if (strchr(badchars, *ch) != NULL || *ch < ' ' || 1311 *ch == 127) { 1312 reject = 1; 1313 break; 1314 } 1315 /* 8-bit characters are only allowed in GECOS fields */ 1316 if (!gecos && (*ch & 0x80)) { 1317 reject = 1; 1318 break; 1319 } 1320 ch++; 1321 } | 997 998 return (grp); 999} 1000 1001static void 1002split_groups(StringList **groups, char *groupsstr) 1003{ 1004 struct group *grp; 1005 char *p; 1006 char tok[] = ", \t"; 1007 1008 for (p = strtok(groupsstr, tok); p != NULL; p = strtok(NULL, tok)) { 1009 grp = group_from_name_or_id(p); 1010 if (*groups == NULL) 1011 *groups = sl_init(); 1012 sl_add(*groups, newstr(grp->gr_name)); |
1322 } | 1013 } |
1323 /* 1324 * A `$' is allowed as the final character for userids and groups, 1325 * mainly for the benefit of samba. 1326 */ 1327 if (reject && !gecos) { 1328 if (*ch == '$' && *(ch + 1) == '\0') { 1329 reject = 0; 1330 ch++; 1331 } 1332 } 1333 if (reject) { 1334 snprintf(showch, sizeof(showch), (*ch >= ' ' && *ch < 127) 1335 ? "`%c'" : "0x%02x", *ch); 1336 errx(EX_DATAERR, "invalid character %s at position %td in %s", 1337 showch, (ch - name), showtype); 1338 } 1339 if (!gecos && (ch - name) > LOGNAMESIZE) 1340 errx(EX_DATAERR, "name too long `%s' (max is %d)", name, 1341 LOGNAMESIZE); | 1014} |
1342 | 1015 |
1343 return (name); | 1016static void 1017validate_grname(struct userconf *cnf, char *group) 1018{ 1019 struct group *grp; 1020 1021 if (group == NULL || *group == '\0') { 1022 cnf->default_group = ""; 1023 return; 1024 } 1025 grp = group_from_name_or_id(group); 1026 cnf->default_group = newstr(grp->gr_name); |
1344} 1345 | 1027} 1028 |
1029static mode_t 1030validate_mode(char *mode) 1031{ 1032 mode_t m; 1033 void *set; |
|
1346 | 1034 |
1035 if ((set = setmode(mode)) == NULL) 1036 errx(EX_DATAERR, "invalid directory creation mode '%s'", mode); 1037 1038 m = getmode(set, _DEF_DIRMODE); 1039 free(set); 1040 return (m); 1041} 1042 |
|
1347static void | 1043static void |
1348rmat(uid_t uid) | 1044mix_config(struct userconf *cmdcnf, struct userconf *cfg) |
1349{ | 1045{ |
1350 DIR *d = opendir("/var/at/jobs"); | |
1351 | 1046 |
1352 if (d != NULL) { 1353 struct dirent *e; | 1047 if (cmdcnf->default_password == 0) 1048 cmdcnf->default_password = cfg->default_password; 1049 if (cmdcnf->reuse_uids == 0) 1050 cmdcnf->reuse_uids = cfg->reuse_uids; 1051 if (cmdcnf->reuse_gids == 0) 1052 cmdcnf->reuse_gids = cfg->reuse_gids; 1053 if (cmdcnf->nispasswd == NULL) 1054 cmdcnf->nispasswd = cfg->nispasswd; 1055 if (cmdcnf->dotdir == NULL) 1056 cmdcnf->dotdir = cfg->dotdir; 1057 if (cmdcnf->newmail == NULL) 1058 cmdcnf->newmail = cfg->newmail; 1059 if (cmdcnf->logfile == NULL) 1060 cmdcnf->logfile = cfg->logfile; 1061 if (cmdcnf->home == NULL) 1062 cmdcnf->home = cfg->home; 1063 if (cmdcnf->homemode == 0) 1064 cmdcnf->homemode = cfg->homemode; 1065 if (cmdcnf->shelldir == NULL) 1066 cmdcnf->shelldir = cfg->shelldir; 1067 if (cmdcnf->shells == NULL) 1068 cmdcnf->shells = cfg->shells; 1069 if (cmdcnf->shell_default == NULL) 1070 cmdcnf->shell_default = cfg->shell_default; 1071 if (cmdcnf->default_group == NULL) 1072 cmdcnf->default_group = cfg->default_group; 1073 if (cmdcnf->groups == NULL) 1074 cmdcnf->groups = cfg->groups; 1075 if (cmdcnf->default_class == NULL) 1076 cmdcnf->default_class = cfg->default_class; 1077 if (cmdcnf->min_uid == 0) 1078 cmdcnf->min_uid = cfg->min_uid; 1079 if (cmdcnf->max_uid == 0) 1080 cmdcnf->max_uid = cfg->max_uid; 1081 if (cmdcnf->min_gid == 0) 1082 cmdcnf->min_gid = cfg->min_gid; 1083 if (cmdcnf->max_gid == 0) 1084 cmdcnf->max_gid = cfg->max_gid; 1085 if (cmdcnf->expire_days == 0) 1086 cmdcnf->expire_days = cfg->expire_days; 1087 if (cmdcnf->password_days == 0) 1088 cmdcnf->password_days = cfg->password_days; 1089} |
1354 | 1090 |
1355 while ((e = readdir(d)) != NULL) { 1356 struct stat st; | 1091int 1092pw_user_add(int argc, char **argv, char *arg1) 1093{ 1094 struct userconf *cnf, *cmdcnf; 1095 struct passwd *pwd; 1096 struct group *grp; 1097 struct stat st; 1098 char args[] = "C:qn:u:c:d:e:p:g:G:mM:k:s:oL:i:w:h:H:Db:NPy:Y"; 1099 char line[_PASSWORD_LEN+1], path[MAXPATHLEN]; 1100 char *gecos, *homedir, *skel, *walk, *userid, *groupid, *grname; 1101 char *default_passwd, *name, *p; 1102 const char *cfg; 1103 login_cap_t *lc; 1104 FILE *pfp, *fp; 1105 intmax_t id = -1; 1106 time_t now; 1107 int rc, ch, fd = -1; 1108 size_t i; 1109 bool dryrun, nis, pretty, quiet, createhome, precrypted, genconf; |
1357 | 1110 |
1358 if (strncmp(e->d_name, ".lock", 5) != 0 && 1359 stat(e->d_name, &st) == 0 && 1360 !S_ISDIR(st.st_mode) && 1361 st.st_uid == uid) { 1362 char tmp[MAXPATHLEN]; | 1111 dryrun = nis = pretty = quiet = createhome = precrypted = false; 1112 genconf = false; 1113 gecos = homedir = skel = userid = groupid = default_passwd = NULL; 1114 grname = name = NULL; |
1363 | 1115 |
1364 snprintf(tmp, sizeof(tmp), "/usr/bin/atrm %s", e->d_name); 1365 system(tmp); | 1116 if ((cmdcnf = calloc(1, sizeof(struct userconf))) == NULL) 1117 err(EXIT_FAILURE, "calloc()"); 1118 1119 if (arg1 != NULL) { 1120 if (strspn(arg1, "0123456789") == strlen(arg1)) 1121 id = pw_checkid(arg1, UID_MAX); 1122 else 1123 name = arg1; 1124 } 1125 1126 while ((ch = getopt(argc, argv, args)) != -1) { 1127 switch (ch) { 1128 case 'C': 1129 cfg = optarg; 1130 break; 1131 case 'q': 1132 quiet = true; 1133 break; 1134 case 'n': 1135 name = optarg; 1136 break; 1137 case 'u': 1138 userid = optarg; 1139 break; 1140 case 'c': 1141 gecos = pw_checkname(optarg, 1); 1142 break; 1143 case 'd': 1144 homedir = optarg; 1145 break; 1146 case 'e': 1147 now = time(NULL); 1148 cmdcnf->expire_days = parse_date(now, optarg); 1149 break; 1150 case 'p': 1151 now = time(NULL); 1152 cmdcnf->password_days = parse_date(now, optarg); 1153 break; 1154 case 'g': 1155 validate_grname(cmdcnf, optarg); 1156 grname = optarg; 1157 break; 1158 case 'G': 1159 split_groups(&cmdcnf->groups, optarg); 1160 break; 1161 case 'm': 1162 createhome = true; 1163 break; 1164 case 'M': 1165 cmdcnf->homemode = validate_mode(optarg); 1166 break; 1167 case 'k': 1168 walk = skel = optarg; 1169 if (*walk == '/') 1170 walk++; 1171 if (fstatat(conf.rootfd, walk, &st, 0) == -1) 1172 errx(EX_OSFILE, "skeleton `%s' does not " 1173 "exists", skel); 1174 if (!S_ISDIR(st.st_mode)) 1175 errx(EX_OSFILE, "skeleton `%s' is not a " 1176 "directory", skel); 1177 cmdcnf->dotdir = skel; 1178 break; 1179 case 's': 1180 cmdcnf->shell_default = optarg; 1181 break; 1182 case 'o': 1183 conf.checkduplicate = false; 1184 break; 1185 case 'L': 1186 cmdcnf->default_class = pw_checkname(optarg, 0); 1187 break; 1188 case 'i': 1189 groupid = optarg; 1190 break; 1191 case 'w': 1192 default_passwd = optarg; 1193 break; 1194 case 'H': 1195 if (fd != -1) 1196 errx(EX_USAGE, "'-h' and '-H' are mutually " 1197 "exclusive options"); 1198 fd = pw_checkfd(optarg); 1199 precrypted = true; 1200 if (fd == '-') 1201 errx(EX_USAGE, "-H expects a file descriptor"); 1202 break; 1203 case 'h': 1204 if (fd != -1) 1205 errx(EX_USAGE, "'-h' and '-H' are mutually " 1206 "exclusive options"); 1207 fd = pw_checkfd(optarg); 1208 break; 1209 case 'D': 1210 genconf = true; 1211 break; 1212 case 'b': 1213 cmdcnf->home = optarg; 1214 break; 1215 case 'N': 1216 dryrun = true; 1217 break; 1218 case 'P': 1219 pretty = true; 1220 break; 1221 case 'y': 1222 cmdcnf->nispasswd = optarg; 1223 break; 1224 case 'Y': 1225 nis = true; 1226 break; 1227 } 1228 } 1229 1230 if (geteuid() != 0 && ! dryrun) 1231 errx(EX_NOPERM, "you must be root"); 1232 1233 if (quiet) 1234 freopen(_PATH_DEVNULL, "w", stderr); 1235 1236 cnf = get_userconfig(cfg); 1237 1238 mix_config(cmdcnf, cnf); 1239 if (default_passwd) 1240 cmdcnf->default_password = boolean_val(default_passwd, 1241 cnf->default_password); 1242 if (genconf) { 1243 if (name != NULL) 1244 errx(EX_DATAERR, "can't combine `-D' with `-n name'"); 1245 if (userid != NULL) { 1246 if ((p = strtok(userid, ", \t")) != NULL) 1247 cmdcnf->min_uid = pw_checkid(p, UID_MAX); 1248 if (cmdcnf->min_uid == 0) 1249 cmdcnf->min_uid = 1000; 1250 if ((p = strtok(NULL, " ,\t")) != NULL) 1251 cmdcnf->max_uid = pw_checkid(p, UID_MAX); 1252 if (cmdcnf->max_uid == 0) 1253 cmdcnf->max_uid = 32000; 1254 } 1255 if (groupid != NULL) { 1256 if ((p = strtok(groupid, ", \t")) != NULL) 1257 cmdcnf->min_gid = pw_checkid(p, GID_MAX); 1258 if (cmdcnf->min_gid == 0) 1259 cmdcnf->min_gid = 1000; 1260 if ((p = strtok(NULL, " ,\t")) != NULL) 1261 cmdcnf->max_gid = pw_checkid(p, GID_MAX); 1262 if (cmdcnf->max_gid == 0) 1263 cmdcnf->max_gid = 32000; 1264 } 1265 if (write_userconfig(cmdcnf, cfg)) 1266 return (EXIT_SUCCESS); 1267 err(EX_IOERR, "config update"); 1268 } 1269 1270 if (userid) 1271 id = pw_checkid(userid, UID_MAX); 1272 if (id < 0 && name == NULL) 1273 errx(EX_DATAERR, "user name or id required"); 1274 1275 if (name == NULL) 1276 errx(EX_DATAERR, "login name required"); 1277 1278 pwd = &fakeuser; 1279 pwd->pw_name = name; 1280 pwd->pw_class = cmdcnf->default_class ? cmdcnf->default_class : ""; 1281 pwd->pw_uid = pw_uidpolicy(cmdcnf, id); 1282 pwd->pw_gid = pw_gidpolicy(cnf, grname, pwd->pw_name, 1283 (gid_t) pwd->pw_uid, dryrun); 1284 pwd->pw_change = cmdcnf->password_days; 1285 pwd->pw_expire = cmdcnf->expire_days; 1286 pwd->pw_dir = pw_homepolicy(cmdcnf, homedir, pwd->pw_name); 1287 pwd->pw_shell = pw_shellpolicy(cmdcnf); 1288 lc = login_getpwclass(pwd); 1289 if (lc == NULL || login_setcryptfmt(lc, "sha512", NULL) == NULL) 1290 warn("setting crypt(3) format"); 1291 login_close(lc); 1292 pwd->pw_passwd = pw_password(cmdcnf, pwd->pw_name, dryrun); 1293 if (pwd->pw_uid == 0 && strcmp(pwd->pw_name, "root") != 0) 1294 warnx("WARNING: new account `%s' has a uid of 0 " 1295 "(superuser access!)", pwd->pw_name); 1296 if (gecos) 1297 pwd->pw_gecos = gecos; 1298 1299 if (fd != -1) 1300 pw_set_passwd(pwd, fd, precrypted, false); 1301 1302 if (dryrun) 1303 return (print_user(pwd, pretty, false)); 1304 1305 if ((rc = addpwent(pwd)) != 0) { 1306 if (rc == -1) 1307 errx(EX_IOERR, "user '%s' already exists", 1308 pwd->pw_name); 1309 else if (rc != 0) 1310 err(EX_IOERR, "passwd file update"); 1311 } 1312 if (nis && cmdcnf->nispasswd && *cmdcnf->nispasswd == '/') { 1313 printf("%s\n", cmdcnf->nispasswd); 1314 rc = addnispwent(cmdcnf->nispasswd, pwd); 1315 if (rc == -1) 1316 warnx("User '%s' already exists in NIS passwd", pwd->pw_name); 1317 else if (rc != 0) 1318 warn("NIS passwd update"); 1319 /* NOTE: we treat NIS-only update errors as non-fatal */ 1320 } 1321 1322 if (cmdcnf->groups != NULL) { 1323 for (i = 0; i < cmdcnf->groups->sl_cur; i++) { 1324 grp = GETGRNAM(cmdcnf->groups->sl_str[i]); 1325 grp = gr_add(grp, pwd->pw_name); 1326 /* 1327 * grp can only be NULL in 2 cases: 1328 * - the new member is already a member 1329 * - a problem with memory occurs 1330 * in both cases we want to skip now. 1331 */ 1332 if (grp == NULL) 1333 continue; 1334 chggrent(grp->gr_name, grp); 1335 free(grp); 1336 } 1337 } 1338 1339 pwd = GETPWNAM(name); 1340 if (pwd == NULL) 1341 errx(EX_NOUSER, "user '%s' disappeared during update", name); 1342 1343 grp = GETGRGID(pwd->pw_gid); 1344 pw_log(cnf, M_ADD, W_USER, "%s(%ju):%s(%ju):%s:%s:%s", 1345 pwd->pw_name, (uintmax_t)pwd->pw_uid, 1346 grp ? grp->gr_name : "unknown", (uintmax_t)(grp ? grp->gr_gid : (uid_t)-1), 1347 pwd->pw_gecos, pwd->pw_dir, pwd->pw_shell); 1348 1349 /* 1350 * let's touch and chown the user's mail file. This is not 1351 * strictly necessary under BSD with a 0755 maildir but it also 1352 * doesn't hurt anything to create the empty mailfile 1353 */ 1354 if (PWALTDIR() != PWF_ALT) { 1355 snprintf(path, sizeof(path), "%s/%s", _PATH_MAILDIR, 1356 pwd->pw_name); 1357 /* Preserve contents & mtime */ 1358 close(openat(conf.rootfd, path +1, O_RDWR | O_CREAT, 0600)); 1359 fchownat(conf.rootfd, path + 1, pwd->pw_uid, pwd->pw_gid, 1360 AT_SYMLINK_NOFOLLOW); 1361 } 1362 1363 /* 1364 * Let's create and populate the user's home directory. Note 1365 * that this also `works' for editing users if -m is used, but 1366 * existing files will *not* be overwritten. 1367 */ 1368 if (PWALTDIR() != PWF_ALT && createhome && pwd->pw_dir && 1369 *pwd->pw_dir == '/' && pwd->pw_dir[1]) 1370 create_and_populate_homedir(cmdcnf, pwd, cmdcnf->dotdir, 1371 cmdcnf->homemode, false); 1372 1373 if (!PWALTDIR() && cmdcnf->newmail && *cmdcnf->newmail && 1374 (fp = fopen(cnf->newmail, "r")) != NULL) { 1375 if ((pfp = popen(_PATH_SENDMAIL " -t", "w")) == NULL) 1376 warn("sendmail"); 1377 else { 1378 fprintf(pfp, "From: root\n" "To: %s\n" 1379 "Subject: Welcome!\n\n", pwd->pw_name); 1380 while (fgets(line, sizeof(line), fp) != NULL) { 1381 /* Do substitutions? */ 1382 fputs(line, pfp); |
1366 } | 1383 } |
1384 pclose(pfp); 1385 pw_log(cnf, M_ADD, W_USER, "%s(%ju) new user mail sent", 1386 pwd->pw_name, (uintmax_t)pwd->pw_uid); |
|
1367 } | 1387 } |
1368 closedir(d); | 1388 fclose(fp); |
1369 } | 1389 } |
1390 1391 if (nis && nis_update() == 0) 1392 pw_log(cnf, M_ADD, W_USER, "NIS maps updated"); 1393 1394 return (EXIT_SUCCESS); |
|
1370} 1371 | 1395} 1396 |
1372static void 1373rmopie(char const * name) | 1397int 1398pw_user_mod(int argc, char **argv, char *arg1) |
1374{ | 1399{ |
1375 char tmp[1014]; 1376 FILE *fp; 1377 int fd; 1378 size_t len; 1379 off_t atofs = 0; 1380 1381 if ((fd = openat(conf.rootfd, "etc/opiekeys", O_RDWR)) == -1) 1382 return; | 1400 struct userconf *cnf; 1401 struct passwd *pwd; 1402 struct group *grp; 1403 StringList *groups = NULL; 1404 char args[] = "C:qn:u:c:d:e:p:g:G:mM:l:k:s:w:L:h:H:NPYy:"; 1405 const char *cfg; 1406 char *gecos, *homedir, *grname, *name, *newname, *walk, *skel, *shell; 1407 char *passwd, *class, *nispasswd; 1408 login_cap_t *lc; 1409 struct stat st; 1410 intmax_t id = -1; 1411 int ch, fd = -1; 1412 size_t i, j; 1413 bool quiet, createhome, pretty, dryrun, nis, edited, docreatehome; 1414 mode_t homemode = 0; 1415 time_t expire_days, password_days, now, precrypted; |
1383 | 1416 |
1384 fp = fdopen(fd, "r+"); 1385 len = strlen(name); | 1417 expire_days = password_days = -1; 1418 gecos = homedir = grname = name = newname = skel = shell =NULL; 1419 passwd = NULL; 1420 class = nispasswd = NULL; 1421 quiet = createhome = pretty = dryrun = nis = precrypted = false; 1422 edited = docreatehome = false; |
1386 | 1423 |
1387 while (fgets(tmp, sizeof(tmp), fp) != NULL) { 1388 if (strncmp(name, tmp, len) == 0 && tmp[len]==' ') { 1389 /* Comment username out */ 1390 if (fseek(fp, atofs, SEEK_SET) == 0) 1391 fwrite("#", 1, 1, fp); | 1424 if (arg1 != NULL) { 1425 if (strspn(arg1, "0123456789") == strlen(arg1)) 1426 id = pw_checkid(arg1, UID_MAX); 1427 else 1428 name = arg1; 1429 } 1430 1431 while ((ch = getopt(argc, argv, args)) != -1) { 1432 switch (ch) { 1433 case 'C': 1434 cfg = optarg; |
1392 break; | 1435 break; |
1436 case 'q': 1437 quiet = true; 1438 break; 1439 case 'n': 1440 name = optarg; 1441 break; 1442 case 'u': 1443 id = pw_checkid(optarg, UID_MAX); 1444 break; 1445 case 'c': 1446 gecos = pw_checkname(optarg, 1); 1447 break; 1448 case 'd': 1449 homedir = optarg; 1450 break; 1451 case 'e': 1452 now = time(NULL); 1453 expire_days = parse_date(now, optarg); 1454 break; 1455 case 'p': 1456 now = time(NULL); 1457 password_days = parse_date(now, optarg); 1458 break; 1459 case 'g': 1460 group_from_name_or_id(optarg); 1461 grname = optarg; 1462 break; 1463 case 'G': 1464 split_groups(&groups, optarg); 1465 break; 1466 case 'm': 1467 createhome = true; 1468 break; 1469 case 'M': 1470 homemode = validate_mode(optarg); 1471 break; 1472 case 'l': 1473 newname = optarg; 1474 break; 1475 case 'k': 1476 walk = skel = optarg; 1477 if (*walk == '/') 1478 walk++; 1479 if (fstatat(conf.rootfd, walk, &st, 0) == -1) 1480 errx(EX_OSFILE, "skeleton `%s' does not " 1481 "exists", skel); 1482 if (!S_ISDIR(st.st_mode)) 1483 errx(EX_OSFILE, "skeleton `%s' is not a " 1484 "directory", skel); 1485 break; 1486 case 's': 1487 shell = optarg; 1488 break; 1489 case 'w': 1490 passwd = optarg; 1491 break; 1492 case 'L': 1493 class = pw_checkname(optarg, 0); 1494 break; 1495 case 'H': 1496 if (fd != -1) 1497 errx(EX_USAGE, "'-h' and '-H' are mutually " 1498 "exclusive options"); 1499 fd = pw_checkfd(optarg); 1500 precrypted = true; 1501 if (fd == '-') 1502 errx(EX_USAGE, "-H expects a file descriptor"); 1503 break; 1504 case 'h': 1505 if (fd != -1) 1506 errx(EX_USAGE, "'-h' and '-H' are mutually " 1507 "exclusive options"); 1508 fd = pw_checkfd(optarg); 1509 break; 1510 case 'N': 1511 dryrun = true; 1512 break; 1513 case 'P': 1514 pretty = true; 1515 break; 1516 case 'y': 1517 nispasswd = optarg; 1518 break; 1519 case 'Y': 1520 nis = true; 1521 break; |
|
1393 } | 1522 } |
1394 atofs = ftell(fp); | |
1395 } | 1523 } |
1524 1525 if (geteuid() != 0 && ! dryrun) 1526 errx(EX_NOPERM, "you must be root"); 1527 1528 if (quiet) 1529 freopen(_PATH_DEVNULL, "w", stderr); 1530 1531 cnf = get_userconfig(cfg); 1532 1533 if (id < 0 && name == NULL) 1534 errx(EX_DATAERR, "username or id required"); 1535 1536 pwd = (name != NULL) ? GETPWNAM(pw_checkname(name, 0)) : GETPWUID(id); 1537 if (pwd == NULL) { 1538 if (name == NULL) 1539 errx(EX_NOUSER, "no such uid `%ju'", 1540 (uintmax_t) id); 1541 errx(EX_NOUSER, "no such user `%s'", name); 1542 } 1543 1544 if (name == NULL) 1545 name = pwd->pw_name; 1546 1547 if (nis && nispasswd == NULL) 1548 nispasswd = cnf->nispasswd; 1549 1550 if (PWF._altdir == PWF_REGULAR && 1551 ((pwd->pw_fields & _PWF_SOURCE) != _PWF_FILES)) { 1552 if ((pwd->pw_fields & _PWF_SOURCE) == _PWF_NIS) { 1553 if (!nis && nispasswd && *nispasswd != '/') 1554 errx(EX_NOUSER, "Cannot modify NIS user `%s'", 1555 name); 1556 } else { 1557 errx(EX_NOUSER, "Cannot modify non local user `%s'", 1558 name); 1559 } 1560 } 1561 1562 if (newname) { 1563 if (strcmp(pwd->pw_name, "root") == 0) 1564 errx(EX_DATAERR, "can't rename `root' account"); 1565 if (strcmp(pwd->pw_name, newname) != 0) { 1566 pwd->pw_name = pw_checkname(newname, 0); 1567 edited = true; 1568 } 1569 } 1570 1571 if (id > 0 && pwd->pw_uid != id) { 1572 pwd->pw_uid = id; 1573 edited = true; 1574 if (pwd->pw_uid != 0 && strcmp(pwd->pw_name, "root") == 0) 1575 errx(EX_DATAERR, "can't change uid of `root' account"); 1576 if (pwd->pw_uid == 0 && strcmp(pwd->pw_name, "root") != 0) 1577 warnx("WARNING: account `%s' will have a uid of 0 (superuser access!)", pwd->pw_name); 1578 } 1579 1580 if (grname && pwd->pw_uid != 0) { 1581 grp = GETGRNAM(grname); 1582 if (grp == NULL) 1583 grp = GETGRGID(pw_checkid(grname, GID_MAX)); 1584 if (grp->gr_gid != pwd->pw_gid) { 1585 pwd->pw_gid = grp->gr_gid; 1586 edited = true; 1587 } 1588 } 1589 1590 if (password_days >= 0 && pwd->pw_change != password_days) { 1591 pwd->pw_change = password_days; 1592 edited = true; 1593 } 1594 1595 if (expire_days >= 0 && pwd->pw_expire != expire_days) { 1596 pwd->pw_expire = expire_days; 1597 edited = true; 1598 } 1599 1600 if (shell) { 1601 shell = shell_path(cnf->shelldir, cnf->shells, shell); 1602 if (shell == NULL) 1603 shell = ""; 1604 if (strcmp(shell, pwd->pw_shell) != 0) { 1605 pwd->pw_shell = shell; 1606 edited = true; 1607 } 1608 } 1609 1610 if (class && strcmp(pwd->pw_class, class) != 0) { 1611 pwd->pw_class = class; 1612 edited = true; 1613 } 1614 1615 if (homedir && strcmp(pwd->pw_dir, homedir) != 0) { 1616 pwd->pw_dir = homedir; 1617 if (fstatat(conf.rootfd, pwd->pw_dir, &st, 0) == -1) { 1618 if (!createhome) 1619 warnx("WARNING: home `%s' does not exist", 1620 pwd->pw_dir); 1621 else 1622 docreatehome = true; 1623 } else if (!S_ISDIR(st.st_mode)) { 1624 warnx("WARNING: home `%s' is not a directory", 1625 pwd->pw_dir); 1626 } 1627 } 1628 1629 if (passwd && conf.fd == -1) { 1630 lc = login_getpwclass(pwd); 1631 if (lc == NULL || login_setcryptfmt(lc, "sha512", NULL) == NULL) 1632 warn("setting crypt(3) format"); 1633 login_close(lc); 1634 pwd->pw_passwd = pw_password(cnf, pwd->pw_name, dryrun); 1635 edited = true; 1636 } 1637 1638 if (gecos && strcmp(pwd->pw_gecos, gecos) != 0) { 1639 pwd->pw_gecos = gecos; 1640 edited = true; 1641 } 1642 1643 if (fd != -1) 1644 edited = pw_set_passwd(pwd, fd, precrypted, true); 1645 1646 if (dryrun) 1647 return (print_user(pwd, pretty, false)); 1648 1649 if (edited) /* Only updated this if required */ 1650 perform_chgpwent(name, pwd, nis ? nispasswd : NULL); 1651 /* Now perform the needed changes concern groups */ 1652 if (groups != NULL) { 1653 /* Delete User from groups using old name */ 1654 SETGRENT(); 1655 while ((grp = GETGRENT()) != NULL) { 1656 if (grp->gr_mem == NULL) 1657 continue; 1658 for (i = 0; grp->gr_mem[i] != NULL; i++) { 1659 if (strcmp(grp->gr_mem[i] , name) != 0) 1660 continue; 1661 for (j = i; grp->gr_mem[j] != NULL ; j++) 1662 grp->gr_mem[j] = grp->gr_mem[j+1]; 1663 chggrent(grp->gr_name, grp); 1664 break; 1665 } 1666 } 1667 ENDGRENT(); 1668 /* Add the user to the needed groups */ 1669 for (i = 0; i < groups->sl_cur; i++) { 1670 grp = GETGRNAM(groups->sl_str[i]); 1671 grp = gr_add(grp, pwd->pw_name); 1672 if (grp == NULL) 1673 continue; 1674 chggrent(grp->gr_name, grp); 1675 free(grp); 1676 } 1677 } 1678 /* In case of rename we need to walk over the different groups */ 1679 if (newname) { 1680 SETGRENT(); 1681 while ((grp = GETGRENT()) != NULL) { 1682 if (grp->gr_mem == NULL) 1683 continue; 1684 for (i = 0; grp->gr_mem[i] != NULL; i++) { 1685 if (strcmp(grp->gr_mem[i], name) != 0) 1686 continue; 1687 grp->gr_mem[i] = newname; 1688 chggrent(grp->gr_name, grp); 1689 break; 1690 } 1691 } 1692 } 1693 1694 /* go get a current version of pwd */ 1695 if (newname) 1696 name = newname; 1697 pwd = GETPWNAM(name); 1698 if (pwd == NULL) 1699 errx(EX_NOUSER, "user '%s' disappeared during update", name); 1700 grp = GETGRGID(pwd->pw_gid); 1701 pw_log(cnf, M_UPDATE, W_USER, "%s(%ju):%s(%ju):%s:%s:%s", 1702 pwd->pw_name, (uintmax_t)pwd->pw_uid, 1703 grp ? grp->gr_name : "unknown", 1704 (uintmax_t)(grp ? grp->gr_gid : (uid_t)-1), 1705 pwd->pw_gecos, pwd->pw_dir, pwd->pw_shell); 1706 |
|
1396 /* | 1707 /* |
1397 * If we got an error of any sort, don't update! | 1708 * Let's create and populate the user's home directory. Note 1709 * that this also `works' for editing users if -m is used, but 1710 * existing files will *not* be overwritten. |
1398 */ | 1711 */ |
1399 fclose(fp); | 1712 if (PWALTDIR() != PWF_ALT && docreatehome && pwd->pw_dir && 1713 *pwd->pw_dir == '/' && pwd->pw_dir[1]) { 1714 if (!skel) 1715 skel = cnf->dotdir; 1716 if (homemode == 0) 1717 homemode = cnf->homemode; 1718 create_and_populate_homedir(cnf, pwd, skel, homemode, true); 1719 } 1720 1721 if (nis && nis_update() == 0) 1722 pw_log(cnf, M_UPDATE, W_USER, "NIS maps updated"); 1723 1724 return (EXIT_SUCCESS); |
1400} | 1725} |