Skip to content

Commit

Permalink
Swap "FromDomains" for "SealHeaderChecks".
Browse files Browse the repository at this point in the history
  • Loading branch information
Murray S. Kucherawy committed Aug 8, 2019
1 parent 94b6b31 commit 56b22d8
Show file tree
Hide file tree
Showing 8 changed files with 237 additions and 59 deletions.
76 changes: 76 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,82 @@ AC_SUBST(LIBMILTER_INCDIRS)
AC_SUBST(LIBMILTER_LIBDIRS)
AC_SUBST(LIBMILTER_LIBS)

#
# header filtering requires libjansson
#

AC_ARG_WITH([libjansson],
AS_HELP_STRING([--with-libjansson],
[location of jansson includes and library]),
[janssonpath="$withval"], [janssonpath="auto"])

LIBJANSSON_CPPFLAGS=""
LIBJANSSON_LDFLAGS=""
LIBJANSSON_LIBS=""

jansson_found="no"
if test \( x"$janssonpath" = x"auto" -o x"$janssonpath" = x"yes" \) -a \
x"$PKG_CONFIG" != x""
then
PKG_CHECK_MODULES([LIBJANSSON], [jansson >= 2.2.1],
[
jansson_found="yes"
LIBJANSSON_CPPFLAGS="$LIBJANSSON_CFLAGS"
LIBJANSSON_LIBS="$LIBJANSSON_LIBS"
],
[
jansson_found="no"
AC_MSG_WARN([pkg-config for libjansson not found, trying manual
search...])
])
fi

if test x"$janssonpath" != x"no" -a x"$jansson_found" = x"no"
then
AC_MSG_CHECKING([for libjansson])
if test x"$janssonpath" != x"auto" -a x"$janssonpath" != x"yes"
then
if test -f $janssonpath/include/jansson.h
then
AC_MSG_RESULT($janssonpath)
jansson_found="yes"
LIBJANSSON_CPPFLAGS="-I$janssonpath/include"
LIBJANSSON_LDFLAGS="-L$janssonpath/lib"
LIBJANSSON_LIBS="-ljansson"
else
AC_MSG_ERROR(not found at $janssonpath)
fi
else
janssondirs="/usr /usr/local"
for d in $janssondirs
do
if test -f $d/include/jansson.h
then
janssonpath=$d
AC_MSG_RESULT($d)
jansson_found="yes"
LIBJANSSON_CPPFLAGS="-I$janssonpath/include"
LIBJANSSON_LDFLAGS="-L$janssonpath/lib"
LIBJANSSON_LIBS="-ljansson"
break
fi
done
fi
if test x"$jansson_found" != x"yes"
then
AC_MSG_RESULT([no])
fi
fi
AC_SUBST(LIBJANSSON_CPPFLAGS)
AC_SUBST(LIBJANSSON_LDFLAGS)
AC_SUBST(LIBJANSSON_LIBS)
AM_CONDITIONAL(JANSSON, test x"$LIBJANSSON_LIBS" != x"")

if test x"$jansson_found" == x"yes"
then
AC_DEFINE(USE_JANSSON, 1, [use libjansson to provide header field checks])
fi

# This (below) is just for the pkg-config file openarc.pc.in
LIBOPENARC_LIBS_PKG="$LIBOPENARC_LIBS"
LIBOPENARC_INC="$LIBCRYPTO_CPPFLAGS $LIBCRYPTO_CFLAGS $LIBTRE_CPPFLAGS"
Expand Down
6 changes: 3 additions & 3 deletions openarc/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ sbin_PROGRAMS = openarc
openarc_SOURCES = config.c config.h openarc.c openarc.h openarc-ar.c openarc-ar.h openarc-config.h openarc-crypto.c openarc-crypto.h openarc-test.c openarc-test.h util.c util.h
openarc_CC = $(PTHREAD_CC)
openarc_CFLAGS = $(PTHREAD_CFLAGS) $(LIBCRYPTO_CFLAGS)
openarc_CPPFLAGS = -I$(srcdir)/../libopenarc $(LIBCRYPTO_CPPFLAGS) $(LIBMILTER_INCDIRS)
openarc_LDFLAGS = $(LIBCRYPTO_LIBDIRS) $(LIBMILTER_LIBDIRS) $(PTHREAD_CFLAGS)
openarc_LDADD = ../libopenarc/libopenarc.la $(LIBMILTER_LIBS) $(LIBCRYPTO_LIBS) $(PTHREAD_LIBS) $(LIBRESOLV)
openarc_CPPFLAGS = -I$(srcdir)/../libopenarc $(LIBCRYPTO_CPPFLAGS) $(LIBMILTER_INCDIRS) $(LIBJANSSON_CPPFLAGS)
openarc_LDFLAGS = $(LIBCRYPTO_LIBDIRS) $(LIBMILTER_LIBDIRS) $(PTHREAD_CFLAGS) $(LIBJANSSON_LDFLAGS)
openarc_LDADD = ../libopenarc/libopenarc.la $(LIBMILTER_LIBS) $(LIBCRYPTO_LIBS) $(PTHREAD_LIBS) $(LIBJANSSON_LIBS) $(LIBRESOLV)
endif
7 changes: 7 additions & 0 deletions openarc/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,12 @@ config_load_level(char *file, struct configdef *def,
break;
}

if (s == NULL)
{
conf_error = CONF_MISSING;
err = 1;
}

if (!err)
{
char *q;
Expand All @@ -279,6 +285,7 @@ config_load_level(char *file, struct configdef *def,

if (*p == '\0' && !err)
{
/* TODO: not reached? */
conf_error = CONF_MISSING;
err = 1;
}
Expand Down
2 changes: 1 addition & 1 deletion openarc/openarc-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ struct configdef arcf_config[] =
{ "EnableCoredumps", CONFIG_TYPE_BOOLEAN, FALSE },
{ "FinalReceiver", CONFIG_TYPE_BOOLEAN, FALSE },
{ "FixedTimestamp", CONFIG_TYPE_STRING, FALSE },
{ "FromDomains", CONFIG_TYPE_STRING, FALSE },
{ "Include", CONFIG_TYPE_INCLUDE, FALSE },
{ "InternalHosts", CONFIG_TYPE_STRING, FALSE },
{ "KeepTemporaryFiles", CONFIG_TYPE_BOOLEAN, FALSE },
Expand All @@ -47,6 +46,7 @@ struct configdef arcf_config[] =
{ "SignatureAlgorithm", CONFIG_TYPE_STRING, FALSE },
{ "SignHeaders", CONFIG_TYPE_STRING, FALSE },
{ "OverSignHeaders", CONFIG_TYPE_STRING, FALSE },
{ "SealHeaderChecks", CONFIG_TYPE_STRING, FALSE },
{ "Socket", CONFIG_TYPE_STRING, FALSE },
{ "SoftwareHeader", CONFIG_TYPE_BOOLEAN, FALSE },
{ "Syslog", CONFIG_TYPE_BOOLEAN, FALSE },
Expand Down
166 changes: 118 additions & 48 deletions openarc/openarc.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ struct arcf_config
ARC_LIB * conf_libopenarc; /* shared library instance */
struct conflist conf_peers; /* peers hosts */
struct conflist conf_internal; /* internal hosts */
struct conflist conf_fromdomains; /* From: domains that matter */
struct conflist conf_sealheaderchecks; /* header checks for sealing */
};

/*
Expand Down Expand Up @@ -1193,7 +1193,6 @@ arcf_config_new(void)

LIST_INIT(&new->conf_peers);
LIST_INIT(&new->conf_internal);
LIST_INIT(&new->conf_fromdomains);

return new;
}
Expand Down Expand Up @@ -1341,9 +1340,6 @@ arcf_config_free(struct arcf_config *conf)
if (!LIST_EMPTY(&conf->conf_internal))
arcf_list_destroy(&conf->conf_internal);

if (!LIST_EMPTY(&conf->conf_fromdomains))
arcf_list_destroy(&conf->conf_fromdomains);

if (conf->conf_data != NULL)
config_free(conf->conf_data);

Expand All @@ -1353,6 +1349,9 @@ arcf_config_free(struct arcf_config *conf)
if (conf->conf_oversignhdrs != NULL)
free(conf->conf_oversignhdrs);

if (!LIST_EMPTY(&conf->conf_sealheaderchecks))
arcf_list_destroy(&conf->conf_sealheaderchecks);

free(conf);
}

Expand Down Expand Up @@ -1510,6 +1509,24 @@ arcf_config_load(struct config *data, struct arcf_config *conf,
&conf->conf_oversignhdrs_raw,
sizeof conf->conf_oversignhdrs_raw);

str = NULL;
(void) config_get(data, "SealHeaderChecks", &str, sizeof str);
if (str != NULL)
{
_Bool status;
char *dberr = NULL;

status = arcf_list_load(&conf->conf_sealheaderchecks,
str, &dberr);
if (!status)
{
snprintf(err, errlen,
"%s: arcf_list_load(): %s",
str, dberr);
return -1;
}
}

str = NULL;
(void) config_get(data, "FixedTimestamp", &str, sizeof str);
if (str != NULL)
Expand Down Expand Up @@ -1621,23 +1638,6 @@ arcf_config_load(struct config *data, struct arcf_config *conf,
}
}

str = NULL;
if (data != NULL)
(void) config_get(data, "FromDomains", &str, sizeof str);
if (str != NULL)
{
_Bool status;
char *dberr = NULL;

status = arcf_list_load(&conf->conf_fromdomains, str, &dberr);
if (!status)
{
snprintf(err, errlen, "%s: arcf_list_load(): %s",
str, dberr);
return -1;
}
}

/* load the secret key, if one was specified */
if (conf->conf_keyfile != NULL)
{
Expand Down Expand Up @@ -3225,56 +3225,126 @@ mlfi_eoh(SMFICTX *ctx)
}
}

#ifdef USE_JANSSON
/*
** If we only care about a specific set of From: domains, make sure
** this is one of those.
** If we only care about messages with specific header properties,
** see if this is one of those.
*/

if (!LIST_EMPTY(&conf->conf_fromdomains))
if (!LIST_EMPTY(&conf->conf_sealheaderchecks))
{
unsigned char *user;
unsigned char *domain;
unsigned char fromhdr[ARC_MAXHEADER + 1];
_Bool found = FALSE;
int restatus;
struct configvalue *node;
char buf[BUFRSZ];

hdr = arcf_findheader(afc, "From", c);
if (hdr == NULL)
LIST_FOREACH(node, &conf->conf_sealheaderchecks, entries)
{
if (conf->conf_dolog)
int hfnum = 0;
char *hfname = NULL;
char *hfmatch;
regex_t re;
json_t *json;
const char *str;
json_error_t json_err;

strlcpy(buf, node->value, sizeof buf);
hfmatch = strchr(buf, ':');
if (hfmatch != NULL)
{
syslog(LOG_INFO,
"%s: From field not found",
afc->mctx_jobid);
hfname = buf;
*hfmatch++ = '\0';
}

return SMFIS_ACCEPT;
}
if (hfmatch != NULL)
restatus = regcomp(&re, hfmatch, 0);

strlcpy(fromhdr, hdr->hdr_val, sizeof fromhdr);
if (arc_mail_parse(fromhdr, &user, &domain) != 0)
{
if (conf->conf_dolog)
if (hfname == NULL || hfmatch == NULL || restatus != 0)
{
syslog(LOG_INFO,
"%s: unable to parse From field \"%s\"",
afc->mctx_jobid, fromhdr);
if (conf->conf_dolog)
{
syslog(LOG_ERR,
"%s: invalid seal header check \"%s\"",
afc->mctx_jobid,
node->value);
}
}

return SMFIS_ACCEPT;
for (hfnum = 0; !found; hfnum++)
{
hdr = arcf_findheader(afc, hfname, hfnum);
if (hdr == NULL)
break;

json = json_loads(hdr->hdr_val, 0, &json_err);
if (json != NULL)
{
if (json_is_string(json))
{
str = json_string_value(json);
if (regexec(&re, str,
0, NULL, 0) == 0)
{
found = TRUE;
break;
}
}
else if (json_is_array(json))
{
size_t jn;
json_t *entry;

for (jn = 0;
!found && jn < json_array_size(json);
jn++)
{
entry = json_array_get(json,
jn);

if (json_is_string(entry))
{
str = json_string_value(entry);

if (regexec(&re,
str,
0,
NULL,
0) == 0)
{
found = TRUE;
break;
}
}

}
}

json_decref(json);
}
else if (regexec(&re, hdr->hdr_val,
0, NULL, 0) == 0)
{
found = TRUE;
break;
}
}

regfree(&re);
}

if (!arcf_checkhost(&conf->conf_fromdomains, domain))
if (!found)
{
/* not from a domain in our whitelist */
if (conf->conf_dolog)
{
syslog(LOG_INFO,
"%s: ignoring mail from %s",
afc->mctx_jobid, domain);
"%s: no seal header check matched; continuing",
afc->mctx_jobid);
}

return SMFIS_ACCEPT;
}
}
#endif /* USE_JANSSON */

/* run the header fields */
mode = conf->conf_mode;
Expand Down
Loading

0 comments on commit 56b22d8

Please sign in to comment.