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
15 static void *ngx_mail_pop3_create_srv_conf(ngx_conf_t *cf);
16 static char *ngx_mail_pop3_merge_srv_conf(ngx_conf_t *cf, void *parent,
17 void *child);
18
19
20 static 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
28 static 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
37 static 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
47 static 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
63 static 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
83 static 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
94 ngx_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
110 static void *
ngx_mail_pop3_create_srv_conf(ngx_conf_t * cf)111 ngx_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
130 static char *
ngx_mail_pop3_merge_srv_conf(ngx_conf_t * cf,void * parent,void * child)131 ngx_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