Port strlist to use async DNS.
[apps/pfixtools.git] / postlicyd / query.c
1 /******************************************************************************/
2 /*          pfixtools: a collection of postfix related tools                  */
3 /*          ~~~~~~~~~                                                         */
4 /*  ________________________________________________________________________  */
5 /*                                                                            */
6 /*  Redistribution and use in source and binary forms, with or without        */
7 /*  modification, are permitted provided that the following conditions        */
8 /*  are met:                                                                  */
9 /*                                                                            */
10 /*  1. Redistributions of source code must retain the above copyright         */
11 /*     notice, this list of conditions and the following disclaimer.          */
12 /*  2. Redistributions in binary form must reproduce the above copyright      */
13 /*     notice, this list of conditions and the following disclaimer in the    */
14 /*     documentation and/or other materials provided with the distribution.   */
15 /*  3. The names of its contributors may not be used to endorse or promote    */
16 /*     products derived from this software without specific prior written     */
17 /*     permission.                                                            */
18 /*                                                                            */
19 /*  THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND   */
20 /*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE     */
21 /*  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR        */
22 /*  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS    */
23 /*  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR    */
24 /*  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF      */
25 /*  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  */
26 /*  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN   */
27 /*  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)   */
28 /*  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF    */
29 /*  THE POSSIBILITY OF SUCH DAMAGE.                                           */
30 /******************************************************************************/
31
32 /*
33  * Copyright © 2007 Pierre Habouzit
34  * Copyright © 2008 Florent Bruneau
35  */
36
37 #include "query.h"
38 #include "policy_tokens.h"
39
40 bool query_parse(query_t *query, char *p)
41 {
42 #define PARSE_CHECK(expr, error, ...)                                        \
43     do {                                                                     \
44         if (!(expr)) {                                                       \
45             err(error, ##__VA_ARGS__);                                       \
46             return false;                                                    \
47         }                                                                    \
48     } while (0)
49
50     p_clear(query, 1);
51     query->state = SMTP_UNKNOWN;
52     while (*p != '\n') {
53         char *k, *v;
54         int klen, vlen, vtk;
55
56         while (isblank(*p))
57             p++;
58         p = strchr(k = p, '=');
59         PARSE_CHECK(p, "could not find '=' in line");
60         for (klen = p - k; klen && isblank(k[klen]); klen--);
61         p += 1; /* skip = */
62
63         while (isblank(*p))
64             p++;
65         p = strchr(v = p, '\n');
66         PARSE_CHECK(p, "could not find final \\n in line");
67         for (vlen = p - v; vlen && isblank(v[vlen]); vlen--);
68         p += 1; /* skip \n */
69
70         vtk = policy_tokenize(v, vlen);
71         switch (policy_tokenize(k, klen)) {
72 #define CASE(up, low)  case PTK_##up: query->low = v; v[vlen] = '\0';  break;
73             CASE(HELO_NAME,           helo_name);
74             CASE(QUEUE_ID,            queue_id);
75             CASE(RECIPIENT_COUNT,     recipient_count);
76             CASE(CLIENT_ADDRESS,      client_address);
77             CASE(CLIENT_NAME,         client_name);
78             CASE(REVERSE_CLIENT_NAME, reverse_client_name);
79             CASE(INSTANCE,            instance);
80             CASE(SASL_METHOD,         sasl_method);
81             CASE(SASL_USERNAME,       sasl_username);
82             CASE(SASL_SENDER,         sasl_sender);
83             CASE(SIZE,                size);
84             CASE(CCERT_SUBJECT,       ccert_subject);
85             CASE(CCERT_ISSUER,        ccert_issuer);
86             CASE(CCERT_FINGERPRINT,   ccert_fingerprint);
87             CASE(ENCRYPTION_PROTOCOL, encryption_protocol);
88             CASE(ENCRYPTION_CIPHER,   encryption_cipher);
89             CASE(ENCRYPTION_KEYSIZE,  encryption_keysize);
90             CASE(ETRN_DOMAIN,         etrn_domain);
91             CASE(STRESS,              stress);
92 #undef CASE
93
94           case PTK_SENDER:
95             query->sender = v;
96             v[vlen] = '\0';
97             query->sender_domain = memchr(query->sender, '@', vlen);
98             if (query->sender_domain != NULL) {
99                 ++query->sender_domain;
100             }
101             break;
102
103           case PTK_RECIPIENT:
104             query->recipient = v;
105             v[vlen] = '\0';
106             query->recipient_domain = memchr(query->recipient, '@', vlen);
107             if (query->recipient_domain != NULL) {
108                 ++query->recipient_domain;
109             }
110             break;
111
112           case PTK_REQUEST:
113             PARSE_CHECK(vtk == PTK_SMTPD_ACCESS_POLICY,
114                         "unexpected `request' value: %.*s", vlen, v);
115             break;
116
117           case PTK_PROTOCOL_NAME:
118             PARSE_CHECK(vtk == PTK_SMTP || vtk == PTK_ESMTP,
119                         "unexpected `protocol_name' value: %.*s", vlen, v);
120             query->esmtp = vtk == PTK_ESMTP;
121             break;
122
123           case PTK_PROTOCOL_STATE:
124             switch (vtk) {
125 #define CASE(name)  case PTK_##name: query->state = SMTP_##name; break;
126                 CASE(CONNECT);
127                 CASE(EHLO);
128                 CASE(HELO);
129                 CASE(MAIL);
130                 CASE(RCPT);
131                 CASE(DATA);
132                 CASE(END_OF_MESSAGE);
133                 CASE(VRFY);
134                 CASE(ETRN);
135               default:
136                 PARSE_CHECK(false, "unexpected `protocol_state` value: %.*s",
137                             vlen, v);
138 #undef CASE
139             }
140             break;
141
142           default:
143             warn("unexpected key, skipped: %.*s", klen, k);
144             continue;
145         }
146     }
147
148     return query->state != SMTP_UNKNOWN;
149 #undef PARSE_CHECK
150 }
151