/* * Unreal Internet Relay Chat Daemon, src/s_serv.c * Copyright (C) 1990 Jarkko Oikarinen and * University of Oulu, Computing Center * * See file AUTHORS in IRC package for additional names of * the programmers. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 1, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef lint static char sccsid[] = "@(#)s_serv.c 2.55 2/7/94 (C) 1988 University of Oulu, Computing Center and Jarkko Oikarinen"; #endif #include "struct.h" #include "common.h" #include "sys.h" #include "numeric.h" #include "msg.h" #include "channel.h" #include "userload.h" #include "version.h" #if defined(PCS) || defined(AIX) || defined(SVR3) #include #endif #include #include #ifndef _WIN32 #include #else #include #endif #include #include "h.h" ID_CVS("$Id$"); static char buf[BUFSIZE]; int max_connection_count = 1, max_client_count = 1; extern ircstats IRCstats; extern int do_garbage_collect; /* We need all these for cached MOTDs -- codemastr */ aMotd *opermotd; aMotd *rules; aMotd *motd; aMotd *svsmotd; aMotd *botmotd; aTrecord *tdata; struct tm *motd_tm; aMotd *read_opermotd(char *filename); aMotd *read_motd(char *filename); aMotd *read_rules(char *filename); aMotd *read_svsmotd(char *filename); aMotd *read_botmotd(char *filename); void read_tlines(void); /* ** m_functions execute protocol messages on this server: ** ** cptr is always NON-NULL, pointing to a *LOCAL* client ** structure (with an open socket connected!). This ** identifies the physical socket where the message ** originated (or which caused the m_function to be ** executed--some m_functions may call others...). ** ** sptr is the source of the message, defined by the ** prefix part of the message if present. If not ** or prefix not found, then sptr==cptr. ** ** (!IsServer(cptr)) => (cptr == sptr), because ** prefixes are taken *only* from servers... ** ** (IsServer(cptr)) ** (sptr == cptr) => the message didn't ** have the prefix. ** ** (sptr != cptr && IsServer(sptr) means ** the prefix specified servername. (?) ** ** (sptr != cptr && !IsServer(sptr) means ** that message originated from a remote ** user (not local). ** ** combining ** ** (!IsServer(sptr)) means that, sptr can safely ** taken as defining the target structure of the ** message in this server. ** ** *Always* true (if 'parse' and others are working correct): ** ** 1) sptr->from == cptr (note: cptr->from == cptr) ** ** 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr ** *cannot* be a local connection, unless it's ** actually cptr!). [MyConnect(x) should probably ** be defined as (x == x->from) --msa ] ** ** parc number of variable parameter strings (if zero, ** parv is allowed to be NULL) ** ** parv a NULL terminated list of parameter pointers, ** ** parv[0], sender (prefix string), if not present ** this points to an empty string. ** parv[1]...parv[parc-1] ** pointers to additional parameters ** parv[parc] == NULL, *always* ** ** note: it is guaranteed that parv[0]..parv[parc-1] are all ** non-NULL pointers. */ #ifndef NO_FDLIST extern fdlist serv_fdlist; #endif /* ** m_version ** parv[0] = sender prefix ** parv[1] = remote server */ int m_version(cptr, sptr, parc, parv) aClient *sptr, *cptr; int parc; char *parv[]; { extern char serveropts[]; char *x; if (TRUEHUB == 1) x = "(H)"; else x = ""; if (hunt_server(cptr, sptr, ":%s VERSION :%s", 1, parc, parv) == HUNTED_ISME) sendto_one(sptr, rpl_str(RPL_VERSION), me.name, parv[0], version, ircnetwork, debugmode, me.name, serveropts, (IsAnOper(sptr) ? MYOSNAME : "*"), UnrealProtocol, x); return 0; } /*int IsMe (acptr) aClient *acptr, server; { if (memcmp (acptr, server, sizeof(aClient)) == 0) return 1; return 0; }*/ /* ** m_squit ** parv[0] = sender prefix ** parv[1] = server name ** parv[parc-1] = comment */ int m_squit(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { aConfItem *aconf; char *server; aClient *acptr; char *comment = (parc > 2 && parv[parc - 1]) ? parv[parc - 1] : cptr->name; if (!IsPrivileged(sptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if (parc > 1) { server = parv[1]; /* ** To accomodate host masking, a squit for a masked server ** name is expanded if the incoming mask is the same as ** the server name for that link to the name of link. */ while ((*server == '*') && IsServer(cptr)) { aconf = cptr->serv->nline; if (!aconf) break; if (!mycmp(server, my_name_for_link(me.name, aconf))) server = cptr->name; break; /* WARNING is normal here */ } /* ** The following allows wild cards in SQUIT. Only usefull ** when the command is issued by an oper. */ for (acptr = client; (acptr = next_client(acptr, server)); acptr = acptr->next) if (IsServer(acptr) || IsMe(acptr)) break; if (acptr && IsMe(acptr)) { acptr = cptr; server = cptr->sockhost; } } else { /* ** This is actually protocol error. But, well, closing ** the link is very proper answer to that... */ server = cptr->sockhost; acptr = cptr; } /* ** SQUIT semantics is tricky, be careful... ** ** The old (irc2.2PL1 and earlier) code just cleans away the ** server client from the links (because it is never true ** "cptr == acptr". ** ** This logic here works the same way until "SQUIT host" hits ** the server having the target "host" as local link. Then it ** will do a real cleanup spewing SQUIT's and QUIT's to all ** directions, also to the link from which the orinal SQUIT ** came, generating one unnecessary "SQUIT host" back to that ** link. ** ** One may think that this could be implemented like ** "hunt_server" (e.g. just pass on "SQUIT" without doing ** nothing until the server having the link as local is ** reached). Unfortunately this wouldn't work in the real life, ** because either target may be unreachable or may not comply ** with the request. In either case it would leave target in ** links--no command to clear it away. So, it's better just ** clean out while going forward, just to be sure. ** ** ...of course, even better cleanout would be to QUIT/SQUIT ** dependant users/servers already on the way out, but ** currently there is not enough information about remote ** clients to do this... --msa */ if (!acptr) { sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], server); return 0; } if (MyClient(sptr) && ((!OPCanGRoute(sptr) && !MyConnect(acptr)) || (!OPCanLRoute(sptr) && MyConnect(acptr)))) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } /* ** Notify all opers, if my local link is remotely squitted */ if (MyConnect(acptr) && !IsAnOper(cptr)) { sendto_locfailops("Received SQUIT %s from %s (%s)", acptr->name, get_client_name(sptr, FALSE), comment); sendto_serv_butone(&me, ":%s GLOBOPS :Received SQUIT %s from %s (%s)", me.name, server, get_client_name(sptr, FALSE), comment); #if defined(USE_SYSLOG) && defined(SYSLOG_SQUIT) syslog(LOG_DEBUG, "SQUIT From %s : %s (%s)", parv[0], server, comment); #endif } else if (MyConnect(acptr)) { if (acptr->user) { sendto_one(sptr, ":%s NOTICE :*** Cannot do fake kill by SQUIT !!!", me.name); sendto_ops ("%s tried to do a fake kill using SQUIT (%s (%s))", sptr->name, acptr->name, comment); sendto_serv_butone(&me, ":%s GLOBOPS :%s tried to fake kill using SQUIT (%s (%s))", me.name, sptr->name, acptr->name, comment); return 0; } sendto_locfailops("Received SQUIT %s from %s (%s)", acptr->name, get_client_name(sptr, FALSE), comment); sendto_serv_butone(&me, ":%s GLOBOPS :Received SQUIT %s from %s (%s)", me.name, acptr->name, get_client_name(sptr, FALSE), comment); } if (IsAnOper(sptr)) { /* * It was manually /squit'ed by a human being(we hope), * there is a very good chance they don't want us to * reconnect right away. -Cabal95 */ acptr->flags |= FLAGS_SQUIT; } return exit_client(cptr, acptr, sptr, comment); } /* * m_protoctl * parv[0] = Sender prefix * parv[1+] = Options */ int m_protoctl(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { int i; #ifndef PROTOCTL_MADNESS int remove = 0; #endif char proto[128], *s; /* static char *dummyblank = ""; Yes, it is kind of ugly */ #ifdef PROTOCTL_MADNESS if (GotProtoctl(sptr)) { /* * But we already GOT a protoctl msg! */ if (!IsServer(sptr)) sendto_one(cptr, "ERROR :Already got a PROTOCTL from you."); return 0; } #endif cptr->flags |= FLAGS_PROTOCTL; /* parv[parc - 1] */ for (i = 1; i < parc; i++) { strncpy(proto, parv[i], 127); proto[127] = '\0'; /* Just to be safe... */ s = proto; #ifndef PROTOCTL_MADNESS if (*s == '-') { s++; remove = 1; } else remove = 0; #endif /* equal = (char *)index(proto, '='); if (equal == NULL) options = dummyblank; else { options = &equal[1]; equal[0] = '\0'; } */ if (strcmp(s, "NOQUIT") == 0) { #ifndef PROTOCTL_MADNESS if (remove) { ClearNoQuit(cptr); continue; } #endif Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name)); SetNoQuit(cptr); } else if (strcmp(s, "TOKEN") == 0) { #ifndef PROTOCTL_MADNESS if (remove) { ClearToken(cptr); continue; } #endif Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name)); SetToken(cptr); } else if (strcmp(s, "HCN") == 0) { #ifndef PROTOCTL_MADNESS if (remove) { ClearHybNotice(cptr); continue; } #endif Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name)); SetHybNotice(cptr); } else if (strcmp(s, "SJOIN") == 0) { #ifndef PROTOCTL_MADNESS if (remove) { ClearSJOIN(cptr); continue; } #endif Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name)); SetSJOIN(cptr); } else if (strcmp(s, "SJOIN2") == 0) { #ifndef PROTOCTL_MADNESS if (remove) { ClearSJOIN2(cptr); continue; } #endif Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name)); SetSJOIN2(cptr); } else if (strcmp(s, "NICKv2") == 0) { #ifndef PROTOCTL_MADNESS if (remove) { ClearNICKv2(cptr); continue; } #endif Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name)); SetNICKv2(cptr); } else if (strcmp(s, "UMODE2") == 0) { #ifndef PROTOCTL_MADNESS if (remove) { ClearUMODE2(cptr); continue; } #endif Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name)); SetUMODE2(cptr); } else if (strcmp(s, "ALN") == 0) { #ifdef PROTOCTL_MADNESS if (remove) { ClearALN(cptr); continue; } #endif Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name)); SetALN(cptr); } else if (strcmp(s, "VL") == 0) { #ifndef PROTOCTL_MADNESS if (remove) { ClearVL(cptr); continue; } #endif Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name)); SetVL(cptr); } else if (strcmp(s, "VHP") == 0) { #ifndef PROTOCTL_MADNESS if (remove) { ClearVHP(cptr); continue; } #endif Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name)); SetVHP(cptr); } else if (strcmp(s, "SJ3") == 0) { #ifndef PROTOCTL_MADNESS if (remove) { ClearSJ3(cptr); continue; } #endif Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name)); SetSJ3(cptr); } /* * Add other protocol extensions here, with proto * containing the base option, and options containing * what it equals, if anything. * * DO NOT error or warn on unknown proto; we just don't * support it. */ } return 0; } /* ** m_server ** parv[0] = sender prefix ** parv[1] = servername ** parv[2] = serverinfo/hopcount ** parv[3] = serverinfo */ int m_server(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { char *ch; int i; char info[REALLEN + 1], *inpath, *host, *encr, *f; char pp[512]; aClient *acptr, *bcptr; aConfItem *aconf, *cconf; int hop, ts = 0; char *parvaln, *flags, *protocol, *inf; info[0] = '\0'; inpath = get_client_name(cptr, FALSE); if (parc < 2 || *parv[1] == '\0') { sendto_one(cptr, "ERROR :No servername"); return 0; } hop = 0; host = parv[1]; if (parc > 4) { ts = atoi(parv[3]); hop = atoi(parv[2]); (void)strncpy(info, parv[4], REALLEN); info[REALLEN] = '\0'; } else if (parc > 3 && atoi(parv[2])) { hop = atoi(parv[2]); (void)strncpy(info, parv[3], REALLEN); info[REALLEN] = '\0'; } else if (parc > 2) { (void)strncpy(info, parv[2], REALLEN); if (parc > 3 && ((i = strlen(info)) < (REALLEN - 2))) { (void)strcat(info, " "); (void)strncat(info, parv[3], REALLEN - i - 2); info[REALLEN] = '\0'; } } /* ** Check for "FRENCH " infection ;-) (actually this should ** be replaced with routine to check the hostname syntax in ** general). [ This check is still needed, even after the parse ** is fixed, because someone can send "SERVER :foo bar " ]. ** Also, changed to check other "difficult" characters, now ** that parse lets all through... --msa */ if (strlen(host) > HOSTLEN) host[HOSTLEN] = '\0'; for (ch = host; *ch; ch++) if (*ch <= ' ' || *ch > '~') break; if (*ch || !index(host, '.')) { sendto_one(sptr, "ERROR :Bogus server name (%s)", sptr->name, host); sendto_ops ("WARNING: Bogus server name (%s) from %s (maybe just a fishy client)", host, get_client_name(cptr, TRUE)); sptr->since += 7; return 0; } if (IsPerson(cptr)) { /* ** A local link that has been identified as a USER ** tries something fishy... ;-) */ sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]); sendto_one(cptr, ":%s NOTICE %s :Sorry, but your IRC program doesn't appear to support changing servers.", me.name, cptr->name); /* sendto_ops("User %s trying to become a server %s", get_client_name(cptr, TRUE),host); */ sptr->since += 7; return 0; } /* *WHEN* can it be that "cptr != sptr" ????? --msa */ /* When SERVER command (like now) has prefix. -avalon */ /* take a prepeek at the password.. */ if (IsUnknown(cptr)) { aconf = find_conf_servern(host); if (!aconf) { sendto_one(cptr,"ERROR :No Access (No matching N:line) %s", inpath); sendto_locfailops("Access denied (No matching N:line) %s", inpath); return exit_client(cptr, cptr, cptr, "No matching N:line"); } #ifdef CRYPT_LINK_PASSWORD /* use first two chars of the password they send in as salt */ /* passwd may be NULL. Head it off at the pass... */ if (*cptr->passwd) { char salt[3]; extern char *crypt(); salt[0] = aconf->passwd[0]; salt[1] = aconf->passwd[1]; salt[2] = '\0'; encr = crypt(cptr->passwd, salt); } else encr = ""; #else encr = cptr->passwd; #endif /* CRYPT_LINK_PASSWORD */ if (*aconf->passwd && !StrEq(aconf->passwd, encr)) { sendto_one(cptr, "ERROR :No Access (passwd mismatch) %s", inpath); sendto_locfailops("Access denied (passwd mismatch) %s", inpath); return exit_client(cptr, cptr, cptr, "Bad Password"); } /* bzero(cptr->passwd, sizeof(cptr->passwd)); */ } f = (char *) does_servername_collide(parv[1]); if (f) { ircsprintf(pp, "Servername %s collides with servername %s (similar hash). Change servername in some way (maybe change case)", parv[1], f); sendto_realops("Link %s cancelled - %s", inpath, pp); return exit_client(cptr, cptr, cptr, pp); } if ((acptr = find_name(host, NULL))) { aClient *ocptr; /* * This link is trying feed me a server that I already have * access through another path -- multiple paths not accepted * currently, kill this link immeatedly!! * * Rather than KILL the link which introduced it, KILL the * youngest of the two links. -avalon */ acptr = acptr->from; ocptr = (cptr->firsttime > acptr->firsttime) ? acptr : cptr; acptr = (cptr->firsttime > acptr->firsttime) ? cptr : acptr; sendto_one(acptr, "ERROR :Server %s already exists from %s", host, (ocptr->from ? ocptr->from->name : "")); sendto_ops ("Link %s cancelled, server %s already exists from %s", get_client_name(acptr, TRUE), host, (ocptr->from ? ocptr->from->name : "")); return exit_client(acptr, acptr, acptr, "Server Exists"); } if ((acptr = find_client(host, 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(cptr, "ERROR :Nickname %s already exists!", host); sendto_locfailops ("Link %s cancelled: Server/nick collision on %s", inpath, host); sendto_serv_butone(&me, ":%s GLOBOPS : Link %s cancelled: Server/nick collision on %s", parv[0], inpath, host); 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. */ if ((aconf = find_conf_host(cptr->confs, host, CONF_LEAF)) && (!aconf->port || (hop > aconf->port))) { sendto_ops("Leaf-only link %s->%s - Closing", get_client_name(cptr, TRUE), aconf->host ? aconf->host : "*"); sendto_one(cptr, "ERROR :Leaf-only link, sorry."); return exit_client(cptr, cptr, cptr, "Leaf Only (You are L:lined)"); } /* ** */ if (!(aconf = find_conf_host(cptr->confs, host, CONF_HUB)) || (aconf->port && (hop > aconf->port))) { sendto_ops("Non-Hub link %s introduced %s(%s).", get_client_name(cptr, TRUE), host, aconf ? (aconf->host ? aconf->host : "*") : "!"); return exit_client(cptr, cptr, cptr, "Too many servers (Missing H:Line)"); } /* ** See if the newly found server has a Q line for it in ** our conf. If it does, lose the link that brought it ** into our network. Format: ** ** Q::: ** ** Example: Q:*:for the hell of it:eris.Berkeley.EDU */ if ((aconf = find_conf_name(host, CONF_QUARANTINED_SERVER))) { sendto_ops_butone(NULL, &me, ":%s WALLOPS * :%s brought in %s, %s %s", me.name, get_client_name(cptr, FALSE), host, "closing link because", BadPtr(aconf->passwd) ? "reason unspecified" : aconf->passwd); sendto_one(cptr, "ERROR :%s is not welcome: %s. %s", host, BadPtr(aconf->passwd) ? "reason unspecified" : aconf->passwd, "Try another network"); return exit_client(cptr, cptr, cptr, "Q-Lined Server"); } acptr = make_client(cptr, find_server(parv[0], NULL)); (void)make_server(acptr); acptr->hopcount = hop; strncpyzt(acptr->name, host, sizeof(acptr->name)); strncpyzt(acptr->info, info, sizeof(acptr->info)); acptr->serv->up = find_or_add(parv[0]); SetServer(acptr); /* Taken from bahamut makes it so all servers behind a U:lined * server are also U:lined, very helpful if HIDE_ULINES is on */ if (IsULine(sptr,sptr) || (find_uline(cptr->confs, acptr->name))) acptr->flags |= FLAGS_ULINE; IRCstats.servers++; (void)find_or_add(acptr->name); acptr->flags |= FLAGS_TS8; add_client_to_list(acptr); (void)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) */ parvaln = (char *)find_server_aln(parv[0]); for (i = 0; i <= highest_fd; i++) { if (!(bcptr = local[i]) || !IsServer(bcptr) || bcptr == cptr || IsMe(bcptr)) continue; if (!(aconf = bcptr->serv->nline)) { sendto_ops("Lost N-line for %s on %s. Closing", get_client_name(cptr, TRUE), host); return exit_client(cptr, cptr, cptr, "Lost N line"); } if (match(my_name_for_link(me.name, aconf), acptr->name) == 0) continue; if (ts) sendto_one(bcptr, "%c%s %s %s %d %d :%s", SupportALN(bcptr) ? '@' : ':', SupportALN(bcptr) ? parvaln : parv[0], IsToken(bcptr) ? TOK_SERVER : MSG_SERVER, acptr->name, hop + 1, ts, acptr->info); else sendto_one(bcptr, "%c%s %s %s %d :%s", SupportALN(bcptr) ? '@' : ':', SupportALN(bcptr) ? parvaln : parv[0], IsToken(bcptr) ? TOK_SERVER : MSG_SERVER, acptr->name, hop + 1, acptr->info); } return 0; } if (!IsUnknown(cptr) && !IsHandshake(cptr)) return 0; /* ** A local link that is still in undefined state wants ** to be a SERVER. Check if this is allowed and change ** status accordingly... */ strncpyzt(cptr->name, host, sizeof(cptr->name)); /* For now, just strip the VL stuff if it's there */ if (SupportVL(cptr)) { /* we also have a fail safe incase they say they are sending * VL stuff and don't -- codemastr */ aConfItem *vlines = NULL; inf = NULL; protocol = NULL; flags = NULL; protocol = (char *)strtok((char *)info, "-"); if (protocol) flags = (char *)strtok((char *)NULL, " "); if (flags) inf = (char *)strtok((char *)NULL, ""); if (inf) { strncpyzt(cptr->info, *inf ? inf : me.name, sizeof(cptr->info)); for (vlines = conf; vlines; vlines = vlines->next) { if ((vlines->status & CONF_VERSION) && !match(vlines->name,cptr->name)) break; } if (vlines) { char *proto = vlines->host; char *vflags = vlines->passwd; int result = 0; int i; protocol++; /* check the protocol */ switch(*proto) { case '<': proto++; if (atoi(protocol) < atoi(proto)) result = 1; else result = 0; break; case '>': proto++; if (atoi(protocol) > atoi(proto)) result = 1; else result = 0; break; case '=': proto++; if (atoi(protocol) == atoi(proto)) result = 1; else result = 0; break; case '!': proto++; if (atoi(protocol) != atoi(proto)) result = 1; else result = 0; break; /* default to = if anything else */ default: if (atoi(protocol) == atoi(proto)) result = 1; else result = 0; break; } /* switch(*proto) */ /* For Services */ if (atoi(protocol) == 0) result = 0; /* if the proto in the V:line is * let it pass */ if (*proto == '*') result = 0; if (result) return exit_client(cptr, cptr, cptr, "Denied by V:line"); /* If it passed the protocol check, check the flags */ for(i = 0; vflags[i]; i++) { if (vflags[i] == '!') { i++; if (strchr(flags, (int)vflags[i])) { result = 1; break; } } if (!strchr(flags, (int)vflags[i])) { result = 1; break; } } /* for(i = 0; vflags[i]; i++) */ if (*vflags == '*') result = 0; /* for services */ if (!strcmp(flags, "0")) result = 0; if (result) return exit_client(cptr, cptr, cptr, "Denied by V:line"); } /* if (vlines) */ } /* if (flags) */ else strncpyzt(cptr->info, info[0] ? info : me.name, sizeof(cptr->info)); } else strncpyzt(cptr->info, info[0] ? info : me.name, sizeof(cptr->info)); cptr->hopcount = hop; /* check connection rules */ for (cconf = conf; cconf; cconf = cconf->next) if ((cconf->status == CONF_CRULEALL) && (match(cconf->host, host) == 0)) if (crule_eval(cconf->passwd)) { ircstp->is_ref++; sendto_ops("Refused connection from %s.", get_client_host(cptr)); return exit_client(cptr, cptr, cptr, "Disallowed by connection rule"); } 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, TRUE)); return 1; default: ircstp->is_ref++; sendto_ops("Received unauthorized connection from %s.", get_client_host(cptr)); sendto_serv_butone(&me, ":%s GLOBOPS :Recieved unauthorized connection from %s.", parv[0], get_client_host(cptr)); return exit_client(cptr, cptr, cptr, "No C/N conf lines"); } } int m_server_estab(cptr) aClient *cptr; { aClient *acptr; aConfItem *aconf, *bconf; char *inpath, *host, *s, *encr; int split, i; char *myaln = find_server_aln(me.name); extern char serveropts[]; inpath = get_client_name(cptr, TRUE); /* "refresh" inpath with host */ split = mycmp(cptr->name, cptr->sockhost); host = cptr->name; current_load_data.conn_count++; update_load(); if (!(aconf = find_conf(cptr->confs, host, CONF_NOCONNECT_SERVER))) { ircstp->is_ref++; sendto_one(cptr, "ERROR :Access denied. No N:line for server %s", inpath); sendto_ops("Access denied. No N:line for server %s", inpath); return exit_client(cptr, cptr, cptr, "No N line for server"); } if (!(bconf = find_conf(cptr->confs, host, CONF_CONNECT_SERVER))) { ircstp->is_ref++; sendto_one(cptr, "ERROR :Only N (no C) field for server %s", inpath); sendto_ops("Only N (no C) field for server %s", inpath); return exit_client(cptr, cptr, cptr, "No C line for server"); } #ifdef CRYPT_LINK_PASSWORD /* use first two chars of the password they send in as salt */ /* passwd may be NULL. Head it off at the pass... */ if (*cptr->passwd) { char salt[3]; extern char *crypt(); salt[0] = aconf->passwd[0]; salt[1] = aconf->passwd[1]; salt[2] = '\0'; encr = crypt(cptr->passwd, salt); } else encr = ""; #else encr = cptr->passwd; #endif /* CRYPT_LINK_PASSWORD */ if (*aconf->passwd && !StrEq(aconf->passwd, encr)) { ircstp->is_ref++; sendto_one(cptr, "ERROR :No Access (passwd mismatch) %s", inpath); sendto_ops("Access denied (passwd mismatch) %s", inpath); return exit_client(cptr, cptr, cptr, "Bad Password"); } bzero(cptr->passwd, sizeof(cptr->passwd)); #ifndef HUB for (i = 0; i <= highest_fd; i++) if (local[i] && IsServer(local[i])) { ircstp->is_ref++; sendto_one(cptr, "ERROR :I'm a leaf not a hub"); return exit_client(cptr, cptr, cptr, "I'm a leaf"); } #endif if (IsUnknown(cptr)) { sendto_one(cptr, "PROTOCTL %s", PROTOCTL_SERVER); if (bconf->passwd[0]) sendto_one(cptr, "PASS :%s", bconf->passwd); /* ** Pass my info to the new server */ /* modified so we send out the Uproto and flags */ sendto_one(cptr, "SERVER %s 1 :U%d-%s %s", my_name_for_link(me.name, aconf), UnrealProtocol, serveropts, (me.info[0]) ? (me.info) : "IRCers United"); } else { s = (char *)index(aconf->host, '@'); *s = '\0'; /* should never be NULL */ Debug((DEBUG_INFO, "Check Usernames [%s]vs[%s]", aconf->host, cptr->username)); if (match(aconf->host, cptr->username)) { *s = '@'; ircstp->is_ref++; sendto_ops("Username mismatch [%s]v[%s] : %s", aconf->host, cptr->username, get_client_name(cptr, TRUE)); sendto_one(cptr, "ERROR :No Username Match"); return exit_client(cptr, cptr, cptr, "Bad User"); } *s = '@'; sendto_one(cptr, "PROTOCTL %s", PROTOCTL_SERVER); } det_confs_butmask(cptr, CONF_LEAF | CONF_HUB | CONF_NOCONNECT_SERVER | CONF_UWORLD); /* ** *WARNING* ** In the following code in place of plain server's ** name we send what is returned by get_client_name ** which may add the "sockhost" after the name. It's ** *very* *important* that there is a SPACE between ** the name and sockhost (if present). The receiving ** server will start the information field from this ** first blank and thus puts the sockhost into info. ** ...a bit tricky, but you have been warned, besides ** code is more neat this way... --msa */ SetServer(cptr); IRCstats.me_servers++; IRCstats.servers++; IRCstats.unknown--; #ifndef NO_FDLIST addto_fdlist(cptr->fd, &serv_fdlist); #endif if ((find_uline(cptr->confs, cptr->name))) cptr->flags |= FLAGS_ULINE; cptr->flags |= FLAGS_TS8; nextping = TStime(); (void)find_or_add(cptr->name); if (TRUEHUB == 1) sendto_serv_butone(&me, ":%s GLOBOPS :Link with %s established.", me.name, inpath); sendto_locfailops("Link with %s established.", inpath); /* Insert here */ (void)add_to_client_hash_table(cptr->name, cptr); /* doesnt duplicate cptr->serv if allocted this struct already */ (void)make_server(cptr); cptr->serv->up = me.name; cptr->srvptr = &me; cptr->serv->nline = aconf; /* ** 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 ((aconf = acptr->serv->nline) && !match(my_name_for_link(me.name, aconf), cptr->name)) continue; if (split) sendto_one(acptr, "%c%s %s %s 2 :%s", (SupportALN(acptr) ? '@' : ':'), (SupportALN(acptr) ? myaln : me.name), (IsToken(acptr) ? TOK_SERVER : MSG_SERVER), cptr->name, cptr->info); else sendto_one(acptr, "%c%s %s %s 2 :%s", (SupportALN(acptr) ? '@' : ':'), (SupportALN(acptr) ? myaln : me.name), (IsToken(cptr) ? TOK_SERVER : MSG_SERVER), 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...) */ aconf = cptr->serv->nline; for (acptr = &me; acptr; acptr = acptr->prev) { /* acptr->from == acptr for acptr == cptr */ if (acptr->from == cptr) continue; if (IsServer(acptr)) { if (match(my_name_for_link(me.name, aconf), acptr->name) == 0) continue; split = (MyConnect(acptr) && mycmp(acptr->name, acptr->sockhost)); if (split) sendto_one(cptr, "%c%s %s %s %d :%s", (SupportALN(cptr) ? '@' : ':'), (SupportALN(cptr) ? find_server_aln(acptr->serv->up) : acptr-> serv->up), (IsToken(cptr) ? TOK_SERVER : MSG_SERVER), acptr->name, acptr->hopcount + 1, acptr->info); else sendto_one(cptr, "%c%s %s %s %d :%s", (SupportALN(cptr) ? '@' : ':'), (SupportALN(cptr) ? find_server_aln(acptr->serv->up) : acptr-> serv->up), (IsToken(cptr) ? TOK_SERVER : MSG_SERVER), acptr->name, acptr->hopcount + 1, acptr->info); } } for (acptr = &me; acptr; acptr = acptr->prev) { /* acptr->from == acptr for acptr == cptr */ if (acptr->from == cptr) continue; if (IsPerson(acptr)) { /* ** IsPerson(x) is true only when IsClient(x) is true. ** These are only true when *BOTH* NICK and USER have ** been received. -avalon ** Apparently USER command was forgotten... -Donwulff */ if (!SupportNICKv2(cptr)) { sendto_one(cptr, "%s %s %d %d %s %s %s %lu :%s", (IsToken(cptr) ? TOK_NICK : MSG_NICK), acptr->name, acptr->hopcount + 1, acptr->lastnick, acptr->user->username, acptr->user->realhost, acptr->user->server, acptr->user->servicestamp, acptr->info); send_umode(cptr, acptr, 0, SEND_UMODES, buf); if (IsHidden(acptr) && acptr->user->virthost) sendto_one(cptr, ":%s %s %s", acptr->name, (IsToken(cptr) ? TOK_SETHOST : MSG_SETHOST), acptr->user->virthost); } else { send_umode(NULL, acptr, 0, SEND_UMODES, buf); if (!SupportVHP(cptr)) sendto_one(cptr, "%s %s %d %d %s %s %s %lu %s %s :%s", (IsToken(cptr) ? TOK_NICK : MSG_NICK), acptr->name, acptr->hopcount + 1, acptr->lastnick, acptr->user->username, acptr->user->realhost, (SupportALN(cptr) ? find_server_aln(acptr->user-> server) : acptr->user->server), acptr->user->servicestamp, (!buf || *buf == '\0' ? "+" : buf), ((IsHidden(acptr) && (acptr->umodes & UMODE_SETHOST)) ? acptr->user->virthost : "*"), acptr->info); else sendto_one(cptr, "%s %s %d %d %s %s %s %lu %s %s :%s", (IsToken(cptr) ? TOK_NICK : MSG_NICK), acptr->name, acptr->hopcount + 1, acptr->lastnick, acptr->user->username, acptr->user->realhost, (SupportALN(cptr) ? find_server_aln(acptr->user-> server) : acptr->user->server), acptr->user->servicestamp, (!buf || *buf == '\0' ? "+" : buf), IsHidden(acptr) ? acptr->user->virthost : acptr->user->realhost, acptr->info); } if (acptr->user->away) sendto_one(cptr, ":%s %s :%s", acptr->name, (IsToken(cptr) ? TOK_AWAY : MSG_AWAY), acptr->user->away); if (acptr->user->swhois) if (*acptr->user->swhois != '\0') sendto_one(cptr, "%s %s :%s", (IsToken(cptr) ? TOK_SWHOIS : MSG_SWHOIS), acptr->name, acptr->user->swhois); if (!SupportSJOIN(cptr)) send_user_joins(cptr, acptr); } } /* ** Last, pass all channels plus statuses */ { aChannel *chptr; for (chptr = channel; chptr; chptr = chptr->nextch) { if (!SupportSJOIN(cptr)) send_channel_modes(cptr, chptr); else if (SupportSJOIN(cptr) && !SupportSJ3(cptr)) { send_channel_modes_sjoin(cptr, chptr); } else send_channel_modes_sjoin3(cptr, chptr); if (chptr->topic_time) sendto_one(cptr, "%s %s %s %lu :%s", (IsToken(cptr) ? TOK_TOPIC : MSG_TOPIC), chptr->chname, chptr->topic_nick, chptr->topic_time, chptr->topic); } } /* pass on TKLs */ tkl_synch(cptr); /* send out SVSFLINEs */ dcc_sync(cptr); /* ** Pass on all services based q-lines */ { aSqlineItem *tmp; for (tmp = sqline; tmp; tmp = tmp->next) { if (tmp->status != CONF_ILLEGAL) if (tmp->reason) sendto_one(cptr, "%c%s %s %s :%s", SupportALN(cptr) ? '@' : ':', SupportALN(cptr) ? myaln : me.name, (IsToken(cptr) ? TOK_SQLINE : MSG_SQLINE), tmp->sqline, tmp->reason); else sendto_one(cptr, ":%s %s %s", me.name, (IsToken(cptr) ? TOK_SQLINE : MSG_SQLINE), tmp->sqline); } } sendto_one(cptr, "%s %li %li %li 0 0 0 0 :%s", (IsToken(cptr) ? TOK_NETINFO : MSG_NETINFO), IRCstats.global_max, TStime(), UnrealProtocol, ircnetwork); return 0; } /* ** m_links ** parv[0] = sender prefix ** parv[1] = servername mask ** or ** parv[0] = sender prefix ** parv[1] = server to query ** parv[2] = servername mask */ int m_links(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { char *mask; aClient *acptr; if (parc > 2 && IsOper(cptr)) { if (hunt_server(cptr, sptr, ":%s LINKS %s :%s", 1, parc, parv) != HUNTED_ISME) return 0; mask = parv[2]; } else mask = parc < 2 ? NULL : parv[1]; for (acptr = client, (void)collapse(mask); acptr; acptr = acptr->next) { if (!IsServer(acptr) && !IsMe(acptr)) continue; if (!BadPtr(mask) && match(mask, acptr->name)) continue; if (HIDE_ULINES == 1) { if (IsULine(acptr, acptr) && !IsAnOper(sptr)) continue; } sendto_one(sptr, rpl_str(RPL_LINKS), me.name, parv[0], acptr->name, acptr->serv->up, acptr->hopcount, (acptr->info[0] ? acptr->info : "(Unknown Location)")); } sendto_one(sptr, rpl_str(RPL_ENDOFLINKS), me.name, parv[0], BadPtr(mask) ? "*" : mask); return 0; } /* ** m_netinfo ** by Stskeeps ** parv[0] = sender prefix ** parv[1] = max global count ** parv[2] = time of end sync ** parv[3] = unreal protocol using (numeric) ** parv[4] = free(for unrealprotocol > 2100) ** parv[5] = free(**) ** parv[6] = free(**) ** parv[7] = free(**) ** parv[8] = ircnet **/ int m_netinfo(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { long lmax; time_t xx; long endsync, protocol; if (IsPerson(sptr)) return 0; if (!IsServer(cptr)) return 0; if (parc < 3) { /* Talking to a UnProtocol 2090 */ sendto_realops ("Link %s is using a too old UnProtocol - (parc < 3)", cptr->name); if (KILLDIFF == 1) { sendto_realops ("Dropped link %s - unProtocol 2090 is not compatible with unProtocol %li", cptr->name, UnrealProtocol); sendto_one(cptr, "ERROR :unProtocol 2090 is not compatible with unProtocol %li", UnrealProtocol); exit_client(cptr, cptr, cptr, "Link using unProtocol 2090"); } return 0; } if (parc < 9) { return 0; } if (GotNetInfo(cptr)) { sendto_realops("Already got NETINFO from Link %s", cptr->name); return 0; } /* is a long therefore not ATOI */ lmax = atol(parv[1]); endsync = atol(parv[2]); protocol = atol(parv[3]); /* max global count != max_global_count --sts */ if (lmax > IRCstats.global_max) { IRCstats.global_max = lmax; sendto_realops("Max Global Count is now %li (set by link %s)", lmax, cptr->name); } xx = TStime(); if ((xx - endsync) < 0) { sendto_realops ("Possible negative TS split at link %s (%li - %li = %li)", cptr->name, (xx), (endsync), (xx - endsync)); sendto_serv_butone(&me, ":%s SMO o :\2(sync)\2 Possible negative TS split at link %s (%li - %li = %li)", me.name, cptr->name, (xx), (endsync), (xx - endsync)); } sendto_realops ("Link %s -> %s is now synced [secs: %li recv: %li.%li sent: %li.%li]", cptr->name, me.name, (TStime() - endsync), sptr->receiveK, sptr->receiveB, sptr->sendK, sptr->sendB); sendto_serv_butone(&me, ":%s SMO o :\2(sync)\2 Link %s -> %s is now synced [secs: %li recv: %li.%li sent: %li.%li]", me.name, cptr->name, me.name, (TStime() - endsync), sptr->receiveK, sptr->receiveB, sptr->sendK, sptr->sendB); if (!(strcmp(ircnetwork, parv[8]) == 0)) { sendto_realops("Network name mismatch from link %s (%s != %s)", cptr->name, parv[8], ircnetwork); sendto_serv_butone(&me, ":%s SMO o :\2(sync)\2 Network name mismatch from link %s (%s != %s)", me.name, cptr->name, parv[8], ircnetwork); } if ((protocol != UnrealProtocol) && (protocol != 0)) { sendto_realops ("Link %s is running Protocol u%li while we are running %li!", cptr->name, protocol, UnrealProtocol); sendto_serv_butone(&me, ":%s SMO o :\2(sync)\2 Link %s is running u%li while %s is running %li!", me.name, cptr->name, protocol, me.name, UnrealProtocol); } SetNetInfo(cptr); } #ifndef IRCDTOTALVERSION #define IRCDTOTALVERSION BASE_VERSION PATCH1 PATCH2 PATCH3 PATCH4 PATCH5 PATCH6 PATCH7 PATCH8 PATCH9 #endif /* * sends m_info into to sptr */ void m_info_send(sptr) aClient *sptr; { sendto_one(sptr, ":%s %d %s :=-=-=-= %s =-=-=-=", me.name, RPL_INFO, sptr->name, IRCDTOTALVERSION); sendto_one(sptr, ":%s %d %s :| Brought to you by the following people:", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :|", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :| * Stskeeps ", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :| * codemastr ", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :| * DrBin ", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :|", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :| Credits - Type /Credits", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :| DALnet Credits - Type /DalInfo", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :|", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :| This is an UnrealIRCD-style server", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :| If you find any bugs, please mail", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :| unreal-dev@lists.sourceforge.net", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :| UnrealIRCd Homepage: http://unreal.tspre.org", me.name, RPL_INFO, sptr->name); #ifdef _WIN32 #ifdef WIN32_SPECIFY sendto_one(sptr, ":%s %d %s :| wIRCd porter: | %s", me.name, RPL_INFO, sptr->name, WIN32_PORTER); sendto_one(sptr, ":%s %d %s :| >>URL: | %s", me.name, RPL_INFO, sptr->name, WIN32_URL); #endif #endif sendto_one(sptr, ":%s %d %s :-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :Birth Date: %s, compile # %s", me.name, RPL_INFO, sptr->name, creation, generation); sendto_one(sptr, ":%s %d %s :On-line since %s", me.name, RPL_INFO, sptr->name, myctime(me.firsttime)); sendto_one(sptr, ":%s %d %s :ReleaseID (%s)", me.name, RPL_INFO, sptr->name, RELEASEID); sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, sptr->name); } /* ** m_info ** parv[0] = sender prefix ** parv[1] = servername ** Modified for hardcode by Stskeeps */ int m_info(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { if (hunt_server(cptr, sptr, ":%s INFO :%s", 1, parc, parv) == HUNTED_ISME) { m_info_send(sptr); } return 0; } /* ** m_dalinfo ** parv[0] = sender prefix ** parv[1] = servername */ int m_dalinfo(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { char **text = dalinfotext; if (hunt_server(cptr, sptr, ":%s DALINFO :%s", 1, parc, parv) == HUNTED_ISME) { while (*text) sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], *text++); sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], ""); sendto_one(sptr, ":%s %d %s :Birth Date: %s, compile # %s", me.name, RPL_INFO, parv[0], creation, generation); sendto_one(sptr, ":%s %d %s :On-line since %s", me.name, RPL_INFO, parv[0], myctime(me.firsttime)); sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, parv[0]); } return 0; } /* ** m_license ** parv[0] = sender prefix ** parv[1] = servername */ int m_license(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { char **text = gnulicense; if (hunt_server(cptr, sptr, ":%s LICENSE :%s", 1, parc, parv) == HUNTED_ISME) { while (*text) sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], *text++); sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], ""); sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, parv[0]); } return 0; } /* ** m_credits ** parv[0] = sender prefix ** parv[1] = servername */ int m_credits(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { char **text = unrealcredits; if (hunt_server(cptr, sptr, ":%s CREDITS :%s", 1, parc, parv) == HUNTED_ISME) { while (*text) sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], *text++); sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], ""); sendto_one(sptr, ":%s %d %s :Birth Date: %s, compile # %s", me.name, RPL_INFO, parv[0], creation, generation); sendto_one(sptr, ":%s %d %s :On-line since %s", me.name, RPL_INFO, parv[0], myctime(me.firsttime)); sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, parv[0]); } return 0; } /* * RPL_NOWON - Online at the moment (Succesfully added to WATCH-list) * RPL_NOWOFF - Offline at the moement (Succesfully added to WATCH-list) * RPL_WATCHOFF - Succesfully removed from WATCH-list. * ERR_TOOMANYWATCH - Take a guess :> Too many WATCH entries. */ static void show_watch(cptr, name, rpl1, rpl2) aClient *cptr; char *name; int rpl1, rpl2; { aClient *acptr; if ((acptr = find_person(name, NULL))) { sendto_one(cptr, rpl_str(rpl1), me.name, cptr->name, acptr->name, acptr->user->username, IsHidden(acptr) ? acptr->user->virthost : acptr-> user->realhost, acptr->lastnick); } else sendto_one(cptr, rpl_str(rpl2), me.name, cptr->name, name, "*", "*", 0); } /* * m_watch */ int m_watch(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { aClient *acptr; char *s, **pav = parv, *user; char *p = NULL, *def = "l"; if (parc < 2) { /* * Default to 'l' - list who's currently online */ parc = 2; parv[1] = def; } for (s = (char *)strtoken(&p, *++pav, " "); s; s = (char *)strtoken(&p, NULL, " ")) { if ((user = (char *)index(s, '!'))) *user++ = '\0'; /* Not used */ /* * Prefix of "+", they want to add a name to their WATCH * list. */ if (*s == '+') { if (do_nick_name(s + 1)) { if (sptr->notifies >= MAXWATCH) { sendto_one(sptr, err_str(ERR_TOOMANYWATCH), me.name, cptr->name, s + 1); continue; } add_to_notify_hash_table(s + 1, sptr); } show_watch(sptr, s + 1, RPL_NOWON, RPL_NOWOFF); continue; } /* * Prefix of "-", coward wants to remove somebody from their * WATCH list. So do it. :-) */ if (*s == '-') { del_from_notify_hash_table(s + 1, sptr); show_watch(sptr, s + 1, RPL_WATCHOFF, RPL_WATCHOFF); continue; } /* * Fancy "C" or "c", they want to nuke their WATCH list and start * over, so be it. */ if (*s == 'C' || *s == 'c') { hash_del_notify_list(sptr); continue; } /* * Now comes the fun stuff, "S" or "s" returns a status report of * their WATCH list. I imagine this could be CPU intensive if its * done alot, perhaps an auto-lag on this? */ if (*s == 'S' || *s == 's') { Link *lp; aNotify *anptr; int count = 0; /* * Send a list of how many users they have on their WATCH list * and how many WATCH lists they are on. */ anptr = hash_get_notify(sptr->name); if (anptr) for (lp = anptr->notify, count = 1; (lp = lp->next); count++) ; sendto_one(sptr, rpl_str(RPL_WATCHSTAT), me.name, parv[0], sptr->notifies, count); /* * Send a list of everybody in their WATCH list. Be careful * not to buffer overflow. */ if ((lp = sptr->notify) == NULL) { sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST), me.name, parv[0], *s); continue; } *buf = '\0'; strcpy(buf, lp->value.nptr->nick); count = strlen(parv[0]) + strlen(me.name) + 10 + strlen(buf); while ((lp = lp->next)) { if (count + strlen(lp->value.nptr->nick) + 1 > BUFSIZE - 2) { sendto_one(sptr, rpl_str(RPL_WATCHLIST), me.name, parv[0], buf); *buf = '\0'; count = strlen(parv[0]) + strlen(me.name) + 10; } strcat(buf, " "); strcat(buf, lp->value.nptr->nick); count += (strlen(lp->value.nptr->nick) + 1); } sendto_one(sptr, rpl_str(RPL_WATCHLIST), me.name, parv[0], buf); sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST), me.name, parv[0], *s); continue; } /* * Well that was fun, NOT. Now they want a list of everybody in * their WATCH list AND if they are online or offline? Sheesh, * greedy arn't we? */ if (*s == 'L' || *s == 'l') { Link *lp = sptr->notify; while (lp) { if ((acptr = find_person(lp->value.nptr->nick, NULL))) { sendto_one(sptr, rpl_str(RPL_NOWON), me.name, parv[0], acptr->name, acptr->user->username, IsHidden(acptr) ? acptr-> user->virthost : acptr->user-> realhost, acptr->lastnick); } /* * But actually, only show them offline if its a capital * 'L' (full list wanted). */ else if (isupper(*s)) sendto_one(sptr, rpl_str(RPL_NOWOFF), me.name, parv[0], lp->value.nptr->nick, "*", "*", lp->value.nptr->lasttime); lp = lp->next; } sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST), me.name, parv[0], *s); continue; } /* * Hmm.. unknown prefix character.. Ignore it. :-) */ } return 0; } /* ** m_summon should be redefined to ":prefix SUMMON host user" so ** that "hunt_server"-function could be used for this too!!! --msa ** As of 2.7.1e, this was the case. -avalon ** ** parv[0] = sender prefix ** parv[1] = user ** parv[2] = server ** parv[3] = channel (optional) */ int m_summon(cptr, sptr, parc, parv) aClient *sptr, *cptr; int parc; char *parv[]; { char *host, *user, *chname; #ifdef ENABLE_SUMMON char hostbuf[17], namebuf[10], linebuf[10]; # ifdef LEAST_IDLE char linetmp[10], ttyname[15]; /* Ack */ struct stat stb; time_t ltime = (time_t) 0; # endif int fd, flag = 0; #endif if (parc < 2 || *parv[1] == '\0') { sendto_one(sptr, err_str(ERR_NORECIPIENT), me.name, parv[0], "SUMMON"); return 0; } user = parv[1]; host = (parc < 3 || BadPtr(parv[2])) ? me.name : parv[2]; chname = (parc > 3) ? parv[3] : "*"; /* ** Summoning someone on remote server, find out which link to ** use and pass the message there... */ parv[1] = user; parv[2] = host; parv[3] = chname; parv[4] = NULL; if (hunt_server(cptr, sptr, ":%s SUMMON %s %s %s", 2, parc, parv) == HUNTED_ISME) { #ifdef ENABLE_SUMMON if ((fd = utmp_open()) == -1) { sendto_one(sptr, err_str(ERR_FILEERROR), me.name, parv[0], "open", UTMP); return 0; } # ifndef LEAST_IDLE while ((flag = utmp_read(fd, namebuf, linebuf, hostbuf, sizeof(hostbuf))) == 0) if (StrEq(namebuf, user)) break; # else /* use least-idle tty, not the first * one we find in utmp. 10/9/90 Spike@world.std.com * (loosely based on Jim Frost jimf@saber.com code) */ while ((flag = utmp_read(fd, namebuf, linetmp, hostbuf, sizeof(hostbuf))) == 0) { if (StrEq(namebuf, user)) { (void)ircsprintf(ttyname, "/dev/%s", linetmp); if (stat(ttyname, &stb) == -1) { sendto_one(sptr, err_str(ERR_FILEERROR), me.name, sptr->name, "stat", ttyname); return 0; } if (!ltime) { ltime = stb.st_mtime; (void)strcpy(linebuf, linetmp); } else if (stb.st_mtime > ltime) /* less idle */ { ltime = stb.st_mtime; (void)strcpy(linebuf, linetmp); } } } # endif (void)utmp_close(fd); # ifdef LEAST_IDLE if (ltime == 0) # else if (flag == -1) # endif sendto_one(sptr, err_str(ERR_NOLOGIN), me.name, parv[0], user); else summon(sptr, user, linebuf, chname); #else sendto_one(sptr, err_str(ERR_SUMMONDISABLED), me.name, parv[0]); #endif /* ENABLE_SUMMON */ } return 0; } /* ** m_stats ** parv[0] = sender prefix ** parv[1] = statistics selector (defaults to Message frequency) ** parv[2] = server name (current server defaulted, if omitted) ** ** Currently supported are: ** M = Message frequency (the old stat behaviour) ** L = Local Link statistics ** C = Report C and N configuration lines */ /* ** m_stats/stats_conf ** Report N/C-configuration lines from this server. This could ** report other configuration lines too, but converting the ** status back to "char" is a bit akward--not worth the code ** it needs... ** ** Note: The info is reported in the order the server uses ** it--not reversed as in ircd.conf! */ static int report_array[][3] = { {CONF_CONNECT_SERVER, RPL_STATSCLINE, 'C'}, {CONF_NOCONNECT_SERVER, RPL_STATSOLDNLINE, 'N'}, {CONF_NLINE, RPL_STATSNLINE, 'n'}, {CONF_CLIENT, RPL_STATSILINE, 'I'}, {CONF_KILL, RPL_STATSKLINE, 'K'}, {CONF_EXCEPT, RPL_STATSKLINE, 'E'}, {CONF_ZAP, RPL_STATSKLINE, 'Z'}, {CONF_QUARANTINED_NICK, RPL_STATSQLINE, 'Q'}, {CONF_LEAF, RPL_STATSLLINE, 'L'}, {CONF_OPERATOR, RPL_STATSOLINE, 'O'}, {CONF_HUB, RPL_STATSHLINE, 'H'}, {CONF_LOCOP, RPL_STATSOLINE, 'o'}, {CONF_CRULEALL, RPL_STATSDLINE, 'D'}, {CONF_CRULEAUTO, RPL_STATSDLINE, 'd'}, {CONF_UWORLD, RPL_STATSULINE, 'U'}, {CONF_MISSING, RPL_STATSXLINE, 'X'}, {CONF_TLINE, RPL_STATSTLINE, 't'}, {CONF_SOCKSEXCEPT, RPL_STATSELINE, 'e'}, {CONF_VERSION, RPL_STATSVLINE, 'V'}, {0, 0} }; static void report_sqlined_nicks(sptr) aClient *sptr; { aSqlineItem *tmp; char *nickmask, *reason; for (tmp = sqline; tmp; tmp = tmp->next) { if (tmp->status != CONF_ILLEGAL) { nickmask = BadPtr(tmp->sqline) ? "" : tmp->sqline; reason = BadPtr(tmp->reason) ? "" : tmp->reason; sendto_one(sptr, rpl_str(RPL_SQLINE_NICK), me.name, sptr->name, nickmask, reason); } } } static void report_configured_links(sptr, mask) aClient *sptr; int mask; { static char null[] = ""; aConfItem *tmp; int *p, port, tmpmask; char c, *host, *pass, *name; tmpmask = (mask == CONF_MISSING) ? CONF_CONNECT_SERVER : mask; for (tmp = conf; tmp; tmp = tmp->next) if (tmp->status & tmpmask) { for (p = &report_array[0][0]; *p; p += 3) if (*p == tmp->status) break; if (!*p) continue; c = (char)*(p + 2); host = BadPtr(tmp->host) ? null : tmp->host; pass = BadPtr(tmp->passwd) ? null : tmp->passwd; name = BadPtr(tmp->name) ? null : tmp->name; port = (int)tmp->port; /* * On K line the passwd contents can be * displayed on STATS reply. -Vesa */ /* Same with Z-lines and q/Q-lines -- Barubary */ if ((tmp->status == CONF_KILL) || (tmp->status & CONF_QUARANTINE) || (tmp->status & CONF_EXCEPT) || (tmp->status == CONF_ZAP)) { /* These mods are to tell the difference between the different kinds * of klines. the only effect it has is in the display. --Russell */ /* Now translates spaces to _'s to show comments in klines -- Barubary */ char *temp; if (!pass) strcpy(buf, ""); else { strcpy(buf, pass); for (temp = buf; *temp; temp++) if (*temp == ' ') *temp = '_'; } /* semicolon intentional -- Barubary */ if (tmp->status == CONF_QUARANTINED_NICK); /* Hide password for servers -- Barubary */ else if (tmp->status & CONF_QUARANTINE) strcpy(buf, "*"); else { /* This wasn't documented before - comments aren't displayed for akills because they are all the same. -- Barubary */ if (tmp->tmpconf == KLINE_AKILL) strcpy(buf, "*"); /* Show comments in E:Lines.. if (tmp->tmpconf == KLINE_EXCEPT) strcpy(buf, "*"); */ /* KLINE_PERM == 0 - watch out when doing Z-lines. -- Barubary */ if (tmp->status != CONF_ZAP) { if (tmp->tmpconf == KLINE_PERM) c = 'K'; if (tmp->tmpconf == KLINE_TEMP) c = 'k'; if (tmp->tmpconf == KLINE_AKILL) c = 'A'; if (tmp->tmpconf == KLINE_EXCEPT) c = 'E'; } else { if (tmp->tmpconf == KLINE_PERM) c = 'Z'; if (tmp->tmpconf == KLINE_TEMP) c = 'z'; if (tmp->tmpconf == KLINE_AKILL) c = 'S'; if (tmp->tmpconf == KLINE_EXCEPT) c = 'e'; } } sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, host, buf, name, port, get_conf_class(tmp)); } else if (mask & CONF_OPS) { sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, host, name, oflagstr(port), get_conf_class(tmp)); } /* connect rules are classless */ else if (tmp->status & CONF_CRULE) sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, host, name); /* Only display on X if server is missing */ else if (mask == CONF_MISSING) { if (!find_server(name, NULL)) sendto_one(sptr, rpl_str(RPL_STATSXLINE), me.name, sptr->name, name, port); } else if (mask == CONF_TLINE) { sendto_one(sptr, rpl_str(RPL_STATSTLINE), me.name, sptr->name, host, pass, name); } else if (mask == CONF_SOCKSEXCEPT) { sendto_one(sptr, rpl_str(RPL_STATSELINE), me.name, sptr->name, host, pass, name); } else if (mask == CONF_NLINE) { sendto_one(sptr, rpl_str(RPL_STATSNLINE), me.name, sptr->name, host, pass); } else if (mask == CONF_VERSION) sendto_one(sptr, rpl_str(RPL_STATSVLINE), me.name, sptr->name, host, pass, name); /* else if (mask == CONF_EXCEPT) { ppx = MyMalloc(strlen(tmp->passwd) + 1); strcpy(ppx, tmp->passwd); for (pp = ppx; *pp != '\0'; pp++) { if (*pp == ' ') *pp = '_'; } sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name, sptr->name, "E", host, ppx, name, 0,0, -1); MyFree(ppx); } */ else { if (!IsOper(sptr) && (mask & CONF_NOCONNECT_SERVER || mask & CONF_CONNECT_SERVER)) sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, "*", name, port, get_conf_class(tmp)); else sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, host, name, port, get_conf_class(tmp)); } } return; } /* Used to blank out ports -- Barubary */ char *get_client_name2(aClient *acptr, int showports) { char *pointer = get_client_name(acptr, TRUE); if (!pointer) return NULL; if (showports) return pointer; if (!strrchr(pointer, '.')) return NULL; strcpy((char *)strrchr((char *)pointer, '.'), ".0]"); return pointer; } int m_stats(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { #ifndef DEBUGMODE static char Sformat[] = ":%s %d %s SendQ SendM SendBytes RcveM RcveBytes Open_since :Idle"; static char Lformat[] = ":%s %d %s %s %u %u %u %u %u %u :%u"; #else static char Sformat[] = ":%s %d %s SendQ SendM SendBytes RcveM RcveBytes Open_since CPU :Idle"; static char Lformat[] = ":%s %d %s %s %u %u %u %u %u %u %s"; char pbuf[96]; /* Should be enough for to ints */ #endif struct Message *mptr; aClient *acptr; char stat = parc > 1 ? parv[1][0] : '\0'; int i; int doall = 0, wilds = 0, showports = IsAnOper(sptr), remote = 0; char *name; #ifdef STATS_ONLYOPER if (!IsAnOper(sptr)) sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); #endif if (hunt_server(cptr, sptr, ":%s STATS %s :%s", 2, parc, parv) != HUNTED_ISME) return 0; if (parc > 2) { name = parv[2]; if (!mycmp(name, me.name)) doall = 2; else if (match(name, me.name) == 0) doall = 1; if (index(name, '*') || index(name, '?')) wilds = 1; } else name = me.name; if (stat != '\0') sendto_umode(UMODE_EYES, "Stats \'%c\' requested by %s (%s@%s)", stat, sptr->name, sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr-> user->realhost); else sendto_umode(UMODE_EYES, "Stats \'NULL\' requested by %s (%s@%s)", sptr->name, sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr-> user->realhost); switch (stat) { case 'b': badwords_stats(); break; case 'L': case 'l': /* * send info about connections which match, or all if the * mask matches me.name. Only restrictions are on those who * are invisible not being visible to 'foreigners' who use * a wild card based search to list it. */ sendto_one(sptr, Sformat, me.name, RPL_STATSLINKINFO, parv[0]); if (IsServer(cptr)) { remote = 1; wilds = 0; } for (i = 0; i <= highest_fd; i++) { if (!(acptr = local[i])) continue; if (IsInvisible(acptr) && (doall || wilds) && !(MyConnect(sptr) && IsOper(sptr)) && !IsAnOper(acptr) && (acptr != sptr)) continue; if (remote && doall && !IsServer(acptr) && !IsMe(acptr)) continue; if (remote && !doall && IsServer(acptr)) continue; if (!doall && wilds && match(name, acptr->name)) continue; if (!(parc == 2 && IsServer(acptr)) && !(doall || wilds) && mycmp(name, acptr->name)) continue; #ifdef DEBUGMODE ircsprintf(pbuf, "%d :%d", acptr->cputime, (acptr->user && MyConnect(acptr)) ? TStime() - acptr->user->last : 0); #endif if (IsOper(sptr)) { sendto_one(sptr, Lformat, me.name, RPL_STATSLINKINFO, parv[0], (isupper(stat)) ? get_client_name2(acptr, showports) : get_client_name(acptr, FALSE), (int)DBufLength(&acptr->sendQ), (int)acptr->sendM, (int)acptr->sendK, (int)acptr->receiveM, (int)acptr->receiveK, TStime() - acptr->firsttime, #ifndef DEBUGMODE (acptr->user && MyConnect(acptr)) ? TStime() - acptr->user->last : 0); #else pbuf); #endif if (!IsServer(acptr) && IsAnOper(acptr)) sendto_one(acptr, ":%s NOTICE %s :*** %s did a /stats L on you! IP may have been shown", me.name, acptr->name, sptr->name); } else if (!strchr(acptr->name, '.')) sendto_one(sptr, Lformat, me.name, RPL_STATSLINKINFO, parv[0], IsHidden(acptr) ? acptr->name : (isupper(stat)) ? /* Potvin - PreZ */ get_client_name2(acptr, showports) : get_client_name(acptr, FALSE), (int)DBufLength(&acptr->sendQ), (int)acptr->sendM, (int)acptr->sendK, (int)acptr->receiveM, (int)acptr->receiveK, TStime() - acptr->firsttime, #ifndef DEBUGMODE (acptr->user && MyConnect(acptr)) ? TStime() - acptr->user->last : 0); #else pbuf); #endif } break; case 'C': case 'c': report_configured_links(sptr, CONF_CONNECT_SERVER | CONF_NOCONNECT_SERVER); break; case 'f': case 'F': report_flines(sptr); break; case 'G': case 'g': tkl_stats(sptr); break; case 'H': case 'h': report_configured_links(sptr, CONF_HUB | CONF_LEAF); break; case 'I': case 'i': report_configured_links(sptr, CONF_CLIENT); break; case 'E': report_configured_links(sptr, CONF_EXCEPT); break; case 'e': report_configured_links(sptr, CONF_SOCKSEXCEPT); break; case 'K': case 'k': report_configured_links(sptr, CONF_KILL | CONF_ZAP | CONF_EXCEPT); break; case 'M': case 'm': for (mptr = msgtab; mptr->cmd; mptr++) if (mptr->count) #ifndef DEBUGMODE sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS), me.name, parv[0], mptr->cmd, mptr->count, mptr->bytes); #else sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS), me.name, parv[0], mptr->cmd, mptr->count, mptr->bytes, mptr->lticks, mptr->lticks / CLOCKS_PER_SEC, mptr->rticks, mptr->rticks / CLOCKS_PER_SEC); #endif break; case 'n': report_configured_links(sptr, CONF_NLINE); break; case 'N': if (IsOper(sptr)) report_network(sptr); break; case 'o': case 'O': /* if (SHOWOPERS == 1) { if(IsOper(sptr)) { report_configured_links(sptr, CONF_OPS); break; } } else if (SHOWOPERS == 0) { report_configured_links(sptr, CONF_OPS); */ if (SHOWOPERS == 0 && (IsOper(sptr))) { report_configured_links(sptr, CONF_OPS); break; } if (SHOWOPERS == 1) report_configured_links(sptr, CONF_OPS); break; case 'Q': report_configured_links(sptr, CONF_QUARANTINE); break; case 'q': report_sqlined_nicks(sptr); break; case 'R': #ifdef DEBUGMODE send_usage(sptr, parv[0]); #endif break; case 's': if (IsOper(sptr)) list_scache(sptr); break; case 'S': if (IsOper(sptr)) report_dynconf(sptr); break; case 'D': report_configured_links(sptr, CONF_CRULEALL); break; case 'd': report_configured_links(sptr, CONF_CRULE); break; case 'r': cr_report(sptr); break; case 't': report_configured_links(sptr, CONF_TLINE); break; case 'T': /* /stats T not t:lines .. */ tstats(sptr, parv[0]); break; case 'U': report_configured_links(sptr, CONF_UWORLD); break; case 'u': { time_t tmpnow; tmpnow = TStime() - me.since; sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0], tmpnow / 86400, (tmpnow / 3600) % 24, (tmpnow / 60) % 60, tmpnow % 60); sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0], max_connection_count, IRCstats.me_max); break; } case 'v': report_configured_links(sptr, CONF_VERSION); break; case 'V': vhost_report(sptr); break; case 'W': case 'w': calc_load(sptr, parv[0]); break; case 'X': case 'x': report_configured_links(sptr, CONF_MISSING); break; case 'Y': case 'y': report_classes(sptr); break; case 'Z': case 'z': if (IsAnOper(sptr)) count_memory(sptr, parv[0]); break; default: stat = '*'; break; } sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat); return 0; } /* ** m_users ** parv[0] = sender prefix ** parv[1] = servername */ int m_users(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { #ifdef ENABLE_USERS char namebuf[10], linebuf[10], hostbuf[17]; int fd, flag = 0; #endif if (hunt_server(cptr, sptr, ":%s USERS :%s", 1, parc, parv) == HUNTED_ISME) { #ifdef ENABLE_USERS if ((fd = utmp_open()) == -1) { sendto_one(sptr, err_str(ERR_FILEERROR), me.name, parv[0], "open", UTMP); return 0; } sendto_one(sptr, rpl_str(RPL_USERSSTART), me.name, parv[0]); while (utmp_read(fd, namebuf, linebuf, hostbuf, sizeof(hostbuf)) == 0) { flag = 1; sendto_one(sptr, rpl_str(RPL_USERS), me.name, parv[0], namebuf, linebuf, hostbuf); } if (flag == 0) sendto_one(sptr, rpl_str(RPL_NOUSERS), me.name, parv[0]); sendto_one(sptr, rpl_str(RPL_ENDOFUSERS), me.name, parv[0]); (void)utmp_close(fd); #else sendto_one(sptr, err_str(ERR_USERSDISABLED), me.name, parv[0]); #endif } return 0; } /* ** Note: At least at protocol level ERROR has only one parameter, ** although this is called internally from other functions ** --msa ** ** parv[0] = sender prefix ** parv[*] = parameters */ int m_error(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { char *para; para = (parc > 1 && *parv[1] != '\0') ? parv[1] : "<>"; Debug((DEBUG_ERROR, "Received ERROR message from %s: %s", sptr->name, para)); /* ** Ignore error messages generated by normal user clients ** (because ill-behaving user clients would flood opers ** screen otherwise). Pass ERROR's from other sources to ** the local operator... */ if (IsPerson(cptr) || IsUnknown(cptr)) return 0; if (cptr == sptr) { sendto_serv_butone(&me, ":%s GLOBOPS :ERROR from %s -- %s", me.name, get_client_name(cptr, FALSE), para); sendto_locfailops("ERROR :from %s -- %s", get_client_name(cptr, FALSE), para); } else { sendto_serv_butone(&me, ":%s GLOBOPS :ERROR from %s via %s -- %s", me.name, sptr->name, get_client_name(cptr, FALSE), para); sendto_ops("ERROR :from %s via %s -- %s", sptr->name, get_client_name(cptr, FALSE), para); } return 0; } Link *helpign = NULL; /* Now just empty ignore-list, in future reload dynamic help. * Move out to help.c -Donwulff */ void reset_help() { free_str_list(helpign); } /* ** m_help (help/write to +h currently online) -Donwulff ** parv[0] = sender prefix ** parv[1] = optional message text */ int m_help(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { char *message, *s; Link *tmpl; message = parc > 1 ? parv[1] : NULL; /* Drags along from wallops code... I'm not sure what it's supposed to do, at least it won't do that gracefully, whatever it is it does - but checking whether or not it's a person _is_ good... -Donwulff */ if (!IsServer(sptr) && MyConnect(sptr) && !IsPerson(sptr)) { } if (IsServer(sptr) || IsHelpOp(sptr)) { if (BadPtr(message)) return 0; if (message[0] == '?') { parse_help(sptr, parv[0], message + 1); return 0; } if (message[1] == '!') sendto_serv_butone_token(IsServer(cptr) ? cptr : NULL, parv[0], MSG_HELP, TOK_HELP, "%s", message); if (!myncmp(message, "IGNORE ", 7)) { tmpl = make_link(); DupString(tmpl->value.cp, message + 7); tmpl->next = helpign; helpign = tmpl; } sendto_helpops("from %s (HelpOp): %s", parv[0], message); } else if (MyConnect(sptr)) { /* New syntax: ?... never goes out, !... always does. */ if (!BadPtr(message)) { parse_help(sptr, parv[0], message); return 0; } if ((!BadPtr(message) && !(message[0] == '!')) || BadPtr(message)) if (parse_help(sptr, parv[0], message)) return 0; s = make_nick_user_host(cptr->name, cptr->user->username, cptr->user->realhost); for (tmpl = helpign; tmpl; tmpl = tmpl->next) if (match(tmpl->value.cp, s) == 0) { sendto_one(sptr, rpl_str(RPL_HELPIGN), me.name, parv[0]); return 0; } sendto_serv_butone_token(IsServer(cptr) ? cptr : NULL, parv[0], MSG_HELP, TOK_HELP, "%s", message); sendto_helpops("from %s (Local): %s", parv[0], message); sendto_one(sptr, rpl_str(RPL_HELPFWD), me.name, parv[0]); } else { sendto_serv_butone_token(IsServer(cptr) ? cptr : NULL, parv[0], MSG_HELP, TOK_HELP, "%s", message); sendto_helpops("from %s: %s", parv[0], message); } return 0; } /* * parv[0] = sender * parv[1] = host/server mask. * parv[2] = server to query */ int m_lusers(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { char mydom_mask[HOSTLEN + 1]; /* Doesn't work anyways --Stskeeps if (parc > 2) if(hunt_server(cptr, sptr, ":%s LUSERS %s :%s", 2, parc, parv) != HUNTED_ISME) return 0; */ mydom_mask[0] = '*'; strncpy(&mydom_mask[1], DOMAINNAME, HOSTLEN - 1); /* Just to correct results ---Stskeeps */ if (IRCstats.clients > IRCstats.global_max) IRCstats.global_max = IRCstats.clients; if (IRCstats.me_clients > IRCstats.me_max) IRCstats.me_max = IRCstats.me_clients; sendto_one(sptr, rpl_str(RPL_LUSERCLIENT), me.name, parv[0], IRCstats.clients - IRCstats.invisible, IRCstats.invisible, IRCstats.servers); if (IRCstats.operators) sendto_one(sptr, rpl_str(RPL_LUSEROP), me.name, parv[0], IRCstats.operators); if (IRCstats.unknown) sendto_one(sptr, rpl_str(RPL_LUSERUNKNOWN), me.name, parv[0], IRCstats.unknown); if (IRCstats.channels) sendto_one(sptr, rpl_str(RPL_LUSERCHANNELS), me.name, parv[0], IRCstats.channels); sendto_one(sptr, rpl_str(RPL_LUSERME), me.name, parv[0], IRCstats.me_clients, IRCstats.me_servers); sendto_one(sptr, rpl_str(RPL_LOCALUSERS), me.name, parv[0], IRCstats.me_clients, IRCstats.me_max); sendto_one(sptr, rpl_str(RPL_GLOBALUSERS), me.name, parv[0], IRCstats.clients, IRCstats.global_max); if ((IRCstats.me_clients + IRCstats.me_servers) > max_connection_count) { max_connection_count = IRCstats.me_clients + IRCstats.me_servers; if (max_connection_count % 10 == 0) /* only send on even tens */ sendto_ops("Maximum connections: %d (%d clients)", max_connection_count, IRCstats.me_clients); } current_load_data.client_count = IRCstats.me_clients; current_load_data.conn_count = IRCstats.me_clients + IRCstats.me_servers; return 0; } extern int Rha; void save_tunefile(void) { FILE *tunefile; tunefile = fopen(IRCDTUNE, "w+"); if (!tunefile) { #if !defined(_WIN32) && !defined(_AMIGA) sendto_ops("Unable to write tunefile.. %s", strerror(errno)); #else sendto_ops("Unable to write tunefile.."); #endif return; } fprintf(tunefile, "%li\n", TSoffset); fprintf(tunefile, "%li\n", IRCstats.me_max); fprintf(tunefile, "%li\n", Rha); fclose(tunefile); } void load_tunefile(void) { FILE *tunefile; char buf[1024]; tunefile = fopen(IRCDTUNE, "r"); if (!tunefile) return; fprintf(stderr, "* Loading tunefile..\n"); fgets(buf, 1023, tunefile); TSoffset = atol(buf); fgets(buf, 1023, tunefile); IRCstats.me_max = atol(buf); fgets(buf, 1023, tunefile); Rha = atol(buf); fclose(tunefile); } /*********************************************************************** * m_connect() - Added by Jto 11 Feb 1989 ***********************************************************************/ /* ** m_connect ** parv[0] = sender prefix ** parv[1] = servername ** parv[2] = port number ** parv[3] = remote server */ int m_connect(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { int port, tmpport, retval; aConfItem *aconf, *cconf; aClient *acptr; if (!IsPrivileged(sptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return -1; } if (MyClient(sptr) && !OPCanGRoute(sptr) && parc > 3) { /* Only allow LocOps to make */ /* local CONNECTS --SRB */ sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if (MyClient(sptr) && !OPCanLRoute(sptr) && parc <= 3) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if (hunt_server(cptr, sptr, ":%s CONNECT %s %s :%s", 3, parc, parv) != HUNTED_ISME) return 0; if (parc < 2 || *parv[1] == '\0') { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "CONNECT"); return -1; } if ((acptr = find_server(parv[1], NULL))) { sendto_one(sptr, ":%s NOTICE %s :Connect: Server %s %s %s.", me.name, parv[0], parv[1], "already exists from", acptr->from->name); return 0; } for (aconf = conf; aconf; aconf = aconf->next) if (aconf->status == CONF_CONNECT_SERVER && match(parv[1], aconf->name) == 0) break; /* Checked first servernames, then try hostnames. */ if (!aconf) for (aconf = conf; aconf; aconf = aconf->next) if (aconf->status == CONF_CONNECT_SERVER && (match(parv[1], aconf->host) == 0 || match(parv[1], index(aconf->host, '@') + 1) == 0)) break; if (!aconf) { sendto_one(sptr, "NOTICE %s :Connect: Host %s not listed in ircd.conf", parv[0], parv[1]); return 0; } /* ** Get port number from user, if given. If not specified, ** use the default form configuration structure. If missing ** from there, then use the precompiled default. */ tmpport = port = aconf->port; if (parc > 2 && !BadPtr(parv[2])) { if ((port = atoi(parv[2])) <= 0) { sendto_one(sptr, "NOTICE %s :Connect: Illegal port number", parv[0]); return 0; } } else if (port <= 0 && (port = PORTNUM) <= 0) { sendto_one(sptr, ":%s NOTICE %s :Connect: missing port number", me.name, parv[0]); return 0; } /* ** Evaluate connection rules... If no rules found, allow the ** connect. Otherwise stop with the first true rule (ie: rules ** are ored together. Oper connects are effected only by D ** lines (CRULEALL) not d lines (CRULEAUTO). */ for (cconf = conf; cconf; cconf = cconf->next) if ((cconf->status == CONF_CRULEALL) && (match(cconf->host, aconf->name) == 0)) if (crule_eval(cconf->passwd)) { sendto_one(sptr, "NOTICE %s :Connect: Disallowed by rule: %s", parv[0], cconf->name); return 0; } /* ** Notify all operators about remote connect requests */ if (!IsAnOper(cptr)) { sendto_serv_butone(&me, ":%s GLOBOPS :Remote CONNECT %s %s from %s", me.name, parv[1], parv[2] ? parv[2] : "", get_client_name(sptr, FALSE)); #if defined(USE_SYSLOG) && defined(SYSLOG_CONNECT) syslog(LOG_DEBUG, "CONNECT From %s : %s %d", parv[0], parv[1], parv[2] ? parv[2] : ""); #endif } aconf->port = port; switch (retval = connect_server(aconf, sptr, NULL)) { case 0: sendto_one(sptr, ":%s NOTICE %s :*** Connecting to %s[%s].", me.name, parv[0], aconf->host, aconf->name); break; case -1: sendto_one(sptr, ":%s NOTICE %s :*** Couldn't connect to %s.", me.name, parv[0], aconf->host); break; case -2: sendto_one(sptr, ":%s NOTICE %s :*** Host %s is unknown.", me.name, parv[0], aconf->host); break; default: sendto_one(sptr, ":%s NOTICE %s :*** Connection to %s failed: %s", me.name, parv[0], aconf->host, strerror(retval)); } aconf->port = tmpport; return 0; } /* ** m_wallops (write to *all* opers currently online) ** parv[0] = sender prefix ** parv[1] = message text */ int m_wallops(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { char *message; message = parc > 1 ? parv[1] : NULL; if (BadPtr(message)) { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "WALLOPS"); return 0; } if (MyClient(sptr) && !OPCanWallOps(sptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } sendto_ops_butone(IsServer(cptr) ? cptr : NULL, sptr, ":%s WALLOPS :%s", parv[0], message); return 0; } /* m_gnotice (Russell) sort of like wallop, but only to +g clients on ** this server. ** parv[0] = sender prefix ** parv[1] = message text */ int m_gnotice(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { char *message; message = parc > 1 ? parv[1] : NULL; if (BadPtr(message)) { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "GNOTICE"); return 0; } if (!IsServer(sptr) && MyConnect(sptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } sendto_serv_butone_token(IsServer(cptr) ? cptr : NULL, parv[0], MSG_GNOTICE, TOK_GNOTICE, ":%s", message); sendto_failops("from %s: %s", parv[0], message); return 0; } /* ** m_addline (write a line to ircd.conf) ** ** De-Potvinized by codemastr */ int m_addline(aClient *cptr, aClient *sptr, int parc, char *parv[]) { FILE *conf; char *text; text = parc > 1 ? parv[1] : NULL; if (!(IsAdmin(sptr) || IsCoAdmin(sptr))) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if (parc < 2) { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "ADDLINE"); return 0; } /* writes to current -f */ conf = fopen(configfile, "a"); if (conf == NULL) { return 0; } /* Display what they wrote too */ sendto_one(sptr, ":%s NOTICE %s :*** Wrote (%s) to ircd.conf", me.name, parv[0], text); fprintf(conf, "# Added by %s\n", make_nick_user_host(sptr->name, sptr->user->username, sptr->user->realhost)); /* for (i=1 ; i 1 ? parv[1] : NULL; if (!MyConnect(sptr)) return 0; if (!(IsAdmin(sptr) || IsCoAdmin(sptr))) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if (parc < 2) { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "ADDMOTD"); return 0; } conf = fopen(MOTD, "a"); if (conf == NULL) { return 0; } sendto_one(sptr, ":%s NOTICE %s :*** Wrote (%s) to file: ircd.motd", me.name, parv[0], text); /* for (i=1 ; i 1 ? parv[1] : NULL; if (!MyConnect(sptr)) return 0; if (!(IsAdmin(sptr) || IsCoAdmin(sptr))) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if (parc < 2) { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "ADDMOTD"); return 0; } conf = fopen(OPATH, "a"); if (conf == NULL) { return 0; } sendto_one(sptr, ":%s NOTICE %s :*** Wrote (%s) to OperMotd", me.name, parv[0], text); /* for (i=1 ; i 1 ? parv[1] : NULL; if (BadPtr(message)) { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "GLOBOPS"); return 0; } if (MyClient(sptr) && !OPCanGlobOps(sptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } sendto_serv_butone_token(IsServer(cptr) ? cptr : NULL, parv[0], MSG_GLOBOPS, TOK_GLOBOPS, ":%s", message); sendto_failops_whoare_opers("from %s: %s", parv[0], message); return 0; } /* ** m_locops (write to opers who are +g currently online *this* server) ** parv[0] = sender prefix ** parv[1] = message text */ int m_locops(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { char *message; message = parc > 1 ? parv[1] : NULL; if (BadPtr(message)) { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "LOCOPS"); return 0; } if (MyClient(sptr) && !OPCanLocOps(sptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } sendto_locfailops("from %s: %s", parv[0], message); return 0; } /* ** m_chatops (write to opers who are +b currently online) ** parv[0] = sender prefix ** parv[1] = message text */ int m_chatops(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { char *message; message = parc > 1 ? parv[1] : NULL; if (BadPtr(message)) { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "CHATOPS"); return 0; } if (ALLOW_CHATOPS == 1) { if (MyClient(sptr) && !SendChatops(sptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } } else { if (MyClient(sptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } } sendto_serv_butone_token(IsServer(cptr) ? cptr : NULL, parv[0], MSG_CHATOPS, TOK_CHATOPS, ":%s", message); if (ALLOW_CHATOPS == 1) sendto_umode(UMODE_CHATOP, "*** ChatOps -- from %s: %s", parv[0], message); return 0; } /* m_goper (Russell) sort of like wallop, but only to ALL +o clients on ** every server. ** parv[0] = sender prefix ** parv[1] = message text */ int m_goper(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { char *message; message = parc > 1 ? parv[1] : NULL; if (BadPtr(message)) { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "GOPER"); return 0; } /* if (!IsServer(sptr) && MyConnect(sptr) && !IsAnOper(sptr))*/ if (!IsServer(sptr) || !IsULine(cptr, sptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } sendto_serv_butone_token(IsServer(cptr) ? cptr : NULL, parv[0], MSG_GOPER, TOK_GOPER, ":%s", message); sendto_opers("from %s: %s", parv[0], message); return 0; } /* ** m_time ** parv[0] = sender prefix ** parv[1] = servername */ int m_time(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { if (hunt_server(cptr, sptr, ":%s TIME :%s", 1, parc, parv) == HUNTED_ISME) sendto_one(sptr, rpl_str(RPL_TIME), me.name, parv[0], me.name, date((long)0)); return 0; } /* ** m_svskill ** parv[0] = servername ** parv[1] = client ** parv[2] = kill message */ int m_svskill(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { aClient *acptr; /* this is very wierd ? */ char *comment = NULL; if (parc < 2) return -1; if (parc > 3) return -1; if (parc == 3) comment = parv[2]; if (parc == 2) comment = "SVS Killed"; if (!IsULine(cptr, sptr)) return -1; /* if (hunt_server(cptr,sptr,":%s SVSKILL %s :%s",1,parc,parv) != HUNTED_ISME) return 0; */ if (parc < 1 || (!(acptr = find_client(parv[1], NULL)))) return 0; sendto_serv_butone(cptr, ":%s SVSKILL %s :%s", parv[0], parv[1], comment); return exit_client(cptr, acptr, sptr, comment); } /* ** m_admin ** parv[0] = sender prefix ** parv[1] = servername */ int m_admin(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { aConfItem *aconf; /* Users may want to get the address in case k-lined, etc. -- Barubary /* Only allow remote ADMINs if registered -- Barubary */ if (IsPerson(sptr) || IsServer(cptr)) if (hunt_server(cptr, sptr, ":%s ADMIN :%s", 1, parc, parv) != HUNTED_ISME) return 0; if ((aconf = find_admin())) { sendto_one(sptr, rpl_str(RPL_ADMINME), me.name, parv[0], me.name); sendto_one(sptr, rpl_str(RPL_ADMINLOC1), me.name, parv[0], (aconf->host ? aconf->host : "-")); sendto_one(sptr, rpl_str(RPL_ADMINLOC2), me.name, parv[0], (aconf->passwd ? aconf->passwd : "-")); sendto_one(sptr, rpl_str(RPL_ADMINEMAIL), me.name, parv[0], (aconf->name ? aconf->name : "-")); } else sendto_one(sptr, err_str(ERR_NOADMININFO), me.name, parv[0], me.name); return 0; } /* ** m_rehash ** remote rehash by binary ** now allows the -flags in remote rehash ** ugly code but it seems to work :) -- codemastr */ int m_rehash(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { int x; if (MyClient(sptr) && !OPCanRehash(sptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if (!MyClient(sptr) && !(IsTechAdmin(sptr) || IsNetAdmin(sptr)) && !IsULine(cptr, sptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } x = 0; if (!BadPtr(parv[1])) { if (*parv[1] == '-') { if (!match("-dcc*", parv[1])) { sendto_ops ("Rehashing dccdeny.conf on request of %s", sptr->name); dcc_rehash(); return 0; } if (!match("-dyn*", parv[1])) { if (!IsAdmin(sptr)) return 0; sendto_ops ("Rehashing dynamic configuration on request of %s", sptr->name); load_conf(ZCONF, 1); return 0; } if (!match("-gar*", parv[1])) { if (!IsAdmin(sptr)) return 0; do_garbage_collect = 1; return 0; } if (!match("-rest*", parv[1])) { if (!IsAdmin(sptr)) return 0; sendto_ops ("Rehashing channel restrict configuration on request of %s", sptr->name); cr_rehash(); return 0; } if (!match("-o*motd", parv[1])) { if (!IsAdmin(sptr)) return 0; sendto_ops ("Rehashing OperMOTD on request of %s", sptr->name); opermotd = (aMotd *) read_opermotd(OPATH); return 0; } if (!match("-b*motd", parv[1])) { if (!IsAdmin(sptr)) return 0; sendto_ops("Rehashing BotMOTD on request of %s", sptr->name); botmotd = (aMotd *) read_botmotd(BPATH); return 0; } if (!match("-motd*", parv[1]) || !match("-rules*", parv[1])) { if (!IsAdmin(sptr)) return 0; sendto_ops ("Rehashing all MOTDs and RULES on request of %s", sptr->name); motd = (aMotd *) read_motd(MPATH); rules = (aMotd *) read_rules(RPATH); read_tlines(); return 0; } if (!match("-vhos*", parv[1])) { if (!IsAdmin(sptr)) return 0; sendto_ops ("Rehashing vhost configuration on request of %s", sptr->name); vhost_rehash(); return 0; } #ifdef STRIPBADWORDS if (!match("-bad*", parv[1])) { if (!IsAdmin(sptr)) return 0; sendto_ops ("Rehashing badword configuration on request of %s", sptr->name); freebadwords(); loadbadwords_channel("badwords.channel.conf"); loadbadwords_message("badwords.message.conf"); return 0; } #endif } if (MyClient(sptr) && !(IsNetAdmin(sptr) || IsTechAdmin(sptr))) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } /* This little number allows us to send a -param to another server, * but only if it exists -- codemastr*/ if (parv[2] != NULL) { if ((x = hunt_server(cptr, sptr, ":%s REHASH %s %s", 1, parc, parv)) != HUNTED_ISME) return 0; } if (parv[2] == NULL) { if ((x = hunt_server(cptr, sptr, ":%s REHASH %s", 1, parc, parv)) != HUNTED_ISME) return 0; } } if (cptr != sptr) { #ifndef REMOTE_REHASH sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; #else if (parv[2] == NULL) { sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing server config file", me.name, sptr->name); sendto_ops ("%s is remotely rehashing server config file", parv[0]); } /* Then we have a hack here to parse the flags (thats the ugly part) */ else { if (!BadPtr(parv[2])) { if (*parv[2] == '-') { if (!match("-dcc*", parv[2])) { sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing dccdeny.conf", me.name, sptr->name); sendto_ops ("Remotely rehashing dccdeny.conf on request of %s", sptr->name); dcc_rehash(); return 0; } if (!match("-dyn*", parv[2])) { if (!IsAdmin(sptr)) return 0; sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing dynamic configuration", me.name, sptr->name); sendto_ops ("Remotely rehashing dynamic configuration on request of %s", sptr->name); load_conf(ZCONF, 1); return 0; } if (!match("-rest*", parv[2])) { if (!IsAdmin(sptr)) return 0; sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing channel restrict configuration", me.name, sptr->name); sendto_ops ("Remotely rehashing channel restrict configuration on request of %s", sptr->name); cr_rehash(); return 0; } if (!match("-o*motd", parv[2])) { if (!IsAdmin(sptr)) return 0; sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing OperMOTD", me.name, sptr->name); sendto_ops ("Remotely rehashing OperMOTD on request of %s", sptr->name); opermotd = (aMotd *) read_opermotd(OPATH); return 0; } if (!match("-b*motd", parv[2])) { if (!IsAdmin(sptr)) return 0; sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing BotMOTD", me.name, sptr->name); sendto_ops ("Remotely rehashing BotMOTD on request of %s", sptr->name); botmotd = (aMotd *) read_botmotd(BPATH); return 0; } if (!match("-motd*", parv[2]) || !match("-rules*", parv[2])) { if (!IsAdmin(sptr)) return 0; sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing all MOTDs and RULES", me.name, sptr->name); sendto_ops ("Remotely rehashing all MOTDs and RULES on request of %s", sptr->name); motd = (aMotd *) read_motd(MPATH); rules = (aMotd *) read_rules(RPATH); read_tlines(); return 0; } if (!match("-vhos*", parv[2])) { if (!IsAdmin(sptr)) return 0; sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing vhost configuration", me.name, sptr->name); sendto_ops ("Remotely rehashing vhost configuration on request of %s", sptr->name); vhost_rehash(); return 0; } } } } #endif } else { sendto_ops("%s is rehashing server config file", parv[0]); } sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0], configfile); #ifdef USE_SYSLOG syslog(LOG_INFO, "REHASH From %s\n", get_client_name(sptr, FALSE)); #endif return rehash(cptr, sptr, (parc > 1) ? ((*parv[1] == 'q') ? 2 : 0) : 0); } /* ** m_restart ** ** parv[1] - password *OR* reason if no X:line ** parv[2] - reason for restart (optional & only if X:line exists) ** ** The password is only valid if there is a matching X line in the ** config file. If it is not, then it becomes the */ int m_restart(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { char *pass = NULL, *encr; int x; #ifdef CRYPT_XLINE_PASSWORD char salt[3]; extern char *crypt(); #endif if (MyClient(sptr) && !OPCanRestart(sptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if (!MyClient(sptr) && !(IsTechAdmin(sptr) || IsNetAdmin(sptr)) && !IsULine(cptr, sptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if (parc > 2) { /* Remote restart. */ if (MyClient(sptr) && !(IsNetAdmin(sptr) || IsTechAdmin(sptr))) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if ((x = hunt_server(cptr, sptr, ":%s RESTART %s %s :%s", 2, parc, parv)) != HUNTED_ISME) return 0; } if (cptr != sptr) { sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely restarting server (%s)", me.name, sptr->name, parv[3]); sendto_ops("%s is remotely restarting IRCd (%s)", parv[0], parv[3]); } if ((pass = find_restartpass())) { if (parc < 2) { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "RESTART"); return 0; } #ifdef CRYPT_XLINE_PASSWORD salt[0]=pass[0]; salt[1]=pass[1]; salt[3]='\0'; encr = crypt(parv[1], salt); #else encr = parv[1]; #endif if (strcmp(pass, encr)) { sendto_one(sptr, err_str(ERR_PASSWDMISMATCH), me.name, parv[0]); return 0; } /* Hack to make the code after this if { } easier: we assign the comment to the * first param, as if we had not had an X:line. We do not need the password * now anyways. Accordingly we decrement parc ;) -- NikB */ parv[1] = parv[2]; parc--; } #ifdef USE_SYSLOG syslog(LOG_WARNING, "Server RESTART by %s - %s\n", get_client_name(sptr, FALSE), (!MyClient(sptr) ? (parc > 2 ? parv[3] : "No reason") : (parc > 1 ? parv[2] : "No reason"))); #endif sendto_ops("Server is Restarting by request of %s", parv[0]); server_reboot((!MyClient(sptr) ? (parc > 2 ? parv[3] : "No reason") : (parc > 1 ? parv[2] : "No reason"))); return 0; } /* ** m_trace ** parv[0] = sender prefix ** parv[1] = servername */ int m_trace(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { int i; aClient *acptr; aClass *cltmp; char *tname; int doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS]; int cnt = 0, wilds, dow; time_t now; if (parc > 2) if (hunt_server(cptr, sptr, ":%s TRACE %s :%s", 2, parc, parv)) return 0; if (parc > 1) tname = parv[1]; else tname = me.name; if (!IsOper(sptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } switch (hunt_server(cptr, sptr, ":%s TRACE :%s", 1, parc, parv)) { case HUNTED_PASS: /* note: gets here only if parv[1] exists */ { aClient *ac2ptr; ac2ptr = next_client(client, tname); sendto_one(sptr, rpl_str(RPL_TRACELINK), me.name, parv[0], version, debugmode, tname, ac2ptr->from->name); return 0; } case HUNTED_ISME: break; default: return 0; } doall = (parv[1] && (parc > 1)) ? !match(tname, me.name) : TRUE; wilds = !parv[1] || index(tname, '*') || index(tname, '?'); dow = wilds || doall; #ifndef _WIN32 for (i = 0; i < MAXCONNECTIONS; i++) link_s[i] = 0, link_u[i] = 0; #else bzero(link_s, sizeof(link_s)); bzero(link_u, sizeof(link_u)); #endif if (doall) for (acptr = client; acptr; acptr = acptr->next) #ifdef SHOW_INVISIBLE_LUSERS if (IsPerson(acptr)) link_u[acptr->from->fd]++; #else if (IsPerson(acptr) && (!IsInvisible(acptr) || IsOper(sptr))) link_u[acptr->from->fd]++; #endif else if (IsServer(acptr)) link_s[acptr->from->fd]++; /* report all direct connections */ now = TStime(); for (i = 0; i <= highest_fd; i++) { char *name; int class; if (!(acptr = local[i])) /* Local Connection? */ continue; /* More bits of code to allow oers to see all users on remote traces * if (IsInvisible(acptr) && dow && * if (dow && * !(MyConnect(sptr) && IsOper(sptr)) && */ if (!IsOper(sptr) && !IsAnOper(acptr) && (acptr != sptr)) continue; if (!doall && wilds && match(tname, acptr->name)) continue; if (!dow && mycmp(tname, acptr->name)) continue; name = get_client_name(acptr, FALSE); class = get_client_class(acptr); switch (acptr->status) { case STAT_CONNECTING: sendto_one(sptr, rpl_str(RPL_TRACECONNECTING), me.name, parv[0], class, name); cnt++; break; case STAT_HANDSHAKE: sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE), me.name, parv[0], class, name); cnt++; break; case STAT_ME: break; case STAT_UNKNOWN: sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN), me.name, parv[0], class, name); cnt++; break; case STAT_CLIENT: /* Only opers see users if there is a wildcard * but anyone can see all the opers. */ /* if (IsOper(sptr) && * Allow opers to see invisible users on a remote trace or wildcard * search ... sure as hell helps to find clonebots. --Russell * (MyClient(sptr) || !(dow && IsInvisible(acptr))) * || !dow || IsAnOper(acptr)) */ if (IsOper(sptr) || (IsAnOper(acptr) && !IsInvisible(acptr))) { if (IsAnOper(acptr)) sendto_one(sptr, rpl_str(RPL_TRACEOPERATOR), me.name, parv[0], class, acptr->name, IsHidden(acptr) ? acptr-> user->virthost : acptr->user-> realhost, now - acptr->lasttime); else sendto_one(sptr, rpl_str(RPL_TRACEUSER), me.name, parv[0], class, acptr->name, acptr->user->realhost, now - acptr->lasttime); cnt++; } break; case STAT_SERVER: if (acptr->serv->user) sendto_one(sptr, rpl_str(RPL_TRACESERVER), me.name, parv[0], class, link_s[i], link_u[i], name, acptr->serv->by, acptr->serv->user->username, acptr->serv->user->realhost, now - acptr->lasttime); else sendto_one(sptr, rpl_str(RPL_TRACESERVER), me.name, parv[0], class, link_s[i], link_u[i], name, *(acptr->serv->by) ? acptr->serv->by : "*", "*", me.name, now - acptr->lasttime); cnt++; break; case STAT_LOG: sendto_one(sptr, rpl_str(RPL_TRACELOG), me.name, parv[0], LOGFILE, acptr->port); cnt++; break; default: /* ...we actually shouldn't come here... --msa */ sendto_one(sptr, rpl_str(RPL_TRACENEWTYPE), me.name, parv[0], name); cnt++; break; } } /* * Add these lines to summarize the above which can get rather long * and messy when done remotely - Avalon */ if (!IsAnOper(sptr) || !cnt) { if (cnt) return 0; /* let the user have some idea that its at the end of the * trace */ sendto_one(sptr, rpl_str(RPL_TRACESERVER), me.name, parv[0], 0, link_s[me.fd], link_u[me.fd], me.name, "*", "*", me.name); return 0; } for (cltmp = FirstClass(); doall && cltmp; cltmp = NextClass(cltmp)) if (Links(cltmp) > 0) sendto_one(sptr, rpl_str(RPL_TRACECLASS), me.name, parv[0], Class(cltmp), Links(cltmp)); return 0; } /* * Heavily modified from the ircu m_motd by codemastr * Also svsmotd support added */ int m_motd(aClient *cptr, aClient *sptr, int parc, char *parv[]) { aTrecord *ptr; aMotd *temp, *temp2; struct tm *tm = motd_tm; int svsnofile = 0; if (hunt_server(cptr, sptr, ":%s MOTD :%s", 1, parc, parv) != HUNTED_ISME) return 0; #ifndef TLINE_Remote if (!MyConnect(sptr)) { temp = motd; goto playmotd; } #endif for (ptr = tdata; ptr; ptr = ptr->next) { if (!match(ptr->hostmask, cptr->user->realhost)) break; } if (ptr) { temp = ptr->tmotd; tm = ptr->tmotd_tm; } else temp = motd; playmotd: if (temp == NULL) { sendto_one(sptr, err_str(ERR_NOMOTD), me.name, parv[0]); svsnofile = 1; goto svsmotd; } if (tm) { sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name); sendto_one(sptr, ":%s %d %s :- %d/%d/%d %d:%02d", me.name, RPL_MOTD, parv[0], tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year, tm->tm_hour, tm->tm_min); } while (temp) { sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0], temp->line); temp = temp->next; } svsmotd: temp2 = svsmotd; while (temp2) { sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0], temp2->line); temp2 = temp2->next; } if (svsnofile == 0) sendto_one(sptr, rpl_str(RPL_ENDOFMOTD), me.name, parv[0]); return 0; } /* * Modified from comstud by codemastr */ int m_opermotd(aClient *cptr, aClient *sptr, int parc, char *parv[]) { aMotd *temp; if (!IsAnOper(sptr)) return 0; if (opermotd == (aMotd *) NULL) { sendto_one(sptr, err_str(ERR_NOOPERMOTD), me.name, parv[0]); return 0; } sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name); sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0], "\2IRC Operator Message of the Day\2"); temp = opermotd; while (temp) { sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0], temp->line); temp = temp->next; } sendto_one(sptr, rpl_str(RPL_ENDOFMOTD), me.name, parv[0]); return 0; } /* read_tlines * Read info from T:lines into trecords which include the file * timestamp, the hostmask, and the contents of the motd file * -Ghostwolf 7sep97 * Modified for Unreal and to support RULES by codemastr */ void read_tlines() { aConfItem *tmp; aTrecord *temp, *last = NULL; /* Init. to avoid compiler warning */ aMotd *amotd, *arules; /* Free the old trecords and the associated motd contents first */ while (tdata) { last = tdata->next; while (tdata->tmotd) { amotd = tdata->tmotd->next; MyFree(tdata->tmotd); tdata->tmotd = amotd; } /* Clear rules too */ while (tdata->trules) { arules = tdata->trules->next; MyFree(tdata->trules); tdata->trules = arules; } MyFree(tdata); tdata = last; } for (tmp = conf; tmp; tmp = tmp->next) if (tmp->status == CONF_TLINE && tmp->host && tmp->passwd) { temp = (aTrecord *) MyMalloc(sizeof(aTrecord)); if (!temp) outofmemory(); temp->hostmask = tmp->host; temp->tmotd = read_motd(tmp->passwd); temp->trules = read_rules(tmp->name); temp->tmotd_tm = motd_tm; temp->next = NULL; if (!tdata) tdata = temp; else last->next = temp; last = temp; } } /* * A merge from ircu and bahamut, and some extra stuff added by codemastr */ aMotd *read_svsmotd(char *filename) { int fd = open(filename, O_RDONLY); aMotd *temp, *newmotd, *last, *old; char line[82]; char *tmp; int i; if (fd == -1) return NULL; while (svsmotd) { old = svsmotd->next; MyFree(svsmotd); svsmotd = old; } newmotd = last = NULL; (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */ while ((i = dgets(fd, line, sizeof(line) - 1)) > 0) { line[i] = '\0'; if ((tmp = (char *)strchr(line, '\n'))) *tmp = '\0'; if ((tmp = (char *)strchr(line, '\r'))) *tmp = '\0'; temp = (aMotd *) MyMalloc(sizeof(aMotd)); if (!temp) outofmemory(); strcpy(temp->line, line); temp->next = NULL; if (!newmotd) newmotd = temp; else last->next = temp; last = temp; } close(fd); return newmotd; } /* * A merge from ircu and bahamut, and some extra stuff added by codemastr */ aMotd *read_rules(char *filename) { int fd = open(filename, O_RDONLY); aMotd *temp, *newmotd, *last, *old; char line[82]; char *tmp; int i; if (fd == -1) return NULL; /* If it is the default RULES, clear it -- codemastr */ if (!stricmp(filename, RPATH)) { while (rules) { old = rules->next; MyFree(rules); rules = old; } } (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */ newmotd = last = NULL; while ((i = dgets(fd, line, sizeof(line) - 1)) > 0) { line[i] = '\0'; if ((tmp = (char *)strchr(line, '\n'))) *tmp = '\0'; if ((tmp = (char *)strchr(line, '\r'))) *tmp = '\0'; temp = (aMotd *) MyMalloc(sizeof(aMotd)); if (!temp) outofmemory(); strcpy(temp->line, line); temp->next = NULL; if (!newmotd) newmotd = temp; else last->next = temp; last = temp; } close(fd); return newmotd; } /* * A merge from ircu and bahamut, and some extra stuff added by codemastr */ aMotd *read_motd(char *filename) { int fd = open(filename, O_RDONLY); aMotd *temp, *newmotd, *last, *old; struct stat sb; char line[82]; char *tmp; int i; if (fd == -1) return NULL; fstat(fd, &sb); /* If it is the default MOTD, clear it -- codemastr */ if (!stricmp(filename, MPATH)) { while (motd) { old = motd->next; MyFree(motd); motd = old; } /* We also wanna set it's last changed value -- codemastr */ motd_tm = localtime(&sb.st_mtime); } (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */ newmotd = last = NULL; while ((i = dgets(fd, line, 81)) > 0) { line[i] = '\0'; if ((tmp = (char *)strchr(line, '\n'))) *tmp = '\0'; if ((tmp = (char *)strchr(line, '\r'))) *tmp = '\0'; temp = (aMotd *) MyMalloc(sizeof(aMotd)); if (!temp) outofmemory(); strcpy(temp->line, line); temp->next = NULL; if (!newmotd) newmotd = temp; else last->next = temp; last = temp; } close(fd); return newmotd; } /* * A merge from ircu and bahamut, and some extra stuff added by codemastr */ aMotd *read_opermotd(char *filename) { int fd = open(filename, O_RDONLY); aMotd *temp, *newmotd, *last, *old; char line[82]; char *tmp; int i; if (fd == -1) return NULL; while (opermotd) { old = opermotd->next; MyFree(opermotd); opermotd = old; } (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */ newmotd = last = NULL; while ((i = dgets(fd, line, 81)) > 0) { line[i] = '\0'; if ((tmp = (char *)strchr(line, '\n'))) *tmp = '\0'; if ((tmp = (char *)strchr(line, '\r'))) *tmp = '\0'; temp = (aMotd *) MyMalloc(sizeof(aMotd)); if (!temp) outofmemory(); strcpy(temp->line, line); temp->next = NULL; if (!newmotd) newmotd = temp; else last->next = temp; last = temp; } close(fd); return newmotd; } /* * A merge from ircu and bahamut, and some extra stuff added by codemastr */ aMotd *read_botmotd(char *filename) { int fd = open(filename, O_RDONLY); aMotd *temp, *newmotd, *last, *old; char line[82]; char *tmp; int i; if (fd == -1) return NULL; while (botmotd) { old = botmotd->next; MyFree(botmotd); botmotd = old; } (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */ newmotd = last = NULL; while (i = dgets(fd, line, 81) > 0) { line[i] = '\0'; if ((tmp = (char *)strchr(line, '\n'))) *tmp = '\0'; if ((tmp = (char *)strchr(line, '\r'))) *tmp = '\0'; temp = (aMotd *) MyMalloc(sizeof(aMotd)); if (!temp) outofmemory(); strcpy(temp->line, line); temp->next = NULL; if (!newmotd) newmotd = temp; else last->next = temp; last = temp; } close(fd); return newmotd; } /* * Modified from comstud by codemastr */ int m_botmotd(aClient *cptr, aClient *sptr, int parc, char *parv[]) { aMotd *temp; if (hunt_server(cptr, sptr, ":%s BOTMOTD :%s", 1, parc, parv) != HUNTED_ISME) return 0; if (botmotd == (aMotd *) NULL) { sendto_one(sptr, ":%s NOTICE AUTH :BOTMOTD File not found", me.name); return 0; } sendto_one(sptr, ":%s NOTICE AUTH :- %s Bot Message of the Day - ", me.name, me.name); temp = botmotd; while (temp) { sendto_one(sptr, ":%s NOTICE AUTH :- %s", me.name, temp->line); temp = temp->next; } sendto_one(sptr, ":%s NOTICE AUTH :End of /BOTMOTD command.", me.name); return 0; } /* * Heavily modified from the ircu m_motd by codemastr * Also svsmotd support added */ int m_rules(aClient *cptr, aClient *sptr, int parc, char *parv[]) { aTrecord *ptr; aMotd *temp; if (hunt_server(cptr, sptr, ":%s RULES :%s", 1, parc, parv) != HUNTED_ISME) return 0; #ifndef TLINE_Remote if (!MyConnect(sptr)) { temp = rules; goto playrules; } #endif for (ptr = tdata; ptr; ptr = ptr->next) { if (!match(ptr->hostmask, cptr->user->realhost)) break; } if (ptr) { temp = ptr->trules; } else temp = rules; playrules: if (temp == NULL) { sendto_one(sptr, err_str(ERR_NORULES), me.name, parv[0]); return 0; } sendto_one(sptr, rpl_str(RPL_RULESSTART), me.name, parv[0], me.name); while (temp) { sendto_one(sptr, rpl_str(RPL_RULES), me.name, parv[0], temp->line); temp = temp->next; } sendto_one(sptr, rpl_str(RPL_ENDOFRULES), me.name, parv[0]); return 0; } /* ** m_close - added by Darren Reed Jul 13 1992. */ int m_close(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { aClient *acptr; int i; int closed = 0; if (!MyOper(sptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } for (i = highest_fd; i; i--) { if (!(acptr = local[i])) continue; if (!IsUnknown(acptr) && !IsConnecting(acptr) && !IsHandshake(acptr)) continue; sendto_one(sptr, rpl_str(RPL_CLOSING), me.name, parv[0], get_client_name(acptr, TRUE), acptr->status); (void)exit_client(acptr, acptr, acptr, "Oper Closing"); closed++; } sendto_one(sptr, rpl_str(RPL_CLOSEEND), me.name, parv[0], closed); sendto_realops("%s!%s@%s closed %d unknown connections", sptr->name, sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost, closed); IRCstats.unknown = 0; return 0; } /* m_die, this terminates the server, and it intentionally does not * have a reason. If you use it you should first do a GLOBOPS and * then a server notice to let everyone know what is going down... */ int m_die(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { aClient *acptr; int i; char *pass = NULL, *encr; #ifdef CRYPT_XLINE_PASSWORD char salt[3]; extern char *crypt(); #endif if (!MyClient(sptr) || !OPCanDie(sptr)) { sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]); return 0; } if ((pass = find_diepass())) /* See if we have and DIE/RESTART password */ { if (parc < 2) /* And if so, require a password :) */ { sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "DIE"); return 0; } #ifdef CRYPT_XLINE_PASSWORD salt[0] = pass[0]; salt[1] = pass[1]; salt[3] = '\0'; encr = crypt(parv[1], salt); #else encr = parv[1]; #endif if (strcmp(pass,encr)) { sendto_one(sptr, err_str(ERR_PASSWDMISMATCH), me.name, parv[0]); return 0; } } /* Let the +s know what is going on */ sendto_ops("Server Terminating by request of %s", parv[0]); for (i = 0; i <= highest_fd; i++) { if (!(acptr = local[i])) continue; if (IsClient(acptr)) sendto_one(acptr, ":%s NOTICE %s :Server Terminating. %s", me.name, acptr->name, get_client_name(sptr, TRUE)); else if (IsServer(acptr)) sendto_one(acptr, ":%s ERROR :Terminated by %s", me.name, get_client_name(sptr, TRUE)); } (void)s_die(); return 0; } char servername[128][128]; int server_usercount[128]; int numservers = 0; /* * New /MAP format -Potvin * dump_map function. */ void dump_map(cptr, server, mask, prompt_length, length) aClient *cptr, *server; char *mask; int prompt_length; int length; { static char prompt[64]; char *p = &prompt[prompt_length]; int cnt = 0, local = 0; aClient *acptr; *p = '\0'; if (prompt_length > 60) sendto_one(cptr, rpl_str(RPL_MAPMORE), me.name, cptr->name, prompt, server->name); else { for (acptr = client; acptr; acptr = acptr->next) { if (IsPerson(acptr)) { ++cnt; /* == */ if (!strcmp(acptr->user->server, server->name)) ++local; } } sendto_one(cptr, rpl_str(RPL_MAP), me.name, cptr->name, prompt, length, server->name, local, (local * 100) / cnt); cnt = 0; } if (prompt_length > 0) { p[-1] = ' '; if (p[-2] == '`') p[-2] = ' '; } if (prompt_length > 60) return; strcpy(p, "|-"); for (acptr = client; acptr; acptr = acptr->next) { if (HIDE_ULINES == 1) { if (!IsServer(acptr) || strcmp(acptr->serv->up, server->name)) continue; if (IsULine(acptr, acptr) && !IsAnOper(cptr)) continue; } if (match(mask, acptr->name)) acptr->flags &= ~FLAGS_MAP; else { acptr->flags |= FLAGS_MAP; cnt++; } } for (acptr = client; acptr; acptr = acptr->next) { if (!(acptr->flags & FLAGS_MAP) || /* != */ !IsServer(acptr) || strcmp(acptr->serv->up, server->name)) continue; if (HIDE_ULINES == 1) { if (IsULine(acptr,acptr) && !IsAnOper(cptr)) continue; } if (--cnt == 0) *p = '`'; dump_map(cptr, acptr, mask, prompt_length + 2, length - 2); } if (prompt_length > 0) p[-1] = '-'; } /* ** New /MAP format. -Potvin ** m_map (NEW) ** ** parv[0] = sender prefix ** parv[1] = server mask **/ int m_map(cptr, sptr, parc, parv) aClient *cptr, *sptr; int parc; char *parv[]; { aClient *acptr; int longest = strlen(me.name); if (parc < 2) parv[1] = "*"; for (acptr = client; acptr; acptr = acptr->next) if (IsServer(acptr) && (strlen(acptr->name) + acptr->hopcount * 2) > longest) longest = strlen(acptr->name) + acptr->hopcount * 2; if (longest > 60) longest = 60; longest += 2; dump_map(sptr, &me, "*", 0, longest); sendto_one(sptr, rpl_str(RPL_MAPEND), me.name, parv[0]); return 0; } #ifdef _WIN32 /* * Added to let the local console shutdown the server without just * calling exit(-1), in Windows mode. -Cabal95 */ int localdie(void) { aClient *acptr; int i; for (i = 0; i <= highest_fd; i++) { if (!(acptr = local[i])) continue; if (IsClient(acptr)) sendto_one(acptr, ":%s NOTICE %s :Server Terminated by local console", me.name, acptr->name); else if (IsServer(acptr)) sendto_one(acptr, ":%s ERROR :Terminated by local console", me.name); } (void)s_die(); return 0; } #endif