Klaus Demo nginx / 02c8d18
Many changes: *) rename imap to mail, sort pop3/imap functions *) smtp auth support *) pop3 starttls only *) fix segfault if cram-md5 was used without apop Igor Sysoev 15 years ago
24 changed file(s) with 7037 addition(s) and 5898 deletion(s). Raw diff Collapse all Expand all
55 $NGX_OBJS/src/os/unix $NGX_OBJS/src/os/win32 \
66 $NGX_OBJS/src/http $NGX_OBJS/src/http/modules \
77 $NGX_OBJS/src/http/modules/perl \
8 $NGX_OBJS/src/imap
8 $NGX_OBJS/src/mail
99
1010
1111 ngx_objs_dir=$NGX_OBJS$ngx_regex_dirsep
4040
4141 # ALL_INCS, required by the addons and by OpenWatcom C precompiled headers
4242
43 ngx_incs=`echo $CORE_INCS $NGX_OBJS $HTTP_INCS $IMAP_INCS\
43 ngx_incs=`echo $CORE_INCS $NGX_OBJS $HTTP_INCS $MAIL_INCS\
4444 | sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont$ngx_include_opt\1/g" \
4545 -e "s/\//$ngx_regex_dirsep/g"`
4646
100100 fi
101101
102102
103 # the imap dependences and include pathes
104
105 if [ $IMAP = YES ]; then
106
107 ngx_all_srcs="$ngx_all_srcs $IMAP_SRCS"
108
109 ngx_deps=`echo $IMAP_DEPS \
103 # the mail dependences and include pathes
104
105 if [ $MAIL = YES ]; then
106
107 ngx_all_srcs="$ngx_all_srcs $MAIL_SRCS"
108
109 ngx_deps=`echo $MAIL_DEPS \
110110 | sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont\1/g" \
111111 -e "s/\//$ngx_regex_dirsep/g"`
112112
113 ngx_incs=`echo $IMAP_INCS \
113 ngx_incs=`echo $MAIL_INCS \
114114 | sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont$ngx_include_opt\1/g" \
115115 -e "s/\//$ngx_regex_dirsep/g"`
116116
117117 cat << END >> $NGX_MAKEFILE
118118
119 IMAP_DEPS = $ngx_deps
120
121
122 IMAP_INCS = $ngx_include_opt$ngx_incs
119 MAIL_DEPS = $ngx_deps
120
121
122 MAIL_INCS = $ngx_include_opt$ngx_incs
123123
124124 END
125125
278278 fi
279279
280280
281 # the imap sources
282
283 if [ $IMAP = YES ]; then
281 # the mail sources
282
283 if [ $MAIL = YES ]; then
284284
285285 if test -n "$NGX_PCH"; then
286286 ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) $ngx_use_pch \$(ALL_INCS)"
287287 else
288 ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) \$(CORE_INCS) \$(IMAP_INCS)"
288 ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) \$(CORE_INCS) \$(MAIL_INCS)"
289289 fi
290290
291 for ngx_src in $IMAP_SRCS
291 for ngx_src in $MAIL_SRCS
292292 do
293293 ngx_src=`echo $ngx_src | sed -e "s/\//$ngx_regex_dirsep/g"`
294294 ngx_obj=`echo $ngx_src \
299299
300300 cat << END >> $NGX_MAKEFILE
301301
302 $ngx_obj: \$(CORE_DEPS) \$(IMAP_DEPS)$ngx_cont$ngx_src
302 $ngx_obj: \$(CORE_DEPS) \$(MAIL_DEPS)$ngx_cont$ngx_src
303303 $ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX
304304
305305 END
301301 fi
302302
303303
304 if [ $IMAP_SSL = YES ]; then
305 IMAP_DEPS="$IMAP_DEPS $IMAP_SSL_DEPS"
306 IMAP_SRCS="$IMAP_SRCS $IMAP_SSL_SRCS"
307 have=NGX_IMAP_SSL . auto/have
304 if [ $MAIL_SSL = YES ]; then
305 MAIL_DEPS="$MAIL_DEPS $MAIL_SSL_DEPS"
306 MAIL_SRCS="$MAIL_SRCS $MAIL_SSL_SRCS"
307 have=NGX_MAIL_SSL . auto/have
308308 USE_OPENSSL=YES
309309 fi
310310
330330 fi
331331
332332
333 if [ $IMAP = YES ]; then
334 modules="$modules $IMAP_MODULES"
335
336 if [ $IMAP_SSL = YES ]; then
337 modules="$modules $IMAP_SSL_MODULE"
333 if [ $MAIL = YES ]; then
334 modules="$modules $MAIL_MODULES"
335
336 if [ $MAIL_SSL = YES ]; then
337 modules="$modules $MAIL_SSL_MODULE"
338338 fi
339339
340 modules="$modules $IMAP_AUTH_HTTP_MODULE"
341 IMAP_SRCS="$IMAP_SRCS $IMAP_AUTH_HTTP_SRCS"
342
343 modules="$modules $IMAP_PROXY_MODULE"
344 IMAP_SRCS="$IMAP_SRCS $IMAP_PROXY_SRCS"
340 modules="$modules $MAIL_AUTH_HTTP_MODULE"
341 MAIL_SRCS="$MAIL_SRCS $MAIL_AUTH_HTTP_SRCS"
342
343 modules="$modules $MAIL_PROXY_MODULE"
344 MAIL_SRCS="$MAIL_SRCS $MAIL_PROXY_SRCS"
345345 fi
346346
347347
7676 # STUB
7777 HTTP_STUB_STATUS=NO
7878
79 IMAP=NO
80 IMAP_SSL=NO
79 MAIL=NO
80 MAIL_SSL=NO
8181
8282 NGX_ADDONS=
8383
181181 # STUB
182182 --with-http_stub_status_module) HTTP_STUB_STATUS=YES ;;
183183
184 --with-imap) IMAP=YES ;;
185 --with-imap_ssl_module) IMAP_SSL=YES ;;
184 --with-mail) MAIL=YES ;;
185 --with-mail_ssl_module) MAIL_SSL=YES ;;
186 # STUB
187 --with-imap) MAIL=YES ;;
188 --with-imap_ssl_module) MAIL_SSL=YES ;;
186189
187190 --add-module=*) NGX_ADDONS="$NGX_ADDONS $value" ;;
188191
291294
292295 --without-http disable HTTP server
293296
294 --with-imap enable IMAP4/POP3 proxy module
295 --with-imap_ssl_module enable ngx_imap_ssl_module
297 --with-mail enable IMAP4/POP3/SMTP proxy module
298 --with-mail_ssl_module enable ngx_mail_ssl_module
296299
297300 --with-cc=PATH set path to C compiler
298301 --with-cpp=PATH set path to C preprocessor
407407 HTTP_UPSTREAM_IP_HASH_SRCS=src/http/modules/ngx_http_upstream_ip_hash_module.c
408408
409409
410 IMAP_INCS="src/imap"
411
412 IMAP_DEPS="src/imap/ngx_imap.h"
413
414 IMAP_MODULES="ngx_imap_module ngx_imap_core_module"
415
416 IMAP_SRCS="src/imap/ngx_imap.c \
417 src/imap/ngx_imap_core_module.c \
418 src/imap/ngx_imap_handler.c \
419 src/imap/ngx_imap_parse.c"
420
421 IMAP_SSL_MODULE="ngx_imap_ssl_module"
422 IMAP_SSL_DEPS="src/imap/ngx_imap_ssl_module.h"
423 IMAP_SSL_SRCS="src/imap/ngx_imap_ssl_module.c"
424
425 IMAP_AUTH_HTTP_MODULE="ngx_imap_auth_http_module"
426 IMAP_AUTH_HTTP_SRCS="src/imap/ngx_imap_auth_http_module.c"
427
428 IMAP_PROXY_MODULE="ngx_imap_proxy_module"
429 IMAP_PROXY_SRCS="src/imap/ngx_imap_proxy_module.c"
410 MAIL_INCS="src/mail"
411
412 MAIL_DEPS="src/mail/ngx_mail.h"
413
414 MAIL_MODULES="ngx_mail_module ngx_mail_core_module"
415
416 MAIL_SRCS="src/mail/ngx_mail.c \
417 src/mail/ngx_mail_core_module.c \
418 src/mail/ngx_mail_handler.c \
419 src/mail/ngx_mail_parse.c"
420
421 MAIL_SSL_MODULE="ngx_mail_ssl_module"
422 MAIL_SSL_DEPS="src/mail/ngx_mail_ssl_module.h"
423 MAIL_SSL_SRCS="src/mail/ngx_mail_ssl_module.c"
424
425 MAIL_AUTH_HTTP_MODULE="ngx_mail_auth_http_module"
426 MAIL_AUTH_HTTP_SRCS="src/mail/ngx_mail_auth_http_module.c"
427
428 MAIL_PROXY_MODULE="ngx_mail_proxy_module"
429 MAIL_PROXY_SRCS="src/mail/ngx_mail_proxy_module.c"
5757
5858 static const char *debug_levels[] = {
5959 "debug_core", "debug_alloc", "debug_mutex", "debug_event",
60 "debug_http", "debug_imap"
60 "debug_http", "debug_mail", "debug_mysql"
6161 };
6262
6363
2626 #define NGX_LOG_DEBUG_MUTEX 0x040
2727 #define NGX_LOG_DEBUG_EVENT 0x080
2828 #define NGX_LOG_DEBUG_HTTP 0x100
29 #define NGX_LOG_DEBUG_IMAP 0x200
29 #define NGX_LOG_DEBUG_MAIL 0x200
3030 #define NGX_LOG_DEBUG_MYSQL 0x400
3131
3232 /*
3535 */
3636
3737 #define NGX_LOG_DEBUG_FIRST NGX_LOG_DEBUG_CORE
38 #define NGX_LOG_DEBUG_LAST NGX_LOG_DEBUG_IMAP
38 #define NGX_LOG_DEBUG_LAST NGX_LOG_DEBUG_MYSQL
3939 #define NGX_LOG_DEBUG_CONNECTION 0x80000000
4040 #define NGX_LOG_DEBUG_ALL 0x7ffffff0
4141
+0
-403
src/imap/ngx_imap.c less more
0
1 /*
2 * Copyright (C) Igor Sysoev
3 */
4
5
6 #include <ngx_config.h>
7 #include <ngx_core.h>
8 #include <ngx_event.h>
9 #include <ngx_imap.h>
10
11
12 static char *ngx_imap_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
13 static int ngx_libc_cdecl ngx_imap_cmp_conf_in_addrs(const void *one,
14 const void *two);
15
16
17 ngx_uint_t ngx_imap_max_module;
18
19
20 static ngx_command_t ngx_imap_commands[] = {
21
22 { ngx_string("imap"),
23 NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
24 ngx_imap_block,
25 0,
26 0,
27 NULL },
28
29 ngx_null_command
30 };
31
32
33 static ngx_core_module_t ngx_imap_module_ctx = {
34 ngx_string("imap"),
35 NULL,
36 NULL
37 };
38
39
40 ngx_module_t ngx_imap_module = {
41 NGX_MODULE_V1,
42 &ngx_imap_module_ctx, /* module context */
43 ngx_imap_commands, /* module directives */
44 NGX_CORE_MODULE, /* module type */
45 NULL, /* init master */
46 NULL, /* init module */
47 NULL, /* init process */
48 NULL, /* init thread */
49 NULL, /* exit thread */
50 NULL, /* exit process */
51 NULL, /* exit master */
52 NGX_MODULE_V1_PADDING
53 };
54
55
56 static char *
57 ngx_imap_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
58 {
59 char *rv;
60 u_char *text;
61 size_t len;
62 ngx_uint_t i, a, l, m, mi, s, p, last, bind_all, done;
63 ngx_conf_t pcf;
64 ngx_array_t in_ports;
65 ngx_listening_t *ls;
66 ngx_imap_listen_t *imls;
67 ngx_imap_module_t *module;
68 ngx_imap_in_port_t *imip;
69 ngx_imap_conf_ctx_t *ctx;
70 ngx_imap_conf_in_port_t *in_port;
71 ngx_imap_conf_in_addr_t *in_addr;
72 ngx_imap_core_srv_conf_t **cscfp;
73 ngx_imap_core_main_conf_t *cmcf;
74
75 /* the main imap context */
76
77 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_imap_conf_ctx_t));
78 if (ctx == NULL) {
79 return NGX_CONF_ERROR;
80 }
81
82 *(ngx_imap_conf_ctx_t **) conf = ctx;
83
84 /* count the number of the http modules and set up their indices */
85
86 ngx_imap_max_module = 0;
87 for (m = 0; ngx_modules[m]; m++) {
88 if (ngx_modules[m]->type != NGX_IMAP_MODULE) {
89 continue;
90 }
91
92 ngx_modules[m]->ctx_index = ngx_imap_max_module++;
93 }
94
95
96 /* the imap main_conf context, it is the same in the all imap contexts */
97
98 ctx->main_conf = ngx_pcalloc(cf->pool,
99 sizeof(void *) * ngx_imap_max_module);
100 if (ctx->main_conf == NULL) {
101 return NGX_CONF_ERROR;
102 }
103
104
105 /*
106 * the imap null srv_conf context, it is used to merge
107 * the server{}s' srv_conf's
108 */
109
110 ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_imap_max_module);
111 if (ctx->srv_conf == NULL) {
112 return NGX_CONF_ERROR;
113 }
114
115
116 /*
117 * create the main_conf's, the null srv_conf's, and the null loc_conf's
118 * of the all imap modules
119 */
120
121 for (m = 0; ngx_modules[m]; m++) {
122 if (ngx_modules[m]->type != NGX_IMAP_MODULE) {
123 continue;
124 }
125
126 module = ngx_modules[m]->ctx;
127 mi = ngx_modules[m]->ctx_index;
128
129 if (module->create_main_conf) {
130 ctx->main_conf[mi] = module->create_main_conf(cf);
131 if (ctx->main_conf[mi] == NULL) {
132 return NGX_CONF_ERROR;
133 }
134 }
135
136 if (module->create_srv_conf) {
137 ctx->srv_conf[mi] = module->create_srv_conf(cf);
138 if (ctx->srv_conf[mi] == NULL) {
139 return NGX_CONF_ERROR;
140 }
141 }
142 }
143
144
145 /* parse inside the imap{} block */
146
147 pcf = *cf;
148 cf->ctx = ctx;
149
150 cf->module_type = NGX_IMAP_MODULE;
151 cf->cmd_type = NGX_IMAP_MAIN_CONF;
152 rv = ngx_conf_parse(cf, NULL);
153
154 if (rv != NGX_CONF_OK) {
155 *cf = pcf;
156 return rv;
157 }
158
159
160 /* init imap{} main_conf's, merge the server{}s' srv_conf's */
161
162 cmcf = ctx->main_conf[ngx_imap_core_module.ctx_index];
163 cscfp = cmcf->servers.elts;
164
165 for (m = 0; ngx_modules[m]; m++) {
166 if (ngx_modules[m]->type != NGX_IMAP_MODULE) {
167 continue;
168 }
169
170 module = ngx_modules[m]->ctx;
171 mi = ngx_modules[m]->ctx_index;
172
173 /* init imap{} main_conf's */
174
175 if (module->init_main_conf) {
176 rv = module->init_main_conf(cf, ctx->main_conf[mi]);
177 if (rv != NGX_CONF_OK) {
178 *cf = pcf;
179 return rv;
180 }
181 }
182
183 for (s = 0; s < cmcf->servers.nelts; s++) {
184
185 /* merge the server{}s' srv_conf's */
186
187 if (module->merge_srv_conf) {
188 rv = module->merge_srv_conf(cf,
189 ctx->srv_conf[mi],
190 cscfp[s]->ctx->srv_conf[mi]);
191 if (rv != NGX_CONF_OK) {
192 *cf = pcf;
193 return rv;
194 }
195 }
196 }
197 }
198
199 /* imap{}'s cf->ctx was needed while the configuration merging */
200
201 *cf = pcf;
202
203
204 if (ngx_array_init(&in_ports, cf->temp_pool, 4,
205 sizeof(ngx_imap_conf_in_port_t))
206 != NGX_OK)
207 {
208 return NGX_CONF_ERROR;
209 }
210
211 imls = cmcf->listen.elts;
212
213 for (l = 0; l < cmcf->listen.nelts; l++) {
214
215 /* AF_INET only */
216
217 in_port = in_ports.elts;
218 for (p = 0; p < in_ports.nelts; p++) {
219 if (in_port[p].port == imls[l].port) {
220 in_port = &in_port[p];
221 goto found;
222 }
223 }
224
225 in_port = ngx_array_push(&in_ports);
226 if (in_port == NULL) {
227 return NGX_CONF_ERROR;
228 }
229
230 in_port->port = imls[l].port;
231
232 if (ngx_array_init(&in_port->addrs, cf->temp_pool, 2,
233 sizeof(ngx_imap_conf_in_addr_t))
234 != NGX_OK)
235 {
236 return NGX_CONF_ERROR;
237 }
238
239 found:
240
241 in_addr = ngx_array_push(&in_port->addrs);
242 if (in_addr == NULL) {
243 return NGX_CONF_ERROR;
244 }
245
246 in_addr->addr = imls[l].addr;
247 in_addr->ctx = imls[l].ctx;
248 in_addr->bind = imls[l].bind;
249 }
250
251 /* optimize the lists of ports and addresses */
252
253 /* AF_INET only */
254
255 in_port = in_ports.elts;
256 for (p = 0; p < in_ports.nelts; p++) {
257
258 ngx_qsort(in_port[p].addrs.elts, (size_t) in_port[p].addrs.nelts,
259 sizeof(ngx_imap_conf_in_addr_t), ngx_imap_cmp_conf_in_addrs);
260
261 in_addr = in_port[p].addrs.elts;
262 last = in_port[p].addrs.nelts;
263
264 /*
265 * if there is the binding to the "*:port" then we need to bind()
266 * to the "*:port" only and ignore the other bindings
267 */
268
269 if (in_addr[last - 1].addr == INADDR_ANY) {
270 in_addr[last - 1].bind = 1;
271 bind_all = 0;
272
273 } else {
274 bind_all = 1;
275 }
276
277 for (a = 0; a < last; /* void */ ) {
278
279 if (!bind_all && !in_addr[a].bind) {
280 a++;
281 continue;
282 }
283
284 ls = ngx_listening_inet_stream_socket(cf, in_addr[a].addr,
285 in_port[p].port);
286 if (ls == NULL) {
287 return NGX_CONF_ERROR;
288 }
289
290 ls->backlog = -1;
291 ls->rcvbuf = -1;
292 ls->sndbuf = -1;
293
294 ls->addr_ntop = 1;
295 ls->handler = ngx_imap_init_connection;
296 ls->pool_size = 256;
297
298 /* STUB */
299 ls->log = *cf->cycle->new_log;
300 ls->log.data = &ls->addr_text;
301 ls->log.handler = ngx_accept_log_error;
302 /**/
303
304 imip = ngx_palloc(cf->pool, sizeof(ngx_imap_in_port_t));
305 if (imip == NULL) {
306 return NGX_CONF_ERROR;
307 }
308
309 ls->servers = imip;
310
311 in_addr = in_port[p].addrs.elts;
312
313 if (in_addr[a].bind && in_addr[a].addr != INADDR_ANY) {
314 imip->naddrs = 1;
315 done = 0;
316
317 } else if (in_port[p].addrs.nelts > 1
318 && in_addr[last - 1].addr == INADDR_ANY)
319 {
320 imip->naddrs = last;
321 done = 1;
322
323 } else {
324 imip->naddrs = 1;
325 done = 0;
326 }
327
328 #if 0
329 ngx_log_error(NGX_LOG_ALERT, cf->log, 0,
330 "%ui: %V %d %ui %ui",
331 a, &ls->addr_text, in_addr[a].bind,
332 imip->naddrs, last);
333 #endif
334
335 imip->addrs = ngx_pcalloc(cf->pool,
336 imip->naddrs * sizeof(ngx_imap_in_addr_t));
337 if (imip->addrs == NULL) {
338 return NGX_CONF_ERROR;
339 }
340
341 for (i = 0; i < imip->naddrs; i++) {
342 imip->addrs[i].addr = in_addr[i].addr;
343 imip->addrs[i].ctx = in_addr[i].ctx;
344
345 text = ngx_palloc(cf->pool,
346 INET_ADDRSTRLEN - 1 + sizeof(":65535") - 1);
347 if (text == NULL) {
348 return NGX_CONF_ERROR;
349 }
350
351 len = ngx_inet_ntop(AF_INET, &in_addr[i].addr, text,
352 INET_ADDRSTRLEN);
353
354 len = ngx_sprintf(text + len, ":%d", in_port[p].port) - text;
355
356 imip->addrs[i].addr_text.len = len;
357 imip->addrs[i].addr_text.data = text;
358 }
359
360 if (done) {
361 break;
362 }
363
364 in_addr++;
365 in_port[p].addrs.elts = in_addr;
366 last--;
367
368 a = 0;
369 }
370 }
371
372 return NGX_CONF_OK;
373 }
374
375
376 static int ngx_libc_cdecl
377 ngx_imap_cmp_conf_in_addrs(const void *one, const void *two)
378 {
379 ngx_imap_conf_in_addr_t *first, *second;
380
381 first = (ngx_imap_conf_in_addr_t *) one;
382 second = (ngx_imap_conf_in_addr_t *) two;
383
384 if (first->addr == INADDR_ANY) {
385 /* the INADDR_ANY must be the last resort, shift it to the end */
386 return 1;
387 }
388
389 if (first->bind && !second->bind) {
390 /* shift explicit bind()ed addresses to the start */
391 return -1;
392 }
393
394 if (!first->bind && second->bind) {
395 /* shift explicit bind()ed addresses to the start */
396 return 1;
397 }
398
399 /* do not sort by default */
400
401 return 0;
402 }
+0
-278
src/imap/ngx_imap.h less more
0
1 /*
2 * Copyright (C) Igor Sysoev
3 */
4
5
6 #ifndef _NGX_IMAP_H_INCLUDED_
7 #define _NGX_IMAP_H_INCLUDED_
8
9
10 #include <ngx_config.h>
11 #include <ngx_core.h>
12 #include <ngx_event.h>
13 #include <ngx_event_connect.h>
14
15 #if (NGX_IMAP_SSL)
16 #include <ngx_imap_ssl_module.h>
17 #endif
18
19
20
21 typedef struct {
22 void **main_conf;
23 void **srv_conf;
24 } ngx_imap_conf_ctx_t;
25
26
27 typedef struct {
28 in_addr_t addr;
29 in_port_t port;
30 int family;
31
32 /* server ctx */
33 ngx_imap_conf_ctx_t *ctx;
34
35 unsigned bind:1;
36 } ngx_imap_listen_t;
37
38
39 typedef struct {
40 in_addr_t addr;
41 ngx_imap_conf_ctx_t *ctx;
42 ngx_str_t addr_text;
43 } ngx_imap_in_addr_t;
44
45
46 typedef struct {
47 ngx_imap_in_addr_t *addrs; /* array of ngx_imap_in_addr_t */
48 ngx_uint_t naddrs;
49 } ngx_imap_in_port_t;
50
51
52 typedef struct {
53 in_port_t port;
54 ngx_array_t addrs; /* array of ngx_imap_conf_in_addr_t */
55 } ngx_imap_conf_in_port_t;
56
57
58 typedef struct {
59 in_addr_t addr;
60 ngx_imap_conf_ctx_t *ctx;
61 unsigned bind:1;
62 } ngx_imap_conf_in_addr_t;
63
64
65 typedef struct {
66 ngx_array_t servers; /* ngx_imap_core_srv_conf_t */
67 ngx_array_t listen; /* ngx_imap_listen_t */
68 } ngx_imap_core_main_conf_t;
69
70
71 #define NGX_IMAP_POP3_PROTOCOL 0
72 #define NGX_IMAP_IMAP_PROTOCOL 1
73
74 typedef struct {
75 ngx_msec_t timeout;
76
77 size_t imap_client_buffer_size;
78
79 ngx_uint_t protocol;
80
81 ngx_flag_t so_keepalive;
82
83 ngx_str_t pop3_capability;
84 ngx_str_t pop3_starttls_capability;
85 ngx_str_t pop3_auth_capability;
86
87 ngx_str_t imap_capability;
88 ngx_str_t imap_starttls_capability;
89 ngx_str_t imap_starttls_only_capability;
90
91 ngx_str_t server_name;
92
93 ngx_uint_t auth_methods;
94
95 ngx_array_t pop3_capabilities;
96 ngx_array_t imap_capabilities;
97
98 /* server ctx */
99 ngx_imap_conf_ctx_t *ctx;
100 } ngx_imap_core_srv_conf_t;
101
102
103 typedef struct {
104 void *(*create_main_conf)(ngx_conf_t *cf);
105 char *(*init_main_conf)(ngx_conf_t *cf, void *conf);
106
107 void *(*create_srv_conf)(ngx_conf_t *cf);
108 char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev,
109 void *conf);
110 } ngx_imap_module_t;
111
112
113 typedef enum {
114 ngx_imap_start = 0,
115 ngx_imap_login,
116 ngx_imap_user,
117 ngx_imap_passwd
118 } ngx_imap_state_e;
119
120
121 typedef enum {
122 ngx_pop3_start = 0,
123 ngx_pop3_user,
124 ngx_pop3_passwd,
125 ngx_pop3_auth_login_username,
126 ngx_pop3_auth_login_password,
127 ngx_pop3_auth_plain,
128 ngx_pop3_auth_cram_md5
129 } ngx_po3_state_e;
130
131
132 typedef struct {
133 ngx_peer_connection_t upstream;
134 ngx_buf_t *buffer;
135 } ngx_imap_proxy_ctx_t;
136
137
138 typedef struct {
139 uint32_t signature; /* "IMAP" */
140
141 ngx_connection_t *connection;
142
143 ngx_str_t out;
144 ngx_buf_t *buffer;
145
146 void **ctx;
147 void **main_conf;
148 void **srv_conf;
149
150 ngx_imap_proxy_ctx_t *proxy;
151
152 ngx_uint_t imap_state;
153
154 unsigned blocked:1;
155 unsigned quit:1;
156 unsigned protocol:1;
157 unsigned quoted:1;
158 unsigned backslash:1;
159 unsigned no_sync_literal:1;
160 unsigned starttls:1;
161 unsigned auth_method:2;
162 unsigned auth_wait:1;
163
164 ngx_str_t login;
165 ngx_str_t passwd;
166
167 ngx_str_t salt;
168 ngx_str_t tag;
169 ngx_str_t tagged_line;
170
171 ngx_str_t *addr_text;
172
173 ngx_uint_t command;
174 ngx_array_t args;
175
176 ngx_uint_t login_attempt;
177
178 /* used to parse IMAP/POP3 command */
179
180 ngx_uint_t state;
181 u_char *cmd_start;
182 u_char *arg_start;
183 u_char *arg_end;
184 ngx_uint_t literal_len;
185 } ngx_imap_session_t;
186
187
188 typedef struct {
189 ngx_str_t *client;
190 ngx_imap_session_t *session;
191 } ngx_imap_log_ctx_t;
192
193
194 #define NGX_POP3_USER 1
195 #define NGX_POP3_PASS 2
196 #define NGX_POP3_CAPA 3
197 #define NGX_POP3_QUIT 4
198 #define NGX_POP3_NOOP 5
199 #define NGX_POP3_STLS 6
200 #define NGX_POP3_APOP 7
201 #define NGX_POP3_AUTH 8
202 #define NGX_POP3_STAT 9
203 #define NGX_POP3_LIST 10
204 #define NGX_POP3_RETR 11
205 #define NGX_POP3_DELE 12
206 #define NGX_POP3_RSET 13
207 #define NGX_POP3_TOP 14
208 #define NGX_POP3_UIDL 15
209
210
211 #define NGX_IMAP_LOGIN 1
212 #define NGX_IMAP_LOGOUT 2
213 #define NGX_IMAP_CAPABILITY 3
214 #define NGX_IMAP_NOOP 4
215 #define NGX_IMAP_STARTTLS 5
216
217 #define NGX_IMAP_NEXT 6
218
219
220 #define NGX_IMAP_AUTH_PLAIN 0
221 #define NGX_IMAP_AUTH_APOP 1
222 #define NGX_IMAP_AUTH_CRAM_MD5 2
223
224
225 #define NGX_IMAP_AUTH_PLAIN_ENABLED 0x0002
226 #define NGX_IMAP_AUTH_APOP_ENABLED 0x0004
227 #define NGX_IMAP_AUTH_CRAM_MD5_ENABLED 0x0008
228
229
230 #define NGX_IMAP_PARSE_INVALID_COMMAND 20
231
232
233 #define NGX_IMAP_MODULE 0x50414D49 /* "IMAP" */
234
235 #define NGX_IMAP_MAIN_CONF 0x02000000
236 #define NGX_IMAP_SRV_CONF 0x04000000
237
238
239 #define NGX_IMAP_MAIN_CONF_OFFSET offsetof(ngx_imap_conf_ctx_t, main_conf)
240 #define NGX_IMAP_SRV_CONF_OFFSET offsetof(ngx_imap_conf_ctx_t, srv_conf)
241
242
243 #define ngx_imap_get_module_ctx(s, module) (s)->ctx[module.ctx_index]
244 #define ngx_imap_set_ctx(s, c, module) s->ctx[module.ctx_index] = c;
245 #define ngx_imap_delete_ctx(s, module) s->ctx[module.ctx_index] = NULL;
246
247
248 #define ngx_imap_get_module_main_conf(s, module) \
249 (s)->main_conf[module.ctx_index]
250 #define ngx_imap_get_module_srv_conf(s, module) (s)->srv_conf[module.ctx_index]
251
252 #define ngx_imap_conf_get_module_main_conf(cf, module) \
253 ((ngx_imap_conf_ctx_t *) cf->ctx)->main_conf[module.ctx_index]
254
255
256 void ngx_imap_init_connection(ngx_connection_t *c);
257 void ngx_imap_send(ngx_event_t *wev);
258 void ngx_imap_auth_state(ngx_event_t *rev);
259 void ngx_pop3_auth_state(ngx_event_t *rev);
260 void ngx_imap_close_connection(ngx_connection_t *c);
261 void ngx_imap_session_internal_server_error(ngx_imap_session_t *s);
262
263 ngx_int_t ngx_imap_parse_command(ngx_imap_session_t *s);
264 ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s);
265
266
267 /* STUB */
268 void ngx_imap_proxy_init(ngx_imap_session_t *s, ngx_peer_addr_t *peer);
269 void ngx_imap_auth_http_init(ngx_imap_session_t *s);
270 /**/
271
272
273 extern ngx_uint_t ngx_imap_max_module;
274 extern ngx_module_t ngx_imap_core_module;
275
276
277 #endif /* _NGX_IMAP_H_INCLUDED_ */
+0
-1357
src/imap/ngx_imap_auth_http_module.c less more
0
1 /*
2 * Copyright (C) Igor Sysoev
3 */
4
5
6 #include <ngx_config.h>
7 #include <ngx_core.h>
8 #include <ngx_event.h>
9 #include <ngx_event_connect.h>
10 #include <ngx_imap.h>
11
12
13 typedef struct {
14 ngx_peer_addr_t *peer;
15
16 ngx_msec_t timeout;
17
18 ngx_str_t host_header;
19 ngx_str_t uri;
20 ngx_str_t header;
21
22 ngx_array_t *headers;
23 } ngx_imap_auth_http_conf_t;
24
25
26 typedef struct ngx_imap_auth_http_ctx_s ngx_imap_auth_http_ctx_t;
27
28 typedef void (*ngx_imap_auth_http_handler_pt)(ngx_imap_session_t *s,
29 ngx_imap_auth_http_ctx_t *ctx);
30
31 struct ngx_imap_auth_http_ctx_s {
32 ngx_buf_t *request;
33 ngx_buf_t *response;
34 ngx_peer_connection_t peer;
35
36 ngx_imap_auth_http_handler_pt handler;
37
38 ngx_uint_t state;
39 ngx_uint_t hash; /* no needed ? */
40
41 u_char *header_name_start;
42 u_char *header_name_end;
43 u_char *header_start;
44 u_char *header_end;
45
46 ngx_str_t addr;
47 ngx_str_t port;
48 ngx_str_t err;
49 ngx_str_t errmsg;
50
51 time_t sleep;
52
53 ngx_pool_t *pool;
54 };
55
56
57 static void ngx_imap_auth_http_write_handler(ngx_event_t *wev);
58 static void ngx_imap_auth_http_read_handler(ngx_event_t *rev);
59 static void ngx_imap_auth_http_ignore_status_line(ngx_imap_session_t *s,
60 ngx_imap_auth_http_ctx_t *ctx);
61 static void ngx_imap_auth_http_process_headers(ngx_imap_session_t *s,
62 ngx_imap_auth_http_ctx_t *ctx);
63 static void ngx_imap_auth_sleep_handler(ngx_event_t *rev);
64 static ngx_int_t ngx_imap_auth_http_parse_header_line(ngx_imap_session_t *s,
65 ngx_imap_auth_http_ctx_t *ctx);
66 static void ngx_imap_auth_http_block_read(ngx_event_t *rev);
67 static void ngx_imap_auth_http_dummy_handler(ngx_event_t *ev);
68 static ngx_buf_t *ngx_imap_auth_http_create_request(ngx_imap_session_t *s,
69 ngx_pool_t *pool, ngx_imap_auth_http_conf_t *ahcf);
70 static ngx_int_t ngx_imap_auth_http_escape(ngx_pool_t *pool, ngx_str_t *text,
71 ngx_str_t *escaped);
72
73 static void *ngx_imap_auth_http_create_conf(ngx_conf_t *cf);
74 static char *ngx_imap_auth_http_merge_conf(ngx_conf_t *cf, void *parent,
75 void *child);
76 static char *ngx_imap_auth_http(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
77 static char *ngx_imap_auth_http_header(ngx_conf_t *cf, ngx_command_t *cmd,
78 void *conf);
79
80
81 static ngx_command_t ngx_imap_auth_http_commands[] = {
82
83 { ngx_string("auth_http"),
84 NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1,
85 ngx_imap_auth_http,
86 NGX_IMAP_SRV_CONF_OFFSET,
87 0,
88 NULL },
89
90 { ngx_string("auth_http_timeout"),
91 NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1,
92 ngx_conf_set_msec_slot,
93 NGX_IMAP_SRV_CONF_OFFSET,
94 offsetof(ngx_imap_auth_http_conf_t, timeout),
95 NULL },
96
97 { ngx_string("auth_http_header"),
98 NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE2,
99 ngx_imap_auth_http_header,
100 NGX_IMAP_SRV_CONF_OFFSET,
101 0,
102 NULL },
103
104 ngx_null_command
105 };
106
107
108 static ngx_imap_module_t ngx_imap_auth_http_module_ctx = {
109 NULL, /* create main configuration */
110 NULL, /* init main configuration */
111
112 ngx_imap_auth_http_create_conf, /* create server configuration */
113 ngx_imap_auth_http_merge_conf /* merge server configuration */
114 };
115
116
117 ngx_module_t ngx_imap_auth_http_module = {
118 NGX_MODULE_V1,
119 &ngx_imap_auth_http_module_ctx, /* module context */
120 ngx_imap_auth_http_commands, /* module directives */
121 NGX_IMAP_MODULE, /* module type */
122 NULL, /* init master */
123 NULL, /* init module */
124 NULL, /* init process */
125 NULL, /* init thread */
126 NULL, /* exit thread */
127 NULL, /* exit process */
128 NULL, /* exit master */
129 NGX_MODULE_V1_PADDING
130 };
131
132
133 static char *ngx_imap_auth_http_protocol[] = { "pop3", "imap" };
134 static ngx_str_t ngx_imap_auth_http_method[] = {
135 ngx_string("plain"),
136 ngx_string("apop"),
137 ngx_string("cram-md5")
138 };
139
140
141 void
142 ngx_imap_auth_http_init(ngx_imap_session_t *s)
143 {
144 ngx_int_t rc;
145 ngx_pool_t *pool;
146 ngx_imap_auth_http_ctx_t *ctx;
147 ngx_imap_auth_http_conf_t *ahcf;
148
149 s->connection->log->action = "in http auth state";
150
151 pool = ngx_create_pool(2048, s->connection->log);
152 if (pool == NULL) {
153 ngx_imap_session_internal_server_error(s);
154 return;
155 }
156
157 ctx = ngx_pcalloc(pool, sizeof(ngx_imap_auth_http_ctx_t));
158 if (ctx == NULL) {
159 ngx_destroy_pool(pool);
160 ngx_imap_session_internal_server_error(s);
161 return;
162 }
163
164 ctx->pool = pool;
165
166 ahcf = ngx_imap_get_module_srv_conf(s, ngx_imap_auth_http_module);
167
168 ctx->request = ngx_imap_auth_http_create_request(s, pool, ahcf);
169 if (ctx->request == NULL) {
170 ngx_destroy_pool(ctx->pool);
171 ngx_imap_session_internal_server_error(s);
172 return;
173 }
174
175 ngx_imap_set_ctx(s, ctx, ngx_imap_auth_http_module);
176
177 ctx->peer.sockaddr = ahcf->peer->sockaddr;
178 ctx->peer.socklen = ahcf->peer->socklen;
179 ctx->peer.name = &ahcf->peer->name;
180 ctx->peer.get = ngx_event_get_peer;
181 ctx->peer.log = s->connection->log;
182 ctx->peer.log_error = NGX_ERROR_ERR;
183
184 rc = ngx_event_connect_peer(&ctx->peer);
185
186 if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
187 if (ctx->peer.connection) {
188 ngx_close_connection(ctx->peer.connection);
189 }
190
191 ngx_destroy_pool(ctx->pool);
192 ngx_imap_session_internal_server_error(s);
193 return;
194 }
195
196 ctx->peer.connection->data = s;
197 ctx->peer.connection->pool = s->connection->pool;
198
199 s->connection->read->handler = ngx_imap_auth_http_block_read;
200 ctx->peer.connection->read->handler = ngx_imap_auth_http_read_handler;
201 ctx->peer.connection->write->handler = ngx_imap_auth_http_write_handler;
202
203 ctx->handler = ngx_imap_auth_http_ignore_status_line;
204
205 ngx_add_timer(ctx->peer.connection->read, ahcf->timeout);
206 ngx_add_timer(ctx->peer.connection->write, ahcf->timeout);
207
208 if (rc == NGX_OK) {
209 ngx_imap_auth_http_write_handler(ctx->peer.connection->write);
210 return;
211 }
212 }
213
214
215 static void
216 ngx_imap_auth_http_write_handler(ngx_event_t *wev)
217 {
218 ssize_t n, size;
219 ngx_connection_t *c;
220 ngx_imap_session_t *s;
221 ngx_imap_auth_http_ctx_t *ctx;
222 ngx_imap_auth_http_conf_t *ahcf;
223
224 c = wev->data;
225 s = c->data;
226
227 ctx = ngx_imap_get_module_ctx(s, ngx_imap_auth_http_module);
228
229 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, wev->log, 0,
230 "imap auth http write handler");
231
232 if (wev->timedout) {
233 ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT,
234 "auth http server %V timed out", ctx->peer.name);
235 ngx_close_connection(ctx->peer.connection);
236 ngx_destroy_pool(ctx->pool);
237 ngx_imap_session_internal_server_error(s);
238 return;
239 }
240
241 size = ctx->request->last - ctx->request->pos;
242
243 n = ngx_send(c, ctx->request->pos, size);
244
245 if (n == NGX_ERROR) {
246 ngx_close_connection(ctx->peer.connection);
247 ngx_destroy_pool(ctx->pool);
248 ngx_imap_session_internal_server_error(s);
249 return;
250 }
251
252 if (n > 0) {
253 ctx->request->pos += n;
254
255 if (n == size) {
256 wev->handler = ngx_imap_auth_http_dummy_handler;
257
258 if (wev->timer_set) {
259 ngx_del_timer(wev);
260 }
261
262 if (ngx_handle_write_event(wev, 0) == NGX_ERROR) {
263 ngx_close_connection(ctx->peer.connection);
264 ngx_destroy_pool(ctx->pool);
265 ngx_imap_session_internal_server_error(s);
266 }
267
268 return;
269 }
270 }
271
272 if (!wev->timer_set) {
273 ahcf = ngx_imap_get_module_srv_conf(s, ngx_imap_auth_http_module);
274 ngx_add_timer(wev, ahcf->timeout);
275 }
276 }
277
278
279 static void
280 ngx_imap_auth_http_read_handler(ngx_event_t *rev)
281 {
282 ssize_t n, size;
283 ngx_connection_t *c;
284 ngx_imap_session_t *s;
285 ngx_imap_auth_http_ctx_t *ctx;
286
287 c = rev->data;
288 s = c->data;
289
290 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0,
291 "imap auth http read handler");
292
293 ctx = ngx_imap_get_module_ctx(s, ngx_imap_auth_http_module);
294
295 if (rev->timedout) {
296 ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT,
297 "auth http server %V timed out", ctx->peer.name);
298 ngx_close_connection(ctx->peer.connection);
299 ngx_destroy_pool(ctx->pool);
300 ngx_imap_session_internal_server_error(s);
301 return;
302 }
303
304 if (ctx->response == NULL) {
305 ctx->response = ngx_create_temp_buf(ctx->pool, 1024);
306 if (ctx->response == NULL) {
307 ngx_close_connection(ctx->peer.connection);
308 ngx_destroy_pool(ctx->pool);
309 ngx_imap_session_internal_server_error(s);
310 return;
311 }
312 }
313
314 size = ctx->response->end - ctx->response->last;
315
316 n = ngx_recv(c, ctx->response->pos, size);
317
318 if (n > 0) {
319 ctx->response->last += n;
320
321 ctx->handler(s, ctx);
322 return;
323 }
324
325 if (n == NGX_AGAIN) {
326 return;
327 }
328
329 ngx_close_connection(ctx->peer.connection);
330 ngx_destroy_pool(ctx->pool);
331 ngx_imap_session_internal_server_error(s);
332 }
333
334
335 static void
336 ngx_imap_auth_http_ignore_status_line(ngx_imap_session_t *s,
337 ngx_imap_auth_http_ctx_t *ctx)
338 {
339 u_char *p, ch;
340 enum {
341 sw_start = 0,
342 sw_H,
343 sw_HT,
344 sw_HTT,
345 sw_HTTP,
346 sw_skip,
347 sw_almost_done
348 } state;
349
350 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
351 "imap auth http process status line");
352
353 state = ctx->state;
354
355 for (p = ctx->response->pos; p < ctx->response->last; p++) {
356 ch = *p;
357
358 switch (state) {
359
360 /* "HTTP/" */
361 case sw_start:
362 if (ch == 'H') {
363 state = sw_H;
364 break;
365 }
366 goto next;
367
368 case sw_H:
369 if (ch == 'T') {
370 state = sw_HT;
371 break;
372 }
373 goto next;
374
375 case sw_HT:
376 if (ch == 'T') {
377 state = sw_HTT;
378 break;
379 }
380 goto next;
381
382 case sw_HTT:
383 if (ch == 'P') {
384 state = sw_HTTP;
385 break;
386 }
387 goto next;
388
389 case sw_HTTP:
390 if (ch == '/') {
391 state = sw_skip;
392 break;
393 }
394 goto next;
395
396 /* any text until end of line */
397 case sw_skip:
398 switch (ch) {
399 case CR:
400 state = sw_almost_done;
401
402 break;
403 case LF:
404 goto done;
405 }
406 break;
407
408 /* end of status line */
409 case sw_almost_done:
410 if (ch == LF) {
411 goto done;
412 }
413
414 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
415 "auth http server &V sent invalid response",
416 ctx->peer.name);
417 ngx_close_connection(ctx->peer.connection);
418 ngx_destroy_pool(ctx->pool);
419 ngx_imap_session_internal_server_error(s);
420 return;
421 }
422 }
423
424 ctx->response->pos = p;
425 ctx->state = state;
426
427 return;
428
429 next:
430
431 p = ctx->response->start - 1;
432
433 done:
434
435 ctx->response->pos = p + 1;
436 ctx->state = 0;
437 ctx->handler = ngx_imap_auth_http_process_headers;
438 ctx->handler(s, ctx);
439 }
440
441
442 static void
443 ngx_imap_auth_http_process_headers(ngx_imap_session_t *s,
444 ngx_imap_auth_http_ctx_t *ctx)
445 {
446 u_char *p;
447 time_t timer;
448 size_t len, size;
449 ngx_int_t rc, port, n;
450 ngx_peer_addr_t *peer;
451 struct sockaddr_in *sin;
452
453 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
454 "imap auth http process headers");
455
456 for ( ;; ) {
457 rc = ngx_imap_auth_http_parse_header_line(s, ctx);
458
459 if (rc == NGX_OK) {
460
461 #if (NGX_DEBUG)
462 {
463 ngx_str_t key, value;
464
465 key.len = ctx->header_name_end - ctx->header_name_start;
466 key.data = ctx->header_name_start;
467 value.len = ctx->header_end - ctx->header_start;
468 value.data = ctx->header_start;
469
470 ngx_log_debug2(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
471 "auth http header: \"%V: %V\"",
472 &key, &value);
473 }
474 #endif
475
476 len = ctx->header_name_end - ctx->header_name_start;
477
478 if (len == sizeof("Auth-Status") - 1
479 && ngx_strncasecmp(ctx->header_name_start,
480 (u_char *) "Auth-Status",
481 sizeof("Auth-Status") - 1)
482 == 0)
483 {
484 len = ctx->header_end - ctx->header_start;
485
486 if (len == 2
487 && ctx->header_start[0] == 'O'
488 && ctx->header_start[1] == 'K')
489 {
490 continue;
491 }
492
493 if (len == 4
494 && ctx->header_start[0] == 'W'
495 && ctx->header_start[1] == 'A'
496 && ctx->header_start[2] == 'I'
497 && ctx->header_start[3] == 'T')
498 {
499 s->auth_wait = 1;
500 continue;
501 }
502
503 ctx->errmsg.len = len;
504 ctx->errmsg.data = ctx->header_start;
505
506 if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
507 size = sizeof("-ERR ") - 1 + len + sizeof(CRLF) - 1;
508
509 } else {
510 size = s->tag.len + sizeof("NO ") - 1 + len
511 + sizeof(CRLF) - 1;
512 }
513
514 p = ngx_pcalloc(s->connection->pool, size);
515 if (p == NULL) {
516 ngx_close_connection(ctx->peer.connection);
517 ngx_destroy_pool(ctx->pool);
518 ngx_imap_session_internal_server_error(s);
519 return;
520 }
521
522 ctx->err.data = p;
523
524 if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
525 *p++ = '-'; *p++ = 'E'; *p++ = 'R'; *p++ = 'R';
526
527 } else {
528 p = ngx_cpymem(p, s->tag.data, s->tag.len);
529 *p++ = 'N'; *p++ = 'O';
530 }
531
532 *p++ = ' ';
533
534 p = ngx_cpymem(p, ctx->header_start, len);
535 *p++ = CR; *p++ = LF;
536
537 ctx->err.len = p - ctx->err.data;
538
539 continue;
540 }
541
542 if (len == sizeof("Auth-Server") - 1
543 && ngx_strncasecmp(ctx->header_name_start,
544 (u_char *) "Auth-Server",
545 sizeof("Auth-Server") - 1)
546 == 0)
547 {
548 ctx->addr.len = ctx->header_end - ctx->header_start;
549 ctx->addr.data = ctx->header_start;
550
551 continue;
552 }
553
554 if (len == sizeof("Auth-Port") - 1
555 && ngx_strncasecmp(ctx->header_name_start,
556 (u_char *) "Auth-Port",
557 sizeof("Auth-Port") - 1)
558 == 0)
559 {
560 ctx->port.len = ctx->header_end - ctx->header_start;
561 ctx->port.data = ctx->header_start;
562
563 continue;
564 }
565
566 if (len == sizeof("Auth-User") - 1
567 && ngx_strncasecmp(ctx->header_name_start,
568 (u_char *) "Auth-User",
569 sizeof("Auth-User") - 1)
570 == 0)
571 {
572 s->login.len = ctx->header_end - ctx->header_start;
573
574 s->login.data = ngx_palloc(s->connection->pool, s->login.len);
575 if (s->login.data == NULL) {
576 ngx_close_connection(ctx->peer.connection);
577 ngx_destroy_pool(ctx->pool);
578 ngx_imap_session_internal_server_error(s);
579 return;
580 }
581
582 ngx_memcpy(s->login.data, ctx->header_start, s->login.len);
583
584 continue;
585 }
586
587 if (len == sizeof("Auth-Pass") - 1
588 && ngx_strncasecmp(ctx->header_name_start,
589 (u_char *) "Auth-Pass",
590 sizeof("Auth-Pass") - 1)
591 == 0)
592 {
593 s->passwd.len = ctx->header_end - ctx->header_start;
594
595 s->passwd.data = ngx_palloc(s->connection->pool, s->passwd.len);
596 if (s->passwd.data == NULL) {
597 ngx_close_connection(ctx->peer.connection);
598 ngx_destroy_pool(ctx->pool);
599 ngx_imap_session_internal_server_error(s);
600 return;
601 }
602
603 ngx_memcpy(s->passwd.data, ctx->header_start, s->passwd.len);
604
605 continue;
606 }
607
608 if (len == sizeof("Auth-Wait") - 1
609 && ngx_strncasecmp(ctx->header_name_start,
610 (u_char *) "Auth-Wait",
611 sizeof("Auth-Wait") - 1)
612 == 0)
613 {
614 n = ngx_atoi(ctx->header_start,
615 ctx->header_end - ctx->header_start);
616
617 if (n != NGX_ERROR) {
618 ctx->sleep = n;
619 }
620
621 continue;
622 }
623
624 /* ignore other headers */
625
626 continue;
627 }
628
629 if (rc == NGX_DONE) {
630 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
631 "auth http header done");
632
633 ngx_close_connection(ctx->peer.connection);
634
635 if (ctx->err.len) {
636 ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
637 "client login failed: \"%V\"", &ctx->errmsg);
638
639 s->out = ctx->err;
640 timer = ctx->sleep;
641
642 ngx_destroy_pool(ctx->pool);
643
644 if (timer == 0) {
645 s->quit = 1;
646 ngx_imap_send(s->connection->write);
647 return;
648 }
649
650 ngx_add_timer(s->connection->read, timer * 1000);
651
652 s->connection->read->handler = ngx_imap_auth_sleep_handler;
653
654 return;
655 }
656
657 if (s->auth_wait) {
658 timer = ctx->sleep;
659
660 ngx_destroy_pool(ctx->pool);
661
662 if (timer == 0) {
663 ngx_imap_auth_http_init(s);
664 return;
665 }
666
667 ngx_add_timer(s->connection->read, timer * 1000);
668
669 s->connection->read->handler = ngx_imap_auth_sleep_handler;
670
671 return;
672 }
673
674 if (ctx->addr.len == 0 || ctx->port.len == 0) {
675 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
676 "auth http server %V did not send server or port",
677 ctx->peer.name);
678 ngx_destroy_pool(ctx->pool);
679 ngx_imap_session_internal_server_error(s);
680 return;
681 }
682
683 if (s->passwd.data == NULL) {
684 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
685 "auth http server %V did not send password",
686 ctx->peer.name);
687 ngx_destroy_pool(ctx->pool);
688 ngx_imap_session_internal_server_error(s);
689 return;
690 }
691
692 peer = ngx_pcalloc(s->connection->pool, sizeof(ngx_peer_addr_t));
693 if (peer == NULL) {
694 ngx_destroy_pool(ctx->pool);
695 ngx_imap_session_internal_server_error(s);
696 return;
697 }
698
699 sin = ngx_pcalloc(s->connection->pool, sizeof(struct sockaddr_in));
700 if (sin == NULL) {
701 ngx_destroy_pool(ctx->pool);
702 ngx_imap_session_internal_server_error(s);
703 return;
704 }
705
706 sin->sin_family = AF_INET;
707
708 port = ngx_atoi(ctx->port.data, ctx->port.len);
709 if (port == NGX_ERROR || port < 1 || port > 65536) {
710 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
711 "auth http server %V sent invalid server "
712 "port:\"%V\"",
713 ctx->peer.name, &ctx->port);
714 ngx_destroy_pool(ctx->pool);
715 ngx_imap_session_internal_server_error(s);
716 return;
717 }
718
719 sin->sin_port = htons((in_port_t) port);
720
721 ctx->addr.data[ctx->addr.len] = '\0';
722 sin->sin_addr.s_addr = inet_addr((char *) ctx->addr.data);
723 if (sin->sin_addr.s_addr == INADDR_NONE) {
724 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
725 "auth http server %V sent invalid server "
726 "address:\"%V\"",
727 ctx->peer.name, &ctx->addr);
728 ngx_destroy_pool(ctx->pool);
729 ngx_imap_session_internal_server_error(s);
730 return;
731 }
732
733 peer->sockaddr = (struct sockaddr *) sin;
734 peer->socklen = sizeof(struct sockaddr_in);
735
736 len = ctx->addr.len + 1 + ctx->port.len;
737
738 peer->name.len = len;
739
740 peer->name.data = ngx_palloc(s->connection->pool, len);
741 if (peer->name.data == NULL) {
742 ngx_destroy_pool(ctx->pool);
743 ngx_imap_session_internal_server_error(s);
744 return;
745 }
746
747 len = ctx->addr.len;
748
749 ngx_memcpy(peer->name.data, ctx->addr.data, len);
750
751 peer->name.data[len++] = ':';
752
753 ngx_memcpy(peer->name.data + len, ctx->port.data, ctx->port.len);
754
755 ngx_destroy_pool(ctx->pool);
756 ngx_imap_proxy_init(s, peer);
757
758 return;
759 }
760
761 if (rc == NGX_AGAIN ) {
762 return;
763 }
764
765 /* rc == NGX_ERROR */
766
767 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
768 "auth http server %V sent invalid header in response",
769 ctx->peer.name);
770 ngx_close_connection(ctx->peer.connection);
771 ngx_destroy_pool(ctx->pool);
772 ngx_imap_session_internal_server_error(s);
773
774 return;
775 }
776 }
777
778
779 static void
780 ngx_imap_auth_sleep_handler(ngx_event_t *rev)
781 {
782 ngx_connection_t *c;
783 ngx_imap_session_t *s;
784 ngx_imap_core_srv_conf_t *cscf;
785
786 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap auth sleep handler");
787
788 c = rev->data;
789 s = c->data;
790
791 if (rev->timedout) {
792
793 rev->timedout = 0;
794
795 if (s->auth_wait) {
796 s->auth_wait = 0;
797 ngx_imap_auth_http_init(s);
798 return;
799 }
800
801 if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
802 s->imap_state = ngx_pop3_start;
803 s->connection->read->handler = ngx_pop3_auth_state;
804
805 } else {
806 s->imap_state = ngx_imap_start;
807 s->connection->read->handler = ngx_imap_auth_state;
808 }
809
810 s->auth_method = NGX_IMAP_AUTH_PLAIN;
811
812 c->log->action = "in auth state";
813
814 ngx_imap_send(s->connection->write);
815
816 if (c->destroyed) {
817 return;
818 }
819
820 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
821
822 ngx_add_timer(rev, cscf->timeout);
823
824 if (rev->ready) {
825 s->connection->read->handler(rev);
826 return;
827 }
828
829 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
830 ngx_imap_close_connection(s->connection);
831 }
832
833 return;
834 }
835
836 if (rev->active) {
837 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
838 ngx_imap_close_connection(s->connection);
839 }
840 }
841 }
842
843
844 static ngx_int_t
845 ngx_imap_auth_http_parse_header_line(ngx_imap_session_t *s,
846 ngx_imap_auth_http_ctx_t *ctx)
847 {
848 u_char c, ch, *p;
849 ngx_uint_t hash;
850 enum {
851 sw_start = 0,
852 sw_name,
853 sw_space_before_value,
854 sw_value,
855 sw_space_after_value,
856 sw_almost_done,
857 sw_header_almost_done
858 } state;
859
860 state = ctx->state;
861 hash = ctx->hash;
862
863 for (p = ctx->response->pos; p < ctx->response->last; p++) {
864 ch = *p;
865
866 switch (state) {
867
868 /* first char */
869 case sw_start:
870
871 switch (ch) {
872 case CR:
873 ctx->header_end = p;
874 state = sw_header_almost_done;
875 break;
876 case LF:
877 ctx->header_end = p;
878 goto header_done;
879 default:
880 state = sw_name;
881 ctx->header_name_start = p;
882
883 c = (u_char) (ch | 0x20);
884 if (c >= 'a' && c <= 'z') {
885 hash = c;
886 break;
887 }
888
889 if (ch >= '0' && ch <= '9') {
890 hash = ch;
891 break;
892 }
893
894 return NGX_ERROR;
895 }
896 break;
897
898 /* header name */
899 case sw_name:
900 c = (u_char) (ch | 0x20);
901 if (c >= 'a' && c <= 'z') {
902 hash += c;
903 break;
904 }
905
906 if (ch == ':') {
907 ctx->header_name_end = p;
908 state = sw_space_before_value;
909 break;
910 }
911
912 if (ch == '-') {
913 hash += ch;
914 break;
915 }
916
917 if (ch >= '0' && ch <= '9') {
918 hash += ch;
919 break;
920 }
921
922 if (ch == CR) {
923 ctx->header_name_end = p;
924 ctx->header_start = p;
925 ctx->header_end = p;
926 state = sw_almost_done;
927 break;
928 }
929
930 if (ch == LF) {
931 ctx->header_name_end = p;
932 ctx->header_start = p;
933 ctx->header_end = p;
934 goto done;
935 }
936
937 return NGX_ERROR;
938
939 /* space* before header value */
940 case sw_space_before_value:
941 switch (ch) {
942 case ' ':
943 break;
944 case CR:
945 ctx->header_start = p;
946 ctx->header_end = p;
947 state = sw_almost_done;
948 break;
949 case LF:
950 ctx->header_start = p;
951 ctx->header_end = p;
952 goto done;
953 default:
954 ctx->header_start = p;
955 state = sw_value;
956 break;
957 }
958 break;
959
960 /* header value */
961 case sw_value:
962 switch (ch) {
963 case ' ':
964 ctx->header_end = p;
965 state = sw_space_after_value;
966 break;
967 case CR:
968 ctx->header_end = p;
969 state = sw_almost_done;
970 break;
971 case LF:
972 ctx->header_end = p;
973 goto done;
974 }
975 break;
976
977 /* space* before end of header line */
978 case sw_space_after_value:
979 switch (ch) {
980 case ' ':
981 break;
982 case CR:
983 state = sw_almost_done;
984 break;
985 case LF:
986 goto done;
987 default:
988 state = sw_value;
989 break;
990 }
991 break;
992
993 /* end of header line */
994 case sw_almost_done:
995 switch (ch) {
996 case LF:
997 goto done;
998 default:
999 return NGX_ERROR;
1000 }
1001
1002 /* end of header */
1003 case sw_header_almost_done:
1004 switch (ch) {
1005 case LF:
1006 goto header_done;
1007 default:
1008 return NGX_ERROR;
1009 }
1010 }
1011 }
1012
1013 ctx->response->pos = p;
1014 ctx->state = state;
1015 ctx->hash = hash;
1016
1017 return NGX_AGAIN;
1018
1019 done:
1020
1021 ctx->response->pos = p + 1;
1022 ctx->state = sw_start;
1023 ctx->hash = hash;
1024
1025 return NGX_OK;
1026
1027 header_done:
1028
1029 ctx->response->pos = p + 1;
1030 ctx->state = sw_start;
1031
1032 return NGX_DONE;
1033 }
1034
1035
1036 static void
1037 ngx_imap_auth_http_block_read(ngx_event_t *rev)
1038 {
1039 ngx_connection_t *c;
1040 ngx_imap_session_t *s;
1041 ngx_imap_auth_http_ctx_t *ctx;
1042
1043 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0,
1044 "imap auth http block read");
1045
1046 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
1047 c = rev->data;
1048 s = c->data;
1049
1050 ctx = ngx_imap_get_module_ctx(s, ngx_imap_auth_http_module);
1051
1052 ngx_close_connection(ctx->peer.connection);
1053 ngx_destroy_pool(ctx->pool);
1054 ngx_imap_session_internal_server_error(s);
1055 }
1056 }
1057
1058
1059 static void
1060 ngx_imap_auth_http_dummy_handler(ngx_event_t *ev)
1061 {
1062 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, ev->log, 0,
1063 "imap auth http dummy handler");
1064 }
1065
1066
1067 static ngx_buf_t *
1068 ngx_imap_auth_http_create_request(ngx_imap_session_t *s, ngx_pool_t *pool,
1069 ngx_imap_auth_http_conf_t *ahcf)
1070 {
1071 size_t len;
1072 ngx_buf_t *b;
1073 ngx_str_t login, passwd;
1074
1075 if (ngx_imap_auth_http_escape(pool, &s->login, &login) != NGX_OK) {
1076 return NULL;
1077 }
1078
1079 if (ngx_imap_auth_http_escape(pool, &s->passwd, &passwd) != NGX_OK) {
1080 return NULL;
1081 }
1082
1083 len = sizeof("GET ") - 1 + ahcf->uri.len + sizeof(" HTTP/1.0" CRLF) - 1
1084 + sizeof("Host: ") - 1 + ahcf->host_header.len + sizeof(CRLF) - 1
1085 + sizeof("Auth-Method: ") - 1
1086 + ngx_imap_auth_http_method[s->auth_method].len
1087 + sizeof(CRLF) - 1
1088 + sizeof("Auth-User: ") - 1 + login.len + sizeof(CRLF) - 1
1089 + sizeof("Auth-Pass: ") - 1 + passwd.len + sizeof(CRLF) - 1
1090 + sizeof("Auth-Salt: ") - 1 + s->salt.len
1091 + sizeof("Auth-Protocol: imap" CRLF) - 1
1092 + sizeof("Auth-Login-Attempt: ") - 1 + NGX_INT_T_LEN
1093 + sizeof(CRLF) - 1
1094 + sizeof("Client-IP: ") - 1 + s->connection->addr_text.len
1095 + sizeof(CRLF) - 1
1096 + sizeof(CRLF) - 1;
1097
1098 b = ngx_create_temp_buf(pool, len);
1099 if (b == NULL) {
1100 return NULL;
1101 }
1102
1103 b->last = ngx_cpymem(b->last, "GET ", sizeof("GET ") - 1);
1104 b->last = ngx_copy(b->last, ahcf->uri.data, ahcf->uri.len);
1105 b->last = ngx_cpymem(b->last, " HTTP/1.0" CRLF,
1106 sizeof(" HTTP/1.0" CRLF) - 1);
1107
1108 b->last = ngx_cpymem(b->last, "Host: ", sizeof("Host: ") - 1);
1109 b->last = ngx_copy(b->last, ahcf->host_header.data,
1110 ahcf->host_header.len);
1111 *b->last++ = CR; *b->last++ = LF;
1112
1113 b->last = ngx_cpymem(b->last, "Auth-Method: ",
1114 sizeof("Auth-Method: ") - 1);
1115 b->last = ngx_cpymem(b->last,
1116 ngx_imap_auth_http_method[s->auth_method].data,
1117 ngx_imap_auth_http_method[s->auth_method].len);
1118 *b->last++ = CR; *b->last++ = LF;
1119
1120 b->last = ngx_cpymem(b->last, "Auth-User: ", sizeof("Auth-User: ") - 1);
1121 b->last = ngx_copy(b->last, login.data, login.len);
1122 *b->last++ = CR; *b->last++ = LF;
1123
1124 b->last = ngx_cpymem(b->last, "Auth-Pass: ", sizeof("Auth-Pass: ") - 1);
1125 b->last = ngx_copy(b->last, passwd.data, passwd.len);
1126 *b->last++ = CR; *b->last++ = LF;
1127
1128 if (s->auth_method != NGX_IMAP_AUTH_PLAIN && s->salt.len) {
1129 b->last = ngx_cpymem(b->last, "Auth-Salt: ", sizeof("Auth-Salt: ") - 1);
1130 b->last = ngx_copy(b->last, s->salt.data, s->salt.len);
1131
1132 s->passwd.data = NULL;
1133 }
1134
1135 b->last = ngx_cpymem(b->last, "Auth-Protocol: ",
1136 sizeof("Auth-Protocol: ") - 1);
1137 b->last = ngx_cpymem(b->last, ngx_imap_auth_http_protocol[s->protocol],
1138 sizeof("imap") - 1);
1139 *b->last++ = CR; *b->last++ = LF;
1140
1141 b->last = ngx_sprintf(b->last, "Auth-Login-Attempt: %ui" CRLF,
1142 s->login_attempt);
1143
1144 b->last = ngx_cpymem(b->last, "Client-IP: ", sizeof("Client-IP: ") - 1);
1145 b->last = ngx_copy(b->last, s->connection->addr_text.data,
1146 s->connection->addr_text.len);
1147 *b->last++ = CR; *b->last++ = LF;
1148
1149 if (ahcf->header.len) {
1150 b->last = ngx_copy(b->last, ahcf->header.data, ahcf->header.len);
1151 }
1152
1153 /* add "\r\n" at the header end */
1154 *b->last++ = CR; *b->last++ = LF;
1155
1156 #if (NGX_DEBUG_IMAP_PASSWD)
1157 {
1158 ngx_str_t l;
1159
1160 l.len = b->last - b->pos;
1161 l.data = b->pos;
1162 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
1163 "imap auth http header:\n\"%V\"", &l);
1164 }
1165 #endif
1166
1167 return b;
1168 }
1169
1170
1171 static ngx_int_t
1172 ngx_imap_auth_http_escape(ngx_pool_t *pool, ngx_str_t *text, ngx_str_t *escaped)
1173 {
1174 u_char ch, *p;
1175 ngx_uint_t i, n;
1176
1177 n = 0;
1178
1179 for (i = 0; i < text->len; i++) {
1180 ch = text->data[i];
1181
1182 if (ch == CR || ch == LF) {
1183 n++;
1184 }
1185 }
1186
1187 if (n == 0) {
1188 *escaped = *text;
1189 return NGX_OK;
1190 }
1191
1192 escaped->len = text->len + n * 2;
1193
1194 p = ngx_palloc(pool, escaped->len);
1195 if (p == NULL) {
1196 return NGX_ERROR;
1197 }
1198
1199 escaped->data = p;
1200
1201 for (i = 0; i < text->len; i++) {
1202 ch = text->data[i];
1203
1204 if (ch == CR) {
1205 *p++ = '%';
1206 *p++ = '0';
1207 *p++ = 'D';
1208 continue;
1209 }
1210
1211 if (ch == LF) {
1212 *p++ = '%';
1213 *p++ = '0';
1214 *p++ = 'A';
1215 continue;
1216 }
1217
1218 *p++ = ch;
1219 }
1220
1221 return NGX_OK;
1222 }
1223
1224
1225 static void *
1226 ngx_imap_auth_http_create_conf(ngx_conf_t *cf)
1227 {
1228 ngx_imap_auth_http_conf_t *ahcf;
1229
1230 ahcf = ngx_pcalloc(cf->pool, sizeof(ngx_imap_auth_http_conf_t));
1231 if (ahcf == NULL) {
1232 return NGX_CONF_ERROR;
1233 }
1234
1235 ahcf->timeout = NGX_CONF_UNSET_MSEC;
1236
1237 return ahcf;
1238 }
1239
1240
1241 static char *
1242 ngx_imap_auth_http_merge_conf(ngx_conf_t *cf, void *parent, void *child)
1243 {
1244 ngx_imap_auth_http_conf_t *prev = parent;
1245 ngx_imap_auth_http_conf_t *conf = child;
1246
1247 u_char *p;
1248 size_t len;
1249 ngx_uint_t i;
1250 ngx_table_elt_t *header;
1251
1252 if (conf->peer == NULL) {
1253 conf->peer = prev->peer;
1254 conf->host_header = prev->host_header;
1255 conf->uri = prev->uri;
1256 }
1257
1258 ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
1259
1260 if (conf->headers == NULL) {
1261 conf->headers = prev->headers;
1262 conf->header = prev->header;
1263 }
1264
1265 if (conf->headers && conf->header.len == 0) {
1266 len = 0;
1267 header = conf->headers->elts;
1268 for (i = 0; i < conf->headers->nelts; i++) {
1269 len += header[i].key.len + 2 + header[i].value.len + 2;
1270 }
1271
1272 p = ngx_palloc(cf->pool, len);
1273 if (p == NULL) {
1274 return NGX_CONF_ERROR;
1275 }
1276
1277 conf->header.len = len;
1278 conf->header.data = p;
1279
1280 for (i = 0; i < conf->headers->nelts; i++) {
1281 p = ngx_cpymem(p, header[i].key.data, header[i].key.len);
1282 *p++ = ':'; *p++ = ' ';
1283 p = ngx_cpymem(p, header[i].value.data, header[i].value.len);
1284 *p++ = CR; *p++ = LF;
1285 }
1286 }
1287
1288 return NGX_CONF_OK;
1289 }
1290
1291
1292 static char *
1293 ngx_imap_auth_http(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1294 {
1295 ngx_imap_auth_http_conf_t *ahcf = conf;
1296
1297 ngx_str_t *value;
1298 ngx_url_t u;
1299
1300 value = cf->args->elts;
1301
1302 ngx_memzero(&u, sizeof(ngx_url_t));
1303
1304 u.url = value[1];
1305 u.default_port = 80;
1306 u.uri_part = 1;
1307 u.one_addr = 1;
1308
1309 if (ngx_parse_url(cf, &u) != NGX_OK) {
1310 if (u.err) {
1311 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1312 "%s in auth_http \"%V\"", u.err, &u.url);
1313 }
1314 }
1315
1316 ahcf->peer = u.addrs;
1317
1318 ahcf->host_header = u.host;
1319 ahcf->uri = u.uri;
1320
1321 if (ahcf->uri.len == 0) {
1322 ahcf->uri.len = sizeof("/") - 1;
1323 ahcf->uri.data = (u_char *) "/";
1324 }
1325
1326 return NGX_CONF_OK;
1327 }
1328
1329
1330 static char *
1331 ngx_imap_auth_http_header(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1332 {
1333 ngx_imap_auth_http_conf_t *ahcf = conf;
1334
1335 ngx_str_t *value;
1336 ngx_table_elt_t *header;
1337
1338 if (ahcf->headers == NULL) {
1339 ahcf->headers = ngx_array_create(cf->pool, 1, sizeof(ngx_table_elt_t));
1340 if (ahcf->headers == NULL) {
1341 return NGX_CONF_ERROR;
1342 }
1343 }
1344
1345 header = ngx_array_push(ahcf->headers);
1346 if (header == NULL) {
1347 return NGX_CONF_ERROR;
1348 }
1349
1350 value = cf->args->elts;
1351
1352 header->key = value[1];
1353 header->value = value[2];
1354
1355 return NGX_CONF_OK;
1356 }
+0
-603
src/imap/ngx_imap_core_module.c less more
0
1 /*
2 * Copyright (C) Igor Sysoev
3 */
4
5
6 #include <ngx_config.h>
7 #include <ngx_core.h>
8 #include <ngx_event.h>
9 #include <ngx_imap.h>
10
11
12 static void *ngx_imap_core_create_main_conf(ngx_conf_t *cf);
13 static void *ngx_imap_core_create_srv_conf(ngx_conf_t *cf);
14 static char *ngx_imap_core_merge_srv_conf(ngx_conf_t *cf, void *parent,
15 void *child);
16 static char *ngx_imap_core_server(ngx_conf_t *cf, ngx_command_t *cmd,
17 void *conf);
18 static char *ngx_imap_core_listen(ngx_conf_t *cf, ngx_command_t *cmd,
19 void *conf);
20 static char *ngx_imap_core_capability(ngx_conf_t *cf, ngx_command_t *cmd,
21 void *conf);
22
23
24 static ngx_conf_enum_t ngx_imap_core_procotol[] = {
25 { ngx_string("pop3"), NGX_IMAP_POP3_PROTOCOL },
26 { ngx_string("imap"), NGX_IMAP_IMAP_PROTOCOL },
27 { ngx_null_string, 0 }
28 };
29
30
31 static ngx_str_t ngx_pop3_default_capabilities[] = {
32 ngx_string("TOP"),
33 ngx_string("USER"),
34 ngx_string("UIDL"),
35 ngx_null_string
36 };
37
38
39 static ngx_str_t ngx_imap_default_capabilities[] = {
40 ngx_string("IMAP4"),
41 ngx_string("IMAP4rev1"),
42 ngx_string("UIDPLUS"),
43 ngx_null_string
44 };
45
46
47 static ngx_conf_bitmask_t ngx_imap_auth_methods[] = {
48 { ngx_string("plain"), NGX_IMAP_AUTH_PLAIN_ENABLED },
49 { ngx_string("apop"), NGX_IMAP_AUTH_APOP_ENABLED },
50 { ngx_string("cram-md5"), NGX_IMAP_AUTH_CRAM_MD5_ENABLED },
51 { ngx_null_string, 0 }
52 };
53
54
55 static ngx_str_t ngx_pop3_auth_plain_capability =
56 ngx_string("+OK methods supported:" CRLF
57 "LOGIN" CRLF
58 "PLAIN" CRLF
59 "." CRLF);
60
61
62 static ngx_str_t ngx_pop3_auth_cram_md5_capability =
63 ngx_string("+OK methods supported:" CRLF
64 "LOGIN" CRLF
65 "PLAIN" CRLF
66 "CRAM-MD5" CRLF
67 "." CRLF);
68
69
70
71 static ngx_command_t ngx_imap_core_commands[] = {
72
73 { ngx_string("server"),
74 NGX_IMAP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
75 ngx_imap_core_server,
76 0,
77 0,
78 NULL },
79
80 { ngx_string("listen"),
81 NGX_IMAP_SRV_CONF|NGX_CONF_TAKE12,
82 ngx_imap_core_listen,
83 0,
84 0,
85 NULL },
86
87 { ngx_string("protocol"),
88 NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1,
89 ngx_conf_set_enum_slot,
90 NGX_IMAP_SRV_CONF_OFFSET,
91 offsetof(ngx_imap_core_srv_conf_t, protocol),
92 &ngx_imap_core_procotol },
93
94 { ngx_string("imap_client_buffer"),
95 NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1,
96 ngx_conf_set_size_slot,
97 NGX_IMAP_SRV_CONF_OFFSET,
98 offsetof(ngx_imap_core_srv_conf_t, imap_client_buffer_size),
99 NULL },
100
101 { ngx_string("so_keepalive"),
102 NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_FLAG,
103 ngx_conf_set_flag_slot,
104 NGX_IMAP_SRV_CONF_OFFSET,
105 offsetof(ngx_imap_core_srv_conf_t, so_keepalive),
106 NULL },
107
108 { ngx_string("timeout"),
109 NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1,
110 ngx_conf_set_msec_slot,
111 NGX_IMAP_SRV_CONF_OFFSET,
112 offsetof(ngx_imap_core_srv_conf_t, timeout),
113 NULL },
114
115 { ngx_string("pop3_capabilities"),
116 NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_1MORE,
117 ngx_imap_core_capability,
118 NGX_IMAP_SRV_CONF_OFFSET,
119 offsetof(ngx_imap_core_srv_conf_t, pop3_capabilities),
120 NULL },
121
122 { ngx_string("imap_capabilities"),
123 NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_1MORE,
124 ngx_imap_core_capability,
125 NGX_IMAP_SRV_CONF_OFFSET,
126 offsetof(ngx_imap_core_srv_conf_t, imap_capabilities),
127 NULL },
128
129 { ngx_string("server_name"),
130 NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1,
131 ngx_conf_set_str_slot,
132 NGX_IMAP_SRV_CONF_OFFSET,
133 offsetof(ngx_imap_core_srv_conf_t, server_name),
134 NULL },
135
136 { ngx_string("auth"),
137 NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_1MORE,
138 ngx_conf_set_bitmask_slot,
139 NGX_IMAP_SRV_CONF_OFFSET,
140 offsetof(ngx_imap_core_srv_conf_t, auth_methods),
141 &ngx_imap_auth_methods },
142
143 ngx_null_command
144 };
145
146
147 static ngx_imap_module_t ngx_imap_core_module_ctx = {
148 ngx_imap_core_create_main_conf, /* create main configuration */
149 NULL, /* init main configuration */
150
151 ngx_imap_core_create_srv_conf, /* create server configuration */
152 ngx_imap_core_merge_srv_conf /* merge server configuration */
153 };
154
155
156 ngx_module_t ngx_imap_core_module = {
157 NGX_MODULE_V1,
158 &ngx_imap_core_module_ctx, /* module context */
159 ngx_imap_core_commands, /* module directives */
160 NGX_IMAP_MODULE, /* module type */
161 NULL, /* init master */
162 NULL, /* init module */
163 NULL, /* init process */
164 NULL, /* init thread */
165 NULL, /* exit thread */
166 NULL, /* exit process */
167 NULL, /* exit master */
168 NGX_MODULE_V1_PADDING
169 };
170
171
172 static void *
173 ngx_imap_core_create_main_conf(ngx_conf_t *cf)
174 {
175 ngx_imap_core_main_conf_t *cmcf;
176
177 cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_imap_core_main_conf_t));
178 if (cmcf == NULL) {
179 return NGX_CONF_ERROR;
180 }
181
182 if (ngx_array_init(&cmcf->servers, cf->pool, 4,
183 sizeof(ngx_imap_core_srv_conf_t *))
184 != NGX_OK)
185 {
186 return NGX_CONF_ERROR;
187 }
188
189 if (ngx_array_init(&cmcf->listen, cf->pool, 4, sizeof(ngx_imap_listen_t))
190 != NGX_OK)
191 {
192 return NGX_CONF_ERROR;
193 }
194
195 return cmcf;
196 }
197
198
199 static void *
200 ngx_imap_core_create_srv_conf(ngx_conf_t *cf)
201 {
202 ngx_imap_core_srv_conf_t *cscf;
203
204 cscf = ngx_pcalloc(cf->pool, sizeof(ngx_imap_core_srv_conf_t));
205 if (cscf == NULL) {
206 return NULL;
207 }
208
209 cscf->imap_client_buffer_size = NGX_CONF_UNSET_SIZE;
210 cscf->protocol = NGX_CONF_UNSET_UINT;
211 cscf->timeout = NGX_CONF_UNSET_MSEC;
212 cscf->so_keepalive = NGX_CONF_UNSET;
213
214 if (ngx_array_init(&cscf->pop3_capabilities, cf->pool, 4, sizeof(ngx_str_t))
215 != NGX_OK)
216 {
217 return NULL;
218 }
219
220 if (ngx_array_init(&cscf->imap_capabilities, cf->pool, 4, sizeof(ngx_str_t))
221 != NGX_OK)
222 {
223 return NULL;
224 }
225
226 return cscf;
227 }
228
229
230 static char *
231 ngx_imap_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
232 {
233 ngx_imap_core_srv_conf_t *prev = parent;
234 ngx_imap_core_srv_conf_t *conf = child;
235
236 u_char *p;
237 size_t size;
238 ngx_str_t *c, *d;
239 ngx_uint_t i;
240
241 ngx_conf_merge_size_value(conf->imap_client_buffer_size,
242 prev->imap_client_buffer_size,
243 (size_t) ngx_pagesize);
244 ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
245 ngx_conf_merge_uint_value(conf->protocol, prev->protocol,
246 NGX_IMAP_IMAP_PROTOCOL);
247 ngx_conf_merge_value(conf->so_keepalive, prev->so_keepalive, 0);
248
249
250 ngx_conf_merge_bitmask_value(conf->auth_methods, prev->auth_methods,
251 (NGX_CONF_BITMASK_SET|NGX_IMAP_AUTH_PLAIN_ENABLED));
252
253
254 ngx_conf_merge_str_value(conf->server_name, prev->server_name, "");
255
256 if (conf->server_name.len == 0) {
257 conf->server_name.data = ngx_palloc(cf->pool, NGX_MAXHOSTNAMELEN);
258 if (conf->server_name.data == NULL) {
259 return NGX_CONF_ERROR;
260 }
261
262 if (gethostname((char *) conf->server_name.data, NGX_MAXHOSTNAMELEN)
263 == -1)
264 {
265 ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
266 "gethostname() failed");
267 return NGX_CONF_ERROR;
268 }
269
270 conf->server_name.len = ngx_strlen(conf->server_name.data);
271 }
272
273
274 if (conf->pop3_capabilities.nelts == 0) {
275 conf->pop3_capabilities = prev->pop3_capabilities;
276 }
277
278 if (conf->pop3_capabilities.nelts == 0) {
279
280 for (d = ngx_pop3_default_capabilities; d->len; d++) {
281 c = ngx_array_push(&conf->pop3_capabilities);
282 if (c == NULL) {
283 return NGX_CONF_ERROR;
284 }
285
286 *c = *d;
287 }
288 }
289
290 size = sizeof("+OK Capability list follows" CRLF) - 1
291 + sizeof("." CRLF) - 1;
292
293 c = conf->pop3_capabilities.elts;
294 for (i = 0; i < conf->pop3_capabilities.nelts; i++) {
295 size += c[i].len + sizeof(CRLF) - 1;
296 }
297
298 if (conf->auth_methods & NGX_IMAP_AUTH_CRAM_MD5_ENABLED) {
299 size += sizeof("SASL LOGIN PLAIN CRAM-MD5" CRLF) - 1;
300
301 } else {
302 size += sizeof("SASL LOGIN PLAIN" CRLF) - 1;
303 }
304
305 p = ngx_palloc(cf->pool, size);
306 if (p == NULL) {
307 return NGX_CONF_ERROR;
308 }
309
310 conf->pop3_capability.len = size;
311 conf->pop3_capability.data = p;
312
313 p = ngx_cpymem(p, "+OK Capability list follows" CRLF,
314 sizeof("+OK Capability list follows" CRLF) - 1);
315
316 for (i = 0; i < conf->pop3_capabilities.nelts; i++) {
317 p = ngx_cpymem(p, c[i].data, c[i].len);
318 *p++ = CR; *p++ = LF;
319 }
320
321 if (conf->auth_methods & NGX_IMAP_AUTH_CRAM_MD5_ENABLED) {
322 p = ngx_cpymem(p, "SASL LOGIN PLAIN CRAM-MD5" CRLF,
323 sizeof("SASL LOGIN PLAIN CRAM-MD5" CRLF) - 1);
324
325 } else {
326 p = ngx_cpymem(p, "SASL LOGIN PLAIN" CRLF,
327 sizeof("SASL LOGIN PLAIN" CRLF) - 1);
328 }
329
330 *p++ = '.'; *p++ = CR; *p = LF;
331
332
333 size += sizeof("STLS" CRLF) - 1;
334
335 p = ngx_palloc(cf->pool, size);
336 if (p == NULL) {
337 return NGX_CONF_ERROR;
338 }
339
340 conf->pop3_starttls_capability.len = size;
341 conf->pop3_starttls_capability.data = p;
342
343 p = ngx_cpymem(p, conf->pop3_capability.data,
344 conf->pop3_capability.len - (sizeof("." CRLF) - 1));
345
346 p = ngx_cpymem(p, "STLS" CRLF, sizeof("STLS" CRLF) - 1);
347 *p++ = '.'; *p++ = CR; *p = LF;
348
349
350 if (conf->auth_methods & NGX_IMAP_AUTH_CRAM_MD5_ENABLED) {
351 conf->pop3_auth_capability = ngx_pop3_auth_cram_md5_capability;
352
353 } else {
354 conf->pop3_auth_capability = ngx_pop3_auth_plain_capability;
355 }
356
357
358 if (conf->imap_capabilities.nelts == 0) {
359 conf->imap_capabilities = prev->imap_capabilities;
360 }
361
362 if (conf->imap_capabilities.nelts == 0) {
363
364 for (d = ngx_imap_default_capabilities; d->len; d++) {
365 c = ngx_array_push(&conf->imap_capabilities);
366 if (c == NULL) {
367 return NGX_CONF_ERROR;
368 }
369
370 *c = *d;
371 }
372 }
373
374 size = sizeof("* CAPABILITY") - 1 + sizeof(CRLF) - 1;
375
376 c = conf->imap_capabilities.elts;
377 for (i = 0; i < conf->imap_capabilities.nelts; i++) {
378 size += 1 + c[i].len;
379 }
380
381 p = ngx_palloc(cf->pool, size);
382 if (p == NULL) {
383 return NGX_CONF_ERROR;
384 }
385
386 conf->imap_capability.len = size;
387 conf->imap_capability.data = p;
388
389 p = ngx_cpymem(p, "* CAPABILITY", sizeof("* CAPABILITY") - 1);
390
391 for (i = 0; i < conf->imap_capabilities.nelts; i++) {
392 *p++ = ' ';
393 p = ngx_cpymem(p, c[i].data, c[i].len);
394 }
395
396 *p++ = CR; *p = LF;
397
398
399 size += sizeof(" STARTTLS") - 1;
400
401 p = ngx_palloc(cf->pool, size);
402 if (p == NULL) {
403 return NGX_CONF_ERROR;
404 }
405
406 conf->imap_starttls_capability.len = size;
407 conf->imap_starttls_capability.data = p;
408
409 p = ngx_cpymem(p, conf->imap_capability.data,
410 conf->imap_capability.len - (sizeof(CRLF) - 1));
411 p = ngx_cpymem(p, " STARTTLS", sizeof(" STARTTLS") - 1);
412 *p++ = CR; *p = LF;
413
414
415 size += sizeof(" LOGINDISABLED") - 1;
416
417 p = ngx_palloc(cf->pool, size);
418 if (p == NULL) {
419 return NGX_CONF_ERROR;
420 }
421
422 conf->imap_starttls_only_capability.len = size;
423 conf->imap_starttls_only_capability.data = p;
424
425 p = ngx_cpymem(p, conf->imap_starttls_capability.data,
426 conf->imap_starttls_capability.len - (sizeof(CRLF) - 1));
427 p = ngx_cpymem(p, " LOGINDISABLED", sizeof(" LOGINDISABLED") - 1);
428 *p++ = CR; *p = LF;
429
430
431 return NGX_CONF_OK;
432 }
433
434
435 static char *
436 ngx_imap_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
437 {
438 char *rv;
439 void *mconf;
440 ngx_uint_t m;
441 ngx_conf_t pcf;
442 ngx_imap_module_t *module;
443 ngx_imap_conf_ctx_t *ctx, *imap_ctx;
444 ngx_imap_core_srv_conf_t *cscf, **cscfp;
445 ngx_imap_core_main_conf_t *cmcf;
446
447
448 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_imap_conf_ctx_t));
449 if (ctx == NULL) {
450 return NGX_CONF_ERROR;
451 }
452
453 imap_ctx = cf->ctx;
454 ctx->main_conf = imap_ctx->main_conf;
455
456 /* the server{}'s srv_conf */
457
458 ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_imap_max_module);
459 if (ctx->srv_conf == NULL) {
460 return NGX_CONF_ERROR;
461 }
462
463 for (m = 0; ngx_modules[m]; m++) {
464 if (ngx_modules[m]->type != NGX_IMAP_MODULE) {
465 continue;
466 }
467
468 module = ngx_modules[m]->ctx;
469
470 if (module->create_srv_conf) {
471 mconf = module->create_srv_conf(cf);
472 if (mconf == NULL) {
473 return NGX_CONF_ERROR;
474 }
475
476 ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf;
477 }
478 }
479
480 /* the server configuration context */
481
482 cscf = ctx->srv_conf[ngx_imap_core_module.ctx_index];
483 cscf->ctx = ctx;
484
485 cmcf = ctx->main_conf[ngx_imap_core_module.ctx_index];
486
487 cscfp = ngx_array_push(&cmcf->servers);
488 if (cscfp == NULL) {
489 return NGX_CONF_ERROR;
490 }
491
492 *cscfp = cscf;
493
494
495 /* parse inside server{} */
496
497 pcf = *cf;
498 cf->ctx = ctx;
499 cf->cmd_type = NGX_IMAP_SRV_CONF;
500
501 rv = ngx_conf_parse(cf, NULL);
502
503 *cf = pcf;
504
505 return rv;
506 }
507
508
509 /* AF_INET only */
510
511 static char *
512 ngx_imap_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
513 {
514 ngx_str_t *value;
515 ngx_url_t u;
516 ngx_uint_t i;
517 ngx_imap_listen_t *imls;
518 ngx_imap_core_main_conf_t *cmcf;
519
520 value = cf->args->elts;
521
522 ngx_memzero(&u, sizeof(ngx_url_t));
523
524 u.url = value[1];
525 u.listen = 1;
526
527 if (ngx_parse_url(cf, &u) != NGX_OK) {
528 if (u.err) {
529 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
530 "%s in \"%V\" of the \"listen\" directive",
531 u.err, &u.url);
532 }
533
534 return NGX_CONF_ERROR;
535 }
536
537 cmcf = ngx_imap_conf_get_module_main_conf(cf, ngx_imap_core_module);
538
539 imls = cmcf->listen.elts;
540
541 for (i = 0; i < cmcf->listen.nelts; i++) {
542
543 if (imls[i].addr != u.addr.in_addr || imls[i].port != u.port) {
544 continue;
545 }
546
547 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
548 "duplicate \"%V\" address and port pair", &u.url);
549 return NGX_CONF_ERROR;
550 }
551
552 imls = ngx_array_push(&cmcf->listen);
553 if (imls == NULL) {
554 return NGX_CONF_ERROR;
555 }
556
557 ngx_memzero(imls, sizeof(ngx_imap_listen_t));
558
559 imls->addr = u.addr.in_addr;
560 imls->port = u.port;
561 imls->family = AF_INET;
562 imls->ctx = cf->ctx;
563
564 if (cf->args->nelts == 2) {
565 return NGX_CONF_OK;
566 }
567
568 if (ngx_strcmp(value[2].data, "bind") == 0) {
569 imls->bind = 1;
570 return NGX_CONF_OK;
571 }
572
573 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
574 "the invalid \"%V\" parameter", &value[2]);
575 return NGX_CONF_ERROR;
576 }
577
578
579 static char *
580 ngx_imap_core_capability(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
581 {
582 char *p = conf;
583
584 ngx_str_t *c, *value;
585 ngx_uint_t i;
586 ngx_array_t *a;
587
588 a = (ngx_array_t *) (p + cmd->offset);
589
590 value = cf->args->elts;
591
592 for (i = 1; i < cf->args->nelts; i++) {
593 c = ngx_array_push(a);
594 if (c == NULL) {
595 return NGX_CONF_ERROR;
596 }
597
598 *c = value[i];
599 }
600
601 return NGX_CONF_OK;
602 }
+0
-1357
src/imap/ngx_imap_handler.c less more
0
1 /*
2 * Copyright (C) Igor Sysoev
3 */
4
5
6 #include <ngx_config.h>
7 #include <ngx_core.h>
8 #include <ngx_event.h>
9 #include <ngx_imap.h>
10
11
12 static void ngx_imap_init_session(ngx_connection_t *c);
13 static void ngx_imap_init_protocol(ngx_event_t *rev);
14 static ngx_int_t ngx_imap_decode_auth_plain(ngx_imap_session_t *s,
15 ngx_str_t *encoded);
16 static void ngx_imap_do_auth(ngx_imap_session_t *s);
17 static ngx_int_t ngx_imap_read_command(ngx_imap_session_t *s);
18 static u_char *ngx_imap_log_error(ngx_log_t *log, u_char *buf, size_t len);
19
20 #if (NGX_IMAP_SSL)
21 static void ngx_imap_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c);
22 static void ngx_imap_ssl_handshake_handler(ngx_connection_t *c);
23 #endif
24
25
26 static ngx_str_t greetings[] = {
27 ngx_string("+OK POP3 ready" CRLF),
28 ngx_string("* OK IMAP4 ready" CRLF)
29 };
30
31 static ngx_str_t internal_server_errors[] = {
32 ngx_string("-ERR internal server error" CRLF),
33 ngx_string("* BAD internal server error" CRLF),
34 };
35
36 static u_char pop3_ok[] = "+OK" CRLF;
37 static u_char pop3_next[] = "+ " CRLF;
38 static u_char pop3_username[] = "+ VXNlcm5hbWU6" CRLF;
39 static u_char pop3_password[] = "+ UGFzc3dvcmQ6" CRLF;
40 static u_char pop3_invalid_command[] = "-ERR invalid command" CRLF;
41
42 static u_char imap_star[] = "* ";
43 static u_char imap_ok[] = "OK completed" CRLF;
44 static u_char imap_next[] = "+ OK" CRLF;
45 static u_char imap_bye[] = "* BYE" CRLF;
46 static u_char imap_invalid_command[] = "BAD invalid command" CRLF;
47
48
49 void
50 ngx_imap_init_connection(ngx_connection_t *c)
51 {
52 in_addr_t in_addr;
53 socklen_t len;
54 ngx_uint_t i;
55 struct sockaddr_in sin;
56 ngx_imap_log_ctx_t *ctx;
57 ngx_imap_in_port_t *imip;
58 ngx_imap_in_addr_t *imia;
59 ngx_imap_session_t *s;
60 #if (NGX_IMAP_SSL)
61 ngx_imap_ssl_conf_t *sslcf;
62 #endif
63
64
65 /* find the server configuration for the address:port */
66
67 /* AF_INET only */
68
69 imip = c->listening->servers;
70 imia = imip->addrs;
71
72 i = 0;
73
74 if (imip->naddrs > 1) {
75
76 /*
77 * There are several addresses on this port and one of them
78 * is the "*:port" wildcard so getsockname() is needed to determine
79 * the server address.
80 *
81 * AcceptEx() already gave this address.
82 */
83
84 #if (NGX_WIN32)
85 if (c->local_sockaddr) {
86 in_addr =
87 ((struct sockaddr_in *) c->local_sockaddr)->sin_addr.s_addr;
88
89 } else
90 #endif
91 {
92 len = sizeof(struct sockaddr_in);
93 if (getsockname(c->fd, (struct sockaddr *) &sin, &len) == -1) {
94 ngx_connection_error(c, ngx_socket_errno,
95 "getsockname() failed");
96 ngx_imap_close_connection(c);
97 return;
98 }
99
100 in_addr = sin.sin_addr.s_addr;
101 }
102
103 /* the last address is "*" */
104
105 for ( /* void */ ; i < imip->naddrs - 1; i++) {
106 if (in_addr == imia[i].addr) {
107 break;
108 }
109 }
110 }
111
112
113 s = ngx_pcalloc(c->pool, sizeof(ngx_imap_session_t));
114 if (s == NULL) {
115 ngx_imap_close_connection(c);
116 return;
117 }
118
119 s->main_conf = imia[i].ctx->main_conf;
120 s->srv_conf = imia[i].ctx->srv_conf;
121
122 s->addr_text = &imia[i].addr_text;
123
124 c->data = s;
125 s->connection = c;
126
127 ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%ui client %V connected to %V",
128 c->number, &c->addr_text, s->addr_text);
129
130 ctx = ngx_palloc(c->pool, sizeof(ngx_imap_log_ctx_t));
131 if (ctx == NULL) {
132 ngx_imap_close_connection(c);
133 return;
134 }
135
136 ctx->client = &c->addr_text;
137 ctx->session = s;
138
139 c->log->connection = c->number;
140 c->log->handler = ngx_imap_log_error;
141 c->log->data = ctx;
142 c->log->action = "sending client greeting line";
143
144 c->log_error = NGX_ERROR_INFO;
145
146 #if (NGX_IMAP_SSL)
147
148 sslcf = ngx_imap_get_module_srv_conf(s, ngx_imap_ssl_module);
149
150 if (sslcf->enable) {
151 ngx_imap_ssl_init_connection(&sslcf->ssl, c);
152 return;
153 }
154
155 #endif
156
157 ngx_imap_init_session(c);
158 }
159
160
161 #if (NGX_IMAP_SSL)
162
163 static void
164 ngx_imap_starttls_handler(ngx_event_t *rev)
165 {
166 ngx_connection_t *c;
167 ngx_imap_session_t *s;
168 ngx_imap_ssl_conf_t *sslcf;
169
170 c = rev->data;
171 s = c->data;
172 s->starttls = 1;
173
174 c->log->action = "in starttls state";
175
176 sslcf = ngx_imap_get_module_srv_conf(s, ngx_imap_ssl_module);
177
178 ngx_imap_ssl_init_connection(&sslcf->ssl, c);
179 }
180
181
182 static void
183 ngx_imap_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c)
184 {
185 ngx_imap_session_t *s;
186 ngx_imap_core_srv_conf_t *cscf;
187
188 if (ngx_ssl_create_connection(ssl, c, 0) == NGX_ERROR) {
189 ngx_imap_close_connection(c);
190 return;
191 }
192
193 if (ngx_ssl_handshake(c) == NGX_AGAIN) {
194
195 s = c->data;
196
197 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
198
199 ngx_add_timer(c->read, cscf->timeout);
200
201 c->ssl->handler = ngx_imap_ssl_handshake_handler;
202
203 return;
204 }
205
206 ngx_imap_ssl_handshake_handler(c);
207 }
208
209
210 static void
211 ngx_imap_ssl_handshake_handler(ngx_connection_t *c)
212 {
213 ngx_imap_session_t *s;
214
215 if (c->ssl->handshaked) {
216
217 s = c->data;
218
219 if (s->starttls) {
220 c->read->handler = ngx_imap_init_protocol;
221 c->write->handler = ngx_imap_send;
222
223 ngx_imap_init_protocol(c->read);
224
225 return;
226 }
227
228 ngx_imap_init_session(c);
229 return;
230 }
231
232 ngx_imap_close_connection(c);
233 }
234
235 #endif
236
237
238 static void
239 ngx_imap_init_session(ngx_connection_t *c)
240 {
241 u_char *p;
242 ngx_imap_session_t *s;
243 ngx_imap_core_srv_conf_t *cscf;
244
245 c->read->handler = ngx_imap_init_protocol;
246 c->write->handler = ngx_imap_send;
247
248 s = c->data;
249
250 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
251
252 s->protocol = cscf->protocol;
253
254 s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_imap_max_module);
255 if (s->ctx == NULL) {
256 ngx_imap_session_internal_server_error(s);
257 return;
258 }
259
260 s->out = greetings[s->protocol];
261
262 if ((cscf->auth_methods & NGX_IMAP_AUTH_APOP_ENABLED)
263 && s->protocol == NGX_IMAP_POP3_PROTOCOL)
264 {
265 s->salt.data = ngx_palloc(c->pool,
266 sizeof(" <18446744073709551616.@>" CRLF) - 1
267 + NGX_TIME_T_LEN
268 + cscf->server_name.len);
269 if (s->salt.data == NULL) {
270 ngx_imap_session_internal_server_error(s);
271 return;
272 }
273
274 s->salt.len = ngx_sprintf(s->salt.data, "<%ul.%T@%V>" CRLF,
275 ngx_random(), ngx_time(), &cscf->server_name)
276 - s->salt.data;
277
278 s->out.data = ngx_palloc(c->pool, greetings[0].len + 1 + s->salt.len);
279 if (s->out.data == NULL) {
280 ngx_imap_session_internal_server_error(s);
281 return;
282 }
283
284 p = ngx_cpymem(s->out.data, greetings[0].data, greetings[0].len - 2);
285 *p++ = ' ';
286 p = ngx_cpymem(p, s->salt.data, s->salt.len);
287
288 s->out.len = p - s->out.data;
289 }
290
291 ngx_add_timer(c->read, cscf->timeout);
292
293 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
294 ngx_imap_close_connection(c);
295 }
296
297 ngx_imap_send(c->write);
298 }
299
300
301 void
302 ngx_imap_send(ngx_event_t *wev)
303 {
304 ngx_int_t n;
305 ngx_connection_t *c;
306 ngx_imap_session_t *s;
307 ngx_imap_core_srv_conf_t *cscf;
308
309 c = wev->data;
310 s = c->data;
311
312 if (wev->timedout) {
313 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
314 c->timedout = 1;
315 ngx_imap_close_connection(c);
316 return;
317 }
318
319 if (s->out.len == 0) {
320 if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
321 ngx_imap_close_connection(c);
322 }
323
324 return;
325 }
326
327 n = c->send(c, s->out.data, s->out.len);
328
329 if (n > 0) {
330 s->out.len -= n;
331
332 if (wev->timer_set) {
333 ngx_del_timer(wev);
334 }
335
336 if (s->quit) {
337 ngx_imap_close_connection(c);
338 return;
339 }
340
341 if (s->blocked) {
342 c->read->handler(c->read);
343 }
344
345 return;
346 }
347
348 if (n == NGX_ERROR) {
349 ngx_imap_close_connection(c);
350 return;
351 }
352
353 /* n == NGX_AGAIN */
354
355 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
356
357 ngx_add_timer(c->write, cscf->timeout);
358
359 if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
360 ngx_imap_close_connection(c);
361 return;
362 }
363 }
364
365
366 static void
367 ngx_imap_init_protocol(ngx_event_t *rev)
368 {
369 size_t size;
370 ngx_connection_t *c;
371 ngx_imap_session_t *s;
372 ngx_imap_core_srv_conf_t *cscf;
373
374 c = rev->data;
375
376 c->log->action = "in auth state";
377
378 if (rev->timedout) {
379 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
380 c->timedout = 1;
381 ngx_imap_close_connection(c);
382 return;
383 }
384
385 s = c->data;
386
387 if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
388 size = 128;
389 s->imap_state = ngx_pop3_start;
390 c->read->handler = ngx_pop3_auth_state;
391
392 } else {
393 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
394 size = cscf->imap_client_buffer_size;
395 s->imap_state = ngx_imap_start;
396 c->read->handler = ngx_imap_auth_state;
397 }
398
399 if (s->buffer == NULL) {
400 if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t))
401 == NGX_ERROR)
402 {
403 ngx_imap_session_internal_server_error(s);
404 return;
405 }
406
407 s->buffer = ngx_create_temp_buf(c->pool, size);
408 if (s->buffer == NULL) {
409 ngx_imap_session_internal_server_error(s);
410 return;
411 }
412 }
413
414 c->read->handler(rev);
415 }
416
417
418 void
419 ngx_imap_auth_state(ngx_event_t *rev)
420 {
421 u_char *text, *last, *p, *dst, *src, *end;
422 ssize_t text_len, last_len;
423 ngx_str_t *arg;
424 ngx_int_t rc;
425 ngx_uint_t tag, i;
426 ngx_connection_t *c;
427 ngx_imap_session_t *s;
428 ngx_imap_core_srv_conf_t *cscf;
429 #if (NGX_IMAP_SSL)
430 ngx_imap_ssl_conf_t *sslcf;
431 #endif
432
433 c = rev->data;
434 s = c->data;
435
436 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap auth state");
437
438 if (rev->timedout) {
439 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
440 c->timedout = 1;
441 ngx_imap_close_connection(c);
442 return;
443 }
444
445 if (s->out.len) {
446 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap send handler busy");
447 s->blocked = 1;
448 return;
449 }
450
451 s->blocked = 0;
452
453 rc = ngx_imap_read_command(s);
454
455 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap auth: %i", rc);
456
457 if (rc == NGX_AGAIN || rc == NGX_ERROR) {
458 return;
459 }
460
461 tag = 1;
462
463 text = NULL;
464 text_len = 0;
465
466 last = imap_ok;
467 last_len = sizeof(imap_ok) - 1;
468
469 if (rc == NGX_OK) {
470
471 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap auth command: %i",
472 s->command);
473
474 if (s->backslash) {
475
476 arg = s->args.elts;
477
478 for (i = 0; i < s->args.nelts; i++) {
479 dst = arg[i].data;
480 end = dst + arg[i].len;
481
482 for (src = dst; src < end; dst++) {
483 *dst = *src;
484 if (*src++ == '\\') {
485 *dst = *src++;
486 }
487 }
488
489 arg[i].len = dst - arg[i].data;
490 }
491
492 s->backslash = 0;
493 }
494
495 switch (s->command) {
496
497 case NGX_IMAP_LOGIN:
498
499 #if (NGX_IMAP_SSL)
500
501 if (c->ssl == NULL) {
502 sslcf = ngx_imap_get_module_srv_conf(s, ngx_imap_ssl_module);
503
504 if (sslcf->starttls == NGX_IMAP_STARTTLS_ONLY) {
505 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
506 break;
507 }
508 }
509 #endif
510
511 arg = s->args.elts;
512
513 if (s->args.nelts == 2 && arg[0].len) {
514
515 s->login.len = arg[0].len;
516 s->login.data = ngx_palloc(c->pool, s->login.len);
517 if (s->login.data == NULL) {
518 ngx_imap_session_internal_server_error(s);
519 return;
520 }
521
522 ngx_memcpy(s->login.data, arg[0].data, s->login.len);
523
524 s->passwd.len = arg[1].len;
525 s->passwd.data = ngx_palloc(c->pool, s->passwd.len);
526 if (s->passwd.data == NULL) {
527 ngx_imap_session_internal_server_error(s);
528 return;
529 }
530
531 ngx_memcpy(s->passwd.data, arg[1].data, s->passwd.len);
532
533 #if (NGX_DEBUG_IMAP_PASSWD)
534 ngx_log_debug2(NGX_LOG_DEBUG_IMAP, c->log, 0,
535 "imap login:\"%V\" passwd:\"%V\"",
536 &s->login, &s->passwd);
537 #else
538 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0,
539 "imap login:\"%V\"", &s->login);
540 #endif
541
542 ngx_imap_do_auth(s);
543 return;
544 }
545
546 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
547 break;
548
549 case NGX_IMAP_CAPABILITY:
550 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
551
552 #if (NGX_IMAP_SSL)
553
554 if (c->ssl == NULL) {
555 sslcf = ngx_imap_get_module_srv_conf(s, ngx_imap_ssl_module);
556
557 if (sslcf->starttls == NGX_IMAP_STARTTLS_ON) {
558 text_len = cscf->imap_starttls_capability.len;
559 text = cscf->imap_starttls_capability.data;
560 break;
561 }
562
563 if (sslcf->starttls == NGX_IMAP_STARTTLS_ONLY) {
564 text_len = cscf->imap_starttls_only_capability.len;
565 text = cscf->imap_starttls_only_capability.data;
566 break;
567 }
568 }
569 #endif
570
571 text_len = cscf->imap_capability.len;
572 text = cscf->imap_capability.data;
573 break;
574
575 case NGX_IMAP_LOGOUT:
576 s->quit = 1;
577 text = imap_bye;
578 text_len = sizeof(imap_bye) - 1;
579 break;
580
581 case NGX_IMAP_NOOP:
582 break;
583
584 #if (NGX_IMAP_SSL)
585
586 case NGX_IMAP_STARTTLS:
587 if (c->ssl == NULL) {
588 sslcf = ngx_imap_get_module_srv_conf(s, ngx_imap_ssl_module);
589 if (sslcf->starttls) {
590 c->read->handler = ngx_imap_starttls_handler;
591 break;
592 }
593 }
594
595 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
596 break;
597 #endif
598
599 default:
600 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
601 break;
602 }
603
604 } else if (rc == NGX_IMAP_NEXT) {
605 last = imap_next;
606 last_len = sizeof(imap_next) - 1;
607 tag = 0;
608 }
609
610 if (rc == NGX_IMAP_PARSE_INVALID_COMMAND) {
611 last = imap_invalid_command;
612 last_len = sizeof(imap_invalid_command) - 1;
613 }
614
615 if (tag) {
616 if (s->tag.len == 0) {
617 s->tag.len = sizeof(imap_star) - 1;
618 s->tag.data = (u_char *) imap_star;
619 }
620
621 if (s->tagged_line.len < s->tag.len + text_len + last_len) {
622 s->tagged_line.len = s->tag.len + text_len + last_len;
623 s->tagged_line.data = ngx_palloc(c->pool, s->tagged_line.len);
624 if (s->tagged_line.data == NULL) {
625 ngx_imap_close_connection(c);
626 return;
627 }
628 }
629
630 s->out.data = s->tagged_line.data;
631 s->out.len = s->tag.len + text_len + last_len;
632
633 p = s->out.data;
634
635 if (text) {
636 p = ngx_cpymem(p, text, text_len);
637 }
638 p = ngx_cpymem(p, s->tag.data, s->tag.len);
639 ngx_memcpy(p, last, last_len);
640
641
642 } else {
643 s->out.data = last;
644 s->out.len = last_len;
645 }
646
647 if (rc != NGX_IMAP_NEXT) {
648 s->args.nelts = 0;
649 s->buffer->pos = s->buffer->start;
650 s->buffer->last = s->buffer->start;
651 s->tag.len = 0;
652 }
653
654 ngx_imap_send(c->write);
655 }
656
657
658 void
659 ngx_pop3_auth_state(ngx_event_t *rev)
660 {
661 u_char *text, *p, *last;
662 ssize_t size;
663 ngx_int_t rc;
664 ngx_str_t *arg, salt;
665 ngx_connection_t *c;
666 ngx_imap_session_t *s;
667 ngx_imap_core_srv_conf_t *cscf;
668 #if (NGX_IMAP_SSL)
669 ngx_imap_ssl_conf_t *sslcf;
670 #endif
671
672 c = rev->data;
673 s = c->data;
674
675 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "pop3 auth state");
676
677 if (rev->timedout) {
678 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
679 c->timedout = 1;
680 ngx_imap_close_connection(c);
681 return;
682 }
683
684 if (s->out.len) {
685 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap send handler busy");
686 s->blocked = 1;
687 return;
688 }
689
690 s->blocked = 0;
691
692 rc = ngx_imap_read_command(s);
693
694 if (rc == NGX_AGAIN || rc == NGX_ERROR) {
695 return;
696 }
697
698 text = pop3_ok;
699 size = sizeof(pop3_ok) - 1;
700
701 if (rc == NGX_OK) {
702 switch (s->imap_state) {
703
704 case ngx_pop3_start:
705
706 switch (s->command) {
707
708 case NGX_POP3_USER:
709 if (s->args.nelts == 1) {
710 s->imap_state = ngx_pop3_user;
711
712 arg = s->args.elts;
713 s->login.len = arg[0].len;
714 s->login.data = ngx_palloc(c->pool, s->login.len);
715 if (s->login.data == NULL) {
716 ngx_imap_session_internal_server_error(s);
717 return;
718 }
719
720 ngx_memcpy(s->login.data, arg[0].data, s->login.len);
721
722 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0,
723 "pop3 login: \"%V\"", &s->login);
724
725 break;
726 }
727
728 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
729 break;
730
731 case NGX_POP3_CAPA:
732 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
733
734 #if (NGX_IMAP_SSL)
735
736 if (c->ssl == NULL) {
737 sslcf = ngx_imap_get_module_srv_conf(s,
738 ngx_imap_ssl_module);
739 if (sslcf->starttls) {
740 size = cscf->pop3_starttls_capability.len;
741 text = cscf->pop3_starttls_capability.data;
742 break;
743 }
744 }
745 #endif
746
747 size = cscf->pop3_capability.len;
748 text = cscf->pop3_capability.data;
749 break;
750
751 case NGX_POP3_APOP:
752 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
753
754 if ((cscf->auth_methods & NGX_IMAP_AUTH_APOP_ENABLED)
755 && s->args.nelts == 2)
756 {
757 arg = s->args.elts;
758
759 s->login.len = arg[0].len;
760 s->login.data = ngx_palloc(c->pool, s->login.len);
761 if (s->login.data == NULL) {
762 ngx_imap_session_internal_server_error(s);
763 return;
764 }
765
766 ngx_memcpy(s->login.data, arg[0].data, s->login.len);
767
768 s->passwd.len = arg[1].len;
769 s->passwd.data = ngx_palloc(c->pool, s->passwd.len);
770 if (s->passwd.data == NULL) {
771 ngx_imap_session_internal_server_error(s);
772 return;
773 }
774
775 ngx_memcpy(s->passwd.data, arg[1].data, s->passwd.len);
776
777 ngx_log_debug2(NGX_LOG_DEBUG_IMAP, c->log, 0,
778 "pop3 apop: \"%V\" \"%V\"",
779 &s->login, &s->passwd);
780
781 s->auth_method = NGX_IMAP_AUTH_APOP;
782
783 ngx_imap_do_auth(s);
784 return;
785 }
786
787 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
788 break;
789
790 case NGX_POP3_AUTH:
791 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
792
793 if (s->args.nelts == 0) {
794 size = cscf->pop3_auth_capability.len;
795 text = cscf->pop3_auth_capability.data;
796 s->state = 0;
797 break;
798 }
799
800 arg = s->args.elts;
801
802 if (arg[0].len == 5) {
803
804 if (ngx_strncasecmp(arg[0].data, (u_char *) "LOGIN", 5)
805 == 0)
806 {
807
808 if (s->args.nelts != 1) {
809 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
810 break;
811 }
812
813 s->imap_state = ngx_pop3_auth_login_username;
814
815 size = sizeof(pop3_username) - 1;
816 text = pop3_username;
817
818 break;
819
820 } else if (ngx_strncasecmp(arg[0].data, (u_char *) "PLAIN",
821 5)
822 == 0)
823 {
824
825 if (s->args.nelts == 1) {
826 s->imap_state = ngx_pop3_auth_plain;
827
828 size = sizeof(pop3_next) - 1;
829 text = pop3_next;
830
831 break;
832 }
833
834 if (s->args.nelts == 2) {
835
836 /*
837 * workaround for Eudora for Mac: it sends
838 * AUTH PLAIN [base64 encoded]
839 */
840
841 rc = ngx_imap_decode_auth_plain(s, &arg[1]);
842
843 if (rc == NGX_OK) {
844 ngx_imap_do_auth(s);
845 return;
846 }
847
848 if (rc == NGX_ERROR) {
849 ngx_imap_session_internal_server_error(s);
850 return;
851 }
852
853 /* rc == NGX_IMAP_PARSE_INVALID_COMMAND */
854
855 break;
856 }
857
858 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
859 break;
860 }
861
862 } else if (arg[0].len == 8
863 && ngx_strncasecmp(arg[0].data,
864 (u_char *) "CRAM-MD5", 8)
865 == 0)
866 {
867 s->imap_state = ngx_pop3_auth_cram_md5;
868
869 text = ngx_palloc(c->pool,
870 sizeof("+ " CRLF) - 1
871 + ngx_base64_encoded_length(s->salt.len));
872 if (text == NULL) {
873 ngx_imap_session_internal_server_error(s);
874 return;
875 }
876
877 text[0] = '+'; text[1]= ' ';
878 salt.data = &text[2];
879 s->salt.len -= 2;
880
881 ngx_encode_base64(&salt, &s->salt);
882
883 s->salt.len += 2;
884 size = 2 + salt.len;
885 text[size++] = CR; text[size++] = LF;
886
887 break;
888 }
889
890 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
891 break;
892