/* * m_gline - user message handler * * parv[0] = Sender prefix * parv[1] = [<server name>] * */ int m_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { if (feature_bool(FEAT_HIS_USERGLINE)) return send_reply(sptr, ERR_DISABLED, "GLINE"); if (parc < 2) return send_reply(sptr, ERR_NOSUCHGLINE, ""); return gline_list(sptr, parv[1]); }
/* * m_rules - generic message handler * * parv[0] - sender prefix * parv[1] - servername */ int m_rules(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { if (!feature_bool(FEAT_RULES)) return send_reply(sptr, ERR_DISABLED, "RULES"); if (hunt_server_cmd(sptr, CMD_RULES, cptr, feature_int(FEAT_HIS_REMOTE), "%C", 1, parc, parv) != HUNTED_ISME) return 0; return motd_send_type(sptr, MOTD_RULES); }
void start_auth(struct Client* client) { struct AuthRequest* auth = 0; assert(0 != client); auth = make_auth_request(client); assert(0 != auth); Debug((DEBUG_INFO, "Beginning auth request on client %p", client)); if (!feature_bool(FEAT_NODNS)) { if (LOOPBACK == inet_netof(cli_ip(client))) strcpy(cli_sockhost(client), cli_name(&me)); else { struct DNSQuery query; query.vptr = auth; query.callback = auth_dns_callback; if (IsUserPort(auth->client)) sendheader(client, REPORT_DO_DNS); cli_dns_reply(client) = gethost_byaddr((const char*) &(cli_ip(client)), &query); if (cli_dns_reply(client)) { ++(cli_dns_reply(client))->ref_count; ircd_strncpy(cli_sockhost(client), cli_dns_reply(client)->hp->h_name, HOSTLEN); if (IsUserPort(auth->client)) sendheader(client, REPORT_FIN_DNSC); Debug((DEBUG_LIST, "DNS entry for %p was cached", auth->client)); } else SetDNSPending(auth); } } if (start_auth_query(auth)) { Debug((DEBUG_LIST, "identd query for %p initiated successfully", auth->client)); link_auth_request(auth, &AuthPollList); } else if (IsDNSPending(auth)) { Debug((DEBUG_LIST, "identd query for %p not initiated successfully; " "waiting on DNS", auth->client)); link_auth_request(auth, &AuthIncompleteList); } else { Debug((DEBUG_LIST, "identd query for %p not initiated successfully; " "no DNS pending; releasing immediately", auth->client)); free_auth_request(auth); release_auth_client(client); } }
/** Apply GeoIP country data to a client. * @param[in] cptr Client to apply GeoIP country data to. */ void geoip_apply(struct Client* cptr) { #ifdef USE_GEOIP int gcid = 0; #endif /* USE_GEOIP */ #ifdef USE_GEOIP_GL GeoIPLookup gl; #endif /* USE_GEOIP_GL */ if (!feature_bool(FEAT_GEOIP_ENABLE)) return; if (!(cptr)) return; #ifdef USE_GEOIP if (irc_in_addr_is_ipv4(&cli_ip(cptr))) { /* User is IPv4 so use gi4. */ if (gi4 != NULL) #ifdef USE_GEOIP_GL gcid = GeoIP_id_by_addr_gl(gi4, cli_sock_ip(cptr), &gl); #else gcid = GeoIP_id_by_addr(gi4, cli_sock_ip(cptr)); #endif /* USE_GEOIP_GL */ } else { /* User is IPv6 so use gi6. */ if (gi6 != NULL) #ifdef USE_GEOIP_GL gcid = GeoIP_id_by_addr_v6_gl(gi6, cli_sock_ip(cptr), &gl); #else gcid = GeoIP_id_by_addr_v6(gi6, cli_sock_ip(cptr)); #endif /* USE_GEOIP_GL */ } #endif /* USE_GEOIP */ #ifdef USE_GEOIP if (gcid == 0) { #endif /* USE_GEOIP */ ircd_strncpy((char *)&cli_countrycode(cptr), "--", 3); ircd_strncpy((char *)&cli_countryname(cptr), "Unknown", 8); ircd_strncpy((char *)&cli_continentcode(cptr), "--", 3); ircd_strncpy((char *)&cli_continentname(cptr), "Unknown", 8); #ifdef USE_GEOIP } else { ircd_strncpy((char *)&cli_countrycode(cptr), GeoIP_code_by_id(gcid), 3); ircd_strncpy((char *)&cli_countryname(cptr), GeoIP_name_by_id(gcid), 256); ircd_strncpy((char *)&cli_continentcode(cptr), GeoIP_continent_by_id(gcid), 3); ircd_strncpy((char *)&cli_continentname(cptr), geoip_continent_name_by_code(GeoIP_continent_by_id(gcid)), 256); } #endif /* USE_GEOIP */ SetGeoIP(cptr); }
int ms_rehash(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { int flag = 0; if ((parc > 2) && (hunt_server_cmd(sptr, CMD_REHASH, cptr, 1, "%s %C", 2, parc, parv) != HUNTED_ISME)) return 0; /* OK, the message has been forwarded, but before we can act... */ if (!feature_bool(FEAT_NETWORK_REHASH)) return 0; if (parc > 1) { /* special processing */ if (parv[1][1] == '\0') { /* one character server name */ if (*parv[1] == 'm') { send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Flushing MOTD cache"); motd_recache(); /* flush MOTD cache */ return 0; } else if (*parv[1] == 'l') { send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Reopening log files"); log_reopen(); /* reopen log files */ return 0; } else if (*parv[1] == 'a') { send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Restarting IAuth"); auth_restart(); /* Restart IAuth program */ return 0; #ifdef USE_SSL } else if (*parv[1] == 's') { send_reply(sptr, SND_EXPLICIT | RPL_REHASHING, ":Reloading SSL certificates"); ssl_reinit(); return 0; #endif } else if (*parv[1] == 'q') flag = 2; } /* * Maybe the user wants to rehash another server with no parameters. * NOTE: Here we assume that there are no servers named * 'm', 'l', 's', or 'q'. */ else if ((parc == 2) && (hunt_server_cmd(sptr, CMD_REHASH, cptr, 1, "%C", 1, parc, parv) != HUNTED_ISME)) return 0; } send_reply(sptr, RPL_REHASHING, configfile); sendto_opmask_butone(0, SNO_OLDSNO, "%C [%s] is remotely rehashing Server config file", sptr, cli_name(cli_user(sptr)->server)); log_write(LS_SYSTEM, L_INFO, 0, "Remote REHASH From %#C [%s]", sptr, cli_name(cli_user(sptr)->server)); return rehash(cptr, flag); }
/** Handle an OPMODE message from an operator. * * \a parv has the same elements as for m_mode(). * * See @ref m_functions for discussion of the arguments. * @param[in] cptr Client that sent us the message. * @param[in] sptr Original source of message. * @param[in] parc Number of arguments. * @param[in] parv Argument vector. */ int mo_opmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Channel *chptr = 0; struct ModeBuf mbuf; char *chname; const char *qreason; int force = 0; if (!feature_bool(FEAT_CONFIG_OPERCMDS)) return send_reply(sptr, ERR_DISABLED, "OPMODE"); if (parc < 3) return need_more_params(sptr, "OPMODE"); chname = parv[1]; if (*chname == '!') { chname++; if (!HasPriv(sptr, IsLocalChannel(chname) ? PRIV_FORCE_LOCAL_OPMODE : PRIV_FORCE_OPMODE)) return send_reply(sptr, ERR_NOPRIVILEGES); force = 1; } if (!HasPriv(sptr, IsLocalChannel(chname) ? PRIV_LOCAL_OPMODE : PRIV_OPMODE)) return send_reply(sptr, ERR_NOPRIVILEGES); if (!IsChannelName(chname) || !(chptr = FindChannel(chname))) return send_reply(sptr, ERR_NOSUCHCHANNEL, chname); if (!force && (qreason = find_quarantine(chptr->chname))) return send_reply(sptr, ERR_QUARANTINED, chptr->chname, qreason); modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send MODE to channel */ MODEBUF_DEST_SERVER | /* And to server */ MODEBUF_DEST_OPMODE | /* Use OPMODE */ MODEBUF_DEST_HACK4 | /* Generate a HACK(4) notice */ MODEBUF_DEST_LOG)); /* Log the mode changes to OPATH */ mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_SET | /* set the modes on the channel */ MODE_PARSE_FORCE), /* And force them to be accepted */ NULL); modebuf_flush(&mbuf); /* flush the modes */ return 0; }
/** Handle a STATS message from some connection. * * \a parv has the following elements: * \li \a parv[1] is the statistics selector * \li \a parv[2] (optional) is server to query * \li \a parv[3] (optional) is a mask to filter the results * * If \a parv[1] is "l" (or "links"), \a parv[3] is a mask of servers. * If \a parv[1] is "p" (or "P" or "ports"), \a parv[3] is a mask of * ports. If \a parv[1] is "k" (or "K" or "klines" or "i" or "I" or * "access"), \a parv[3] is a hostname with optional username@ prefix * (for opers, hostmasks are allowed). * * See @ref m_functions for discussion of the arguments. * @param[in] cptr Client that sent us the message. * @param[in] sptr Original source of message. * @param[in] parc Number of arguments. * @param[in] parv Argument vector. */ int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { const struct StatDesc *sd; char *param; /* If we didn't find a descriptor, send them help */ if ((parc < 2) || !(sd = stats_find(parv[1]))) parv[1] = "*", sd = stats_find("*"); assert(sd != 0); /* Check whether the client can issue this command. If source is * not privileged (server or an operator), then the STAT_FLAG_OPERONLY * flag must not be set, and if the STAT_FLAG_OPERFEAT flag is set, * then the feature given by sd->sd_control must be off. * * This checks cptr rather than sptr so that a local oper may send * /stats queries to other servers. */ if (!IsPrivileged(cptr) && ((sd->sd_flags & STAT_FLAG_OPERONLY) || ((sd->sd_flags & STAT_FLAG_OPERFEAT) && feature_bool(sd->sd_control)))) return send_reply(sptr, ERR_NOPRIVILEGES); /* Check for extra parameter */ if ((sd->sd_flags & STAT_FLAG_VARPARAM) && parc > 3 && !EmptyString(parv[3])) param = parv[3]; else param = NULL; /* Ok, track down who's supposed to get this... */ if (hunt_server_cmd(sptr, CMD_STATS, cptr, feature_int(FEAT_HIS_REMOTE), param ? "%s %C :%s" : "%s :%C", 2, parc, parv) != HUNTED_ISME) return 0; /* Someone else--cool :) */ /* Check if they are a local user */ if ((sd->sd_flags & STAT_FLAG_LOCONLY) && !MyUser(sptr)) return send_reply(sptr, ERR_NOPRIVILEGES); assert(sd->sd_func != 0); /* Ok, dispatch the stats function */ (*sd->sd_func)(sptr, sd, param); /* Done sending them the stats */ return send_reply(sptr, RPL_ENDOFSTATS, parv[1]); }
/* * m_map - generic message handler * -- by Run * * parv[0] = sender prefix * parv[1] = server mask */ int m_map(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { void *args[1]; if (feature_bool(FEAT_HIS_MAP) && !IsAnOper(sptr)) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s %s", sptr, "/MAP has been disabled; visit", feature_str(FEAT_HIS_URLSERVERS)); return 0; } if (parc < 2) parv[1] = "*"; args[0] = sptr; if (feature_bool(FEAT_HIS_MAP_SCRAMBLED) && !IsAnOper(sptr)) map_dump_head_in_sand(sptr, map_reply, args); else map_dump(&me, parv[1], 0, map_reply, args); send_reply(sptr, RPL_MAPEND); return 0; }
/** Set EXCEPTS, MAXEXCEPTS, and CHANMODES based on if HALFOPS are enabled or not */ static void set_isupport_excepts(void) { char imaxlist[BUFSIZE] = ""; if (feature_bool(FEAT_EXCEPTS)) { add_isupport_s("EXCEPTS", "e"); add_isupport_i("MAXEXCEPTS", feature_int(FEAT_MAXEXCEPTS)); } else { del_isupport("EXCEPTS"); del_isupport("MAXEXCEPTS"); } add_isupport_s("CHANMODES", feature_bool(FEAT_EXCEPTS) ? "be,k,lL,acimnprstzCMNOQSTZ" : "b,k,lL,acimnprstzCMNOQSTZ"); strcat(imaxlist, "b:"); strcat(imaxlist, itoa(feature_int(FEAT_MAXBANS))); if (feature_bool(FEAT_EXCEPTS)) { strcat(imaxlist, ",e:"); strcat(imaxlist, itoa(feature_int(FEAT_MAXEXCEPTS))); } add_isupport_s("MAXLIST", imaxlist); }
/** Deactivate a jupe. * @param[in] cptr Local client that sent us the jupe. * @param[in] sptr Originator of the jupe. * @param[in] jupe Jupe to deactivate. * @param[in] lastmod New timestamp for last modification of the jupe. * @param[in] flags Flags to set on the jupe. * @return Zero. */ int jupe_deactivate(struct Client *cptr, struct Client *sptr, struct Jupe *jupe, time_t lastmod, unsigned int flags) { unsigned int saveflags = 0; assert(0 != jupe); saveflags = jupe->ju_flags; if (!JupeIsLocal(jupe)) { if (flags & JUPE_LOCAL) jupe->ju_flags |= JUPE_LDEACT; else { jupe->ju_flags &= ~JUPE_ACTIVE; if (jupe->ju_lastmod >= lastmod) /* force lastmod to increase */ jupe->ju_lastmod++; else jupe->ju_lastmod = lastmod; } if ((saveflags & JUPE_ACTMASK) != JUPE_ACTIVE) return 0; /* was inactive to begin with */ } /* Inform ops and log it */ sendto_opmask_butone(0, SNO_NETWORK, "%s %s JUPE for %s, expiring at %Tu: " "%s", (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? cli_name(sptr) : cli_name((cli_user(sptr))->server), JupeIsLocal(jupe) ? "removing local" : "deactivating", jupe->ju_server, jupe->ju_expire + TSoffset, jupe->ju_reason); log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE, "%#C %s JUPE for %s, expiring at %Tu: %s", sptr, JupeIsLocal(jupe) ? "removing local" : "deactivating", jupe->ju_server, jupe->ju_expire + TSoffset, jupe->ju_reason); if (JupeIsLocal(jupe)) jupe_free(jupe); else if (!(flags & JUPE_LOCAL)) /* don't propagate local changes */ propagate_jupe(cptr, sptr, jupe); return 0; }
/* * m_map - generic message handler * -- by Run * * parv[0] = sender prefix * parv[1] = server mask */ int m_map(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { if (feature_bool(FEAT_HIS_MAP) && !IsAnOper(sptr)) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s %s", sptr, "/MAP has been disabled; visit", feature_str(FEAT_HIS_URLSERVERS)); return 0; } if (parc < 2) parv[1] = "*"; dump_map(sptr, &me, parv[1], 0); send_reply(sptr, RPL_MAPEND); return 0; }
/** Set MAXBANS, self explanatory */ static void set_isupport_maxbans(void) { char imaxlist[BUFSIZE] = ""; add_isupport_i("MAXBANS", feature_int(FEAT_MAXBANS)); strcat(imaxlist, "b:"); strcat(imaxlist, itoa(feature_int(FEAT_MAXBANS))); if (feature_bool(FEAT_EXCEPTS)) { strcat(imaxlist, ",e:"); strcat(imaxlist, itoa(feature_int(FEAT_MAXEXCEPTS))); } add_isupport_s("MAXLIST", imaxlist); }
/** Destroy a local Z-line. * @param[in] cptr Peer that gave us the message. * @param[in] sptr Client that initiated the destruction. * @param[in] zline Z-line to destroy. * @return Zero. */ int zline_destroy(struct Client *cptr, struct Client *sptr, struct Zline *zline) { assert(zline); assert(ZlineIsLocal(zline)); /* Inform ops and log it */ sendto_opmask_butone(0, SNO_GLINE, "%s removing local ZLINE for %s", (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? cli_name(sptr) : cli_name((cli_user(sptr))->server), zline->zl_mask); log_write(LS_GLINE, L_INFO, LOG_NOSNOTICE, "%#C removing local ZLINE for %s", sptr, zline->zl_mask); zline_free(zline); /* get rid of the Z-line */ return 0; /* convenience return */ }
/* * m_privmsg - generic message handler */ int m_privmsg(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char* name; char* server; int i; int count; char* vector[MAXTARGETS]; assert(0 != cptr); assert(cptr == sptr); assert(0 != cli_user(sptr)); ClrFlag(sptr, FLAG_TS8); if (feature_bool(FEAT_IDLE_FROM_MSG)) cli_user(sptr)->last = CurrentTime; if (parc < 2 || EmptyString(parv[1])) return send_reply(sptr, ERR_NORECIPIENT, MSG_PRIVATE); if (parc < 3 || EmptyString(parv[parc - 1])) return send_reply(sptr, ERR_NOTEXTTOSEND); count = unique_name_vector(parv[1], ',', vector, MAXTARGETS); for (i = 0; i < count; ++i) { name = vector[i]; /* * channel msg? */ if (IsChannelPrefix(*name)) { relay_channel_message(sptr, name, parv[parc - 1]); } /* * we have to check for the '@' at least once no matter what we do * handle it first so we don't have to do it twice */ else if ((server = strchr(name, '@'))) relay_directed_message(sptr, name, server, parv[parc - 1]); else relay_private_message(sptr, name, parv[parc - 1]); } return 0; }
/** Activate a currently inactive Z-line. * @param[in] cptr Peer that told us to activate the Z-line. * @param[in] sptr Client that originally thought it was a good idea. * @param[in] zline Z-line to activate. * @param[in] lastmod New value for last modification timestamp. * @param[in] flags 0 if the activation should be propagated, ZLINE_LOCAL if not. * @return Zero, unless \a sptr had a death wish (in which case CPTR_KILLED). */ int zline_activate(struct Client *cptr, struct Client *sptr, struct Zline *zline, time_t lastmod, unsigned int flags) { unsigned int saveflags = 0; assert(0 != zline); saveflags = zline->zl_flags; if (flags & ZLINE_LOCAL) zline->zl_flags &= ~ZLINE_LDEACT; else { zline->zl_flags |= ZLINE_ACTIVE; if (zline->zl_lastmod) { if (zline->zl_lastmod >= lastmod) /* force lastmod to increase */ zline->zl_lastmod++; else zline->zl_lastmod = lastmod; } } if ((saveflags & ZLINE_ACTMASK) == ZLINE_ACTIVE) return 0; /* was active to begin with */ /* Inform ops and log it */ sendto_opmask_butone(0, SNO_GLINE, "%s activating global ZLINE for %s, " "expiring at %Tu: %s", (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? cli_name(sptr) : cli_name((cli_user(sptr))->server), zline->zl_mask, zline->zl_expire, zline->zl_reason); log_write(LS_GLINE, L_INFO, LOG_NOSNOTICE, "%#C activating global ZLINE for %s, expiring at %Tu: %s", sptr, zline->zl_mask, zline->zl_expire, zline->zl_reason); if (!(flags & ZLINE_LOCAL)) /* don't propagate local changes */ zline_propagate(cptr, sptr, zline); return do_zline(cptr, sptr, zline); }
/** Set a channel topic or report an error. * @param[in] sptr Original topic setter. * @param[in] cptr Neighbor that sent the topic message. * @param[in] chptr Channel to set topic on. * @param[in] topic New topic. * @param[in] ts Timestamp that topic was set (0 for current time). */ static void do_settopic(struct Client *sptr, struct Client *cptr, struct Channel *chptr, char *topic, time_t ts) { struct Client *from; int newtopic; if (feature_bool(FEAT_HIS_BANWHO) && IsServer(sptr)) from = &his; else from = sptr; /* Note if this is just a refresh of an old topic, and don't * send it to all the clients to save bandwidth. We still send * it to other servers as they may have split and lost the topic. */ newtopic=ircd_strncmp(chptr->topic,topic,TOPICLEN)!=0; /* setting a topic */ ircd_strncpy(chptr->topic, topic, TOPICLEN); ircd_strncpy(chptr->topic_nick, cli_name(from), NICKLEN); chptr->topic_time = ts ? ts : TStime(); /* Fixed in 2.10.11: Don't propagate local topics */ if (!IsLocalChannel(chptr->chname)) sendcmdto_serv(sptr, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr, chptr->creationtime, chptr->topic_time, chptr->topic); if (newtopic) { struct Membership *member; /* If the member is delayed-join, show them. */ member = find_channel_member(sptr, chptr); if (member && IsDelayedJoin(member)) RevealDelayedJoin(member); sendcmdto_channel(from, CMD_TOPIC, chptr, NULL, SKIP_SERVERS, "%H :%s", chptr, chptr->topic); } /* if this is the same topic as before we send it to the person that * set it (so they knew it went through ok), but don't bother sending * it to everyone else on the channel to save bandwidth */ else if (MyUser(sptr)) sendcmdto_one(sptr, CMD_TOPIC, sptr, "%H :%s", chptr, chptr->topic); }
/** Add a new server jupe. * @param[in] cptr Local client that sent us the jupe. * @param[in] sptr Originator of the jupe. * @param[in] server Server name to jupe. * @param[in] reason Reason for the jupe. * @param[in] expire Jupe duration in seconds. * @param[in] lastmod Last modification timestamp (or NULL). * @param[in] flags Flags to set on jupe. * @return Zero, unless the jupe causes \a cptr to be SQUIT, in which * case CPTR_KILLED. */ int jupe_add(struct Client *cptr, struct Client *sptr, char *server, char *reason, time_t expire, time_t lastmod, unsigned int flags) { struct Jupe *ajupe; assert(0 != server); assert(0 != reason); /* * You cannot set a negative (or zero) expire time, nor can you set an * expiration time for greater than JUPE_MAX_EXPIRE. */ if (expire <= 0 || expire > JUPE_MAX_EXPIRE) { if (!IsServer(cptr) && MyConnect(cptr)) send_reply(cptr, ERR_BADEXPIRE, expire); return 0; } expire += CurrentTime; /* convert from lifetime to timestamp */ /* Inform ops and log it */ sendto_opmask_butone(0, SNO_NETWORK, "%s adding %sJUPE for %s, expiring at " "%Tu: %s", (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? cli_name(sptr) : cli_name((cli_user(sptr))->server), flags & JUPE_LOCAL ? "local " : "", server, expire + TSoffset, reason); log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE, "%#C adding %sJUPE for %s, expiring at %Tu: %s", sptr, flags & JUPE_LOCAL ? "local " : "", server, expire + TSoffset, reason); /* make the jupe */ ajupe = make_jupe(server, reason, expire, lastmod, flags); propagate_jupe(cptr, sptr, ajupe); return do_jupe(cptr, sptr, ajupe); /* remove server if necessary */ }
/** Handle an update to FEAT_GEOIP_IPV6_FILE. */ void geoip_handle_ipv6_file(void) { if (!feature_bool(FEAT_GEOIP_ENABLE)) return; #ifdef USE_GEOIP if (gi6 != NULL) GeoIP_delete(gi6); gi6 = NULL; /* Load IPv6 GeoIP database */ if (feature_str(FEAT_GEOIP_IPV6_FILE)) { gi6 = GeoIP_open(feature_str(FEAT_GEOIP_IPV6_FILE), GEOIP_STANDARD); } /* Try to load GeoIPv6.dat from lib/ if FEAT_GEOIP_IPV6_FILE was not loaded. */ if (gi6 == NULL) gi6 = GeoIP_open_type(GEOIP_COUNTRY_EDITION_V6, GEOIP_STANDARD); #endif /* USE_GEOIP */ }
/* * mo_clearmode - oper message handler * * parv[0] = Send prefix * parv[1] = Channel name * parv[2] = Control string */ int mo_clearmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Channel *chptr; char *control = "ovpsmikbl"; /* default control string */ const char *chname, *qreason; int force = 0; if (!feature_bool(FEAT_CONFIG_OPERCMDS)) return send_reply(sptr, ERR_DISABLED, "CLEARMODE"); if (parc < 2) return need_more_params(sptr, "CLEARMODE"); if (parc > 2) control = parv[2]; chname = parv[1]; if (*chname == '!') { chname++; if (!HasPriv(sptr, IsLocalChannel(chname) ? PRIV_FORCE_LOCAL_OPMODE : PRIV_FORCE_OPMODE)) return send_reply(sptr, ERR_NOPRIVILEGES); force = 1; } if (!HasPriv(sptr, IsLocalChannel(chname) ? PRIV_LOCAL_OPMODE : PRIV_OPMODE)) return send_reply(sptr, ERR_NOPRIVILEGES); if (('#' != *chname && '&' != *chname) || !(chptr = FindChannel(chname))) return send_reply(sptr, ERR_NOSUCHCHANNEL, chname); if (!force && (qreason = find_quarantine(chptr->chname))) return send_reply(sptr, ERR_QUARANTINED, chptr->chname, qreason); return do_clearmode(cptr, sptr, chptr, control); }
/* * m_oper - generic message handler */ int m_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct ConfItem* aconf; char* name; char* password; assert(0 != cptr); assert(cptr == sptr); if ((parc > 3) && feature_bool(FEAT_REMOTE_OPER)) { struct Client *srv; if (!string_has_wildcards(parv[1])) srv = FindServer(parv[1]); else srv = find_match_server(parv[1]); if (!srv) return send_reply(sptr, ERR_NOOPERHOST); if (IsMe(srv)) { parv[1] = parv[2]; parv[2] = parv[3]; } else { sendcmdto_one(sptr, CMD_OPER, srv, "%C %s %s", srv, parv[2], parv[3]); return 0; } } name = parc > 1 ? parv[1] : 0; password = parc > 2 ? parv[2] : 0; if (EmptyString(name) || EmptyString(password)) return need_more_params(sptr, "OPER"); if (can_oper(cptr, sptr, name, password, &aconf)) do_oper(cptr, sptr, aconf); return 0; }
/* * m_links - generic message handler * * 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(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char *mask; struct Client *acptr; if (feature_bool(FEAT_HIS_LINKS) && !IsAnOper(sptr)) { send_reply(sptr, RPL_ENDOFLINKS, parc < 2 ? "*" : parv[1]); sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s %s", sptr, "/LINKS has been disabled, from CFV-165. Visit ", feature_str(FEAT_HIS_URLSERVERS)); return 0; } if (parc > 2) { if (hunt_server_cmd(sptr, CMD_LINKS, cptr, 1, "%C :%s", 1, parc, parv) != HUNTED_ISME) return 0; mask = parv[2]; } else mask = parc < 2 ? 0 : parv[1]; for (acptr = GlobalClientList, collapse(mask); acptr; acptr = cli_next(acptr)) { if (!IsServer(acptr) && !IsMe(acptr)) continue; if (!BadPtr(mask) && match(mask, cli_name(acptr))) continue; send_reply(sptr, RPL_LINKS, cli_name(acptr), cli_name(cli_serv(acptr)->up), cli_hopcount(acptr), cli_serv(acptr)->prot, ((cli_info(acptr))[0] ? cli_info(acptr) : "(Unknown Location)")); } send_reply(sptr, RPL_ENDOFLINKS, BadPtr(mask) ? "*" : mask); return 0; }
static void stats_dbs(struct Client *sptr, struct StatDesc *sd, int stat, char *param) { char db; char buffer[1024]; if (!feature_bool(FEAT_BDD_SUPPORT)) return; for (db=BDD_START;db<=BDD_END;db++) { if (tabla_es_residente(db) || tabla_registros[db][0]) { if (tabla_es_residente(db)) { if (!tabla_es_corrupta(db)) sprintf(buffer, "S=%09lu R=%09lu", tabla_registros[db][0], tabla_registros[db][1]); else sprintf(buffer, "S=%09lu TABLA_CORRUPTA", tabla_registros[db][0]); } else { sprintf(buffer, "S=%09lu NO_RESIDENTE", tabla_registros[db][0]); } send_reply(sptr, RPL_STATSDEBUG, db, buffer); } } for (db=BDD2_START;db<=BDD2_END;db++) { if (tabla_es_residente(db) || tabla_registros[db][0]) { if (tabla_es_residente(db)) { if (!tabla_es_corrupta(db)) sprintf(buffer, "S=%09lu R=%09lu", tabla_registros[db][0], tabla_registros[db][1]); else sprintf(buffer, "S=%09lu TABLA_CORRUPTA", tabla_registros[db][0]); } else { sprintf(buffer, "S=%09lu NO_RESIDENTE", tabla_registros[db][0]); } send_reply(sptr, RPL_STATSDEBUG, db, buffer); } } }
/** Update server start timestamps and TS offsets. * @param[in] cptr Server that just connected. * @param[in] timestamp Current time according to \a cptr. * @param[in] start_timestamp Time that \a cptr started. * @param[in] recv_time Current time as we know it. */ static void check_start_timestamp(struct Client *cptr, time_t timestamp, time_t start_timestamp, time_t recv_time) { Debug((DEBUG_DEBUG, "My start time: %Tu; other's start time: %Tu", cli_serv(&me)->timestamp, start_timestamp)); Debug((DEBUG_DEBUG, "Receive time: %Tu; received timestamp: %Tu; " "difference %ld", recv_time, timestamp, timestamp - recv_time)); if (feature_bool(FEAT_RELIABLE_CLOCK)) { if (start_timestamp < cli_serv(&me)->timestamp) cli_serv(&me)->timestamp = start_timestamp; if (IsUnknown(cptr)) cli_serv(cptr)->timestamp = TStime(); } else if (start_timestamp < cli_serv(&me)->timestamp) { sendto_opmask_butone(0, SNO_OLDSNO, "got earlier start time: " "%Tu < %Tu", start_timestamp, cli_serv(&me)->timestamp); cli_serv(&me)->timestamp = start_timestamp; TSoffset += timestamp - recv_time; sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d", (int)(timestamp - recv_time)); } else if ((start_timestamp > cli_serv(&me)->timestamp) && IsUnknown(cptr)) { cli_serv(cptr)->timestamp = TStime(); } else if (timestamp != recv_time) { /* * Equal start times, we have a collision. Let the connected-to * server decide. This assumes leafs issue more than half of the * connection attempts. */ if (IsUnknown(cptr)) cli_serv(cptr)->timestamp = TStime(); else if (IsHandshake(cptr)) { sendto_opmask_butone(0, SNO_OLDSNO, "clock adjusted by adding %d", (int)(timestamp - recv_time)); TSoffset += timestamp - recv_time; } } }
/** Send the signon MOTD to a user. * If FEAT_NODEFAULTMOTD is true and a matching MOTD exists for the * user, direct the client to type /MOTD to read it. Otherwise, call * motd_forward() for the user. * @param[in] cptr Client that has just connected. */ void motd_signon(struct Client* cptr) { struct MotdCache *cache; const char *banner = NULL; cache = motd_cache(motd_lookup(cptr)); if (!feature_bool(FEAT_NODEFAULTMOTD) || !cache) motd_forward(cptr, cache); else { send_reply(cptr, RPL_MOTDSTART, cli_name(&me)); if ((banner = feature_str(FEAT_MOTD_BANNER))) send_reply(cptr, SND_EXPLICIT | RPL_MOTD, ":%s", banner); send_reply(cptr, SND_EXPLICIT | RPL_MOTD, ":\002Type /MOTD to read the " "AUP before continuing using this service.\002"); send_reply(cptr, SND_EXPLICIT | RPL_MOTD, ":The message of the day was " "last changed: %d-%d-%d %d:%d", cache->modtime.tm_year + 1900, cache->modtime.tm_mon + 1, cache->modtime.tm_mday, cache->modtime.tm_hour, cache->modtime.tm_min); send_reply(cptr, RPL_ENDOFMOTD); } }
/** Handle a JOIN message from a client connection. * See @ref m_functions for discussion of the arguments. * @param[in] cptr Client that sent us the message. * @param[in] sptr Original source of message. * @param[in] parc Number of arguments. * @param[in] parv Argument vector. */ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Channel *chptr; struct JoinBuf join; struct JoinBuf create; struct Gline *gline; char *p = 0; char *chanlist; char *name; char *keys; if (parc < 2 || *parv[1] == '\0') return need_more_params(sptr, "JOIN"); joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0); joinbuf_init(&create, sptr, cptr, JOINBUF_TYPE_CREATE, 0, TStime()); chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */ keys = parv[2]; /* remember where keys are */ for (name = ircd_strtok(&p, chanlist, ","); name; name = ircd_strtok(&p, 0, ",")) { char *key = 0; /* If we have any more keys, take the first for this channel. */ if (!BadPtr(keys) && (keys = strchr(key = keys, ','))) *keys++ = '\0'; /* Empty keys are the same as no keys. */ if (key && !key[0]) key = 0; if (!IsChannelName(name) || !strIsIrcCh(name)) { /* bad channel name */ send_reply(sptr, ERR_NOSUCHCHANNEL, name); continue; } if (cli_user(sptr)->joined >= feature_int(FEAT_MAXCHANNELSPERUSER) && !HasPriv(sptr, PRIV_CHAN_LIMIT)) { send_reply(sptr, ERR_TOOMANYCHANNELS, name); break; /* no point processing the other channels */ } /* BADCHANed channel */ if ((gline = gline_find(name, GLINE_BADCHAN | GLINE_EXACT)) && GlineIsActive(gline) && !IsAnOper(sptr)) { send_reply(sptr, ERR_BANNEDFROMCHAN, name); continue; } if (!(chptr = FindChannel(name))) { if (((name[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(name) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) { send_reply(sptr, ERR_NOSUCHCHANNEL, name); continue; } if (!(chptr = get_channel(sptr, name, CGT_CREATE))) continue; /* Try to add the new channel as a recent target for the user. */ if (check_target_limit(sptr, chptr, chptr->chname, 0)) { chptr->members = 0; destruct_channel(chptr); continue; } joinbuf_join(&create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER); } else if (find_member_link(chptr, sptr)) { continue; /* already on channel */ } else if (check_target_limit(sptr, chptr, chptr->chname, 0)) { continue; } else { int flags = CHFL_DEOPPED; int err = 0; /* Check Apass/Upass -- since we only ever look at a single * "key" per channel now, this hampers brute force attacks. */ if (key && !strcmp(key, chptr->mode.apass)) flags = CHFL_CHANOP | CHFL_CHANNEL_MANAGER; else if (key && !strcmp(key, chptr->mode.upass)) flags = CHFL_CHANOP; else if (chptr->users == 0 && !chptr->mode.apass[0]) { /* Joining a zombie channel (zannel): give ops and increment TS. */ flags = CHFL_CHANOP; chptr->creationtime++; } else if (IsInvited(sptr, chptr)) { /* Invites bypass these other checks. */ } else if (chptr->mode.mode & MODE_INVITEONLY) err = ERR_INVITEONLYCHAN; else if (chptr->mode.limit && (chptr->users >= chptr->mode.limit)) err = ERR_CHANNELISFULL; else if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr)) err = ERR_NEEDREGGEDNICK; else if (find_ban(sptr, chptr->banlist)) err = ERR_BANNEDFROMCHAN; else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key))) err = ERR_BADCHANNELKEY; /* An oper with WALK_LCHAN privilege can join a local channel * he otherwise could not join by using "OVERRIDE" as the key. * This will generate a HACK(4) notice, but fails if the oper * could normally join the channel. */ if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) && !(flags & CHFL_CHANOP) && key && !strcmp(key, "OVERRIDE")) { switch (err) { case 0: if (strcmp(chptr->mode.key, "OVERRIDE") && strcmp(chptr->mode.apass, "OVERRIDE") && strcmp(chptr->mode.upass, "OVERRIDE")) { send_reply(sptr, ERR_DONTCHEAT, chptr->chname); continue; } break; case ERR_INVITEONLYCHAN: err = 'i'; break; case ERR_CHANNELISFULL: err = 'l'; break; case ERR_BANNEDFROMCHAN: err = 'b'; break; case ERR_BADCHANNELKEY: err = 'k'; break; case ERR_NEEDREGGEDNICK: err = 'r'; break; default: err = '?'; break; } /* send accountability notice */ if (err) sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H " "(overriding +%c)", sptr, chptr, err); err = 0; } /* Is there some reason the user may not join? */ if (err) { switch(err) { case ERR_NEEDREGGEDNICK: send_reply(sptr, ERR_NEEDREGGEDNICK, chptr->chname, feature_str(FEAT_URLREG)); break; default: send_reply(sptr, err, chptr->chname); break; } continue; } joinbuf_join(&join, chptr, flags); if (flags & CHFL_CHANOP) { struct ModeBuf mbuf; /* Always let the server op him: this is needed on a net with older servers because they 'destruct' channels immediately when they become empty without sending out a DESTRUCT message. As a result, they would always bounce a mode (as HACK(2)) when the user ops himself. (There is also no particularly good reason to have the user op himself.) */ modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER); modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr, chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL); modebuf_flush(&mbuf); } } del_invite(sptr, chptr); if (chptr->topic[0]) { send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic); send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick, chptr->topic_time); } do_names(sptr, chptr, NAMES_ALL|NAMES_EON); /* send /names list */ } joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */ joinbuf_flush(&create); return 0; }
/* * ms_invite - server message handler * * parv[0] - sender prefix * parv[1] - user to invite * parv[2] - channel name * parv[3] - (optional) channel timestamp * * - INVITE now is accepted only if who does it is chanop (this of course * implies that channel must exist and he must be on it). * * - On the other side it IS processed even if channel is NOT invite only * leaving room for other enhancements like inviting banned ppl. -- Nemesi * * - Invite with no parameters now lists the channels you are invited to. * - Isomer 23 Oct 99 * * - Invite with too-late timestamp, or with no timestamp from a bursting * server, is silently discarded. - Entrope 19 Jan 05 */ int ms_invite(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client *acptr; struct Channel *chptr; time_t invite_ts; if (IsServer(sptr)) { /* * this will blow up if we get an invite from a server * we look for channel membership in sptr below. */ return protocol_violation(sptr,"Server attempting to invite"); } if (parc < 3 || EmptyString(parv[2])) { /* * should have been handled upstream, ignore it. */ protocol_violation(sptr,"Too few arguments to invite"); return need_more_params(sptr,"INVITE"); } if (!IsGlobalChannel(parv[2])) { /* * should not be sent */ return protocol_violation(sptr, "Invite to a non-standard channel %s",parv[2]); } if (!(acptr = FindUser(parv[1]))) { send_reply(sptr, ERR_NOSUCHNICK, parv[1]); return 0; } if (!(chptr = FindChannel(parv[2]))) { /* * allow invites to non existent channels, bleah * avoid JOIN, INVITE, PART abuse */ sendcmdto_one(sptr, CMD_INVITE, acptr, "%C :%s", acptr, parv[2]); return 0; } if (parc > 3) { invite_ts = atoi(parv[3]); if (invite_ts > chptr->creationtime) return 0; } else if (IsBurstOrBurstAck(cptr)) return 0; if (!IsChannelService(sptr) && !find_channel_member(sptr, chptr)) { send_reply(sptr, ERR_NOTONCHANNEL, chptr->chname); return 0; } if (find_channel_member(acptr, chptr)) { send_reply(sptr, ERR_USERONCHANNEL, cli_name(acptr), chptr->chname); return 0; } if (is_silenced(sptr, acptr)) return 0; if (MyConnect(acptr)) { add_invite(acptr, chptr); sendcmdto_one(sptr, CMD_INVITE, acptr, "%s %H", cli_name(acptr), chptr); } else { sendcmdto_one(sptr, CMD_INVITE, acptr, "%s %H %Tu", cli_name(acptr), chptr, chptr->creationtime); } if (feature_bool(FEAT_ANNOUNCE_INVITES)) { /* Announce to channel operators. */ sendcmdto_channel_butserv_butone(&his, get_error_numeric(RPL_ISSUEDINVITE)->str, NULL, chptr, sptr, SKIP_NONOPS, "%H %C %C :%C has been invited by %C", chptr, acptr, sptr, acptr, sptr); /* Announce to servers with channel operators. */ sendcmdto_channel_servers_butone(sptr, NULL, TOK_INVITE, chptr, acptr, SKIP_NONOPS, "%s %H %Tu", cli_name(acptr), chptr, chptr->creationtime); } return 0; }
/* * m_invite - generic message handler * * parv[0] - sender prefix * parv[1] - user to invite * parv[2] - channel name * * - INVITE now is accepted only if who does it is chanop (this of course * implies that channel must exist and he must be on it). * * - On the other side it IS processed even if channel is NOT invite only * leaving room for other enhancements like inviting banned ppl. -- Nemesi * * - Invite with no parameters now lists the channels you are invited to. * - Isomer 23 Oct 99 */ int m_invite(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client *acptr; struct Channel *chptr; if (parc < 2 ) { /* * list the channels you have an invite to. */ struct SLink *lp; for (lp = cli_user(sptr)->invited; lp; lp = lp->next) send_reply(cptr, RPL_INVITELIST, lp->value.chptr->chname); send_reply(cptr, RPL_ENDOFINVITELIST); return 0; } if (parc < 3 || EmptyString(parv[2])) return need_more_params(sptr, "INVITE"); if (!(acptr = FindUser(parv[1]))) { send_reply(sptr, ERR_NOSUCHNICK, parv[1]); return 0; } if (is_silenced(sptr, acptr)) return 0; if (!IsChannelName(parv[2]) || !strIsIrcCh(parv[2]) || !(chptr = FindChannel(parv[2]))) { send_reply(sptr, ERR_NOSUCHCHANNEL, parv[2]); return 0; } if (!find_channel_member(sptr, chptr)) { send_reply(sptr, ERR_NOTONCHANNEL, chptr->chname); return 0; } if (find_channel_member(acptr, chptr)) { send_reply(sptr, ERR_USERONCHANNEL, cli_name(acptr), chptr->chname); return 0; } if (!is_chan_op(sptr, chptr)) { send_reply(sptr, ERR_CHANOPRIVSNEEDED, chptr->chname); return 0; } /* If we get here, it was a VALID and meaningful INVITE */ if (check_target_limit(sptr, acptr, cli_name(acptr), 0)) return 0; send_reply(sptr, RPL_INVITING, cli_name(acptr), chptr->chname); if (cli_user(acptr)->away) send_reply(sptr, RPL_AWAY, cli_name(acptr), cli_user(acptr)->away); if (MyConnect(acptr)) { add_invite(acptr, chptr); sendcmdto_one(sptr, CMD_INVITE, acptr, "%s %H", cli_name(acptr), chptr); } else if (!IsLocalChannel(chptr->chname)) { sendcmdto_one(sptr, CMD_INVITE, acptr, "%s %H %Tu", cli_name(acptr), chptr, chptr->creationtime); } if (!IsLocalChannel(chptr->chname) || MyConnect(acptr)) { if (feature_bool(FEAT_ANNOUNCE_INVITES)) { /* Announce to channel operators. */ sendcmdto_channel_butserv_butone(&his, get_error_numeric(RPL_ISSUEDINVITE)->str, NULL, chptr, sptr, SKIP_NONOPS, "%H %C %C :%C has been invited by %C", chptr, acptr, sptr, acptr, sptr); /* Announce to servers with channel operators. */ sendcmdto_channel_servers_butone(sptr, NULL, TOK_INVITE, chptr, acptr, SKIP_NONOPS, "%s %H %Tu", cli_name(acptr), chptr, chptr->creationtime); } } return 0; }
/** Append bytes to a data buffer. * @param[in] dyn Buffer to append to. * @param[in] buf Data to append. * @param[in] length Number of bytes to append. * @return Non-zero on success, or zero on failure. */ int dbuf_put(struct DBuf *dyn, const char *buf, unsigned int length) { struct DBufBuffer** h; struct DBufBuffer* db; unsigned int chunk; assert(0 != dyn); assert(0 != buf); /* * Locate the last non-empty buffer. If the last buffer is full, * the loop will terminate with 'db==NULL'. * This loop assumes that the 'dyn->length' field is correctly * maintained, as it should--no other check really needed. */ if (!dyn->length) h = &(dyn->head); else h = &(dyn->tail); /* * Append users data to buffer, allocating buffers as needed */ dyn->length += length; for (; length > 0; h = &(db->next)) { if (0 == (db = *h)) { if (0 == (db = dbuf_alloc())) { if (feature_bool(FEAT_HAS_FERGUSON_FLUSHER)) { /* * from "Married With Children" episode were Al bought a REAL toilet * on the black market because he was tired of the wimpy water * conserving toilets they make these days --Bleep */ /* * Apparently this doesn't work, the server _has_ to * dump a few clients to handle the load. A fully loaded * server cannot handle a net break without dumping some * clients. If we flush the connections here under a full * load we may end up starving the kernel for mbufs and * crash the machine */ /* * attempt to recover from buffer starvation before * bailing this may help servers running out of memory */ flush_connections(0); db = dbuf_alloc(); } if (0 == db) return dbuf_malloc_error(dyn); } dyn->tail = db; *h = db; db->next = 0; db->start = db->end = db->data; } chunk = (db->data + DBUF_SIZE) - db->end; if (chunk) { if (chunk > length) chunk = length; memcpy(db->end, buf, chunk); length -= chunk; buf += chunk; db->end += chunk; } } return 1; }
/* * mo_gline - oper message handler * * parv[0] = Sender prefix * parv[1] = [[+|-]<G-line mask>] * * Local (to me) style: * * parv[2] = [Expiration offset] * parv[3] = [Comment] * * Global (or remote local) style: * * parv[2] = [target] * parv[3] = [Expiration offset] * parv[4] = [Comment] * */ int mo_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Client *acptr = 0; struct Gline *agline; unsigned int flags = 0; time_t expire_off; char *mask = parv[1], *target = 0, *reason; if (parc < 2) return gline_list(sptr, 0); if (*mask == '!') { mask++; if (HasPriv(sptr, PRIV_WIDE_GLINE)) flags |= GLINE_OPERFORCE; } if (*mask == '+') { flags |= GLINE_ACTIVE; mask++; } else if (*mask == '-') mask++; else return gline_list(sptr, mask); if (parc == 4) { expire_off = atoi(parv[2]); reason = parv[3]; flags |= GLINE_LOCAL; } else if (parc > 4) { target = parv[2]; expire_off = atoi(parv[3]); reason = parv[4]; } else return need_more_params(sptr, "GLINE"); if (target) { if (!(target[0] == '*' && target[1] == '\0')) { if (!(acptr = find_match_server(target))) return send_reply(sptr, ERR_NOSUCHSERVER, target); /* manually propagate, since we don't set it */ if (!IsMe(acptr)) { if (!feature_bool(FEAT_CONFIG_OPERCMDS)) return send_reply(sptr, ERR_DISABLED, "GLINE"); if (!HasPriv(sptr, PRIV_GLINE)) return send_reply(sptr, ERR_NOPRIVILEGES); sendcmdto_one(sptr, CMD_GLINE, acptr, "%C %s%c%s %s %Tu :%s", acptr, flags & GLINE_OPERFORCE ? "!" : "", flags & GLINE_ACTIVE ? '+' : '-', mask, parv[3], TStime(), reason); return 0; } flags |= GLINE_LOCAL; } } if (!(flags & GLINE_LOCAL) && !feature_bool(FEAT_CONFIG_OPERCMDS)) return send_reply(sptr, ERR_DISABLED, "GLINE"); if (!HasPriv(sptr, (flags & GLINE_LOCAL ? PRIV_LOCAL_GLINE : PRIV_GLINE))) return send_reply(sptr, ERR_NOPRIVILEGES); agline = gline_find(mask, GLINE_ANY | GLINE_EXACT); if (agline) { if (GlineIsLocal(agline) && !(flags & GLINE_LOCAL)) /* global over local */ gline_free(agline); else { if (!GlineLastMod(agline)) /* force mods to Uworld-set G-lines local */ flags |= GLINE_LOCAL; if (flags & GLINE_ACTIVE) return gline_activate(cptr, sptr, agline, GlineLastMod(agline) ? TStime() : 0, flags); else return gline_deactivate(cptr, sptr, agline, GlineLastMod(agline) ? TStime() : 0, flags); } } return gline_add(cptr, sptr, mask, reason, expire_off, TStime(), flags); }
/** Send a (prefixed) WALL of type \a type to all users except \a one. * @warning \a pattern must not contain %v. * @param[in] from Source of the command. * @param[in] type One of WALL_DESYNCH, WALL_WALLOPS or WALL_WALLUSERS. * @param[in] one Client direction to skip (or NULL). * @param[in] pattern Format string for command arguments. */ void sendwallto_group_butone(struct Client *from, int type, struct Client *one, const char *pattern, ...) { struct VarData vd; struct Client *cptr; struct MsgBuf *mb; struct DLink *lp; char *prefix=NULL; char *tok=NULL; int his_wallops; int i; vd.vd_format = pattern; /* Build buffer to send to users */ va_start(vd.vd_args, pattern); switch (type) { case WALL_DESYNCH: prefix=""; tok=TOK_DESYNCH; break; case WALL_WALLOPS: prefix="* "; tok=TOK_WALLOPS; break; case WALL_WALLUSERS: prefix="$ "; tok=TOK_WALLUSERS; break; default: assert(0); } mb = msgq_make(0, "%:#C " MSG_WALLOPS " :%s%v", from, prefix,&vd); va_end(vd.vd_args); /* send buffer along! */ his_wallops = feature_bool(FEAT_HIS_WALLOPS); for (i = 0; i <= HighestFd; i++) { if (!(cptr = LocalClientArray[i]) || (cli_fd(cli_from(cptr)) < 0) || (type == WALL_DESYNCH && !SendDebug(cptr)) || (type == WALL_WALLOPS && (!SendWallops(cptr) || (his_wallops && !IsAnOper(cptr)))) || (type == WALL_WALLUSERS && !SendWallops(cptr))) continue; /* skip it */ send_buffer(cptr, mb, 1); } msgq_clean(mb); /* Build buffer to send to servers */ va_start(vd.vd_args, pattern); mb = msgq_make(&me, "%C %s :%v", from, tok, &vd); va_end(vd.vd_args); /* send buffer along! */ for (lp = cli_serv(&me)->down; lp; lp = lp->next) { if (one && lp->value.cptr == cli_from(one)) continue; send_buffer(lp->value.cptr, mb, 1); } msgq_clean(mb); }