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 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 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 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 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