]> jfr.im git - irc/quakenet/snircd.git/commitdiff
forward port of asuka-sethost.patch to .12.
authorpaul <redacted>
Sun, 23 Oct 2005 21:59:00 +0000 (22:59 +0100)
committerpaul <redacted>
Sun, 23 Oct 2005 21:59:00 +0000 (22:59 +0100)
Note: check - corrupted patch file manually applied.

33 files changed:
include/client.h
include/handlers.h
include/ircd_features.h
include/ircd_log.h
include/msg.h
include/numeric.h
include/s_conf.h
include/s_user.h
include/struct.h
ircd/Makefile.in
ircd/channel.c
ircd/gline.c
ircd/ircd_features.c
ircd/ircd_lexer.l
ircd/ircd_log.c
ircd/ircd_parser.y
ircd/ircd_snprintf.c
ircd/m_oper.c
ircd/m_sethost.c [new file with mode: 0644]
ircd/m_userhost.c
ircd/m_userip.c
ircd/m_who.c
ircd/m_whois.c
ircd/parse.c
ircd/s_auth.c
ircd/s_conf.c
ircd/s_err.c
ircd/s_serv.c
ircd/s_stats.c
ircd/s_user.c
ircd/send.c
ircd/whocmds.c
tools/convert_slines.sh [new file with mode: 0644]

index ce6ebadccd640c8ad7b0fb0a9c9c2f3a1bfab69b..1983bfbc36d9bef34b90b1fc86744d46f1bae798 100644 (file)
@@ -169,6 +169,7 @@ enum Flag
     FLAG_ACCOUNTONLY,               /**< ASUKA_R: hide privmsgs/notices if
                                      user is not authed or opered */
     FLAG_HIDDENHOST,                /**< user's host is hidden */
+    FLAG_SETHOST,                   /**< ASUKA_h: oper's host is changed */
     FLAG_NOCHAN,                    /**< user's channels are hidden */
     FLAG_NOIDLE,                    /**< user's idletime is hidden */
     FLAG_XTRAOP,                    /**< oper has special powers */
@@ -626,6 +627,9 @@ struct Client {
 #define IsPrivileged(x)         (IsAnOper(x) || IsServer(x))
 /** Return non-zero if the client's host is hidden. */
 #define HasHiddenHost(x)        (IsHiddenHost(x) && IsAccount(x))
+/** Return non-zero if the client is using a spoofhost */
+#define IsSetHost(x)            HasFlag(x, FLAG_SETHOST)
+#define HasSetHost(x)           (IsSetHost(x))
 
 /** Mark a client as having an in-progress net.burst. */
 #define SetBurst(x)             SetFlag(x, FLAG_BURST)
@@ -667,6 +671,8 @@ struct Client {
 #define SetAccount(x)           SetFlag(x, FLAG_ACCOUNT)
 /** Mark a client as having mode +x (hidden host). */
 #define SetHiddenHost(x)        SetFlag(x, FLAG_HIDDENHOST)
+/** Mark a client as having mode +h (spoofhost). */
+#define SetSetHost(x)           SetFlag(x, FLAG_SETHOST)
 /** Mark a client as having mode +X (xtraop). */
 #define SetXtraOp(x)            SetFlag(x, FLAG_XTRAOP)
 /** Mark a client as having mode +n (hide channels). */
@@ -708,6 +714,8 @@ struct Client {
 #define ClearServNotice(x)      ClrFlag(x, FLAG_SERVNOTICE)
 /** Remove mode +x (hidden host) from the client. */
 #define ClearHiddenHost(x)      ClrFlag(x, FLAG_HIDDENHOST)
+/** Remove mode +h (spoofhost) from a client. */
+#define ClearSetHost(x)         ClrFlag(x, FLAG_SETHOST)
 /** Remove mode +X (xtraop) from a client. */
 #define ClearXtraOp(x)          ClrFlag(x, FLAG_XTRAOP)
 /** Remove mode +n (hide channels) from a client. */
index 36c80fb2b8e87a3aeef611124cfe39003236d4df..0a56025289875b06ddabee33021880831b83c09a 100644 (file)
@@ -124,6 +124,7 @@ extern int m_proto(struct Client*, struct Client*, int, char*[]);
 extern int m_pseudo(struct Client*, struct Client*, int, char*[]);
 extern int m_quit(struct Client*, struct Client*, int, char*[]);
 extern int m_registered(struct Client*, struct Client*, int, char*[]);
+extern int m_sethost(struct Client*, struct Client*, int, char*[]);
 extern int m_silence(struct Client*, struct Client*, int, char*[]);
 extern int m_stats(struct Client*, struct Client*, int, char*[]);
 extern int m_time(struct Client*, struct Client*, int, char*[]);
index ccba85fdfe41b348d3fbb267ebcc93383fc03483..589b746f8c88f964f09ae74f68b849806a084532 100644 (file)
@@ -101,6 +101,10 @@ enum Feature {
 
   /* features that affect all operators */
   FEAT_CONFIG_OPERCMDS,
+  FEAT_SETHOST,
+  FEAT_SETHOST_FREEFORM,
+  FEAT_SETHOST_USER,
+  FEAT_SETHOST_AUTO,
 
   /* HEAD_IN_SAND Features */
   FEAT_HIS_SNOTICES,
@@ -129,6 +133,7 @@ enum Feature {
   FEAT_HIS_STATS_q,
   FEAT_HIS_STATS_R,
   FEAT_HIS_STATS_r,
+  FEAT_HIS_STATS_s,
   FEAT_HIS_STATS_t,
   FEAT_HIS_STATS_T,
   FEAT_HIS_STATS_u,
index d50590ec92e2c1bbe5fe22af82671c52304c412b..472ca8b903ae93004ee7db90ed2777f0d3869808 100644 (file)
@@ -65,6 +65,7 @@ enum LogSys {
   LS_SOCKET,     /**< Unexpected socket operation errors. */
   LS_IAUTH,      /**< IAuth status. */
   LS_DEBUG,      /**< Debug messages. */
+  LS_SETHOST,    /**< Usage of the sethost command. */
   LS_LAST_SYSTEM /**< Count of valid LogSys values. */
 };
 
index 212852cc19b84ee126186c364dbabee3531b4021..ee2e4d66de1012245915374b36244cd71f6c77c5 100644 (file)
@@ -356,6 +356,10 @@ struct Client;
 #define TOK_PRIVS              "PR"
 #define CMD_PRIVS               MSG_PRIVS, TOK_PRIVS
 
+#define MSG_SETHOST            "SETHOST"       /* SETHOST */
+#define TOK_SETHOST            "SH"
+#define CMD_SETHOST            MSG_SETHOST, TOK_SETHOST
+
 #define MSG_CAP                        "CAP"
 #define TOK_CAP                        "CAP"
 #define CMD_CAP                        MSG_CAP, TOK_CAP
index 939561ab494af2554b680bcf0fd3592672ece502..3e5fd204ce8b91a902f22e002a4fcb63aac2c59b 100644 (file)
@@ -207,7 +207,7 @@ extern const struct Numeric* get_error_numeric(int err);
 #define RPL_AWAY             301
 #define RPL_USERHOST         302
 #define RPL_ISON             303
-/*      RPL_TEXT             304       unused */
+#define RPL_TEXT             304       /* unused */
 #define RPL_UNAWAY           305
 #define RPL_NOWAWAY          306
                                         /* NotAway, aircd */
@@ -312,6 +312,8 @@ extern const struct Numeric* get_error_numeric(int err);
 /*      RPL_END_USERS        394        Dalnet/EFnet/IRCnet */
 /*      RPL_NOUSERS          395        Dalnet/EFnet/IRCnet */
 #define RPL_HOSTHIDDEN       396       /* UMODE +x completed succesfuly */
+#define RPL_STATSSLINE       398       /* QuakeNet extension -froo */
+#define RPL_USINGSLINE       399       /* QuakeNet extension -froo */
 
 /*
  * Errors are in the range from 400-599 currently and are grouped by what
@@ -457,7 +459,9 @@ extern const struct Numeric* get_error_numeric(int err);
        ERR_LISTSYNTAX       521        dalnet
        ERR_WHOSYNTAX        522        dalnet
        ERR_WHOLIMEXCEED     523        dalnet */
-#define ERR_QUARANTINED      524       /* Undernet extension -Vampire */
+#define ERR_QUARANTINED      524        /* Undernet extension -Vampire */
+#define ERR_BADHOSTMASK      530       /* QuakeNet extension -froo */
+#define ERR_HOSTUNAVAIL      531       /* QuakeNet extension -froo */
 
 #define ERR_NOTLOWEROPLEVEL  560       /* Undernet extension */
 #define ERR_NOTMANAGER       561       /* Undernet extension */
index e309f2f22030803f75629226434f0e5fbac9619e..5f119ced35d943a67425ff06e037df42870a4fac 100644 (file)
@@ -80,6 +80,20 @@ struct qline
   char *reason;       /**< Reason for quarantine. */
 };
 
+struct sline {
+  struct sline *next;
+  char *spoofhost;
+  char *passwd;
+  char *realhost;
+  char *username;
+  struct irc_in_addr address;
+  unsigned int flags;
+  char bits; /* Number of bits for CIDR match on realhost */
+};
+
+#define SLINE_FLAGS_HOSTNAME 0x0001 /* S-line by hostname */
+#define SLINE_FLAGS_IP       0x0002 /* S-line by IP address/CIDR */
+
 /** Local K-line structure. */
 struct DenyConf {
   struct DenyConf*    next;     /**< Next DenyConf in #denyConfList. */
@@ -157,6 +171,7 @@ extern struct ConfItem* GlobalConfList;
 extern int              GlobalConfCount;
 extern struct s_map*    GlobalServiceMapList;
 extern struct qline*    GlobalQuarantineList;
+extern struct sline*   GlobalSList;
 
 /*
  * Proto types
@@ -188,6 +203,11 @@ extern void conf_parse_userhost(struct ConfItem *aconf, char *host);
 extern struct ConfItem *conf_debug_iline(const char *client);
 extern void free_mapping(struct s_map *smap);
 
+extern void conf_add_sline(const char* const* fields, int count);
+extern void clear_slines(void);
+extern int conf_check_slines(struct Client *cptr);
+extern void free_spoofhost(struct sline *spoof);
+
 extern void yyerror(const char *msg);
 
 #endif /* INCLUDED_s_conf_h */
index 9565a6f5a7b03182bac3e6667d41ad9b95323bef..7c911a992dc8ba38b4d6fcfe025c3cbbbf4d738f 100644 (file)
@@ -79,6 +79,8 @@ extern void send_user_info(struct Client* to, char* names, int rpl,
                            InfoFormatter fmt);
 
 extern int hide_hostmask(struct Client *cptr, unsigned int flags);
+extern int set_hostmask(struct Client *cptr, char *hostmask, char *password);
+extern int is_hostmask(char *word);
 extern int set_user_mode(struct Client *cptr, struct Client *sptr,
                          int parc, char *parv[]);
 extern int is_silenced(struct Client *sptr, struct Client *acptr);
index 361f1aea410a1da636d8e480b594fff3e456ab54..358336904f4f40022e085629bd6998bf5b678c08 100644 (file)
@@ -79,10 +79,11 @@ struct User {
    * overwritten with the ident response.
    */
   char               username[USERLEN + 1];
-  char               host[HOSTLEN + 1];       /**< displayed hostname */
-  char               realhost[HOSTLEN + 1];   /**< actual hostname */
-  char               account[ACCOUNTLEN + 1]; /**< IRC account name */
-  time_t            acc_create;              /**< IRC account timestamp */
+  char               host[HOSTLEN + 1];         /**< displayed hostname */
+  char               realusername[USERLEN + 1]; /**< actual username */
+  char               realhost[HOSTLEN + 1];     /**< actual hostname */
+  char               account[ACCOUNTLEN + 1];   /**< IRC account name */
+  time_t            acc_create;                /**< IRC account timestamp */
 };
 
 #endif /* INCLUDED_struct_h */
index aa28b7e1c1139322da70af6e2faab18f8db8100d..e926e8a0581412753313b1315134c184d40d7619 100644 (file)
@@ -168,6 +168,7 @@ IRCD_SRC = \
        m_rpong.c \
        m_server.c \
        m_set.c \
+       m_sethost.c \
        m_settime.c \
        m_silence.c \
        m_squit.c \
index 2a2d2115e593000dd1365712515e54b30b58f8a2..aaa53dbd7070a6389410c33d8ab2a3c46a971e32 100644 (file)
@@ -357,7 +357,7 @@ struct Ban *find_ban(struct Client *cptr, struct Ban *banlist)
   ircd_ntoa_r(iphost, &cli_ip(cptr));
   if (!IsAccount(cptr))
     sr = NULL;
-  else if (HasHiddenHost(cptr))
+  else if (HasHiddenHost(cptr) || HasSetHost(cptr))
     sr = cli_user(cptr)->realhost;
   else
   {
index 3b4fea7435fe7439929d4b941faf7fe6d32271a4..89fa06c33b0398a42ecefc0f228e3c8ee8db07fd 100644 (file)
@@ -217,7 +217,7 @@ do_gline(struct Client *cptr, struct Client *sptr, struct Gline *gline)
         Debug((DEBUG_DEBUG,"Matched!"));
       } else { /* Host/IP gline */
         if (cli_user(acptr)->username &&
-            match(gline->gl_user, (cli_user(acptr))->username) != 0)
+            match(gline->gl_user, (cli_user(acptr))->realusername) != 0)
           continue;
 
         if (GlineIsIpMask(gline)) {
index 92e0d022bf0f985b77ff2d3dc9136be6f4bea799..bb44faedf9e0d2b2e399128f5fb75d3b6646935e 100644 (file)
@@ -354,6 +354,10 @@ static struct FeatureDesc {
 
   /* features that affect all operators */
   F_B(CONFIG_OPERCMDS, 0, 0, 0),
+  F_B(SETHOST, 0, 0, 0),
+  F_B(SETHOST_FREEFORM, 0, 0, 0),
+  F_B(SETHOST_USER, 0, 0, 0),
+  F_B(SETHOST_AUTO, 0, 0, 0),
 
   /* HEAD_IN_SAND Features */
   F_B(HIS_SNOTICES, 0, 1, 0),
@@ -382,6 +386,7 @@ static struct FeatureDesc {
   F_B(HIS_STATS_q, 0, 1, 0),
   F_B(HIS_STATS_R, 0, 1, 0),
   F_B(HIS_STATS_r, 0, 1, 0),
+  F_B(HIS_STATS_s, 0, 1, 0),
   F_B(HIS_STATS_t, 0, 1, 0),
   F_B(HIS_STATS_T, 0, 1, 0),
   F_B(HIS_STATS_u, 0, 0, 0),
index 6b49b54f756649c952aa0d802e945da3c7496f9e..1543dd6fceca7ac5c1375b573cbc670616ec13ab 100644 (file)
@@ -102,6 +102,7 @@ static struct lexer_token {
   TOKEN(USERMODE),
   TOKEN(FAST),
   TOKEN(AUTOCONNECT),
+  TOKEN(SPOOFHOST),
 #undef TOKEN
   { "administrator", ADMIN },
   { "apass_opmode", TPRIV_APASS_OPMODE },
index f5872bc52d011223b98c9b440aff59862042cb8c..eca3302d08d6560d4fca0bcd906a5765a10dbc9e 100644 (file)
@@ -164,6 +164,7 @@ static struct LogDesc {
   S(SOCKET, -1, 0),
   S(IAUTH, -1, SNO_NETWORK),
   S(DEBUG, -1, SNO_DEBUG),
+  S(SETHOST, -1, SNO_OLDSNO),
 #undef S
   { LS_LAST_SYSTEM, 0, 0, -1, 0, -1, 0 }
 };
index 4ec19c56426c1c446c3d22c58df98453e89462ef..20fbc5ec24a6d771ba8f591a74fc4d2ba61e243a 100644 (file)
@@ -65,6 +65,7 @@
   extern struct ServerConf* serverConfList;
   extern struct s_map*      GlobalServiceMapList;
   extern struct qline*      GlobalQuarantineList;
+  extern struct sline*      GlobalSList;
 
   int yylex(void);
   /* Now all the globals we need :/... */
@@ -75,6 +76,7 @@
   struct DenyConf *dconf;
   struct ServerConf *sconf;
   struct s_map *smap;
+  struct sline *spoof; 
   struct Privs privs;
   struct Privs privs_dirty;
 
@@ -156,6 +158,7 @@ static void parse_error(char *pattern,...) {
 %token TIMEOUT
 %token FAST
 %token AUTOCONNECT
+%token SPOOFHOST
 /* and now a lot of privileges... */
 %token TPRIV_CHAN_LIMIT TPRIV_MODE_LCHAN TPRIV_DEOP_LCHAN TPRIV_WALK_LCHAN
 %token TPRIV_LOCAL_KILL TPRIV_REHASH TPRIV_RESTART TPRIV_DIE
@@ -182,7 +185,7 @@ blocks: blocks block | block;
 block: adminblock | generalblock | classblock | connectblock |
        uworldblock | operblock | portblock | jupeblock | clientblock |
        killblock | cruleblock | motdblock | featuresblock | quarantineblock |
-       pseudoblock | iauthblock | error ';';
+       pseudoblock | iauthblock | spoofblock | error ';';
 
 /* The timespec, sizespec and expr was ripped straight from
  * ircd-hybrid-7. */
@@ -1044,3 +1047,62 @@ iauthtimeout: TIMEOUT '=' timespec ';'
 {
   tping = $3;
 };
+
+spoofblock: SPOOFHOST QSTRING '{'
+{
+  spoof = MyCalloc(1, sizeof(struct sline));
+  spoof->spoofhost = $2;
+  spoof->passwd = NULL;
+  spoof->realhost = NULL;
+  spoof->username = NULL;
+}
+spoofitems '}' ';'
+{
+  struct irc_in_addr ip;
+  char bits;
+
+  if (spoof->username == NULL && spoof->realhost) {
+    parse_error("Username missing in spoofhost.");
+  } else if (spoof->realhost == NULL && spoof->username) {
+    parse_error("Realhost missing in spoofhost.");
+  }
+
+  if (spoof->realhost) {
+    if (!string_has_wildcards(spoof->realhost)) {
+      if (ipmask_parse(spoof->realhost, &ip, &bits) != 0) {
+        spoof->address = ip;
+        spoof->bits = bits;
+        spoof->flags = SLINE_FLAGS_IP;
+      } else {
+        Debug((DEBUG_DEBUG, "S-Line: \"%s\" appears not to be a valid IP address, might be wildcarded.", spoof->realhost));
+        spoof->flags = SLINE_FLAGS_HOSTNAME;
+      }
+    } else
+      spoof->flags = SLINE_FLAGS_HOSTNAME;
+  } else
+    spoof->flags = 0;
+
+
+  spoof->next = GlobalSList;
+  GlobalSList = spoof;
+
+  spoof = NULL;
+};
+
+spoofitems: spoofitem spoofitems | spoofitem;
+spoofitem: spoofpassword | spoofrealhost | spoofrealident;
+spoofpassword: PASS '=' QSTRING ';'
+{
+  MyFree(spoof->passwd);
+  spoof->passwd = $3;
+};
+spoofrealhost: HOST '=' QSTRING ';'
+{
+  MyFree(spoof->realhost);
+  spoof->realhost = $3;
+};
+spoofrealident: USERNAME '=' QSTRING ';'
+{
+  MyFree(spoof->username);
+  spoof->username = $3;
+};
index 673daa894d6c997f5c1a665f50143429fd8acfde..af47af561358490bb176dbe6ddbd199d32ac55c1 100644 (file)
@@ -180,8 +180,8 @@ struct FieldData {
 #define CONV_VARARGS   0x05000000      /**< convert a %v */
 #define CONV_CLIENT    0x06000000      /**< convert a struct Client */
 #define CONV_CHANNEL   0x07000000      /**< convert a struct Channel */
+#define CONV_REAL      0x08000000      /**< convert a struct Client and show realhost */
 
-#define CONV_RESERVED7 0x08000000      /**< reserved for future expansion */
 #define CONV_RESERVED6 0x09000000      /**< reserved for future expansion */
 #define CONV_RESERVED5 0x0a000000      /**< reserved for future expansion */
 #define CONV_RESERVED4 0x0b000000      /**< reserved for future expansion */
@@ -1778,6 +1778,11 @@ doprintf(struct Client *dest, struct BufData *buf_p, const char *fmt,
        fld_s.flags |= ARG_PTR | CONV_CLIENT;
        break;
 
+      case 'R': /* convert a client name... */
+        fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_ZERO | TYPE_MASK);
+        fld_s.flags |= ARG_PTR | CONV_REAL;
+        break;
+       
       case 'H': /* convert a channel name... */
        fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_ALT | FLAG_ZERO |
                         FLAG_COLON | TYPE_MASK);
@@ -2038,7 +2043,8 @@ doprintf(struct Client *dest, struct BufData *buf_p, const char *fmt,
 
       vdata->vd_chars = buf_s.buf_loc; /* return relevant data */
       vdata->vd_overflow = SNP_MAX(buf_s.buf_overflow, buf_s.overflow);
-    } else if ((fld_s.flags & CONV_MASK) == CONV_CLIENT) {
+    } else if (((fld_s.flags & CONV_MASK) == CONV_CLIENT) ||
+               ((fld_s.flags & CONV_MASK) == CONV_REAL)) {
       struct Client *cptr = (struct Client*) fld_s.value.v_ptr;
       const char *str1 = 0, *str2 = 0, *str3 = 0;
       int slen1 = 0, slen2 = 0, slen3 = 0, elen = 0, plen = 0;
@@ -2057,8 +2063,13 @@ doprintf(struct Client *dest, struct BufData *buf_p, const char *fmt,
        if (!IsServer(cptr) && !IsMe(cptr) && fld_s.flags & FLAG_ALT) {
          assert(0 != cli_user(cptr));
          assert(0 != *(cli_name(cptr)));
-         str2 = cli_user(cptr)->username;
-         str3 = cli_user(cptr)->host;
+          if ((fld_s.flags & CONV_MASK) == CONV_REAL) {
+            str2 = cli_user(cptr)->realusername;
+            str3 = cli_user(cptr)->realhost;
+          } else {
+            str2 = cli_user(cptr)->username;
+            str3 = cli_user(cptr)->host;
+          }
        } else
          fld_s.flags &= ~FLAG_ALT;
       }
index 15cc50911d1b7b89f9c0b9f0be036bdd1ba38c14..580a5ca6138d81959eb4149cadb73abe1fb0796a 100644 (file)
@@ -151,7 +151,7 @@ int m_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
   {
     send_reply(sptr, ERR_NOOPERHOST);
     sendto_opmask_butone(0, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s)",
-                        parv[0], cli_user(sptr)->username, cli_sockhost(sptr));
+                        parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr));
     return 0;
   }
   assert(0 != (aconf->status & CONF_OPERATOR));
@@ -163,7 +163,7 @@ int m_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
     if (ACR_OK != attach_conf(sptr, aconf)) {
       send_reply(sptr, ERR_NOOPERHOST);
       sendto_opmask_butone(0, SNO_OLDREALOP, "Failed OPER attempt by %s "
-                          "(%s@%s)", parv[0], cli_user(sptr)->username,
+                          "(%s@%s)", parv[0], cli_user(sptr)->realusername,
                           cli_sockhost(sptr));
       return 0;
     }
@@ -187,16 +187,16 @@ int m_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
     send_reply(sptr, RPL_YOUREOPER);
 
     sendto_opmask_butone(0, SNO_OLDSNO, "%s (%s@%s) is now operator (%c)",
-                        parv[0], cli_user(sptr)->username, cli_sockhost(sptr),
+                        parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr),
                         IsOper(sptr) ? 'O' : 'o');
 
-    log_write(LS_OPER, L_INFO, 0, "OPER (%s) by (%#C)", name, sptr);
+    log_write(LS_OPER, L_INFO, 0, "OPER (%s) by (%#R)", name, sptr);
   }
   else
   {
     send_reply(sptr, ERR_PASSWDMISMATCH);
     sendto_opmask_butone(0, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s)",
-                        parv[0], cli_user(sptr)->username, cli_sockhost(sptr));
+                        parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr));
   }
   return 0;
 }
diff --git a/ircd/m_sethost.c b/ircd/m_sethost.c
new file mode 100644 (file)
index 0000000..9d05309
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_sethost.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: asuka-sethost.patch,v 1.27 2005/02/13 17:28:11 froo Exp $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "ircd_features.h"
+#include "msgq.h"
+#include "numeric.h"
+#include "s_user.h"
+#include "s_debug.h"
+#include "struct.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+/*
+ * 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, 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, 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, parv[1], parv[2]))
+        FlagClr(&setflags, FLAG_SETHOST);
+    }
+  }  
+
+  send_umode_out(cptr, sptr, &setflags, 0);
+}
index 9fe392c1813c68799b28b09fb59d6f05ef6e821d..b6790809b8fee35c768ade8e0ca5246571ead4de 100644 (file)
@@ -104,7 +104,7 @@ static void userhost_formatter(struct Client* cptr, struct Client *sptr, struct
               * of +x.  If an oper wants the real host, he should go to
               * /whois to get it.
               */
-             HasHiddenHost(cptr) && (sptr != cptr) ?
+             !IsAnOper(sptr) ?
              cli_user(cptr)->host : cli_user(cptr)->realhost);
 }
 
index 062fe687ea3a6cd01899734db0befce4e9db32b6..dd0481027dea8faeefbf5295741fc1c55908a846 100644 (file)
@@ -95,6 +95,7 @@
 
 static void userip_formatter(struct Client* cptr, struct Client *sptr, struct MsgBuf* mb)
 {
+  /* !!FIXME!! */
   assert(IsUser(cptr));
   msgq_append(0, mb, "%s%s=%c%s@%s", cli_name(cptr),
              SeeOper(sptr,cptr) ? "*" : "",
@@ -105,7 +106,7 @@ static void userip_formatter(struct Client* cptr, struct Client *sptr, struct Ms
               * of +x.  If an oper wants the real IP, he should go to
               * /whois to get it.
               */
-             HasHiddenHost(cptr) && (sptr != cptr) ?
+             (HasHiddenHost(cptr) || HasSetHost(cptr)) && !IsAnOper(sptr) ?
              feature_str(FEAT_HIDDEN_IP) :
              ircd_ntoa(&cli_ip(cptr)));
 }
index b0de69466905def5fbfc29f442734e2484dbced9..ad6f11e2dbee49a4cd08953ce57028391754e405 100644 (file)
@@ -404,13 +404,14 @@ int m_who(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
               && ((!(matchsel & WHO_FIELD_HOS))
               || matchexec(cli_user(acptr)->host, mymask, minlen))
               && ((!(matchsel & WHO_FIELD_HOS))
+              || !HasSetHost(acptr)
              || !HasHiddenHost(acptr)
              || !IsAnOper(sptr)
               || matchexec(cli_user(acptr)->realhost, mymask, minlen))
               && ((!(matchsel & WHO_FIELD_REN))
               || matchexec(cli_info(acptr), mymask, minlen))
               && ((!(matchsel & WHO_FIELD_NIP))
-             || (HasHiddenHost(acptr) && !IsAnOper(sptr))
+              || ((HasHiddenHost(acptr) || HasSetHost(acptr)) && !IsAnOper(sptr))
               || !ipmask_check(&cli_ip(acptr), &imask, ibits))
               && ((!(matchsel & WHO_FIELD_ACC))
               || matchexec(cli_user(acptr)->account, mymask, minlen)))
@@ -442,13 +443,14 @@ int m_who(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
             && ((!(matchsel & WHO_FIELD_HOS))
             || matchexec(cli_user(acptr)->host, mymask, minlen))
             && ((!(matchsel & WHO_FIELD_HOS))
+            || !HasSetHost(acptr)
            || !HasHiddenHost(acptr)
            || !IsAnOper(sptr)
             || matchexec(cli_user(acptr)->realhost, mymask, minlen))
             && ((!(matchsel & WHO_FIELD_REN))
             || matchexec(cli_info(acptr), mymask, minlen))
             && ((!(matchsel & WHO_FIELD_NIP))
-           || (HasHiddenHost(acptr) && !IsAnOper(sptr))
+            || ((HasHiddenHost(acptr) || HasSetHost(acptr)) && !IsAnOper(sptr))
             || !ipmask_check(&cli_ip(acptr), &imask, ibits))
             && ((!(matchsel & WHO_FIELD_ACC))
             || matchexec(cli_user(acptr)->account, mymask, minlen)))
index fec4b53074d7e78829c013e2bbaac3467153ec72..63d25166d81bff1e5779115236b01d6a3d1aa225 100644 (file)
@@ -211,8 +211,8 @@ static void do_whois(struct Client* sptr, struct Client *acptr, int parc)
     if (IsAccount(acptr))
       send_reply(sptr, RPL_WHOISACCOUNT, name, user->account);
 
-    if (HasHiddenHost(acptr) && (IsAnOper(sptr) || acptr == sptr))
-      send_reply(sptr, RPL_WHOISACTUALLY, name, user->username,
+    if ((HasHiddenHost(acptr) || HasSetHost(acptr)) && (IsAnOper(sptr) || acptr == sptr))
+      send_reply(sptr, RPL_WHOISACTUALLY, name, user->realusername,
                  user->realhost, ircd_ntoa(&cli_ip(acptr)));
 
     /* Hint: if your looking to add more flags to a user, eg +h, here's
index 9cdb6f2495b98b98a64229a81cf459638d91029b..fe0488e3a3fb18db624bc7ad70797ddcf50f2ff5 100644 (file)
@@ -617,6 +617,13 @@ struct Message msgtab[] = {
     /* UNREG, CLIENT, SERVER, OPER, SERVICE */
     { m_ignore, m_not_oper, ms_asll, mo_asll, m_ignore }
    },
+  {
+    MSG_SETHOST,
+    TOK_SETHOST,
+    0, MAXPARA, MFLG_SLOW, 0, NULL,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_sethost, m_ignore, m_sethost, m_ignore }
+  },
 #if WE_HAVE_A_REAL_CAPABILITY_NOW
   {
     MSG_CAP,
index 170b2c2578e2af3eba9067cbe830296459e82f27..75f56ce028e6826d2bf9c0abaaabcc977ead246b 100644 (file)
@@ -48,6 +48,7 @@
 #include "querycmds.h"
 #include "res.h"
 #include "s_bsd.h"
+#include "s_conf.h"
 #include "s_debug.h"
 #include "s_misc.h"
 #include "send.h"
index 5fb596bd3995ecaf464cfd00e0c07f42c22ced6d..fb96296239004e5085ebe4eccbc4ffe1891c4831 100644 (file)
@@ -74,6 +74,8 @@ int              GlobalConfCount;
 struct s_map     *GlobalServiceMapList;
 /** Global list of channel quarantines. */
 struct qline     *GlobalQuarantineList;
+/** Global list of spoofhosts. */
+struct sline    *GlobalSList = 0;
 
 /** Current line number in scanner input. */
 int lineno;
@@ -942,6 +944,7 @@ int rehash(struct Client *cptr, int sig)
   clearNickJupes();
 
   clear_quarantines();
+  clear_slines();
 
   if (sig != 2)
     restart_resolver();
@@ -1192,3 +1195,81 @@ int conf_check_server(struct Client *cptr)
   return 0;
 }
 
+void clear_slines(void)
+{
+  struct sline *sline;
+  while ((sline = GlobalSList)) {
+    GlobalSList = sline->next;
+    MyFree(sline->spoofhost);
+    if (!EmptyString(sline->passwd))
+      MyFree(sline->passwd);
+    if (!EmptyString(sline->realhost))
+      MyFree(sline->realhost);
+    if (!EmptyString(sline->username))
+      MyFree(sline->username);
+    MyFree(sline);
+  }
+}
+
+/*
+ * conf_check_slines()
+ *
+ * Check S lines for the specified client, passed in cptr struct.
+ * If the client's IP is S-lined, process the substitution here.
+ *
+ * Precondition
+ *  cptr != NULL
+ *
+ * Returns
+ *  0 = No S-line found
+ *  1 = S-line found and substitution done.
+ *
+ * -mbuna 9/2001
+ * -froo 1/2003
+ *
+ */
+
+int
+conf_check_slines(struct Client *cptr)
+{
+  struct sline *sconf;
+  char *hostonly;
+
+  for (sconf = GlobalSList; sconf; sconf = sconf->next) {
+    if (sconf->flags == SLINE_FLAGS_IP) {
+      if (!ipmask_check(&(cli_ip(cptr)), &(sconf->address), sconf->bits))
+        continue;
+    } else if (sconf->flags == SLINE_FLAGS_HOSTNAME) {
+        if ((match(sconf->realhost, cli_sockhost(cptr)) != 0) &&
+           (match(sconf->realhost, cli_sock_ip(cptr)) != 0))   /* wildcarded IP address */
+          continue;
+    } else {
+        continue;
+    }
+
+    if (match(sconf->username, cli_user(cptr)->username) == 0) {
+     /* Ignore user part if u@h. */
+     if ((hostonly = strchr(sconf->spoofhost, '@')))
+        hostonly++;
+      else
+        hostonly = sconf->spoofhost;
+
+      if(!*hostonly)
+        continue;
+
+      ircd_strncpy(cli_user(cptr)->host, hostonly, HOSTLEN);
+      log_write(LS_USER, L_INFO, LOG_NOSNOTICE, "S-Line (%s@%s) by (%#R)",
+          cli_user(cptr)->username, hostonly, cptr);
+      return 1;
+    }
+  }
+  return 0;
+}
+
+void free_spoofhost(struct sline *spoof) {
+       MyFree(spoof->spoofhost);
+       MyFree(spoof->passwd);
+       MyFree(spoof->realhost);
+       MyFree(spoof->username);
+       MyFree(spoof);
+}
index d5b8458147b341a5232b34f6b525c89141f5d28c..16503e4525362d9dc89206ee494b773b09f2b54c 100644 (file)
@@ -640,7 +640,7 @@ static Numeric replyTable[] = {
 /* 303 */
   { RPL_ISON, ":", "303" },
 /* 304 */
-  { 0 },
+  { RPL_TEXT, "%s", "304" },
 /* 305 */
   { RPL_UNAWAY, ":You are no longer marked as being away", "305" },
 /* 306 */
@@ -828,9 +828,9 @@ static Numeric replyTable[] = {
 /* 397 */
   { 0 },
 /* 398 */
-  { 0 },
+  { RPL_STATSSLINE, "%d %s %s %s %s", "398" },
 /* 399 */
-  { 0 },
+  { RPL_USINGSLINE, ":Using S-line privilege", "399" },
 /* 400 */
   { 0 },
 /* 401 */
@@ -1092,9 +1092,9 @@ static Numeric replyTable[] = {
 /* 529 */
   { 0 },
 /* 530 */
-  { 0 },
+  { ERR_BADHOSTMASK, "%s :Invalid username/hostmask", "530" },
 /* 531 */
-  { 0 },
+  { ERR_HOSTUNAVAIL, "%s :sethost not found", "531" },
 /* 532 */
   { 0 },
 /* 533 */
index 71274a11c43694cd400c1b80430fbf87c473abb6..2b3f46ac37c3ce8998e168d48271ddc48bce5b92 100644 (file)
@@ -247,7 +247,7 @@ int server_estab(struct Client *cptr, struct ConfItem *aconf)
       sendcmdto_one(cli_user(acptr)->server, CMD_NICK, cptr,
                    "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
                    cli_name(acptr), cli_hopcount(acptr) + 1, cli_lastnick(acptr),
-                   cli_user(acptr)->username, cli_user(acptr)->realhost,
+                   cli_user(acptr)->realusername, cli_user(acptr)->realhost,
                    *s ? "+" : "", s, *s ? " " : "",
                    iptobase64(xxx_buf, &cli_ip(acptr), sizeof(xxx_buf), IsIPv6(cptr)),
                    NumNick(acptr), cli_info(acptr));
index 85da5e24ef9cd3d33ca323e99172433544fe1704..0c04d59a1a9e4fb1a39c579229c32d9e3077d976 100644 (file)
@@ -397,6 +397,44 @@ stats_quarantine(struct Client* to, const struct StatDesc* sd, char* param)
   }
 }
 
+static void
+stats_sline(struct Client* to, const struct StatDesc* sd, char* param)
+{
+  int y = 1, i = 1;
+  struct sline *sline;
+
+  if (IsAnOper(to))
+    send_reply(to, SND_EXPLICIT | RPL_TEXT, "# Type Spoofhost Realhost Ident");
+  else
+    send_reply(to, SND_EXPLICIT | RPL_TEXT, "# Type Spoofhost");
+
+  for (sline = GlobalSList; sline; sline = sline->next) {
+    if (param && match(param, sline->spoofhost)) { /* narrow search */
+      if (IsAnOper(to))
+          y++;
+      else
+        if (!EmptyString(sline->passwd))
+          y++;
+      continue;
+    }
+
+    if (IsAnOper(to)) {
+      send_reply(to, RPL_STATSSLINE, (param) ? y : i, 
+         (EmptyString(sline->passwd)) ? "oper" : "user",
+         sline->spoofhost, 
+         (EmptyString(sline->realhost)) ? "" : sline->realhost,
+         (EmptyString(sline->username)) ? "" : sline->username);
+      i++;
+    } else {
+      if (!EmptyString(sline->passwd)) {
+        send_reply(to, RPL_STATSSLINE, (param) ? y : i, "user", sline->spoofhost,
+           "", "", "");
+        i++;
+      }
+    }
+  }
+}
+
 /** List service pseudo-command mappings.
  * @param[in] to Client requesting statistics.
  * @param[in] sd Stats descriptor for request (ignored).
@@ -586,6 +624,9 @@ struct StatDesc statsinfo[] = {
     send_usage, 0,
     "System resource usage (Debug only)." },
 #endif
+  { 's', "spoofhosts", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_s,
+    stats_sline, 0,
+    "Spoofed hosts information." },
   { 'T', "motds", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_T,
     motd_report, 0,
     "Configured Message Of The Day files." },
index eae4b4952e7618233d43658640331d4613ecdc91..f35634a1ef8187d66dea7722c6ed6d6fd97fc1a2 100644 (file)
@@ -73,6 +73,9 @@
 #include <string.h>
 #include <sys/stat.h>
 
+static char *IsVhost(char *hostmask, int oper);
+static char *IsVhostPass(char *hostmask);
+
 /** Count of allocated User structures. */
 static int userCount = 0;
 
@@ -458,7 +461,11 @@ int register_user(struct Client *cptr, struct Client *sptr,
 
     clean_user_id(user->username,
                   HasFlag(sptr, FLAG_GOTID) ? cli_username(sptr) : username,
-                  HasFlag(sptr, FLAG_DOID) && !HasFlag(sptr, FLAG_GOTID));
+                  HasFlag(sptr, FLAG_DOID) && !HasFlag(sptr, FLAG_GOTID)
+                  && !(HasSetHost(sptr))); /* No tilde for S-lined users. */
+
+    /* Have to set up "realusername" before doing the gline check below */
+    ircd_strncpy(user->realusername, user->username, USERLEN);
 
     if ((user->username[0] == '\0')
         || ((user->username[0] == '~') && (user->username[1] == '\000')))
@@ -564,6 +571,13 @@ int register_user(struct Client *cptr, struct Client *sptr,
     if (MyConnect(sptr) && feature_bool(FEAT_AUTOINVISIBLE))
       SetInvisible(sptr);
     
+    if(MyConnect(sptr) && feature_bool(FEAT_SETHOST_AUTO)) {
+      if (conf_check_slines(sptr)) {
+        send_reply(sptr, RPL_USINGSLINE);
+        SetSetHost(sptr);
+      }
+    }
+
     SetUser(sptr);
     cli_handler(sptr) = CLIENT_HANDLER;
     SetLocalNumNick(sptr);
@@ -661,6 +675,14 @@ int register_user(struct Client *cptr, struct Client *sptr,
                     sptr, cli_name(&me));
       return exit_client(cptr, sptr, &me,"Too many connections from your host -- throttled");
     }
+
+    if(MyConnect(sptr) && feature_bool(FEAT_SETHOST_AUTO)) {
+      if (conf_check_slines(sptr)) {
+        send_reply(sptr, RPL_USINGSLINE);
+        SetSetHost(sptr);
+      }
+    }
+
     SetUser(sptr);
   }
 
@@ -675,7 +697,7 @@ int register_user(struct Client *cptr, struct Client *sptr,
                              FLAG_IPV6, FLAG_LAST_FLAG,
                              "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
                              nick, cli_hopcount(sptr) + 1, cli_lastnick(sptr),
-                             user->username, user->realhost,
+                             user->realusername, user->realhost,
                              *tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
                              iptobase64(ip_base64, &cli_ip(sptr), sizeof(ip_base64), 1),
                              NumNick(sptr), cli_info(sptr));
@@ -684,7 +706,7 @@ int register_user(struct Client *cptr, struct Client *sptr,
                              FLAG_LAST_FLAG, FLAG_IPV6,
                              "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
                              nick, cli_hopcount(sptr) + 1, cli_lastnick(sptr),
-                             user->username, user->realhost,
+                             user->realusername, user->realhost,
                              *tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
                              iptobase64(ip_base64, &cli_ip(sptr), sizeof(ip_base64), 0),
                              NumNick(sptr), cli_info(sptr));
@@ -718,7 +740,8 @@ static const struct UserMode {
   { FLAG_ACCOUNTONLY, 'R' },
   { FLAG_XTRAOP,      'X' },
   { FLAG_NOCHAN,      'n' },
-  { FLAG_NOIDLE,      'I' }
+  { FLAG_NOIDLE,      'I' },
+  { FLAG_SETHOST,     'h' }
 };
 
 /** Length of #userModeList. */
@@ -745,6 +768,8 @@ int set_nick_name(struct Client* cptr, struct Client* sptr,
   if (IsServer(sptr)) {
     int   i;
     const char* account = 0;
+    char* hostmask = 0;
+    char* host = 0;
     const char* p;
 
     /*
@@ -766,6 +791,8 @@ int set_nick_name(struct Client* cptr, struct Client* sptr,
             SetFlag(new_client, userModeList[i].flag);
            if (userModeList[i].flag == FLAG_ACCOUNT)
              account = parv[7];
+            if (userModeList[i].flag == FLAG_SETHOST)
+              hostmask = parv[parc - 4];
             break;
           }
         }
@@ -789,6 +816,7 @@ int set_nick_name(struct Client* cptr, struct Client* sptr,
 
     cli_serv(sptr)->ghost = 0;        /* :server NICK means end of net.burst */
     ircd_strncpy(cli_username(new_client), parv[4], USERLEN);
+    ircd_strncpy(cli_user(new_client)->realusername, parv[4], USERLEN);
     ircd_strncpy(cli_user(new_client)->host, parv[5], HOSTLEN);
     ircd_strncpy(cli_user(new_client)->realhost, parv[5], HOSTLEN);
     ircd_strncpy(cli_info(new_client), parv[parc - 1], REALLEN);
@@ -806,8 +834,15 @@ int set_nick_name(struct Client* cptr, struct Client* sptr,
     if (HasHiddenHost(new_client))
       ircd_snprintf(0, cli_user(new_client)->host, HOSTLEN, "%s.%s",
         account, feature_str(FEAT_HIDDEN_HOST));
+    if (HasSetHost(new_client)) {
+      if ((host = strrchr(hostmask, '@')) != NULL) {
+        *host++ = '\0';
+        ircd_strncpy(cli_username(new_client), hostmask, USERLEN);
+        ircd_strncpy(cli_user(new_client)->host, host, HOSTLEN);
+      }
+    }
 
-    return register_user(cptr, new_client, cli_name(new_client), parv[4]);
+    return register_user(cptr, new_client, cli_name(new_client), cli_username(new_client));
   }
   else if ((cli_name(sptr))[0]) {
     /*
@@ -1099,7 +1134,7 @@ void send_umode_out(struct Client *cptr, struct Client *sptr,
   {
     if ((acptr = LocalClientArray[i]) && IsServer(acptr) &&
         (acptr != cptr) && (acptr != sptr) && *umodeBuf)
-      sendcmdto_one(sptr, CMD_MODE, acptr, "%s :%s", cli_name(sptr), umodeBuf);
+      sendcmdto_one(sptr, CMD_MODE, acptr, "%s %s", cli_name(sptr), umodeBuf);
   }
   if (cptr && MyUser(cptr))
     send_umode(cptr, sptr, old, ALL_UMODES);
@@ -1155,6 +1190,11 @@ hide_hostmask(struct Client *cptr, unsigned int flag)
     /* Local users cannot set +x unless FEAT_HOST_HIDING is true. */
     if (MyConnect(cptr) && !feature_bool(FEAT_HOST_HIDING))
       return 0;
+    /* If the user is +h, we don't hide the hostmask.  Set the flag to keep sync though */
+    if (HasSetHost(cptr)) {
+      SetFlag(cptr, flag);
+       return 0;
+    }
     break;
   case FLAG_ACCOUNT:
     /* Invalidate all bans against the user so we check them again */
@@ -1201,6 +1241,190 @@ hide_hostmask(struct Client *cptr, unsigned int flag)
   return 0;
 }
 
+/*
+ * set_hostmask() - derived from hide_hostmask()
+ *
+ */
+int set_hostmask(struct Client *cptr, char *hostmask, char *password)
+{
+  int restore = 0;
+  int freeform = 0;
+  char *host, *new_vhost, *vhost_pass;
+  char hiddenhost[USERLEN + HOSTLEN + 2];
+  struct Membership *chan;
+
+  Debug((DEBUG_INFO, "set_hostmask() %C, %s, %s", cptr, hostmask, password));
+
+  /* sethost enabled? */
+  if (MyConnect(cptr) && !feature_bool(FEAT_SETHOST)) {
+    send_reply(cptr, ERR_DISABLED, "SETHOST");
+    return 0;
+  }
+
+  /* sethost enabled for users? */
+  if (MyConnect(cptr) && !IsAnOper(cptr) && !feature_bool(FEAT_SETHOST_USER)) {
+    send_reply(cptr, ERR_NOPRIVILEGES);
+    return 0;
+  }
+  /* MODE_DEL: restore original hostmask */
+  if (EmptyString(hostmask)) {
+    /* is already sethost'ed? */
+    if (IsSetHost(cptr)) {
+      restore = 1;
+      sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
+      /* If they are +rx, we need to return to their +x host, not their "real" host */
+      if (HasHiddenHost(cptr))
+        ircd_snprintf(0, cli_user(cptr)->host, HOSTLEN, "%s.%s",
+          cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
+      else
+        strncpy(cli_user(cptr)->host, cli_user(cptr)->realhost, HOSTLEN);
+      strncpy(cli_user(cptr)->username, cli_user(cptr)->realusername, USERLEN);
+      /* log it */
+      if (MyConnect(cptr))
+        log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE,
+            "SETHOST (%s@%s) by (%#R): restoring real hostmask",
+            cli_user(cptr)->username, cli_user(cptr)->host, cptr);
+    } else
+      return 0;
+  /* MODE_ADD: set a new hostmask */
+  } else {
+    /* chop up ident and host.cc */
+    if ((host = strrchr(hostmask, '@'))) /* oper can specifiy ident@host.cc */
+      *host++ = '\0';
+    else /* user can only specifiy host.cc [password] */
+      host = hostmask;
+    /*
+     * Oper sethost
+     */
+    if (MyConnect(cptr)) {
+      if (IsAnOper(cptr)) {
+        if ((new_vhost = IsVhost(host, 1)) == NULL) {
+          if (!feature_bool(FEAT_SETHOST_FREEFORM)) {
+            send_reply(cptr, ERR_HOSTUNAVAIL, hostmask);
+            log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE,
+                "SETHOST (%s@%s) by (%#R): no such s-line",
+                (host != hostmask) ? hostmask : cli_user(cptr)->username, host, cptr);
+            return 0;
+          } else /* freeform active, log and go */
+            freeform = 1;
+        }
+        sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
+        /* set the new ident and host */
+        if (host != hostmask) /* oper only specified host.cc */
+          strncpy(cli_user(cptr)->username, hostmask, USERLEN);
+        strncpy(cli_user(cptr)->host, host, HOSTLEN);
+        /* log it */
+        log_write(LS_SETHOST, (freeform) ? L_NOTICE : L_INFO,
+            (freeform) ? 0 : LOG_NOSNOTICE, "SETHOST (%s@%s) by (%#R)%s",
+            cli_user(cptr)->username, cli_user(cptr)->host, cptr,
+            (freeform) ? ": using freeform" : "");
+      /*
+       * plain user sethost, handled here
+       */
+      } else {
+        /* empty password? */
+        if (EmptyString(password)) {
+          send_reply(cptr, ERR_NEEDMOREPARAMS, "MODE");
+          return 0;
+        }
+        /* no such s-line */
+        if ((new_vhost = IsVhost(host, 0)) == NULL) {
+          send_reply(cptr, ERR_HOSTUNAVAIL, hostmask);
+          log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE, "SETHOST (%s@%s %s) by (%#R): no such s-line",
+              cli_user(cptr)->username, host, password, cptr);
+          return 0;
+        }
+        /* no password */
+        if ((vhost_pass = IsVhostPass(new_vhost)) == NULL) {
+          send_reply(cptr, ERR_PASSWDMISMATCH);
+          log_write(LS_SETHOST, L_INFO, 0, "SETHOST (%s@%s %s) by (%#R): trying to use an oper s-line",
+              cli_user(cptr)->username, host, password, cptr);
+          return 0;
+        }
+        /* incorrect password */
+        if (strCasediff(vhost_pass, password)) {
+          send_reply(cptr, ERR_PASSWDMISMATCH);
+          log_write(LS_SETHOST, L_NOTICE, 0, "SETHOST (%s@%s %s) by (%#R): incorrect password",
+              cli_user(cptr)->username, host, password, cptr);
+          return 0;
+        }
+        sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
+        /* set the new host */
+        strncpy(cli_user(cptr)->host, new_vhost, HOSTLEN);
+        /* log it */
+        log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE, "SETHOST (%s@%s) by (%#R)",
+            cli_user(cptr)->username, cli_user(cptr)->host, cptr);
+      }
+    } else { /* remote user */
+        sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
+        if (host != hostmask) /* oper only specified host.cc */
+          strncpy(cli_user(cptr)->username, hostmask, USERLEN);
+        strncpy(cli_user(cptr)->host, host, HOSTLEN);
+    }
+  }
+
+  if (restore)
+    ClearSetHost(cptr);
+  else
+    SetSetHost(cptr);
+
+  if (MyConnect(cptr)) {
+    ircd_snprintf(0, hiddenhost, HOSTLEN + USERLEN + 2, "%s@%s",
+      cli_user(cptr)->username, cli_user(cptr)->host);
+    send_reply(cptr, RPL_HOSTHIDDEN, hiddenhost);
+  }
+
+#if 0
+  /* Code copied from hide_hostmask().  This is the old (pre-delayedjoin) 
+   * version.  Switch this in if you're not using the delayed join patch. */
+  /*
+   * Go through all channels the client was on, rejoin him
+   * and set the modes, if any
+   */
+  for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) {
+    if (IsZombie(chan))
+      continue;
+    sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr,
+      "%H", chan->channel);
+    if (IsChanOp(chan) && HasVoice(chan)) {
+      sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr,
+        "%H +ov %C %C", chan->channel, cptr, cptr);
+    } else if (IsChanOp(chan) || HasVoice(chan)) {
+      sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr,
+        "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr);
+    }
+  }
+#endif
+
+  /*
+   * Go through all channels the client was on, rejoin him
+   * and set the modes, if any
+   */
+  for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) {
+    if (IsZombie(chan))
+      continue;
+    /* If this channel has delayed joins and the user has no modes, just set
+     * the delayed join flag rather than showing the join, even if the user
+     * was visible before */
+    if (!IsChanOp(chan) && !HasVoice(chan)
+        && (chan->channel->mode.mode & MODE_DELJOINS)) {
+      SetDelayedJoin(chan);
+    } else {
+      sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr, 0,
+        "%H", chan->channel);
+    }
+    if (IsChanOp(chan) && HasVoice(chan)) {
+      sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr, 0,
+        "%H +ov %C %C", chan->channel, cptr, cptr);
+    } else if (IsChanOp(chan) || HasVoice(chan)) {
+      sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr, 0,
+        "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr);
+    }
+  }
+  return 1;
+}
+
 /** Set a user's mode.  This function checks that \a cptr is trying to
  * set his own mode, prevents local users from setting inappropriate
  * modes through this function, and applies any other side effects of
@@ -1223,9 +1447,12 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv
   unsigned int tmpmask = 0;
   int snomask_given = 0;
   char buf[BUFSIZE];
+  char *hostmask, *password;
   int prop = 0;
   int do_host_hiding = 0;
+  int do_set_host = 0;
 
+  hostmask = password = NULL;
   what = MODE_ADD;
 
   if (parc < 2)
@@ -1256,7 +1483,8 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv
     for (i = 0; i < USERMODELIST_SIZE; i++)
     {
       if (HasFlag(sptr, userModeList[i].flag) &&
-          userModeList[i].flag != FLAG_ACCOUNT)
+          ((userModeList[i].flag != FLAG_ACCOUNT) &&
+          (userModeList[i].flag != FLAG_SETHOST)))
         *m++ = userModeList[i].c;
     }
     *m = '\0';
@@ -1381,8 +1609,32 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv
         break;
       case 'x':
         if (what == MODE_ADD)
-         do_host_hiding = 1;
-       break;
+          do_host_hiding = 1;
+         break;
+      case 'h':
+         if (what == MODE_ADD) {
+           if (*(p + 1) && is_hostmask(*(p + 1))) {
+             do_set_host = 1;
+             hostmask = *++p;
+             /* DON'T step p onto the trailing NULL in the parameter array! - splidge */
+             if (*(p+1))
+               password = *++p;
+             else
+               password = NULL;
+           } else {
+             if (!*(p+1))
+               send_reply(sptr, ERR_NEEDMOREPARAMS, "SETHOST");
+             else {
+               send_reply(sptr, ERR_BADHOSTMASK, *(p+1));
+               p++; /* Swallow the arg anyway */
+             }
+           }
+         } else { /* MODE_DEL */
+           do_set_host = 1;
+           hostmask = NULL;
+           password = NULL;
+         }
+         break;
       case 'R':
         if (what == MODE_ADD)
           SetAccountOnly(sptr);
@@ -1475,6 +1727,12 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv
     ++UserStats.inv_clients;
   if (!FlagHas(&setflags, FLAG_HIDDENHOST) && do_host_hiding)
     hide_hostmask(sptr, FLAG_HIDDENHOST);
+  if (do_set_host) {
+    /* We clear the flag in the old mask, so that the +h will be sent */
+    /* Only do this if we're SETTING +h and it succeeded */
+    if (set_hostmask(sptr, hostmask, password) && hostmask)
+      FlagClr(&setflags, FLAG_SETHOST);
+  }
   send_umode_out(cptr, sptr, &setflags, prop);
 
   return 0;
@@ -1520,10 +1778,15 @@ char *umode_str(struct Client *cptr)
       while ((*m++ = *t++))
        ; /* Empty loop */
     }
+    m--; /* Step back over the '\0' */
   }
 
-  *m = '\0';
-
+  if (IsSetHost(cptr)) {
+    *m++ = ' ';
+    ircd_snprintf(0, m, USERLEN + HOSTLEN + 2, "%s@%s", cli_user(cptr)->username,
+         cli_user(cptr)->host);
+  } else
+    *m = '\0';
   return umodeBuf;                /* Note: static buffer, gets
                                    overwritten by send_umode() */
 }
@@ -1540,6 +1803,7 @@ void send_umode(struct Client *cptr, struct Client *sptr, struct Flags *old,
 {
   int i;
   int flag;
+  int needhost = 0;
   char *m;
   int what = MODE_NULL;
 
@@ -1569,6 +1833,16 @@ void send_umode(struct Client *cptr, struct Client *sptr, struct Flags *old,
         continue;
       break;      
     }
+    /* Special case for SETHOST.. */
+    if (flag == FLAG_SETHOST) {
+      /* Don't send to users */
+      if (cptr && MyUser(cptr))
+       continue;
+      
+      /* If we're setting +h, add the parameter later */
+      if (!FlagHas(old, flag)) 
+       needhost++;    
+    }
     if (FlagHas(old, flag))
     {
       if (what == MODE_DEL)
@@ -1592,9 +1866,14 @@ void send_umode(struct Client *cptr, struct Client *sptr, struct Flags *old,
       }
     }
   }
-  *m = '\0';
+  if (needhost) {
+    *m++ = ' ';
+    ircd_snprintf(0, m, USERLEN + HOSTLEN + 1, "%s@%s", cli_user(sptr)->username,
+         cli_user(sptr)->host);
+  } else
+    *m = '\0';
   if (*umodeBuf && cptr)
-    sendcmdto_one(sptr, CMD_MODE, cptr, "%s :%s", cli_name(sptr), umodeBuf);
+    sendcmdto_one(sptr, CMD_MODE, cptr, "%s %s", cli_name(sptr), umodeBuf);
 }
 
 /**
@@ -1617,6 +1896,110 @@ int is_snomask(char *word)
   return 0;
 }
 
+ /*
+  * Check to see if it resembles a valid hostmask.
+  */
+int is_hostmask(char *word)
+{
+  int i = 0;
+  char *host;
+
+  Debug((DEBUG_INFO, "is_hostmask() %s", word));
+
+  if (strlen(word) > (HOSTLEN + USERLEN + 1) || strlen(word) <= 0)
+    return 0;
+
+  /* if a host is specified, make sure it's valid */
+  host = strrchr(word, '@');
+  if (host) {
+     if (strlen(++host) < 1)
+       return 0;
+     if (strlen(host) > HOSTLEN)
+       return 0;
+  }
+
+  if (word) {
+    if ('@' == *word)  /* no leading @'s */
+        return 0;
+
+    if ('#' == *word) {        /* numeric index given? */
+      for (word++; *word; word++) {
+        if (!IsDigit(*word))
+          return 0;
+      }
+      return 1;
+    }
+
+    /* normal hostmask, account for at most one '@' */
+    for (; *word; word++) {
+      if ('@' == *word) {
+        i++;
+        continue;
+      }
+      if (!IsHostChar(*word))
+        return 0;
+    }
+    return (1 < i) ? 0 : 1; /* no more than on '@' */
+  }
+  return 0;
+}
+
+ /*
+  * IsVhost() - Check if given host is a valid spoofhost
+  * (ie: configured thru a S:line)
+  */
+static char *IsVhost(char *hostmask, int oper)
+{
+  unsigned int i = 0, y = 0;
+  struct sline *sconf;
+
+  Debug((DEBUG_INFO, "IsVhost() %s", hostmask));
+
+  if (EmptyString(hostmask))
+    return NULL;
+
+  /* spoofhost specified as index, ie: #27 */
+  if ('#' == hostmask[0]) {
+    y = atoi(hostmask + 1);
+    for (i = 0, sconf = GlobalSList; sconf; sconf = sconf->next) {
+      if (!oper && EmptyString(sconf->passwd))
+        continue;
+      if (y == ++i)
+        return sconf->spoofhost;
+    }
+    return NULL;
+  }
+
+  /* spoofhost specified as host, ie: host.cc */
+  for (sconf = GlobalSList; sconf; sconf = sconf->next)
+    if (strCasediff(hostmask, sconf->spoofhost) == 0)
+      return sconf->spoofhost;
+
+  return NULL;
+}
+
+ /*
+  * IsVhostPass() - Check if given spoofhost has a password
+  * associated with it, and if, return the password (cleartext)
+  */
+static char *IsVhostPass(char *hostmask)
+{
+  struct sline *sconf;
+
+  Debug((DEBUG_INFO, "IsVhostPass() %s", hostmask));
+
+  if (EmptyString(hostmask))
+    return NULL;
+
+  for (sconf = GlobalSList; sconf; sconf = sconf->next)
+    if (strCasediff(hostmask, sconf->spoofhost) == 0) {
+      Debug((DEBUG_INFO, "sconf->passwd %s", sconf->passwd));
+      return EmptyString(sconf->passwd) ? NULL : sconf->passwd;
+    }
+
+  return NULL;
+}
+
 /** Update snomask \a oldmask according to \a arg and \a what.
  * @param[in] oldmask Original user mask.
  * @param[in] arg Update string (either a number or '+'/'-' followed by a number).
index f2649d36ee003c400516f1c1335803ed12b8980b..f4c5c019d9056722d34eaa4deef68415acdddad4 100644 (file)
@@ -281,7 +281,7 @@ static int match_it(struct Client *from, struct Client *one, const char *mask, i
   {
     case MATCH_HOST:
       return (match(mask, cli_user(one)->host) == 0 ||
-        (HasHiddenHost(one) && match(mask, cli_user(one)->realhost) == 0));
+        ((HasHiddenHost(one) || HasSetHost(one)) && match(mask, cli_user(one)->realhost) == 0));
     case MATCH_SERVER:
     default:
       return (match(mask, cli_name(cli_user(one)->server)) == 0);
index 4e33e2fb2f00153182522eba26101b9b0813904f..195b4b133fa6a6b654f80bd5da51968c4a13d3d2 100644 (file)
@@ -127,7 +127,7 @@ void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
 
   if (fields & WHO_FIELD_NIP)
   {
-    const char* p2 = HasHiddenHost(acptr) && !IsAnOper(sptr) ?
+    const char* p2 = (HasHiddenHost(acptr) || HasSetHost(acptr)) && !IsAnOper(sptr) ?
       feature_str(FEAT_HIDDEN_IP) :
       ircd_ntoa(&cli_ip(acptr));
     *(p1++) = ' ';
@@ -203,6 +203,8 @@ void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
         *(p1++) = 'w';
       if (SendDebug(acptr))
         *(p1++) = 'g';
+      if (HasSetHost(acptr))
+        *(p1++) = 'h';
     }
     if (HasHiddenHost(acptr))
       *(p1++) = 'x';
diff --git a/tools/convert_slines.sh b/tools/convert_slines.sh
new file mode 100644 (file)
index 0000000..f6a401b
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/sh
+#
+# $Id: asuka-sethost.patch,v 1.29 2005/02/24 01:06:52 froo Exp $
+#
+# aid in converting S: and F:lines from old lain configs
+# to the new "super S:line" format of asuka.
+#
+# When       Who                               What
+# 2003-01-05 froo@quakenet.org Created.
+
+PATH=/bin:/usr/bin
+PROG=`basename $0`
+USAGE="Usage: $PROG </path/to/ircd.cfg>"
+
+if [ $# -lt 1 ]; then
+       echo $USAGE
+       exit
+fi
+
+CONFIG=$1
+
+if [ ! -f $CONFIG ]; then
+       echo "Can't open \"$CONFIG\", bailing out."
+       exit
+fi
+
+{
+for LINE in `grep -E "^F:" $CONFIG`
+do
+       IDENT=`echo $LINE | cut -f2 -d:`
+       REALHOST=`echo $LINE | cut -f3 -d:`
+       SPOOFHOST=`echo $LINE | cut -f4 -d:`
+
+       IDENT=`echo $IDENT | sed -e 's,^~,\*,'`
+
+       echo "S:$SPOOFHOST::$REALHOST:$IDENT"
+done
+
+for LINE in `grep -E "^S:" $CONFIG`
+do
+       SPOOFHOST=`echo $LINE | cut -f2 -d:`
+       PASSWD=`echo $LINE | cut -f3 -d:`
+
+       IDENT=`echo $IDENT | sed -e 's,^~,\*,'`
+
+       echo "S:$SPOOFHOST:$PASSWD::"
+done
+} | sort
+
+exit 0