Annotation of src/usr.bin/calendar/calendar.c, Revision 1.37
1.37 ! millert 1: /* $OpenBSD: calendar.c,v 1.36 2019/01/29 20:08:56 millert Exp $ */
1.1 deraadt 2:
3: /*
4: * Copyright (c) 1989, 1993, 1994
5: * The Regents of the University of California. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
1.20 millert 15: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
31:
1.15 pjanzen 32: #include <sys/stat.h>
33: #include <sys/types.h>
34: #include <sys/wait.h>
1.1 deraadt 35: #include <err.h>
36: #include <errno.h>
1.5 millert 37: #include <locale.h>
1.15 pjanzen 38: #include <login_cap.h>
1.1 deraadt 39: #include <pwd.h>
1.15 pjanzen 40: #include <signal.h>
1.1 deraadt 41: #include <stdio.h>
42: #include <stdlib.h>
43: #include <string.h>
1.31 deraadt 44: #include <limits.h>
1.5 millert 45: #include <time.h>
1.1 deraadt 46: #include <unistd.h>
47:
48: #include "pathnames.h"
1.5 millert 49: #include "calendar.h"
1.1 deraadt 50:
1.15 pjanzen 51: char *calendarFile = "calendar"; /* default calendar file */
52: char *calendarHome = ".calendar"; /* HOME */
53: char *calendarNoMail = "nomail"; /* don't sent mail if this file exists */
54:
1.1 deraadt 55: struct passwd *pw;
1.5 millert 56: int doall = 0;
1.35 espie 57: int daynames = 0;
1.5 millert 58: time_t f_time = 0;
1.16 mickey 59: int bodun_always = 0;
1.1 deraadt 60:
1.37 ! millert 61: int f_dayAfter = 0; /* days after current date */
! 62: int f_dayBefore = 0; /* days before current date */
! 63: int f_Setday = 0; /* calendar invoked with -A or -B */
1.1 deraadt 64:
1.12 pjanzen 65: struct specialev spev[NUMEV];
66:
1.17 millert 67: void childsig(int);
1.15 pjanzen 68:
1.1 deraadt 69: int
1.21 deraadt 70: main(int argc, char *argv[])
1.1 deraadt 71: {
1.15 pjanzen 72: int ch;
1.31 deraadt 73: const char *errstr;
1.1 deraadt 74: char *caldir;
75:
1.12 pjanzen 76: (void)setlocale(LC_ALL, "");
1.5 millert 77:
1.35 espie 78: while ((ch = getopt(argc, argv, "abwf:t:A:B:-")) != -1)
1.1 deraadt 79: switch (ch) {
80: case '-': /* backward contemptible */
81: case 'a':
1.5 millert 82: if (getuid())
1.13 millert 83: errx(1, "%s", strerror(EPERM));
1.1 deraadt 84: doall = 1;
85: break;
1.5 millert 86:
1.16 mickey 87: case 'b':
1.29 deraadt 88: bodun_always = 1;
1.16 mickey 89: break;
90:
1.5 millert 91: case 'f': /* other calendar file */
92: calendarFile = optarg;
93: break;
94:
95: case 't': /* other date, undocumented, for tests */
1.12 pjanzen 96: if ((f_time = Mktime(optarg)) <= 0)
1.11 pjanzen 97: errx(1, "specified date is outside allowed range");
1.5 millert 98: break;
99:
100: case 'A': /* days after current date */
1.31 deraadt 101: f_dayAfter = strtonum(optarg, 0, INT_MAX, &errstr);
102: if (errstr)
103: errx(1, "-A %s: %s", optarg, errstr);
1.37 ! millert 104: f_Setday = 1;
1.5 millert 105: break;
106:
107: case 'B': /* days before current date */
1.31 deraadt 108: f_dayBefore = strtonum(optarg, 0, INT_MAX, &errstr);
109: if (errstr)
110: errx(1, "-B %s: %s", optarg, errstr);
1.37 ! millert 111: if (f_dayBefore != 0)
! 112: f_Setday = 1;
1.5 millert 113: break;
114:
1.35 espie 115: case 'w':
116: daynames = 1;
117: break;
118:
1.1 deraadt 119: default:
120: usage();
121: }
122: argc -= optind;
123: argv += optind;
124:
125: if (argc)
126: usage();
1.33 pascal 127:
128: if (doall) {
1.34 semarie 129: if (pledge("stdio rpath tmppath fattr getpw id proc exec", NULL)
1.33 pascal 130: == -1)
131: err(1, "pledge");
132: } else {
133: if (pledge("stdio rpath proc exec", NULL) == -1)
134: err(1, "pledge");
135: }
1.1 deraadt 136:
1.5 millert 137: /* use current time */
138: if (f_time <= 0)
139: (void)time(&f_time);
140:
1.12 pjanzen 141: if (f_dayBefore) {
142: /* Move back in time and only look forwards */
143: f_dayAfter += f_dayBefore;
144: f_time -= SECSPERDAY * f_dayBefore;
145: f_dayBefore = 0;
146: }
147: settime(&f_time);
1.5 millert 148:
1.10 millert 149: if (doall) {
1.15 pjanzen 150: pid_t kid, deadkid;
151: int kidstat, kidreaped, runningkids;
152: int acstat;
153: struct stat sbuf;
154: time_t t;
155: unsigned int sleeptime;
156:
157: signal(SIGCHLD, childsig);
158: runningkids = 0;
159: t = time(NULL);
1.1 deraadt 160: while ((pw = getpwent()) != NULL) {
1.15 pjanzen 161: acstat = 0;
162: /* Avoid unnecessary forks. The calendar file is only
163: * opened as the user later; if it can't be opened,
164: * it's no big deal. Also, get to correct directory.
165: * Note that in an NFS environment root may get EACCES
166: * on a chdir(), in which case we have to fork. As long as
167: * we can chdir() we can stat(), unless the user is
168: * modifying permissions while this is running.
169: */
170: if (chdir(pw->pw_dir)) {
171: if (errno == EACCES)
172: acstat = 1;
173: else
174: continue;
175: }
176: if (stat(calendarFile, &sbuf) != 0) {
177: if (chdir(calendarHome)) {
178: if (errno == EACCES)
179: acstat = 1;
180: else
181: continue;
182: }
183: if (stat(calendarNoMail, &sbuf) == 0 ||
184: stat(calendarFile, &sbuf) != 0)
185: continue;
186: }
187: sleeptime = USERTIMEOUT;
188: switch ((kid = fork())) {
189: case -1: /* error */
190: warn("fork");
191: continue;
192: case 0: /* child */
1.28 otto 193: (void)setpgid(getpid(), getpid());
1.15 pjanzen 194: (void)setlocale(LC_ALL, "");
195: if (setusercontext(NULL, pw, pw->pw_uid,
196: LOGIN_SETALL ^ LOGIN_SETLOGIN))
1.18 deraadt 197: err(1, "unable to set user context (uid %u)",
198: pw->pw_uid);
1.15 pjanzen 199: if (acstat) {
200: if (chdir(pw->pw_dir) ||
201: stat(calendarFile, &sbuf) != 0 ||
1.32 zhuk 202: chdir(calendarHome) ||
1.15 pjanzen 203: stat(calendarNoMail, &sbuf) == 0 ||
204: stat(calendarFile, &sbuf) != 0)
205: exit(0);
206: }
1.1 deraadt 207: cal();
1.15 pjanzen 208: exit(0);
209: }
210: /* parent: wait a reasonable time, then kill child if
211: * necessary.
212: */
213: runningkids++;
214: kidreaped = 0;
215: do {
216: sleeptime = sleep(sleeptime);
217: /* Note that there is the possibility, if the sleep
218: * stops early due to some other signal, of the child
219: * terminating and not getting detected during the next
220: * sleep. In that unlikely worst case, we just sleep
221: * too long for that user.
222: */
223: for (;;) {
224: deadkid = waitpid(-1, &kidstat, WNOHANG);
225: if (deadkid <= 0)
226: break;
227: runningkids--;
228: if (deadkid == kid) {
229: kidreaped = 1;
230: sleeptime = 0;
231: }
232: }
233: } while (sleeptime);
234:
235: if (!kidreaped) {
236: /* It doesn't _really_ matter if the kill fails, e.g.
237: * if there's only a zombie now.
238: */
1.28 otto 239: if (getpgid(kid) != getpgrp())
240: (void)killpg(getpgid(kid), SIGTERM);
241: else
242: (void)kill(kid, SIGTERM);
1.18 deraadt 243: warnx("uid %u did not finish in time", pw->pw_uid);
1.12 pjanzen 244: }
1.15 pjanzen 245: if (time(NULL) - t >= SECSPERDAY)
1.25 deraadt 246: errx(2, "'calendar -a' took more than a day; "
247: "stopped at uid %u",
1.18 deraadt 248: pw->pw_uid);
1.15 pjanzen 249: }
250: for (;;) {
251: deadkid = waitpid(-1, &kidstat, WNOHANG);
252: if (deadkid <= 0)
253: break;
254: runningkids--;
1.1 deraadt 255: }
1.15 pjanzen 256: if (runningkids)
1.25 deraadt 257: warnx("%d child processes still running when "
258: "'calendar -a' finished", runningkids);
259: } else if ((caldir = getenv("CALENDAR_DIR")) != NULL) {
1.5 millert 260: if(!chdir(caldir))
261: cal();
1.1 deraadt 262: } else
263: cal();
1.5 millert 264:
1.1 deraadt 265: exit(0);
266: }
267:
268:
269: void
1.21 deraadt 270: usage(void)
1.1 deraadt 271: {
1.5 millert 272: (void)fprintf(stderr,
1.35 espie 273: "usage: calendar [-abw] [-A num] [-B num] [-f calendarfile] "
1.27 jmc 274: "[-t [[[cc]yy]mm]dd]\n");
1.1 deraadt 275: exit(1);
1.15 pjanzen 276: }
277:
278:
279: void
1.21 deraadt 280: childsig(int signo)
1.15 pjanzen 281: {
1.1 deraadt 282: }