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