mirror of
https://bitbucket.org/jsuto/piler.git
synced 2024-11-07 23:31:58 +01:00
Fixed smtp acl implementation
Signed-off-by: Janos SUTO <sj@acts.hu>
This commit is contained in:
parent
c1150832dd
commit
ed8fc2a6e8
@ -232,11 +232,10 @@ mmap_dedup_test=0
|
|||||||
security_header=
|
security_header=
|
||||||
|
|
||||||
; whether to enable (1) or not (0) an smtp access list similar to
|
; whether to enable (1) or not (0) an smtp access list similar to
|
||||||
; postfix's postscreen. If so, then create a text file %sysconfdir%/piler/smtp.acl
|
; postfix's postscreen. Valid actions in the acl file are "permit"
|
||||||
; An example for /usr/local/etc/piler/smtp.acl:
|
; and "reject" (without quotes). See smtp.acl.example for more.
|
||||||
;
|
|
||||||
; 1.2.3.4/32 permit
|
|
||||||
; 10.0.1.0/24 reject
|
|
||||||
; 172.16.0.0/16 permit
|
|
||||||
;
|
;
|
||||||
|
; Important! There's an implicit default deny at the end of the
|
||||||
|
; rules. In other words if you decide to use the acl file, then
|
||||||
|
; everyone is not explicitly permitted is denied.
|
||||||
smtp_access_list=0
|
smtp_access_list=0
|
||||||
|
9
etc/smtp.acl.example
Normal file
9
etc/smtp.acl.example
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Allow office365 servers. See the below URI for more
|
||||||
|
# https://docs.microsoft.com/en-us/microsoft-365/enterprise/urls-and-ip-address-ranges?view=o365-worldwide
|
||||||
|
#
|
||||||
|
# Anything is not listed below will be rejected
|
||||||
|
#
|
||||||
|
40.92.0.0/15 permit
|
||||||
|
40.107.0.0/16 permit
|
||||||
|
52.100.0.0/14 permit
|
||||||
|
104.47.0.0/17 permit
|
73
src/screen.c
73
src/screen.c
@ -64,29 +64,25 @@ int add_smtp_acl(struct smtp_acl *smtp_acl[], char *network_str, struct smtp_acl
|
|||||||
|
|
||||||
|
|
||||||
int is_valid_line(char *line){
|
int is_valid_line(char *line){
|
||||||
// Skip comments
|
|
||||||
if(line[0] == ';' || line[0] == '#') return 0;
|
|
||||||
|
|
||||||
trimBuffer(line);
|
|
||||||
|
|
||||||
// Skip empty line
|
|
||||||
if(line[0] == 0) return 0;
|
|
||||||
|
|
||||||
// Currently we support ipv4 stuff only, ie. valid characters are: 0-9./
|
// Currently we support ipv4 stuff only, ie. valid characters are: 0-9./
|
||||||
// and a line should look like "1.2.3.4/24 permit" or similar (without quotes)
|
// and a line should look like "1.2.3.4/24 permit" or similar (without quotes)
|
||||||
|
|
||||||
if(!strchr(line, '.') || !strchr(line, '/') || (!strchr(line, ' ') && !strchr(line, '\t')) ){
|
if(!strchr(line, '.') || !strchr(line, '/') || (!strchr(line, ' ') && !strchr(line, '\t')) ){
|
||||||
return -1;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!strstr(line, "permit") && !strstr(line, "reject")){
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ascii values:
|
// ascii values:
|
||||||
// 46: .
|
// 46: .
|
||||||
// 47: /
|
// 47: /
|
||||||
// 48-57: 0-9
|
// 48-57: 0-9
|
||||||
// 65-90: A-Z
|
|
||||||
// 97-122: a-z
|
// 97-122: a-z
|
||||||
|
//
|
||||||
for(; *line; line++){
|
for(; *line; line++){
|
||||||
if(isalnum(*line) == 0 && isblank(*line) == 0 && *line != 46 && *line != 47) return -1;
|
if(isalnum(*line) == 0 && isblank(*line) == 0 && *line != 46 && *line != 47) return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -101,6 +97,8 @@ int a_to_hl(char *ipstr, in_addr_t *addr){
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
syslog(LOG_PRIORITY, "invalid ipv4 address string: *%s*", ipstr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,14 +149,25 @@ int str_to_net_range(char *network_addr_prefix, struct smtp_acl *smtp_acl){
|
|||||||
snprintf(buf, sizeof(buf)-1, "%s", network_addr_prefix);
|
snprintf(buf, sizeof(buf)-1, "%s", network_addr_prefix);
|
||||||
|
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
prefix = atoi(++p);
|
p++;
|
||||||
|
|
||||||
|
// Even though the remaining part of the acl line continues with some number
|
||||||
|
// then whitespace characters and the permit/reject action atoi() can still
|
||||||
|
// figure out the numeric part properly, that's why I'm lazy here.
|
||||||
|
prefix = atoi(p);
|
||||||
|
|
||||||
|
// The prefix string (p) must start with a digit and the prefix integer must be in 0..32 range
|
||||||
|
if(*p < 48 || *p > 57 || prefix < 0 || prefix > 32){
|
||||||
|
syslog(LOG_PRIORITY, "error: invalid prefix: %s", p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if(a_to_hl(network_addr_prefix, &net)){
|
if(a_to_hl(network_addr_prefix, &net)){
|
||||||
smtp_acl->low = network(net, prefix);
|
smtp_acl->low = network(net, prefix);
|
||||||
smtp_acl->high = broadcast(net, prefix);
|
smtp_acl->high = broadcast(net, prefix);
|
||||||
smtp_acl->prefix = prefix;
|
smtp_acl->prefix = prefix;
|
||||||
|
|
||||||
syslog(LOG_PRIORITY, "info: parsed acl *%s* to low: %u, high: %u, prefix: %d, reject: %d", buf, smtp_acl->low, smtp_acl->high, smtp_acl->prefix, smtp_acl->rejected);
|
syslog(LOG_PRIORITY, "info: parsed acl *%s*", buf);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -183,20 +192,31 @@ void load_smtp_acl(struct smtp_acl *smtp_acl[]){
|
|||||||
struct smtp_acl acl;
|
struct smtp_acl acl;
|
||||||
|
|
||||||
while(fgets(line, sizeof(line)-1, f)){
|
while(fgets(line, sizeof(line)-1, f)){
|
||||||
int rc = is_valid_line(line);
|
// Skip comments
|
||||||
if(rc < 0){
|
if(line[0] == ';' || line[0] == '#') continue;
|
||||||
syslog(LOG_PRIORITY, "warn: invalid network range: *%s*", line);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(rc == 1 && str_to_net_range(line, &acl) == 1){
|
trimBuffer(line);
|
||||||
|
|
||||||
|
// Skip empty line
|
||||||
|
if(line[0] == 0) continue;
|
||||||
|
|
||||||
|
char line2[SMALLBUFSIZE];
|
||||||
|
int rc = 0;
|
||||||
|
snprintf(line2, sizeof(line2)-1, "%s", line);
|
||||||
|
|
||||||
|
if(is_valid_line(line) == 1 && str_to_net_range(line, &acl) == 1){
|
||||||
add_smtp_acl(smtp_acl, line, &acl);
|
add_smtp_acl(smtp_acl, line, &acl);
|
||||||
count++;
|
count++;
|
||||||
|
rc = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!rc) syslog(LOG_PRIORITY, "error: failed to parse line: *%s*", line2);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
// If we have entries on the smtp acl list, then add 127.0.0.1/8
|
// If we have entries on the smtp acl list, then add 127.0.0.1/8
|
||||||
|
// to let the GUI health page connect to the piler-smtp daemon
|
||||||
if(count){
|
if(count){
|
||||||
snprintf(line, sizeof(line)-1, "127.0.0.1/8 permit");
|
snprintf(line, sizeof(line)-1, "127.0.0.1/8 permit");
|
||||||
|
|
||||||
@ -208,30 +228,27 @@ void load_smtp_acl(struct smtp_acl *smtp_acl[]){
|
|||||||
|
|
||||||
|
|
||||||
int is_blocked_by_pilerscreen(struct smtp_acl *smtp_acl[], char *ipaddr, struct config *cfg){
|
int is_blocked_by_pilerscreen(struct smtp_acl *smtp_acl[], char *ipaddr, struct config *cfg){
|
||||||
struct smtp_acl *q;
|
struct smtp_acl *q=smtp_acl[0];
|
||||||
in_addr_t addr = 0;
|
in_addr_t addr = 0;
|
||||||
|
|
||||||
|
// Empty acl, let it pass
|
||||||
|
if(!q) return 0;
|
||||||
|
|
||||||
if(a_to_hl(ipaddr, &addr) == 0){
|
if(a_to_hl(ipaddr, &addr) == 0){
|
||||||
syslog(LOG_PRIORITY, "error: invalid smtp client address: *%s*", ipaddr);
|
syslog(LOG_PRIORITY, "error: invalid smtp client address: *%s*", ipaddr);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
q = smtp_acl[0];
|
|
||||||
|
|
||||||
// Empty network ranges list
|
|
||||||
if(!q){
|
|
||||||
syslog(LOG_PRIORITY, "info: empty network ranges list, pass");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(q){
|
while(q){
|
||||||
if(addr >= q->low && addr <= q->high){
|
if(addr >= q->low && addr <= q->high){
|
||||||
if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "info: smtp client %s is on %s/%d rejected: %d", ipaddr, q->network_str, q->prefix, q->rejected);
|
if(q->rejected) syslog(LOG_PRIORITY, "denied connection from %s, acl: %s/%d reject", ipaddr, q->network_str, q->prefix);
|
||||||
return q->rejected;
|
return q->rejected;
|
||||||
}
|
}
|
||||||
|
|
||||||
q = q->r;
|
q = q->r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
syslog(LOG_PRIORITY, "denied connection from %s by implicit default deny", ipaddr);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,6 @@ int start_new_session(struct smtp_session **sessions, int socket, int *num_conne
|
|||||||
if(cfg->smtp_access_list && is_blocked_by_pilerscreen(smtp_acl, client_addr, cfg)){
|
if(cfg->smtp_access_list && is_blocked_by_pilerscreen(smtp_acl, client_addr, cfg)){
|
||||||
send(socket, SMTP_RESP_550_ERR, strlen(SMTP_RESP_550_ERR), 0);
|
send(socket, SMTP_RESP_550_ERR, strlen(SMTP_RESP_550_ERR), 0);
|
||||||
close(socket);
|
close(socket);
|
||||||
syslog(LOG_PRIORITY, "denied connection from %s by %s", client_addr, SMTP_ACL_FILE);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user