diff --git a/include/struct.h b/include/struct.h index d21fddc42..3bfc5defb 100644 --- a/include/struct.h +++ b/include/struct.h @@ -1116,6 +1116,9 @@ struct _ssloptions { long options; int renegotiate_bytes; int renegotiate_timeout; + int sts_port; + long sts_duration; + int sts_preload; }; struct _configitem_mask { diff --git a/src/modules/cap/sts.c b/src/modules/cap/sts.c index 7d6f25c01..269b0a9ea 100644 --- a/src/modules/cap/sts.c +++ b/src/modules/cap/sts.c @@ -52,14 +52,58 @@ MOD_UNLOAD(sts) return MOD_SUCCESS; } +SSLOptions *FindSSLOptionsForUser(aClient *acptr) +{ + if (!MyConnect(acptr) || !IsSecure(acptr)) + return NULL; + + /* TODO: different sts-policy depending on SNI */ + + if (!iConf.ssl_options) + return NULL; + + return iConf.ssl_options; +} + int sts_capability_visible(aClient *acptr) { - return 1; + SSLOptions *ssl; + + if (!MyConnect(acptr)) + return 0; /* not needed I guess */ + + if (!IsSecure(acptr)) + { + if (iConf.ssl_options && iConf.ssl_options->sts_port) + return 1; /* YES, non-SSL user and set::ssl::sts-policy configured */ + return 0; /* NO, there is no sts-policy */ + } + + ssl = FindSSLOptionsForUser(acptr); + + if (ssl && ssl->sts_port) + return 1; + + return 0; } char *sts_capability_parameter(aClient *acptr) { - return "port=6697"; + SSLOptions *ssl; + static char buf[256]; + + ssl = FindSSLOptionsForUser(acptr); + if (!ssl) + ssl = iConf.ssl_options; /* default, eg: for non-SSL users */ + + if (!ssl) + return ""; /* A possible, but rather silly configuration error. */ + + snprintf(buf, sizeof(buf), "port=%d,duration=%ld", ssl->sts_port, ssl->sts_duration); + if (ssl->sts_preload) + strlcat(buf, ",preload", sizeof(buf)); + + return buf; } void init_sts(ModuleInfo *modinfo) diff --git a/src/s_conf.c b/src/s_conf.c index 518c052a8..ea0f9435c 100644 --- a/src/s_conf.c +++ b/src/s_conf.c @@ -7137,6 +7137,56 @@ void test_sslblock(ConfigFile *conf, ConfigEntry *cep, int *totalerrors) errors ++; } } + else if (!strcmp(cepp->ce_varname, "sts-policy")) + { + int has_port = 0; + int has_duration = 0; + for (ceppp = cepp->ce_entries; ceppp; ceppp = ceppp->ce_next) + { + if (!strcmp(ceppp->ce_varname, "port")) + { + int port; + CheckNull(ceppp); + port = atoi(ceppp->ce_vardata); + if ((port < 1) || (port > 65535)) + { + config_error("%s:%i: invalid port number specified in sts-policy::port (%d)", + ceppp->ce_fileptr->cf_filename, ceppp->ce_varlinenum, port); + errors++; + } + has_port = 1; + } + else if (!strcmp(ceppp->ce_varname, "duration")) + { + long duration; + CheckNull(ceppp); + duration = config_checkval(ceppp->ce_vardata, CFG_TIME); + if (duration < 1) + { + config_error("%s:%i: invalid duration specified in sts-policy::duration (%ld seconds)", + ceppp->ce_fileptr->cf_filename, ceppp->ce_varlinenum, duration); + errors++; + } + has_duration = 1; + } + else if (!strcmp(ceppp->ce_varname, "preload")) + { + CheckNull(ceppp); + } + } + if (!has_port) + { + config_error("%s:%i: sts-policy block without port", + cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum); + errors++; + } + if (!has_duration) + { + config_error("%s:%i: sts-policy block without duration", + cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum); + errors++; + } + } else { config_error("%s:%i: unknown directive %s", @@ -7180,6 +7230,9 @@ void conf_sslblock(ConfigFile *conf, ConfigEntry *cep, SSLOptions *ssloptions) ssloptions->options = tempiConf.ssl_options->options; ssloptions->renegotiate_bytes = tempiConf.ssl_options->renegotiate_bytes; ssloptions->renegotiate_timeout = tempiConf.ssl_options->renegotiate_timeout; + ssloptions->sts_port = tempiConf.ssl_options->sts_port; + ssloptions->sts_duration = tempiConf.ssl_options->sts_duration; + ssloptions->sts_preload = tempiConf.ssl_options->sts_preload; } /* Now process the options */ @@ -7270,6 +7323,22 @@ void conf_sslblock(ConfigFile *conf, ConfigEntry *cep, SSLOptions *ssloptions) if (!(ssloptions->options & SSLFLAG_VERIFYCERT)) ssloptions->options |= SSLFLAG_VERIFYCERT; } + else if (!strcmp(cepp->ce_varname, "sts-policy")) + { + /* We do not inherit ::sts-policy if there is a specific block for this one... */ + ssloptions->sts_port = 0; + ssloptions->sts_duration = 0; + ssloptions->sts_preload = 0; + for (ceppp = cepp->ce_entries; ceppp; ceppp = ceppp->ce_next) + { + if (!strcmp(ceppp->ce_varname, "port")) + ssloptions->sts_port = atoi(ceppp->ce_vardata); + else if (!strcmp(ceppp->ce_varname, "duration")) + ssloptions->sts_duration = config_checkval(ceppp->ce_vardata, CFG_TIME); + else if (!strcmp(ceppp->ce_varname, "preload")) + ssloptions->sts_preload = config_checkval(ceppp->ce_vardata, CFG_YESNO); + } + } } }