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