/*
 * send_auth_query - send the ident server a query giving "theirport , ourport"
 * The write is only attempted *once* so it is deemed to be a fail if the
 * entire write doesn't write all the data given.  This shouldnt be a
 * problem since the socket should have a write buffer far greater than
 * this message to store it in should problems arise. -avalon
 */
void send_auth_query(struct AuthRequest* auth)
{
  struct sockaddr_in us;
  struct sockaddr_in them;
  char               authbuf[32];
  unsigned int       count;

  assert(0 != auth);
  assert(0 != auth->client);

  if (!os_get_sockname(cli_fd(auth->client), &us) ||
      !os_get_peername(cli_fd(auth->client), &them)) {
    auth_error(auth, 1);
    return;
  }
  ircd_snprintf(0, authbuf, sizeof(authbuf), "%u , %u\r\n",
		(unsigned int) ntohs(them.sin_port),
		(unsigned int) ntohs(us.sin_port));

  if (IO_SUCCESS == os_send_nonb(auth->fd, authbuf, strlen(authbuf), &count)) {
    ClearAuthConnect(auth);
    SetAuthPending(auth);
  }
  else
    auth_error(auth, 0);
}
Beispiel #2
0
static void
feature_notify_excepts(void)
{
    char imaxlist[BUFSIZE] = "";
    char cmodebuf[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");
    }

    /* "be,AkU,Ll,aCcDdiMmNnOpQRrSsTtZz" */

    ircd_snprintf(0, cmodebuf, BUFSIZE, "b%s,%sk%s,Ll,aCcDdiMmNnOpQRrSsTtZz",
                  feature_bool(FEAT_EXCEPTS) ? "e" : "",
                  feature_bool(FEAT_OPLEVELS) ? "A" : "",
                  feature_bool(FEAT_OPLEVELS) ? "U" : "");

    add_isupport_s("CHANMODES", cmodebuf);

    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);
}
Beispiel #3
0
/** Count number of users who match \a mask.
 * @param[in] mask ip mask to check.
 * @param[in] flags Bitmask possibly containing the value ZLINE_LOCAL, to limit searches to this server.
 * @return Count of matching users.
 */
static int
count_users(char *mask, int flags)
{
  struct irc_in_addr ipmask;
  struct Client *acptr;
  int count = 0;
  int ipmask_valid;
  char ipbuf[SOCKIPLEN + 2];
  unsigned char ipmask_len;

  ipmask_valid = ipmask_parse(mask, &ipmask, &ipmask_len);
  for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) {
    if (!IsUser(acptr))
      continue;
    if ((flags & ZLINE_LOCAL) && !MyConnect(acptr))
      continue;

    ircd_snprintf(0, ipbuf, sizeof(ipbuf), "%s", ircd_ntoa(&cli_ip(acptr)));

    if (!match(mask, ipbuf)
        || (ipmask_valid && ipmask_check(&cli_ip(acptr), &ipmask, ipmask_len)
            && (irc_in_addr_type_cmp(&cli_ip(acptr), &ipmask) && ipmask_len)))
      count++;
  }

  return count;
}
Beispiel #4
0
void checkChannel(struct Client *sptr, struct Channel *chptr)
{
   char outbuf[TOPICLEN + MODEBUFLEN + 64], modebuf[MODEBUFLEN], parabuf[MODEBUFLEN];

   /* Header */
   send_reply(sptr, RPL_DATASTR, " ");
   send_reply(sptr, RPL_CHKHEAD, "channel", chptr->chname);
   send_reply(sptr, RPL_DATASTR, " ");

   /* Creation Time */
   ircd_snprintf(sptr, outbuf, sizeof(outbuf), "  Creation time:: %s", myctime(chptr->creationtime));
   send_reply(sptr, RPL_DATASTR, outbuf);

   /* Topic */
   if (strlen(chptr->topic) <= 0)
      send_reply(sptr, RPL_DATASTR, "          Topic:: <none>");
   else {
      ircd_snprintf(sptr, outbuf, sizeof(outbuf), "          Topic:: %s", chptr->topic);
      send_reply(sptr, RPL_DATASTR, outbuf);

      /* ..set by */
      ircd_snprintf(sptr, outbuf, sizeof(outbuf), "         Set by:: %s", chptr->topic_nick);
      send_reply(sptr, RPL_DATASTR, outbuf);
   }

   /* Channel Modes */

   strcpy(outbuf, "Channel mode(s):: ");

   modebuf[0] = '\0';
   parabuf[0] = '\0';

   channel_modes(sptr, modebuf, parabuf, sizeof(modebuf), chptr);

   if(modebuf[1] == '\0')
      strcat(outbuf, "<none>");
   else if(*parabuf) {
      strcat(outbuf, modebuf);
      strcat(outbuf, " ");
      strcat(outbuf, parabuf);
   } else
      strcat(outbuf, modebuf);

   send_reply(sptr, RPL_DATASTR, outbuf);

   /* Don't send 'END OF CHECK' message, it's sent in checkUsers, which is called after this. */
}
Beispiel #5
0
void checkServer(struct Client *sptr, struct Client *acptr)
{
   char outbuf[BUFSIZE];

   /* Header */
   send_reply(sptr, RPL_DATASTR, " ");
   send_reply(sptr, RPL_CHKHEAD, "server", acptr->cli_name);
   send_reply(sptr, RPL_DATASTR, " ");

   ircd_snprintf(0, outbuf, sizeof(outbuf),  "   Connected at:: %s (%Tu)", myctime(acptr->cli_serv->timestamp), acptr->cli_serv->timestamp);
   send_reply(sptr, RPL_DATASTR, outbuf);

   ircd_snprintf(0, outbuf, sizeof(outbuf), "    Server name:: %s", acptr->cli_name);
   send_reply(sptr, RPL_DATASTR,  outbuf);

   if (cli_sslclifp(acptr) && (strlen(cli_sslclifp(acptr)) > 0)) {
     ircd_snprintf(0, outbuf, sizeof(outbuf), "SSL Fingerprint:: %s", cli_sslclifp(acptr));
     send_reply(sptr, RPL_DATASTR, outbuf);
   }

   ircd_snprintf(0, outbuf, sizeof(outbuf), "        Numeric:: %s --> %d", NumServ(acptr), base64toint(acptr->cli_yxx));
   send_reply(sptr, RPL_DATASTR, outbuf);

   ircd_snprintf(0, outbuf, sizeof(outbuf), "          Users:: %d / %d", (acptr == &me) ? UserStats.local_clients : cli_serv(acptr)->clients, 
                 base64toint(cli_serv(acptr)->nn_capacity));
   send_reply(sptr, RPL_DATASTR, outbuf);

   if (IsBurst(acptr))
     send_reply(sptr, RPL_DATASTR, "         Status:: Bursting");
   else if (IsBurstAck(acptr))
     send_reply(sptr, RPL_DATASTR, "         Status:: Awaiting EOB Ack");
   else if (IsService(acptr))
     send_reply(sptr, RPL_DATASTR, "         Status:: Network Service");
   else if (IsHub(acptr))
     send_reply(sptr, RPL_DATASTR, "         Status:: Network Hub");

   ircd_snprintf(0, outbuf, sizeof(outbuf), "          Class:: %s", get_client_class(acptr));
   send_reply(sptr, RPL_DATASTR, outbuf);

   if (feature_bool(FEAT_CHECK_EXTENDED)) {
     int dlinkc = 0;
     struct DLink* slink = NULL;
    
     send_reply(sptr, RPL_DATASTR, " ");
     send_reply(sptr, RPL_DATASTR, "Downlinks::");
     for (slink = cli_serv(acptr)->down; slink; slink = slink->next) {
       ircd_snprintf(0, outbuf, sizeof(outbuf), "[%d] - %s%s", ++dlinkc, 
             IsBurst(slink->value.cptr) ? "*" : IsBurstAck(slink->value.cptr) ? "!" : IsService(slink->value.cptr) ? "=" : IsHub(slink->value.cptr) ? "+" : " ", 
             cli_name(slink->value.cptr));
       send_reply(sptr, RPL_DATASTR, outbuf);
     }

     if (!dlinkc)
       send_reply(sptr, RPL_DATASTR, "<none>");
   }

   /* Send 'END OF CHECK' message */
   send_reply(sptr, RPL_ENDOFCHECK, " ");
}
Beispiel #6
0
/** Send a query to look up the name for an address.
 * @param[in] query Callback information.
 * @param[in] addr Address to look up.
 * @param[in] request DNS lookup structure (may be NULL).
 */
static void
do_query_number(dns_callback_f callback, void *ctx, const struct irc_in_addr *addr,
                struct reslist *request)
{
  char ipbuf[128];
  const unsigned char *cp;

  if (irc_in_addr_is_ipv4(addr))
  {
    cp = (const unsigned char*)&addr->in6_16[6];
    ircd_snprintf(NULL, ipbuf, sizeof(ipbuf), "%u.%u.%u.%u.in-addr.arpa.",
                  (unsigned int)(cp[3]), (unsigned int)(cp[2]),
                  (unsigned int)(cp[1]), (unsigned int)(cp[0]));
  }
  else
  {
    const char *intarpa;

    if (request != NULL && request->state == REQ_INT)
      intarpa = "int";
    else
      intarpa = "arpa";

    cp = (const unsigned char *)&addr->in6_16[0];
    ircd_snprintf(NULL, ipbuf, sizeof(ipbuf),
                  "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
                  "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.%s.",
                  (unsigned int)(cp[15]&0xf), (unsigned int)(cp[15]>>4),
                  (unsigned int)(cp[14]&0xf), (unsigned int)(cp[14]>>4),
                  (unsigned int)(cp[13]&0xf), (unsigned int)(cp[13]>>4),
                  (unsigned int)(cp[12]&0xf), (unsigned int)(cp[12]>>4),
                  (unsigned int)(cp[11]&0xf), (unsigned int)(cp[11]>>4),
                  (unsigned int)(cp[10]&0xf), (unsigned int)(cp[10]>>4),
                  (unsigned int)(cp[9]&0xf), (unsigned int)(cp[9]>>4),
                  (unsigned int)(cp[8]&0xf), (unsigned int)(cp[8]>>4),
                  (unsigned int)(cp[7]&0xf), (unsigned int)(cp[7]>>4),
                  (unsigned int)(cp[6]&0xf), (unsigned int)(cp[6]>>4),
                  (unsigned int)(cp[5]&0xf), (unsigned int)(cp[5]>>4),
                  (unsigned int)(cp[4]&0xf), (unsigned int)(cp[4]>>4),
                  (unsigned int)(cp[3]&0xf), (unsigned int)(cp[3]>>4),
                  (unsigned int)(cp[2]&0xf), (unsigned int)(cp[2]>>4),
                  (unsigned int)(cp[1]&0xf), (unsigned int)(cp[1]>>4),
                  (unsigned int)(cp[0]&0xf), (unsigned int)(cp[0]>>4), intarpa);
  }
  if (request == NULL)
  {
    request       = make_request(callback, ctx);
    request->state= REQ_PTR;
    request->type = T_PTR;
    memcpy(&request->addr, addr, sizeof(request->addr));
    request->name = (char *)MyMalloc(HOSTLEN + 1);
  }
  Debug((DEBUG_DNS, "Requesting DNS PTR %s as %p", ipbuf, request));
  query_name(ipbuf, C_IN, T_PTR, request);
}
/** Return the name of the client for various tracking and admin
 * purposes. The main purpose of this function is to return the
 * "socket host" name of the client, if that differs from the
 * advertised name (other than case).  But, this can be used on any
 * client structure.
 * @param sptr Client to operate on.
 * @param showip If non-zero, append [username\@text-ip] to name.
 * @return Either cli_name(\a sptr) or a static buffer.
 */
const char* get_client_name(const struct Client* sptr, int showip)
{
  static char nbuf[HOSTLEN * 2 + USERLEN + 5];

  if (!MyConnect(sptr) || !showip)
    return cli_name(sptr);
  ircd_snprintf(0, nbuf, sizeof(nbuf), "%s[%s@%s]", cli_name(sptr),
                IsIdented(sptr) ? cli_username(sptr) : "",
                cli_sock_ip(sptr));
  return nbuf;
}
/*
 * mo_kill - oper message handler
 *
 * NOTE: IsPrivileged(sptr), IsAnOper(sptr) == true
 *       IsServer(cptr), IsServer(sptr) == false
 *
 * parv[0]      = sender prefix
 * parv[1]      = kill victim
 * parv[parc-1] = kill path
 */
int mo_kill(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  struct Client* victim;
  char*          user;
  char           msg[TOPICLEN + 3]; /* (, ), and \0 */

  assert(0 != cptr);
  assert(0 != sptr);
  /*
   * oper connection to this server, cptr is always sptr
   */
  assert(cptr == sptr);
  assert(IsAnOper(sptr));

  if (parc < 3 || EmptyString(parv[parc - 1]))
    return need_more_params(sptr, "KILL");

  user = parv[1];
  ircd_snprintf(0, msg, sizeof(msg), "(%.*s)", TOPICLEN, parv[parc - 1]);

  if (!(victim = FindClient(user))) {
    /*
     * If the user has recently changed nick, we automaticly
     * rewrite the KILL for this new nickname--this keeps
     * servers in synch when nick change and kill collide
     */
    if (!(victim = get_history(user, (long)15)))
      return send_reply(sptr, ERR_NOSUCHNICK, user);

    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Changed KILL %s into %s", sptr,
		  user, cli_name(victim));
  }
  if (!HasPriv(sptr, MyConnect(victim) ? PRIV_LOCAL_KILL : PRIV_KILL))
    return send_reply(sptr, ERR_NOPRIVILEGES);

  if (IsServer(victim) || IsMe(victim)) {
    return send_reply(sptr, ERR_CANTKILLSERVER);
  }
  /*
   * if the user is +k, prevent a kill from local user
   */
  if (IsChannelService(victim))
    return send_reply(sptr, ERR_ISCHANSERVICE, "KILL", cli_name(victim));


  if (!MyConnect(victim) && !HasPriv(sptr, PRIV_KILL)) {
    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Nick %s isnt on your server",
		  sptr, cli_name(victim));
    return 0;
  }
  return do_kill(cptr, sptr, victim, cli_user(sptr)->host, cli_name(sptr),
		 msg);
}
Beispiel #9
0
char *hidehost_normalhost(char *host, int components)
{
char *p;
static char buf[512], res[512], res2[512], result[HOSTLEN+1];
unsigned int alpha, n;
int comps = 0;

        ircd_snprintf(0, buf, 512, "%s:%s:%s", KEY1, host, KEY2);
        DoMD5((unsigned char *)&res, (unsigned char *)&buf, strlen(buf));
        strcpy(res+16, KEY3); /* first 16 bytes are filled, append our key.. */
        n = strlen(res+16) + 16;
        DoMD5((unsigned char *)&res2, (unsigned char *)&res, n);
        alpha = downsample((unsigned char *)&res2);

        for (p = host; *p; p++) {
                if (*p == '.') {
                        comps++;
                        if ((comps >= components) && IsAlpha(*(p + 1)))
                                break;
                }
        }

        if (*p)
        {
                unsigned int len;
                p++;

                ircd_snprintf(0, result, HOSTLEN, "%s-%X.", PREFIX, alpha);
                len = strlen(result) + strlen(p);
                if (len <= HOSTLEN)
                        strcat(result, p);
                else
                        strcat(result, p + (len - HOSTLEN));
        } else
                ircd_snprintf(0, result, HOSTLEN, "%s-%X", PREFIX, alpha);

        return result;
}
Beispiel #10
0
int
count_users(char *mask)
{
  struct Client *acptr;
  int count = 0;
  char namebuf[USERLEN + HOSTLEN + 2];
  char ipbuf[USERLEN + 16 + 2];

  for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) {
    if (!IsUser(acptr))
      continue;

    ircd_snprintf(0, namebuf, sizeof(namebuf), "%s@%s",
		  cli_user(acptr)->username, cli_user(acptr)->realhost);
    ircd_snprintf(0, ipbuf, sizeof(ipbuf), "%s@%s", cli_user(acptr)->username,
		  ircd_ntoa((const char *) &(cli_ip(acptr))));

    if (!match(mask, namebuf) || !match(mask, ipbuf))
      count++;
  }

  return count;
}
Beispiel #11
0
/** Forwards a numeric message from a remote server.
 * @param numeric Value of numeric message.
 * @param nnn If non-zero, treat parv[1] as a numnick; else as a client name.
 * @param cptr Client that originated the numeric.
 * @param sptr Peer that sent us the numeric.
 * @param parc Count of valid arguments in \a parv.
 * @param parv Argument list.
 * @return Zero (always).
 */
int do_numeric(int numeric, int nnn, struct Client *cptr, struct Client *sptr,
    int parc, char *parv[])
{
  struct Client *acptr = 0;
  struct Channel *achptr = 0;
  char num[4];

  /* Avoid trash, we need it to come from a server and have a target  */
  if ((parc < 2) || !IsServer(sptr))
    return 0;

  /* Who should receive this message ? Will we do something with it ?
     Note that we use findUser functions, so the target can't be neither
     a server, nor a channel (?) nor a list of targets (?) .. u2.10
     should never generate numeric replies to non-users anyway
     Ahem... it can be a channel actually, csc bots use it :\ --Nem */

  if (IsChannelName(parv[1]))
    achptr = FindChannel(parv[1]);
  else
    acptr = (nnn) ? (findNUser(parv[1])) : (FindUser(parv[1]));

  if (((!acptr) || (cli_from(acptr) == cptr)) && !achptr)
    return 0;

  /* Remap low number numerics, not that I understand WHY.. --Nemesi  */
  /* numerics below 100 talk about the current 'connection', you're not
   * connected to a remote server so it doesn't make sense to send them
   * remotely - but the information they contain may be useful, so we
   * remap them up.  Weird, but true.  -- Isomer */
  if (numeric < 100)
    numeric += 100;

  ircd_snprintf(0, num, sizeof(num), "%03d", numeric);

  /* Since 2.10.10.pl14 we rewrite numerics from remote servers to appear to
   * come from the local server
   */
  if (acptr)
    sendcmdto_one((feature_bool(FEAT_HIS_REWRITE) && !IsOper(acptr)) ?
                    &me : sptr,
                  num, num, acptr, "%C %s", acptr, parv[2]);
  else
    sendcmdto_channel_butone(feature_bool(FEAT_HIS_REWRITE) ? &me : sptr,
                             num, num, achptr, cptr, SKIP_DEAF | SKIP_BURST,
                             '\0', "%H %s", achptr, parv[2]);
  return 0;
}
Beispiel #12
0
/*
 * m_pseudo - generic service message handler
 *
 * parv[0] = sender prefix
 * parv[1] = service mapping (s_map * disguised as char *)
 * parv[2] = message
 */
int m_pseudo(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  char *text, buffer[BUFSIZE];
  struct s_map *map;
  struct nick_host *nh;

  assert(0 != cptr);
  assert(cptr == sptr);
  assert(0 != cli_user(sptr));

  /* By default, relay the message straight through. */
  text = parv[parc - 1];

  /* HACK! HACK! HACK! HACK! Yes. It's icky, but
   * it's the only way. */
  map = (struct s_map *)parv[1];
  assert(0 != map);

  if (parc < 3 || EmptyString(text)) {
    if (map->defaulttext)
      text = map->defaulttext;
    else
      return send_reply(sptr, ERR_NOTEXTTOSEND);
  }

  if (map->prepend) {
    ircd_snprintf(0, buffer, sizeof(buffer) - 1, "%s%s", map->prepend, text);
    buffer[sizeof(buffer) - 1] = 0;
    text = buffer;
  }

  for (nh = map->services; nh; nh = nh->next) {
    struct Client *target, *server;

    if (NULL == (server = FindServer(nh->nick + nh->nicklen + 1)))
      continue;
    nh->nick[nh->nicklen] = '\0';
    if ((NULL == (target = FindUser(nh->nick)))
        || (server != cli_user(target)->server))
      continue;
    nh->nick[nh->nicklen] = '@';
    relay_directed_message(sptr, nh->nick, nh->nick + nh->nicklen, text);
    return 0;
  }

  return send_reply(sptr, ERR_SERVICESDOWN, map->name);
}
Beispiel #13
0
/** Update whether #me has oplevels support or not.
*/
static void
feature_notify_oplevels(void)
{
    char cmodebuf[BUFSIZE] = "";

    if (feature_bool(FEAT_OPLEVELS))
        SetOpLevels(&me);
    else
        ClearOpLevels(&me);

    /* "be,AkU,Ll,aCcDdiMmNnOpQRrSsTtZz" */

    ircd_snprintf(0, cmodebuf, BUFSIZE, "b%s,%sk%s,Ll,aCcDdiMmNnOpQRrSsTtZz",
                  feature_bool(FEAT_EXCEPTS) ? "e" : "",
                  feature_bool(FEAT_OPLEVELS) ? "A" : "",
                  feature_bool(FEAT_OPLEVELS) ? "U" : "");

    add_isupport_s("CHANMODES", cmodebuf);
}
Beispiel #14
0
/*
 * m_sethost - generic message handler
 *
 * mimic old lain syntax:
 *
 * (Oper) /SETHOST ident host.cc [quit-message]
 * (User) /SETHOST host.cc password
 * (Both) /SETHOST undo
 *
 * check for undo, prepend parv w. <nick> -h or +h
 */
int m_sethost(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
    char hostmask[512];
    struct Flags setflags;

    /* Back up the flags first */
    setflags = cli_flags(sptr);

    if (parc < 2)
        return need_more_params(sptr, "SETHOST");

    if (0 == ircd_strcmp("undo", parv[1])) {
        set_hostmask(sptr, sptr, NULL, NULL);
    } else {
        if (parc<3)
            return need_more_params(sptr, "SETHOST");
        if (IsAnOper(sptr)) {
            ircd_snprintf(0, hostmask, USERLEN + HOSTLEN + 1, "%s@%s", parv[1], parv[2]);
            if (!is_hostmask(hostmask)) {
                send_reply(sptr, ERR_BADHOSTMASK, hostmask);
                return 0;
            }
            if (set_hostmask(sptr, sptr, hostmask, NULL))
                FlagClr(&setflags, FLAG_SETHOST);
        } else {
            if (!is_hostmask(parv[1])) {
                send_reply(sptr, ERR_BADHOSTMASK, parv[1]);
                return 0;
            }
            if (set_hostmask(sptr, sptr, parv[1], parv[2]))
                FlagClr(&setflags, FLAG_SETHOST);
        }
    }

    send_umode_out(cptr, sptr, &setflags, 0);

    return 0;
}
Beispiel #15
0
int m_challenge(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
#ifdef USE_SSL
  struct ConfItem *aconf;
  RSA *rsa_public_key;
  BIO *file = NULL;
  char *challenge = NULL;
  char *name;
  char *tmpname;
  char             chan[CHANNELLEN-1];
  char*            join[2];
  int nl;
  struct Flags old_mode = cli_flags(sptr);

  if (!MyUser(sptr))
    return 0;

  if (parc < 2)
    return need_more_params(sptr, "CHALLENGE");

  if (parc > 2) { /* This is a remote OPER Request */
    struct Client *srv;
    if (!string_has_wildcards(parv[1]))
      srv = FindServer(parv[1]);
    else
      srv = find_match_server(parv[1]);

    if (!feature_bool(FEAT_REMOTE_OPER))
      return send_reply(sptr, ERR_NOOPERHOST);

    if (!srv)
      return send_reply(sptr, ERR_NOOPERHOST);

    if (IsMe(srv)) {
      parv[1] = parv[2];
    } else {
      sendcmdto_one(sptr, CMD_CHALLENGE, srv, "%C %s", srv, parv[2]);
      return 0;
    }
  }

  /* if theyre an oper, reprint oper motd and ignore */
  if (IsOper(sptr))
  {
    send_reply(sptr, RPL_YOUREOPER);
    if (feature_bool(FEAT_OPERMOTD))
      m_opermotd(sptr, sptr, 1, parv);
  }

  if (*parv[1] == '+')
  {
    /* Ignore it if we aren't expecting this... -A1kmm */
    if (cli_user(sptr)->response == NULL)
      return 0;

    if (ircd_strcmp(cli_user(sptr)->response, ++parv[1]))
    {
      send_reply(sptr, ERR_PASSWDMISMATCH);
      sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (Password Incorrect)",
                         parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr));
      tmpname = strdup(cli_user(sptr)->auth_oper);
      failed_challenge_notice(sptr, tmpname, "challenge failed");
      return 0;
    }

    name = strdup(cli_user(sptr)->auth_oper);
     
    aconf = find_conf_exact(cli_user(sptr)->auth_oper, cli_user(sptr)->realusername,
                            MyUser(sptr) ? cli_sockhost(sptr) :
                            cli_user(sptr)->realhost, CONF_OPS);

    if (!aconf)
      aconf = find_conf_exact(cli_user(sptr)->auth_oper, cli_user(sptr)->realusername,
                              ircd_ntoa((const char*) &(cli_ip(sptr))), CONF_OPS);

    if (!aconf)
      aconf = find_conf_cidr(cli_user(sptr)->auth_oper, cli_user(sptr)->realusername,
                              cli_ip(sptr), CONF_OPS);

    if (!aconf)
    {
      send_reply(sptr, ERR_NOOPERHOST);
      sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (No O:line)",
                         parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr));
      return 0;
    }

    if (CONF_LOCOP == aconf->status) {
      ClearOper(sptr);
      SetLocOp(sptr);
    }
    else {
      /*
       * prevent someone from being both oper and local oper
       */
      ClearLocOp(sptr);
      if (!feature_bool(FEAT_OPERFLAGS) || !(aconf->port & OFLAG_ADMIN)) {
        /* Global Oper */
        SetOper(sptr);
        ClearAdmin(sptr);
      } else {
        /* Admin */
        SetOper(sptr);
        OSetGlobal(sptr);
        SetAdmin(sptr);
      }
      ++UserStats.opers;
    }
    cli_handler(cptr) = OPER_HANDLER;

    if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_WHOIS)) {
      OSetWhois(sptr);
    }
    if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_IDLE)) {
      OSetIdle(sptr);
    }
    if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_XTRAOP)) {
      OSetXtraop(sptr);
    }
    if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_HIDECHANS)) {
      OSetHideChans(sptr);
    }

    SetFlag(sptr, FLAG_WALLOP);
    SetFlag(sptr, FLAG_SERVNOTICE);
    SetFlag(sptr, FLAG_DEBUG);

    if (!IsAdmin(sptr))
      cli_oflags(sptr) = aconf->port;

    set_snomask(sptr, SNO_OPERDEFAULT, SNO_ADD);
    client_set_privs(sptr, aconf);
    cli_max_sendq(sptr) = 0; /* Get the sendq from the oper's class */
    send_umode_out(cptr, sptr, &old_mode, HasPriv(sptr, PRIV_PROPAGATE));
    send_reply(sptr, RPL_YOUREOPER);

    if (IsAdmin(sptr)) {
      sendto_allops(&me, SNO_OLDSNO, "%s (%s@%s) is now an IRC Administrator",
                    parv[0], cli_user(sptr)->username, cli_sockhost(sptr));

      /* Autojoin admins to admin channel and oper channel (if enabled) */
      if (feature_bool(FEAT_AUTOJOIN_ADMIN)) {
        if (feature_bool(FEAT_AUTOJOIN_ADMIN_NOTICE))
              sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, feature_str(FEAT_AUTOJOIN_ADMIN_NOTICE_VALUE));

        ircd_strncpy(chan, feature_str(FEAT_AUTOJOIN_ADMIN_CHANNEL), CHANNELLEN-1);
        join[0] = cli_name(sptr);
        join[1] = chan;
        m_join(sptr, sptr, 2, join);
      }
      if (feature_bool(FEAT_AUTOJOIN_OPER) && IsOper(sptr)) {
        if (feature_bool(FEAT_AUTOJOIN_OPER_NOTICE))
              sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, feature_str(FEAT_AUTOJOIN_OPER_NOTICE_VALUE));

        ircd_strncpy(chan, feature_str(FEAT_AUTOJOIN_OPER_CHANNEL), CHANNELLEN-1);
        join[0] = cli_name(sptr);
        join[1] = chan;
        m_join(sptr, sptr, 2, join);
      }
    } else {
      sendto_allops(&me, SNO_OLDSNO, "%s (%s@%s) is now an IRC Operator (%c)",
                         parv[0], cli_user(sptr)->username, cli_sockhost(sptr),
                         IsOper(sptr) ? 'O' : 'o');

      if (feature_bool(FEAT_AUTOJOIN_OPER) && IsOper(sptr)) {
        if (feature_bool(FEAT_AUTOJOIN_OPER_NOTICE))
              sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, feature_str(FEAT_AUTOJOIN_OPER_NOTICE_VALUE));

        ircd_strncpy(chan, feature_str(FEAT_AUTOJOIN_OPER_CHANNEL), CHANNELLEN-1);
        join[0] = cli_name(sptr);
        join[1] = chan;
        m_join(sptr, sptr, 2, join);
      }
    }

    if (feature_bool(FEAT_OPERMOTD))
      m_opermotd(sptr, sptr, 1, parv);

    log_write(LS_OPER, L_INFO, 0, "OPER (%s) by (%#C)", name, sptr);

    ircd_snprintf(0, cli_user(sptr)->response, BUFSIZE+1, "%s", "");
    return 0;
  }

  ircd_snprintf(0, cli_user(sptr)->response, BUFSIZE+1, "%s", "");
  ircd_snprintf(0, cli_user(sptr)->auth_oper, NICKLEN+1, "%s", "");

  aconf = find_conf_exact(parv[1], cli_user(sptr)->realusername,
                          cli_user(sptr)->realhost, CONF_OPS);

  if (!aconf)
    aconf = find_conf_exact(parv[1], cli_user(sptr)->realusername,
                            ircd_ntoa((const char*) &(cli_ip(sptr))), CONF_OPS);

  if (!aconf)
    aconf = find_conf_cidr(parv[1], cli_user(sptr)->realusername,
                            cli_ip(sptr), CONF_OPS);

  if (aconf == NULL)
  {
    send_reply(sptr, ERR_NOOPERHOST);
    failed_challenge_notice(sptr, parv[1], "No o:line");
    sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (No O:line)",
                       parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr));
    return 0;
  }

  if (!(aconf->port & OFLAG_RSA))
  {
    send_reply(sptr, RPL_NO_CHALL);
    return 0;
  }

  if (!verify_sslclifp(sptr, aconf))
  {
    sendto_allops(&me, SNO_OLDREALOP,
           "Failed OPER attempt by %s (%s@%s) (SSL Fingerprint Missmatch)",
           parv[0], cli_user(sptr)->realusername,
           cli_user(sptr)->realhost);
    send_reply(sptr, ERR_SSLCLIFP);
    return 0;
  }

  if ((file = BIO_new_file(aconf->passwd, "r")) == NULL)
  {
    send_reply(sptr, RPL_NO_KEY);
    return 0;
  }

  rsa_public_key = (RSA *)PEM_read_bio_RSA_PUBKEY(file, NULL, 0, NULL);
  if (rsa_public_key == NULL)
     return send_reply(sptr, RPL_INVALID_KEY);


  if (!generate_challenge(&challenge, rsa_public_key, sptr)) {
      Debug((DEBUG_DEBUG, "generating challenge sum (%s)", challenge));
      send_reply(sptr, RPL_RSACHALLENGE, challenge);
      ircd_snprintf(0, cli_user(sptr)->auth_oper, NICKLEN + 1, "%s", aconf->name);
  }
  nl = BIO_set_close(file, BIO_CLOSE);
  BIO_free(file);

  return 1;
#else
  return 1;
#endif
}
Beispiel #16
0
/*
 * mo_settime - oper message handler
 *
 * parv[0] = sender prefix
 * parv[1] = new time
 * parv[2] = servername (Only used when sptr is an Oper).
 */
int mo_settime(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  time_t t;
  long dt;
  static char tbuf[11];

  /* Must be a global oper */
  if (!IsOper(sptr))
    return send_reply(sptr, ERR_NOPRIVILEGES);

  if (parc < 2) /* verify argument count */
    return need_more_params(sptr, "SETTIME");

  if (parc == 2 && MyUser(sptr)) /* default to me */
    parv[parc++] = cli_name(&me);

  t = atoi(parv[1]); /* convert the time */

  /* If we're reliable_clock or if the oper specified a 0 time, use current */
  if (!t || feature_bool(FEAT_RELIABLE_CLOCK))
  {
    t = TStime();
    ircd_snprintf(0, tbuf, sizeof(tbuf), "%Tu", TStime());
    parv[1] = tbuf;
  }

  dt = TStime() - t; /* calculate the delta */

  if (t < OLDEST_TS || dt < -9000000) /* verify value */
  {
    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :SETTIME: Bad value", sptr);
    return 0;
  }

  /* OK, send the message off to its destination */
  if (hunt_server_prio_cmd(sptr, CMD_SETTIME, cptr, 1, "%s %C", 2, parc,
                           parv) != HUNTED_ISME)
    return 0;

  if (feature_bool(FEAT_RELIABLE_CLOCK)) /* don't apply settime--reliable */
  {
    if ((dt > 600) || (dt < -600))
      sendcmdto_serv_butone(&me, CMD_DESYNCH, 0, ":Bad SETTIME from %s: %Tu "
                            "(delta %ld)", cli_name(sptr), t, dt);
    if (IsUser(sptr)) /* Let user know we're ignoring him */
      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :clock is not set %ld seconds "
                    "%s: RELIABLE_CLOCK is defined", sptr, (dt < 0) ? -dt : dt,
                    (dt < 0) ? "forwards" : "backwards");
  }
  else /* tell opers about time change */
  {
    sendto_opmask_butone(0, SNO_OLDSNO, "SETTIME from %s, clock is set %ld "
			 "seconds %s", cli_name(sptr), (dt < 0) ? -dt : dt,
			 (dt < 0) ? "forwards" : "backwards");
    TSoffset -= dt; /* apply time change */
    if (IsUser(sptr)) /* let user know what we did */
      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :clock is set %ld seconds %s",
		    sptr, (dt < 0) ? -dt : dt,
		    (dt < 0) ? "forwards" : "backwards");
  }

  return 0;
}
Beispiel #17
0
int ms_challenge(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
#ifdef USE_SSL
  struct ConfItem *aconf;
  RSA *rsa_public_key;
  BIO *file = NULL;
  char *challenge = NULL;
  char *name;
  char *tmpname;
  char             chan[CHANNELLEN-1];
  char*            join[2];
  int nl;
  struct Client *acptr = NULL;
  char *privbuf;

  if (!IsServer(cptr))
    return 0;

  /* if theyre an oper, reprint oper motd and ignore */
  if (IsOper(sptr))
  {
    send_reply(sptr, RPL_YOUREOPER);
    if (feature_bool(FEAT_OPERMOTD))
      m_opermotd(sptr, sptr, 1, parv);
  }

  if (parc < 3) {
    return send_reply(sptr, ERR_NOOPERHOST);
  }

  if (!(acptr = FindNServer(parv[1]))) {
    return send_reply(sptr, ERR_NOOPERHOST);
  } else if (!IsMe(acptr)) {
    sendcmdto_one(sptr, CMD_CHALLENGE, acptr, "%C %s %s", acptr, parv[2],
                  parv[3]);
    return 0;
  }

  if (*parv[2] == '+')
  {
    /* Ignore it if we aren't expecting this... -A1kmm */
    if (cli_user(sptr)->response == NULL)
      return 0;

    if (ircd_strcmp(cli_user(sptr)->response, ++parv[2]))
    {
      send_reply(sptr, ERR_PASSWDMISMATCH);
      sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (Password Incorrect)",
                         parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr));
      tmpname = strdup(cli_user(sptr)->auth_oper);
      failed_challenge_notice(sptr, tmpname, "challenge failed");
      return 0;
    }

    name = strdup(cli_user(sptr)->auth_oper);
     
    aconf = find_conf_exact(cli_user(sptr)->auth_oper, cli_user(sptr)->realusername,
                            MyUser(sptr) ? cli_sockhost(sptr) :
                            cli_user(sptr)->realhost, CONF_OPS);

    if (!aconf)
      aconf = find_conf_exact(cli_user(sptr)->auth_oper, cli_user(sptr)->realusername,
                              ircd_ntoa((const char*) &(cli_ip(sptr))), CONF_OPS);

    if (!aconf)
      aconf = find_conf_cidr(cli_user(sptr)->auth_oper, cli_user(sptr)->realusername,
                              cli_ip(sptr), CONF_OPS);

    if (!aconf)
    {
      send_reply(sptr, ERR_NOOPERHOST);
      sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (No O:line)",
                         parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr));
      return 0;
    }

    if (CONF_LOCOP == aconf->status) {
      ClearOper(sptr);
      SetLocOp(sptr);
    }
    else {
      /* This must be called before client_set_privs() */
      SetRemoteOper(sptr);

      if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_WHOIS)) {
        OSetWhois(sptr);
      }
      if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_IDLE)) {
        OSetIdle(sptr);
      }
      if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_XTRAOP)) {
        OSetXtraop(sptr);
      }
      if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_HIDECHANS)) {
        OSetHideChans(sptr);
      }

      /* prevent someone from being both oper and local oper */
      ClearLocOp(sptr);

      if (!feature_bool(FEAT_OPERFLAGS) || !(aconf->port & OFLAG_ADMIN)) {
        /* Global Oper */
        ClearAdmin(sptr);
        OSetGlobal(sptr);
        SetOper(sptr);
      } else {
        /* Admin */
        OSetGlobal(sptr);
        OSetAdmin(sptr);
        SetOper(sptr);
        SetAdmin(sptr);
      }

      /* Tell client_set_privs to send privileges to the user */
      client_set_privs(sptr, aconf);

      ClearOper(sptr);
      ClearAdmin(sptr);

      ClearRemoteOper(sptr);
      privbuf = client_print_privs(sptr);
      sendcmdto_one(&me, CMD_PRIVS, sptr, "%C %s", sptr, privbuf);
    }

    sendcmdto_one(&me, CMD_MODE, sptr, "%s %s", cli_name(sptr),
                  (OIsAdmin(sptr)) ? "+aoiwsg" : "+oiwsg");

    send_reply(sptr, RPL_YOUREOPER);

    if (OIsAdmin(sptr)) {
      sendto_allops(&me, SNO_OLDSNO, "%s (%s@%s) is now an IRC Administrator",
                    parv[0], cli_user(sptr)->username, cli_sockhost(sptr));

      /* Autojoin admins to admin channel and oper channel (if enabled) */
      if (feature_bool(FEAT_AUTOJOIN_ADMIN)) {
        if (feature_bool(FEAT_AUTOJOIN_ADMIN_NOTICE))
              sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, feature_str(FEAT_AUTOJOIN_ADMIN_NOTICE_VALUE));

        ircd_strncpy(chan, feature_str(FEAT_AUTOJOIN_ADMIN_CHANNEL), CHANNELLEN-1);
        join[0] = cli_name(sptr);
        join[1] = chan;
        m_join(sptr, sptr, 2, join);
      }
      if (feature_bool(FEAT_AUTOJOIN_OPER) && OIsGlobal(sptr)) {
        if (feature_bool(FEAT_AUTOJOIN_OPER_NOTICE))
              sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, feature_str(FEAT_AUTOJOIN_OPER_NOTICE_VALUE));

        ircd_strncpy(chan, feature_str(FEAT_AUTOJOIN_OPER_CHANNEL), CHANNELLEN-1);
        join[0] = cli_name(sptr);
        join[1] = chan;
        m_join(sptr, sptr, 2, join);
      }
    } else {
      sendto_allops(&me, SNO_OLDSNO, "%s (%s@%s) is now an IRC Operator (%c)",
                         parv[0], cli_user(sptr)->username, cli_sockhost(sptr),
                         OIsGlobal(sptr) ? 'O' : 'o');

      if (feature_bool(FEAT_AUTOJOIN_OPER) && OIsGlobal(sptr)) {
        if (feature_bool(FEAT_AUTOJOIN_OPER_NOTICE))
              sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, feature_str(FEAT_AUTOJOIN_OPER_NOTICE_VALUE));

        ircd_strncpy(chan, feature_str(FEAT_AUTOJOIN_OPER_CHANNEL), CHANNELLEN-1);
        join[0] = cli_name(sptr);
        join[1] = chan;
        m_join(sptr, sptr, 2, join);
      }
    }

    if (feature_bool(FEAT_OPERMOTD))
      m_opermotd(sptr, sptr, 1, parv);

    log_write(LS_OPER, L_INFO, 0, "OPER (%s) by (%#C)", name, sptr);

    ircd_snprintf(0, cli_user(sptr)->response, BUFSIZE+1, "%s", "");
    return 0;
  }

  ircd_snprintf(0, cli_user(sptr)->response, BUFSIZE+1, "%s", "");
  ircd_snprintf(0, cli_user(sptr)->auth_oper, NICKLEN+1, "%s", "");

  aconf = find_conf_exact(parv[2], cli_user(sptr)->realusername,
                          cli_user(sptr)->realhost, CONF_OPS);

  if (!aconf)
    aconf = find_conf_exact(parv[2], cli_user(sptr)->realusername,
                            ircd_ntoa((const char*) &(cli_ip(sptr))), CONF_OPS);

  if (!aconf)
    aconf = find_conf_cidr(parv[2], cli_user(sptr)->realusername,
                            cli_ip(sptr), CONF_OPS);

  if (aconf == NULL)
  {
    send_reply(sptr, ERR_NOOPERHOST);
    failed_challenge_notice(sptr, parv[2], "No o:line");
    sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (No O:line)",
                       parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr));
    return 0;
  }

  if (!(aconf->port & OFLAG_REMOTE)) {
    send_reply(sptr, ERR_NOOPERHOST);
    sendto_allops(&me, SNO_OLDREALOP,
      "Failed OPER attempt by %s (%s@%s) (Remote Oper)", parv[0],
      cli_user(sptr)->realusername, cli_user(sptr)->realhost);
    return 0;
  }

  if (!(aconf->port & OFLAG_RSA))
  {
    send_reply(sptr, RPL_NO_CHALL);
    return 0;
  }

  if (!verify_sslclifp(sptr, aconf))
  {
    sendto_allops(&me, SNO_OLDREALOP,
           "Failed OPER attempt by %s (%s@%s) (SSL Fingerprint Missmatch)",
           parv[0], cli_user(sptr)->realusername,
           cli_user(sptr)->realhost);
    send_reply(sptr, ERR_SSLCLIFP);
    return 0;
  }

  if ((file = BIO_new_file(aconf->passwd, "r")) == NULL)
  {
    send_reply(sptr, RPL_NO_KEY);
    return 0;
  }

  rsa_public_key = (RSA *)PEM_read_bio_RSA_PUBKEY(file, NULL, 0, NULL);
  if (rsa_public_key == NULL)
     return send_reply(sptr, RPL_INVALID_KEY);


  if (!generate_challenge(&challenge, rsa_public_key, sptr)) {
      Debug((DEBUG_DEBUG, "generating challenge sum (%s)", challenge));
      send_reply(sptr, RPL_RSACHALLENGE, challenge);
      ircd_snprintf(0, cli_user(sptr)->auth_oper, NICKLEN + 1, "%s", aconf->name);
  }
  nl = BIO_set_close(file, BIO_CLOSE);
  BIO_free(file);

  return 1;
#else
  return 1;
#endif
}
Beispiel #18
0
/** Modify a global Z-line.
 * @param[in] cptr Client that sent us the Z-line modification.
 * @param[in] sptr Client that originated the Z-line modification.
 * @param[in] zline Z-line being modified.
 * @param[in] action Resultant status of the Z-line.
 * @param[in] reason Reason for Z-line.
 * @param[in] expire Expiration time of Z-line.
 * @param[in] lastmod Last modification time of Z-line.
 * @param[in] lifetime Lifetime of Z-line.
 * @param[in] flags Bitwise combination of ZLINE_* flags.
 * @return Zero or CPTR_KILLED, depending on whether \a sptr is suicidal.
 */
int
zline_modify(struct Client *cptr, struct Client *sptr, struct Zline *zline,
	     enum ZlineAction action, char *reason, time_t expire,
	     time_t lastmod, time_t lifetime, unsigned int flags)
{
  char buf[BUFSIZE], *op = "";
  int pos = 0, non_auto = 0;

  assert(zline);
  assert(!ZlineIsLocal(zline));

  Debug((DEBUG_DEBUG,  "zline_modify(\"%s\", \"%s\", \"%s\", %s, \"%s\", "
	 "%Tu, %Tu, %Tu, 0x%04x)", cli_name(cptr), cli_name(sptr),
	 zline->zl_mask,
	 action == ZLINE_ACTIVATE ? "ZLINE_ACTIVATE" :
	 (action == ZLINE_DEACTIVATE ? "ZLINE_DEACTIVATE" :
	  (action == ZLINE_LOCAL_ACTIVATE ? "ZLINE_LOCAL_ACTIVATE" :
	   (action == ZLINE_LOCAL_DEACTIVATE ? "ZLINE_LOCAL_DEACTIVATE" :
	    (action == ZLINE_MODIFY ? "ZLINE_MODIFY" : "<UNKNOWN>")))),
	 reason, expire, lastmod, lifetime, flags));

  /* First, let's check lastmod... */
  if (action != ZLINE_LOCAL_ACTIVATE && action != ZLINE_LOCAL_DEACTIVATE) {
    if (ZlineLastMod(zline) > lastmod) { /* we have a more recent version */
      if (IsBurstOrBurstAck(cptr))
	return 0; /* middle of a burst, it'll resync on its own */
      return zline_resend(cptr, zline); /* resync the server */
    } else if (ZlineLastMod(zline) == lastmod)
      return 0; /* we have that version of the Z-line... */
  }

  /* All right, we know that there's a change of some sort.  What is it? */
  /* first, check out the expiration time... */
  if ((flags & ZLINE_EXPIRE) && expire) {
    if (!(flags & ZLINE_FORCE) &&
	(expire <= TStime() || expire > TStime() + ZLINE_MAX_EXPIRE)) {
      if (!IsServer(sptr) && MyConnect(sptr)) /* bad expiration time */
	send_reply(sptr, ERR_BADEXPIRE, expire);
      return 0;
    }
  } else
    flags &= ~ZLINE_EXPIRE;

  /* Now check to see if there's any change... */
  if ((flags & ZLINE_EXPIRE) && expire == zline->zl_expire) {
    flags &= ~ZLINE_EXPIRE; /* no change to expiration time... */
    expire = 0;
  }

  /* Next, check out lifetime--this one's a bit trickier... */
  if (!(flags & ZLINE_LIFETIME) || !lifetime)
    lifetime = zline->zl_lifetime; /* use Z-line lifetime */

  lifetime = IRCD_MAX(lifetime, expire); /* set lifetime to the max */

  /* OK, let's see which is greater... */
  if (lifetime > zline->zl_lifetime)
    flags |= ZLINE_LIFETIME; /* have to update lifetime */
  else {
    flags &= ~ZLINE_LIFETIME; /* no change to lifetime */
    lifetime = 0;
  }

  /* Finally, let's see if the reason needs to be updated */
  if ((flags & ZLINE_REASON) && reason &&
      !ircd_strcmp(zline->zl_reason, reason))
    flags &= ~ZLINE_REASON; /* no changes to the reason */

  /* OK, now let's take a look at the action... */
  if ((action == ZLINE_ACTIVATE && (zline->zl_flags & ZLINE_ACTIVE)) ||
      (action == ZLINE_DEACTIVATE && !(zline->zl_flags & ZLINE_ACTIVE)) ||
      (action == ZLINE_LOCAL_ACTIVATE &&
       (zline->zl_state == ZLOCAL_ACTIVATED)) ||
      (action == ZLINE_LOCAL_DEACTIVATE &&
       (zline->zl_state == ZLOCAL_DEACTIVATED)) ||
      /* can't activate an expired Z-line */
      IRCD_MAX(zline->zl_expire, expire) <= TStime())
    action = ZLINE_MODIFY; /* no activity state modifications */

  Debug((DEBUG_DEBUG,  "About to perform changes; flags 0x%04x, action %s",
	 flags, action == ZLINE_ACTIVATE ? "ZLINE_ACTIVATE" :
	 (action == ZLINE_DEACTIVATE ? "ZLINE_DEACTIVATE" :
	  (action == ZLINE_LOCAL_ACTIVATE ? "ZLINE_LOCAL_ACTIVATE" :
	   (action == ZLINE_LOCAL_DEACTIVATE ? "ZLINE_LOCAL_DEACTIVATE" :
	    (action == ZLINE_MODIFY ? "ZLINE_MODIFY" : "<UNKNOWN>"))))));

  /* If there are no changes to perform, do no changes */
  if (!(flags & ZLINE_UPDATE) && action == ZLINE_MODIFY)
    return 0;

  /* Now we know what needs to be changed, so let's process the changes... */

  /* Start by updating lastmod, if indicated... */
  if (action != ZLINE_LOCAL_ACTIVATE && action != ZLINE_LOCAL_DEACTIVATE)
    zline->zl_lastmod = lastmod;

  /* Then move on to activity status changes... */
  switch (action) {
  case ZLINE_ACTIVATE: /* Globally activating Z-line */
    zline->zl_flags |= ZLINE_ACTIVE; /* make it active... */
    zline->zl_state = ZLOCAL_GLOBAL; /* reset local activity state */
    pos += ircd_snprintf(0, buf, sizeof(buf), " globally activating Z-line");
    op = "+"; /* operation for Z-line propagation */
    break;

  case ZLINE_DEACTIVATE: /* Globally deactivating Z-line */
    zline->zl_flags &= ~ZLINE_ACTIVE; /* make it inactive... */
    zline->zl_state = ZLOCAL_GLOBAL; /* reset local activity state */
    pos += ircd_snprintf(0, buf, sizeof(buf), " globally deactivating Z-line");
    op = "-"; /* operation for Z-line propagation */
    break;

  case ZLINE_LOCAL_ACTIVATE: /* Locally activating Z-line */
    zline->zl_state = ZLOCAL_ACTIVATED; /* make it locally active */
    pos += ircd_snprintf(0, buf, sizeof(buf), " locally activating Z-line");
    break;

  case ZLINE_LOCAL_DEACTIVATE: /* Locally deactivating Z-line */
    zline->zl_state = ZLOCAL_DEACTIVATED; /* make it locally inactive */
    pos += ircd_snprintf(0, buf, sizeof(buf), " locally deactivating Z-line");
    break;

  case ZLINE_MODIFY: /* no change to activity status */
    break;
  }

  /* Handle expiration changes... */
  if (flags & ZLINE_EXPIRE) {
    zline->zl_expire = expire; /* save new expiration time */
    if (pos < BUFSIZE)
      pos += ircd_snprintf(0, buf + pos, sizeof(buf) - pos,
			   "%s%s changing expiration time to %Tu",
			   pos ? ";" : "",
			   pos && !(flags & (ZLINE_LIFETIME | ZLINE_REASON)) ?
			   " and" : "", expire);
  }

  /* Next, handle lifetime changes... */
  if (flags & ZLINE_LIFETIME) {
    zline->zl_lifetime = lifetime; /* save new lifetime */
    if (pos < BUFSIZE)
      pos += ircd_snprintf(0, buf + pos, sizeof(buf) - pos,
			   "%s%s extending record lifetime to %Tu",
			   pos ? ";" : "", pos && !(flags & ZLINE_REASON) ?
			   " and" : "", lifetime);
  }

  /* Now, handle reason changes... */
  if (flags & ZLINE_REASON) {
    non_auto = non_auto || ircd_strncmp(zline->zl_reason, "AUTO", 4);
    MyFree(zline->zl_reason); /* release old reason */
    DupString(zline->zl_reason, reason); /* store new reason */
    if (pos < BUFSIZE)
      pos += ircd_snprintf(0, buf + pos, sizeof(buf) - pos,
			   "%s%s changing reason to \"%s\"",
			   pos ? ";" : "", pos ? " and" : "", reason);
  }

  /* All right, inform ops... */
  non_auto = non_auto || ircd_strncmp(zline->zl_reason, "AUTO", 4);
  sendto_opmask_butone(0, non_auto ? SNO_GLINE : SNO_AUTO,
		       "%s modifying global ZLINE for %s:%s",
		       (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
		       cli_name(sptr) : cli_name((cli_user(sptr))->server),
		       zline->zl_mask, buf);

  /* and log the change */
  log_write(LS_GLINE, L_INFO, LOG_NOSNOTICE,
	    "%#C modifying global ZLINE for %s:%s", sptr, zline->zl_mask, buf);

  /* We'll be simple for this release, but we can update this to change
   * the propagation syntax on future updates
   */
  if (action != ZLINE_LOCAL_ACTIVATE && action != ZLINE_LOCAL_DEACTIVATE)
    sendcmdto_serv_butone(sptr, CMD_ZLINE, cptr,
			  "* %s%s%s %Tu %Tu %Tu :%s",
			  flags & ZLINE_OPERFORCE ? "!" : "", op,
			  zline->zl_mask, zline->zl_expire - TStime(),
                          zline->zl_lastmod, zline->zl_lifetime, zline->zl_reason);

  /* OK, let's do the Z-line... */
  return do_zline(cptr, sptr, zline);
}
Beispiel #19
0
/*
 * ms_settime - server message handler
 *
 * parv[0] = sender prefix
 * parv[1] = new time
 * parv[2] = server name (Only used when sptr is an Oper).
 */
int ms_settime(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  time_t t;
  long dt;
  static char tbuf[11];
  struct DLink *lp;

  if (parc < 2) /* verify argument count */
    return need_more_params(sptr, "SETTIME");

  t = atoi(parv[1]); /* convert time and compute delta */
  dt = TStime() - t;

  /* verify value */
  if (t < OLDEST_TS || dt < -9000000)
  {
    if (IsServer(sptr)) /* protocol violation if it's from a server */
      protocol_violation(sptr, "SETTIME: Bad value (%Tu, delta %ld)", t, dt);
    else
      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :SETTIME: Bad value (%Tu, "
                    "delta %ld)", sptr, t, dt);
      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :SETTIME: Bad value", sptr);
    return 0;
  }

  /* reset time... */
  if (feature_bool(FEAT_RELIABLE_CLOCK))
  {
    ircd_snprintf(0, tbuf, sizeof(tbuf), "%Tu", TStime());
    parv[1] = tbuf;
  }

  if (BadPtr(parv[2])) /* spam the network */
  {
    for (lp = cli_serv(&me)->down; lp; lp = lp->next)
      if (cptr != lp->value.cptr)
        sendcmdto_prio_one(sptr, CMD_SETTIME, lp->value.cptr, "%s", parv[1]);
  }
  else
  {
    if (hunt_server_prio_cmd(sptr, CMD_SETTIME, cptr, 1, "%s %C", 2, parc,
                             parv) != HUNTED_ISME)
    {
      /* If the destination was *not* me, but I'm RELIABLE_CLOCK and the
       * delta is more than 30 seconds off, bounce back a corrected
       * SETTIME
       */
      if (feature_bool(FEAT_RELIABLE_CLOCK) && (dt > 30 || dt < -30))
        sendcmdto_prio_one(&me, CMD_SETTIME, cptr, "%s %C", parv[1], cptr);
      return 0;
    }
  }

  if (feature_bool(FEAT_RELIABLE_CLOCK))
  {
    /* don't apply settime--reliable */
    if ((dt > 600) || (dt < -600))
      sendcmdto_serv_butone(&me, CMD_DESYNCH, 0, ":Bad SETTIME from %s: %Tu "
                            "(delta %ld)", cli_name(sptr), t, dt);
    /* Let user know we're ignoring him */
    if (IsUser(sptr))
    {
      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :clock is not set %ld "
		    "seconds %s : RELIABLE_CLOCK is defined", sptr,
		    (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
    }
  }
  else /* tell opers about time change */
  {
    sendto_opmask_butone(0, SNO_OLDSNO, "SETTIME from %s, clock is set %ld "
			 "seconds %s", cli_name(sptr), (dt < 0) ? -dt : dt,
			 (dt < 0) ? "forwards" : "backwards");
    /* Apply time change... */
    TSoffset -= dt;
    /* Let the issuing user know what we did... */
    if (IsUser(sptr))
    {
      sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :clock is set %ld seconds %s",
                    sptr, (dt < 0) ? -dt : dt,
                    (dt < 0) ? "forwards" : "backwards");
    }
  }

  return 0;
}
Beispiel #20
0
/** Read a 'packet' of data from a connection and process it.  Read in
 * 8k chunks to give a better performance rating (for server
 * connections).  Do some tricky stuff for client connections to make
 * sure they don't do any flooding >:-) -avalon
 * @param cptr Client from which to read data.
 * @param socket_ready If non-zero, more data can be read from the client's socket.
 * @return Positive number on success, zero on connection-fatal failure, negative
 *   if user is killed.
 */
static int read_packet(struct Client *cptr, int socket_ready)
{
  unsigned int dolen = 0;
  unsigned int length = 0;

  if (socket_ready &&
      !(IsUser(cptr) &&
	DBufLength(&(cli_recvQ(cptr))) > feature_uint(FEAT_CLIENT_FLOOD))) {
#if defined(USE_SSL)
    switch (client_recv(cptr, readbuf, sizeof(readbuf), &length)) {
#else
    switch (os_recv_nonb(cli_fd(cptr), readbuf, sizeof(readbuf), &length)) {
#endif
    case IO_SUCCESS:
      if (length)
      {
        cli_lasttime(cptr) = CurrentTime;
        ClearPingSent(cptr);
        ClrFlag(cptr, FLAG_NONL);
        if (cli_lasttime(cptr) > cli_since(cptr))
          cli_since(cptr) = cli_lasttime(cptr);
      }
      break;
    case IO_BLOCKED:
      break;
    case IO_FAILURE:
      cli_error(cptr) = errno;
      /* SetFlag(cptr, FLAG_DEADSOCKET); */
      return 0;
    }
  }

  /*
   * For server connections, we process as many as we can without
   * worrying about the time of day or anything :)
   */
  if (length > 0 && IsServer(cptr))
    return server_dopacket(cptr, readbuf, length);
  else if (length > 0 && (IsHandshake(cptr) || IsConnecting(cptr)))
    return connect_dopacket(cptr, readbuf, length);
  else
  {
    /*
     * Before we even think of parsing what we just read, stick
     * it on the end of the receive queue and do it when its
     * turn comes around.
     */
    if (length > 0 && dbuf_put(cptr, &(cli_recvQ(cptr)), readbuf, length) == 0)
      return exit_client(cptr, cptr, &me, "dbuf_put fail");

    if ((DBufLength(&(cli_recvQ(cptr))) > feature_uint(FEAT_CLIENT_FLOOD))
         && !IsChannelService(cptr))
      return exit_client(cptr, cptr, &me, "Excess Flood");

    while (DBufLength(&(cli_recvQ(cptr))) && !NoNewLine(cptr) &&
           (IsTrusted(cptr) || IsChannelService(cptr) || cli_since(cptr) - CurrentTime < 10))
    {
      dolen = dbuf_getmsg(&(cli_recvQ(cptr)), cli_buffer(cptr), BUFSIZE);
      /*
       * Devious looking...whats it do ? well..if a client
       * sends a *long* message without any CR or LF, then
       * dbuf_getmsg fails and we pull it out using this
       * loop which just gets the next 512 bytes and then
       * deletes the rest of the buffer contents.
       * -avalon
       */
      if (dolen == 0)
      {
        if (DBufLength(&(cli_recvQ(cptr))) < 510)
          SetFlag(cptr, FLAG_NONL);
        else
        {
          /* More than 512 bytes in the line - drop the input and yell
           * at the client.
           */
          DBufClear(&(cli_recvQ(cptr)));
          send_reply(cptr, ERR_INPUTTOOLONG);
        }
      }
      else if (client_dopacket(cptr, dolen) == CPTR_KILLED)
        return CPTR_KILLED;
      /*
       * If it has become registered as a Server
       * then skip the per-message parsing below.
       */
      if (IsHandshake(cptr) || IsServer(cptr))
      {
        while (-1)
        {
          dolen = dbuf_get(&(cli_recvQ(cptr)), readbuf, sizeof(readbuf));
          if (dolen <= 0)
            return 1;
          else if (dolen == 0)
          {
            if (DBufLength(&(cli_recvQ(cptr))) < 510)
              SetFlag(cptr, FLAG_NONL);
            else {
              DBufClear(&(cli_recvQ(cptr)));
              /* send_reply(cptr, ERR_INPUTTOOLONG); */
            }
          }
          else if ((IsServer(cptr) &&
                    server_dopacket(cptr, readbuf, dolen) == CPTR_KILLED) ||
                   (!IsServer(cptr) &&
                    connect_dopacket(cptr, readbuf, dolen) == CPTR_KILLED))
            return CPTR_KILLED;
        }
      }
    }

    /* If there's still data to process, wait 2 seconds first */
    if (DBufLength(&(cli_recvQ(cptr))) && !NoNewLine(cptr) &&
	!t_onqueue(&(cli_proc(cptr))))
    {
      Debug((DEBUG_LIST, "Adding client process timer for %C", cptr));
      cli_freeflag(cptr) |= FREEFLAG_TIMER;
      timer_add(&(cli_proc(cptr)), client_timer_callback, cli_connect(cptr),
		TT_RELATIVE, 2);
    }
  }
  return 1;
}

/** Start a connection to another server.
 * @param aconf Connect block data for target server.
 * @param by Client who requested the connection (if any).
 * @return Non-zero on success; zero on failure.
 */
int connect_server(struct ConfItem* aconf, struct Client* by)
{
  struct Client*   cptr = 0;
  assert(0 != aconf);

  if (aconf->dns_pending) {
    sendto_opmask(0, SNO_OLDSNO, "Server %s connect DNS pending",
                  aconf->name);
    return 0;
  }
  Debug((DEBUG_NOTICE, "Connect to %s[@%s]", aconf->name,
         ircd_ntoa(&aconf->address.addr)));

  if ((cptr = FindClient(aconf->name))) {
    if (IsServer(cptr) || IsMe(cptr)) {
      sendto_opmask(0, SNO_OLDSNO, "Server %s already present from %s",
                    aconf->name, cli_name(cli_from(cptr)));
      if (by && IsUser(by) && !MyUser(by)) {
        sendcmdto_one(&me, CMD_NOTICE, by, "%C :Server %s already present "
                      "from %s", by, aconf->name, cli_name(cli_from(cptr)));
      }
      return 0;
    }
    else if (IsHandshake(cptr) || IsConnecting(cptr)) {
      if (by && IsUser(by)) {
        sendcmdto_one(&me, CMD_NOTICE, by, "%C :Connection to %s already in "
                      "progress", by, cli_name(cptr));
      }
      return 0;
    }
  }
  /*
   * If we don't know the IP# for this host and it is a hostname and
   * not a ip# string, then try and find the appropriate host record.
   */
  if (!irc_in_addr_valid(&aconf->address.addr)
      && !ircd_aton(&aconf->address.addr, aconf->host)) {
    char buf[HOSTLEN + 1];

    host_from_uh(buf, aconf->host, HOSTLEN);
    gethost_byname(buf, connect_dns_callback, aconf);
    aconf->dns_pending = 1;
    return 0;
  }
  cptr = make_client(NULL, STAT_UNKNOWN_SERVER);

  /*
   * Copy these in so we have something for error detection.
   */
  ircd_strncpy(cli_name(cptr), aconf->name, HOSTLEN);
  ircd_strncpy(cli_sockhost(cptr), aconf->host, HOSTLEN);

  /*
   * Attach config entries to client here rather than in
   * completed_connection. This to avoid null pointer references
   */
  attach_confs_byhost(cptr, aconf->host, CONF_SERVER);

  if (!find_conf_byhost(cli_confs(cptr), aconf->host, CONF_SERVER)) {
    sendto_opmask(0, SNO_OLDSNO, "Host %s is not enabled for "
                  "connecting: no Connect block", aconf->name);
    if (by && IsUser(by) && !MyUser(by)) {
      sendcmdto_one(&me, CMD_NOTICE, by, "%C :Connect to host %s failed: no "
                    "Connect block", by, aconf->name);
    }
    det_confs_butmask(cptr, 0);
    free_client(cptr);
    return 0;
  }
  /*
   * attempt to connect to the server in the conf line
   */
  if (!connect_inet(aconf, cptr)) {
    if (by && IsUser(by) && !MyUser(by)) {
      sendcmdto_one(&me, CMD_NOTICE, by, "%C :Couldn't connect to %s", by,
                    cli_name(cptr));
    }
    det_confs_butmask(cptr, 0);
    free_client(cptr);
    return 0;
  }
  /*
   * NOTE: if we're here we have a valid C:Line and the client should
   * have started the connection and stored the remote address/port and
   * ip address name in itself
   *
   * The socket has been connected or connect is in progress.
   */
  make_server(cptr);
  if (by && IsUser(by)) {
    ircd_snprintf(0, cli_serv(cptr)->by, sizeof(cli_serv(cptr)->by), "%s%s",
		  NumNick(by));
    assert(0 == cli_serv(cptr)->user);
    cli_serv(cptr)->user = cli_user(by);
    cli_user(by)->refcnt++;
  }
  else {
    *(cli_serv(cptr))->by = '\0';
    /* strcpy(cptr->serv->by, "Auto"); */
  }
  cli_serv(cptr)->up = &me;
  SetConnecting(cptr);

  if (cli_fd(cptr) > HighestFd)
    HighestFd = cli_fd(cptr);

  LocalClientArray[cli_fd(cptr)] = cptr;

  Count_newunknown(UserStats);
  /* Actually we lie, the connect hasn't succeeded yet, but we have a valid
   * cptr, so we register it now.
   * Maybe these two calls should be merged.
   */
  add_client_to_list(cptr);
  hAddClient(cptr);
/*    nextping = CurrentTime; */

  return (s_state(&cli_socket(cptr)) == SS_CONNECTED) ?
    completed_connection(cptr) : 1;
}

/** Find the real hostname for the host running the server (or one which
 * matches the server's name) and its primary IP#.  Hostname is stored
 * in the client structure passed as a pointer.
 */
void init_server_identity(void)
{
  const struct LocalConf* conf = conf_get_local();
  assert(0 != conf);

  ircd_strncpy(cli_name(&me), conf->name, HOSTLEN);
  SetYXXServerName(&me, conf->numeric);
}

/** Process events on a client socket.
 * @param ev Socket event structure that has a struct Connection as
 *   its associated data.
 */
static void client_sock_callback(struct Event* ev)
{
  struct Client* cptr;
  struct Connection* con;
  char *fmt = "%s";
  char *fallback = 0;

  assert(0 != ev_socket(ev));
  assert(0 != s_data(ev_socket(ev)));

  con = (struct Connection*) s_data(ev_socket(ev));

  assert(0 != con_client(con) || ev_type(ev) == ET_DESTROY);

  cptr = con_client(con);

  assert(0 == cptr || con == cli_connect(cptr));

  switch (ev_type(ev)) {
  case ET_DESTROY:
    con_freeflag(con) &= ~FREEFLAG_SOCKET;

    if (!con_freeflag(con) && !cptr)
      free_connection(con);
#if defined(USE_SSL)
    ssl_free(ev_socket(ev));
#endif
    break;

  case ET_CONNECT: /* socket connection completed */
    if (!completed_connection(cptr) || IsDead(cptr))
      fallback = cli_info(cptr);
    break;

  case ET_ERROR: /* an error occurred */
    fallback = cli_info(cptr);
    cli_error(cptr) = ev_data(ev);
    /* If the OS told us we have a bad file descriptor, we should
     * record that for future reference.
     */
    if (cli_error(cptr) == EBADF)
      cli_fd(cptr) = -1;
    if (s_state(&(con_socket(con))) == SS_CONNECTING) {
      completed_connection(cptr);
      /* for some reason, the os_get_sockerr() in completed_connection()
       * can return 0 even when ev_data(ev) indicates a real error, so
       * re-assign the client error here.
       */
      cli_error(cptr) = ev_data(ev);
      break;
    }
    /*FALLTHROUGH*/
  case ET_EOF: /* end of file on socket */
    Debug((DEBUG_ERROR, "READ ERROR: fd = %d %d", cli_fd(cptr),
	   cli_error(cptr)));
    SetFlag(cptr, FLAG_DEADSOCKET);
    if ((IsServer(cptr) || IsHandshake(cptr)) && cli_error(cptr) == 0) {
      exit_client_msg(cptr, cptr, &me, "Server %s closed the connection (%s)",
		      cli_name(cptr), cli_serv(cptr)->last_error_msg);
      return;
    } else {
      fmt = "Read error: %s";
      fallback = "EOF from client";
    }
    break;

  case ET_WRITE: /* socket is writable */
    ClrFlag(cptr, FLAG_BLOCKED);
    if (cli_listing(cptr) && MsgQLength(&(cli_sendQ(cptr))) < 2048)
      list_next_channels(cptr);
    Debug((DEBUG_SEND, "Sending queued data to %C", cptr));
    send_queued(cptr);
    break;

  case ET_READ: /* socket is readable */
    if (!IsDead(cptr)) {
      Debug((DEBUG_DEBUG, "Reading data from %C", cptr));
      if (read_packet(cptr, 1) == 0) /* error while reading packet */
	fallback = "EOF from client";
    }
    break;

  default:
    assert(0 && "Unrecognized socket event in client_sock_callback()");
    break;
  }

  assert(0 == cptr || 0 == cli_connect(cptr) || con == cli_connect(cptr));

  if (fallback) {
    const char* msg = (cli_error(cptr)) ? strerror(cli_error(cptr)) : fallback;
    if (!msg)
      msg = "Unknown error";
    exit_client_msg(cptr, cptr, &me, fmt, msg);
  }
}

/** Process a timer on client socket.
 * @param ev Timer event that has a struct Connection as its
 * associated data.
 */
static void client_timer_callback(struct Event* ev)
{
  struct Client* cptr;
  struct Connection* con;

  assert(0 != ev_timer(ev));
  assert(0 != t_data(ev_timer(ev)));
  assert(ET_DESTROY == ev_type(ev) || ET_EXPIRE == ev_type(ev));

  con = (struct Connection*) t_data(ev_timer(ev));

  assert(0 != con_client(con) || ev_type(ev) == ET_DESTROY);

  cptr = con_client(con);

  assert(0 == cptr || con == cli_connect(cptr));

  if (ev_type(ev)== ET_DESTROY) {
    con_freeflag(con) &= ~FREEFLAG_TIMER; /* timer has expired... */

    if (!con_freeflag(con) && !cptr)
      free_connection(con); /* client is being destroyed */
  } else {
    Debug((DEBUG_LIST, "Client process timer for %C expired; processing",
	   cptr));
    read_packet(cptr, 0); /* read_packet will re-add timer if needed */
  }

  assert(0 == cptr || 0 == cli_connect(cptr) || con == cli_connect(cptr));
}
Beispiel #21
0
/** Create a new Z-line and add it to global lists.
 * \a ipmask must be an IP mask to create an IP-based ban.
 *
 * @param[in] cptr Client that sent us the Z-line.
 * @param[in] sptr Client that originated the Z-line.
 * @param[in] ipmask Text mask for the Z-line.
 * @param[in] reason Reason for Z-line.
 * @param[in] expire Expiration time of Z-line.
 * @param[in] lastmod Last modification time of Z-line.
 * @param[in] lifetime Lifetime of Z-line.
 * @param[in] flags Bitwise combination of ZLINE_* flags.
 * @return Zero or CPTR_KILLED, depending on whether \a sptr is suicidal.
 */
int
zline_add(struct Client *cptr, struct Client *sptr, char *ipmask,
	  char *reason, time_t expire, time_t lastmod, time_t lifetime,
	  unsigned int flags)
{
  struct Zline *azline;
  char imask[HOSTLEN + 2];
  char *mask;
  int tmp;

  assert(0 != ipmask);
  assert(0 != reason);
  assert(((flags & (ZLINE_GLOBAL | ZLINE_LOCAL)) == ZLINE_GLOBAL) ||
         ((flags & (ZLINE_GLOBAL | ZLINE_LOCAL)) == ZLINE_LOCAL));

  Debug((DEBUG_DEBUG, "zline_add(\"%s\", \"%s\", \"%s\", \"%s\", %Tu, %Tu "
	 "%Tu, 0x%04x)", cli_name(cptr), cli_name(sptr), ipmask, reason,
	 expire, lastmod, lifetime, flags));

  mask = ipmask;
  if (sizeof(imask) <
      ircd_snprintf(0, imask, sizeof(imask), "%s", mask))
    return send_reply(sptr, ERR_LONGMASK);
  else if (MyUser(sptr) || (IsUser(sptr) && flags & ZLINE_LOCAL)) {
    switch (zline_checkmask(mask)) {
      case CHECK_OVERRIDABLE: /* oper overrided restriction */
        if (flags & ZLINE_OPERFORCE)
          break;
      /*FALLTHROUGH*/
      case CHECK_REJECTED:
        return send_reply(sptr, ERR_MASKTOOWIDE, imask);
        break;
    }

    if ((tmp = count_users(imask, flags)) >=
      feature_int(FEAT_ZLINEMAXUSERCOUNT) && !(flags & ZLINE_OPERFORCE))
    return send_reply(sptr, ERR_TOOMANYUSERS, tmp);
  }

  if (!check_if_ipmask(ipmask))
    return send_reply(sptr, ERR_INVALIDMASK);

  /*
   * You cannot set a negative (or zero) expire time, nor can you set an
   * expiration time for greater than ZLINE_MAX_EXPIRE.
   */
  if (!(flags & ZLINE_FORCE) &&
      (expire <= TStime() || expire > TStime() + ZLINE_MAX_EXPIRE)) {
    if (!IsServer(sptr) && MyConnect(sptr))
      send_reply(sptr, ERR_BADEXPIRE, expire);
    return 0;
  } else if (expire <= TStime()) {
    /* This expired Z-line was forced to be added, so mark it inactive. */
    flags &= ~ZLINE_ACTIVE;
  }

  if (!lifetime) /* no lifetime set, use expiration time */
    lifetime = expire;

  /* lifetime is already an absolute timestamp */

  /* Inform ops... */
  sendto_opmask_butone(0, ircd_strncmp(reason, "AUTO", 4) ? SNO_GLINE :
                       SNO_AUTO, "%s adding %s%s ZLINE for %s, expiring at "
                       "%Tu: %s",
                       (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
                         cli_name(sptr) :
                         cli_name((cli_user(sptr))->server),
                       (flags & ZLINE_ACTIVE) ? "" : "deactivated ",
		       (flags & ZLINE_LOCAL) ? "local" : "global",
		       mask, expire, reason);

  /* and log it */
  log_write(LS_GLINE, L_INFO, LOG_NOSNOTICE,
	    "%#C adding %s ZLINE for %s, expiring at %Tu: %s", sptr,
	    flags & ZLINE_LOCAL ? "local" : "global", mask,
	    expire, reason);

  /* make the zline */
  azline = make_zline(mask, reason, expire, lastmod, lifetime, flags);

  /* since we've disabled overlapped Z-line checking, azline should
   * never be NULL...
   */
  assert(azline);

  zline_propagate(cptr, sptr, azline);

  return do_zline(cptr, sptr, azline); /* knock off users if necessary */
}
Beispiel #22
0
/*
 * The function that actually prints out the WHO reply for a client found
 */
void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
            int fields, char* qrt)
{
  char *p1;
  struct Channel *chptr = repchan;

  static char buf1[512];
  /* NOTE: with current fields list and sizes this _cannot_ overrun, 
     and also the message finally sent shouldn't ever be truncated */

  p1 = buf1;
  buf1[1] = '\0';

  /* If we don't have a channel and we need one... try to find it,
     unless the listing is for a channel service, we already know
     that there are no common channels, thus use PubChannel and not
     SeeChannel */
  if (!chptr && (!fields || (fields & (WHO_FIELD_CHA | WHO_FIELD_FLA))) &&
      !IsChannelService(acptr))
  {
    struct Membership* chan;
    for (chan = cli_user(acptr)->channel; chan && !chptr; chan = chan->next_channel)
      if (PubChannel(chan->channel) &&
          (acptr == sptr || !IsZombie(chan)))
        chptr = chan->channel;
  }

  /* Place the fields one by one in the buffer and send it
     note that fields == NULL means "default query" */

  if (fields & WHO_FIELD_QTY)   /* Query type */
  {
    *(p1++) = ' ';
    if (BadPtr(qrt))
      *(p1++) = '0';
    else
      while ((*qrt) && (*(p1++) = *(qrt++)));
  }

  if (!fields || (fields & WHO_FIELD_CHA))
  {
    char *p2;
    *(p1++) = ' ';
    if ((p2 = (chptr ? chptr->chname : NULL)))
      while ((*p2) && (*(p1++) = *(p2++)));
    else
      *(p1++) = '*';
  }

  if (!fields || (fields & WHO_FIELD_UID))
  {
    char *p2 = cli_user(acptr)->username;
    *(p1++) = ' ';
    while ((*p2) && (*(p1++) = *(p2++)));
  }

  if (fields & WHO_FIELD_NIP)
  {
    const char* p2 = IsHiddenHost(acptr) && (!IsViewip(sptr) && acptr != sptr) ?
      feature_str(FEAT_HIDDEN_IP) :
      ircd_ntoa((const char*) &(cli_ip(acptr)));
    *(p1++) = ' ';
    while ((*p2) && (*(p1++) = *(p2++)));
  }

  if (!fields || (fields & WHO_FIELD_HOS))
  {
	char *p2 = (IsViewip(sptr) || acptr == sptr) ? get_realhost(acptr) : get_virtualhost(acptr);
    *(p1++) = ' ';
    while ((*p2) && (*(p1++) = *(p2++)));
  }

  if (!fields || (fields & WHO_FIELD_SER))
  {
    char *p2;
    int haspriv = IsAnOper(sptr) || es_representante(sptr);
    
    if (IsMe(cli_user(acptr)->server))
    {
      if ((sptr != acptr) && feature_bool(FEAT_HIS_WHO_SERVERNAME) && !haspriv)
        p2 = (char *)feature_str(FEAT_HIS_SERVERNAME);
      else
        p2 = cli_name(&me);
    }
    else
    {
      if (IsHiddenserv(cli_user(acptr)->server) && !haspriv)
        p2 = (char *)feature_str(FEAT_HIS_SERVERNAME);
      else
        p2 = cli_name(cli_user(acptr)->server);
    }
    *(p1++) = ' ';
    while ((*p2) && (*(p1++) = *(p2++)));
  }

  if (!fields || (fields & WHO_FIELD_NIC))
  {
    char *p2 = cli_name(acptr);
    *(p1++) = ' ';
    while ((*p2) && (*(p1++) = *(p2++)));
  }

  if (!fields || (fields & WHO_FIELD_FLA))
  {
    *(p1++) = ' ';
    if (cli_user(acptr)->away)
      *(p1++) = 'G';
    else
      *(p1++) = 'H';
    if ((IsAnOper(acptr) || es_representante(acptr) || IsPreoper(acptr))/* &&
	(HasPriv(acptr, PRIV_DISPLAY) || HasPriv(sptr, PRIV_SEE_OPERS))*/)
      *(p1++) = '*';
    if (fields) {
      /* If you specified flags then we assume you know how to parse
       * multiple channel status flags, as this is currently the only
       * way to know if someone has @'s *and* is +'d.
       */
      if (chptr && is_chan_op(acptr, chptr))
        *(p1++) = '@';
      if (chptr && has_voice(acptr, chptr))
        *(p1++) = '+';
	  if (chptr && is_chan_halfop(acptr, chptr))
		*(p1++) = '%';
	  if (chptr && is_chan_owner(acptr, chptr))
		*(p1++) = '.';
      if (chptr && is_zombie(acptr, chptr))
        *(p1++) = '!';
    }
    else {
      if (chptr && is_chan_op(acptr, chptr))
        *(p1++) = '@';
      else if (chptr && has_voice(acptr, chptr))
        *(p1++) = '+';
      else if (chptr && is_zombie(acptr, chptr))
        *(p1++) = '!';
	  else if (chptr && is_chan_halfop(acptr, chptr))
		*(p1++) = '%';
	  else if (chptr && is_chan_owner(acptr, chptr))
		*(p1++) = '.';
    }
    if (IsDeaf(acptr))
      *(p1++) = 'd';
    if (IsAnOper(sptr))
    {
      if (IsInvisible(acptr))
        *(p1++) = 'i';
      if (SendWallops(acptr))
        *(p1++) = 'w';
      if (SendDebug(acptr))
        *(p1++) = 'g';
    }
    if (HasHiddenHost(acptr))
      *(p1++) = 'x';
    if (IsAnOper(acptr))
      *(p1++) = 'o';
	if (IsPreoper(acptr))
	  *(p1++) = 'p';
	if (IsHelpOp(acptr))
	  *(p1++) = 'h';
	if (IsCoadmin(acptr))
	  *(p1++) = 'a';
	if (IsAdmin(acptr))
	  *(p1++) = 'A';
	if (IsDevel(acptr))
	  *(p1++) = 'D';
	if (IsViewip(acptr))
	  *(p1++) = 'X';
  }

  if (!fields || (fields & WHO_FIELD_DIS))
  {
    *p1++ = ' ';
    if (!fields)
      *p1++ = ':';              /* Place colon here for default reply */
    if (feature_bool(FEAT_HIS_WHO_HOPCOUNT) && !IsAnOper(sptr))
      *p1++ = (sptr == acptr) ? '0' : '3';
    else
      /* three digit hopcount maximum */
      p1 += ircd_snprintf(0, p1, 3, "%d", cli_hopcount(acptr));
  }

  if (fields & WHO_FIELD_IDL)
  {
    *p1++ = ' ';
    if (MyUser(acptr)) {
	    p1 += ircd_snprintf(0, p1, 11, "%d",
				CurrentTime - cli_user(acptr)->last);
    }    
    else {
    	    *p1++ = '0';
    }
  }

  if (!fields || (fields & WHO_FIELD_REN))
  {
    char *p2 = cli_info(acptr);
    *p1++ = ' ';
    if (fields)
      *p1++ = ':';              /* Place colon here for special reply */
    while ((*p2) && (*(p1++) = *(p2++)));
  }

  if (fields & WHO_FIELD_ACC)
  {
    char *p2 = cli_user(acptr)->account;
    *(p1++) = ' ';
    while ((*p2) && (*(p1++) = *(p2++)));
  }

  /* The first char will always be an useless blank and we 
     need to terminate buf1 */
  *p1 = '\0';
  p1 = buf1;
  send_reply(sptr, fields ? RPL_WHOSPCRPL : RPL_WHOREPLY, ++p1);
}
Beispiel #23
0
char *hidehost_ipv4(struct irc_in_addr *ip)
{
unsigned int a, b, c, d;
static char buf[512], res[512], res2[512], result[128];
unsigned long n;
unsigned int alpha, beta, gamma, delta;
unsigned char *pch;

        /*
         * Output: ALPHA.BETA.GAMMA.DELTA.IP
         * ALPHA is unique for a.b.c.d
         * BETA  is unique for a.b.c.*
         * GAMMA is unique for a.b.*
         * We cloak like this:
         * ALPHA = downsample24(md5(md5("KEY2:A.B.C.D:KEY3")+"KEY1"));
         * BETA  = downsample24(md5(md5("KEY3:A.B.C:KEY1")+"KEY2"));
         * GAMMA = downsample24(md5(md5("KEY1:A.B:KEY2")+"KEY3"));
         * DELTA = downsample24(md5(md5("KEY2:A:KEY1:KEY3")+"KEY1"));
         */
        if (!irc_in_addr_is_ipv4(ip))
          return hidehost_ipv6(ip);

        pch = (unsigned char*)&ip->in6_16[6];
        a = *pch++;
        b = *pch;
        pch = (unsigned char*)&ip->in6_16[7];
        c = *pch++;
        d = *pch;

        /* ALPHA... */
        ircd_snprintf(0, buf, 512, "%s:%d.%d.%d.%d:%s", KEY2, a, b, c, d, KEY3);
        DoMD5((unsigned char *)&res, (unsigned char *)&buf, strlen(buf));
        strcpy(res+16, KEY1); /* first 16 bytes are filled, append our key.. */
        n = strlen(res+16) + 16;
        DoMD5((unsigned char *)&res2, (unsigned char *)&res, n);
        alpha = downsample24((unsigned char *)&res2);

        /* BETA... */
        ircd_snprintf(0, buf, 512, "%s:%d.%d.%d:%s", KEY3, a, b, c, KEY1);
        DoMD5((unsigned char *)&res, (unsigned char *)&buf, strlen(buf));
        strcpy(res+16, KEY2); /* first 16 bytes are filled, append our key.. */
        n = strlen(res+16) + 16;
        DoMD5((unsigned char *)&res2, (unsigned char *)&res, n);
        beta = downsample24((unsigned char *)&res2);

        /* GAMMA... */
        ircd_snprintf(0, buf, 512, "%s:%d.%d:%s", KEY1, a, b, KEY2);
        DoMD5((unsigned char *)&res, (unsigned char *)&buf, strlen(buf));
        strcpy(res+16, KEY3); /* first 16 bytes are filled, append our key.. */
        n = strlen(res+16) + 16;
        DoMD5((unsigned char *)&res2, (unsigned char *)&res, n);
        gamma = downsample24((unsigned char *)&res2);

        /* DELTA... */
        ircd_snprintf(0, buf, 512, "%s:%d:%s:%s", KEY2, a, KEY1, KEY3);
        DoMD5((unsigned char *)&res, (unsigned char *)&buf, strlen(buf));
        strcpy(res+16, KEY1); /* first 16 bytes are filled, append our key.. */
        n = strlen(res+16) + 16;
        DoMD5((unsigned char *)&res2, (unsigned char *)&res, n);
        delta = downsample24((unsigned char *)&res2);

        ircd_snprintf(0, result, HOSTLEN, "%X.%X.%X.%X.IP", alpha, beta, gamma, delta);
        return result;
}
Beispiel #24
0
char *hidehost_ipv6(struct irc_in_addr *ip)
{
unsigned int a, b, c, d, e, f, g, h;
static char buf[512], res[512], res2[512], result[128];
unsigned long n;
unsigned int alpha, beta, gamma, delta;

        /*
         * Output: ALPHA:BETA:GAMMA:IP
         * ALPHA is unique for a:b:c:d:e:f:g:h
         * BETA  is unique for a:b:c:d:e:f:g
         * GAMMA is unique for a:b:c:d
         * We cloak like this:
         * ALPHA = downsample24(md5(md5("KEY2:a:b:c:d:e:f:g:h:KEY3")+"KEY1"));
         * BETA  = downsample24(md5(md5("KEY3:a:b:c:d:e:f:g:KEY1")+"KEY2"));
         * GAMMA = downsample24(md5(md5("KEY1:a:b:c:d:KEY2")+"KEY3"));
         * DELTA = downsample24(md5(md5("KEY2:a:b:KEY1:KEY3")+"KEY1"));
         */

        if (irc_in_addr_is_ipv4(ip))
          return hidehost_ipv4(ip);

        a = ntohs(ip->in6_16[0]);
        b = ntohs(ip->in6_16[1]);
        c = ntohs(ip->in6_16[2]);
        d = ntohs(ip->in6_16[3]);
        e = ntohs(ip->in6_16[4]);
        f = ntohs(ip->in6_16[5]);
        g = ntohs(ip->in6_16[6]);
        h = ntohs(ip->in6_16[7]);

        /* ALPHA... */
        ircd_snprintf(0, buf, 512, "%s:%x:%x:%x:%x:%x:%x:%x:%x:%s", KEY2, a, b, c, d, e, f, g, h, KEY3);
        DoMD5((unsigned char *)&res, (unsigned char *)&buf, strlen(buf));
        strcpy(res+16, KEY1); /* first 16 bytes are filled, append our key.. */
        n = strlen(res+16) + 16;
        DoMD5((unsigned char *)&res2, (unsigned char *)&res, n);
        alpha = downsample24((unsigned char *)&res2);

        /* BETA... */
        ircd_snprintf(0, buf, 512, "%s:%x:%x:%x:%x:%x:%x:%x:%s", KEY3, a, b, c, d, e, f, g, KEY1);
        DoMD5((unsigned char *)&res, (unsigned char *)&buf, strlen(buf));
        strcpy(res+16, KEY2); /* first 16 bytes are filled, append our key.. */
        n = strlen(res+16) + 16;
        DoMD5((unsigned char *)&res2, (unsigned char *)&res, n);
        beta = downsample24((unsigned char *)&res2);

        /* GAMMA... */
        ircd_snprintf(0, buf, 512, "%s:%x:%x:%x:%x:%s", KEY1, a, b, c, d, KEY2);
        DoMD5((unsigned char *)&res, (unsigned char *)&buf, strlen(buf));
        strcpy(res+16, KEY3); /* first 16 bytes are filled, append our key.. */
        n = strlen(res+16) + 16;
        DoMD5((unsigned char *)&res2, (unsigned char *)&res, n);
        gamma = downsample24((unsigned char *)&res2);

        /* DELTA... */
        ircd_snprintf(0, buf, 512, "%s:%x:%x:%s:%s", KEY2, a, b, KEY1, KEY3);
        DoMD5((unsigned char *)&res, (unsigned char *)&buf, strlen(buf));
        strcpy(res+16, KEY1); /* first 16 bytes are filled, append our key.. */
        n = strlen(res+16) + 16;
        DoMD5((unsigned char *)&res2, (unsigned char *)&res, n);
        delta = downsample24((unsigned char *)&res2);

        ircd_snprintf(0, result, HOSTLEN, "%X:%X:%X:%X:IP", alpha, beta, gamma, delta);
        return result;
}
Beispiel #25
0
void checkUsers(struct Client *sptr, struct Channel *chptr, int flags) {
  struct Membership *lp;
  struct SLink *slp;
  struct Client *acptr;

   char outbuf[BUFSIZE], ustat[64];
   int cntr = 0, opcntr = 0, hopcntr = 0, vcntr = 0, clones = 0, bans = 0, excepts = 0, c = 0, authed = 0;

   if (flags & CHECK_SHOWUSERS) {
     if (feature_bool(FEAT_HALFOPS))
       send_reply(sptr, RPL_DATASTR, "Users (@ = op, % = halfop, + = voice, * = clone)");
     else
       send_reply(sptr, RPL_DATASTR, "Users (@ = op, + = voice, * = clone)");
   }

   for (lp = chptr->members; lp; lp = lp->next_member)
   {
      int opped = 0;

      acptr = lp->user;

      if ((c = checkClones(chptr, acptr->cli_name, acptr->cli_user->realhost)) != 0)
      {
         ircd_snprintf(0, ustat, sizeof(ustat), "%2d ", c);
         clones++;
      }
      else
      {
         strcpy(ustat, "   ");
      }

      if (chptr && IsChanOp(lp))
      {
         strcat(ustat, "@");
         opcntr++;
         opped = 1;
      }

      else if (chptr && IsHalfOp(lp))
      {
         strcat(ustat, "%");
         hopcntr++;
      }

      else if (chptr && HasVoice(lp))
      {
         strcat(ustat, "+");
         vcntr++;
      }
      else
         strcat(ustat, " ");

      if ((c = IsAccount(acptr)) != 0) ++authed;

      if ((flags & CHECK_SHOWUSERS) || ((flags & CHECK_OPSONLY) && opped)) {
        ircd_snprintf(0, outbuf, sizeof(outbuf), "%s%c", acptr->cli_info, COLOR_OFF);
        send_reply(sptr, RPL_CHANUSER, ustat, acptr->cli_name, acptr->cli_user->realusername,
            (flags & CHECK_SHOWIPS) ? ircd_ntoa((const char*)&(cli_ip(acptr))) : acptr->cli_user->realhost, outbuf, 
            (c ? acptr->cli_user->account : ""));
      }

      cntr++;
   }

   send_reply(sptr, RPL_DATASTR, " ");

   if (feature_bool(FEAT_HALFOPS))
     ircd_snprintf(0, outbuf, sizeof(outbuf),
        "Total users:: %d (%d ops, %d half ops, %d voiced, %d clones, %d authed)",
        cntr, opcntr, hopcntr, vcntr, clones, authed);
   else
     ircd_snprintf(0, outbuf, sizeof(outbuf),
        "Total users:: %d (%d ops, %d voiced, %d clones, %d authed)",
        cntr, opcntr, vcntr, clones, authed);

   send_reply(sptr, RPL_DATASTR, outbuf);

   send_reply(sptr, RPL_DATASTR, " ");

   /* Do not display bans if ! flags & CHECK_SHOWUSERS */
   if (!(flags & CHECK_SHOWUSERS)) {
     send_reply(sptr, RPL_ENDOFCHECK, " ");
     return;
   }

   /* Bans */
   send_reply(sptr, RPL_DATASTR, "Bans on channel::");

   for (slp = chptr->banlist; slp; slp = slp->next)
   {
      ircd_snprintf(0, outbuf, sizeof(outbuf),  "[%d] - %s - Set by %s, on %s", 
         ++bans, slp->value.ban.banstr, slp->value.ban.who, myctime(slp->value.ban.when));
      send_reply(sptr, RPL_DATASTR, outbuf);
   }

   if (bans == 0)
     send_reply(sptr, RPL_DATASTR, "<none>");

   /* Excepts */
   if (feature_bool(FEAT_EXCEPTS)) {
     send_reply(sptr, RPL_DATASTR, "Excepts on channel::");

     for (slp = chptr->exceptlist; slp; slp = slp->next)
     {
        ircd_snprintf(0, outbuf, sizeof(outbuf),  "[%d] - %s - Set by %s, on %s",
           ++excepts, slp->value.except.exceptstr, slp->value.except.who, myctime(slp->value.except.when));
        send_reply(sptr, RPL_DATASTR, outbuf);
     }

     if (excepts == 0)
       send_reply(sptr, RPL_DATASTR, "<none>");
   }

   send_reply(sptr, RPL_ENDOFCHECK, " ");
}
Beispiel #26
0
void checkClient(struct Client *sptr, struct Client *acptr)
{
   struct Channel *chptr;
   struct Membership *lp;
   char outbuf[BUFSIZE];
   char *privs;
   time_t nowr;

   /* Header */
   send_reply(sptr, RPL_DATASTR, " ");
   send_reply(sptr, RPL_CHKHEAD, "user", acptr->cli_name);
   send_reply(sptr, RPL_DATASTR, " ");

   ircd_snprintf(0, outbuf, sizeof(outbuf), "           Nick:: %s (%s%s)", acptr->cli_name, NumNick(acptr));
   send_reply(sptr, RPL_DATASTR, outbuf);

   if (MyUser(acptr))
   {  
      ircd_snprintf(0, outbuf, sizeof(outbuf),  "      Signed on:: %s", myctime(acptr->cli_firsttime));
      send_reply(sptr, RPL_DATASTR, outbuf);
   }

   ircd_snprintf(0, outbuf, sizeof(outbuf), "      Timestamp:: %s (%d)", myctime(acptr->cli_lastnick), acptr->cli_lastnick);
   send_reply(sptr, RPL_DATASTR, outbuf);

   ircd_snprintf(0, outbuf, sizeof(outbuf), "  User/Hostmask:: %s@%s (%s)", acptr->cli_user->username, acptr->cli_user->host,
   ircd_ntoa((const char*) &(cli_ip(acptr))));
   send_reply(sptr, RPL_DATASTR, outbuf);

   if (((feature_int(FEAT_HOST_HIDING_STYLE) == 1) ? HasHiddenHost(acptr) : IsHiddenHost(acptr)) || IsSetHost(acptr))
   {
      ircd_snprintf(0, outbuf, sizeof(outbuf), " Real User/Host:: %s@%s", acptr->cli_user->realusername, acptr->cli_user->realhost);
      send_reply(sptr, RPL_DATASTR, outbuf);
   }

   ircd_snprintf(0, outbuf, sizeof(outbuf), "      Real Name:: %s%c", cli_info(acptr), COLOR_OFF);
   send_reply(sptr, RPL_DATASTR, outbuf);

   if (IsService(cli_user(acptr)->server)) {
     if (acptr)
       send_reply(sptr, RPL_DATASTR, "         Status:: Network Service");
     else if (IsAdmin(acptr))
       send_reply(sptr, RPL_DATASTR, "         Status:: IRC Administrator (service)");
     else if (IsAnOper(acptr))
       send_reply(sptr, RPL_DATASTR, "         Status:: IRC Operator (service)");
     else 
       send_reply(sptr, RPL_DATASTR, "         Status:: Client (service)");
   } else if (IsAdmin(acptr)) {
     send_reply(sptr, RPL_DATASTR, "         Status:: IRC Administrator");
   } else if (IsAnOper(acptr)) {
     send_reply(sptr, RPL_DATASTR, "         Status:: IRC Operator");
   } else {
     send_reply(sptr, RPL_DATASTR, "         Status:: Client");
   }

   if (MyUser(acptr)) {
     ircd_snprintf(0, outbuf, sizeof(outbuf), "          Class:: %s", get_client_class(acptr));
     send_reply(sptr, RPL_DATASTR, outbuf);
   }

   privs = client_print_privs(acptr);
   if (strlen(privs) > 1)
     client_check_privs(acptr, sptr);

   ircd_snprintf(0, outbuf, sizeof(outbuf), "   Connected to:: %s", cli_name(acptr->cli_user->server));
   send_reply(sptr, RPL_DATASTR, outbuf);

   if (cli_version(acptr)) {
     if (strlen(cli_version(acptr)) > 0) {
       ircd_snprintf(0, outbuf, sizeof(outbuf), "   CTCP Version:: %s", cli_version(acptr));
       send_reply(sptr, RPL_DATASTR, outbuf);
     }
   }

   if (cli_user(acptr) && !EmptyString(cli_user(acptr)->swhois)) {
     ircd_snprintf(0, outbuf, sizeof(outbuf), "         SWHOIS:: %s", cli_user(acptr)->swhois);
     send_reply(sptr, RPL_DATASTR, outbuf);
   }

   if (cli_webirc(acptr)) {
     if (strlen(cli_webirc(acptr)) > 0) {
       ircd_snprintf(0, outbuf, sizeof(outbuf), "         WebIRC:: %s", cli_webirc(acptr));
       send_reply(sptr, RPL_DATASTR, outbuf);
     }
   }

   if (cli_sslclifp(acptr) && (strlen(cli_sslclifp(acptr)) > 0)) {
     ircd_snprintf(0, outbuf, sizeof(outbuf), "SSL Fingerprint:: %s", cli_sslclifp(acptr));
     send_reply(sptr, RPL_DATASTR, outbuf);
   }

   if (MyUser(acptr))
     get_eflags(sptr, acptr);

   /* +s (SERV_NOTICE) is not relayed to us from remote servers,
    * so we cannot tell if a remote client has that mode set.
    * And hacking it onto the end of the output of umode_str is EVIL BAD AND WRONG
    * (and breaks if the user is +r) so we won't do that either.
    */

   if (strlen(umode_str(acptr)) < 1)
      strcpy(outbuf, "       Umode(s):: <none>");
   else
      ircd_snprintf(0, outbuf, sizeof(outbuf), "       Umode(s):: +%s", umode_str(acptr));

   send_reply(sptr, RPL_DATASTR, outbuf);

   if (acptr->cli_user->joined == 0)
      send_reply(sptr, RPL_DATASTR, "     Channel(s):: <none>");
   else if (acptr->cli_user->joined > 50) 
   {

      /* NB. As a sanity check, we DO NOT show the individual channels the
       *     client is on if it is on > 50 channels.  This is to prevent the ircd
       *     barfing ala Uworld when someone does /quote check Q :).. (I shouldn't imagine
       *     an Oper would want to see every single channel 'x' client is on anyway if
       *     they are on *that* many).
       */

      ircd_snprintf(0, outbuf, sizeof(outbuf), "     Channel(s):: - (total: %u)", acptr->cli_user->joined);
      send_reply(sptr, RPL_DATASTR, outbuf);
   }
   else
   {
      char chntext[BUFSIZE];
      int len = strlen("     Channel(s):: ");
      int mlen = strlen(me.cli_name) + len + strlen(sptr->cli_name);
      *chntext = '\0';

      strcpy(chntext, "     Channel(s):: ");
      for (lp = acptr->cli_user->channel; lp; lp = lp->next_channel) {
         chptr = lp->channel;
         if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5) {
            send_reply(sptr, RPL_DATASTR, chntext);
            *chntext = '\0';
            strcpy(chntext, "     Channel(s):: ");
            len = strlen(chntext);
         }
         if (IsDeaf(acptr))
            *(chntext + len++) = '-';
         if (is_chan_op(acptr, chptr))
            *(chntext + len++) = '@';
         if (is_half_op(acptr, chptr))
            *(chntext + len++) = '%';
         if (IsOper(sptr) && !ShowChannel(sptr,chptr))
            *(chntext + len++) = '*';
         if (IsZombie(lp))
            *(chntext + len++) = '!';
         if (len)
            *(chntext + len) = '\0';

         strcpy(chntext + len, chptr->chname);
         len += strlen(chptr->chname);
         strcat(chntext + len, " ");
         len++;
      }

      if (chntext[0] != '\0')
        send_reply(sptr, RPL_DATASTR, chntext);
   }

   /* If client processing command ISN'T target (or a registered
    * Network Service), show idle time since the last time we
    * parsed something.
    */
   if (MyUser(acptr) && !(IsService(acptr) == -1) && !(strCasediff(acptr->cli_name, sptr->cli_name) == 0)) {
      nowr = CurrentTime - acptr->cli_user->last;
      ircd_snprintf(0, outbuf, sizeof(outbuf), "       Idle for:: %d days, %02ld:%02ld:%02ld",
         nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
      send_reply(sptr, RPL_DATASTR, outbuf);
   }

   /* Away message (if applicable) */
   if (acptr->cli_user->away) {
      ircd_snprintf(0, outbuf, sizeof(outbuf), "   Away message:: %s", acptr->cli_user->away);
      send_reply(sptr, RPL_DATASTR, outbuf);
   }

   /* If local user.. */

   if (MyUser(acptr)) {
      send_reply(sptr, RPL_DATASTR, " ");
      ircd_snprintf(0, outbuf, sizeof(outbuf), "          Ports:: %d -> %d (client -> server)",
         cli_port(acptr), cli_listener(acptr)->port);
      send_reply(sptr, RPL_DATASTR, outbuf);
      if (feature_bool(FEAT_CHECK_EXTENDED)) {
        /* Note: sendq = receiveq for a client (it makes sense really) */
        ircd_snprintf(0, outbuf, sizeof(outbuf), "      Data sent:: %u.%0.3u Kb (%u protocol messages)",
           cli_receiveK(acptr), cli_receiveB(acptr), cli_receiveM(acptr));
        send_reply(sptr, RPL_DATASTR, outbuf);                          
        ircd_snprintf(0, outbuf, sizeof(outbuf), "  Data received:: %u.%0.3u Kb (%u protocol messages)",
           cli_sendK(acptr), cli_sendB(acptr), cli_sendM(acptr));                                       
        send_reply(sptr, RPL_DATASTR, outbuf);
        ircd_snprintf(0, outbuf, sizeof(outbuf), "  receiveQ size:: %d bytes (max. %d bytes)",
           DBufLength(&(cli_recvQ(acptr))), feature_int(FEAT_CLIENT_FLOOD));
        send_reply(sptr, RPL_DATASTR, outbuf);
        ircd_snprintf(0, outbuf, sizeof(outbuf), "     sendQ size:: %d bytes (max. %d bytes)",
           DBufLength(&(cli_sendQ(acptr))), get_sendq(acptr));                                
        send_reply(sptr, RPL_DATASTR, outbuf);                
      }
   }
   
   /* Send 'END OF CHECK' message */
   send_reply(sptr, RPL_ENDOFCHECK, " ");
}
Beispiel #27
0
signed int checkHostmask(struct Client *sptr, char *hoststr, int flags) {
  struct Client *acptr;
  struct Channel *chptr;
  struct Membership *lp;
  int count = 0, found = 0, cidr_check_bits = 0;
  char outbuf[BUFSIZE];
  char targhost[NICKLEN + USERLEN + HOSTLEN + 3], curhost[NICKLEN + USERLEN + HOSTLEN + 3];
  char nickm[NICKLEN + 1], userm[USERLEN + 1], hostm[HOSTLEN + 1];
  char *p = NULL;
  struct in_addr cidr_check;

  strcpy(nickm,"*");
  strcpy(userm,"*");
  strcpy(hostm,"*");

  if (!strchr(hoststr, '!') && !strchr(hoststr, '@'))
    ircd_strncpy(hostm,hoststr,HOSTLEN);
  else {
    if ((p = strchr(hoststr, '@'))) {
      *p++ = '\0';
      if (*p) ircd_strncpy(hostm,p, HOSTLEN);
    }

    /* Get the nick!user mask */
    if ((p = strchr(hoststr, '!'))) {
      *p++ = '\0';
      if (*p) ircd_strncpy(userm,p,USERLEN);
      if (*hoststr) ircd_strncpy(nickm,hoststr,NICKLEN);
    }
    else if (*hoststr) {
      /* Durz: We should only do the following *IF* the hoststr has not already been
       * copied into hostm (ie. neither ! or @ specified).. otherwise, when we do
       * /quote check *.barrysworld.com - we end up with targhost as: *!*.barryswo@*.barrysworld.com
       */
      ircd_strncpy(userm,hoststr,USERLEN);
    }
  }
  
  if ((p = strchr(hostm, '/')) || inet_aton(hostm, &cidr_check)) {
    if (p)
      *p = '\0';
    if (inet_aton(hostm, &cidr_check)) {
      cidr_check_bits = p ? atoi(p + 1) : 32;
      if ((cidr_check_bits >= 0) && (cidr_check_bits <= 32)) {
        flags |= CHECK_CIDRMASK;
        cidr_check.s_addr &= NETMASK(cidr_check_bits);
      }
    }
    if (p)
      *p = '/';
  }

  /* Copy formatted string into "targhost" buffer */
  ircd_snprintf(0, targhost, sizeof(targhost),  "%s!%s@%s", nickm, userm, hostm);

  targhost[sizeof(targhost) - 1] = '\0';

  /* Note: we have to exclude the last client struct as it is not a real client
   * structure, and therefore any attempt to access elements in it would cause
   * a segfault.
   */

  for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) {
    /* Dont process if acptr is a unregistered client, a server or a ping */
    if (!IsRegistered(acptr) || IsServer(acptr))
      continue;

    if (IsMe(acptr))   /* Always the last acptr record */
      break;

    if(count > feature_int(FEAT_MAX_CHECK_OUTPUT)) { /* sanity stuff */
      ircd_snprintf(0, outbuf, sizeof(outbuf), "More than %d results, truncating...", count);
      send_reply(sptr, RPL_DATASTR, outbuf);
      send_reply(sptr, RPL_ENDOFCHECK, " ");
      break;
    }

    /* Copy host info into buffer */
    curhost[0] = '\0';
    ircd_snprintf(0, curhost, sizeof(curhost), "%s!%s@%s", acptr->cli_name, acptr->cli_user->realusername, acptr->cli_user->realhost);

    if (flags & CHECK_CIDRMASK) {
      if (((cli_ip(acptr).s_addr & NETMASK(cidr_check_bits)) == cidr_check.s_addr) && !match(nickm, acptr->cli_name) 
            && (!match(userm, acptr->cli_user->realusername) || !match(userm, acptr->cli_user->username)))
        found = 1;
    }
    else {
      if(match((const char*)targhost,(const char*)curhost) == 0)
        found = 1;
      else {
        curhost[0] = '\0';
        ircd_snprintf(0, curhost, sizeof(curhost), "%s!%s@%s", acptr->cli_name, acptr->cli_user->username, acptr->cli_user->host);

        if(match((const char*)targhost,(const char*)curhost) == 0)
          found = 1;
      }
    }

    if (found == 1) {
      found = 0;  /* reset that so it doesn't get crazy go nuts */

      /* Show header if we've found at least 1 record */
      if (count == 0) {
        /* Output header */ 
        send_reply(sptr, RPL_DATASTR, " ");
        send_reply(sptr, RPL_CHKHEAD, "host", targhost);

        send_reply(sptr, RPL_DATASTR, " ");
        ircd_snprintf(0, outbuf, sizeof(outbuf),  "%s   %-*s%-*s%s", "No.", (NICKLEN + 2 ), "Nick",
                (USERLEN + 2), "User", "Host");
        send_reply(sptr, RPL_DATASTR, outbuf);
      }

      ircd_snprintf(0, outbuf, sizeof(outbuf), "%-4d  %-*s%-*s%s", (count+1), (NICKLEN + 2),
            acptr->cli_name, (USERLEN + 2), acptr->cli_user->realusername, 
            (flags & CHECK_SHOWIPS) ? ircd_ntoa((const char*)&(cli_ip(acptr))) : acptr->cli_user->realhost);
      send_reply(sptr, RPL_DATASTR, outbuf);

      /* Show channel output (if applicable) - the 50 channel limit sanity check
       * is specifically to prevent coredumping when someone lamely tries to /check
       * Q or some other channel service...
       */
      if (flags & CHECK_CHECKCHAN) {
        if (acptr->cli_user->joined > 0 && acptr->cli_user->joined <= 50) {
          char chntext[BUFSIZE];
          int len = strlen("      on channels: ");
          int mlen = strlen(me.cli_name) + len + strlen(sptr->cli_name);
          *chntext = '\0';

          strcpy(chntext, "      on channels: ");
          for (lp = acptr->cli_user->channel; lp; lp = lp->next_channel) {
            chptr = lp->channel;
            if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5) {
              send_reply(sptr, RPL_DATASTR, chntext);
              *chntext = '\0';
              strcpy(chntext, "      on channels: ");
              len = strlen(chntext);
            }
            if (IsDeaf(acptr))
              *(chntext + len++) = '-';
            if (is_chan_op(acptr, chptr))
              *(chntext + len++) = '@';
            if (is_half_op(acptr, chptr))
              *(chntext + len++) = '%';
            if (IsOper(sptr) && !ShowChannel(sptr,chptr))
              *(chntext + len++) = '*';
            else if (has_voice(acptr, chptr))
              *(chntext + len++) = '+';
            else if (IsZombie(lp))
              *(chntext + len++) = '!';
            if (len)
              *(chntext + len) = '\0';

            strcpy(chntext + len, chptr->chname);
            len += strlen(chptr->chname);
            strcat(chntext + len, " ");
            len++;
          }
          if (chntext[0] != '\0')
            send_reply(sptr, RPL_DATASTR, chntext);

          send_reply(sptr, RPL_DATASTR, " ");
        }
      }
      count++;
    }
  }

  if (count > 0) {
    send_reply(sptr, RPL_DATASTR, " ");

    ircd_snprintf(0, outbuf, sizeof(outbuf), "Matching records found:: %d", count);
    send_reply(sptr, RPL_DATASTR, outbuf);

    send_reply(sptr, RPL_ENDOFCHECK, " ");
  }

  return count;
}
Beispiel #28
0
int get_eflags(struct Client *sptr, struct Client *acptr) {
  struct eline *eline;
  unsigned int e_flag = 0;
  int found = 0;
  char outbuf[BUFSIZE];
  char i_host[SOCKIPLEN + USERLEN + 2];
  char s_host[HOSTLEN + USERLEN + 2];

  ircd_snprintf(0, i_host, USERLEN+SOCKIPLEN+2, "%s@%s", cli_username(acptr), ircd_ntoa((const char*) &(cli_ip(acptr))));
  ircd_snprintf(0, s_host, USERLEN+HOSTLEN+2, "%s@%s", cli_username(acptr), cli_sockhost(acptr));

  for (eline = GlobalEList; eline; eline = eline->next) {
    char* ip_start;
    char* cidr_start;
    in_addr_t cli_addr = 0;
    *outbuf = '\0';

    e_flag = eflagstr(eline->flags);

    if (s_host) {
      if ((match(eline->mask, s_host) == 0) || (match(eline->mask, i_host) == 0)) {
        found = 1;
      }
    }

    if ((ip_start = strrchr(i_host, '@')))
      cli_addr = inet_addr(ip_start + 1);

    if ((ip_start = strrchr(eline->mask, '@')) && (cidr_start = strchr(ip_start + 1, '/'))) {
      int bits = atoi(cidr_start + 1);
      char* p = strchr(i_host, '@');

      if (p) {
        *p = *ip_start = 0;
        if (match(eline->mask, i_host) == 0) {
          if ((bits > 0) && (bits < 33)) {
            in_addr_t ban_addr;
            *cidr_start = 0;
            ban_addr = inet_addr(ip_start + 1);
            *cidr_start = '/';
            if ((NETMASK(bits) & cli_addr) == ban_addr) {
              *p = *ip_start = '@';
              found = 1;
            }
          }
        }
        *p = *ip_start = '@';
      }
    }

    if (found) {
      strcat(outbuf, "     Exemptions:: ");

      if (e_flag & EFLAG_KLINE) {
        if (strlen(outbuf) > 21)
          strcat(outbuf, ", ");
        strcat(outbuf, "K:Lines");
      }

      if (e_flag & EFLAG_GLINE) {
        if (strlen(outbuf) > 21)
          strcat(outbuf, ", ");
        strcat(outbuf, "G:Lines");
      }

      if (e_flag & EFLAG_SHUN) {
        if (strlen(outbuf) > 21)
          strcat(outbuf, ", ");
        strcat(outbuf, "Shuns");
      }

      if (e_flag & EFLAG_ZLINE) {
        if (strlen(outbuf) > 21)
          strcat(outbuf, ", ");
        strcat(outbuf, "Z:Lines");
      }

      if (e_flag & EFLAG_SFILTER) {
        if (strlen(outbuf) > 21)
          strcat(outbuf, ", ");
        strcat(outbuf, "Spamfilters");
      }

      if (e_flag & EFLAG_LIST) {
        if (strlen(outbuf) > 21)
          strcat(outbuf, ", ");
        strcat(outbuf, "List Delays");
      }

      if (e_flag & EFLAG_IDENT) {
        if (strlen(outbuf) > 21)
          strcat(outbuf, ", ");
        strcat(outbuf, "Ident Prompts");
      }

      if ((e_flag & EFLAG_IPCHECK) && IsIPCheckExempted(acptr)) {
        if (strlen(outbuf) > 21)
          strcat(outbuf, ", ");
        strcat(outbuf, "IPCheck");
      }

      if (strlen(outbuf) > 18)
        send_reply(sptr, RPL_DATASTR, outbuf);
    }
    found = 0;
  }

  return 0;
}
Beispiel #29
0
/*
 * ms_burst - server message handler
 *
 * --  by Run [email protected]  december 1995 till march 1997
 *
 * parv[0] = sender prefix
 * parv[1] = channel name
 * parv[2] = channel timestamp
 * The meaning of the following parv[]'s depend on their first character:
 * If parv[n] starts with a '+':
 * Net burst, additive modes
 *   parv[n] = <mode>
 *   parv[n+1] = <param> (optional)
 *   parv[n+2] = <param> (optional)
 * If parv[n] starts with a '%', then n will be parc-1:
 *   parv[n] = %<ban> <ban> <ban> ...
 * If parv[n] starts with another character:
 *   parv[n] = <nick>[:<mode>],<nick>[:<mode>],...
 *   where <mode> defines the mode and op-level
 *   for nick and all following nicks until the
 *   next <mode> field.
 *   Digits in the <mode> field have of two meanings:
 *   1) if it is the first field in this BURST message
 *      that contains digits, and/or when a 'v' is
 *      present in the <mode>:
 *      The absolute value of the op-level.
 *   2) if there are only digits in this field and
 *      it is not the first field with digits:
 *      An op-level increment relative to the previous
 *      op-level.
 *   First all modeless nicks must be emmitted,
 *   then all combinations of modes without ops
 *   (currently that is only 'v') followed by the same
 *   series but then with ops (currently 'o','ov').
 *
 * Example:
 * "A8 B #test 87654321 +ntkAl key secret 123 A8AAG,A8AAC:v,A8AAA:0,A8AAF:2,A8AAD,A8AAB:v1,A8AAE:1 :%ban1 ban2"
 *
 * <mode> list example:
 *
 * "xxx,sss:v,ttt,aaa:123,bbb,ccc:2,ddd,kkk:v2,lll:2,mmm"
 *
 * means
 *
 *  xxx		// first modeless nicks
 *  sss +v	// then opless nicks
 *  ttt +v	// no ":<mode>": everything stays the same
 *  aaa -123	// first field with digit: absolute value
 *  bbb -123
 *  ccc -125	// only digits, not first field: increment
 *  ddd -125
 *  kkk -2 +v	// field with a 'v': absolute value
 *  lll -4 +v	// only digits: increment
 *  mmm -4 +v
 *
 * Anti net.ride code.
 *
 * When the channel already exist, and its TS is larger than
 * the TS in the BURST message, then we cancel all existing modes.
 * If its is smaller then the received BURST message is ignored.
 * If it's equal, then the received modes are just added.
 *
 * BURST is also accepted outside a netburst now because it
 * is sent upstream as reaction to a DESTRUCT message.  For
 * these BURST messages it is possible that the listed channel
 * members are already joined.
 */
int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
  struct ModeBuf modebuf, *mbuf = 0;
  struct Channel *chptr;
  time_t timestamp;
  struct Membership *member, *nmember;
  struct Ban *lp, **lp_p;
  unsigned int parse_flags = (MODE_PARSE_FORCE | MODE_PARSE_BURST);
  int param, nickpos = 0, banpos = 0;
  char modestr[BUFSIZE], nickstr[BUFSIZE], banstr[BUFSIZE];

  if (parc < 3)
    return protocol_violation(sptr,"Too few parameters for BURST");

  if (!(chptr = get_channel(sptr, parv[1], CGT_CREATE)))
    return 0; /* can't create the channel? */

  timestamp = atoi(parv[2]);

  if (chptr->creationtime)	/* 0 for new (empty) channels,
                                   i.e. when this server just restarted. */
  {
    if (parc == 3)		/* Zannel BURST? */
    {
      /* An empty channel without +A set, will cause a BURST message
	 with exactly 3 parameters (because all modes have been reset).
	 If the timestamp on such channels is only a few seconds older
	 from our own, then we ignore this burst: we do not deop our
	 own side.
	 Likewise, we expect the other (empty) side to copy our timestamp
	 from our own BURST message, even though it is slightly larger.

	 The reason for this is to allow people to join an empty
	 non-A channel (a zannel) during a net.split, and not be
	 deopped when the net reconnects (with another zannel). When
	 someone joins a split zannel, their side increments the TS by one.
	 If they cycle a few times then we still don't have a reason to
	 deop them. Theoretically I see no reason not to accept ANY timestamp,
	 but to be sure, we only accept timestamps that are just a few
	 seconds off (one second for each time they cycled the channel). */

      /* Don't even deop users who cycled four times during the net.break. */
      if (timestamp < chptr->creationtime &&
          chptr->creationtime <= timestamp + 4 &&
	  chptr->users != 0)	/* Only do this when WE have users, so that
	  			   if we do this the BURST that we sent has
				   parc > 3 and the other side will use the
				   test below: */
	timestamp = chptr->creationtime; /* Do not deop our side. */
    }
    else if (chptr->creationtime < timestamp &&
             timestamp <= chptr->creationtime + 4 &&
	     chptr->users == 0)
    {
      /* If one side of the net.junction does the above
         timestamp = chptr->creationtime, then the other
	 side must do this: */
      chptr->creationtime = timestamp;	/* Use the same TS on both sides. */
    }
    /* In more complex cases, we might still end up with a
       creationtime desync of a few seconds, but that should
       be synced automatically rather quickly (every JOIN
       caries a timestamp and will sync it; modes by users do
       not carry timestamps and are accepted regardless).
       Only when nobody joins the channel on the side with
       the oldest timestamp before a new net.break occurs
       precisely inbetween the desync, an unexpected bounce
       might happen on reconnect. */
  }

  if (!chptr->creationtime || chptr->creationtime > timestamp) {
    /*
     * Kick local members if channel is +i or +k and our TS was larger
     * than the burst TS (anti net.ride). The modes hack is here because
     * we have to do this before mode_parse, as chptr may go away.
     */
    for (param = 3; param < parc; param++)
    {
      int check_modes;
      if (parv[param][0] != '+')
        continue;
      check_modes = netride_modes(parc - param, parv + param, chptr->mode.key);
      if (check_modes < 0)
      {
        if (chptr->users == 0)
          sub1_from_channel(chptr);
        return protocol_violation(sptr, "Invalid mode string in BURST");
      }
      else if (check_modes)
      {
        /* Clear any outstanding rogue invites */
        mode_invite_clear(chptr);
        for (member = chptr->members; member; member = nmember)
        {
          nmember = member->next_member;
          if (!MyUser(member->user) || IsZombie(member))
            continue;
          /* Kick as netrider if key mismatch *or* remote channel is
           * +i (unless user is an oper) *or* remote channel is +r
           * (unless user has an account).
           */
          if (!(check_modes & MODE_KEY)
              && (!(check_modes & MODE_INVITEONLY) || IsAnOper(member->user))
              && (!(check_modes & MODE_REGONLY) || IsAccount(member->user)))
            continue;
          sendcmdto_serv_butone(&me, CMD_KICK, NULL, "%H %C :Net Rider", chptr, member->user);
          sendcmdto_channel_butserv_butone(&his, CMD_KICK, chptr, NULL, 0, "%H %C :Net Rider", chptr, member->user);
          make_zombie(member, member->user, &me, &me, chptr);
        }
      }
      break;
    }

    /* If the channel had only locals, it went away by now. */
    if (!(chptr = get_channel(sptr, parv[1], CGT_CREATE)))
      return 0; /* can't create the channel? */
  }

  /* turn off burst joined flag */
  for (member = chptr->members; member; member = member->next_member)
    member->status &= ~(CHFL_BURST_JOINED|CHFL_BURST_ALREADY_OPPED|CHFL_BURST_ALREADY_VOICED);

  if (!chptr->creationtime) /* mark channel as created during BURST */
    chptr->mode.mode |= MODE_BURSTADDED;

  /* new channel or an older one */
  if (!chptr->creationtime || chptr->creationtime > timestamp) {
    chptr->creationtime = timestamp;

    modebuf_init(mbuf = &modebuf, &me, cptr, chptr,
		 MODEBUF_DEST_CHANNEL | MODEBUF_DEST_NOKEY);
    modebuf_mode(mbuf, MODE_DEL | chptr->mode.mode); /* wipeout modes */
    chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS;

    /* wipe out modes not represented in chptr->mode.mode */
    if (chptr->mode.limit) {
      modebuf_mode_uint(mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit);
      chptr->mode.limit = 0;
    }
    if (chptr->mode.key[0]) {
      modebuf_mode_string(mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
      chptr->mode.key[0] = '\0';
    }
    if (chptr->mode.upass[0]) {
      modebuf_mode_string(mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0);
      chptr->mode.upass[0] = '\0';
    }
    if (chptr->mode.apass[0]) {
      modebuf_mode_string(mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0);
      chptr->mode.apass[0] = '\0';
    }

    parse_flags |= (MODE_PARSE_SET | MODE_PARSE_WIPEOUT); /* wipeout keys */

    /* mark bans for wipeout */
    for (lp = chptr->banlist; lp; lp = lp->next)
      lp->flags |= BAN_BURST_WIPEOUT;

    /* clear topic set by netrider (if set) */
    if (*chptr->topic) {
      *chptr->topic = '\0';
      *chptr->topic_nick = '\0';
      chptr->topic_time = 0;
      sendcmdto_channel_butserv_butone(&his, CMD_TOPIC, chptr, NULL, 0,
                                       "%H :%s", chptr, chptr->topic);
    }
  } else if (chptr->creationtime == timestamp) {
    modebuf_init(mbuf = &modebuf, &me, cptr, chptr,
		 MODEBUF_DEST_CHANNEL | MODEBUF_DEST_NOKEY);

    parse_flags |= MODE_PARSE_SET; /* set new modes */
  }

  param = 3; /* parse parameters */
  while (param < parc) {
    switch (*parv[param]) {
    case '+': /* parameter introduces a mode string */
      param += mode_parse(mbuf, cptr, sptr, chptr, parc - param,
			  parv + param, parse_flags, NULL);
      break;

    case '%': /* parameter contains bans */
      if (parse_flags & MODE_PARSE_SET) {
	char *banlist = parv[param] + 1, *p = 0, *ban, *ptr;
	struct Ban *newban;

	for (ban = ircd_strtok(&p, banlist, " "); ban;
	     ban = ircd_strtok(&p, 0, " ")) {
	  ban = collapse(pretty_mask(ban));

	    /*
	     * Yeah, we should probably do this elsewhere, and make it better
	     * and more general; this will hold until we get there, though.
	     * I dislike the current add_banid API... -Kev
	     *
	     * I wish there were a better algo. for this than the n^2 one
	     * shown below *sigh*
	     */
	  for (lp = chptr->banlist; lp; lp = lp->next) {
	    if (!ircd_strcmp(lp->banstr, ban)) {
	      ban = 0; /* don't add ban */
	      lp->flags &= ~BAN_BURST_WIPEOUT; /* not wiping out */
	      break; /* new ban already existed; don't even repropagate */
	    } else if (!(lp->flags & BAN_BURST_WIPEOUT) &&
		       !mmatch(lp->banstr, ban)) {
	      ban = 0; /* don't add ban unless wiping out bans */
	      break; /* new ban is encompassed by an existing one; drop */
	    } else if (!mmatch(ban, lp->banstr))
	      lp->flags |= BAN_OVERLAPPED; /* remove overlapping ban */

	    if (!lp->next)
	      break;
	  }

	  if (ban) { /* add the new ban to the end of the list */
	    /* Build ban buffer */
	    if (!banpos) {
	      banstr[banpos++] = ' ';
	      banstr[banpos++] = ':';
	      banstr[banpos++] = '%';
	    } else
	      banstr[banpos++] = ' ';
	    for (ptr = ban; *ptr; ptr++) /* add ban to buffer */
	      banstr[banpos++] = *ptr;

	    newban = make_ban(ban); /* create new ban */
            strcpy(newban->who, "*");
	    newban->when = TStime();
	    newban->flags |= BAN_BURSTED;
	    newban->next = 0;
	    if (lp)
	      lp->next = newban; /* link it in */
	    else
	      chptr->banlist = newban;
	  }
	}
      } 
      param++; /* look at next param */
      break;

    default: /* parameter contains clients */
      {
	struct Client *acptr;
	char *nicklist = parv[param], *p = 0, *nick, *ptr;
	int current_mode, last_mode, base_mode;
	int oplevel = -1;	/* Mark first field with digits: means the same as 'o' (but with level). */
	int last_oplevel = 0;
	struct Membership* member;

        base_mode = CHFL_DEOPPED | CHFL_BURST_JOINED;
        if (chptr->mode.mode & MODE_DELJOINS)
            base_mode |= CHFL_DELAYED;
        current_mode = last_mode = base_mode;

	for (nick = ircd_strtok(&p, nicklist, ","); nick;
	     nick = ircd_strtok(&p, 0, ",")) {

	  if ((ptr = strchr(nick, ':'))) { /* new flags; deal */
	    *ptr++ = '\0';

	    if (parse_flags & MODE_PARSE_SET) {
	      int current_mode_needs_reset;
	      for (current_mode_needs_reset = 1; *ptr; ptr++) {
		if (*ptr == 'o') { /* has oper status */
		  /*
		   * An 'o' is pre-oplevel protocol, so this is only for
		   * backwards compatibility.  Give them an op-level of
		   * MAXOPLEVEL so everyone can deop them.
		   */
		  oplevel = MAXOPLEVEL;
		  if (current_mode_needs_reset) {
		    current_mode = base_mode;
		    current_mode_needs_reset = 0;
		  }
		  current_mode = (current_mode & ~(CHFL_DEOPPED | CHFL_DELAYED)) | CHFL_CHANOP;
                  /*
                   * Older servers may send XXYYY:ov, in which case we
                   * do not want to use the code for 'v' below.
                   */
                  if (ptr[1] == 'v') {
                    current_mode |= CHFL_VOICE;
                    ptr++;
                  }
		}
		else if (*ptr == 'v') { /* has voice status */
		  if (current_mode_needs_reset) {
                    current_mode = base_mode;
		    current_mode_needs_reset = 0;
		  }
		  current_mode = (current_mode & ~CHFL_DELAYED) | CHFL_VOICE;
		  oplevel = -1;	/* subsequent digits are an absolute op-level value. */
                }
		else if (IsDigit(*ptr)) {
		  int level_increment = 0;
		  if (oplevel == -1) { /* op-level is absolute value? */
		    if (current_mode_needs_reset) {
		      current_mode = base_mode;
		      current_mode_needs_reset = 0;
		    }
		    oplevel = 0;
		  }
		  current_mode = (current_mode & ~(CHFL_DEOPPED | CHFL_DELAYED)) | CHFL_CHANOP;
		  do {
		    level_increment = 10 * level_increment + *ptr++ - '0';
		  } while (IsDigit(*ptr));
		  oplevel += level_increment;
		}
		else /* I don't recognize that flag */
		  break; /* so stop processing */
	      }
	    }
	  }

	  if (!(acptr = findNUser(nick)) || cli_from(acptr) != cptr)
	    continue; /* ignore this client */

	  /* Build nick buffer */
	  nickstr[nickpos] = nickpos ? ',' : ' '; /* first char */
	  nickpos++;

	  for (ptr = nick; *ptr; ptr++) /* store nick */
	    nickstr[nickpos++] = *ptr;

	  if (current_mode != last_mode) { /* if mode changed... */
	    last_mode = current_mode;
	    last_oplevel = oplevel;

	    nickstr[nickpos++] = ':'; /* add a specifier */
	    if (current_mode & CHFL_VOICE)
	      nickstr[nickpos++] = 'v';
	    if (current_mode & CHFL_CHANOP)
            {
              if (chptr->mode.apass[0])
	        nickpos += ircd_snprintf(0, nickstr + nickpos, sizeof(nickstr) - nickpos, "%u", oplevel);
              else
                nickstr[nickpos++] = 'o';
            }
	  } else if (current_mode & CHFL_CHANOP && oplevel != last_oplevel) { /* if just op level changed... */
	    nickstr[nickpos++] = ':'; /* add a specifier */
	    nickpos += ircd_snprintf(0, nickstr + nickpos, sizeof(nickstr) - nickpos, "%u", oplevel - last_oplevel);
            last_oplevel = oplevel;
	  }

	  if (!(member = find_member_link(chptr, acptr)))
	  {
	    add_user_to_channel(chptr, acptr, current_mode, oplevel);
            if (!(current_mode & CHFL_DELAYED))
              sendcmdto_channel_butserv_butone(acptr, CMD_JOIN, chptr, NULL, 0, "%H", chptr);
	  }
	  else
	  {
	    /* The member was already joined (either by CREATE or JOIN).
	       Remember the current mode. */
	    if (member->status & CHFL_CHANOP)
	      member->status |= CHFL_BURST_ALREADY_OPPED;
	    if (member->status & CHFL_VOICE)
	      member->status |= CHFL_BURST_ALREADY_VOICED;
	    /* Synchronize with the burst. */
	    member->status |= CHFL_BURST_JOINED | (current_mode & (CHFL_CHANOP|CHFL_VOICE));
	    SetOpLevel(member, oplevel);
	  }
	}
      }
      param++;
      break;
    } /* switch (*parv[param]) */
  } /* while (param < parc) */

  nickstr[nickpos] = '\0';
  banstr[banpos] = '\0';

  if (parse_flags & MODE_PARSE_SET) {
    modebuf_extract(mbuf, modestr + 1); /* for sending BURST onward */
    modestr[0] = modestr[1] ? ' ' : '\0';
  } else
    modestr[0] = '\0';

  sendcmdto_serv_butone(sptr, CMD_BURST, cptr, "%H %Tu%s%s%s", chptr,
			chptr->creationtime, modestr, nickstr, banstr);

  if (parse_flags & MODE_PARSE_WIPEOUT || banpos)
    mode_ban_invalidate(chptr);

  if (parse_flags & MODE_PARSE_SET) { /* any modes changed? */
    /* first deal with channel members */
    for (member = chptr->members; member; member = member->next_member) {
      if (member->status & CHFL_BURST_JOINED) { /* joined during burst */
	if ((member->status & CHFL_CHANOP) && !(member->status & CHFL_BURST_ALREADY_OPPED))
	  modebuf_mode_client(mbuf, MODE_ADD | CHFL_CHANOP, member->user, OpLevel(member));
	if ((member->status & CHFL_VOICE) && !(member->status & CHFL_BURST_ALREADY_VOICED))
	  modebuf_mode_client(mbuf, MODE_ADD | CHFL_VOICE, member->user, OpLevel(member));
      } else if (parse_flags & MODE_PARSE_WIPEOUT) { /* wipeout old ops */
	if (member->status & CHFL_CHANOP)
	  modebuf_mode_client(mbuf, MODE_DEL | CHFL_CHANOP, member->user, OpLevel(member));
	if (member->status & CHFL_VOICE)
	  modebuf_mode_client(mbuf, MODE_DEL | CHFL_VOICE, member->user, OpLevel(member));
	member->status = (member->status
                          & ~(CHFL_CHANNEL_MANAGER | CHFL_CHANOP | CHFL_VOICE))
			 | CHFL_DEOPPED;
      }
    }

    /* Now deal with channel bans */
    lp_p = &chptr->banlist;
    while (*lp_p) {
      lp = *lp_p;

      /* remove ban from channel */
      if (lp->flags & (BAN_OVERLAPPED | BAN_BURST_WIPEOUT)) {
        char *bandup;
        DupString(bandup, lp->banstr);
	modebuf_mode_string(mbuf, MODE_DEL | MODE_BAN,
			    bandup, 1);
	*lp_p = lp->next; /* clip out of list */
        free_ban(lp);
	continue;
      } else if (lp->flags & BAN_BURSTED) /* add ban to channel */
	modebuf_mode_string(mbuf, MODE_ADD | MODE_BAN,
			    lp->banstr, 0); /* don't free banstr */

      lp->flags &= BAN_IPMASK; /* reset the flag */
      lp_p = &(*lp_p)->next;
    }
  }

  return mbuf ? modebuf_flush(mbuf) : 0;
}
Beispiel #30
0
/** Start a connection to another server.
 * @param aconf Connect block data for target server.
 * @param by Client who requested the connection (if any).
 * @return Non-zero on success; zero on failure.
 */
int connect_server(struct ConfItem* aconf, struct Client* by)
{
  struct Client*   cptr = 0;
  assert(0 != aconf);

  if (aconf->dns_pending) {
    sendto_opmask_butone(0, SNO_OLDSNO, "Server %s connect DNS pending",
                         aconf->name);
    return 0;
  }
  Debug((DEBUG_NOTICE, "Connect to %s[@%s]", aconf->name,
         ircd_ntoa(&aconf->address.addr)));

  if ((cptr = FindClient(aconf->name))) {
    if (IsServer(cptr) || IsMe(cptr)) {
      sendto_opmask_butone(0, SNO_OLDSNO, "Server %s already present from %s", 
                           aconf->name, cli_name(cli_from(cptr)));
      if (by && IsUser(by) && !MyUser(by)) {
        sendcmdto_one(&me, CMD_NOTICE, by, "%C :Server %s already present "
                      "from %s", by, aconf->name, cli_name(cli_from(cptr)));
      }
      return 0;
    }
    else if (IsHandshake(cptr) || IsConnecting(cptr)) {
      if (by && IsUser(by)) {
        sendcmdto_one(&me, CMD_NOTICE, by, "%C :Connection to %s already in "
                      "progress", by, cli_name(cptr));
      }
      return 0;
    }
  }
  /*
   * If we don't know the IP# for this host and it is a hostname and
   * not a ip# string, then try and find the appropriate host record.
   */
  if (!irc_in_addr_valid(&aconf->address.addr)
      && !ircd_aton(&aconf->address.addr, aconf->host)) {
    char buf[HOSTLEN + 1];

    host_from_uh(buf, aconf->host, HOSTLEN);
    gethost_byname(buf, connect_dns_callback, aconf);
    aconf->dns_pending = 1;
    return 0;
  }
  cptr = make_client(NULL, STAT_UNKNOWN_SERVER);

  /*
   * Copy these in so we have something for error detection.
   */
  ircd_strncpy(cli_name(cptr), aconf->name, HOSTLEN);
  ircd_strncpy(cli_sockhost(cptr), aconf->host, HOSTLEN);

  /*
   * Attach config entries to client here rather than in
   * completed_connection. This to avoid null pointer references
   */
  attach_confs_byhost(cptr, aconf->host, CONF_SERVER);

  if (!find_conf_byhost(cli_confs(cptr), aconf->host, CONF_SERVER)) {
    sendto_opmask_butone(0, SNO_OLDSNO, "Host %s is not enabled for "
                         "connecting: no Connect block", aconf->name);
    if (by && IsUser(by) && !MyUser(by)) {
      sendcmdto_one(&me, CMD_NOTICE, by, "%C :Connect to host %s failed: no "
                    "Connect block", by, aconf->name);
    }
    det_confs_butmask(cptr, 0);
    free_client(cptr);
    return 0;
  }
  /*
   * attempt to connect to the server in the conf line
   */
  if (!connect_inet(aconf, cptr)) {
    if (by && IsUser(by) && !MyUser(by)) {
      sendcmdto_one(&me, CMD_NOTICE, by, "%C :Couldn't connect to %s", by,
                    cli_name(cptr));
    }
    det_confs_butmask(cptr, 0);
    free_client(cptr);
    return 0;
  }
  /*
   * NOTE: if we're here we have a valid C:Line and the client should
   * have started the connection and stored the remote address/port and
   * ip address name in itself
   *
   * The socket has been connected or connect is in progress.
   */
  make_server(cptr);
  if (by && IsUser(by)) {
    ircd_snprintf(0, cli_serv(cptr)->by, sizeof(cli_serv(cptr)->by), "%s%s",
		  NumNick(by));
    assert(0 == cli_serv(cptr)->user);
    cli_serv(cptr)->user = cli_user(by);
    cli_user(by)->refcnt++;
  }
  else {
    *(cli_serv(cptr))->by = '\0';
    /* strcpy(cptr->serv->by, "Auto"); */
  }
  cli_serv(cptr)->up = &me;
  SetConnecting(cptr);

  if (cli_fd(cptr) > HighestFd)
    HighestFd = cli_fd(cptr);

  LocalClientArray[cli_fd(cptr)] = cptr;

  Count_newunknown(UserStats);
  /* Actually we lie, the connect hasn't succeeded yet, but we have a valid
   * cptr, so we register it now.
   * Maybe these two calls should be merged.
   */
  add_client_to_list(cptr);
  hAddClient(cptr);
/*    nextping = CurrentTime; */

  return (s_state(&cli_socket(cptr)) == SS_CONNECTED) ?
    completed_connection(cptr) : 1;
}