edit.c revision 8874
1283276Sgonzo/*- 2283276Sgonzo * Copyright (c) 1990, 1993, 1994 3283276Sgonzo * The Regents of the University of California. All rights reserved. 4283276Sgonzo * 5283276Sgonzo * Redistribution and use in source and binary forms, with or without 6283276Sgonzo * modification, are permitted provided that the following conditions 7283276Sgonzo * are met: 8283276Sgonzo * 1. Redistributions of source code must retain the above copyright 9283276Sgonzo * notice, this list of conditions and the following disclaimer. 10283276Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 11283276Sgonzo * notice, this list of conditions and the following disclaimer in the 12283276Sgonzo * documentation and/or other materials provided with the distribution. 13283276Sgonzo * 3. All advertising materials mentioning features or use of this software 14283276Sgonzo * must display the following acknowledgement: 15283276Sgonzo * This product includes software developed by the University of 16283276Sgonzo * California, Berkeley and its contributors. 17283276Sgonzo * 4. Neither the name of the University nor the names of its contributors 18283276Sgonzo * may be used to endorse or promote products derived from this software 19283276Sgonzo * without specific prior written permission. 20283276Sgonzo * 21283276Sgonzo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22283276Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23283276Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24283276Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25283276Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26283276Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27283276Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28283276Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29283276Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30283276Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31283276Sgonzo * SUCH DAMAGE. 32283276Sgonzo */ 33283276Sgonzo 34283276Sgonzo#ifndef lint 35283276Sgonzostatic char sccsid[] = "@(#)edit.c 8.3 (Berkeley) 4/2/94"; 36283276Sgonzo#endif /* not lint */ 37283276Sgonzo 38283276Sgonzo#include <sys/param.h> 39283276Sgonzo#include <sys/stat.h> 40283276Sgonzo 41283276Sgonzo#include <ctype.h> 42283276Sgonzo#include <err.h> 43283276Sgonzo#include <errno.h> 44283276Sgonzo#include <paths.h> 45283276Sgonzo#include <pwd.h> 46283276Sgonzo#include <stdio.h> 47283276Sgonzo#include <stdlib.h> 48283276Sgonzo#include <string.h> 49283276Sgonzo#include <unistd.h> 50283276Sgonzo 51283276Sgonzo#include <pw_scan.h> 52283276Sgonzo#include <pw_util.h> 53283276Sgonzo 54283276Sgonzo#include "chpass.h" 55283276Sgonzo 56283276Sgonzoextern char *tempname; 57283276Sgonzo 58283276Sgonzovoid 59283276Sgonzoedit(pw) 60283276Sgonzo struct passwd *pw; 61283276Sgonzo{ 62283276Sgonzo struct stat begin, end; 63283276Sgonzo 64283276Sgonzo for (;;) { 65283276Sgonzo if (stat(tempname, &begin)) 66283276Sgonzo pw_error(tempname, 1, 1); 67283276Sgonzo pw_edit(1); 68283276Sgonzo if (stat(tempname, &end)) 69283276Sgonzo pw_error(tempname, 1, 1); 70283276Sgonzo if (begin.st_mtime == end.st_mtime) { 71283276Sgonzo warnx("no changes made"); 72283276Sgonzo pw_error(NULL, 0, 0); 73283276Sgonzo } 74283276Sgonzo if (verify(pw)) 75283276Sgonzo break; 76283276Sgonzo pw_prompt(); 77283276Sgonzo } 78283276Sgonzo} 79283276Sgonzo 80283276Sgonzo/* 81283276Sgonzo * display -- 82283276Sgonzo * print out the file for the user to edit; strange side-effect: 83283276Sgonzo * set conditional flag if the user gets to edit the shell. 84283276Sgonzo */ 85283276Sgonzovoid 86283276Sgonzodisplay(fd, pw) 87283276Sgonzo int fd; 88283276Sgonzo struct passwd *pw; 89283276Sgonzo{ 90283276Sgonzo FILE *fp; 91283276Sgonzo char *bp, *p, *ttoa(); 92283276Sgonzo 93283276Sgonzo if (!(fp = fdopen(fd, "w"))) 94283276Sgonzo pw_error(tempname, 1, 1); 95283276Sgonzo 96283276Sgonzo (void)fprintf(fp, 97283276Sgonzo "#Changing user database information for %s.\n", pw->pw_name); 98283276Sgonzo if (!uid) { 99283276Sgonzo (void)fprintf(fp, "Login: %s\n", pw->pw_name); 100283276Sgonzo (void)fprintf(fp, "Password: %s\n", pw->pw_passwd); 101283276Sgonzo (void)fprintf(fp, "Uid [#]: %d\n", pw->pw_uid); 102283276Sgonzo (void)fprintf(fp, "Gid [# or name]: %d\n", pw->pw_gid); 103283276Sgonzo (void)fprintf(fp, "Change [month day year]: %s\n", 104283276Sgonzo ttoa(pw->pw_change)); 105283276Sgonzo (void)fprintf(fp, "Expire [month day year]: %s\n", 106283276Sgonzo ttoa(pw->pw_expire)); 107283276Sgonzo (void)fprintf(fp, "Class: %s\n", pw->pw_class); 108283276Sgonzo (void)fprintf(fp, "Home directory: %s\n", pw->pw_dir); 109283276Sgonzo (void)fprintf(fp, "Shell: %s\n", 110283276Sgonzo *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL); 111283276Sgonzo } 112283276Sgonzo /* Only admin can change "restricted" shells. */ 113283276Sgonzo else if (ok_shell(pw->pw_shell)) 114283276Sgonzo /* 115283276Sgonzo * Make shell a restricted field. Ugly with a 116283276Sgonzo * necklace, but there's not much else to do. 117283276Sgonzo */ 118283276Sgonzo (void)fprintf(fp, "Shell: %s\n", 119283276Sgonzo *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL); 120283276Sgonzo else 121283276Sgonzo list[E_SHELL].restricted = 1; 122283276Sgonzo bp = pw->pw_gecos; 123283276Sgonzo 124283276Sgonzo p = strsep(&bp, ","); 125283276Sgonzo if (p) 126283276Sgonzo list[E_NAME].save = strdup(p); 127283276Sgonzo if (!list[E_NAME].restricted || !uid) 128283276Sgonzo (void)fprintf(fp, "Full Name: %s\n", p ? p : ""); 129283276Sgonzo 130283276Sgonzo p = strsep(&bp, ","); 131283276Sgonzo if (p) 132283276Sgonzo list[E_LOCATE].save = strdup(p); 133283276Sgonzo if (!list[E_LOCATE].restricted || !uid) 134283276Sgonzo (void)fprintf(fp, "Location: %s\n", p ? p : ""); 135283276Sgonzo 136283276Sgonzo p = strsep(&bp, ","); 137283276Sgonzo if (p) 138283276Sgonzo list[E_BPHONE].save = strdup(p); 139283276Sgonzo if (!list[E_BPHONE].restricted || !uid) 140283276Sgonzo (void)fprintf(fp, "Office Phone: %s\n", p ? p : ""); 141283276Sgonzo 142283276Sgonzo p = strsep(&bp, ","); 143283276Sgonzo if (p) 144283276Sgonzo list[E_HPHONE].save = strdup(p); 145283276Sgonzo if (!list[E_HPHONE].restricted || !uid) 146283276Sgonzo (void)fprintf(fp, "Home Phone: %s\n", p ? p : ""); 147283276Sgonzo 148283276Sgonzo (void)fchown(fd, getuid(), getgid()); 149283276Sgonzo (void)fclose(fp); 150283276Sgonzo} 151283276Sgonzo 152283276Sgonzoint 153283276Sgonzoverify(pw) 154283276Sgonzo struct passwd *pw; 155283276Sgonzo{ 156283276Sgonzo ENTRY *ep; 157283276Sgonzo char *p; 158283276Sgonzo struct stat sb; 159283276Sgonzo FILE *fp; 160283276Sgonzo int len; 161283276Sgonzo char buf[LINE_MAX]; 162283276Sgonzo 163283276Sgonzo if (!(fp = fopen(tempname, "r"))) 164283276Sgonzo pw_error(tempname, 1, 1); 165283276Sgonzo if (fstat(fileno(fp), &sb)) 166283276Sgonzo pw_error(tempname, 1, 1); 167283276Sgonzo if (sb.st_size == 0) { 168283276Sgonzo warnx("corrupted temporary file"); 169283276Sgonzo goto bad; 170283276Sgonzo } 171283276Sgonzo while (fgets(buf, sizeof(buf), fp)) { 172283276Sgonzo if (!buf[0] || buf[0] == '#') 173283276Sgonzo continue; 174283276Sgonzo if (!(p = strchr(buf, '\n'))) { 175283276Sgonzo warnx("line too long"); 176283276Sgonzo goto bad; 177283276Sgonzo } 178283276Sgonzo *p = '\0'; 179283276Sgonzo for (ep = list;; ++ep) { 180283276Sgonzo if (!ep->prompt) { 181283276Sgonzo warnx("unrecognized field"); 182283276Sgonzo goto bad; 183283276Sgonzo } 184283276Sgonzo if (!strncasecmp(buf, ep->prompt, ep->len)) { 185283276Sgonzo if (ep->restricted && uid) { 186283276Sgonzo warnx( 187283276Sgonzo "you may not change the %s field", 188283276Sgonzo ep->prompt); 189283276Sgonzo goto bad; 190283276Sgonzo } 191283276Sgonzo if (!(p = strchr(buf, ':'))) { 192283276Sgonzo warnx("line corrupted"); 193283276Sgonzo goto bad; 194283276Sgonzo } 195283276Sgonzo while (isspace(*++p)); 196283276Sgonzo if (ep->except && strpbrk(p, ep->except)) { 197283276Sgonzo warnx( 198283276Sgonzo "illegal character in the \"%s\" field", 199283276Sgonzo ep->prompt); 200283276Sgonzo goto bad; 201283276Sgonzo } 202283276Sgonzo if ((ep->func)(p, pw, ep)) { 203283276Sgonzobad: (void)fclose(fp); 204283276Sgonzo return (0); 205283276Sgonzo } 206283276Sgonzo break; 207283276Sgonzo } 208283276Sgonzo } 209283276Sgonzo } 210283276Sgonzo (void)fclose(fp); 211283276Sgonzo 212283276Sgonzo /* Build the gecos field. */ 213283276Sgonzo len = strlen(list[E_NAME].save) + strlen(list[E_BPHONE].save) + 214283276Sgonzo strlen(list[E_HPHONE].save) + strlen(list[E_LOCATE].save) + 4; 215283276Sgonzo if (!(p = malloc(len))) 216283276Sgonzo err(1, NULL); 217283276Sgonzo (void)sprintf(pw->pw_gecos = p, "%s,%s,%s,%s", list[E_NAME].save, 218283276Sgonzo list[E_LOCATE].save, list[E_BPHONE].save, list[E_HPHONE].save); 219283276Sgonzo 220283276Sgonzo if (snprintf(buf, sizeof(buf), 221283276Sgonzo "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s", 222283276Sgonzo pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid, pw->pw_class, 223283276Sgonzo pw->pw_change, pw->pw_expire, pw->pw_gecos, pw->pw_dir, 224283276Sgonzo pw->pw_shell) >= sizeof(buf)) { 225283276Sgonzo warnx("entries too long"); 226283276Sgonzo return (0); 227283276Sgonzo } 228283276Sgonzo return (pw_scan(buf, pw)); 229283276Sgonzo} 230283276Sgonzo