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 */ 259