1*3b08765cSmillert /* $OpenBSD: skeyaudit.c,v 1.19 2003/05/06 15:34:08 millert Exp $ */ 2c2ff5ecdSmillert 3c2ff5ecdSmillert /* 43adef2e4Smillert * Copyright (c) 1997, 2000, 2003 Todd C. Miller <Todd.Miller@courtesan.com> 5c2ff5ecdSmillert * All rights reserved. 6c2ff5ecdSmillert * 7c2ff5ecdSmillert * Redistribution and use in source and binary forms, with or without 8c2ff5ecdSmillert * modification, are permitted provided that the following conditions 9c2ff5ecdSmillert * are met: 10c2ff5ecdSmillert * 1. Redistributions of source code must retain the above copyright 11c2ff5ecdSmillert * notice, this list of conditions and the following disclaimer. 12c2ff5ecdSmillert * 2. Redistributions in binary form must reproduce the above copyright 13c2ff5ecdSmillert * notice, this list of conditions and the following disclaimer in the 14c2ff5ecdSmillert * documentation and/or other materials provided with the distribution. 159141dda3Smillert * 3. The name of the author may not be used to endorse or promote products 16c2ff5ecdSmillert * derived from this software without specific prior written permission. 17c2ff5ecdSmillert * 18c2ff5ecdSmillert * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 19c2ff5ecdSmillert * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 20c2ff5ecdSmillert * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21c2ff5ecdSmillert * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22c2ff5ecdSmillert * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23c2ff5ecdSmillert * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 24c2ff5ecdSmillert * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25c2ff5ecdSmillert * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26c2ff5ecdSmillert * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 27c2ff5ecdSmillert * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 283adef2e4Smillert * 293adef2e4Smillert * Sponsored in part by the Defense Advanced Research Projects 303adef2e4Smillert * Agency (DARPA) and Air Force Research Laboratory, Air Force 313adef2e4Smillert * Materiel Command, USAF, under agreement number F39502-99-1-0512. 32c2ff5ecdSmillert */ 33c2ff5ecdSmillert 34fed231abSmillert #include <sys/param.h> 35fed231abSmillert #include <sys/wait.h> 36fed231abSmillert 370165dd6fSmillert #include <err.h> 380165dd6fSmillert #include <errno.h> 393adef2e4Smillert #include <fcntl.h> 400165dd6fSmillert #include <limits.h> 41fed231abSmillert #include <login_cap.h> 420165dd6fSmillert #include <paths.h> 430165dd6fSmillert #include <pwd.h> 440165dd6fSmillert #include <stdio.h> 450165dd6fSmillert #include <stdlib.h> 460165dd6fSmillert #include <string.h> 470165dd6fSmillert #include <unistd.h> 480165dd6fSmillert #include <skey.h> 490165dd6fSmillert 50c72b5b24Smillert void notify(struct passwd *, int, int); 51c72b5b24Smillert FILE *runsendmail(struct passwd *, int *); 528959c9bfSmillert __dead void usage(void); 530165dd6fSmillert 540165dd6fSmillert int 558959c9bfSmillert main(int argc, char **argv) 560165dd6fSmillert { 570165dd6fSmillert struct passwd *pw; 580165dd6fSmillert struct skey key; 59d4eb3024Smillert char *name; 608959c9bfSmillert int ch, left, aflag, iflag, limit; 610165dd6fSmillert 623adef2e4Smillert aflag = iflag = 0; 638959c9bfSmillert limit = 12; 64d4eb3024Smillert while ((ch = getopt(argc, argv, "ail:")) != -1) 650165dd6fSmillert switch(ch) { 66d4eb3024Smillert case 'a': 67d4eb3024Smillert if (getuid() != 0) 68d4eb3024Smillert errx(1, "only root may use the -a flag"); 698959c9bfSmillert aflag = 1; 70d4eb3024Smillert break; 710165dd6fSmillert case 'i': 720165dd6fSmillert iflag = 1; 730165dd6fSmillert break; 740165dd6fSmillert case 'l': 750165dd6fSmillert errno = 0; 760165dd6fSmillert if ((limit = (int)strtol(optarg, NULL, 10)) == 0) 770165dd6fSmillert errno = ERANGE; 780165dd6fSmillert if (errno) { 790165dd6fSmillert warn("key limit"); 800165dd6fSmillert usage(); 810165dd6fSmillert } 820165dd6fSmillert break; 830165dd6fSmillert default: 840165dd6fSmillert usage(); 850165dd6fSmillert } 860165dd6fSmillert 873adef2e4Smillert /* 883adef2e4Smillert * Make sure STDIN_FILENO, STDOUT_FILENO, and STDERR_FILENO are open. 893adef2e4Smillert * If not, open /dev/null in their place or bail. 903adef2e4Smillert * If we are in interactive mode, STDOUT_FILENO *must* be open. 913adef2e4Smillert */ 923adef2e4Smillert for (ch = STDIN_FILENO; ch <= STDERR_FILENO; ch++) { 933adef2e4Smillert if (fcntl(ch, F_GETFL, &left) == -1 && errno == EBADF) { 943adef2e4Smillert if (ch == STDOUT_FILENO && iflag) 953adef2e4Smillert exit(1); /* need stdout for -i */ 963adef2e4Smillert if (open(_PATH_DEVNULL, O_RDWR, 0644) == -1) 973adef2e4Smillert exit(1); /* just bail */ 983adef2e4Smillert } 993adef2e4Smillert } 1003adef2e4Smillert 1010165dd6fSmillert if (argc - optind > 0) 1020165dd6fSmillert usage(); 1030165dd6fSmillert 104d4eb3024Smillert /* Need key.keyfile zero'd at the very least */ 105d4eb3024Smillert (void)memset(&key, 0, sizeof(key)); 106d4eb3024Smillert 1073adef2e4Smillert left = 0; 108d4eb3024Smillert if (aflag) { 109d4eb3024Smillert while ((ch = skeygetnext(&key)) == 0) { 110d4eb3024Smillert left = key.n - 1; 111d4eb3024Smillert if ((pw = getpwnam(key.logname)) == NULL) 112d4eb3024Smillert continue; 113d4eb3024Smillert if (left >= limit) 114d4eb3024Smillert continue; 1153adef2e4Smillert (void)fclose(key.keyfile); 1163adef2e4Smillert key.keyfile = NULL; 117fed231abSmillert notify(pw, left, iflag); 118d4eb3024Smillert } 119d4eb3024Smillert if (ch == -1) 120fc7f3601Smillert errx(-1, "cannot open %s", _PATH_SKEYDIR); 121d4eb3024Smillert } else { 1220165dd6fSmillert if ((pw = getpwuid(getuid())) == NULL) 1230165dd6fSmillert errx(1, "no passwd entry for uid %u", getuid()); 1240165dd6fSmillert if ((name = strdup(pw->pw_name)) == NULL) 1250165dd6fSmillert err(1, "cannot allocate memory"); 1260165dd6fSmillert sevenbit(name); 1270165dd6fSmillert 1288959c9bfSmillert switch (skeylookup(&key, name)) { 1290165dd6fSmillert case 0: /* Success! */ 1300165dd6fSmillert left = key.n - 1; 1310165dd6fSmillert break; 1320165dd6fSmillert case -1: /* File error */ 1338959c9bfSmillert errx(1, "cannot open %s/%s", _PATH_SKEYDIR, 1348959c9bfSmillert name); 1350165dd6fSmillert break; 1360165dd6fSmillert case 1: /* Unknown user */ 1378959c9bfSmillert errx(1, "user %s is not listed in %s", name, 138fc7f3601Smillert _PATH_SKEYDIR); 1390165dd6fSmillert } 14042cc5412Smillert (void)fclose(key.keyfile); 1410165dd6fSmillert 1428959c9bfSmillert if (left < limit) 143fed231abSmillert notify(pw, left, iflag); 1440165dd6fSmillert } 1450165dd6fSmillert 1468959c9bfSmillert exit(0); 147d4eb3024Smillert } 148d4eb3024Smillert 149d4eb3024Smillert void 1508959c9bfSmillert notify(struct passwd *pw, int seq, int interactive) 151d4eb3024Smillert { 152d4eb3024Smillert static char hostname[MAXHOSTNAMELEN]; 1538959c9bfSmillert pid_t pid; 154d4eb3024Smillert FILE *out; 155d4eb3024Smillert 156d4eb3024Smillert /* Only set this once */ 157d4eb3024Smillert if (hostname[0] == '\0' && gethostname(hostname, sizeof(hostname)) == -1) 15821a5bbfaSmillert strlcpy(hostname, "unknown", sizeof(hostname)); 159d4eb3024Smillert 160d4eb3024Smillert if (interactive) 161d4eb3024Smillert out = stdout; 162d4eb3024Smillert else 163fed231abSmillert out = runsendmail(pw, &pid); 164d4eb3024Smillert 165d4eb3024Smillert if (!interactive) 1660165dd6fSmillert (void)fprintf(out, 167fed231abSmillert "To: %s\nSubject: IMPORTANT action required\n", pw->pw_name); 1680165dd6fSmillert 169188a098fSpjanzen if (seq) 1700165dd6fSmillert (void)fprintf(out, 1710165dd6fSmillert "\nYou are nearing the end of your current S/Key sequence for account\n\ 1720165dd6fSmillert %s on system %s.\n\n\ 173188a098fSpjanzen Your S/Key sequence number is now %d. When it reaches zero\n\ 174188a098fSpjanzen you will no longer be able to use S/Key to log into the system.\n\n", 175fed231abSmillert pw->pw_name, hostname, seq); 176188a098fSpjanzen else 177188a098fSpjanzen (void)fprintf(out, 178188a098fSpjanzen "\nYou are at the end of your current S/Key sequence for account\n\ 179188a098fSpjanzen %s on system %s.\n\n\ 180188a098fSpjanzen At this point you can no longer use S/Key to log into the system.\n\n", 181188a098fSpjanzen pw->pw_name, hostname); 182188a098fSpjanzen (void)fprintf(out, 183188a098fSpjanzen "Type \"skeyinit -s\" to reinitialize your sequence number.\n\n"); 1840165dd6fSmillert 1853adef2e4Smillert if (!interactive) { 1860165dd6fSmillert (void)fclose(out); 187d4eb3024Smillert (void)waitpid(pid, NULL, 0); 1880165dd6fSmillert } 1893adef2e4Smillert } 1900165dd6fSmillert 191d4eb3024Smillert FILE * 1928959c9bfSmillert runsendmail(struct passwd *pw, pid_t *pidp) 193d4eb3024Smillert { 194d4eb3024Smillert FILE *fp; 1958959c9bfSmillert int pfd[2]; 1968959c9bfSmillert pid_t pid; 197d4eb3024Smillert 198d4eb3024Smillert if (pipe(pfd) < 0) 199d4eb3024Smillert return(NULL); 200d4eb3024Smillert 201d4eb3024Smillert switch (pid = fork()) { 202d4eb3024Smillert case -1: /* fork(2) failed */ 203d4eb3024Smillert (void)close(pfd[0]); 204d4eb3024Smillert (void)close(pfd[1]); 205d4eb3024Smillert return(NULL); 206d4eb3024Smillert case 0: /* In child */ 207d4eb3024Smillert (void)close(pfd[1]); 208d4eb3024Smillert (void)dup2(pfd[0], STDIN_FILENO); 209d4eb3024Smillert (void)close(pfd[0]); 210d4eb3024Smillert 211d4eb3024Smillert /* Run sendmail as target user not root */ 212*3b08765cSmillert if (getuid() == 0 && 213*3b08765cSmillert setusercontext(NULL, pw, pw->pw_uid, LOGIN_SETALL) != 0) { 214fed231abSmillert warn("cannot set user context"); 215fed231abSmillert _exit(127); 216fed231abSmillert } 217d4eb3024Smillert 218c96f6a27Sderaadt execl(_PATH_SENDMAIL, "sendmail", "-t", (char *)NULL); 219d4eb3024Smillert warn("cannot run \"%s -t\"", _PATH_SENDMAIL); 220d4eb3024Smillert _exit(127); 221d4eb3024Smillert } 222d4eb3024Smillert 223d4eb3024Smillert /* In parent */ 224d4eb3024Smillert *pidp = pid; 225d4eb3024Smillert fp = fdopen(pfd[1], "w"); 226d4eb3024Smillert (void)close(pfd[0]); 227d4eb3024Smillert 228d4eb3024Smillert return(fp); 229d4eb3024Smillert } 2308959c9bfSmillert 2318959c9bfSmillert __dead void 2328959c9bfSmillert usage(void) 2330165dd6fSmillert { 2348959c9bfSmillert extern char *__progname; 2358959c9bfSmillert 2362e2d720aSmpech (void)fprintf(stderr, "Usage: %s [-a] [-i] [-l limit]\n", 2370165dd6fSmillert __progname); 2380165dd6fSmillert exit(1); 2390165dd6fSmillert } 240