Add hostname match on recipient_domain and sender_domain.
[apps/pfixtools.git] / postlicyd / strlist.c
index 20e6a58..19fd0b2 100644 (file)
@@ -43,15 +43,17 @@ typedef struct strlist_config_t {
     PA(trie_t) tries;
     A(int)     weights;
     A(bool)    reverses;
+    A(bool)    partiales;
 
     int soft_threshold;
     int hard_threshold;
 
     unsigned is_email         :1;
+    unsigned is_hostname      :1;
+
     unsigned match_sender     :1;
     unsigned match_recipient  :1;
 
-    unsigned is_hostname      :1;
     unsigned match_helo       :1;
     unsigned match_client     :1;
     unsigned match_reverse    :1;
@@ -69,6 +71,7 @@ static void strlist_config_delete(strlist_config_t **config)
         array_deep_wipe((*config)->tries, trie_delete);
         array_wipe((*config)->weights);
         array_wipe((*config)->reverses);
+        array_wipe((*config)->partiales);
         p_delete(config);
     }
 }
@@ -109,8 +112,8 @@ static trie_t *strlist_create(const char *file, bool reverse, bool lock)
         --end;
     }
     if (end != map.end) {
-        syslog(LOG_WARNING, "file %s miss a final \\n, ignoring last line",
-               file);
+        warn("file %s miss a final \\n, ignoring last line",
+             file);
     }
 
     db = trie_new();
@@ -120,7 +123,7 @@ static trie_t *strlist_create(const char *file, bool reverse, bool lock)
             eol = end;
         }
         if (eol - p >= BUFSIZ) {
-            syslog(LOG_ERR, "unreasonnable long line");
+            err("unreasonnable long line");
             file_map_close(&map);
             trie_delete(&db);
             return NULL;
@@ -152,7 +155,7 @@ static bool strlist_filter_constructor(filter_t *filter)
 
 #define PARSE_CHECK(Expr, Str, ...)                                            \
     if (!(Expr)) {                                                             \
-        syslog(LOG_ERR, Str, ##__VA_ARGS__);                                   \
+        err(Str, ##__VA_ARGS__);                                               \
         strlist_config_delete(&config);                                        \
         return false;                                                          \
     }
@@ -177,6 +180,7 @@ static bool strlist_filter_constructor(filter_t *filter)
             bool lock = false;
             int  weight = 0;
             bool reverse = false;
+            bool partial = false;
             trie_t *trie = NULL;
             const char *current = param->value;
             const char *p = m_strchrnul(param->value, ':');
@@ -198,6 +202,11 @@ static bool strlist_filter_constructor(filter_t *filter)
                     break;
 
                   case 1:
+                    if (p - current > (ssize_t)strlen("partial-") 
+                        && strncmp(current, "partial-", strlen("partial-")) == 0) {
+                        partial = true;
+                        current += strlen("partial-");
+                    }
                     if ((p - current) == 6 && strncmp(current, "suffix", 6) == 0) {
                         reverse = true;
                     } else if ((p - current) == 6 && strncmp(current, "prefix", 6) == 0) {
@@ -222,6 +231,7 @@ static bool strlist_filter_constructor(filter_t *filter)
                     array_add(config->tries, trie);
                     array_add(config->weights, weight);
                     array_add(config->reverses, reverse);
+                    array_add(config->partiales, partial);
                     break;
                 }
                 if (i != 3) {
@@ -267,6 +277,8 @@ static bool strlist_filter_constructor(filter_t *filter)
                   CASE(HELO_NAME, helo, hostname);
                   CASE(CLIENT_NAME, client, hostname);
                   CASE(REVERSE_CLIENT_NAME, reverse, hostname);
+                  CASE(SENDER_DOMAIN, sender, hostname);
+                  CASE(RECIPIENT_DOMAIN, recipient, hostname);
                   CASE(SENDER, sender, email);
                   CASE(RECIPIENT, recipient, email);
 #undef CASE
@@ -310,27 +322,31 @@ static filter_result_t strlist_filter(const filter_t *filter, const query_t *que
     if (config->is_email && 
         ((config->match_sender && query->state < SMTP_MAIL)
         || (config->match_recipient && query->state != SMTP_RCPT))) {
-        syslog(LOG_WARNING, "trying to match an email against a field that is not "
-               "available in current protocol state");
+        warn("trying to match an email against a field that is not "
+             "available in current protocol state");
         return HTK_ABORT;
     } else if (config->is_hostname && config->match_helo && query->state < SMTP_HELO) {
-        syslog(LOG_WARNING, "trying to match hostname against helo before helo "
-               "is received");
+        warn("trying to match hostname against helo before helo is received");
         return HTK_ABORT;
     }
 #define LOOKUP(Flag, Field)                                                    \
-    if (config->match_ ## Flag) {                                          \
-        const int len = m_strlen(query->Field);                            \
-        strlist_copy(normal, query->Field, len, false);                    \
-        strlist_copy(reverse, query->Field, len, true);                    \
-        for (int i = 0 ; i < config->tries.len ; ++i) {                    \
-            const int weight   = array_elt(config->weights, i);            \
-            const trie_t *trie = array_elt(config->tries, i);              \
-            const bool rev = array_elt(config->reverses, i);               \
-            if (trie_lookup(trie, rev ? reverse : normal)) {               \
-                sum += weight;                                             \
-            }                                                              \
-        }                                                                  \
+    if (config->match_ ## Flag) {                                              \
+        const int len = m_strlen(query->Field);                                \
+        strlist_copy(normal, query->Field, len, false);                        \
+        strlist_copy(reverse, query->Field, len, true);                        \
+        for (uint32_t i = 0 ; i < config->tries.len ; ++i) {                   \
+            const int weight   = array_elt(config->weights, i);                \
+            const trie_t *trie = array_elt(config->tries, i);                  \
+            const bool rev     = array_elt(config->reverses, i);               \
+            const bool part    = array_elt(config->partiales, i);              \
+            if ((!part && trie_lookup(trie, rev ? reverse : normal))           \
+                || (part && trie_prefix(trie, rev ? reverse : normal))) {      \
+                sum += weight;                                                 \
+                if (sum >= config->hard_threshold) {                           \
+                    return HTK_HARD_MATCH;                                     \
+                }                                                              \
+            }                                                                  \
+        }                                                                      \
     }
     if (config->is_email) {
         LOOKUP(sender, sender);
@@ -339,6 +355,8 @@ static filter_result_t strlist_filter(const filter_t *filter, const query_t *que
         LOOKUP(helo, helo_name);
         LOOKUP(client, client_name);
         LOOKUP(reverse, reverse_client_name);
+        LOOKUP(recipient, recipient_domain);
+        LOOKUP(sender, sender_domain);
     }
 #undef  LOOKUP
     if (sum >= config->hard_threshold) {