Print this page
374 cron should send more useful mail


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