1 /*- 2 * Copyright (c) 1990, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)pw_util.c 8.4 (Berkeley) 04/28/95"; 10 #endif /* not lint */ 11 12 /* 13 * This file is used by all the "password" programs; vipw(8), chpass(1), 14 * and passwd(1). 15 */ 16 17 #include <sys/param.h> 18 #include <sys/time.h> 19 #include <sys/resource.h> 20 #include <sys/stat.h> 21 #include <sys/wait.h> 22 23 #include <err.h> 24 #include <errno.h> 25 #include <fcntl.h> 26 #include <paths.h> 27 #include <pwd.h> 28 #include <signal.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <unistd.h> 33 34 #include "pw_util.h" 35 36 extern char *tempname; 37 static pid_t editpid = -1; 38 static int lockfd; 39 40 void 41 pw_cont(sig) 42 int sig; 43 { 44 45 if (editpid != -1) 46 kill(editpid, sig); 47 } 48 49 void 50 pw_init() 51 { 52 struct rlimit rlim; 53 54 /* Unlimited resource limits. */ 55 rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; 56 (void)setrlimit(RLIMIT_CPU, &rlim); 57 (void)setrlimit(RLIMIT_FSIZE, &rlim); 58 (void)setrlimit(RLIMIT_STACK, &rlim); 59 (void)setrlimit(RLIMIT_DATA, &rlim); 60 (void)setrlimit(RLIMIT_RSS, &rlim); 61 62 /* Don't drop core (not really necessary, but GP's). */ 63 rlim.rlim_cur = rlim.rlim_max = 0; 64 (void)setrlimit(RLIMIT_CORE, &rlim); 65 66 /* Turn off signals. */ 67 (void)signal(SIGALRM, SIG_IGN); 68 (void)signal(SIGHUP, SIG_IGN); 69 (void)signal(SIGINT, SIG_IGN); 70 (void)signal(SIGPIPE, SIG_IGN); 71 (void)signal(SIGQUIT, SIG_IGN); 72 (void)signal(SIGTERM, SIG_IGN); 73 (void)signal(SIGCONT, pw_cont); 74 75 /* Create with exact permissions. */ 76 (void)umask(0); 77 } 78 79 int 80 pw_lock() 81 { 82 /* 83 * If the master password file doesn't exist, the system is hosed. 84 * Might as well try to build one. Set the close-on-exec bit so 85 * that users can't get at the encrypted passwords while editing. 86 * Open should allow flock'ing the file; see 4.4BSD. XXX 87 */ 88 lockfd = open(_PATH_MASTERPASSWD, O_RDONLY, 0); 89 if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1) 90 err(1, "%s", _PATH_MASTERPASSWD); 91 if (flock(lockfd, LOCK_EX|LOCK_NB)) 92 errx(1, "the password db file is busy"); 93 return (lockfd); 94 } 95 96 int 97 pw_tmp() 98 { 99 static char path[MAXPATHLEN] = _PATH_MASTERPASSWD; 100 int fd; 101 char *p; 102 103 if (p = strrchr(path, '/')) 104 ++p; 105 else 106 p = path; 107 strcpy(p, "pw.XXXXXX"); 108 if ((fd = mkstemp(path)) == -1) 109 err(1, "%s", path); 110 tempname = path; 111 return (fd); 112 } 113 114 int 115 pw_mkdb() 116 { 117 int pstat; 118 pid_t pid; 119 120 warnx("rebuilding the database..."); 121 (void)fflush(stderr); 122 if (!(pid = vfork())) { 123 execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", tempname, NULL); 124 pw_error(_PATH_PWD_MKDB, 1, 1); 125 } 126 pid = waitpid(pid, &pstat, 0); 127 if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0) 128 return (0); 129 warnx("done"); 130 return (1); 131 } 132 133 void 134 pw_edit(notsetuid) 135 int notsetuid; 136 { 137 int pstat; 138 char *p, *editor; 139 140 if (!(editor = getenv("EDITOR"))) 141 editor = _PATH_VI; 142 if (p = strrchr(editor, '/')) 143 ++p; 144 else 145 p = editor; 146 147 if (!(editpid = vfork())) { 148 if (notsetuid) { 149 (void)setgid(getgid()); 150 (void)setuid(getuid()); 151 } 152 execlp(editor, p, tempname, NULL); 153 _exit(1); 154 } 155 for (;;) { 156 editpid = waitpid(editpid, (int *)&pstat, WUNTRACED); 157 if (editpid == -1) 158 pw_error(editor, 1, 1); 159 else if (WIFSTOPPED(pstat)) 160 raise(WSTOPSIG(pstat)); 161 else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0) 162 break; 163 else 164 pw_error(editor, 1, 1); 165 } 166 editpid = -1; 167 } 168 169 void 170 pw_prompt() 171 { 172 int c; 173 174 (void)printf("re-edit the password file? [y]: "); 175 (void)fflush(stdout); 176 c = getchar(); 177 if (c != EOF && c != '\n') 178 while (getchar() != '\n'); 179 if (c == 'n') 180 pw_error(NULL, 0, 0); 181 } 182 183 void 184 pw_error(name, err, eval) 185 char *name; 186 int err, eval; 187 { 188 if (err) 189 warn(name); 190 191 warnx("%s: unchanged", _PATH_MASTERPASSWD); 192 (void)unlink(tempname); 193 exit(eval); 194 } 195