unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
ircd.c (29336B)
1 /************************************************************************ 2 * Unreal Internet Relay Chat Daemon, src/ircd.c 3 * Copyright (C) 1989-1990 Jarkko Oikarinen and 4 * University of Oulu, Computing Center 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 #include <ares.h> 23 24 #ifdef __FreeBSD__ 25 char *malloc_options = "h" MALLOC_FLAGS_EXTRA; 26 #endif 27 28 /* Forward declarations */ 29 void server_reboot(const char *); 30 void restart(const char *); 31 static void open_debugfile(), setup_signals(); 32 33 EVENT(loop_event) 34 { 35 if (loop.do_garbage_collect == 1) { 36 garbage_collect(NULL); 37 } 38 } 39 40 EVENT(garbage_collect) 41 { 42 extern int freelinks; 43 extern Link *freelink; 44 Link p; 45 int ii; 46 47 if (loop.do_garbage_collect == 1) 48 unreal_log(ULOG_INFO, "main", "GARBAGE_COLLECT_STARTED", NULL, "Doing garbage collection..."); 49 if (freelinks > HOW_MANY_FREELINKS_ALLOWED) { 50 ii = freelinks; 51 while (freelink && (freelinks > HOW_MANY_FREELINKS_ALLOWED)) { 52 freelinks--; 53 p.next = freelink; 54 freelink = freelink->next; 55 safe_free(p.next); 56 } 57 if (loop.do_garbage_collect == 1) { 58 loop.do_garbage_collect = 0; 59 unreal_log(ULOG_INFO, "main", "GARBAGE_COLLECT_STARTED", NULL, "Cleaned up $count garbage blocks", 60 log_data_integer("count", (ii - freelinks))); 61 } 62 } 63 if (loop.do_garbage_collect == 1) 64 loop.do_garbage_collect = 0; 65 } 66 67 /** Does this user match any TKL's? */ 68 int match_tkls(Client *client) 69 { 70 ConfigItem_ban *bconf = NULL; 71 char banbuf[1024]; 72 73 /* Process dynamic *LINES */ 74 if (find_tkline_match(client, 0)) 75 return 1; /* user killed */ 76 77 find_shun(client); /* check for shunned and take action, if so */ 78 79 if (IsUser(client)) 80 { 81 /* Check ban realname { } */ 82 if (!ValidatePermissionsForPath("immune",client,NULL,NULL,NULL) && (bconf = find_ban(NULL, client->info, CONF_BAN_REALNAME))) 83 { 84 unreal_log(ULOG_INFO, "tkl", "BAN_REALNAME", client, 85 "Banned client $client.details due to realname ban: $reason", 86 log_data_string("reason", bconf->reason ? bconf->reason : "no reason")); 87 88 if (bconf->reason) { 89 if (IsUser(client)) 90 snprintf(banbuf, sizeof(banbuf), "User has been banned (%s)", bconf->reason); 91 else 92 snprintf(banbuf, sizeof(banbuf), "Banned (%s)", bconf->reason); 93 exit_client(client, NULL, banbuf); 94 } else { 95 if (IsUser(client)) 96 exit_client(client, NULL, "User has been banned"); 97 else 98 exit_client(client, NULL, "Banned"); 99 } 100 return 1; /* stop processing, client is dead now */ 101 } 102 } 103 104 if (loop.do_bancheck_spamf_user && IsUser(client) && find_spamfilter_user(client, SPAMFLAG_NOWARN)) 105 return 1; 106 107 if (loop.do_bancheck_spamf_away && IsUser(client) && 108 client->user->away != NULL && 109 match_spamfilter(client, client->user->away, SPAMF_AWAY, "AWAY", NULL, SPAMFLAG_NOWARN, NULL)) 110 { 111 return 1; 112 } 113 114 return 0; 115 } 116 117 /** Time out connections that are still in handshake. */ 118 EVENT(handshake_timeout) 119 { 120 Client *client, *next; 121 122 list_for_each_entry_safe(client, next, &unknown_list, lclient_node) 123 { 124 if (client->local->creationtime && 125 ((TStime() - client->local->creationtime) > iConf.handshake_timeout) && 126 !(client->local->listener && (client->local->listener->socket_type == SOCKET_TYPE_UNIX))) 127 { 128 Hook *h; 129 int n = HOOK_CONTINUE; 130 const char *quitreason = "Registration Timeout"; 131 char reasonbuf[512]; 132 133 if (client->server && *client->server->by) 134 continue; /* handled by server module */ 135 136 for (h = Hooks[HOOKTYPE_PRE_LOCAL_HANDSHAKE_TIMEOUT]; h; h = h->next) 137 { 138 n = (*(h->func.intfunc))(client, &quitreason); 139 if (n == HOOK_ALLOW) 140 break; 141 } 142 if (n == HOOK_ALLOW) 143 continue; /* Do not exit the client due to registration timeout */ 144 145 /* Work on a copy here, since the 'quitreason' may point to 146 * some kind of buffer that gets freed in the exit code. 147 */ 148 strlcpy(reasonbuf, quitreason ? quitreason : "Registration Timeout", sizeof(reasonbuf)); 149 exit_client(client, NULL, reasonbuf); 150 continue; 151 } 152 } 153 } 154 155 /** Ping individual user, and check for ping timeout */ 156 void check_ping(Client *client) 157 { 158 char scratch[64]; 159 int ping = 0; 160 161 ping = client->local->class ? client->local->class->pingfreq : iConf.handshake_timeout; 162 163 /* If ping is less than or equal to the last time we received a command from them */ 164 if (ping > (TStime() - client->local->last_msg_received)) 165 return; /* some recent command was executed */ 166 167 if ( 168 /* If we have sent a ping */ 169 (IsPingSent(client) 170 /* And they had 2x ping frequency to respond */ 171 && ((TStime() - client->local->last_msg_received) >= (2 * ping))) 172 || 173 /* Or isn't registered and time spent is larger than ping (CONNECTTIMEOUT).. */ 174 (!IsRegistered(client) && (TStime() - client->local->fake_lag >= ping)) 175 ) 176 { 177 if (IsServer(client) || IsConnecting(client) || 178 IsHandshake(client) || IsTLSConnectHandshake(client)) 179 { 180 unreal_log(ULOG_ERROR, "link", "LINK_DISCONNECTED", client, 181 "Lost server link to $client [$client.ip]: No response (Ping timeout)", 182 client->server->conf ? log_data_link_block(client->server->conf) : NULL); 183 SetServerDisconnectLogged(client); 184 } 185 ircsnprintf(scratch, sizeof(scratch), "Ping timeout: %lld seconds", 186 (long long) (TStime() - client->local->last_msg_received)); 187 exit_client(client, NULL, scratch); 188 return; 189 } 190 else if (IsRegistered(client) && !IsPingSent(client)) 191 { 192 /* Time to send a PING */ 193 SetPingSent(client); 194 ClearPingWarning(client); 195 /* not nice but does the job */ 196 client->local->last_msg_received = TStime() - ping; 197 sendto_one(client, NULL, "PING :%s", me.name); 198 } 199 else if (!IsPingWarning(client) && PINGWARNING > 0 && 200 (IsServer(client) || IsHandshake(client) || IsConnecting(client) || 201 IsTLSConnectHandshake(client)) && 202 (TStime() - client->local->last_msg_received) >= (ping + PINGWARNING)) 203 { 204 SetPingWarning(client); 205 unreal_log(ULOG_WARNING, "link", "LINK_UNRELIABLE", client, 206 "Warning, no response from $client for $time_delta seconds", 207 log_data_integer("time_delta", PINGWARNING), 208 client->server->conf ? log_data_link_block(client->server->conf) : NULL); 209 } 210 211 return; 212 } 213 214 /** Check registered connections for ping timeout. Also, check for server bans. */ 215 EVENT(check_pings) 216 { 217 Client *client, *next; 218 219 list_for_each_entry_safe(client, next, &lclient_list, lclient_node) 220 { 221 /* Check TKLs for this user */ 222 if (loop.do_bancheck && match_tkls(client)) 223 continue; 224 check_ping(client); 225 /* don't touch 'client' after this as it may have been killed */ 226 } 227 228 list_for_each_entry_safe(client, next, &server_list, special_node) 229 { 230 check_ping(client); 231 } 232 233 loop.do_bancheck = loop.do_bancheck_spamf_user = loop.do_bancheck_spamf_away = 0; 234 /* done */ 235 } 236 237 /** Check for clients that are pending to be terminated */ 238 EVENT(check_deadsockets) 239 { 240 Client *client, *next; 241 242 list_for_each_entry_safe(client, next, &unknown_list, lclient_node) 243 { 244 /* No need to notify opers here. It's already done when dead socket is set */ 245 if (IsDeadSocket(client)) 246 { 247 ClearDeadSocket(client); /* CPR. So we send the error. */ 248 exit_client(client, NULL, client->local->error_str ? client->local->error_str : "Dead socket"); 249 continue; 250 } 251 } 252 253 list_for_each_entry_safe(client, next, &lclient_list, lclient_node) 254 { 255 /* No need to notify opers here. It's already done when dead socket is set */ 256 if (IsDeadSocket(client)) 257 { 258 ClearDeadSocket(client); /* CPR. So we send the error. */ 259 exit_client(client, NULL, client->local->error_str ? client->local->error_str : "Dead socket"); 260 continue; 261 } 262 } 263 264 /* Next is for clients that are already exited (unlike the above). 265 * The client is already out of all lists (channels, invites, etc etc) 266 * and 90% has been freed. Here we actually free the remaining parts. 267 * We don't have to send anything anymore. 268 */ 269 list_for_each_entry_safe(client, next, &dead_list, client_node) 270 { 271 if (!IsDead(client)) 272 abort(); /* impossible */ 273 list_del(&client->client_node); 274 free_client(client); 275 } 276 } 277 278 /* 279 ** bad_command 280 ** This is called when the commandline is not acceptable. 281 ** Give error message and exit without starting anything. 282 */ 283 static int bad_command(const char *argv0) 284 { 285 #ifndef _WIN32 286 if (!argv0) 287 argv0 = "unrealircd"; 288 289 printf("ERROR: Incorrect command line argument encountered.\n" 290 "This is the unrealircd BINARY. End-users should NOT call this binary directly.\n" 291 "Please run the SCRIPT instead: %s/unrealircd\n", SCRIPTDIR); 292 printf("Server not started\n\n"); 293 #else 294 if (!IsService) { 295 MessageBox(NULL, 296 "Usage: UnrealIRCd [-f configfile]\n", 297 "UnrealIRCD/32", MB_OK); 298 } 299 #endif 300 return (-1); 301 } 302 303 char chess[] = { 304 85, 110, 114, 101, 97, 108, 0 305 }; 306 307 extern void applymeblock(void); 308 309 extern MODVAR Event *events; 310 311 /** This functions resets a couple of timers and does other things that 312 * are absolutely cruicial when the clock is adjusted - particularly 313 * when the clock goes backwards. -- Syzop 314 */ 315 void fix_timers(void) 316 { 317 int i, cnt; 318 Client *client; 319 Event *e; 320 struct ThrottlingBucket *thr; 321 ConfigItem_link *lnk; 322 323 list_for_each_entry(client, &lclient_list, lclient_node) 324 { 325 if (client->local->fake_lag > TStime()) 326 client->local->fake_lag = TStime(); 327 if (client->local->last_msg_received > TStime()) 328 client->local->last_msg_received = TStime(); 329 if (client->local->idle_since > TStime()) 330 client->local->idle_since = TStime(); 331 332 /* users */ 333 if (MyUser(client)) 334 { 335 if (client->local->next_nick_allowed > TStime()) 336 client->local->next_nick_allowed = TStime(); 337 if (client->local->nexttarget > TStime()) 338 client->local->nexttarget = TStime(); 339 } 340 } 341 342 /* Reset all event timers */ 343 for (e = events; e; e = e->next) 344 { 345 if (e->last_run.tv_sec > TStime()) 346 { 347 e->last_run.tv_sec = TStime()-1; 348 e->last_run.tv_usec = 0; 349 } 350 } 351 352 /* For throttling we only have to deal with time jumping backward, which 353 * is a real problem as if the jump was, say, 900 seconds, then it would 354 * (potentially) throttle for 900 seconds. 355 * Time going forward is "no problem", it just means we expire our entries 356 * sonner than we should. 357 */ 358 cnt = 0; 359 for (i = 0; i < THROTTLING_HASH_TABLE_SIZE; i++) 360 { 361 for (thr = ThrottlingHash[i]; thr; thr = thr->next) 362 { 363 if (thr->since > TStime()) 364 thr->since = TStime(); 365 } 366 } 367 368 /* Make sure autoconnect for servers still works (lnk->hold) */ 369 for (lnk = conf_link; lnk; lnk = lnk->next) 370 { 371 int t = lnk->class ? lnk->class->connfreq : 90; 372 373 if (lnk->hold > TStime() + t) 374 { 375 lnk->hold = TStime() + (t / 2); /* compromise */ 376 } 377 } 378 } 379 380 381 /* MY tdiff... because 'double' sucks. 382 * This should work until 2038, and very likely after that as well 383 * because 'long' should be 64 bit on all systems by then... -- Syzop 384 */ 385 #define mytdiff(a, b) ((long)a - (long)b) 386 387 #define NEGATIVE_SHIFT_WARN -15 388 #define POSITIVE_SHIFT_WARN 20 389 390 void detect_timeshift_and_warn(void) 391 { 392 static time_t highesttimeofday=0, oldtimeofday=0, lasthighwarn=0; 393 394 if (oldtimeofday == 0) 395 oldtimeofday = timeofday; /* pretend everything is ok the first time.. */ 396 397 if (mytdiff(timeofday, oldtimeofday) < NEGATIVE_SHIFT_WARN) 398 { 399 /* tdiff = # of seconds of time set backwards (positive number! eg: 60) */ 400 time_t tdiff = oldtimeofday - timeofday; 401 unreal_log(ULOG_WARNING, "system", "SYSTEM_CLOCK_JUMP_BACKWARDS", NULL, 402 "System clock jumped back in time ~$time_delta seconds ($time_from -> $time_to)\n" 403 "Incorrect time for IRC servers is a serious problem. " 404 "Time being set backwards (system clock changed) is " 405 "even more serious and can cause clients to freeze, channels to be " 406 "taken over, and other issues.\n" 407 "Please be sure your clock is always synchronized before the IRCd is started!", 408 log_data_integer("time_delta", tdiff), 409 log_data_timestamp("time_from", oldtimeofday), 410 log_data_timestamp("time_to", timeofday)); 411 fix_timers(); 412 } else 413 if (mytdiff(timeofday, oldtimeofday) > POSITIVE_SHIFT_WARN) /* do not set too low or you get false positives */ 414 { 415 /* tdiff = # of seconds of time set forward (eg: 60) */ 416 time_t tdiff = timeofday - oldtimeofday; 417 unreal_log(ULOG_WARNING, "system", "SYSTEM_CLOCK_JUMP_FORWARDS", NULL, 418 "System clock jumped ~$time_delta seconds forward ($time_from -> $time_to)\n" 419 "Incorrect time for IRC servers is a serious problem. " 420 "Time being adjusted (by changing the system clock) " 421 "more than a few seconds forward/backward can lead to serious issues.\n" 422 "Please be sure your clock is always synchronized before the IRCd is started!", 423 log_data_integer("time_delta", tdiff), 424 log_data_timestamp("time_from", oldtimeofday), 425 log_data_timestamp("time_to", timeofday)); 426 fix_timers(); 427 } 428 429 if (highesttimeofday+NEGATIVE_SHIFT_WARN > timeofday) 430 { 431 if (lasthighwarn > timeofday) 432 lasthighwarn = timeofday; 433 if (timeofday - lasthighwarn > 300) 434 { 435 unreal_log(ULOG_WARNING, "system", "SYSTEM_CLOCK_JUMP_BACKWARDS_PREVIOUSLY", NULL, 436 "The system clock previously went backwards. Waiting for time to be OK again. This will be in $time_delta seconds.", 437 log_data_integer("time_delta", highesttimeofday - timeofday), 438 log_data_timestamp("time_from", highesttimeofday), 439 log_data_timestamp("time_to", timeofday)); 440 lasthighwarn = timeofday; 441 } 442 } else { 443 highesttimeofday = timeofday; 444 } 445 446 oldtimeofday = timeofday; 447 } 448 449 void SetupEvents(void) 450 { 451 /* Start events */ 452 EventAdd(NULL, "tunefile", save_tunefile, NULL, 300*1000, 0); 453 EventAdd(NULL, "garbage", garbage_collect, NULL, GARBAGE_COLLECT_EVERY*1000, 0); 454 EventAdd(NULL, "loop", loop_event, NULL, 1000, 0); 455 EventAdd(NULL, "unrealdns_removeoldrecords", unrealdns_removeoldrecords, NULL, 15000, 0); 456 EventAdd(NULL, "check_pings", check_pings, NULL, 1000, 0); 457 EventAdd(NULL, "check_deadsockets", check_deadsockets, NULL, 1000, 0); 458 EventAdd(NULL, "handshake_timeout", handshake_timeout, NULL, 1000, 0); 459 EventAdd(NULL, "tls_check_expiry", tls_check_expiry, NULL, (86400/2)*1000, 0); 460 EventAdd(NULL, "unrealdb_expire_secret_cache", unrealdb_expire_secret_cache, NULL, 61000, 0); 461 EventAdd(NULL, "throttling_check_expire", throttling_check_expire, NULL, 1000, 0); 462 } 463 464 /** The main function. This will call SocketLoop() once the server is ready. */ 465 #ifndef _WIN32 466 int main(int argc, char *argv[]) 467 #else 468 int InitUnrealIRCd(int argc, char *argv[]) 469 #endif 470 { 471 #ifndef _WIN32 472 uid_t uid, euid; 473 gid_t gid, egid; 474 #endif 475 #ifdef HAVE_PSTAT 476 union pstun pstats; 477 #endif 478 #ifndef _WIN32 479 struct rlimit corelim; 480 #endif 481 482 gettimeofday(&timeofday_tv, NULL); 483 timeofday = timeofday_tv.tv_sec; 484 485 safe_strdup(configfile, CONFIGFILE); 486 487 init_random(); /* needs to be done very early!! */ 488 if (sodium_init() < 0) 489 { 490 fprintf(stderr, "Failed to initialize sodium library -- error accessing random device?\n"); 491 exit(-1); 492 } 493 494 memset(&botmotd, '\0', sizeof(MOTDFile)); 495 memset(&rules, '\0', sizeof(MOTDFile)); 496 memset(&opermotd, '\0', sizeof(MOTDFile)); 497 memset(&motd, '\0', sizeof(MOTDFile)); 498 memset(&smotd, '\0', sizeof(MOTDFile)); 499 memset(&svsmotd, '\0', sizeof(MOTDFile)); 500 memset(&me, 0, sizeof(me)); 501 me.local = safe_alloc(sizeof(LocalClient)); 502 memset(&loop, 0, sizeof(loop)); 503 504 init_hash(); 505 506 SetupEvents(); 507 508 #ifdef _WIN32 509 CreateMutex(NULL, FALSE, "UnrealMutex"); 510 SetErrorMode(SEM_FAILCRITICALERRORS); 511 #endif 512 #if !defined(_WIN32) && !defined(_AMIGA) 513 uid = getuid(); 514 euid = geteuid(); 515 gid = getgid(); 516 egid = getegid(); 517 518 if (euid == 0) 519 { 520 fprintf(stderr, 521 "** ERROR **\n" 522 "You attempted to run UnrealIRCd as root. This is VERY DANGEROUS\n" 523 "as any compromise of your UnrealIRCd will result in full\n" 524 "privileges to the attacker on the entire machine.\n" 525 "You MUST start UnrealIRCd as a different user!\n" 526 "\n" 527 "For more information, see:\n" 528 "https://www.unrealircd.org/docs/Do_not_run_as_root\n" 529 "\n"); 530 exit(1); 531 } 532 #endif 533 #ifndef _WIN32 534 myargv = argv; 535 #else 536 cmdLine = GetCommandLine(); 537 #endif 538 #ifndef _WIN32 539 (void)umask(077); /* better safe than sorry --SRB */ 540 #else 541 init_winsock(); 542 #endif 543 setup_signals(); 544 545 memset(&irccounts, '\0', sizeof(irccounts)); 546 irccounts.servers = 1; 547 548 mp_pool_init(); 549 dbuf_init(); 550 initlists(); 551 initlist_channels(); 552 553 early_init_tls(); 554 url_init(); 555 tkl_init(); 556 umode_init(); 557 extcmode_init(); 558 efunctions_init(); 559 clear_scache_hash_table(); 560 #ifndef _WIN32 561 /* Make it so we can dump core */ 562 corelim.rlim_cur = corelim.rlim_max = RLIM_INFINITY; 563 setrlimit(RLIMIT_CORE, &corelim); 564 #endif 565 /* 566 * ** All command line parameters have the syntax "-fstring" 567 * ** or "-f string" (e.g. the space is optional). String may 568 * ** be empty. Flag characters cannot be concatenated (like 569 * ** "-fxyz"), it would conflict with the form "-fstring". 570 */ 571 while (--argc > 0 && (*++argv)[0] == '-') { 572 char *p = argv[0] + 1; 573 int flag = *p++; 574 if (flag == '\0' || *p == '\0') { 575 if (argc > 1 && argv[1][0] != '-') { 576 p = *++argv; 577 argc -= 1; 578 } else 579 p = ""; 580 } 581 switch (flag) 582 { 583 case 'F': 584 bootopt |= BOOT_NOFORK; 585 break; 586 case 'f': 587 #ifndef _WIN32 588 if ((uid != euid) || (gid != egid)) 589 { 590 printf("ERROR: Command line config with a setuid/setgid ircd is not allowed"); 591 exit(1); 592 } 593 #endif 594 safe_strdup(configfile, p); 595 convert_to_absolute_path(&configfile, CONFDIR); 596 break; 597 #if 0 598 case 'S': 599 charsys_dump_table(p ? p : "*"); 600 //unrealdb_test(); 601 #endif 602 #ifndef _WIN32 603 case 't': 604 bootopt |= BOOT_TTY; 605 break; 606 case 'v': 607 (void)printf("%s\n", version); 608 #else 609 case 'v': 610 if (!IsService) { 611 MessageBox(NULL, version, 612 "UnrealIRCD/Win32 version", MB_OK); 613 } 614 #endif 615 exit(0); 616 case 'C': 617 config_verbose = atoi(p); 618 break; 619 case 'c': 620 loop.config_test = 1; 621 break; 622 case 'x': 623 #ifdef DEBUGMODE 624 debuglevel = atoi(p); 625 debugmode = *p ? p : "0"; 626 bootopt |= BOOT_DEBUG; 627 break; 628 #else 629 # ifndef _WIN32 630 (void)fprintf(stderr, 631 "%s: DEBUGMODE must be defined for -x y\n", 632 myargv[0]); 633 # else 634 if (!IsService) { 635 MessageBox(NULL, 636 "DEBUGMODE must be defined for -x option", 637 "UnrealIRCD/32", MB_OK); 638 } 639 # endif 640 exit(0); 641 #endif 642 case 'K': 643 { 644 char *p = NULL; 645 if (chdir(TMPDIR) < 0) 646 { 647 fprintf(stderr, "Could not change to directory '%s'\n", TMPDIR); 648 exit(1); 649 } 650 fprintf(stderr, "Starting crash test!\n"); 651 *p = 'a'; 652 fprintf(stderr, "It is impossible to get here\n"); 653 exit(0); 654 } 655 case 'R': 656 report_crash(); 657 exit(0); 658 #ifndef _WIN32 659 case 'm': 660 modulemanager(argc, argv); 661 exit(0); 662 #endif 663 case '8': 664 utf8_test(); 665 exit(0); 666 case 'L': 667 loop.boot_function = link_generator; 668 break; 669 default: 670 #ifndef _WIN32 671 return bad_command(myargv[0]); 672 #else 673 return bad_command(NULL); 674 #endif 675 break; 676 } 677 } 678 679 #if !defined(_WIN32) 680 #ifndef _WIN32 681 mkdir(TMPDIR, S_IRUSR|S_IWUSR|S_IXUSR); /* Create the tmp dir, if it doesn't exist */ 682 mkdir(CACHEDIR, S_IRUSR|S_IWUSR|S_IXUSR); /* Create the cache dir, if it doesn't exist */ 683 #else 684 mkdir(TMPDIR); 685 mkdir(CACHEDIR); 686 #endif 687 if (chdir(TMPDIR)) { 688 # ifndef _WIN32 689 perror("chdir"); 690 fprintf(stderr, "ERROR: Unable to change to directory '%s'\n", TMPDIR); 691 # else 692 if (!IsService) { 693 MessageBox(NULL, strerror(GetLastError()), 694 "UnrealIRCD/32: chdir()", MB_OK); 695 } 696 # endif 697 exit(-1); 698 } 699 #endif 700 #ifndef _WIN32 701 /* 702 * didn't set debuglevel 703 */ 704 /* 705 * but asked for debugging output to tty 706 */ 707 if ((debuglevel < 0) && (bootopt & BOOT_TTY)) { 708 (void)fprintf(stderr, 709 "you specified -t without -x. use -x <n>\n"); 710 exit(-1); 711 } 712 #endif 713 714 /* HACK! This ifndef should be removed when the restart-on-w32-brings-up-dialog bug 715 * is fixed. This is just an ugly "ignore the invalid parameter" thing ;). -- Syzop 716 */ 717 #ifndef _WIN32 718 if (argc > 0) 719 return bad_command(myargv[0]); /* This should exit out */ 720 #endif 721 #ifndef _WIN32 722 fprintf(stderr, "%s", unreallogo); 723 fprintf(stderr, " v%s\n\n", VERSIONONLY); 724 fprintf(stderr, "UnrealIRCd is brought to you by Bram Matthys (Syzop),\n" 725 "Krzysztof Beresztant (k4be), Gottem and i\n\n"); 726 727 fprintf(stderr, "Using the following libraries:\n"); 728 fprintf(stderr, "* %s\n", SSLeay_version(SSLEAY_VERSION)); 729 fprintf(stderr, "* libsodium %s\n", sodium_version_string()); 730 #ifdef USE_LIBCURL 731 fprintf(stderr, "* %s\n", curl_version()); 732 #endif 733 fprintf(stderr, "* c-ares %s\n", ares_version(NULL)); 734 fprintf(stderr, "* %s\n", pcre2_version()); 735 #endif 736 #if JANSSON_VERSION_HEX >= 0x020D00 737 fprintf(stderr, "* jansson %s\n", jansson_version_str()); 738 #endif 739 check_user_limit(); 740 #ifndef _WIN32 741 fprintf(stderr, "\n"); 742 fprintf(stderr, "This server can handle %d concurrent sockets (%d clients + %d reserve)\n\n", 743 maxclients+CLIENTS_RESERVE, maxclients, CLIENTS_RESERVE); 744 #endif 745 init_CommandHash(); 746 initwhowas(); 747 initstats(); 748 if (!loop.config_test) 749 DeleteTempModules(); 750 #if !defined(_WIN32) && !defined(_AMIGA) && !defined(OSXTIGER) && DEFAULT_PERMISSIONS != 0 751 /* Hack to stop people from being able to read the config file */ 752 (void)chmod(CPATH, DEFAULT_PERMISSIONS); 753 #endif 754 init_dynconf(); 755 init_sys(); 756 clicap_init(); 757 /* 758 * Add default class 759 */ 760 default_class = safe_alloc(sizeof(ConfigItem_class)); 761 default_class->flag.permanent = 1; 762 default_class->pingfreq = 120; 763 default_class->maxclients = 100; 764 default_class->sendq = DEFAULT_RECVQ; 765 default_class->name = "default"; 766 AddListItem(default_class, conf_class); 767 if (config_read_start() < 0) 768 exit(-1); 769 while (!is_config_read_finished()) 770 { 771 gettimeofday(&timeofday_tv, NULL); 772 timeofday = timeofday_tv.tv_sec; 773 url_socket_timeout(NULL); 774 unrealdns_timeout(NULL); 775 fd_select(500); 776 } 777 if (config_test() < 0) 778 exit(-1); 779 load_tunefile(); 780 make_umodestr(); 781 SetListening(&me); 782 me.local->fd = -1; 783 SetMe(&me); 784 make_server(&me); 785 umodes_check_for_changes(); 786 charsys_check_for_changes(); 787 if (!find_command_simple("PRIVMSG")) 788 { 789 config_error("Someone forgot to load modules with proper commands in them. READ THE DOCUMENTATION"); 790 exit(-4); 791 } 792 793 if (!init_tls()) 794 { 795 config_error("Failed to load TLS (see errors above). UnrealIRCd can not start."); 796 #ifdef _WIN32 797 win_error(); /* display error dialog box */ 798 #endif 799 exit(9); 800 } 801 unreal_log(ULOG_INFO, "config", "CONFIG_PASSED", NULL, "Configuration test passed OK"); 802 if (loop.config_test) 803 { 804 fflush(stderr); 805 exit(0); 806 } 807 if (loop.boot_function) 808 loop.boot_function(); 809 open_debugfile(); 810 me.local->port = 6667; /* pointless? */ 811 applymeblock(); 812 #ifdef HAVE_SYSLOG 813 openlog("ircd", LOG_PID | LOG_NDELAY, LOG_DAEMON); 814 #endif 815 config_run(); 816 unreal_log(ULOG_INFO, "main", "UNREALIRCD_START", NULL, "UnrealIRCd started."); 817 818 read_motd(conf_files->botmotd_file, &botmotd); 819 read_motd(conf_files->rules_file, &rules); 820 read_motd(conf_files->opermotd_file, &opermotd); 821 read_motd(conf_files->motd_file, &motd); 822 read_motd(conf_files->smotd_file, &smotd); 823 read_motd(conf_files->svsmotd_file, &svsmotd); 824 825 me.hopcount = 0; 826 me.local->authfd = -1; 827 me.user = NULL; 828 me.direction = &me; 829 830 /* 831 * This listener will never go away 832 */ 833 me_hash = find_or_add(me.name); 834 timeofday = time(NULL); 835 me.local->last_msg_received = me.local->fake_lag = me.local->creationtime = me.server->boottime = TStime(); 836 me.server->features.protocol = UnrealProtocol; 837 safe_strdup(me.server->features.software, version); 838 add_to_client_hash_table(me.name, &me); 839 add_to_id_hash_table(me.id, &me); 840 list_add(&me.client_node, &global_server_list); 841 #if !defined(_AMIGA) && !defined(_WIN32) && !defined(NO_FORKING) 842 if (!(bootopt & BOOT_NOFORK)) 843 { 844 pid_t p; 845 p = fork(); 846 if (p < 0) 847 { 848 fprintf(stderr, "Could not create background job. Call to fork() failed: %s\n", 849 strerror(errno)); 850 exit(-1); 851 } 852 if (p > 0) 853 { 854 /* Background job created and we are the parent. We can terminate. */ 855 exit(0); 856 } 857 /* Background process (child) continues below... */ 858 close_std_descriptors(); 859 fd_fork(); 860 loop.forked = 1; 861 } 862 #endif 863 #ifdef _WIN32 864 loop.forked = 1; 865 #endif 866 867 fix_timers(); 868 write_pidfile(); 869 loop.booted = 1; 870 #if defined(HAVE_SETPROCTITLE) 871 setproctitle("%s", me.name); 872 #elif defined(HAVE_PSTAT) 873 pstats.pst_command = me.name; 874 pstat(PSTAT_SETCMD, pstats, strlen(me.name), 0, 0); 875 #elif defined(HAVE_PSSTRINGS) 876 PS_STRINGS->ps_nargvstr = 1; 877 PS_STRINGS->ps_argvstr = me.name; 878 #endif 879 module_loadall(); 880 loop.config_status = CONFIG_STATUS_COMPLETE; 881 882 #ifndef _WIN32 883 SocketLoop(NULL); 884 #endif 885 return 1; 886 } 887 888 /** The main loop that the server will run all the time. 889 * On Windows this is a thread, on *NIX we simply jump here from main() 890 * when the server is ready. 891 */ 892 void SocketLoop(void *dummy) 893 { 894 struct timeval doevents_tv, process_clients_tv; 895 896 memset(&doevents_tv, 0, sizeof(doevents_tv)); 897 memset(&process_clients_tv, 0, sizeof(process_clients_tv)); 898 899 while (1) 900 { 901 gettimeofday(&timeofday_tv, NULL); 902 timeofday = timeofday_tv.tv_sec; 903 904 detect_timeshift_and_warn(); 905 906 if (minimum_msec_since_last_run(&doevents_tv, 250)) 907 DoEvents(); 908 909 /* Update statistics */ 910 if (irccounts.clients > irccounts.global_max) 911 irccounts.global_max = irccounts.clients; 912 if (irccounts.me_clients > irccounts.me_max) 913 irccounts.me_max = irccounts.me_clients; 914 915 /* Process I/O */ 916 fd_select(SOCKETLOOP_MAX_DELAY); 917 918 if (minimum_msec_since_last_run(&process_clients_tv, 200)) 919 process_clients(); 920 921 /* Check if there are pending "actions". 922 * These are actions that should be done outside of 923 * process_clients() and fd_select() when we are not 924 * processing any clients. 925 */ 926 if (dorehash) 927 { 928 request_rehash(NULL); 929 dorehash = 0; 930 } 931 if (dorestart) 932 { 933 server_reboot("SIGINT"); 934 } 935 if (doreloadcert) 936 { 937 unreal_log(ULOG_INFO, "config", "CONFIG_RELOAD_TLS", NULL, "Reloading all TLS related data (./unrealircd reloadtls)"); 938 reinit_tls(); 939 doreloadcert = 0; 940 } 941 /* If rehashing, check if we are done. */ 942 if (loop.rehashing && is_config_read_finished()) 943 rehash_internal(loop.rehash_save_client); 944 } 945 } 946 947 /* 948 * open_debugfile 949 * 950 * If the -t option is not given on the command line when the server is 951 * started, all debugging output is sent to the file set by LPATH in config.h 952 * If the debuglevel is not set from the command line by -x, use /dev/null 953 * as the dummy logfile as long as DEBUGMODE has been defined, else don't 954 * waste the fd. 955 */ 956 static void open_debugfile(void) 957 { 958 #ifdef DEBUGMODE 959 int fd; 960 Client *client; 961 if (debuglevel >= 0) { 962 client = make_client(NULL, NULL); 963 client->local->fd = 2; 964 SetLog(client); 965 client->local->port = debuglevel; 966 client->flags = 0; 967 968 strlcpy(client->local->sockhost, me.local->sockhost, sizeof client->local->sockhost); 969 # ifndef _WIN32 970 /*(void)printf("isatty = %d ttyname = %#x\n", 971 isatty(2), (u_int)ttyname(2)); */ 972 if (!(bootopt & BOOT_TTY)) { /* leave debugging output on fd 2 */ 973 if (truncate(LOGFILE, 0) < 0) 974 fprintf(stderr, "WARNING: could not truncate log file '%s'\n", LOGFILE); 975 if ((fd = open(LOGFILE, O_WRONLY | O_CREAT, 0600)) < 0) 976 if ((fd = open("/dev/null", O_WRONLY)) < 0) 977 exit(-1); 978 979 #if 1 980 client->local->fd = fd; 981 debugfd = fd; 982 #else 983 /* if (fd != 2) { 984 (void)dup2(fd, 2); 985 (void)close(fd); 986 } -- hands off stderr! */ 987 #endif 988 strlcpy(client->name, LOGFILE, sizeof(client->name)); 989 } else if (isatty(2) && ttyname(2)) 990 strlcpy(client->name, ttyname(2), sizeof(client->name)); 991 else 992 # endif 993 strlcpy(client->name, "FD2-Pipe", sizeof(client->name)); 994 } 995 #endif 996 } 997 998 static void setup_signals() 999 { 1000 #ifndef _WIN32 1001 struct sigaction act; 1002 act.sa_handler = SIG_IGN; 1003 act.sa_flags = 0; 1004 (void)sigemptyset(&act.sa_mask); 1005 (void)sigaddset(&act.sa_mask, SIGPIPE); 1006 (void)sigaddset(&act.sa_mask, SIGALRM); 1007 #ifdef SIGWINCH 1008 (void)sigaddset(&act.sa_mask, SIGWINCH); 1009 (void)sigaction(SIGWINCH, &act, NULL); 1010 #endif 1011 (void)sigaction(SIGPIPE, &act, NULL); 1012 act.sa_handler = ignore_this_signal; 1013 (void)sigaction(SIGALRM, &act, NULL); 1014 act.sa_handler = s_rehash; 1015 (void)sigemptyset(&act.sa_mask); 1016 (void)sigaddset(&act.sa_mask, SIGHUP); 1017 (void)sigaction(SIGHUP, &act, NULL); 1018 act.sa_handler = s_restart; 1019 (void)sigaddset(&act.sa_mask, SIGINT); 1020 (void)sigaction(SIGINT, &act, NULL); 1021 act.sa_handler = s_die; 1022 (void)sigaddset(&act.sa_mask, SIGTERM); 1023 (void)sigaction(SIGTERM, &act, NULL); 1024 act.sa_handler = s_reloadcert; 1025 (void)sigemptyset(&act.sa_mask); 1026 (void)sigaddset(&act.sa_mask, SIGUSR1); 1027 (void)sigaction(SIGUSR1, &act, NULL); 1028 #endif 1029 }