1*433d6423SLionel Sambuc /* crontab 1.2 - user crontab manipulation Author: Kees J. Bot
2*433d6423SLionel Sambuc * 12 Jan 1997
3*433d6423SLionel Sambuc */
4*433d6423SLionel Sambuc #define nil ((void*)0)
5*433d6423SLionel Sambuc #include <sys/types.h>
6*433d6423SLionel Sambuc #include <stdio.h>
7*433d6423SLionel Sambuc #include <stdlib.h>
8*433d6423SLionel Sambuc #include <string.h>
9*433d6423SLionel Sambuc #include <signal.h>
10*433d6423SLionel Sambuc #include <time.h>
11*433d6423SLionel Sambuc #include <errno.h>
12*433d6423SLionel Sambuc #include <unistd.h>
13*433d6423SLionel Sambuc #include <fcntl.h>
14*433d6423SLionel Sambuc #include <pwd.h>
15*433d6423SLionel Sambuc #include <sys/stat.h>
16*433d6423SLionel Sambuc #include "misc.h"
17*433d6423SLionel Sambuc #include "tab.h"
18*433d6423SLionel Sambuc
opentab(int uid,char * file,int how)19*433d6423SLionel Sambuc static int opentab(int uid, char *file, int how)
20*433d6423SLionel Sambuc /* Open a crontab file under the given uid. How is 'r' or 'w'. Return
21*433d6423SLionel Sambuc * the result of open(2).
22*433d6423SLionel Sambuc */
23*433d6423SLionel Sambuc {
24*433d6423SLionel Sambuc uid_t safe_uid;
25*433d6423SLionel Sambuc int flags, r, err;
26*433d6423SLionel Sambuc
27*433d6423SLionel Sambuc switch (how) {
28*433d6423SLionel Sambuc case 'r': flags= O_RDONLY; break;
29*433d6423SLionel Sambuc case 'w': flags= O_WRONLY | O_CREAT | O_TRUNC; break;
30*433d6423SLionel Sambuc default: errno= EINVAL; return -1;
31*433d6423SLionel Sambuc }
32*433d6423SLionel Sambuc
33*433d6423SLionel Sambuc safe_uid= geteuid();
34*433d6423SLionel Sambuc seteuid(uid);
35*433d6423SLionel Sambuc r= open(file, flags, 0666);
36*433d6423SLionel Sambuc err= errno;
37*433d6423SLionel Sambuc seteuid(safe_uid);
38*433d6423SLionel Sambuc errno= err;
39*433d6423SLionel Sambuc return r;
40*433d6423SLionel Sambuc }
41*433d6423SLionel Sambuc
copytab(int fd_in,char * file_in,int fd_out,char * file_out)42*433d6423SLionel Sambuc static void copytab(int fd_in, char *file_in, int fd_out, char *file_out)
43*433d6423SLionel Sambuc /* Copy one open file to another. Complain and exit on errors. */
44*433d6423SLionel Sambuc {
45*433d6423SLionel Sambuc ssize_t r, w;
46*433d6423SLionel Sambuc char buf[1024];
47*433d6423SLionel Sambuc
48*433d6423SLionel Sambuc while ((r= read(fd_in, buf, sizeof(buf))) > 0) {
49*433d6423SLionel Sambuc w= 0;
50*433d6423SLionel Sambuc while (w < r) {
51*433d6423SLionel Sambuc if ((r= write(fd_out, buf+w, r-w)) <= 0) {
52*433d6423SLionel Sambuc fprintf(stderr,
53*433d6423SLionel Sambuc "%s: Write error on %s: %s\n",
54*433d6423SLionel Sambuc prog_name,
55*433d6423SLionel Sambuc file_out,
56*433d6423SLionel Sambuc r == 0 ? "End of file"
57*433d6423SLionel Sambuc : strerror(errno));
58*433d6423SLionel Sambuc exit(1);
59*433d6423SLionel Sambuc }
60*433d6423SLionel Sambuc w+= r;
61*433d6423SLionel Sambuc }
62*433d6423SLionel Sambuc }
63*433d6423SLionel Sambuc if (r < 0) {
64*433d6423SLionel Sambuc fprintf(stderr, "%s: Read error on %s: %s\n",
65*433d6423SLionel Sambuc prog_name, file_in, strerror(errno));
66*433d6423SLionel Sambuc exit(1);
67*433d6423SLionel Sambuc }
68*433d6423SLionel Sambuc }
69*433d6423SLionel Sambuc
usage(void)70*433d6423SLionel Sambuc static void usage(void)
71*433d6423SLionel Sambuc {
72*433d6423SLionel Sambuc fprintf(stderr,
73*433d6423SLionel Sambuc "Usage: %s -c [user] file # Change crontab\n"
74*433d6423SLionel Sambuc " %s -l [user] # List crontab\n"
75*433d6423SLionel Sambuc " %s -r [user] # Remove crontab\n"
76*433d6423SLionel Sambuc " %s -p # Tell cron to reload\n",
77*433d6423SLionel Sambuc prog_name, prog_name, prog_name, prog_name);
78*433d6423SLionel Sambuc exit(1);
79*433d6423SLionel Sambuc }
80*433d6423SLionel Sambuc
main(int argc,char ** argv)81*433d6423SLionel Sambuc int main(int argc, char **argv)
82*433d6423SLionel Sambuc {
83*433d6423SLionel Sambuc int i;
84*433d6423SLionel Sambuc int cflag, lflag, rflag, pflag;
85*433d6423SLionel Sambuc uid_t uid;
86*433d6423SLionel Sambuc char *user, *file;
87*433d6423SLionel Sambuc struct passwd *pw;
88*433d6423SLionel Sambuc static char SPOOLDIR[]= "/usr/spool/crontabs";
89*433d6423SLionel Sambuc char tabfile[sizeof(SPOOLDIR) + NAME_MAX];
90*433d6423SLionel Sambuc
91*433d6423SLionel Sambuc prog_name= strrchr(argv[0], '/');
92*433d6423SLionel Sambuc if (prog_name == nil) prog_name= argv[0]; else prog_name++;
93*433d6423SLionel Sambuc
94*433d6423SLionel Sambuc cflag= lflag= rflag= pflag= 0;
95*433d6423SLionel Sambuc i= 1;
96*433d6423SLionel Sambuc while (i < argc && argv[i][0] == '-') {
97*433d6423SLionel Sambuc char *opt= argv[i++] + 1;
98*433d6423SLionel Sambuc
99*433d6423SLionel Sambuc if (opt[0] == '-' && opt[1] == 0) break; /* -- */
100*433d6423SLionel Sambuc
101*433d6423SLionel Sambuc while (*opt != 0) switch (*opt++) {
102*433d6423SLionel Sambuc case 'c': cflag= 1; break;
103*433d6423SLionel Sambuc case 'l': lflag= 1; break;
104*433d6423SLionel Sambuc case 'r': rflag= 1; break;
105*433d6423SLionel Sambuc case 'p': pflag= 1; break;
106*433d6423SLionel Sambuc default: usage();
107*433d6423SLionel Sambuc }
108*433d6423SLionel Sambuc }
109*433d6423SLionel Sambuc if (cflag + lflag + rflag + pflag != 1) usage();
110*433d6423SLionel Sambuc
111*433d6423SLionel Sambuc user= file= nil;
112*433d6423SLionel Sambuc if (!pflag && i < argc) user= argv[i++];
113*433d6423SLionel Sambuc if (cflag) {
114*433d6423SLionel Sambuc if (user == nil) usage();
115*433d6423SLionel Sambuc if (i < argc) {
116*433d6423SLionel Sambuc file= argv[i++];
117*433d6423SLionel Sambuc } else {
118*433d6423SLionel Sambuc file= user;
119*433d6423SLionel Sambuc user= nil;
120*433d6423SLionel Sambuc }
121*433d6423SLionel Sambuc }
122*433d6423SLionel Sambuc if (i != argc) usage();
123*433d6423SLionel Sambuc
124*433d6423SLionel Sambuc if (geteuid() != 0) {
125*433d6423SLionel Sambuc fprintf(stderr, "%s: No root privileges?\n", prog_name);
126*433d6423SLionel Sambuc }
127*433d6423SLionel Sambuc uid= getuid();
128*433d6423SLionel Sambuc if (user == nil) {
129*433d6423SLionel Sambuc if ((pw= getpwuid(uid)) == nil) {
130*433d6423SLionel Sambuc fprintf(stderr,
131*433d6423SLionel Sambuc "%s: Don't know who you (uid %lu) are!\n",
132*433d6423SLionel Sambuc prog_name, (unsigned long) uid);
133*433d6423SLionel Sambuc exit(1);
134*433d6423SLionel Sambuc }
135*433d6423SLionel Sambuc } else {
136*433d6423SLionel Sambuc if ((pw= getpwnam(user)) == nil) {
137*433d6423SLionel Sambuc fprintf(stderr,
138*433d6423SLionel Sambuc "%s: Don't know who you (%s) are!\n",
139*433d6423SLionel Sambuc prog_name, user);
140*433d6423SLionel Sambuc exit(1);
141*433d6423SLionel Sambuc }
142*433d6423SLionel Sambuc }
143*433d6423SLionel Sambuc if (uid != 0 && pw->pw_uid != uid) {
144*433d6423SLionel Sambuc fprintf(stderr,
145*433d6423SLionel Sambuc "%s: Only root can change the crontabs of others!\n",
146*433d6423SLionel Sambuc prog_name);
147*433d6423SLionel Sambuc exit(1);
148*433d6423SLionel Sambuc }
149*433d6423SLionel Sambuc user= pw->pw_name;
150*433d6423SLionel Sambuc uid= pw->pw_uid;
151*433d6423SLionel Sambuc seteuid(uid);
152*433d6423SLionel Sambuc umask(0077);
153*433d6423SLionel Sambuc
154*433d6423SLionel Sambuc selectlog(STDERR);
155*433d6423SLionel Sambuc sprintf(tabfile, "%s/%s", SPOOLDIR, user);
156*433d6423SLionel Sambuc
157*433d6423SLionel Sambuc if (lflag) {
158*433d6423SLionel Sambuc int fd;
159*433d6423SLionel Sambuc
160*433d6423SLionel Sambuc if ((fd= opentab(0, tabfile, 'r')) < 0) {
161*433d6423SLionel Sambuc fprintf(stderr, "%s: Can't open %s: %s\n",
162*433d6423SLionel Sambuc prog_name, tabfile, strerror(errno));
163*433d6423SLionel Sambuc exit(1);
164*433d6423SLionel Sambuc }
165*433d6423SLionel Sambuc copytab(fd, tabfile, 1, "stdout");
166*433d6423SLionel Sambuc close(fd);
167*433d6423SLionel Sambuc }
168*433d6423SLionel Sambuc
169*433d6423SLionel Sambuc if (rflag) {
170*433d6423SLionel Sambuc seteuid(0);
171*433d6423SLionel Sambuc if (unlink(tabfile) < 0) {
172*433d6423SLionel Sambuc fprintf(stderr, "%s: Can't remove %s: %s\n",
173*433d6423SLionel Sambuc prog_name, tabfile, strerror(errno));
174*433d6423SLionel Sambuc exit(1);
175*433d6423SLionel Sambuc }
176*433d6423SLionel Sambuc seteuid(uid);
177*433d6423SLionel Sambuc printf("Crontab of %s removed\n", user);
178*433d6423SLionel Sambuc pflag= 1;
179*433d6423SLionel Sambuc }
180*433d6423SLionel Sambuc
181*433d6423SLionel Sambuc /* Initialize current Time */
182*433d6423SLionel Sambuc time(&now);
183*433d6423SLionel Sambuc
184*433d6423SLionel Sambuc if (cflag) {
185*433d6423SLionel Sambuc int fd1, fd2;
186*433d6423SLionel Sambuc
187*433d6423SLionel Sambuc if ((fd1= opentab(uid, file, 'r')) < 0) {
188*433d6423SLionel Sambuc fprintf(stderr, "%s: Can't open %s: %s\n",
189*433d6423SLionel Sambuc prog_name, file, strerror(errno));
190*433d6423SLionel Sambuc exit(1);
191*433d6423SLionel Sambuc }
192*433d6423SLionel Sambuc
193*433d6423SLionel Sambuc /* Try to parse the new crontab file. If the parsing
194*433d6423SLionel Sambuc * succeeds then 'crontabs' will be non-null.
195*433d6423SLionel Sambuc */
196*433d6423SLionel Sambuc tab_parse(file, user);
197*433d6423SLionel Sambuc tab_purge();
198*433d6423SLionel Sambuc if (crontabs == nil) exit(1);
199*433d6423SLionel Sambuc
200*433d6423SLionel Sambuc if ((fd2= opentab(0, tabfile, 'w')) < 0) {
201*433d6423SLionel Sambuc fprintf(stderr, "%s: Can't open %s: %s\n",
202*433d6423SLionel Sambuc prog_name, tabfile, strerror(errno));
203*433d6423SLionel Sambuc exit(1);
204*433d6423SLionel Sambuc }
205*433d6423SLionel Sambuc copytab(fd1, file, fd2, tabfile);
206*433d6423SLionel Sambuc close(fd1);
207*433d6423SLionel Sambuc close(fd2);
208*433d6423SLionel Sambuc printf("New crontab for %s installed\n", user);
209*433d6423SLionel Sambuc pflag= 1;
210*433d6423SLionel Sambuc }
211*433d6423SLionel Sambuc
212*433d6423SLionel Sambuc if (pflag) {
213*433d6423SLionel Sambuc /* Alert cron to the new situation. */
214*433d6423SLionel Sambuc FILE *fp;
215*433d6423SLionel Sambuc
216*433d6423SLionel Sambuc seteuid(0);
217*433d6423SLionel Sambuc if ((fp= fopen(PIDFILE, "r")) != NULL) {
218*433d6423SLionel Sambuc unsigned long pid;
219*433d6423SLionel Sambuc int c;
220*433d6423SLionel Sambuc
221*433d6423SLionel Sambuc pid= 0;
222*433d6423SLionel Sambuc while ((c= fgetc(fp)) != EOF && c != '\n') {
223*433d6423SLionel Sambuc if ((unsigned) (c - '0') >= 10) {
224*433d6423SLionel Sambuc pid= 0; break;
225*433d6423SLionel Sambuc }
226*433d6423SLionel Sambuc pid= 10*pid + (c - '0');
227*433d6423SLionel Sambuc if (pid >= 30000) { pid= 0; break; }
228*433d6423SLionel Sambuc }
229*433d6423SLionel Sambuc if (pid > 1 && kill((pid_t) pid, SIGHUP) == 0) {
230*433d6423SLionel Sambuc pflag= 0;
231*433d6423SLionel Sambuc }
232*433d6423SLionel Sambuc }
233*433d6423SLionel Sambuc seteuid(uid);
234*433d6423SLionel Sambuc if (pflag) {
235*433d6423SLionel Sambuc fprintf(stderr,
236*433d6423SLionel Sambuc "%s: Alerting cron has failed; cron still running?\n",
237*433d6423SLionel Sambuc prog_name);
238*433d6423SLionel Sambuc exit(1);
239*433d6423SLionel Sambuc }
240*433d6423SLionel Sambuc printf("Cron signalled to reload tables\n");
241*433d6423SLionel Sambuc }
242*433d6423SLionel Sambuc return 0;
243*433d6423SLionel Sambuc }
244*433d6423SLionel Sambuc
245*433d6423SLionel Sambuc /*
246*433d6423SLionel Sambuc * $PchId: crontab.c,v 1.4 2000/07/17 18:54:50 philip Exp $
247*433d6423SLionel Sambuc */
248