]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blobdiff - sethost.patch
remove empty patches
[irc/quakenet/snircd-patchqueue.git] / sethost.patch
index bd45a77c85765fa6da1392477753d84ec6f30ee4..b4338eed224e6dd33bd0e85ef1295f22a3527bfa 100644 (file)
@@ -17,6 +17,9 @@ change syntax to "SETHOST [<user>@]<host> [<password>]"
 disallow client to use MODE +h [<user>@]<host> [<pass>] (bug: mode +h took 2 parameters, even from remote users!)
 
 sethost can only be unset with "MODE <nick> -h"
+and only if the sethost was not remotely set by a service (unless the user is an oper)
+and only if the user has an account set, and is +x (or is allowed to set +x)
+so the +x host becomes visible, and never the realhost
 
 sethost #N no longer supported (N being the Nth configured spoof block)
 
@@ -42,29 +45,57 @@ show if spoofhost is valid or not (S = valid, s = invalid)
 removed numbering (not required anymore?)
 merged showing of user@host
 
-diff -r c6f3803ee169 include/client.h
---- a/include/client.h
-+++ b/include/client.h
+diff -r a771a07b5020 include/client.h
+--- a/include/client.h Sat Jul 20 14:54:11 2013 +0100
++++ b/include/client.h Sat Jul 20 14:54:45 2013 +0100
 @@ -90,7 +90,7 @@
  #define FlagClr(set,flag) ((set)->bits[FLAGSET_INDEX(flag)] &= ~FLAGSET_MASK(flag))
  
  /** String containing valid user modes, in no particular order. */
--#define infousermodes "dioOswkgxRXInP"
-+#define infousermodes "dioOswkghxRXInP"
+-#define infousermodes "diOoswkgxRXInP"
++#define infousermodes "diOoswkghxRXInP"
  
  /** Character to indicate no oper name available */
  #define NOOPERNAMECHARACTER '-'
-@@ -627,7 +627,6 @@
+@@ -171,6 +171,7 @@
+     FLAG_BURST,                     /**< Server is receiving a net.burst */
+     FLAG_BURST_ACK,                 /**< Server is waiting for eob ack */
+     FLAG_IPCHECK,                   /**< Added or updated IPregistry data */
++    FLAG_REMOTESETHOST,             /**< user has a remote sethost */
+     FLAG_LOCOP,                     /**< Local operator -- SRB */
+     FLAG_SERVNOTICE,                /**< server notices such as kill */
+     FLAG_OPER,                      /**< Operator */
+@@ -629,7 +630,8 @@
  #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))
++/** Return non-zero if the client is using a spoofhost that was set by a service */
++#define IsRemoteSetHost(x)      HasFlag(x, FLAG_REMOTESETHOST)
  
  /** Mark a client as having an in-progress net.burst. */
  #define SetBurst(x)             SetFlag(x, FLAG_BURST)
-diff -r c6f3803ee169 include/ircd_chattr.h
---- a/include/ircd_chattr.h
-+++ b/include/ircd_chattr.h
+@@ -673,6 +675,8 @@
+ #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 a remote sethost. */
++#define SetRemoteSetHost(x)     SetFlag(x, FLAG_REMOTESETHOST)
+ /** Mark a client as having mode +X (xtraop). */
+ #define SetXtraOp(x)            SetFlag(x, FLAG_XTRAOP)
+ /** Mark a client as having mode +n (hide channels). */
+@@ -718,6 +722,8 @@
+ #define ClearHiddenHost(x)      ClrFlag(x, FLAG_HIDDENHOST)
+ /** Remove mode +h (spoofhost) from a client. */
+ #define ClearSetHost(x)         ClrFlag(x, FLAG_SETHOST)
++/** Clear the client's remote SETHOST flag. */
++#define ClearRemoteSetHost(x)   ClrFlag(x, FLAG_REMOTESETHOST)
+ /** Remove mode +X (xtraop) from a client. */
+ #define ClearXtraOp(x)          ClrFlag(x, FLAG_XTRAOP)
+ /** Remove mode +n (hide channels) from a client. */
+diff -r a771a07b5020 include/ircd_chattr.h
+--- a/include/ircd_chattr.h    Sat Jul 20 14:54:11 2013 +0100
++++ b/include/ircd_chattr.h    Sat Jul 20 14:54:45 2013 +0100
 @@ -117,6 +117,8 @@
  #define IsUserChar(c)      (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCUI)
  /** Test whether a character is valid in a hostname. */
@@ -80,9 +111,9 @@ diff -r c6f3803ee169 include/ircd_chattr.h
  
 +
  #endif /* INCLUDED_ircd_chattr_h */
-diff -r c6f3803ee169 include/numeric.h
---- a/include/numeric.h
-+++ b/include/numeric.h
+diff -r a771a07b5020 include/numeric.h
+--- a/include/numeric.h        Sat Jul 20 14:54:11 2013 +0100
++++ b/include/numeric.h        Sat Jul 20 14:54:45 2013 +0100
 @@ -314,7 +314,7 @@
  /*      RPL_NOUSERS          395        Dalnet/EFnet/IRCnet */
  #define RPL_HOSTHIDDEN       396      /* UMODE +x completed succesfuly */
@@ -92,22 +123,22 @@ diff -r c6f3803ee169 include/numeric.h
  
  /*
   * Errors are in the range from 400-599 currently and are grouped by what
-diff -r c6f3803ee169 include/s_conf.h
---- a/include/s_conf.h
-+++ b/include/s_conf.h
+diff -r a771a07b5020 include/s_conf.h
+--- a/include/s_conf.h Sat Jul 20 14:54:11 2013 +0100
++++ b/include/s_conf.h Sat Jul 20 14:54:45 2013 +0100
 @@ -205,7 +205,8 @@
  
  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 struct sline *find_spoofblock(struct Client *cptr, char *spoofhost, char *password);
++extern struct sline *find_spoofblock(struct Client *cptr, char *host, char *password);
 +extern int apply_spoofblock(struct Client *cptr);
  extern void free_spoofhost(struct sline *spoof);
  
  extern void yyerror(const char *msg);
-diff -r c6f3803ee169 include/s_user.h
---- a/include/s_user.h
-+++ b/include/s_user.h
+diff -r a771a07b5020 include/s_user.h
+--- a/include/s_user.h Sat Jul 20 14:54:11 2013 +0100
++++ b/include/s_user.h Sat Jul 20 14:54:45 2013 +0100
 @@ -79,15 +79,15 @@
  extern int set_nick_name(struct Client* cptr, struct Client* sptr,
                           const char* nick, int parc, char* parv[]);
@@ -136,9 +167,9 @@ diff -r c6f3803ee169 include/s_user.h
  extern void set_snomask(struct Client *, unsigned int, int);
  extern int is_snomask(char *);
  extern int check_target_limit(struct Client *sptr, void *target, const char *name,
-diff -r c6f3803ee169 ircd/channel.c
---- a/ircd/channel.c
-+++ b/ircd/channel.c
+diff -r a771a07b5020 ircd/channel.c
+--- a/ircd/channel.c   Sat Jul 20 14:54:11 2013 +0100
++++ b/ircd/channel.c   Sat Jul 20 14:54:45 2013 +0100
 @@ -384,12 +384,12 @@
    ircd_ntoa_r(iphost, &cli_ip(cptr));
  
@@ -154,9 +185,9 @@ diff -r c6f3803ee169 ircd/channel.c
        sa = cli_user(cptr)->realhost;
      } else {
        ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
-diff -r c6f3803ee169 ircd/m_oper.c
---- a/ircd/m_oper.c
-+++ b/ircd/m_oper.c
+diff -r a771a07b5020 ircd/m_oper.c
+--- a/ircd/m_oper.c    Sat Jul 20 14:54:11 2013 +0100
++++ b/ircd/m_oper.c    Sat Jul 20 14:54:45 2013 +0100
 @@ -189,7 +189,7 @@
      
      set_snomask(sptr, SNO_OPERDEFAULT, SNO_ADD);
@@ -166,10 +197,74 @@ diff -r c6f3803ee169 ircd/m_oper.c
      send_reply(sptr, RPL_YOUREOPER);
  
      sendto_opmask_butone(0, SNO_OLDSNO, "%s (%s@%s) is now operator (%c) as %s",
-diff -r c6f3803ee169 ircd/m_sethost.c
---- a/ircd/m_sethost.c
-+++ b/ircd/m_sethost.c
-@@ -82,174 +82,225 @@
+diff -r a771a07b5020 ircd/m_remotemode.c
+--- a/ircd/m_remotemode.c      Sat Jul 20 14:54:11 2013 +0100
++++ b/ircd/m_remotemode.c      Sat Jul 20 14:54:45 2013 +0100
+@@ -126,6 +126,7 @@
+   int what = MODE_ADD;
+   int do_host_hiding = 0;
+   int do_set_host = 0;
++  int alreadyh = 0;
+   /* not from a server */
+   if (!IsServer(sptr))
+@@ -216,17 +217,15 @@
+           break;
+         case 'h':
+           if (what == MODE_ADD) {
+-            if (*(p + 1) && is_hostmask(*(p + 1))) {
+-              do_set_host = 1;
+-              hostmask = *++p;
+-            } else {
+-              if (!*(p+1))
+-                protocol_violation(sptr, "Received REMOTEMODE +h without host parameter for user %C", acptr);
+-              else {
+-                protocol_violation(sptr, "Received REMOTEMODE +h with invalid host parameter %s for user %C", *(p+1), acptr);
+-                p++; /* Swallow the arg anyway */
+-              }
+-            }
++           /* TODO: */
++           if (IsServer(cptr)) {
++             if (!*(p + 1))
++               protocol_violation(cptr, "Received MODE +h for %C without sethost parameter", sptr);
++             else {
++               hostmask = *++p;
++               do_set_host = 1;
++             }
++           }
+           } else { /* MODE_DEL */
+             do_set_host = 1;
+             hostmask = NULL;
+@@ -275,10 +274,12 @@
+       host = hostmask;
+     /* check if new sethost is different from before */
+-    if (IsSetHost(acptr) && 
+-       (!user || strcmp(cli_user(acptr)->username, user) == 0) &&
+-        strcmp(cli_user(acptr)->host, host) == 0)
+-      do_set_host = 0;
++    if (IsSetHost(acptr)) {
++      alreadyh = 1;
++      if ((!user || strcmp(cli_user(acptr)->username, user) == 0) &&
++          strcmp(cli_user(acptr)->host, host) == 0)
++        do_set_host = 0;
++    }
+   }
+   /* do host hiding for +h/-h */
+@@ -353,7 +354,7 @@
+   assert(UserStats.inv_clients <= UserStats.clients + UserStats.unknowns);
+   /* send out the mode */
+-  send_umode_out(acptr, acptr, &setflags, 0);
++  send_umode_out(acptr, acptr, &setflags, 0, alreadyh);
+   return 0;
+ }
+diff -r a771a07b5020 ircd/m_sethost.c
+--- a/ircd/m_sethost.c Sat Jul 20 14:54:11 2013 +0100
++++ b/ircd/m_sethost.c Sat Jul 20 14:54:45 2013 +0100
+@@ -82,175 +82,233 @@
  #include "config.h"
  
  #include "client.h"
@@ -240,7 +335,7 @@ diff -r c6f3803ee169 ircd/m_sethost.c
 +  /* need hostmask parameter
 +   *   and need password parameter from an ordinary user
 +   */
-+  if (parc < 2 || EmptyString(parv[1]) || (parc < 3 && !IsAnOper(sptr)))
++  if (parc < 2 || *parv[1] == 0 || (parc < 3 && !IsAnOper(sptr)))
 +    return need_more_params(sptr, "SETHOST");
 +
 +  hostmask = parv[1];
@@ -253,8 +348,8 @@ diff -r c6f3803ee169 ircd/m_sethost.c
 +  else
 +    host = hostmask;
 +
-+  /* got a pasword */
-+  if (parc > 2 && !EmptyString(parv[2]))
++  /* got a pasword and not empty */
++  if (parc > 2 && *parv[2])
 +    password = parv[2];
 +
 +  /* freeform - do not bother with password */
@@ -285,10 +380,11 @@ diff -r c6f3803ee169 ircd/m_sethost.c
  
 -  if (parc < 2)
 -    return need_more_params(sptr, "SETHOST");
-+  /* already +h, clear flag to force mode +h to be sent out again */
++  /* already +h, clear flag to force mode +h to be sent out again, and clear remote sethost flag */
 +  if (IsSetHost(sptr)) {
 +    FlagClr(&setflags, FLAG_SETHOST);
 +    alreadyh = 1;
++    ClearRemoteSetHost(sptr);
 +  }
  
 -  if (0 == ircd_strcmp("undo", parv[1])) {
@@ -340,10 +436,12 @@ diff -r c6f3803ee169 ircd/m_sethost.c
 +  if (freeform) {
 +
 +    sendto_opmask_butone(0, SNO_OLDSNO,
-+      "%C SETHOST %s@%s (freeform)", sptr, user, host);
++      "%C SETHOST %s%s%s (freeform)", sptr,
++      user ? user : "", user ? "@" : "", host);
 +
 +    log_write(LS_SETHOST, L_NOTICE, LOG_NOSNOTICE,
-+      "%s SETHOST %s@%s (freeform)", get_client_name(sptr, SHOW_IP), user, host);
++      "%s SETHOST %s%s%s (freeform)", get_client_name(sptr, SHOW_IP),
++      user ? user : "", user ? "@" : "", host);
 +  }
 +
 +  /* send the mode out */
@@ -436,7 +534,7 @@ diff -r c6f3803ee169 ircd/m_sethost.c
 +
 +    /* user has no sethost or has no account
 +     *
-+     * user has +h their host is hidden, do not remove it
++     * user has +h their host is hidden, do not remove it
 +     *   unless the user has an account set
 +     *     we should not out of the blue expose the real host
 +     */
@@ -502,6 +600,10 @@ diff -r c6f3803ee169 ircd/m_sethost.c
    }
  
 -  send_umode_out(target, target, &setflags, 0);
++  /* setting remote sethost, set flag */
++  if (host)
++    SetRemoteSetHost(acptr);
++
 +  /* do it */
 +  set_hostmask(acptr, user, host);
 +
@@ -510,9 +612,10 @@ diff -r c6f3803ee169 ircd/m_sethost.c
 +
    return 0;
  }
-diff -r c6f3803ee169 ircd/m_userhost.c
---- a/ircd/m_userhost.c
-+++ b/ircd/m_userhost.c
+diff -r a771a07b5020 ircd/m_userhost.c
+--- a/ircd/m_userhost.c        Sat Jul 20 14:54:11 2013 +0100
++++ b/ircd/m_userhost.c        Sat Jul 20 14:54:45 2013 +0100
 @@ -104,7 +104,7 @@
               * of +x.  If an oper wants the real host, he should go to
               * /whois to get it.
@@ -522,9 +625,9 @@ diff -r c6f3803ee169 ircd/m_userhost.c
              cli_user(cptr)->host : cli_user(cptr)->realhost);
  }
  
-diff -r c6f3803ee169 ircd/m_userip.c
---- a/ircd/m_userip.c
-+++ b/ircd/m_userip.c
+diff -r a771a07b5020 ircd/m_userip.c
+--- a/ircd/m_userip.c  Sat Jul 20 14:54:11 2013 +0100
++++ b/ircd/m_userip.c  Sat Jul 20 14:54:45 2013 +0100
 @@ -106,7 +106,7 @@
               * of +x.  If an oper wants the real IP, he should go to
               * /whois to get it.
@@ -534,10 +637,10 @@ diff -r c6f3803ee169 ircd/m_userip.c
              feature_str(FEAT_HIDDEN_IP) :
              ircd_ntoa(&cli_ip(cptr)));
  }
-diff -r c6f3803ee169 ircd/m_who.c
---- a/ircd/m_who.c
-+++ b/ircd/m_who.c
-@@ -394,14 +394,14 @@
+diff -r a771a07b5020 ircd/m_who.c
+--- a/ircd/m_who.c     Sat Jul 20 14:54:11 2013 +0100
++++ b/ircd/m_who.c     Sat Jul 20 14:54:45 2013 +0100
+@@ -395,14 +395,14 @@
                && ((!(matchsel & WHO_FIELD_HOS))
                || matchexec(cli_user(acptr)->host, mymask, minlen))
                && ((!(matchsel & WHO_FIELD_HOS))
@@ -554,7 +657,7 @@ diff -r c6f3803ee169 ircd/m_who.c
                || !ipmask_check(&cli_ip(acptr), &imask, ibits))
                && ((!(matchsel & WHO_FIELD_ACC))
                || matchexec(cli_user(acptr)->account, mymask, minlen)))
-@@ -433,14 +433,14 @@
+@@ -434,14 +434,14 @@
              && ((!(matchsel & WHO_FIELD_HOS))
              || matchexec(cli_user(acptr)->host, mymask, minlen))
              && ((!(matchsel & WHO_FIELD_HOS))
@@ -571,9 +674,9 @@ diff -r c6f3803ee169 ircd/m_who.c
              || !ipmask_check(&cli_ip(acptr), &imask, ibits))
              && ((!(matchsel & WHO_FIELD_ACC))
              || matchexec(cli_user(acptr)->account, mymask, minlen)))
-diff -r c6f3803ee169 ircd/m_whois.c
---- a/ircd/m_whois.c
-+++ b/ircd/m_whois.c
+diff -r a771a07b5020 ircd/m_whois.c
+--- a/ircd/m_whois.c   Sat Jul 20 14:54:11 2013 +0100
++++ b/ircd/m_whois.c   Sat Jul 20 14:54:45 2013 +0100
 @@ -214,7 +214,7 @@
      if (IsAccount(acptr))
        send_reply(sptr, RPL_WHOISACCOUNT, name, user->account);
@@ -583,9 +686,9 @@ diff -r c6f3803ee169 ircd/m_whois.c
        send_reply(sptr, RPL_WHOISACTUALLY, name, user->realusername,
                   user->realhost, ircd_ntoa(&cli_ip(acptr)));
  
-diff -r c6f3803ee169 ircd/s_conf.c
---- a/ircd/s_conf.c
-+++ b/ircd/s_conf.c
+diff -r a771a07b5020 ircd/s_conf.c
+--- a/ircd/s_conf.c    Sat Jul 20 14:54:11 2013 +0100
++++ b/ircd/s_conf.c    Sat Jul 20 14:54:45 2013 +0100
 @@ -52,6 +52,7 @@
  #include "s_bsd.h"
  #include "s_debug.h"
@@ -594,75 +697,108 @@ diff -r c6f3803ee169 ircd/s_conf.c
  #include "send.h"
  #include "struct.h"
  #include "sys.h"
-@@ -1239,44 +1240,159 @@
-  * -froo 1/2003
-  *
-  */
+@@ -1204,6 +1205,10 @@
+   return 0;
+ }
++/**
++ * clear spoof blocks
++ *
++ */
+ void clear_slines(void)
+ {
+   struct sline *sline;
+@@ -1220,61 +1225,164 @@
+   }
+ }
+-/*
+- * conf_check_slines()
 +/** 
 + * find_spoofblock
-+ *
+  *
+- * Check S lines for the specified client, passed in cptr struct.
+- * If the client's IP is S-lined, process the substitution here.
 + *  Find matching spoof block for a user for the given spoofhost and password
-+ *
+  *
+- * Precondition
+- *  cptr != NULL
 + *  @param cptr       User wanting to get a spoof host.
-+ *  @param spoofhost  Spoof host to look for.
++ *  @param host       Spoof host to look for.
 + *  @param password   Password given by user (can be NULL).
-+ *
+  *
+- * Returns
+- *  0 = No S-line found
+- *  1 = S-line found and substitution done.
+- *
+- * -mbuna 9/2001
+- * -froo 1/2003
 + *  @return pointer to the matching spoofblock is found, else NULL
-+ *
-+ */
-+struct sline *find_spoofblock(struct Client *cptr, char *spoofhost, char *password) {
+  *
+  */
++struct sline *find_spoofblock(struct Client *cptr, char *host, char *password) {
  
-+  char *error[4];  
-+  struct sline *sconf;
+-int
+-conf_check_slines(struct Client *cptr)
+-{
+   struct sline *sconf;
+-  char *hostonly;
 +  int result = 0;
 +  int r = 0;
++  char *error;
 +
-+  /* set error messages */  
-+  error[0] = "no such Spoof block";
-+  error[1] = "IP / host mismatch";
-+  error[2] = "username mismatch";
-+  error[3] = password ? "password mismatch" : "password required";
-+
-+  Debug((DEBUG_INFO, "find_spoofblock() cptr=%C spoofhost=%s password=%s",
-+    cptr, spoofhost, password));
-+
-+  for (sconf = GlobalSList; sconf; sconf = sconf->next) {
++  Debug((DEBUG_INFO, "find_spoofblock() cptr=%C host=%s password=%s",
++    cptr, host, password));
+   for (sconf = GlobalSList; sconf; sconf = sconf->next) {
 +
 +    /* check result of previous loop */
 +    if (r > result)
 +      result = r;
 +
 +    /* check spoofhost */
-+    if (strcasecmp(sconf->spoofhost, spoofhost) != 0)
++    if (strcasecmp(sconf->spoofhost, host) != 0)
 +      continue;
 +    r = 1;
 +
 +    /* check cptr's host */
 +    /* cidr mask */
-+    if (sconf->flags == SLINE_FLAGS_IP) {
-+      if (!ipmask_check(&(cli_ip(cptr)), &(sconf->address), sconf->bits))
-+        continue;
+     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 {
 +    }
 +
 +    /* hostname */
 +    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;
-+    }
-+
+         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;
 +    /* not cidr or hostname.. */ 
 +    else
 +      continue;
 +    r = 2;
-+
+-      if(!*hostonly)
 +    /* check cptr's username */
 +    if (!EmptyString(sconf->username) && match(sconf->username, cli_user(cptr)->realusername) != 0)
 +      continue;
 +    r = 3;
 +
 +    /* check password */
-+    if (password) {
++    if (!EmptyString(password)) {
 +      if (EmptyString(sconf->passwd) || strcmp(sconf->passwd, password) != 0)
 +        continue;
 +    }
@@ -672,21 +808,39 @@ diff -r c6f3803ee169 ircd/s_conf.c
 +      continue;
 +
 +    /* got one */
-+    log_write(LS_SETHOST, L_INFO, 0, "%s SETHOST %s (ok)",
-+      get_client_name(cptr, SHOW_IP), sconf->spoofhost);
++    log_write(LS_SETHOST, L_INFO, 0, "%s SETHOST %s (ok) [password: %s]",
++      get_client_name(cptr, SHOW_IP), sconf->spoofhost,
++      password ? "yes" : "no");
 +    return sconf;
 +  }
 +
++  /* set error messages */
++  switch (result) {
++    case 0:
++      error = "no such Spoof block";
++      break;
++    case 1:
++      error = "IP / host mismatch";
++      break;
++    case 2:
++      error = "username mismatch";
++      break;
++    case 3:
++      error = password ? "password mismatch" : "password required";
++      break;
++    default:
++      error = "unknown failure";
++  }
++
 +  /* TODO: lookup LOG stuff */
 +  /* TODO: L_INFO LOG_NOSNOTICE */
 +  /* log best result we got */
-+  log_write(LS_SETHOST, L_INFO, 0, "%s SETHOST %s (%s)",
-+    get_client_name(cptr, SHOW_IP), spoofhost, error[result]);
++  log_write(LS_SETHOST, L_INFO, 0, "%s SETHOST %s (failed: %s) [password: %s]",
++    get_client_name(cptr, SHOW_IP), host,
++    error, password ? "yes" : "no");
 +  return NULL;
 +}
 +
-+
-+
 +/** 
 + * apply_spoofblock
 + *
@@ -695,86 +849,66 @@ diff -r c6f3803ee169 ircd/s_conf.c
 + * @return 1 for success, else 0
 + * 
 + */
- int
--conf_check_slines(struct Client *cptr)
++int
 +apply_spoofblock(struct Client *cptr)
- {
-   struct sline *sconf;
-   char *hostonly;
++{
++  struct sline *sconf;
++
 +  /* disabled */
 +  if(!feature_bool(FEAT_SETHOST_AUTO))
 +    return 0;
 +
 +  /* go over spoof blocks */
-   for (sconf = GlobalSList; sconf; sconf = sconf->next) {
++  for (sconf = GlobalSList; sconf; sconf = sconf->next) {
 +
 +    /* check IP */
-     if (sconf->flags == SLINE_FLAGS_IP) {
-       if (!ipmask_check(&(cli_ip(cptr)), &(sconf->address), sconf->bits))
++    if (sconf->flags == SLINE_FLAGS_IP) {
++      if (!ipmask_check(&(cli_ip(cptr)), &(sconf->address), sconf->bits))
          continue;
-+
-+    /* check host */
-     } 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 */
-+            (match(sconf->realhost, cli_sock_ip(cptr)) != 0))   /* wildcarded IP address */
-           continue;
--    } else {
--        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;
-+    /* check username */
-+    if (match(sconf->username, cli_user(cptr)->username) != 0)
-+      continue;
--      if(!*hostonly)
--        continue;
-+    /* Ignore user part if u@h. */
-+    if ((hostonly = strchr(sconf->spoofhost, '@')))
-+      hostonly++;
-+    else
-+      hostonly = sconf->spoofhost;
  
 -      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;
 -    }
++    /* check host */
++    } 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;
++
++    /* check username */
++    if (match(sconf->username, cli_user(cptr)->realusername) != 0)
++      continue;
++
 +    /* invalid */
-+    if (!is_validsethost(NULL, hostonly))
++    if (!is_validsethost(NULL, sconf->spoofhost))
 +      continue;
 +
-+    /* do it and log */
-+    set_hostmask(cptr, NULL, hostonly);
-+    /* LOG_NOSNOTICE */
-+    log_write(LS_USER, L_INFO, 0, "AUTO SETHOST %s on %s",
-+      hostonly, get_client_name(cptr, SHOW_IP));
++    /* do it */
++    set_hostmask(cptr, NULL, sconf->spoofhost);
++
++    /* TODO: LOG_NOSNOTICE */
++    /* log it */
++    log_write(LS_USER, L_INFO, 0, "%s SETHOST %s (auto)",
++      get_client_name(cptr, SHOW_IP), sconf->spoofhost);
 +    return 1;
    }
    return 0;
  }
  
-+
-+
 +/**
-+ *
++ * free a spoofblock
 + *
 + */
  void free_spoofhost(struct sline *spoof) {
        MyFree(spoof->spoofhost);
        MyFree(spoof->passwd);
-diff -r c6f3803ee169 ircd/s_err.c
---- a/ircd/s_err.c
-+++ b/ircd/s_err.c
+diff -r a771a07b5020 ircd/s_err.c
+--- a/ircd/s_err.c     Sat Jul 20 14:54:11 2013 +0100
++++ b/ircd/s_err.c     Sat Jul 20 14:54:45 2013 +0100
 @@ -824,13 +824,13 @@
  /* 395 */
    { 0 },
@@ -804,9 +938,9 @@ diff -r c6f3803ee169 ircd/s_err.c
  /* 532 */
    { 0 },
  /* 533 */
-diff -r c6f3803ee169 ircd/s_stats.c
---- a/ircd/s_stats.c
-+++ b/ircd/s_stats.c
+diff -r a771a07b5020 ircd/s_stats.c
+--- a/ircd/s_stats.c   Sat Jul 20 14:54:11 2013 +0100
++++ b/ircd/s_stats.c   Sat Jul 20 14:54:45 2013 +0100
 @@ -400,41 +400,37 @@
    }
  }
@@ -869,9 +1003,9 @@ diff -r c6f3803ee169 ircd/s_stats.c
    }
  }
  
-diff -r c6f3803ee169 ircd/s_user.c
---- a/ircd/s_user.c
-+++ b/ircd/s_user.c
+diff -r a771a07b5020 ircd/s_user.c
+--- a/ircd/s_user.c    Sat Jul 20 14:54:11 2013 +0100
++++ b/ircd/s_user.c    Sat Jul 20 14:54:45 2013 +0100
 @@ -73,9 +73,6 @@
  #include <string.h>
  #include <sys/stat.h>
@@ -988,7 +1122,6 @@ diff -r c6f3803ee169 ircd/s_user.c
 -  char hiddenhost[USERLEN + HOSTLEN + 2];
 +
 +  int userchange = 0;
-+  char hiddenhost[USERLEN + 1 + HOSTLEN + 1];
 +  char *msg = "Host change";
    struct Membership *chan;
  
@@ -1018,8 +1151,9 @@ diff -r c6f3803ee169 ircd/s_user.c
 +  /* remove sethost */
 +  if (!host) {
 +
-+    /* clear flag */
++    /* clear flags */
 +    ClearSetHost(cptr);
++    ClearRemoteSetHost(cptr);
 +
 +    /* restore user and host */
 +    if (HasHiddenHost(cptr))
@@ -1317,19 +1451,31 @@ diff -r c6f3803ee169 ircd/s_user.c
           }
           break;
        case 'R':
-@@ -1468,6 +1362,11 @@
+@@ -1468,6 +1362,23 @@
      if (!FlagHas(&setflags, FLAG_PARANOID) && !(IsOper(sptr) && HasPriv(sptr, PRIV_PARANOID)))
        ClearParanoid(sptr);
  
 +    /* TODO: */
-+    /* only opers can remove a sethost */
-+    if (do_set_host && !hostmask && !FlagHas(&setflags, FLAG_LOCOP) && !FlagHas(&setflags, FLAG_OPER))
-+      do_set_host = 0;
++    /* setting -h */
++    if (do_set_host && !hostmask && IsSetHost(sptr)) {
++      /* cannot do -h if user has a remote sethost, unless they are an oper */
++      if (!FlagHas(&setflags, FLAG_LOCOP) && !FlagHas(&setflags, FLAG_OPER) && IsRemoteSetHost(sptr))
++        do_set_host = 0;
++      /* cannot do -h if user has no account set */
++      else if (!IsAccount(sptr))
++        do_set_host = 0;
++      /* cannot do -h if user does not have +x set and is not allowed to set it */
++      else if (!IsHiddenHost(sptr) && !feature_bool(FEAT_HOST_HIDING))
++        do_set_host = 0;
++      /* all ok, set user +x */
++      else
++        SetHiddenHost(sptr);
++    }
 +
      /*
       * only send wallops to opers
       */
-@@ -1521,11 +1420,38 @@
+@@ -1524,11 +1435,38 @@
    }
    if (!FlagHas(&setflags, FLAG_HIDDENHOST) && do_host_hiding && allow_modes != ALLOWMODES_DEFAULT)
      hide_hostmask(sptr, FLAG_HIDDENHOST);
@@ -1360,7 +1506,7 @@ diff -r c6f3803ee169 ircd/s_user.c
 +       */
 +      if (*user == 0 || user[0] == ':' || *host == 0 || host[0] == ':')
 +        protocol_violation(cptr, "Received MODE +h for %C with an invalid user@host '%s@%s'",
-+          sptr, user ? user : "", host);
++          sptr, user ? user : "", host ? host : "");
 +
 +      /* apply it */
 +      else {
@@ -1372,7 +1518,7 @@ diff -r c6f3803ee169 ircd/s_user.c
    }
  
    if (IsRegistered(sptr)) {
-@@ -1577,7 +1503,7 @@
+@@ -1580,7 +1518,7 @@
      }
      assert(UserStats.opers <= UserStats.clients + UserStats.unknowns);
      assert(UserStats.inv_clients <= UserStats.clients + UserStats.unknowns);
@@ -1381,7 +1527,7 @@ diff -r c6f3803ee169 ircd/s_user.c
    }
  
    return 0;
-@@ -1652,9 +1578,11 @@
+@@ -1655,9 +1593,11 @@
   * @param[in] old Pre-change set of modes for \a sptr.
   * @param[in] sendset One of ALL_UMODES, SEND_UMODES_BUT_OPER,
   * SEND_UMODES, to select which changed user modes to send.
@@ -1394,7 +1540,7 @@ diff -r c6f3803ee169 ircd/s_user.c
  {
    int i;
    int flag;
-@@ -1697,12 +1625,15 @@
+@@ -1700,12 +1640,15 @@
      }
      /* Special case for SETHOST.. */
      if (flag == FLAG_SETHOST) {
@@ -1416,7 +1562,7 @@ diff -r c6f3803ee169 ircd/s_user.c
                needhost++;    
      }
      if (FlagHas(old, flag))
-@@ -1741,7 +1672,7 @@
+@@ -1744,7 +1687,7 @@
    }
    if (needhost) {
      *m++ = ' ';
@@ -1425,7 +1571,7 @@ diff -r c6f3803ee169 ircd/s_user.c
           cli_user(sptr)->host);
    } else
      *m = '\0';
-@@ -1769,108 +1700,53 @@
+@@ -1772,108 +1715,53 @@
    return 0;
  }
  
@@ -1572,9 +1718,9 @@ diff -r c6f3803ee169 ircd/s_user.c
  }
  
  /** Update snomask \a oldmask according to \a arg and \a what.
-diff -r c6f3803ee169 ircd/send.c
---- a/ircd/send.c
-+++ b/ircd/send.c
+diff -r a771a07b5020 ircd/send.c
+--- a/ircd/send.c      Sat Jul 20 14:54:11 2013 +0100
++++ b/ircd/send.c      Sat Jul 20 14:54:45 2013 +0100
 @@ -281,7 +281,7 @@
    {
      case MATCH_HOST:
@@ -1584,9 +1730,9 @@ diff -r c6f3803ee169 ircd/send.c
      case MATCH_SERVER:
      default:
        return (match(mask, cli_name(cli_user(one)->server)) == 0);
-diff -r c6f3803ee169 ircd/whocmds.c
---- a/ircd/whocmds.c
-+++ b/ircd/whocmds.c
+diff -r a771a07b5020 ircd/whocmds.c
+--- a/ircd/whocmds.c   Sat Jul 20 14:54:11 2013 +0100
++++ b/ircd/whocmds.c   Sat Jul 20 14:54:45 2013 +0100
 @@ -134,7 +134,7 @@
  
    if (fields & WHO_FIELD_NIP)