summaryrefslogtreecommitdiffstats
path: root/chpass
diff options
context:
space:
mode:
Diffstat (limited to 'chpass')
-rw-r--r--chpass/chpass.c2
-rw-r--r--chpass/chpass.h4
-rw-r--r--chpass/edit.c298
-rw-r--r--chpass/field.c263
-rw-r--r--chpass/util.c2
5 files changed, 568 insertions, 1 deletions
diff --git a/chpass/chpass.c b/chpass/chpass.c
index 74c96be..643b0f3 100644
--- a/chpass/chpass.c
+++ b/chpass/chpass.c
@@ -1,4 +1,6 @@
/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
* Copyright (c) 1988, 1993, 1994
* The Regents of the University of California. All rights reserved.
* Copyright (c) 2002 Networks Associates Technology, Inc.
diff --git a/chpass/chpass.h b/chpass/chpass.h
index fd3a839..b655c5d 100644
--- a/chpass/chpass.h
+++ b/chpass/chpass.h
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
* Copyright (c) 1988, 1993, 1994
* The Regents of the University of California. All rights reserved.
* Copyright (c) 2002 Networks Associates Technology, Inc.
diff --git a/chpass/edit.c b/chpass/edit.c
new file mode 100644
index 0000000..fbe1015
--- /dev/null
+++ b/chpass/edit.c
@@ -0,0 +1,298 @@
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)edit.c 8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <pw_scan.h>
+#include <libutil.h>
+
+#include "chpass.h"
+
+static int display(const char *tfn, struct passwd *pw);
+static struct passwd *verify(const char *tfn, struct passwd *pw);
+
+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);
+ }
+}
+
+/*
+ * display --
+ * print out the file for the user to edit; strange side-effect:
+ * set conditional flag if the user gets to edit the shell.
+ */
+static int
+display(const char *tfn, struct passwd *pw)
+{
+ FILE *fp;
+ char *bp, *gecos, *p;
+
+ if ((fp = fopen(tfn, "w")) == NULL) {
+ warn("%s", tfn);
+ return (-1);
+ }
+
+ (void)fprintf(fp,
+ "#Changing user information for %s.\n", pw->pw_name);
+ if (master_mode) {
+ (void)fprintf(fp, "Login: %s\n", pw->pw_name);
+ (void)fprintf(fp, "Password: %s\n", pw->pw_passwd);
+ (void)fprintf(fp, "Uid [#]: %lu\n", (unsigned long)pw->pw_uid);
+ (void)fprintf(fp, "Gid [# or name]: %lu\n",
+ (unsigned long)pw->pw_gid);
+ (void)fprintf(fp, "Change [month day year]: %s\n",
+ ttoa(pw->pw_change));
+ (void)fprintf(fp, "Expire [month day year]: %s\n",
+ ttoa(pw->pw_expire));
+ (void)fprintf(fp, "Class: %s\n", pw->pw_class);
+ (void)fprintf(fp, "Home directory: %s\n", pw->pw_dir);
+ (void)fprintf(fp, "Shell: %s\n",
+ *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL);
+ }
+ /* Only admin can change "restricted" shells. */
+#if 0
+ else if (ok_shell(pw->pw_shell))
+ /*
+ * Make shell a restricted field. Ugly with a
+ * necklace, but there's not much else to do.
+ */
+#else
+ else if ((!list[E_SHELL].restricted && ok_shell(pw->pw_shell)) ||
+ master_mode)
+ /*
+ * If change not restrict (table.c) and standard shell
+ * OR if root, then allow editing of shell.
+ */
+#endif
+ (void)fprintf(fp, "Shell: %s\n",
+ *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL);
+ else
+ list[E_SHELL].restricted = 1;
+
+ if ((bp = gecos = strdup(pw->pw_gecos)) == NULL) {
+ warn(NULL);
+ fclose(fp);
+ return (-1);
+ }
+
+ p = strsep(&bp, ",");
+ p = strdup(p ? p : "");
+ list[E_NAME].save = p;
+ if (!list[E_NAME].restricted || master_mode)
+ (void)fprintf(fp, "Full Name: %s\n", p);
+
+ p = strsep(&bp, ",");
+ p = strdup(p ? p : "");
+ list[E_LOCATE].save = p;
+ if (!list[E_LOCATE].restricted || master_mode)
+ (void)fprintf(fp, "Office Location: %s\n", p);
+
+ p = strsep(&bp, ",");
+ p = strdup(p ? p : "");
+ list[E_BPHONE].save = p;
+ if (!list[E_BPHONE].restricted || master_mode)
+ (void)fprintf(fp, "Office Phone: %s\n", p);
+
+ p = strsep(&bp, ",");
+ p = strdup(p ? p : "");
+ list[E_HPHONE].save = p;
+ if (!list[E_HPHONE].restricted || master_mode)
+ (void)fprintf(fp, "Home Phone: %s\n", p);
+
+ bp = strdup(bp ? bp : "");
+ list[E_OTHER].save = bp;
+ if (!list[E_OTHER].restricted || master_mode)
+ (void)fprintf(fp, "Other information: %s\n", bp);
+
+ free(gecos);
+
+ (void)fchown(fileno(fp), getuid(), getgid());
+ (void)fclose(fp);
+ return (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);
+}
diff --git a/chpass/field.c b/chpass/field.c
new file mode 100644
index 0000000..3b5129c
--- /dev/null
+++ b/chpass/field.c
@@ -0,0 +1,263 @@
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)field.c 8.4 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "chpass.h"
+
+/* ARGSUSED */
+int
+p_login(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+ if (!*p) {
+ warnx("empty login field");
+ return (-1);
+ }
+ if (*p == '-') {
+ warnx("login names may not begin with a hyphen");
+ return (-1);
+ }
+ if (!(pw->pw_name = strdup(p))) {
+ warnx("can't save entry");
+ return (-1);
+ }
+ if (strchr(p, '.'))
+ warnx("\'.\' is dangerous in a login name");
+ for (; *p; ++p)
+ if (isupper(*p)) {
+ warnx("upper-case letters are dangerous in a login name");
+ break;
+ }
+ return (0);
+}
+
+/* ARGSUSED */
+int
+p_passwd(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+ if (!(pw->pw_passwd = strdup(p))) {
+ warnx("can't save password entry");
+ return (-1);
+ }
+
+ return (0);
+}
+
+/* ARGSUSED */
+int
+p_uid(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+ uid_t id;
+ char *np;
+
+ if (!*p) {
+ warnx("empty uid field");
+ return (-1);
+ }
+ if (!isdigit(*p)) {
+ warnx("illegal uid");
+ return (-1);
+ }
+ errno = 0;
+ id = strtoul(p, &np, 10);
+ if (*np || (id == (uid_t)ULONG_MAX && errno == ERANGE)) {
+ warnx("illegal uid");
+ return (-1);
+ }
+ pw->pw_uid = id;
+ return (0);
+}
+
+/* ARGSUSED */
+int
+p_gid(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+ struct group *gr;
+ gid_t id;
+ char *np;
+
+ if (!*p) {
+ warnx("empty gid field");
+ return (-1);
+ }
+ if (!isdigit(*p)) {
+ if (!(gr = getgrnam(p))) {
+ warnx("unknown group %s", p);
+ return (-1);
+ }
+ pw->pw_gid = gr->gr_gid;
+ return (0);
+ }
+ errno = 0;
+ id = strtoul(p, &np, 10);
+ if (*np || (id == (uid_t)ULONG_MAX && errno == ERANGE)) {
+ warnx("illegal gid");
+ return (-1);
+ }
+ pw->pw_gid = id;
+ return (0);
+}
+
+/* ARGSUSED */
+int
+p_class(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+ if (!(pw->pw_class = strdup(p))) {
+ warnx("can't save entry");
+ return (-1);
+ }
+
+ return (0);
+}
+
+/* ARGSUSED */
+int
+p_change(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+ if (!atot(p, &pw->pw_change))
+ return (0);
+ warnx("illegal date for change field");
+ return (-1);
+}
+
+/* ARGSUSED */
+int
+p_expire(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+ if (!atot(p, &pw->pw_expire))
+ return (0);
+ warnx("illegal date for expire field");
+ return (-1);
+}
+
+/* ARGSUSED */
+int
+p_gecos(char *p, struct passwd *pw __unused, ENTRY *ep)
+{
+ if (!(ep->save = strdup(p))) {
+ warnx("can't save entry");
+ return (-1);
+ }
+ return (0);
+}
+
+/* ARGSUSED */
+int
+p_hdir(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+ if (!*p) {
+ warnx("empty home directory field");
+ return (-1);
+ }
+ if (!(pw->pw_dir = strdup(p))) {
+ warnx("can't save entry");
+ return (-1);
+ }
+ return (0);
+}
+
+/* ARGSUSED */
+int
+p_shell(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+ struct stat sbuf;
+
+ if (!*p) {
+ pw->pw_shell = strdup(_PATH_BSHELL);
+ return (0);
+ }
+ /* only admin can change from or to "restricted" shells */
+ if (!master_mode && pw->pw_shell && !ok_shell(pw->pw_shell)) {
+ warnx("%s: current shell non-standard", pw->pw_shell);
+ return (-1);
+ }
+ if (!ok_shell(p)) {
+ if (!master_mode) {
+ warnx("%s: non-standard shell", p);
+ return (-1);
+ }
+ pw->pw_shell = strdup(p);
+ }
+ else
+ pw->pw_shell = dup_shell(p);
+ if (!pw->pw_shell) {
+ warnx("can't save entry");
+ return (-1);
+ }
+ if (stat(pw->pw_shell, &sbuf) < 0) {
+ if (errno == ENOENT)
+ warnx("WARNING: shell '%s' does not exist",
+ pw->pw_shell);
+ else
+ warn("WARNING: can't stat shell '%s'", pw->pw_shell);
+ return (0);
+ }
+ if (!S_ISREG(sbuf.st_mode)) {
+ warnx("WARNING: shell '%s' is not a regular file",
+ pw->pw_shell);
+ return (0);
+ }
+ if ((sbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) == 0) {
+ warnx("WARNING: shell '%s' is not executable", pw->pw_shell);
+ return (0);
+ }
+ return (0);
+}
diff --git a/chpass/util.c b/chpass/util.c
index baf160e..bfece1d 100644
--- a/chpass/util.c
+++ b/chpass/util.c
@@ -1,4 +1,6 @@
/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
* Copyright (c) 1988, 1993, 1994
* The Regents of the University of California. All rights reserved.
* Copyright (c) 2002 Networks Associates Technology, Inc.