Mercurial > hg > nginx-quic
annotate src/mail/ngx_mail_ssl_module.c @ 3755:76e3a93821b1
fix race condition if during reconfiguration two cache managers try
to delete old inactive entries: one of them removes a entry just locked by
other manager from the queue and the rbtree as long inactive entry,
causes the latter manager to segfault leaving cache mutex locked,
the bug has been introduced in r3727
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Thu, 02 Sep 2010 14:31:47 +0000 |
parents | dd1570b6f237 |
children | 1e90599af73b |
rev | line source |
---|---|
539 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
1136 | 9 #include <ngx_mail.h> |
539 | 10 |
11 | |
3196
b7e68ee09e0c
use only strong ciphers by default
Igor Sysoev <igor@sysoev.ru>
parents:
3190
diff
changeset
|
12 #define NGX_DEFAULT_CIPHERS "HIGH:!ADH:!MD5" |
539 | 13 |
14 | |
1136 | 15 static void *ngx_mail_ssl_create_conf(ngx_conf_t *cf); |
16 static char *ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child); | |
2224 | 17 |
18 static char *ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, | |
19 void *conf); | |
20 static char *ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, | |
21 void *conf); | |
1136 | 22 static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, |
976 | 23 void *conf); |
539 | 24 |
25 | |
583 | 26 static ngx_conf_enum_t ngx_http_starttls_state[] = { |
1136 | 27 { ngx_string("off"), NGX_MAIL_STARTTLS_OFF }, |
28 { ngx_string("on"), NGX_MAIL_STARTTLS_ON }, | |
29 { ngx_string("only"), NGX_MAIL_STARTTLS_ONLY }, | |
583 | 30 { ngx_null_string, 0 } |
31 }; | |
32 | |
33 | |
34 | |
1136 | 35 static ngx_conf_bitmask_t ngx_mail_ssl_protocols[] = { |
547 | 36 { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, |
37 { ngx_string("SSLv3"), NGX_SSL_SSLv3 }, | |
38 { ngx_string("TLSv1"), NGX_SSL_TLSv1 }, | |
39 { ngx_null_string, 0 } | |
40 }; | |
41 | |
42 | |
1136 | 43 static ngx_command_t ngx_mail_ssl_commands[] = { |
539 | 44 |
45 { ngx_string("ssl"), | |
1136 | 46 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, |
2224 | 47 ngx_mail_ssl_enable, |
1136 | 48 NGX_MAIL_SRV_CONF_OFFSET, |
49 offsetof(ngx_mail_ssl_conf_t, enable), | |
539 | 50 NULL }, |
51 | |
583 | 52 { ngx_string("starttls"), |
1136 | 53 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, |
2224 | 54 ngx_mail_ssl_starttls, |
1136 | 55 NGX_MAIL_SRV_CONF_OFFSET, |
56 offsetof(ngx_mail_ssl_conf_t, starttls), | |
583 | 57 ngx_http_starttls_state }, |
58 | |
539 | 59 { ngx_string("ssl_certificate"), |
1136 | 60 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, |
539 | 61 ngx_conf_set_str_slot, |
1136 | 62 NGX_MAIL_SRV_CONF_OFFSET, |
63 offsetof(ngx_mail_ssl_conf_t, certificate), | |
539 | 64 NULL }, |
65 | |
66 { ngx_string("ssl_certificate_key"), | |
1136 | 67 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, |
539 | 68 ngx_conf_set_str_slot, |
1136 | 69 NGX_MAIL_SRV_CONF_OFFSET, |
70 offsetof(ngx_mail_ssl_conf_t, certificate_key), | |
539 | 71 NULL }, |
72 | |
2044 | 73 { ngx_string("ssl_dhparam"), |
74 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, | |
75 ngx_conf_set_str_slot, | |
76 NGX_MAIL_SRV_CONF_OFFSET, | |
77 offsetof(ngx_mail_ssl_conf_t, dhparam), | |
78 NULL }, | |
79 | |
547 | 80 { ngx_string("ssl_protocols"), |
1136 | 81 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE, |
547 | 82 ngx_conf_set_bitmask_slot, |
1136 | 83 NGX_MAIL_SRV_CONF_OFFSET, |
84 offsetof(ngx_mail_ssl_conf_t, protocols), | |
85 &ngx_mail_ssl_protocols }, | |
547 | 86 |
539 | 87 { ngx_string("ssl_ciphers"), |
1136 | 88 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, |
539 | 89 ngx_conf_set_str_slot, |
1136 | 90 NGX_MAIL_SRV_CONF_OFFSET, |
91 offsetof(ngx_mail_ssl_conf_t, ciphers), | |
539 | 92 NULL }, |
93 | |
547 | 94 { ngx_string("ssl_prefer_server_ciphers"), |
1136 | 95 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, |
547 | 96 ngx_conf_set_flag_slot, |
1136 | 97 NGX_MAIL_SRV_CONF_OFFSET, |
98 offsetof(ngx_mail_ssl_conf_t, prefer_server_ciphers), | |
547 | 99 NULL }, |
563 | 100 |
976 | 101 { ngx_string("ssl_session_cache"), |
1136 | 102 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE12, |
103 ngx_mail_ssl_session_cache, | |
104 NGX_MAIL_SRV_CONF_OFFSET, | |
976 | 105 0, |
106 NULL }, | |
107 | |
573 | 108 { ngx_string("ssl_session_timeout"), |
1136 | 109 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, |
573 | 110 ngx_conf_set_sec_slot, |
1136 | 111 NGX_MAIL_SRV_CONF_OFFSET, |
112 offsetof(ngx_mail_ssl_conf_t, session_timeout), | |
573 | 113 NULL }, |
547 | 114 |
539 | 115 ngx_null_command |
116 }; | |
117 | |
118 | |
1136 | 119 static ngx_mail_module_t ngx_mail_ssl_module_ctx = { |
1487
f69493e8faab
ngx_mail_pop3_module, ngx_mail_imap_module, and ngx_mail_smtp_module
Igor Sysoev <igor@sysoev.ru>
parents:
1136
diff
changeset
|
120 NULL, /* protocol */ |
f69493e8faab
ngx_mail_pop3_module, ngx_mail_imap_module, and ngx_mail_smtp_module
Igor Sysoev <igor@sysoev.ru>
parents:
1136
diff
changeset
|
121 |
539 | 122 NULL, /* create main configuration */ |
123 NULL, /* init main configuration */ | |
124 | |
1136 | 125 ngx_mail_ssl_create_conf, /* create server configuration */ |
126 ngx_mail_ssl_merge_conf /* merge server configuration */ | |
539 | 127 }; |
128 | |
129 | |
1136 | 130 ngx_module_t ngx_mail_ssl_module = { |
539 | 131 NGX_MODULE_V1, |
1136 | 132 &ngx_mail_ssl_module_ctx, /* module context */ |
133 ngx_mail_ssl_commands, /* module directives */ | |
134 NGX_MAIL_MODULE, /* module type */ | |
541 | 135 NULL, /* init master */ |
539 | 136 NULL, /* init module */ |
541 | 137 NULL, /* init process */ |
138 NULL, /* init thread */ | |
139 NULL, /* exit thread */ | |
140 NULL, /* exit process */ | |
141 NULL, /* exit master */ | |
142 NGX_MODULE_V1_PADDING | |
539 | 143 }; |
144 | |
145 | |
1136 | 146 static ngx_str_t ngx_mail_ssl_sess_id_ctx = ngx_string("MAIL"); |
543 | 147 |
148 | |
539 | 149 static void * |
1136 | 150 ngx_mail_ssl_create_conf(ngx_conf_t *cf) |
577 | 151 { |
1136 | 152 ngx_mail_ssl_conf_t *scf; |
577 | 153 |
1136 | 154 scf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_ssl_conf_t)); |
539 | 155 if (scf == NULL) { |
2912
c7d57b539248
return NULL instead of NGX_CONF_ERROR on a create conf failure
Igor Sysoev <igor@sysoev.ru>
parents:
2759
diff
changeset
|
156 return NULL; |
539 | 157 } |
158 | |
159 /* | |
577 | 160 * set by ngx_pcalloc(): |
539 | 161 * |
547 | 162 * scf->protocols = 0; |
2044 | 163 * scf->certificate = { 0, NULL }; |
164 * scf->certificate_key = { 0, NULL }; | |
165 * scf->dhparam = { 0, NULL }; | |
3516
dd1570b6f237
ngx_str_set() and ngx_str_null()
Igor Sysoev <igor@sysoev.ru>
parents:
3196
diff
changeset
|
166 * scf->ciphers = { 0, NULL }; |
976 | 167 * scf->shm_zone = NULL; |
539 | 168 */ |
169 | |
170 scf->enable = NGX_CONF_UNSET; | |
2759 | 171 scf->starttls = NGX_CONF_UNSET_UINT; |
976 | 172 scf->prefer_server_ciphers = NGX_CONF_UNSET; |
173 scf->builtin_session_cache = NGX_CONF_UNSET; | |
573 | 174 scf->session_timeout = NGX_CONF_UNSET; |
539 | 175 |
176 return scf; | |
177 } | |
178 | |
179 | |
180 static char * | |
1136 | 181 ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) |
539 | 182 { |
1136 | 183 ngx_mail_ssl_conf_t *prev = parent; |
184 ngx_mail_ssl_conf_t *conf = child; | |
539 | 185 |
2224 | 186 char *mode; |
563 | 187 ngx_pool_cleanup_t *cln; |
188 | |
539 | 189 ngx_conf_merge_value(conf->enable, prev->enable, 0); |
2224 | 190 ngx_conf_merge_uint_value(conf->starttls, prev->starttls, |
191 NGX_MAIL_STARTTLS_OFF); | |
539 | 192 |
573 | 193 ngx_conf_merge_value(conf->session_timeout, |
194 prev->session_timeout, 300); | |
195 | |
547 | 196 ngx_conf_merge_value(conf->prefer_server_ciphers, |
197 prev->prefer_server_ciphers, 0); | |
198 | |
199 ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, | |
3190
dd2ae3872634
disable SSLv2 and low ciphers by default
Igor Sysoev <igor@sysoev.ru>
parents:
2996
diff
changeset
|
200 (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3|NGX_SSL_TLSv1)); |
547 | 201 |
2224 | 202 ngx_conf_merge_str_value(conf->certificate, prev->certificate, ""); |
203 ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, ""); | |
539 | 204 |
2044 | 205 ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, ""); |
206 | |
2124 | 207 ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); |
539 | 208 |
209 | |
547 | 210 conf->ssl.log = cf->log; |
539 | 211 |
2224 | 212 if (conf->enable) { |
213 mode = "ssl"; | |
214 | |
215 } else if (conf->starttls != NGX_MAIL_STARTTLS_OFF) { | |
216 mode = "starttls"; | |
217 | |
218 } else { | |
219 mode = ""; | |
220 } | |
221 | |
222 if (*mode) { | |
223 | |
224 if (conf->certificate.len == 0) { | |
225 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | |
226 "no \"ssl_certificate\" is defined for " | |
227 "the \"%s\" directive in %s:%ui", | |
228 mode, conf->file, conf->line); | |
229 return NGX_CONF_ERROR; | |
230 } | |
231 | |
232 if (conf->certificate_key.len == 0) { | |
233 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | |
234 "no \"ssl_certificate_key\" is defined for " | |
235 "the \"%s\" directive in %s:%ui", | |
236 mode, conf->file, conf->line); | |
237 return NGX_CONF_ERROR; | |
238 } | |
239 | |
240 } else { | |
241 | |
242 if (conf->certificate.len == 0) { | |
243 return NGX_CONF_OK; | |
244 } | |
245 | |
246 if (conf->certificate_key.len == 0) { | |
247 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | |
248 "no \"ssl_certificate_key\" is defined " | |
249 "for certificate \"%V\"", | |
250 &conf->certificate); | |
251 return NGX_CONF_ERROR; | |
252 } | |
253 } | |
254 | |
969 | 255 if (ngx_ssl_create(&conf->ssl, conf->protocols, NULL) != NGX_OK) { |
539 | 256 return NGX_CONF_ERROR; |
257 } | |
258 | |
563 | 259 cln = ngx_pool_cleanup_add(cf->pool, 0); |
260 if (cln == NULL) { | |
539 | 261 return NGX_CONF_ERROR; |
262 } | |
263 | |
563 | 264 cln->handler = ngx_ssl_cleanup_ctx; |
265 cln->data = &conf->ssl; | |
266 | |
267 if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate, | |
268 &conf->certificate_key) | |
269 != NGX_OK) | |
547 | 270 { |
271 return NGX_CONF_ERROR; | |
272 } | |
539 | 273 |
274 if (conf->ciphers.len) { | |
547 | 275 if (SSL_CTX_set_cipher_list(conf->ssl.ctx, |
563 | 276 (const char *) conf->ciphers.data) |
277 == 0) | |
539 | 278 { |
279 ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, | |
280 "SSL_CTX_set_cipher_list(\"%V\") failed", | |
281 &conf->ciphers); | |
282 } | |
283 } | |
284 | |
563 | 285 if (conf->prefer_server_ciphers) { |
286 SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); | |
287 } | |
288 | |
547 | 289 if (ngx_ssl_generate_rsa512_key(&conf->ssl) != NGX_OK) { |
539 | 290 return NGX_CONF_ERROR; |
291 } | |
292 | |
2044 | 293 if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) { |
294 return NGX_CONF_ERROR; | |
295 } | |
296 | |
976 | 297 ngx_conf_merge_value(conf->builtin_session_cache, |
2032 | 298 prev->builtin_session_cache, NGX_SSL_NONE_SCACHE); |
976 | 299 |
300 if (conf->shm_zone == NULL) { | |
301 conf->shm_zone = prev->shm_zone; | |
302 } | |
539 | 303 |
1136 | 304 if (ngx_ssl_session_cache(&conf->ssl, &ngx_mail_ssl_sess_id_ctx, |
976 | 305 conf->builtin_session_cache, |
306 conf->shm_zone, conf->session_timeout) | |
307 != NGX_OK) | |
308 { | |
309 return NGX_CONF_ERROR; | |
310 } | |
573 | 311 |
539 | 312 return NGX_CONF_OK; |
313 } | |
563 | 314 |
577 | 315 |
976 | 316 static char * |
2224 | 317 ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
318 { | |
319 ngx_mail_ssl_conf_t *scf = conf; | |
320 | |
321 char *rv; | |
322 | |
323 rv = ngx_conf_set_flag_slot(cf, cmd, conf); | |
324 | |
325 if (rv != NGX_CONF_OK) { | |
326 return rv; | |
327 } | |
328 | |
329 if (scf->enable && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) { | |
330 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, | |
331 "\"starttls\" directive conflicts with \"ssl on\""); | |
332 return NGX_CONF_ERROR; | |
333 } | |
334 | |
335 scf->file = cf->conf_file->file.name.data; | |
336 scf->line = cf->conf_file->line; | |
337 | |
338 return NGX_CONF_OK; | |
339 } | |
340 | |
341 | |
342 static char * | |
343 ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
344 { | |
345 ngx_mail_ssl_conf_t *scf = conf; | |
346 | |
347 char *rv; | |
348 | |
349 rv = ngx_conf_set_enum_slot(cf, cmd, conf); | |
350 | |
351 if (rv != NGX_CONF_OK) { | |
352 return rv; | |
353 } | |
354 | |
355 if (scf->enable == 1 && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) { | |
356 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, | |
357 "\"ssl\" directive conflicts with \"starttls\""); | |
358 return NGX_CONF_ERROR; | |
359 } | |
360 | |
361 scf->file = cf->conf_file->file.name.data; | |
362 scf->line = cf->conf_file->line; | |
363 | |
364 return NGX_CONF_OK; | |
365 } | |
366 | |
367 | |
368 static char * | |
1136 | 369 ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
976 | 370 { |
1136 | 371 ngx_mail_ssl_conf_t *scf = conf; |
976 | 372 |
373 size_t len; | |
374 ngx_str_t *value, name, size; | |
375 ngx_int_t n; | |
376 ngx_uint_t i, j; | |
377 | |
378 value = cf->args->elts; | |
379 | |
380 for (i = 1; i < cf->args->nelts; i++) { | |
381 | |
1778 | 382 if (ngx_strcmp(value[i].data, "off") == 0) { |
383 scf->builtin_session_cache = NGX_SSL_NO_SCACHE; | |
384 continue; | |
385 } | |
386 | |
2032 | 387 if (ngx_strcmp(value[i].data, "none") == 0) { |
388 scf->builtin_session_cache = NGX_SSL_NONE_SCACHE; | |
389 continue; | |
390 } | |
391 | |
976 | 392 if (ngx_strcmp(value[i].data, "builtin") == 0) { |
393 scf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE; | |
394 continue; | |
395 } | |
396 | |
397 if (value[i].len > sizeof("builtin:") - 1 | |
398 && ngx_strncmp(value[i].data, "builtin:", sizeof("builtin:") - 1) | |
399 == 0) | |
400 { | |
401 n = ngx_atoi(value[i].data + sizeof("builtin:") - 1, | |
402 value[i].len - (sizeof("builtin:") - 1)); | |
403 | |
404 if (n == NGX_ERROR) { | |
405 goto invalid; | |
406 } | |
407 | |
408 scf->builtin_session_cache = n; | |
409 | |
410 continue; | |
411 } | |
412 | |
413 if (value[i].len > sizeof("shared:") - 1 | |
414 && ngx_strncmp(value[i].data, "shared:", sizeof("shared:") - 1) | |
415 == 0) | |
416 { | |
417 len = 0; | |
418 | |
419 for (j = sizeof("shared:") - 1; j < value[i].len; j++) { | |
420 if (value[i].data[j] == ':') { | |
421 break; | |
422 } | |
423 | |
424 len++; | |
425 } | |
426 | |
427 if (len == 0) { | |
428 goto invalid; | |
429 } | |
430 | |
431 name.len = len; | |
432 name.data = value[i].data + sizeof("shared:") - 1; | |
433 | |
434 size.len = value[i].len - j - 1; | |
435 size.data = name.data + len + 1; | |
436 | |
437 n = ngx_parse_size(&size); | |
438 | |
439 if (n == NGX_ERROR) { | |
440 goto invalid; | |
441 } | |
442 | |
443 if (n < (ngx_int_t) (8 * ngx_pagesize)) { | |
444 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
445 "session cache \"%V\" is too small", | |
446 &value[i]); | |
447 | |
448 return NGX_CONF_ERROR; | |
449 } | |
450 | |
451 scf->shm_zone = ngx_shared_memory_add(cf, &name, n, | |
1136 | 452 &ngx_mail_ssl_module); |
976 | 453 if (scf->shm_zone == NULL) { |
454 return NGX_CONF_ERROR; | |
455 } | |
456 | |
457 continue; | |
458 } | |
459 | |
460 goto invalid; | |
461 } | |
462 | |
463 if (scf->shm_zone && scf->builtin_session_cache == NGX_CONF_UNSET) { | |
464 scf->builtin_session_cache = NGX_SSL_NO_BUILTIN_SCACHE; | |
465 } | |
466 | |
467 return NGX_CONF_OK; | |
468 | |
469 invalid: | |
470 | |
471 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
472 "invalid session cache \"%V\"", &value[i]); | |
473 | |
474 return NGX_CONF_ERROR; | |
475 } |