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