Ejemplo n.º 1
0
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 */
	}
}
Ejemplo n.º 2
0
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);
	}
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
/*
 * 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);
}
Ejemplo n.º 5
0
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);
}
Ejemplo n.º 6
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;
}
Ejemplo n.º 7
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);
}
Ejemplo n.º 8
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);
}
Ejemplo n.º 9
0
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);
}
Ejemplo n.º 10
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);
}
Ejemplo n.º 11
0
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");
	}
}
Ejemplo n.º 12
0
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);
}