1 /*- 2 * Copyright (c) 1990, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)edit.c 8.3 (Berkeley) 04/02/94"; 10 #endif /* not lint */ 11 12 #include <sys/param.h> 13 #include <sys/stat.h> 14 15 #include <ctype.h> 16 #include <err.h> 17 #include <errno.h> 18 #include <paths.h> 19 #include <pwd.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <unistd.h> 24 25 #include <pw_scan.h> 26 #include <pw_util.h> 27 28 #include "chpass.h" 29 30 extern char *tempname; 31 32 void 33 edit(pw) 34 struct passwd *pw; 35 { 36 struct stat begin, end; 37 38 for (;;) { 39 if (stat(tempname, &begin)) 40 pw_error(tempname, 1, 1); 41 pw_edit(1); 42 if (stat(tempname, &end)) 43 pw_error(tempname, 1, 1); 44 if (begin.st_mtime == end.st_mtime) { 45 warnx("no changes made"); 46 pw_error(NULL, 0, 0); 47 } 48 if (verify(pw)) 49 break; 50 pw_prompt(); 51 } 52 } 53 54 /* 55 * display -- 56 * print out the file for the user to edit; strange side-effect: 57 * set conditional flag if the user gets to edit the shell. 58 */ 59 void 60 display(fd, pw) 61 int fd; 62 struct passwd *pw; 63 { 64 FILE *fp; 65 char *bp, *p, *ttoa(); 66 67 if (!(fp = fdopen(fd, "w"))) 68 pw_error(tempname, 1, 1); 69 70 (void)fprintf(fp, 71 "#Changing user database information for %s.\n", pw->pw_name); 72 if (!uid) { 73 (void)fprintf(fp, "Login: %s\n", pw->pw_name); 74 (void)fprintf(fp, "Password: %s\n", pw->pw_passwd); 75 (void)fprintf(fp, "Uid [#]: %d\n", pw->pw_uid); 76 (void)fprintf(fp, "Gid [# or name]: %d\n", pw->pw_gid); 77 (void)fprintf(fp, "Change [month day year]: %s\n", 78 ttoa(pw->pw_change)); 79 (void)fprintf(fp, "Expire [month day year]: %s\n", 80 ttoa(pw->pw_expire)); 81 (void)fprintf(fp, "Class: %s\n", pw->pw_class); 82 (void)fprintf(fp, "Home directory: %s\n", pw->pw_dir); 83 (void)fprintf(fp, "Shell: %s\n", 84 *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL); 85 } 86 /* Only admin can change "restricted" shells. */ 87 else if (ok_shell(pw->pw_shell)) 88 /* 89 * Make shell a restricted field. Ugly with a 90 * necklace, but there's not much else to do. 91 */ 92 (void)fprintf(fp, "Shell: %s\n", 93 *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL); 94 else 95 list[E_SHELL].restricted = 1; 96 bp = pw->pw_gecos; 97 p = strsep(&bp, ","); 98 (void)fprintf(fp, "Full Name: %s\n", p ? p : ""); 99 p = strsep(&bp, ","); 100 (void)fprintf(fp, "Location: %s\n", p ? p : ""); 101 p = strsep(&bp, ","); 102 (void)fprintf(fp, "Office Phone: %s\n", p ? p : ""); 103 p = strsep(&bp, ","); 104 (void)fprintf(fp, "Home Phone: %s\n", p ? p : ""); 105 106 (void)fchown(fd, getuid(), getgid()); 107 (void)fclose(fp); 108 } 109 110 int 111 verify(pw) 112 struct passwd *pw; 113 { 114 ENTRY *ep; 115 char *p; 116 struct stat sb; 117 FILE *fp; 118 int len; 119 char buf[LINE_MAX]; 120 121 if (!(fp = fopen(tempname, "r"))) 122 pw_error(tempname, 1, 1); 123 if (fstat(fileno(fp), &sb)) 124 pw_error(tempname, 1, 1); 125 if (sb.st_size == 0) { 126 warnx("corrupted temporary file"); 127 goto bad; 128 } 129 while (fgets(buf, sizeof(buf), fp)) { 130 if (!buf[0] || buf[0] == '#') 131 continue; 132 if (!(p = strchr(buf, '\n'))) { 133 warnx("line too long"); 134 goto bad; 135 } 136 *p = '\0'; 137 for (ep = list;; ++ep) { 138 if (!ep->prompt) { 139 warnx("unrecognized field"); 140 goto bad; 141 } 142 if (!strncasecmp(buf, ep->prompt, ep->len)) { 143 if (ep->restricted && uid) { 144 warnx( 145 "you may not change the %s field", 146 ep->prompt); 147 goto bad; 148 } 149 if (!(p = strchr(buf, ':'))) { 150 warnx("line corrupted"); 151 goto bad; 152 } 153 while (isspace(*++p)); 154 if (ep->except && strpbrk(p, ep->except)) { 155 warnx( 156 "illegal character in the \"%s\" field", 157 ep->prompt); 158 goto bad; 159 } 160 if ((ep->func)(p, pw, ep)) { 161 bad: (void)fclose(fp); 162 return (0); 163 } 164 break; 165 } 166 } 167 } 168 (void)fclose(fp); 169 170 /* Build the gecos field. */ 171 len = strlen(list[E_NAME].save) + strlen(list[E_BPHONE].save) + 172 strlen(list[E_HPHONE].save) + strlen(list[E_LOCATE].save) + 4; 173 if (!(p = malloc(len))) 174 err(1, NULL); 175 (void)sprintf(pw->pw_gecos = p, "%s,%s,%s,%s", list[E_NAME].save, 176 list[E_LOCATE].save, list[E_BPHONE].save, list[E_HPHONE].save); 177 178 if (snprintf(buf, sizeof(buf), 179 "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s", 180 pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid, pw->pw_class, 181 pw->pw_change, pw->pw_expire, pw->pw_gecos, pw->pw_dir, 182 pw->pw_shell) >= sizeof(buf)) { 183 warnx("entries too long"); 184 return (0); 185 } 186 return (pw_scan(buf, pw)); 187 } 188