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"
21 sethost #N no longer supported (N being the Nth configured spoof block)
23 remote sethost can now be undone by using 0 as username and host,
24 but only when the user has an account set and is allowed by server settings to set mode +x,
25 to avoid revealing the real host out of the blue
27 SETHOST now same as OPER
28 modes h and o can only be set with SETHOST and OPER
29 modes h and o are visible to clients
30 modes h and o can only be unset with MODE <nick> -ho
32 user sethosts are now also checked against their user@host/ip (and not just the password)
34 applying the sethost and syncing of clients (quit user, rejoin user, restore modes on user) is now done in one place
36 remote sethost can come from any server, does not need to have a Uworld block or be a service (ACCOUNT doesnt require that either)
39 show if spoofhost is valid or not (S = valid, s = invalid)
40 removed numbering (not required anymore?)
41 merged showing of user@host
43 diff -r c6f3803ee169 include/client.h
44 --- a/include/client.h
45 +++ b/include/client.h
47 #define FlagClr(set,flag) ((set)->bits[FLAGSET_INDEX(flag)] &= ~FLAGSET_MASK(flag))
49 /** String containing valid user modes, in no particular order. */
50 -#define infousermodes "dioOswkgxRXInP"
51 +#define infousermodes "dioOswkghxRXInP"
53 /** Character to indicate no oper name available */
54 #define NOOPERNAMECHARACTER '-'
56 #define HasHiddenHost(x) (IsHiddenHost(x) && IsAccount(x))
57 /** Return non-zero if the client is using a spoofhost */
58 #define IsSetHost(x) HasFlag(x, FLAG_SETHOST)
59 -#define HasSetHost(x) (IsSetHost(x))
61 /** Mark a client as having an in-progress net.burst. */
62 #define SetBurst(x) SetFlag(x, FLAG_BURST)
63 diff -r c6f3803ee169 include/numeric.h
64 --- a/include/numeric.h
65 +++ b/include/numeric.h
67 /* RPL_NOUSERS 395 Dalnet/EFnet/IRCnet */
68 #define RPL_HOSTHIDDEN 396 /* UMODE +x completed succesfuly */
69 #define RPL_STATSSLINE 398 /* QuakeNet extension -froo */
70 -#define RPL_USINGSLINE 399 /* QuakeNet extension -froo */
71 +/* RPL_USINGSLINE 399 QuakeNet extension -froo */
74 * Errors are in the range from 400-599 currently and are grouped by what
75 diff -r c6f3803ee169 include/s_conf.h
76 --- a/include/s_conf.h
77 +++ b/include/s_conf.h
80 extern void conf_add_sline(const char* const* fields, int count);
81 extern void clear_slines(void);
82 -extern int conf_check_slines(struct Client *cptr);
83 +extern struct sline *find_spoofblock(struct Client *cptr, char *spoofhost, char *password);
84 +extern int apply_spoofblock(struct Client *cptr);
85 extern void free_spoofhost(struct sline *spoof);
87 extern void yyerror(const char *msg);
88 diff -r c6f3803ee169 include/s_user.h
89 --- a/include/s_user.h
90 +++ b/include/s_user.h
92 extern int set_nick_name(struct Client* cptr, struct Client* sptr,
93 const char* nick, int parc, char* parv[]);
94 extern void send_umode_out(struct Client* cptr, struct Client* sptr,
95 - struct Flags* old, int prop);
96 + struct Flags* old, int prop, int alreadyh);
97 extern int whisper(struct Client* source, const char* nick,
98 const char* channel, const char* text, int is_notice);
99 extern void send_user_info(struct Client* to, char* names, int rpl,
102 extern int hide_hostmask(struct Client *cptr, unsigned int flags);
103 -extern int set_hostmask(struct Client *cptr, char *hostmask, char *password);
104 -extern int is_hostmask(char *word);
105 +extern int set_hostmask(struct Client *sptr, char *user, char *host);
106 +extern int is_validsethost(char *mask, int maxlen);
107 extern int set_user_mode(struct Client *cptr, struct Client *sptr,
108 int parc, char *parv[], int allow_modes);
109 extern int is_silenced(struct Client *sptr, struct Client *acptr);
111 extern struct Client* next_client(struct Client* next, const char* ch);
112 extern char *umode_str(struct Client *cptr, int type);
113 extern void send_umode(struct Client *cptr, struct Client *sptr,
114 - struct Flags *old, int sendset, int opernames);
115 + struct Flags *old, int sendset, int opernames, int alreadyh);
116 extern void set_snomask(struct Client *, unsigned int, int);
117 extern int is_snomask(char *);
118 extern int check_target_limit(struct Client *sptr, void *target, const char *name,
119 diff -r c6f3803ee169 ircd/channel.c
122 @@ -384,12 +384,12 @@
123 ircd_ntoa_r(iphost, &cli_ip(cptr));
125 /* sr is real host if +h */
126 - if (HasSetHost(cptr))
127 + if (IsSetHost(cptr))
128 sr = cli_user(cptr)->realhost;
130 /* if +x and not +h sa is real host, if -x or +h sa is the account host */
131 if (IsAccount(cptr)) {
132 - if (HasHiddenHost(cptr) && !HasSetHost(cptr)) {
133 + if (HasHiddenHost(cptr) && !IsSetHost(cptr)) {
134 sa = cli_user(cptr)->realhost;
136 ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
137 diff -r c6f3803ee169 ircd/m_oper.c
142 set_snomask(sptr, SNO_OPERDEFAULT, SNO_ADD);
143 cli_max_sendq(sptr) = 0; /* Get the sendq from the oper's class */
144 - send_umode_out(cptr, sptr, &old_mode, HasPriv(sptr, PRIV_PROPAGATE));
145 + send_umode_out(cptr, sptr, &old_mode, HasPriv(sptr, PRIV_PROPAGATE), 0);
146 send_reply(sptr, RPL_YOUREOPER);
148 sendto_opmask_butone(0, SNO_OLDSNO, "%s (%s@%s) is now operator (%c) as %s",
149 diff -r c6f3803ee169 ircd/m_sethost.c
150 --- a/ircd/m_sethost.c
151 +++ b/ircd/m_sethost.c
152 @@ -82,174 +82,222 @@
156 +#include "ircd_features.h"
157 +#include "ircd_log.h"
158 #include "ircd_reply.h"
159 #include "ircd_string.h"
160 #include "ircd_snprintf.h"
161 -#include "ircd_features.h"
166 +#include "s_debug.h"
168 -#include "s_debug.h"
171 #include "numnicks.h"
173 -#include "channel.h"
181 * m_sethost - generic message handler
183 - * mimic old lain syntax:
184 + * SETHOST [<user>@]<host> [<password>]
186 - * (Oper) /SETHOST ident host.cc [quit-message]
187 - * (User) /SETHOST host.cc password
188 - * (Both) /SETHOST undo
189 + * parv[0] = sender prefix
190 + * parv[1] = [user@]host
191 + * parv[2] = password
193 - * check for undo, prepend parv w. <nick> -h or +h
194 + * "MODE <nick> -h" to remove sethost
197 int m_sethost(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
199 - char hostmask[USERLEN + HOSTLEN + 2];
200 - char curhostmask[USERLEN + HOSTLEN + 2];
206 + char *password = NULL;
207 + struct Flags setflags;
208 + struct sline *sconf;
210 - struct Flags setflags;
212 + if (!feature_bool(FEAT_SETHOST))
213 + return send_reply(sptr, ERR_DISABLED, "SETHOST");
215 - /* Back up the flags first */
216 + /* disabled for ordinary users */
217 + if (!IsAnOper(sptr) && !feature_bool(FEAT_SETHOST_USER))
218 + return send_reply(sptr, ERR_NOPRIVILEGES);
220 + /* need hostmask parameter
221 + * and need password parameter from an ordinary user
223 + if (parc < 2 || EmptyString(parv[1]) || (parc < 3 && !IsAnOper(sptr)))
224 + return need_more_params(sptr, "SETHOST");
226 + hostmask = parv[1];
228 + /* get user and host */
229 + if ((host = strrchr(hostmask, '@'))) {
236 + /* got a pasword */
237 + if (parc > 2 && !EmptyString(parv[2]))
238 + password = parv[2];
240 + /* freeform - do not bother with password */
241 + if (IsAnOper(sptr) && HasPriv(sptr, PRIV_FREEFORM)) {
246 + /* check if user and host are valid */
247 + if ((user && !is_validsethost(user, USERLEN)) ||
248 + !is_validsethost(host, HOSTLEN))
249 + return send_reply(sptr, ERR_BADHOSTMASK, user ? user : "", user ? "@" : "", host);
254 + /* find the spoof block */
255 + if (!(sconf = find_spoofblock(sptr, host, password)))
256 + return send_reply(sptr, ERR_HOSTUNAVAIL, user ? user : "", user ? "@" : "", host);
258 + host = (char *)sconf->spoofhost;
260 + /* only freeform allowed to specify user */
265 setflags = cli_flags(sptr);
268 - return need_more_params(sptr, "SETHOST");
269 + /* already +h, clear flag to force mode +h to be sent out again */
270 + if (IsSetHost(sptr)) {
271 + FlagClr(&setflags, FLAG_SETHOST);
275 - if (0 == ircd_strcmp("undo", parv[1])) {
276 - set_hostmask(sptr, NULL, NULL);
279 - return need_more_params(sptr, "SETHOST");
280 - if (IsAnOper(sptr)) {
281 - ircd_snprintf(0, hostmask, USERLEN + HOSTLEN + 2, "%s@%s", parv[1], parv[2]);
282 - if (!is_hostmask(hostmask)) {
283 - send_reply(sptr, ERR_BADHOSTMASK, hostmask);
286 - if (IsSetHost(sptr) || IsAccount(sptr)) {
287 - ircd_snprintf(0, curhostmask, USERLEN + HOSTLEN + 2, "%s@%s", sptr->cli_user->username, sptr->cli_user->host);
288 - if (0 == strcmp(hostmask, curhostmask)) {
289 - send_reply(sptr, RPL_HOSTHIDDEN, curhostmask);
293 - if (set_hostmask(sptr, hostmask, NULL))
294 - FlagClr(&setflags, FLAG_SETHOST);
296 - if (!is_hostmask(parv[1])) {
297 - send_reply(sptr, ERR_BADHOSTMASK, parv[1]);
300 - if (IsSetHost(sptr) || IsAccount(sptr)) {
301 - if (0 == strcmp(parv[1], sptr->cli_user->host)) {
302 - send_reply(sptr, RPL_HOSTHIDDEN, parv[1]);
306 - if (set_hostmask(sptr, parv[1], parv[2]))
307 - FlagClr(&setflags, FLAG_SETHOST);
310 + /* check if new sethost is different from before */
311 + if (IsSetHost(sptr) &&
312 + (!user || strcmp(cli_user(sptr)->username, user) == 0) &&
313 + strcmp(cli_user(sptr)->host, host) == 0)
314 + return send_reply(sptr, RPL_HOSTHIDDEN, user ? user : "", user ? "@" : "", host);
316 - send_umode_out(cptr, sptr, &setflags, 0);
318 + set_hostmask(sptr, user, host);
322 + log_write(LS_SETHOST, L_NOTICE, 0,
323 + "SETHOST (%s@%s) by (%#R) using freeform",
324 + cli_user(cptr)->username, cli_user(cptr)->host, cptr);
326 + /* send the mode out */
327 + send_umode_out(cptr, sptr, &setflags, 0, alreadyh);
336 * ms_sethost - sethost server message handler
338 * parv[0] = sender prefix
339 * parv[1] = target user numeric
340 - * parv[2] = target user's new ident
341 - * parv[3] = target user's new host
342 + * parv[2] = spoof username
343 + * parv[3] = spoof host
345 + * undo sethost when spoof username and host are 0
348 + /* TODO: IsRemoteSetHost() */
349 int ms_sethost(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
351 - struct Client *target;
352 - char hostmask[USERLEN + HOSTLEN + 2];
353 - struct Membership *chan;
358 + struct Client *acptr;
359 struct Flags setflags;
361 + /* check paramaters */
363 return need_more_params(sptr, "SETHOST");
369 + /* not from a server */
371 - return protocol_violation(cptr, "SETHOST from non-server %s",
373 + return protocol_violation(cptr, "SETHOST from non-server %s", cli_name(sptr));
375 - /* Locate our target user; ignore the message if we can't */
376 - if(!(target = findNUser(parv[1])))
378 + if(!(acptr = findNUser(target)))
381 - /* Fake host assignments must be from services */
382 - if (!find_conf_byhost(cli_confs(sptr), cli_name(sptr), CONF_UWORLD))
383 - return protocol_violation(cptr, "Non-U:lined server %s set fake host on user %s", cli_name(sptr), cli_name(target));
385 - if (!MyConnect(target)) {
386 - sendcmdto_one(sptr, CMD_SETHOST, cli_user(target)->server, "%C %s %s", target,
388 + /* not for my user, pass it along */
389 + if (!MyConnect(acptr)) {
390 + sendcmdto_one(sptr, CMD_SETHOST, acptr, "%C %s %s", acptr, user, host);
394 - /* Back up the flags first */
395 - setflags = cli_flags(target);
396 - FlagClr(&setflags, FLAG_SETHOST);
398 + setflags = cli_flags(acptr);
400 - if (IsSetHost(target) || IsAccount(target)) {
401 - if ((0 == strcmp(parv[2], target->cli_user->username)) && (0 == strcmp(parv[3], target->cli_user->host)))
402 + /* check user and host are valid */
403 + if (!is_validsethost(user, USERLEN) || !is_validsethost(host, HOSTLEN))
404 + return protocol_violation(cptr,
405 + "Server %C tried to SETHOST user %C with a badmask: %s@%s",
406 + sptr, acptr, user, host);
408 + /* 'user host' is '0 0' - undo sethost */
409 + if (user[0] == '0' && user[1] == '\0' &&
410 + host[0] == '0' && host[1] == '\0') {
412 + /* user has no sethost or has no account
414 + * user has +h their host is hidden, do not remove it
415 + * unless the user has an account set
416 + * we should not out of the blue expose the real host
418 + if (!IsSetHost(acptr) || !IsAccount(acptr))
421 + /* user not +x and not allowed to set it */
422 + if (!IsHiddenHost(acptr) && !feature_bool(FEAT_HOST_HIDING))
426 + SetHiddenHost(acptr);
431 - ircd_snprintf(0, hostmask, USERLEN + HOSTLEN + 2, "%s@%s", parv[2], parv[3]);
432 - if (!is_hostmask(hostmask))
433 - return protocol_violation(cptr, "Bad Host mask %s for user %s", hostmask, cli_name(target));
434 + /* check if new sethost is different from before */
435 + else if (IsSetHost(acptr) &&
436 + strcmp(cli_user(acptr)->username, user) == 0 &&
437 + strcmp(cli_user(acptr)->host, host) == 0)
440 - sendcmdto_common_channels_butone(target, CMD_QUIT, target, ":Host change");
442 - /* Assign and propagate the fakehost */
443 - SetSetHost(target);
444 - ircd_strncpy(cli_user(target)->username, parv[2], USERLEN);
445 - ircd_strncpy(cli_user(target)->host, parv[3], HOSTLEN);
447 - send_reply(target, RPL_HOSTHIDDEN, hostmask);
450 - * Go through all channels the client was on, rejoin him
451 - * and set the modes, if any
453 - for (chan = cli_user(target)->channel; chan; chan = chan->next_channel) {
454 - if (IsZombie(chan))
456 - /* If this channel has delayed joins and the user has no modes, just set
457 - * the delayed join flag rather than showing the join, even if the user
458 - * was visible before */
459 - if (!IsChanOp(chan) && !HasVoice(chan)
460 - && (chan->channel->mode.mode & MODE_DELJOINS)) {
461 - SetDelayedJoin(chan);
463 - sendcmdto_channel_butserv_butone(target, CMD_JOIN, chan->channel, target, 0,
464 - "%H", chan->channel);
466 - if (IsChanOp(chan) && HasVoice(chan)) {
467 - sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, target, 0,
468 - "%H +ov %C %C", chan->channel, target, target);
469 - } else if (IsChanOp(chan) || HasVoice(chan)) {
470 - sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, target, 0,
471 - "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', target);
473 + /* already +h, clear flag to force mode +h to be sent out again */
474 + else if (IsSetHost(acptr)) {
475 + FlagClr(&setflags, FLAG_SETHOST);
479 - send_umode_out(target, target, &setflags, 0);
481 + set_hostmask(acptr, user, host);
483 + /* send out the mode */
484 + send_umode_out(acptr, acptr, &setflags, 0, alreadyh);
488 diff -r c6f3803ee169 ircd/m_userhost.c
489 --- a/ircd/m_userhost.c
490 +++ b/ircd/m_userhost.c
492 * of +x. If an oper wants the real host, he should go to
495 - (HasHiddenHost(cptr) || HasSetHost(cptr)) && (sptr != cptr) ?
496 + (HasHiddenHost(cptr) || IsSetHost(cptr)) && (sptr != cptr) ?
497 cli_user(cptr)->host : cli_user(cptr)->realhost);
500 diff -r c6f3803ee169 ircd/m_userip.c
501 --- a/ircd/m_userip.c
502 +++ b/ircd/m_userip.c
504 * of +x. If an oper wants the real IP, he should go to
507 - ((HasHiddenHost(cptr) || HasSetHost(cptr) || feature_bool(FEAT_HIS_USERIP)) && (sptr != cptr)) ?
508 + ((HasHiddenHost(cptr) || IsSetHost(cptr) || feature_bool(FEAT_HIS_USERIP)) && (sptr != cptr)) ?
509 feature_str(FEAT_HIDDEN_IP) :
510 ircd_ntoa(&cli_ip(cptr)));
512 diff -r c6f3803ee169 ircd/m_who.c
515 @@ -394,14 +394,14 @@
516 && ((!(matchsel & WHO_FIELD_HOS))
517 || matchexec(cli_user(acptr)->host, mymask, minlen))
518 && ((!(matchsel & WHO_FIELD_HOS))
519 - || !HasSetHost(acptr)
520 + || !IsSetHost(acptr)
521 || !HasHiddenHost(acptr)
523 || matchexec(cli_user(acptr)->realhost, mymask, minlen))
524 && ((!(matchsel & WHO_FIELD_REN))
525 || matchexec(cli_info(acptr), mymask, minlen))
526 && ((!(matchsel & WHO_FIELD_NIP))
527 - || ((HasHiddenHost(acptr) || HasSetHost(acptr)) && !IsAnOper(sptr))
528 + || ((HasHiddenHost(acptr) || IsSetHost(acptr)) && !IsAnOper(sptr))
529 || !ipmask_check(&cli_ip(acptr), &imask, ibits))
530 && ((!(matchsel & WHO_FIELD_ACC))
531 || matchexec(cli_user(acptr)->account, mymask, minlen)))
532 @@ -433,14 +433,14 @@
533 && ((!(matchsel & WHO_FIELD_HOS))
534 || matchexec(cli_user(acptr)->host, mymask, minlen))
535 && ((!(matchsel & WHO_FIELD_HOS))
536 - || !HasSetHost(acptr)
537 + || !IsSetHost(acptr)
538 || !HasHiddenHost(acptr)
540 || matchexec(cli_user(acptr)->realhost, mymask, minlen))
541 && ((!(matchsel & WHO_FIELD_REN))
542 || matchexec(cli_info(acptr), mymask, minlen))
543 && ((!(matchsel & WHO_FIELD_NIP))
544 - || ((HasHiddenHost(acptr) || HasSetHost(acptr)) && !IsAnOper(sptr))
545 + || ((HasHiddenHost(acptr) || IsSetHost(acptr)) && !IsAnOper(sptr))
546 || !ipmask_check(&cli_ip(acptr), &imask, ibits))
547 && ((!(matchsel & WHO_FIELD_ACC))
548 || matchexec(cli_user(acptr)->account, mymask, minlen)))
549 diff -r c6f3803ee169 ircd/m_whois.c
553 if (IsAccount(acptr))
554 send_reply(sptr, RPL_WHOISACCOUNT, name, user->account);
556 - if ((HasHiddenHost(acptr) || HasSetHost(acptr)) && ((IsAnOper(sptr) && HasPriv(sptr, PRIV_USER_PRIVACY)) || acptr == sptr))
557 + if ((HasHiddenHost(acptr) || IsSetHost(acptr)) && ((IsAnOper(sptr) && HasPriv(sptr, PRIV_USER_PRIVACY)) || acptr == sptr))
558 send_reply(sptr, RPL_WHOISACTUALLY, name, user->realusername,
559 user->realhost, ircd_ntoa(&cli_ip(acptr)));
561 diff -r c6f3803ee169 ircd/s_conf.c
572 @@ -1239,44 +1240,162 @@
579 + * Find matching spoof block for a user for the given spoofhost and password
581 + * @param cptr User wanting to get a spoof host.
582 + * @param spoofhost Spoof host to look for.
583 + * @param password Password given by user (can be NULL).
585 + * @return pointer to the matching spoofblock is found, else NULL
588 +struct sline *find_spoofblock(struct Client *cptr, char *spoofhost, char *password) {
589 + struct sline *sconf;
593 + Debug((DEBUG_INFO, "find_spoofblock() cptr=%C spoofhost=%s password=%s",
594 + cptr, spoofhost, password));
596 + for (sconf = GlobalSList; sconf; sconf = sconf->next) {
598 + /* check result of previous loop */
602 + /* check spoofhost */
603 + if (strcasecmp(sconf->spoofhost, spoofhost) != 0)
607 + /* check cptr's host */
609 + if (sconf->flags == SLINE_FLAGS_IP) {
610 + if (!ipmask_check(&(cli_ip(cptr)), &(sconf->address), sconf->bits))
615 + else if (sconf->flags == SLINE_FLAGS_HOSTNAME) {
616 + if ((match(sconf->realhost, cli_sockhost(cptr)) != 0) &&
617 + (match(sconf->realhost, cli_sock_ip(cptr)) != 0)) /* wildcarded IP address */
621 + /* not cidr or hostname.. */
626 + /* check cptr's username */
627 + if (!EmptyString(sconf->username) && match(sconf->username, cli_user(cptr)->realusername) != 0)
631 + /* check password */
633 + if (EmptyString(sconf->passwd) || strcmp(sconf->passwd, password) != 0)
637 + /* no password, but need one for this spoofblock */
638 + else if (!EmptyString(sconf->passwd))
642 + log_write(LS_SETHOST, L_INFO, 0,
643 + "SETHOST (%s) by (%#R): ", sconf->spoofhost, cptr);
647 + /* TODO: lookup LOG stuff */
648 + /* TODO: L_INFO LOG_NOSNOTICE */
649 + /* log of best result we got */
651 + log_write(LS_SETHOST, L_INFO, 0,
652 + "SETHOST (%s) by (%#R): no such Spoof block", spoofhost, cptr);
654 + log_write(LS_SETHOST, L_INFO, 0,
655 + "SETHOST (%s) by (%#R): IP / host mismatch", spoofhost, cptr);
657 + log_write(LS_SETHOST, L_INFO, 0,
658 + "SETHOST (%s) by (%#R): username mismatch", spoofhost, cptr);
660 + log_write(LS_SETHOST, L_INFO, 0,
661 + "SETHOST (%s) by (%#R): %s", spoofhost, cptr,
662 + password ? "password mismatch" : "password required");
671 + * @param cptr User to apply Spoof block to on connect
673 + * @return 1 for success, else 0
677 -conf_check_slines(struct Client *cptr)
678 +apply_spoofblock(struct Client *cptr)
684 + if(!feature_bool(FEAT_SETHOST_AUTO))
687 + /* go over spoof blocks */
688 for (sconf = GlobalSList; sconf; sconf = sconf->next) {
691 if (sconf->flags == SLINE_FLAGS_IP) {
692 if (!ipmask_check(&(cli_ip(cptr)), &(sconf->address), sconf->bits))
696 } else if (sconf->flags == SLINE_FLAGS_HOSTNAME) {
697 if ((match(sconf->realhost, cli_sockhost(cptr)) != 0) &&
698 - (match(sconf->realhost, cli_sock_ip(cptr)) != 0)) /* wildcarded IP address */
699 + (match(sconf->realhost, cli_sock_ip(cptr)) != 0)) /* wildcarded IP address */
707 - if (match(sconf->username, cli_user(cptr)->username) == 0) {
708 - /* Ignore user part if u@h. */
709 - if ((hostonly = strchr(sconf->spoofhost, '@')))
712 - hostonly = sconf->spoofhost;
713 + /* check username */
714 + if (match(sconf->username, cli_user(cptr)->username) != 0)
719 + /* Ignore user part if u@h. */
720 + if ((hostonly = strchr(sconf->spoofhost, '@')))
723 + hostonly = sconf->spoofhost;
725 - ircd_strncpy(cli_user(cptr)->host, hostonly, HOSTLEN);
726 - log_write(LS_USER, L_INFO, LOG_NOSNOTICE, "S-Line (%s@%s) by (%#R)",
727 - cli_user(cptr)->username, hostonly, cptr);
731 + if (!is_validsethost(hostonly, HOSTLEN))
734 + /* do it and log */
735 + set_hostmask(cptr, NULL, hostonly);
736 + /* LOG_NOSNOTICE */
737 + log_write(LS_USER, L_INFO, 0, "AUTO SETHOST %s on %s",
738 + hostonly, get_client_name(cptr, SHOW_IP));
750 void free_spoofhost(struct sline *spoof) {
751 MyFree(spoof->spoofhost);
752 MyFree(spoof->passwd);
753 diff -r c6f3803ee169 ircd/s_err.c
756 @@ -824,13 +824,13 @@
760 - { RPL_HOSTHIDDEN, "%s :is now your hidden host", "396" },
761 + { RPL_HOSTHIDDEN, "%s%s%s :is now your hidden host", "396" },
765 - { RPL_STATSSLINE, "%d %s %s %s %s", "398" },
766 + { RPL_STATSSLINE, "%c %s %s %s%s%s", "398" },
768 - { RPL_USINGSLINE, ":Using S-line privilege", "399" },
773 @@ -1092,9 +1092,9 @@
777 - { ERR_BADHOSTMASK, "%s :Invalid username/hostmask", "530" },
778 + { ERR_BADHOSTMASK, "%s%s%s :Invalid username/hostmask", "530" },
780 - { ERR_HOSTUNAVAIL, "%s :sethost not found", "531" },
781 + { ERR_HOSTUNAVAIL, "%s%s%s :Sethost not found", "531" },
785 diff -r c6f3803ee169 ircd/s_stats.c
788 @@ -400,41 +400,37 @@
793 +/** List spoof blocks.
794 + * @param[in] to Client requesting statistics.
795 + * @param[in] sd Stats descriptor for request (ignored).
796 + * @param[in] param Filter for spoofhost names.
799 stats_sline(struct Client* to, const struct StatDesc* sd, char* param)
805 - send_reply(to, SND_EXPLICIT | RPL_TEXT, "# Type Spoofhost Realhost Ident");
806 + send_reply(to, SND_EXPLICIT | RPL_TEXT, "S Type Spoofhost Hostmask");
808 - send_reply(to, SND_EXPLICIT | RPL_TEXT, "# Type Spoofhost");
809 + send_reply(to, SND_EXPLICIT | RPL_TEXT, "S Type Spoofhost");
811 for (sline = GlobalSList; sline; sline = sline->next) {
812 - if (param && match(param, sline->spoofhost)) { /* narrow search */
816 - if (!EmptyString(sline->passwd))
819 + if (param && match(param, sline->spoofhost))
823 - if (IsAnOper(to)) {
824 - send_reply(to, RPL_STATSSLINE, (param) ? y : i,
825 - (EmptyString(sline->passwd)) ? "oper" : "user",
827 - (EmptyString(sline->realhost)) ? "" : sline->realhost,
828 - (EmptyString(sline->username)) ? "" : sline->username);
831 - if (!EmptyString(sline->passwd)) {
832 - send_reply(to, RPL_STATSSLINE, (param) ? y : i, "user", sline->spoofhost,
838 + send_reply(to, RPL_STATSSLINE,
839 + is_validsethost(sline->spoofhost, HOSTLEN) ? 'S' : 's', /* valid show S else s */
840 + (EmptyString(sline->passwd)) ? "Oper" : "User",
842 + (EmptyString(sline->username)) ? "" : sline->username,
843 + (!EmptyString(sline->username)) ? "@" : "", /* always place a @ after the username */
844 + (EmptyString(sline->realhost)) ? "" : sline->realhost);
845 + else if (!EmptyString(sline->passwd) && is_validsethost(sline->spoofhost, HOSTLEN))
846 + send_reply(to, RPL_STATSSLINE, 'S', "User", sline->spoofhost, "", "", "");
850 diff -r c6f3803ee169 ircd/s_user.c
855 #include <sys/stat.h>
857 -static char *IsVhost(char *hostmask, int oper);
858 -static char *IsVhostPass(char *hostmask);
860 /** Count of allocated User structures. */
861 static int userCount = 0;
865 if (feature_bool(FEAT_AUTOINVISIBLE))
868 - if(feature_bool(FEAT_SETHOST_AUTO)) {
869 - if (conf_check_slines(sptr)) {
870 - send_reply(sptr, RPL_USINGSLINE);
876 cli_handler(sptr) = CLIENT_HANDLER;
878 cli_info(sptr), NumNick(cptr) /* two %s's */);
880 IPcheck_connect_succeeded(sptr);
883 + /* apply auto sethost if needed */
884 + apply_spoofblock(sptr);
887 struct Client *acptr = user->server;
890 FlagClr(&flags, FLAG_ACCOUNT);
891 client_set_privs(sptr, NULL);
892 - send_umode(cptr, sptr, &flags, ALL_UMODES, 0);
893 + send_umode(cptr, sptr, &flags, ALL_UMODES, 0, 0);
894 if ((cli_snomask(sptr) != SNO_DEFAULT) && HasFlag(sptr, FLAG_SERVNOTICE))
895 send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr));
897 @@ -874,14 +868,15 @@
898 * @param[in] sptr Client who sent us the mode change message.
899 * @param[in] old Prior set of user flags.
900 * @param[in] prop If non-zero, also include FLAG_OPER.
901 + * @param[in] alreadyh Client is already +h, do not show +h change
903 void send_umode_out(struct Client *cptr, struct Client *sptr,
904 - struct Flags *old, int prop)
905 + struct Flags *old, int prop, int alreadyh)
908 struct Client *acptr;
910 - send_umode(NULL, sptr, old, prop ? SEND_UMODES : SEND_UMODES_BUT_OPER, 0);
911 + send_umode(NULL, sptr, old, prop ? SEND_UMODES : SEND_UMODES_BUT_OPER, 0, 0);
913 for (i = HighestFd; i >= 0; i--)
916 sendcmdto_one(sptr, CMD_MODE, acptr, "%s %s", cli_name(sptr), umodeBuf);
919 - send_umode(NULL, sptr, old, prop ? SEND_UMODES : SEND_UMODES_BUT_OPER, 1);
920 + send_umode(NULL, sptr, old, prop ? SEND_UMODES : SEND_UMODES_BUT_OPER, 1, 0);
922 for (i = HighestFd; i >= 0; i--)
927 if (cptr && MyUser(cptr))
928 - send_umode(cptr, sptr, old, ALL_UMODES, 0);
929 + send_umode(cptr, sptr, old, ALL_UMODES, 0, alreadyh);
937 - if (!HasFlag(cptr, FLAG_HIDDENHOST) || !HasFlag(cptr, FLAG_ACCOUNT) || HasSetHost(cptr))
938 + if (!HasFlag(cptr, FLAG_HIDDENHOST) || !HasFlag(cptr, FLAG_ACCOUNT) || IsSetHost(cptr))
941 sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Registered");
944 /* ok, the client is now fully hidden, so let them know -- hikari */
946 - send_reply(cptr, RPL_HOSTHIDDEN, cli_user(cptr)->host);
947 + send_reply(cptr, RPL_HOSTHIDDEN, "", "", cli_user(cptr)->host);
950 * Go through all channels the client was on, rejoin him
951 @@ -999,201 +994,104 @@
957 * set_hostmask() - derived from hide_hostmask()
960 -int set_hostmask(struct Client *cptr, char *hostmask, char *password)
961 +int set_hostmask(struct Client *cptr, char *user, char *host)
965 - char *host, *new_vhost, *vhost_pass;
966 - char hiddenhost[USERLEN + HOSTLEN + 2];
968 + int userchange = 0;
969 + char hiddenhost[USERLEN + 1 + HOSTLEN + 1];
970 + char *msg = "Host change";
971 struct Membership *chan;
973 - Debug((DEBUG_INFO, "set_hostmask() %C, %s, %s", cptr, hostmask, password));
976 - /* sethost enabled? */
977 - if (MyConnect(cptr) && !feature_bool(FEAT_SETHOST)) {
978 - send_reply(cptr, ERR_DISABLED, "SETHOST");
979 + Debug((DEBUG_INFO, "set_hostmask() cptr=%C user=%s host=%s",
980 + cptr, user ? user : "<null>", host ? host : "<null>"));
982 + /* remove sethost, but user has none */
983 + if (!host && !IsSetHost(cptr))
986 + /* remove sethost, user has +x host, realusername and username are the same
987 + * pretend the user just set +x
989 + if (!host && HasHiddenHost(cptr) &&
990 + strcmp(cli_user(cptr)->username, cli_user(cptr)->realusername) == 0)
991 + msg = "Registered";
994 + sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":%s", msg);
996 + /* remove sethost */
1000 + ClearSetHost(cptr);
1002 + /* restore user and host */
1003 + if (HasHiddenHost(cptr))
1004 + ircd_snprintf(0, cli_user(cptr)->host, HOSTLEN, "%s.%s",
1005 + cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
1007 + strncpy(cli_user(cptr)->host, cli_user(cptr)->realhost, HOSTLEN);
1008 + if (MyConnect(cptr) && strcmp(cli_user(cptr)->username, cli_user(cptr)->realusername) != 0)
1010 + strncpy(cli_user(cptr)->username, cli_user(cptr)->realusername, USERLEN);
1013 - /* sethost enabled for users? */
1014 - if (MyConnect(cptr) && !IsAnOper(cptr) && !feature_bool(FEAT_SETHOST_USER)) {
1015 - send_reply(cptr, ERR_NOPRIVILEGES);
1019 - /* MODE_DEL: restore original hostmask */
1020 - if (EmptyString(hostmask)) {
1021 - /* is already sethost'ed? and only opers can remove a sethost */
1022 - if (IsSetHost(cptr) && IsAnOper(cptr)) {
1024 - sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
1025 - /* If they are +rx, we need to return to their +x host, not their "real" host */
1026 - if (HasHiddenHost(cptr))
1027 - ircd_snprintf(0, cli_user(cptr)->host, HOSTLEN, "%s.%s",
1028 - cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
1030 - strncpy(cli_user(cptr)->host, cli_user(cptr)->realhost, HOSTLEN);
1031 - strncpy(cli_user(cptr)->username, cli_user(cptr)->realusername, USERLEN);
1033 - if (MyConnect(cptr))
1034 - log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE,
1035 - "SETHOST (%s@%s) by (%#R): restoring real hostmask",
1036 - cli_user(cptr)->username, cli_user(cptr)->host, cptr);
1039 - /* MODE_ADD: set a new hostmask */
1041 - /* chop up ident and host.cc */
1042 - if ((host = strrchr(hostmask, '@'))) { /* oper can specifiy ident@host.cc */
1044 - if ( MyConnect(cptr) && (0 == strcmp(host, cli_user(cptr)->host)) && (0 == strcmp(hostmask, cli_user(cptr)->username))) {
1045 - ircd_snprintf(0, hiddenhost, HOSTLEN + USERLEN + 2, "%s@%s",
1046 - cli_user(cptr)->username, cli_user(cptr)->host);
1047 - send_reply(cptr, RPL_HOSTHIDDEN, hiddenhost);
1050 - } else { /* user can only specifiy host.cc [password] */
1052 - if ( MyConnect(cptr) && (0 == strcmp(host, cli_user(cptr)->host))) {
1053 - ircd_snprintf(0, hiddenhost, HOSTLEN + USERLEN + 2, "%s@%s",
1054 - cli_user(cptr)->username, cli_user(cptr)->host);
1055 - send_reply(cptr, RPL_HOSTHIDDEN, hiddenhost);
1062 - if (MyConnect(cptr)) {
1063 - if (IsAnOper(cptr)) {
1064 - if ((new_vhost = IsVhost(host, 1)) == NULL) {
1065 - if (!HasPriv(cptr, PRIV_FREEFORM)) {
1066 - send_reply(cptr, ERR_HOSTUNAVAIL, hostmask);
1067 - log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE,
1068 - "SETHOST (%s@%s) by (%#R): no such s-line",
1069 - (host != hostmask) ? hostmask : cli_user(cptr)->username, host, cptr);
1071 - } else /* freeform active, log and go */
1074 - sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
1075 - /* set the new ident and host */
1076 - if (host != hostmask) /* oper only specified host.cc */
1077 - strncpy(cli_user(cptr)->username, hostmask, USERLEN);
1078 - strncpy(cli_user(cptr)->host, host, HOSTLEN);
1080 - log_write(LS_SETHOST, (freeform) ? L_NOTICE : L_INFO,
1081 - (freeform) ? 0 : LOG_NOSNOTICE, "SETHOST (%s@%s) by (%#R)%s",
1082 - cli_user(cptr)->username, cli_user(cptr)->host, cptr,
1083 - (freeform) ? ": using freeform" : "");
1085 - * plain user sethost, handled here
1088 - /* empty password? */
1089 - if (EmptyString(password)) {
1090 - send_reply(cptr, ERR_NEEDMOREPARAMS, "MODE");
1093 - /* no such s-line */
1094 - if ((new_vhost = IsVhost(host, 0)) == NULL) {
1095 - send_reply(cptr, ERR_HOSTUNAVAIL, hostmask);
1096 - log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE, "SETHOST (%s@%s %s) by (%#R): no such s-line",
1097 - cli_user(cptr)->username, host, password, cptr);
1101 - if ((vhost_pass = IsVhostPass(new_vhost)) == NULL) {
1102 - send_reply(cptr, ERR_PASSWDMISMATCH);
1103 - log_write(LS_SETHOST, L_INFO, 0, "SETHOST (%s@%s %s) by (%#R): trying to use an oper s-line",
1104 - cli_user(cptr)->username, host, password, cptr);
1107 - /* incorrect password */
1108 - if (strCasediff(vhost_pass, password)) {
1109 - send_reply(cptr, ERR_PASSWDMISMATCH);
1110 - log_write(LS_SETHOST, L_NOTICE, 0, "SETHOST (%s@%s %s) by (%#R): incorrect password",
1111 - cli_user(cptr)->username, host, password, cptr);
1114 - sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
1115 - /* set the new host */
1116 - strncpy(cli_user(cptr)->host, new_vhost, HOSTLEN);
1118 - log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE, "SETHOST (%s@%s) by (%#R)",
1119 - cli_user(cptr)->username, cli_user(cptr)->host, cptr);
1121 - } else { /* remote user */
1122 - sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
1123 - if (host != hostmask) /* oper only specified host.cc */
1124 - strncpy(cli_user(cptr)->username, hostmask, USERLEN);
1125 - strncpy(cli_user(cptr)->host, host, HOSTLEN);
1127 + /* apply sethost */
1133 + /* update user and host */
1135 + strncpy(cli_user(cptr)->username, user, USERLEN);
1136 + strncpy(cli_user(cptr)->host, host, HOSTLEN);
1140 - ClearSetHost(cptr);
1144 + if (MyConnect(cptr)) {
1146 - if (MyConnect(cptr)) {
1147 - ircd_snprintf(0, hiddenhost, HOSTLEN + USERLEN + 2, "%s@%s",
1148 - cli_user(cptr)->username, cli_user(cptr)->host);
1149 - send_reply(cptr, RPL_HOSTHIDDEN, hiddenhost);
1150 + /* user and host changed */
1151 + if (userchange || strcmp(cli_user(cptr)->username, cli_user(cptr)->realusername) != 0)
1152 + send_reply(cptr, RPL_HOSTHIDDEN, cli_user(cptr)->username, "@", cli_user(cptr)->host);
1154 + /* just host changed */
1156 + send_reply(cptr, RPL_HOSTHIDDEN, "", "", cli_user(cptr)->host);
1160 - /* Code copied from hide_hostmask(). This is the old (pre-delayedjoin)
1161 - * version. Switch this in if you're not using the delayed join patch. */
1163 - * Go through all channels the client was on, rejoin him
1164 - * and set the modes, if any
1166 + /* go over the channels */
1167 for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) {
1169 + /* invalidate bans so they are rechecked */
1170 + ClearBanValid(chan);
1175 - sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr,
1176 - "%H", chan->channel);
1177 - if (IsChanOp(chan) && HasVoice(chan)) {
1178 - sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr,
1179 - "%H +ov %C %C", chan->channel, cptr, cptr);
1180 - } else if (IsChanOp(chan) || HasVoice(chan)) {
1181 - sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr,
1182 - "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr);
1188 - * Go through all channels the client was on, rejoin him
1189 - * and set the modes, if any
1191 - for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) {
1192 - if (IsZombie(chan))
1194 - /* If this channel has delayed joins and the user has no modes, just set
1195 - * the delayed join flag rather than showing the join, even if the user
1196 - * was visible before */
1197 - if (!IsChanOp(chan) && !HasVoice(chan)
1198 - && (chan->channel->mode.mode & MODE_DELJOINS)) {
1199 - SetDelayedJoin(chan);
1201 + /* not delayed join, rejoin user to chan */
1202 + if (!IsDelayedJoin(chan))
1203 sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr, 0,
1204 "%H", chan->channel);
1206 - if (IsChanOp(chan) && HasVoice(chan)) {
1208 + /* restore modes */
1209 + if (IsChanOp(chan) && HasVoice(chan))
1210 sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, cptr, 0,
1211 "%H +ov %C %C", chan->channel, cptr, cptr);
1212 - } else if (IsChanOp(chan) || HasVoice(chan)) {
1213 + else if (IsChanOp(chan) || HasVoice(chan))
1214 sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, cptr, 0,
1215 "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr);
1223 /** Set a user's mode. This function checks that \a cptr is trying to
1224 @@ -1220,15 +1118,17 @@
1225 unsigned int tmpmask = 0;
1226 int snomask_given = 0;
1228 - char *hostmask, *password;
1229 + char *hostmask = NULL;
1231 int do_host_hiding = 0;
1232 int do_set_host = 0;
1236 char* account = NULL;
1237 + char *user = NULL;
1238 + char *host = NULL;
1240 - hostmask = password = NULL;
1244 @@ -1238,8 +1138,7 @@
1245 for (i = 0; i < USERMODELIST_SIZE; i++)
1247 if (HasFlag(sptr, userModeList[i].flag) &&
1248 - ((userModeList[i].flag != FLAG_ACCOUNT) &&
1249 - (userModeList[i].flag != FLAG_SETHOST)))
1250 + userModeList[i].flag != FLAG_ACCOUNT)
1251 *m++ = userModeList[i].c;
1254 @@ -1251,6 +1150,9 @@
1258 + if (IsSetHost(sptr))
1262 * find flags already set for user
1263 * why not just copy them?
1264 @@ -1394,26 +1296,18 @@
1267 if (what == MODE_ADD) {
1268 - if (*(p + 1) && is_hostmask(*(p + 1))) {
1271 - /* DON'T step p onto the trailing NULL in the parameter array! - splidge */
1278 - send_reply(sptr, ERR_NEEDMOREPARAMS, "SETHOST");
1280 + if (IsServer(cptr)) {
1282 + protocol_violation(cptr, "Received mode +h for user %C without sethost parameter", sptr);
1284 - send_reply(sptr, ERR_BADHOSTMASK, *(p+1));
1285 - p++; /* Swallow the arg anyway */
1290 } else { /* MODE_DEL */
1298 @@ -1468,6 +1362,11 @@
1299 if (!FlagHas(&setflags, FLAG_PARANOID) && !(IsOper(sptr) && HasPriv(sptr, PRIV_PARANOID)))
1300 ClearParanoid(sptr);
1303 + /* only opers can remove a sethost */
1304 + if (do_set_host && !hostmask && !FlagHas(&setflags, FLAG_LOCOP) && !FlagHas(&setflags, FLAG_OPER))
1308 * only send wallops to opers
1310 @@ -1521,11 +1420,35 @@
1312 if (!FlagHas(&setflags, FLAG_HIDDENHOST) && do_host_hiding && allow_modes != ALLOWMODES_DEFAULT)
1313 hide_hostmask(sptr, FLAG_HIDDENHOST);
1317 - /* We clear the flag in the old mask, so that the +h will be sent */
1318 - /* Only do this if we're SETTING +h and it succeeded */
1319 - if (set_hostmask(sptr, hostmask, password) && hostmask)
1320 - FlagClr(&setflags, FLAG_SETHOST);
1324 + set_hostmask(sptr, NULL, NULL);
1328 + if ((host = strrchr(hostmask, '@'))) {
1336 + if (!user || !is_validsethost(user, USERLEN) || !is_validsethost(host, HOSTLEN))
1337 + protocol_violation(cptr, "Received mode +h for user %C with an invalid sethost parameter '%s@%s'",
1338 + sptr, user ? user : "", host);
1342 + /* clear flag in old mask so that +h will be sent again */
1343 + FlagClr(&setflags, FLAG_SETHOST);
1344 + set_hostmask(sptr, user, host);
1349 if (IsRegistered(sptr)) {
1350 @@ -1577,7 +1500,7 @@
1352 assert(UserStats.opers <= UserStats.clients + UserStats.unknowns);
1353 assert(UserStats.inv_clients <= UserStats.clients + UserStats.unknowns);
1354 - send_umode_out(cptr, sptr, &setflags, prop);
1355 + send_umode_out(cptr, sptr, &setflags, prop, alreadyh);
1359 @@ -1652,9 +1575,11 @@
1360 * @param[in] old Pre-change set of modes for \a sptr.
1361 * @param[in] sendset One of ALL_UMODES, SEND_UMODES_BUT_OPER,
1362 * SEND_UMODES, to select which changed user modes to send.
1363 + * @param[in] opernames Include opername parameter.
1364 + * @param[in] alreadyh Client already has +h set, do not show +h change.
1366 void send_umode(struct Client *cptr, struct Client *sptr, struct Flags *old,
1367 - int sendset, int opernames)
1368 + int sendset, int opernames, int alreadyh)
1372 @@ -1697,12 +1622,15 @@
1374 /* Special case for SETHOST.. */
1375 if (flag == FLAG_SETHOST) {
1376 - /* Don't send to users */
1377 - if (cptr && MyUser(cptr))
1380 - /* If we're setting +h, add the parameter later */
1381 - if (!FlagHas(old, flag))
1383 + /* do not show +h if client already had it */
1384 + if (cptr && MyUser(cptr) && IsSetHost(cptr) && alreadyh)
1387 + /* If we're setting +h, add the parameter later,
1388 + * but not when showing to the user
1390 + if (!FlagHas(old, flag) && (!cptr || !MyUser(cptr)))
1393 if (FlagHas(old, flag))
1394 @@ -1769,108 +1697,30 @@
1399 - * Check to see if it resembles a valid hostmask.
1401 -int is_hostmask(char *word)
1403 + * Check to see if it resembles a valid sethost.
1405 + * @param[in] mask Mask to check (user or host part from a sethost)
1406 + * @param[in] maxlen Max length for parameter mask (USERLEN or HOSTLEN)
1407 + * @return Non-zero if \a mask looks like a valid sethost
1410 +int is_validsethost(char *mask, int maxlen)
1414 + assert(mask != NULL);
1415 + assert(maxlen > 0);
1417 - Debug((DEBUG_INFO, "is_hostmask() %s", word));
1419 - if (strlen(word) > (HOSTLEN + USERLEN + 1) || strlen(word) <= 0)
1420 + /* too long or too short */
1421 + if (strlen(mask) > maxlen || strlen(mask) <= 0)
1424 - /* if a host is specified, make sure it's valid */
1425 - host = strrchr(word, '@');
1427 - if (strlen(++host) < 1)
1429 - if (strlen(host) > HOSTLEN)
1432 + for (; *mask; mask++) {
1433 + if (!IsHostChar(*mask))
1438 - if ('@' == *word) /* no leading @'s */
1441 - if ('#' == *word) { /* numeric index given? */
1442 - for (word++; *word; word++) {
1443 - if (!IsDigit(*word))
1449 - /* normal hostmask, account for at most one '@' */
1450 - for (; *word; word++) {
1451 - if ('@' == *word) {
1455 - if (!IsHostChar(*word))
1458 - return (1 < i) ? 0 : 1; /* no more than on '@' */
1464 - * IsVhost() - Check if given host is a valid spoofhost
1465 - * (ie: configured thru a S:line)
1467 -static char *IsVhost(char *hostmask, int oper)
1469 - unsigned int i = 0, y = 0;
1470 - struct sline *sconf;
1472 - Debug((DEBUG_INFO, "IsVhost() %s", hostmask));
1474 - if (EmptyString(hostmask))
1477 - /* spoofhost specified as index, ie: #27 */
1478 - if ('#' == hostmask[0]) {
1479 - y = atoi(hostmask + 1);
1480 - for (i = 0, sconf = GlobalSList; sconf; sconf = sconf->next) {
1481 - if (!oper && EmptyString(sconf->passwd))
1484 - return sconf->spoofhost;
1489 - /* spoofhost specified as host, ie: host.cc */
1490 - for (sconf = GlobalSList; sconf; sconf = sconf->next)
1491 - if (strCasediff(hostmask, sconf->spoofhost) == 0)
1492 - return sconf->spoofhost;
1498 - * IsVhostPass() - Check if given spoofhost has a password
1499 - * associated with it, and if, return the password (cleartext)
1501 -static char *IsVhostPass(char *hostmask)
1503 - struct sline *sconf;
1505 - Debug((DEBUG_INFO, "IsVhostPass() %s", hostmask));
1507 - if (EmptyString(hostmask))
1510 - for (sconf = GlobalSList; sconf; sconf = sconf->next)
1511 - if (strCasediff(hostmask, sconf->spoofhost) == 0) {
1512 - Debug((DEBUG_INFO, "sconf->passwd %s", sconf->passwd));
1513 - return EmptyString(sconf->passwd) ? NULL : sconf->passwd;
1520 /** Update snomask \a oldmask according to \a arg and \a what.
1521 diff -r c6f3803ee169 ircd/send.c
1527 return (match(mask, cli_user(one)->host) == 0 ||
1528 - ((HasHiddenHost(one) || HasSetHost(one)) && match(mask, cli_user(one)->realhost) == 0));
1529 + ((HasHiddenHost(one) || IsSetHost(one)) && match(mask, cli_user(one)->realhost) == 0));
1532 return (match(mask, cli_name(cli_user(one)->server)) == 0);
1533 diff -r c6f3803ee169 ircd/whocmds.c
1534 --- a/ircd/whocmds.c
1535 +++ b/ircd/whocmds.c
1538 if (fields & WHO_FIELD_NIP)
1540 - const char* p2 = (HasHiddenHost(acptr) || HasSetHost(acptr) || feature_bool(FEAT_HIS_USERIP)) && (!IsAnOper(sptr) || (IsAnOper(sptr) && !HasPriv(sptr, PRIV_USER_PRIVACY))) ?
1541 + const char* p2 = (HasHiddenHost(acptr) || IsSetHost(acptr) || feature_bool(FEAT_HIS_USERIP)) && (!IsAnOper(sptr) || (IsAnOper(sptr) && !HasPriv(sptr, PRIV_USER_PRIVACY))) ?
1542 feature_str(FEAT_HIDDEN_IP) :
1543 ircd_ntoa(&cli_ip(acptr));
1547 if (SendDebug(acptr))
1549 - if (HasSetHost(acptr))
1550 + if (IsSetHost(acptr))
1553 if (HasHiddenHost(acptr))