1*fed231abSmillert /* $OpenBSD: skeyaudit.c,v 1.9 2000/08/20 18:42:40 millert Exp $ */ 2c2ff5ecdSmillert 3c2ff5ecdSmillert /* 4*fed231abSmillert * Copyright (c) 1997, 2000 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. 28c2ff5ecdSmillert */ 29c2ff5ecdSmillert 30*fed231abSmillert #include <sys/param.h> 31*fed231abSmillert #include <sys/wait.h> 32*fed231abSmillert 330165dd6fSmillert #include <err.h> 340165dd6fSmillert #include <errno.h> 350165dd6fSmillert #include <limits.h> 36*fed231abSmillert #include <login_cap.h> 370165dd6fSmillert #include <paths.h> 380165dd6fSmillert #include <pwd.h> 390165dd6fSmillert #include <stdio.h> 400165dd6fSmillert #include <stdlib.h> 410165dd6fSmillert #include <string.h> 420165dd6fSmillert #include <unistd.h> 430165dd6fSmillert #include <skey.h> 440165dd6fSmillert 450165dd6fSmillert extern char *__progname; 460165dd6fSmillert 47*fed231abSmillert void notify __P((struct passwd *, int, int)); 48*fed231abSmillert FILE *runsendmail __P((struct passwd *, int *)); 490165dd6fSmillert void usage __P((void)); 500165dd6fSmillert 510165dd6fSmillert int 520165dd6fSmillert main(argc, argv) 530165dd6fSmillert int argc; 540165dd6fSmillert char **argv; 550165dd6fSmillert { 560165dd6fSmillert struct passwd *pw; 570165dd6fSmillert struct skey key; 58d4eb3024Smillert int ch, errs = 0, left = 0, aflag = 0, iflag = 0, limit = 12; 59d4eb3024Smillert char *name; 600165dd6fSmillert 61d4eb3024Smillert if (geteuid() != 0) 62d4eb3024Smillert errx(1, "must be setuid root"); 63d4eb3024Smillert 64d4eb3024Smillert while ((ch = getopt(argc, argv, "ail:")) != -1) 650165dd6fSmillert switch(ch) { 66d4eb3024Smillert case 'a': 67d4eb3024Smillert aflag = 1; 68d4eb3024Smillert if (getuid() != 0) 69d4eb3024Smillert errx(1, "only root may use the -a flag"); 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 870165dd6fSmillert if (argc - optind > 0) 880165dd6fSmillert usage(); 890165dd6fSmillert 90d4eb3024Smillert /* Need key.keyfile zero'd at the very least */ 91d4eb3024Smillert (void)memset(&key, 0, sizeof(key)); 92d4eb3024Smillert 93d4eb3024Smillert if (aflag) { 94d4eb3024Smillert while ((ch = skeygetnext(&key)) == 0) { 95d4eb3024Smillert left = key.n - 1; 96d4eb3024Smillert if ((pw = getpwnam(key.logname)) == NULL) 97d4eb3024Smillert continue; 98d4eb3024Smillert if (left >= limit) 99d4eb3024Smillert continue; 100*fed231abSmillert notify(pw, left, iflag); 101d4eb3024Smillert } 102d4eb3024Smillert if (ch == -1) 103d4eb3024Smillert errx(-1, "cannot open %s", _PATH_SKEYKEYS); 104d4eb3024Smillert else 105d4eb3024Smillert (void)fclose(key.keyfile); 106d4eb3024Smillert } else { 1070165dd6fSmillert if ((pw = getpwuid(getuid())) == NULL) 1080165dd6fSmillert errx(1, "no passwd entry for uid %u", getuid()); 1090165dd6fSmillert if ((name = strdup(pw->pw_name)) == NULL) 1100165dd6fSmillert err(1, "cannot allocate memory"); 1110165dd6fSmillert sevenbit(name); 1120165dd6fSmillert 1130165dd6fSmillert errs = skeylookup(&key, name); 1140165dd6fSmillert switch (errs) { 1150165dd6fSmillert case 0: /* Success! */ 1160165dd6fSmillert left = key.n - 1; 1170165dd6fSmillert break; 1180165dd6fSmillert case -1: /* File error */ 119d4eb3024Smillert errx(errs, "cannot open %s", _PATH_SKEYKEYS); 1200165dd6fSmillert break; 1210165dd6fSmillert case 1: /* Unknown user */ 122d4eb3024Smillert warnx("%s is not listed in %s", name, 123d4eb3024Smillert _PATH_SKEYKEYS); 1240165dd6fSmillert } 12542cc5412Smillert (void)fclose(key.keyfile); 1260165dd6fSmillert 127d4eb3024Smillert if (!errs && left < limit) 128*fed231abSmillert notify(pw, left, iflag); 1290165dd6fSmillert } 1300165dd6fSmillert 131d4eb3024Smillert exit(errs); 132d4eb3024Smillert } 133d4eb3024Smillert 134d4eb3024Smillert void 135*fed231abSmillert notify(pw, seq, interactive) 136*fed231abSmillert struct passwd *pw; 137d4eb3024Smillert int seq; 138d4eb3024Smillert int interactive; 139d4eb3024Smillert { 140d4eb3024Smillert static char hostname[MAXHOSTNAMELEN]; 141d4eb3024Smillert int pid; 142d4eb3024Smillert FILE *out; 143d4eb3024Smillert 144d4eb3024Smillert /* Only set this once */ 145d4eb3024Smillert if (hostname[0] == '\0' && gethostname(hostname, sizeof(hostname)) == -1) 146d4eb3024Smillert strcpy(hostname, "unknown"); 147d4eb3024Smillert 148d4eb3024Smillert if (interactive) 149d4eb3024Smillert out = stdout; 150d4eb3024Smillert else 151*fed231abSmillert out = runsendmail(pw, &pid); 152d4eb3024Smillert 153d4eb3024Smillert if (!interactive) 1540165dd6fSmillert (void)fprintf(out, 155*fed231abSmillert "To: %s\nSubject: IMPORTANT action required\n", pw->pw_name); 1560165dd6fSmillert 1570165dd6fSmillert (void)fprintf(out, 1580165dd6fSmillert "\nYou are nearing the end of your current S/Key sequence for account\n\ 1590165dd6fSmillert %s on system %s.\n\n\ 1600165dd6fSmillert Your S/key sequence number is now %d. When it reaches zero\n\ 1610165dd6fSmillert you will no longer be able to use S/Key to login into the system.\n\n\ 1620165dd6fSmillert Type \"skeyinit -s\" to reinitialize your sequence number.\n\n", 163*fed231abSmillert pw->pw_name, hostname, seq); 1640165dd6fSmillert 1650165dd6fSmillert (void)fclose(out); 166d4eb3024Smillert if (!interactive) 167d4eb3024Smillert (void)waitpid(pid, NULL, 0); 1680165dd6fSmillert } 1690165dd6fSmillert 170d4eb3024Smillert FILE * 171*fed231abSmillert runsendmail(pw, pidp) 172*fed231abSmillert struct passwd *pw; 173d4eb3024Smillert int *pidp; 174d4eb3024Smillert { 175d4eb3024Smillert FILE *fp; 176d4eb3024Smillert int pfd[2], pid; 177d4eb3024Smillert 178d4eb3024Smillert if (pipe(pfd) < 0) 179d4eb3024Smillert return(NULL); 180d4eb3024Smillert 181d4eb3024Smillert switch (pid = fork()) { 182d4eb3024Smillert case -1: /* fork(2) failed */ 183d4eb3024Smillert (void)close(pfd[0]); 184d4eb3024Smillert (void)close(pfd[1]); 185d4eb3024Smillert return(NULL); 186d4eb3024Smillert case 0: /* In child */ 187d4eb3024Smillert (void)close(pfd[1]); 188d4eb3024Smillert (void)dup2(pfd[0], STDIN_FILENO); 189d4eb3024Smillert (void)close(pfd[0]); 190d4eb3024Smillert 191d4eb3024Smillert /* Run sendmail as target user not root */ 192*fed231abSmillert if (setusercontext(NULL, pw, pw->pw_uid, LOGIN_SETALL) != 0) { 193*fed231abSmillert warn("cannot set user context"); 194*fed231abSmillert _exit(127); 195*fed231abSmillert } 196d4eb3024Smillert 197d4eb3024Smillert execl(_PATH_SENDMAIL, "sendmail", "-t", NULL); 198d4eb3024Smillert warn("cannot run \"%s -t\"", _PATH_SENDMAIL); 199d4eb3024Smillert _exit(127); 200d4eb3024Smillert } 201d4eb3024Smillert 202d4eb3024Smillert /* In parent */ 203d4eb3024Smillert *pidp = pid; 204d4eb3024Smillert fp = fdopen(pfd[1], "w"); 205d4eb3024Smillert (void)close(pfd[0]); 206d4eb3024Smillert 207d4eb3024Smillert return(fp); 208d4eb3024Smillert } 2090165dd6fSmillert void 2100165dd6fSmillert usage() 2110165dd6fSmillert { 2120165dd6fSmillert (void)fprintf(stderr, "Usage: %s [-i] [-l limit]\n", 2130165dd6fSmillert __progname); 2140165dd6fSmillert exit(1); 2150165dd6fSmillert } 216