unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
oper.c (12251B)
1 /* 2 * Unreal Internet Relay Chat Daemon, src/modules/oper.c 3 * (C) 2000-2001 Carsten V. Munk and the UnrealIRCd Team 4 * Moved to modules by Fish (Justin Hammond) 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 1, or (at your option) 9 * any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 */ 20 21 #include "unrealircd.h" 22 23 #define MSG_OPER "OPER" /* OPER */ 24 25 ModuleHeader MOD_HEADER 26 = { 27 "oper", /* Name of module */ 28 "5.0", /* Version */ 29 "command /oper", /* Short description of module */ 30 "UnrealIRCd Team", 31 "unrealircd-6", 32 }; 33 34 /* Forward declarations */ 35 CMD_FUNC(cmd_oper); 36 int _make_oper(Client *client, const char *operblock_name, const char *operclass, ConfigItem_class *clientclass, long modes, const char *snomask, const char *vhost); 37 int oper_connect(Client *client); 38 39 MOD_TEST() 40 { 41 MARK_AS_OFFICIAL_MODULE(modinfo); 42 EfunctionAdd(modinfo->handle, EFUNC_MAKE_OPER, _make_oper); 43 return MOD_SUCCESS; 44 } 45 46 MOD_INIT() 47 { 48 MARK_AS_OFFICIAL_MODULE(modinfo); 49 CommandAdd(modinfo->handle, MSG_OPER, cmd_oper, MAXPARA, CMD_USER); 50 HookAdd(modinfo->handle, HOOKTYPE_LOCAL_CONNECT, 0, oper_connect); 51 return MOD_SUCCESS; 52 } 53 54 MOD_LOAD() 55 { 56 return MOD_SUCCESS; 57 } 58 59 MOD_UNLOAD() 60 { 61 return MOD_SUCCESS; 62 } 63 64 void set_oper_host(Client *client, const char *host) 65 { 66 char uhost[HOSTLEN + USERLEN + 1]; 67 char *p; 68 69 if (!valid_vhost(host)) 70 return; 71 72 strlcpy(uhost, host, sizeof(uhost)); 73 74 if ((p = strchr(uhost, '@'))) 75 { 76 *p++ = '\0'; 77 strlcpy(client->user->username, uhost, sizeof(client->user->username)); 78 sendto_server(NULL, 0, 0, NULL, ":%s SETIDENT %s", 79 client->id, client->user->username); 80 host = p; 81 } 82 safe_strdup(client->user->virthost, host); 83 if (MyConnect(client)) 84 sendto_server(NULL, 0, 0, NULL, ":%s SETHOST :%s", client->id, client->user->virthost); 85 client->umodes |= UMODE_SETHOST|UMODE_HIDE; 86 } 87 88 int _make_oper(Client *client, const char *operblock_name, const char *operclass, ConfigItem_class *clientclass, long modes, const char *snomask, const char *vhost) 89 { 90 long old_umodes = client->umodes & ALL_UMODES; 91 92 userhost_save_current(client); 93 94 /* Put in the right class (if any) */ 95 if (clientclass) 96 { 97 if (client->local->class) 98 client->local->class->clients--; 99 client->local->class = clientclass; 100 client->local->class->clients++; 101 } 102 103 /* set oper user modes */ 104 client->umodes |= UMODE_OPER; 105 if (modes) 106 client->umodes |= modes; /* oper::modes */ 107 else 108 client->umodes |= OPER_MODES; /* set::modes-on-oper */ 109 110 /* oper::vhost */ 111 if (vhost) 112 { 113 set_oper_host(client, vhost); 114 } else 115 if (IsHidden(client) && !client->user->virthost) 116 { 117 /* +x has just been set by modes-on-oper and no vhost. cloak the oper! */ 118 safe_strdup(client->user->virthost, client->user->cloakedhost); 119 } 120 121 userhost_changed(client); 122 123 unreal_log(ULOG_INFO, "oper", "OPER_SUCCESS", client, 124 "$client.details is now an IRC Operator [oper-block: $oper_block] [operclass: $operclass]", 125 log_data_string("oper_block", operblock_name), 126 log_data_string("operclass", operclass)); 127 128 /* set oper snomasks */ 129 if (snomask) 130 set_snomask(client, snomask); /* oper::snomask */ 131 else 132 set_snomask(client, OPER_SNOMASK); /* set::snomask-on-oper */ 133 134 send_umode_out(client, 1, old_umodes); 135 if (client->user->snomask) 136 sendnumeric(client, RPL_SNOMASK, client->user->snomask); 137 138 list_add(&client->special_node, &oper_list); 139 140 RunHook(HOOKTYPE_LOCAL_OPER, client, 1, operblock_name, operclass); 141 142 sendnumeric(client, RPL_YOUREOPER); 143 144 /* Update statistics */ 145 if (IsInvisible(client) && !(old_umodes & UMODE_INVISIBLE)) 146 irccounts.invisible++; 147 if (IsOper(client) && !IsHideOper(client)) 148 irccounts.operators++; 149 150 if (SHOWOPERMOTD == 1) 151 { 152 const char *args[1] = { NULL }; 153 do_cmd(client, NULL, "OPERMOTD", 1, args); 154 } 155 156 if (!BadPtr(OPER_AUTO_JOIN_CHANS) && strcmp(OPER_AUTO_JOIN_CHANS, "0")) 157 { 158 char *chans = strdup(OPER_AUTO_JOIN_CHANS); 159 const char *args[3] = { 160 client->name, 161 chans, 162 NULL 163 }; 164 do_cmd(client, NULL, "JOIN", 3, args); 165 safe_free(chans); 166 /* Theoretically the oper may be killed on join. Would be fun, though */ 167 if (IsDead(client)) 168 return 0; 169 } 170 171 return 1; 172 } 173 174 /* 175 ** cmd_oper 176 ** parv[1] = oper name 177 ** parv[2] = oper password 178 */ 179 CMD_FUNC(cmd_oper) 180 { 181 ConfigItem_oper *operblock; 182 const char *operblock_name, *password; 183 184 if (!MyUser(client)) 185 return; 186 187 if ((parc < 2) || BadPtr(parv[1])) 188 { 189 sendnumeric(client, ERR_NEEDMOREPARAMS, "OPER"); 190 return; 191 } 192 193 if (SVSNOOP) 194 { 195 sendnotice(client, 196 "*** This server is in NOOP mode, you cannot /oper"); 197 return; 198 } 199 200 if (IsOper(client)) 201 { 202 sendnotice(client, "You are already an IRC Operator. If you want to re-oper then de-oper first via /MODE yournick -o"); 203 return; 204 } 205 206 operblock_name = parv[1]; 207 password = (parc > 2) ? parv[2] : ""; 208 209 /* set::plaintext-policy::oper 'deny' */ 210 if (!IsSecure(client) && !IsLocalhost(client) && (iConf.plaintext_policy_oper == POLICY_DENY)) 211 { 212 sendnotice_multiline(client, iConf.plaintext_policy_oper_message); 213 unreal_log(ULOG_WARNING, "oper", "OPER_FAILED", client, 214 "Failed OPER attempt by $client.details [reason: $reason] [oper-block: $oper_block]", 215 log_data_string("reason", "Not using TLS"), 216 log_data_string("fail_type", "NO_TLS"), 217 log_data_string("oper_block", parv[1])); 218 add_fake_lag(client, 7000); 219 return; 220 } 221 222 /* set::outdated-tls-policy::oper 'deny' */ 223 if (IsSecure(client) && (iConf.outdated_tls_policy_oper == POLICY_DENY) && outdated_tls_client(client)) 224 { 225 sendnotice(client, "%s", outdated_tls_client_build_string(iConf.outdated_tls_policy_oper_message, client)); 226 unreal_log(ULOG_WARNING, "oper", "OPER_FAILED", client, 227 "Failed OPER attempt by $client.details [reason: $reason] [oper-block: $oper_block]", 228 log_data_string("reason", "Outdated TLS protocol or cipher"), 229 log_data_string("fail_type", "OUTDATED_TLS_PROTOCOL_OR_CIPHER"), 230 log_data_string("oper_block", parv[1])); 231 add_fake_lag(client, 7000); 232 return; 233 } 234 235 if (!(operblock = find_oper(operblock_name))) 236 { 237 sendnumeric(client, ERR_NOOPERHOST); 238 unreal_log(ULOG_WARNING, "oper", "OPER_FAILED", client, 239 "Failed OPER attempt by $client.details [reason: $reason] [oper-block: $oper_block]", 240 log_data_string("reason", "Unknown oper operblock_name"), 241 log_data_string("fail_type", "UNKNOWN_OPER_NAME"), 242 log_data_string("oper_block", parv[1])); 243 add_fake_lag(client, 7000); 244 return; 245 } 246 247 /* Below here, the oper block exists, any errors here we take (even) 248 * more seriously, they are logged as errors instead of warnings. 249 */ 250 251 if (!user_allowed_by_security_group(client, operblock->match)) 252 { 253 sendnumeric(client, ERR_NOOPERHOST); 254 unreal_log(ULOG_ERROR, "oper", "OPER_FAILED", client, 255 "Failed OPER attempt by $client.details [reason: $reason] [oper-block: $oper_block]", 256 log_data_string("reason", "Host does not match"), 257 log_data_string("fail_type", "NO_HOST_MATCH"), 258 log_data_string("oper_block", parv[1])); 259 add_fake_lag(client, 7000); 260 return; 261 } 262 263 if (operblock->auth && !Auth_Check(client, operblock->auth, password)) 264 { 265 sendnumeric(client, ERR_PASSWDMISMATCH); 266 if (FAILOPER_WARN) 267 sendnotice(client, 268 "*** Your attempt has been logged."); 269 unreal_log(ULOG_ERROR, "oper", "OPER_FAILED", client, 270 "Failed OPER attempt by $client.details [reason: $reason] [oper-block: $oper_block]", 271 log_data_string("reason", "Authentication failed"), 272 log_data_string("fail_type", "AUTHENTICATION_FAILED"), 273 log_data_string("oper_block", parv[1])); 274 add_fake_lag(client, 7000); 275 return; 276 } 277 278 /* Authentication of the oper succeeded (like, password, ssl cert), 279 * but we still have some other restrictions to check below as well, 280 * like 'require-modes' and 'maxlogins'... 281 */ 282 283 /* Check oper::require_modes */ 284 if (operblock->require_modes & ~client->umodes) 285 { 286 sendnumericfmt(client, ERR_NOOPERHOST, ":You are missing user modes required to OPER"); 287 unreal_log(ULOG_WARNING, "oper", "OPER_FAILED", client, 288 "Failed OPER attempt by $client.details [reason: $reason] [oper-block: $oper_block]", 289 log_data_string("reason", "Not matching oper::require-modes"), 290 log_data_string("fail_type", "REQUIRE_MODES_NOT_SATISFIED"), 291 log_data_string("oper_block", parv[1])); 292 add_fake_lag(client, 7000); 293 return; 294 } 295 296 if (!find_operclass(operblock->operclass)) 297 { 298 sendnotice(client, "ERROR: There is a non-existant oper::operclass specified for your oper block"); 299 unreal_log(ULOG_WARNING, "oper", "OPER_FAILED", client, 300 "Failed OPER attempt by $client.details [reason: $reason] [oper-block: $oper_block]", 301 log_data_string("reason", "Config error: invalid oper::operclass"), 302 log_data_string("fail_type", "OPER_OPERCLASS_INVALID"), 303 log_data_string("oper_block", parv[1])); 304 return; 305 } 306 307 if (operblock->maxlogins && (count_oper_sessions(operblock->name) >= operblock->maxlogins)) 308 { 309 sendnumeric(client, ERR_NOOPERHOST); 310 sendnotice(client, "Your maximum number of concurrent oper logins has been reached (%d)", 311 operblock->maxlogins); 312 unreal_log(ULOG_WARNING, "oper", "OPER_FAILED", client, 313 "Failed OPER attempt by $client.details [reason: $reason] [oper-block: $oper_block]", 314 log_data_string("reason", "oper::maxlogins limit reached"), 315 log_data_string("fail_type", "OPER_MAXLOGINS_LIMIT"), 316 log_data_string("oper_block", parv[1])); 317 add_fake_lag(client, 4000); 318 return; 319 } 320 321 /* /OPER really succeeded now. Start processing it. */ 322 323 /* Store which oper block was used to become IRCOp (for maxlogins and whois) */ 324 safe_strdup(client->user->operlogin, operblock->name); 325 326 /* oper::swhois */ 327 if (operblock->swhois) 328 { 329 SWhois *s; 330 for (s = operblock->swhois; s; s = s->next) 331 swhois_add(client, "oper", -100, s->line, &me, NULL); 332 } 333 334 make_oper(client, operblock->name, operblock->operclass, operblock->class, operblock->modes, operblock->snomask, operblock->vhost); 335 336 /* set::plaintext-policy::oper 'warn' */ 337 if (!IsSecure(client) && !IsLocalhost(client) && (iConf.plaintext_policy_oper == POLICY_WARN)) 338 { 339 sendnotice_multiline(client, iConf.plaintext_policy_oper_message); 340 unreal_log(ULOG_WARNING, "oper", "OPER_UNSAFE", client, 341 "Insecure (non-TLS) connection used to OPER up by $client.details [oper-block: $oper_block]", 342 log_data_string("oper_block", parv[1]), 343 log_data_string("warn_type", "NO_TLS")); 344 } 345 346 /* set::outdated-tls-policy::oper 'warn' */ 347 if (IsSecure(client) && (iConf.outdated_tls_policy_oper == POLICY_WARN) && outdated_tls_client(client)) 348 { 349 sendnotice(client, "%s", outdated_tls_client_build_string(iConf.outdated_tls_policy_oper_message, client)); 350 unreal_log(ULOG_WARNING, "oper", "OPER_UNSAFE", client, 351 "Outdated TLS protocol/cipher used to OPER up by $client.details [oper-block: $oper_block]", 352 log_data_string("oper_block", parv[1]), 353 log_data_string("warn_type", "OUTDATED_TLS_PROTOCOL_OR_CIPHER")); 354 } 355 } 356 357 int oper_connect(Client *client) 358 { 359 ConfigItem_oper *e; 360 361 if (IsOper(client)) 362 return 0; 363 364 for (e = conf_oper; e; e = e->next) 365 { 366 if (e->auto_login && user_allowed_by_security_group(client, e->match)) 367 { 368 /* Ideally we would check all the criteria that cmd_oper does. 369 * I'm taking a shortcut for now that is not ideal... 370 */ 371 const char *parx[3]; 372 parx[0] = NULL; 373 parx[1] = e->name; 374 parx[2] = NULL; 375 do_cmd(client, NULL, "OPER", 3, parx); 376 return 0; 377 } 378 } 379 380 return 0; 381 }