unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
user.c (26152B)
1 /* 2 * Unreal Internet Relay Chat Daemon, src/user.c 3 * Copyright (C) 1990 Jarkko Oikarinen and 4 * University of Oulu, Computing Center 5 * 6 * See file AUTHORS in IRC package for additional names of 7 * the programmers. 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 1, or (at your option) 12 * any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 */ 23 24 /** @file 25 * @brief User-related functions 26 */ 27 28 /* s_user.c 2.74 2/8/94 (C) 1988 University of Oulu, Computing Center and Jarkko Oikarinen */ 29 30 #include "unrealircd.h" 31 32 MODVAR int dontspread = 0; 33 34 /** Inhibit labeled/response reply. This means it will result in an empty ACK 35 * because we cannot handle the command via labeled-reponse. Rare, but 36 * possible in for example /TRACE which multiple servers handle and which 37 * has no clear end. 38 */ 39 MODVAR int labeled_response_inhibit = 0; 40 41 /** Force a labeled/response reply (of course, only if a label is present etc.). 42 * This is used in case the "a remote server is handling the request" was 43 * incorrect and there were 0 responses. This is the case for PRIVMSG. 44 * It will force an empty ACK. 45 * No, this cannot be merged with the other one. Also, the other one 46 * (labeled_response_inhibit) has priority over this one (labeled_response_force). 47 */ 48 MODVAR int labeled_response_force = 0; 49 50 /** Inhibit labeled/response END. Only used in /LIST. 51 */ 52 MODVAR int labeled_response_inhibit_end = 0; 53 54 /** Set to 1 if an UTF8 incompatible nick character set is in use */ 55 MODVAR int non_utf8_nick_chars_in_use = 0; 56 57 /** Set a new vhost on the user 58 * @param client The client (user) 59 * @param host The new vhost 60 */ 61 void iNAH_host(Client *client, const char *host) 62 { 63 if (!client->user) 64 return; 65 66 userhost_save_current(client); 67 68 safe_strdup(client->user->virthost, host); 69 if (MyConnect(client)) 70 sendto_server(NULL, 0, 0, NULL, ":%s SETHOST :%s", client->id, client->user->virthost); 71 client->umodes |= UMODE_SETHOST|UMODE_HIDE; 72 73 userhost_changed(client); 74 } 75 76 /** Convert a user mode string to a bitmask - only used by config. 77 * @param umode The user mode string 78 * @returns the user mode value (long) 79 */ 80 long set_usermode(const char *umode) 81 { 82 Umode *um; 83 int newumode; 84 int what; 85 const char *m; 86 87 newumode = 0; 88 what = MODE_ADD; 89 for (m = umode; *m; m++) 90 { 91 switch (*m) 92 { 93 case '+': 94 what = MODE_ADD; 95 break; 96 case '-': 97 what = MODE_DEL; 98 break; 99 case ' ': 100 case '\n': 101 case '\r': 102 case '\t': 103 break; 104 default: 105 for (um = usermodes; um; um = um->next) 106 { 107 if (um->letter == *m) 108 { 109 if (what == MODE_ADD) 110 newumode |= um->mode; 111 else 112 newumode &= ~um->mode; 113 } 114 } 115 } 116 } 117 118 return newumode; 119 } 120 121 /** Convert a target pointer to an 8 bit hash, used for target limiting. */ 122 unsigned char hash_target(void *target) 123 { 124 uintptr_t v = (uintptr_t)target; 125 /* ircu does >> 16 and 8 but since our sizeof(Client) is 126 * towards 512 (and hence the alignment), that bit is useless. 127 * So we do >> 17 and 9. 128 */ 129 return (unsigned char)((v >> 17) ^ (v >> 9)); 130 } 131 132 /** target_limit_exceeded 133 * @param client The client. 134 * @param target The target client 135 * @param name The name of the target client (used in the error message) 136 * @retval Returns 1 if too many targets were addressed (do not send!), 0 if ok to send. 137 */ 138 int target_limit_exceeded(Client *client, void *target, const char *name) 139 { 140 u_char hash = hash_target(target); 141 int i; 142 int max_concurrent_conversations_users, max_concurrent_conversations_new_user_every; 143 FloodSettings *settings; 144 145 if (ValidatePermissionsForPath("immune:max-concurrent-conversations",client,NULL,NULL,NULL)) 146 return 0; 147 148 if (client->local->targets[0] == hash) 149 return 0; 150 151 settings = get_floodsettings_for_user(client, FLD_CONVERSATIONS); 152 max_concurrent_conversations_users = settings->limit[FLD_CONVERSATIONS]; 153 max_concurrent_conversations_new_user_every = settings->period[FLD_CONVERSATIONS]; 154 155 if (max_concurrent_conversations_users <= 0) 156 return 0; /* unlimited */ 157 158 /* Shouldn't be needed, but better check here than access out-of-bounds memory */ 159 if (max_concurrent_conversations_users > MAXCCUSERS) 160 max_concurrent_conversations_users = MAXCCUSERS; 161 162 for (i = 1; i < max_concurrent_conversations_users; i++) 163 { 164 if (client->local->targets[i] == hash) 165 { 166 /* Move this target hash to the first position */ 167 memmove(&client->local->targets[1], &client->local->targets[0], i); 168 client->local->targets[0] = hash; 169 return 0; 170 } 171 } 172 173 if (TStime() < client->local->nexttarget) 174 { 175 /* Target limit reached */ 176 client->local->nexttarget += 2; /* punish them some more */ 177 add_fake_lag(client, 2000); /* lag them up as well */ 178 179 flood_limit_exceeded_log(client, "max-concurrent-conversations"); 180 sendnumeric(client, ERR_TARGETTOOFAST, name, (long long)(client->local->nexttarget - TStime())); 181 182 return 1; 183 } 184 185 /* If not set yet or in the very past, then adjust it. 186 * This is so client->local->nexttarget=0 will become client->local->nexttarget=currenttime-... 187 */ 188 if (TStime() > client->local->nexttarget + 189 (max_concurrent_conversations_users * max_concurrent_conversations_new_user_every)) 190 { 191 client->local->nexttarget = TStime() - ((max_concurrent_conversations_users-1) * max_concurrent_conversations_new_user_every); 192 } 193 194 client->local->nexttarget += max_concurrent_conversations_new_user_every; 195 196 /* Add the new target (first move the rest, then add us at position 0 */ 197 memmove(&client->local->targets[1], &client->local->targets[0], max_concurrent_conversations_users - 1); 198 client->local->targets[0] = hash; 199 200 return 0; 201 } 202 203 /** De-duplicate a string of "x,x,y,z" to "x,y,z" 204 * @param buffer Input string 205 * @returns The new de-duplicated buffer (temporary storage, only valid until next canonize call) 206 */ 207 char *canonize(const char *buffer) 208 { 209 static char cbuf[2048]; 210 char tbuf[2048]; 211 char *s, *t, *cp = cbuf; 212 int l = 0; 213 char *p = NULL, *p2; 214 215 *cp = '\0'; 216 217 if (!buffer) 218 return NULL; 219 220 strlcpy(tbuf, buffer, sizeof(tbuf)); 221 for (s = strtoken(&p, tbuf, ","); s; s = strtoken(&p, NULL, ",")) 222 { 223 if (l) 224 { 225 for (p2 = NULL, t = strtoken(&p2, cbuf, ","); t; 226 t = strtoken(&p2, NULL, ",")) 227 if (!mycmp(s, t)) 228 break; 229 else if (p2) 230 p2[-1] = ','; 231 } 232 else 233 t = NULL; 234 if (!t) 235 { 236 if (l) 237 *(cp - 1) = ','; 238 else 239 l = 1; 240 strcpy(cp, s); 241 if (p) 242 cp += (p - s); 243 } 244 else if (p2) 245 p2[-1] = ','; 246 } 247 return cbuf; 248 } 249 250 /** Get user modes as a string. 251 * @param client The client 252 * @returns string of user modes (temporary storage) 253 */ 254 const char *get_usermode_string(Client *client) 255 { 256 static char buf[128]; 257 Umode *um; 258 259 strlcpy(buf, "+", sizeof(buf)); 260 for (um = usermodes; um; um = um->next) 261 if (client->umodes & um->mode) 262 strlcat_letter(buf, um->letter, sizeof(buf)); 263 264 return buf; 265 } 266 267 /** Get user modes as a string - buffer is specified. 268 * @param client The client 269 * @param buf The buffer to write to 270 * @param buflen The size of the buffer 271 * @returns string of user modes (buf) 272 */ 273 const char *get_usermode_string_r(Client *client, char *buf, size_t buflen) 274 { 275 Umode *um; 276 277 strlcpy(buf, "+", buflen); 278 for (um = usermodes; um; um = um->next) 279 if (client->umodes & um->mode) 280 strlcat_letter(buf, um->letter, buflen); 281 282 return buf; 283 } 284 285 /** Get user modes as a string - this one does not work on 'client' but directly on 'umodes'. 286 * @param umodes The user modes that are set 287 * @returns string of user modes (temporary storage) 288 */ 289 const char *get_usermode_string_raw(long umodes) 290 { 291 static char buf[128]; 292 Umode *um; 293 294 strlcpy(buf, "+", sizeof(buf)); 295 for (um = usermodes; um; um = um->next) 296 if (umodes & um->mode) 297 strlcat_letter(buf, um->letter, sizeof(buf)); 298 299 return buf; 300 } 301 302 /** Get user modes as a string - this one does not work on 'client' but directly on 'umodes'. 303 * @param umodes The user modes that are set 304 * @param buf The buffer to write to 305 * @param buflen The size of the buffer 306 * @returns string of user modes (buf) 307 */ 308 const char *get_usermode_string_raw_r(long umodes, char *buf, size_t buflen) 309 { 310 Umode *um; 311 312 strlcpy(buf, "+", buflen); 313 for (um = usermodes; um; um = um->next) 314 if (umodes & um->mode) 315 strlcat_letter(buf, um->letter, buflen); 316 317 return buf; 318 } 319 320 321 /** Set a new snomask on the user. 322 * The user is not informed of the change by this function. 323 * @param client The client 324 * @param snomask The snomask to add or delete (eg: "+k-c") 325 */ 326 void set_snomask(Client *client, const char *snomask) 327 { 328 int what = MODE_ADD; /* keep this an int. -- Syzop */ 329 const char *p; 330 int i; 331 332 if (snomask == NULL) 333 { 334 remove_all_snomasks(client); 335 return; 336 } 337 338 for (p = snomask; p && *p; p++) 339 { 340 switch (*p) 341 { 342 case '+': 343 what = MODE_ADD; 344 break; 345 case '-': 346 what = MODE_DEL; 347 break; 348 default: 349 if (what == MODE_ADD) 350 { 351 if (!isalpha(*p) || !is_valid_snomask(*p)) 352 continue; 353 addlettertodynamicstringsorted(&client->user->snomask, *p); 354 } else { 355 delletterfromstring(client->user->snomask, *p); 356 } 357 break; 358 } 359 } 360 /* If the snomask becomes empty ("") then set it to NULL and user mode -s */ 361 if (client->user->snomask && !*client->user->snomask) 362 remove_all_snomasks(client); 363 } 364 365 /** Build the MODE line with (modified) user modes for this user. 366 * @author Originally by avalon. 367 */ 368 void build_umode_string(Client *client, long old, long sendmask, char *umode_buf) 369 { 370 Umode *um; 371 long flag; 372 char *m; 373 int what = MODE_NULL; 374 375 /* 376 * build a string in umode_buf to represent the change in the user's 377 * mode between the new (client->flag) and 'old'. 378 */ 379 m = umode_buf; 380 *m = '\0'; 381 for (um = usermodes; um; um = um->next) 382 { 383 flag = um->mode; 384 if (MyUser(client) && !(flag & sendmask)) 385 continue; 386 if ((flag & old) && !(client->umodes & flag)) 387 { 388 if (what == MODE_DEL) 389 *m++ = um->letter; 390 else 391 { 392 what = MODE_DEL; 393 *m++ = '-'; 394 *m++ = um->letter; 395 } 396 } 397 else if (!(flag & old) && (client->umodes & flag)) 398 { 399 if (what == MODE_ADD) 400 *m++ = um->letter; 401 else 402 { 403 what = MODE_ADD; 404 *m++ = '+'; 405 *m++ = um->letter; 406 } 407 } 408 } 409 *m = '\0'; 410 } 411 412 /** Send usermode change to other servers. 413 * @param client The client 414 * @param show_to_user Set to 1 to show the MODE change to the user 415 * @param old The old user modes set on the client 416 */ 417 void send_umode_out(Client *client, int show_to_user, long old) 418 { 419 Client *acptr; 420 char buf[512]; 421 422 build_umode_string(client, old, SEND_UMODES, buf); 423 424 list_for_each_entry(acptr, &server_list, special_node) 425 { 426 if ((acptr != client) && (acptr != client->direction) && *buf) 427 { 428 sendto_one(acptr, NULL, ":%s UMODE2 %s", 429 client->name, buf); 430 } 431 } 432 433 if (MyUser(client) && show_to_user) 434 { 435 build_umode_string(client, old, ALL_UMODES, buf); 436 if (*buf) 437 sendto_one(client, NULL, ":%s MODE %s :%s", client->name, client->name, buf); 438 } 439 } 440 441 static MaxTarget *maxtargets = NULL; /**< For set::max-targets-per-command configuration */ 442 443 static void maxtarget_add_sorted(MaxTarget *n) 444 { 445 MaxTarget *e; 446 447 if (!maxtargets) 448 { 449 maxtargets = n; 450 return; 451 } 452 453 for (e = maxtargets; e; e = e->next) 454 { 455 if (strcmp(n->cmd, e->cmd) < 0) 456 { 457 /* Insert us before */ 458 if (e->prev) 459 e->prev->next = n; 460 else 461 maxtargets = n; /* new head */ 462 n->prev = e->prev; 463 464 n->next = e; 465 e->prev = n; 466 return; 467 } 468 if (!e->next) 469 { 470 /* Append us at end */ 471 e->next = n; 472 n->prev = e; 473 return; 474 } 475 } 476 } 477 478 /** Find a maxtarget structure for a cmd (internal) */ 479 MaxTarget *findmaxtarget(const char *cmd) 480 { 481 MaxTarget *m; 482 483 for (m = maxtargets; m; m = m->next) 484 if (!strcasecmp(m->cmd, cmd)) 485 return m; 486 return NULL; 487 } 488 489 /** Set a maximum targets per command restriction */ 490 void setmaxtargets(const char *cmd, int limit) 491 { 492 MaxTarget *m = findmaxtarget(cmd); 493 if (!m) 494 { 495 char cmdupper[64]; 496 strlcpy(cmdupper, cmd, sizeof(cmdupper)); 497 strtoupper(cmdupper); 498 m = safe_alloc(sizeof(MaxTarget)); 499 safe_strdup(m->cmd, cmdupper); 500 maxtarget_add_sorted(m); 501 } 502 m->limit = limit; 503 } 504 505 /** Free all set::max-targets-per-command configuration (internal) */ 506 void freemaxtargets(void) 507 { 508 MaxTarget *m, *m_next; 509 510 for (m = maxtargets; m; m = m_next) 511 { 512 m_next = m->next; 513 safe_free(m->cmd); 514 safe_free(m); 515 } 516 maxtargets = NULL; 517 } 518 519 /** Return the maximum number of targets permitted for a command */ 520 int max_targets_for_command(const char *cmd) 521 { 522 MaxTarget *m = findmaxtarget(cmd); 523 if (m) 524 return m->limit; 525 return 1; /* default to 1 */ 526 } 527 528 void set_isupport_targmax(void) 529 { 530 char buf[512], tbuf[64]; 531 MaxTarget *m; 532 533 *buf = '\0'; 534 for (m = maxtargets; m; m = m->next) 535 { 536 if (m->limit == MAXTARGETS_MAX) 537 snprintf(tbuf, sizeof(tbuf), "%s:", m->cmd); 538 else 539 snprintf(tbuf, sizeof(tbuf), "%s:%d", m->cmd, m->limit); 540 541 if (*buf) 542 strlcat(buf, ",", sizeof(buf)); 543 strlcat(buf, tbuf, sizeof(buf)); 544 } 545 ISupportSet(NULL, "TARGMAX", buf); 546 } 547 548 /** Called between config test and config run */ 549 void set_targmax_defaults(void) 550 { 551 /* Free existing... */ 552 freemaxtargets(); 553 554 /* Set the defaults */ 555 setmaxtargets("PRIVMSG", 4); 556 setmaxtargets("NOTICE", 1); 557 setmaxtargets("TAGMSG", 1); 558 setmaxtargets("NAMES", 1); // >1 is not supported 559 setmaxtargets("WHOIS", 1); 560 setmaxtargets("WHOWAS", 1); // >1 is not supported 561 setmaxtargets("KICK", 4); 562 setmaxtargets("LIST", MAXTARGETS_MAX); 563 setmaxtargets("JOIN", MAXTARGETS_MAX); 564 setmaxtargets("PART", MAXTARGETS_MAX); 565 setmaxtargets("SAJOIN", MAXTARGETS_MAX); 566 setmaxtargets("SAPART", MAXTARGETS_MAX); 567 setmaxtargets("KILL", MAXTARGETS_MAX); 568 setmaxtargets("DCCALLOW", MAXTARGETS_MAX); 569 /* The following 3 are space-separated (and actually the previous 570 * mentioned DCCALLOW is both space-and-comma separated). 571 * It seems most IRCd's don't list space-separated targets list 572 * in TARGMAX... On the other hand, why not? It says nowhere in 573 * the TARGMAX specification that it's only for comma-separated 574 * commands. So let's be nice and consistent and inform the 575 * clients about the limits for such commands as well: 576 */ 577 setmaxtargets("USERHOST", MAXTARGETS_MAX); // not configurable 578 setmaxtargets("USERIP", MAXTARGETS_MAX); // not configurable 579 setmaxtargets("ISON", MAXTARGETS_MAX); // not configurable 580 setmaxtargets("WATCH", MAXTARGETS_MAX); // not configurable 581 } 582 583 /** Is the user handshake finished and can register_user() be called? 584 * This checks things like: do we have a NICK, USER, nospoof, 585 * and any other things modules may add: 586 * eg: the cap module checks if client capability negotiation 587 * is in progress 588 */ 589 int is_handshake_finished(Client *client) 590 { 591 Hook *h; 592 int n; 593 594 for (h = Hooks[HOOKTYPE_IS_HANDSHAKE_FINISHED]; h; h = h->next) 595 { 596 n = (*(h->func.intfunc))(client); 597 if (n == 0) 598 return 0; /* We can stop already */ 599 } 600 601 /* I figured these can be here, in the core: */ 602 if (client->user && *client->user->username && client->name[0] && IsNotSpoof(client)) 603 return 1; 604 605 return 0; 606 } 607 608 /** Should we show connection info to the user? 609 * This depends on the set::show-connect-info setting but also 610 * on various other properties, such as serversonly ports, 611 * websocket, etc. 612 * If someone needs it, then we can also call a hook here. Just tell us. 613 */ 614 int should_show_connect_info(Client *client) 615 { 616 if (SHOWCONNECTINFO && 617 !client->server && 618 !IsServersOnlyListener(client->local->listener) && 619 !client->local->listener->websocket_options) 620 { 621 return 1; 622 } 623 return 0; 624 } 625 626 /* (helper function for uid_get) */ 627 static char uid_int_to_char(int v) 628 { 629 if (v < 10) 630 return '0'+v; 631 else 632 return 'A'+v-10; 633 } 634 635 /** Acquire a new unique UID */ 636 const char *uid_get(void) 637 { 638 Client *acptr; 639 static char uid[IDLEN]; 640 static int uidcounter = 0; 641 642 uidcounter++; 643 if (uidcounter == 36*36) 644 uidcounter = 0; 645 646 do 647 { 648 snprintf(uid, sizeof(uid), "%s%c%c%c%c%c%c", 649 me.id, 650 uid_int_to_char(getrandom8() % 36), 651 uid_int_to_char(getrandom8() % 36), 652 uid_int_to_char(getrandom8() % 36), 653 uid_int_to_char(getrandom8() % 36), 654 uid_int_to_char(uidcounter / 36), 655 uid_int_to_char(uidcounter % 36)); 656 acptr = find_client(uid, NULL); 657 } while (acptr); 658 659 return uid; 660 } 661 662 /** Get cloaked host for user */ 663 const char *getcloak(Client *client) 664 { 665 if (!*client->user->cloakedhost) 666 { 667 /* need to calculate (first-time) */ 668 make_cloakedhost(client, client->user->realhost, client->user->cloakedhost, sizeof(client->user->cloakedhost)); 669 } 670 671 return client->user->cloakedhost; 672 } 673 674 /** Calculate the cloaked host for a client. 675 * @param client The client 676 * @param curr The real host or real IP 677 * @param buf Buffer to store the new cloaked host in 678 * @param buflen Length of the buffer (should be HOSTLEN+1) 679 */ 680 void make_cloakedhost(Client *client, const char *curr, char *buf, size_t buflen) 681 { 682 const char *p; 683 char host[256], *q; 684 const char *mask; 685 686 /* Convert host to lowercase and cut off at 255 bytes just to be sure */ 687 for (p = curr, q = host; *p && (q < host+sizeof(host)-1); p++, q++) 688 *q = tolower(*p); 689 *q = '\0'; 690 691 /* Call the cloaking layer */ 692 if (RCallbacks[CALLBACKTYPE_CLOAK_EX] != NULL) 693 mask = RCallbacks[CALLBACKTYPE_CLOAK_EX]->func.stringfunc(client, host); 694 else if (RCallbacks[CALLBACKTYPE_CLOAK] != NULL) 695 mask = RCallbacks[CALLBACKTYPE_CLOAK]->func.stringfunc(host); 696 else 697 mask = curr; 698 699 strlcpy(buf, mask, buflen); 700 } 701 702 /** Called after a user is logged in (or out) of a services account */ 703 void user_account_login(MessageTag *recv_mtags, Client *client) 704 { 705 if (MyConnect(client)) 706 { 707 find_shun(client); 708 if (find_tkline_match(client, 0) && IsDead(client)) 709 return; 710 } 711 RunHook(HOOKTYPE_ACCOUNT_LOGIN, client, recv_mtags); 712 } 713 714 /** Should we hide the idle time of 'target' to user 'client'? 715 * This depends on the set::hide-idle-time policy. 716 */ 717 int hide_idle_time(Client *client, Client *target) 718 { 719 /* First of all, IRCOps bypass the restriction */ 720 if (IsOper(client)) 721 return 0; 722 723 /* Other than that, it depends on the settings: */ 724 switch (iConf.hide_idle_time) 725 { 726 case HIDE_IDLE_TIME_NEVER: 727 return 0; 728 case HIDE_IDLE_TIME_ALWAYS: 729 return 1; 730 case HIDE_IDLE_TIME_USERMODE: 731 case HIDE_IDLE_TIME_OPER_USERMODE: 732 if (target->umodes & UMODE_HIDLE) 733 return 1; 734 return 0; 735 default: 736 return 0; 737 } 738 } 739 740 /** Get creation time of a client. 741 * @param client The client to check (user, server, anything) 742 * @returns the time when the client first connected to IRC, or 0 for unknown. 743 */ 744 time_t get_creationtime(Client *client) 745 { 746 const char *str; 747 748 /* Shortcut for local clients */ 749 if (client->local) 750 return client->local->creationtime; 751 752 /* Otherwise, hopefully available through this... */ 753 str = moddata_client_get(client, "creationtime"); 754 if (!BadPtr(str) && (*str != '0')) 755 return atoll(str); 756 return 0; 757 } 758 759 /** Get how long a client is connected to IRC. 760 * @param client The client to check 761 * @returns how long the client is connected to IRC (number of seconds) 762 */ 763 long get_connected_time(Client *client) 764 { 765 const char *str; 766 long connect_time = 0; 767 768 /* Shortcut for local clients */ 769 if (client->local) 770 return TStime() - client->local->creationtime; 771 772 /* Otherwise, hopefully available through this... */ 773 str = moddata_client_get(client, "creationtime"); 774 if (!BadPtr(str) && (*str != '0')) 775 return TStime() - atoll(str); 776 return 0; 777 } 778 779 /** Return extended information about user for the "Client connecting" line. 780 * @returns A string such as "[secure] [reputation: 5]", never returns NULL. 781 */ 782 const char *get_connect_extinfo(Client *client) 783 { 784 static char retbuf[512]; 785 char tmp[512]; 786 const char *s; 787 const char *secgroups; 788 NameValuePrioList *list = NULL, *e; 789 790 /* From modules... */ 791 RunHook(HOOKTYPE_CONNECT_EXTINFO, client, &list); 792 793 /* And some built-in: */ 794 795 /* "vhost": this should be first */ 796 if (IsHidden(client)) 797 add_nvplist(&list, -1000000, "vhost", client->user->virthost); 798 799 /* "class": second */ 800 if (MyUser(client) && client->local->class) 801 add_nvplist(&list, -100000, "class", client->local->class->name); 802 803 /* "secure": TLS */ 804 s = tls_get_cipher(client); 805 if (s) 806 add_nvplist(&list, -1000, "secure", s); 807 else if (IsSecure(client) || IsSecureConnect(client)) 808 add_nvplist(&list, -1000, "secure", NULL); /* old server or otherwise no details (eg: fake secure) */ 809 810 /* services account? */ 811 if (IsLoggedIn(client)) 812 add_nvplist(&list, -500, "account", client->user->account); 813 814 /* security groups */ 815 secgroups = get_security_groups(client); 816 if (secgroups) 817 add_nvplist(&list, 100, "security-groups", secgroups); 818 819 /* tkl shunned */ 820 if (IsShunned(client)) 821 add_nvplist(&list, 110, "shunned", NULL); 822 823 *retbuf = '\0'; 824 for (e = list; e; e = e->next) 825 { 826 if (e->value) 827 snprintf(tmp, sizeof(tmp), "[%s: %s] ", e->name, e->value); 828 else 829 snprintf(tmp, sizeof(tmp), "[%s] ", e->name); 830 strlcat(retbuf, tmp, sizeof(retbuf)); 831 } 832 /* Cut off last space (unless empty string) */ 833 if (*retbuf) 834 retbuf[strlen(retbuf)-1] = '\0'; 835 836 /* Free the list, as it was only used to build retbuf */ 837 free_nvplist(list); 838 839 return retbuf; 840 } 841 842 /** Log a message that flood protection kicked in for the client. 843 * This sends to the +f snomask at the moment. 844 * @param client The client to check flood for (local user) 845 * @param opt The flood option (eg FLD_AWAY) 846 */ 847 void flood_limit_exceeded_log(Client *client, const char *floodname) 848 { 849 char buf[1024]; 850 851 // NOTE: If you ever change this format, there are a few more 852 // direct unreal_log() calls with "FLOOD_BLOCKED" in the file 853 // src/modules/targetfloodprot.c, so update those as well. 854 unreal_log(ULOG_INFO, "flood", "FLOOD_BLOCKED", client, 855 "Flood blocked ($flood_type) from $client.details [$client.ip]", 856 log_data_string("flood_type", floodname)); 857 } 858 859 /** Is the flood limit exceeded for an option? eg for away-flood. 860 * @param client The client to check flood for (local user) 861 * @param opt The flood option (eg FLD_AWAY) 862 * @note This increments the flood counter as well. 863 * @returns 1 if exceeded, 0 if not. 864 */ 865 int flood_limit_exceeded(Client *client, FloodOption opt) 866 { 867 FloodSettings *f; 868 869 if (!MyUser(client)) 870 return 0; 871 872 f = get_floodsettings_for_user(client, opt); 873 if (f->limit[opt] <= 0) 874 return 0; /* No limit set or unlimited */ 875 876 /* Ok, let's do the flood check */ 877 if ((client->local->flood[opt].t + f->period[opt]) <= timeofday) 878 { 879 /* Time exceeded, reset */ 880 client->local->flood[opt].count = 0; 881 client->local->flood[opt].t = timeofday; 882 } 883 if (client->local->flood[opt].count <= f->limit[opt]) 884 client->local->flood[opt].count++; 885 if (client->local->flood[opt].count > f->limit[opt]) 886 { 887 flood_limit_exceeded_log(client, floodoption_names[opt]); 888 return 1; /* Flood limit hit! */ 889 } 890 891 return 0; 892 } 893 894 /** Get the appropriate anti-flood settings block for this user. 895 * @param client The client, should be locally connected. 896 * @param opt The flood option we are interested in 897 * @returns The FloodSettings for this user, never returns NULL. 898 */ 899 FloodSettings *get_floodsettings_for_user(Client *client, FloodOption opt) 900 { 901 SecurityGroup *s; 902 FloodSettings *f; 903 904 /* Go through all security groups by order of priority 905 * (eg: first "known-users", then "unknown-users"). 906 * For each of these: 907 * - Check if a set::anti-flood::xxxx block exists for this group 908 * - Check if the limit is non-zero (eg there is any limit set) 909 * If any of these are false then we continue with next block 910 * that matches. 911 */ 912 913 // XXX: alternatively, instead of this double loop, 914 // do a post-conf thing and sort iConf.floodsettings 915 // according to the security-group { } order. 916 for (s = securitygroups; s; s = s->next) 917 { 918 if (user_allowed_by_security_group(client, s) && 919 ((f = find_floodsettings_block(s->name))) && 920 f->limit[opt]) 921 { 922 return f; 923 } 924 } 925 926 /* Return default settings block (which may have a zero limit set) */ 927 f = find_floodsettings_block("unknown-users"); 928 if (!f) 929 abort(); /* impossible */ 930 931 return f; 932 } 933 934 MODVAR const char *floodoption_names[] = { 935 "nick-flood", 936 "join-flood", 937 "away-flood", 938 "invite-flood", 939 "knock-flood", 940 "max-concurrent-conversations", 941 "lag-penalty", 942 "vhost-flood", 943 NULL 944 }; 945 946 /** Lookup GEO information for an IP address. 947 * @param ip The IP to lookup 948 * @returns A struct containing all the details. Must be freed by caller! 949 */ 950 GeoIPResult *geoip_lookup(const char *ip) 951 { 952 if (!RCallbacks[CALLBACKTYPE_GEOIP_LOOKUP]) 953 return NULL; 954 return RCallbacks[CALLBACKTYPE_GEOIP_LOOKUP]->func.pvoidfunc(ip); 955 } 956 957 void free_geoip_result(GeoIPResult *r) 958 { 959 if (!r) 960 return; 961 safe_free(r->country_code); 962 safe_free(r->country_name); 963 safe_free(r); 964 } 965 966 /** Grab geoip information for client */ 967 GeoIPResult *geoip_client(Client *client) 968 { 969 ModData *m = moddata_client_get_raw(client, "geoip"); 970 if (!m) 971 return NULL; 972 return m->ptr; /* can still be NULL */ 973 } 974 975 /** Get the oper block that was used to become OPER. 976 * @param client The client to fetch the info for 977 * @returns the oper block name (eg: "OpEr") or NULL. 978 */ 979 const char *get_operlogin(Client *client) 980 { 981 if (client->user->operlogin) 982 return client->user->operlogin; 983 return moddata_client_get(client, "operlogin"); 984 } 985 986 /** Get the operclass of the IRCOp. 987 * @param client The client to fetch the info for 988 * @returns the operclass name or NULL 989 */ 990 const char *get_operclass(Client *client) 991 { 992 const char *operlogin = NULL; 993 994 if (MyUser(client) && client->user->operlogin) 995 { 996 ConfigItem_oper *oper; 997 operlogin = client->user->operlogin; 998 oper = find_oper(operlogin); 999 if (oper && oper->operclass) 1000 return oper->operclass; 1001 } 1002 1003 /* Remote user or locally no longer available 1004 * (eg oper block removed but user is still oper) 1005 */ 1006 return moddata_client_get(client, "operclass"); 1007 }