1*3aaa63ebSderaadt /* $OpenBSD: skeyaudit.c,v 1.29 2019/06/28 13:35:03 deraadt Exp $ */
2c2ff5ecdSmillert
3c2ff5ecdSmillert /*
4bf198cc6Smillert * Copyright (c) 1997, 2000, 2003 Todd C. Miller <millert@openbsd.org>
5c2ff5ecdSmillert *
606f01696Smillert * Permission to use, copy, modify, and distribute this software for any
706f01696Smillert * purpose with or without fee is hereby granted, provided that the above
806f01696Smillert * copyright notice and this permission notice appear in all copies.
9c2ff5ecdSmillert *
1006f01696Smillert * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL
1106f01696Smillert * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
1206f01696Smillert * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE
1306f01696Smillert * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1406f01696Smillert * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
1506f01696Smillert * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
1606f01696Smillert * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
173adef2e4Smillert *
183adef2e4Smillert * Sponsored in part by the Defense Advanced Research Projects
193adef2e4Smillert * Agency (DARPA) and Air Force Research Laboratory, Air Force
203adef2e4Smillert * Materiel Command, USAF, under agreement number F39502-99-1-0512.
21c2ff5ecdSmillert */
22c2ff5ecdSmillert
23fed231abSmillert #include <sys/wait.h>
24fed231abSmillert
250165dd6fSmillert #include <err.h>
260165dd6fSmillert #include <errno.h>
273adef2e4Smillert #include <fcntl.h>
280165dd6fSmillert #include <limits.h>
29fed231abSmillert #include <login_cap.h>
300165dd6fSmillert #include <paths.h>
310165dd6fSmillert #include <pwd.h>
320165dd6fSmillert #include <stdio.h>
330165dd6fSmillert #include <stdlib.h>
340165dd6fSmillert #include <string.h>
350165dd6fSmillert #include <unistd.h>
360165dd6fSmillert #include <skey.h>
370165dd6fSmillert
38c72b5b24Smillert void notify(struct passwd *, int, int);
39426a6f8cSkrw void sanitise_stdfd(void);
40c72b5b24Smillert FILE *runsendmail(struct passwd *, int *);
418959c9bfSmillert __dead void usage(void);
420165dd6fSmillert
43426a6f8cSkrw void
sanitise_stdfd(void)44426a6f8cSkrw sanitise_stdfd(void)
45426a6f8cSkrw {
46426a6f8cSkrw int nullfd, dupfd;
47426a6f8cSkrw
48426a6f8cSkrw if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
49426a6f8cSkrw fprintf(stderr, "Couldn't open /dev/null: %s\n",
50426a6f8cSkrw strerror(errno));
51426a6f8cSkrw exit(1);
52426a6f8cSkrw }
53426a6f8cSkrw while (++dupfd <= STDERR_FILENO) {
54426a6f8cSkrw /* Only populate closed fds. */
55426a6f8cSkrw if (fcntl(dupfd, F_GETFL) == -1 && errno == EBADF) {
56426a6f8cSkrw if (dup2(nullfd, dupfd) == -1) {
57426a6f8cSkrw fprintf(stderr, "dup2: %s\n", strerror(errno));
58426a6f8cSkrw exit(1);
59426a6f8cSkrw }
60426a6f8cSkrw }
61426a6f8cSkrw }
62426a6f8cSkrw if (nullfd > STDERR_FILENO)
63426a6f8cSkrw close(nullfd);
64426a6f8cSkrw }
65426a6f8cSkrw
660165dd6fSmillert int
main(int argc,char ** argv)678959c9bfSmillert main(int argc, char **argv)
680165dd6fSmillert {
690165dd6fSmillert struct passwd *pw;
700165dd6fSmillert struct skey key;
71d4eb3024Smillert char *name;
728959c9bfSmillert int ch, left, aflag, iflag, limit;
730165dd6fSmillert
7449afeee2Stim if (pledge("stdio rpath wpath flock getpw proc exec id", NULL) == -1)
7549afeee2Stim err(1, "pledge");
7649afeee2Stim
773adef2e4Smillert aflag = iflag = 0;
788959c9bfSmillert limit = 12;
79d4eb3024Smillert while ((ch = getopt(argc, argv, "ail:")) != -1)
800165dd6fSmillert switch(ch) {
81d4eb3024Smillert case 'a':
82d4eb3024Smillert if (getuid() != 0)
83d4eb3024Smillert errx(1, "only root may use the -a flag");
848959c9bfSmillert aflag = 1;
85d4eb3024Smillert break;
860165dd6fSmillert case 'i':
870165dd6fSmillert iflag = 1;
880165dd6fSmillert break;
890165dd6fSmillert case 'l':
900165dd6fSmillert errno = 0;
910165dd6fSmillert if ((limit = (int)strtol(optarg, NULL, 10)) == 0)
920165dd6fSmillert errno = ERANGE;
930165dd6fSmillert if (errno) {
940165dd6fSmillert warn("key limit");
950165dd6fSmillert usage();
960165dd6fSmillert }
970165dd6fSmillert break;
980165dd6fSmillert default:
990165dd6fSmillert usage();
1000165dd6fSmillert }
1010165dd6fSmillert
10249afeee2Stim if (iflag) {
10349afeee2Stim if (pledge("stdio rpath wpath flock getpw", NULL) == -1)
10449afeee2Stim err(1, "pledge");
10549afeee2Stim }
10649afeee2Stim
107426a6f8cSkrw /* If we are in interactive mode, STDOUT_FILENO *must* be open. */
108426a6f8cSkrw if (iflag && fcntl(STDOUT_FILENO, F_GETFL) == -1 && errno == EBADF)
109426a6f8cSkrw exit(1);
110426a6f8cSkrw
1113adef2e4Smillert /*
1123adef2e4Smillert * Make sure STDIN_FILENO, STDOUT_FILENO, and STDERR_FILENO are open.
1133adef2e4Smillert * If not, open /dev/null in their place or bail.
1143adef2e4Smillert */
115426a6f8cSkrw sanitise_stdfd();
1163adef2e4Smillert
1170165dd6fSmillert if (argc - optind > 0)
1180165dd6fSmillert usage();
1190165dd6fSmillert
120d4eb3024Smillert /* Need key.keyfile zero'd at the very least */
121d4eb3024Smillert (void)memset(&key, 0, sizeof(key));
122d4eb3024Smillert
1233adef2e4Smillert left = 0;
124d4eb3024Smillert if (aflag) {
125d4eb3024Smillert while ((ch = skeygetnext(&key)) == 0) {
126d4eb3024Smillert left = key.n - 1;
127d4eb3024Smillert if ((pw = getpwnam(key.logname)) == NULL)
128d4eb3024Smillert continue;
129d4eb3024Smillert if (left >= limit)
130d4eb3024Smillert continue;
1313adef2e4Smillert (void)fclose(key.keyfile);
1323adef2e4Smillert key.keyfile = NULL;
133fed231abSmillert notify(pw, left, iflag);
134d4eb3024Smillert }
135d4eb3024Smillert if (ch == -1)
136fc7f3601Smillert errx(-1, "cannot open %s", _PATH_SKEYDIR);
137d4eb3024Smillert } else {
1380165dd6fSmillert if ((pw = getpwuid(getuid())) == NULL)
1390165dd6fSmillert errx(1, "no passwd entry for uid %u", getuid());
1400165dd6fSmillert if ((name = strdup(pw->pw_name)) == NULL)
1410165dd6fSmillert err(1, "cannot allocate memory");
1420165dd6fSmillert sevenbit(name);
1430165dd6fSmillert
1448959c9bfSmillert switch (skeylookup(&key, name)) {
1450165dd6fSmillert case 0: /* Success! */
1460165dd6fSmillert left = key.n - 1;
1470165dd6fSmillert break;
1480165dd6fSmillert case -1: /* File error */
1498959c9bfSmillert errx(1, "cannot open %s/%s", _PATH_SKEYDIR,
1508959c9bfSmillert name);
1510165dd6fSmillert break;
1520165dd6fSmillert case 1: /* Unknown user */
1538959c9bfSmillert errx(1, "user %s is not listed in %s", name,
154fc7f3601Smillert _PATH_SKEYDIR);
1550165dd6fSmillert }
15642cc5412Smillert (void)fclose(key.keyfile);
1570165dd6fSmillert
1588959c9bfSmillert if (left < limit)
159fed231abSmillert notify(pw, left, iflag);
1600165dd6fSmillert }
1610165dd6fSmillert
1628959c9bfSmillert exit(0);
163d4eb3024Smillert }
164d4eb3024Smillert
165d4eb3024Smillert void
notify(struct passwd * pw,int seq,int interactive)1668959c9bfSmillert notify(struct passwd *pw, int seq, int interactive)
167d4eb3024Smillert {
168b9fc9a72Sderaadt static char hostname[HOST_NAME_MAX+1];
1698959c9bfSmillert pid_t pid;
170d4eb3024Smillert FILE *out;
171d4eb3024Smillert
172d4eb3024Smillert /* Only set this once */
173d4eb3024Smillert if (hostname[0] == '\0' && gethostname(hostname, sizeof(hostname)) == -1)
17421a5bbfaSmillert strlcpy(hostname, "unknown", sizeof(hostname));
175d4eb3024Smillert
176d4eb3024Smillert if (interactive)
177d4eb3024Smillert out = stdout;
178d4eb3024Smillert else
179fed231abSmillert out = runsendmail(pw, &pid);
180d4eb3024Smillert
181d4eb3024Smillert if (!interactive)
1820165dd6fSmillert (void)fprintf(out,
183775a2683Sderaadt "Auto-Submitted: auto-generated\n"
184fed231abSmillert "To: %s\nSubject: IMPORTANT action required\n", pw->pw_name);
1850165dd6fSmillert
186188a098fSpjanzen if (seq)
1870165dd6fSmillert (void)fprintf(out,
1880165dd6fSmillert "\nYou are nearing the end of your current S/Key sequence for account\n\
1890165dd6fSmillert %s on system %s.\n\n\
190188a098fSpjanzen Your S/Key sequence number is now %d. When it reaches zero\n\
191188a098fSpjanzen you will no longer be able to use S/Key to log into the system.\n\n",
192fed231abSmillert pw->pw_name, hostname, seq);
193188a098fSpjanzen else
194188a098fSpjanzen (void)fprintf(out,
195188a098fSpjanzen "\nYou are at the end of your current S/Key sequence for account\n\
196188a098fSpjanzen %s on system %s.\n\n\
197188a098fSpjanzen At this point you can no longer use S/Key to log into the system.\n\n",
198188a098fSpjanzen pw->pw_name, hostname);
199188a098fSpjanzen (void)fprintf(out,
200188a098fSpjanzen "Type \"skeyinit -s\" to reinitialize your sequence number.\n\n");
2010165dd6fSmillert
2023adef2e4Smillert if (!interactive) {
2030165dd6fSmillert (void)fclose(out);
204d4eb3024Smillert (void)waitpid(pid, NULL, 0);
2050165dd6fSmillert }
2063adef2e4Smillert }
2070165dd6fSmillert
208d4eb3024Smillert FILE *
runsendmail(struct passwd * pw,pid_t * pidp)2098959c9bfSmillert runsendmail(struct passwd *pw, pid_t *pidp)
210d4eb3024Smillert {
211d4eb3024Smillert FILE *fp;
2128959c9bfSmillert int pfd[2];
2138959c9bfSmillert pid_t pid;
214d4eb3024Smillert
215*3aaa63ebSderaadt if (pipe(pfd) == -1)
216d4eb3024Smillert return(NULL);
217d4eb3024Smillert
218d4eb3024Smillert switch (pid = fork()) {
219d4eb3024Smillert case -1: /* fork(2) failed */
220d4eb3024Smillert (void)close(pfd[0]);
221d4eb3024Smillert (void)close(pfd[1]);
222d4eb3024Smillert return(NULL);
223d4eb3024Smillert case 0: /* In child */
224d4eb3024Smillert (void)close(pfd[1]);
225d4eb3024Smillert (void)dup2(pfd[0], STDIN_FILENO);
226d4eb3024Smillert (void)close(pfd[0]);
227d4eb3024Smillert
228d4eb3024Smillert /* Run sendmail as target user not root */
2293b08765cSmillert if (getuid() == 0 &&
2303b08765cSmillert setusercontext(NULL, pw, pw->pw_uid, LOGIN_SETALL) != 0) {
231fed231abSmillert warn("cannot set user context");
232fed231abSmillert _exit(127);
233fed231abSmillert }
234d4eb3024Smillert
235c96f6a27Sderaadt execl(_PATH_SENDMAIL, "sendmail", "-t", (char *)NULL);
236d4eb3024Smillert warn("cannot run \"%s -t\"", _PATH_SENDMAIL);
237d4eb3024Smillert _exit(127);
238d4eb3024Smillert }
239d4eb3024Smillert
240d4eb3024Smillert /* In parent */
241d4eb3024Smillert *pidp = pid;
242d4eb3024Smillert fp = fdopen(pfd[1], "w");
243d4eb3024Smillert (void)close(pfd[0]);
244d4eb3024Smillert
245d4eb3024Smillert return(fp);
246d4eb3024Smillert }
2478959c9bfSmillert
2488959c9bfSmillert __dead void
usage(void)2498959c9bfSmillert usage(void)
2500165dd6fSmillert {
2518959c9bfSmillert extern char *__progname;
2528959c9bfSmillert
253a9050c90Ssobrado (void)fprintf(stderr, "usage: %s [-ai] [-l limit]\n",
2540165dd6fSmillert __progname);
2550165dd6fSmillert exit(1);
2560165dd6fSmillert }
257