io.c revision 205821
1205821Sedwin/*- 213840Swosch * Copyright (c) 1989, 1993, 1994 313840Swosch * The Regents of the University of California. All rights reserved. 413840Swosch * 513840Swosch * Redistribution and use in source and binary forms, with or without 613840Swosch * modification, are permitted provided that the following conditions 713840Swosch * are met: 813840Swosch * 1. Redistributions of source code must retain the above copyright 913840Swosch * notice, this list of conditions and the following disclaimer. 1013840Swosch * 2. Redistributions in binary form must reproduce the above copyright 1113840Swosch * notice, this list of conditions and the following disclaimer in the 1213840Swosch * documentation and/or other materials provided with the distribution. 1313840Swosch * 3. All advertising materials mentioning features or use of this software 1413840Swosch * must display the following acknowledgement: 1513840Swosch * This product includes software developed by the University of 1613840Swosch * California, Berkeley and its contributors. 1713840Swosch * 4. Neither the name of the University nor the names of its contributors 1813840Swosch * may be used to endorse or promote products derived from this software 1913840Swosch * without specific prior written permission. 2013840Swosch * 2113840Swosch * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2213840Swosch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2313840Swosch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2413840Swosch * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2513840Swosch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2613840Swosch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2713840Swosch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2813840Swosch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2913840Swosch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3013840Swosch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3113840Swosch * SUCH DAMAGE. 3213840Swosch */ 3313840Swosch 3413840Swosch#ifndef lint 3515714Sachestatic const char copyright[] = 3613840Swosch"@(#) Copyright (c) 1989, 1993\n\ 3713840Swosch The Regents of the University of California. All rights reserved.\n"; 3887235Smarkm#endif 3913840Swosch 4087628Sdwmalone#if 0 4113840Swosch#ifndef lint 4287628Sdwmalonestatic char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94"; 4387235Smarkm#endif 4487628Sdwmalone#endif 4513840Swosch 4687628Sdwmalone#include <sys/cdefs.h> 4787628Sdwmalone__FBSDID("$FreeBSD: head/usr.bin/calendar/io.c 205821 2010-03-29 06:49:20Z edwin $"); 4887628Sdwmalone 4913840Swosch#include <sys/param.h> 5087235Smarkm#include <sys/stat.h> 5187235Smarkm#include <sys/wait.h> 5213840Swosch#include <ctype.h> 5313840Swosch#include <err.h> 5413840Swosch#include <errno.h> 5574583Sache#include <langinfo.h> 5615714Sache#include <locale.h> 5787235Smarkm#include <pwd.h> 5887235Smarkm#include <stdio.h> 5987235Smarkm#include <stdlib.h> 6013840Swosch#include <string.h> 6187235Smarkm#include <unistd.h> 6213840Swosch 6313840Swosch#include "pathnames.h" 6413840Swosch#include "calendar.h" 6513840Swosch 66181322Sedwinconst char *calendarFile = "calendar"; /* default calendar file */ 67181322Sedwinconst char *calendarHomes[] = {".calendar", _PATH_INCLUDE}; /* HOME */ 68181322Sedwinconst char *calendarNoMail = "nomail"; /* don't sent mail if this file exist */ 6913840Swosch 70181322Sedwinchar path[MAXPATHLEN]; 71181322Sedwin 72205821Sedwinstruct fixs neaster, npaskha, ncny, nfullmoon, nnewmoon; 73205821Sedwinstruct fixs nmarequinox, nsepequinox, njunsolstice, ndecsolstice; 7415720Sache 75205821Sedwin#define REPLACE(string, slen, struct_) \ 76205821Sedwin if (strncasecmp(buf, (string), (slen)) == 0 && buf[(slen)]) { \ 77205821Sedwin if (struct_.name != NULL) \ 78205821Sedwin free(struct_.name); \ 79205821Sedwin if ((struct_.name = strdup(buf + (slen))) == NULL) \ 80205821Sedwin errx(1, "cannot allocate memory"); \ 81205821Sedwin struct_.len = strlen(buf + (slen)); \ 82205821Sedwin continue; \ 83205821Sedwin } 8413840Swoschvoid 85169343Sdwmalonecal(void) 8613840Swosch{ 87205821Sedwin char *pp, p; 8813840Swosch FILE *fp; 8915714Sache int ch, l; 90205821Sedwin int count, i; 91205821Sedwin int month[MAXCOUNT]; 92205821Sedwin int day[MAXCOUNT]; 93205821Sedwin int year[MAXCOUNT]; 94205821Sedwin char **extradata; /* strings of 20 length */ 95205821Sedwin int flags; 9674583Sache static int d_first = -1; 9713840Swosch char buf[2048 + 1]; 98205821Sedwin struct event *events[MAXCOUNT]; 99205821Sedwin struct tm tm; 100205821Sedwin char dbuf[80]; 10113840Swosch 102205821Sedwin extradata = (char **)calloc(MAXCOUNT, sizeof(char *)); 103205821Sedwin for (i = 0; i < MAXCOUNT; i++) { 104205821Sedwin extradata[i] = (char *)calloc(1, 20); 105205821Sedwin } 106205821Sedwin 107205821Sedwin /* Unused */ 108205821Sedwin tm.tm_sec = 0; 109205821Sedwin tm.tm_min = 0; 110205821Sedwin tm.tm_hour = 0; 111205821Sedwin tm.tm_wday = 0; 112205821Sedwin 113205821Sedwin count = 0; 11413840Swosch if ((fp = opencal()) == NULL) 11513840Swosch return; 116205821Sedwin while (fgets(buf, sizeof(buf), stdin) != NULL) { 117205821Sedwin if ((pp = strchr(buf, '\n')) != NULL) 118205821Sedwin *pp = '\0'; 11913840Swosch else 120205821Sedwin /* Flush this line */ 12113840Swosch while ((ch = getchar()) != '\n' && ch != EOF); 12215714Sache for (l = strlen(buf); 12315714Sache l > 0 && isspace((unsigned char)buf[l - 1]); 12415714Sache l--) 12515714Sache ; 12615714Sache buf[l] = '\0'; 12713840Swosch if (buf[0] == '\0') 12813840Swosch continue; 129205821Sedwin 130205821Sedwin /* Parse special definitions: LANG, Easter, Paskha etc */ 13115714Sache if (strncmp(buf, "LANG=", 5) == 0) { 132181322Sedwin (void)setlocale(LC_ALL, buf + 5); 13374583Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 13415714Sache setnnames(); 13515714Sache continue; 13615714Sache } 137205821Sedwin REPLACE("Easter=", 7, neaster); 138205821Sedwin REPLACE("Paskha=", 7, npaskha); 139205821Sedwin REPLACE("ChineseNewYear=", 15, ncny); 140205821Sedwin REPLACE("NewMoon=", 8, nnewmoon); 141205821Sedwin REPLACE("FullMoon=", 9, nfullmoon); 142205821Sedwin REPLACE("MarEquinox=", 11, nmarequinox); 143205821Sedwin REPLACE("SepEquinox=", 11, nsepequinox); 144205821Sedwin REPLACE("JunSolstice=", 12, njunsolstice); 145205821Sedwin REPLACE("DecSolstice=", 12, ndecsolstice); 146205821Sedwin if (strncmp(buf, "SEQUENCE=", 9) == 0) { 147205821Sedwin setnsequences(buf + 9); 14815720Sache continue; 14915720Sache } 15015723Sache 151181322Sedwin /* 152205821Sedwin * If the line starts with a tab, the data has to be 153205821Sedwin * added to the previous line 154181322Sedwin */ 155205821Sedwin if (buf[0] == '\t') { 156205821Sedwin for (i = 0; i < count; i++) 157205821Sedwin event_continue(events[i], buf); 158205821Sedwin continue; 159170447Sgrog } 160170447Sgrog 161205821Sedwin /* Get rid of leading spaces (non-standard) */ 162205821Sedwin while (isspace(buf[0])) 163205821Sedwin memcpy(buf, buf + 1, strlen(buf) - 1); 164170447Sgrog 165205821Sedwin /* No tab in the line, then not a valid line */ 166205821Sedwin if ((pp = strchr(buf, '\t')) == NULL) 167205821Sedwin continue; 168170447Sgrog 169205821Sedwin /* Trim spaces in front of the tab */ 170205821Sedwin while (isspace(pp[-1])) 171205821Sedwin pp--; 172205821Sedwin 173205821Sedwin p = *pp; 174205821Sedwin *pp = '\0'; 175205821Sedwin if ((count = parsedaymonth(buf, year, month, day, &flags, 176205821Sedwin extradata)) == 0) 177205821Sedwin continue; 178205821Sedwin *pp = p; 179205821Sedwin if (count < 0) { 180205821Sedwin /* Show error status based on return value */ 181205821Sedwin fprintf(stderr, "Ignored: %s\n", buf); 182205821Sedwin if (count == -1) 183170447Sgrog continue; 184205821Sedwin count = -count + 1; 185170447Sgrog } 186170447Sgrog 187205821Sedwin /* Find the last tab */ 188205821Sedwin while (pp[1] == '\t') 189205821Sedwin pp++; 19013840Swosch 191205821Sedwin if (d_first < 0) 192205821Sedwin d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 193170447Sgrog 194205821Sedwin for (i = 0; i < count; i++) { 195205821Sedwin tm.tm_mon = month[i] - 1; 196205821Sedwin tm.tm_mday = day[i]; 197205821Sedwin tm.tm_year = year[i] - 1900; 198205821Sedwin (void)strftime(dbuf, sizeof(dbuf), 199205821Sedwin d_first ? "%e %b" : "%b %e", &tm); 200205821Sedwin if (debug) 201205821Sedwin fprintf(stderr, "got %s\n", pp); 202205821Sedwin events[i] = event_add(year[i], month[i], day[i], dbuf, 203205821Sedwin ((flags &= F_VARIABLE) != 0) ? 1 : 0, pp, 204205821Sedwin extradata[i]); 205181322Sedwin } 20613840Swosch } 20713840Swosch 208205821Sedwin event_print_all(fp); 209205821Sedwin closecal(fp); 21013840Swosch} 21113840Swosch 21213840SwoschFILE * 213169343Sdwmaloneopencal(void) 21413840Swosch{ 21522473Smpp uid_t uid; 216100811Sjmallett size_t i; 217100811Sjmallett int fd, found, pdes[2]; 21813840Swosch struct stat sbuf; 21913840Swosch 22013840Swosch /* open up calendar file as stdin */ 22113840Swosch if (!freopen(calendarFile, "r", stdin)) { 22213840Swosch if (doall) { 223181322Sedwin if (chdir(calendarHomes[0]) != 0) 224181322Sedwin return (NULL); 225181322Sedwin if (stat(calendarNoMail, &sbuf) == 0) 226181322Sedwin return (NULL); 227181322Sedwin if (!freopen(calendarFile, "r", stdin)) 228181322Sedwin return (NULL); 22913840Swosch } else { 230173169Skevlo char *home = getenv("HOME"); 231173169Skevlo if (home == NULL || *home == '\0') 232173169Skevlo errx(1, "cannot get home directory"); 233173169Skevlo chdir(home); 234100811Sjmallett for (found = i = 0; i < sizeof(calendarHomes) / 235100811Sjmallett sizeof(calendarHomes[0]); i++) 236181322Sedwin if (chdir(calendarHomes[i]) == 0 && 237181322Sedwin freopen(calendarFile, "r", stdin)) { 238181322Sedwin found = 1; 239181322Sedwin break; 240181322Sedwin } 241100811Sjmallett if (!found) 242181322Sedwin errx(1, 243181322Sedwin "can't open calendar file \"%s\": %s (%d)", 244181322Sedwin calendarFile, strerror(errno), errno); 24513840Swosch } 24613840Swosch } 24713840Swosch if (pipe(pdes) < 0) 24813840Swosch return (NULL); 24940302Sdes switch (fork()) { 25013840Swosch case -1: /* error */ 25113840Swosch (void)close(pdes[0]); 25213840Swosch (void)close(pdes[1]); 25313840Swosch return (NULL); 25413840Swosch case 0: 25513840Swosch /* child -- stdin already setup, set stdout to pipe input */ 25613840Swosch if (pdes[1] != STDOUT_FILENO) { 25713840Swosch (void)dup2(pdes[1], STDOUT_FILENO); 25813840Swosch (void)close(pdes[1]); 25913840Swosch } 26013840Swosch (void)close(pdes[0]); 26122473Smpp uid = geteuid(); 26222473Smpp if (setuid(getuid()) < 0) { 26326839Scharnier warnx("first setuid failed"); 26422473Smpp _exit(1); 26522473Smpp }; 26622473Smpp if (setgid(getegid()) < 0) { 26726839Scharnier warnx("setgid failed"); 26822473Smpp _exit(1); 26922473Smpp } 27022473Smpp if (setuid(uid) < 0) { 27126839Scharnier warnx("setuid failed"); 27222473Smpp _exit(1); 27322473Smpp } 27455716Sobrien execl(_PATH_CPP, "cpp", "-P", 27555716Sobrien "-traditional", "-nostdinc", /* GCC specific opts */ 27679452Sbrian "-I.", "-I", _PATH_INCLUDE, (char *)NULL); 27726839Scharnier warn(_PATH_CPP); 27813840Swosch _exit(1); 27913840Swosch } 28013840Swosch /* parent -- set stdin to pipe output */ 28113840Swosch (void)dup2(pdes[0], STDIN_FILENO); 28213840Swosch (void)close(pdes[0]); 28313840Swosch (void)close(pdes[1]); 28413840Swosch 28513840Swosch /* not reading all calendar files, just set output to stdout */ 28613840Swosch if (!doall) 28713840Swosch return (stdout); 28813840Swosch 28913840Swosch /* set output to a temporary file, so if no output don't send mail */ 29013840Swosch (void)snprintf(path, sizeof(path), "%s/_calXXXXXX", _PATH_TMP); 29113840Swosch if ((fd = mkstemp(path)) < 0) 29213840Swosch return (NULL); 29313840Swosch return (fdopen(fd, "w+")); 29413840Swosch} 29513840Swosch 29613840Swoschvoid 297169343Sdwmaloneclosecal(FILE *fp) 29813840Swosch{ 29922473Smpp uid_t uid; 30013840Swosch struct stat sbuf; 30113840Swosch int nread, pdes[2], status; 30213840Swosch char buf[1024]; 30313840Swosch 30413840Swosch if (!doall) 30513840Swosch return; 30613840Swosch 307200628Srse rewind(fp); 30813840Swosch if (fstat(fileno(fp), &sbuf) || !sbuf.st_size) 30913840Swosch goto done; 31013840Swosch if (pipe(pdes) < 0) 31113840Swosch goto done; 31240302Sdes switch (fork()) { 31313840Swosch case -1: /* error */ 31413840Swosch (void)close(pdes[0]); 31513840Swosch (void)close(pdes[1]); 31613840Swosch goto done; 31713840Swosch case 0: 31813840Swosch /* child -- set stdin to pipe output */ 31913840Swosch if (pdes[0] != STDIN_FILENO) { 32013840Swosch (void)dup2(pdes[0], STDIN_FILENO); 32113840Swosch (void)close(pdes[0]); 32213840Swosch } 32313840Swosch (void)close(pdes[1]); 32422473Smpp uid = geteuid(); 32522473Smpp if (setuid(getuid()) < 0) { 32626839Scharnier warnx("setuid failed"); 32722473Smpp _exit(1); 32822473Smpp }; 32922473Smpp if (setgid(getegid()) < 0) { 33026839Scharnier warnx("setgid failed"); 33122473Smpp _exit(1); 33222473Smpp } 33322473Smpp if (setuid(uid) < 0) { 33426839Scharnier warnx("setuid failed"); 33522473Smpp _exit(1); 33622473Smpp } 33713840Swosch execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F", 33879452Sbrian "\"Reminder Service\"", (char *)NULL); 33926839Scharnier warn(_PATH_SENDMAIL); 34013840Swosch _exit(1); 34113840Swosch } 34213840Swosch /* parent -- write to pipe input */ 34313840Swosch (void)close(pdes[0]); 34413840Swosch 345205821Sedwin write(pdes[1], "From: \"Reminder Service\" <", 26); 346205821Sedwin write(pdes[1], pw->pw_name, strlen(pw->pw_name)); 347205821Sedwin write(pdes[1], ">\nTo: <", 7); 348205821Sedwin write(pdes[1], pw->pw_name, strlen(pw->pw_name)); 349205821Sedwin write(pdes[1], ">\nSubject: ", 12); 350205821Sedwin write(pdes[1], dayname, strlen(dayname)); 351205821Sedwin write(pdes[1], "'s Calendar\nPrecedence: bulk\n\n", 30); 352205821Sedwin 35313840Swosch while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0) 35413840Swosch (void)write(pdes[1], buf, nread); 35513840Swosch (void)close(pdes[1]); 35613840Swoschdone: (void)fclose(fp); 35713840Swosch (void)unlink(path); 35813840Swosch while (wait(&status) >= 0); 35913840Swosch} 360