Bug 235136

Summary: cron email header has bogus date value
Product: Base System Reporter: Mike Lempriere <ml-freebsd.org>
Component: binAssignee: freebsd-bugs (Nobody) <bugs>
Status: New ---    
Severity: Affects Only Me CC: michaelo
Priority: ---    
Version: 11.2-RELEASE   
Hardware: Any   
OS: Any   
See Also: https://github.com/rspamd/rspamd/issues/3255

Description Mike Lempriere 2019-01-22 18:54:42 UTC
Obscure problem with 'cron'.

I have a script that fires hourly, normally producing no output, thus no email.  It has started reporting a problem (nothing to do with FreeBSD), thus is now emailing me output hourly.

The problem is that the email coming through my 'spamassassin' filter, is getting flagged as 'DATE_IN_FUTURE'_*.  (This forces it into the "probably spam" range.)  As time goes by, this will go up from '_06_12' to '_12_24', etc.

Looking at the Recieved: headers, it appears that the email arrives from 'localhost' with a time setting that does not change, regardless of the time the 'cron' job fired.

And, in fact, the time appears to be pretty close to the boot time of the system.

My guess is that when 'cron' builds the header of the email, for the "Date:" it's using the start time of the 'cron' daemon, instead of properly using the time of this 'cron' job.  I guess I would expect it should be using the time _now_, as opposed to the time the job was started, but I'll let you figure that out.
Comment 1 Michael Osipov freebsd_committer freebsd_triage 2024-04-10 18:32:58 UTC
Does this still happen, looking at the code I guess it is updated:
> osipovmi@deblndw011x:~/var/Projekte/freebsd/src/usr.sbin/cron (main =)
> $ grep -r TargetTime .
> ./cron/cron.c:                                  tm = localtime(&TargetTime);
> ./cron/cron.c:          TargetTime += (secres1 != 0) ? 1 : 60;
> ./cron/cron.c:                          e->lastexit = TargetTime;
> ./cron/cron.c:  struct tm *tm = localtime(&TargetTime);
> ./cron/cron.c:  && TargetTime > last_time /* exclude stepping back */
> ./cron/cron.c:                  difflimit = TargetTime + diff;
> ./cron/cron.c:                                  if ( e->lastrun >= TargetTime )
> ./cron/cron.c:                                  if ( e->lastrun < TargetTime - 3600 )
> ./cron/cron.c:                  difflimit = TargetTime - diff;
> ./cron/cron.c:          if (last_time == 0 || TargetTime >= difflimit) {
> ./cron/cron.c:                  time_t difftime = TargetTime + tm->tm_gmtoff - diff;
> ./cron/cron.c:                              TargetTime >= e->lastexit + e->interval)
> ./cron/cron.c:                                          e->lastrun = TargetTime;
> ./cron/cron.c:                          e->lastrun = TargetTime;
> ./cron/cron.c:  last_time = TargetTime;
> ./cron/cron.c: * following minute and initialize TargetTime to this value.  TargetTime
> ./cron/cron.c:  TargetTime = time((time_t*)0);
> ./cron/cron.c:          TargetTime += 1;
> ./cron/cron.c:          tm = localtime(&TargetTime);
> ./cron/cron.c:          TargetTime += (60 - tm->tm_sec);
> ./cron/cron.c:          ttime.tv_sec = TargetTime;
> ./cron/cron.c:          Debug(DSCH, ("[%d] TargetTime=%ld, sec-to-wait=%d\n",
> ./cron/cron.c:                  getpid(), (long)TargetTime, seconds_to_wait))
> ./cron/database.c:               * TargetTime == 0 when we're initially populating the database,
> ./cron/database.c:               * and TargetTime > 0 any time after that (i.e. we're reloading
> ./cron/database.c:              if (TargetTime != 0) {
> ./cron/do_command.c:                                    arpadate(&TargetTime));
> ./cron/globals.h:XTRN time_t    TargetTime INIT(0);
Comment 2 Mike Lempriere 2024-04-12 17:58:59 UTC
I barely even remember this one...  I worked around my issue by lowering spamassassin scores, so haven't paid it further attention.

However, looking closely now at email source headers, I am still seeing DATE_IN_FUTURE_03_06 in my built-in "daily run" cron emails.  The Received headers and Date all agree on the time of 03:02:03.  This job (I believe) is started by /etc/crontab which shows:
    1       3       *       *       *       root    periodic daily
meaning it starts at 03:01.  Just trying 'periodic daily' on the command line it's about a min to run, and that's what we're seeing in the email header.
Here's the sample I'm looking at:
    Date: Sat, 6 Apr 2024 03:02:03 -0700 (PDT)
Looking at RFC 2822, I'm not sure that the closing "(PDT)" is compliant, so perhaps the fault could be considered to be cron.  However, if this is compliant, and this is my incomplete understanding of the RFC, that would mean that cron is fine, and spamassassin is misunderstanding the headers.
Comment 3 Michael Osipov freebsd_committer freebsd_triage 2024-04-15 09:16:41 UTC
Here is the updated spec: https://datatracker.ietf.org/doc/html/rfc5322#section-3.3

You are right, but I think that the issue with the format isn't in cron itself regardless of th invalid time value.
This what I see: Date: Mon, 15 Apr 2024 10:59:00 +0200 (CEST)
That value isn't comming from cron:
> 560 #ifdef MAIL_DATE
> 561 /* Sat, 27 Feb 93 11:44:51 CST
> 562  * 123456789012345678901234567
> 563  */
> 564 char *
> 565 arpadate(clock)
> 566     time_t *clock;
> 567 {
> 568     time_t t = clock ?*clock :time(0L);
> 569     struct tm *tm = localtime(&t);
> 570     static char ret[32];    /* zone name might be >3 chars */
> 571
> 572     if (tm->tm_year >= 100)
> 573         tm->tm_year += 1900;
> 574
> 575     (void) snprintf(ret, sizeof(ret), "%s, %2d %s %d %02d:%02d:%02d %s",
> 576                DowNames[tm->tm_wday],
> 577                tm->tm_mday,
> 578                MonthNames[tm->tm_mon],
> 579                tm->tm_year,
> 580                tm->tm_hour,
> 581                tm->tm_min,
> 582                tm->tm_sec,
> 583                TZONE(*tm));
> 584     return ret;
> 585 }
> 586 #endif /*MAIL_DATE*/

TZONE macro looks fine to me. Now look into config.h:
 58
 59 /* #define MAIL_DATE */             /*-*/
 60             /* should we include an ersatz Date: header in
 61              * generated mail?  if you are using sendmail
 62              * for MAILCMD, it is better to let sendmail
 63              * generate the Date: header.
 64              */

So I consider the sendmail command is producing this value. If you are running from stable can you enable that MAIL_DATE macro and see what happens? As it really turns out: "Date: ..." isn't produced by cron at all.
Comment 5 Michael Osipov freebsd_committer freebsd_triage 2024-04-15 09:29:38 UTC
If you happen to run Postfix like me then it is broken there as well: https://github.com/vdukhovni/postfix/blob/a6993c3a48ebc3ac6cefd9913dab4b8c23b66ab8/postfix/src/global/mail_date.c#L125-L130