Print this page
374 cron should send more useful mail
Reviewed by: Richard Lowe <richlowe@richlowe.net>


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.


  24  */
  25 
  26 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  27 /*        All Rights Reserved   */
  28 
  29 /*      Copyright (c) 1987, 1988 Microsoft Corporation  */
  30 /*        All Rights Reserved   */
  31 
  32 #ifdef lint
  33 /* make lint happy */
  34 #define __EXTENSIONS__
  35 #endif
  36 
  37 #include <sys/contract/process.h>
  38 #include <sys/ctfs.h>
  39 #include <sys/param.h>
  40 #include <sys/resource.h>
  41 #include <sys/stat.h>
  42 #include <sys/task.h>
  43 #include <sys/time.h>


 128 #define NOREAD          "can't read your crontab file.  Resubmit it."
 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 


2694         }
2695 
2696         free_if_unused(p);
2697 }
2698 
2699 /*
2700  * Mail stdout and stderr of a job to user. Get uid for real user and become
2701  * that person. We do this so that mail won't come from root since this
2702  * could be a security hole. If failure, quit - don't send mail as root.
2703  */
2704 static void
2705 mail_result(struct usr *p, struct runinfo *pr, size_t filesize)
2706 {
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);
2749                 (void) fclose(st);
2750         } else {
2751                 (void) fprintf(mailpipe, "completed.\n");
2752         }
2753         (void) pclose(mailpipe);
2754         exit(0);
2755 }
2756 
2757 static int
2758 msg_wait(long tim)
2759 {
2760         struct  message msg;
2761         int     cnt;
2762         time_t  reftime;
2763         fd_set  fds;
2764         struct timespec tout, *toutp;
2765         static int      pending_msg;
2766         static time_t   pending_reftime;
2767 
2768         if (pending_msg) {
2769                 process_msg(&msgbuf, pending_reftime);
2770                 pending_msg = 0;
2771                 return (0);




   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  *
  25  * Copyright 2013 Joshua M. Clulow <josh@sysmgr.org>
  26  */
  27 
  28 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  29 /*        All Rights Reserved   */
  30 
  31 /*      Copyright (c) 1987, 1988 Microsoft Corporation  */
  32 /*        All Rights Reserved   */
  33 
  34 #ifdef lint
  35 /* make lint happy */
  36 #define __EXTENSIONS__
  37 #endif
  38 
  39 #include <sys/contract/process.h>
  40 #include <sys/ctfs.h>
  41 #include <sys/param.h>
  42 #include <sys/resource.h>
  43 #include <sys/stat.h>
  44 #include <sys/task.h>
  45 #include <sys/time.h>


 130 #define NOREAD          "can't read your crontab file.  Resubmit it."
 131 #define BADTYPE         "crontab or at-job file is not a regular file.\n"
 132 #define NOSTDIN         "unable to create a standard input file for \
 133 one of your crontab commands. \
 134 \nThat command was not executed."
 135 
 136 #define NOTALLOWED      "you are not authorized to use cron.  Sorry."
 137 #define STDERRMSG       "\n\n********************************************\
 138 *****\nCron: The previous message is the \
 139 standard output and standard error \
 140 \nof one of your cron commands.\n"
 141 
 142 #define STDOUTERR       "one of your commands generated output or errors, \
 143 but cron was unable to mail you this output.\
 144 \nRemember to redirect standard output and standard \
 145 error for each of your commands."
 146 
 147 #define CLOCK_DRIFT     "clock time drifted backwards after event!\n"
 148 #define PIDERR          "unexpected pid returned %d (ignored)"
 149 #define CRONTABERR      "Subject: Your crontab file has an error in it\n\n"

 150 #define MALLOCERR       "out of space, cannot create new string\n"
 151 
 152 #define DIDFORK didfork
 153 #define NOFORK !didfork
 154 
 155 #define MAILBUFLEN      (8*1024)
 156 #define LINELIMIT       80
 157 #define MAILBINITFREE   (MAILBUFLEN - (sizeof (cte_intro) - 1) \
 158             - (sizeof (cte_trail1) - 1) - (sizeof (cte_trail2) - 1) - 1)
 159 
 160 #define ERR_CRONTABENT  0       /* error in crontab file entry */
 161 #define ERR_UNIXERR     1       /* error in some system call */
 162 #define ERR_CANTEXECCRON 2      /* error setting up "cron" job environment */
 163 #define ERR_CANTEXECAT  3       /* error setting up "at" job environment */
 164 #define ERR_NOTREG      4       /* error not a regular file */
 165 
 166 #define PROJECT         "project="
 167 
 168 #define MAX_LOST_CONTRACTS      2048    /* reset if this many failed abandons */
 169 


2695         }
2696 
2697         free_if_unused(p);
2698 }
2699 
2700 /*
2701  * Mail stdout and stderr of a job to user. Get uid for real user and become
2702  * that person. We do this so that mail won't come from root since this
2703  * could be a security hole. If failure, quit - don't send mail as root.
2704  */
2705 static void
2706 mail_result(struct usr *p, struct runinfo *pr, size_t filesize)
2707 {
2708         struct  passwd  *ruser_ids;
2709         FILE    *mailpipe;
2710         FILE    *st;
2711         struct utsname  name;
2712         int     nbytes;
2713         char    iobuf[BUFSIZ];
2714         char    *cmd;
2715         char    *lowname = (pr->jobtype == CRONEVENT ? "cron" : "at");
2716 
2717         (void) uname(&name);
2718         if ((ruser_ids = getpwnam(p->name)) == NULL)
2719                 exit(0);
2720         (void) setuid(ruser_ids->pw_uid);
2721 
2722         cmd = xmalloc(strlen(MAIL) + strlen(p->name)+2);
2723         (void) sprintf(cmd, "%s %s", MAIL, p->name);
2724         mailpipe = popen(cmd, "w");
2725         free(cmd);
2726         if (mailpipe == NULL)
2727                 exit(127);
2728         (void) fprintf(mailpipe, "To: %s\n", p->name);
2729         (void) fprintf(mailpipe, "Subject: %s <%s@%s> %s\n",
2730             (pr->jobtype == CRONEVENT ? "Cron" : "At"),
2731             p->name, name.nodename, pr->jobname);
2732 
2733         /*
2734          * RFC3834 (Section 5) defines the Auto-Submitted header to prevent
2735          * vacation replies, et al, from being sent in response to
2736          * machine-generated mail.
2737          */
2738         (void) fprintf(mailpipe, "Auto-Submitted: auto-generated\n");
2739 
2740         /*
2741          * Additional headers for mail filtering and diagnostics:
2742          */
2743         (void) fprintf(mailpipe, "X-Mailer: cron (%s %s)\n", name.sysname,
2744             name.release);
2745         (void) fprintf(mailpipe, "X-Cron-User: %s\n", p->name);
2746         (void) fprintf(mailpipe, "X-Cron-Host: %s\n", name.nodename);
2747         (void) fprintf(mailpipe, "X-Cron-Job-Name: %s\n", pr->jobname);
2748         (void) fprintf(mailpipe, "X-Cron-Job-Type: %s\n", lowname);
2749 
2750         /*
2751          * Message Body:
2752          *
2753          * (Temporary file is fopen'ed with "r", secure open.)
2754          */
2755         (void) fprintf(mailpipe, "\n");
2756         if (filesize > 0 &&
2757             (st = fopen(pr->outfile, "r")) != NULL) {


2758                 while ((nbytes = fread(iobuf, sizeof (char), BUFSIZ, st)) != 0)
2759                         (void) fwrite(iobuf, sizeof (char), nbytes, mailpipe);
2760                 (void) fclose(st);
2761         } else {
2762                 (void) fprintf(mailpipe, "Job completed with no output.\n");
2763         }
2764         (void) pclose(mailpipe);
2765         exit(0);
2766 }
2767 
2768 static int
2769 msg_wait(long tim)
2770 {
2771         struct  message msg;
2772         int     cnt;
2773         time_t  reftime;
2774         fd_set  fds;
2775         struct timespec tout, *toutp;
2776         static int      pending_msg;
2777         static time_t   pending_reftime;
2778 
2779         if (pending_msg) {
2780                 process_msg(&msgbuf, pending_reftime);
2781                 pending_msg = 0;
2782                 return (0);