Mercurial > hg > nginx
comparison src/mail/ngx_mail_ssl_module.c @ 1136:68f30ab68bb7
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
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Mon, 19 Mar 2007 13:36:56 +0000 |
parents | src/imap/ngx_imap_ssl_module.c@b1431c191cf5 |
children | f69493e8faab |
comparison
equal
deleted
inserted
replaced
1135:03f1133f24e8 | 1136:68f30ab68bb7 |
---|---|
1 | |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_mail.h> | |
10 | |
11 | |
12 #define NGX_DEFLAUT_CERTIFICATE "cert.pem" | |
13 #define NGX_DEFLAUT_CERTIFICATE_KEY "cert.pem" | |
14 #define NGX_DEFLAUT_CIPHERS "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP" | |
15 | |
16 | |
17 static void *ngx_mail_ssl_create_conf(ngx_conf_t *cf); | |
18 static char *ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child); | |
19 static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, | |
20 void *conf); | |
21 | |
22 #if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE) | |
23 | |
24 static char *ngx_mail_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd, | |
25 void *conf); | |
26 | |
27 static char ngx_mail_ssl_openssl097[] = "OpenSSL 0.9.7 and higher"; | |
28 | |
29 #endif | |
30 | |
31 | |
32 static ngx_conf_enum_t ngx_http_starttls_state[] = { | |
33 { ngx_string("off"), NGX_MAIL_STARTTLS_OFF }, | |
34 { ngx_string("on"), NGX_MAIL_STARTTLS_ON }, | |
35 { ngx_string("only"), NGX_MAIL_STARTTLS_ONLY }, | |
36 { ngx_null_string, 0 } | |
37 }; | |
38 | |
39 | |
40 | |
41 static ngx_conf_bitmask_t ngx_mail_ssl_protocols[] = { | |
42 { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, | |
43 { ngx_string("SSLv3"), NGX_SSL_SSLv3 }, | |
44 { ngx_string("TLSv1"), NGX_SSL_TLSv1 }, | |
45 { ngx_null_string, 0 } | |
46 }; | |
47 | |
48 | |
49 static ngx_command_t ngx_mail_ssl_commands[] = { | |
50 | |
51 { ngx_string("ssl"), | |
52 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, | |
53 ngx_conf_set_flag_slot, | |
54 NGX_MAIL_SRV_CONF_OFFSET, | |
55 offsetof(ngx_mail_ssl_conf_t, enable), | |
56 NULL }, | |
57 | |
58 { ngx_string("starttls"), | |
59 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, | |
60 ngx_conf_set_enum_slot, | |
61 NGX_MAIL_SRV_CONF_OFFSET, | |
62 offsetof(ngx_mail_ssl_conf_t, starttls), | |
63 ngx_http_starttls_state }, | |
64 | |
65 { ngx_string("ssl_certificate"), | |
66 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, | |
67 ngx_conf_set_str_slot, | |
68 NGX_MAIL_SRV_CONF_OFFSET, | |
69 offsetof(ngx_mail_ssl_conf_t, certificate), | |
70 NULL }, | |
71 | |
72 { ngx_string("ssl_certificate_key"), | |
73 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, | |
74 ngx_conf_set_str_slot, | |
75 NGX_MAIL_SRV_CONF_OFFSET, | |
76 offsetof(ngx_mail_ssl_conf_t, certificate_key), | |
77 NULL }, | |
78 | |
79 { ngx_string("ssl_protocols"), | |
80 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE, | |
81 ngx_conf_set_bitmask_slot, | |
82 NGX_MAIL_SRV_CONF_OFFSET, | |
83 offsetof(ngx_mail_ssl_conf_t, protocols), | |
84 &ngx_mail_ssl_protocols }, | |
85 | |
86 { ngx_string("ssl_ciphers"), | |
87 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, | |
88 ngx_conf_set_str_slot, | |
89 NGX_MAIL_SRV_CONF_OFFSET, | |
90 offsetof(ngx_mail_ssl_conf_t, ciphers), | |
91 NULL }, | |
92 | |
93 { ngx_string("ssl_prefer_server_ciphers"), | |
94 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, | |
95 #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE | |
96 ngx_conf_set_flag_slot, | |
97 NGX_MAIL_SRV_CONF_OFFSET, | |
98 offsetof(ngx_mail_ssl_conf_t, prefer_server_ciphers), | |
99 NULL }, | |
100 #else | |
101 ngx_mail_ssl_nosupported, 0, 0, ngx_mail_ssl_openssl097 }, | |
102 #endif | |
103 | |
104 { ngx_string("ssl_session_cache"), | |
105 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE12, | |
106 ngx_mail_ssl_session_cache, | |
107 NGX_MAIL_SRV_CONF_OFFSET, | |
108 0, | |
109 NULL }, | |
110 | |
111 { ngx_string("ssl_session_timeout"), | |
112 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, | |
113 ngx_conf_set_sec_slot, | |
114 NGX_MAIL_SRV_CONF_OFFSET, | |
115 offsetof(ngx_mail_ssl_conf_t, session_timeout), | |
116 NULL }, | |
117 | |
118 ngx_null_command | |
119 }; | |
120 | |
121 | |
122 static ngx_mail_module_t ngx_mail_ssl_module_ctx = { | |
123 NULL, /* create main configuration */ | |
124 NULL, /* init main configuration */ | |
125 | |
126 ngx_mail_ssl_create_conf, /* create server configuration */ | |
127 ngx_mail_ssl_merge_conf /* merge server configuration */ | |
128 }; | |
129 | |
130 | |
131 ngx_module_t ngx_mail_ssl_module = { | |
132 NGX_MODULE_V1, | |
133 &ngx_mail_ssl_module_ctx, /* module context */ | |
134 ngx_mail_ssl_commands, /* module directives */ | |
135 NGX_MAIL_MODULE, /* module type */ | |
136 NULL, /* init master */ | |
137 NULL, /* init module */ | |
138 NULL, /* init process */ | |
139 NULL, /* init thread */ | |
140 NULL, /* exit thread */ | |
141 NULL, /* exit process */ | |
142 NULL, /* exit master */ | |
143 NGX_MODULE_V1_PADDING | |
144 }; | |
145 | |
146 | |
147 static ngx_str_t ngx_mail_ssl_sess_id_ctx = ngx_string("MAIL"); | |
148 | |
149 | |
150 static void * | |
151 ngx_mail_ssl_create_conf(ngx_conf_t *cf) | |
152 { | |
153 ngx_mail_ssl_conf_t *scf; | |
154 | |
155 scf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_ssl_conf_t)); | |
156 if (scf == NULL) { | |
157 return NGX_CONF_ERROR; | |
158 } | |
159 | |
160 /* | |
161 * set by ngx_pcalloc(): | |
162 * | |
163 * scf->protocols = 0; | |
164 * scf->certificate.len = 0; | |
165 * scf->certificate.data = NULL; | |
166 * scf->certificate_key.len = 0; | |
167 * scf->certificate_key.data = NULL; | |
168 * scf->ciphers.len = 0; | |
169 * scf->ciphers.data = NULL; | |
170 * scf->shm_zone = NULL; | |
171 */ | |
172 | |
173 scf->enable = NGX_CONF_UNSET; | |
174 scf->starttls = NGX_CONF_UNSET; | |
175 scf->prefer_server_ciphers = NGX_CONF_UNSET; | |
176 scf->builtin_session_cache = NGX_CONF_UNSET; | |
177 scf->session_timeout = NGX_CONF_UNSET; | |
178 | |
179 return scf; | |
180 } | |
181 | |
182 | |
183 static char * | |
184 ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) | |
185 { | |
186 ngx_mail_ssl_conf_t *prev = parent; | |
187 ngx_mail_ssl_conf_t *conf = child; | |
188 | |
189 ngx_pool_cleanup_t *cln; | |
190 | |
191 ngx_conf_merge_value(conf->enable, prev->enable, 0); | |
192 ngx_conf_merge_value(conf->starttls, prev->starttls, NGX_MAIL_STARTTLS_OFF); | |
193 | |
194 if (conf->enable == 0 && conf->starttls == NGX_MAIL_STARTTLS_OFF) { | |
195 return NGX_CONF_OK; | |
196 } | |
197 | |
198 ngx_conf_merge_value(conf->session_timeout, | |
199 prev->session_timeout, 300); | |
200 | |
201 ngx_conf_merge_value(conf->prefer_server_ciphers, | |
202 prev->prefer_server_ciphers, 0); | |
203 | |
204 ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, | |
205 (NGX_CONF_BITMASK_SET | |
206 |NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1)); | |
207 | |
208 ngx_conf_merge_str_value(conf->certificate, prev->certificate, | |
209 NGX_DEFLAUT_CERTIFICATE); | |
210 | |
211 ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, | |
212 NGX_DEFLAUT_CERTIFICATE_KEY); | |
213 | |
214 ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFLAUT_CIPHERS); | |
215 | |
216 | |
217 conf->ssl.log = cf->log; | |
218 | |
219 if (ngx_ssl_create(&conf->ssl, conf->protocols, NULL) != NGX_OK) { | |
220 return NGX_CONF_ERROR; | |
221 } | |
222 | |
223 cln = ngx_pool_cleanup_add(cf->pool, 0); | |
224 if (cln == NULL) { | |
225 return NGX_CONF_ERROR; | |
226 } | |
227 | |
228 cln->handler = ngx_ssl_cleanup_ctx; | |
229 cln->data = &conf->ssl; | |
230 | |
231 if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate, | |
232 &conf->certificate_key) | |
233 != NGX_OK) | |
234 { | |
235 return NGX_CONF_ERROR; | |
236 } | |
237 | |
238 if (conf->ciphers.len) { | |
239 if (SSL_CTX_set_cipher_list(conf->ssl.ctx, | |
240 (const char *) conf->ciphers.data) | |
241 == 0) | |
242 { | |
243 ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, | |
244 "SSL_CTX_set_cipher_list(\"%V\") failed", | |
245 &conf->ciphers); | |
246 } | |
247 } | |
248 | |
249 #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE | |
250 | |
251 if (conf->prefer_server_ciphers) { | |
252 SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); | |
253 } | |
254 | |
255 #endif | |
256 | |
257 if (ngx_ssl_generate_rsa512_key(&conf->ssl) != NGX_OK) { | |
258 return NGX_CONF_ERROR; | |
259 } | |
260 | |
261 ngx_conf_merge_value(conf->builtin_session_cache, | |
262 prev->builtin_session_cache, | |
263 NGX_SSL_DFLT_BUILTIN_SCACHE); | |
264 | |
265 if (conf->shm_zone == NULL) { | |
266 conf->shm_zone = prev->shm_zone; | |
267 } | |
268 | |
269 if (ngx_ssl_session_cache(&conf->ssl, &ngx_mail_ssl_sess_id_ctx, | |
270 conf->builtin_session_cache, | |
271 conf->shm_zone, conf->session_timeout) | |
272 != NGX_OK) | |
273 { | |
274 return NGX_CONF_ERROR; | |
275 } | |
276 | |
277 return NGX_CONF_OK; | |
278 } | |
279 | |
280 | |
281 static char * | |
282 ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
283 { | |
284 ngx_mail_ssl_conf_t *scf = conf; | |
285 | |
286 size_t len; | |
287 ngx_str_t *value, name, size; | |
288 ngx_int_t n; | |
289 ngx_uint_t i, j; | |
290 | |
291 value = cf->args->elts; | |
292 | |
293 for (i = 1; i < cf->args->nelts; i++) { | |
294 | |
295 if (ngx_strcmp(value[i].data, "builtin") == 0) { | |
296 scf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE; | |
297 continue; | |
298 } | |
299 | |
300 if (value[i].len > sizeof("builtin:") - 1 | |
301 && ngx_strncmp(value[i].data, "builtin:", sizeof("builtin:") - 1) | |
302 == 0) | |
303 { | |
304 n = ngx_atoi(value[i].data + sizeof("builtin:") - 1, | |
305 value[i].len - (sizeof("builtin:") - 1)); | |
306 | |
307 if (n == NGX_ERROR) { | |
308 goto invalid; | |
309 } | |
310 | |
311 scf->builtin_session_cache = n; | |
312 | |
313 continue; | |
314 } | |
315 | |
316 if (value[i].len > sizeof("shared:") - 1 | |
317 && ngx_strncmp(value[i].data, "shared:", sizeof("shared:") - 1) | |
318 == 0) | |
319 { | |
320 len = 0; | |
321 | |
322 for (j = sizeof("shared:") - 1; j < value[i].len; j++) { | |
323 if (value[i].data[j] == ':') { | |
324 break; | |
325 } | |
326 | |
327 len++; | |
328 } | |
329 | |
330 if (len == 0) { | |
331 goto invalid; | |
332 } | |
333 | |
334 name.len = len; | |
335 name.data = value[i].data + sizeof("shared:") - 1; | |
336 | |
337 size.len = value[i].len - j - 1; | |
338 size.data = name.data + len + 1; | |
339 | |
340 n = ngx_parse_size(&size); | |
341 | |
342 if (n == NGX_ERROR) { | |
343 goto invalid; | |
344 } | |
345 | |
346 if (n < (ngx_int_t) (8 * ngx_pagesize)) { | |
347 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
348 "session cache \"%V\" is too small", | |
349 &value[i]); | |
350 | |
351 return NGX_CONF_ERROR; | |
352 } | |
353 | |
354 scf->shm_zone = ngx_shared_memory_add(cf, &name, n, | |
355 &ngx_mail_ssl_module); | |
356 if (scf->shm_zone == NULL) { | |
357 return NGX_CONF_ERROR; | |
358 } | |
359 | |
360 continue; | |
361 } | |
362 | |
363 goto invalid; | |
364 } | |
365 | |
366 if (scf->shm_zone && scf->builtin_session_cache == NGX_CONF_UNSET) { | |
367 scf->builtin_session_cache = NGX_SSL_NO_BUILTIN_SCACHE; | |
368 } | |
369 | |
370 return NGX_CONF_OK; | |
371 | |
372 invalid: | |
373 | |
374 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
375 "invalid session cache \"%V\"", &value[i]); | |
376 | |
377 return NGX_CONF_ERROR; | |
378 } | |
379 | |
380 | |
381 #if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE) | |
382 | |
383 static char * | |
384 ngx_mail_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
385 { | |
386 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
387 "\"%V\" directive is available only in %s,", | |
388 &cmd->name, cmd->post); | |
389 | |
390 return NGX_CONF_ERROR; | |
391 } | |
392 | |
393 #endif |