unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
nick.c (40135B)
1 /* 2 * IRC - Internet Relay Chat, src/modules/nick.c 3 * (C) 1999-2005 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 ModuleHeader MOD_HEADER 26 = { 27 "nick", 28 "5.0", 29 "command /nick", 30 "UnrealIRCd Team", 31 "unrealircd-6", 32 }; 33 34 /* Defines */ 35 36 #define NICKCOL_EQUAL 0 37 #define NICKCOL_NEW_WON 1 38 #define NICKCOL_EXISTING_WON 2 39 40 /* Assume that on collision a NICK is in flight and the other server will take 41 * the exact same decision we would do, and thus we don't send a KILL to cptr? 42 * This works great with this code, seems to kill the correct person and not 43 * cause desyncs even without UID/SID. HOWEVER.. who knows what code the other servers run? 44 * Should use UID/SID anyway, then this whole problem doesn't exist. 45 */ 46 #define ASSUME_NICK_IN_FLIGHT 47 48 /* Variables */ 49 static char spamfilter_user[NICKLEN + USERLEN + HOSTLEN + REALLEN + 64]; 50 51 /* Forward declarations */ 52 CMD_FUNC(cmd_nick); 53 CMD_FUNC(cmd_nick_local); 54 CMD_FUNC(cmd_nick_remote); 55 CMD_FUNC(cmd_uid); 56 int _register_user(Client *client); 57 void nick_collision(Client *cptr, const char *newnick, const char *newid, Client *new, Client *existing, int type); 58 int AllowClient(Client *client); 59 60 MOD_TEST() 61 { 62 MARK_AS_OFFICIAL_MODULE(modinfo); 63 EfunctionAdd(modinfo->handle, EFUNC_REGISTER_USER, _register_user); 64 return MOD_SUCCESS; 65 } 66 67 MOD_INIT() 68 { 69 CommandAdd(modinfo->handle, "NICK", cmd_nick, MAXPARA, CMD_USER|CMD_SERVER|CMD_UNREGISTERED); 70 CommandAdd(modinfo->handle, "UID", cmd_uid, MAXPARA, CMD_SERVER); 71 MARK_AS_OFFICIAL_MODULE(modinfo); 72 return MOD_SUCCESS; 73 } 74 75 MOD_LOAD() 76 { 77 return MOD_SUCCESS; 78 } 79 80 MOD_UNLOAD() 81 { 82 return MOD_SUCCESS; 83 } 84 85 /** Hmm.. don't we already have such a function? */ 86 void set_user_modes_dont_spread(Client *client, const char *umode) 87 { 88 const char *args[4]; 89 90 args[0] = client->name; 91 args[1] = client->name; 92 args[2] = umode; 93 args[3] = NULL; 94 95 dontspread = 1; 96 do_cmd(client, NULL, "MODE", 3, args); 97 dontspread = 0; 98 } 99 100 /** Remote client (already fully registered) changing their nick */ 101 CMD_FUNC(cmd_nick_remote) 102 { 103 TKL *tklban; 104 int ishold; 105 Client *acptr; 106 char nick[NICKLEN + 2]; 107 char oldnick[NICKLEN + 1]; 108 time_t lastnick = 0; 109 int differ = 1; 110 unsigned char removemoder = (client->umodes & UMODE_REGNICK) ? 1 : 0; 111 MessageTag *mtags = NULL; 112 113 /* 'client' is always the fully registered user doing the nick change */ 114 115 strlcpy(nick, parv[1], NICKLEN + 1); 116 strlcpy(oldnick, client->name, sizeof(oldnick)); 117 118 if (parc > 2) 119 lastnick = atol(parv[2]); 120 121 if (!do_remote_nick_name(nick) || !strcasecmp("ircd", nick) || !strcasecmp("irc", nick)) 122 { 123 ircstats.is_kill++; 124 unreal_log(ULOG_ERROR, "nick", "BAD_NICK_REMOTE", client, 125 "Server link $server tried to change '$client' to bad nick '$nick' -- rejected.", 126 log_data_string("nick", parv[1]), 127 log_data_client("server", client->uplink)); 128 mtags = NULL; 129 new_message(client, NULL, &mtags); 130 sendto_one(client, mtags, ":%s KILL %s :Illegal nick name", me.id, client->id); 131 SetKilled(client); 132 exit_client(client, mtags, "Illegal nick name"); 133 free_message_tags(mtags); 134 mtags = NULL; 135 return; 136 } 137 138 /* Check Q-lines / ban nick */ 139 if (!IsULine(client) && (tklban = find_qline(client, nick, &ishold)) && !ishold) 140 { 141 unreal_log(ULOG_INFO, "nick", "QLINE_NICK_REMOTE", client, 142 "Banned nick $nick [$ip] from server $server ($reason)", 143 log_data_string("nick", parv[1]), 144 log_data_string("ip", GetIP(client)), 145 log_data_client("server", client->uplink), 146 log_data_string("reason", tklban->ptr.nameban->reason)); 147 /* Let it through */ 148 } 149 150 if ((acptr = find_client(nick, NULL))) 151 { 152 /* If existing nick is still in handshake, kill it */ 153 if (IsUnknown(acptr) && MyConnect(acptr)) 154 { 155 SetKilled(acptr); 156 exit_client(acptr, NULL, "Overridden"); 157 } else 158 if (acptr == client) 159 { 160 /* 100% identical? Must be a bug, but ok */ 161 if (!strcmp(acptr->name, nick)) 162 return; 163 /* Allows change of case in their nick */ 164 removemoder = 0; /* don't set the user -r */ 165 } else 166 { 167 /* 168 ** A NICK change has collided (e.g. message type ":old NICK new"). 169 */ 170 differ = (mycmp(acptr->user->username, client->user->username) || 171 mycmp(acptr->user->realhost, client->user->realhost)); 172 173 if (!(parc > 2) || lastnick == acptr->lastnick) 174 { 175 nick_collision(client, parv[1], client->id, client, acptr, NICKCOL_EQUAL); 176 return; /* Now that I killed them both, ignore the NICK */ 177 } else 178 if ((differ && (acptr->lastnick > lastnick)) || 179 (!differ && (acptr->lastnick < lastnick))) 180 { 181 nick_collision(client, parv[1], client->id, client, acptr, NICKCOL_NEW_WON); 182 /* fallthrough: their user won, continue and proceed with the nick change */ 183 } else 184 if ((differ && (acptr->lastnick < lastnick)) || 185 (!differ && (acptr->lastnick > lastnick))) 186 { 187 nick_collision(client, parv[1], client->id, client, acptr, NICKCOL_EXISTING_WON); 188 return; /* their user lost, ignore the NICK */ 189 } else 190 { 191 return; /* just in case */ 192 } 193 } 194 } 195 196 mtags = NULL; 197 198 if (!IsULine(client)) 199 { 200 unreal_log(ULOG_INFO, "nick", "REMOTE_NICK_CHANGE", client, 201 "Client $client.details has changed their nickname to $new_nick", 202 log_data_string("new_nick", nick)); 203 } 204 205 new_message(client, recv_mtags, &mtags); 206 RunHook(HOOKTYPE_REMOTE_NICKCHANGE, client, mtags, nick); 207 client->lastnick = lastnick ? lastnick : TStime(); 208 add_history(client, 1, WHOWAS_EVENT_NICK_CHANGE); 209 sendto_server(client, 0, 0, mtags, ":%s NICK %s %lld", 210 client->id, nick, (long long)client->lastnick); 211 sendto_local_common_channels(client, client, 0, mtags, ":%s NICK :%s", client->name, nick); 212 if (removemoder) 213 client->umodes &= ~UMODE_REGNICK; 214 215 /* Finally set new nick name. */ 216 del_from_client_hash_table(client->name, client); 217 strlcpy(client->name, nick, sizeof(client->name)); 218 add_to_client_hash_table(nick, client); 219 220 RunHook(HOOKTYPE_POST_REMOTE_NICKCHANGE, client, mtags, oldnick); 221 free_message_tags(mtags); 222 } 223 224 /* Local user: either setting their nick for the first time (registration) 225 * or changing their nick (fully registered already, or not) 226 */ 227 CMD_FUNC(cmd_nick_local) 228 { 229 TKL *tklban; 230 int ishold; 231 Client *acptr; 232 char nick[NICKLEN + 2]; 233 char oldnick[NICKLEN + 1]; 234 char descbuf[BUFSIZE]; 235 Membership *mp; 236 int newuser = 0; 237 unsigned char removemoder = (client->umodes & UMODE_REGNICK) ? 1 : 0; 238 Hook *h; 239 int ret; 240 241 strlcpy(oldnick, client->name, sizeof(oldnick)); 242 243 /* Enforce minimum nick length */ 244 if (iConf.min_nick_length && !IsOper(client) && !IsULine(client) && strlen(parv[1]) < iConf.min_nick_length) 245 { 246 snprintf(descbuf, sizeof descbuf, "A minimum length of %d chars is required", iConf.min_nick_length); 247 sendnumeric(client, ERR_ERRONEUSNICKNAME, parv[1], descbuf); 248 return; 249 } 250 251 /* Enforce maximum nick length */ 252 strlcpy(nick, parv[1], iConf.nick_length + 1); 253 254 /* Check if this is a valid nick name */ 255 if (!do_nick_name(nick)) 256 { 257 sendnumeric(client, ERR_ERRONEUSNICKNAME, parv[1], "Illegal characters"); 258 return; 259 } 260 261 /* Check for collisions / in use */ 262 if (!strcasecmp("ircd", nick) || !strcasecmp("irc", nick)) 263 { 264 sendnumeric(client, ERR_ERRONEUSNICKNAME, nick, "Reserved for internal IRCd purposes"); 265 return; 266 } 267 268 if (MyUser(client)) 269 { 270 /* Local client changing nick: check spamfilter */ 271 spamfilter_build_user_string(spamfilter_user, nick, client); 272 if (match_spamfilter(client, spamfilter_user, SPAMF_USER, "NICK", NULL, 0, NULL)) 273 return; 274 } 275 276 /* Check Q-lines / ban nick */ 277 if (!IsULine(client) && (tklban = find_qline(client, nick, &ishold))) 278 { 279 if (ishold) 280 { 281 sendnumeric(client, ERR_ERRONEUSNICKNAME, nick, tklban->ptr.nameban->reason); 282 return; 283 } 284 if (!ValidatePermissionsForPath("immune:server-ban:ban-nick",client,NULL,NULL,nick)) 285 { 286 add_fake_lag(client, 4000); /* lag them up */ 287 sendnumeric(client, ERR_ERRONEUSNICKNAME, nick, tklban->ptr.nameban->reason); 288 unreal_log(ULOG_INFO, "nick", "QLINE_NICK_LOCAL_ATTEMPT", client, 289 "Attempt to use banned nick $nick [$ip] blocked ($reason)", 290 log_data_string("nick", parv[1]), 291 log_data_string("ip", GetIP(client)), 292 log_data_client("server", client->uplink), 293 log_data_string("reason", tklban->ptr.nameban->reason)); 294 return; /* NICK message ignored */ 295 } 296 /* fallthrough for ircops that have sufficient privileges */ 297 } 298 299 if (!ValidatePermissionsForPath("immune:nick-flood",client,NULL,NULL,NULL)) 300 add_fake_lag(client, 3000); 301 302 if ((acptr = find_client(nick, NULL))) 303 { 304 /* Shouldn't be possible since dot is disallowed: */ 305 if (IsServer(acptr)) 306 { 307 sendnumeric(client, ERR_NICKNAMEINUSE, nick); 308 return; 309 } 310 if (acptr == client) 311 { 312 /* New nick is exactly the same as the old nick? */ 313 if (!strcmp(acptr->name, nick)) 314 return; 315 /* Changing cAsE */ 316 removemoder = 0; 317 } else 318 /* Collision with a nick of a session that is still in handshake */ 319 if (IsUnknown(acptr) && MyConnect(acptr)) 320 { 321 /* Kill the other connection that is still in progress */ 322 SetKilled(acptr); 323 exit_client(acptr, NULL, "Overridden"); 324 } else 325 { 326 sendnumeric(client, ERR_NICKNAMEINUSE, nick); 327 return; /* NICK message ignored */ 328 } 329 } 330 331 /* set::anti-flood::nick-flood */ 332 if (client->user && 333 !ValidatePermissionsForPath("immune:nick-flood",client,NULL,NULL,NULL) && 334 flood_limit_exceeded(client, FLD_NICK)) 335 { 336 /* Throttle... */ 337 sendnumeric(client, ERR_NCHANGETOOFAST, nick); 338 return; 339 } 340 341 /* New local client? */ 342 if (!client->name[0]) 343 { 344 newuser = 1; 345 346 if (iConf.ping_cookie) 347 { 348 /* 349 * Client setting NICK the first time. 350 * 351 * Generate a random string for them to pong with. 352 */ 353 client->local->nospoof = getrandom32(); 354 355 sendto_one(client, NULL, "PING :%X", client->local->nospoof); 356 } 357 358 /* Copy password to the passwd field if it's given after NICK */ 359 if ((parc > 2) && (strlen(parv[2]) <= PASSWDLEN)) 360 safe_strdup(client->local->passwd, parv[2]); 361 362 /* This had to be copied here to avoid problems.. */ 363 strlcpy(client->name, nick, sizeof(client->name)); 364 365 /* Let's see if we can get online now... */ 366 if (is_handshake_finished(client)) 367 { 368 /* Send a CTCP VERSION */ 369 if (!iConf.ping_cookie && USE_BAN_VERSION && MyConnect(client)) 370 sendto_one(client, NULL, ":IRC!IRC@%s PRIVMSG %s :\1VERSION\1", me.name, nick); 371 372 client->lastnick = TStime(); 373 if (!register_user(client)) 374 { 375 if (IsDead(client)) 376 return; 377 /* ..otherwise.. fallthrough so we run the same code 378 * as in case of !is_handshake_finished() 379 */ 380 } else { 381 /* New user! */ 382 strlcpy(nick, client->name, sizeof(nick)); /* don't ask, but I need this. do not remove! -- Syzop */ 383 } 384 } 385 } else 386 if (MyUser(client)) 387 { 388 MessageTag *mtags = NULL; 389 int ret; 390 391 /* Existing client nick-changing */ 392 393 /* 394 ** If the client belongs to me, then check to see 395 ** if client is currently on any channels where it 396 ** is currently banned. If so, do not allow the nick 397 ** change to occur. 398 ** Also set 'lastnick' to current time, if changed. 399 */ 400 for (mp = client->user->channel; mp; mp = mp->next) 401 { 402 int ret = HOOK_CONTINUE; 403 Hook *h; 404 if (!check_channel_access(client, mp->channel, "hoaq") && is_banned(client, mp->channel, BANCHK_NICK, NULL, NULL)) 405 { 406 sendnumeric(client, ERR_BANNICKCHANGE, 407 mp->channel->name); 408 return; 409 } 410 if (CHECK_TARGET_NICK_BANS && !check_channel_access(client, mp->channel, "hoaq") && is_banned_with_nick(client, mp->channel, BANCHK_NICK, nick, NULL, NULL)) 411 { 412 sendnumeric(client, ERR_BANNICKCHANGE, mp->channel->name); 413 return; 414 } 415 416 for (h = Hooks[HOOKTYPE_CHAN_PERMIT_NICK_CHANGE]; h; h = h->next) 417 { 418 ret = (*(h->func.intfunc))(client,mp->channel); 419 if (ret != HOOK_CONTINUE) 420 break; 421 } 422 423 if (ret == HOOK_DENY) 424 { 425 sendnumeric(client, ERR_NONICKCHANGE, mp->channel->name); 426 return; 427 } 428 } 429 430 unreal_log(ULOG_INFO, "nick", "LOCAL_NICK_CHANGE", client, 431 "Client $client.details has changed their nickname to $new_nick", 432 log_data_string("new_nick", nick)); 433 434 new_message(client, recv_mtags, &mtags); 435 RunHook(HOOKTYPE_LOCAL_NICKCHANGE, client, mtags, nick); 436 add_history(client, 1, WHOWAS_EVENT_NICK_CHANGE); 437 client->lastnick = TStime(); /* needs to be done AFTER add_history() */ 438 sendto_server(client, 0, 0, mtags, ":%s NICK %s %lld", 439 client->id, nick, (long long)client->lastnick); 440 sendto_local_common_channels(client, client, 0, mtags, ":%s NICK :%s", client->name, nick); 441 sendto_one(client, mtags, ":%s NICK :%s", client->name, nick); 442 free_message_tags(mtags); 443 if (removemoder) 444 client->umodes &= ~UMODE_REGNICK; 445 } else 446 { 447 /* Someone changing nicks in the pre-registered phase */ 448 } 449 450 del_from_client_hash_table(client->name, client); 451 452 strlcpy(client->name, nick, sizeof(client->name)); 453 add_to_client_hash_table(nick, client); 454 455 /* update fdlist --nenolod */ 456 snprintf(descbuf, sizeof(descbuf), "Client: %s", nick); 457 fd_desc(client->local->fd, descbuf); 458 459 if (removemoder && MyUser(client)) 460 sendto_one(client, NULL, ":%s MODE %s :-r", me.name, client->name); 461 462 if (MyUser(client) && !newuser) 463 RunHook(HOOKTYPE_POST_LOCAL_NICKCHANGE, client, recv_mtags, oldnick); 464 } 465 466 /* 467 ** cmd_uid 468 ** parv[1] = nickname 469 ** parv[2] = hopcount 470 ** parv[3] = timestamp 471 ** parv[4] = username 472 ** parv[5] = hostname 473 ** parv[6] = UID 474 ** parv[7] = account name (SVID) 475 ** parv[8] = umodes 476 ** parv[9] = virthost, * if none 477 ** parv[10] = cloaked host, * if none 478 ** parv[11] = ip 479 ** parv[12] = info 480 ** 481 ** Technical documentation is available at: 482 ** https://www.unrealircd.org/docs/Server_protocol:UID_command 483 */ 484 CMD_FUNC(cmd_uid) 485 { 486 TKL *tklban; 487 int ishold; 488 Client *acptr, *serv = NULL; 489 Client *acptrs; 490 char nick[NICKLEN + 1]; 491 char buf[BUFSIZE]; 492 long lastnick = 0; 493 int differ = 1; 494 const char *hostname, *username, *sstamp, *umodes, *virthost, *ip_raw, *realname; 495 const char *ip = NULL; 496 497 if (parc < 13) 498 { 499 sendnumeric(client, ERR_NEEDMOREPARAMS, "UID"); 500 return; 501 } 502 503 /* It's not just the directly attached client which must be a 504 * server. The source itself needs to be a server. 505 */ 506 if (!IsServer(client)) 507 { 508 sendnumeric(client, ERR_NOTFORUSERS, "UID"); 509 return; 510 } 511 512 strlcpy(nick, parv[1], sizeof(nick)); 513 hostname = parv[5]; 514 sstamp = parv[7]; 515 username = parv[4]; 516 umodes = parv[8]; 517 virthost = parv[9]; 518 ip_raw = parv[11]; 519 realname = parv[12]; 520 521 /* Do some *MINIMAL* nick name checking for remote nicknames. 522 * This will only catch things that severely break things. -- Syzop 523 */ 524 if (!do_remote_nick_name(nick) || !strcasecmp("ircd", nick) || !strcasecmp("irc", nick)) 525 { 526 unreal_log(ULOG_ERROR, "nick", "BAD_NICK_REMOTE", client->uplink, 527 "Server link $client tried to introduce bad nick '$nick' -- rejected.", 528 log_data_string("nick", parv[1])); 529 sendnumeric(client, ERR_ERRONEUSNICKNAME, parv[1], "Illegal nick name"); 530 531 ircstats.is_kill++; 532 /* Send kill to uplink only, hasn't been broadcasted to the rest, anyway */ 533 sendto_one(client, NULL, ":%s KILL %s :Bad nick", me.id, parv[1]); 534 return; 535 } 536 537 if (!valid_uid(parv[6]) || strncmp(parv[6], client->id, 3)) 538 { 539 ircstats.is_kill++; 540 unreal_log(ULOG_ERROR, "link", "BAD_UID", client, 541 "Server link $client ($sid) used bad UID $uid in UID command.", 542 log_data_string("sid", client->id), 543 log_data_string("uid", parv[6])); 544 /* Send kill to uplink only, hasn't been broadcasted to the rest, anyway */ 545 sendto_one(client, NULL, ":%s KILL %s :Bad UID", me.id, parv[6]); 546 return; 547 } 548 549 if (!valid_host(hostname, 0)) 550 { 551 ircstats.is_kill++; 552 unreal_log(ULOG_ERROR, "link", "BAD_HOSTNAME", client, 553 "Server link $client ($client.id) introduced user $nick with bad host name: $bad_hostname.", 554 log_data_string("nick", nick), 555 log_data_string("bad_hostname", hostname)); 556 /* Send kill to uplink only, hasn't been broadcasted to the rest, anyway */ 557 sendto_one(client, NULL, ":%s KILL %s :Bad hostname", me.id, parv[6]); 558 return; 559 } 560 561 if (strcmp(virthost, "*") && !valid_host(virthost, 0)) 562 { 563 ircstats.is_kill++; 564 unreal_log(ULOG_ERROR, "link", "BAD_HOSTNAME", client, 565 "Server link $client ($client.id) introduced user $nick with bad virtual hostname: $bad_hostname.", 566 log_data_string("nick", nick), 567 log_data_string("bad_hostname", virthost)); 568 /* Send kill to uplink only, hasn't been broadcasted to the rest, anyway */ 569 sendto_one(client, NULL, ":%s KILL %s :Bad virtual host", me.id, parv[6]); 570 return; 571 } 572 573 if (strcmp(ip_raw, "*")) 574 { 575 if (!(ip = decode_ip(ip_raw))) 576 { 577 ircstats.is_kill++; 578 unreal_log(ULOG_ERROR, "link", "BAD_IP", client, 579 "Server link $client ($client.id) introduced user $nick with bad IP: $bad_ip.", 580 log_data_string("nick", nick), 581 log_data_string("bad_ip", ip_raw)); 582 /* Send kill to uplink only, hasn't been broadcasted to the rest, anyway */ 583 sendto_one(client, NULL, ":%s KILL %s :Bad IP in UID command", me.id, parv[6]); 584 return; 585 } 586 } 587 588 /* Kill quarantined opers early... */ 589 if (IsQuarantined(client->direction) && strchr(parv[8], 'o')) 590 { 591 ircstats.is_kill++; 592 /* Send kill to uplink only, hasn't been broadcasted to the rest, anyway */ 593 unreal_log(ULOG_INFO, "link", "OPER_KILLED_QUARANTINE", NULL, 594 "QUARANTINE: Oper $nick on server $server killed, due to quarantine", 595 log_data_string("nick", parv[1]), 596 log_data_client("server", client)); 597 sendto_one(client, NULL, ":%s KILL %s :Quarantined: no oper privileges allowed", me.id, parv[6]); 598 return; 599 } 600 601 if (!IsULine(client) && (tklban = find_qline(client, nick, &ishold))) 602 { 603 unreal_log(ULOG_INFO, "nick", "QLINE_NICK_REMOTE", client, 604 "Banned nick $nick [$nick.ip] from server $server ($reason)", 605 log_data_string("nick", parv[1]), 606 log_data_string("ip", ip), 607 log_data_client("server", client->uplink), 608 log_data_string("reason", tklban->ptr.nameban->reason)); 609 /* Let it through */ 610 } 611 612 /* Now check if 'nick' already exists - collision with a user (or still in handshake, unknown) */ 613 if ((acptr = find_client(nick, NULL)) != NULL) 614 { 615 /* If there's a collision with a user that is still in handshake, on our side, 616 * then we can just kill our client and continue. 617 */ 618 if (MyConnect(acptr) && IsUnknown(acptr)) 619 { 620 SetKilled(acptr); 621 exit_client(acptr, NULL, "Overridden"); 622 goto nickkill2done; 623 } 624 625 lastnick = atol(parv[3]); 626 differ = (mycmp(acptr->user->username, parv[4]) || mycmp(acptr->user->realhost, parv[5])); 627 628 if (acptr->lastnick == lastnick) 629 { 630 nick_collision(client, parv[1], parv[6], NULL, acptr, NICKCOL_EQUAL); 631 return; /* We killed both users, now stop the process. */ 632 } 633 634 if ((differ && (acptr->lastnick > lastnick)) || 635 (!differ && (acptr->lastnick < lastnick)) || acptr->direction == client->direction) /* we missed a QUIT somewhere ? */ 636 { 637 nick_collision(client, parv[1], parv[6], NULL, acptr, NICKCOL_NEW_WON); 638 /* We got rid of the "wrong" user. Introduce the correct one. */ 639 /* ^^ hmm.. why was this absent in nenolod's code, resulting in a 'return 0'? seems wrong. */ 640 goto nickkill2done; 641 } 642 643 if ((differ && (acptr->lastnick < lastnick)) || (!differ && (acptr->lastnick > lastnick))) 644 { 645 nick_collision(client, parv[1], parv[6], NULL, acptr, NICKCOL_EXISTING_WON); 646 return; /* Ignore the NICK */ 647 } 648 return; /* just in case */ 649 } 650 651 nickkill2done: 652 /* Proceed with introducing the new client, change source (replace client) */ 653 654 serv = client; 655 client = make_client(serv->direction, serv); 656 strlcpy(client->id, parv[6], IDLEN); 657 add_client_to_list(client); 658 add_to_id_hash_table(client->id, client); 659 client->lastnick = atol(parv[3]); 660 strlcpy(client->name, nick, NICKLEN+1); 661 add_to_client_hash_table(nick, client); 662 663 make_user(client); 664 665 /* Note that cloaked host aka parv[10] is unused */ 666 667 client->user->server = find_or_add(client->uplink->name); 668 strlcpy(client->user->realhost, hostname, sizeof(client->user->realhost)); 669 if (ip) 670 safe_strdup(client->ip, ip); 671 672 if (*sstamp != '*') 673 strlcpy(client->user->account, sstamp, sizeof(client->user->account)); 674 675 strlcpy(client->info, realname, sizeof(client->info)); 676 strlcpy(client->user->username, username, USERLEN + 1); 677 SetUser(client); 678 679 make_cloakedhost(client, client->user->realhost, client->user->cloakedhost, sizeof(client->user->cloakedhost)); 680 safe_strdup(client->user->virthost, client->user->cloakedhost); 681 682 /* Inherit flags from server, makes it easy in the send routines 683 * and this also makes clients inherit ulines. 684 */ 685 client->flags |= client->uplink->flags; 686 687 /* Update counts */ 688 irccounts.clients++; 689 if (client->uplink->server) 690 client->uplink->server->users++; 691 if (client->umodes & UMODE_INVISIBLE) 692 irccounts.invisible++; 693 694 /* Set user modes */ 695 set_user_modes_dont_spread(client, umodes); 696 697 /* Set the vhost */ 698 if (*virthost != '*') 699 safe_strdup(client->user->virthost, virthost); 700 701 build_umode_string(client, 0, SEND_UMODES|UMODE_SERVNOTICE, buf); 702 703 sendto_serv_butone_nickcmd(client->direction, recv_mtags, client, (*buf == '\0' ? "+" : buf)); 704 705 moddata_extract_s2s_mtags(client, recv_mtags); 706 707 if (IsLoggedIn(client)) 708 { 709 user_account_login(recv_mtags, client); 710 /* no need to check for kill upon user_account_login() here 711 * since that can only happen for local users. 712 */ 713 } 714 715 RunHook(HOOKTYPE_REMOTE_CONNECT, client); 716 717 if (!IsULine(serv) && IsSynched(serv)) 718 { 719 unreal_log(ULOG_INFO, "connect", "REMOTE_CLIENT_CONNECT", client, 720 "Client connecting: $client ($client.user.username@$client.hostname) [$client.ip] $extended_client_info", 721 log_data_string("extended_client_info", get_connect_extinfo(client)), 722 log_data_string("from_server_name", client->user->server)); 723 } 724 } 725 726 /** The NICK command. 727 * In UnrealIRCd 4 and later this should only happen for: 728 * 1) A local user setting or changing the nick name ("NICK xyz") 729 * -> cmd_nick_local() 730 * 2) A remote user changing their nick name (":<uid> NICK <newnick>") 731 * -> cmd_nick_remote() 732 */ 733 CMD_FUNC(cmd_nick) 734 { 735 if ((parc < 2) || BadPtr(parv[1])) 736 { 737 sendnumeric(client, ERR_NONICKNAMEGIVEN); 738 return; 739 } 740 741 if (MyConnect(client) && !IsServer(client)) 742 { 743 CALL_CMD_FUNC(cmd_nick_local); 744 } else 745 if (!IsUser(client)) 746 { 747 unreal_log(ULOG_ERROR, "link", "LINK_OLD_PROTOCOL_NICK", client->direction, 748 "Server link $client tried to introduce $nick using NICK command. " 749 "Server is using an old and unsupported protocol from UnrealIRCd 3.2.x or earlier, should use the UID command. " 750 "See https://www.unrealircd.org/docs/FAQ#old-server-protocol", 751 log_data_string("nick", parv[1])); 752 /* Split the entire uplink, as it should never have allowed this (and probably they are to blame too) */ 753 exit_client(client->direction, NULL, "Server used NICK command, bad, must use UID!"); 754 return; 755 } else 756 { 757 CALL_CMD_FUNC(cmd_nick_remote); 758 } 759 } 760 761 /** Welcome the user on IRC. 762 * Send the RPL_WELCOME, LUSERS, MOTD, auto join channels, everything... 763 */ 764 void welcome_user(Client *client, TKL *viruschan_tkl) 765 { 766 int i; 767 ConfigItem_tld *tld; 768 char buf[BUFSIZE]; 769 770 /* Make creation time the real 'online since' time, excluding registration time. 771 * Otherwise things like set::anti-spam-quit-messagetime 10s could mean 772 * 1 second in practice (#2174). 773 */ 774 client->local->creationtime = TStime(); 775 client->local->idle_since = TStime(); 776 777 RunHook(HOOKTYPE_WELCOME, client, 0); 778 sendnumeric(client, RPL_WELCOME, NETWORK_NAME, client->name, client->user->username, client->user->realhost); 779 780 RunHook(HOOKTYPE_WELCOME, client, 1); 781 sendnumeric(client, RPL_YOURHOST, me.name, version); 782 783 RunHook(HOOKTYPE_WELCOME, client, 2); 784 sendnumeric(client, RPL_CREATED, creation); 785 786 RunHook(HOOKTYPE_WELCOME, client, 3); 787 sendnumeric(client, RPL_MYINFO, me.name, version, umodestring, cmodestring); 788 789 RunHook(HOOKTYPE_WELCOME, client, 4); 790 for (i = 0; ISupportStrings[i]; i++) 791 sendnumeric(client, RPL_ISUPPORT, ISupportStrings[i]); 792 793 RunHook(HOOKTYPE_WELCOME, client, 5); 794 795 if (IsHidden(client)) 796 { 797 sendnumeric(client, RPL_HOSTHIDDEN, client->user->virthost); 798 RunHook(HOOKTYPE_WELCOME, client, 396); 799 } 800 801 if (IsSecureConnect(client)) 802 { 803 if (client->local->ssl && !iConf.no_connect_tls_info) 804 { 805 sendnotice(client, "*** You are connected to %s with %s", 806 me.name, tls_get_cipher(client)); 807 } 808 } 809 810 { 811 const char *parv[2]; 812 parv[0] = NULL; 813 parv[1] = NULL; 814 do_cmd(client, NULL, "LUSERS", 1, parv); 815 if (IsDead(client)) 816 return; 817 } 818 819 RunHook(HOOKTYPE_WELCOME, client, 266); 820 821 short_motd(client); 822 823 RunHook(HOOKTYPE_WELCOME, client, 376); 824 825 #ifdef EXPERIMENTAL 826 sendnotice(client, 827 "*** \2NOTE:\2 This server is running experimental IRC server software (UnrealIRCd %s). " 828 "If you find any bugs or problems, please report them at https://bugs.unrealircd.org/", 829 VERSIONONLY); 830 #endif 831 832 if (client->umodes & UMODE_INVISIBLE) 833 irccounts.invisible++; 834 835 build_umode_string(client, 0, SEND_UMODES|UMODE_SERVNOTICE, buf); 836 837 sendto_serv_butone_nickcmd(client->direction, NULL, client, (*buf == '\0' ? "+" : buf)); 838 839 broadcast_moddata_client(client); 840 841 if (buf[0] != '\0' && buf[1] != '\0') 842 sendto_one(client, NULL, ":%s MODE %s :%s", client->name, 843 client->name, buf); 844 845 if (client->user->snomask) 846 sendnumeric(client, RPL_SNOMASK, client->user->snomask); 847 848 if (!IsSecure(client) && !IsLocalhost(client) && (iConf.plaintext_policy_user == POLICY_WARN)) 849 sendnotice_multiline(client, iConf.plaintext_policy_user_message); 850 851 if (IsSecure(client) && (iConf.outdated_tls_policy_user == POLICY_WARN) && outdated_tls_client(client)) 852 sendnotice(client, "%s", outdated_tls_client_build_string(iConf.outdated_tls_policy_user_message, client)); 853 854 RunHook(HOOKTYPE_LOCAL_CONNECT, client); 855 856 /* Give the user a fresh start as far as fake-lag is concerned. 857 * Otherwise the user could be lagged up already due to all the CAP stuff. 858 */ 859 client->local->fake_lag = TStime(); 860 861 RunHook(HOOKTYPE_WELCOME, client, 999); 862 863 /* NOTE: Code after this 'if (viruschan_tkl)' will not be executed for quarantined- 864 * virus-users. So be carefull with the order. -- Syzop 865 */ 866 // FIXME: verify if this works, trace code path upstream!!!! 867 if (viruschan_tkl) 868 { 869 join_viruschan(client, viruschan_tkl, SPAMF_USER); 870 return; 871 } 872 873 /* Force the user to join the given chans -- codemastr */ 874 tld = find_tld(client); 875 876 if (tld && !BadPtr(tld->channel)) 877 { 878 char *chans = strdup(tld->channel); 879 const char *args[3] = { 880 NULL, 881 chans, 882 NULL 883 }; 884 do_cmd(client, NULL, "JOIN", 3, args); 885 safe_free(chans); 886 if (IsDead(client)) 887 return; 888 } 889 else if (!BadPtr(AUTO_JOIN_CHANS) && strcmp(AUTO_JOIN_CHANS, "0")) 890 { 891 char *chans = strdup(AUTO_JOIN_CHANS); 892 const char *args[3] = { 893 NULL, 894 chans, 895 NULL 896 }; 897 do_cmd(client, NULL, "JOIN", 3, args); 898 safe_free(chans); 899 if (IsDead(client)) 900 return; 901 } 902 } 903 904 /** Make a valid client->user->username, or try to anyway. 905 * @param client The client to check 906 * @param noident Whether we should ignore the first ~ or not 907 * @returns 1 if the username is acceptable, 0 if not. 908 * @note This function will modify client->user->username to make it valid. 909 * Only if there are zero valid characters it will return 0. 910 * @note There is also valid_username() in src/misc.c 911 */ 912 int make_valid_username(Client *client, int noident) 913 { 914 static char stripuser[USERLEN + 1]; 915 char *i; 916 char *o = stripuser; 917 char filtered = 0; /* any changes? */ 918 919 *stripuser = '\0'; 920 921 for (i = client->user->username + noident; *i; i++) 922 { 923 if (isallowed(*i)) 924 *o++ = *i; 925 else 926 filtered = 1; 927 } 928 *o = '\0'; 929 930 if (filtered == 0) 931 return 1; /* No change needed, all good */ 932 933 if (*stripuser == '\0') 934 return 0; /* Zero valid characters, reject it */ 935 936 strlcpy(client->user->username + 1, stripuser, sizeof(client->user->username)-1); 937 client->user->username[0] = '~'; 938 client->user->username[USERLEN] = '\0'; 939 return 1; /* Filtered, but OK */ 940 } 941 942 /** Register the connection as a User - only for local connections! 943 * This is called after NICK + USER (in no particular order) 944 * and possibly other protocol messages as well (eg CAP). 945 * @param client Client to be made a user. 946 * @returns 1 if successfully registered, 0 if not (client might be killed). 947 */ 948 int _register_user(Client *client) 949 { 950 ConfigItem_ban *bconf; 951 char *tmpstr; 952 char noident = 0; 953 int i; 954 Hook *h; 955 TKL *savetkl = NULL; 956 char temp[USERLEN + 1]; 957 char descbuf[BUFSIZE]; 958 959 if (!MyConnect(client)) 960 abort(); 961 962 /* Set client->local->sockhost: 963 * First deal with the special 'localhost' case and 964 * then with generic setting based on DNS. 965 */ 966 if (!strcmp(GetIP(client), "127.0.0.1") || 967 !strcmp(GetIP(client), "0:0:0:0:0:0:0:1") || 968 !strcmp(GetIP(client), "0:0:0:0:0:ffff:127.0.0.1")) 969 { 970 set_sockhost(client, "localhost"); 971 if (client->local->hostp) 972 { 973 unreal_free_hostent(client->local->hostp); 974 client->local->hostp = NULL; 975 } 976 } else 977 { 978 struct hostent *hp = client->local->hostp; 979 if (hp && hp->h_name) 980 set_sockhost(client, hp->h_name); 981 } 982 983 /* Set the hostname (client->user->realhost). 984 * This may later be overwritten by the AllowClient() call to 985 * revert to the IP again if allow::options::useip is set. 986 */ 987 strlcpy(client->user->realhost, client->local->sockhost, sizeof(client->local->sockhost)); 988 989 /* Check allow { } blocks... */ 990 if (!AllowClient(client)) 991 { 992 ircstats.is_ref++; 993 /* For safety, we have an extra kill here */ 994 if (!IsDead(client)) 995 exit_client(client, NULL, "Rejected"); 996 return 0; 997 } 998 999 if (IsUseIdent(client)) 1000 { 1001 if (IsIdentSuccess(client)) 1002 { 1003 /* ident succeeded: overwite client->user->username with the ident reply */ 1004 strlcpy(client->user->username, client->ident, sizeof(client->user->username)); 1005 } else 1006 if (IDENT_CHECK) 1007 { 1008 /* ident check is enabled and it failed: prefix the username with ~ */ 1009 char temp[USERLEN+1]; 1010 strlcpy(temp, client->user->username, sizeof(temp)); 1011 snprintf(client->user->username, sizeof(client->user->username), "~%s", temp); 1012 noident = 1; 1013 } 1014 } 1015 1016 /* Now validate the username. This may alter client->user->username 1017 * or reject it completely. 1018 */ 1019 if (!make_valid_username(client, noident)) 1020 { 1021 exit_client(client, NULL, "Hostile username. Please use only 0-9 a-z A-Z _ - and . in your username."); 1022 return 0; 1023 } 1024 1025 /* Check ban realname { } blocks */ 1026 if ((bconf = find_ban(NULL, client->info, CONF_BAN_REALNAME))) 1027 { 1028 ircstats.is_ref++; 1029 banned_client(client, "realname", bconf->reason?bconf->reason:"", 0, 0); 1030 return 0; 1031 } 1032 /* Check G/Z lines before shuns -- kill before quite -- codemastr */ 1033 if (find_tkline_match(client, 0)) 1034 { 1035 if (!IsDead(client) && client->local->class) 1036 { 1037 /* Fix client count bug, in case that it was a hold such as via authprompt */ 1038 client->local->class->clients--; 1039 client->local->class = NULL; 1040 } 1041 ircstats.is_ref++; 1042 return 0; 1043 } 1044 find_shun(client); 1045 1046 spamfilter_build_user_string(spamfilter_user, client->name, client); 1047 if (match_spamfilter(client, spamfilter_user, SPAMF_USER, NULL, NULL, 0, &savetkl)) 1048 { 1049 if (savetkl && ((savetkl->ptr.spamfilter->action == BAN_ACT_VIRUSCHAN) || 1050 (savetkl->ptr.spamfilter->action == BAN_ACT_SOFT_VIRUSCHAN))) 1051 { 1052 /* 'viruschan' action: 1053 * Continue with registering the client, and at the end 1054 * of this function we will do the actual joining to the 1055 * virus channel. 1056 */ 1057 } else { 1058 /* Client is either dead or blocked (will hang, on purpose, and timeout) */ 1059 return 0; 1060 } 1061 } 1062 1063 for (h = Hooks[HOOKTYPE_PRE_LOCAL_CONNECT]; h; h = h->next) 1064 { 1065 int ret = (*(h->func.intfunc))(client); 1066 if (ret == HOOK_DENY) 1067 { 1068 if (!IsDead(client) && client->local->class) 1069 { 1070 /* Fix client count bug, in case that 1071 * the HOOK_DENY was only meant temporarily. 1072 */ 1073 client->local->class->clients--; 1074 client->local->class = NULL; 1075 } 1076 return 0; 1077 } 1078 if (ret == HOOK_ALLOW) 1079 break; 1080 } 1081 1082 SetUser(client); 1083 1084 make_cloakedhost(client, client->user->realhost, client->user->cloakedhost, sizeof(client->user->cloakedhost)); 1085 1086 /* client->user->virthost should never be empty */ 1087 if (!IsSetHost(client) || !client->user->virthost) 1088 safe_strdup(client->user->virthost, client->user->cloakedhost); 1089 1090 snprintf(descbuf, sizeof descbuf, "Client: %s", client->name); 1091 fd_desc(client->local->fd, descbuf); 1092 1093 /* Move user from unknown list to client list */ 1094 list_move(&client->lclient_node, &lclient_list); 1095 1096 /* Update counts */ 1097 irccounts.unknown--; 1098 irccounts.clients++; 1099 irccounts.me_clients++; 1100 if (client->uplink && client->uplink->server) 1101 client->uplink->server->users++; 1102 1103 if (IsSecure(client)) 1104 { 1105 client->umodes |= UMODE_SECURE; 1106 RunHook(HOOKTYPE_SECURE_CONNECT, client); 1107 } 1108 1109 safe_free(client->local->passwd); 1110 1111 unreal_log(ULOG_INFO, "connect", "LOCAL_CLIENT_CONNECT", client, 1112 "Client connecting: $client ($client.user.username@$client.hostname) [$client.ip] $extended_client_info", 1113 log_data_string("extended_client_info", get_connect_extinfo(client))); 1114 1115 /* Send the RPL_WELCOME, LUSERS, MOTD, auto join channels, everything... */ 1116 welcome_user(client, savetkl); 1117 1118 return IsDead(client) ? 0 : 1; 1119 } 1120 1121 /** Nick collission detected. A winner has been decided upstream. Deal with killing. 1122 * I moved this all to a single routine here rather than having all code duplicated 1123 * due to SID vs NICK and some code quadruplicated. 1124 */ 1125 void nick_collision(Client *cptr, const char *newnick, const char *newid, Client *new, Client *existing, int type) 1126 { 1127 char comment[512]; 1128 const char *new_server, *existing_server; 1129 const char *who_won; 1130 const char *nickcol_reason; 1131 1132 if (type == NICKCOL_NEW_WON) 1133 who_won = "new"; 1134 else if (type == NICKCOL_EXISTING_WON) 1135 who_won = "existing"; 1136 else 1137 who_won = "none"; 1138 1139 nickcol_reason = new ? "nick change" : "new user connecting"; 1140 1141 unreal_log(ULOG_ERROR, "nick", "NICK_COLLISION", NULL, 1142 "Nick collision: " 1143 "$new_nick[$new_id]@$uplink (new) vs " 1144 "$existing_client[$existing_client.id]@$existing_client.user.servername (existing). " 1145 "Winner: $nick_collision_winner. " 1146 "Cause: $nick_collision_reason", 1147 log_data_string("new_nick", newnick), 1148 log_data_string("new_id", newid), 1149 log_data_client("uplink", cptr), 1150 log_data_client("existing_client", existing), 1151 log_data_string("nick_collision_winner", who_won), 1152 log_data_string("nick_collision_reason", nickcol_reason)); 1153 1154 new_server = cptr->name; 1155 existing_server = (existing == existing->direction) ? me.name : existing->direction->name; 1156 if (type == NICKCOL_EXISTING_WON) 1157 snprintf(comment, sizeof(comment), "Nick collision: %s <- %s", new_server, existing_server); 1158 else if (type == NICKCOL_NEW_WON) 1159 snprintf(comment, sizeof(comment), "Nick collision: %s <- %s", existing_server, new_server); 1160 else 1161 snprintf(comment, sizeof(comment), "Nick collision: %s <-> %s", existing_server, new_server); 1162 1163 /* We only care about the direction from this point, not about the originally sending server */ 1164 cptr = cptr->direction; 1165 1166 if ((type == NICKCOL_EQUAL) || (type == NICKCOL_EXISTING_WON)) 1167 { 1168 /* Kill 'new': 1169 * - 'new' is known by the cptr-side as 'newnick' already 1170 * - if not nick-changing then the other servers don't know this user 1171 * - if nick-changing, then the the other servers know the user as new->name 1172 */ 1173 1174 /* cptr case first... this side knows the user by newnick/newid */ 1175 /* SID server can kill 'new' by ID */ 1176 sendto_one(cptr, NULL, ":%s KILL %s :%s", me.id, newid, comment); 1177 1178 /* non-cptr case... only necessary if nick-changing. */ 1179 if (new) 1180 { 1181 MessageTag *mtags = NULL; 1182 1183 new_message(new, NULL, &mtags); 1184 1185 /* non-cptr side knows this user by their old nick name */ 1186 sendto_server(cptr, 0, 0, mtags, ":%s KILL %s :%s", me.id, new->id, comment); 1187 1188 /* Exit the client */ 1189 ircstats.is_kill++; 1190 SetKilled(new); 1191 exit_client(new, mtags, comment); 1192 1193 free_message_tags(mtags); 1194 } 1195 } 1196 1197 if ((type == NICKCOL_EQUAL) || (type == NICKCOL_NEW_WON)) 1198 { 1199 MessageTag *mtags = NULL; 1200 1201 new_message(existing, NULL, &mtags); 1202 1203 /* Now let's kill 'existing' */ 1204 sendto_server(NULL, 0, 0, mtags, ":%s KILL %s :%s", me.id, existing->id, comment); 1205 1206 /* Exit the client */ 1207 ircstats.is_kill++; 1208 SetKilled(existing); 1209 exit_client(existing, mtags, comment); 1210 1211 free_message_tags(mtags); 1212 } 1213 } 1214 1215 /** Returns 1 if allow::maxperip is exceeded by 'client' */ 1216 int exceeds_maxperip(Client *client, ConfigItem_allow *aconf) 1217 { 1218 Client *acptr; 1219 int local_cnt = 1; 1220 int global_cnt = 1; 1221 1222 if (find_tkl_exception(TKL_MAXPERIP, client)) 1223 return 0; /* exempt */ 1224 1225 list_for_each_entry(acptr, &client_list, client_node) 1226 { 1227 if (IsUser(acptr) && !strcmp(GetIP(acptr), GetIP(client))) 1228 { 1229 if (MyUser(acptr)) 1230 { 1231 local_cnt++; 1232 if (local_cnt > aconf->maxperip) 1233 return 1; 1234 } 1235 global_cnt++; 1236 if (global_cnt > aconf->global_maxperip) 1237 return 1; 1238 } 1239 } 1240 return 0; 1241 } 1242 1243 /** Allow or reject the client based on allow { } blocks and all other restrictions. 1244 * @param client Client to check (local) 1245 * @param username Username, for some reason... 1246 * @returns 1 if OK, 0 if client is rejected (likely killed too) 1247 */ 1248 int AllowClient(Client *client) 1249 { 1250 static char sockhost[HOSTLEN + 1]; 1251 int i; 1252 ConfigItem_allow *aconf; 1253 char *hname; 1254 static char uhost[HOSTLEN + USERLEN + 3]; 1255 static char fullname[HOSTLEN + 1]; 1256 1257 if (!IsSecure(client) && !IsLocalhost(client) && (iConf.plaintext_policy_user == POLICY_DENY)) 1258 { 1259 exit_client(client, NULL, iConf.plaintext_policy_user_message->line); 1260 return 0; 1261 } 1262 1263 if (IsSecure(client) && (iConf.outdated_tls_policy_user == POLICY_DENY) && outdated_tls_client(client)) 1264 { 1265 const char *msg = outdated_tls_client_build_string(iConf.outdated_tls_policy_user_message, client); 1266 exit_client(client, NULL, msg); 1267 return 0; 1268 } 1269 1270 for (aconf = conf_allow; aconf; aconf = aconf->next) 1271 { 1272 if (aconf->flags.tls && !IsSecure(client)) 1273 continue; 1274 1275 if (!user_allowed_by_security_group(client, aconf->match)) 1276 continue; 1277 1278 /* Check authentication */ 1279 if (aconf->auth && !Auth_Check(client, aconf->auth, client->local->passwd)) 1280 { 1281 /* Incorrect password/authentication - but was is it required? */ 1282 if (aconf->flags.reject_on_auth_failure) 1283 { 1284 exit_client(client, NULL, iConf.reject_message_unauthorized); 1285 return 0; 1286 } else { 1287 continue; /* Continue (this is the default behavior) */ 1288 } 1289 } 1290 1291 if (!aconf->flags.noident) 1292 SetUseIdent(client); 1293 1294 if (aconf->flags.useip) 1295 set_sockhost(client, GetIP(client)); 1296 1297 if (exceeds_maxperip(client, aconf)) 1298 { 1299 /* Already got too many with that ip# */ 1300 exit_client(client, NULL, iConf.reject_message_too_many_connections); 1301 return 0; 1302 } 1303 1304 if (!((aconf->class->clients + 1) > aconf->class->maxclients)) 1305 { 1306 client->local->class = aconf->class; 1307 client->local->class->clients++; 1308 } 1309 else 1310 { 1311 /* Class is full */ 1312 sendnumeric(client, RPL_REDIR, aconf->server ? aconf->server : DEFAULT_SERVER, aconf->port ? aconf->port : 6667); 1313 exit_client(client, NULL, iConf.reject_message_server_full); 1314 return 0; 1315 } 1316 return 1; 1317 } 1318 /* User did not match any allow { } blocks: */ 1319 exit_client(client, NULL, iConf.reject_message_unauthorized); 1320 return 0; 1321 }