Logo Search packages:      
Sourcecode: rageircd version File versions  Download package

s_misc.c

/*
 * RageIRCd: an advanced Internet Relay Chat daemon (ircd).
 * (C) 2000-2005 the RageIRCd Development Team, all rights reserved.
 *
 * This software is free, licensed under the General Public License.
 * Please refer to doc/LICENSE and doc/README for further details.
 *
 * $Id: s_misc.c,v 1.128.2.2 2005/06/26 18:47:07 amcwilliam Exp $
 */

#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "zlink.h"
#include "memory.h"
#include "h.h"
#include "fd.h"
#include "hook.h"
#include "dlink.h"
#include "res.h"
#include "xmode.h"
#include "user_ban.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <time.h>
#include <sys/param.h>

static char *months[] = {
      "January",
      "February",
      "March",
      "April",
      "May",
      "June",
      "July",
      "August",
      "September",
      "October",
      "November",
      "December"
};
static char *weekdays[] = {
      "Sunday",
      "Monday",
      "Tuesday",
      "Wednesday",
      "Thursday",
      "Friday",
      "Saturday"
};

static void exit_one_client(aClient *, aClient *, aClient *, char *, int);

struct stats ircst, *ircstp = &ircst;

char *date(time_t c)
{
      static char buf[80], plus;
      struct tm *lt, *gm, gmbuf;
      int minswest;

      if (!c) {
            time(&c);
      }

      gm = gmtime(&c);
      memcpy((char *)&gmbuf, (char *)gm, sizeof(gmbuf));
      gm = &gmbuf;
      lt = localtime(&c);

      if (lt->tm_yday == gm->tm_yday) {
            minswest = (gm->tm_hour - lt->tm_hour) * 60 + (gm->tm_min - lt->tm_min);
      }
      else if (lt->tm_yday > gm->tm_yday) {
            minswest = (gm->tm_hour - (lt->tm_hour + 24)) * 60;
      }
      else {
            minswest = ((gm->tm_hour + 24) - lt->tm_hour) * 60;
      }

      plus = (minswest > 0) ? '-' : '+';
      if (minswest < 0) {
            minswest = -minswest;
      }
      ircsprintf(buf, "%s %s %d %04d -- %02d:%02d %c%02d:%02d", weekdays[lt->tm_wday], months[lt->tm_mon],
            lt->tm_mday, lt->tm_year + 1900, lt->tm_hour, lt->tm_min, plus, minswest / 60, minswest % 60);
      return buf;
}

char *smalldate(time_t c)
{
      static char buf[MAX_DATE_STRING];
      struct tm *lt, *gm, gmbuf;

      if (!c) {
            time(&c);
      }

      gm = gmtime(&c);
      memcpy((char *)&gmbuf, (char *)gm, sizeof(gmbuf));
      gm = &gmbuf;
      lt = localtime(&c);

      ircsprintf(buf, "%04d/%02d/%02d %02d:%02d", lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday,
            lt->tm_hour, lt->tm_min);
      return buf;
}

char *myctime(time_t value)
{
      static char buf[28];
      char *p;

      strcpy(buf, ctime(&value));
      if ((p = strchr(buf, '\n')) != NULL) {
            *p = '\0';
      }
      return buf;
}

char *check_string(char *str)
{
      char *p;

      if (BadPtr(str)) {
            return "*";
      }
      for (p = str; *p != '\0'; p++) {
            if (IsSpace(*p)) {
                  *p = '\0';
                  break;
            }
      }
      return BadPtr(str) ? "*" : str;
}

char *make_nick_user_host(char *nick, char *user, char *host)
{
      static char namebuf[NICKLEN + USERLEN + HOSTLEN + 6];
      int n;
      char *t = namebuf, *s;

      for (s = check_string(nick), n = NICKLEN; *s != '\0' && n-- > 0;) {
            *t++ = *s++;
      }

      *t++ = '!';
      for (s = check_string(user), n = USERLEN; *s != '\0' && n-- > 0;) {
            *t++ = *s++;
      }

      *t++ = '@';
      for (s = check_string(host), n = HOSTLEN; *s != '\0' && n-- > 0;) {
            *t++ = *s++;
      }

      *t = '\0';
      return namebuf;
}

char *make_user_host(char *user, char *host)
{
      static char namebuf[USERLEN + HOSTLEN + 4];
      char *t = namebuf, *s;
      int n;

      for (s = check_string(user), n = USERLEN; *s != '\0' && n-- > 0;) {
            *t++ = *s++;
      }

      *t++ = '@';
      for (s = check_string(host), n = HOSTLEN; *s != '\0' && n-- > 0;) {
            *t++ = *s++;
      }

      *t = '\0';
      return namebuf;
}

char *get_client_name(aClient *sptr, int show_ip)
{
      static char nbuf[HOSTLEN * 2 + USERLEN + 5];

      ASSERT(sptr != NULL);

      if (!MyConnect(sptr)) {
            return sptr->name;
      }

      ASSERT(sptr->localClient != NULL);

      switch (show_ip) {
            case SHOW_IP:
                  ircsprintf(nbuf, "%s[%s@%s]", sptr->name, (!GotID(sptr)) ? "" : sptr->username,
                        (*sptr->hostip != '\0') ? sptr->hostip : inetntoa((const char *)&sptr->ip));
                  break;
            case HIDE_IP:
                  ircsprintf(nbuf, "%s[%s@" HIDDEN_IP "]", sptr->name, (!GotID(sptr)) ? "" : sptr->username);
                  break;
            default:
                  if (!mycmp(sptr->name, sptr->localClient->sockhost)) {
                        return sptr->name;
                  }
                  ircsprintf(nbuf, "%s[%s@%s]", sptr->name, sptr->username, sptr->localClient->sockhost);
                  break;
      }

      return nbuf;
}

void target_left(aClient *cptr, char *target_name, char *cmd, char *msgbuf)
{
      if (IsMe(cptr)) {
            return;
      }
      if (MyClient(cptr) || *target_name != '!') {
            send_me_numeric(cptr, ERR_NOSUCHNICK, target_name);
      }
      else if (msgbuf != NULL) {
            char truncated_msgbuf[24], *p;
            int i = 0;

            for (p = msgbuf; (*p != '\0') && (i < 20); p++) {
                  truncated_msgbuf[i++] = *p;
            }
            if (i == 20) {
                  truncated_msgbuf[i++] = '.';
                  truncated_msgbuf[i++] = '.';
                  truncated_msgbuf[i++] = '.';
            }
            truncated_msgbuf[i] = '\0';

            send_me_numeric_buf(cptr, "* :Target lost in transit. Could not deliver %s: %s",
                  ERR_NOSUCHNICK, cmd, truncated_msgbuf);
      }
      else {
            send_me_numeric_buf(cptr, "* :Target lost in transit. Could not deliver %s",
                  ERR_NOSUCHNICK, cmd);
      }
}

static void exit_one_client_in_split(aClient *sptr, aClient *dead, char *reason)
{
      chanMember *cm;
      SLink *lp;
      HookData hdata = HOOKDATA_INIT;

      sendto_serv_capab_msg_butone(dead, sptr, NO_CAPS, CAP_NOQUIT, &CMD_QUIT, ":%s", reason);
      sendto_channel_local_msg_common(sptr, &CMD_QUIT, ":%s", reason);

      while ((cm = sptr->user->channel) != NULL) {
            remove_user_from_channel(sptr, cm->chptr);
      }
      while ((lp = sptr->user->silence) != NULL) {
            del_silence(sptr, lp->value.cp);
      }

      hdata.cptr = dead;
      hdata.sptr = sptr;
      hdata.c = reason;
      hook_run(h_exit_user_remote, &hdata);

      if (HasSUID(sptr)) {
            del_userid_from_serv(sptr->uplink, sptr);
      }

      del_from_client_hash_table(sptr->name, sptr);
      hash_check_watch(sptr, RPL_LOGOFF);
      remove_client_from_list(sptr);
}

static void exit_one_server(aClient *cptr, aClient *dead, aClient *from, aClient *lcptr, char *spinfo, char *comment)
{
      aClient *acptr, *next = NULL;
      dlink_node *node;
      HookData hdata = HOOKDATA_INIT;

      Debug((DEBUG_NOTICE, "server noquit: %s", cptr->name));

      for (acptr = client; acptr != NULL; acptr = next)  {
            next = acptr->next;
            if (acptr->uplink != cptr || !IsPerson(acptr)) {
                  continue;
            }
            exit_one_client_in_split(acptr, dead, spinfo);
      }
      for (acptr = client; acptr != NULL; acptr = next) {
            next = acptr->next;
            if (acptr->uplink != cptr || !IsServer(acptr)) {
                  continue;
            }
            exit_one_server(acptr, dead, from, lcptr, spinfo, comment);
            next = client;
      }

      Debug((DEBUG_NOTICE, "done exiting server: %s", cptr->name));

      DLINK_FOREACH_DATA(lserver_list.head, node, acptr, aClient) {
            if (acptr == cptr || IsMe(acptr) || acptr == dead || acptr == lcptr) {
                  continue;
            }
            if (CapNOQUIT(acptr) && (cptr != dead)) {
                  continue;
            }
            sendto_one_client_real(acptr, cptr, (cptr->from == acptr) ? from : NULL,
                  &CMD_SQUIT, ":%s", comment);
      }

      hdata.sptr = cptr;
      hdata.c = comment;
      hook_run(h_exit_server, &hdata);

      del_from_client_hash_table(cptr->name, cptr); 
      hash_check_watch(cptr, RPL_LOGOFF);

      if (HasSUID(cptr)) {
            del_base64_serv(cptr);
      }

      remove_client_from_list(cptr);
}

static void exit_server(aClient *lcptr, aClient *cptr, aClient *from, char *comment)
{
      char splitname[HOSTLEN + HOSTLEN + 2];

      Debug((DEBUG_NOTICE, "exit_server(%s, %s, %s)", cptr->name, from->name, comment));

      ircsprintf(splitname, "%s %s", cptr->uplink->name, cptr->name);
      exit_one_server(cptr, cptr, from, lcptr, splitname, comment);
}

int exit_client_kill(aClient *cptr, aClient *sptr, userBan *uban)
{
      char *ban, *banned;

      ASSERT(sptr != NULL);
      ASSERT(uban != NULL);

      ban = (uban->flags & BAN_LOCAL) ? LOCAL_BAN : NETWORK_BAN;
      banned = (uban->flags & BAN_LOCAL) ? LOCAL_BANNED : NETWORK_BANNED;

      ircstp->is_ref++;

      ircdlog(LOG_KILL, "%s active for %s!%s@%s", ban, sptr->name, sptr->username, sptr->host);
      sendto_realops_lev(REJ_LEV, "%s active for %s!%s@%s", ban, sptr->name, sptr->username, sptr->host);

      send_me_numeric(sptr, ERR_YOUREBANNEDCREEP, banned);

      send_me_notice(sptr, ":*** You are not welcome on this %s: %s",
            (uban->flags & BAN_LOCAL) ? "server" : "network", BanReason(uban));
      send_me_notice(sptr, ":*** For assistance, please e-mail %s and include everything shown here.",
            (uban->flags & BAN_LOCAL) ? ServerInfo->kline_address : NetworkConfig.kline_address);

#ifdef USE_THROTTLE
      if (FloodConfig.throttle_rejected_clients) {
            throttle_force(sptr->host);
      }
#endif

      return exit_client(cptr, sptr, &me, banned);
}

int exit_client_zap(aClient *cptr, aClient *sptr, userBan *uban)
{
      ASSERT(sptr != NULL);
      ASSERT(uban != NULL);

      ircstp->is_ref++;

      ircdlog(LOG_KILL, "zap active for %s!%s@%s", sptr->name, sptr->username, sptr->hostip);
      sendto_realops_lev(REJ_LEV, "zap active for %s!%s@%s", sptr->name, sptr->username, sptr->hostip);

      sendto_one_client_nopostfix(sptr, NULL, &CMD_ERROR, ":You have been zapped: %s", BanReason(uban));

      return exit_client(cptr, sptr, &me, "zapped");
}

int exit_client(aClient *cptr, aClient *sptr, aClient *from, char *comment)
{
      int is_remote = 1;
      
      if (MyConnect(sptr)) {
            HookData hdata = HOOKDATA_INIT;
            hdata.sptr = sptr;
            hdata.c = comment;

            ASSERT(sptr->localClient != NULL);

            if (IsClosing(sptr)) {
                  return 0;
            }
            SetClosing(sptr);
            
            is_remote = 0;

            if (sptr->localClient->auth != NULL) {
                  connauth_delete_queries(sptr);
            }
            if (HashedIP(sptr)) {
                  remove_one_ip(&sptr->ip);
            }
            if ((sptr->serv != NULL) && DoingDKEY(sptr)) {
                  sendto_realops("Lost server %s during negotiation: %s", sptr->name, comment);
            }

            if (IsServer(sptr)) {
                  Count.myserver--;
                  if (IsULine(sptr)) {
                        Count.mysuper--;
                  }

                  dlink_del_nofree(&lserver_list, NULL, &sptr->localClient->self);
            }

            if (IsPerson(sptr)) {
                  SLink *lp, *next = NULL;

                  hash_del_watch_list(sptr);

                  if (sptr->localUser->lopt != NULL) {
                        LOpts *lopt = sptr->localUser->lopt;

                        dlink_del(&listingcli_list, sptr, NULL);
                        for (lp = lopt->yeslist; lp != NULL; lp = next) {
                              next = lp->next;
                              MyFree(lp->value.cp);
                              free_slink(lp);
                        }
                        for (lp = lopt->nolist; lp != NULL; lp = next) {
                              next = lp->next;
                              MyFree(lp->value.cp);
                              free_slink(lp);
                        }
                        MyFree(sptr->localUser->lopt);
                  }

                  ircdlog(LOG_CLIENT, "disconnecting client %s (%s)", get_client_name(sptr, FALSE),
                        comment);
                  sendto_realops_lev(CCONN_LEV, "Client exiting: %s (%s@%s) [%s]", sptr->name, sptr->username,
                        sptr->host, NormalExit(sptr) ?
                        !GeneralConfig.show_cliconn_quit_msgs ? "Client Quit" : comment : comment);

                  hook_run(h_exit_user_local, &hdata);
            }
            else if (IsUnknown(sptr)) {
                  Count.unknown--;
                  hook_run(h_exit_unknown, &hdata);
            }
            if (sptr->localClient->fd >= 0) {
                  if (cptr != NULL && (sptr != cptr)) {
                        sendto_one_client_nopostfix(sptr, NULL, &CMD_ERROR, ":Closing Link: %s %s (%s)",
                              IsPerson(sptr) ? sptr->localClient->sockhost : HIDDEN_IP,
                              sptr->name, comment);
                  }
                  else {
                        sendto_one_client_nopostfix(sptr, NULL, &CMD_ERROR, ":Closing Link: %s (%s)",
                              IsPerson(sptr) ? sptr->localClient->sockhost : HIDDEN_IP, comment);
                  }
            }

            close_connection(sptr);
            SetDeadSocket(sptr);

            if (IsServer(sptr)) {
                  sendto_realops("%s was connected for %s. %lu/%lu sendK/recvK.", sptr->name,
                        time_to_str(timeofday - sptr->firsttime), sptr->localClient->sendK,
                        sptr->localClient->receiveK);
                  ircdlog(LOG_SERVER, "%s was connected for %s. %lu/%lu sendK/recvK.",
                        sptr->name, time_to_str(timeofday - sptr->firsttime),
                        sptr->localClient->sendK, sptr->localClient->receiveK);
            }

            if (!IsRegistered(sptr)) {
                  dlink_del_nofree(&lunknown_list, NULL, &sptr->localClient->self);
            }
            else if (IsClient(sptr)) {
                  Count.local--;
                  dlink_del_nofree(&lclient_list, NULL, &sptr->localClient->self);

                  if (HasMode(sptr, UMODE_OPER)) {
                        dlink_del(&oper_list, sptr, NULL);
                  }
            }
      }

      exit_one_client(cptr, sptr, from, comment, is_remote);

      return (cptr == sptr) ? FLUSH_BUFFER : 0;
}

static void exit_one_client(aClient *cptr, aClient *sptr, aClient *from,
  char *comment, int is_remote)
{
      chanMember *cm;
      SLink *lp;

      if (IsMe(sptr)) {
            sendto_realops("ERROR: tried to exit me! : %s", comment);
            return;
      }
      else if (IsServer(sptr)) {
#ifdef ALWAYS_SEND_DURING_SPLIT
            Internal.net_split = 1;
#endif
            exit_server(cptr, sptr, from, comment);
#ifdef ALWAYS_SEND_DURING_SPLIT
            Internal.net_split = 0;
#endif
            return;
      }
      else if (!(IsPerson(sptr))) {
            /* Nothing! */
      }
      else if (*sptr->name) {
            if (!IsKilled(sptr)) {
                  sendto_serv_msg_butone(cptr, sptr, &CMD_QUIT, ":%s", comment);
            }
            if (sptr->user != NULL) {
                  /* Send global client connect notice here rather than in
                   * exit_client() so we know this is not a netsplit.
                   */
                  if (!IsULine(sptr) && is_remote) {
                        sendto_realops_lev(GCCONN_LEV, "Client exiting at %s: "
                              "%s (%s@%s) [%s]", sptr->user->server, sptr->name,
                              sptr->username, sptr->host,
                              (NormalExit(sptr) && !GeneralConfig.show_cliconn_quit_msgs) ? "Client Quit" : comment);
                  }
                  
                  send_part_to_common_channels(sptr, comment);
                  send_quit_to_common_channels(sptr, comment);

                  while ((cm = sptr->user->channel) != NULL) {
                        remove_user_from_channel(sptr, cm->chptr);
                  }
                  while ((lp = sptr->user->silence) != NULL) {
                        del_silence(sptr, lp->value.cp);
                  }
                  if (MyConnect(sptr)) {
                        free_local_userid(sptr);
                        while ((lp = sptr->localUser->invited) != NULL) {
                              del_invite(sptr, lp->value.chptr);
                        }
                  }
                  else {
                        HookData hdata = HOOKDATA_INIT;
                        hdata.sptr = sptr;
                        hdata.c = comment;
                        hook_run(h_exit_user_remote, &hdata);
                  }
            }
      }
      if (HasSUID(sptr)) {
            if (IsServer(sptr)) {
                  del_base64_serv(sptr);
            }
            else {
                  del_userid_from_serv(sptr->uplink, sptr);
            }
      }
      if (IsHashed(sptr) && del_from_client_hash_table(sptr->name, sptr) != 1) {
            sendto_realops_lev(DEBUG_LEV, "HASHING ERROR! %#x !in tab %s[%s] from %#x next %#x "
                  "hnext %#x prev %#x fd %d status %d user %#x", sptr, sptr->name,
                  sptr->from ? sptr->from->localClient->sockhost : "??host", sptr->from, sptr->next,
                  sptr->hnext, sptr->prev, sptr->localClient->fd, sptr->status, sptr->user);
            ircdlog(LOG_ERROR, "HASHING ERROR! %#x !in tab %s[%s] from %#x next %#x "
                  "hnext %#x prev %#x fd %d status %d user %#x", sptr, sptr->name,
                  sptr->from ? sptr->from->localClient->sockhost : "??host", sptr->from, sptr->next,
                  sptr->hnext, sptr->prev, sptr->localClient->fd, sptr->status, sptr->user);
            Debug((DEBUG_ERROR, "HASHING ERROR! %#x !in tab %s[%s] from %#x next %#x "
                  "hnext %#x prev %#x fd %d status %d user %#x", sptr, sptr->name,
                  sptr->from ? sptr->from->localClient->sockhost : "??host", sptr->from, sptr->next,
                  sptr->hnext, sptr->prev, sptr->localClient->fd, sptr->status, sptr->user));
      }
      if (IsRegistered(sptr)) {
            hash_check_watch(sptr, RPL_LOGOFF);
      }
      remove_client_from_list(sptr);
}

void init_stats()
{
      memset((char *)&ircst, '\0', sizeof(ircst));
}

void serv_stats(aClient *cptr)
{
      aClient *acptr;
      dlink_node *node;
      struct stats tmp, *sp = &tmp;

      memcpy(sp, ircstp, sizeof(*sp));

      sp->is_sv = dlink_length(&lserver_list);
      DLINK_FOREACH_DATA(lserver_list.head, node, acptr, aClient) {
            sp->is_sbs += acptr->localClient->sendB;
            sp->is_sbr += acptr->localClient->receiveB;
            sp->is_sks += acptr->localClient->sendK;
            sp->is_skr += acptr->localClient->receiveK;
            sp->is_sti += timeofday - acptr->firsttime;

            if (sp->is_sbs > 1023) {
                  sp->is_sks += (sp->is_sbs >> 10);
                  sp->is_sbs &= 0x3ff;
            }
            if (sp->is_sbr > 1023) {
                  sp->is_skr += (sp->is_sbr >> 10);
                  sp->is_sbr &= 0x3ff;
            }
      }

      sp->is_cl = dlink_length(&lclient_list);
      DLINK_FOREACH_DATA(lclient_list.head, node, acptr, aClient) {
            sp->is_cbs += acptr->localClient->sendB;
            sp->is_cbr += acptr->localClient->receiveB;
            sp->is_cks += acptr->localClient->sendK;
            sp->is_ckr += acptr->localClient->receiveK;
            sp->is_cti += timeofday - acptr->firsttime;

            if (sp->is_cbs > 1023) {
                  sp->is_cks += (sp->is_cbs >> 10);
                  sp->is_cbs &= 0x3ff;
            }
            if (sp->is_cbr > 1023) {
                  sp->is_ckr += (sp->is_cbr >> 10);
                  sp->is_cbr &= 0x3ff;
            }
      }

      sp->is_ni = dlink_length(&lunknown_list);

      send_me_debug(cptr, "t :accepts %u refused %u", sp->is_ac, sp->is_ref);
      send_me_debug(cptr, "t :unknown commands %u prefixes %u", sp->is_unco, sp->is_unpf);
      send_me_debug(cptr, "t :nick collisions %u unknown closes %u", sp->is_kill, sp->is_ni);
      send_me_debug(cptr, "t :wrong direction %u empty %u", sp->is_wrdi, sp->is_empt);
      send_me_debug(cptr, "t :numerics seen %u mode fakes %u", sp->is_num, sp->is_fake);
      send_me_debug(cptr, "t :auth successes %u fails %u", sp->is_asuc, sp->is_abad);
      send_me_debug(cptr, "t :udp packets %u", sp->is_udp);

      send_me_debugNA(cptr, "t :Client Server");

      send_me_debug(cptr, "t :connected %u %u", sp->is_cl, sp->is_sv);
      send_me_debug(cptr, "t :bytes sent %u.%uK %u.%uK", sp->is_cks, sp->is_cbs, sp->is_sks, sp->is_sbs);
      send_me_debug(cptr, "t :bytes recv %u.%uK %u.%uK", sp->is_ckr, sp->is_cbr, sp->is_skr, sp->is_sbr);
      send_me_debug(cptr, "t :time connected %u %u", sp->is_cti, sp->is_sti);
#ifdef FLUD
      send_me_debug(cptr, "t :CTCP floods blocked %u", sp->is_flud);
#endif
}

Generated by  Doxygen 1.6.0   Back to index