ngx_mail_pop3_module.c revision e18a033b
1
2/*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8#include <ngx_config.h>
9#include <ngx_core.h>
10#include <ngx_event.h>
11#include <ngx_mail.h>
12#include <ngx_mail_pop3_module.h>
13
14
15static void *ngx_mail_pop3_create_srv_conf(ngx_conf_t *cf);
16static char *ngx_mail_pop3_merge_srv_conf(ngx_conf_t *cf, void *parent,
17    void *child);
18
19
20static ngx_str_t  ngx_mail_pop3_default_capabilities[] = {
21    ngx_string("TOP"),
22    ngx_string("USER"),
23    ngx_string("UIDL"),
24    ngx_null_string
25};
26
27
28static ngx_conf_bitmask_t  ngx_mail_pop3_auth_methods[] = {
29    { ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED },
30    { ngx_string("apop"), NGX_MAIL_AUTH_APOP_ENABLED },
31    { ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED },
32    { ngx_string("external"), NGX_MAIL_AUTH_EXTERNAL_ENABLED },
33    { ngx_null_string, 0 }
34};
35
36
37static ngx_str_t  ngx_mail_pop3_auth_methods_names[] = {
38    ngx_string("PLAIN"),
39    ngx_string("LOGIN"),
40    ngx_null_string,  /* APOP */
41    ngx_string("CRAM-MD5"),
42    ngx_string("EXTERNAL"),
43    ngx_null_string   /* NONE */
44};
45
46
47static ngx_mail_protocol_t  ngx_mail_pop3_protocol = {
48    ngx_string("pop3"),
49    { 110, 995, 0, 0 },
50    NGX_MAIL_POP3_PROTOCOL,
51
52    ngx_mail_pop3_init_session,
53    ngx_mail_pop3_init_protocol,
54    ngx_mail_pop3_parse_command,
55    ngx_mail_pop3_auth_state,
56
57    ngx_string("-ERR internal server error" CRLF),
58    ngx_string("-ERR SSL certificate error" CRLF),
59    ngx_string("-ERR No required SSL certificate" CRLF)
60};
61
62
63static ngx_command_t  ngx_mail_pop3_commands[] = {
64
65    { ngx_string("pop3_capabilities"),
66      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
67      ngx_mail_capabilities,
68      NGX_MAIL_SRV_CONF_OFFSET,
69      offsetof(ngx_mail_pop3_srv_conf_t, capabilities),
70      NULL },
71
72    { ngx_string("pop3_auth"),
73      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
74      ngx_conf_set_bitmask_slot,
75      NGX_MAIL_SRV_CONF_OFFSET,
76      offsetof(ngx_mail_pop3_srv_conf_t, auth_methods),
77      &ngx_mail_pop3_auth_methods },
78
79      ngx_null_command
80};
81
82
83static ngx_mail_module_t  ngx_mail_pop3_module_ctx = {
84    &ngx_mail_pop3_protocol,               /* protocol */
85
86    NULL,                                  /* create main configuration */
87    NULL,                                  /* init main configuration */
88
89    ngx_mail_pop3_create_srv_conf,         /* create server configuration */
90    ngx_mail_pop3_merge_srv_conf           /* merge server configuration */
91};
92
93
94ngx_module_t  ngx_mail_pop3_module = {
95    NGX_MODULE_V1,
96    &ngx_mail_pop3_module_ctx,             /* module context */
97    ngx_mail_pop3_commands,                /* module directives */
98    NGX_MAIL_MODULE,                       /* module type */
99    NULL,                                  /* init master */
100    NULL,                                  /* init module */
101    NULL,                                  /* init process */
102    NULL,                                  /* init thread */
103    NULL,                                  /* exit thread */
104    NULL,                                  /* exit process */
105    NULL,                                  /* exit master */
106    NGX_MODULE_V1_PADDING
107};
108
109
110static void *
111ngx_mail_pop3_create_srv_conf(ngx_conf_t *cf)
112{
113    ngx_mail_pop3_srv_conf_t  *pscf;
114
115    pscf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_pop3_srv_conf_t));
116    if (pscf == NULL) {
117        return NULL;
118    }
119
120    if (ngx_array_init(&pscf->capabilities, cf->pool, 4, sizeof(ngx_str_t))
121        != NGX_OK)
122    {
123        return NULL;
124    }
125
126    return pscf;
127}
128
129
130static char *
131ngx_mail_pop3_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
132{
133    ngx_mail_pop3_srv_conf_t *prev = parent;
134    ngx_mail_pop3_srv_conf_t *conf = child;
135
136    u_char      *p;
137    size_t       size, stls_only_size;
138    ngx_str_t   *c, *d;
139    ngx_uint_t   i, m;
140
141    ngx_conf_merge_bitmask_value(conf->auth_methods,
142                                 prev->auth_methods,
143                                 (NGX_CONF_BITMASK_SET
144                                  |NGX_MAIL_AUTH_PLAIN_ENABLED));
145
146    if (conf->auth_methods & NGX_MAIL_AUTH_PLAIN_ENABLED) {
147        conf->auth_methods |= NGX_MAIL_AUTH_LOGIN_ENABLED;
148    }
149
150    if (conf->capabilities.nelts == 0) {
151        conf->capabilities = prev->capabilities;
152    }
153
154    if (conf->capabilities.nelts == 0) {
155
156        for (d = ngx_mail_pop3_default_capabilities; d->len; d++) {
157            c = ngx_array_push(&conf->capabilities);
158            if (c == NULL) {
159                return NGX_CONF_ERROR;
160            }
161
162            *c = *d;
163        }
164    }
165
166    size = sizeof("+OK Capability list follows" CRLF) - 1
167           + sizeof("." CRLF) - 1;
168
169    stls_only_size = size + sizeof("STLS" CRLF) - 1;
170
171    c = conf->capabilities.elts;
172    for (i = 0; i < conf->capabilities.nelts; i++) {
173        size += c[i].len + sizeof(CRLF) - 1;
174
175        if (ngx_strcasecmp(c[i].data, (u_char *) "USER") == 0) {
176            continue;
177        }
178
179        stls_only_size += c[i].len + sizeof(CRLF) - 1;
180    }
181
182    size += sizeof("SASL") - 1 + sizeof(CRLF) - 1;
183
184    for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
185         m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED;
186         m <<= 1, i++)
187    {
188        if (ngx_mail_pop3_auth_methods_names[i].len == 0) {
189            continue;
190        }
191
192        if (m & conf->auth_methods) {
193            size += 1 + ngx_mail_pop3_auth_methods_names[i].len;
194        }
195    }
196
197    p = ngx_pnalloc(cf->pool, size);
198    if (p == NULL) {
199        return NGX_CONF_ERROR;
200    }
201
202    conf->capability.len = size;
203    conf->capability.data = p;
204
205    p = ngx_cpymem(p, "+OK Capability list follows" CRLF,
206                   sizeof("+OK Capability list follows" CRLF) - 1);
207
208    for (i = 0; i < conf->capabilities.nelts; i++) {
209        p = ngx_cpymem(p, c[i].data, c[i].len);
210        *p++ = CR; *p++ = LF;
211    }
212
213    p = ngx_cpymem(p, "SASL", sizeof("SASL") - 1);
214
215    for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
216         m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED;
217         m <<= 1, i++)
218    {
219        if (ngx_mail_pop3_auth_methods_names[i].len == 0) {
220            continue;
221        }
222
223        if (m & conf->auth_methods) {
224            *p++ = ' ';
225            p = ngx_cpymem(p, ngx_mail_pop3_auth_methods_names[i].data,
226                           ngx_mail_pop3_auth_methods_names[i].len);
227        }
228    }
229
230    *p++ = CR; *p++ = LF;
231
232    *p++ = '.'; *p++ = CR; *p = LF;
233
234
235    size += sizeof("STLS" CRLF) - 1;
236
237    p = ngx_pnalloc(cf->pool, size);
238    if (p == NULL) {
239        return NGX_CONF_ERROR;
240    }
241
242    conf->starttls_capability.len = size;
243    conf->starttls_capability.data = p;
244
245    p = ngx_cpymem(p, conf->capability.data,
246                   conf->capability.len - (sizeof("." CRLF) - 1));
247
248    p = ngx_cpymem(p, "STLS" CRLF, sizeof("STLS" CRLF) - 1);
249    *p++ = '.'; *p++ = CR; *p = LF;
250
251
252    size = sizeof("+OK methods supported:" CRLF) - 1
253           + sizeof("." CRLF) - 1;
254
255    for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
256         m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED;
257         m <<= 1, i++)
258    {
259        if (ngx_mail_pop3_auth_methods_names[i].len == 0) {
260            continue;
261        }
262
263        if (m & conf->auth_methods) {
264            size += ngx_mail_pop3_auth_methods_names[i].len
265                    + sizeof(CRLF) - 1;
266        }
267    }
268
269    p = ngx_pnalloc(cf->pool, size);
270    if (p == NULL) {
271        return NGX_CONF_ERROR;
272    }
273
274    conf->auth_capability.data = p;
275    conf->auth_capability.len = size;
276
277    p = ngx_cpymem(p, "+OK methods supported:" CRLF,
278                   sizeof("+OK methods supported:" CRLF) - 1);
279
280    for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
281         m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED;
282         m <<= 1, i++)
283    {
284        if (ngx_mail_pop3_auth_methods_names[i].len == 0) {
285            continue;
286        }
287
288        if (m & conf->auth_methods) {
289            p = ngx_cpymem(p, ngx_mail_pop3_auth_methods_names[i].data,
290                           ngx_mail_pop3_auth_methods_names[i].len);
291            *p++ = CR; *p++ = LF;
292        }
293    }
294
295    *p++ = '.'; *p++ = CR; *p = LF;
296
297
298    p = ngx_pnalloc(cf->pool, stls_only_size);
299    if (p == NULL) {
300        return NGX_CONF_ERROR;
301    }
302
303    conf->starttls_only_capability.len = stls_only_size;
304    conf->starttls_only_capability.data = p;
305
306    p = ngx_cpymem(p, "+OK Capability list follows" CRLF,
307                   sizeof("+OK Capability list follows" CRLF) - 1);
308
309    for (i = 0; i < conf->capabilities.nelts; i++) {
310        if (ngx_strcasecmp(c[i].data, (u_char *) "USER") == 0) {
311            continue;
312        }
313
314        p = ngx_cpymem(p, c[i].data, c[i].len);
315        *p++ = CR; *p++ = LF;
316    }
317
318    p = ngx_cpymem(p, "STLS" CRLF, sizeof("STLS" CRLF) - 1);
319    *p++ = '.'; *p++ = CR; *p = LF;
320
321    return NGX_CONF_OK;
322}
323