Skip to content

Commit

Permalink
Merge pull request #75 from jcbf/jcbf/skip_auth
Browse files Browse the repository at this point in the history
Implement SpikAuth. Will be on by default
  • Loading branch information
jcbf committed Aug 7, 2020
2 parents b050077 + 57f7140 commit 3c54545
Show file tree
Hide file tree
Showing 21 changed files with 392 additions and 19 deletions.
14 changes: 11 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,19 @@ smf-spf: smf-spf.o
smf-spf.o: smf-spf.c
$(CC) $(CFLAGS) -c smf-spf.c

coverage:
coverage: clean
$(CC) $(CFLAGS) -c smf-spf.c -coverage
$(CC) -o smf-spf smf-spf.o $(LDFLAGS) -lgcov
strip smf-spf

showcov:
lcov --directory . --capture --output-file coverage.info
lcov --remove coverage.info 'tests/*' '/usr/*' --output-file coverage.info
genhtml coverage.info --output-directory out
lcov --list coverage.info
clean:
rm -f smf-spf.o smf-spf smf.spf.gcno sample coverage.info smf-spf.gc*
rm -f smf-spf.o smf-spf smf.spf.gcno sample coverage.info smf-spf.gc*
rm -rf ./out

install:
@./install.sh
Expand All @@ -54,7 +61,8 @@ install:
fi
@echo Please, inspect and edit the $(CONFDIR)/smf-spf.conf file.


test:
./run_tests.sh


#
Expand Down
8 changes: 8 additions & 0 deletions smf-spf-tests-faiillogfile.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
LogTo /devsdasdadadssad/stdout
RefuseFail off # (on|off)
TTL 1D
User nobody
Socket inet:2424@127.0.0.1
Syslog none
Daemonize off # (on|off)
AuthservID mail.example.com
9 changes: 9 additions & 0 deletions smf-spf-tests-fail-user.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
LogTo /dev/stdout
RefuseFail off # (on|off)
TTL 1H
TTL 1h
User asdasdadasda
Socket inet:2424@127.0.0.1
Syslog none
Daemonize off # (on|off)
AuthservID mail.example.com
1 change: 1 addition & 0 deletions smf-spf-tests-fixedip.conf
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ Socket inet:2424@127.0.0.1
Syslog mail # (daemon|mail|local0...local7)
Daemonize off # (on|off)
AuthservID mail.example.com
SkipAuth off
2 changes: 2 additions & 0 deletions smf-spf-tests-natip.conf
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ ClientIPNAT 127.0.0.ss:54.154.127.152
ClientIPNAT 127.0.0.3:192.168.0.3
ClientIPNAT 127.0.0.2:192.168.0.1
ClientIPNAT 127.0.0.10:5aa4.154.126.152
ClientIPNAT 127.0.0.10:354.154.126.152
ClientIPNAT 327.0.0.2:192.168.0.1
ClientIPNAT 127.0.0.10
ClientIPNAT 127.0.0.1:54.154.127.152
RefuseFail on
Expand Down
4 changes: 3 additions & 1 deletion smf-spf-tests-q.conf
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Quarantine on # (on|off)
QuarantineBox postmaster
TTL 60m
User nobody
Socket unix:./milter.sock
Socket inet:2424@127.0.0.1
Syslog mail # (daemon|mail|local0...local7)
Daemonize off # (on|off)

LogTo /dev/stdout
5 changes: 4 additions & 1 deletion smf-spf-tests.conf
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ QuarantineBox postmaster
# Default: 1h
#
TTL 1D
TTL 1h
TTL 1d
TTL 1s

# Run as a selected user (smf-spf must be started by root)
#
Expand Down Expand Up @@ -129,3 +130,5 @@ Syslog mail # (daemon|mail|local0...local7)
#
Daemonize off # (on|off)
AuthservID mail.example.com
AddReceivedHeader on
LogTo /dev/stdout
33 changes: 23 additions & 10 deletions smf-spf.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include <time.h>
#include <unistd.h>
#include <limits.h>
#include <stdbool.h>
#include "spf2/spf.h"

#define CONFIG_FILE "/etc/mail/smfs/smf-spf.conf"
Expand All @@ -62,6 +63,7 @@
#define ADD_RECV_HEADER 0
#define QUARANTINE 0
#define DAEMONIZE 1
#define SKIP_AUTH true
#define VERSION "2.4.5"
#define REJECT_REASON "Rejected, look at http://www.openspf.org/why.html?sender=%s&ip=%s&receiver=%s"
#define SYSLOG_DISABLE -2
Expand Down Expand Up @@ -162,6 +164,7 @@ typedef struct config {
int daemonize;
unsigned long spf_ttl;
char *fixed_ip;
bool skip_auth;
char *reject_reason;
} config;

Expand Down Expand Up @@ -454,6 +457,7 @@ static int load_config(void) {
conf.quarantine = QUARANTINE;
conf.spf_ttl = SPF_TTL;
conf.daemonize = DAEMONIZE;
conf.skip_auth = SKIP_AUTH;
if (!(fp = fopen(config_file, "r"))) return 0;
while (fgets(buf, sizeof(buf) - 1, fp)) {
char key[MAXLINE];
Expand Down Expand Up @@ -618,6 +622,10 @@ static int load_config(void) {
conf.add_recv_spf_header = 1;
continue;
}
if (!strcasecmp(key, "skipauth") && !strcasecmp(val, "off")) {
conf.skip_auth = false;
continue;
}
if (!strcasecmp(key, "quarantine") && !strcasecmp(val, "on")) {
conf.quarantine = 1;
continue;
Expand Down Expand Up @@ -868,7 +876,10 @@ static sfsistat smf_envfrom(SMFICTX *ctx, char **args) {
SPF_response_t *spf_response = NULL;
SPF_result_t status;

if (smfi_getsymval(ctx, "{auth_authen}")) return SMFIS_ACCEPT;
if ((conf.skip_auth) && (smfi_getsymval(ctx, "{auth_authen}"))){
log_message(LOG_INFO, "SPF skip : username %s, from=%s", smfi_getsymval(ctx, "{auth_authen}"), context->from);
return SMFIS_ACCEPT;
}
if (verify && strcmp(verify, "OK") == 0) return SMFIS_ACCEPT;
if (*args) strscpy(context->from, *args, sizeof(context->from) - 1);
if (strstr(context->from, "<>")) {
Expand Down Expand Up @@ -1245,36 +1256,38 @@ int main(int argc, char **argv) {
struct passwd *pw;

if ((pw = getpwnam(conf.run_as_user)) == NULL) {
fprintf(stderr, "%s: %s\n", conf.run_as_user, strerror(errno));
fprintf(stderr, "getpwnam %s: %s\n", conf.run_as_user, errno ? strerror(errno) : "User does not exists");
goto done;
}
// LCOV_EXCL_START
setgroups(1, &pw->pw_gid);
if (setgid(pw->pw_gid)) { // LCOV_EXCL_LINE
fprintf(stderr, "setgid: %s\n", strerror(errno)); // LCOV_EXCL_LINE
if (setgid(pw->pw_gid)) {
fprintf(stderr, "setgid: %s\n", strerror(errno));
goto done;
}
if (setuid(pw->pw_uid)) { // LCOV_EXCL_LINE
fprintf(stderr, "setuid: %s\n", strerror(errno)); // LCOV_EXCL_LINE
if (setuid(pw->pw_uid)) {
fprintf(stderr, "setuid: %s\n", strerror(errno));
goto done;
}
log_message(LOG_INFO, "running as uid: %d, gid: %d", (int) pw->pw_uid, (int) pw->pw_gid);
}
if (smfi_setconn((char *)conf.sendmail_socket) != MI_SUCCESS) {
fprintf(stderr, "smfi_setconn failed: %s\n", conf.sendmail_socket); // LCOV_EXCL_LINE
fprintf(stderr, "smfi_setconn failed: %s\n", conf.sendmail_socket);
goto done;
}
if (smfi_register(smfilter) != MI_SUCCESS) {
fprintf(stderr, "smfi_register failed\n"); // LCOV_EXCL_LINE
fprintf(stderr, "smfi_register failed\n");
goto done;
}
if (!foreground && conf.daemonize && daemon(0, 0)) {
fprintf(stderr, "daemonize failed: %s\n", strerror(errno)); // LCOV_EXCL_LINE
fprintf(stderr, "daemonize failed: %s\n", strerror(errno));
goto done;
}
if (pthread_mutex_init(&cache_mutex, 0)) {
fprintf(stderr, "pthread_mutex_init failed\n"); // LCOV_EXCL_LINE
fprintf(stderr, "pthread_mutex_init failed\n");
goto done;
}
// LCOV_EXCL_END
umask(0177);
if (conf.spf_ttl && !cache_init()) log_message(LOG_ERR, "[ERROR] cache engine init failed");
ret = smfi_main();
Expand Down
6 changes: 6 additions & 0 deletions smf-spf.conf
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ WhitelistIP 192.168.0.0/16
#
#FixedClientIP 192.0.0.1

# SkipAuth, when set to ON, will skip evaluation when the user authnticates
#
# Default: on
#
#SkipAuth ON

# ClientIPNAT allows IP address translation of the connecting IP
# This is particular useful when you have internal email flows
# and still have a SPF evaluation
Expand Down
12 changes: 12 additions & 0 deletions tests/01-loadconfig-fail-logfile.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
mt.startfilter("./smf-spf", "-f", "-c","./smf-spf-tests-faiillogfile.conf")
-- try to connect to it
conn = mt.connect("inet:2424@127.0.0.1", 10, 0.25)
if conn == nil then
error("mt.connect() failed")
end

if conn == nil then
print "Connect to Milter failed: should fail"
else
error("mt.connect() to milter. Test failed")
end
12 changes: 12 additions & 0 deletions tests/01-loadconfig-fail.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
mt.startfilter("./smf-spf", "-f", "-c","./smf-spf-not-exists.conf")
-- try to connect to it
conn = mt.connect("inet:2424@127.0.0.1", 10, 0.25)
if conn == nil then
error("mt.connect() failed")
end

if conn == nil then
print "Connect to Milter failed: should fail"
else
error("mt.connect() to milter. Test failed")
end
2 changes: 1 addition & 1 deletion tests/03-bad-dns.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ end
-- badspf2.underspell.com. 7200 TXT "v=spf1 "

mt.macro(conn, SMFIC_MAIL, "i", "DEADBEAF")
if mt.mailfrom(conn, "<user@mail.bad.underspell.com>") ~= nil then
if mt.mailfrom(conn, "<user@bad.underspell.com>") ~= nil then
error("mt.mailfrom() failed")
end
if mt.getreply(conn) ~= SMFIR_CONTINUE then
Expand Down
21 changes: 21 additions & 0 deletions tests/03-invalid-mta-name.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

mt.echo("SPF fail test")

-- try to start the filter
mt.startfilter("./smf-spf", "-f", "-c","./smf-spf-tests-q.conf")

-- try to connect to it
conn = mt.connect("unix:./milter.sock", 40, 0.25)
if conn == nil then
error("mt.connect() failed")
end

if mt.conninfo(conn, "localhost", "10.11.12.13") ~= nil then
error("mt.conninfo() failed")
end
if mt.getreply(conn) == SMFIR_ACCEPT then
mt.echo("no MTA name test passed")
else
error("mt.conninfo() unexpected reply")
end
mt.disconnect(conn)
37 changes: 37 additions & 0 deletions tests/03-invalid-sender-soft.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
mt.echo("Invalid sender hardfail - ./smf-spf-tests-refuse.conf")

-- try to start the filter
mt.startfilter("./smf-spf", "-f", "-c","./smf-spf-tests-fixedip-fail.conf")

-- try to connect to it
conn = mt.connect("inet:2424@127.0.0.1", 40, 0.25)
if conn == nil then
error("mt.connect() failed")
end

-- send connection information

mt.macro(conn, SMFIC_CONNECT, "j", "mta.name.local")
if mt.conninfo(conn, "a.server.name.local", "10.11.12.13") ~= nil then
error("mt.conninfo() failed")
end

-- send envelope macros and sender data
-- mt.helo() is called implicitly
mt.macro(conn, SMFIC_MAIL, "i", "DEADBEAF")
if mt.mailfrom(conn, "underspell.com") ~= nil then
error("mt.mailfrom() failed")
end
if mt.getreply(conn) ~= SMFIR_REPLYCODE then
error("mt.mailfrom() unexpected reply")
end
print ("received SMFIR_REPLYCODE ")

if mt.mailfrom(conn, "<12345678901234567890123456789012345678901234567890123456789012345@underspell.com>") ~= nil then
error("mt.mailfrom() failed")
end
if mt.getreply(conn) ~= SMFIR_REPLYCODE then
error("mt.mailfrom() unexpected reply")
end
print ("received SMFIR_REPLYCODE ")

8 changes: 8 additions & 0 deletions tests/03-invalid-user.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
mt.startfilter("./smf-spf", "-f", "-c","./smf-spf-tests-fail-user.conf")
-- try to connect to it
conn = mt.connect("inet:2424@127.0.0.1", 4, 0.25)
if conn == nil then
error("mt.connect() failed")
end

print "Connect to Milter: OK"
39 changes: 39 additions & 0 deletions tests/04-fixed-client-auth-pass.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
-- Copyright (c) 2009-2013, The Trusted Domain Project. All rights reserved.
mt.echo("SPF skip auth test")

-- try to start the filter
mt.startfilter("./smf-spf", "-f", "-c","./smf-spf-tests-natip.conf")

-- try to connect to it
conn = mt.connect("inet:2424@127.0.0.1", 40, 0.25)
if conn == nil then
error("mt.connect() failed")
end

-- send connection information
-- mt.negotiate() is called implicitly
mt.macro(conn, SMFIC_CONNECT, "{j)", "mta.name.local")
if mt.conninfo(conn, "localhost", "192.0.0.194") ~= nil then
error("mt.conninfo() failed")
end
if mt.getreply(conn) ~= SMFIR_CONTINUE then
error("mt.conninfo() unexpected reply")
end

if mt.helo(conn, "underspell.com") ~= nil then
error("mt.helo() failed")
end
if mt.getreply(conn) ~= SMFIR_CONTINUE then
error("mt.helo() unexpected reply")
end
-- send envelope macros and sender data
mt.macro(conn, SMFIC_MAIL, "{i}", "t-verify-malformed")
mt.macro(conn, SMFIC_MAIL, "{auth_authen}", "username@example.net")
if mt.mailfrom(conn, "<user@underspell.com>") ~= nil then
error("mt.mailfrom() failed")
end
if mt.getreply(conn) ~= SMFIR_REPLYCODE then
error("mt.mailfrom() unexpected reply")
end

mt.disconnect(conn)
39 changes: 39 additions & 0 deletions tests/04-fixed-client-verify-pass.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
-- Copyright (c) 2009-2013, The Trusted Domain Project. All rights reserved.
mt.echo("SPF skip auth test")

-- try to start the filter
mt.startfilter("./smf-spf", "-f", "-c","./smf-spf-tests-natip.conf")

-- try to connect to it
conn = mt.connect("inet:2424@127.0.0.1", 40, 0.25)
if conn == nil then
error("mt.connect() failed")
end

-- send connection information
-- mt.negotiate() is called implicitly
mt.macro(conn, SMFIC_CONNECT, "{j)", "mta.name.local")
if mt.conninfo(conn, "localhost", "192.0.0.194") ~= nil then
error("mt.conninfo() failed")
end
if mt.getreply(conn) ~= SMFIR_CONTINUE then
error("mt.conninfo() unexpected reply")
end

if mt.helo(conn, "underspell.com") ~= nil then
error("mt.helo() failed")
end
if mt.getreply(conn) ~= SMFIR_CONTINUE then
error("mt.helo() unexpected reply")
end
-- send envelope macros and sender data
mt.macro(conn, SMFIC_MAIL, "{i}", "t-verify-malformed")
mt.macro(conn, SMFIC_MAIL, "{verify}", "OK")
if mt.mailfrom(conn, "<user@underspell.com>") ~= nil then
error("mt.mailfrom() failed")
end
if mt.getreply(conn) ~= SMFIR_REPLYCODE then
error("mt.mailfrom() unexpected reply")
end

mt.disconnect(conn)
Loading

0 comments on commit 3c54545

Please sign in to comment.