1/*- 2 * SPDX-License-Identifier: BSD-4-Clause 3 * 4 * Copyright (c) 1990, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#ifndef lint 37#if 0 38static const char sccsid[] = "@(#)pw_util.c 8.3 (Berkeley) 4/2/94"; 39#endif 40static const char rcsid[] = 41 "$FreeBSD$"; 42#endif /* not lint */ 43 44/* 45 * This file is used by all the "password" programs; vipw(8), chpass(1), 46 * and passwd(1). 47 */ 48 49#include <sys/param.h> 50#include <sys/errno.h> 51#include <sys/time.h> 52#include <sys/resource.h> 53#include <sys/stat.h> 54#include <sys/wait.h> 55 56#include <err.h> 57#include <fcntl.h> 58#include <paths.h> 59#include <pwd.h> 60#include <signal.h> 61#include <stdio.h> 62#include <stdlib.h> 63#include <string.h> 64#include <unistd.h> 65 66#include "pw_util.h" 67 68extern char *tempname; 69static pid_t editpid = -1; 70static int lockfd; 71static char _default_editor[] = _PATH_VI; 72static char _default_mppath[] = _PATH_PWD; 73static char _default_masterpasswd[] = _PATH_MASTERPASSWD; 74char *mppath = _default_mppath; 75char *masterpasswd = _default_masterpasswd; 76 77void pw_cont(int); 78 79void 80pw_cont(int sig) 81{ 82 83 if (editpid != -1) 84 kill(editpid, sig); 85} 86 87void 88pw_init(void) 89{ 90 struct rlimit rlim; 91 92 /* Unlimited resource limits. */ 93 rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; 94 (void)setrlimit(RLIMIT_CPU, &rlim); 95 (void)setrlimit(RLIMIT_FSIZE, &rlim); 96 (void)setrlimit(RLIMIT_STACK, &rlim); 97 (void)setrlimit(RLIMIT_DATA, &rlim); 98 (void)setrlimit(RLIMIT_RSS, &rlim); 99 100 /* Don't drop core (not really necessary, but GP's). */ 101 rlim.rlim_cur = rlim.rlim_max = 0; 102 (void)setrlimit(RLIMIT_CORE, &rlim); 103 104 /* Turn off signals. */ 105 (void)signal(SIGALRM, SIG_IGN); 106 (void)signal(SIGHUP, SIG_IGN); 107 (void)signal(SIGINT, SIG_IGN); 108 (void)signal(SIGPIPE, SIG_IGN); 109 (void)signal(SIGQUIT, SIG_IGN); 110 (void)signal(SIGTERM, SIG_IGN); 111 (void)signal(SIGCONT, pw_cont); 112 113 /* Create with exact permissions. */ 114 (void)umask(0); 115} 116 117int 118pw_lock(void) 119{ 120 /* 121 * If the master password file doesn't exist, the system is hosed. 122 * Might as well try to build one. Set the close-on-exec bit so 123 * that users can't get at the encrypted passwords while editing. 124 * Open should allow flock'ing the file; see 4.4BSD. XXX 125 */ 126 for (;;) { 127 struct stat st; 128 129 lockfd = open(masterpasswd, O_RDONLY, 0); 130 if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1) 131 err(1, "%s", masterpasswd); 132 if (flock(lockfd, LOCK_EX|LOCK_NB)) 133 errx(1, "the password db file is busy"); 134 135 /* 136 * If the password file was replaced while we were trying to 137 * get the lock, our hardlink count will be 0 and we have to 138 * close and retry. 139 */ 140 if (fstat(lockfd, &st) < 0) 141 errx(1, "fstat() failed"); 142 if (st.st_nlink != 0) 143 break; 144 close(lockfd); 145 lockfd = -1; 146 } 147 return (lockfd); 148} 149 150int 151pw_tmp(void) 152{ 153 static char path[MAXPATHLEN]; 154 int fd; 155 char *p; 156 157 strncpy(path, masterpasswd, MAXPATHLEN - 1); 158 path[MAXPATHLEN] = '\0'; 159 160 if ((p = strrchr(path, '/'))) 161 ++p; 162 else 163 p = path; 164 strcpy(p, "pw.XXXXXX"); 165 if ((fd = mkstemp(path)) == -1) 166 err(1, "%s", path); 167 tempname = path; 168 return (fd); 169} 170 171int 172pw_mkdb(const char *username) 173{ 174 int pstat; 175 pid_t pid; 176 177 (void)fflush(stderr); 178 if (!(pid = fork())) { 179 if(!username) { 180 warnx("rebuilding the database..."); 181 execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", "-d", mppath, 182 tempname, (char *)NULL); 183 } else { 184 warnx("updating the database..."); 185 execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", "-d", mppath, 186 "-u", username, tempname, (char *)NULL); 187 } 188 pw_error(_PATH_PWD_MKDB, 1, 1); 189 } 190 pid = waitpid(pid, &pstat, 0); 191 if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0) 192 return (0); 193 warnx("done"); 194 return (1); 195} 196 197void 198pw_edit(int notsetuid) 199{ 200 int pstat; 201 char *p, *editor; 202 203 if (!(editor = getenv("EDITOR"))) 204 editor = _default_editor; 205 if ((p = strrchr(editor, '/'))) 206 ++p; 207 else 208 p = editor; 209 210 if (!(editpid = fork())) { 211 if (notsetuid) { 212 (void)setgid(getgid()); 213 (void)setuid(getuid()); 214 } 215 errno = 0; 216 execlp(editor, p, tempname, (char *)NULL); 217 _exit(errno); 218 } 219 for (;;) { 220 editpid = waitpid(editpid, (int *)&pstat, WUNTRACED); 221 errno = WEXITSTATUS(pstat); 222 if (editpid == -1) 223 pw_error(editor, 1, 1); 224 else if (WIFSTOPPED(pstat)) 225 raise(WSTOPSIG(pstat)); 226 else if (WIFEXITED(pstat) && errno == 0) 227 break; 228 else 229 pw_error(editor, 1, 1); 230 } 231 editpid = -1; 232} 233 234void 235pw_prompt(void) 236{ 237 int c, first; 238 239 (void)printf("re-edit the password file? [y]: "); 240 (void)fflush(stdout); 241 first = c = getchar(); 242 while (c != '\n' && c != EOF) 243 c = getchar(); 244 if (first == 'n') 245 pw_error(NULL, 0, 0); 246} 247 248void 249pw_error(const char *name, int error, int eval) 250{ 251 if (error) { 252 if (name != NULL) 253 warn("%s", name); 254 else 255 warn(NULL); 256 } 257 warnx("password information unchanged"); 258 (void)unlink(tempname); 259 exit(eval); 260} 261