/* * mr_server - SERVER message handler * parv[0] = sender prefix * parv[1] = servername * parv[2] = serverinfo/hopcount * parv[3] = serverinfo */ static void mr_server(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char info[REALLEN + 1]; char *name; struct Client *target_p; int hop; if (parc < 4) { sendto_one(client_p,"ERROR :No servername"); exit_client(client_p, client_p, client_p, "Wrong number of args"); return; } name = parv[1]; hop = atoi(parv[2]); strlcpy(info, parv[3], REALLEN); /* * Reject a direct nonTS server connection if we're TS_ONLY -orabidoo */ if (!DoesTS(client_p)) { sendto_realops_flags(FLAGS_ALL, L_ADMIN,"Link %s dropped, non-TS server", get_client_name(client_p, HIDE_IP)); sendto_realops_flags(FLAGS_ALL, L_OPER,"Link %s dropped, non-TS server", get_client_name(client_p, MASK_IP)); exit_client(client_p, client_p, client_p, "Non-TS server"); return; } if (bogus_host(name)) { exit_client(client_p, client_p, client_p, "Bogus server name"); return; } /* Now we just have to call check_server and everything should be * check for us... -A1kmm. */ switch (check_server(name, client_p, CHECK_SERVER_NOCRYPTLINK)) { case -1: if (ConfigFileEntry.warn_no_nline) { sendto_realops_flags(FLAGS_ALL, L_ADMIN, "Unauthorized server connection attempt from %s: No entry for " "servername %s", get_client_name(client_p, HIDE_IP), name); sendto_realops_flags(FLAGS_ALL, L_OPER, "Unauthorized server connection attempt from %s: No entry for " "servername %s", get_client_name(client_p, MASK_IP), name); } exit_client(client_p, client_p, client_p, "Invalid servername."); return; /* NOT REACHED */ break; case -2: sendto_realops_flags(FLAGS_ALL, L_ADMIN, "Unauthorized server connection attempt from %s: Bad password " "for server %s", get_client_name(client_p, HIDE_IP), name); sendto_realops_flags(FLAGS_ALL, L_OPER, "Unauthorized server connection attempt from %s: Bad password " "for server %s", get_client_name(client_p, MASK_IP), name); exit_client(client_p, client_p, client_p, "Invalid password."); return; /* NOT REACHED */ break; case -3: sendto_realops_flags(FLAGS_ALL, L_ADMIN, "Unauthorized server connection attempt from %s: Invalid host " "for server %s", get_client_name(client_p, HIDE_IP), name); sendto_realops_flags(FLAGS_ALL, L_OPER, "Unauthorized server connection attempt from %s: Invalid host " "for server %s", get_client_name(client_p, MASK_IP), name); exit_client(client_p, client_p, client_p, "Invalid host."); return; /* NOT REACHED */ break; /* servername is > HOSTLEN */ case -4: sendto_realops_flags(FLAGS_ALL, L_ADMIN, "Invalid servername %s from %s", name, get_client_name(client_p, HIDE_IP)); sendto_realops_flags(FLAGS_ALL, L_OPER, "Invalid servername %s from %s", name, get_client_name(client_p, MASK_IP)); exit_client(client_p, client_p, client_p, "Invalid servername."); return; /* NOT REACHED */ break; } 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 * * Definitely don't do that here. This is from an unregistered * connect - A1kmm. */ sendto_realops_flags(FLAGS_ALL, L_ADMIN, "Attempt to re-introduce server %s from %s", name, get_client_name(client_p, HIDE_IP)); sendto_realops_flags(FLAGS_ALL, L_OPER, "Attempt to re-introduce server %s from %s", name, get_client_name(client_p, MASK_IP)); sendto_one(client_p, "ERROR :Server already exists."); exit_client(client_p, client_p, client_p, "Server Exists"); return; } if(ServerInfo.hub && IsCapable(client_p, CAP_LL)) { if(IsCapable(client_p, CAP_HUB)) { ClearCap(client_p,CAP_LL); sendto_realops_flags(FLAGS_ALL, L_ALL, "*** LazyLinks to a hub from a hub, thats a no-no."); } else { client_p->localClient->serverMask = nextFreeMask(); if(!client_p->localClient->serverMask) { sendto_realops_flags(FLAGS_ALL, L_ALL, "serverMask is full!"); /* try and negotiate a non LL connect */ ClearCap(client_p,CAP_LL); } } } else if (IsCapable(client_p, CAP_LL)) { if(!IsCapable(client_p, CAP_HUB)) { ClearCap(client_p,CAP_LL); sendto_realops_flags(FLAGS_ALL, L_ALL, "*** LazyLinks to a leaf from a leaf, thats a no-no."); } } /* * if we are connecting (Handshake), we already have the name from the * C:line in client_p->name */ strlcpy(client_p->name, name, HOSTLEN+1); set_server_gecos(client_p, info); client_p->hopcount = hop; server_estab(client_p); }
/* * m_lljoin * parv[0] = sender prefix * parv[1] = channel * parv[2] = nick ("!nick" == cjoin) * parv[3] = key (optional) * * If a lljoin is received, from our uplink, join * the requested client to the given channel, or ignore it * if there is an error. * * Ok, the way this works. Leaf client tries to join a channel, * it doesn't exist so the join does a cburst request on behalf of the * client, and aborts that join. The cburst sjoin's the channel if it * exists on the hub, and sends back an LLJOIN to the leaf. Thats where * this is now.. * */ static void ms_lljoin(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char *chname = NULL; char *nick = NULL; char *key = NULL; int flags; int i; struct Client *target_p; struct Channel *chptr; if (uplink && !IsCapable(uplink,CAP_LL)) { sendto_realops_flags(UMODE_ALL, L_ALL, "*** LLJOIN requested from non LL server %s", client_p->name); return; } chname = parv[1]; if(chname == NULL) return; nick = parv[2]; if(nick == NULL) return; if(parc >3) { key = parv[3]; } flags = 0; target_p = find_person(nick); if( !target_p || !target_p->user ) return; if( !MyClient(target_p) ) return; chptr = get_or_create_channel(target_p, chname, NULL); flags = CHFL_CHANOP; if(!chptr) return; if (dlink_list_length(&chptr->members) == 0) flags = CHFL_CHANOP; else flags = 0; /* XXX in m_join.c :( */ /* check_spambot_warning(target_p, chname); */ /* They _could_ join a channel twice due to lag */ if(chptr) { if (IsMember(target_p, chptr)) /* already a member, ignore this */ return; } else { sendto_one(target_p, form_str(ERR_UNAVAILRESOURCE), me.name, nick, chptr->chname); return; } if ((i = can_join(target_p, chptr, key))) { sendto_one(target_p, form_str(i), me.name, nick, chptr->chname); return; } if ((dlink_list_length(&target_p->user->channel) >= ConfigChannel.max_chans_per_user) && (!IsOper(target_p) || (dlink_list_length(&target_p->user->channel) >= ConfigChannel.max_chans_per_user*3))) { sendto_one(target_p, form_str(ERR_TOOMANYCHANNELS), me.name, nick, chptr->chname ); return; } if (flags == CHFL_CHANOP) { chptr->channelts = CurrentTime; sendto_one(uplink, ":%s SJOIN %lu %s + :@%s", me.name, (unsigned long) chptr->channelts, chptr->chname, nick); } sendto_one(uplink, ":%s SJOIN %lu %s + :%s", me.name, (unsigned long) chptr->channelts, chptr->chname, nick); add_user_to_channel(chptr, target_p, flags); sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s", target_p->name, target_p->username, target_p->host, chptr->chname); if (flags & CHFL_CHANOP) { chptr->mode.mode |= MODE_TOPICLIMIT; chptr->mode.mode |= MODE_NOPRIVMSGS; sendto_channel_local(ALL_MEMBERS,chptr, ":%s MODE %s +nt", me.name, chptr->chname); sendto_one(uplink, ":%s MODE %s +nt", me.name, chptr->chname); } channel_member_names(target_p, chptr, 1); }
/* * 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); }
/* * * parc number of arguments ('sender' counted as one!) * parv[0] pointer to 'sender' (may point to empty string) (not used) * parv[1]..parv[parc-1] * pointers to additional parameters, this is a NULL * terminated list (parv[parc] == NULL). * * *WARNING* * Numerics are mostly error reports. If there is something * wrong with the message, just *DROP* it! Don't even think of * sending back a neat error message -- big danger of creating * a ping pong error message... */ static void do_numeric(char numeric[], struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Client *target_p; struct Channel *chptr; static char buffer[IRCD_BUFSIZE * 2]; if(parc < 2 || !IsServer(source_p)) return; /* Remap low number numerics. */ if(numeric[0] == '0') numeric[0] = '1'; /* * Prepare the parameter portion of the message into 'buffer'. * (Because the buffer is twice as large as the message buffer * for the socket, no overflow can occur here... ...on current * assumptions--bets are off, if these are changed --msa) * Note: if buffer is non-empty, it will begin with SPACE. */ if(parc > 1) { char *t = buffer; /* Current position within the buffer */ int i; int tl; /* current length of presently being built string in t */ for(i = 2; i < (parc - 1); i++) { tl = sprintf(t, " %s", parv[i]); t += tl; } sprintf(t, " :%s", parv[parc - 1]); } if((target_p = find_client(parv[1])) != NULL) { if(IsMe(target_p)) { /* * We shouldn't get numerics sent to us, * any numerics we do get indicate a bug somewhere.. */ /* ugh. this is here because of nick collisions. when two servers * relink, they burst each other their nicks, then perform collides. * if there is a nick collision, BOTH servers will kill their own * nicks, and BOTH will kill the other servers nick, which wont exist, * because it will have been already killed by the local server. * * unfortunately, as we cant guarantee other servers will do the * "right thing" on a nick collision, we have to keep both kills. * ergo we need to ignore ERR_NOSUCHNICK. --fl_ */ /* quick comment. This _was_ tried. i.e. assume the other servers * will do the "right thing" and kill a nick that is colliding. * unfortunately, it did not work. --Dianora */ /* note, now we send PING on server connect, we can * also get ERR_NOSUCHSERVER.. */ if(atoi(numeric) != ERR_NOSUCHNICK && atoi(numeric) != ERR_NOSUCHSERVER) sendto_realops_flags(UMODE_ALL, L_ADMIN, "*** %s(via %s) sent a %s numeric to me: %s", source_p->name, client_p->name, numeric, buffer); return; } else if(target_p->from == client_p) { /* This message changed direction (nick collision?) * ignore it. */ return; } /* csircd will send out unknown umode flag for +a (admin), drop it here. */ if((atoi(numeric) == ERR_UMODEUNKNOWNFLAG) && MyClient(target_p)) return; /* Fake it for server hiding, if its our client */ sendto_one(target_p, ":%s %s %s%s", get_id(source_p, target_p), numeric, get_id(target_p, target_p), buffer); return; } else if((chptr = find_channel(parv[1])) != NULL) sendto_channel_local(ALL_MEMBERS, chptr, ":%s %s %s %s", source_p->name, numeric, chptr->chname, buffer); }