mirror of
git://git.acid.vegas/unrealircd.git
synced 2025-04-17 06:28:27 +00:00
282 lines
7.7 KiB
C
282 lines
7.7 KiB
C
/*
|
|
* IRC - Internet Relay Chat, src/modules/link-security.c
|
|
* (C) 2017 Syzop & The UnrealIRCd Team
|
|
*
|
|
* See file AUTHORS in IRC package for additional names of
|
|
* the programmers.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 1, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include "unrealircd.h"
|
|
|
|
/* Module header */
|
|
ModuleHeader MOD_HEADER
|
|
= {
|
|
"link-security",
|
|
"5.0",
|
|
"Link Security CAP",
|
|
"UnrealIRCd Team",
|
|
"unrealircd-5",
|
|
};
|
|
|
|
/* Forward declarations */
|
|
char *link_security_md_serialize(ModData *m);
|
|
void link_security_md_unserialize(char *str, ModData *m);
|
|
EVENT(checklinksec);
|
|
char *link_security_capability_parameter(Client *client);
|
|
CMD_FUNC(cmd_linksecurity);
|
|
|
|
/* Global variables */
|
|
ModDataInfo *link_security_md;
|
|
int local_link_security = -1;
|
|
int global_link_security = -1;
|
|
int effective_link_security = -1;
|
|
|
|
/** Module initalization */
|
|
MOD_INIT()
|
|
{
|
|
ModDataInfo mreq;
|
|
|
|
MARK_AS_OFFICIAL_MODULE(modinfo);
|
|
ModuleSetOptions(modinfo->handle, MOD_OPT_PERM_RELOADABLE, 1);
|
|
|
|
memset(&mreq, 0, sizeof(mreq));
|
|
mreq.name = "link-security";
|
|
mreq.type = MODDATATYPE_CLIENT;
|
|
mreq.serialize = link_security_md_serialize;
|
|
mreq.unserialize = link_security_md_unserialize;
|
|
mreq.sync = 1;
|
|
link_security_md = ModDataAdd(modinfo->handle, mreq);
|
|
if (!link_security_md)
|
|
{
|
|
config_error("Unable to ModDataAdd() -- too many 3rd party modules loaded perhaps?");
|
|
abort();
|
|
}
|
|
|
|
CommandAdd(modinfo->handle, "LINKSECURITY", cmd_linksecurity, MAXPARA, CMD_USER);
|
|
|
|
return MOD_SUCCESS;
|
|
}
|
|
|
|
MOD_LOAD()
|
|
{
|
|
ClientCapabilityInfo cap;
|
|
|
|
memset(&cap, 0, sizeof(cap));
|
|
cap.name = "unrealircd.org/link-security";
|
|
cap.flags = CLICAP_FLAGS_ADVERTISE_ONLY;
|
|
cap.parameter = link_security_capability_parameter;
|
|
ClientCapabilityAdd(modinfo->handle, &cap, NULL);
|
|
|
|
EventAdd(modinfo->handle, "checklinksec", checklinksec, NULL, 2000, 0);
|
|
checklinksec(NULL);
|
|
return MOD_SUCCESS;
|
|
}
|
|
|
|
MOD_UNLOAD()
|
|
{
|
|
return MOD_SUCCESS;
|
|
}
|
|
|
|
/* Magic value to differentiate between "not set" and "zero".
|
|
* Only used for internal moddata storage, not exposed
|
|
* outside these two functions.
|
|
*/
|
|
#define LNKSECMAGIC 100
|
|
|
|
char *link_security_md_serialize(ModData *m)
|
|
{
|
|
static char buf[32];
|
|
if (m->i == 0)
|
|
return NULL; /* not set */
|
|
snprintf(buf, sizeof(buf), "%d", m->i - LNKSECMAGIC);
|
|
return buf;
|
|
}
|
|
|
|
void link_security_md_unserialize(char *str, ModData *m)
|
|
{
|
|
m->i = atoi(str) + LNKSECMAGIC;
|
|
}
|
|
|
|
/** Return 1 if the server certificate is verified for
|
|
* server 'client', return 0 if not.
|
|
*/
|
|
int certificate_verification_active(Client *client)
|
|
{
|
|
ConfigItem_link *conf;
|
|
|
|
if (!client->serv || !client->serv->conf)
|
|
return 0; /* wtf? */
|
|
conf = client->serv->conf;
|
|
|
|
if (conf->verify_certificate)
|
|
return 1; /* yes, verify-certificate is 'yes' */
|
|
|
|
if ((conf->auth->type == AUTHTYPE_TLS_CLIENTCERT) ||
|
|
(conf->auth->type == AUTHTYPE_TLS_CLIENTCERTFP) ||
|
|
(conf->auth->type == AUTHTYPE_SPKIFP))
|
|
{
|
|
/* yes, verified by link::password being a
|
|
* certificate fingerprint or certificate file.
|
|
*/
|
|
return 1;
|
|
}
|
|
|
|
return 0; /* no, certificate is not verified in any way */
|
|
}
|
|
|
|
/** Calculate our (local) link-security level.
|
|
* This means stepping through the list of directly linked
|
|
* servers and determining if they are linked via SSL and
|
|
* certificate verification is active.
|
|
* @returns value from 0 to 2.
|
|
*/
|
|
int our_link_security(void)
|
|
{
|
|
Client *client;
|
|
int level = 2; /* safest */
|
|
|
|
list_for_each_entry(client, &server_list, special_node)
|
|
{
|
|
if (IsLocalhost(client))
|
|
continue; /* server connected via localhost */
|
|
if (!IsSecure(client))
|
|
return 0; /* Any non-SSL server (which is not localhost) results in level 0. */
|
|
if (!certificate_verification_active(client))
|
|
level = 1; /* downgrade to level 1 */
|
|
}
|
|
|
|
return level;
|
|
}
|
|
|
|
char *valtostr(int i)
|
|
{
|
|
static char buf[32];
|
|
snprintf(buf, sizeof(buf), "%d", i);
|
|
return buf;
|
|
}
|
|
|
|
/** Check link security. This is called every X seconds to see if there
|
|
* is a change, either local or network-wide.
|
|
*/
|
|
EVENT(checklinksec)
|
|
{
|
|
int last_local_link_security = local_link_security;
|
|
int last_global_link_security = global_link_security;
|
|
Client *client;
|
|
char *s;
|
|
int v;
|
|
int warning_sent = 0;
|
|
|
|
local_link_security = our_link_security();
|
|
if (local_link_security != last_local_link_security)
|
|
{
|
|
/* Our own link-security changed (for better or worse),
|
|
* Set and broadcast it immediately to the other servers.
|
|
*/
|
|
moddata_client_set(&me, "link-security", valtostr(local_link_security));
|
|
}
|
|
|
|
global_link_security = 2;
|
|
list_for_each_entry(client, &global_server_list, client_node)
|
|
{
|
|
s = moddata_client_get(client, "link-security");
|
|
if (s)
|
|
{
|
|
v = atoi(s);
|
|
if (v == 0)
|
|
{
|
|
global_link_security = 0;
|
|
break;
|
|
}
|
|
if (v == 1)
|
|
global_link_security = 1;
|
|
}
|
|
}
|
|
|
|
if (local_link_security < last_local_link_security)
|
|
{
|
|
sendto_realops("Local link-security downgraded from level %d to %d due to just linked in server(s)",
|
|
last_local_link_security, local_link_security);
|
|
warning_sent = 1;
|
|
}
|
|
|
|
if (global_link_security < last_global_link_security)
|
|
{
|
|
sendto_realops("Global link-security downgraded from level %d to %d due to just linked in server(s)",
|
|
last_global_link_security, global_link_security);
|
|
warning_sent = 1;
|
|
}
|
|
|
|
effective_link_security = MIN(local_link_security, global_link_security);
|
|
|
|
if (warning_sent)
|
|
{
|
|
sendto_realops("Effective (network-wide) link-security is: level %d", effective_link_security);
|
|
sendto_realops("More information about this can be found at https://www.unrealircd.org/docs/Link_security");
|
|
}
|
|
}
|
|
|
|
char *link_security_capability_parameter(Client *client)
|
|
{
|
|
return valtostr(effective_link_security);
|
|
}
|
|
|
|
/** /LINKSECURITY command */
|
|
CMD_FUNC(cmd_linksecurity)
|
|
{
|
|
Client *acptr;
|
|
char *s;
|
|
int v;
|
|
|
|
if (!IsOper(client))
|
|
{
|
|
sendnumeric(client, ERR_NOPRIVILEGES);
|
|
return;
|
|
}
|
|
|
|
sendtxtnumeric(client, "== Link Security Report ==");
|
|
|
|
sendtxtnumeric(client, "= By server =");
|
|
list_for_each_entry(acptr, &global_server_list, client_node)
|
|
{
|
|
v = -1;
|
|
s = moddata_client_get(acptr, "link-security");
|
|
if (s)
|
|
{
|
|
v = atoi(s);
|
|
sendtxtnumeric(client, "%s: level %d", acptr->name, v);
|
|
} else {
|
|
sendtxtnumeric(client, "%s: level UNKNOWN", acptr->name);
|
|
}
|
|
}
|
|
|
|
sendtxtnumeric(client, "-");
|
|
sendtxtnumeric(client, "= Network =");
|
|
sendtxtnumeric(client, "This results in an effective (network-wide) link-security of level %d", effective_link_security);
|
|
sendtxtnumeric(client, "-");
|
|
sendtxtnumeric(client, "= Legend =");
|
|
sendtxtnumeric(client, "Higher level means better link security");
|
|
sendtxtnumeric(client, "Level UNKNOWN: Not an UnrealIRCd server (eg: services) or an old version (<4.0.14)");
|
|
sendtxtnumeric(client, "Level 0: One or more servers linked insecurely (not using SSL/TLS)");
|
|
sendtxtnumeric(client, "Level 1: Servers are linked with SSL/TLS but at least one of them is not verifying certificates");
|
|
sendtxtnumeric(client, "Level 2: Servers linked with SSL/TLS and certificates are properly verified");
|
|
sendtxtnumeric(client, "-");
|
|
sendtxtnumeric(client, "= More information =");
|
|
sendtxtnumeric(client, "To understand more about link security and how to improve your level");
|
|
sendtxtnumeric(client, "see https://www.unrealircd.org/docs/Link_security");
|
|
}
|