1 sethost patch: minor overhaul of sethost system
3 this patch replaces a number of other patches:
4 autosethost.patch invalidatebanssethost.patch issethost.patch
5 sethostnewhostmask.patch sethostoldcode.patch sethostprotocolviolation.patch
6 showumodehtoclients.patch ulined.patch
8 makes usermode +h visible to clients
10 removes HasSetHost() macro (was same as IsSetHost())
12 removed 'Using S-line privilege' message on connect
13 client is informed of spoofhost by 396 RPL_HOSTHIDDEN (host :is now your hidden host)
15 change syntax to "SETHOST [<user>@]<host> [<password>]"
17 disallow client to use MODE +h [<user>@]<host> [<pass>] (bug: mode +h took 2 parameters, even from remote users!)
19 sethost can only be unset with "MODE <nick> -h"
20 and only if the sethost was not remotely set by a service (unless the user is an oper)
21 and only if the user has an account set, and is +x (or is allowed to set +x)
22 so the +x host becomes visible, and never the realhost
24 sethost #N no longer supported (N being the Nth configured spoof block)
26 remote sethost can now be undone by using 0 as username and host,
27 but only when the user has an account set and is allowed by server settings to set mode +x,
28 to avoid revealing the real host out of the blue
30 SETHOST now same as OPER
31 modes h and o can only be set with SETHOST and OPER
32 modes h and o are visible to clients
33 modes h and o can only be unset with MODE <nick> -ho
35 user sethosts are now also checked against their user@host/ip (and not just the password)
37 applying the sethost and syncing of clients (quit user, rejoin user, restore modes on user) is now done in one place
39 remote sethost can come from any server, does not need to have a Uworld block or be a service (ACCOUNT doesnt require that either)
41 allow chars -. 0-9 A-Z [\]^_ a-Z {|} ~: in user and host part of sethost (only change is that : is allowed because of IPv6)
44 show if spoofhost is valid or not (S = valid, s = invalid)
45 removed numbering (not required anymore?)
46 merged showing of user@host
48 diff -r a771a07b5020 include/client.h
49 --- a/include/client.h Sat Jul 20 14:54:11 2013 +0100
50 +++ b/include/client.h Sat Jul 20 14:54:45 2013 +0100
52 #define FlagClr(set,flag) ((set)->bits[FLAGSET_INDEX(flag)] &= ~FLAGSET_MASK(flag))
54 /** String containing valid user modes, in no particular order. */
55 -#define infousermodes "diOoswkgxRXInP"
56 +#define infousermodes "diOoswkghxRXInP"
58 /** Character to indicate no oper name available */
59 #define NOOPERNAMECHARACTER '-'
61 FLAG_BURST, /**< Server is receiving a net.burst */
62 FLAG_BURST_ACK, /**< Server is waiting for eob ack */
63 FLAG_IPCHECK, /**< Added or updated IPregistry data */
64 + FLAG_REMOTESETHOST, /**< user has a remote sethost */
65 FLAG_LOCOP, /**< Local operator -- SRB */
66 FLAG_SERVNOTICE, /**< server notices such as kill */
67 FLAG_OPER, /**< Operator */
69 #define HasHiddenHost(x) (IsHiddenHost(x) && IsAccount(x))
70 /** Return non-zero if the client is using a spoofhost */
71 #define IsSetHost(x) HasFlag(x, FLAG_SETHOST)
72 -#define HasSetHost(x) (IsSetHost(x))
73 +/** Return non-zero if the client is using a spoofhost that was set by a service */
74 +#define IsRemoteSetHost(x) HasFlag(x, FLAG_REMOTESETHOST)
76 /** Mark a client as having an in-progress net.burst. */
77 #define SetBurst(x) SetFlag(x, FLAG_BURST)
79 #define SetHiddenHost(x) SetFlag(x, FLAG_HIDDENHOST)
80 /** Mark a client as having mode +h (spoofhost). */
81 #define SetSetHost(x) SetFlag(x, FLAG_SETHOST)
82 +/** Mark a client as having a remote sethost. */
83 +#define SetRemoteSetHost(x) SetFlag(x, FLAG_REMOTESETHOST)
84 /** Mark a client as having mode +X (xtraop). */
85 #define SetXtraOp(x) SetFlag(x, FLAG_XTRAOP)
86 /** Mark a client as having mode +n (hide channels). */
88 #define ClearHiddenHost(x) ClrFlag(x, FLAG_HIDDENHOST)
89 /** Remove mode +h (spoofhost) from a client. */
90 #define ClearSetHost(x) ClrFlag(x, FLAG_SETHOST)
91 +/** Clear the client's remote SETHOST flag. */
92 +#define ClearRemoteSetHost(x) ClrFlag(x, FLAG_REMOTESETHOST)
93 /** Remove mode +X (xtraop) from a client. */
94 #define ClearXtraOp(x) ClrFlag(x, FLAG_XTRAOP)
95 /** Remove mode +n (hide channels) from a client. */
96 diff -r a771a07b5020 include/ircd_chattr.h
97 --- a/include/ircd_chattr.h Sat Jul 20 14:54:11 2013 +0100
98 +++ b/include/ircd_chattr.h Sat Jul 20 14:54:45 2013 +0100
100 #define IsUserChar(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCUI)
101 /** Test whether a character is valid in a hostname. */
102 #define IsHostChar(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCHN)
103 +/** Test whether a character is valid in a sethost - snircd */
104 +#define IsSetHostChar(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & (NTL_IRCHN|NTL_IRCIP6))
105 /** Test whether a character is valid in an IPv4 address. */
106 #define IsIPChar(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCIP)
107 /** Test whether a character is valid in an IPv6 address. */
109 #define IsKTimeChar(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_KTIME)
113 #endif /* INCLUDED_ircd_chattr_h */
114 diff -r a771a07b5020 include/numeric.h
115 --- a/include/numeric.h Sat Jul 20 14:54:11 2013 +0100
116 +++ b/include/numeric.h Sat Jul 20 14:54:45 2013 +0100
118 /* RPL_NOUSERS 395 Dalnet/EFnet/IRCnet */
119 #define RPL_HOSTHIDDEN 396 /* UMODE +x completed succesfuly */
120 #define RPL_STATSSLINE 398 /* QuakeNet extension -froo */
121 -#define RPL_USINGSLINE 399 /* QuakeNet extension -froo */
122 +/* RPL_USINGSLINE 399 QuakeNet extension -froo */
125 * Errors are in the range from 400-599 currently and are grouped by what
126 diff -r a771a07b5020 include/s_conf.h
127 --- a/include/s_conf.h Sat Jul 20 14:54:11 2013 +0100
128 +++ b/include/s_conf.h Sat Jul 20 14:54:45 2013 +0100
131 extern void conf_add_sline(const char* const* fields, int count);
132 extern void clear_slines(void);
133 -extern int conf_check_slines(struct Client *cptr);
134 +extern struct sline *find_spoofblock(struct Client *cptr, char *host, char *password);
135 +extern int apply_spoofblock(struct Client *cptr);
136 extern void free_spoofhost(struct sline *spoof);
138 extern void yyerror(const char *msg);
139 diff -r a771a07b5020 include/s_user.h
140 --- a/include/s_user.h Sat Jul 20 14:54:11 2013 +0100
141 +++ b/include/s_user.h Sat Jul 20 14:54:45 2013 +0100
143 extern int set_nick_name(struct Client* cptr, struct Client* sptr,
144 const char* nick, int parc, char* parv[]);
145 extern void send_umode_out(struct Client* cptr, struct Client* sptr,
146 - struct Flags* old, int prop);
147 + struct Flags* old, int prop, int alreadyh);
148 extern int whisper(struct Client* source, const char* nick,
149 const char* channel, const char* text, int is_notice);
150 extern void send_user_info(struct Client* to, char* names, int rpl,
153 extern int hide_hostmask(struct Client *cptr, unsigned int flags);
154 -extern int set_hostmask(struct Client *cptr, char *hostmask, char *password);
155 -extern int is_hostmask(char *word);
156 +extern int set_hostmask(struct Client *sptr, char *user, char *host);
157 +extern int is_validsethost(char *user, char *host);
158 extern int set_user_mode(struct Client *cptr, struct Client *sptr,
159 int parc, char *parv[], int allow_modes);
160 extern int is_silenced(struct Client *sptr, struct Client *acptr);
162 extern struct Client* next_client(struct Client* next, const char* ch);
163 extern char *umode_str(struct Client *cptr, int type);
164 extern void send_umode(struct Client *cptr, struct Client *sptr,
165 - struct Flags *old, int sendset, int opernames);
166 + struct Flags *old, int sendset, int opernames, int alreadyh);
167 extern void set_snomask(struct Client *, unsigned int, int);
168 extern int is_snomask(char *);
169 extern int check_target_limit(struct Client *sptr, void *target, const char *name,
170 diff -r a771a07b5020 ircd/channel.c
171 --- a/ircd/channel.c Sat Jul 20 14:54:11 2013 +0100
172 +++ b/ircd/channel.c Sat Jul 20 14:54:45 2013 +0100
173 @@ -384,12 +384,12 @@
174 ircd_ntoa_r(iphost, &cli_ip(cptr));
176 /* sr is real host if +h */
177 - if (HasSetHost(cptr))
178 + if (IsSetHost(cptr))
179 sr = cli_user(cptr)->realhost;
181 /* if +x and not +h sa is real host, if -x or +h sa is the account host */
182 if (IsAccount(cptr)) {
183 - if (HasHiddenHost(cptr) && !HasSetHost(cptr)) {
184 + if (HasHiddenHost(cptr) && !IsSetHost(cptr)) {
185 sa = cli_user(cptr)->realhost;
187 ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
188 diff -r a771a07b5020 ircd/m_oper.c
189 --- a/ircd/m_oper.c Sat Jul 20 14:54:11 2013 +0100
190 +++ b/ircd/m_oper.c Sat Jul 20 14:54:45 2013 +0100
193 set_snomask(sptr, SNO_OPERDEFAULT, SNO_ADD);
194 cli_max_sendq(sptr) = 0; /* Get the sendq from the oper's class */
195 - send_umode_out(cptr, sptr, &old_mode, HasPriv(sptr, PRIV_PROPAGATE));
196 + send_umode_out(cptr, sptr, &old_mode, HasPriv(sptr, PRIV_PROPAGATE), 0);
197 send_reply(sptr, RPL_YOUREOPER);
199 sendto_opmask_butone(0, SNO_OLDSNO, "%s (%s@%s) is now operator (%c) as %s",
200 diff -r a771a07b5020 ircd/m_remotemode.c
201 --- a/ircd/m_remotemode.c Sat Jul 20 14:54:11 2013 +0100
202 +++ b/ircd/m_remotemode.c Sat Jul 20 14:54:45 2013 +0100
205 int do_host_hiding = 0;
209 /* not from a server */
211 @@ -216,17 +217,15 @@
214 if (what == MODE_ADD) {
215 - if (*(p + 1) && is_hostmask(*(p + 1))) {
220 - protocol_violation(sptr, "Received REMOTEMODE +h without host parameter for user %C", acptr);
222 - protocol_violation(sptr, "Received REMOTEMODE +h with invalid host parameter %s for user %C", *(p+1), acptr);
223 - p++; /* Swallow the arg anyway */
227 + if (IsServer(cptr)) {
229 + protocol_violation(cptr, "Received MODE +h for %C without sethost parameter", sptr);
235 } else { /* MODE_DEL */
238 @@ -275,10 +274,12 @@
241 /* check if new sethost is different from before */
242 - if (IsSetHost(acptr) &&
243 - (!user || strcmp(cli_user(acptr)->username, user) == 0) &&
244 - strcmp(cli_user(acptr)->host, host) == 0)
246 + if (IsSetHost(acptr)) {
248 + if ((!user || strcmp(cli_user(acptr)->username, user) == 0) &&
249 + strcmp(cli_user(acptr)->host, host) == 0)
254 /* do host hiding for +h/-h */
256 assert(UserStats.inv_clients <= UserStats.clients + UserStats.unknowns);
258 /* send out the mode */
259 - send_umode_out(acptr, acptr, &setflags, 0);
260 + send_umode_out(acptr, acptr, &setflags, 0, alreadyh);
264 diff -r a771a07b5020 ircd/m_sethost.c
265 --- a/ircd/m_sethost.c Sat Jul 20 14:54:11 2013 +0100
266 +++ b/ircd/m_sethost.c Sat Jul 20 14:54:45 2013 +0100
267 @@ -82,175 +82,233 @@
271 +#include "ircd_features.h"
272 +#include "ircd_log.h"
273 #include "ircd_reply.h"
274 #include "ircd_string.h"
275 #include "ircd_snprintf.h"
276 -#include "ircd_features.h"
281 +#include "s_debug.h"
283 -#include "s_debug.h"
286 #include "numnicks.h"
288 -#include "channel.h"
296 * m_sethost - generic message handler
298 - * mimic old lain syntax:
299 + * SETHOST [<user>@]<host> [<password>]
301 - * (Oper) /SETHOST ident host.cc [quit-message]
302 - * (User) /SETHOST host.cc password
303 - * (Both) /SETHOST undo
304 + * parv[0] = sender prefix
305 + * parv[1] = [user@]host
306 + * parv[2] = password
308 - * check for undo, prepend parv w. <nick> -h or +h
309 + * "MODE <nick> -h" to remove sethost
312 int m_sethost(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
314 - char hostmask[USERLEN + HOSTLEN + 2];
315 - char curhostmask[USERLEN + HOSTLEN + 2];
321 + char *password = NULL;
322 + struct Flags setflags;
323 + struct sline *sconf;
325 - struct Flags setflags;
327 + if (!feature_bool(FEAT_SETHOST))
328 + return send_reply(sptr, ERR_DISABLED, "SETHOST");
330 - /* Back up the flags first */
331 + /* disabled for ordinary users */
332 + if (!IsAnOper(sptr) && !feature_bool(FEAT_SETHOST_USER))
333 + return send_reply(sptr, ERR_NOPRIVILEGES);
335 + /* need hostmask parameter
336 + * and need password parameter from an ordinary user
338 + if (parc < 2 || *parv[1] == 0 || (parc < 3 && !IsAnOper(sptr)))
339 + return need_more_params(sptr, "SETHOST");
341 + hostmask = parv[1];
343 + /* get user and host */
344 + if ((host = strrchr(hostmask, '@'))) {
351 + /* got a pasword and not empty */
352 + if (parc > 2 && *parv[2])
353 + password = parv[2];
355 + /* freeform - do not bother with password */
356 + if (IsAnOper(sptr) && HasPriv(sptr, PRIV_FREEFORM)) {
361 + /* check if user and host are valid */
362 + if (!is_validsethost(user, host))
363 + return send_reply(sptr, ERR_BADHOSTMASK, user ? user : "", user ? "@" : "", host);
368 + /* find the spoof block */
369 + if (!(sconf = find_spoofblock(sptr, host, password)))
370 + return send_reply(sptr, ERR_HOSTUNAVAIL, user ? user : "", user ? "@" : "", host);
372 + host = (char *)sconf->spoofhost;
374 + /* only freeform allowed to specify user */
379 setflags = cli_flags(sptr);
382 - return need_more_params(sptr, "SETHOST");
383 + /* already +h, clear flag to force mode +h to be sent out again, and clear remote sethost flag */
384 + if (IsSetHost(sptr)) {
385 + FlagClr(&setflags, FLAG_SETHOST);
387 + ClearRemoteSetHost(sptr);
390 - if (0 == ircd_strcmp("undo", parv[1])) {
391 - set_hostmask(sptr, NULL, NULL);
394 - return need_more_params(sptr, "SETHOST");
395 - if (IsAnOper(sptr)) {
396 - ircd_snprintf(0, hostmask, USERLEN + HOSTLEN + 2, "%s@%s", parv[1], parv[2]);
397 - if (!is_hostmask(hostmask)) {
398 - send_reply(sptr, ERR_BADHOSTMASK, hostmask);
401 - if (IsSetHost(sptr) || IsAccount(sptr)) {
402 - ircd_snprintf(0, curhostmask, USERLEN + HOSTLEN + 2, "%s@%s", sptr->cli_user->username, sptr->cli_user->host);
403 - if (0 == strcmp(hostmask, curhostmask)) {
404 - send_reply(sptr, RPL_HOSTHIDDEN, curhostmask);
408 - if (set_hostmask(sptr, hostmask, NULL))
409 - FlagClr(&setflags, FLAG_SETHOST);
411 - if (!is_hostmask(parv[1])) {
412 - send_reply(sptr, ERR_BADHOSTMASK, parv[1]);
415 - if (IsSetHost(sptr) || IsAccount(sptr)) {
416 - if (0 == strcmp(parv[1], sptr->cli_user->host)) {
417 - send_reply(sptr, RPL_HOSTHIDDEN, parv[1]);
421 - if (set_hostmask(sptr, parv[1], parv[2]))
422 - FlagClr(&setflags, FLAG_SETHOST);
425 + /* check if new sethost is different from before */
426 + if (IsSetHost(sptr) &&
427 + (!user || strcmp(cli_user(sptr)->username, user) == 0) &&
428 + strcmp(cli_user(sptr)->host, host) == 0)
429 + return send_reply(sptr, RPL_HOSTHIDDEN, user ? user : "", user ? "@" : "", host);
431 - send_umode_out(cptr, sptr, &setflags, 0);
433 + set_hostmask(sptr, user, host);
438 + sendto_opmask_butone(0, SNO_OLDSNO,
439 + "%C SETHOST %s%s%s (freeform)", sptr,
440 + user ? user : "", user ? "@" : "", host);
442 + log_write(LS_SETHOST, L_NOTICE, LOG_NOSNOTICE,
443 + "%s SETHOST %s%s%s (freeform)", get_client_name(sptr, SHOW_IP),
444 + user ? user : "", user ? "@" : "", host);
447 + /* send the mode out */
448 + send_umode_out(cptr, sptr, &setflags, 0, alreadyh);
457 * ms_sethost - sethost server message handler
459 * parv[0] = sender prefix
460 * parv[1] = target user numeric
461 - * parv[2] = target user's new ident
462 - * parv[3] = target user's new host
463 + * parv[2] = spoof username
464 + * parv[3] = spoof host
466 + * undo sethost when spoof username and host are 0
469 + /* TODO: IsRemoteSetHost() */
470 int ms_sethost(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
472 - struct Client *target;
473 - char hostmask[USERLEN + HOSTLEN + 2];
474 - struct Membership *chan;
479 + struct Client *acptr;
480 struct Flags setflags;
482 + /* not from a server */
483 + if (!IsServer(sptr))
484 + return protocol_violation(cptr, "Received SETHOST from user %C", sptr);
486 + /* check paramaters */
488 - return need_more_params(sptr, "SETHOST");
489 + return protocol_violation(cptr, "Received too few parameters for SETHOST from %C (got %d - need 4)", sptr, parc);
491 - if (!IsServer(sptr))
492 - return protocol_violation(cptr, "SETHOST from non-server %s",
498 - /* Locate our target user; ignore the message if we can't */
499 - if(!(target = findNUser(parv[1])))
501 + if(!(acptr = findNUser(target)))
504 - /* Fake host assignments must be from services */
505 - if (!find_conf_byhost(cli_confs(sptr), cli_name(sptr), CONF_UWORLD))
506 - return protocol_violation(cptr, "Non-U:lined server %s set fake host on user %s", cli_name(sptr), cli_name(target));
508 - if (!MyConnect(target)) {
509 - sendcmdto_one(sptr, CMD_SETHOST, cli_user(target)->server, "%C %s %s", target,
511 + /* not for my user, pass it along */
512 + if (!MyConnect(acptr)) {
513 + sendcmdto_one(sptr, CMD_SETHOST, acptr, "%C %s %s", acptr, user, host);
517 - /* Back up the flags first */
518 - setflags = cli_flags(target);
519 - FlagClr(&setflags, FLAG_SETHOST);
521 + setflags = cli_flags(acptr);
523 - if (IsSetHost(target) || IsAccount(target)) {
524 - if ((0 == strcmp(parv[2], target->cli_user->username)) && (0 == strcmp(parv[3], target->cli_user->host)))
525 + /* check user and host are valid */
526 + if (!is_validsethost(user, host))
527 + return protocol_violation(cptr,
528 + "Received SETHOST for %C with invalid user host '%s %s' from %C",
529 + acptr, user, host, sptr);
531 + /* 'user host' is '0 0' - undo sethost */
532 + if (user[0] == '0' && user[1] == '\0' &&
533 + host[0] == '0' && host[1] == '\0') {
535 + /* user has no sethost or has no account
537 + * user has +h - their host is hidden, do not remove it
538 + * unless the user has an account set
539 + * we should not out of the blue expose the real host
541 + if (!IsSetHost(acptr) || !IsAccount(acptr))
544 + /* user not +x and not allowed to set it */
545 + if (!IsHiddenHost(acptr) && !feature_bool(FEAT_HOST_HIDING))
549 + SetHiddenHost(acptr);
554 - ircd_snprintf(0, hostmask, USERLEN + HOSTLEN + 2, "%s@%s", parv[2], parv[3]);
555 - if (!is_hostmask(hostmask))
556 - return protocol_violation(cptr, "Bad Host mask %s for user %s", hostmask, cli_name(target));
557 + /* check if new sethost is different from before */
558 + else if (IsSetHost(acptr) &&
559 + strcmp(cli_user(acptr)->username, user) == 0 &&
560 + strcmp(cli_user(acptr)->host, host) == 0)
563 - sendcmdto_common_channels_butone(target, CMD_QUIT, target, ":Host change");
565 - /* Assign and propagate the fakehost */
566 - SetSetHost(target);
567 - ircd_strncpy(cli_user(target)->username, parv[2], USERLEN);
568 - ircd_strncpy(cli_user(target)->host, parv[3], HOSTLEN);
570 - send_reply(target, RPL_HOSTHIDDEN, hostmask);
573 - * Go through all channels the client was on, rejoin him
574 - * and set the modes, if any
576 - for (chan = cli_user(target)->channel; chan; chan = chan->next_channel) {
577 - if (IsZombie(chan))
579 - /* If this channel has delayed joins and the user has no modes, just set
580 - * the delayed join flag rather than showing the join, even if the user
581 - * was visible before */
582 - if (!IsChanOp(chan) && !HasVoice(chan)
583 - && (chan->channel->mode.mode & MODE_DELJOINS)) {
584 - SetDelayedJoin(chan);
586 - sendcmdto_channel_butserv_butone(target, CMD_JOIN, chan->channel, target, 0,
587 - "%H", chan->channel);
589 - if (IsChanOp(chan) && HasVoice(chan)) {
590 - sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, target, 0,
591 - "%H +ov %C %C", chan->channel, target, target);
592 - } else if (IsChanOp(chan) || HasVoice(chan)) {
593 - sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, target, 0,
594 - "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', target);
596 + /* already +h, clear flag to force mode +h to be sent out again */
597 + else if (IsSetHost(acptr)) {
598 + FlagClr(&setflags, FLAG_SETHOST);
602 - send_umode_out(target, target, &setflags, 0);
603 + /* setting remote sethost, set flag */
605 + SetRemoteSetHost(acptr);
608 + set_hostmask(acptr, user, host);
610 + /* send out the mode */
611 + send_umode_out(acptr, acptr, &setflags, 0, alreadyh);
616 diff -r a771a07b5020 ircd/m_userhost.c
617 --- a/ircd/m_userhost.c Sat Jul 20 14:54:11 2013 +0100
618 +++ b/ircd/m_userhost.c Sat Jul 20 14:54:45 2013 +0100
620 * of +x. If an oper wants the real host, he should go to
623 - (HasHiddenHost(cptr) || HasSetHost(cptr)) && (sptr != cptr) ?
624 + (HasHiddenHost(cptr) || IsSetHost(cptr)) && (sptr != cptr) ?
625 cli_user(cptr)->host : cli_user(cptr)->realhost);
628 diff -r a771a07b5020 ircd/m_userip.c
629 --- a/ircd/m_userip.c Sat Jul 20 14:54:11 2013 +0100
630 +++ b/ircd/m_userip.c Sat Jul 20 14:54:45 2013 +0100
632 * of +x. If an oper wants the real IP, he should go to
635 - ((HasHiddenHost(cptr) || HasSetHost(cptr) || feature_bool(FEAT_HIS_USERIP)) && (sptr != cptr)) ?
636 + ((HasHiddenHost(cptr) || IsSetHost(cptr) || feature_bool(FEAT_HIS_USERIP)) && (sptr != cptr)) ?
637 feature_str(FEAT_HIDDEN_IP) :
638 ircd_ntoa(&cli_ip(cptr)));
640 diff -r a771a07b5020 ircd/m_who.c
641 --- a/ircd/m_who.c Sat Jul 20 14:54:11 2013 +0100
642 +++ b/ircd/m_who.c Sat Jul 20 14:54:45 2013 +0100
643 @@ -395,14 +395,14 @@
644 && ((!(matchsel & WHO_FIELD_HOS))
645 || matchexec(cli_user(acptr)->host, mymask, minlen))
646 && ((!(matchsel & WHO_FIELD_HOS))
647 - || !HasSetHost(acptr)
648 + || !IsSetHost(acptr)
649 || !HasHiddenHost(acptr)
651 || matchexec(cli_user(acptr)->realhost, mymask, minlen))
652 && ((!(matchsel & WHO_FIELD_REN))
653 || matchexec(cli_info(acptr), mymask, minlen))
654 && ((!(matchsel & WHO_FIELD_NIP))
655 - || ((HasHiddenHost(acptr) || HasSetHost(acptr)) && !IsAnOper(sptr))
656 + || ((HasHiddenHost(acptr) || IsSetHost(acptr)) && !IsAnOper(sptr))
657 || !ipmask_check(&cli_ip(acptr), &imask, ibits))
658 && ((!(matchsel & WHO_FIELD_ACC))
659 || matchexec(cli_user(acptr)->account, mymask, minlen)))
660 @@ -434,14 +434,14 @@
661 && ((!(matchsel & WHO_FIELD_HOS))
662 || matchexec(cli_user(acptr)->host, mymask, minlen))
663 && ((!(matchsel & WHO_FIELD_HOS))
664 - || !HasSetHost(acptr)
665 + || !IsSetHost(acptr)
666 || !HasHiddenHost(acptr)
668 || matchexec(cli_user(acptr)->realhost, mymask, minlen))
669 && ((!(matchsel & WHO_FIELD_REN))
670 || matchexec(cli_info(acptr), mymask, minlen))
671 && ((!(matchsel & WHO_FIELD_NIP))
672 - || ((HasHiddenHost(acptr) || HasSetHost(acptr)) && !IsAnOper(sptr))
673 + || ((HasHiddenHost(acptr) || IsSetHost(acptr)) && !IsAnOper(sptr))
674 || !ipmask_check(&cli_ip(acptr), &imask, ibits))
675 && ((!(matchsel & WHO_FIELD_ACC))
676 || matchexec(cli_user(acptr)->account, mymask, minlen)))
677 diff -r a771a07b5020 ircd/m_whois.c
678 --- a/ircd/m_whois.c Sat Jul 20 14:54:11 2013 +0100
679 +++ b/ircd/m_whois.c Sat Jul 20 14:54:45 2013 +0100
681 if (IsAccount(acptr))
682 send_reply(sptr, RPL_WHOISACCOUNT, name, user->account);
684 - if ((HasHiddenHost(acptr) || HasSetHost(acptr)) && ((IsAnOper(sptr) && HasPriv(sptr, PRIV_USER_PRIVACY)) || acptr == sptr))
685 + if ((HasHiddenHost(acptr) || IsSetHost(acptr)) && ((IsAnOper(sptr) && HasPriv(sptr, PRIV_USER_PRIVACY)) || acptr == sptr))
686 send_reply(sptr, RPL_WHOISACTUALLY, name, user->realusername,
687 user->realhost, ircd_ntoa(&cli_ip(acptr)));
689 diff -r a771a07b5020 ircd/s_conf.c
690 --- a/ircd/s_conf.c Sat Jul 20 14:54:11 2013 +0100
691 +++ b/ircd/s_conf.c Sat Jul 20 14:54:45 2013 +0100
700 @@ -1204,6 +1205,10 @@
705 + * clear spoof blocks
708 void clear_slines(void)
711 @@ -1220,61 +1225,164 @@
716 - * conf_check_slines()
720 - * Check S lines for the specified client, passed in cptr struct.
721 - * If the client's IP is S-lined, process the substitution here.
722 + * Find matching spoof block for a user for the given spoofhost and password
726 + * @param cptr User wanting to get a spoof host.
727 + * @param host Spoof host to look for.
728 + * @param password Password given by user (can be NULL).
731 - * 0 = No S-line found
732 - * 1 = S-line found and substitution done.
736 + * @return pointer to the matching spoofblock is found, else NULL
739 +struct sline *find_spoofblock(struct Client *cptr, char *host, char *password) {
742 -conf_check_slines(struct Client *cptr)
750 + Debug((DEBUG_INFO, "find_spoofblock() cptr=%C host=%s password=%s",
751 + cptr, host, password));
753 for (sconf = GlobalSList; sconf; sconf = sconf->next) {
755 + /* check result of previous loop */
759 + /* check spoofhost */
760 + if (strcasecmp(sconf->spoofhost, host) != 0)
764 + /* check cptr's host */
766 if (sconf->flags == SLINE_FLAGS_IP) {
767 if (!ipmask_check(&(cli_ip(cptr)), &(sconf->address), sconf->bits))
769 - } else if (sconf->flags == SLINE_FLAGS_HOSTNAME) {
770 - if ((match(sconf->realhost, cli_sockhost(cptr)) != 0) &&
771 - (match(sconf->realhost, cli_sock_ip(cptr)) != 0)) /* wildcarded IP address */
777 + else if (sconf->flags == SLINE_FLAGS_HOSTNAME) {
778 + if ((match(sconf->realhost, cli_sockhost(cptr)) != 0) &&
779 + (match(sconf->realhost, cli_sock_ip(cptr)) != 0)) /* wildcarded IP address */
783 - if (match(sconf->username, cli_user(cptr)->username) == 0) {
784 - /* Ignore user part if u@h. */
785 - if ((hostonly = strchr(sconf->spoofhost, '@')))
788 - hostonly = sconf->spoofhost;
789 + /* not cidr or hostname.. */
795 + /* check cptr's username */
796 + if (!EmptyString(sconf->username) && match(sconf->username, cli_user(cptr)->realusername) != 0)
800 + /* check password */
801 + if (!EmptyString(password)) {
802 + if (EmptyString(sconf->passwd) || strcmp(sconf->passwd, password) != 0)
806 + /* no password, but need one for this spoofblock */
807 + else if (!EmptyString(sconf->passwd))
811 + log_write(LS_SETHOST, L_INFO, 0, "%s SETHOST %s (ok) [password: %s]",
812 + get_client_name(cptr, SHOW_IP), sconf->spoofhost,
813 + password ? "yes" : "no");
817 + /* set error messages */
820 + error = "no such Spoof block";
823 + error = "IP / host mismatch";
826 + error = "username mismatch";
829 + error = password ? "password mismatch" : "password required";
832 + error = "unknown failure";
835 + /* TODO: lookup LOG stuff */
836 + /* TODO: L_INFO LOG_NOSNOTICE */
837 + /* log best result we got */
838 + log_write(LS_SETHOST, L_INFO, 0, "%s SETHOST %s (failed: %s) [password: %s]",
839 + get_client_name(cptr, SHOW_IP), host,
840 + error, password ? "yes" : "no");
847 + * @param cptr User to apply Spoof block to on connect
849 + * @return 1 for success, else 0
853 +apply_spoofblock(struct Client *cptr)
855 + struct sline *sconf;
858 + if(!feature_bool(FEAT_SETHOST_AUTO))
861 + /* go over spoof blocks */
862 + for (sconf = GlobalSList; sconf; sconf = sconf->next) {
865 + if (sconf->flags == SLINE_FLAGS_IP) {
866 + if (!ipmask_check(&(cli_ip(cptr)), &(sconf->address), sconf->bits))
869 - ircd_strncpy(cli_user(cptr)->host, hostonly, HOSTLEN);
870 - log_write(LS_USER, L_INFO, LOG_NOSNOTICE, "S-Line (%s@%s) by (%#R)",
871 - cli_user(cptr)->username, hostonly, cptr);
875 + } else if (sconf->flags == SLINE_FLAGS_HOSTNAME) {
876 + if ((match(sconf->realhost, cli_sockhost(cptr)) != 0) &&
877 + (match(sconf->realhost, cli_sock_ip(cptr)) != 0)) /* wildcarded IP address */
882 + /* check username */
883 + if (match(sconf->username, cli_user(cptr)->realusername) != 0)
887 + if (!is_validsethost(NULL, sconf->spoofhost))
891 + set_hostmask(cptr, NULL, sconf->spoofhost);
893 + /* TODO: LOG_NOSNOTICE */
895 + log_write(LS_USER, L_INFO, 0, "%s SETHOST %s (auto)",
896 + get_client_name(cptr, SHOW_IP), sconf->spoofhost);
903 + * free a spoofblock
906 void free_spoofhost(struct sline *spoof) {
907 MyFree(spoof->spoofhost);
908 MyFree(spoof->passwd);
909 diff -r a771a07b5020 ircd/s_err.c
910 --- a/ircd/s_err.c Sat Jul 20 14:54:11 2013 +0100
911 +++ b/ircd/s_err.c Sat Jul 20 14:54:45 2013 +0100
912 @@ -824,13 +824,13 @@
916 - { RPL_HOSTHIDDEN, "%s :is now your hidden host", "396" },
917 + { RPL_HOSTHIDDEN, "%s%s%s :is now your hidden host", "396" },
921 - { RPL_STATSSLINE, "%d %s %s %s %s", "398" },
922 + { RPL_STATSSLINE, "%c %s %s %s%s%s", "398" },
924 - { RPL_USINGSLINE, ":Using S-line privilege", "399" },
929 @@ -1092,9 +1092,9 @@
933 - { ERR_BADHOSTMASK, "%s :Invalid username/hostmask", "530" },
934 + { ERR_BADHOSTMASK, "%s%s%s :Invalid username/hostmask", "530" },
936 - { ERR_HOSTUNAVAIL, "%s :sethost not found", "531" },
937 + { ERR_HOSTUNAVAIL, "%s%s%s :Sethost not found", "531" },
941 diff -r a771a07b5020 ircd/s_stats.c
942 --- a/ircd/s_stats.c Sat Jul 20 14:54:11 2013 +0100
943 +++ b/ircd/s_stats.c Sat Jul 20 14:54:45 2013 +0100
944 @@ -400,41 +400,37 @@
949 +/** List spoof blocks.
950 + * @param[in] to Client requesting statistics.
951 + * @param[in] sd Stats descriptor for request (ignored).
952 + * @param[in] param Filter for spoofhost names.
955 stats_sline(struct Client* to, const struct StatDesc* sd, char* param)
961 - send_reply(to, SND_EXPLICIT | RPL_TEXT, "# Type Spoofhost Realhost Ident");
962 + send_reply(to, SND_EXPLICIT | RPL_TEXT, "S Type Spoofhost Hostmask");
964 - send_reply(to, SND_EXPLICIT | RPL_TEXT, "# Type Spoofhost");
965 + send_reply(to, SND_EXPLICIT | RPL_TEXT, "S Type Spoofhost");
967 for (sline = GlobalSList; sline; sline = sline->next) {
968 - if (param && match(param, sline->spoofhost)) { /* narrow search */
972 - if (!EmptyString(sline->passwd))
975 + if (param && match(param, sline->spoofhost))
979 - if (IsAnOper(to)) {
980 - send_reply(to, RPL_STATSSLINE, (param) ? y : i,
981 - (EmptyString(sline->passwd)) ? "oper" : "user",
983 - (EmptyString(sline->realhost)) ? "" : sline->realhost,
984 - (EmptyString(sline->username)) ? "" : sline->username);
987 - if (!EmptyString(sline->passwd)) {
988 - send_reply(to, RPL_STATSSLINE, (param) ? y : i, "user", sline->spoofhost,
994 + send_reply(to, RPL_STATSSLINE,
995 + is_validsethost(NULL, sline->spoofhost) ? 'S' : 's', /* valid show S else s */
996 + (EmptyString(sline->passwd)) ? "Oper" : "User",
998 + (EmptyString(sline->username)) ? "" : sline->username,
999 + (!EmptyString(sline->username)) ? "@" : "", /* always place a @ after the username */
1000 + (EmptyString(sline->realhost)) ? "" : sline->realhost);
1001 + else if (!EmptyString(sline->passwd) && is_validsethost(NULL, sline->spoofhost))
1002 + send_reply(to, RPL_STATSSLINE, 'S', "User", sline->spoofhost, "", "", "");
1006 diff -r a771a07b5020 ircd/s_user.c
1007 --- a/ircd/s_user.c Sat Jul 20 14:54:11 2013 +0100
1008 +++ b/ircd/s_user.c Sat Jul 20 14:54:45 2013 +0100
1011 #include <sys/stat.h>
1013 -static char *IsVhost(char *hostmask, int oper);
1014 -static char *IsVhostPass(char *hostmask);
1016 /** Count of allocated User structures. */
1017 static int userCount = 0;
1019 @@ -373,13 +370,6 @@
1021 if (feature_bool(FEAT_AUTOINVISIBLE))
1024 - if(feature_bool(FEAT_SETHOST_AUTO)) {
1025 - if (conf_check_slines(sptr)) {
1026 - send_reply(sptr, RPL_USINGSLINE);
1032 cli_handler(sptr) = CLIENT_HANDLER;
1033 @@ -411,6 +401,10 @@
1034 cli_info(sptr), NumNick(cptr) /* two %s's */);
1036 IPcheck_connect_succeeded(sptr);
1039 + /* apply auto sethost if needed */
1040 + apply_spoofblock(sptr);
1043 struct Client *acptr = user->server;
1046 FlagClr(&flags, FLAG_ACCOUNT);
1047 client_set_privs(sptr, NULL);
1048 - send_umode(cptr, sptr, &flags, ALL_UMODES, 0);
1049 + send_umode(cptr, sptr, &flags, ALL_UMODES, 0, 0);
1050 if ((cli_snomask(sptr) != SNO_DEFAULT) && HasFlag(sptr, FLAG_SERVNOTICE))
1051 send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr));
1053 @@ -874,14 +868,15 @@
1054 * @param[in] sptr Client who sent us the mode change message.
1055 * @param[in] old Prior set of user flags.
1056 * @param[in] prop If non-zero, also include FLAG_OPER.
1057 + * @param[in] alreadyh Client is already +h, do not show +h change
1059 void send_umode_out(struct Client *cptr, struct Client *sptr,
1060 - struct Flags *old, int prop)
1061 + struct Flags *old, int prop, int alreadyh)
1064 struct Client *acptr;
1066 - send_umode(NULL, sptr, old, prop ? SEND_UMODES : SEND_UMODES_BUT_OPER, 0);
1067 + send_umode(NULL, sptr, old, prop ? SEND_UMODES : SEND_UMODES_BUT_OPER, 0, 0);
1069 for (i = HighestFd; i >= 0; i--)
1072 sendcmdto_one(sptr, CMD_MODE, acptr, "%s %s", cli_name(sptr), umodeBuf);
1075 - send_umode(NULL, sptr, old, prop ? SEND_UMODES : SEND_UMODES_BUT_OPER, 1);
1076 + send_umode(NULL, sptr, old, prop ? SEND_UMODES : SEND_UMODES_BUT_OPER, 1, 0);
1078 for (i = HighestFd; i >= 0; i--)
1083 if (cptr && MyUser(cptr))
1084 - send_umode(cptr, sptr, old, ALL_UMODES, 0);
1085 + send_umode(cptr, sptr, old, ALL_UMODES, 0, alreadyh);
1092 SetFlag(cptr, flag);
1093 - if (!HasFlag(cptr, FLAG_HIDDENHOST) || !HasFlag(cptr, FLAG_ACCOUNT) || HasSetHost(cptr))
1094 + if (!HasFlag(cptr, FLAG_HIDDENHOST) || !HasFlag(cptr, FLAG_ACCOUNT) || IsSetHost(cptr))
1097 sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Registered");
1100 /* ok, the client is now fully hidden, so let them know -- hikari */
1101 if (MyConnect(cptr))
1102 - send_reply(cptr, RPL_HOSTHIDDEN, cli_user(cptr)->host);
1103 + send_reply(cptr, RPL_HOSTHIDDEN, "", "", cli_user(cptr)->host);
1106 * Go through all channels the client was on, rejoin him
1107 @@ -999,201 +994,104 @@
1113 * set_hostmask() - derived from hide_hostmask()
1116 -int set_hostmask(struct Client *cptr, char *hostmask, char *password)
1117 +int set_hostmask(struct Client *cptr, char *user, char *host)
1121 - char *host, *new_vhost, *vhost_pass;
1122 - char hiddenhost[USERLEN + HOSTLEN + 2];
1124 + int userchange = 0;
1125 + char *msg = "Host change";
1126 struct Membership *chan;
1128 - Debug((DEBUG_INFO, "set_hostmask() %C, %s, %s", cptr, hostmask, password));
1129 + assert(0 != cptr);
1131 - /* sethost enabled? */
1132 - if (MyConnect(cptr) && !feature_bool(FEAT_SETHOST)) {
1133 - send_reply(cptr, ERR_DISABLED, "SETHOST");
1134 + Debug((DEBUG_INFO, "set_hostmask() cptr=%C user=%s host=%s",
1135 + cptr, user ? user : "<null>", host ? host : "<null>"));
1137 + /* remove sethost, but user has none */
1138 + if (!host && !IsSetHost(cptr))
1141 + /* remove sethost, user has +x host, realusername and username are the same
1142 + * pretend the user just set +x
1144 + if (!host && HasHiddenHost(cptr) &&
1145 + strcmp(cli_user(cptr)->username, cli_user(cptr)->realusername) == 0)
1146 + msg = "Registered";
1149 + sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":%s", msg);
1151 + /* remove sethost */
1155 + ClearSetHost(cptr);
1156 + ClearRemoteSetHost(cptr);
1158 + /* restore user and host */
1159 + if (HasHiddenHost(cptr))
1160 + ircd_snprintf(0, cli_user(cptr)->host, HOSTLEN, "%s.%s",
1161 + cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
1163 + strncpy(cli_user(cptr)->host, cli_user(cptr)->realhost, HOSTLEN);
1164 + if (MyConnect(cptr) && strcmp(cli_user(cptr)->username, cli_user(cptr)->realusername) != 0)
1166 + strncpy(cli_user(cptr)->username, cli_user(cptr)->realusername, USERLEN);
1169 - /* sethost enabled for users? */
1170 - if (MyConnect(cptr) && !IsAnOper(cptr) && !feature_bool(FEAT_SETHOST_USER)) {
1171 - send_reply(cptr, ERR_NOPRIVILEGES);
1175 - /* MODE_DEL: restore original hostmask */
1176 - if (EmptyString(hostmask)) {
1177 - /* is already sethost'ed? and only opers can remove a sethost */
1178 - if (IsSetHost(cptr) && IsAnOper(cptr)) {
1180 - sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
1181 - /* If they are +rx, we need to return to their +x host, not their "real" host */
1182 - if (HasHiddenHost(cptr))
1183 - ircd_snprintf(0, cli_user(cptr)->host, HOSTLEN, "%s.%s",
1184 - cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
1186 - strncpy(cli_user(cptr)->host, cli_user(cptr)->realhost, HOSTLEN);
1187 - strncpy(cli_user(cptr)->username, cli_user(cptr)->realusername, USERLEN);
1189 - if (MyConnect(cptr))
1190 - log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE,
1191 - "SETHOST (%s@%s) by (%#R): restoring real hostmask",
1192 - cli_user(cptr)->username, cli_user(cptr)->host, cptr);
1195 - /* MODE_ADD: set a new hostmask */
1197 - /* chop up ident and host.cc */
1198 - if ((host = strrchr(hostmask, '@'))) { /* oper can specifiy ident@host.cc */
1200 - if ( MyConnect(cptr) && (0 == strcmp(host, cli_user(cptr)->host)) && (0 == strcmp(hostmask, cli_user(cptr)->username))) {
1201 - ircd_snprintf(0, hiddenhost, HOSTLEN + USERLEN + 2, "%s@%s",
1202 - cli_user(cptr)->username, cli_user(cptr)->host);
1203 - send_reply(cptr, RPL_HOSTHIDDEN, hiddenhost);
1206 - } else { /* user can only specifiy host.cc [password] */
1208 - if ( MyConnect(cptr) && (0 == strcmp(host, cli_user(cptr)->host))) {
1209 - ircd_snprintf(0, hiddenhost, HOSTLEN + USERLEN + 2, "%s@%s",
1210 - cli_user(cptr)->username, cli_user(cptr)->host);
1211 - send_reply(cptr, RPL_HOSTHIDDEN, hiddenhost);
1218 - if (MyConnect(cptr)) {
1219 - if (IsAnOper(cptr)) {
1220 - if ((new_vhost = IsVhost(host, 1)) == NULL) {
1221 - if (!HasPriv(cptr, PRIV_FREEFORM)) {
1222 - send_reply(cptr, ERR_HOSTUNAVAIL, hostmask);
1223 - log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE,
1224 - "SETHOST (%s@%s) by (%#R): no such s-line",
1225 - (host != hostmask) ? hostmask : cli_user(cptr)->username, host, cptr);
1227 - } else /* freeform active, log and go */
1230 - sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
1231 - /* set the new ident and host */
1232 - if (host != hostmask) /* oper only specified host.cc */
1233 - strncpy(cli_user(cptr)->username, hostmask, USERLEN);
1234 - strncpy(cli_user(cptr)->host, host, HOSTLEN);
1236 - log_write(LS_SETHOST, (freeform) ? L_NOTICE : L_INFO,
1237 - (freeform) ? 0 : LOG_NOSNOTICE, "SETHOST (%s@%s) by (%#R)%s",
1238 - cli_user(cptr)->username, cli_user(cptr)->host, cptr,
1239 - (freeform) ? ": using freeform" : "");
1241 - * plain user sethost, handled here
1244 - /* empty password? */
1245 - if (EmptyString(password)) {
1246 - send_reply(cptr, ERR_NEEDMOREPARAMS, "MODE");
1249 - /* no such s-line */
1250 - if ((new_vhost = IsVhost(host, 0)) == NULL) {
1251 - send_reply(cptr, ERR_HOSTUNAVAIL, hostmask);
1252 - log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE, "SETHOST (%s@%s %s) by (%#R): no such s-line",
1253 - cli_user(cptr)->username, host, password, cptr);
1257 - if ((vhost_pass = IsVhostPass(new_vhost)) == NULL) {
1258 - send_reply(cptr, ERR_PASSWDMISMATCH);
1259 - log_write(LS_SETHOST, L_INFO, 0, "SETHOST (%s@%s %s) by (%#R): trying to use an oper s-line",
1260 - cli_user(cptr)->username, host, password, cptr);
1263 - /* incorrect password */
1264 - if (strCasediff(vhost_pass, password)) {
1265 - send_reply(cptr, ERR_PASSWDMISMATCH);
1266 - log_write(LS_SETHOST, L_NOTICE, 0, "SETHOST (%s@%s %s) by (%#R): incorrect password",
1267 - cli_user(cptr)->username, host, password, cptr);
1270 - sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
1271 - /* set the new host */
1272 - strncpy(cli_user(cptr)->host, new_vhost, HOSTLEN);
1274 - log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE, "SETHOST (%s@%s) by (%#R)",
1275 - cli_user(cptr)->username, cli_user(cptr)->host, cptr);
1277 - } else { /* remote user */
1278 - sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
1279 - if (host != hostmask) /* oper only specified host.cc */
1280 - strncpy(cli_user(cptr)->username, hostmask, USERLEN);
1281 - strncpy(cli_user(cptr)->host, host, HOSTLEN);
1283 + /* apply sethost */
1289 + /* update user and host */
1291 + strncpy(cli_user(cptr)->username, user, USERLEN);
1292 + strncpy(cli_user(cptr)->host, host, HOSTLEN);
1296 - ClearSetHost(cptr);
1300 + if (MyConnect(cptr)) {
1302 - if (MyConnect(cptr)) {
1303 - ircd_snprintf(0, hiddenhost, HOSTLEN + USERLEN + 2, "%s@%s",
1304 - cli_user(cptr)->username, cli_user(cptr)->host);
1305 - send_reply(cptr, RPL_HOSTHIDDEN, hiddenhost);
1306 + /* user and host changed */
1307 + if (userchange || strcmp(cli_user(cptr)->username, cli_user(cptr)->realusername) != 0)
1308 + send_reply(cptr, RPL_HOSTHIDDEN, cli_user(cptr)->username, "@", cli_user(cptr)->host);
1310 + /* just host changed */
1312 + send_reply(cptr, RPL_HOSTHIDDEN, "", "", cli_user(cptr)->host);
1316 - /* Code copied from hide_hostmask(). This is the old (pre-delayedjoin)
1317 - * version. Switch this in if you're not using the delayed join patch. */
1319 - * Go through all channels the client was on, rejoin him
1320 - * and set the modes, if any
1322 + /* go over the channels */
1323 for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) {
1325 + /* invalidate bans so they are rechecked */
1326 + ClearBanValid(chan);
1331 - sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr,
1332 - "%H", chan->channel);
1333 - if (IsChanOp(chan) && HasVoice(chan)) {
1334 - sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr,
1335 - "%H +ov %C %C", chan->channel, cptr, cptr);
1336 - } else if (IsChanOp(chan) || HasVoice(chan)) {
1337 - sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr,
1338 - "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr);
1344 - * Go through all channels the client was on, rejoin him
1345 - * and set the modes, if any
1347 - for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) {
1348 - if (IsZombie(chan))
1350 - /* If this channel has delayed joins and the user has no modes, just set
1351 - * the delayed join flag rather than showing the join, even if the user
1352 - * was visible before */
1353 - if (!IsChanOp(chan) && !HasVoice(chan)
1354 - && (chan->channel->mode.mode & MODE_DELJOINS)) {
1355 - SetDelayedJoin(chan);
1357 + /* not delayed join, rejoin user to chan */
1358 + if (!IsDelayedJoin(chan))
1359 sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr, 0,
1360 "%H", chan->channel);
1362 - if (IsChanOp(chan) && HasVoice(chan)) {
1364 + /* restore modes */
1365 + if (IsChanOp(chan) && HasVoice(chan))
1366 sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, cptr, 0,
1367 "%H +ov %C %C", chan->channel, cptr, cptr);
1368 - } else if (IsChanOp(chan) || HasVoice(chan)) {
1369 + else if (IsChanOp(chan) || HasVoice(chan))
1370 sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, cptr, 0,
1371 "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr);
1379 /** Set a user's mode. This function checks that \a cptr is trying to
1380 @@ -1220,15 +1118,17 @@
1381 unsigned int tmpmask = 0;
1382 int snomask_given = 0;
1384 - char *hostmask, *password;
1385 + char *hostmask = NULL;
1387 int do_host_hiding = 0;
1388 int do_set_host = 0;
1392 char* account = NULL;
1393 + char *user = NULL;
1394 + char *host = NULL;
1396 - hostmask = password = NULL;
1400 @@ -1238,8 +1138,7 @@
1401 for (i = 0; i < USERMODELIST_SIZE; i++)
1403 if (HasFlag(sptr, userModeList[i].flag) &&
1404 - ((userModeList[i].flag != FLAG_ACCOUNT) &&
1405 - (userModeList[i].flag != FLAG_SETHOST)))
1406 + userModeList[i].flag != FLAG_ACCOUNT)
1407 *m++ = userModeList[i].c;
1410 @@ -1251,6 +1150,9 @@
1414 + if (IsSetHost(sptr))
1418 * find flags already set for user
1419 * why not just copy them?
1420 @@ -1394,26 +1296,18 @@
1423 if (what == MODE_ADD) {
1424 - if (*(p + 1) && is_hostmask(*(p + 1))) {
1427 - /* DON'T step p onto the trailing NULL in the parameter array! - splidge */
1434 - send_reply(sptr, ERR_NEEDMOREPARAMS, "SETHOST");
1436 + if (IsServer(cptr)) {
1438 + protocol_violation(cptr, "Received MODE +h for %C without sethost parameter", sptr);
1440 - send_reply(sptr, ERR_BADHOSTMASK, *(p+1));
1441 - p++; /* Swallow the arg anyway */
1446 } else { /* MODE_DEL */
1454 @@ -1468,6 +1362,23 @@
1455 if (!FlagHas(&setflags, FLAG_PARANOID) && !(IsOper(sptr) && HasPriv(sptr, PRIV_PARANOID)))
1456 ClearParanoid(sptr);
1460 + if (do_set_host && !hostmask && IsSetHost(sptr)) {
1461 + /* cannot do -h if user has a remote sethost, unless they are an oper */
1462 + if (!FlagHas(&setflags, FLAG_LOCOP) && !FlagHas(&setflags, FLAG_OPER) && IsRemoteSetHost(sptr))
1464 + /* cannot do -h if user has no account set */
1465 + else if (!IsAccount(sptr))
1467 + /* cannot do -h if user does not have +x set and is not allowed to set it */
1468 + else if (!IsHiddenHost(sptr) && !feature_bool(FEAT_HOST_HIDING))
1470 + /* all ok, set user +x */
1472 + SetHiddenHost(sptr);
1476 * only send wallops to opers
1478 @@ -1524,11 +1435,38 @@
1480 if (!FlagHas(&setflags, FLAG_HIDDENHOST) && do_host_hiding && allow_modes != ALLOWMODES_DEFAULT)
1481 hide_hostmask(sptr, FLAG_HIDDENHOST);
1485 - /* We clear the flag in the old mask, so that the +h will be sent */
1486 - /* Only do this if we're SETTING +h and it succeeded */
1487 - if (set_hostmask(sptr, hostmask, password) && hostmask)
1488 - FlagClr(&setflags, FLAG_SETHOST);
1492 + set_hostmask(sptr, NULL, NULL);
1496 + if ((host = strrchr(hostmask, '@'))) {
1503 + /* dont check if sethost from remote users is valid with is_validsethost(),
1504 + * do check that user and host are not emtpy and
1505 + * do check if they start with a : as things go horribly wrong then
1507 + if (*user == 0 || user[0] == ':' || *host == 0 || host[0] == ':')
1508 + protocol_violation(cptr, "Received MODE +h for %C with an invalid user@host '%s@%s'",
1509 + sptr, user ? user : "", host ? host : "");
1513 + /* clear flag in old mask so that +h will be sent again */
1514 + FlagClr(&setflags, FLAG_SETHOST);
1515 + set_hostmask(sptr, user, host);
1520 if (IsRegistered(sptr)) {
1521 @@ -1580,7 +1518,7 @@
1523 assert(UserStats.opers <= UserStats.clients + UserStats.unknowns);
1524 assert(UserStats.inv_clients <= UserStats.clients + UserStats.unknowns);
1525 - send_umode_out(cptr, sptr, &setflags, prop);
1526 + send_umode_out(cptr, sptr, &setflags, prop, alreadyh);
1530 @@ -1655,9 +1593,11 @@
1531 * @param[in] old Pre-change set of modes for \a sptr.
1532 * @param[in] sendset One of ALL_UMODES, SEND_UMODES_BUT_OPER,
1533 * SEND_UMODES, to select which changed user modes to send.
1534 + * @param[in] opernames Include opername parameter.
1535 + * @param[in] alreadyh Client already has +h set, do not show +h change.
1537 void send_umode(struct Client *cptr, struct Client *sptr, struct Flags *old,
1538 - int sendset, int opernames)
1539 + int sendset, int opernames, int alreadyh)
1543 @@ -1700,12 +1640,15 @@
1545 /* Special case for SETHOST.. */
1546 if (flag == FLAG_SETHOST) {
1547 - /* Don't send to users */
1548 - if (cptr && MyUser(cptr))
1551 - /* If we're setting +h, add the parameter later */
1552 - if (!FlagHas(old, flag))
1554 + /* do not show +h if client already had it */
1555 + if (cptr && MyUser(cptr) && IsSetHost(cptr) && alreadyh)
1558 + /* If we're setting +h, add the parameter later,
1559 + * but not when showing to the user
1561 + if (!FlagHas(old, flag) && (!cptr || !MyUser(cptr)))
1564 if (FlagHas(old, flag))
1565 @@ -1744,7 +1687,7 @@
1569 - ircd_snprintf(0, m, USERLEN + HOSTLEN + 1, "%s@%s", cli_user(sptr)->username,
1570 + ircd_snprintf(0, m, USERLEN + HOSTLEN + 2, "%s@%s", cli_user(sptr)->username,
1571 cli_user(sptr)->host);
1574 @@ -1772,108 +1715,53 @@
1579 - * Check to see if it resembles a valid hostmask.
1581 -int is_hostmask(char *word)
1584 + * Check to see if it resembles a valid sethost.
1586 + * @param[in] user Username to check (can be NULL)
1587 + * @param[in] host Hostname to check
1588 + * @return Non-zero if user and host look valid for a sethost
1591 +int is_validsethost(char *user, char *host)
1595 + int i; /* loop variable */
1597 - Debug((DEBUG_INFO, "is_hostmask() %s", word));
1598 + assert(host != NULL);
1600 - if (strlen(word) > (HOSTLEN + USERLEN + 1) || strlen(word) <= 0)
1601 + /* must not be empty, not longer than HOSTLEN, not start with a : */
1602 + if (*host == 0 || strlen(host) > HOSTLEN || host[0] == ':')
1605 - /* if a host is specified, make sure it's valid */
1606 - host = strrchr(word, '@');
1608 - if (strlen(++host) < 1)
1610 - if (strlen(host) > HOSTLEN)
1612 + /* got a user part */
1615 + /* must not be empty, not longer than USERLEN, not start with a : */
1616 + if (*user == 0 || strlen(user) > USERLEN || user[0] == ':')
1619 + /* check user chars
1620 + * use IsSetHostChar instead of IsUserChar
1621 + * as the latter allows a lot more chars
1622 + * we dont want in a sethost
1624 + for (i = 0; user[i]; i++) {
1625 + if (!IsSetHostChar(user[i]))
1631 - if ('@' == *word) /* no leading @'s */
1634 - if ('#' == *word) { /* numeric index given? */
1635 - for (word++; *word; word++) {
1636 - if (!IsDigit(*word))
1642 - /* normal hostmask, account for at most one '@' */
1643 - for (; *word; word++) {
1644 - if ('@' == *word) {
1648 - if (!IsHostChar(*word))
1651 - return (1 < i) ? 0 : 1; /* no more than on '@' */
1657 - * IsVhost() - Check if given host is a valid spoofhost
1658 - * (ie: configured thru a S:line)
1660 -static char *IsVhost(char *hostmask, int oper)
1662 - unsigned int i = 0, y = 0;
1663 - struct sline *sconf;
1665 - Debug((DEBUG_INFO, "IsVhost() %s", hostmask));
1667 - if (EmptyString(hostmask))
1670 - /* spoofhost specified as index, ie: #27 */
1671 - if ('#' == hostmask[0]) {
1672 - y = atoi(hostmask + 1);
1673 - for (i = 0, sconf = GlobalSList; sconf; sconf = sconf->next) {
1674 - if (!oper && EmptyString(sconf->passwd))
1677 - return sconf->spoofhost;
1680 + /* check host chars
1681 + * IsSetHostChar allows -. 0-9 A-Z [\]^_ a-Z {|} ~ and :
1683 + for (i = 0; host[i]; i++) {
1684 + if (!IsSetHostChar(host[i]))
1688 - /* spoofhost specified as host, ie: host.cc */
1689 - for (sconf = GlobalSList; sconf; sconf = sconf->next)
1690 - if (strCasediff(hostmask, sconf->spoofhost) == 0)
1691 - return sconf->spoofhost;
1697 - * IsVhostPass() - Check if given spoofhost has a password
1698 - * associated with it, and if, return the password (cleartext)
1700 -static char *IsVhostPass(char *hostmask)
1702 - struct sline *sconf;
1704 - Debug((DEBUG_INFO, "IsVhostPass() %s", hostmask));
1706 - if (EmptyString(hostmask))
1709 - for (sconf = GlobalSList; sconf; sconf = sconf->next)
1710 - if (strCasediff(hostmask, sconf->spoofhost) == 0) {
1711 - Debug((DEBUG_INFO, "sconf->passwd %s", sconf->passwd));
1712 - return EmptyString(sconf->passwd) ? NULL : sconf->passwd;
1720 /** Update snomask \a oldmask according to \a arg and \a what.
1721 diff -r a771a07b5020 ircd/send.c
1722 --- a/ircd/send.c Sat Jul 20 14:54:11 2013 +0100
1723 +++ b/ircd/send.c Sat Jul 20 14:54:45 2013 +0100
1727 return (match(mask, cli_user(one)->host) == 0 ||
1728 - ((HasHiddenHost(one) || HasSetHost(one)) && match(mask, cli_user(one)->realhost) == 0));
1729 + ((HasHiddenHost(one) || IsSetHost(one)) && match(mask, cli_user(one)->realhost) == 0));
1732 return (match(mask, cli_name(cli_user(one)->server)) == 0);
1733 diff -r a771a07b5020 ircd/whocmds.c
1734 --- a/ircd/whocmds.c Sat Jul 20 14:54:11 2013 +0100
1735 +++ b/ircd/whocmds.c Sat Jul 20 14:54:45 2013 +0100
1738 if (fields & WHO_FIELD_NIP)
1740 - const char* p2 = (HasHiddenHost(acptr) || HasSetHost(acptr) || feature_bool(FEAT_HIS_USERIP)) && (!IsAnOper(sptr) || (IsAnOper(sptr) && !HasPriv(sptr, PRIV_USER_PRIVACY))) ?
1741 + const char* p2 = (HasHiddenHost(acptr) || IsSetHost(acptr) || feature_bool(FEAT_HIS_USERIP)) && (!IsAnOper(sptr) || (IsAnOper(sptr) && !HasPriv(sptr, PRIV_USER_PRIVACY))) ?
1742 feature_str(FEAT_HIDDEN_IP) :
1743 ircd_ntoa(&cli_ip(acptr));
1747 if (SendDebug(acptr))
1749 - if (HasSetHost(acptr))
1750 + if (IsSetHost(acptr))
1753 if (HasHiddenHost(acptr))