Can remove the sender and/or the recipient from the key of the greylister.
[apps/pfixtools.git] / postlicyd / query.c
index 26b590a..4a4ae9c 100644 (file)
 
 #include "query.h"
 #include "policy_tokens.h"
+#include "str.h"
+
+const char *smtp_state_names[SMTP_count] = {
+  "CONNECT",
+  "HELO",
+  "MAIL",
+  "RCPT",
+  "DATA",
+  "END-OF-MESSAGE",
+  "VRFY",
+  "ETRN",
+};
 
 bool query_parse(query_t *query, char *p)
 {
@@ -72,8 +84,6 @@ bool query_parse(query_t *query, char *p)
 #define CASE(up, low)  case PTK_##up: query->low = v; v[vlen] = '\0';  break;
             CASE(HELO_NAME,           helo_name);
             CASE(QUEUE_ID,            queue_id);
-            CASE(SENDER,              sender);
-            CASE(RECIPIENT,           recipient);
             CASE(RECIPIENT_COUNT,     recipient_count);
             CASE(CLIENT_ADDRESS,      client_address);
             CASE(CLIENT_NAME,         client_name);
@@ -93,6 +103,24 @@ bool query_parse(query_t *query, char *p)
             CASE(STRESS,              stress);
 #undef CASE
 
+          case PTK_SENDER:
+            query->sender = v;
+            v[vlen] = '\0';
+            query->sender_domain = memchr(query->sender, '@', vlen);
+            if (query->sender_domain != NULL) {
+                ++query->sender_domain;
+            }
+            break;
+
+          case PTK_RECIPIENT:
+            query->recipient = v;
+            v[vlen] = '\0';
+            query->recipient_domain = memchr(query->recipient, '@', vlen);
+            if (query->recipient_domain != NULL) {
+                ++query->recipient_domain;
+            }
+            break;
+
           case PTK_REQUEST:
             PARSE_CHECK(vtk == PTK_SMTPD_ACCESS_POLICY,
                         "unexpected `request' value: %.*s", vlen, v);
@@ -133,3 +161,101 @@ bool query_parse(query_t *query, char *p)
 #undef PARSE_CHECK
 }
 
+const char *query_field_for_id(const query_t *query, postlicyd_token id)
+{
+    switch (id) {
+#define CASE(Up, Low)                                                          \
+      case PTK_ ## Up: return query->Low;
+      CASE(HELO_NAME, helo_name)
+      CASE(QUEUE_ID, queue_id)
+      CASE(SENDER, sender)
+      CASE(SENDER_DOMAIN, sender_domain)
+      CASE(RECIPIENT, recipient)
+      CASE(RECIPIENT_DOMAIN, recipient_domain)
+      CASE(RECIPIENT_COUNT, recipient_count)
+      CASE(CLIENT_ADDRESS, client_address)
+      CASE(CLIENT_NAME, client_name)
+      CASE(REVERSE_CLIENT_NAME, reverse_client_name)
+      CASE(INSTANCE, instance)
+      CASE(SASL_METHOD, sasl_method)
+      CASE(SASL_USERNAME, sasl_username)
+      CASE(SASL_SENDER, sasl_sender)
+      CASE(SIZE, size)
+      CASE(CCERT_SUBJECT, ccert_subject)
+      CASE(CCERT_ISSUER, ccert_issuer)
+      CASE(CCERT_FINGERPRINT, ccert_fingerprint)
+      CASE(ENCRYPTION_PROTOCOL, encryption_protocol)
+      CASE(ENCRYPTION_CIPHER, encryption_cipher)
+      CASE(ENCRYPTION_KEYSIZE, encryption_keysize)
+      CASE(ETRN_DOMAIN, etrn_domain)
+      CASE(STRESS, stress)
+#undef CASE
+      case PTK_PROTOCOL_NAME:
+        return query->esmtp ? "ESMTP" : "SMTP";
+
+      case PTK_PROTOCOL_STATE:
+        return smtp_state_names[query->state];
+
+      default: return NULL;
+    }
+}
+
+const char *query_field_for_name(const query_t *query, const char *name)
+{
+    postlicyd_token id = policy_tokenize(name, strlen(name));
+    if (id == PTK_UNKNOWN) {
+        warn("unknown query field %s", name);
+        return NULL;
+    }
+    return query_field_for_id(query, id);
+}
+
+ssize_t query_format(char *dest, size_t len, const char *fmt, const query_t *query)
+{
+    size_t written = 0;
+    size_t pos = 0;
+    const char *end = fmt + m_strlen(fmt);
+
+#define WRITE(Src, Len)                                                        \
+    do {                                                                       \
+        size_t __len     = (Len);                                              \
+        if (written < len) {                                                   \
+            size_t __to_write = MIN(len - written - 1, __len);                 \
+            memcpy(dest + written, (Src), __to_write);                         \
+            written += __to_write;                                             \
+        }                                                                      \
+        pos += __len;                                                          \
+    } while (0)
+    while (*fmt != '\0') {
+        const char *next_format = strstr(fmt, "${");
+        if (next_format == NULL) {
+            next_format = end;
+        }
+        WRITE(fmt, next_format - fmt);
+        fmt = next_format;
+        if (*fmt != '\0') {
+            fmt += 2;
+            next_format = strchr(fmt, '}');
+            if (next_format == NULL) {
+                return -1;
+            }
+
+            postlicyd_token tok = policy_tokenize(fmt, next_format - fmt);
+            if (tok == PTK_UNKNOWN) {
+                warn("unknown field name \"%.*s\"", (int)(next_format - fmt), fmt);
+            }
+            const char *field = query == NULL ? NULL : query_field_for_id(query, tok);
+            if (field == NULL) {
+                WRITE("(null)", 6);
+            } else {
+                WRITE(field, m_strlen(field));
+            }
+            fmt = next_format + 1;
+        }
+    }
+
+    if (written > 0 && len > 0) {
+        dest[written] = '\0';
+    }
+    return pos;
+}