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.2 (Berkeley) 03/03/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((char *)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 FILE *fp; 108 int len; 109 char buf[LINE_MAX]; 110 111 if (!(fp = fopen(tempname, "r"))) 112 pw_error(tempname, 1, 1); 113 while (fgets(buf, sizeof(buf), fp)) { 114 if (!buf[0] || buf[0] == '#') 115 continue; 116 if (!(p = index(buf, '\n'))) { 117 (void)fprintf(stderr, "chpass: line too long.\n"); 118 goto bad; 119 } 120 *p = '\0'; 121 for (ep = list;; ++ep) { 122 if (!ep->prompt) { 123 (void)fprintf(stderr, 124 "chpass: unrecognized field.\n"); 125 goto bad; 126 } 127 if (!strncasecmp(buf, ep->prompt, ep->len)) { 128 if (ep->restricted && uid) { 129 (void)fprintf(stderr, 130 "chpass: you may not change the %s field.\n", 131 ep->prompt); 132 goto bad; 133 } 134 if (!(p = index(buf, ':'))) { 135 (void)fprintf(stderr, 136 "chpass: line corrupted.\n"); 137 goto bad; 138 } 139 while (isspace(*++p)); 140 if (ep->except && strpbrk(p, ep->except)) { 141 (void)fprintf(stderr, 142 "chpass: illegal character in the \"%s\" field.\n", 143 ep->prompt); 144 goto bad; 145 } 146 if ((ep->func)(p, pw, ep)) { 147 bad: (void)fclose(fp); 148 return(0); 149 } 150 break; 151 } 152 } 153 } 154 (void)fclose(fp); 155 156 /* Build the gecos field. */ 157 len = strlen(list[E_NAME].save) + strlen(list[E_BPHONE].save) + 158 strlen(list[E_HPHONE].save) + strlen(list[E_LOCATE].save) + 4; 159 if (!(p = malloc(len))) { 160 (void)fprintf(stderr, "chpass: %s\n", strerror(errno)); 161 exit(1); 162 } 163 (void)sprintf(pw->pw_gecos = p, "%s,%s,%s,%s", list[E_NAME].save, 164 list[E_LOCATE].save, list[E_BPHONE].save, list[E_HPHONE].save); 165 166 if (snprintf(buf, sizeof(buf), 167 "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s", 168 pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid, pw->pw_class, 169 pw->pw_change, pw->pw_expire, pw->pw_gecos, pw->pw_dir, 170 pw->pw_shell) >= sizeof(buf)) { 171 (void)fprintf(stderr, "chpass: entries too long\n"); 172 return(0); 173 } 174 return(pw_scan(buf, pw)); 175 } 176