55 #include <fcntl.h>
56 #include <grp.h>
57 #include <libcontract.h>
58 #include <libcontract_priv.h>
59 #include <limits.h>
60 #include <locale.h>
61 #include <poll.h>
62 #include <project.h>
63 #include <pwd.h>
64 #include <signal.h>
65 #include <stdarg.h>
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <string.h>
69 #include <stropts.h>
70 #include <time.h>
71 #include <unistd.h>
72 #include <libzoneinfo.h>
73
74 #include "cron.h"
75
76 /*
77 * #define DEBUG
78 */
79
80 #define MAIL "/usr/bin/mail" /* mail program to use */
81 #define CONSOLE "/dev/console" /* where messages go when cron dies */
82
83 #define TMPINFILE "/tmp/crinXXXXXX" /* file to put stdin in for cmd */
84 #define TMPDIR "/tmp"
85 #define PFX "crout"
86 #define TMPOUTFILE "/tmp/croutXXXXXX" /* file to place stdout, stderr */
87
88 #define INMODE 00400 /* mode for stdin file */
89 #define OUTMODE 00600 /* mode for stdout file */
90 #define ISUID S_ISUID /* mode for verifing at jobs */
91
92 #define INFINITY 2147483647L /* upper bound on time */
93 #define CUSHION 180L
94 #define ZOMB 100 /* proc slot used for mailing output */
129 #define BADTYPE "crontab or at-job file is not a regular file.\n"
130 #define NOSTDIN "unable to create a standard input file for \
131 one of your crontab commands. \
132 \nThat command was not executed."
133
134 #define NOTALLOWED "you are not authorized to use cron. Sorry."
135 #define STDERRMSG "\n\n********************************************\
136 *****\nCron: The previous message is the \
137 standard output and standard error \
138 \nof one of your cron commands.\n"
139
140 #define STDOUTERR "one of your commands generated output or errors, \
141 but cron was unable to mail you this output.\
142 \nRemember to redirect standard output and standard \
143 error for each of your commands."
144
145 #define CLOCK_DRIFT "clock time drifted backwards after event!\n"
146 #define PIDERR "unexpected pid returned %d (ignored)"
147 #define CRONTABERR "Subject: Your crontab file has an error in it\n\n"
148 #define CRONOUT "Subject: Output from \"cron\" command\n\n"
149 #define MALLOCERR "out of space, cannot create new string\n"
150
151 #define DIDFORK didfork
152 #define NOFORK !didfork
153
154 #define MAILBUFLEN (8*1024)
155 #define LINELIMIT 80
156 #define MAILBINITFREE (MAILBUFLEN - (sizeof (cte_intro) - 1) \
157 - (sizeof (cte_trail1) - 1) - (sizeof (cte_trail2) - 1) - 1)
158
159 #define ERR_CRONTABENT 0 /* error in crontab file entry */
160 #define ERR_UNIXERR 1 /* error in some system call */
161 #define ERR_CANTEXECCRON 2 /* error setting up "cron" job environment */
162 #define ERR_CANTEXECAT 3 /* error setting up "at" job environment */
163 #define ERR_NOTREG 4 /* error not a regular file */
164
165 #define PROJECT "project="
166
167 #define MAX_LOST_CONTRACTS 2048 /* reset if this many failed abandons */
168
340 static void cte_sendmail(char *);
341
342 static int set_user_cred(const struct usr *, struct project *);
343
344 static struct shared *create_shared_str(char *str);
345 static struct shared *dup_shared(struct shared *obj);
346 static void rel_shared(struct shared *obj);
347 static void *get_obj(struct shared *obj);
348 /*
349 * last_time is set immediately prior to exection of an event (via ex())
350 * to indicate the last time an event was executed. This was (surely)
351 * it's original intended use.
352 */
353 static time_t last_time, init_time, t_old;
354 static int reset_needed; /* set to 1 when cron(1M) needs to re-initialize */
355
356 static int refresh;
357 static sigset_t defmask, sigmask;
358
359 /*
360 * BSM hooks
361 */
362 extern int audit_cron_session(char *, char *, uid_t, gid_t, char *);
363 extern void audit_cron_new_job(char *, int, void *);
364 extern void audit_cron_bad_user(char *);
365 extern void audit_cron_user_acct_expired(char *);
366 extern int audit_cron_create_anc_file(char *, char *, char *, uid_t);
367 extern int audit_cron_delete_anc_file(char *, char *);
368 extern int audit_cron_is_anc_name(char *);
369 extern int audit_cron_mode();
370
371 static int cron_conv(int, struct pam_message **,
372 struct pam_response **, void *);
373
374 static struct pam_conv pam_conv = {cron_conv, NULL};
375 static pam_handle_t *pamh; /* Authentication handle */
376
377 /*
378 * Function to help check a user's credentials.
379 */
658 } else {
659 eprev = e;
660 e = e->link;
661 }
662 }
663 break;
664 }
665 next_event = NULL;
666 }
667
668 /*NOTREACHED*/
669 }
670
671 static void
672 initialize(int firstpass)
673 {
674 #ifdef DEBUG
675 (void) fprintf(stderr, "in initialize\n");
676 #endif
677 if (firstpass) {
678 /* for mail(1), make sure messages come from root */
679 if (putenv("LOGNAME=root") != 0) {
680 crabort("cannot expand env variable",
681 REMOVE_FIFO|CONSOLE_MSG);
682 }
683 if (access(FIFO, R_OK) == -1) {
684 if (errno == ENOENT) {
685 if (mknod(FIFO, S_IFIFO|0600, 0) != 0)
686 crabort("cannot create fifo queue",
687 REMOVE_FIFO|CONSOLE_MSG);
688 } else {
689 if (NOFORK) {
690 /* didn't fork... init(1M) is waiting */
691 (void) sleep(60);
692 }
693 perror("FIFO");
694 crabort("cannot access fifo queue",
695 REMOVE_FIFO|CONSOLE_MSG);
696 }
697 } else {
698 if (NOFORK) {
699 /* didn't fork... init(1M) is waiting */
700 (void) sleep(60);
701 /*
702 * the wait is painful, but we don't want
703 * init respawning this quickly
704 */
705 }
706 crabort("cannot start cron; FIFO exists", CONSOLE_MSG);
707 }
708 }
709
710 if ((msgfd = open(FIFO, O_RDWR)) < 0) {
711 perror("! open");
712 crabort("cannot open fifo queue", REMOVE_FIFO|CONSOLE_MSG);
713 }
714
715 init_time = time(NULL);
716 el_init(8, init_time, (time_t)(60*60*24), 10);
717
718 init_time = time(NULL);
719 el_init(8, init_time, (time_t)(60*60*24), 10);
720
721 /*
722 * read directories, create users list, and add events to the
723 * main event list. Only zero user list on firstpass.
724 */
725 if (firstpass)
726 uhead = NULL;
727 read_dirs(firstpass);
728 next_event = NULL;
2707 struct passwd *ruser_ids;
2708 FILE *mailpipe;
2709 FILE *st;
2710 struct utsname name;
2711 int nbytes;
2712 char iobuf[BUFSIZ];
2713 char *cmd;
2714
2715 (void) uname(&name);
2716 if ((ruser_ids = getpwnam(p->name)) == NULL)
2717 exit(0);
2718 (void) setuid(ruser_ids->pw_uid);
2719
2720 cmd = xmalloc(strlen(MAIL) + strlen(p->name)+2);
2721 (void) sprintf(cmd, "%s %s", MAIL, p->name);
2722 mailpipe = popen(cmd, "w");
2723 free(cmd);
2724 if (mailpipe == NULL)
2725 exit(127);
2726 (void) fprintf(mailpipe, "To: %s\n", p->name);
2727 if (pr->jobtype == CRONEVENT) {
2728 (void) fprintf(mailpipe, CRONOUT);
2729 (void) fprintf(mailpipe, "Your \"cron\" job on %s\n",
2730 name.nodename);
2731 if (pr->jobname != NULL) {
2732 (void) fprintf(mailpipe, "%s\n\n", pr->jobname);
2733 }
2734 } else {
2735 (void) fprintf(mailpipe, "Subject: Output from \"at\" job\n\n");
2736 (void) fprintf(mailpipe, "Your \"at\" job on %s\n",
2737 name.nodename);
2738 if (pr->jobname != NULL) {
2739 (void) fprintf(mailpipe, "\"%s\"\n\n", pr->jobname);
2740 }
2741 }
2742 /* Tmp. file is fopen'ed w/ "r", secure open */
2743 if (filesize > 0 &&
2744 (st = fopen(pr->outfile, "r")) != NULL) {
2745 (void) fprintf(mailpipe,
2746 "produced the following output:\n\n");
2747 while ((nbytes = fread(iobuf, sizeof (char), BUFSIZ, st)) != 0)
2748 (void) fwrite(iobuf, sizeof (char), nbytes, mailpipe);
|
55 #include <fcntl.h>
56 #include <grp.h>
57 #include <libcontract.h>
58 #include <libcontract_priv.h>
59 #include <limits.h>
60 #include <locale.h>
61 #include <poll.h>
62 #include <project.h>
63 #include <pwd.h>
64 #include <signal.h>
65 #include <stdarg.h>
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <string.h>
69 #include <stropts.h>
70 #include <time.h>
71 #include <unistd.h>
72 #include <libzoneinfo.h>
73
74 #include "cron.h"
75 #include "cron_scf.h"
76
77 /*
78 * #define DEBUG
79 */
80
81 #define MAIL "/usr/bin/mail" /* mail program to use */
82 #define CONSOLE "/dev/console" /* where messages go when cron dies */
83
84 #define TMPINFILE "/tmp/crinXXXXXX" /* file to put stdin in for cmd */
85 #define TMPDIR "/tmp"
86 #define PFX "crout"
87 #define TMPOUTFILE "/tmp/croutXXXXXX" /* file to place stdout, stderr */
88
89 #define INMODE 00400 /* mode for stdin file */
90 #define OUTMODE 00600 /* mode for stdout file */
91 #define ISUID S_ISUID /* mode for verifing at jobs */
92
93 #define INFINITY 2147483647L /* upper bound on time */
94 #define CUSHION 180L
95 #define ZOMB 100 /* proc slot used for mailing output */
130 #define BADTYPE "crontab or at-job file is not a regular file.\n"
131 #define NOSTDIN "unable to create a standard input file for \
132 one of your crontab commands. \
133 \nThat command was not executed."
134
135 #define NOTALLOWED "you are not authorized to use cron. Sorry."
136 #define STDERRMSG "\n\n********************************************\
137 *****\nCron: The previous message is the \
138 standard output and standard error \
139 \nof one of your cron commands.\n"
140
141 #define STDOUTERR "one of your commands generated output or errors, \
142 but cron was unable to mail you this output.\
143 \nRemember to redirect standard output and standard \
144 error for each of your commands."
145
146 #define CLOCK_DRIFT "clock time drifted backwards after event!\n"
147 #define PIDERR "unexpected pid returned %d (ignored)"
148 #define CRONTABERR "Subject: Your crontab file has an error in it\n\n"
149 #define CRONOUT "Subject: Output from \"cron\" command\n\n"
150 #define CRONOUTNEW "Subject: Cron <%s@%s>: %s\n\n"
151 #define MALLOCERR "out of space, cannot create new string\n"
152
153 #define DIDFORK didfork
154 #define NOFORK !didfork
155
156 #define MAILBUFLEN (8*1024)
157 #define LINELIMIT 80
158 #define MAILBINITFREE (MAILBUFLEN - (sizeof (cte_intro) - 1) \
159 - (sizeof (cte_trail1) - 1) - (sizeof (cte_trail2) - 1) - 1)
160
161 #define ERR_CRONTABENT 0 /* error in crontab file entry */
162 #define ERR_UNIXERR 1 /* error in some system call */
163 #define ERR_CANTEXECCRON 2 /* error setting up "cron" job environment */
164 #define ERR_CANTEXECAT 3 /* error setting up "at" job environment */
165 #define ERR_NOTREG 4 /* error not a regular file */
166
167 #define PROJECT "project="
168
169 #define MAX_LOST_CONTRACTS 2048 /* reset if this many failed abandons */
170
342 static void cte_sendmail(char *);
343
344 static int set_user_cred(const struct usr *, struct project *);
345
346 static struct shared *create_shared_str(char *str);
347 static struct shared *dup_shared(struct shared *obj);
348 static void rel_shared(struct shared *obj);
349 static void *get_obj(struct shared *obj);
350 /*
351 * last_time is set immediately prior to exection of an event (via ex())
352 * to indicate the last time an event was executed. This was (surely)
353 * it's original intended use.
354 */
355 static time_t last_time, init_time, t_old;
356 static int reset_needed; /* set to 1 when cron(1M) needs to re-initialize */
357
358 static int refresh;
359 static sigset_t defmask, sigmask;
360
361 /*
362 * Configuration from smf(5)
363 */
364 static int legacy_subject;
365 static int extra_headers;
366
367 /*
368 * BSM hooks
369 */
370 extern int audit_cron_session(char *, char *, uid_t, gid_t, char *);
371 extern void audit_cron_new_job(char *, int, void *);
372 extern void audit_cron_bad_user(char *);
373 extern void audit_cron_user_acct_expired(char *);
374 extern int audit_cron_create_anc_file(char *, char *, char *, uid_t);
375 extern int audit_cron_delete_anc_file(char *, char *);
376 extern int audit_cron_is_anc_name(char *);
377 extern int audit_cron_mode();
378
379 static int cron_conv(int, struct pam_message **,
380 struct pam_response **, void *);
381
382 static struct pam_conv pam_conv = {cron_conv, NULL};
383 static pam_handle_t *pamh; /* Authentication handle */
384
385 /*
386 * Function to help check a user's credentials.
387 */
666 } else {
667 eprev = e;
668 e = e->link;
669 }
670 }
671 break;
672 }
673 next_event = NULL;
674 }
675
676 /*NOTREACHED*/
677 }
678
679 static void
680 initialize(int firstpass)
681 {
682 #ifdef DEBUG
683 (void) fprintf(stderr, "in initialize\n");
684 #endif
685 if (firstpass) {
686 int val;
687 /* for mail(1), make sure messages come from root */
688 if (putenv("LOGNAME=root") != 0) {
689 crabort("cannot expand env variable",
690 REMOVE_FIFO|CONSOLE_MSG);
691 }
692 if (access(FIFO, R_OK) == -1) {
693 if (errno == ENOENT) {
694 if (mknod(FIFO, S_IFIFO|0600, 0) != 0)
695 crabort("cannot create fifo queue",
696 REMOVE_FIFO|CONSOLE_MSG);
697 } else {
698 if (NOFORK) {
699 /* didn't fork... init(1M) is waiting */
700 (void) sleep(60);
701 }
702 perror("FIFO");
703 crabort("cannot access fifo queue",
704 REMOVE_FIFO|CONSOLE_MSG);
705 }
706 } else {
707 if (NOFORK) {
708 /* didn't fork... init(1M) is waiting */
709 (void) sleep(60);
710 /*
711 * the wait is painful, but we don't want
712 * init respawning this quickly
713 */
714 }
715 crabort("cannot start cron; FIFO exists", CONSOLE_MSG);
716 }
717 switch (init_scf()) {
718 case 0:
719 val = get_config_boolean("legacy_subject");
720 legacy_subject = (val < 0 ? 0 : val);
721 val = get_config_boolean("extra_headers");
722 extra_headers = (val < 0 ? 1 : val);
723 break;
724 case -2:
725 crabort("cron not running under smf(5)",
726 REMOVE_FIFO|CONSOLE_MSG);
727 break;
728 default:
729 crabort("could not initialise libscf",
730 REMOVE_FIFO|CONSOLE_MSG);
731 }
732 }
733
734 if ((msgfd = open(FIFO, O_RDWR)) < 0) {
735 perror("! open");
736 crabort("cannot open fifo queue", REMOVE_FIFO|CONSOLE_MSG);
737 }
738
739 init_time = time(NULL);
740 el_init(8, init_time, (time_t)(60*60*24), 10);
741
742 init_time = time(NULL);
743 el_init(8, init_time, (time_t)(60*60*24), 10);
744
745 /*
746 * read directories, create users list, and add events to the
747 * main event list. Only zero user list on firstpass.
748 */
749 if (firstpass)
750 uhead = NULL;
751 read_dirs(firstpass);
752 next_event = NULL;
2731 struct passwd *ruser_ids;
2732 FILE *mailpipe;
2733 FILE *st;
2734 struct utsname name;
2735 int nbytes;
2736 char iobuf[BUFSIZ];
2737 char *cmd;
2738
2739 (void) uname(&name);
2740 if ((ruser_ids = getpwnam(p->name)) == NULL)
2741 exit(0);
2742 (void) setuid(ruser_ids->pw_uid);
2743
2744 cmd = xmalloc(strlen(MAIL) + strlen(p->name)+2);
2745 (void) sprintf(cmd, "%s %s", MAIL, p->name);
2746 mailpipe = popen(cmd, "w");
2747 free(cmd);
2748 if (mailpipe == NULL)
2749 exit(127);
2750 (void) fprintf(mailpipe, "To: %s\n", p->name);
2751 if (extra_headers) {
2752 (void) fprintf(mailpipe, "X-Mailer: cron (%s %s)\n",
2753 name.sysname, name.release);
2754 (void) fprintf(mailpipe, "X-Cron-User: %s\n", p->name);
2755 (void) fprintf(mailpipe, "X-Cron-Host: %s\n", name.nodename);
2756 (void) fprintf(mailpipe, "X-Cron-Job-Name: %s\n", pr->jobname);
2757 (void) fprintf(mailpipe, "X-Cron-Job-Type: %s\n",
2758 (pr->jobtype == CRONEVENT ? "cron" : "at"));
2759 }
2760 if (pr->jobtype == CRONEVENT) {
2761 if (legacy_subject)
2762 (void) fprintf(mailpipe, CRONOUT);
2763 else
2764 (void) fprintf(mailpipe, CRONOUTNEW,
2765 p->name, name.nodename, pr->jobname);
2766 (void) fprintf(mailpipe, "Your \"cron\" job on %s\n",
2767 name.nodename);
2768 if (pr->jobname != NULL) {
2769 (void) fprintf(mailpipe, "%s\n\n", pr->jobname);
2770 }
2771 } else {
2772 (void) fprintf(mailpipe, "Subject: Output from \"at\" job\n\n");
2773 (void) fprintf(mailpipe, "Your \"at\" job on %s\n",
2774 name.nodename);
2775 if (pr->jobname != NULL) {
2776 (void) fprintf(mailpipe, "\"%s\"\n\n", pr->jobname);
2777 }
2778 }
2779 /* Tmp. file is fopen'ed w/ "r", secure open */
2780 if (filesize > 0 &&
2781 (st = fopen(pr->outfile, "r")) != NULL) {
2782 (void) fprintf(mailpipe,
2783 "produced the following output:\n\n");
2784 while ((nbytes = fread(iobuf, sizeof (char), BUFSIZ, st)) != 0)
2785 (void) fwrite(iobuf, sizeof (char), nbytes, mailpipe);
|