rework the password subsystem
authorKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Wed, 13 Feb 1991 14:36:34 +0000 (06:36 -0800)
committerKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Wed, 13 Feb 1991 14:36:34 +0000 (06:36 -0800)
date and time created 91/02/12 22:36:34 by bostic

SCCS-vsn: usr.bin/chpass/edit.c 5.1

usr/src/usr.bin/chpass/edit.c [new file with mode: 0644]

diff --git a/usr/src/usr.bin/chpass/edit.c b/usr/src/usr.bin/chpass/edit.c
new file mode 100644 (file)
index 0000000..bb1783f
--- /dev/null
@@ -0,0 +1,185 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)edit.c     5.1 (Berkeley) %G%";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+#include "chpass.h"
+
+extern char *tempname;
+
+edit(tfd, pw)
+       int tfd;
+       struct passwd *pw;
+{
+       struct stat begin, end;
+
+       /*
+        * Give the file to the real user; setuid permissions are discarded
+        * in pw_edit().
+        */
+       (void)fchown(tfd, getuid(), getgid());
+
+       display(tfd, pw);
+
+       for (;;) {
+               if (stat(tempname, &begin))
+                       pw_error(tempname, 1, 1);
+               if (pw_edit(1)) {
+                       (void)fprintf(stderr, "chpass: edit failed\n");
+                       break;
+               }
+               if (stat(tempname, &end))
+                       pw_error(tempname, 1, 1);
+               if (begin.st_mtime == end.st_mtime) {
+                       (void)fprintf(stderr, "chpass: no changes made\n");
+                       pw_error((char *)NULL, 0, 0);
+               }
+               if (verify(pw))
+                       break;
+               pw_prompt();
+       }
+}
+
+/*
+ * display --
+ *     print out the file for the user to edit; strange side-effect:
+ *     set conditional flag if the user gets to edit the shell.
+ */
+display(fd, pw)
+       int fd;
+       struct passwd *pw;
+{
+       register char *p;
+       FILE *fp;
+       char *bp, *ok_shell(), *ttoa();
+
+       if (!(fp = fdopen(fd, "w")))
+               pw_error(tempname, 1, 1);
+
+       (void)fprintf(fp,
+           "#Changing user database information for %s.\n", pw->pw_name);
+       if (!uid) {
+               (void)fprintf(fp, "Login: %s\n", pw->pw_name);
+               (void)fprintf(fp, "Password: %s\n", pw->pw_passwd);
+               (void)fprintf(fp, "Uid [#]: %d\n", pw->pw_uid);
+               (void)fprintf(fp, "Gid [# or name]: %d\n", 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. */
+       else if (ok_shell(pw->pw_shell))
+               /*
+                * Make shell a restricted field.  Ugly with a
+                * necklace, but there's not much else to do.
+                */
+               (void)fprintf(fp, "Shell: %s\n",
+                   *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL);
+       else
+               list[E_SHELL].restricted = 1;
+       bp = pw->pw_gecos;
+       p = strsep(&bp, ",");
+       (void)fprintf(fp, "Full Name: %s\n", p ? p : "");
+       p = strsep(&bp, ",");
+       (void)fprintf(fp, "Location: %s\n", p ? p : "");
+       p = strsep(&bp, ",");
+       (void)fprintf(fp, "Office Phone: %s\n", p ? p : "");
+       p = strsep(&bp, ",");
+       (void)fprintf(fp, "Home Phone: %s\n", p ? p : "");
+
+       (void)fclose(fp);
+}
+
+verify(pw)
+       struct passwd *pw;
+{
+       register ENTRY *ep;
+       register char *p;
+       FILE *fp;
+       int len;
+       char buf[LINE_MAX];
+
+       if (!(fp = fopen(tempname, "r")))
+               pw_error(tempname, 1, 1);
+       while (fgets(buf, sizeof(buf), fp)) {
+               if (!buf[0] || buf[0] == '#')
+                       continue;
+               if (!(p = index(buf, '\n'))) {
+                       (void)fprintf(stderr, "chpass: line too long.\n");
+                       goto bad;
+               }
+               *p = '\0';
+               for (ep = list;; ++ep) {
+                       if (!ep->prompt) {
+                               (void)fprintf(stderr,
+                                   "chpass: unrecognized field.\n");
+                               goto bad;
+                       }
+                       if (!strncasecmp(buf, ep->prompt, ep->len)) {
+                               if (ep->restricted && uid) {
+                                       (void)fprintf(stderr,
+                           "chpass: you may not change the %s field.\n",
+                                           ep->prompt);
+                                       goto bad;
+                               }
+                               if (!(p = index(buf, ':'))) {
+                                       (void)fprintf(stderr,
+                                           "chpass: line corrupted.\n");
+                                       goto bad;
+                               }
+                               while (isspace(*++p));
+                               if (ep->except && strpbrk(p, ep->except)) {
+                                       (void)fprintf(stderr,
+                           "chpass: illegal character in the \"%s\" field.\n",
+                                           ep->prompt);
+                                       goto bad;
+                               }
+                               if ((ep->func)(p, pw, ep)) {
+bad:                                   (void)fclose(fp);
+                                       return(0);
+                               }
+                               break;
+                       }
+               }
+       }
+       (void)fclose(fp);
+
+       /* Build the gecos field. */
+       len = strlen(list[E_NAME].save) + strlen(list[E_BPHONE].save) +
+           strlen(list[E_HPHONE].save) + strlen(list[E_LOCATE].save) + 4;
+       if (!(p = malloc(len))) {
+               (void)fprintf(stderr, "chpass: %s\n", strerror(errno));
+               exit(1);
+       }
+       (void)sprintf(pw->pw_gecos = p, "%s,%s,%s,%s", list[E_NAME].save,
+           list[E_LOCATE].save, list[E_BPHONE].save, list[E_HPHONE].save);
+
+       if (snprintf(buf, sizeof(buf),
+           "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s",
+           pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid, pw->pw_class,
+           pw->pw_change, pw->pw_expire, pw->pw_gecos, pw->pw_dir,
+           pw->pw_shell) >= sizeof(buf)) {
+               (void)fprintf(stderr, "chpass: entries too long\n");
+               return(0);
+       }
+       return(pw_scan(buf, pw));
+}