Skip to content

Commit 56b22d8

Browse files
author
Murray S. Kucherawy
committed
Swap "FromDomains" for "SealHeaderChecks".
1 parent 94b6b31 commit 56b22d8

File tree

8 files changed

+237
-59
lines changed

8 files changed

+237
-59
lines changed

configure.ac

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,82 @@ AC_SUBST(LIBMILTER_INCDIRS)
796796
AC_SUBST(LIBMILTER_LIBDIRS)
797797
AC_SUBST(LIBMILTER_LIBS)
798798

799+
#
800+
# header filtering requires libjansson
801+
#
802+
803+
AC_ARG_WITH([libjansson],
804+
AS_HELP_STRING([--with-libjansson],
805+
[location of jansson includes and library]),
806+
[janssonpath="$withval"], [janssonpath="auto"])
807+
808+
LIBJANSSON_CPPFLAGS=""
809+
LIBJANSSON_LDFLAGS=""
810+
LIBJANSSON_LIBS=""
811+
812+
jansson_found="no"
813+
if test \( x"$janssonpath" = x"auto" -o x"$janssonpath" = x"yes" \) -a \
814+
x"$PKG_CONFIG" != x""
815+
then
816+
PKG_CHECK_MODULES([LIBJANSSON], [jansson >= 2.2.1],
817+
[
818+
jansson_found="yes"
819+
LIBJANSSON_CPPFLAGS="$LIBJANSSON_CFLAGS"
820+
LIBJANSSON_LIBS="$LIBJANSSON_LIBS"
821+
],
822+
[
823+
jansson_found="no"
824+
AC_MSG_WARN([pkg-config for libjansson not found, trying manual
825+
search...])
826+
])
827+
fi
828+
829+
if test x"$janssonpath" != x"no" -a x"$jansson_found" = x"no"
830+
then
831+
AC_MSG_CHECKING([for libjansson])
832+
if test x"$janssonpath" != x"auto" -a x"$janssonpath" != x"yes"
833+
then
834+
if test -f $janssonpath/include/jansson.h
835+
then
836+
AC_MSG_RESULT($janssonpath)
837+
jansson_found="yes"
838+
LIBJANSSON_CPPFLAGS="-I$janssonpath/include"
839+
LIBJANSSON_LDFLAGS="-L$janssonpath/lib"
840+
LIBJANSSON_LIBS="-ljansson"
841+
else
842+
AC_MSG_ERROR(not found at $janssonpath)
843+
fi
844+
else
845+
janssondirs="/usr /usr/local"
846+
for d in $janssondirs
847+
do
848+
if test -f $d/include/jansson.h
849+
then
850+
janssonpath=$d
851+
AC_MSG_RESULT($d)
852+
jansson_found="yes"
853+
LIBJANSSON_CPPFLAGS="-I$janssonpath/include"
854+
LIBJANSSON_LDFLAGS="-L$janssonpath/lib"
855+
LIBJANSSON_LIBS="-ljansson"
856+
break
857+
fi
858+
done
859+
fi
860+
if test x"$jansson_found" != x"yes"
861+
then
862+
AC_MSG_RESULT([no])
863+
fi
864+
fi
865+
AC_SUBST(LIBJANSSON_CPPFLAGS)
866+
AC_SUBST(LIBJANSSON_LDFLAGS)
867+
AC_SUBST(LIBJANSSON_LIBS)
868+
AM_CONDITIONAL(JANSSON, test x"$LIBJANSSON_LIBS" != x"")
869+
870+
if test x"$jansson_found" == x"yes"
871+
then
872+
AC_DEFINE(USE_JANSSON, 1, [use libjansson to provide header field checks])
873+
fi
874+
799875
# This (below) is just for the pkg-config file openarc.pc.in
800876
LIBOPENARC_LIBS_PKG="$LIBOPENARC_LIBS"
801877
LIBOPENARC_INC="$LIBCRYPTO_CPPFLAGS $LIBCRYPTO_CFLAGS $LIBTRE_CPPFLAGS"

openarc/Makefile.am

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ sbin_PROGRAMS = openarc
1414
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
1515
openarc_CC = $(PTHREAD_CC)
1616
openarc_CFLAGS = $(PTHREAD_CFLAGS) $(LIBCRYPTO_CFLAGS)
17-
openarc_CPPFLAGS = -I$(srcdir)/../libopenarc $(LIBCRYPTO_CPPFLAGS) $(LIBMILTER_INCDIRS)
18-
openarc_LDFLAGS = $(LIBCRYPTO_LIBDIRS) $(LIBMILTER_LIBDIRS) $(PTHREAD_CFLAGS)
19-
openarc_LDADD = ../libopenarc/libopenarc.la $(LIBMILTER_LIBS) $(LIBCRYPTO_LIBS) $(PTHREAD_LIBS) $(LIBRESOLV)
17+
openarc_CPPFLAGS = -I$(srcdir)/../libopenarc $(LIBCRYPTO_CPPFLAGS) $(LIBMILTER_INCDIRS) $(LIBJANSSON_CPPFLAGS)
18+
openarc_LDFLAGS = $(LIBCRYPTO_LIBDIRS) $(LIBMILTER_LIBDIRS) $(PTHREAD_CFLAGS) $(LIBJANSSON_LDFLAGS)
19+
openarc_LDADD = ../libopenarc/libopenarc.la $(LIBMILTER_LIBS) $(LIBCRYPTO_LIBS) $(PTHREAD_LIBS) $(LIBJANSSON_LIBS) $(LIBRESOLV)
2020
endif

openarc/config.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,12 @@ config_load_level(char *file, struct configdef *def,
263263
break;
264264
}
265265

266+
if (s == NULL)
267+
{
268+
conf_error = CONF_MISSING;
269+
err = 1;
270+
}
271+
266272
if (!err)
267273
{
268274
char *q;
@@ -279,6 +285,7 @@ config_load_level(char *file, struct configdef *def,
279285

280286
if (*p == '\0' && !err)
281287
{
288+
/* TODO: not reached? */
282289
conf_error = CONF_MISSING;
283290
err = 1;
284291
}

openarc/openarc-config.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ struct configdef arcf_config[] =
3333
{ "EnableCoredumps", CONFIG_TYPE_BOOLEAN, FALSE },
3434
{ "FinalReceiver", CONFIG_TYPE_BOOLEAN, FALSE },
3535
{ "FixedTimestamp", CONFIG_TYPE_STRING, FALSE },
36-
{ "FromDomains", CONFIG_TYPE_STRING, FALSE },
3736
{ "Include", CONFIG_TYPE_INCLUDE, FALSE },
3837
{ "InternalHosts", CONFIG_TYPE_STRING, FALSE },
3938
{ "KeepTemporaryFiles", CONFIG_TYPE_BOOLEAN, FALSE },
@@ -47,6 +46,7 @@ struct configdef arcf_config[] =
4746
{ "SignatureAlgorithm", CONFIG_TYPE_STRING, FALSE },
4847
{ "SignHeaders", CONFIG_TYPE_STRING, FALSE },
4948
{ "OverSignHeaders", CONFIG_TYPE_STRING, FALSE },
49+
{ "SealHeaderChecks", CONFIG_TYPE_STRING, FALSE },
5050
{ "Socket", CONFIG_TYPE_STRING, FALSE },
5151
{ "SoftwareHeader", CONFIG_TYPE_BOOLEAN, FALSE },
5252
{ "Syslog", CONFIG_TYPE_BOOLEAN, FALSE },

openarc/openarc.c

Lines changed: 118 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ struct arcf_config
139139
ARC_LIB * conf_libopenarc; /* shared library instance */
140140
struct conflist conf_peers; /* peers hosts */
141141
struct conflist conf_internal; /* internal hosts */
142-
struct conflist conf_fromdomains; /* From: domains that matter */
142+
struct conflist conf_sealheaderchecks; /* header checks for sealing */
143143
};
144144

145145
/*
@@ -1193,7 +1193,6 @@ arcf_config_new(void)
11931193

11941194
LIST_INIT(&new->conf_peers);
11951195
LIST_INIT(&new->conf_internal);
1196-
LIST_INIT(&new->conf_fromdomains);
11971196

11981197
return new;
11991198
}
@@ -1341,9 +1340,6 @@ arcf_config_free(struct arcf_config *conf)
13411340
if (!LIST_EMPTY(&conf->conf_internal))
13421341
arcf_list_destroy(&conf->conf_internal);
13431342

1344-
if (!LIST_EMPTY(&conf->conf_fromdomains))
1345-
arcf_list_destroy(&conf->conf_fromdomains);
1346-
13471343
if (conf->conf_data != NULL)
13481344
config_free(conf->conf_data);
13491345

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

1352+
if (!LIST_EMPTY(&conf->conf_sealheaderchecks))
1353+
arcf_list_destroy(&conf->conf_sealheaderchecks);
1354+
13561355
free(conf);
13571356
}
13581357

@@ -1510,6 +1509,24 @@ arcf_config_load(struct config *data, struct arcf_config *conf,
15101509
&conf->conf_oversignhdrs_raw,
15111510
sizeof conf->conf_oversignhdrs_raw);
15121511

1512+
str = NULL;
1513+
(void) config_get(data, "SealHeaderChecks", &str, sizeof str);
1514+
if (str != NULL)
1515+
{
1516+
_Bool status;
1517+
char *dberr = NULL;
1518+
1519+
status = arcf_list_load(&conf->conf_sealheaderchecks,
1520+
str, &dberr);
1521+
if (!status)
1522+
{
1523+
snprintf(err, errlen,
1524+
"%s: arcf_list_load(): %s",
1525+
str, dberr);
1526+
return -1;
1527+
}
1528+
}
1529+
15131530
str = NULL;
15141531
(void) config_get(data, "FixedTimestamp", &str, sizeof str);
15151532
if (str != NULL)
@@ -1621,23 +1638,6 @@ arcf_config_load(struct config *data, struct arcf_config *conf,
16211638
}
16221639
}
16231640

1624-
str = NULL;
1625-
if (data != NULL)
1626-
(void) config_get(data, "FromDomains", &str, sizeof str);
1627-
if (str != NULL)
1628-
{
1629-
_Bool status;
1630-
char *dberr = NULL;
1631-
1632-
status = arcf_list_load(&conf->conf_fromdomains, str, &dberr);
1633-
if (!status)
1634-
{
1635-
snprintf(err, errlen, "%s: arcf_list_load(): %s",
1636-
str, dberr);
1637-
return -1;
1638-
}
1639-
}
1640-
16411641
/* load the secret key, if one was specified */
16421642
if (conf->conf_keyfile != NULL)
16431643
{
@@ -3225,56 +3225,126 @@ mlfi_eoh(SMFICTX *ctx)
32253225
}
32263226
}
32273227

3228+
#ifdef USE_JANSSON
32283229
/*
3229-
** If we only care about a specific set of From: domains, make sure
3230-
** this is one of those.
3230+
** If we only care about messages with specific header properties,
3231+
** see if this is one of those.
32313232
*/
32323233

3233-
if (!LIST_EMPTY(&conf->conf_fromdomains))
3234+
if (!LIST_EMPTY(&conf->conf_sealheaderchecks))
32343235
{
3235-
unsigned char *user;
3236-
unsigned char *domain;
3237-
unsigned char fromhdr[ARC_MAXHEADER + 1];
3236+
_Bool found = FALSE;
3237+
int restatus;
3238+
struct configvalue *node;
3239+
char buf[BUFRSZ];
32383240

3239-
hdr = arcf_findheader(afc, "From", c);
3240-
if (hdr == NULL)
3241+
LIST_FOREACH(node, &conf->conf_sealheaderchecks, entries)
32413242
{
3242-
if (conf->conf_dolog)
3243+
int hfnum = 0;
3244+
char *hfname = NULL;
3245+
char *hfmatch;
3246+
regex_t re;
3247+
json_t *json;
3248+
const char *str;
3249+
json_error_t json_err;
3250+
3251+
strlcpy(buf, node->value, sizeof buf);
3252+
hfmatch = strchr(buf, ':');
3253+
if (hfmatch != NULL)
32433254
{
3244-
syslog(LOG_INFO,
3245-
"%s: From field not found",
3246-
afc->mctx_jobid);
3255+
hfname = buf;
3256+
*hfmatch++ = '\0';
32473257
}
32483258

3249-
return SMFIS_ACCEPT;
3250-
}
3259+
if (hfmatch != NULL)
3260+
restatus = regcomp(&re, hfmatch, 0);
32513261

3252-
strlcpy(fromhdr, hdr->hdr_val, sizeof fromhdr);
3253-
if (arc_mail_parse(fromhdr, &user, &domain) != 0)
3254-
{
3255-
if (conf->conf_dolog)
3262+
if (hfname == NULL || hfmatch == NULL || restatus != 0)
32563263
{
3257-
syslog(LOG_INFO,
3258-
"%s: unable to parse From field \"%s\"",
3259-
afc->mctx_jobid, fromhdr);
3264+
if (conf->conf_dolog)
3265+
{
3266+
syslog(LOG_ERR,
3267+
"%s: invalid seal header check \"%s\"",
3268+
afc->mctx_jobid,
3269+
node->value);
3270+
}
32603271
}
32613272

3262-
return SMFIS_ACCEPT;
3273+
for (hfnum = 0; !found; hfnum++)
3274+
{
3275+
hdr = arcf_findheader(afc, hfname, hfnum);
3276+
if (hdr == NULL)
3277+
break;
3278+
3279+
json = json_loads(hdr->hdr_val, 0, &json_err);
3280+
if (json != NULL)
3281+
{
3282+
if (json_is_string(json))
3283+
{
3284+
str = json_string_value(json);
3285+
if (regexec(&re, str,
3286+
0, NULL, 0) == 0)
3287+
{
3288+
found = TRUE;
3289+
break;
3290+
}
3291+
}
3292+
else if (json_is_array(json))
3293+
{
3294+
size_t jn;
3295+
json_t *entry;
3296+
3297+
for (jn = 0;
3298+
!found && jn < json_array_size(json);
3299+
jn++)
3300+
{
3301+
entry = json_array_get(json,
3302+
jn);
3303+
3304+
if (json_is_string(entry))
3305+
{
3306+
str = json_string_value(entry);
3307+
3308+
if (regexec(&re,
3309+
str,
3310+
0,
3311+
NULL,
3312+
0) == 0)
3313+
{
3314+
found = TRUE;
3315+
break;
3316+
}
3317+
}
3318+
3319+
}
3320+
}
3321+
3322+
json_decref(json);
3323+
}
3324+
else if (regexec(&re, hdr->hdr_val,
3325+
0, NULL, 0) == 0)
3326+
{
3327+
found = TRUE;
3328+
break;
3329+
}
3330+
}
3331+
3332+
regfree(&re);
32633333
}
32643334

3265-
if (!arcf_checkhost(&conf->conf_fromdomains, domain))
3335+
if (!found)
32663336
{
3267-
/* not from a domain in our whitelist */
32683337
if (conf->conf_dolog)
32693338
{
32703339
syslog(LOG_INFO,
3271-
"%s: ignoring mail from %s",
3272-
afc->mctx_jobid, domain);
3340+
"%s: no seal header check matched; continuing",
3341+
afc->mctx_jobid);
32733342
}
32743343

32753344
return SMFIS_ACCEPT;
32763345
}
32773346
}
3347+
#endif /* USE_JANSSON */
32783348

32793349
/* run the header fields */
32803350
mode = conf->conf_mode;

0 commit comments

Comments
 (0)