pw_util.c revision 302408
160484Sobrien/*- 289857Sobrien * Copyright (c) 1990, 1993, 1994 360484Sobrien * The Regents of the University of California. All rights reserved. 460484Sobrien * 560484Sobrien * Redistribution and use in source and binary forms, with or without 660484Sobrien * modification, are permitted provided that the following conditions 760484Sobrien * are met: 860484Sobrien * 1. Redistributions of source code must retain the above copyright 960484Sobrien * notice, this list of conditions and the following disclaimer. 1060484Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1160484Sobrien * notice, this list of conditions and the following disclaimer in the 1260484Sobrien * documentation and/or other materials provided with the distribution. 1360484Sobrien * 3. All advertising materials mentioning features or use of this software 1460484Sobrien * must display the following acknowledgement: 1560484Sobrien * This product includes software developed by the University of 1660484Sobrien * California, Berkeley and its contributors. 1760484Sobrien * 4. Neither the name of the University nor the names of its contributors 1860484Sobrien * may be used to endorse or promote products derived from this software 1960484Sobrien * without specific prior written permission. 2060484Sobrien * 2177298Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2260484Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2360484Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2460484Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2560484Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2660484Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2760484Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2860484Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2960484Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3060484Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3160484Sobrien * SUCH DAMAGE. 3260484Sobrien */ 3360484Sobrien 3460484Sobrien#ifndef lint 3560484Sobrien#if 0 3660484Sobrienstatic const char sccsid[] = "@(#)pw_util.c 8.3 (Berkeley) 4/2/94"; 3760484Sobrien#endif 3860484Sobrienstatic const char rcsid[] = 3960484Sobrien "$FreeBSD: stable/11/release/picobsd/tinyware/passwd/pw_util.c 98514 2002-06-20 21:17:33Z luigi $"; 4060484Sobrien#endif /* not lint */ 4160484Sobrien 4260484Sobrien/* 4360484Sobrien * This file is used by all the "password" programs; vipw(8), chpass(1), 4460484Sobrien * and passwd(1). 4560484Sobrien */ 4660484Sobrien 4760484Sobrien#include <sys/param.h> 4860484Sobrien#include <sys/errno.h> 4960484Sobrien#include <sys/time.h> 5077298Sobrien#include <sys/resource.h> 5160484Sobrien#include <sys/stat.h> 5277298Sobrien#include <sys/wait.h> 5360484Sobrien 5460484Sobrien#include <err.h> 5560484Sobrien#include <fcntl.h> 5660484Sobrien#include <paths.h> 5760484Sobrien#include <pwd.h> 5877298Sobrien#include <signal.h> 5989857Sobrien#include <stdio.h> 6060484Sobrien#include <stdlib.h> 6160484Sobrien#include <string.h> 6260484Sobrien#include <unistd.h> 6360484Sobrien 6460484Sobrien#include "pw_util.h" 6560484Sobrien 6660484Sobrienextern char *tempname; 6760484Sobrienstatic pid_t editpid = -1; 6860484Sobrienstatic int lockfd; 6960484Sobrienstatic char _default_editor[] = _PATH_VI; 7060484Sobrienstatic char _default_mppath[] = _PATH_PWD; 7160484Sobrienstatic char _default_masterpasswd[] = _PATH_MASTERPASSWD; 7260484Sobrienchar *mppath = _default_mppath; 7360484Sobrienchar *masterpasswd = _default_masterpasswd; 7460484Sobrien 7560484Sobrienvoid pw_cont(int); 7660484Sobrien 7760484Sobrienvoid 7860484Sobrienpw_cont(int sig) 7960484Sobrien{ 8060484Sobrien 8160484Sobrien if (editpid != -1) 8260484Sobrien kill(editpid, sig); 8360484Sobrien} 8460484Sobrien 8589857Sobrienvoid 8689857Sobrienpw_init(void) 8789857Sobrien{ 8889857Sobrien struct rlimit rlim; 8989857Sobrien 9089857Sobrien /* Unlimited resource limits. */ 9189857Sobrien rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; 9289857Sobrien (void)setrlimit(RLIMIT_CPU, &rlim); 9389857Sobrien (void)setrlimit(RLIMIT_FSIZE, &rlim); 9489857Sobrien (void)setrlimit(RLIMIT_STACK, &rlim); 9589857Sobrien (void)setrlimit(RLIMIT_DATA, &rlim); 9689857Sobrien (void)setrlimit(RLIMIT_RSS, &rlim); 9789857Sobrien 9889857Sobrien /* Don't drop core (not really necessary, but GP's). */ 9989857Sobrien rlim.rlim_cur = rlim.rlim_max = 0; 10089857Sobrien (void)setrlimit(RLIMIT_CORE, &rlim); 10189857Sobrien 10289857Sobrien /* Turn off signals. */ 10389857Sobrien (void)signal(SIGALRM, SIG_IGN); 10489857Sobrien (void)signal(SIGHUP, SIG_IGN); 10589857Sobrien (void)signal(SIGINT, SIG_IGN); 10689857Sobrien (void)signal(SIGPIPE, SIG_IGN); 10789857Sobrien (void)signal(SIGQUIT, SIG_IGN); 10889857Sobrien (void)signal(SIGTERM, SIG_IGN); 10989857Sobrien (void)signal(SIGCONT, pw_cont); 11089857Sobrien 11189857Sobrien /* Create with exact permissions. */ 11289857Sobrien (void)umask(0); 11360484Sobrien} 11460484Sobrien 11560484Sobrienint 11660484Sobrienpw_lock(void) 11760484Sobrien{ 11860484Sobrien /* 11960484Sobrien * If the master password file doesn't exist, the system is hosed. 12060484Sobrien * Might as well try to build one. Set the close-on-exec bit so 12160484Sobrien * that users can't get at the encrypted passwords while editing. 12260484Sobrien * Open should allow flock'ing the file; see 4.4BSD. XXX 12360484Sobrien */ 12460484Sobrien for (;;) { 12560484Sobrien struct stat st; 12660484Sobrien 12760484Sobrien lockfd = open(masterpasswd, O_RDONLY, 0); 12860484Sobrien if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1) 12960484Sobrien err(1, "%s", masterpasswd); 13060484Sobrien if (flock(lockfd, LOCK_EX|LOCK_NB)) 13160484Sobrien errx(1, "the password db file is busy"); 13260484Sobrien 13360484Sobrien /* 13460484Sobrien * If the password file was replaced while we were trying to 13560484Sobrien * get the lock, our hardlink count will be 0 and we have to 13660484Sobrien * close and retry. 13760484Sobrien */ 13860484Sobrien if (fstat(lockfd, &st) < 0) 13960484Sobrien errx(1, "fstat() failed"); 14060484Sobrien if (st.st_nlink != 0) 14160484Sobrien break; 14260484Sobrien close(lockfd); 14360484Sobrien lockfd = -1; 14460484Sobrien } 14560484Sobrien return (lockfd); 14660484Sobrien} 14760484Sobrien 14860484Sobrienint 14960484Sobrienpw_tmp(void) 15060484Sobrien{ 15160484Sobrien static char path[MAXPATHLEN]; 15260484Sobrien int fd; 15360484Sobrien char *p; 15460484Sobrien 15560484Sobrien strncpy(path, masterpasswd, MAXPATHLEN - 1); 15660484Sobrien path[MAXPATHLEN] = '\0'; 15760484Sobrien 15860484Sobrien if ((p = strrchr(path, '/'))) 15960484Sobrien ++p; 16060484Sobrien else 16160484Sobrien p = path; 16260484Sobrien strcpy(p, "pw.XXXXXX"); 16360484Sobrien if ((fd = mkstemp(path)) == -1) 16460484Sobrien err(1, "%s", path); 16560484Sobrien tempname = path; 16660484Sobrien return (fd); 16760484Sobrien} 16860484Sobrien 16960484Sobrienint 17060484Sobrienpw_mkdb(const char *username) 17160484Sobrien{ 17260484Sobrien int pstat; 17360484Sobrien pid_t pid; 17460484Sobrien 17560484Sobrien (void)fflush(stderr); 17660484Sobrien if (!(pid = fork())) { 17760484Sobrien if(!username) { 17860484Sobrien warnx("rebuilding the database..."); 17960484Sobrien execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", "-d", mppath, 18060484Sobrien tempname, (char *)NULL); 18160484Sobrien } else { 18260484Sobrien warnx("updating the database..."); 18360484Sobrien execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", "-d", mppath, 18460484Sobrien "-u", username, tempname, (char *)NULL); 18560484Sobrien } 18660484Sobrien pw_error(_PATH_PWD_MKDB, 1, 1); 18760484Sobrien } 18860484Sobrien pid = waitpid(pid, &pstat, 0); 18960484Sobrien if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0) 19060484Sobrien return (0); 19160484Sobrien warnx("done"); 19260484Sobrien return (1); 19360484Sobrien} 19460484Sobrien 19560484Sobrienvoid 19660484Sobrienpw_edit(int notsetuid) 19760484Sobrien{ 19860484Sobrien int pstat; 19960484Sobrien char *p, *editor; 20077298Sobrien 20177298Sobrien if (!(editor = getenv("EDITOR"))) 20260484Sobrien editor = _default_editor; 20360484Sobrien if ((p = strrchr(editor, '/'))) 20460484Sobrien ++p; 20560484Sobrien else 20660484Sobrien p = editor; 20760484Sobrien 20860484Sobrien if (!(editpid = fork())) { 20960484Sobrien if (notsetuid) { 21060484Sobrien (void)setgid(getgid()); 21160484Sobrien (void)setuid(getuid()); 21260484Sobrien } 21360484Sobrien errno = 0; 21460484Sobrien execlp(editor, p, tempname, (char *)NULL); 21560484Sobrien _exit(errno); 21660484Sobrien } 21760484Sobrien for (;;) { 21860484Sobrien editpid = waitpid(editpid, (int *)&pstat, WUNTRACED); 21960484Sobrien errno = WEXITSTATUS(pstat); 22060484Sobrien if (editpid == -1) 22160484Sobrien pw_error(editor, 1, 1); 22260484Sobrien else if (WIFSTOPPED(pstat)) 22360484Sobrien raise(WSTOPSIG(pstat)); 22460484Sobrien else if (WIFEXITED(pstat) && errno == 0) 22560484Sobrien break; 22689857Sobrien else 22789857Sobrien pw_error(editor, 1, 1); 22860484Sobrien } 22960484Sobrien editpid = -1; 23060484Sobrien} 23160484Sobrien 23260484Sobrienvoid 23360484Sobrienpw_prompt(void) 23460484Sobrien{ 23560484Sobrien int c, first; 23660484Sobrien 23760484Sobrien (void)printf("re-edit the password file? [y]: "); 23860484Sobrien (void)fflush(stdout); 23960484Sobrien first = c = getchar(); 24060484Sobrien while (c != '\n' && c != EOF) 24160484Sobrien c = getchar(); 24260484Sobrien if (first == 'n') 24360484Sobrien pw_error(NULL, 0, 0); 24460484Sobrien} 24560484Sobrien 24660484Sobrienvoid 24789857Sobrienpw_error(const char *name, int error, int eval) 24889857Sobrien{ 24989857Sobrien if (error) { 25089857Sobrien if (name != NULL) 25189857Sobrien warn("%s", name); 25289857Sobrien else 25360484Sobrien warn(NULL); 25460484Sobrien } 25560484Sobrien warnx("password information unchanged"); 25660484Sobrien (void)unlink(tempname); 25760484Sobrien exit(eval); 25860484Sobrien} 25960484Sobrien