]> git.ipfire.org Git - thirdparty/fcron.git/commitdiff
Rename config key displayname to maildisplayname, and refactor. (#33)
authorThibault Godouet <yo8192@users.noreply.github.com>
Sat, 24 Aug 2024 22:40:44 +0000 (23:40 +0100)
committerGitHub <noreply@github.com>
Sat, 24 Aug 2024 22:40:44 +0000 (23:40 +0100)
The main changes are:

-  rename the fcron.conf config key displayname into maildisplayname, for clarity.
-   move the underlying code into its own mail.c file, with some refactoring to improve clarity and simplify slightly.
-   extend the extra overflow tests to test at the limit, and just over the limit (expecting an overflow error)
-   ensure things work on systems which don't have stdbool.h (which is C99)

Full commit list:
* fix compilation error (couldn't find selinux.h)
* Rename boolean variable names.
* Check for stdbool.h's availability.
* Refactor maildisplayname.
* Move format_displayname() and make_mailbox_addr() into their own file.
* Ignore test binary.
* Rename option displayname to maildisplayname.

19 files changed:
.gitignore
Makefile.in
config.h.in
configure.in
doc/en/fcron.conf.5.sgml
doc/fcron-doc.mod.in
fcronconf.c
fcronconf.h
fcrondyn_svr.c
fileconf.c
files/fcron.conf.in
global.h
job.c
job.h
mail.c [new file with mode: 0644]
mail.h [new file with mode: 0644]
script/gen-in.pl
test/Makefile.in
test/mailbox_addr.c

index 17c2b5a939e8da7f0d1493a61b21eb4bb10abfc0..73e818188a9259336d6f5de4414431a4e9f6c3ec 100644 (file)
@@ -27,6 +27,7 @@ doc/fr/HTML/*
 doc/fr/man/*
 doc/fr/txt/*
 configure
+test/mailbox_addr
 tests/test-open*
 tests/test-types*
 tests/test-uidgid*
index 79b1583b82cf27c5ffcd0d26cbff2e1f3b2ae490..c82582fda4146f6d8d518ed8118e74873af98b68 100644 (file)
@@ -20,42 +20,42 @@ SRCDIR        := @srcdir@
 DESTDIR       :=
 
 # Where should we install it ?
-prefix         = @prefix@
-exec_prefix    = @exec_prefix@
-DESTSBIN       = @sbindir@
-DESTBIN        = @bindir@
-ETC            = @sysconfdir@
-FCRONTABS      = @FCRONTABS@
-PIDDIR         = @PIDDIR@
-FIFODIR        = @FIFODIR@
-PIDFILE        = @PIDFILE@
-REBOOT_LOCK    = @REBOOT_LOCK@
-SUSPEND_FILE   = @SUSPEND_FILE@
-FIFOFILE       = @FIFOFILE@
-FCRON_SHELL    = @FCRON_SHELL@
-SENDMAIL       = @SENDMAIL@
-FCRON_EDITOR   = @FCRON_EDITOR@
-OPTIM         := @CFLAGS@
-LDFLAGS       := @LDFLAGS@
-CPPFLAGS      := @CPPFLAGS@ -I. -I${SRCDIR}
-LIBS          := @LIBS@
-LIBOBJS       := @LIBOBJS@
-DEFS          := @DEFS@
-CC            := @CC@
-INSTALL       := @INSTALL@
-STRIP         := @STRIP@
-ROOTNAME      := @ROOTNAME@
-ROOTGROUP     := @ROOTGROUP@
-USERNAME      := @USERNAME@
-GROUPNAME     := @GROUPNAME@
-SYSFCRONTAB   := @SYSFCRONTAB@
-DEBUG         := @DEBUG@
-BOOTINSTALL   := @BOOTINSTALL@
-ANSWERALL     := @ANSWERALL@
-USEPAM        := @USEPAM@
-FCRONDYN      := @FCRONDYN@
-SYSTEMD_DIR   := @SYSTEMD_DIR@
-DISPLAYNAME   := @DISPLAYNAME@
+prefix           = @prefix@
+exec_prefix      = @exec_prefix@
+DESTSBIN         = @sbindir@
+DESTBIN          = @bindir@
+ETC              = @sysconfdir@
+FCRONTABS        = @FCRONTABS@
+PIDDIR           = @PIDDIR@
+FIFODIR          = @FIFODIR@
+PIDFILE          = @PIDFILE@
+REBOOT_LOCK      = @REBOOT_LOCK@
+SUSPEND_FILE     = @SUSPEND_FILE@
+FIFOFILE         = @FIFOFILE@
+FCRON_SHELL      = @FCRON_SHELL@
+SENDMAIL         = @SENDMAIL@
+FCRON_EDITOR     = @FCRON_EDITOR@
+OPTIM           := @CFLAGS@
+LDFLAGS         := @LDFLAGS@
+CPPFLAGS        := @CPPFLAGS@ -I. -I${SRCDIR}
+LIBS            := @LIBS@
+LIBOBJS         := @LIBOBJS@
+DEFS            := @DEFS@
+CC              := @CC@
+INSTALL         := @INSTALL@
+STRIP           := @STRIP@
+ROOTNAME        := @ROOTNAME@
+ROOTGROUP       := @ROOTGROUP@
+USERNAME        := @USERNAME@
+GROUPNAME       := @GROUPNAME@
+SYSFCRONTAB     := @SYSFCRONTAB@
+DEBUG           := @DEBUG@
+BOOTINSTALL     := @BOOTINSTALL@
+ANSWERALL       := @ANSWERALL@
+USEPAM          := @USEPAM@
+FCRONDYN        := @FCRONDYN@
+SYSTEMD_DIR     := @SYSTEMD_DIR@
+MAILDISPLAYNAME := @MAILDISPLAYNAME@
 
 # Options
 #   -DDEBUG             even more verbose
@@ -76,12 +76,12 @@ CFLAGS        += $(OPTIM) $(OPTION) $(DEFS) $(CPPFLAGS) $(LDFLAGS)
 ifeq ($(FCRONDYN), 1)
        LIBOBJS   := $(LIBOBJS)
 endif
-OBJSD         := fcron.o cl.o subs.o mem.o save.o temp_file.o log.o database.o job.o conf.o u_list.o exe_list.o lavg_list.o env_list.o fcronconf.o filesubs.o select.o fcrondyn_svr.o suspend.o $(LIBOBJS)
-OBJSTAB       := fcrontab.o cl.o subs.o mem.o save.o temp_file.o  log.o fileconf.o allow.o read_string.o u_list.o env_list.o fcronconf.o filesubs.o
-OBJSDYN       := fcrondyn.o subs.o mem.o log.o allow.o read_string.o fcronconf.o filesubs.o
-OBJCONV       := convert-fcrontab.o cl.o subs.o mem.o save.o log.o u_list.o env_list.o fcronconf.o filesubs.o
-OBJSIG        := fcronsighup.o subs.o mem.o log.o allow.o fcronconf.o filesubs.o
-HEADERSALL    := config.h $(SRCDIR)/global.h $(SRCDIR)/cl.h $(SRCDIR)/log.h $(SRCDIR)/subs.h $(SRCDIR)/mem.h $(SRCDIR)/save.h $(SRCDIR)/option.h $(SRCDIR)/dyncom.h
+OBJSD         := fcron.o cl.o subs.o mem.o save.o temp_file.o log.o database.o job.o conf.o u_list.o exe_list.o lavg_list.o env_list.o fcronconf.o mail.o filesubs.o select.o fcrondyn_svr.o suspend.o $(LIBOBJS)
+OBJSTAB       := fcrontab.o cl.o subs.o mem.o save.o temp_file.o log.o fileconf.o allow.o read_string.o u_list.o env_list.o fcronconf.o mail.o filesubs.o
+OBJSDYN       := fcrondyn.o subs.o mem.o log.o allow.o read_string.o fcronconf.o mail.o filesubs.o
+OBJCONV       := convert-fcrontab.o cl.o subs.o mem.o save.o log.o u_list.o env_list.o fcronconf.o mail.o filesubs.o
+OBJSIG        := fcronsighup.o subs.o mem.o log.o allow.o fcronconf.o mail.o filesubs.o
+HEADERSALL    := config.h $(SRCDIR)/global.h $(SRCDIR)/cl.h $(SRCDIR)/log.h $(SRCDIR)/subs.h $(SRCDIR)/mem.h $(SRCDIR)/save.h $(SRCDIR)/option.h $(SRCDIR)/dyncom.h $(SRCDIR)/mail.h
 
 # this is a regular expression :
 # do not ci automaticaly generated files and doc (done by doc's Makefile)
@@ -127,7 +127,7 @@ exe_list_test: exe_list.o u_list.o exe_list_test.o log.o subs.o
        -DFCRONTABS="\"${FCRONTABS}\"" \
        -DFCRON_ALLOW="\"${FCRON_ALLOW}\"" -DFCRON_DENY="\"${FCRON_DENY}\"" \
        -DFCRON_SHELL="\"${FCRON_SHELL}\"" -DSENDMAIL="\"${SENDMAIL}\"" \
-       -DFCRON_EDITOR="\"${FCRON_EDITOR}\"" \-DDISPLAYNAME="\"${DISPLAYNAME}\"" -DBINDIREX="\"${DESTBIN}\"" \
+       -DFCRON_EDITOR="\"${FCRON_EDITOR}\"" \-DMAILDISPLAYNAME="\"${MAILDISPLAYNAME}\"" -DBINDIREX="\"${DESTBIN}\"" \
        -c $<
 
 initscripts:
@@ -140,7 +140,7 @@ documentation:
        $(MAKE) -C doc doc-if-none
 
 .PHONY: test
-test:
+test: fcron
        $(MAKE) -C test tests
 
 
index 5d73f2a3eb848e8285d673141355b194bcfe2dc3..7a03ef1a53396879320eefb8de3eaf5af4537af3 100644 (file)
 /* Define if you have <shadow.h>.  */
 #undef HAVE_SHADOW_H
 
+/* Define if you have <stdbool.h>.  */
+#undef HAVE_STDBOOL_H
+
 /* Define if you have the unsetenv function.  */
 #undef HAVE_UNSETENV
 
index 7ef4b45c2b707ee1bf655b7040ab54e2b5cccc00..374f19ce8cfa37070ac28112059ef0bb6d48bf15 100644 (file)
@@ -47,6 +47,7 @@ dnl Checks for libraries.
 
 dnl Checks for header files.
 AC_HEADER_DIRENT
+AC_HEADER_STDBOOL
 AC_HEADER_STDC
 AC_HEADER_SYS_WAIT
 AC_CHECK_HEADERS(fcntl.h sys/file.h sys/ioctl.h sys/time.h syslog.h unistd.h)
@@ -180,9 +181,10 @@ AC_ARG_ENABLE(checks,
   esac
 ])
 
-DISPLAYNAME=
-AC_MSG_RESULT([$DISPLAYNAME])
-AC_SUBST([DISPLAYNAME])
+MAILDISPLAYNAME=""
+AC_MSG_CHECKING([mail display name])
+AC_MSG_RESULT([$MAILDISPLAYNAME])
+AC_SUBST([MAILDISPLAYNAME])
 
 
 dnl ---------------------------------------------------------------------
index 8f1d00d41917236504552f2d705577dbcaaa0bf3..afc25fe8fbca59ac88230414a2d52f78ceb8ab30 100644 (file)
@@ -154,8 +154,8 @@ A copy of the license is included in gfdl.sgml.
                                </varlistentry>
                                <varlistentry>
                                        <term>
-                                               <varname>displayname</varname>=<replaceable>string</replaceable>
-                                               (<option>&displayname;</option>)
+                                               <varname>maildisplayname</varname>=<replaceable>string</replaceable>
+                                               (<option>&maildisplayname;</option>)
                                        </term>
                                        <listitem>
                                                <para>
index 74344b9940bf835fff4888fb17591b30517bc45f..8a5b21aa5765df3179ada27c8c3c85ddf6538970 100644 (file)
@@ -42,7 +42,7 @@
 <!ENTITY sysfcrontab "@@SYSFCRONTAB@">
 <!ENTITY rootname "@@ROOTNAME@">
 <!ENTITY rootgroup "@@ROOTGROUP@">
-<!ENTITY displayname "@@DISPLAYNAME@">
+<!ENTITY maildisplayname "@@MAILDISPLAYNAME@">
 
 <!-- shortcuts -->
 
index a1c5a442ddeb8fc84c0cf32206ee97e397657e76..bf3271149199b441ace4b8c8f0bfb61ac851d980 100644 (file)
@@ -25,6 +25,7 @@
 #include "global.h"
 #include "mem.h"
 #include "fcronconf.h"
+#include "mail.h"
 #include "subs.h"
 
 void init_conf(void);
@@ -44,69 +45,7 @@ char *fcrondeny = NULL;
 char *shell = NULL;
 char *sendmail = NULL;
 char *editor = NULL;
-char *displayname = NULL;
-
-char
-*format_displayname(char *conf_value)
-    /* Format the input string `conf_value` according to RFC5322 sec. 3.2.3.
-     * <https://datatracker.ietf.org/doc/html/rfc5322#section-3.2.3>.
-     * Returns: either the formatted displayname (possibly unchanged or empty)
-     * as a new dynamically allocated string (must be properly freed by the
-     * caller) or NULL on errors like buffer overflow. */
-{
-    bool need_quotes = false;
-    char c = '\0';
-    char *bpos = NULL, *dpos = NULL;
-    char *buf1 = NULL, *buf2 = NULL;
-
-    /* Shorter than max because of the option prefix "displayname = " */
-    const uint buf_len = LINE_LEN - 14;
-    uint cwritten = 0;
-
-    if (strlen(conf_value) == 0) return strdup2("");
-
-    buf1 = (char *)alloc_safe(buf_len * sizeof(char), "1st buffer");
-    buf2 = (char *)alloc_safe(buf_len * sizeof(char), "2nd buffer");
-
-    /* walk the conf_value and rebuild it in buf1 */
-    bpos = buf1;
-    for (dpos = conf_value; *dpos; *dpos++) {
-        c = *dpos;
-        if (strchr(SPECIAL_MBOX_CHARS, c)) {
-            /* insert escape */
-            if (c == DQUOTE) {
-                *bpos++ = BSLASH;
-                ++cwritten;
-            }
-            need_quotes = true;
-        }
-        if (cwritten >= buf_len) {
-            error("Formatted 'displayname' exceeds %u chars", buf_len);
-            Free_safe(buf1);
-            Free_safe(buf2);
-            return NULL;
-        }
-        *bpos++ = c;
-        ++cwritten;
-    }
-
-    if (need_quotes) {
-        if (snprintf(buf2, buf_len, "\"%s\"", buf1) >= buf_len){
-            error("Formatted 'displayname' exceeds %u chars", buf_len);
-            Free_safe(buf1);
-            Free_safe(buf2);
-            return NULL;
-        }
-        Free_safe(buf1);
-
-        return buf2;
-    }
-
-    /* unchanged */
-    Free_safe(buf2);
-
-    return buf1;
-}
+char *maildisplayname = NULL;
 
 void
 init_conf(void)
@@ -129,7 +68,7 @@ init_conf(void)
     sendmail = strdup2(SENDMAIL);
 #endif
     editor = strdup2(FCRON_EDITOR);
-    displayname = strdup2(DISPLAYNAME);
+    maildisplayname = strdup2(MAILDISPLAYNAME);
 }
 
 void
@@ -146,7 +85,7 @@ free_conf(void)
     Free_safe(shell);
     Free_safe(sendmail);
     Free_safe(editor);
-    Free_safe(displayname);
+    Free_safe(maildisplayname);
 }
 
 void
@@ -253,9 +192,9 @@ read_conf(void)
         else if (strncmp(ptr1, "editor", namesize) == 0) {
             Set(editor, ptr2);
         }
-        else if (strncmp(ptr1, "displayname", namesize) == 0) {
-            char *output = format_displayname(ptr2);
-            Set(displayname, output ? output : "");
+        else if (strncmp(ptr1, "maildisplayname", namesize) == 0) {
+            char *output = format_maildisplayname(ptr2);
+            Set(maildisplayname, output ? output : "");
             Free_safe(output);
         }
         else
index d3b03ce6b42ed33b35744e3f608b617083df5465..d9a93e60f5083df86d0dc3f49edd07108f3f2b61 100644 (file)
@@ -43,7 +43,7 @@ extern char *fifofile;
 extern char *editor;
 extern char *shell;
 extern char *sendmail;
-extern char *displayname;
+extern char *maildisplayname;
 /* end of global variables */
 
 /* functions prototypes */
index 11e74757cf038e5155eab73166a6ccd120c8bf9f..d7069e7d14968e583e47c7754bfa87df7c48f39f 100644 (file)
@@ -251,9 +251,7 @@ auth_client_so_peercred(struct fcrondyn_cl *client)
      * Sets client->fcl_user on success, don't do anything on failure
      * so that the client stays unauthenticated */
 {
-    /* [@PR #17] renamed (previously called 'true') to avoid conflict with
-       stdbool */
-    const int value = 1;
+    const int true_val = 1;
     /* There is no ucred.h (or equivalent) on linux to define struct ucred (!!)
      * so we do it here */
 #if ! ( defined(HAVE_CRED_H) && defined(HAVE_UCRED_H) \
@@ -268,8 +266,8 @@ auth_client_so_peercred(struct fcrondyn_cl *client)
     socklen_t cred_size = sizeof(cred);
     struct passwd *p_entry = NULL;
 
-    setsockopt(client->fcl_sock_fd, SOL_SOCKET, SO_PASSCRED, &value,
-               sizeof(value));
+    setsockopt(client->fcl_sock_fd, SOL_SOCKET, SO_PASSCRED, &true_val,
+               sizeof(true_val));
     if (getsockopt
         (client->fcl_sock_fd, SOL_SOCKET, SO_PEERCRED, &cred,
          &cred_size) != 0) {
index 99b7923853e0ccc719da265caa1d0d92b48ff96e..f7c6539b3176ab4cd5bfba75020ab674544d56cb 100644 (file)
@@ -458,42 +458,40 @@ assign_option_string(char **var, char *value)
 }
 
 
-/* [@PR #17] renamed labels 'true' and 'false' to avoid conflict with
-   stdbool */
 char *
 get_bool(char *ptr, int *i)
     /* get a bool value : either true (1) or false (0)
      * return NULL on error */
 {
     if (*ptr == '1')
-        goto conf_true;
+        goto true_val;
     else if (*ptr == '0')
-        goto conf_false;
+        goto false_val;
     else if (strncmp(ptr, "true", 4) == 0) {
         ptr += 3;
-        goto conf_true;
+        goto true_val;
     }
     else if (strncmp(ptr, "yes", 3) == 0) {
         ptr += 2;
-        goto conf_true;
+        goto true_val;
     }
     else if (strncmp(ptr, "false", 5) == 0) {
         ptr += 4;
-        goto conf_false;
+        goto false_val;
     }
     else if (strncmp(ptr, "no", 2) == 0) {
         ptr += 1;
-        goto conf_false;
+        goto false_val;
     }
     else
         return NULL;
 
conf_true:
true_val:
     *i = true;
     ptr++;
     return ptr;
 
conf_false:
false_val:
     *i = false;
     ptr++;
     return ptr;
index 14436133167cc593045e14fb1442ccfea217bdb9..68b0935462d4fb0418a66b1047294c18b9b6b465 100644 (file)
@@ -26,10 +26,10 @@ editor              =       @@FCRON_EDITOR@
 
 # Display name for the "From: " header of mails sent by us. Default is
 # unset/empty, which keeps the "From: " header as it was before this feature
-# was added -- not RFC5322-compliant, though. A sane RFC5322-compliant setting,
-# could be:
+# was added -- not RFC5322-compliant, though.
+# The default will soon be the sane RFC5322-compliant:
 #
-#   displayname = Fcron Deamon
+#   maildisplayname = Fcron Daemon
 #
 # Please read fcron.conf(5) before setting it!
-displayname =   @@DISPLAYNAME@
+maildisplayname        =       @@MAILDISPLAYNAME@
index 0a1160ef9fe9d912059ae3d80cae45a3210751e7..d2c0f2c02c4a3fc7117f2c5c70953d506f557d10 100644 (file)
--- a/global.h
+++ b/global.h
 #include <stdarg.h>
 #endif
 
+#ifdef HAVE_STDBOOL_H
 #include <stdbool.h>
+#else
+#define bool    char
+#define true    1
+#define false   0
+#endif
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
diff --git a/job.c b/job.c
index 71a0ee923feb748a8faeb5f7aafa5f71b115b919..9afddfad50da7d376da9dcf5368fa5737c3ba6db 100644 (file)
--- a/job.c
+++ b/job.c
@@ -25,6 +25,7 @@
 #include "fcron.h"
 
 #include "job.h"
+#include "mail.h"
 #include "temp_file.h"
 
 
@@ -277,43 +278,6 @@ sig_dfl(void)
     signal(SIGPIPE, SIG_DFL);
 }
 
-char *
-make_mailbox_addr(char *displayname_conf, char *mail_from, char *hostname)
-    /* Produce a "mailbox" header as per RFC5322 sec. 3.2.3
-     * <https://datatracker.ietf.org/doc/html/rfc5322#section-3.2.3>.
-     * Returns: either the formatted mailbox header as a new dynamically
-     * allocated string (must be properly freed by the caller) or NULL on
-     * errors like buffer overflow. */
-{
-    char *buf = NULL;
-    uint written = 0;
-    bool need_anglebrackets = false;
-
-    /* Shorter than max because the header prefix "From: " are added
-       downstream. */
-    const uint buf_len = MAIL_LINE_LEN_MAX - 6;
-
-    buf = (char *)alloc_safe(buf_len * sizeof(char), "mailbox addr buffer");
-
-    /* == strlen(),but faster */
-    need_anglebrackets = displayname_conf[0] != '\0';
-
-    /* no @ here, it's handled upstream */
-    if (need_anglebrackets)
-        written = snprintf(buf, buf_len, "%s %c%s%s%c",
-                           displayname_conf, '<', mail_from, hostname, '>');
-    else
-        written = snprintf(buf, buf_len, "%s%s", mail_from, hostname);
-
-    if (written >= buf_len) {
-        error("Mailbox addr exceeds %u chars", buf_len);
-        Free_safe(buf);
-        return NULL;
-    }
-
-    return buf;
-}
-
 FILE *
 create_mail(cl_t * line, char *subject, char *content_type, char *encoding,
             char **env)
@@ -327,7 +291,7 @@ create_mail(cl_t * line, char *subject, char *content_type, char *encoding,
     /* hostname to add to email addresses (depending on if they have a '@') */
     char *hostname_from = "";
     char *hostname_to = "";
-    char *mailbox_addr = "";
+    char *mailbox_addr = NULL;
     int i = 0;
 
     if (mailf == NULL)
@@ -356,22 +320,22 @@ create_mail(cl_t * line, char *subject, char *content_type, char *encoding,
     hostname[0] = '\0';
 #endif                          /* HAVE_GETHOSTNAME */
 
-    /* write mail header. Global 'displayname' comes from fcronconf.h */
-    if (strlen(displayname) > 0){
+    /* write mail header. Global 'maildisplayname' comes from fcronconf.h */
+    if (maildisplayname[0] != '\0'){
         /* New behavior -- RFC-compliant */
-        mailbox_addr = make_mailbox_addr(displayname, mailfrom, hostname_from);
-        if (mailbox_addr) {
-            fprintf(mailf, "From: %s\n", mailbox_addr);
-            Free_safe(mailbox_addr);
-        }
-        else {
-            error("could not make the mailbox address");
-            fprintf(mailf, "From: %s%s\n", mailfrom, hostname_from);
+        mailbox_addr = make_mailbox_addr(maildisplayname, mailfrom, hostname_from);
+        if (! mailbox_addr) {
+            warn("could not make the mailbox address");
         }
     }
-    else
+    if (mailbox_addr) {
+        fprintf(mailf, FROM_HEADER_KEY"%s\n", mailbox_addr);
+        Free_safe(mailbox_addr);
+    }
+    else {
         /* Old behavior */
-        fprintf(mailf, "From: %s%s (fcron)\n", mailfrom, hostname_from);
+        fprintf(mailf, FROM_HEADER_KEY"%s%s (fcron)\n", mailfrom, hostname_from);
+    }
 
     fprintf(mailf, "To: %s%s\n", line->cl_mailto, hostname_to);
 
diff --git a/job.h b/job.h
index a83c46bb127c33cf42c870d20db763b3bce9d8b5..046e2478aa4b19668aac3c8c564b06969a3451e7 100644 (file)
--- a/job.h
+++ b/job.h
@@ -26,6 +26,7 @@
 #define __JOB_H__
 
 #define MAIL_LINE_LEN_MAX 998 /* RFC5322's max line length */
+#define FROM_HEADER_KEY "From: "
 
 /* functions prototypes */
 extern void change_user_setup_env(struct cl_t *cl, char ***sendmailenv,
diff --git a/mail.c b/mail.c
new file mode 100644 (file)
index 0000000..9596861
--- /dev/null
+++ b/mail.c
@@ -0,0 +1,120 @@
+/*
+ * FCRON - periodic command scheduler
+ *
+ *  Copyright 2000-2021 Thibault Godouet <fcron@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  The GNU General Public License can also be found in the file
+ *  `LICENSE' that comes with the fcron source distribution.
+ */
+
+
+#include "fcron.h"
+#include "mail.h"
+
+char
+*format_maildisplayname(char *displayname_conf)
+    /* Format the input string `conf_value` according to RFC5322 sec. 3.2.3.
+     * <https://datatracker.ietf.org/doc/html/rfc5322#section-3.2.3>.
+     * Returns: either the formatted displayname (possibly unchanged or empty)
+     * as a new dynamically allocated string (must be properly freed by the
+     * caller) or NULL on errors like buffer overflow. */
+{
+    bool need_quotes = false;
+    char c = '\0';
+    char *ipos = NULL;  /* Input position */
+    char *output = NULL, *quoted_output = NULL;
+
+    const uint buf_len = MAIL_FROM_VALUE_LEN_MAX;
+    uint cwritten = 0;  /* how many chars we have written */
+
+    if (strlen(displayname_conf) == 0) return strdup2("");
+
+    output = (char *)alloc_safe(buf_len * sizeof(char), "output buffer");
+
+    /* walk the conf_value and rebuild it in buf1 */
+    for (ipos = displayname_conf; *ipos; ipos++) {
+        c = *ipos;
+        if (strchr(SPECIAL_MBOX_CHARS, c)) {
+            /* insert escape */
+            if (c == DQUOTE) {
+                output[cwritten] = BSLASH;
+                cwritten++;
+            }
+            need_quotes = true;
+        }
+        if (cwritten >= buf_len) {
+            error("Formatted 'displayname' exceeds %u chars", buf_len);
+            Free_safe(output);
+            return NULL;
+        }
+        output[cwritten] = c;
+        cwritten++;
+    }
+
+    if (need_quotes) {
+        quoted_output = (char *)alloc_safe(buf_len * sizeof(char), "quoted output buffer");
+        int needed_len = snprintf(quoted_output, buf_len, "\"%s\"", output);
+        if (needed_len >= buf_len){
+            error("Formatted 'displayname' too long: length:%u > max:%u chars", needed_len, buf_len);
+            Free_safe(output);
+            Free_safe(quoted_output);
+            return NULL;
+        }
+        Free_safe(output);
+
+        return quoted_output;
+    }
+
+    return output;
+}
+
+char *
+make_mailbox_addr(char *displayname_conf, char *mail_from, char *hostname)
+    /* Produce a "mailbox" header as per RFC5322 sec. 3.2.3
+     * <https://datatracker.ietf.org/doc/html/rfc5322#section-3.2.3>.
+     * Returns: either the formatted mailbox header as a new dynamically
+     * allocated string (must be properly freed by the caller) or NULL on
+     * errors like buffer overflow. */
+{
+    char *buf = NULL;
+    uint written = 0;
+    bool need_anglebrackets = false;
+
+    const uint buf_len = MAIL_FROM_VALUE_LEN_MAX+1;
+
+    buf = (char *)alloc_safe(buf_len * sizeof(char), "mailbox addr buffer");
+
+    if (displayname_conf[0] != '\0') {
+        /* displayname_conf isn't an empty string */
+        need_anglebrackets = true;
+    }
+
+    /* no @ here, it's handled upstream */
+    if (need_anglebrackets)
+        written = snprintf(buf, buf_len, "%s %c%s%s%c",
+                           displayname_conf, '<', mail_from, hostname, '>');
+    else
+        written = snprintf(buf, buf_len, "%s%s", mail_from, hostname);
+
+    if (written >= buf_len) {
+        error("Mailbox addr exceeds %u chars", buf_len);
+        Free_safe(buf);
+        return NULL;
+    }
+
+    return buf;
+}
diff --git a/mail.h b/mail.h
new file mode 100644 (file)
index 0000000..d9157a2
--- /dev/null
+++ b/mail.h
@@ -0,0 +1,35 @@
+/*
+ * FCRON - periodic command scheduler
+ *
+ *  Copyright 2000-2021 Thibault Godouet <fcron@free.fr>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  The GNU General Public License can also be found in the file
+ *  `LICENSE' that comes with the fcron source distribution.
+ */
+
+
+#ifndef __MAIL_H__
+#define __MAIL_H__
+
+#define MAIL_LINE_LEN_MAX 998 /* RFC5322's max line length */
+#define FROM_HEADER_KEY "From: "
+#define MAIL_FROM_VALUE_LEN_MAX (MAIL_LINE_LEN_MAX - sizeof(FROM_HEADER_KEY))
+
+extern char *format_maildisplayname(char *displayname_conf);
+extern char *make_mailbox_addr(char *displayname_conf, char *mail_from, char *hostname);
+
+#endif                          /* __MAIL_H__ */
index 5bc4de92fbabea10843d971dd968316ff9319aa6..574e7feac0e3b08cf163c8de1bbcd6a1a10bcb51 100755 (executable)
@@ -30,7 +30,7 @@ close(CONFIG);
 
 open(MAKEFILE, "$ARGV[2]/Makefile") or print "error while opening Makefile: $!\n" and exit;
 while ( <MAKEFILE> ) {
-    if ( /^\s*?(\w+?)\s*?=\s*?([^\s]+)\s/ ) {
+    if ( /^\s*?(\w+?)\s*?:?=\s*?([^\s].+?)\s*$/ ) {
        $name = $1;
        $value = $2;
 
index accc77227d7370d2d22a210eb2d18ec376a2736b..38c54765f8e804fd4deb4c283a59de15bc405f07 100644 (file)
@@ -4,9 +4,10 @@ LIBS   := @LIBS@
 SRCST  := mailbox_addr.c
 OBJST  := $(patsubst %.c,%.o,$(SRCST))
 EXEST  := $(patsubst %.c,%,$(SRCST))
-OBJSD  := $(addprefix $(SRCDIR)/,log.o job.o mem.o filesubs.o subs.o fcronconf.o temp_file.o env_list.o u_list.o)
+OBJSD  := $(addprefix $(SRCDIR)/,log.o job.o mem.o filesubs.o subs.o fcronconf.o mail.o temp_file.o env_list.o u_list.o)
 
 CFLAGS += -I$(SRCDIR)
+CFLAGS += @CFLAGS@
 
 .PHONY: clean tests
 
index cb3cbebad912a99489cc44b8cb4f48a8455aa887..c529b7f02b5594edb8fef3b4bdf6351dca2031fe 100644 (file)
@@ -7,13 +7,20 @@
 #include "fcron.h"
 #include "job.h"
 #include "fcronconf.h"
+#include "mail.h"
 
-#define dasserteq(DESCR, RETURNED, EXPECTED) \
+#define AssertEq(DESCR, RETURNED, EXPECTED) \
 { \
-    printf("%s: %ld ?= %ld\n", (DESCR), (long)(RETURNED), (long)(EXPECTED)); \
+    printf("%s: check %ld == %ld\n", (DESCR), (long)(RETURNED), (long)(EXPECTED)); \
     assert((RETURNED) == (EXPECTED)); \
 }
 
+#define AssertNeq(DESCR, RETURNED, EXPECTED) \
+{ \
+    printf("%s: check %ld != %ld\n", (DESCR), (long)(RETURNED), (long)(EXPECTED)); \
+    assert((RETURNED) != (EXPECTED)); \
+}
+
 /* These globals should maybe come from a lib instead of the various exes? */
 char *prog_name = NULL;
 pid_t daemon_pid = 0;
@@ -25,7 +32,7 @@ mode_t saved_umask;
 uid_t rootuid = 0;
 char *tmp_path = "";
 
-char *format_displayname(char *displayname);
+char *format_maildisplayname(char *displayname);
 char *make_mailbox_addr(char *displayname, char *mail_from, char *hostname);
 
 
@@ -33,7 +40,7 @@ void _test_format_displayname(char *test_desc, char *arg, char *expected)
 {
     char *output = NULL;
 
-    output = format_displayname(arg);
+    output = format_maildisplayname(arg);
     printf("%s: format_displayname('%s'): '%s' ?= '%s'\n",
            test_desc, arg, output, expected);
     assert(strcmp(output, expected) == 0);
@@ -58,7 +65,7 @@ int main(int argc, char* argv[])
     char *displayname = NULL;
     char *output = NULL;
 
-    /* Mind that format_displayname() might modify input displayname, thus all
+    /* Mind that format_maildisplayname() might modify input displayname, thus all
        special characters must be tested */
     _test_format_displayname("empty displayname", "", "");
     _test_format_displayname("displayname with no special char",
@@ -103,22 +110,57 @@ int main(int argc, char* argv[])
                             "Foo Bar", "baz", "@quux", "Foo Bar <baz@quux>");
 
 
-    /* overflow tests */
+    /*
+     * format_displayname() overflow tests
+     */
+
     displayname = (char *)realloc_safe(displayname,
-                                       LINE_LEN + 1 * sizeof(char),
+                                       MAIL_FROM_VALUE_LEN_MAX * 2 * sizeof(char),
                                        "displayname buffer");
-    memset(displayname, 'a', LINE_LEN);
-    displayname[LINE_LEN] = '\0';
+
+    memset(displayname, 'a', MAIL_FROM_VALUE_LEN_MAX*2);
+
+    printf("=== format_maildisplayname: one-char overflow with no expansion...\n");
+    displayname[MAIL_FROM_VALUE_LEN_MAX+1] = '\0';
+    output = format_maildisplayname(displayname);
+    AssertEq("format_displayname: overflow with no expansion", output, NULL);
+    Free_safe(output);
+
+
+    printf("=== format_maildisplayname: max size with no special char...\n");
+    displayname[MAIL_FROM_VALUE_LEN_MAX] = '\0';
+    output = format_maildisplayname(displayname);
+    _test_format_displayname("format_displayname: max size with no special chars",
+                             output, displayname);
+    printf("format_displayname: max size with no special char: len(output)=%lu, MAIL_FROM_VALUE_LEN_MAX=%lu\n", strlen(output), MAIL_FROM_VALUE_LEN_MAX);
+    Free_safe(output);
+
+    printf("=== format_maildisplayname: overflow on max size with special char...\n");
     displayname[0] = DQUOTE;
+    output = format_maildisplayname(displayname);
+    AssertEq("format_displayname: overflow on max size with special char", output, NULL);
+    Free_safe(output);
 
-    output = format_displayname(displayname);
-    dasserteq("format_displayname: overflow", output, NULL);
+    /*
+     * make_mailbox_addr() overflow tests
+     */
+
+    printf("=== make_mailbox_addr: overflow on displayname at max size + 1...\n");
+    /* make_mailbox_addr() adds 3 chars: space, <, > */
+    displayname[MAIL_FROM_VALUE_LEN_MAX-strlen("baz")-strlen("@quux")-2] = '\0';
+    output = make_mailbox_addr(displayname, "baz", "@quux");
+    AssertEq("make_mailbox_addr: overflow", output, NULL);
     Free_safe(output);
 
+    printf("=== make_mailbox_addr: displayname at max size...\n");
+    /* make_mailbox_addr() adds 3 chars: space, <, > */
+    displayname[MAIL_FROM_VALUE_LEN_MAX-strlen("baz")-strlen("@quux")-3] = '\0';
     output = make_mailbox_addr(displayname, "baz", "@quux");
-    dasserteq("make_mailbox_addr: overflow", output, NULL);
+    printf("make_mailbox_addr: max size with no special char: len(output)=%lu, MAIL_FROM_VALUE_LEN_MAX=%lu\n", strlen(output), MAIL_FROM_VALUE_LEN_MAX);
+    AssertNeq("make_mailbox_addr: max size", output, NULL);
     Free_safe(output);
 
+
     Free_safe(displayname);
 
     return 0;