aboutsummaryrefslogtreecommitdiff
path: root/miscutils
diff options
context:
space:
mode:
Diffstat (limited to 'miscutils')
-rw-r--r--miscutils/Config.in7
-rw-r--r--miscutils/crond.c411
2 files changed, 193 insertions, 225 deletions
diff --git a/miscutils/Config.in b/miscutils/Config.in
index b4a3475de..0c56f0ee9 100644
--- a/miscutils/Config.in
+++ b/miscutils/Config.in
@@ -19,6 +19,13 @@ config CONFIG_CROND
19 Crond is a background daemon that parses individual crontab 19 Crond is a background daemon that parses individual crontab
20 files and executes commands on behalf of the users in question. 20 files and executes commands on behalf of the users in question.
21 21
22config CONFIG_FEATURE_CROND_CALL_SENDMAIL
23 bool " Using /usr/sbin/sendmail?"
24 default n
25 depends on CONFIG_CROND
26 help
27 Support call /usr/sbin/sendmail for send cmd outputs.
28
22config CONFIG_CRONTAB 29config CONFIG_CRONTAB
23 bool "crontab" 30 bool "crontab"
24 default n 31 default n
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 */