Example #1
0
/*
 * 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]);
}
Example #2
0
/*
 * 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);
}
Example #3
0
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);
  }
}
Example #4
0
/** 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);
}
Example #5
0
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);
}
Example #6
0
/** 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;
}
Example #7
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]);
}
Example #8
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[])
{
  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;
}
Example #9
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);
}
Example #10
0
/** 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;
}
Example #12
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);
}
Example #13
0
/** 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 */
}
Example #14
0
/*
 * 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;
}
Example #15
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);
}
Example #16
0
/** 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);
}
Example #17
0
/** 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 */
}
Example #18
0
/** 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 */
}
Example #19
0
/*
 * 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);
}
Example #20
0
/*
 * 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;
}
Example #21
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;
}
Example #22
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;
    }
  }
}
Example #24
0
/** 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;
}
Example #28
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;
}
Example #29
0
/*
 * 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);
}
Example #30
0
/** 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);
}