/* ** m_svsnick ** parv[0] = sender ** parv[1] = old nickname ** parv[2] = new nickname ** parv[3] = timestamp */ int m_svsnick(aClient *cptr, aClient *sptr, int parc, char *parv[]) { aClient *acptr; aClient *ocptr; /* Other client */ if (!IsULine(sptr) || parc < 4 || (strlen(parv[2]) > NICKLEN)) return -1; /* This looks like an error anyway -Studded */ if (hunt_server_token(cptr, sptr, MSG_SVSNICK, TOK_SVSNICK, "%s %s :%s", 1, parc, parv) != HUNTED_ISME) return 0; /* Forwarded, done */ if (do_nick_name(parv[2]) == 0) return 0; if (!(acptr = find_person(parv[1], NULL))) return 0; /* User not found, bail out */ if ((ocptr = find_client(parv[2], NULL)) && ocptr != acptr) /* Collision */ { exit_client(acptr, acptr, sptr, "Nickname collision due to Services enforced " "nickname change, your nick was overruled"); return 0; } if (acptr != ocptr) acptr->umodes &= ~UMODE_REGNICK; acptr->lastnick = TS2ts(parv[3]); sendto_common_channels(acptr, ":%s NICK :%s", parv[1], parv[2]); add_history(acptr, 1); sendto_serv_butone_token(NULL, parv[1], MSG_NICK, TOK_NICK, "%s :%ld", parv[2], TS2ts(parv[3])); (void)del_from_client_hash_table(acptr->name, acptr); hash_check_watch(acptr, RPL_LOGOFF); sendto_snomask(SNO_NICKCHANGE, "*** Notice -- %s (%s@%s) has been forced to change his/her nickname to %s", acptr->name, acptr->user->username, acptr->user->realhost, parv[2]); RunHook2(HOOKTYPE_LOCAL_NICKCHANGE, acptr, parv[2]); strlcpy(acptr->name, parv[2], sizeof acptr->name); add_to_client_hash_table(parv[2], acptr); hash_check_watch(acptr, RPL_LOGON); return 0; }
static void setup_me(aClient *mp) { struct passwd *p; p = getpwuid(getuid()); strncpyzt(mp->username, (p) ? p->pw_name : "unknown", sizeof(mp->username)); (void)get_my_name(mp, mp->sockhost, sizeof(mp->sockhost)-1); /* I think we need no hostp, especially fake one --B. */ mp->hostp = NULL; if (mp->serv->namebuf[0] == '\0') strncpyzt(mp->serv->namebuf, mp->sockhost, sizeof(mp->serv->namebuf)); if (me.info == DefInfo) me.info = mystrdup("IRCers United"); mp->lasttime = mp->since = mp->firsttime = time(NULL); mp->hopcount = 0; mp->authfd = -1; mp->auth = mp->username; mp->confs = NULL; mp->flags = 0; mp->acpt = mp->from = mp; mp->next = NULL; mp->user = NULL; mp->fd = -1; SetMe(mp); mp->serv->snum = find_server_num (ME); /* we don't fill our own IP -> 0 as ip lenght */ (void) make_user(mp,0); istat.is_users++; /* here, cptr->next is NULL, see make_user() */ mp->user->flags |= FLAGS_OPER; mp->serv->up = mp; mp->serv->maskedby = mp; mp->serv->version |= SV_UID; mp->user->server = find_server_string(mp->serv->snum); strncpyzt(mp->user->username, (p) ? p->pw_name : "unknown", sizeof(mp->user->username)); (void) strcpy(mp->user->host, mp->name); SetEOB(mp); istat.is_eobservers = 1; (void)add_to_client_hash_table(mp->name, mp); (void)add_to_sid_hash_table(mp->serv->sid, mp); strncpyzt(mp->serv->verstr, PATCHLEVEL, sizeof(mp->serv->verstr)); setup_server_channels(mp); }
void change_nick(aClient *acptr, char *newnick) { char nick[NICKLEN + 2]; strncpy_irc(nick, newnick, NICKLEN); nick[NICKLEN] = '\0'; ClearIdentified(acptr); /* maybe not needed, but safe -Lamego */ /* send change to common channels */ sendto_common_channels(acptr, ":%s NICK :%s", acptr->name, nick); if (acptr->user) { acptr->tsinfo = CurrentTime; add_history(acptr,1); /* propagate to all servers */ sendto_serv_butone(NULL, ":%s NICK %s :%lu", acptr->name, nick, acptr->tsinfo); } /* ** Finally set new nick name. */ if (acptr->name[0]) { del_from_client_hash_table(acptr->name, acptr); hash_check_watch(acptr, RPL_LOGOFF); } strcpy(acptr->name, nick); add_to_client_hash_table(nick, acptr); hash_check_watch(acptr, RPL_LOGON); /* Lets apply nick change delay (if needed) */ acptr->services_nick_change++; if(acptr->services_nick_change>1) { acptr->number_of_nick_changes = MAX_NICK_CHANGES+1; acptr->last_nick_change = CurrentTime; acptr->services_nick_change = 0; } }
/* * set_initial_nick * inputs * output * side effects - * * This function is only called to set up an initially registering * client. */ int set_initial_nick(struct Client *client_p, struct Client *source_p, char *nick) { char buf[USERLEN + 1]; /* Client setting NICK the first time */ /* This had to be copied here to avoid problems.. */ source_p->tsinfo = CurrentTime; if (source_p->name[0]) del_from_client_hash_table(source_p->name, source_p); strcpy(source_p->name, nick); add_to_client_hash_table(nick, source_p); /* fd_desc is long enough */ fd_note(client_p->localClient->fd, "Nick: %s", nick); /* They have the nick they want now.. */ *client_p->llname = '\0'; if (source_p->user) { strlcpy(buf, source_p->username, USERLEN); /* * USER already received, now we have NICK. * *NOTE* For servers "NICK" *must* precede the * user message (giving USER before NICK is possible * only for local client connection!). register_user * may reject the client and call exit_client for it * --must test this and exit m_nick too!!! */ #ifdef USE_IAUTH /* * Send the client to the iauth module for verification */ BeginAuthorization(source_p); #else if (register_local_user(client_p, source_p, nick, buf) == CLIENT_EXITED) return CLIENT_EXITED; #endif } return 0; }
/* ** m_nick ** parv[0] = sender prefix ** parv[1] = nickname ** if from new client -taz ** parv[2] = nick password ** if from server: ** parv[2] = hopcount ** parv[3] = timestamp ** parv[4] = username ** parv[5] = hostname ** parv[6] = servername ** if NICK version 1: ** parv[7] = servicestamp ** parv[8] = info ** if NICK version 2: ** parv[7] = servicestamp ** parv[8] = umodes ** parv[9] = virthost, * if none ** parv[10] = info ** if NICKIP: ** parv[10] = ip ** parv[11] = info */ DLLFUNC CMD_FUNC(m_nick) { aTKline *tklban; int ishold; aClient *acptr, *serv = NULL; aClient *acptrs; char nick[NICKLEN + 2], *s; Membership *mp; time_t lastnick = (time_t) 0; int differ = 1, update_watch = 1; unsigned char newusr = 0, removemoder = 1; /* * If the user didn't specify a nickname, complain */ if (parc < 2) { sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]); return 0; } strncpyzt(nick, parv[1], NICKLEN + 1); if (MyConnect(sptr) && sptr->user && !IsAnOper(sptr)) { if ((sptr->user->flood.nick_c >= NICK_COUNT) && (TStime() - sptr->user->flood.nick_t < NICK_PERIOD)) { /* Throttle... */ sendto_one(sptr, err_str(ERR_NCHANGETOOFAST), me.name, sptr->name, nick, (int)(NICK_PERIOD - (TStime() - sptr->user->flood.nick_t))); return 0; } } /* For a local clients, do proper nickname checking via do_nick_name() * and reject the nick if it returns false. * For remote clients, do a quick check by using do_remote_nick_name(), * if this returned false then reject and kill it. -- Syzop */ if ((IsServer(cptr) && !do_remote_nick_name(nick)) || (!IsServer(cptr) && !do_nick_name(nick))) { sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, parv[0], parv[1], "Illegal characters"); if (IsServer(cptr)) { ircstp->is_kill++; sendto_failops("Bad Nick: %s From: %s %s", parv[1], parv[0], get_client_name(cptr, FALSE)); sendto_one(cptr, ":%s KILL %s :%s (%s <- %s[%s])", me.name, parv[1], me.name, parv[1], nick, cptr->name); if (sptr != cptr) { /* bad nick change */ sendto_serv_butone(cptr, ":%s KILL %s :%s (%s <- %s!%s@%s)", me.name, parv[0], me.name, get_client_name(cptr, FALSE), parv[0], sptr->user ? sptr->username : "", sptr->user ? sptr->user->server : cptr->name); sptr->flags |= FLAGS_KILLED; return exit_client(cptr, sptr, &me, "BadNick"); } } return 0; } /* Kill quarantined opers early... */ if (IsServer(cptr) && (sptr->from->flags & FLAGS_QUARANTINE) && (parc >= 11) && strchr(parv[8], 'o')) { ircstp->is_kill++; /* Send kill to uplink only, hasn't been broadcasted to the rest, anyway */ sendto_one(cptr, ":%s KILL %s :%s (Quarantined: no global oper privileges allowed)", me.name, parv[1], me.name); sendto_realops("QUARANTINE: Oper %s on server %s killed, due to quarantine", parv[1], sptr->name); /* (nothing to exit_client or to free, since user was never added) */ return 0; } /* ** Protocol 4 doesn't send the server as prefix, so it is possible ** the server doesn't exist (a lagged net.burst), in which case ** we simply need to ignore the NICK. Also when we got that server ** name (again) but from another direction. --Run */ /* ** We should really only deal with this for msgs from servers. ** -- Aeto */ if (IsServer(cptr) && (parc > 7 && (!(serv = (aClient *)find_server_b64_or_real(parv[6])) || serv->from != cptr->from))) { sendto_realops("Cannot find server %s (%s)", parv[6], backupbuf); return 0; } /* ** Check against nick name collisions. ** ** Put this 'if' here so that the nesting goes nicely on the screen :) ** We check against server name list before determining if the nickname ** is present in the nicklist (due to the way the below for loop is ** constructed). -avalon */ /* I managed to f**k this up i guess --stskeeps */ if ((acptr = find_server(nick, NULL))) { if (MyConnect(sptr)) { #ifdef GUEST if (IsUnknown(sptr)) { RunHook4(HOOKTYPE_GUEST, cptr, sptr, parc, parv); return 0; } #endif sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name, BadPtr(parv[0]) ? "*" : parv[0], nick); return 0; /* NICK message ignored */ } } /* ** Check for a Q-lined nickname. If we find it, and it's our ** client, just reject it. -Lefler ** Allow opers to use Q-lined nicknames. -Russell */ if (!stricmp("ircd", nick)) { sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, BadPtr(parv[0]) ? "*" : parv[0], nick, "Reserved for internal IRCd purposes"); return 0; } if (!stricmp("irc", nick)) { sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, BadPtr(parv[0]) ? "*" : parv[0], nick, "Reserved for internal IRCd purposes"); return 0; } if (MyClient(sptr)) /* local client changin nick afterwards.. */ { int xx; spamfilter_build_user_string(spamfilter_user, nick, sptr); xx = dospamfilter(sptr, spamfilter_user, SPAMF_USER, NULL, 0, NULL); if (xx < 0) return xx; } if (!IsULine(sptr) && (tklban = find_qline(sptr, nick, &ishold))) { if (IsServer(sptr) && !ishold) /* server introducing new client */ { acptrs = (aClient *)find_server_b64_or_real(sptr->user == NULL ? (char *)parv[6] : (char *)sptr->user-> server); /* (NEW: no unregistered q:line msgs anymore during linking) */ if (!acptrs || (acptrs->serv && acptrs->serv->flags.synced)) sendto_snomask(SNO_QLINE, "Q:lined nick %s from %s on %s", nick, (*sptr->name != 0 && !IsServer(sptr) ? sptr->name : "<unregistered>"), acptrs ? acptrs->name : "unknown server"); } if (IsServer(cptr) && IsPerson(sptr) && !ishold) /* remote user changing nick */ { sendto_snomask(SNO_QLINE, "Q:lined nick %s from %s on %s", nick, sptr->name, sptr->srvptr ? sptr->srvptr->name : "<unknown>"); } if (!IsServer(cptr)) /* local */ { if (ishold) { sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, BadPtr(parv[0]) ? "*" : parv[0], nick, tklban->reason); return 0; } if (!IsOper(cptr)) { sptr->since += 4; /* lag them up */ sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, BadPtr(parv[0]) ? "*" : parv[0], nick, tklban->reason); sendto_snomask(SNO_QLINE, "Forbidding Q-lined nick %s from %s.", nick, get_client_name(cptr, FALSE)); return 0; /* NICK message ignored */ } } } /* ** acptr already has result from previous find_server() */ if (acptr) { /* ** We have a nickname trying to use the same name as ** a server. Send out a nick collision KILL to remove ** the nickname. As long as only a KILL is sent out, ** there is no danger of the server being disconnected. ** Ultimate way to jupiter a nick ? >;-). -avalon */ sendto_failops("Nick collision on %s(%s <- %s)", sptr->name, acptr->from->name, get_client_name(cptr, FALSE)); ircstp->is_kill++; sendto_one(cptr, ":%s KILL %s :%s (%s <- %s)", me.name, sptr->name, me.name, acptr->from->name, /* NOTE: Cannot use get_client_name ** twice here, it returns static ** string pointer--the other info ** would be lost */ get_client_name(cptr, FALSE)); sptr->flags |= FLAGS_KILLED; return exit_client(cptr, sptr, &me, "Nick/Server collision"); } if (MyClient(cptr) && !IsOper(cptr)) cptr->since += 3; /* Nick-flood prot. -Donwulff */ if (!(acptr = find_client(nick, NULL))) goto nickkilldone; /* No collisions, all clear... */ /* ** If the older one is "non-person", the new entry is just ** allowed to overwrite it. Just silently drop non-person, ** and proceed with the nick. This should take care of the ** "dormant nick" way of generating collisions... */ /* Moved before Lost User Field to fix some bugs... -- Barubary */ if (IsUnknown(acptr) && MyConnect(acptr)) { /* This may help - copying code below */ if (acptr == cptr) return 0; acptr->flags |= FLAGS_KILLED; exit_client(NULL, acptr, &me, "Overridden"); goto nickkilldone; } /* A sanity check in the user field... */ if (acptr->user == NULL) { /* This is a Bad Thing */ sendto_failops("Lost user field for %s in change from %s", acptr->name, get_client_name(cptr, FALSE)); ircstp->is_kill++; sendto_one(acptr, ":%s KILL %s :%s (Lost user field!)", me.name, acptr->name, me.name); acptr->flags |= FLAGS_KILLED; /* Here's the previous versions' desynch. If the old one is messed up, trash the old one and accept the new one. Remember - at this point there is a new nick coming in! Handle appropriately. -- Barubary */ exit_client(NULL, acptr, &me, "Lost user field"); goto nickkilldone; } /* ** If acptr == sptr, then we have a client doing a nick ** change between *equivalent* nicknames as far as server ** is concerned (user is changing the case of his/her ** nickname or somesuch) */ if (acptr == sptr) { if (strcmp(acptr->name, nick) != 0) { /* Allows change of case in his/her nick */ removemoder = 0; /* don't set the user -r */ goto nickkilldone; /* -- go and process change */ } else /* ** This is just ':old NICK old' type thing. ** Just forget the whole thing here. There is ** no point forwarding it to anywhere, ** especially since servers prior to this ** version would treat it as nick collision. */ return 0; /* NICK Message ignored */ } /* ** Note: From this point forward it can be assumed that ** acptr != sptr (point to different client structures). */ /* ** Decide, we really have a nick collision and deal with it */ if (!IsServer(cptr)) { /* ** NICK is coming from local client connection. Just ** send error reply and ignore the command. */ #ifdef GUEST if (IsUnknown(sptr)) { RunHook4(HOOKTYPE_GUEST, cptr, sptr, parc, parv); return 0; } #endif sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), /* parv[0] is empty when connecting */ me.name, BadPtr(parv[0]) ? "*" : parv[0], nick); return 0; /* NICK message ignored */ } /* ** NICK was coming from a server connection. ** This means we have a race condition (two users signing on ** at the same time), or two net fragments reconnecting with ** the same nick. ** The latter can happen because two different users connected ** or because one and the same user switched server during a ** net break. ** If we have the old protocol (no TimeStamp and no user@host) ** or if the TimeStamps are equal, we kill both (or only 'new' ** if it was a "NICK new"). Otherwise we kill the youngest ** when user@host differ, or the oldest when they are the same. ** --Run ** */ if (IsServer(sptr)) { /* ** A new NICK being introduced by a neighbouring ** server (e.g. message type "NICK new" received) */ if (parc > 3) { lastnick = TS2ts(parv[3]); if (parc > 5) differ = (mycmp(acptr->user->username, parv[4]) || mycmp(acptr->user->realhost, parv[5])); } sendto_failops("Nick collision on %s (%s %ld <- %s %ld)", acptr->name, acptr->from->name, acptr->lastnick, cptr->name, lastnick); /* ** I'm putting the KILL handling here just to make it easier ** to read, it's hard to follow it the way it used to be. ** Basically, this is what it will do. It will kill both ** users if no timestamp is given, or they are equal. It will ** kill the user on our side if the other server is "correct" ** (user@host differ and their user is older, or user@host are ** the same and their user is younger), otherwise just kill the ** user an reintroduce our correct user. ** The old code just sat there and "hoped" the other server ** would kill their user. Not anymore. ** -- binary */ if (!(parc > 3) || (acptr->lastnick == lastnick)) { ircstp->is_kill++; sendto_serv_butone(NULL, ":%s KILL %s :%s (Nick Collision)", me.name, acptr->name, me.name); acptr->flags |= FLAGS_KILLED; (void)exit_client(NULL, acptr, &me, "Nick collision with no timestamp/equal timestamps"); return 0; /* We killed both users, now stop the process. */ } if ((differ && (acptr->lastnick > lastnick)) || (!differ && (acptr->lastnick < lastnick)) || acptr->from == cptr) /* we missed a QUIT somewhere ? */ { ircstp->is_kill++; sendto_serv_butone(cptr, ":%s KILL %s :%s (Nick Collision)", me.name, acptr->name, me.name); acptr->flags |= FLAGS_KILLED; (void)exit_client(NULL, acptr, &me, "Nick collision"); goto nickkilldone; /* OK, we got rid of the "wrong" user, ** now we're going to add the user the ** other server introduced. */ } if ((differ && (acptr->lastnick < lastnick)) || (!differ && (acptr->lastnick > lastnick))) { /* * Introduce our "correct" user to the other server */ sendto_one(cptr, ":%s KILL %s :%s (Nick Collision)", me.name, parv[1], me.name); send_umode(NULL, acptr, 0, SEND_UMODES, buf); sendto_one_nickcmd(cptr, acptr, buf); if (acptr->user->away) sendto_one(cptr, ":%s AWAY :%s", acptr->name, acptr->user->away); send_user_joins(cptr, acptr); return 0; /* Ignore the NICK */ } return 0; } else { /* ** A NICK change has collided (e.g. message type ":old NICK new"). */ if (parc > 2) lastnick = TS2ts(parv[2]); differ = (mycmp(acptr->user->username, sptr->user->username) || mycmp(acptr->user->realhost, sptr->user->realhost)); sendto_failops ("Nick change collision from %s to %s (%s %ld <- %s %ld)", sptr->name, acptr->name, acptr->from->name, acptr->lastnick, sptr->from->name, lastnick); if (!(parc > 2) || lastnick == acptr->lastnick) { ircstp->is_kill += 2; sendto_serv_butone(NULL, /* First kill the new nick. */ ":%s KILL %s :%s (Self Collision)", me.name, acptr->name, me.name); sendto_serv_butone(cptr, /* Tell my servers to kill the old */ ":%s KILL %s :%s (Self Collision)", me.name, sptr->name, me.name); sptr->flags |= FLAGS_KILLED; acptr->flags |= FLAGS_KILLED; (void)exit_client(NULL, sptr, &me, "Self Collision"); (void)exit_client(NULL, acptr, &me, "Self Collision"); return 0; /* Now that I killed them both, ignore the NICK */ } if ((differ && (acptr->lastnick > lastnick)) || (!differ && (acptr->lastnick < lastnick))) { /* sptr (their user) won, let's kill acptr (our user) */ ircstp->is_kill++; sendto_serv_butone(cptr, ":%s KILL %s :%s (Nick collision: %s <- %s)", me.name, acptr->name, me.name, acptr->from->name, sptr->from->name); acptr->flags |= FLAGS_KILLED; (void)exit_client(NULL, acptr, &me, "Nick collision"); goto nickkilldone; /* their user won, introduce new nick */ } if ((differ && (acptr->lastnick < lastnick)) || (!differ && (acptr->lastnick > lastnick))) { /* acptr (our user) won, let's kill sptr (their user), ** and reintroduce our "correct" user */ ircstp->is_kill++; /* Kill the user trying to change their nick. */ sendto_serv_butone(cptr, ":%s KILL %s :%s (Nick collision: %s <- %s)", me.name, sptr->name, me.name, sptr->from->name, acptr->from->name); sptr->flags |= FLAGS_KILLED; (void)exit_client(NULL, sptr, &me, "Nick collision"); /* * Introduce our "correct" user to the other server */ /* Kill their user. */ sendto_one(cptr, ":%s KILL %s :%s (Nick Collision)", me.name, parv[1], me.name); send_umode(NULL, acptr, 0, SEND_UMODES, buf); sendto_one_nickcmd(cptr, acptr, buf); if (acptr->user->away) sendto_one(cptr, ":%s AWAY :%s", acptr->name, acptr->user->away); send_user_joins(cptr, acptr); return 0; /* their user lost, ignore the NICK */ } } return 0; /* just in case */ nickkilldone: if (IsServer(sptr)) { /* A server introducing a new client, change source */ sptr = make_client(cptr, serv); add_client_to_list(sptr); if (parc > 2) sptr->hopcount = TS2ts(parv[2]); if (parc > 3) sptr->lastnick = TS2ts(parv[3]); else /* Little bit better, as long as not all upgraded */ sptr->lastnick = TStime(); if (sptr->lastnick < 0) { sendto_realops ("Negative timestamp recieved from %s, resetting to TStime (%s)", cptr->name, backupbuf); sptr->lastnick = TStime(); } newusr = 1; } else if (sptr->name[0] && IsPerson(sptr)) { /* ** If the client belongs to me, then check to see ** if client is currently on any channels where it ** is currently banned. If so, do not allow the nick ** change to occur. ** Also set 'lastnick' to current time, if changed. */ if (MyClient(sptr)) { for (mp = sptr->user->channel; mp; mp = mp->next) { if (!is_skochanop(sptr, mp->chptr) && is_banned(sptr, mp->chptr, BANCHK_NICK)) { sendto_one(sptr, err_str(ERR_BANNICKCHANGE), me.name, parv[0], mp->chptr->chname); return 0; } if (CHECK_TARGET_NICK_BANS && !is_skochanop(sptr, mp->chptr) && is_banned_with_nick(sptr, mp->chptr, BANCHK_NICK, nick)) { sendto_one(sptr, ":%s 437 %s %s :Cannot change to a nickname banned on channel", me.name, parv[0], mp->chptr->chname); return 0; } if (!IsOper(sptr) && !IsULine(sptr) && mp->chptr->mode.mode & MODE_NONICKCHANGE && !is_chanownprotop(sptr, mp->chptr)) { sendto_one(sptr, err_str(ERR_NONICKCHANGE), me.name, parv[0], mp->chptr->chname); return 0; } } if (TStime() - sptr->user->flood.nick_t >= NICK_PERIOD) { sptr->user->flood.nick_t = TStime(); sptr->user->flood.nick_c = 1; } else sptr->user->flood.nick_c++; sendto_snomask(SNO_NICKCHANGE, "*** Notice -- %s (%s@%s) has changed his/her nickname to %s", sptr->name, sptr->user->username, sptr->user->realhost, nick); RunHook2(HOOKTYPE_LOCAL_NICKCHANGE, sptr, nick); } else { if (!IsULine(sptr)) sendto_snomask(SNO_FNICKCHANGE, "*** Notice -- %s (%s@%s) has changed his/her nickname to %s", sptr->name, sptr->user->username, sptr->user->realhost, nick); RunHook3(HOOKTYPE_REMOTE_NICKCHANGE, cptr, sptr, nick); } /* * Client just changing his/her nick. If he/she is * on a channel, send note of change to all clients * on that channel. Propagate notice to other servers. */ if (mycmp(parv[0], nick) || /* Next line can be removed when all upgraded --Run */ (!MyClient(sptr) && parc > 2 && TS2ts(parv[2]) < sptr->lastnick)) sptr->lastnick = (MyClient(sptr) || parc < 3) ? TStime() : TS2ts(parv[2]); if (sptr->lastnick < 0) { sendto_realops("Negative timestamp (%s)", backupbuf); sptr->lastnick = TStime(); } add_history(sptr, 1); sendto_common_channels(sptr, ":%s NICK :%s", parv[0], nick); sendto_serv_butone_token(cptr, parv[0], MSG_NICK, TOK_NICK, "%s %ld", nick, sptr->lastnick); if (removemoder) sptr->umodes &= ~UMODE_REGNICK; } else if (!sptr->name[0]) { #ifdef NOSPOOF /* * Client setting NICK the first time. * * Generate a random string for them to pong with. */ sptr->nospoof = getrandom32(); if (PINGPONG_WARNING) sendto_one(sptr, ":%s NOTICE %s :*** If you are having problems" " connecting due to ping timeouts, please" " type /quote pong %X or /raw pong %X now.", me.name, nick, sptr->nospoof, sptr->nospoof); sendto_one(sptr, "PING :%X", sptr->nospoof); #endif /* NOSPOOF */ #ifdef CONTACT_EMAIL sendto_one(sptr, ":%s NOTICE %s :*** If you need assistance with a" " connection problem, please email " CONTACT_EMAIL " with the name and version of the client you are" " using, and the server you tried to connect to: %s", me.name, nick, me.name); #endif /* CONTACT_EMAIL */ #ifdef CONTACT_URL sendto_one(sptr, ":%s NOTICE %s :*** If you need assistance with" " connecting to this server, %s, please refer to: " CONTACT_URL, me.name, nick, me.name); #endif /* CONTACT_URL */ /* Copy password to the passwd field if it's given after NICK * - originally by taz, modified by Wizzu */ if ((parc > 2) && (strlen(parv[2]) <= PASSWDLEN) && !(sptr->listener->umodes & LISTENER_JAVACLIENT)) { if (sptr->passwd) MyFree(sptr->passwd); sptr->passwd = MyMalloc(strlen(parv[2]) + 1); (void)strcpy(sptr->passwd, parv[2]); } /* This had to be copied here to avoid problems.. */ (void)strcpy(sptr->name, nick); if (sptr->user && IsNotSpoof(sptr)) { /* ** USER already received, now we have NICK. ** *NOTE* For servers "NICK" *must* precede the ** user message (giving USER before NICK is possible ** only for local client connection!). register_user ** may reject the client and call exit_client for it ** --must test this and exit m_nick too!!! */ #ifndef NOSPOOF if (USE_BAN_VERSION && MyConnect(sptr)) sendto_one(sptr, ":IRC!IRC@%s PRIVMSG %s :\1VERSION\1", me.name, nick); #endif sptr->lastnick = TStime(); /* Always local client */ if (register_user(cptr, sptr, nick, sptr->user->username, NULL, NULL, NULL) == FLUSH_BUFFER) return FLUSH_BUFFER; strcpy(nick, sptr->name); /* don't ask, but I need this. do not remove! -- Syzop */ update_watch = 0; newusr = 1; } } /* * Finally set new nick name. */ if (update_watch && sptr->name[0]) { (void)del_from_client_hash_table(sptr->name, sptr); if (IsPerson(sptr)) hash_check_watch(sptr, RPL_LOGOFF); } (void)strcpy(sptr->name, nick); (void)add_to_client_hash_table(nick, sptr); if (IsServer(cptr) && parc > 7) { parv[3] = nick; do_cmd(cptr, sptr, "USER", parc - 3, &parv[3]); if (GotNetInfo(cptr) && !IsULine(sptr)) sendto_fconnectnotice(sptr->name, sptr->user, sptr, 0, NULL); } else if (IsPerson(sptr) && update_watch) hash_check_watch(sptr, RPL_LOGON); #ifdef NEWCHFLOODPROT if (sptr->user && !newusr && !IsULine(sptr)) { for (mp = sptr->user->channel; mp; mp = mp->next) { aChannel *chptr = mp->chptr; if (chptr && !(mp->flags & (CHFL_CHANOP|CHFL_VOICE|CHFL_CHANOWNER|CHFL_HALFOP|CHFL_CHANPROT)) && chptr->mode.floodprot && do_chanflood(chptr->mode.floodprot, FLD_NICK) && MyClient(sptr)) { do_chanflood_action(chptr, FLD_NICK, "nick"); } } } #endif if (newusr && !MyClient(sptr) && IsPerson(sptr)) { RunHook(HOOKTYPE_REMOTE_CONNECT, sptr); } return 0; }
int main(int argc, char *argv[]) { time_t delay = 0; aConfItem* aconf; if(geteuid() == 0) { fprintf(stderr, "ERROR: Don't run ircd as root!\n"); return -1; } /* * save server boot time right away, so getrusage works correctly */ if ((CurrentTime = time(0)) == -1) { fprintf(stderr, "ERROR: Clock Failure: %s\n", strerror(errno)); exit(errno); } /* * Setup corefile size immediately after boot */ setup_corefile(); /* * set initialVMTop before we allocate any memory */ initialVMTop = get_vm_top(); /* * Initialize the Blockheap allocator */ initBlockHeap(); ServerRunning = 0; memset(&me, 0, sizeof(me)); GlobalClientList = &me; /* Pointer to beginning of Client list */ cold_start = YES; /* set when server first starts up */ memset(&Count, 0, sizeof(Count)); Count.server = 1; /* us */ initialize_global_set_options(); #ifdef REJECT_HOLD reject_held_fds = 0; #endif ConfigFileEntry.dpath = DPATH; ConfigFileEntry.configfile = CPATH; /* Server configuration file */ #ifdef KPATH ConfigFileEntry.klinefile = KPATH; /* Server kline file */ #else ConfigFileEntry.klinefile = CPATH; #endif /* KPATH */ #ifdef DLPATH ConfigFileEntry.dlinefile = DLPATH; #else ConfigFileEntry.dlinefile = CPATH; #endif /* DLPATH */ #ifdef GLINES ConfigFileEntry.glinefile = GLINEFILE; #endif #ifdef ZIP_LINKS /* Make sure the include files match the library version number. */ /* configure takes care of looking for zlib and zlibVersion(). */ if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { fprintf(stderr, "WARNING: zlib include files differ from library.\n"); fprintf(stderr, "WARNING: ZIPLINKS may fail!\n"); fprintf(stderr, "WARNING: library %s, include files %s\n", zlibVersion(), ZLIB_VERSION); } #endif myargv = argv; umask(077); /* better safe than sorry --SRB */ parse_command_line(argc, argv); if (chdir(ConfigFileEntry.dpath)) { perror("chdir"); exit(-1); } /* * Check if daemon is already running */ check_pidfile(); init_sys(bootDaemon); init_log(logFileName); setup_signals(); initialize_message_files(); isupport = make_isupport(); dbuf_init(); /* set up some dbuf stuff to control paging */ init_hash(); clear_scache_hash_table(); /* server cache name table */ clear_ip_hash_table(); /* client host ip hash table */ clear_Dline_table(); /* d line tree */ initlists(); initclass(); initwhowas(); init_stats(); init_tree_parse(msgtab); /* tree parse code (orabidoo) */ fdlist_init(); init_netio(); read_conf_files(YES); /* cold start init conf files */ aconf = find_me(); if (EmptyString(me.name)) strncpy_irc(me.name, aconf->host, HOSTLEN); strncpy_irc(me.host, aconf->host, HOSTLEN); me.fd = -1; me.from = &me; me.servptr = &me; SetMe(&me); make_server(&me); me.serv->up = me.name; me.lasttime = me.since = me.firsttime = CurrentTime; add_to_client_hash_table(me.name, &me); check_class(); write_pidfile(); log(L_NOTICE, "Server Ready"); ServerRunning = 1; while (ServerRunning) { usleep(100000); do_adns_io(); delay = io_loop(delay); do_adns_io(); } return 0; }
/* * m_nick * parv[0] = sender prefix * parv[1] = nickname * parv[2] = hopcount when new user; TS when nick change * parv[3] = TS * ---- new user only below ---- * parv[4] = umode * parv[5] = username * parv[6] = hostname * parv[7] = server * parv[8] = serviceid * parv[9] = IP * parv[10] = ircname * -- endif */ int m_nick(aClient *cptr, aClient *sptr, int parc, char *parv[]) { struct simBan *ban; aClient *acptr, *uplink; Link *lp, *lp2; char nick[NICKLEN + 2]; ts_val newts = 0; int sameuser = 0, samenick = 0; if (parc < 2) { sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]); return 0; } if (!IsServer(sptr) && IsServer(cptr) && parc > 2) newts = atol(parv[2]); else if (IsServer(sptr) && parc > 3) newts = atol(parv[3]); else parc = 2; /* * parc == 2 on a normal client sign on (local) and a normal client * nick change * parc == 4 on a normal server-to-server client nick change * parc == 11 on a normal TS style server-to-server NICK introduction */ if ((IsServer(sptr) || (parc > 4)) && (parc < 11)) { /* * We got the wrong number of params. Someone is trying to trick * us. Kill it. -ThemBones As discussed with ThemBones, not much * point to this code now sending a whack of global kills would * also be more annoying then its worth, just note the problem, * and continue -Dianora */ sendto_realops("IGNORING BAD NICK: %s[%s@%s] on %s (from %s)", parv[1], (parc >= 6) ? parv[5] : "-", (parc >= 7) ? parv[6] : "-", (parc >= 8) ? parv[7] : "-", parv[0]); return 0; } strncpyzt(nick, parv[1], NICKLEN + 1); /* * if do_nick_name() returns a null name OR if the server sent a * nick name and do_nick_name() changed it in some way (due to rules * of nick creation) then reject it. If from a server and we reject * it, and KILL it. -avalon 4/4/92 */ if (do_nick_name(nick) == 0 || (IsServer(cptr) && strcmp(nick, parv[1]))) { sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, parv[0], parv[1], "Erroneous Nickname"); if (IsServer(cptr)) { ircstp->is_kill++; sendto_realops_lev(DEBUG_LEV, "Bad Nick: %s From: %s Via: %s", parv[1], parv[0], get_client_name(cptr, HIDEME)); sendto_one(cptr, ":%s KILL %s :%s (Bad Nick)", me.name, parv[1], me.name); if (sptr != cptr) { /* bad nick change */ sendto_serv_butone(cptr, ":%s KILL %s :%s (Bad Nick)", me.name, parv[0], me.name); sptr->flags |= FLAGS_KILLED; return exit_client(cptr, sptr, &me, "BadNick"); } } return 0; } /* * Check against nick name collisions. * * Put this 'if' here so that the nesting goes nicely on the screen * :) We check against server name list before determining if the * nickname is present in the nicklist (due to the way the below * for loop is constructed). -avalon */ do { if ((acptr = find_server(nick, NULL))) if (MyConnect(sptr)) { sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name, BadPtr(parv[0]) ? "*" : parv[0], nick); return 0; } /* * acptr already has result from find_server * Well. unless we have a capricious server on the net, a nick can * never be the same as a server name - Dianora * That's not the only case; maybe someone broke do_nick_name * or changed it so they could use "." in nicks on their network * - sedition */ if (acptr) { /* * We have a nickname trying to use the same name as a * server. Send out a nick collision KILL to remove the * nickname. As long as only a KILL is sent out, there is no * danger of the server being disconnected. Ultimate way to * jupiter a nick ? >;-). -avalon */ sendto_realops_lev(SKILL_LEV, "Nick collision on %s", sptr->name); ircstp->is_kill++; sendto_one(cptr, ":%s KILL %s :%s (Nick Collision)", me.name, sptr->name, me.name); sptr->flags |= FLAGS_KILLED; return exit_client(cptr, sptr, &me, "Nick/Server collision"); } if (!(acptr = find_client(nick, NULL))) break; /* * If acptr == sptr, then we have a client doing a nick change * between *equivalent* nicknames as far as server is concerned * (user is changing the case of his/her nickname or somesuch) */ if (acptr == sptr) { if (strcmp(acptr->name, nick) == 0) return 0; else break; } /* If user is changing nick to itself no point in propogating */ /* * Note: From this point forward it can be assumed that acptr != * sptr (point to different client structures). * * If the older one is "non-person", the new entry is just * allowed to overwrite it. Just silently drop non-person, and * proceed with the nick. This should take care of the "dormant * nick" way of generating collisions... */ if (IsUnknown(acptr)) { if (MyConnect(acptr)) { exit_client(NULL, acptr, &me, "Overridden"); break; } else if (!(acptr->user)) { sendto_realops_lev(SKILL_LEV, "Nick Collision on %s", parv[1]); sendto_serv_butone(NULL, ":%s KILL %s :%s (Nick Collision)", me.name, acptr->name, me.name); acptr->flags |= FLAGS_KILLED; /* Having no USER struct should be ok... */ return exit_client(cptr, acptr, &me, "Got TS NICK before Non-TS USER"); } } if (!IsServer(cptr)) { /* * NICK is coming from local client connection. Just send * error reply and ignore the command. * parv[0] is empty on connecting clients */ sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name, BadPtr(parv[0]) ? "*" : parv[0], nick); return 0; } /* * NICK was coming from a server connection. Means that the same * nick is registered for different users by different server. * This is either a race condition (two users coming online about * same time, or net reconnecting) or just two net fragments * becoming joined and having same nicks in use. We cannot have * TWO users with same nick--purge this NICK from the system with * a KILL... >;) * * Changed to something reasonable like IsServer(sptr) (true if * "NICK new", false if ":old NICK new") -orabidoo */ if (IsServer(sptr)) { /* * A new NICK being introduced by a neighbouring server (e.g. * message type "NICK new" received) */ if (!newts || !acptr->tsinfo || (newts == acptr->tsinfo)) { sendto_realops_lev(SKILL_LEV, "Nick collision on %s", parv[1]); ircstp->is_kill++; sendto_one(acptr, err_str(ERR_NICKCOLLISION), me.name, acptr->name, acptr->name); sendto_serv_butone(NULL, ":%s KILL %s :%s (Nick Collision)", me.name, acptr->name, me.name); acptr->flags |= FLAGS_KILLED; return exit_client(cptr, acptr, &me, "Nick collision"); } else { /* XXX This looks messed up to me XXX - Raist */ sameuser = (acptr->user) && mycmp(acptr->user->username, parv[5]) == 0 && mycmp(acptr->user->host, parv[6]) == 0; if ((sameuser && newts < acptr->tsinfo) || (!sameuser && newts > acptr->tsinfo)) { return 0; } else { sendto_realops_lev(SKILL_LEV, "Nick collision on %s",parv[1]); ircstp->is_kill++; sendto_one(acptr, err_str(ERR_NICKCOLLISION), me.name, acptr->name, acptr->name); sendto_serv_butone(sptr, ":%s KILL %s :%s (Nick Collision)", me.name, acptr->name, me.name); acptr->flags |= FLAGS_KILLED; (void) exit_client(cptr, acptr, &me, "Nick collision"); break; } } } /* * * A NICK change has collided (e.g. message type * ":old NICK * new". This requires more complex cleanout. * Both clients must be * purged from this server, the "new" * must be killed from the * incoming connection, and "old" must * be purged from all outgoing * connections. */ if (!newts || !acptr->tsinfo || (newts == acptr->tsinfo) || !sptr->user) { sendto_realops_lev(SKILL_LEV, "Nick change collision: %s", parv[1]); ircstp->is_kill++; sendto_one(acptr, err_str(ERR_NICKCOLLISION), me.name, acptr->name, acptr->name); sendto_serv_butone(NULL, ":%s KILL %s :%s (Nick Collision)",me.name, sptr->name, me.name); ircstp->is_kill++; sendto_serv_butone(NULL, ":%s KILL %s :%s (Nick Collision)",me.name, acptr->name, me.name); acptr->flags |= FLAGS_KILLED; (void) exit_client(NULL, acptr, &me, "Nick collision(new)"); sptr->flags |= FLAGS_KILLED; return exit_client(cptr, sptr, &me, "Nick collision(old)"); } else { /* XXX This looks messed up XXX */ sameuser = mycmp(acptr->user->username, sptr->user->username) == 0 && mycmp(acptr->user->host, sptr->user->host) == 0; if ((sameuser && newts < acptr->tsinfo) || (!sameuser && newts > acptr->tsinfo)) { if (sameuser) sendto_realops_lev(SKILL_LEV, "Nick change collision from %s to %s", sptr->name, acptr->name); ircstp->is_kill++; sendto_serv_butone(cptr, ":%s KILL %s :%s (Nick Collision)", me.name, sptr->name, me.name); sptr->flags |= FLAGS_KILLED; if (sameuser) return exit_client(cptr, sptr, &me, "Nick collision(old)"); else return exit_client(cptr, sptr, &me, "Nick collision(new)"); } else { sendto_realops_lev(SKILL_LEV, "Nick collision on %s", acptr->name); ircstp->is_kill++; sendto_one(acptr, err_str(ERR_NICKCOLLISION), me.name, acptr->name, acptr->name); sendto_serv_butone(sptr, ":%s KILL %s :%s (Nick Collision)",me.name, acptr->name, me.name); acptr->flags |= FLAGS_KILLED; (void) exit_client(cptr, acptr, &me, "Nick collision"); } } } while (0); if (IsServer(sptr)) { uplink = find_server(parv[7], NULL); if(!uplink) { /* if we can't find the server this nick is on, * complain loudly and ignore it. - lucas */ sendto_realops("Remote nick %s on UNKNOWN server %s", nick, parv[7]); return 0; } sptr = make_client(cptr, uplink); /* If this is on a U: lined server, it's a U: lined client. */ if(IsULine(uplink)) sptr->flags|=FLAGS_ULINE; add_client_to_list(sptr); if (parc > 2) sptr->hopcount = atoi(parv[2]); if (newts) { sptr->tsinfo = newts; } else { newts = sptr->tsinfo = (ts_val) timeofday; ts_warn("Remote nick %s introduced without a TS", nick); } /* copy the nick in place */ (void) strcpy(sptr->name, nick); (void) add_to_client_hash_table(nick, sptr); if (parc >= 10) { int *s, flag; char *m; /* parse the usermodes -orabidoo */ m = &parv[4][1]; while (*m) { for (s = user_modes; (flag = *s); s += 2) if (*m == *(s + 1)) { if ((flag == UMODE_o) || (flag == UMODE_O)) Count.oper++; sptr->umode |= flag & SEND_UMODES; break; } m++; } if (parc==10) { return do_user(nick, cptr, sptr, parv[5], parv[6], parv[7], strtoul(parv[8], NULL, 0), "0.0.0.0", parv[9]); } else if (parc==11) { return do_user(nick, cptr, sptr, parv[5], parv[6], parv[7], strtoul(parv[8], NULL, 0), parv[9], parv[10]); } } } else if (sptr->name[0]) { #ifdef DONT_CHECK_QLINE_REMOTE if (MyConnect(sptr)) { #endif if ((ban = check_mask_simbanned(nick, SBAN_NICK))) { #ifndef DONT_CHECK_QLINE_REMOTE if (!MyConnect(sptr)) sendto_realops("Restricted nick %s from %s on %s", nick, (*sptr->name != 0 && !IsServer(sptr)) ? sptr->name : "<unregistered>", (sptr->user == NULL) ? ((IsServer(sptr)) ? parv[6] : me.name) : sptr->user->server); #endif if (MyConnect(sptr) && (!IsServer(cptr)) && (!IsOper(cptr)) && (!IsULine(sptr))) { sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, BadPtr(parv[0]) ? "*" : parv[0], nick, BadPtr(ban->reason) ? "Erroneous Nickname" : ban->reason); if (call_hooks(CHOOK_FORBID, cptr, nick, ban) != FLUSH_BUFFER) sendto_realops_lev(REJ_LEV, "Forbidding restricted nick %s from %s", nick, get_client_name(cptr, FALSE)); return 0; } } #ifdef DONT_CHECK_QLINE_REMOTE } #endif if (MyConnect(sptr)) { if (IsRegisteredUser(sptr)) { /* before we change their nick, make sure they're not banned * on any channels, and!! make sure they're not changing to * a banned nick -sed */ /* a little cleaner - lucas */ for (lp = sptr->user->channel; lp; lp = lp->next) { if (can_send(sptr, lp->value.chptr, NULL)) { sendto_one(sptr, err_str(ERR_BANNICKCHANGE), me.name, sptr->name, lp->value.chptr->chname); return 0; } if (nick_is_banned(lp->value.chptr, nick, sptr) != NULL) { sendto_one(sptr, err_str(ERR_BANONCHAN), me.name, sptr->name, nick, lp->value.chptr->chname); return 0; } } #ifdef ANTI_NICK_FLOOD if ((sptr->last_nick_change + MAX_NICK_TIME) < NOW) sptr->number_of_nick_changes = 0; sptr->last_nick_change = NOW; sptr->number_of_nick_changes++; if (sptr->number_of_nick_changes > MAX_NICK_CHANGES && !IsAnOper(sptr)) { sendto_one(sptr, ":%s NOTICE %s :*** Notice -- Too many nick " "changes. Wait %d seconds before trying again.", me.name, sptr->name, MAX_NICK_TIME); return 0; } #endif /* If it changed nicks, -r it */ if ((sptr->umode & UMODE_r) && (mycmp(parv[0], nick) != 0)) { unsigned int oldumode; char mbuf[BUFSIZE]; oldumode = sptr->umode; sptr->umode &= ~UMODE_r; send_umode(sptr, sptr, oldumode, ALL_UMODES, mbuf); } /* LOCAL NICKHANGE */ /* * Client just changing his/her nick. If he/she is on a * channel, send note of change to all clients on that channel. * Propagate notice to other servers. */ /* if the nickname is different, set the TS */ if (mycmp(parv[0], nick)) { sptr->tsinfo = newts ? newts : (ts_val) timeofday; } sendto_common_channels(sptr, ":%s NICK :%s", parv[0], nick); if (sptr->user) { add_history(sptr, 1); sendto_serv_butone(cptr, ":%s NICK %s :%ld", parv[0], nick, sptr->tsinfo); } } } else { /* REMOTE NICKCHANGE */ /* * Client just changing his/her nick. If he/she is on a * channel, send note of change to all clients on that channel. * Propagate notice to other servers. */ /* if the nickname is different, set the TS */ if (mycmp(parv[0], nick)) { sptr->tsinfo = newts ? newts : (ts_val) timeofday; } sendto_common_channels(sptr, ":%s NICK :%s", parv[0], nick); if (sptr->user) { add_history(sptr, 1); sendto_serv_butone(cptr, ":%s NICK %s :%ld", parv[0], nick, sptr->tsinfo); } /* If it changed nicks, -r it */ if (mycmp(parv[0], nick)) sptr->umode &= ~UMODE_r; /* * Flush the banserial for the channels the user is in, since this * could be a SVSNICK induced nick change, which overrides any ban * checking on the originating server. */ flush_user_banserial(sptr); } /* Remove dccallow entries for users who don't share common channel(s) unless they only change their nick capitalization -Kobi_S */ if(sptr->user && mycmp(parv[0], nick)) { for(lp = sptr->user->dccallow; lp; lp = lp2) { lp2 = lp->next; if(lp->flags == DCC_LINK_ME) continue; if(!find_shared_chan(sptr, lp->value.cptr)) { sendto_one(lp->value.cptr, ":%s %d %s :%s has been removed from " "your DCC allow list for signing off", me.name, RPL_DCCINFO, lp->value.cptr->name, parv[0]); del_dccallow(lp->value.cptr, sptr, 1); } } } } else { /* Client setting NICK the first time */ if (MyConnect(sptr)) { if ((ban = check_mask_simbanned(nick, SBAN_NICK))) { if (MyConnect(sptr) && (!IsServer(cptr)) && (!IsOper(cptr)) && (!IsULine(sptr))) { sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, BadPtr(parv[0]) ? "*" : parv[0], nick, BadPtr(ban->reason) ? "Erroneous Nickname" : ban->reason); if (call_hooks(CHOOK_FORBID, cptr, nick, ban) != FLUSH_BUFFER) sendto_realops_lev(REJ_LEV, "Forbidding restricted nick %s from %s", nick, get_client_name(cptr, FALSE)); return 0; } } } strcpy(sptr->name, nick); sptr->tsinfo = timeofday; if (sptr->user) { /* USER already received, now we have NICK */ if (register_user(cptr, sptr, nick, sptr->user->username, NULL) == FLUSH_BUFFER) return FLUSH_BUFFER; } } /* Finally set new nick name. */ if (sptr->name[0]) { del_from_client_hash_table(sptr->name, sptr); samenick = mycmp(sptr->name, nick) ? 0 : 1; if (IsPerson(sptr)) { if (!samenick) hash_check_watch(sptr, RPL_LOGOFF); #ifdef RWHO_PROBABILITY probability_change(sptr->name, nick); #endif } } strcpy(sptr->name, nick); add_to_client_hash_table(nick, sptr); if (IsPerson(sptr) && !samenick) hash_check_watch(sptr, RPL_LOGON); return 0; }
static int do_server_estab(aClient *cptr) { aClient *acptr; aConnect *aconn; aChannel *chptr; int i; /* "refresh" inpath with host */ char *inpath = get_client_name(cptr, HIDEME); SetServer(cptr); Count.unknown--; Count.server++; Count.myserver++; if(IsZipCapable(cptr) && DoZipThis(cptr)) { sendto_one(cptr, "SVINFO ZIP"); SetZipOut(cptr); cptr->serv->zip_out = zip_create_output_session(); } #ifdef MAXBUFFERS /* let's try to bump up server sock_opts... -Taner */ reset_sock_opts(cptr->fd, 1); #endif /* adds to server list */ add_to_list(&server_list, cptr); set_effective_class(cptr); /* Check one more time for good measure... is it there? */ if ((acptr = find_name(cptr->name, NULL))) { char nbuf[HOSTLEN * 2 + USERLEN + 5]; aClient *bcptr; /* * While negotiating stuff, another copy of this server appeared. * * Rather than KILL the link which introduced it, KILL the * youngest of the two links. -avalon */ bcptr = (cptr->firsttime > acptr->from->firsttime) ? cptr : acptr->from; sendto_one(bcptr, "ERROR :Server %s already exists", cptr->name); if (bcptr == cptr) { sendto_gnotice("from %s: Link %s cancelled, server %s already " "exists (final phase)", me.name, get_client_name(bcptr, HIDEME), cptr->name); sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, " "server %s already exists (final phase)", me.name, get_client_name(bcptr, HIDEME), cptr->name); return exit_client(bcptr, bcptr, &me, "Server Exists (final phase)"); } /* inform all those who care (set +n) -epi */ strcpy(nbuf, get_client_name(bcptr, HIDEME)); sendto_gnotice("from %s: Link %s cancelled, server %s reintroduced " "by %s (final phase)", me.name, nbuf, cptr->name, get_client_name(cptr, HIDEME)); sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, server %s " "reintroduced by %s (final phase)", me.name, nbuf, cptr->name, get_client_name(cptr, HIDEME)); exit_client(bcptr, bcptr, &me, "Server Exists (final phase)"); } /* error, error, error! if a server is U:'d, and it connects to us, * we need to figure that out! So, do it here. - lucas */ if (find_aUserver(cptr->name)) { Count.myulined++; cptr->flags |= FLAGS_ULINE; /* If the server has special u:line flags, let's set them.. */ cptr->serv->uflags = cptr->serv->aconn->uflags; } fakelinkserver_update(cptr->name, cptr->info); sendto_gnotice("from %s: Link with %s established, states:%s%s%s%s", me.name, inpath, ZipOut(cptr) ? " Output-compressed" : "", RC4EncLink(cptr) ? " encrypted" : "", IsULine(cptr) ? " ULined" : "", DoesTS(cptr) ? " TS" : " Non-TS"); /* * Notify everyone of the fact that this has just linked: the entire * network should get two of these, one explaining the link between * me->serv and the other between serv->me */ sendto_serv_butone(NULL, ":%s GNOTICE :Link with %s established: %s", me.name, inpath, DoesTS(cptr) ? "TS link" : "Non-TS link!"); add_to_client_hash_table(cptr->name, cptr); /* add it to scache */ find_or_add(cptr->name); /* * Old sendto_serv_but_one() call removed because we now need to * send different names to different servers (domain name * matching) Send new server to other servers. */ for (i = 0; i <= highest_fd; i++) { if (!(acptr = local[i]) || !IsServer(acptr) || acptr == cptr || IsMe(acptr)) continue; if ((aconn = acptr->serv->aconn) && !match(my_name_for_link(me.name, aconn), cptr->name)) continue; sendto_one(acptr, ":%s SERVER %s 2 :%s", me.name, cptr->name, cptr->info); } /* * Pass on my client information to the new server * * First, pass only servers (idea is that if the link gets * cancelled beacause the server was already there, there are no * NICK's to be cancelled...). Of course, if cancellation occurs, * all this info is sent anyway, and I guess the link dies when a * read is attempted...? --msa * * Note: Link cancellation to occur at this point means that at * least two servers from my fragment are building up connection * this other fragment at the same time, it's a race condition, * not the normal way of operation... * * ALSO NOTE: using the get_client_name for server names-- see * previous *WARNING*!!! (Also, original inpath is * destroyed...) */ aconn = cptr->serv->aconn; for (acptr = &me; acptr; acptr = acptr->prev) { if (acptr->from == cptr) continue; if (IsServer(acptr)) { if (match(my_name_for_link(me.name, aconn), acptr->name) == 0) continue; sendto_one(cptr, ":%s SERVER %s %d :%s", acptr->serv->up, acptr->name, acptr->hopcount + 1, acptr->info); } } /* send out our SQLINES and SGLINES too */ send_simbans(cptr, SBAN_CHAN|SBAN_NETWORK); send_simbans(cptr, SBAN_NICK|SBAN_NETWORK); send_simbans(cptr, SBAN_GCOS|SBAN_NETWORK); /* Send out fake server list and other 'fake' stuff */ fakeserver_sendserver(cptr); /* Send UHM (user host-masking) type */ if(confopts & FLAGS_HUB) sendto_one(cptr, "SVSUHM %d", uhm_type); /* send clone list */ clones_send(cptr); /* Bursts are about to start.. send a BURST */ if (IsBurst(cptr)) sendto_one(cptr, "BURST"); /* * * Send it in the shortened format with the TS, if it's a TS * server; walk the list of channels, sending all the nicks that * haven't been sent yet for each channel, then send the channel * itself -- it's less obvious than sending all nicks first, but * on the receiving side memory will be allocated more nicely * saving a few seconds in the handling of a split -orabidoo */ { chanMember *cm; static char nickissent = 1; nickissent = 3 - nickissent; /* * flag used for each nick to check if we've sent it yet - must * be different each time and !=0, so we alternate between 1 and * 2 -orabidoo */ for (chptr = channel; chptr; chptr = chptr->nextch) { for (cm = chptr->members; cm; cm = cm->next) { acptr = cm->cptr; if (acptr->nicksent != nickissent) { acptr->nicksent = nickissent; if (acptr->from != cptr) sendnick_TS(cptr, acptr); } } send_channel_modes(cptr, chptr); } /* also send out those that are not on any channel */ for (acptr = &me; acptr; acptr = acptr->prev) if (acptr->nicksent != nickissent) { acptr->nicksent = nickissent; if (acptr->from != cptr) sendnick_TS(cptr, acptr); } } if(confopts & FLAGS_HUB) fakelusers_sendlock(cptr); if(ZipOut(cptr)) { unsigned long inb, outb; double rat; zip_out_get_stats(cptr->serv->zip_out, &inb, &outb, &rat); if(inb) { sendto_gnotice("from %s: Connect burst to %s: %lu bytes normal, " "%lu compressed (%3.2f%%)", me.name, get_client_name(cptr, HIDEME), inb, outb, rat); sendto_serv_butone(cptr, ":%s GNOTICE :Connect burst to %s: %lu " "bytes normal, %lu compressed (%3.2f%%)", me.name, get_client_name(cptr, HIDEME), inb, outb, rat); } } /* stuff a PING at the end of this burst so we can figure out when the other side has finished processing it. */ cptr->flags |= FLAGS_BURST|FLAGS_PINGSENT; if (IsBurst(cptr)) cptr->flags |= FLAGS_SOBSENT; sendto_one(cptr, "PING :%s", me.name); return 0; }
/* * m_server * parv[0] = sender prefix * parv[1] = servername * parv[2] = serverinfo/hopcount * parv[3] = serverinfo */ int m_server(aClient *cptr, aClient *sptr, int parc, char *parv[]) { int i; char info[REALLEN + 1], *host; aClient *acptr, *bcptr; aConnect *aconn; int hop; char nbuf[HOSTLEN * 2 + USERLEN + 5]; /* same size as in s_misc.c */ info[0] = '\0'; if (parc < 2 || *parv[1] == '\0') { sendto_one(cptr, "ERROR :No servername"); return 0; } hop = 0; host = parv[1]; if (parc > 3 && atoi(parv[2])) { hop = atoi(parv[2]); strncpyzt(info, parv[3], REALLEN + 1); } else if (parc > 2) { strncpyzt(info, parv[2], REALLEN + 1); if ((parc > 3) && ((i = strlen(info)) < (REALLEN - 2))) { strcat(info, " "); strncat(info, parv[3], REALLEN - i - 2); info[REALLEN] = '\0'; } } /* * July 5, 1997 * Rewritten to throw away server cruft from users, * combined the hostname validity test with cleanup of host name, * so a cleaned up hostname can be returned as an error if * necessary. - Dianora */ /* yes, the if(strlen) below is really needed!! */ if (strlen(host) > HOSTLEN) host[HOSTLEN] = '\0'; if (IsPerson(cptr)) { /* A local link that has been identified as a USER tries * something fishy... ;-) */ sendto_one(cptr, err_str(ERR_UNKNOWNCOMMAND), me.name, parv[0], "SERVER"); return 0; } else /* hostile servername check */ { /* * Lets check for bogus names and clean them up we don't bother * cleaning up ones from users, becasuse we will never see them * any more - Dianora */ int bogus_server = 0; int found_dot = 0; char clean_host[(2 * HOSTLEN) + 1]; char *s; char *d; int n; s = host; d = clean_host; n = (2 * HOSTLEN) - 2; while (*s && n > 0) { if ((unsigned char) *s < (unsigned char) ' ') /* Is it a control character? */ { bogus_server = 1; *d++ = '^'; *d++ = (char) ((unsigned char) *s + 0x40); /* turn it into a printable */ n -= 2; } else if ((unsigned char) *s > (unsigned char) '~') { bogus_server = 1; *d++ = '.'; n--; } else { if (*s == '.') found_dot = 1; *d++ = *s; n--; } s++; } *d = '\0'; if ((!found_dot) || bogus_server) { sendto_one(sptr, "ERROR :Bogus server name (%s)", clean_host); return exit_client(cptr, cptr, cptr, "Bogus server name"); } } /* new connection */ if (IsUnknown(cptr) || IsHandshake(cptr)) { strncpyzt(cptr->name, host, sizeof(cptr->name)); strncpyzt(cptr->info, info[0] ? info : me.name, REALLEN + 1); cptr->hopcount = hop; switch (check_server_init(cptr)) { case 0: return m_server_estab(cptr); case 1: sendto_ops("Access check for %s in progress", get_client_name(cptr, HIDEME)); return 1; default: ircstp->is_ref++; sendto_ops_lev(ADMIN_LEV, "Link %s dropped, no Connect block", get_client_name(cptr, TRUE)); return exit_client(cptr, cptr, cptr, "No Connect block"); } } /* already linked server */ if (!IsServer(cptr)) return 0; if ((acptr = find_name(host, NULL))) { /* * * This link is trying feed me a server that I already have * access through another path -- multiple paths not accepted * currently, kill this link immediately!! * * Rather than KILL the link which introduced it, KILL the * youngest of the two links. -avalon */ bcptr = (cptr->firsttime > acptr->from->firsttime) ? cptr : acptr->from; sendto_one(bcptr, "ERROR :Server %s already exists", host); if (bcptr == cptr) { /* Don't complain for servers that are juped */ /* (don't complain if the server that already exists is U: lined, unless I actually have a .conf U: line for it */ if(!IsULine(acptr) || find_aUserver(acptr->name)) { sendto_gnotice("from %s: Link %s cancelled, server %s already " "exists", me.name, get_client_name(bcptr, HIDEME), host); sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, " "server %s already exists", me.name, get_client_name(bcptr, HIDEME), host); } return exit_client(bcptr, bcptr, &me, "Server Exists"); } /* inform all those who care (set +n) -epi */ strcpy(nbuf, get_client_name(bcptr, HIDEME)); sendto_gnotice("from %s: Link %s cancelled, server %s reintroduced " "by %s", me.name, nbuf, host, get_client_name(cptr, HIDEME)); sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, server %s " "reintroduced by %s", me.name, nbuf, host, get_client_name(cptr, HIDEME)); exit_client(bcptr, bcptr, &me, "Server Exists"); } /* * The following if statement would be nice to remove since user * nicks never have '.' in them and servers must always have '.' in * them. There should never be a server/nick name collision, but it * is possible a capricious server admin could deliberately do * something strange. * * -Dianora */ if ((acptr = find_client(host, NULL)) && acptr != cptr) { /* * * Server trying to use the same name as a person. Would * cause a fair bit of confusion. Enough to make it hellish for * a while and servers to send stuff to the wrong place. */ sendto_one(cptr, "ERROR :Nickname %s already exists!", host); strcpy(nbuf, get_client_name(cptr, HIDEME)); sendto_gnotice("from %s: Link %s cancelled, servername/nick collision", me.name, nbuf); sendto_serv_butone(cptr, ":%s GNOTICE :Link %s cancelled, " "servername/nick collision", me.name, nbuf); return exit_client(cptr, cptr, cptr, "Nick as Server"); } if (IsServer(cptr)) { /* * * Server is informing about a new server behind this link. * Create REMOTE server structure, add it to list and propagate * word to my other server links... */ if (parc == 1 || info[0] == '\0') { sendto_one(cptr, "ERROR :No server info specified for %s", host); return 0; } /* * * See if the newly found server is behind a guaranteed leaf * (L-line). If so, close the link. * * Depreciated. Kinda redundant with Hlines. -epi */ if (!(cptr->serv->aconn->flags & CONN_HUB)) { aconn = cptr->serv->aconn; sendto_gnotice("from %s: Non-Hub link %s introduced %s", me.name, get_client_name(cptr, HIDEME), host); sendto_serv_butone(cptr,":%s GNOTICE :Non-Hub link %s introduced " "%s", me.name, get_client_name(cptr, HIDEME), host); sendto_one(cptr, "ERROR :You're not a hub (introducing %s)", host); return exit_client(cptr, cptr, cptr, "Too many servers"); } acptr = make_client(cptr, sptr); make_server(acptr); acptr->hopcount = hop; strncpyzt(acptr->name, host, sizeof(acptr->name)); strncpyzt(acptr->info, info, REALLEN + 1); acptr->serv->up = find_or_add(parv[0]); fakelinkserver_update(acptr->name, acptr->info); SetServer(acptr); /* * if this server is behind a U-lined server, make it U-lined as * well. - lucas */ if (IsULine(sptr) || find_aUserver(acptr->name)) { acptr->flags |= FLAGS_ULINE; sendto_realops_lev(DEBUG_LEV, "%s introducing super server %s", cptr->name, acptr->name); } Count.server++; add_client_to_list(acptr); add_to_client_hash_table(acptr->name, acptr); /* * Old sendto_serv_but_one() call removed because we now need * to send different names to different servers (domain name matching) */ for (i = 0; i <= highest_fd; i++) { if (!(bcptr = local[i]) || !IsServer(bcptr) || bcptr == cptr || IsMe(bcptr)) continue; if (!(aconn = bcptr->serv->aconn)) { sendto_gnotice("from %s: Lost Connect block for %s on %s." " Closing", me.name, get_client_name(cptr, HIDEME), host); sendto_serv_butone(cptr, ":%s GNOTICE :Lost Connect block for" " %s on %s. Closing", me.name, get_client_name(cptr, HIDEME), host); return exit_client(cptr, cptr, cptr, "Lost Connect block"); } if (match(my_name_for_link(me.name, aconn), acptr->name) == 0) continue; sendto_one(bcptr, ":%s SERVER %s %d :%s", parv[0], acptr->name, hop + 1, acptr->info); } return 0; } return 0; }
/* ** mo_jupe ** parv[0] = sender prefix ** parv[1] = server we're juping ** parv[2] = reason for jupe */ static void mo_jupe(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Client *target_p; struct Client *ajupe; dlink_node *m; char reason[REALLEN+2]; if(!ServerInfo.hub) return; if(!IsOperAdmin(source_p)) { sendto_one(source_p, ":%s NOTICE %s :You must be an admin to use this command", me.name, parv[0]); return; } if (bogus_host(parv[1])) { sendto_one(source_p, ":%s NOTICE %s :Invalid servername: %s", me.name, parv[0], parv[1]); return; } if(match(parv[1], me.name)) { sendto_one(source_p, ":%s NOTICE %s :I cant jupe myself!", me.name, source_p->name); return; } sendto_wallops_flags(UMODE_WALLOP, &me, "JUPE for %s requested by %s: %s", parv[1], get_oper_name(source_p), parv[2]); sendto_server(NULL, NOCAPS, NOCAPS, ":%s WALLOPS :JUPE for %s requested by %s!%s@%s: %s", parv[0], parv[1], source_p->name, source_p->username, source_p->host, parv[2]); ilog(L_NOTICE, "JUPE for %s requested by %s: %s", parv[1], get_oper_name(source_p), parv[2]); target_p= find_server(parv[1]); if(target_p) exit_client(client_p, target_p, &me, parv[2]); sendto_server(NULL, NOCAPS, NOCAPS, ":%s SERVER %s 1 :JUPED: %s", me.name, parv[1], parv[2]); sendto_realops_flags(UMODE_ALL, L_ALL, "Link with %s established: (JUPED) link", parv[1]); ajupe = make_client(NULL); /* make_client() adds client to unknown_list */ m = dlinkFind(&unknown_list, ajupe); if(m != NULL) dlinkDelete(m, &unknown_list); free_dlink_node(m); make_server(ajupe); ajupe->hopcount = 1; strlcpy(ajupe->name,parv[1],HOSTLEN); /* we need to give 7 chars to prepend "JUPED: " */ if(strlen(parv[2]) > (REALLEN-7)) parv[2][REALLEN-7] = '\0'; ircsprintf(reason, "%s %s", "JUPED:", parv[2]); strlcpy(ajupe->info,reason,REALLEN); ajupe->serv->up = me.name; ajupe->servptr = &me; SetServer(ajupe); SetDead(ajupe); Count.server++; Count.myserver++; /* Some day, all these lists will be consolidated *sigh* */ add_client_to_list(ajupe); add_to_client_hash_table(ajupe->name, ajupe); dlinkAdd(ajupe, &ajupe->lnode, &ajupe->servptr->serv->servers); add_server_to_list(ajupe); }
int main(int argc, char *argv[]) { uid_t uid, euid; int portarg = 0, fd; #ifdef SAVE_MAXCLIENT_STATS FILE *mcsfp; #endif memset(&me, 0, sizeof(aClient)); if ((timeofday = time(NULL)) == -1) { (void) fprintf(stderr, "ERROR: Clock Failure (%d)\n", errno); exit(errno); } build_version(); Count.server = 1; /* us */ Count.oper = 0; Count.chan = 0; Count.local = 0; Count.total = 0; Count.invisi = 0; Count.unknown = 0; Count.max_loc = 0; Count.max_tot = 0; Count.today = 0; Count.weekly = 0; Count.monthly = 0; Count.yearly = 0; Count.start = NOW; Count.day = NOW; Count.week = NOW; Count.month = NOW; Count.year = NOW; #ifdef SAVE_MAXCLIENT_STATS mcsfp=fopen(DPATH "/.maxclients", "r"); if(mcsfp!=NULL) { fscanf(mcsfp, "%d %d %li %li %li %ld %ld %ld %ld", &Count.max_loc, &Count.max_tot, &Count.weekly, &Count.monthly, &Count.yearly, &Count.start, &Count.week, &Count.month, &Count.year); fclose(mcsfp); } #endif /* * this code by [email protected] * it is intended to keep the ircd from being swapped out. BSD * swapping criteria do not match the requirements of ircd */ #ifdef INITIAL_DBUFS dbuf_init(); /* set up some dbuf stuff to control paging */ #endif sbrk0 = (char *) sbrk((size_t) 0); uid = getuid(); euid = geteuid(); #ifdef PROFIL (void) monstartup(0, etext); (void) moncontrol(1); (void) signal(SIGUSR1, s_monitor); #endif myargv = argv; (void) umask(077); /* better safe than sorry --SRB */ memset((char *) &me, '\0', sizeof(me)); setup_signals(); /* * * All command line parameters have the syntax "-fstring" or "-f * string" (e.g. the space is optional). String may be empty. Flag * characters cannot be concatenated (like "-fxyz"), it would * conflict with the form "-fstring". */ while (--argc > 0 && (*++argv)[0] == '-') { char *p = argv[0] + 1; int flag = *p++; if (flag == '\0' || *p == '\0') { if (argc > 1 && argv[1][0] != '-') { p = *++argv; argc -= 1; } else p = ""; } switch (flag) { case 'a': bootopt |= BOOT_AUTODIE; break; case 'c': bootopt |= BOOT_CONSOLE; break; case 'q': bootopt |= BOOT_QUICK; break; case 'd': (void) setuid((uid_t) uid); dpath = p; break; case 'o': /* Per user local daemon... */ (void) setuid((uid_t) uid); bootopt |= BOOT_OPER; break; #ifdef CMDLINE_CONFIG case 'f': (void) setuid((uid_t) uid); configfile = p; break; # ifdef KPATH case 'k': (void) setuid((uid_t) uid); klinefile = p; break; # endif #endif case 'h': strncpyzt(me.name, p, sizeof(me.name)); break; case 'i': bootopt |= BOOT_INETD | BOOT_AUTODIE; break; case 'p': if ((portarg = atoi(p)) > 0) portnum = portarg; break; case 's': bootopt |= BOOT_STDERR; break; case 't': (void) setuid((uid_t) uid); bootopt |= BOOT_TTY; break; case 'v': (void) printf("ircd %s\n", version); exit(0); case 'x': #ifdef DEBUGMODE (void) setuid((uid_t) uid); debuglevel = atoi(p); debugmode = *p ? p : "0"; bootopt |= BOOT_DEBUG; break; #else (void) fprintf(stderr, "%s: DEBUGMODE must be defined for -x y\n", myargv[0]); exit(0); #endif default: bad_command(); break; } } if (chdir(dpath)) { perror("chdir"); exit(-1); } if ((uid != euid) && !euid) { (void) fprintf(stderr, "ERROR: do not run ircd setuid root. Make it setuid a normal user.\n"); exit(-1); } if (argc > 0) return bad_command(); /* This should exit out */ initialize_ssl(); motd = (aMotd *) NULL; helpfile = (aMotd *) NULL; motd_tm = NULL; #ifdef SHORT_MOTD shortmotd = NULL; #endif read_motd(MOTD); read_help(HELPFILE); #ifdef SHORT_MOTD read_shortmotd(SHORTMOTD); #endif clear_client_hash_table(); clear_channel_hash_table(); clear_scache_hash_table(); /* server cache name table */ clear_ip_hash_table(); /* client host ip hash table */ initlists(); initclass(); initwhowas(); initstats(); init_tree_parse(msgtab); init_send(); NOW = time(NULL); open_debugfile(); NOW = time(NULL); init_fdlist(&serv_fdlist); init_fdlist(&oper_fdlist); init_fdlist(&listen_fdlist); #ifndef NO_PRIORITY init_fdlist(&busycli_fdlist); #endif init_fdlist(&default_fdlist); { int i; for (i = MAXCONNECTIONS + 1; i > 0; i--) { default_fdlist.entry[i] = i - 1; } } if ((timeofday = time(NULL)) == -1) { #ifdef USE_SYSLOG syslog(LOG_WARNING, "Clock Failure (%d), TS can be corrupted", errno); #endif sendto_ops("Clock Failure (%d), TS can be corrupted", errno); } #ifdef WINGATE_NOTICE strcpy(ProxyMonURL, "http://"); strncpyzt((ProxyMonURL + 7), DEFAULT_PROXY_INFO_URL, (TOPICLEN + 1) - 7); strncpyzt(ProxyMonHost, MONITOR_HOST, (HOSTLEN + 1)); #endif if (portnum < 0) portnum = PORTNUM; me.port = portnum; (void) init_sys(); me.flags = FLAGS_LISTEN; #ifndef _WIN32 if (bootopt & BOOT_INETD) { me.fd = 0; local[0] = &me; me.flags = FLAGS_LISTEN; } else #endif me.fd = -1; #ifdef USE_SYSLOG # define SYSLOG_ME "ircd" openlog(SYSLOG_ME, LOG_PID | LOG_NDELAY, LOG_FACILITY); #endif if ((fd = openconf(configfile)) == -1) { Debug((DEBUG_FATAL, "Failed in reading configuration file %s", configfile)); (void) printf("Couldn't open configuration file %s\n", configfile); exit(-1); } (void) initconf(bootopt, fd); /* comstuds SEPARATE_QUOTE_KLINES_BY_DATE code */ #ifdef SEPARATE_QUOTE_KLINES_BY_DATE { struct tm *tmptr; char timebuffer[20], filename[200]; tmptr = localtime(&NOW); (void) strftime(timebuffer, 20, "%y%m%d", tmptr); ircsprintf(filename, "%s.%s", klinefile, timebuffer); if ((fd = openconf(filename)) == -1) { Debug((DEBUG_ERROR, "Failed reading kline file %s", filename)); (void) printf("Couldn't open kline file %s\n", filename); } else (void) initconf(0, fd); } #else # ifdef KPATH if ((fd = openconf(klinefile)) == -1) { Debug((DEBUG_ERROR, "Failed reading kline file %s", klinefile)); (void) printf("Couldn't open kline file %s\n", klinefile); } else (void) initconf(0, fd); # endif #endif if (!(bootopt & BOOT_INETD)) { static char star[] = "*"; aConfItem *aconf; u_long vaddr; if ((aconf = find_me()) && portarg <= 0 && aconf->port > 0) portnum = aconf->port; Debug((DEBUG_ERROR, "Port = %d", portnum)); if ((aconf->passwd[0] != '\0') && (aconf->passwd[0] != '*')) vaddr = inet_addr(aconf->passwd); else vaddr = (u_long) NULL; if (inetport(&me, star, portnum, vaddr)) { if (bootopt & BOOT_STDERR) fprintf(stderr, "Couldn't bind to primary port %d\n", portnum); #ifdef USE_SYSLOG (void) syslog(LOG_CRIT, "Couldn't bind to primary port %d\n", portnum); #endif exit(1); } } else if (inetport(&me, "*", 0, 0)) { if (bootopt & BOOT_STDERR) fprintf(stderr, "Couldn't bind to port passed from inetd\n"); #ifdef USE_SYSLOG (void) syslog(LOG_CRIT, "Couldn't bind to port passed from inetd\n"); #endif exit(1); } (void) get_my_name(&me, me.sockhost, sizeof(me.sockhost) - 1); if (me.name[0] == '\0') strncpyzt(me.name, me.sockhost, sizeof(me.name)); me.hopcount = 0; me.authfd = -1; me.confs = NULL; me.next = NULL; me.user = NULL; me.from = &me; SetMe(&me); make_server(&me); me.serv->up = me.name; me.lasttime = me.since = me.firsttime = NOW; (void) add_to_client_hash_table(me.name, &me); /* We don't want to calculate these every time they are used :) */ sprintf(REPORT_DO_DNS, REPORT_DO_DNS_, me.name); sprintf(REPORT_FIN_DNS, REPORT_FIN_DNS_, me.name); sprintf(REPORT_FIN_DNSC, REPORT_FIN_DNSC_, me.name); sprintf(REPORT_FAIL_DNS, REPORT_FAIL_DNS_, me.name); sprintf(REPORT_DO_ID, REPORT_DO_ID_, me.name); sprintf(REPORT_FIN_ID, REPORT_FIN_ID_, me.name); sprintf(REPORT_FAIL_ID, REPORT_FAIL_ID_, me.name); R_do_dns = strlen(REPORT_DO_DNS); R_fin_dns = strlen(REPORT_FIN_DNS); R_fin_dnsc = strlen(REPORT_FIN_DNSC); R_fail_dns = strlen(REPORT_FAIL_DNS); R_do_id = strlen(REPORT_DO_ID); R_fin_id = strlen(REPORT_FIN_ID); R_fail_id = strlen(REPORT_FAIL_ID); check_class(); if (bootopt & BOOT_OPER) { aClient *tmp = add_connection(&me, 0); if (!tmp) exit(1); SetMaster(tmp); } else write_pidfile(); Debug((DEBUG_NOTICE, "Server ready...")); #ifdef USE_SYSLOG syslog(LOG_NOTICE, "Server Ready"); #endif NOW = time(NULL); #ifndef NO_PRIORITY check_fdlists(); #endif if ((timeofday = time(NULL)) == -1) { #ifdef USE_SYSLOG syslog(LOG_WARNING, "Clock Failure (%d), TS can be corrupted", errno); #endif sendto_ops("Clock Failure (%d), TS can be corrupted", errno); } #ifdef DUMP_DEBUG dumpfp=fopen("dump.log", "w"); #endif io_loop(); return 0; }
/* * change_local_nick * inputs - pointer to server * - pointer to client * output - * side effects - changes nick of a LOCAL user * */ int change_local_nick(struct Client *client_p, struct Client *source_p, char *nick) { /* ** Client just changing his/her nick. If he/she is ** on a channel, send note of change to all clients ** on that channel. Propagate notice to other servers. */ source_p->tsinfo = CurrentTime; if((source_p->localClient->last_nick_change + ConfigFileEntry.max_nick_time) < CurrentTime) source_p->localClient->number_of_nick_changes = 0; source_p->localClient->last_nick_change = CurrentTime; source_p->localClient->number_of_nick_changes++; if((ConfigFileEntry.anti_nick_flood && (source_p->localClient->number_of_nick_changes <= ConfigFileEntry.max_nick_changes)) || !ConfigFileEntry.anti_nick_flood || (IsOper(source_p) && ConfigFileEntry.no_oper_flood)) { sendto_realops_flags(FLAGS_NCHANGE, L_ALL, "Nick change: From %s to %s [%s@%s]", source_p->name, nick, source_p->username, source_p->host); sendto_common_channels_local(source_p, ":%s!%s@%s NICK :%s", source_p->name, source_p->username, source_p->host, nick); if (source_p->user) { add_history(source_p, 1); /* Only hubs care about lazy link nicks not being sent on yet * lazylink leafs/leafs always send their nicks up to hub, * hence must always propogate nick changes. * hubs might not propogate a nick change, if the leaf * does not know about that client yet. */ sendto_server(client_p, source_p, NULL, NOCAPS, NOCAPS, NOFLAGS, ":%s NICK %s :%lu", source_p->name, nick, (unsigned long) source_p->tsinfo); } } else { sendto_one(source_p, form_str(ERR_NICKTOOFAST),me.name, source_p->name, source_p->name, nick, ConfigFileEntry.max_nick_time); return 0; } /* Finally, add to hash */ del_from_client_hash_table(source_p->name, source_p); strcpy(source_p->name, nick); add_to_client_hash_table(nick, source_p); /* Make sure everyone that has this client on its accept list * loses that reference. */ del_all_accepts(source_p); /* fd_desc is long enough */ fd_note(client_p->localClient->fd, "Nick: %s", nick); return 1; }
/* * nick_from_server() */ static int nick_from_server(struct Client *client_p, struct Client *source_p, int parc, char *parv[], time_t newts, char *nick) { if(IsServer(source_p)) { /* A server introducing a new client, change source */ source_p = make_client(client_p); add_client_to_list(source_p); if(parc > 2) source_p->hopcount = atoi(parv[2]); if(newts) source_p->tsinfo = newts; else { newts = source_p->tsinfo = CurrentTime; ts_warn("Remote nick %s (%s) introduced without a TS", nick, parv[0]); } /* copy the nick in place */ (void) strcpy(source_p->name, nick); (void) add_to_client_hash_table(nick, source_p); if(parc > 8) { int flag; char *m; /* parse usermodes */ m = &parv[4][1]; while (*m) { flag = user_modes_from_c_to_bitmask[(unsigned char) *m]; if(!(source_p->umodes & UMODE_INVISIBLE) && (flag & UMODE_INVISIBLE)) Count.invisi++; if(!(source_p->umodes & UMODE_OPER) && (flag & UMODE_OPER)) Count.oper++; source_p->umodes |= flag & SEND_UMODES; m++; } return do_remote_user(nick, client_p, source_p, parv[5], parv[6], parv[7], (parc > 9)? parv[8] : NULL, parv[(parc > 9)? 9 : 8]); } } else if(source_p->name[0]) { /* client changing their nick */ if(irccmp(parv[0], nick)) source_p->tsinfo = newts ? newts : CurrentTime; sendto_common_channels_local(source_p, ":%s!%s@%s NICK :%s", source_p->name, source_p->username, source_p->host, nick); if(source_p->user) { add_history(source_p, 1); sendto_server(client_p, NULL, NOCAPS, NOCAPS, ":%s NICK %s :%lu", parv[0], nick, (unsigned long) source_p->tsinfo); } } /* set the new nick name */ if(source_p->name[0]) del_from_client_hash_table(source_p->name, source_p); strcpy(source_p->name, nick); add_to_client_hash_table(nick, source_p); /* remove all accepts pointing to the client */ del_all_accepts(source_p); return 0; }
/* * ms_server - SERVER message handler * parv[0] = sender prefix * parv[1] = servername * parv[2] = serverinfo/hopcount * parv[3] = serverinfo */ static void ms_server(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char info[REALLEN + 1]; /* same size as in s_misc.c */ char* name; struct Client* target_p; struct Client* bclient_p; struct ConfItem* aconf; int hop; int hlined = 0; int llined = 0; dlink_node *ptr; /* Just to be sure -A1kmm. */ if (!IsServer(source_p)) return; if (parc < 4) { sendto_one(client_p,"ERROR :No servername"); return; } name = parv[1]; hop = atoi(parv[2]); strlcpy(info, parv[3], REALLEN); if ((target_p = server_exists(name))) { /* * This link is trying feed me a server that I already have * access through another path -- multiple paths not accepted * currently, kill this link immediately!! * * Rather than KILL the link which introduced it, KILL the * youngest of the two links. -avalon * * I think that we should exit the link itself, not the introducer, * and we should always exit the most recently received(i.e. the * one we are receiving this SERVER for. -A1kmm * * You *cant* do this, if you link somewhere, it bursts you a server * that already exists, then sends you a client burst, you squit the * server, but you keep getting the burst of clients on a server that * doesnt exist, although ircd can handle it, its not a realistic * solution.. --fl_ */ /* It is behind a host-masked server. Completely ignore the * server message(don't propagate or we will delink from whoever * we propagate to). -A1kmm */ if (irccmp(target_p->name, name) && target_p->from==client_p) return; sendto_one(client_p, "ERROR :Server %s already exists", name); sendto_realops_flags(FLAGS_ALL, L_ADMIN, "Link %s cancelled, server %s already exists", get_client_name(client_p, SHOW_IP), name); sendto_realops_flags(FLAGS_ALL, L_OPER, "Link %s cancelled, server %s already exists", client_p->name, name); exit_client(client_p, client_p, &me, "Server Exists"); return; } /* * User nicks never have '.' in them and server names * must always have '.' in them. */ if (strchr(name,'.') == NULL) { /* * Server trying to use the same name as a person. Would * cause a fair bit of confusion. Enough to make it hellish * for a while and servers to send stuff to the wrong place. */ sendto_one(client_p,"ERROR :Nickname %s already exists!", name); sendto_realops_flags(FLAGS_ALL, L_ADMIN, "Link %s cancelled: Server/nick collision on %s", /* inpath */ get_client_name(client_p, HIDE_IP), name); sendto_realops_flags(FLAGS_ALL, L_OPER, "Link %s cancelled: Server/nick collision on %s", get_client_name(client_p, MASK_IP), name); exit_client(client_p, client_p, client_p, "Nick as Server"); return; } /* * Server is informing about a new server behind * this link. Create REMOTE server structure, * add it to list and propagate word to my other * server links... */ if (parc == 1 || info[0] == '\0') { sendto_one(client_p, "ERROR :No server info specified for %s", name); return; } /* * See if the newly found server is behind a guaranteed * leaf. If so, close the link. * */ for (aconf = ConfigItemList; aconf; aconf=aconf->next) { if ((aconf->status & (CONF_LEAF|CONF_HUB)) == 0) continue; if (match(aconf->name, client_p->name)) { if (aconf->status == CONF_HUB) { if(match(aconf->host, name)) hlined++; } else if (aconf->status == CONF_LEAF) { if(match(aconf->host, name)) llined++; } } } /* Ok, this way this works is * * A server can have a CONF_HUB allowing it to introduce servers * behind it. * * connect { * name = "irc.bighub.net"; * hub_mask="*"; * ... * * That would allow "irc.bighub.net" to introduce anything it wanted.. * * However * * connect { * name = "irc.somehub.fi"; * hub_mask="*"; * leaf_mask="*.edu"; *... * Would allow this server in finland to hub anything but * .edu's */ /* Ok, check client_p can hub the new server, and make sure it's not a LL */ if (!hlined || (IsCapable(client_p, CAP_LL) && !IsCapable(client_p, CAP_HUB))) { /* OOOPs nope can't HUB */ sendto_realops_flags(FLAGS_ALL, L_ADMIN, "Non-Hub link %s introduced %s.", get_client_name(client_p, HIDE_IP), name); sendto_realops_flags(FLAGS_ALL, L_OPER, "Non-Hub link %s introduced %s.", get_client_name(client_p, MASK_IP), name); exit_client(NULL, source_p, &me, "No matching hub_mask."); return; } /* Check for the new server being leafed behind this HUB */ if (llined) { /* OOOPs nope can't HUB this leaf */ sendto_realops_flags(FLAGS_ALL, L_ADMIN, "Link %s introduced leafed server %s.", get_client_name(client_p, HIDE_IP), name); sendto_realops_flags(FLAGS_ALL, L_OPER, "Link %s introduced leafed server %s.", client_p->name, name); /* If it is new, we are probably misconfigured, so split the * non-hub server introducing this. Otherwise, split the new * server. -A1kmm. */ /* wastes too much bandwidth, generates too many errors on * larger networks, dont bother. --fl_ */ #if 0 if ((CurrentTime - source_p->firsttime) < 20) { exit_client(NULL, source_p, &me, "Leafed Server."); return; } else { sendto_one(source_p, ":%s SQUIT %s :Sorry, Leafed server.", me.name, name); return; } #endif exit_client(NULL, client_p, &me, "Leafed Server."); return; } if(strlen(name) > HOSTLEN) { sendto_realops_flags(FLAGS_ALL, L_ADMIN, "Link %s introduced server with invalid servername %s", get_client_name(client_p, HIDE_IP), name); sendto_realops_flags(FLAGS_ALL, L_OPER, "Link %s introduced server with invalid servername %s", client_p->name, name); exit_client(NULL, client_p, &me, "Invalid servername introduced."); return; } target_p = make_client(client_p); make_server(target_p); target_p->hopcount = hop; strlcpy(target_p->name, name, HOSTLEN+1); set_server_gecos(target_p, info); target_p->serv->up = find_or_add(parv[0]); target_p->servptr = source_p; SetServer(target_p); Count.server++; add_client_to_list(target_p); add_server_to_list(target_p); add_to_client_hash_table(target_p->name, target_p); add_client_to_llist(&(target_p->servptr->serv->servers), target_p); /* * Old sendto_serv_but_one() call removed because we now * need to send different names to different servers * (domain name matching) */ for (ptr = serv_list.head; ptr; ptr = ptr->next) { bclient_p = ptr->data; if (bclient_p == client_p) continue; if (!(aconf = bclient_p->serv->sconf)) { sendto_realops_flags(FLAGS_ALL, L_ADMIN, "Lost N-line for %s on %s. Closing", get_client_name(client_p, HIDE_IP), name); sendto_realops_flags(FLAGS_ALL, L_OPER, "Lost N-line for %s on %s. Closing", get_client_name(client_p, MASK_IP), name); exit_client(client_p, client_p, client_p, "Lost N line"); return; } if (match(my_name_for_link(me.name, aconf), target_p->name)) continue; sendto_one(bclient_p, ":%s SERVER %s %d :%s%s", parv[0], target_p->name, hop + 1, target_p->hidden_server ? "(H) " : "", target_p->info); } if (!IsRelay(target_p)) sendto_realops_flags(FLAGS_EXTERNAL, L_ALL, "Server %s being introduced by %s", target_p->name, source_p->name); }
int m_hash(struct Client *cptr, struct Client *sptr,int parc,char *parv[]) { register int l; register int i; register struct HashEntry* tab; struct HashEntry* table; struct tm* tmptr; int deepest = 0; int deeplink = 0; int showlist = 0; int tothits = 0; int mosthit = 0; int mosthits = 0; int used = 0; int used_now = 0; int totlink = 0; int size = U_MAX; char ch; int out = 0; int link_pop[10]; char result_buf[256]; char hash_log_file[256]; char timebuffer[MAX_DATE_STRING]; if (!MyClient(sptr) || !HasUmode(sptr,UMODE_DEBUG)) { sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if(parc > 1) { if(!irccmp(parv[1],"iphash")) { iphash_stats(cptr,sptr,parc,parv,-1); return 0; } else if(!irccmp(parv[1],"Diphash")) { tmptr = localtime(&CurrentTime); strftime(timebuffer, MAX_DATE_STRING, "%Y%m%d%H%M", tmptr); sprintf(hash_log_file, "%s.%s", hash_log_file_base, timebuffer); if ((out = open(hash_log_file, O_RDWR | O_APPEND | O_CREAT,0664))==-1) sendto_one(sptr, ":%s NOTICE %s :Problem opening %s", me.name, parv[0], hash_log_file); else sendto_one(sptr, ":%s NOTICE %s :Writing hash log to %s", me.name, parv[0], hash_log_file); iphash_stats(cptr,sptr,parc,parv,out); return 0; } ch = *parv[1]; if (IsLower(ch)) { table = clientTable; } else { table = channelTable; size = CH_MAX; } if (ch == 'L' || ch == 'l') { tmptr = localtime(&CurrentTime); strftime(timebuffer, MAX_DATE_STRING, "%Y%m%d%H%M", tmptr); sprintf(hash_log_file, "%s-%cdump.%s", hash_log_file_base, ch, timebuffer); showlist = 1; if ((out = open(hash_log_file, O_RDWR|O_APPEND|O_CREAT,0664))==-1) sendto_one(sptr, ":%s NOTICE %s :Problem opening %s ", me.name, parv[0], hash_log_file); else sendto_one(sptr, ":%s NOTICE %s :Writing hash log to %s ", me.name, parv[0], hash_log_file); } } else { ch = '\0'; table = clientTable; } for (i = 0; i < 10; i++) link_pop[i] = 0; for (i = 0; i < size; i++) { tab = &table[i]; l = tab->links; if (showlist) { /* sendto_one(sptr, "NOTICE %s :Hash Entry:%6d Hits:%7d Links:%6d", parv[0], i, tab->hits, l); */ if(out >= 0) { sprintf(result_buf,"Hash Entry:%6d Hits;%7d Links:%6d\n", i, tab->hits, l); write(out,result_buf,strlen(result_buf)); } } if (l > 0) { if (l < 10) link_pop[l]++; else link_pop[9]++; used_now++; totlink += l; if (l > deepest) { deepest = l; deeplink = i; } } else link_pop[0]++; l = tab->hits; if (l) { used++; tothits += l; if (l > mosthits) { mosthits = l; mosthit = i; } } } if(showlist && (out >= 0)) (void)close(out); switch((int)ch) { case 'V' : case 'v' : { register struct Client* acptr; int bad = 0, listlength = 0; for (acptr = GlobalClientList; acptr; acptr = acptr->next) { if (hash_find_client(acptr->name,acptr) != acptr) { if (ch == 'V') sendto_one(sptr, "NOTICE %s :Bad hash for %s", parv[0], acptr->name); bad++; } listlength++; } sendto_one(sptr,"NOTICE %s :List Length: %d Bad Hashes: %d", parv[0], listlength, bad); } case 'P' : case 'p' : for (i = 0; i < 10; i++) sendto_one(sptr,"NOTICE %s :Entires with %d links : %d", parv[0], i, link_pop[i]); return (0); case 'r' : { register struct Client *acptr; sendto_one(sptr,"NOTICE %s :Rehashing Client List.", parv[0]); clear_client_hash_table(); for (acptr = GlobalClientList; acptr; acptr = acptr->next) add_to_client_hash_table(acptr->name, acptr); break; } case 'R' : { register struct Channel *acptr; sendto_one(sptr,"NOTICE %s :Rehashing Channel List.", parv[0]); clear_channel_hash_table(); for (acptr = channel; acptr; acptr = acptr->nextch) (void)add_to_channel_hash_table(acptr->chname, acptr); break; } case 'H' : if (parc > 2) sendto_one(sptr,"NOTICE %s :%s hash to entry %d", parv[0], parv[2], hash_channel_name(parv[2])); return (0); case 'h' : if (parc > 2) sendto_one(sptr,"NOTICE %s :%s hash to entry %d", parv[0], parv[2], hash_nick_name(parv[2])); return (0); case 'n' : { struct Client *tmp; int max; if (parc <= 2) return (0); l = atoi(parv[2]) % U_MAX; if (parc > 3) max = atoi(parv[3]) % U_MAX; else max = l; for (;l <= max; l++) for (i = 0, tmp = (struct Client *)clientTable[l].list; tmp; i++, tmp = tmp->hnext) { if (parv[1][2] == '1' && tmp != tmp->from) continue; sendto_one(sptr,"NOTICE %s :Node: %d #%d %s", parv[0], l, i, tmp->name); } return (0); } case 'N' : { struct Channel *tmp; int max; if (parc <= 2) return (0); l = atoi(parv[2]) % CH_MAX; if (parc > 3) max = atoi(parv[3]) % CH_MAX; else max = l; for (;l <= max; l++) for (i = 0, tmp = (struct Channel*) channelTable[l].list; tmp; i++, tmp = tmp->hnextch) sendto_one(sptr,"NOTICE %s :Node: %d #%d %s", parv[0], l, i, tmp->chname); return (0); } #ifdef DEBUGMODE case 'S' : sendto_one(sptr,"NOTICE %s :Entries Hashed: %d NonEmpty: %d of %d", parv[0], totlink, used_now, size); if (!used_now) used_now = 1; sendto_one(sptr,"NOTICE %s :Hash Ratio (av. depth): %f %%Full: %f", parv[0], (float)((1.0 * totlink) / (1.0 * used_now)), (float)((1.0 * used_now) / (1.0 * size))); sendto_one(sptr,"NOTICE %s :Deepest Link: %d Links: %d", parv[0], deeplink, deepest); if (!used) used = 1; sendto_one(sptr,"NOTICE %s :Total Hits: %d Unhit: %d Av Hits: %f", parv[0], tothits, size-used, (float)((1.0 * tothits) / (1.0 * used))); sendto_one(sptr,"NOTICE %s :Entry Most Hit: %d Hits: %d", parv[0], mosthit, mosthits); sendto_one(sptr,"NOTICE %s :Client hits %d miss %d", parv[0], clhits, clmiss); sendto_one(sptr,"NOTICE %s :Channel hits %d miss %d", parv[0], chhits, chmiss); return 0; #endif } return 0; }