aboutsummaryrefslogtreecommitdiff
path: root/miscutils/crond.c
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2003-07-28 07:40:39 +0000
committerEric Andersen <andersen@codepoet.org>2003-07-28 07:40:39 +0000
commit35e643b39f6cc77b702c714cfa8e70f1e10601a9 (patch)
treead6b608081a4dde117563a1f1e9a6e3892a8752c /miscutils/crond.c
parent4f4631732cab5886105d8809d4e9b17711def65b (diff)
downloadbusybox-w32-35e643b39f6cc77b702c714cfa8e70f1e10601a9.tar.gz
busybox-w32-35e643b39f6cc77b702c714cfa8e70f1e10601a9.tar.bz2
busybox-w32-35e643b39f6cc77b702c714cfa8e70f1e10601a9.zip
last_patch95 from vodz:
Hi. Last patch have new libbb function vfork_rexec() for can use daemon() to uClinux system. This patched daemons: syslog, klogd, inetd, crond. This not tested! I havn`t this systems. Also. Previous patch for feature request MD5 crypt password for httpd don`t sended to this mailist on 07/15/03 (mailist have Pytom module problem?). The previous patch included, and have testing. --w vodz
Diffstat (limited to 'miscutils/crond.c')
-rw-r--r--miscutils/crond.c411
1 files changed, 186 insertions, 225 deletions
diff --git a/miscutils/crond.c b/miscutils/crond.c
index 9d9ecc290..198bc2d85 100644
--- a/miscutils/crond.c
+++ b/miscutils/crond.c
@@ -41,14 +41,11 @@
41#ifndef TMPDIR 41#ifndef TMPDIR
42#define TMPDIR "/var/spool/cron" 42#define TMPDIR "/var/spool/cron"
43#endif 43#endif
44#ifndef LOG_FILE
45#define LOG_FILE "/var/log/cron"
46#endif
47#ifndef SENDMAIL 44#ifndef SENDMAIL
48#define SENDMAIL "/usr/sbin/sendmail" 45#define SENDMAIL "/usr/sbin/sendmail"
49#endif 46#endif
50#ifndef SENDMAIL_ARGS 47#ifndef SENDMAIL_ARGS
51#define SENDMAIL_ARGS "-t", "-oem", "-i" 48#define SENDMAIL_ARGS "-ti", "oem"
52#endif 49#endif
53#ifndef CRONUPDATE 50#ifndef CRONUPDATE
54#define CRONUPDATE "cron.update" 51#define CRONUPDATE "cron.update"
@@ -57,6 +54,7 @@
57#define MAXLINES 256 /* max lines in non-root crontabs */ 54#define MAXLINES 256 /* max lines in non-root crontabs */
58#endif 55#endif
59 56
57static const char def_sh[] = "/bin/sh";
60 58
61 59
62typedef struct CronFile { 60typedef struct CronFile {
@@ -71,7 +69,7 @@ typedef struct CronFile {
71typedef struct CronLine { 69typedef struct CronLine {
72 struct CronLine *cl_Next; 70 struct CronLine *cl_Next;
73 char *cl_Shell; /* shell command */ 71 char *cl_Shell; /* shell command */
74 int cl_Pid; /* running pid, 0, or armed (-1) */ 72 pid_t cl_Pid; /* running pid, 0, or armed (-1) */
75 int cl_MailFlag; /* running pid is for mail */ 73 int cl_MailFlag; /* running pid is for mail */
76 int cl_MailPos; /* 'empty file' size */ 74 int cl_MailPos; /* 'empty file' size */
77 char cl_Mins[60]; /* 0-59 */ 75 char cl_Mins[60]; /* 0-59 */
@@ -92,13 +90,9 @@ static short DebugOpt;
92#endif 90#endif
93 91
94static short LogLevel = 8; 92static short LogLevel = 8;
95static short ForegroundOpt; 93static const char *LogFile;
96static short LoggerOpt;
97static const char *LogFile = LOG_FILE;
98static const char *CDir = CRONTABS; 94static const char *CDir = CRONTABS;
99 95
100static void log(int level, const char *ctl, ...);
101static void log9(const char *ctl, ...);
102static void startlogger(void); 96static void startlogger(void);
103 97
104static void CheckUpdates(void); 98static void CheckUpdates(void);
@@ -106,14 +100,54 @@ static void SynchronizeDir(void);
106static int TestJobs(time_t t1, time_t t2); 100static int TestJobs(time_t t1, time_t t2);
107static void RunJobs(void); 101static void RunJobs(void);
108static int CheckJobs(void); 102static int CheckJobs(void);
109static void RunJob(CronFile *file, CronLine *line); 103
110static void EndJob(const CronFile *file, CronLine *line); 104static void RunJob(const char *user, CronLine *line);
105#ifdef CONFIG_FEATURE_CROND_CALL_SENDMAIL
106static void EndJob(const char *user, CronLine *line);
107#else
108#define EndJob(user, line) line->cl_Pid = 0
109#endif
111 110
112static void DeleteFile(const char *userName); 111static void DeleteFile(const char *userName);
113 112
114static CronFile *FileBase; 113static CronFile *FileBase;
115 114
116 115
116static void
117log(const char *ctl, ...)
118{
119 va_list va;
120 int level = (int)(ctl[0] & 0xf);
121 int type = level == 20 ?
122 LOG_ERR : ((ctl[0] & 0100) ? LOG_WARNING : LOG_NOTICE);
123
124
125 va_start(va, ctl);
126 if (level >= LogLevel) {
127
128#ifdef FEATURE_DEBUG_OPT
129 if (DebugOpt) vfprintf(stderr, ctl, va);
130 else
131#endif
132 if (LogFile == 0) vsyslog(type, ctl, va);
133 else {
134 int logfd;
135
136 if ((logfd = open(LogFile, O_WRONLY|O_CREAT|O_APPEND, 600)) >= 0) {
137 vdprintf(logfd, ctl, va);
138 close(logfd);
139#ifdef FEATURE_DEBUG_OPT
140 } else {
141 bb_perror_msg("Can't open log file");
142#endif
143 }
144 }
145 }
146 va_end(va);
147 if(ctl[0] & 0200)
148 exit(20);
149}
150
117int 151int
118crond_main(int ac, char **av) 152crond_main(int ac, char **av)
119{ 153{
@@ -138,10 +172,8 @@ crond_main(int ac, char **av)
138 ); 172 );
139 if(opt & 1) 173 if(opt & 1)
140 LogLevel = atoi(lopt); 174 LogLevel = atoi(lopt);
141 LoggerOpt = opt & 2; 175 if(opt & 2)
142 if(LoggerOpt)
143 if (*Lopt != 0) LogFile = Lopt; 176 if (*Lopt != 0) LogFile = Lopt;
144 ForegroundOpt = opt & 4;
145 if(opt & 32) { 177 if(opt & 32) {
146 if (*copt != 0) CDir = copt; 178 if (*copt != 0) CDir = copt;
147 } 179 }
@@ -157,7 +189,7 @@ crond_main(int ac, char **av)
157 */ 189 */
158 190
159 if (chdir(CDir) != 0) 191 if (chdir(CDir) != 0)
160 bb_perror_msg_and_die("chdir"); 192 bb_perror_msg_and_die("%s", CDir);
161 193
162 signal(SIGHUP,SIG_IGN); /* hmm.. but, if kill -HUP original 194 signal(SIGHUP,SIG_IGN); /* hmm.. but, if kill -HUP original
163 * version - his died. ;( 195 * version - his died. ;(
@@ -168,9 +200,15 @@ crond_main(int ac, char **av)
168 * optional detach from controlling terminal 200 * optional detach from controlling terminal
169 */ 201 */
170 202
171 if (ForegroundOpt == 0) { 203 if (!(opt & 4)) {
172 if(daemon(1, 0) < 0) 204 if(daemon(1, 0) < 0) {
173 bb_perror_msg_and_die("daemon"); 205 bb_perror_msg_and_die("daemon");
206#if defined(__uClinux__)
207 } else {
208 /* reexec for vfork() do continue parent */
209 vfork_daemon_rexec(ac, av, "-f");
210 }
211#endif /* uClinux */
174 } 212 }
175 213
176 (void)startlogger(); /* need if syslog mode selected */ 214 (void)startlogger(); /* need if syslog mode selected */
@@ -180,7 +218,8 @@ crond_main(int ac, char **av)
180 * of 1 second. 218 * of 1 second.
181 */ 219 */
182 220
183 log(9,"%s " VERSION " dillon, started, log level %d\n", av[0], LogLevel); 221 log("\011%s " VERSION " dillon, started, log level %d\n", bb_applet_name,
222 LogLevel);
184 223
185 SynchronizeDir(); 224 SynchronizeDir();
186 225
@@ -221,11 +260,11 @@ crond_main(int ac, char **av)
221 CheckUpdates(); 260 CheckUpdates();
222#ifdef FEATURE_DEBUG_OPT 261#ifdef FEATURE_DEBUG_OPT
223 if (DebugOpt) 262 if (DebugOpt)
224 log(5, "Wakeup dt=%d\n", dt); 263 log("\005Wakeup dt=%d\n", dt);
225#endif 264#endif
226 if (dt < -60*60 || dt > 60*60) { 265 if (dt < -60*60 || dt > 60*60) {
227 t1 = t2; 266 t1 = t2;
228 log9("time disparity of %d minutes detected\n", dt / 60); 267 log("\111time disparity of %d minutes detected\n", dt / 60);
229 } else if (dt > 0) { 268 } else if (dt > 0) {
230 TestJobs(t1, t2); 269 TestJobs(t1, t2);
231 RunJobs(); 270 RunJobs();
@@ -242,81 +281,10 @@ crond_main(int ac, char **av)
242} 281}
243 282
244 283
245static void 284#if defined(FEATURE_DEBUG_OPT) || defined(CONFIG_FEATURE_CROND_CALL_SENDMAIL)
246vlog(int level, int MLOG_LEVEL, const char *ctl, va_list va)
247{
248 char buf[1024];
249 int logfd;
250
251 if (level >= LogLevel) {
252
253 vsnprintf(buf,sizeof(buf), ctl, va);
254#ifdef FEATURE_DEBUG_OPT
255 if (DebugOpt) fprintf(stderr,"%s",buf);
256 else
257#endif
258 if (LoggerOpt == 0) syslog(MLOG_LEVEL, "%s", buf);
259 else {
260 if ((logfd = open(LogFile,O_WRONLY|O_CREAT|O_APPEND,600)) >= 0){
261 write(logfd, buf, strlen(buf));
262 close(logfd);
263 } else
264#ifdef FEATURE_DEBUG_OPT
265 bb_perror_msg("Can't open log file")
266#endif
267 ;
268 }
269 }
270}
271
272/*
273 set log_level=9 and log messages
274*/
275
276static void
277log9(const char *ctl, ...)
278{
279 va_list va;
280
281 va_start(va, ctl);
282 vlog(9, LOG_WARNING, ctl, va);
283 va_end(va);
284}
285
286/*
287 normal logger call point.
288*/
289
290static void
291log(int level, const char *ctl, ...)
292{
293 va_list va;
294
295 va_start(va, ctl);
296 vlog(level, LOG_NOTICE, ctl, va);
297 va_end(va);
298}
299
300/* 285/*
301 Original: void 286 write to temp file..
302 logfd(int fd, const char *ctl, ...)
303 Updated to: log_error (used by jobs.c)
304*/ 287*/
305
306static void
307log_err(const char *ctl, ...)
308{
309 va_list va;
310
311 va_start(va, ctl);
312 vlog(20, LOG_ERR, ctl, va);
313 va_end(va);
314}
315
316/*
317 used by jobs.c (write to temp file..)
318*/
319
320static void 288static void
321fdprintf(int fd, const char *ctl, ...) 289fdprintf(int fd, const char *ctl, ...)
322{ 290{
@@ -326,10 +294,11 @@ fdprintf(int fd, const char *ctl, ...)
326 vdprintf(fd, ctl, va); 294 vdprintf(fd, ctl, va);
327 va_end(va); 295 va_end(va);
328} 296}
297#endif
329 298
330 299
331static int 300static int
332ChangeUser(const char *user, short dochdir) 301ChangeUser(const char *user)
333{ 302{
334 struct passwd *pas; 303 struct passwd *pas;
335 304
@@ -338,58 +307,55 @@ ChangeUser(const char *user, short dochdir)
338 */ 307 */
339 308
340 if ((pas = getpwnam(user)) == 0) { 309 if ((pas = getpwnam(user)) == 0) {
341 log(9, "failed to get uid for %s", user); 310 log("\011failed to get uid for %s", user);
342 return(-1); 311 return(-1);
343 } 312 }
344 setenv("USER", pas->pw_name, 1); 313 setenv("USER", pas->pw_name, 1);
345 setenv("HOME", pas->pw_dir, 1); 314 setenv("HOME", pas->pw_dir, 1);
346 setenv("SHELL", "/bin/sh", 1); 315 setenv("SHELL", def_sh, 1);
347 316
348 /* 317 /*
349 * Change running state to the user in question 318 * Change running state to the user in question
350 */ 319 */
351 320
352 if (initgroups(user, pas->pw_gid) < 0) { 321 if (initgroups(user, pas->pw_gid) < 0) {
353 log(9, "initgroups failed: %s %m", user); 322 log("\011initgroups failed: %s %m", user);
354 return(-1); 323 return(-1);
355 } 324 }
356 if (setregid(pas->pw_gid, pas->pw_gid) < 0) { 325 /* drop all priviledges */
357 log(9, "setregid failed: %s %d", user, pas->pw_gid); 326 if (setgid(pas->pw_gid) < 0) {
327 log("\011setgid failed: %s %d", user, pas->pw_gid);
358 return(-1); 328 return(-1);
359 } 329 }
360 if (setreuid(pas->pw_uid, pas->pw_uid) < 0) { 330 if (setuid(pas->pw_uid) < 0) {
361 log(9, "setreuid failed: %s %d", user, pas->pw_uid); 331 log("\011setuid failed: %s %d", user, pas->pw_uid);
362 return(-1); 332 return(-1);
363 } 333 }
364 if (dochdir) {
365 if (chdir(pas->pw_dir) < 0) { 334 if (chdir(pas->pw_dir) < 0) {
366 log(8, "chdir failed: %s %s", user, pas->pw_dir); 335 log("\011chdir failed: %s: %m", pas->pw_dir);
367 if (chdir(TMPDIR) < 0) { 336 if (chdir(TMPDIR) < 0) {
368 log(9, "chdir failed: %s %s", TMPDIR, user); 337 log("\011chdir failed: %s: %m", TMPDIR);
369 return(-1); 338 return(-1);
370 } 339 }
371 } 340 }
372 }
373 return(pas->pw_uid); 341 return(pas->pw_uid);
374} 342}
375 343
376static void 344static void
377startlogger(void) 345startlogger(void)
378{ 346{
347 if (LogFile == 0)
348 openlog(bb_applet_name, LOG_CONS|LOG_PID, LOG_CRON);
349#ifdef FEATURE_DEBUG_OPT
350 else { /* test logfile */
379 int logfd; 351 int logfd;
380 352
381 if (LoggerOpt == 0) 353 if ((logfd = open(LogFile, O_WRONLY|O_CREAT|O_APPEND, 600)) >= 0)
382 openlog(bb_applet_name, LOG_CONS|LOG_PID,LOG_CRON);
383
384 else { /* test logfile */
385 if ((logfd = open(LogFile,O_WRONLY|O_CREAT|O_APPEND,600)) >= 0)
386 close(logfd); 354 close(logfd);
387 else 355 else
388#ifdef FEATURE_DEBUG_OPT 356 bb_perror_msg("Failed to open log file '%s' reason", LogFile);
389 printf("Failed to open log file '%s' reason: %m", LogFile)
390#endif
391 ;
392 } 357 }
358#endif
393} 359}
394 360
395 361
@@ -493,7 +459,7 @@ ParseField(char *user, char *ary, int modvalue, int off,
493 */ 459 */
494 460
495 if (skip == 0) { 461 if (skip == 0) {
496 log9("failed user %s parsing %s\n", user, base); 462 log("\111failed user %s parsing %s\n", user, base);
497 return(NULL); 463 return(NULL);
498 } 464 }
499 if (*ptr == '-' && n2 < 0) { 465 if (*ptr == '-' && n2 < 0) {
@@ -532,7 +498,7 @@ ParseField(char *user, char *ary, int modvalue, int off,
532 } while (n1 != n2 && --failsafe); 498 } while (n1 != n2 && --failsafe);
533 499
534 if (failsafe == 0) { 500 if (failsafe == 0) {
535 log9("failed user %s parsing %s\n", user, base); 501 log("\111failed user %s parsing %s\n", user, base);
536 return(NULL); 502 return(NULL);
537 } 503 }
538 } 504 }
@@ -544,7 +510,7 @@ ParseField(char *user, char *ary, int modvalue, int off,
544 } 510 }
545 511
546 if (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') { 512 if (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') {
547 log9("failed user %s parsing %s\n", user, base); 513 log("\111failed user %s parsing %s\n", user, base);
548 return(NULL); 514 return(NULL);
549 } 515 }
550 516
@@ -556,8 +522,8 @@ ParseField(char *user, char *ary, int modvalue, int off,
556 int i; 522 int i;
557 523
558 for (i = 0; i < modvalue; ++i) 524 for (i = 0; i < modvalue; ++i)
559 log(5, "%d", ary[i]); 525 log("\005%d", ary[i]);
560 log(5, "\n"); 526 log("\005\n");
561 } 527 }
562#endif 528#endif
563 529
@@ -636,7 +602,7 @@ SynchronizeFile(const char *fileName)
636 602
637#ifdef FEATURE_DEBUG_OPT 603#ifdef FEATURE_DEBUG_OPT
638 if (DebugOpt) 604 if (DebugOpt)
639 log9("User %s Entry %s\n", fileName, buf); 605 log("\111User %s Entry %s\n", fileName, buf);
640#endif 606#endif
641 607
642 /* 608 /*
@@ -674,7 +640,7 @@ SynchronizeFile(const char *fileName)
674 640
675#ifdef FEATURE_DEBUG_OPT 641#ifdef FEATURE_DEBUG_OPT
676 if (DebugOpt) { 642 if (DebugOpt) {
677 log9(" Command %s\n", ptr); 643 log("\111 Command %s\n", ptr);
678 } 644 }
679#endif 645#endif
680 646
@@ -686,7 +652,7 @@ SynchronizeFile(const char *fileName)
686 FileBase = file; 652 FileBase = file;
687 653
688 if (maxLines == 0 || maxEntries == 0) 654 if (maxLines == 0 || maxEntries == 0)
689 log9("Maximum number of lines reached for user %s\n", fileName); 655 log("\111Maximum number of lines reached for user %s\n", fileName);
690 } 656 }
691 fclose(fi); 657 fclose(fi);
692 } 658 }
@@ -712,21 +678,17 @@ static void
712SynchronizeDir(void) 678SynchronizeDir(void)
713{ 679{
714 /* 680 /*
715 * Attempt to delete the database. Note that we have to make a copy 681 * Attempt to delete the database.
716 * of the string
717 */ 682 */
718 683
719 for (;;) { 684 for (;;) {
720 CronFile *file; 685 CronFile *file;
721 char *user;
722 686
723 for (file = FileBase; file && file->cf_Deleted; file = file->cf_Next) 687 for (file = FileBase; file && file->cf_Deleted; file = file->cf_Next)
724 ; 688 ;
725 if (file == NULL) 689 if (file == NULL)
726 break; 690 break;
727 user = strdup(file->cf_User); 691 DeleteFile(file->cf_User);
728 DeleteFile(user);
729 free(user);
730 } 692 }
731 693
732 /* 694 /*
@@ -740,8 +702,7 @@ SynchronizeDir(void)
740 702
741 remove(CRONUPDATE); 703 remove(CRONUPDATE);
742 if (chdir(CDir) < 0) { 704 if (chdir(CDir) < 0) {
743 log9("unable to find %s\n", CDir); 705 log("\311unable to find %s\n", CDir);
744 exit(20);
745 } 706 }
746 { 707 {
747 DIR *dir; 708 DIR *dir;
@@ -754,12 +715,11 @@ SynchronizeDir(void)
754 if (getpwnam(den->d_name)) 715 if (getpwnam(den->d_name))
755 SynchronizeFile(den->d_name); 716 SynchronizeFile(den->d_name);
756 else 717 else
757 log(7, "ignoring %s\n", den->d_name); 718 log("\007ignoring %s\n", den->d_name);
758 } 719 }
759 closedir(dir); 720 closedir(dir);
760 } else { 721 } else {
761 log9("Unable to open current dir!\n"); 722 log("\311Unable to open current dir!\n");
762 exit(20);
763 } 723 }
764 } 724 }
765} 725}
@@ -836,14 +796,14 @@ TestJobs(time_t t1, time_t t2)
836 for (file = FileBase; file; file = file->cf_Next) { 796 for (file = FileBase; file; file = file->cf_Next) {
837#ifdef FEATURE_DEBUG_OPT 797#ifdef FEATURE_DEBUG_OPT
838 if (DebugOpt) 798 if (DebugOpt)
839 log(5, "FILE %s:\n", file->cf_User); 799 log("\005FILE %s:\n", file->cf_User);
840#endif 800#endif
841 if (file->cf_Deleted) 801 if (file->cf_Deleted)
842 continue; 802 continue;
843 for (line = file->cf_LineBase; line; line = line->cl_Next) { 803 for (line = file->cf_LineBase; line; line = line->cl_Next) {
844#ifdef FEATURE_DEBUG_OPT 804#ifdef FEATURE_DEBUG_OPT
845 if (DebugOpt) 805 if (DebugOpt)
846 log(5, " LINE %s\n", line->cl_Shell); 806 log("\005 LINE %s\n", line->cl_Shell);
847#endif 807#endif
848 if (line->cl_Mins[tp->tm_min] && 808 if (line->cl_Mins[tp->tm_min] &&
849 line->cl_Hrs[tp->tm_hour] && 809 line->cl_Hrs[tp->tm_hour] &&
@@ -852,10 +812,10 @@ TestJobs(time_t t1, time_t t2)
852 ) { 812 ) {
853#ifdef FEATURE_DEBUG_OPT 813#ifdef FEATURE_DEBUG_OPT
854 if (DebugOpt) 814 if (DebugOpt)
855 log(5, " JobToDo: %d %s\n", line->cl_Pid, line->cl_Shell); 815 log("\005 JobToDo: %d %s\n", line->cl_Pid, line->cl_Shell);
856#endif 816#endif
857 if (line->cl_Pid > 0) { 817 if (line->cl_Pid > 0) {
858 log(8, " process already running: %s %s\n", 818 log("\010 process already running: %s %s\n",
859 file->cf_User, 819 file->cf_User,
860 line->cl_Shell 820 line->cl_Shell
861 ); 821 );
@@ -885,9 +845,9 @@ RunJobs(void)
885 for (line = file->cf_LineBase; line; line = line->cl_Next) { 845 for (line = file->cf_LineBase; line; line = line->cl_Next) {
886 if (line->cl_Pid < 0) { 846 if (line->cl_Pid < 0) {
887 847
888 RunJob(file, line); 848 RunJob(file->cf_User, line);
889 849
890 log(8, "USER %s pid %3d cmd %s\n", 850 log("\010USER %s pid %3d cmd %s\n",
891 file->cf_User, 851 file->cf_User,
892 line->cl_Pid, 852 line->cl_Pid,
893 line->cl_Shell 853 line->cl_Shell
@@ -926,7 +886,7 @@ CheckJobs(void)
926 int r = wait4(line->cl_Pid, &status, WNOHANG, NULL); 886 int r = wait4(line->cl_Pid, &status, WNOHANG, NULL);
927 887
928 if (r < 0 || r == line->cl_Pid) { 888 if (r < 0 || r == line->cl_Pid) {
929 EndJob(file, line); 889 EndJob(file->cf_User, line);
930 if (line->cl_Pid) 890 if (line->cl_Pid)
931 file->cf_Running = 1; 891 file->cf_Running = 1;
932 } else if (r == 0) { 892 } else if (r == 0) {
@@ -941,83 +901,54 @@ CheckJobs(void)
941} 901}
942 902
943 903
944 904#ifdef CONFIG_FEATURE_CROND_CALL_SENDMAIL
945static void 905static void
946RunJob(CronFile *file, CronLine *line) 906ForkJob(const char *user, CronLine *line, int mailFd,
907 const char *prog, const char *cmd, const char *arg, const char *mailf)
947{ 908{
948 char mailFile[128];
949 int mailFd;
950
951 line->cl_Pid = 0;
952 line->cl_MailFlag = 0;
953
954 /*
955 * open mail file - owner root so nobody can screw with it.
956 */
957
958 snprintf(mailFile, sizeof(mailFile), TMPDIR "/cron.%s.%d",
959 file->cf_User, getpid());
960 mailFd = open(mailFile, O_CREAT|O_TRUNC|O_WRONLY|O_EXCL|O_APPEND, 0600);
961
962 if (mailFd >= 0) {
963 line->cl_MailFlag = 1;
964 fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n",
965 file->cf_User,
966 line->cl_Shell
967 );
968 line->cl_MailPos = lseek(mailFd, 0, 1);
969 }
970
971 /* 909 /*
972 * Fork as the user in question and run program 910 * Fork as the user in question and run program
973 */ 911 */
912 pid_t pid = fork();
974 913
975 if ((line->cl_Pid = fork()) == 0) { 914 line->cl_Pid = pid;
915 if (pid == 0) {
976 /* 916 /*
977 * CHILD, FORK OK 917 * CHILD
978 */ 918 */
979 919
980 /* 920 /*
981 * Change running state to the user in question 921 * Change running state to the user in question
982 */ 922 */
983 923
984 if (ChangeUser(file->cf_User, 1) < 0) 924 if (ChangeUser(user) < 0)
985 return; 925 exit(0);
986 926
987#ifdef FEATURE_DEBUG_OPT 927#ifdef FEATURE_DEBUG_OPT
988 if (DebugOpt) 928 if (DebugOpt)
989 log(5, "Child Running %s\n", line->cl_Shell); 929 log("\005Child Running %s\n", prog);
990#endif 930#endif
991 931
992 /*
993 * stdin is already /dev/null, setup stdout and stderr
994 */
995
996 if (mailFd >= 0) { 932 if (mailFd >= 0) {
997 dup2(mailFd, 1); 933 dup2(mailFd, mailf != NULL);
998 dup2(mailFd, 2); 934 dup2((mailf ? mailFd : 1), 2);
999 close(mailFd); 935 close(mailFd);
1000 } else {
1001 log_err("unable to create mail file user %s file %s, output to /dev/null\n",
1002 file->cf_User,
1003 mailFile
1004 );
1005 } 936 }
1006 execl("/bin/sh", "/bin/sh", "-c", line->cl_Shell, NULL, NULL); 937 execl(prog, prog, cmd, arg, NULL);
1007 log_err("unable to exec, user %s cmd /bin/sh -c %s\n", 938 log("\024unable to exec, user %s cmd %s %s %s\n", user,
1008 file->cf_User, 939 prog, cmd, arg);
1009 line->cl_Shell 940 if(mailf)
1010 ); 941 fdprintf(1, "Exec failed: %s -c %s\n", prog, arg);
1011 fdprintf(1, "Exec failed: /bin/sh -c %s\n", line->cl_Shell);
1012 exit(0); 942 exit(0);
1013 } else if (line->cl_Pid < 0) { 943 } else if (pid < 0) {
1014 /* 944 /*
1015 * PARENT, FORK FAILED 945 * FORK FAILED
1016 */ 946 */
1017 log_err("couldn't fork, user %s\n", file->cf_User); 947 log("\024couldn't fork, user %s\n", user);
1018 line->cl_Pid = 0; 948 line->cl_Pid = 0;
1019 remove(mailFile); 949 if(mailf)
1020 } else { 950 remove(mailf);
951 } else if(mailf) {
1021 /* 952 /*
1022 * PARENT, FORK SUCCESS 953 * PARENT, FORK SUCCESS
1023 * 954 *
@@ -1026,10 +957,9 @@ RunJob(CronFile *file, CronLine *line)
1026 char mailFile2[128]; 957 char mailFile2[128];
1027 958
1028 snprintf(mailFile2, sizeof(mailFile2), TMPDIR "/cron.%s.%d", 959 snprintf(mailFile2, sizeof(mailFile2), TMPDIR "/cron.%s.%d",
1029 file->cf_User, line->cl_Pid); 960 user, pid);
1030 rename(mailFile, mailFile2); 961 rename(mailf, mailFile2);
1031 } 962 }
1032
1033 /* 963 /*
1034 * Close the mail file descriptor.. we can't just leave it open in 964 * Close the mail file descriptor.. we can't just leave it open in
1035 * a structure, closing it later, because we might run out of descriptors 965 * a structure, closing it later, because we might run out of descriptors
@@ -1039,12 +969,42 @@ RunJob(CronFile *file, CronLine *line)
1039 close(mailFd); 969 close(mailFd);
1040} 970}
1041 971
972static void
973RunJob(const char *user, CronLine *line)
974{
975 char mailFile[128];
976 int mailFd;
977
978 line->cl_Pid = 0;
979 line->cl_MailFlag = 0;
980
981 /*
982 * open mail file - owner root so nobody can screw with it.
983 */
984
985 snprintf(mailFile, sizeof(mailFile), TMPDIR "/cron.%s.%d",
986 user, getpid());
987 mailFd = open(mailFile, O_CREAT|O_TRUNC|O_WRONLY|O_EXCL|O_APPEND, 0600);
988
989 if (mailFd >= 0) {
990 line->cl_MailFlag = 1;
991 fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n", user,
992 line->cl_Shell);
993 line->cl_MailPos = lseek(mailFd, 0, 1);
994 } else {
995 log("\024unable to create mail file user %s file %s, output to /dev/null\n",
996 user, mailFile);
997 }
998
999 ForkJob(user, line, mailFd, def_sh, "-c", line->cl_Shell, mailFile);
1000}
1001
1042/* 1002/*
1043 * EndJob - called when job terminates and when mail terminates 1003 * EndJob - called when job terminates and when mail terminates
1044 */ 1004 */
1045 1005
1046static void 1006static void
1047EndJob(const CronFile *file, CronLine *line) 1007EndJob(const char *user, CronLine *line)
1048{ 1008{
1049 int mailFd; 1009 int mailFd;
1050 char mailFile[128]; 1010 char mailFile[128];
@@ -1065,7 +1025,7 @@ EndJob(const CronFile *file, CronLine *line)
1065 */ 1025 */
1066 1026
1067 snprintf(mailFile, sizeof(mailFile), TMPDIR "/cron.%s.%d", 1027 snprintf(mailFile, sizeof(mailFile), TMPDIR "/cron.%s.%d",
1068 file->cf_User, line->cl_Pid); 1028 user, line->cl_Pid);
1069 line->cl_Pid = 0; 1029 line->cl_Pid = 0;
1070 1030
1071 if (line->cl_MailFlag != 1) 1031 if (line->cl_MailFlag != 1)
@@ -1093,46 +1053,47 @@ EndJob(const CronFile *file, CronLine *line)
1093 close(mailFd); 1053 close(mailFd);
1094 return; 1054 return;
1095 } 1055 }
1056 ForkJob(user, line, mailFd, SENDMAIL, SENDMAIL_ARGS, NULL);
1057}
1058#else
1059/* crond whithout sendmail */
1096 1060
1097 if ((line->cl_Pid = fork()) == 0) { 1061static void
1062RunJob(const char *user, CronLine *line)
1063{
1098 /* 1064 /*
1099 * CHILD, FORK OK 1065 * Fork as the user in question and run program
1100 */ 1066 */
1067 pid_t pid = fork();
1101 1068
1069 if (pid == 0) {
1102 /* 1070 /*
1103 * change user id - no way in hell security can be compromised 1071 * CHILD
1104 * by the mailing and we already verified the mail file.
1105 */ 1072 */
1106 1073
1107 if (ChangeUser(file->cf_User, 1) < 0)
1108 exit(0);
1109
1110 /* 1074 /*
1111 * run sendmail with mail file as standard input, only if 1075 * Change running state to the user in question
1112 * mail file exists!
1113 */ 1076 */
1114 1077
1115 dup2(mailFd, 0); 1078 if (ChangeUser(user) < 0)
1116 dup2(1, 2); 1079 exit(0);
1117 close(mailFd); 1080
1081#ifdef FEATURE_DEBUG_OPT
1082 if (DebugOpt)
1083 log("\005Child Running %s\n", def_sh);
1084#endif
1118 1085
1119 execl(SENDMAIL, SENDMAIL, SENDMAIL_ARGS, NULL, NULL); 1086 execl(def_sh, def_sh, "-c", line->cl_Shell, NULL);
1120 log_err("unable to exec %s %s, user %s, output to sink null", 1087 log("\024unable to exec, user %s cmd %s -c %s\n", user,
1121 SENDMAIL, 1088 def_sh, line->cl_Shell);
1122 SENDMAIL_ARGS,
1123 file->cf_User
1124 );
1125 exit(0); 1089 exit(0);
1126 } else if (line->cl_Pid < 0) { 1090 } else if (pid < 0) {
1127 /*
1128 * PARENT, FORK FAILED
1129 */
1130 log_err("unable to fork, user %s", file->cf_User);
1131 line->cl_Pid = 0;
1132 } else {
1133 /* 1091 /*
1134 * PARENT, FORK OK 1092 * FORK FAILED
1135 */ 1093 */
1094 log("\024couldn't fork, user %s\n", user);
1095 pid = 0;
1136 } 1096 }
1137 close(mailFd); 1097 line->cl_Pid = pid;
1138} 1098}
1099#endif /* CONFIG_FEATURE_CROND_CALL_SENDMAIL */