/* * Copyright (C) 1997 Robey Pointer * Copyright (C) 1999 - 2002 Eggheads Development Team * Copyright (C) 2002 - 2010 Bryan Drewery * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * servmsg.c -- part of server.mod * */ #include char cursrvname[120] = ""; char curnetwork[120] = ""; static time_t last_ctcp = (time_t) 0L; static int count_ctcp = 0; char altnick_char = 0; unsigned int rolls = 0; #define ROLL_RIGHT #undef ROLL_LEFT static void rotate_nick(char *nick, char *orignick) { size_t len = strlen(nick); // Cap the len calcs at the max NICKLEN for this server if (len > nick_len) { len = nick_len; nick[len] = 0; } int use_chr = 1; #ifdef DEBUG sdprintf("rotate_nick(%s, %s) rolls: %d altnick_char: %c", nick, orignick, rolls, altnick_char); #endif /* First run? */ if (altnick_char == 0 && !rolls && altchars[0]) { altnick_char = altchars[0]; /* the nick is already as long as it can be. */ if (len == (unsigned) nick_len) { /* make the last char the current altnick_char */ nick[len - 1] = altnick_char; } else { /* tack it on to the end */ nick[len] = altnick_char; nick[len + 1] = 0; } } else { char *p = NULL; if ((p = strchr(altchars, altnick_char))) p++; /* if we haven't been rolling, use the ALTCHARS */ if (!rolls && p && *p) { altnick_char = *p; /* if we've already rolled, just keep rolling until we've rolled completely * after that, just generate random chars */ } else if (rolls < len) { /* fun BX style rolling, WEEEE */ char tmp = 0; size_t i = 0; altnick_char = 0; use_chr = 0; if (rolls == 0) { strlcpy(nick, orignick, sizeof(botname)); len = strlen(nick); } #ifdef ROLL_RIGHT tmp = nick[len - 1]; #endif /* ROLL_RIGHT */ #ifdef ROLL_LEFT tmp = nick[0]; #endif /* ROLL_LEFT */ if (strchr(BADHANDCHARS, tmp)) tmp = '_'; rolls++; #ifdef ROLL_RIGHT for (i = (len - 1); i > 0; i--) nick[i] = nick[i - 1]; nick[0] = tmp; #endif /* ROLL_RIGHT */ #ifdef ROLL_LEFT for (i = 0; i < (len - 1); i++) nick[i] = nick[i + 1]; nick[len - 1] = tmp; #endif /* ROLL_LEFT */ nick[len] = 0; } else { /* we've tried ALTCHARS, and rolled the nick, just use random chars now */ altnick_char = 'a' + randint(26); } if (use_chr && altnick_char) { nick[len - 1] = altnick_char; nick[len] = 0; } } } //This is only called on failed nick on connect static int gotfake433(char *nick) { //Failed to get jupenick on connect, try normal nick if (altnick_char == 0 && jupenick[0] && !rfc_casecmp(botname, jupenick)) { strlcpy(botname, origbotname, sizeof(botname)); } else //Rotate on failed normal nick rotate_nick(botname, origbotname); putlog(LOG_SERV, "*", "NICK IN USE: '%s' Trying '%s'", nick, botname); dprintf(DP_SERVER, "NICK %s\n", botname); return 0; } /* Check for tcl-bound msg command, return 1 if found * * msg: proc-name */ static void check_bind_msg(const char *cmd, char *nick, char *uhost, struct userrec *u, char *args) { struct flag_record fr = {FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0 }; int x; get_user_flagrec(u, &fr, NULL); x = check_bind(BT_msg, cmd, &fr, nick, uhost, u, args); if (x & BIND_RET_LOG) putlog(LOG_CMDS, "*", "(%s!%s) !%s! %s %s", nick, uhost, u ? u->handle : "*" , cmd, args); else if (x == 0) putlog(LOG_MSGS, "*", "[%s!%s] %s %s", nick, uhost, cmd, args); } /* Return 1 if processed. */ static int check_bind_raw(char *from, char *code, char *msg) { char *p1 = NULL, *p2 = NULL, *myfrom = NULL, *mymsg = NULL; int ret = 0; myfrom = p1 = strdup(from); // Decrypt FiSH before processing if (!strcmp(code, "PRIVMSG")) { char* colon = strchr(msg, ':'); ++colon; if (colon) { if (!strncmp(colon, "+OK ", 4)) { char *p = strchr(from, '!'); bd::String ciphertext(colon), sharedKey, nick(from, p - from); if (FishKeys.contains(nick)) { sharedKey = FishKeys[nick]->sharedKey; } else { struct userrec *u = get_user_by_host(from); if (u) { sharedKey = static_cast(get_user(&USERENTRY_SECPASS, u)); } } if (sharedKey.length()) { // Decrypt the message before passing along to the binds bd::String cleartext(bd::String(msg, colon - msg) + egg_bf_decrypt(ciphertext, sharedKey)); mymsg = p2 = strdup(cleartext.c_str()); } } } } if (!p2) mymsg = p2 = strdup(msg); ret = check_bind(BT_raw, code, NULL, myfrom, mymsg); free(p1); free(p2); return ret; } int check_bind_ctcpr(char *nick, char *uhost, struct userrec *u, char *dest, char *keyword, char *args, bind_table_t *table) { struct flag_record fr = {FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0 }; get_user_flagrec(u, &fr, NULL); return check_bind(table, keyword, &fr, nick, uhost, u, dest, keyword, args); } bool match_my_nick(char *nick) { return (!rfc_ncasecmp(nick, botname, nick_len)); } void rehash_monitor_list() { if (!use_monitor) return; dprintf(DP_SERVER, "MONITOR C\n"); if (jupenick[0]) dprintf(DP_SERVER, "MONITOR + %s,%s\n", jupenick, origbotname); else dprintf(DP_SERVER, "MONITOR + %s", origbotname); } void rehash_server(const char *servname, const char *nick) { strlcpy(cursrvname, servname, sizeof(cursrvname)); if (servidx >= 0) curservport = dcc[servidx].port; if (nick && nick[0]) { strlcpy(botname, nick, sizeof(botname)); dprintf(DP_MODE, "WHOIS %s\n", botname); /* get user@host */ dprintf(DP_MODE, "USERHOST %s\n", botname); /* get user@ip */ dprintf(DP_SERVER, "MODE %s %s\n", botname, var_get_str_by_name("usermode")); rehash_monitor_list(); } } void join_chans() { for (register struct chanset_t *chan = chanset; chan; chan = chan->next) { if (shouldjoin(chan)) force_join_chan(chan, DP_SERVER); } } /* 001: welcome to IRC (use it to fix the server name) */ static int got001(char *from, char *msg) { fixcolon(msg); server_online = now; waiting_for_awake = 0; rehash_server(from, msg); /* Ok...param #1 of 001 = what server thinks my nick is */ #ifdef no if (strcasecmp(from, dcc[servidx].host)) { struct server_list *x = serverlist; if (x == NULL) return 0; /* Uh, no server list */ putlog(LOG_MISC, "*", "(%s claims to be %s; updating server list)", dcc[servidx].host, from); for (int i = curserv; i > 0 && x != NULL; i--) x = x->next; if (x == NULL) { putlog(LOG_MISC, "*", "Invalid server list!"); return 0; } } #endif return 0; } /* 004 */ static int got004(char *from, char *msg) { char *tmp = NULL; newsplit(&msg); /* nick */ newsplit(&msg); /* server */ //Cache the results for later parsing if needed (after a restart) //Sending 'VERSION' does not work on all servers, plus this speeds //up a restart by removing the need to wait for the information if (!replaying_cache) dprintf(DP_CACHE, ":%s 004 . . %s", from, msg); tmp = newsplit(&msg); bool connect_burst = 0; /* cookies won't work on ircu or Unreal or snircd */ if (strstr(tmp, "u2.") || strstr(tmp, "Unreal") || strstr(tmp, "snircd")) { putlog(LOG_DEBUG, "*", "Disabling cookies as they are not supported on %s", cursrvname); cookies_disabled = true; } else if (strstr(tmp, "hybrid") || strstr(tmp, "ratbox") || strstr(tmp, "Charybdis") || strstr(tmp, "ircd-seven")) { connect_burst = 1; if (!strstr(tmp, "hybrid")) use_flood_count = 1; } if (!replaying_cache && connect_burst) { connect_bursting = now; msgburst = SERVER_CONNECT_BURST_RATE; msgrate = 200; reset_flood(); putlog(LOG_DEBUG, "*", "Server allows connect bursting, bursting for %d seconds", SERVER_CONNECT_BURST_TIME); } if (!replaying_cache) join_chans(); return 0; } /* 005