static void perform_chgpwent(const char *name, struct passwd *pwd, char *nispasswd) { int rc; struct passwd *nispwd; /* duplicate for nis so that chgpwent is not modifying before NIS */ if (nispasswd && *nispasswd == '/') nispwd = pw_dup(pwd); rc = chgpwent(name, pwd); if (rc == -1) errx(EX_IOERR, "user '%s' does not exist (NIS?)", pwd->pw_name); else if (rc != 0) err(EX_IOERR, "passwd file update"); if (nispasswd && *nispasswd == '/') { rc = chgnispwent(nispasswd, name, nispwd); if (rc == -1) warn("User '%s' not found in NIS passwd", pwd->pw_name); else if (rc != 0) warn("NIS passwd update"); /* NOTE: NIS-only update errors are not fatal */ } }
struct passwd * edit(const char *tfn, struct passwd *pw) { struct passwd *npw; char *line; size_t len; if (display(tfn, pw) == -1) return (NULL); for (;;) { switch (pw_edit(1)) { case -1: return (NULL); case 0: return (pw_dup(pw)); default: break; } if ((npw = verify(tfn, pw)) != NULL) return (npw); free(npw); printf("re-edit the password file? "); fflush(stdout); if ((line = fgetln(stdin, &len)) == NULL) { warn("fgetln()"); return (NULL); } if (len > 0 && (*line == 'N' || *line == 'n')) return (NULL); } }
void job_add(entry * e, user * u) { job *j; struct passwd *newpwd; struct passwd *temppwd; const char *uname; /* if already on queue, keep going */ for (j = jhead; j != NULL; j = j->next) if (j->e == e && j->u == u) return; uname = e->pwd->pw_name; /* check if user exists in time of job is being run f.e. ldap */ if ((temppwd = getpwnam(uname)) != NULL) { char **tenvp; Debug(DSCH | DEXT, ("user [%s:%ld:%ld:...] cmd=\"%s\"\n", e->pwd->pw_name, (long) temppwd->pw_uid, (long) temppwd->pw_gid, e->cmd)); if ((newpwd = pw_dup(temppwd)) == NULL) { log_it(uname, getpid(), "ERROR", "memory allocation failed", errno); return; } free(e->pwd); e->pwd = newpwd; if ((tenvp = env_update_home(e->envp, e->pwd->pw_dir)) == NULL) { log_it(uname, getpid(), "ERROR", "memory allocation failed", errno); return; } e->envp = tenvp; } else { log_it(uname, getpid(), "ERROR", "getpwnam() failed",errno); Debug(DSCH | DEXT, ("%s:%d pid=%d time=%ld getpwnam(%s) failed errno=%d error=%s\n", __FILE__,__LINE__,getpid(),time(NULL),uname,errno,strerror(errno))); return; } /* build a job queue element */ if ((j = (job *) malloc(sizeof (job))) == NULL) return; j->next = NULL; j->e = e; j->u = u; /* add it to the tail */ if (jhead == NULL) jhead = j; else jtail->next = j; jtail = j; }
/* * Wrapper around an internal libc function */ struct passwd * pw_scan(const char *line, int flags) { struct passwd pw, *ret; char *bp; if ((bp = strdup(line)) == NULL) return (NULL); if (!__pw_scan(bp, &pw, flags)) { free(bp); return (NULL); } ret = pw_dup(&pw); free(bp); return (ret); }
static int pw_update(struct passwd * pwd, char const * user) { struct passwd *pw = NULL; struct passwd *old_pw = NULL; int rc, pfd, tfd; if ((rc = pwdb_check()) != 0) return (rc); if (pwd != NULL) pw = pw_dup(pwd); if (user != NULL) old_pw = GETPWNAM(user); if (pw_init(conf.etcpath, NULL)) err(1, "pw_init()"); if ((pfd = pw_lock()) == -1) { pw_fini(); err(1, "pw_lock()"); } if ((tfd = pw_tmp(-1)) == -1) { pw_fini(); err(1, "pw_tmp()"); } if (pw_copy(pfd, tfd, pw, old_pw) == -1) { pw_fini(); close(tfd); err(1, "pw_copy()"); } fsync(tfd); close(tfd); /* * in case of deletion of a user, the whole database * needs to be regenerated */ if (pw_mkdb(pw != NULL ? pw->pw_name : NULL) == -1) { pw_fini(); err(1, "pw_mkdb()"); } free(pw); pw_fini(); return (0); }
static int pw_update(struct passwd * pwd, char const * user) { int rc = 0; rc = pwdb("-C", (char *)NULL); /* Check only */ if (rc == 0) { int pfd, tfd; struct passwd *pw = NULL; struct passwd *old_pw = NULL; if (pwd != NULL) pw = pw_dup(pwd); if (user != NULL) old_pw = GETPWNAM(user); if (pw_init(pwpath, NULL)) err(1, "pw_init()"); if ((pfd = pw_lock()) == -1) { pw_fini(); err(1, "pw_lock()"); } if ((tfd = pw_tmp(-1)) == -1) { pw_fini(); err(1, "pw_tmp()"); } if (pw_copy(pfd, tfd, pw, old_pw) == -1) { pw_fini(); err(1, "pw_copy()"); } /* * in case of deletion of a user, the whole database * needs to be regenerated */ if (pw_mkdb(pw != NULL ? pw->pw_name : NULL) == -1) { pw_fini(); err(1, "pw_mkdb()"); } free(pw); pw_fini(); } return 0; }
static int pw_nisupdate(const char * path, struct passwd * pwd, char const * user) { int pfd, tfd; struct passwd *pw = NULL; struct passwd *old_pw = NULL; printf("===> %s\n", path); if (pwd != NULL) pw = pw_dup(pwd); if (user != NULL) old_pw = GETPWNAM(user); if (pw_init(NULL, path)) err(1,"pw_init()"); if ((pfd = pw_lock()) == -1) { pw_fini(); err(1, "pw_lock()"); } if ((tfd = pw_tmp(-1)) == -1) { pw_fini(); err(1, "pw_tmp()"); } if (pw_copy(pfd, tfd, pw, old_pw) == -1) { pw_fini(); close(tfd); err(1, "pw_copy()"); } close(tfd); if (chmod(pw_tempname(), 0644) == -1) err(1, "chmod()"); if (rename(pw_tempname(), path) == -1) err(1, "rename()"); free(pw); pw_fini(); return (0); }
/* return NULL if eof or syntax error occurs; * otherwise return a pointer to a new entry. */ entry * load_entry(FILE *file, void (*error_func)(const char *), struct passwd *pw, char **envp) { /* this function reads one crontab entry -- the next -- from a file. * it skips any leading blank lines, ignores comments, and returns * NULL if for any reason the entry can't be read and parsed. * * the entry is also parsed here. * * syntax: * user crontab: * minutes hours doms months dows cmd\n * system crontab (/etc/crontab): * minutes hours doms months dows USERNAME cmd\n */ ecode_e ecode = e_none; entry *e; int ch; char cmd[MAX_COMMAND]; char envstr[MAX_ENVSTR]; char **tenvp; Debug(DPARS, ("load_entry()...about to eat comments\n")); skip_comments(file); ch = get_char(file); if (ch == EOF) return (NULL); /* ch is now the first useful character of a useful line. * it may be an @special or it may be the first character * of a list of minutes. */ e = calloc(sizeof(*e), sizeof(char)); if (ch == '@') { /* all of these should be flagged and load-limited; i.e., * instead of @hourly meaning "0 * * * *" it should mean * "close to the front of every hour but not 'til the * system load is low". Problems are: how do you know * what "low" means? (save me from /etc/cron.conf!) and: * how to guarantee low variance (how low is low?), which * means how to we run roughly every hour -- seems like * we need to keep a history or let the first hour set * the schedule, which means we aren't load-limited * anymore. too much for my overloaded brain. (vix, jan90) * HINT */ ch = get_string(cmd, MAX_COMMAND, file, " \t\n"); if (!strcmp("reboot", cmd)) { e->flags |= WHEN_REBOOT; } else if (!strcmp("yearly", cmd) || !strcmp("annually", cmd)){ bit_set(e->minute, 0); bit_set(e->hour, 0); bit_set(e->dom, 0); bit_set(e->month, 0); bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1)); e->flags |= DOW_STAR; } else if (!strcmp("monthly", cmd)) { bit_set(e->minute, 0); bit_set(e->hour, 0); bit_set(e->dom, 0); bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1)); bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1)); e->flags |= DOW_STAR; } else if (!strcmp("weekly", cmd)) { bit_set(e->minute, 0); bit_set(e->hour, 0); bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1)); bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1)); bit_set(e->dow, 0); e->flags |= DOM_STAR; } else if (!strcmp("daily", cmd) || !strcmp("midnight", cmd)) { bit_set(e->minute, 0); bit_set(e->hour, 0); bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1)); bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1)); bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1)); e->flags |= DOM_STAR | DOW_STAR; } else if (!strcmp("hourly", cmd)) { bit_set(e->minute, 0); bit_nset(e->hour, 0, (LAST_HOUR-FIRST_HOUR+1)); bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1)); bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1)); bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1)); e->flags |= DOM_STAR | DOW_STAR; } else { ecode = e_timespec; goto eof; } /* Advance past whitespace between shortcut and * username/command. */ Skip_Blanks(ch, file); if (ch == EOF || ch == '\n') { ecode = e_cmd; goto eof; } } else { Debug(DPARS, ("load_entry()...about to parse numerics\n")); if (ch == '*') e->flags |= MIN_STAR; ch = get_list(e->minute, FIRST_MINUTE, LAST_MINUTE, PPC_NULL, ch, file); if (ch == EOF) { ecode = e_minute; goto eof; } /* hours */ if (ch == '*') e->flags |= HR_STAR; ch = get_list(e->hour, FIRST_HOUR, LAST_HOUR, PPC_NULL, ch, file); if (ch == EOF) { ecode = e_hour; goto eof; } /* DOM (days of month) */ if (ch == '*') e->flags |= DOM_STAR; ch = get_list(e->dom, FIRST_DOM, LAST_DOM, PPC_NULL, ch, file); if (ch == EOF) { ecode = e_dom; goto eof; } /* month */ ch = get_list(e->month, FIRST_MONTH, LAST_MONTH, MonthNames, ch, file); if (ch == EOF) { ecode = e_month; goto eof; } /* DOW (days of week) */ if (ch == '*') e->flags |= DOW_STAR; ch = get_list(e->dow, FIRST_DOW, LAST_DOW, DowNames, ch, file); if (ch == EOF) { ecode = e_dow; goto eof; } } /* make sundays equivalent */ if (bit_test(e->dow, 0) || bit_test(e->dow, 7)) { bit_set(e->dow, 0); bit_set(e->dow, 7); } /* check for permature EOL and catch a common typo */ if (ch == '\n' || ch == '*') { ecode = e_cmd; goto eof; } /* ch is the first character of a command, or a username */ unget_char(ch, file); if (!pw) { char *username = cmd; /* temp buffer */ Debug(DPARS, ("load_entry()...about to parse username\n")); ch = get_string(username, MAX_COMMAND, file, " \t\n"); Debug(DPARS, ("load_entry()...got %s\n",username)); if (ch == EOF || ch == '\n' || ch == '*') { ecode = e_cmd; goto eof; } pw = getpwnam(username); if (pw == NULL) { ecode = e_username; goto eof; } Debug(DPARS, ("load_entry()...uid %ld, gid %ld\n", (long)pw->pw_uid, (long)pw->pw_gid)); } if ((e->pwd = pw_dup(pw)) == NULL) { ecode = e_memory; goto eof; } (void)memset(e->pwd->pw_passwd, 0, strlen(e->pwd->pw_passwd)); /* copy and fix up environment. some variables are just defaults and * others are overrides. */ if ((e->envp = env_copy(envp)) == NULL) { ecode = e_memory; goto eof; } if (!env_get("SHELL", e->envp)) { if (glue_strings(envstr, sizeof envstr, "SHELL", _PATH_BSHELL, '=')) { if ((tenvp = env_set(e->envp, envstr)) == NULL) { ecode = e_memory; goto eof; } e->envp = tenvp; } else log_it("CRON", getpid(), "error", "can't set SHELL"); } if (!env_get("HOME", e->envp)) { if (glue_strings(envstr, sizeof envstr, "HOME", pw->pw_dir, '=')) { if ((tenvp = env_set(e->envp, envstr)) == NULL) { ecode = e_memory; goto eof; } e->envp = tenvp; } else log_it("CRON", getpid(), "error", "can't set HOME"); } /* If login.conf is in used we will get the default PATH later. */ if (!env_get("PATH", e->envp)) { if (glue_strings(envstr, sizeof envstr, "PATH", _PATH_DEFPATH, '=')) { if ((tenvp = env_set(e->envp, envstr)) == NULL) { ecode = e_memory; goto eof; } e->envp = tenvp; } else log_it("CRON", getpid(), "error", "can't set PATH"); } if (glue_strings(envstr, sizeof envstr, "LOGNAME", pw->pw_name, '=')) { if ((tenvp = env_set(e->envp, envstr)) == NULL) { ecode = e_memory; goto eof; } e->envp = tenvp; } else log_it("CRON", getpid(), "error", "can't set LOGNAME"); #if defined(BSD) || defined(__linux) if (glue_strings(envstr, sizeof envstr, "USER", pw->pw_name, '=')) { if ((tenvp = env_set(e->envp, envstr)) == NULL) { ecode = e_memory; goto eof; } e->envp = tenvp; } else log_it("CRON", getpid(), "error", "can't set USER"); #endif Debug(DPARS, ("load_entry()...about to parse command\n")); /* If the first character of the command is '-' it is a cron option. */ while ((ch = get_char(file)) == '-') { switch (ch = get_char(file)) { case 'q': e->flags |= DONT_LOG; Skip_Nonblanks(ch, file); break; default: ecode = e_option; goto eof; } Skip_Blanks(ch, file); if (ch == EOF || ch == '\n') { ecode = e_cmd; goto eof; } } unget_char(ch, file); /* Everything up to the next \n or EOF is part of the command... * too bad we don't know in advance how long it will be, since we * need to malloc a string for it... so, we limit it to MAX_COMMAND. */ ch = get_string(cmd, MAX_COMMAND, file, "\n"); /* a file without a \n before the EOF is rude, so we'll complain... */ if (ch == EOF) { ecode = e_cmd; goto eof; } /* got the command in the 'cmd' string; save it in *e. */ if ((e->cmd = strdup(cmd)) == NULL) { ecode = e_memory; goto eof; } Debug(DPARS, ("load_entry()...returning successfully\n")); /* success, fini, return pointer to the entry we just created... */ return (e); eof: if (e->envp) env_free(e->envp); if (e->pwd) free(e->pwd); if (e->cmd) free(e->cmd); free(e); while (ch != '\n' && !feof(file)) ch = get_char(file); if (ecode != e_none && error_func) (*error_func)(ecodes[(int)ecode]); return (NULL); }
int main(int argc, char *argv[]) { struct passwd *pw = NULL, *opw = NULL, lpw; int i, ch, pfd, tfd, dfd; char *tz, *arg = NULL; sigset_t fullset; #ifdef YP use_yp = _yp_check(NULL); #endif /* We need to use the system timezone for date conversions. */ if ((tz = getenv("TZ")) != NULL) { unsetenv("TZ"); tzset(); setenv("TZ", tz, 1); } op = EDITENTRY; while ((ch = getopt(argc, argv, "a:s:ly")) != -1) switch(ch) { case 'a': op = LOADENTRY; arg = optarg; break; case 's': op = NEWSH; arg = optarg; break; #ifdef YP case 'l': use_yp = 0; break; case 'y': if (!use_yp) { warnx("YP not in use."); usage(); } force_yp = 1; break; #endif case '?': default: usage(); } argc -= optind; argv += optind; #ifdef YP if (op == LOADENTRY && use_yp) errx(1, "cannot load using YP, use -l to load local."); #endif uid = getuid(); if (op == EDITENTRY || op == NEWSH) switch(argc) { case 0: pw = getpwuid(uid); #ifdef YP if (pw && !force_yp) use_yp = 0; else if (use_yp) pw = ypgetpwuid(uid); #endif /* YP */ if (!pw) errx(1, "unknown user: uid %u", uid); break; case 1: pw = getpwnam(*argv); #ifdef YP if (pw && !force_yp) use_yp = 0; else if (use_yp) pw = ypgetpwnam(*argv); #endif /* YP */ if (!pw) errx(1, "unknown user: %s", *argv); if (uid && uid != pw->pw_uid) baduser(); break; default: usage(); } if (op == LOADENTRY) { if (argc != 0) errx(1, "option -a does not accept user argument"); if (uid) baduser(); pw = &lpw; if (!pw_scan(arg, pw, NULL)) exit(1); opw = getpwnam(pw->pw_name); } if (opw == NULL && (opw = pw_dup(pw)) == NULL) err(1, NULL); /* Edit the user passwd information if requested. */ if (op == EDITENTRY) { char tempname[] = _PATH_VARTMP "pw.XXXXXXXXXX"; int edit_status; if ((pw = pw_dup(pw)) == NULL) pw_error(NULL, 1, 1); dfd = mkstemp(tempname); if (dfd == -1 || fcntl(dfd, F_SETFD, 1) == -1) pw_error(tempname, 1, 1); display(tempname, dfd, pw); edit_status = edit(tempname, pw); close(dfd); unlink(tempname); switch (edit_status) { case EDIT_OK: break; case EDIT_NOCHANGE: pw_error(NULL, 0, 0); break; case EDIT_ERROR: default: pw_error(tempname, 1, 1); break; } } if (op == NEWSH) { /* protect p_shell -- it thinks NULL is /bin/sh */ if (!arg[0]) usage(); if (p_shell(arg, pw, NULL)) pw_error(NULL, 0, 1); } /* Drop user's real uid and block all signals to avoid a DoS. */ setuid(0); sigfillset(&fullset); sigdelset(&fullset, SIGINT); sigprocmask(SIG_BLOCK, &fullset, NULL); /* Get the passwd lock file and open the passwd file for reading. */ pw_init(); for (i = 1; (tfd = pw_lock(0)) == -1; i++) { if (i == 4) (void)fputs("Attempting to lock password file, " "please wait or press ^C to abort", stderr); (void)signal(SIGINT, kbintr); if (i % 16 == 0) fputc('.', stderr); usleep(250000); (void)signal(SIGINT, SIG_IGN); } if (i >= 4) fputc('\n', stderr); pfd = open(_PATH_MASTERPASSWD, O_RDONLY, 0); if (pfd == -1 || fcntl(pfd, F_SETFD, 1) == -1) pw_error(_PATH_MASTERPASSWD, 1, 1); #ifdef YP if (use_yp) { if (pw_yp(pw, uid)) pw_error(NULL, 0, 1); else { pw_abort(); exit(0); } } else #endif /* YP */ { /* Copy the passwd file to the lock file, updating pw. */ pw_copy(pfd, tfd, pw, opw); /* If username changed we need to rebuild the entire db. */ arg = !strcmp(opw->pw_name, pw->pw_name) ? pw->pw_name : NULL; /* Now finish the passwd file update. */ if (pw_mkdb(arg, 0) == -1) pw_error(NULL, 0, 1); } exit(0); }
static struct passwd * verify(const char *tfn, struct passwd *pw) { struct passwd *npw; ENTRY *ep; char *buf, *p, *val; struct stat sb; FILE *fp; int line; size_t len; if ((pw = pw_dup(pw)) == NULL) return (NULL); if ((fp = fopen(tfn, "r")) == NULL || fstat(fileno(fp), &sb) == -1) { warn("%s", tfn); free(pw); return (NULL); } if (sb.st_size == 0) { warnx("corrupted temporary file"); fclose(fp); free(pw); return (NULL); } val = NULL; for (line = 1; (buf = fgetln(fp, &len)) != NULL; ++line) { if (*buf == '\0' || *buf == '#') continue; while (len > 0 && isspace(buf[len - 1])) --len; for (ep = list;; ++ep) { if (!ep->prompt) { warnx("%s: unrecognized field on line %d", tfn, line); goto bad; } if (ep->len > len) continue; if (strncasecmp(buf, ep->prompt, ep->len) != 0) continue; if (ep->restricted && !master_mode) { warnx("%s: you may not change the %s field", tfn, ep->prompt); goto bad; } for (p = buf; p < buf + len && *p != ':'; ++p) /* nothing */ ; if (*p != ':') { warnx("%s: line %d corrupted", tfn, line); goto bad; } while (++p < buf + len && isspace(*p)) /* nothing */ ; free(val); asprintf(&val, "%.*s", (int)(buf + len - p), p); if (val == NULL) goto bad; if (ep->except && strpbrk(val, ep->except)) { warnx("%s: invalid character in \"%s\" field '%s'", tfn, ep->prompt, val); goto bad; } if ((ep->func)(val, pw, ep)) goto bad; break; } } free(val); fclose(fp); /* Build the gecos field. */ len = asprintf(&p, "%s,%s,%s,%s,%s", list[E_NAME].save, list[E_LOCATE].save, list[E_BPHONE].save, list[E_HPHONE].save, list[E_OTHER].save); if (p == NULL) { warn("asprintf()"); free(pw); return (NULL); } while (len > 0 && p[len - 1] == ',') p[--len] = '\0'; pw->pw_gecos = p; buf = pw_make(pw); free(pw); free(p); if (buf == NULL) { warn("pw_make()"); return (NULL); } npw = pw_scan(buf, PWSCAN_WARN|PWSCAN_MASTER); free(buf); return (npw); bad: free(pw); free(val); fclose(fp); return (NULL); }
int main(int argc, char *argv[]) { enum { NEWSH, LOADENTRY, EDITENTRY, NEWPW, NEWEXP } op; struct passwd lpw, *old_pw, *pw; int ch, pfd, tfd; const char *password; char *arg = NULL; uid_t uid; #ifdef YP struct ypclnt *ypclnt; const char *yp_domain = NULL, *yp_host = NULL; #endif pw = old_pw = NULL; op = EDITENTRY; #ifdef YP while ((ch = getopt(argc, argv, "a:p:s:e:d:h:loy")) != -1) #else while ((ch = getopt(argc, argv, "a:p:s:e:")) != -1) #endif switch (ch) { case 'a': op = LOADENTRY; arg = optarg; break; case 's': op = NEWSH; arg = optarg; break; case 'p': op = NEWPW; arg = optarg; break; case 'e': op = NEWEXP; arg = optarg; break; #ifdef YP case 'd': yp_domain = optarg; break; case 'h': yp_host = optarg; break; case 'l': case 'o': case 'y': /* compatibility */ break; #endif case '?': default: usage(); } argc -= optind; argv += optind; if (argc > 1) usage(); uid = getuid(); if (op == EDITENTRY || op == NEWSH || op == NEWPW || op == NEWEXP) { if (argc == 0) { if ((pw = getpwuid(uid)) == NULL) errx(1, "unknown user: uid %lu", (unsigned long)uid); } else { if ((pw = getpwnam(*argv)) == NULL) errx(1, "unknown user: %s", *argv); if (uid != 0 && uid != pw->pw_uid) baduser(); } /* Make a copy for later verification */ if ((pw = pw_dup(pw)) == NULL || (old_pw = pw_dup(pw)) == NULL) err(1, "pw_dup"); } #ifdef YP if (pw != NULL && (pw->pw_fields & _PWF_SOURCE) == _PWF_NIS) { ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_host); master_mode = (ypclnt != NULL && ypclnt_connect(ypclnt) != -1 && ypclnt_havepasswdd(ypclnt) == 1); ypclnt_free(ypclnt); } else #endif master_mode = (uid == 0); if (op == NEWSH) { /* protect p_shell -- it thinks NULL is /bin/sh */ if (!arg[0]) usage(); if (p_shell(arg, pw, (ENTRY *)NULL) == -1) exit(1); } if (op == NEWEXP) { if (uid) /* only root can change expire */ baduser(); if (p_expire(arg, pw, (ENTRY *)NULL) == -1) exit(1); } if (op == LOADENTRY) { if (uid) baduser(); pw = &lpw; old_pw = NULL; if (!__pw_scan(arg, pw, _PWSCAN_WARN|_PWSCAN_MASTER)) exit(1); } if (op == NEWPW) { if (uid) baduser(); if (strchr(arg, ':')) errx(1, "invalid format for password"); pw->pw_passwd = arg; } if (op == EDITENTRY) { /* * We don't really need pw_*() here, but pw_edit() (used * by edit()) is just too useful... */ if (pw_init(NULL, NULL)) err(1, "pw_init()"); if ((tfd = pw_tmp(-1)) == -1) { pw_fini(); err(1, "pw_tmp()"); } free(pw); pw = edit(pw_tempname(), old_pw); pw_fini(); if (pw == NULL) err(1, "edit()"); /* * pw_equal does not check for crypted passwords, so we * should do it explicitly */ if (pw_equal(old_pw, pw) && strcmp(old_pw->pw_passwd, pw->pw_passwd) == 0) errx(0, "user information unchanged"); } if (old_pw && !master_mode) { password = getpass("Password: "******""; } if (old_pw != NULL) pw->pw_fields |= (old_pw->pw_fields & _PWF_SOURCE); switch (pw->pw_fields & _PWF_SOURCE) { #ifdef YP case _PWF_NIS: ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_host); if (ypclnt == NULL) { warnx("ypclnt_new failed"); exit(1); } if (ypclnt_connect(ypclnt) == -1 || ypclnt_passwd(ypclnt, pw, password) == -1) { warnx("%s", ypclnt->error); ypclnt_free(ypclnt); exit(1); } ypclnt_free(ypclnt); errx(0, "NIS user information updated"); #endif /* YP */ case 0: case _PWF_FILES: if (pw_init(NULL, NULL)) err(1, "pw_init()"); if ((pfd = pw_lock()) == -1) { pw_fini(); err(1, "pw_lock()"); } if ((tfd = pw_tmp(-1)) == -1) { pw_fini(); err(1, "pw_tmp()"); } if (pw_copy(pfd, tfd, pw, old_pw) == -1) { pw_fini(); err(1, "pw_copy"); } if (pw_mkdb(pw->pw_name) == -1) { pw_fini(); err(1, "pw_mkdb()"); } pw_fini(); errx(0, "user information updated"); break; default: errx(1, "unsupported passwd source"); } }
static int pw_update(struct passwd * pwd, char const * user) { int rc = 0; /* * First, let's check the see if the database is alright * Note: -C is only available in FreeBSD 2.2 and above */ #ifdef HAVE_PWDB_C rc = pwdb("-C", (char *)NULL); /* Check only */ if (rc == 0) { #else { /* No -C */ #endif int pfd, tfd; struct passwd *pw = NULL; struct passwd *old_pw = NULL; if (pwd != NULL) pw = pw_dup(pwd); if (user != NULL) old_pw = GETPWNAM(user); if (pw_init(pwpath, NULL)) err(1, "pw_init()"); if ((pfd = pw_lock()) == -1) { pw_fini(); err(1, "pw_lock()"); } if ((tfd = pw_tmp(-1)) == -1) { pw_fini(); err(1, "pw_tmp()"); } if (pw_copy(pfd, tfd, pw, old_pw) == -1) { pw_fini(); err(1, "pw_copy()"); } if (pw_mkdb(user) == -1) { pw_fini(); err(1, "pw_mkdb()"); } free(pw); pw_fini(); } return 0; } int addpwent(struct passwd * pwd) { return pw_update(pwd, NULL); } int chgpwent(char const * login, struct passwd * pwd) { return pw_update(pwd, login); } int delpwent(struct passwd * pwd) { char login[MAXLOGNAME]; strlcpy(login, pwd->pw_name, MAXLOGNAME); return pw_update(NULL, login); }