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