int remove_dcc_references(aClient *sptr) { aClient *acptr; Link *lp, *nextlp; Link **lpp, *tmp; int found; lp = sptr->user->dccallow; while(lp) { nextlp = lp->next; acptr = lp->value.cptr; for(found = 0, lpp = &(acptr->user->dccallow); *lpp; lpp=&((*lpp)->next)) { if(lp->flags == (*lpp)->flags) continue; /* match only opposite types for sanity */ if((*lpp)->value.cptr == sptr) { if((*lpp)->flags == DCC_LINK_ME) { sendto_one(&me, acptr, ":%s %d %s :%s has been removed from " "your DCC allow list for signing off", me.name, RPL_DCCINFO, acptr->name, sptr->name); } tmp = *lpp; *lpp = tmp->next; free_link(tmp); found++; break; } } if(!found) sendto_realops_lev(DEBUG_LEV, "rdr(): %s was in dccallowme " "list[%d] of %s but not in dccallowrem list!", acptr->name, lp->flags, sptr->name); free_link(lp); lp = nextlp; } return 0; }
int parse(aClient *cptr, char *buffer, char *bufend) { aClient *from = cptr; char *ch, *s; int i, numeric = 0, paramcount; struct Message *mptr; #ifdef DUMP_DEBUG if(dumpfp!=NULL) { fprintf(dumpfp, "<- %s: %s\n", (cptr->name ? cptr->name : "*"), buffer); fflush(dumpfp); } #endif Debug((DEBUG_DEBUG, "Parsing %s: %s", get_client_name(cptr, TRUE), buffer)); if (IsDead(cptr)) return -1; s = sender; *s = '\0'; for (ch = buffer; *ch == ' '; ch++); /* skip spaces */ para[0] = from->name; if (*ch == ':') { /* * Copy the prefix to 'sender' assuming it terminates with * SPACE (or NULL, which is an error, though). */ for (++ch; *ch && *ch != ' '; ++ch) if (s < (sender + HOSTLEN)) *s++ = *ch; *s = '\0'; /* * Actually, only messages coming from servers can have the * prefix--prefix silently ignored, if coming from a user * client... * * ...sigh, the current release "v2.2PL1" generates also null * prefixes, at least to NOTIFY messages (e.g. it puts * "sptr->nickname" as prefix from server structures where it's * null--the following will handle this case as "no prefix" at * all --msa (": NOTICE nick ...") */ if (*sender && IsServer(cptr)) { from = find_client(sender, (aClient *) NULL); /* * okay, this doesn't seem to do much here. * from->name _MUST_ be equal to sender. * That's what find_client does. * find_client will find servers too, and since we don't use server * masking, the find server call is useless (and very wasteful). * now, there HAS to be a from and from->name and * sender have to be the same * for us to get to the next if. but the next if * starts out with if(!from) * so this is UNREACHABLE CODE! AGH! - lucas * * if (!from || mycmp(from->name, sender)) * from = find_server(sender, (aClient *) NULL); * else if (!from && strchr(sender, '@')) * from = find_nickserv(sender, (aClient *) NULL); */ para[0] = sender; /* * Hmm! If the client corresponding to the prefix is not * found--what is the correct action??? Now, I will ignore the * message (old IRC just let it through as if the prefix just * wasn't there...) --msa */ if (!from) { Debug((DEBUG_ERROR, "Unknown prefix (%s)(%s) from (%s)", sender, buffer, cptr->name)); ircstp->is_unpf++; remove_unknown(cptr, sender, buffer); return -1; } if (from->from != cptr) { ircstp->is_wrdi++; Debug((DEBUG_ERROR, "Message (%s) coming from (%s)", buffer, cptr->name)); return cancel_clients(cptr, from, buffer); } } while (*ch == ' ') ch++; } if (*ch == '\0') { ircstp->is_empt++; Debug((DEBUG_NOTICE, "Empty message from host %s:%s", cptr->name, from->name)); return (-1); } /* * Extract the command code from the packet. Point s to the end * of the command code and calculate the length using pointer * arithmetic. Note: only need length for numerics and *all* * numerics must have parameters and thus a space after the command * code. -avalon * * ummm???? - Dianora */ /* Reparse point for /msg raw - Tux` */ reparse: /* check for numeric */ if (*(ch + 3) == ' ' && IsDigit(*ch) && IsDigit(*(ch + 1)) && IsDigit(*(ch + 2))) { mptr = (struct Message *) NULL; numeric = (*ch - '0') * 100 + (*(ch + 1) - '0') * 10 + (*(ch + 2) - '0'); paramcount = MAXPARA; ircstp->is_num++; s = ch + 3; *s++ = '\0'; } else { s = strchr(ch, ' '); if (s) *s++ = '\0'; mptr = tree_parse(ch); if ((mptr && mptr->func == m_private) && (s && !strncasecmp(s, "raw ", 4))) { ch = index(s, ':'); if (ch++) goto reparse; } else if (!mptr || !mptr->cmd) { /* * only send error messages to things that actually sent * buffers to us and only people, too. */ if (buffer[0] != '\0') { if (IsPerson(from)) sendto_one(from, ":%s %d %s %s :Unknown command", me.name, ERR_UNKNOWNCOMMAND, from->name, ch); Debug((DEBUG_ERROR, "Unknown (%s) from %s", ch, get_client_name(cptr, TRUE))); } ircstp->is_unco++; return -1; } paramcount = mptr->parameters; i = bufend - ((s) ? s : ch); mptr->bytes += i; /* * Allow only 1 msg per 2 seconds (on average) to prevent * dumping. to keep the response rate up, bursts of up to 5 msgs * are allowed -SRB Opers can send 1 msg per second, burst of ~20 * -Taner */ if (!IsServer(cptr)) { if (!NoMsgThrottle(cptr)) { #ifdef NO_OPER_FLOOD if (IsAnOper(cptr)) /* "randomly" (weighted) increase the since */ cptr->since += (cptr->receiveM % 10) ? 1 : 0; else #endif cptr->since += (2 + i / 120); } } } /* * Must the following loop really be so devious? On surface it * splits the message to parameters from blank spaces. But, if * paramcount has been reached, the rest of the message goes into * this last parameter (about same effect as ":" has...) --msa */ /* Note initially true: s==NULL || *(s-1) == '\0' !! */ i = 1; if (s) { if (paramcount > MAXPARA) paramcount = MAXPARA; for (;;) { while (*s == ' ') *s++ = '\0'; if (*s == '\0') break; if (*s == ':') { /* The rest is a single parameter */ para[i++] = s + 1; break; } para[i++] = s; if (i >= paramcount) { if(paramcount == MAXPARA && strchr(s, ' ')) { sendto_realops_lev(DEBUG_LEV, "Overflowed MAXPARA on %s from %s", mptr ? mptr->cmd : "numeric", get_client_name(cptr, (IsServer(cptr) ? HIDEME : FALSE))); } break; } while(*s && *s != ' ') s++; } } para[i] = NULL; if (mptr == (struct Message *) NULL) return (do_numeric(numeric, cptr, from, i, para)); mptr->count++; /* patch to avoid server flooding from unregistered connects */ if (!IsRegistered(cptr) && !(mptr->flags & MF_UNREG)) { sendto_one(from, ":%s %d %s %s :Register first.", me.name, ERR_NOTREGISTERED, from->name, ch); return -1; } if (IsRegisteredUser(cptr) && (mptr->flags & MF_RIDLE)) from->user->last = timeofday; if (mptr->flags & MF_ALIAS) return mptr->func(cptr, from, i, para, &aliastab[mptr->aliasidx]); return (*mptr->func) (cptr, from, i, para); }
/* * exit_client * This is old "m_bye". Name changed, because this is not a * protocol function, but a general server utility function. * * This function exits a client of *any* type (user, server, etc) * from this server. Also, this generates all necessary prototol * messages that this exit may cause. * * 1) If the client is a local client, then this implicitly exits * all other clients depending on this connection (e.g. remote * clients having 'from'-field that points to this. * * 2) If the client is a remote client, then only this is exited. * * For convenience, this function returns a suitable value for * m_function return value: * * FLUSH_BUFFER if (cptr == sptr) * 0 if (cptr != sptr) */ int exit_client(aClient *cptr, aClient *sptr, aClient *from, char *comment) { #ifdef FNAME_USERLOG time_t on_for; #endif if (MyConnect(sptr)) { call_hooks(CHOOK_SIGNOFF, sptr); if (IsUnknown(sptr)) Count.unknown--; if (IsAnOper(sptr)) remove_from_list(&oper_list, sptr, NULL); if (sptr->flags & FLAGS_HAVERECVQ) { /* mark invalid, will be deleted in do_recvqs() */ DLink *lp = find_dlink(recvq_clients, sptr); if (lp) lp->flags = -1; } if (IsClient(sptr)) Count.local--; if (IsNegoServer(sptr)) sendto_realops("Lost server %s during negotiation: %s", sptr->name, comment); if (IsServer(sptr)) { Count.myserver--; if (IsULine(sptr)) Count.myulined--; remove_from_list(&server_list, sptr, NULL); if (server_list == NULL) server_was_split = YES; } sptr->flags |= FLAGS_CLOSING; if (IsPerson(sptr)) { Link *lp, *next; LOpts *lopt = sptr->user->lopt; /* poof goes their watchlist! */ hash_del_watch_list(sptr); /* if they have listopts, axe those, too */ if(lopt != NULL) { remove_from_list(&listing_clients, sptr, NULL); for (lp = lopt->yeslist; lp; lp = next) { next = lp->next; MyFree(lp->value.cp); free_link(lp); } for (lp = lopt->nolist; lp; lp = next) { next = lp->next; MyFree(lp->value.cp); free_link(lp); } MyFree(sptr->user->lopt); sptr->user->lopt = NULL; } sendto_realops_lev(CCONN_LEV, "Client exiting: %s (%s@%s) [%s] [%s]", sptr->name, sptr->user->username, sptr->user->host, (sptr->flags & FLAGS_NORMALEX) ? "Client Quit" : comment, sptr->hostip); } #ifdef FNAME_USERLOG on_for = timeofday - sptr->firsttime; #endif #if defined(USE_SYSLOG) && defined(SYSLOG_USERS) if (IsPerson(sptr)) syslog(LOG_NOTICE, "%s (%3d:%02d:%02d): %s!%s@%s %d/%d\n", myctime(sptr->firsttime), on_for / 3600, (on_for % 3600) / 60, on_for % 60, sptr->name, sptr->user->username, sptr->user->host, sptr->sendK, sptr->receiveK); #endif #if defined(FNAME_USERLOG) { char linebuf[300]; static int logfile = -1; static long lasttime; /* * This conditional makes the logfile active only after it's * been created - thus logging can be turned off by removing * the file. * * stop NFS hangs...most systems should be able to open a file in * 3 seconds. -avalon (curtesy of wumpus) * * Keep the logfile open, syncing it every 10 seconds -Taner */ if (IsPerson(sptr)) { if (logfile == -1) { alarm(3); logfile = open(FNAME_USERLOG, O_WRONLY | O_APPEND); alarm(0); } ircsprintf(linebuf, "%s (%3d:%02d:%02d): %s!%s@%s %d/%d\n", myctime(sptr->firsttime), on_for / 3600, (on_for % 3600) / 60, on_for % 60, sptr->name, sptr->user->username, sptr->user->host, sptr->sendK, sptr->receiveK); alarm(3); write(logfile, linebuf, strlen(linebuf)); alarm(0); /* Resync the file evey 10 seconds*/ if (timeofday - lasttime > 10) { alarm(3); close(logfile); alarm(0); logfile = -1; lasttime = timeofday; } } } #endif if (sptr->fd >= 0) { if (cptr != NULL && sptr != cptr) sendto_one(&me, sptr, "ERROR :Closing Link: %s %s (%s)", IsPerson(sptr) ? sptr->sockhost : "0.0.0.0", sptr->name, comment); else sendto_one(&me, sptr, "ERROR :Closing Link: %s (%s)", IsPerson(sptr) ? sptr->sockhost : "0.0.0.0", comment); } /* * * Currently only server connections can have * depending * remote clients here, but it does no * harm to check for all * local clients. In * future some other clients than servers * might * have remotes too... * * * Close the Client connection first and mark it * so that no * messages are attempted to send to it. *, The following *must* * make MyConnect(sptr) == FALSE!). * It also makes sptr->from == * NULL, thus it's unnecessary * to test whether "sptr != acptr" * in the following loops. */ if (IsServer(sptr)) { sendto_ops("%s was connected for %lu seconds. %lu/%lu " "sendK/recvK.", sptr->name, (long)(timeofday - sptr->firsttime), sptr->sendK, sptr->receiveK); #ifdef USE_SYSLOG syslog(LOG_NOTICE, "%s was connected for %lu seconds. %lu/%lu " "sendK/recvK.", sptr->name, (u_long) timeofday - sptr->firsttime, sptr->sendK, sptr->receiveK); #endif close_connection(sptr); sptr->sockerr = 0; sptr->flags |= FLAGS_DEADSOCKET; } else { close_connection(sptr); sptr->sockerr = 0; sptr->flags |= FLAGS_DEADSOCKET; } } exit_one_client(cptr, sptr, from, comment); return cptr == sptr ? FLUSH_BUFFER : 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; }
/* * 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; }
static int fatal_ssl_error(int ssl_error, int where, aClient *sptr) { /* don`t alter errno */ int errtmp = errno; #if defined( SSL_DEBUG ) || defined( USE_SYSLOG ) char *errstr = strerror(errtmp); #endif char *ssl_errstr, *ssl_func; switch(where) { case SAFE_SSL_READ: ssl_func = "SSL_read()"; break; case SAFE_SSL_WRITE: ssl_func = "SSL_write()"; break; case SAFE_SSL_ACCEPT: ssl_func = "SSL_accept()"; break; default: ssl_func = "undefined SSL func [this is a bug] reporto to [email protected]"; } switch(ssl_error) { case SSL_ERROR_NONE: ssl_errstr = "No error"; break; case SSL_ERROR_SSL: ssl_errstr = "Internal OpenSSL error or protocol error"; break; case SSL_ERROR_WANT_READ: ssl_errstr = "OpenSSL functions requested a read()"; break; case SSL_ERROR_WANT_WRITE: ssl_errstr = "OpenSSL functions requested a write()"; break; case SSL_ERROR_WANT_X509_LOOKUP: ssl_errstr = "OpenSSL requested a X509 lookup which didn`t arrive"; break; case SSL_ERROR_SYSCALL: ssl_errstr = "Underlying syscall error"; break; case SSL_ERROR_ZERO_RETURN: ssl_errstr = "Underlying socket operation returned zero"; break; case SSL_ERROR_WANT_CONNECT: ssl_errstr = "OpenSSL functions wanted a connect()"; break; default: ssl_errstr = "Unknown OpenSSL error (huh?)"; } #ifdef SSL_DEBUG sendto_realops_lev(DEBUG_LEV, "%s to " "%s!%s@%s aborted with%serror (%s). [%s]", ssl_func, *sptr->name ? sptr->name : "<unknown>", (sptr->user && sptr->user->username) ? sptr->user-> username : "******", sptr->sockhost, (errno > 0) ? " " : " no ", errstr, ssl_errstr); #endif #ifdef USE_SYSLOG syslog(LOG_ERR, "SSL error in %s: %s [%s]", ssl_func, errstr, ssl_errstr); #endif /* if we reply() something here, we might just trigger another * fatal_ssl_error() call and loop until a stack overflow... * the client won`t get the ERROR : ... string, but this is * the only way to do it. * IRC protocol wasn`t SSL enabled .. --vjt */ errno = errtmp ? errtmp : EIO; /* Stick a generic I/O error */ sptr->sockerr = IRCERR_SSL; sptr->flags |= FLAGS_DEADSOCKET; return -1; }