Fixes for crontab and crond
[unix-history] / usr / src / usr.bin / crontab / crontab.c
CommitLineData
33ee458a
WJ
1#if !defined(lint) && !defined(LINT)
2static char rcsid[] = "$Header: /home/local/site/cron2.1/orig/RCS/crontab.c,v 2.3 1992/05/13 05:56:35 rich Exp $";
3#endif
4
5/* Revision 1.5 87/05/02 17:33:22 paul
6 * pokecron? (RCS file has the rest of the log)
7 *
8 * Revision 1.5 87/05/02 17:33:22 paul
9 * baseline for mod.sources release
10 *
11 * Revision 1.4 87/03/31 13:11:48 paul
12 * I won't say that rs@mirror gave me this idea but crontab uses getopt() now
13 *
14 * Revision 1.3 87/03/30 23:43:48 paul
15 * another suggestion from rs@mirror:
16 * use getpwuid(getuid)->pw_name instead of getenv("USER")
17 * this is a boost to security...
18 *
19 * Revision 1.2 87/02/11 17:40:12 paul
20 * changed command syntax to allow append and replace instead of append as
21 * default and no replace at all.
22 *
23 * Revision 1.1 87/01/26 23:49:06 paul
24 * Initial revision
7b1a346c
AG
25 *
26 * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
27 * -------------------- ----- ----------------------
28 * CURRENT PATCH LEVEL: 1 00131
29 * -------------------- ----- ----------------------
30 *
31 * 06 Apr 93 Adam Glass Fixes so it compiles quitely
32 *
33ee458a
WJ
33 */
34
35/* Copyright 1988,1990 by Paul Vixie
36 * All rights reserved
37 *
38 * Distribute freely, except: don't remove my name from the source or
39 * documentation (don't take credit for my work), mark your changes (don't
40 * get me blamed for your possible bugs), don't alter or remove this
41 * notice. May be sold if buildable source is provided to buyer. No
42 * warrantee of any kind, express or implied, is included with this
43 * software; use at your own risk, responsibility for damages (if any) to
44 * anyone resulting from the use of this software rests entirely with the
45 * user.
46 *
47 * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
48 * I'll try to keep a version up to date. I can be reached as follows:
49 * Paul Vixie, 329 Noe Street, San Francisco, CA, 94114, (415) 864-7013,
50 * paul@vixie.sf.ca.us || {hoptoad,pacbell,decwrl,crash}!vixie!paul
51 */
52
53
54#define MAIN_PROGRAM
55
56
57#include "cron.h"
58#include <pwd.h>
59#include <errno.h>
60#include <sys/file.h>
61#if defined(BSD)
62# include <sys/time.h>
63#endif /*BSD*/
64
65/* extern char *sprintf(); */
66
67
68static int Pid;
69static char User[MAX_UNAME], RealUser[MAX_UNAME];
70static char Filename[MAX_FNAME];
71static FILE *NewCrontab;
72static int CheckErrorCount;
73static enum {opt_unknown, opt_list, opt_delete, opt_replace}
74 Option;
75
76extern void log_it();
77
78#if DEBUGGING
79static char *Options[] = {"???", "list", "delete", "replace"};
80#endif
81
7b1a346c 82void
33ee458a
WJ
83usage()
84{
85 fprintf(stderr, "usage: %s [-u user] ...\n", ProgramName);
86 fprintf(stderr, " ... -l (list user's crontab)\n");
87 fprintf(stderr, " ... -d (delete user's crontab)\n");
88 fprintf(stderr, " ... -r file (replace user's crontab)\n");
89 exit(ERROR_EXIT);
90}
91
92
93main(argc, argv)
94 int argc;
95 char *argv[];
96{
7b1a346c
AG
97 void parse_args(), set_cron_uid(), set_cron_cwd(),
98 list_cmd(), delete_cmd(), replace_cmd();
33ee458a
WJ
99
100 Pid = getpid();
101 ProgramName = argv[0];
102#if defined(BSD)
103 setlinebuf(stderr);
104#endif
105 parse_args(argc, argv); /* sets many globals, opens a file */
106 set_cron_uid();
107 set_cron_cwd();
108 if (!allowed(User)) {
109 fprintf(stderr,
110 "You (%s) are not allowed to use this program (%s)\n",
111 User, ProgramName);
112 fprintf(stderr, "See crontab(1) for more information\n");
113 log_it(RealUser, Pid, "AUTH", "crontab command not allowed");
114 exit(ERROR_EXIT);
115 }
116 switch (Option)
117 {
118 case opt_list: list_cmd();
119 break;
120 case opt_delete: delete_cmd();
121 break;
122 case opt_replace: replace_cmd();
123 break;
124 }
125}
126
127
7b1a346c 128 void
33ee458a
WJ
129parse_args(argc, argv)
130 int argc;
131 char *argv[];
132{
133 void usage();
134 char *getenv(), *strcpy();
135 int getuid();
136 struct passwd *getpwnam();
137 extern int getopt(), optind;
138 extern char *optarg;
139
140 struct passwd *pw;
141 int argch;
142
143 if (!(pw = getpwuid(getuid())))
144 {
145 fprintf(stderr, "%s: your UID isn't in the passwd file.\n",
146 ProgramName);
147 fprintf(stderr, "bailing out.\n");
148 exit(ERROR_EXIT);
149 }
150 strcpy(User, pw->pw_name);
151 strcpy(RealUser, User);
152 Filename[0] = '\0';
153 Option = opt_unknown;
154 while (EOF != (argch = getopt(argc, argv, "u:ldr:x:")))
155 {
156 switch (argch)
157 {
158 case 'x':
159 if (!set_debug_flags(optarg))
160 usage();
161 break;
162 case 'u':
163 if (getuid() != ROOT_UID)
164 {
165 fprintf(stderr,
166 "must be privileged to use -u\n");
167 exit(ERROR_EXIT);
168 }
169 if ((struct passwd *)NULL == getpwnam(optarg))
170 {
171 fprintf(stderr, "%s: user `%s' unknown\n",
172 ProgramName, optarg);
173 exit(ERROR_EXIT);
174 }
175 (void) strcpy(User, optarg);
176 break;
177 case 'l':
178 if (Option != opt_unknown)
179 usage();
180 Option = opt_list;
181 break;
182 case 'd':
183 if (Option != opt_unknown)
184 usage();
185 Option = opt_delete;
186 break;
187 case 'r':
188 if (Option != opt_unknown)
189 usage();
190 Option = opt_replace;
191 (void) strcpy(Filename, optarg);
192 break;
193 default:
194 usage();
195 }
196 }
197
198 endpwent();
199
200 if (Option == opt_unknown || argv[optind] != NULL)
201 usage();
202
203 if (Option == opt_replace) {
204 if (!Filename[0]) {
205 /* getopt(3) says this can't be true
206 * but I'm paranoid today.
207 */
208 fprintf(stderr, "filename must be given for -a or -r\n");
209 usage();
210 }
211 /* we have to open the file here because we're going to
212 * chdir(2) into /var/cron before we get around to
213 * reading the file.
214 */
215 if (!strcmp(Filename, "-")) {
216 NewCrontab = stdin;
217 } else {
218 if (!(NewCrontab = fopen(Filename, "r"))) {
219 perror(Filename);
220 exit(ERROR_EXIT);
221 }
222 }
223 }
224
225 Debug(DMISC, ("user=%s, file=%s, option=%s\n",
226 User, Filename, Options[(int)Option]))
227}
228
229
7b1a346c 230 void
33ee458a
WJ
231list_cmd()
232{
233 extern errno;
234 char n[MAX_FNAME];
235 FILE *f;
236 int ch;
237
238 log_it(RealUser, Pid, "LIST", User);
239 (void) sprintf(n, CRON_TAB(User));
240 if (!(f = fopen(n, "r")))
241 {
242 if (errno == ENOENT)
243 fprintf(stderr, "no crontab for %s\n", User);
244 else
245 perror(n);
246 exit(ERROR_EXIT);
247 }
248
249 /* file is open. copy to stdout, close.
250 */
251 Set_LineNum(1)
252 while (EOF != (ch = get_char(f)))
253 putchar(ch);
254 fclose(f);
255}
256
257
7b1a346c 258 void
33ee458a
WJ
259delete_cmd()
260{
261 extern errno;
262 int unlink();
263 void poke_daemon();
264 char n[MAX_FNAME];
265
266 log_it(RealUser, Pid, "DELETE", User);
267 (void) sprintf(n, CRON_TAB(User));
268 if (unlink(n))
269 {
270 if (errno == ENOENT)
271 fprintf(stderr, "no crontab for %s\n", User);
272 else
273 perror(n);
274 exit(ERROR_EXIT);
275 }
276 poke_daemon();
277}
278
279
7b1a346c 280 void
33ee458a
WJ
281check_error(msg)
282 char *msg;
283{
284 CheckErrorCount += 1;
285 fprintf(stderr, "\"%s\", line %d: %s\n", Filename, LineNumber, msg);
286}
287
288
7b1a346c 289 void
33ee458a
WJ
290replace_cmd()
291{
33ee458a
WJ
292 entry *load_entry();
293 int load_env();
294 int unlink();
295 void free_entry();
296 void check_error();
297 void poke_daemon();
298 extern errno;
299
300 char n[MAX_FNAME], envstr[MAX_ENVSTR], tn[MAX_FNAME];
301 FILE *tmp;
302 int ch;
303 entry *e;
304 int status;
305 time_t now = time(NULL);
306
307 (void) sprintf(n, "tmp.%d", Pid);
308 (void) sprintf(tn, CRON_TAB(n));
309 if (!(tmp = fopen(tn, "w"))) {
310 perror(tn);
311 exit(ERROR_EXIT);
312 }
313
314 /* write a signature at the top of the file. for brian.
315 */
316 fprintf(tmp, "# (%s installed on %-24.24s)\n", Filename, ctime(&now));
317 fprintf(tmp, "# (Cron version -- %s)\n", rcsid);
318
319 /* copy the crontab to the tmp
320 */
321 Set_LineNum(1)
322 while (EOF != (ch = get_char(NewCrontab)))
323 putc(ch, tmp);
324 fclose(NewCrontab);
325 fflush(tmp); rewind(tmp);
326
327 if (ferror(tmp)) {
7b1a346c 328 fprintf(stderr, "%s: error while writing new crontab to %s\n",
33ee458a
WJ
329 ProgramName, tn);
330 fclose(tmp); unlink(tn);
331 exit(ERROR_EXIT);
332 }
333
334 /* check the syntax of the file being installed.
335 */
336
337 /* BUG: was reporting errors after the EOF if there were any errors
338 * in the file proper -- kludged it by stopping after first error.
339 * vix 31mar87
340 */
341 CheckErrorCount = 0;
342 while (!CheckErrorCount && (status = load_env(envstr, tmp)) >= OK)
343 {
344 if (status == FALSE)
345 {
346 if (NULL != (e = load_entry(NewCrontab, check_error)))
347 free((char *) e);
348 }
349 }
350
351 if (CheckErrorCount != 0)
352 {
353 fprintf(stderr, "errors in crontab file, can't install.\n");
354 fclose(tmp); unlink(tn);
355 exit(ERROR_EXIT);
356 }
357
358 if (fchown(fileno(tmp), ROOT_UID, -1) < OK)
359 {
360 perror("chown");
361 fclose(tmp); unlink(tn);
362 exit(ERROR_EXIT);
363 }
364
365 if (fchmod(fileno(tmp), 0600) < OK)
366 {
367 perror("chown");
368 fclose(tmp); unlink(tn);
369 exit(ERROR_EXIT);
370 }
371
372 if (fclose(tmp) == EOF) {
373 perror("fclose");
374 unlink(tn);
375 exit(ERROR_EXIT);
376 }
377
378 (void) sprintf(n, CRON_TAB(User));
379 if (rename(tn, n))
380 {
381 fprintf(stderr, "%s: error renaming %s to %s\n",
382 ProgramName, tn, n);
383 perror("rename");
384 unlink(tn);
385 exit(ERROR_EXIT);
386 }
387 log_it(RealUser, Pid, "REPLACE", User);
388
389 poke_daemon();
390}
391
392
7b1a346c 393 void
33ee458a
WJ
394poke_daemon()
395{
396#if defined(BSD)
397 struct timeval tvs[2];
398 struct timezone tz;
399
400 (void) gettimeofday(&tvs[0], &tz);
401 tvs[1] = tvs[0];
402 if (utimes(SPOOL_DIR, tvs) < OK)
403 {
404 fprintf(stderr, "crontab: can't update mtime on spooldir\n");
405 perror(SPOOL_DIR);
406 return;
407 }
408#endif /*BSD*/
409#if defined(ATT)
410 if (utime(SPOOL_DIR, NULL) < OK)
411 {
412 fprintf(stderr, "crontab: can't update mtime on spooldir\n");
413 perror(SPOOL_DIR);
414 return;
415 }
416#endif /*ATT*/
417}