xref: /openbsd/usr.bin/skeyaudit/skeyaudit.c (revision 3b08765c)
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