xref: /nginx/src/mail/ngx_mail_ssl_module.c (revision 7938:dc955d274130)
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_mail.h>
11 
12 
13 #define NGX_DEFAULT_CIPHERS     "HIGH:!aNULL:!MD5"
14 #define NGX_DEFAULT_ECDH_CURVE  "auto"
15 
16 
17 #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
18 static int ngx_mail_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn,
19     const unsigned char **out, unsigned char *outlen,
20     const unsigned char *in, unsigned int inlen, void *arg);
21 #endif
22 
23 static void *ngx_mail_ssl_create_conf(ngx_conf_t *cf);
24 static char *ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child);
25 
26 static char *ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd,
27     void *conf);
28 static char *ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd,
29     void *conf);
30 static char *ngx_mail_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd,
31     void *conf);
32 static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
33     void *conf);
34 
35 static char *ngx_mail_ssl_conf_command_check(ngx_conf_t *cf, void *post,
36     void *data);
37 
38 
39 static ngx_conf_enum_t  ngx_mail_starttls_state[] = {
40     { ngx_string("off"), NGX_MAIL_STARTTLS_OFF },
41     { ngx_string("on"), NGX_MAIL_STARTTLS_ON },
42     { ngx_string("only"), NGX_MAIL_STARTTLS_ONLY },
43     { ngx_null_string, 0 }
44 };
45 
46 
47 
48 static ngx_conf_bitmask_t  ngx_mail_ssl_protocols[] = {
49     { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
50     { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
51     { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
52     { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
53     { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
54     { ngx_string("TLSv1.3"), NGX_SSL_TLSv1_3 },
55     { ngx_null_string, 0 }
56 };
57 
58 
59 static ngx_conf_enum_t  ngx_mail_ssl_verify[] = {
60     { ngx_string("off"), 0 },
61     { ngx_string("on"), 1 },
62     { ngx_string("optional"), 2 },
63     { ngx_string("optional_no_ca"), 3 },
64     { ngx_null_string, 0 }
65 };
66 
67 
68 static ngx_conf_deprecated_t  ngx_mail_ssl_deprecated = {
69     ngx_conf_deprecated, "ssl", "listen ... ssl"
70 };
71 
72 
73 static ngx_conf_post_t  ngx_mail_ssl_conf_command_post =
74     { ngx_mail_ssl_conf_command_check };
75 
76 
77 static ngx_command_t  ngx_mail_ssl_commands[] = {
78 
79     { ngx_string("ssl"),
80       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
81       ngx_mail_ssl_enable,
82       NGX_MAIL_SRV_CONF_OFFSET,
83       offsetof(ngx_mail_ssl_conf_t, enable),
84       &ngx_mail_ssl_deprecated },
85 
86     { ngx_string("starttls"),
87       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
88       ngx_mail_ssl_starttls,
89       NGX_MAIL_SRV_CONF_OFFSET,
90       offsetof(ngx_mail_ssl_conf_t, starttls),
91       ngx_mail_starttls_state },
92 
93     { ngx_string("ssl_certificate"),
94       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
95       ngx_conf_set_str_array_slot,
96       NGX_MAIL_SRV_CONF_OFFSET,
97       offsetof(ngx_mail_ssl_conf_t, certificates),
98       NULL },
99 
100     { ngx_string("ssl_certificate_key"),
101       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
102       ngx_conf_set_str_array_slot,
103       NGX_MAIL_SRV_CONF_OFFSET,
104       offsetof(ngx_mail_ssl_conf_t, certificate_keys),
105       NULL },
106 
107     { ngx_string("ssl_password_file"),
108       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
109       ngx_mail_ssl_password_file,
110       NGX_MAIL_SRV_CONF_OFFSET,
111       0,
112       NULL },
113 
114     { ngx_string("ssl_dhparam"),
115       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
116       ngx_conf_set_str_slot,
117       NGX_MAIL_SRV_CONF_OFFSET,
118       offsetof(ngx_mail_ssl_conf_t, dhparam),
119       NULL },
120 
121     { ngx_string("ssl_ecdh_curve"),
122       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
123       ngx_conf_set_str_slot,
124       NGX_MAIL_SRV_CONF_OFFSET,
125       offsetof(ngx_mail_ssl_conf_t, ecdh_curve),
126       NULL },
127 
128     { ngx_string("ssl_protocols"),
129       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
130       ngx_conf_set_bitmask_slot,
131       NGX_MAIL_SRV_CONF_OFFSET,
132       offsetof(ngx_mail_ssl_conf_t, protocols),
133       &ngx_mail_ssl_protocols },
134 
135     { ngx_string("ssl_ciphers"),
136       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
137       ngx_conf_set_str_slot,
138       NGX_MAIL_SRV_CONF_OFFSET,
139       offsetof(ngx_mail_ssl_conf_t, ciphers),
140       NULL },
141 
142     { ngx_string("ssl_prefer_server_ciphers"),
143       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
144       ngx_conf_set_flag_slot,
145       NGX_MAIL_SRV_CONF_OFFSET,
146       offsetof(ngx_mail_ssl_conf_t, prefer_server_ciphers),
147       NULL },
148 
149     { ngx_string("ssl_session_cache"),
150       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE12,
151       ngx_mail_ssl_session_cache,
152       NGX_MAIL_SRV_CONF_OFFSET,
153       0,
154       NULL },
155 
156     { ngx_string("ssl_session_tickets"),
157       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
158       ngx_conf_set_flag_slot,
159       NGX_MAIL_SRV_CONF_OFFSET,
160       offsetof(ngx_mail_ssl_conf_t, session_tickets),
161       NULL },
162 
163     { ngx_string("ssl_session_ticket_key"),
164       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
165       ngx_conf_set_str_array_slot,
166       NGX_MAIL_SRV_CONF_OFFSET,
167       offsetof(ngx_mail_ssl_conf_t, session_ticket_keys),
168       NULL },
169 
170     { ngx_string("ssl_session_timeout"),
171       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
172       ngx_conf_set_sec_slot,
173       NGX_MAIL_SRV_CONF_OFFSET,
174       offsetof(ngx_mail_ssl_conf_t, session_timeout),
175       NULL },
176 
177     { ngx_string("ssl_verify_client"),
178       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
179       ngx_conf_set_enum_slot,
180       NGX_MAIL_SRV_CONF_OFFSET,
181       offsetof(ngx_mail_ssl_conf_t, verify),
182       &ngx_mail_ssl_verify },
183 
184     { ngx_string("ssl_verify_depth"),
185       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
186       ngx_conf_set_num_slot,
187       NGX_MAIL_SRV_CONF_OFFSET,
188       offsetof(ngx_mail_ssl_conf_t, verify_depth),
189       NULL },
190 
191     { ngx_string("ssl_client_certificate"),
192       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
193       ngx_conf_set_str_slot,
194       NGX_MAIL_SRV_CONF_OFFSET,
195       offsetof(ngx_mail_ssl_conf_t, client_certificate),
196       NULL },
197 
198     { ngx_string("ssl_trusted_certificate"),
199       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
200       ngx_conf_set_str_slot,
201       NGX_MAIL_SRV_CONF_OFFSET,
202       offsetof(ngx_mail_ssl_conf_t, trusted_certificate),
203       NULL },
204 
205     { ngx_string("ssl_crl"),
206       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
207       ngx_conf_set_str_slot,
208       NGX_MAIL_SRV_CONF_OFFSET,
209       offsetof(ngx_mail_ssl_conf_t, crl),
210       NULL },
211 
212     { ngx_string("ssl_conf_command"),
213       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE2,
214       ngx_conf_set_keyval_slot,
215       NGX_MAIL_SRV_CONF_OFFSET,
216       offsetof(ngx_mail_ssl_conf_t, conf_commands),
217       &ngx_mail_ssl_conf_command_post },
218 
219       ngx_null_command
220 };
221 
222 
223 static ngx_mail_module_t  ngx_mail_ssl_module_ctx = {
224     NULL,                                  /* protocol */
225 
226     NULL,                                  /* create main configuration */
227     NULL,                                  /* init main configuration */
228 
229     ngx_mail_ssl_create_conf,              /* create server configuration */
230     ngx_mail_ssl_merge_conf                /* merge server configuration */
231 };
232 
233 
234 ngx_module_t  ngx_mail_ssl_module = {
235     NGX_MODULE_V1,
236     &ngx_mail_ssl_module_ctx,              /* module context */
237     ngx_mail_ssl_commands,                 /* module directives */
238     NGX_MAIL_MODULE,                       /* module type */
239     NULL,                                  /* init master */
240     NULL,                                  /* init module */
241     NULL,                                  /* init process */
242     NULL,                                  /* init thread */
243     NULL,                                  /* exit thread */
244     NULL,                                  /* exit process */
245     NULL,                                  /* exit master */
246     NGX_MODULE_V1_PADDING
247 };
248 
249 
250 static ngx_str_t ngx_mail_ssl_sess_id_ctx = ngx_string("MAIL");
251 
252 
253 #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
254 
255 static int
256 ngx_mail_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out,
257     unsigned char *outlen, const unsigned char *in, unsigned int inlen,
258     void *arg)
259 {
260     unsigned int               srvlen;
261     unsigned char             *srv;
262     ngx_connection_t          *c;
263     ngx_mail_session_t        *s;
264     ngx_mail_core_srv_conf_t  *cscf;
265 #if (NGX_DEBUG)
266     unsigned int               i;
267 #endif
268 
269     c = ngx_ssl_get_connection(ssl_conn);
270     s = c->data;
271 
272 #if (NGX_DEBUG)
273     for (i = 0; i < inlen; i += in[i] + 1) {
274         ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
275                        "SSL ALPN supported by client: %*s",
276                        (size_t) in[i], &in[i + 1]);
277     }
278 #endif
279 
280     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
281 
282     srv = cscf->protocol->alpn.data;
283     srvlen = cscf->protocol->alpn.len;
284 
285     if (SSL_select_next_proto((unsigned char **) out, outlen, srv, srvlen,
286                               in, inlen)
287         != OPENSSL_NPN_NEGOTIATED)
288     {
289         return SSL_TLSEXT_ERR_ALERT_FATAL;
290     }
291 
292     ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
293                    "SSL ALPN selected: %*s", (size_t) *outlen, *out);
294 
295     return SSL_TLSEXT_ERR_OK;
296 }
297 
298 #endif
299 
300 
301 static void *
302 ngx_mail_ssl_create_conf(ngx_conf_t *cf)
303 {
304     ngx_mail_ssl_conf_t  *scf;
305 
306     scf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_ssl_conf_t));
307     if (scf == NULL) {
308         return NULL;
309     }
310 
311     /*
312      * set by ngx_pcalloc():
313      *
314      *     scf->listen = 0;
315      *     scf->protocols = 0;
316      *     scf->dhparam = { 0, NULL };
317      *     scf->ecdh_curve = { 0, NULL };
318      *     scf->client_certificate = { 0, NULL };
319      *     scf->trusted_certificate = { 0, NULL };
320      *     scf->crl = { 0, NULL };
321      *     scf->ciphers = { 0, NULL };
322      *     scf->shm_zone = NULL;
323      */
324 
325     scf->enable = NGX_CONF_UNSET;
326     scf->starttls = NGX_CONF_UNSET_UINT;
327     scf->certificates = NGX_CONF_UNSET_PTR;
328     scf->certificate_keys = NGX_CONF_UNSET_PTR;
329     scf->passwords = NGX_CONF_UNSET_PTR;
330     scf->conf_commands = NGX_CONF_UNSET_PTR;
331     scf->prefer_server_ciphers = NGX_CONF_UNSET;
332     scf->verify = NGX_CONF_UNSET_UINT;
333     scf->verify_depth = NGX_CONF_UNSET_UINT;
334     scf->builtin_session_cache = NGX_CONF_UNSET;
335     scf->session_timeout = NGX_CONF_UNSET;
336     scf->session_tickets = NGX_CONF_UNSET;
337     scf->session_ticket_keys = NGX_CONF_UNSET_PTR;
338 
339     return scf;
340 }
341 
342 
343 static char *
344 ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
345 {
346     ngx_mail_ssl_conf_t *prev = parent;
347     ngx_mail_ssl_conf_t *conf = child;
348 
349     char                *mode;
350     ngx_pool_cleanup_t  *cln;
351 
352     ngx_conf_merge_value(conf->enable, prev->enable, 0);
353     ngx_conf_merge_uint_value(conf->starttls, prev->starttls,
354                          NGX_MAIL_STARTTLS_OFF);
355 
356     ngx_conf_merge_value(conf->session_timeout,
357                          prev->session_timeout, 300);
358 
359     ngx_conf_merge_value(conf->prefer_server_ciphers,
360                          prev->prefer_server_ciphers, 0);
361 
362     ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols,
363                          (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
364                           |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
365 
366     ngx_conf_merge_uint_value(conf->verify, prev->verify, 0);
367     ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1);
368 
369     ngx_conf_merge_ptr_value(conf->certificates, prev->certificates, NULL);
370     ngx_conf_merge_ptr_value(conf->certificate_keys, prev->certificate_keys,
371                          NULL);
372 
373     ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL);
374 
375     ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, "");
376 
377     ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve,
378                          NGX_DEFAULT_ECDH_CURVE);
379 
380     ngx_conf_merge_str_value(conf->client_certificate,
381                          prev->client_certificate, "");
382     ngx_conf_merge_str_value(conf->trusted_certificate,
383                          prev->trusted_certificate, "");
384     ngx_conf_merge_str_value(conf->crl, prev->crl, "");
385 
386     ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS);
387 
388     ngx_conf_merge_ptr_value(conf->conf_commands, prev->conf_commands, NULL);
389 
390 
391     conf->ssl.log = cf->log;
392 
393     if (conf->listen) {
394         mode = "listen ... ssl";
395 
396     } else if (conf->enable) {
397         mode = "ssl";
398 
399     } else if (conf->starttls != NGX_MAIL_STARTTLS_OFF) {
400         mode = "starttls";
401 
402     } else {
403         return NGX_CONF_OK;
404     }
405 
406     if (conf->file == NULL) {
407         conf->file = prev->file;
408         conf->line = prev->line;
409     }
410 
411     if (conf->certificates == NULL) {
412         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
413                       "no \"ssl_certificate\" is defined for "
414                       "the \"%s\" directive in %s:%ui",
415                       mode, conf->file, conf->line);
416         return NGX_CONF_ERROR;
417     }
418 
419     if (conf->certificate_keys == NULL) {
420         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
421                       "no \"ssl_certificate_key\" is defined for "
422                       "the \"%s\" directive in %s:%ui",
423                       mode, conf->file, conf->line);
424         return NGX_CONF_ERROR;
425     }
426 
427     if (conf->certificate_keys->nelts < conf->certificates->nelts) {
428         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
429                       "no \"ssl_certificate_key\" is defined "
430                       "for certificate \"%V\" and "
431                       "the \"%s\" directive in %s:%ui",
432                       ((ngx_str_t *) conf->certificates->elts)
433                       + conf->certificates->nelts - 1,
434                       mode, conf->file, conf->line);
435         return NGX_CONF_ERROR;
436     }
437 
438     if (ngx_ssl_create(&conf->ssl, conf->protocols, NULL) != NGX_OK) {
439         return NGX_CONF_ERROR;
440     }
441 
442     cln = ngx_pool_cleanup_add(cf->pool, 0);
443     if (cln == NULL) {
444         ngx_ssl_cleanup_ctx(&conf->ssl);
445         return NGX_CONF_ERROR;
446     }
447 
448     cln->handler = ngx_ssl_cleanup_ctx;
449     cln->data = &conf->ssl;
450 
451 #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
452     SSL_CTX_set_alpn_select_cb(conf->ssl.ctx, ngx_mail_ssl_alpn_select, NULL);
453 #endif
454 
455     if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers,
456                         conf->prefer_server_ciphers)
457         != NGX_OK)
458     {
459         return NGX_CONF_ERROR;
460     }
461 
462     if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates,
463                              conf->certificate_keys, conf->passwords)
464         != NGX_OK)
465     {
466         return NGX_CONF_ERROR;
467     }
468 
469     if (conf->verify) {
470 
471         if (conf->client_certificate.len == 0 && conf->verify != 3) {
472             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
473                           "no ssl_client_certificate for ssl_verify_client");
474             return NGX_CONF_ERROR;
475         }
476 
477         if (ngx_ssl_client_certificate(cf, &conf->ssl,
478                                        &conf->client_certificate,
479                                        conf->verify_depth)
480             != NGX_OK)
481         {
482             return NGX_CONF_ERROR;
483         }
484 
485         if (ngx_ssl_trusted_certificate(cf, &conf->ssl,
486                                         &conf->trusted_certificate,
487                                         conf->verify_depth)
488             != NGX_OK)
489         {
490             return NGX_CONF_ERROR;
491         }
492 
493         if (ngx_ssl_crl(cf, &conf->ssl, &conf->crl) != NGX_OK) {
494             return NGX_CONF_ERROR;
495         }
496     }
497 
498     if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) {
499         return NGX_CONF_ERROR;
500     }
501 
502     if (ngx_ssl_ecdh_curve(cf, &conf->ssl, &conf->ecdh_curve) != NGX_OK) {
503         return NGX_CONF_ERROR;
504     }
505 
506     ngx_conf_merge_value(conf->builtin_session_cache,
507                          prev->builtin_session_cache, NGX_SSL_NONE_SCACHE);
508 
509     if (conf->shm_zone == NULL) {
510         conf->shm_zone = prev->shm_zone;
511     }
512 
513     if (ngx_ssl_session_cache(&conf->ssl, &ngx_mail_ssl_sess_id_ctx,
514                               conf->certificates, conf->builtin_session_cache,
515                               conf->shm_zone, conf->session_timeout)
516         != NGX_OK)
517     {
518         return NGX_CONF_ERROR;
519     }
520 
521     ngx_conf_merge_value(conf->session_tickets,
522                          prev->session_tickets, 1);
523 
524 #ifdef SSL_OP_NO_TICKET
525     if (!conf->session_tickets) {
526         SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_NO_TICKET);
527     }
528 #endif
529 
530     ngx_conf_merge_ptr_value(conf->session_ticket_keys,
531                          prev->session_ticket_keys, NULL);
532 
533     if (ngx_ssl_session_ticket_keys(cf, &conf->ssl, conf->session_ticket_keys)
534         != NGX_OK)
535     {
536         return NGX_CONF_ERROR;
537     }
538 
539     if (ngx_ssl_conf_commands(cf, &conf->ssl, conf->conf_commands) != NGX_OK) {
540         return NGX_CONF_ERROR;
541     }
542 
543     return NGX_CONF_OK;
544 }
545 
546 
547 static char *
548 ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
549 {
550     ngx_mail_ssl_conf_t  *scf = conf;
551 
552     char  *rv;
553 
554     rv = ngx_conf_set_flag_slot(cf, cmd, conf);
555 
556     if (rv != NGX_CONF_OK) {
557         return rv;
558     }
559 
560     if (scf->enable && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) {
561         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
562                            "\"starttls\" directive conflicts with \"ssl on\"");
563         return NGX_CONF_ERROR;
564     }
565 
566     if (!scf->listen) {
567         scf->file = cf->conf_file->file.name.data;
568         scf->line = cf->conf_file->line;
569     }
570 
571     return NGX_CONF_OK;
572 }
573 
574 
575 static char *
576 ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
577 {
578     ngx_mail_ssl_conf_t  *scf = conf;
579 
580     char  *rv;
581 
582     rv = ngx_conf_set_enum_slot(cf, cmd, conf);
583 
584     if (rv != NGX_CONF_OK) {
585         return rv;
586     }
587 
588     if (scf->enable == 1 && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) {
589         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
590                            "\"ssl\" directive conflicts with \"starttls\"");
591         return NGX_CONF_ERROR;
592     }
593 
594     if (!scf->listen) {
595         scf->file = cf->conf_file->file.name.data;
596         scf->line = cf->conf_file->line;
597     }
598 
599     return NGX_CONF_OK;
600 }
601 
602 
603 static char *
604 ngx_mail_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
605 {
606     ngx_mail_ssl_conf_t  *scf = conf;
607 
608     ngx_str_t  *value;
609 
610     if (scf->passwords != NGX_CONF_UNSET_PTR) {
611         return "is duplicate";
612     }
613 
614     value = cf->args->elts;
615 
616     scf->passwords = ngx_ssl_read_password_file(cf, &value[1]);
617 
618     if (scf->passwords == NULL) {
619         return NGX_CONF_ERROR;
620     }
621 
622     return NGX_CONF_OK;
623 }
624 
625 
626 static char *
627 ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
628 {
629     ngx_mail_ssl_conf_t  *scf = conf;
630 
631     size_t       len;
632     ngx_str_t   *value, name, size;
633     ngx_int_t    n;
634     ngx_uint_t   i, j;
635 
636     value = cf->args->elts;
637 
638     for (i = 1; i < cf->args->nelts; i++) {
639 
640         if (ngx_strcmp(value[i].data, "off") == 0) {
641             scf->builtin_session_cache = NGX_SSL_NO_SCACHE;
642             continue;
643         }
644 
645         if (ngx_strcmp(value[i].data, "none") == 0) {
646             scf->builtin_session_cache = NGX_SSL_NONE_SCACHE;
647             continue;
648         }
649 
650         if (ngx_strcmp(value[i].data, "builtin") == 0) {
651             scf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE;
652             continue;
653         }
654 
655         if (value[i].len > sizeof("builtin:") - 1
656             && ngx_strncmp(value[i].data, "builtin:", sizeof("builtin:") - 1)
657                == 0)
658         {
659             n = ngx_atoi(value[i].data + sizeof("builtin:") - 1,
660                          value[i].len - (sizeof("builtin:") - 1));
661 
662             if (n == NGX_ERROR) {
663                 goto invalid;
664             }
665 
666             scf->builtin_session_cache = n;
667 
668             continue;
669         }
670 
671         if (value[i].len > sizeof("shared:") - 1
672             && ngx_strncmp(value[i].data, "shared:", sizeof("shared:") - 1)
673                == 0)
674         {
675             len = 0;
676 
677             for (j = sizeof("shared:") - 1; j < value[i].len; j++) {
678                 if (value[i].data[j] == ':') {
679                     break;
680                 }
681 
682                 len++;
683             }
684 
685             if (len == 0) {
686                 goto invalid;
687             }
688 
689             name.len = len;
690             name.data = value[i].data + sizeof("shared:") - 1;
691 
692             size.len = value[i].len - j - 1;
693             size.data = name.data + len + 1;
694 
695             n = ngx_parse_size(&size);
696 
697             if (n == NGX_ERROR) {
698                 goto invalid;
699             }
700 
701             if (n < (ngx_int_t) (8 * ngx_pagesize)) {
702                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
703                                    "session cache \"%V\" is too small",
704                                    &value[i]);
705 
706                 return NGX_CONF_ERROR;
707             }
708 
709             scf->shm_zone = ngx_shared_memory_add(cf, &name, n,
710                                                    &ngx_mail_ssl_module);
711             if (scf->shm_zone == NULL) {
712                 return NGX_CONF_ERROR;
713             }
714 
715             scf->shm_zone->init = ngx_ssl_session_cache_init;
716 
717             continue;
718         }
719 
720         goto invalid;
721     }
722 
723     if (scf->shm_zone && scf->builtin_session_cache == NGX_CONF_UNSET) {
724         scf->builtin_session_cache = NGX_SSL_NO_BUILTIN_SCACHE;
725     }
726 
727     return NGX_CONF_OK;
728 
729 invalid:
730 
731     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
732                        "invalid session cache \"%V\"", &value[i]);
733 
734     return NGX_CONF_ERROR;
735 }
736 
737 
738 static char *
739 ngx_mail_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data)
740 {
741 #ifndef SSL_CONF_FLAG_FILE
742     return "is not supported on this platform";
743 #else
744     return NGX_CONF_OK;
745 #endif
746 }
747