198514Sluigi/*- 298514Sluigi * Copyright (c) 1990, 1993, 1994 398514Sluigi * The Regents of the University of California. All rights reserved. 498514Sluigi * 598514Sluigi * Redistribution and use in source and binary forms, with or without 698514Sluigi * modification, are permitted provided that the following conditions 798514Sluigi * are met: 898514Sluigi * 1. Redistributions of source code must retain the above copyright 998514Sluigi * notice, this list of conditions and the following disclaimer. 1098514Sluigi * 2. Redistributions in binary form must reproduce the above copyright 1198514Sluigi * notice, this list of conditions and the following disclaimer in the 1298514Sluigi * documentation and/or other materials provided with the distribution. 1398514Sluigi * 3. All advertising materials mentioning features or use of this software 1498514Sluigi * must display the following acknowledgement: 1598514Sluigi * This product includes software developed by the University of 1698514Sluigi * California, Berkeley and its contributors. 1798514Sluigi * 4. Neither the name of the University nor the names of its contributors 1898514Sluigi * may be used to endorse or promote products derived from this software 1998514Sluigi * without specific prior written permission. 2098514Sluigi * 2198514Sluigi * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2298514Sluigi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2398514Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2498514Sluigi * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2598514Sluigi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2698514Sluigi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2798514Sluigi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2898514Sluigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2998514Sluigi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3098514Sluigi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3198514Sluigi * SUCH DAMAGE. 3298514Sluigi */ 3398514Sluigi 3498514Sluigi#ifndef lint 3598514Sluigi#if 0 3698514Sluigistatic const char sccsid[] = "@(#)pw_util.c 8.3 (Berkeley) 4/2/94"; 3798514Sluigi#endif 3898514Sluigistatic const char rcsid[] = 3998514Sluigi "$FreeBSD$"; 4098514Sluigi#endif /* not lint */ 4198514Sluigi 4298514Sluigi/* 4398514Sluigi * This file is used by all the "password" programs; vipw(8), chpass(1), 4498514Sluigi * and passwd(1). 4598514Sluigi */ 4698514Sluigi 4798514Sluigi#include <sys/param.h> 4898514Sluigi#include <sys/errno.h> 4998514Sluigi#include <sys/time.h> 5098514Sluigi#include <sys/resource.h> 5198514Sluigi#include <sys/stat.h> 5298514Sluigi#include <sys/wait.h> 5398514Sluigi 5498514Sluigi#include <err.h> 5598514Sluigi#include <fcntl.h> 5698514Sluigi#include <paths.h> 5798514Sluigi#include <pwd.h> 5898514Sluigi#include <signal.h> 5998514Sluigi#include <stdio.h> 6098514Sluigi#include <stdlib.h> 6198514Sluigi#include <string.h> 6298514Sluigi#include <unistd.h> 6398514Sluigi 6498514Sluigi#include "pw_util.h" 6598514Sluigi 6698514Sluigiextern char *tempname; 6798514Sluigistatic pid_t editpid = -1; 6898514Sluigistatic int lockfd; 6998514Sluigistatic char _default_editor[] = _PATH_VI; 7098514Sluigistatic char _default_mppath[] = _PATH_PWD; 7198514Sluigistatic char _default_masterpasswd[] = _PATH_MASTERPASSWD; 7298514Sluigichar *mppath = _default_mppath; 7398514Sluigichar *masterpasswd = _default_masterpasswd; 7498514Sluigi 7598514Sluigivoid pw_cont(int); 7698514Sluigi 7798514Sluigivoid 7898514Sluigipw_cont(int sig) 7998514Sluigi{ 8098514Sluigi 8198514Sluigi if (editpid != -1) 8298514Sluigi kill(editpid, sig); 8398514Sluigi} 8498514Sluigi 8598514Sluigivoid 8698514Sluigipw_init(void) 8798514Sluigi{ 8898514Sluigi struct rlimit rlim; 8998514Sluigi 9098514Sluigi /* Unlimited resource limits. */ 9198514Sluigi rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; 9298514Sluigi (void)setrlimit(RLIMIT_CPU, &rlim); 9398514Sluigi (void)setrlimit(RLIMIT_FSIZE, &rlim); 9498514Sluigi (void)setrlimit(RLIMIT_STACK, &rlim); 9598514Sluigi (void)setrlimit(RLIMIT_DATA, &rlim); 9698514Sluigi (void)setrlimit(RLIMIT_RSS, &rlim); 9798514Sluigi 9898514Sluigi /* Don't drop core (not really necessary, but GP's). */ 9998514Sluigi rlim.rlim_cur = rlim.rlim_max = 0; 10098514Sluigi (void)setrlimit(RLIMIT_CORE, &rlim); 10198514Sluigi 10298514Sluigi /* Turn off signals. */ 10398514Sluigi (void)signal(SIGALRM, SIG_IGN); 10498514Sluigi (void)signal(SIGHUP, SIG_IGN); 10598514Sluigi (void)signal(SIGINT, SIG_IGN); 10698514Sluigi (void)signal(SIGPIPE, SIG_IGN); 10798514Sluigi (void)signal(SIGQUIT, SIG_IGN); 10898514Sluigi (void)signal(SIGTERM, SIG_IGN); 10998514Sluigi (void)signal(SIGCONT, pw_cont); 11098514Sluigi 11198514Sluigi /* Create with exact permissions. */ 11298514Sluigi (void)umask(0); 11398514Sluigi} 11498514Sluigi 11598514Sluigiint 11698514Sluigipw_lock(void) 11798514Sluigi{ 11898514Sluigi /* 11998514Sluigi * If the master password file doesn't exist, the system is hosed. 12098514Sluigi * Might as well try to build one. Set the close-on-exec bit so 12198514Sluigi * that users can't get at the encrypted passwords while editing. 12298514Sluigi * Open should allow flock'ing the file; see 4.4BSD. XXX 12398514Sluigi */ 12498514Sluigi for (;;) { 12598514Sluigi struct stat st; 12698514Sluigi 12798514Sluigi lockfd = open(masterpasswd, O_RDONLY, 0); 12898514Sluigi if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1) 12998514Sluigi err(1, "%s", masterpasswd); 13098514Sluigi if (flock(lockfd, LOCK_EX|LOCK_NB)) 13198514Sluigi errx(1, "the password db file is busy"); 13298514Sluigi 13398514Sluigi /* 13498514Sluigi * If the password file was replaced while we were trying to 13598514Sluigi * get the lock, our hardlink count will be 0 and we have to 13698514Sluigi * close and retry. 13798514Sluigi */ 13898514Sluigi if (fstat(lockfd, &st) < 0) 13998514Sluigi errx(1, "fstat() failed"); 14098514Sluigi if (st.st_nlink != 0) 14198514Sluigi break; 14298514Sluigi close(lockfd); 14398514Sluigi lockfd = -1; 14498514Sluigi } 14598514Sluigi return (lockfd); 14698514Sluigi} 14798514Sluigi 14898514Sluigiint 14998514Sluigipw_tmp(void) 15098514Sluigi{ 15198514Sluigi static char path[MAXPATHLEN]; 15298514Sluigi int fd; 15398514Sluigi char *p; 15498514Sluigi 15598514Sluigi strncpy(path, masterpasswd, MAXPATHLEN - 1); 15698514Sluigi path[MAXPATHLEN] = '\0'; 15798514Sluigi 15898514Sluigi if ((p = strrchr(path, '/'))) 15998514Sluigi ++p; 16098514Sluigi else 16198514Sluigi p = path; 16298514Sluigi strcpy(p, "pw.XXXXXX"); 16398514Sluigi if ((fd = mkstemp(path)) == -1) 16498514Sluigi err(1, "%s", path); 16598514Sluigi tempname = path; 16698514Sluigi return (fd); 16798514Sluigi} 16898514Sluigi 16998514Sluigiint 17098514Sluigipw_mkdb(const char *username) 17198514Sluigi{ 17298514Sluigi int pstat; 17398514Sluigi pid_t pid; 17498514Sluigi 17598514Sluigi (void)fflush(stderr); 17698514Sluigi if (!(pid = fork())) { 17798514Sluigi if(!username) { 17898514Sluigi warnx("rebuilding the database..."); 17998514Sluigi execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", "-d", mppath, 18098514Sluigi tempname, (char *)NULL); 18198514Sluigi } else { 18298514Sluigi warnx("updating the database..."); 18398514Sluigi execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", "-d", mppath, 18498514Sluigi "-u", username, tempname, (char *)NULL); 18598514Sluigi } 18698514Sluigi pw_error(_PATH_PWD_MKDB, 1, 1); 18798514Sluigi } 18898514Sluigi pid = waitpid(pid, &pstat, 0); 18998514Sluigi if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0) 19098514Sluigi return (0); 19198514Sluigi warnx("done"); 19298514Sluigi return (1); 19398514Sluigi} 19498514Sluigi 19598514Sluigivoid 19698514Sluigipw_edit(int notsetuid) 19798514Sluigi{ 19898514Sluigi int pstat; 19998514Sluigi char *p, *editor; 20098514Sluigi 20198514Sluigi if (!(editor = getenv("EDITOR"))) 20298514Sluigi editor = _default_editor; 20398514Sluigi if ((p = strrchr(editor, '/'))) 20498514Sluigi ++p; 20598514Sluigi else 20698514Sluigi p = editor; 20798514Sluigi 20898514Sluigi if (!(editpid = fork())) { 20998514Sluigi if (notsetuid) { 21098514Sluigi (void)setgid(getgid()); 21198514Sluigi (void)setuid(getuid()); 21298514Sluigi } 21398514Sluigi errno = 0; 21498514Sluigi execlp(editor, p, tempname, (char *)NULL); 21598514Sluigi _exit(errno); 21698514Sluigi } 21798514Sluigi for (;;) { 21898514Sluigi editpid = waitpid(editpid, (int *)&pstat, WUNTRACED); 21998514Sluigi errno = WEXITSTATUS(pstat); 22098514Sluigi if (editpid == -1) 22198514Sluigi pw_error(editor, 1, 1); 22298514Sluigi else if (WIFSTOPPED(pstat)) 22398514Sluigi raise(WSTOPSIG(pstat)); 22498514Sluigi else if (WIFEXITED(pstat) && errno == 0) 22598514Sluigi break; 22698514Sluigi else 22798514Sluigi pw_error(editor, 1, 1); 22898514Sluigi } 22998514Sluigi editpid = -1; 23098514Sluigi} 23198514Sluigi 23298514Sluigivoid 23398514Sluigipw_prompt(void) 23498514Sluigi{ 23598514Sluigi int c, first; 23698514Sluigi 23798514Sluigi (void)printf("re-edit the password file? [y]: "); 23898514Sluigi (void)fflush(stdout); 23998514Sluigi first = c = getchar(); 24098514Sluigi while (c != '\n' && c != EOF) 24198514Sluigi c = getchar(); 24298514Sluigi if (first == 'n') 24398514Sluigi pw_error(NULL, 0, 0); 24498514Sluigi} 24598514Sluigi 24698514Sluigivoid 24798514Sluigipw_error(const char *name, int error, int eval) 24898514Sluigi{ 24998514Sluigi if (error) { 25098514Sluigi if (name != NULL) 25198514Sluigi warn("%s", name); 25298514Sluigi else 25398514Sluigi warn(NULL); 25498514Sluigi } 25598514Sluigi warnx("password information unchanged"); 25698514Sluigi (void)unlink(tempname); 25798514Sluigi exit(eval); 25898514Sluigi} 259