unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
link-security.c (8408B)
1 /* 2 * IRC - Internet Relay Chat, src/modules/link-security.c 3 * (C) 2017 Syzop & The UnrealIRCd Team 4 * 5 * See file AUTHORS in IRC package for additional names of 6 * the programmers. 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 1, or (at your option) 11 * any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 */ 22 23 #include "unrealircd.h" 24 25 /* Module header */ 26 ModuleHeader MOD_HEADER 27 = { 28 "link-security", 29 "5.0", 30 "Link Security CAP", 31 "UnrealIRCd Team", 32 "unrealircd-6", 33 }; 34 35 /* Forward declarations */ 36 const char *link_security_md_serialize(ModData *m); 37 void link_security_md_unserialize(const char *str, ModData *m); 38 EVENT(checklinksec); 39 const char *link_security_capability_parameter(Client *client); 40 CMD_FUNC(cmd_linksecurity); 41 42 /* Global variables */ 43 ModDataInfo *link_security_md; 44 int local_link_security = -1; 45 int global_link_security = -1; 46 int effective_link_security = -1; 47 48 /** Module initalization */ 49 MOD_INIT() 50 { 51 ModDataInfo mreq; 52 53 MARK_AS_OFFICIAL_MODULE(modinfo); 54 ModuleSetOptions(modinfo->handle, MOD_OPT_PERM_RELOADABLE, 1); 55 56 memset(&mreq, 0, sizeof(mreq)); 57 mreq.name = "link-security"; 58 mreq.type = MODDATATYPE_CLIENT; 59 mreq.serialize = link_security_md_serialize; 60 mreq.unserialize = link_security_md_unserialize; 61 mreq.sync = 1; 62 mreq.self_write = 1; 63 link_security_md = ModDataAdd(modinfo->handle, mreq); 64 if (!link_security_md) 65 { 66 config_error("Unable to ModDataAdd() -- too many 3rd party modules loaded perhaps?"); 67 abort(); 68 } 69 70 CommandAdd(modinfo->handle, "LINKSECURITY", cmd_linksecurity, MAXPARA, CMD_USER); 71 72 return MOD_SUCCESS; 73 } 74 75 MOD_LOAD() 76 { 77 ClientCapabilityInfo cap; 78 79 memset(&cap, 0, sizeof(cap)); 80 cap.name = "unrealircd.org/link-security"; 81 cap.flags = CLICAP_FLAGS_ADVERTISE_ONLY; 82 cap.parameter = link_security_capability_parameter; 83 ClientCapabilityAdd(modinfo->handle, &cap, NULL); 84 85 EventAdd(modinfo->handle, "checklinksec", checklinksec, NULL, 2000, 0); 86 checklinksec(NULL); 87 return MOD_SUCCESS; 88 } 89 90 MOD_UNLOAD() 91 { 92 return MOD_SUCCESS; 93 } 94 95 /* Magic value to differentiate between "not set" and "zero". 96 * Only used for internal moddata storage, not exposed 97 * outside these two functions. 98 */ 99 #define LNKSECMAGIC 100 100 101 const char *link_security_md_serialize(ModData *m) 102 { 103 static char buf[32]; 104 if (m->i == 0) 105 return NULL; /* not set */ 106 snprintf(buf, sizeof(buf), "%d", m->i - LNKSECMAGIC); 107 return buf; 108 } 109 110 void link_security_md_unserialize(const char *str, ModData *m) 111 { 112 m->i = atoi(str) + LNKSECMAGIC; 113 } 114 115 /** Return 1 if the server certificate is verified for 116 * server 'client', return 0 if not. 117 */ 118 int certificate_verification_active(Client *client) 119 { 120 ConfigItem_link *conf; 121 122 if (!client->server || !client->server->conf) 123 return 0; /* wtf? */ 124 conf = client->server->conf; 125 126 if (conf->verify_certificate) 127 return 1; /* yes, verify-certificate is 'yes' */ 128 129 if ((conf->auth->type == AUTHTYPE_TLS_CLIENTCERT) || 130 (conf->auth->type == AUTHTYPE_TLS_CLIENTCERTFP) || 131 (conf->auth->type == AUTHTYPE_SPKIFP)) 132 { 133 /* yes, verified by link::password being a 134 * certificate fingerprint or certificate file. 135 */ 136 return 1; 137 } 138 139 return 0; /* no, certificate is not verified in any way */ 140 } 141 142 /** Calculate our (local) link-security level. 143 * This means stepping through the list of directly linked 144 * servers and determining if they are linked via TLS and 145 * certificate verification is active. 146 * @returns value from 0 to 2. 147 */ 148 int our_link_security(void) 149 { 150 Client *client; 151 int level = 2; /* safest */ 152 153 list_for_each_entry(client, &server_list, special_node) 154 { 155 if (IsLocalhost(client)) 156 continue; /* server connected via localhost */ 157 if (!IsSecure(client)) 158 return 0; /* Any non-TLS server (which is not localhost) results in level 0. */ 159 if (!certificate_verification_active(client)) 160 level = 1; /* downgrade to level 1 */ 161 } 162 163 return level; 164 } 165 166 char *valtostr(int i) 167 { 168 static char buf[32]; 169 snprintf(buf, sizeof(buf), "%d", i); 170 return buf; 171 } 172 173 /** Check link security. This is called every X seconds to see if there 174 * is a change, either local or network-wide. 175 */ 176 EVENT(checklinksec) 177 { 178 int last_local_link_security = local_link_security; 179 int last_global_link_security = global_link_security; 180 Client *client; 181 int v; 182 int warning_sent = 0; 183 184 local_link_security = our_link_security(); 185 if (local_link_security != last_local_link_security) 186 { 187 /* Our own link-security changed (for better or worse), 188 * Set and broadcast it immediately to the other servers. 189 */ 190 moddata_client_set(&me, "link-security", valtostr(local_link_security)); 191 } 192 193 global_link_security = 2; 194 list_for_each_entry(client, &global_server_list, client_node) 195 { 196 const char *s = moddata_client_get(client, "link-security"); 197 if (s) 198 { 199 v = atoi(s); 200 if (v == 0) 201 { 202 global_link_security = 0; 203 break; 204 } 205 if (v == 1) 206 global_link_security = 1; 207 } 208 } 209 210 if (local_link_security < last_local_link_security) 211 { 212 unreal_log(ULOG_INFO, "link-security", "LOCAL_LINK_SECURITY_DOWNGRADED", NULL, 213 "Local link-security downgraded from level $previous_level to $new_level due to just linked in server(s)", 214 log_data_integer("previous_level", last_local_link_security), 215 log_data_integer("new_level", local_link_security)); 216 warning_sent = 1; 217 } 218 219 if (global_link_security < last_global_link_security) 220 { 221 unreal_log(ULOG_INFO, "link-security", "GLOBAL_LINK_SECURITY_DOWNGRADED", NULL, 222 "Global link-security downgraded from level $previous_level to $new_level due to just linked in server(s)", 223 log_data_integer("previous_level", last_global_link_security), 224 log_data_integer("new_level", global_link_security)); 225 warning_sent = 1; 226 } 227 228 effective_link_security = MIN(local_link_security, global_link_security); 229 230 if (warning_sent) 231 { 232 unreal_log(ULOG_INFO, "link-security", "EFFECTIVE_LINK_SECURITY_REPORT", NULL, 233 "Effective (network-wide) link-security is now: level $effective_link_security\n" 234 "More information about this can be found at https://www.unrealircd.org/docs/Link_security", 235 log_data_integer("effective_link_security", effective_link_security)); 236 } 237 } 238 239 const char *link_security_capability_parameter(Client *client) 240 { 241 return valtostr(effective_link_security); 242 } 243 244 /** /LINKSECURITY command */ 245 CMD_FUNC(cmd_linksecurity) 246 { 247 Client *acptr; 248 249 if (!IsOper(client)) 250 { 251 sendnumeric(client, ERR_NOPRIVILEGES); 252 return; 253 } 254 255 sendtxtnumeric(client, "== Link Security Report =="); 256 257 sendtxtnumeric(client, "= By server ="); 258 list_for_each_entry(acptr, &global_server_list, client_node) 259 { 260 const char *s = moddata_client_get(acptr, "link-security"); 261 if (s) 262 sendtxtnumeric(client, "%s: level %d", acptr->name, atoi(s)); 263 else 264 sendtxtnumeric(client, "%s: level UNKNOWN", acptr->name); 265 } 266 267 sendtxtnumeric(client, "-"); 268 sendtxtnumeric(client, "= Network ="); 269 sendtxtnumeric(client, "This results in an effective (network-wide) link-security of level %d", effective_link_security); 270 sendtxtnumeric(client, "-"); 271 sendtxtnumeric(client, "= Legend ="); 272 sendtxtnumeric(client, "Higher level means better link security"); 273 sendtxtnumeric(client, "Level UNKNOWN: Not an UnrealIRCd server (eg: services) or an old version (<4.0.14)"); 274 sendtxtnumeric(client, "Level 0: One or more servers linked insecurely (not using TLS)"); 275 sendtxtnumeric(client, "Level 1: Servers are linked with TLS but at least one of them is not verifying certificates"); 276 sendtxtnumeric(client, "Level 2: Servers linked with TLS and certificates are properly verified"); 277 sendtxtnumeric(client, "-"); 278 sendtxtnumeric(client, "= More information ="); 279 sendtxtnumeric(client, "To understand more about link security and how to improve your level"); 280 sendtxtnumeric(client, "see https://www.unrealircd.org/docs/Link_security"); 281 }