diff --git a/doc/ircd.conf.example b/doc/ircd.conf.example index c5c5fbe3..28a926ab 100755 --- a/doc/ircd.conf.example +++ b/doc/ircd.conf.example @@ -461,6 +461,14 @@ general { default_operstring = "is an IRC Operator"; default_adminstring = "is a Server Administrator"; servicestring = "is a Network Service"; + + /* + * Nick of the network's SASL agent. Used to check whether services are here, + * SASL credentials are only sent to its server. Needs to be a service. + * + * Defaults to SaslServ if unspecified. + */ + sasl_service = "SaslServ"; disable_fake_channels = no; tkline_expire_notices = no; default_floodcount = 10; diff --git a/doc/reference.conf b/doc/reference.conf index c4a9c06c..b49104ea 100755 --- a/doc/reference.conf +++ b/doc/reference.conf @@ -955,6 +955,14 @@ general { */ servicestring = "is a Network Service"; + /* + * Nick of the network's SASL agent. Used to check whether services are here, + * SASL credentials are only sent to its server. Needs to be a service. + * + * Defaults to SaslServ if unspecified. + */ + sasl_service = "SaslServ"; + /* disable fake channels: disable local users joining fake versions * of channels, eg #foo^B^B. Disables bold, mirc colour, reverse, * underline and hard space. (ASCII 2, 3, 22, 31, 160 respectively). diff --git a/include/s_conf.h b/include/s_conf.h index 58e57b64..ceeae01a 100644 --- a/include/s_conf.h +++ b/include/s_conf.h @@ -151,6 +151,8 @@ struct config_file_entry char *identifyservice; char *identifycommand; + char *sasl_service; + char *fname_userlog; char *fname_fuserlog; char *fname_operlog; diff --git a/modules/m_sasl.c b/modules/m_sasl.c index 84017523..9b139951 100644 --- a/modules/m_sasl.c +++ b/modules/m_sasl.c @@ -40,6 +40,8 @@ #include "s_serv.h" #include "s_stats.h" #include "string.h" +#include "s_newconf.h" +#include "s_conf.h" static int mr_authenticate(struct Client *, struct Client *, int, const char **); static int me_sasl(struct Client *, struct Client *, int, const char **); @@ -72,6 +74,7 @@ mr_authenticate(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *agent_p = NULL; + struct Client *saslserv_p = NULL; /* They really should use CAP for their own sake. */ if(!IsCapable(source_p, CLICAP_SASL)) @@ -83,6 +86,13 @@ mr_authenticate(struct Client *client_p, struct Client *source_p, return 0; } + saslserv_p = find_named_client(ConfigFileEntry.sasl_service); + if (saslserv_p == NULL || !IsService(saslserv_p)) + { + sendto_one(source_p, form_str(ERR_SASLABORTED), me.name, EmptyString(source_p->name) ? "*" : source_p->name); + return 0; + } + if(source_p->preClient->sasl_complete) { sendto_one(source_p, form_str(ERR_SASLALREADY), me.name, EmptyString(source_p->name) ? "*" : source_p->name); @@ -108,16 +118,20 @@ mr_authenticate(struct Client *client_p, struct Client *source_p, if(agent_p == NULL) { if (!strcmp(parv[1], "EXTERNAL") && source_p->certfp != NULL) - sendto_server(NULL, NULL, CAP_TS6|CAP_ENCAP, NOCAPS, ":%s ENCAP * SASL %s * S %s %s", me.id, - source_p->id, parv[1], - source_p->certfp); + sendto_one(saslserv_p, ":%s ENCAP %s SASL %s %s S %s %s", me.id, saslserv_p->servptr->name, + source_p->id, saslserv_p->id, + parv[1], source_p->certfp); else - sendto_server(NULL, NULL, CAP_TS6|CAP_ENCAP, NOCAPS, ":%s ENCAP * SASL %s * S %s", me.id, - source_p->id, parv[1]); + sendto_one(saslserv_p, ":%s ENCAP %s SASL %s %s S %s", me.id, saslserv_p->servptr->name, + source_p->id, saslserv_p->id, + parv[1]); + + rb_strlcpy(source_p->preClient->sasl_agent, saslserv_p->id, IDLEN); } else sendto_one(agent_p, ":%s ENCAP %s SASL %s %s C %s", me.id, agent_p->servptr->name, - source_p->id, agent_p->id, parv[1]); + source_p->id, agent_p->id, + parv[1]); source_p->preClient->sasl_out++; return 0; diff --git a/src/newconf.c b/src/newconf.c index 7af7ad9d..6a7a256d 100644 --- a/src/newconf.c +++ b/src/newconf.c @@ -2315,6 +2315,7 @@ static struct ConfEntry conf_general_table[] = { "kline_reason", CF_QSTRING, NULL, REALLEN, &ConfigFileEntry.kline_reason }, { "identify_service", CF_QSTRING, NULL, REALLEN, &ConfigFileEntry.identifyservice }, { "identify_command", CF_QSTRING, NULL, REALLEN, &ConfigFileEntry.identifycommand }, + { "sasl_service", CF_QSTRING, NULL, REALLEN, &ConfigFileEntry.sasl_service }, { "anti_spam_exit_message_time", CF_TIME, NULL, 0, &ConfigFileEntry.anti_spam_exit_message_time }, { "disable_fake_channels", CF_YESNO, NULL, 0, &ConfigFileEntry.disable_fake_channels }, diff --git a/src/s_conf.c b/src/s_conf.c index 1a70de25..a329c7b7 100644 --- a/src/s_conf.c +++ b/src/s_conf.c @@ -692,6 +692,7 @@ set_default_conf(void) ConfigFileEntry.default_operstring = NULL; ConfigFileEntry.default_adminstring = NULL; ConfigFileEntry.servicestring = NULL; + ConfigFileEntry.sasl_service = NULL; ConfigFileEntry.default_umodes = UMODE_INVISIBLE; ConfigFileEntry.failed_oper_notice = YES; @@ -886,6 +887,9 @@ validate_conf(void) if (ConfigFileEntry.servicestring == NULL) ConfigFileEntry.servicestring = rb_strdup("is a Network Service"); + if (ConfigFileEntry.sasl_service == NULL) + ConfigFileEntry.sasl_service = rb_strdup("SaslServ"); + /* RFC 1459 says 1 message per 2 seconds on average and bursts of * 5 messages are acceptable, so allow at least that. */ @@ -1489,6 +1493,8 @@ clear_out_old_conf(void) ConfigFileEntry.servicestring = NULL; rb_free(ConfigFileEntry.kline_reason); ConfigFileEntry.kline_reason = NULL; + rb_free(ConfigFileEntry.sasl_service); + ConfigFileEntry.sasl_service = NULL; /* clean out log */ rb_free(ConfigFileEntry.fname_userlog);