]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blame - sethost.patch
rename patch files
[irc/quakenet/snircd-patchqueue.git] / sethost.patch
CommitLineData
0a17908b 1sethost patch: minor overhaul of sethost system
2
3this patch replaces a number of other patches:
4autosethost.patch invalidatebanssethost.patch issethost.patch
5sethostnewhostmask.patch sethostoldcode.patch sethostprotocolviolation.patch
6showumodehtoclients.patch ulined.patch
7
8makes usermode +h visible to clients
9
10removes HasSetHost() macro (was same as IsSetHost())
11
12removed 'Using S-line privilege' message on connect
13client is informed of spoofhost by 396 RPL_HOSTHIDDEN (host :is now your hidden host)
14
15change syntax to "SETHOST [<user>@]<host> [<password>]"
16
17disallow client to use MODE +h [<user>@]<host> [<pass>] (bug: mode +h took 2 parameters, even from remote users!)
18
19sethost can only be unset with "MODE <nick> -h"
e455e308 20and only if the sethost was not remotely set by a service (unless the user is an oper)
21and only if the user has an account set, and is +x (or is allowed to set +x)
22so the +x host becomes visible, and never the realhost
0a17908b 23
24sethost #N no longer supported (N being the Nth configured spoof block)
25
26remote sethost can now be undone by using 0 as username and host,
27but only when the user has an account set and is allowed by server settings to set mode +x,
28to avoid revealing the real host out of the blue
29
30SETHOST now same as OPER
31modes h and o can only be set with SETHOST and OPER
32modes h and o are visible to clients
33modes h and o can only be unset with MODE <nick> -ho
34
35user sethosts are now also checked against their user@host/ip (and not just the password)
36
37applying the sethost and syncing of clients (quit user, rejoin user, restore modes on user) is now done in one place
38
39remote sethost can come from any server, does not need to have a Uworld block or be a service (ACCOUNT doesnt require that either)
40
a5c2deba 41allow chars -. 0-9 A-Z [\]^_ a-Z {|} ~: in user and host part of sethost (only change is that : is allowed because of IPv6)
42
0a17908b 43STATS s
44show if spoofhost is valid or not (S = valid, s = invalid)
45removed numbering (not required anymore?)
46merged showing of user@host
47
6fe1b135
P
48diff -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
0a17908b 51@@ -90,7 +90,7 @@
52 #define FlagClr(set,flag) ((set)->bits[FLAGSET_INDEX(flag)] &= ~FLAGSET_MASK(flag))
53
54 /** String containing valid user modes, in no particular order. */
6fe1b135
P
55-#define infousermodes "diOoswkgxRXInP"
56+#define infousermodes "diOoswkghxRXInP"
0a17908b 57
58 /** Character to indicate no oper name available */
59 #define NOOPERNAMECHARACTER '-'
77cdb5de 60@@ -171,6 +171,7 @@
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 */
6fe1b135 68@@ -629,7 +630,8 @@
0a17908b 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))
77cdb5de 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)
0a17908b 75
76 /** Mark a client as having an in-progress net.burst. */
77 #define SetBurst(x) SetFlag(x, FLAG_BURST)
6fe1b135 78@@ -673,6 +675,8 @@
77cdb5de 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). */
6fe1b135 87@@ -718,6 +722,8 @@
77cdb5de 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. */
6fe1b135
P
96diff -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
34145209 99@@ -117,6 +117,8 @@
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)
a5c2deba 103+/** Test whether a character is valid in a sethost - snircd */
34145209 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. */
108@@ -127,4 +129,5 @@
109 #define IsKTimeChar(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_KTIME)
110
111
112+
113 #endif /* INCLUDED_ircd_chattr_h */
6fe1b135
P
114diff -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
0a17908b 117@@ -314,7 +314,7 @@
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 */
123
124 /*
125 * Errors are in the range from 400-599 currently and are grouped by what
6fe1b135
P
126diff -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
0a17908b 129@@ -205,7 +205,8 @@
130
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);
8aa31c50 134+extern struct sline *find_spoofblock(struct Client *cptr, char *host, char *password);
0a17908b 135+extern int apply_spoofblock(struct Client *cptr);
136 extern void free_spoofhost(struct sline *spoof);
137
138 extern void yyerror(const char *msg);
6fe1b135
P
139diff -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
0a17908b 142@@ -79,15 +79,15 @@
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,
151 InfoFormatter fmt);
152
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);
04d03d60 157+extern int is_validsethost(char *user, char *host);
0a17908b 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);
161@@ -102,7 +102,7 @@
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,
6fe1b135
P
170diff -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
0a17908b 173@@ -384,12 +384,12 @@
174 ircd_ntoa_r(iphost, &cli_ip(cptr));
175
176 /* sr is real host if +h */
177- if (HasSetHost(cptr))
178+ if (IsSetHost(cptr))
179 sr = cli_user(cptr)->realhost;
180
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;
186 } else {
187 ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
6fe1b135
P
188diff -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
0a17908b 191@@ -189,7 +189,7 @@
192
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);
198
199 sendto_opmask_butone(0, SNO_OLDSNO, "%s (%s@%s) is now operator (%c) as %s",
6fe1b135
P
200diff -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
23015afc
P
203@@ -126,6 +126,7 @@
204 int what = MODE_ADD;
205 int do_host_hiding = 0;
206 int do_set_host = 0;
207+ int alreadyh = 0;
208
209 /* not from a server */
210 if (!IsServer(sptr))
211@@ -216,17 +217,15 @@
212 break;
213 case 'h':
214 if (what == MODE_ADD) {
215- if (*(p + 1) && is_hostmask(*(p + 1))) {
216- do_set_host = 1;
217- hostmask = *++p;
218- } else {
219- if (!*(p+1))
220- protocol_violation(sptr, "Received REMOTEMODE +h without host parameter for user %C", acptr);
221- else {
222- protocol_violation(sptr, "Received REMOTEMODE +h with invalid host parameter %s for user %C", *(p+1), acptr);
223- p++; /* Swallow the arg anyway */
224- }
225- }
226+ /* TODO: */
227+ if (IsServer(cptr)) {
228+ if (!*(p + 1))
229+ protocol_violation(cptr, "Received MODE +h for %C without sethost parameter", sptr);
230+ else {
231+ hostmask = *++p;
232+ do_set_host = 1;
233+ }
234+ }
235 } else { /* MODE_DEL */
236 do_set_host = 1;
237 hostmask = NULL;
238@@ -275,10 +274,12 @@
239 host = hostmask;
240
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)
245- do_set_host = 0;
246+ if (IsSetHost(acptr)) {
247+ alreadyh = 1;
248+ if ((!user || strcmp(cli_user(acptr)->username, user) == 0) &&
249+ strcmp(cli_user(acptr)->host, host) == 0)
250+ do_set_host = 0;
251+ }
252 }
253
254 /* do host hiding for +h/-h */
255@@ -353,7 +354,7 @@
256 assert(UserStats.inv_clients <= UserStats.clients + UserStats.unknowns);
257
258 /* send out the mode */
259- send_umode_out(acptr, acptr, &setflags, 0);
260+ send_umode_out(acptr, acptr, &setflags, 0, alreadyh);
261
262 return 0;
263 }
6fe1b135
P
264diff -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
23015afc 267@@ -82,175 +82,233 @@
0a17908b 268 #include "config.h"
269
270 #include "client.h"
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"
277+#include "msg.h"
278 #include "msgq.h"
279 #include "numeric.h"
280 #include "s_conf.h"
281+#include "s_debug.h"
282 #include "s_user.h"
283-#include "s_debug.h"
284 #include "send.h"
285 #include "struct.h"
286 #include "numnicks.h"
287
288-#include "channel.h"
289-#include "msg.h"
290-
291-#include <assert.h>
292 #include <stdlib.h>
293
294-/*
295+/**
296 * m_sethost - generic message handler
297 *
298- * mimic old lain syntax:
299+ * SETHOST [<user>@]<host> [<password>]
300 *
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
307 *
308- * check for undo, prepend parv w. <nick> -h or +h
309+ * "MODE <nick> -h" to remove sethost
310+ *
311 */
312 int m_sethost(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
313 {
314- char hostmask[USERLEN + HOSTLEN + 2];
315- char curhostmask[USERLEN + HOSTLEN + 2];
316+ int alreadyh = 0;
317+ int freeform = 0;
318+ char *hostmask;
319+ char *user = NULL;
320+ char *host;
321+ char *password = NULL;
322+ struct Flags setflags;
323+ struct sline *sconf;
324
325- struct Flags setflags;
326+ /* disabled */
327+ if (!feature_bool(FEAT_SETHOST))
328+ return send_reply(sptr, ERR_DISABLED, "SETHOST");
329
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);
334+
335+ /* need hostmask parameter
336+ * and need password parameter from an ordinary user
337+ */
c23d9d77 338+ if (parc < 2 || *parv[1] == 0 || (parc < 3 && !IsAnOper(sptr)))
0a17908b 339+ return need_more_params(sptr, "SETHOST");
340+
341+ hostmask = parv[1];
342+
343+ /* get user and host */
344+ if ((host = strrchr(hostmask, '@'))) {
345+ *host++ = '\0';
346+ user = hostmask;
347+ }
348+ else
349+ host = hostmask;
350+
c23d9d77 351+ /* got a pasword and not empty */
352+ if (parc > 2 && *parv[2])
0a17908b 353+ password = parv[2];
354+
355+ /* freeform - do not bother with password */
356+ if (IsAnOper(sptr) && HasPriv(sptr, PRIV_FREEFORM)) {
357+ freeform = 1;
358+ password = NULL;
359+ }
360+
361+ /* check if user and host are valid */
04d03d60 362+ if (!is_validsethost(user, host))
0a17908b 363+ return send_reply(sptr, ERR_BADHOSTMASK, user ? user : "", user ? "@" : "", host);
364+
365+ /* not freeform */
366+ if (!freeform) {
367+
368+ /* find the spoof block */
369+ if (!(sconf = find_spoofblock(sptr, host, password)))
370+ return send_reply(sptr, ERR_HOSTUNAVAIL, user ? user : "", user ? "@" : "", host);
371+ else
372+ host = (char *)sconf->spoofhost;
373+
374+ /* only freeform allowed to specify user */
375+ user = NULL;
376+ }
377+
378+ /* backup flags */
379 setflags = cli_flags(sptr);
380
381- if (parc < 2)
382- return need_more_params(sptr, "SETHOST");
77cdb5de 383+ /* already +h, clear flag to force mode +h to be sent out again, and clear remote sethost flag */
0a17908b 384+ if (IsSetHost(sptr)) {
385+ FlagClr(&setflags, FLAG_SETHOST);
386+ alreadyh = 1;
77cdb5de 387+ ClearRemoteSetHost(sptr);
0a17908b 388+ }
389
390- if (0 == ircd_strcmp("undo", parv[1])) {
391- set_hostmask(sptr, NULL, NULL);
392- } else {
393- if (parc<3)
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);
399- return 0;
400- }
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);
405- return 0;
406- }
407- }
408- if (set_hostmask(sptr, hostmask, NULL))
409- FlagClr(&setflags, FLAG_SETHOST);
410- } else {
411- if (!is_hostmask(parv[1])) {
412- send_reply(sptr, ERR_BADHOSTMASK, parv[1]);
413- return 0;
414- }
415- if (IsSetHost(sptr) || IsAccount(sptr)) {
416- if (0 == strcmp(parv[1], sptr->cli_user->host)) {
417- send_reply(sptr, RPL_HOSTHIDDEN, parv[1]);
418- return 0;
419- }
420- }
421- if (set_hostmask(sptr, parv[1], parv[2]))
422- FlagClr(&setflags, FLAG_SETHOST);
423- }
424- }
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);
430
431- send_umode_out(cptr, sptr, &setflags, 0);
432+ /* do it */
433+ set_hostmask(sptr, user, host);
434+
435+ /* log freeform */
9ba0fa7c 436+ if (freeform) {
437+
438+ sendto_opmask_butone(0, SNO_OLDSNO,
4b356e8c 439+ "%C SETHOST %s%s%s (freeform)", sptr,
440+ user ? user : "", user ? "@" : "", host);
9ba0fa7c 441+
442+ log_write(LS_SETHOST, L_NOTICE, LOG_NOSNOTICE,
4b356e8c 443+ "%s SETHOST %s%s%s (freeform)", get_client_name(sptr, SHOW_IP),
444+ user ? user : "", user ? "@" : "", host);
9ba0fa7c 445+ }
0a17908b 446+
447+ /* send the mode out */
448+ send_umode_out(cptr, sptr, &setflags, 0, alreadyh);
449+
450 return 0;
451 }
452
453
454-/*
455+
456+/**
457 * ms_sethost - sethost server message handler
458 *
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
465+ *
466+ * undo sethost when spoof username and host are 0
467+ *
468 */
469+ /* TODO: IsRemoteSetHost() */
470 int ms_sethost(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
471 {
472- struct Client *target;
473- char hostmask[USERLEN + HOSTLEN + 2];
474- struct Membership *chan;
475+ int alreadyh = 0;
476+ char *target;
477+ char *user;
478+ char *host;
479+ struct Client *acptr;
480 struct Flags setflags;
481
71300e6b 482+ /* not from a server */
483+ if (!IsServer(sptr))
484+ return protocol_violation(cptr, "Received SETHOST from user %C", sptr);
485+
0a17908b 486+ /* check paramaters */
487 if (parc < 4)
71300e6b 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);
0a17908b 490
71300e6b 491- if (!IsServer(sptr))
492- return protocol_violation(cptr, "SETHOST from non-server %s",
493- cli_name(sptr));
0a17908b 494+ target = parv[1];
495+ user = parv[2];
496+ host = parv[3];
0a17908b 497
498- /* Locate our target user; ignore the message if we can't */
499- if(!(target = findNUser(parv[1])))
500+ /* find user */
501+ if(!(acptr = findNUser(target)))
502 return 0;
503
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));
507-
508- if (!MyConnect(target)) {
509- sendcmdto_one(sptr, CMD_SETHOST, cli_user(target)->server, "%C %s %s", target,
510- parv[2], parv[3]);
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);
514 return 0;
515 }
516
517- /* Back up the flags first */
518- setflags = cli_flags(target);
519- FlagClr(&setflags, FLAG_SETHOST);
520+ /* backup flags */
521+ setflags = cli_flags(acptr);
522
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 */
04d03d60 526+ if (!is_validsethost(user, host))
0a17908b 527+ return protocol_violation(cptr,
71300e6b 528+ "Received SETHOST for %C with invalid user host '%s %s' from %C",
529+ acptr, user, host, sptr);
0a17908b 530+
531+ /* 'user host' is '0 0' - undo sethost */
532+ if (user[0] == '0' && user[1] == '\0' &&
533+ host[0] == '0' && host[1] == '\0') {
534+
535+ /* user has no sethost or has no account
536+ *
1bc74ef7 537+ * user has +h - their host is hidden, do not remove it
0a17908b 538+ * unless the user has an account set
539+ * we should not out of the blue expose the real host
540+ */
541+ if (!IsSetHost(acptr) || !IsAccount(acptr))
542 return 0;
543+
544+ /* user not +x and not allowed to set it */
545+ if (!IsHiddenHost(acptr) && !feature_bool(FEAT_HOST_HIDING))
546+ return 0;
547+
548+ /* set +x */
549+ SetHiddenHost(acptr);
550+ user = NULL;
551+ host = NULL;
552 }
553
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)
561+ return 0;
562
563- sendcmdto_common_channels_butone(target, CMD_QUIT, target, ":Host change");
564-
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);
569-
570- send_reply(target, RPL_HOSTHIDDEN, hostmask);
571-
572- /*
573- * Go through all channels the client was on, rejoin him
574- * and set the modes, if any
575- */
576- for (chan = cli_user(target)->channel; chan; chan = chan->next_channel) {
577- if (IsZombie(chan))
578- continue;
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);
585- } else {
586- sendcmdto_channel_butserv_butone(target, CMD_JOIN, chan->channel, target, 0,
587- "%H", chan->channel);
588- }
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);
595- }
596+ /* already +h, clear flag to force mode +h to be sent out again */
597+ else if (IsSetHost(acptr)) {
598+ FlagClr(&setflags, FLAG_SETHOST);
599+ alreadyh = 1;
600 }
601
602- send_umode_out(target, target, &setflags, 0);
77cdb5de 603+ /* setting remote sethost, set flag */
604+ if (host)
605+ SetRemoteSetHost(acptr);
606+
0a17908b 607+ /* do it */
608+ set_hostmask(acptr, user, host);
609+
610+ /* send out the mode */
611+ send_umode_out(acptr, acptr, &setflags, 0, alreadyh);
612+
613 return 0;
614 }
23015afc 615
6fe1b135
P
616diff -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
0a17908b 619@@ -104,7 +104,7 @@
620 * of +x. If an oper wants the real host, he should go to
621 * /whois to get it.
622 */
623- (HasHiddenHost(cptr) || HasSetHost(cptr)) && (sptr != cptr) ?
624+ (HasHiddenHost(cptr) || IsSetHost(cptr)) && (sptr != cptr) ?
625 cli_user(cptr)->host : cli_user(cptr)->realhost);
626 }
627
6fe1b135
P
628diff -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
0a17908b 631@@ -106,7 +106,7 @@
632 * of +x. If an oper wants the real IP, he should go to
633 * /whois to get it.
634 */
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)));
639 }
6fe1b135
P
640diff -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 @@
0a17908b 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)
650 || !IsAnOper(sptr)
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)))
6fe1b135 660@@ -434,14 +434,14 @@
0a17908b 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)
667 || !IsAnOper(sptr)
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)))
6fe1b135
P
677diff -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
0a17908b 680@@ -214,7 +214,7 @@
681 if (IsAccount(acptr))
682 send_reply(sptr, RPL_WHOISACCOUNT, name, user->account);
683
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)));
688
6fe1b135
P
689diff -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
0a17908b 692@@ -52,6 +52,7 @@
693 #include "s_bsd.h"
694 #include "s_debug.h"
695 #include "s_misc.h"
696+#include "s_user.h"
697 #include "send.h"
698 #include "struct.h"
699 #include "sys.h"
6fe1b135 700@@ -1204,6 +1205,10 @@
cabe24c1 701 return 0;
702 }
703
704+/**
705+ * clear spoof blocks
706+ *
707+ */
708 void clear_slines(void)
709 {
710 struct sline *sline;
6fe1b135 711@@ -1220,61 +1225,164 @@
cabe24c1 712 }
713 }
714
715-/*
716- * conf_check_slines()
0a17908b 717+/**
718+ * find_spoofblock
cabe24c1 719 *
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.
0a17908b 722+ * Find matching spoof block for a user for the given spoofhost and password
cabe24c1 723 *
724- * Precondition
725- * cptr != NULL
0a17908b 726+ * @param cptr User wanting to get a spoof host.
8aa31c50 727+ * @param host Spoof host to look for.
0a17908b 728+ * @param password Password given by user (can be NULL).
cabe24c1 729 *
730- * Returns
731- * 0 = No S-line found
732- * 1 = S-line found and substitution done.
733- *
734- * -mbuna 9/2001
735- * -froo 1/2003
0a17908b 736+ * @return pointer to the matching spoofblock is found, else NULL
cabe24c1 737 *
738 */
8aa31c50 739+struct sline *find_spoofblock(struct Client *cptr, char *host, char *password) {
9ba0fa7c 740
2d34e05c 741-int
742-conf_check_slines(struct Client *cptr)
743-{
744 struct sline *sconf;
745- char *hostonly;
0a17908b 746+ int result = 0;
747+ int r = 0;
2a3660fd 748+ char *error;
9ba0fa7c 749+
8aa31c50 750+ Debug((DEBUG_INFO, "find_spoofblock() cptr=%C host=%s password=%s",
751+ cptr, host, password));
2d34e05c 752
753 for (sconf = GlobalSList; sconf; sconf = sconf->next) {
0a17908b 754+
755+ /* check result of previous loop */
756+ if (r > result)
757+ result = r;
758+
759+ /* check spoofhost */
8aa31c50 760+ if (strcasecmp(sconf->spoofhost, host) != 0)
0a17908b 761+ continue;
762+ r = 1;
763+
764+ /* check cptr's host */
765+ /* cidr mask */
2d34e05c 766 if (sconf->flags == SLINE_FLAGS_IP) {
767 if (!ipmask_check(&(cli_ip(cptr)), &(sconf->address), sconf->bits))
768 continue;
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 */
772- continue;
773- } else {
0a17908b 774+ }
775+
776+ /* hostname */
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 */
2d34e05c 780 continue;
781 }
782
783- if (match(sconf->username, cli_user(cptr)->username) == 0) {
784- /* Ignore user part if u@h. */
785- if ((hostonly = strchr(sconf->spoofhost, '@')))
786- hostonly++;
787- else
788- hostonly = sconf->spoofhost;
0a17908b 789+ /* not cidr or hostname.. */
790+ else
791+ continue;
792+ r = 2;
2d34e05c 793
794- if(!*hostonly)
0a17908b 795+ /* check cptr's username */
796+ if (!EmptyString(sconf->username) && match(sconf->username, cli_user(cptr)->realusername) != 0)
797+ continue;
798+ r = 3;
799+
800+ /* check password */
c23d9d77 801+ if (!EmptyString(password)) {
0a17908b 802+ if (EmptyString(sconf->passwd) || strcmp(sconf->passwd, password) != 0)
803+ continue;
804+ }
805+
806+ /* no password, but need one for this spoofblock */
807+ else if (!EmptyString(sconf->passwd))
808+ continue;
809+
810+ /* got one */
4b356e8c 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");
0a17908b 814+ return sconf;
815+ }
816+
4b356e8c 817+ /* set error messages */
2a3660fd 818+ switch (result) {
819+ case 0:
820+ error = "no such Spoof block";
821+ break;
822+ case 1:
823+ error = "IP / host mismatch";
824+ break;
825+ case 2:
826+ error = "username mismatch";
827+ break;
828+ case 3:
829+ error = password ? "password mismatch" : "password required";
830+ break;
831+ default:
832+ error = "unknown failure";
833+ }
4b356e8c 834+
0a17908b 835+ /* TODO: lookup LOG stuff */
836+ /* TODO: L_INFO LOG_NOSNOTICE */
9ba0fa7c 837+ /* log best result we got */
2a3660fd 838+ log_write(LS_SETHOST, L_INFO, 0, "%s SETHOST %s (failed: %s) [password: %s]",
8aa31c50 839+ get_client_name(cptr, SHOW_IP), host,
4b356e8c 840+ error, password ? "yes" : "no");
0a17908b 841+ return NULL;
842+}
843+
0a17908b 844+/**
845+ * apply_spoofblock
846+ *
847+ * @param cptr User to apply Spoof block to on connect
848+ *
849+ * @return 1 for success, else 0
850+ *
851+ */
2d34e05c 852+int
0a17908b 853+apply_spoofblock(struct Client *cptr)
2d34e05c 854+{
855+ struct sline *sconf;
856+
0a17908b 857+ /* disabled */
858+ if(!feature_bool(FEAT_SETHOST_AUTO))
859+ return 0;
860+
861+ /* go over spoof blocks */
2d34e05c 862+ for (sconf = GlobalSList; sconf; sconf = sconf->next) {
0a17908b 863+
864+ /* check IP */
2d34e05c 865+ if (sconf->flags == SLINE_FLAGS_IP) {
866+ if (!ipmask_check(&(cli_ip(cptr)), &(sconf->address), sconf->bits))
0a17908b 867 continue;
2d34e05c 868
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);
872- return 1;
873- }
0a17908b 874+ /* check host */
2d34e05c 875+ } else if (sconf->flags == SLINE_FLAGS_HOSTNAME) {
876+ if ((match(sconf->realhost, cli_sockhost(cptr)) != 0) &&
0a17908b 877+ (match(sconf->realhost, cli_sock_ip(cptr)) != 0)) /* wildcarded IP address */
2d34e05c 878+ continue;
0a17908b 879+ } else
880+ continue;
2d34e05c 881+
0a17908b 882+ /* check username */
1bdfce7f 883+ if (match(sconf->username, cli_user(cptr)->realusername) != 0)
0a17908b 884+ continue;
2d34e05c 885+
0a17908b 886+ /* invalid */
2d34e05c 887+ if (!is_validsethost(NULL, sconf->spoofhost))
0a17908b 888+ continue;
889+
c7da5b33 890+ /* do it */
2d34e05c 891+ set_hostmask(cptr, NULL, sconf->spoofhost);
c7da5b33 892+
893+ /* TODO: LOG_NOSNOTICE */
894+ /* log it */
895+ log_write(LS_USER, L_INFO, 0, "%s SETHOST %s (auto)",
896+ get_client_name(cptr, SHOW_IP), sconf->spoofhost);
0a17908b 897+ return 1;
898 }
899 return 0;
900 }
901
0a17908b 902+/**
cabe24c1 903+ * free a spoofblock
0a17908b 904+ *
905+ */
906 void free_spoofhost(struct sline *spoof) {
907 MyFree(spoof->spoofhost);
908 MyFree(spoof->passwd);
6fe1b135
P
909diff -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
0a17908b 912@@ -824,13 +824,13 @@
913 /* 395 */
914 { 0 },
915 /* 396 */
916- { RPL_HOSTHIDDEN, "%s :is now your hidden host", "396" },
917+ { RPL_HOSTHIDDEN, "%s%s%s :is now your hidden host", "396" },
918 /* 397 */
919 { 0 },
920 /* 398 */
921- { RPL_STATSSLINE, "%d %s %s %s %s", "398" },
922+ { RPL_STATSSLINE, "%c %s %s %s%s%s", "398" },
923 /* 399 */
924- { RPL_USINGSLINE, ":Using S-line privilege", "399" },
925+ { 0 },
926 /* 400 */
927 { 0 },
928 /* 401 */
929@@ -1092,9 +1092,9 @@
930 /* 529 */
931 { 0 },
932 /* 530 */
933- { ERR_BADHOSTMASK, "%s :Invalid username/hostmask", "530" },
934+ { ERR_BADHOSTMASK, "%s%s%s :Invalid username/hostmask", "530" },
935 /* 531 */
936- { ERR_HOSTUNAVAIL, "%s :sethost not found", "531" },
937+ { ERR_HOSTUNAVAIL, "%s%s%s :Sethost not found", "531" },
938 /* 532 */
939 { 0 },
940 /* 533 */
6fe1b135
P
941diff -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
0a17908b 944@@ -400,41 +400,37 @@
945 }
946 }
947
948+/* TODO: */
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.
953+ */
954 static void
955 stats_sline(struct Client* to, const struct StatDesc* sd, char* param)
956 {
957- int y = 1, i = 1;
958 struct sline *sline;
959
960 if (IsAnOper(to))
961- send_reply(to, SND_EXPLICIT | RPL_TEXT, "# Type Spoofhost Realhost Ident");
962+ send_reply(to, SND_EXPLICIT | RPL_TEXT, "S Type Spoofhost Hostmask");
963 else
964- send_reply(to, SND_EXPLICIT | RPL_TEXT, "# Type Spoofhost");
965+ send_reply(to, SND_EXPLICIT | RPL_TEXT, "S Type Spoofhost");
966
967 for (sline = GlobalSList; sline; sline = sline->next) {
968- if (param && match(param, sline->spoofhost)) { /* narrow search */
969- if (IsAnOper(to))
970- y++;
971- else
972- if (!EmptyString(sline->passwd))
973- y++;
974+
975+ if (param && match(param, sline->spoofhost))
976 continue;
977- }
978
979- if (IsAnOper(to)) {
980- send_reply(to, RPL_STATSSLINE, (param) ? y : i,
981- (EmptyString(sline->passwd)) ? "oper" : "user",
982- sline->spoofhost,
983- (EmptyString(sline->realhost)) ? "" : sline->realhost,
984- (EmptyString(sline->username)) ? "" : sline->username);
985- i++;
986- } else {
987- if (!EmptyString(sline->passwd)) {
988- send_reply(to, RPL_STATSSLINE, (param) ? y : i, "user", sline->spoofhost,
989- "", "", "");
990- i++;
991- }
992- }
993+ if (IsAnOper(to))
994+ send_reply(to, RPL_STATSSLINE,
04d03d60 995+ is_validsethost(NULL, sline->spoofhost) ? 'S' : 's', /* valid show S else s */
0a17908b 996+ (EmptyString(sline->passwd)) ? "Oper" : "User",
997+ sline->spoofhost,
998+ (EmptyString(sline->username)) ? "" : sline->username,
999+ (!EmptyString(sline->username)) ? "@" : "", /* always place a @ after the username */
1000+ (EmptyString(sline->realhost)) ? "" : sline->realhost);
04d03d60 1001+ else if (!EmptyString(sline->passwd) && is_validsethost(NULL, sline->spoofhost))
0a17908b 1002+ send_reply(to, RPL_STATSSLINE, 'S', "User", sline->spoofhost, "", "", "");
1003 }
1004 }
1005
6fe1b135
P
1006diff -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
0a17908b 1009@@ -73,9 +73,6 @@
1010 #include <string.h>
1011 #include <sys/stat.h>
1012
1013-static char *IsVhost(char *hostmask, int oper);
1014-static char *IsVhostPass(char *hostmask);
1015-
1016 /** Count of allocated User structures. */
1017 static int userCount = 0;
1018
1019@@ -373,13 +370,6 @@
1020
1021 if (feature_bool(FEAT_AUTOINVISIBLE))
1022 SetInvisible(sptr);
1023-
1024- if(feature_bool(FEAT_SETHOST_AUTO)) {
1025- if (conf_check_slines(sptr)) {
1026- send_reply(sptr, RPL_USINGSLINE);
1027- SetSetHost(sptr);
1028- }
1029- }
1030
1031 SetUser(sptr);
1032 cli_handler(sptr) = CLIENT_HANDLER;
1033@@ -411,6 +401,10 @@
1034 cli_info(sptr), NumNick(cptr) /* two %s's */);
1035
1036 IPcheck_connect_succeeded(sptr);
1037+
1038+ /* TODO: */
1039+ /* apply auto sethost if needed */
1040+ apply_spoofblock(sptr);
1041 }
1042 else {
1043 struct Client *acptr = user->server;
1044@@ -519,7 +513,7 @@
1045 else
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));
1052 }
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
1058 */
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)
1062 {
1063 int i;
1064 struct Client *acptr;
1065
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);
1068
1069 for (i = HighestFd; i >= 0; i--)
1070 {
1071@@ -890,7 +885,7 @@
1072 sendcmdto_one(sptr, CMD_MODE, acptr, "%s %s", cli_name(sptr), umodeBuf);
1073 }
1074
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);
1077
1078 for (i = HighestFd; i >= 0; i--)
1079 {
1080@@ -900,7 +895,7 @@
1081 }
1082
1083 if (cptr && MyUser(cptr))
1084- send_umode(cptr, sptr, old, ALL_UMODES, 0);
1085+ send_umode(cptr, sptr, old, ALL_UMODES, 0, alreadyh);
1086 }
1087
1088
1089@@ -965,7 +960,7 @@
1090 }
1091
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))
1095 return 0;
1096
1097 sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Registered");
1098@@ -974,7 +969,7 @@
1099
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);
1104
1105 /*
1106 * Go through all channels the client was on, rejoin him
1107@@ -999,201 +994,104 @@
1108 return 0;
1109 }
1110
1111+/* TODO: */
1112 /*
1113 * set_hostmask() - derived from hide_hostmask()
1114 *
1115 */
1116-int set_hostmask(struct Client *cptr, char *hostmask, char *password)
1117+int set_hostmask(struct Client *cptr, char *user, char *host)
1118 {
1119- int restore = 0;
1120- int freeform = 0;
1121- char *host, *new_vhost, *vhost_pass;
1122- char hiddenhost[USERLEN + HOSTLEN + 2];
1123+
1124+ int userchange = 0;
0a17908b 1125+ char *msg = "Host change";
1126 struct Membership *chan;
1127
1128- Debug((DEBUG_INFO, "set_hostmask() %C, %s, %s", cptr, hostmask, password));
1129+ assert(0 != cptr);
1130
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>"));
1136+
1137+ /* remove sethost, but user has none */
1138+ if (!host && !IsSetHost(cptr))
1139 return 0;
1140+
1141+ /* remove sethost, user has +x host, realusername and username are the same
1142+ * pretend the user just set +x
1143+ */
1144+ if (!host && HasHiddenHost(cptr) &&
1145+ strcmp(cli_user(cptr)->username, cli_user(cptr)->realusername) == 0)
1146+ msg = "Registered";
1147+
1148+ /* quit user */
1149+ sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":%s", msg);
1150+
1151+ /* remove sethost */
1152+ if (!host) {
1153+
77cdb5de 1154+ /* clear flags */
0a17908b 1155+ ClearSetHost(cptr);
77cdb5de 1156+ ClearRemoteSetHost(cptr);
0a17908b 1157+
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));
1162+ else
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)
1165+ userchange = 1;
1166+ strncpy(cli_user(cptr)->username, cli_user(cptr)->realusername, USERLEN);
1167 }
1168
1169- /* sethost enabled for users? */
1170- if (MyConnect(cptr) && !IsAnOper(cptr) && !feature_bool(FEAT_SETHOST_USER)) {
1171- send_reply(cptr, ERR_NOPRIVILEGES);
1172- return 0;
1173- }
1174-
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)) {
1179- restore = 1;
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));
1185- else
1186- strncpy(cli_user(cptr)->host, cli_user(cptr)->realhost, HOSTLEN);
1187- strncpy(cli_user(cptr)->username, cli_user(cptr)->realusername, USERLEN);
1188- /* log it */
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);
1193- } else
1194- return 0;
1195- /* MODE_ADD: set a new hostmask */
1196- } else {
1197- /* chop up ident and host.cc */
1198- if ((host = strrchr(hostmask, '@'))) { /* oper can specifiy ident@host.cc */
1199- *host++ = '\0';
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);
1204- return 0;
1205- }
1206- } else { /* user can only specifiy host.cc [password] */
1207- host = hostmask;
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);
1212- return 0;
1213- }
1214- }
1215- /*
1216- * Oper sethost
1217- */
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);
1226- return 0;
1227- } else /* freeform active, log and go */
1228- freeform = 1;
1229- }
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);
1235- /* log it */
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" : "");
1240- /*
1241- * plain user sethost, handled here
1242- */
1243- } else {
1244- /* empty password? */
1245- if (EmptyString(password)) {
1246- send_reply(cptr, ERR_NEEDMOREPARAMS, "MODE");
1247- return 0;
1248- }
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);
1254- return 0;
1255- }
1256- /* no password */
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);
1261- return 0;
1262- }
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);
1268- return 0;
1269- }
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);
1273- /* log it */
1274- log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE, "SETHOST (%s@%s) by (%#R)",
1275- cli_user(cptr)->username, cli_user(cptr)->host, cptr);
1276- }
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);
1282- }
1283+ /* apply sethost */
1284+ else {
1285+
1286+ /* set flag */
1287+ SetSetHost(cptr);
1288+
1289+ /* update user and host */
1290+ if (user)
1291+ strncpy(cli_user(cptr)->username, user, USERLEN);
1292+ strncpy(cli_user(cptr)->host, host, HOSTLEN);
1293 }
1294
1295- if (restore)
1296- ClearSetHost(cptr);
1297- else
1298- SetSetHost(cptr);
1299+ /* tell user */
1300+ if (MyConnect(cptr)) {
1301
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);
1309+
1310+ /* just host changed */
1311+ else
1312+ send_reply(cptr, RPL_HOSTHIDDEN, "", "", cli_user(cptr)->host);
1313 }
1314
1315-#if 0
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. */
1318- /*
1319- * Go through all channels the client was on, rejoin him
1320- * and set the modes, if any
1321- */
1322+ /* go over the channels */
1323 for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) {
1324+
1325+ /* invalidate bans so they are rechecked */
1326+ ClearBanValid(chan);
1327+
1328+ /* zombie */
1329 if (IsZombie(chan))
1330 continue;
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);
1339- }
1340- }
1341-#endif
1342
1343- /*
1344- * Go through all channels the client was on, rejoin him
1345- * and set the modes, if any
1346- */
1347- for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) {
1348- if (IsZombie(chan))
1349- continue;
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);
1356- } else {
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);
1361- }
1362- if (IsChanOp(chan) && HasVoice(chan)) {
1363+
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);
1372- }
1373 }
1374- return 1;
1375+
1376+ return 0;
1377 }
1378
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;
1383 char buf[BUFSIZE];
1384- char *hostmask, *password;
1385+ char *hostmask = NULL;
1386 int prop = 0;
1387 int do_host_hiding = 0;
1388 int do_set_host = 0;
1389+ int alreadyh = 0;
1390 size_t opernamelen;
1391 char *opername = 0;
1392 char* account = NULL;
1393+ char *user = NULL;
1394+ char *host = NULL;
1395
1396- hostmask = password = NULL;
1397 what = MODE_ADD;
1398
1399 if (parc < 3)
1400@@ -1238,8 +1138,7 @@
1401 for (i = 0; i < USERMODELIST_SIZE; i++)
1402 {
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;
1408 }
1409 *m = '\0';
1410@@ -1251,6 +1150,9 @@
1411 return 0;
1412 }
1413
1414+ if (IsSetHost(sptr))
1415+ alreadyh = 1;
1416+
1417 /*
1418 * find flags already set for user
1419 * why not just copy them?
1420@@ -1394,26 +1296,18 @@
1421 break;
1422 case 'h':
1423 if (what == MODE_ADD) {
1424- if (*(p + 1) && is_hostmask(*(p + 1))) {
1425- do_set_host = 1;
1426- hostmask = *++p;
1427- /* DON'T step p onto the trailing NULL in the parameter array! - splidge */
1428- if (*(p+1))
1429- password = *++p;
1430- else
1431- password = NULL;
1432- } else {
1433- if (!*(p+1))
1434- send_reply(sptr, ERR_NEEDMOREPARAMS, "SETHOST");
1435+ /* TODO: */
1436+ if (IsServer(cptr)) {
1437+ if (!*(p + 1))
71300e6b 1438+ protocol_violation(cptr, "Received MODE +h for %C without sethost parameter", sptr);
0a17908b 1439 else {
1440- send_reply(sptr, ERR_BADHOSTMASK, *(p+1));
1441- p++; /* Swallow the arg anyway */
1442+ hostmask = *++p;
1443+ do_set_host = 1;
1444 }
1445 }
1446 } else { /* MODE_DEL */
1447+ hostmask = NULL;
1448 do_set_host = 1;
1449- hostmask = NULL;
1450- password = NULL;
1451 }
1452 break;
1453 case 'R':
77cdb5de 1454@@ -1468,6 +1362,23 @@
0a17908b 1455 if (!FlagHas(&setflags, FLAG_PARANOID) && !(IsOper(sptr) && HasPriv(sptr, PRIV_PARANOID)))
1456 ClearParanoid(sptr);
1457
1458+ /* TODO: */
77cdb5de 1459+ /* setting -h */
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))
1463+ do_set_host = 0;
1464+ /* cannot do -h if user has no account set */
1465+ else if (!IsAccount(sptr))
1466+ do_set_host = 0;
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))
1469+ do_set_host = 0;
1470+ /* all ok, set user +x */
1471+ else
1472+ SetHiddenHost(sptr);
1473+ }
0a17908b 1474+
1475 /*
1476 * only send wallops to opers
1477 */
6fe1b135 1478@@ -1524,11 +1435,38 @@
0a17908b 1479 }
1480 if (!FlagHas(&setflags, FLAG_HIDDENHOST) && do_host_hiding && allow_modes != ALLOWMODES_DEFAULT)
1481 hide_hostmask(sptr, FLAG_HIDDENHOST);
1482+
1483+ /* TODO: */
1484 if (do_set_host) {
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);
1489+
1490+ /* mode -h */
1491+ if (!hostmask)
1492+ set_hostmask(sptr, NULL, NULL);
1493+
1494+ /* mode +h */
1495+ else {
1496+ if ((host = strrchr(hostmask, '@'))) {
1497+ *host++ = '\0';
1498+ user = hostmask;
1499+ }
1500+ else
1501+ host = hostmask;
1502+
77cf570e 1503+ /* dont check if sethost from remote users is valid with is_validsethost(),
1504+ * do check that user and host are not emtpy and
04d03d60 1505+ * do check if they start with a : as things go horribly wrong then
1506+ */
77cf570e 1507+ if (*user == 0 || user[0] == ':' || *host == 0 || host[0] == ':')
71300e6b 1508+ protocol_violation(cptr, "Received MODE +h for %C with an invalid user@host '%s@%s'",
8e8fc2f9 1509+ sptr, user ? user : "", host ? host : "");
0a17908b 1510+
1511+ /* apply it */
1512+ else {
1513+ /* clear flag in old mask so that +h will be sent again */
1514+ FlagClr(&setflags, FLAG_SETHOST);
1515+ set_hostmask(sptr, user, host);
1516+ }
1517+ }
1518 }
1519
1520 if (IsRegistered(sptr)) {
6fe1b135 1521@@ -1580,7 +1518,7 @@
0a17908b 1522 }
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);
1527 }
1528
1529 return 0;
6fe1b135 1530@@ -1655,9 +1593,11 @@
0a17908b 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.
1536 */
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)
1540 {
1541 int i;
1542 int flag;
6fe1b135 1543@@ -1700,12 +1640,15 @@
0a17908b 1544 }
1545 /* Special case for SETHOST.. */
1546 if (flag == FLAG_SETHOST) {
1547- /* Don't send to users */
1548- if (cptr && MyUser(cptr))
1549- continue;
1550-
1551- /* If we're setting +h, add the parameter later */
1552- if (!FlagHas(old, flag))
1553+
1554+ /* do not show +h if client already had it */
1555+ if (cptr && MyUser(cptr) && IsSetHost(cptr) && alreadyh)
1556+ continue;
1557+
1558+ /* If we're setting +h, add the parameter later,
1559+ * but not when showing to the user
1560+ */
1561+ if (!FlagHas(old, flag) && (!cptr || !MyUser(cptr)))
1562 needhost++;
1563 }
1564 if (FlagHas(old, flag))
6fe1b135 1565@@ -1744,7 +1687,7 @@
6fb35586 1566 }
1567 if (needhost) {
1568 *m++ = ' ';
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);
1572 } else
1573 *m = '\0';
6fe1b135 1574@@ -1772,108 +1715,53 @@
0a17908b 1575 return 0;
1576 }
1577
1578- /*
1579- * Check to see if it resembles a valid hostmask.
1580- */
1581-int is_hostmask(char *word)
04d03d60 1582+/* TODO: */
0a17908b 1583+/**
1584+ * Check to see if it resembles a valid sethost.
1585+ *
04d03d60 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
0a17908b 1589+ *
1590+ */
04d03d60 1591+int is_validsethost(char *user, char *host)
0a17908b 1592 {
1593- int i = 0;
1594- char *host;
34145209 1595+ int i; /* loop variable */
0a17908b 1596
1597- Debug((DEBUG_INFO, "is_hostmask() %s", word));
04d03d60 1598+ assert(host != NULL);
1599
0a17908b 1600- if (strlen(word) > (HOSTLEN + USERLEN + 1) || strlen(word) <= 0)
34145209 1601+ /* must not be empty, not longer than HOSTLEN, not start with a : */
04d03d60 1602+ if (*host == 0 || strlen(host) > HOSTLEN || host[0] == ':')
0a17908b 1603 return 0;
1604
1605- /* if a host is specified, make sure it's valid */
1606- host = strrchr(word, '@');
1607- if (host) {
1608- if (strlen(++host) < 1)
1609- return 0;
1610- if (strlen(host) > HOSTLEN)
1611- return 0;
04d03d60 1612+ /* got a user part */
1613+ if (user) {
1614+
34145209 1615+ /* must not be empty, not longer than USERLEN, not start with a : */
1616+ if (*user == 0 || strlen(user) > USERLEN || user[0] == ':')
0a17908b 1617+ return 0;
04d03d60 1618+
34145209 1619+ /* check user chars
1620+ * use IsSetHostChar instead of IsUserChar
04d03d60 1621+ * as the latter allows a lot more chars
1622+ * we dont want in a sethost
1623+ */
1624+ for (i = 0; user[i]; i++) {
34145209 1625+ if (!IsSetHostChar(user[i]))
04d03d60 1626+ return 0;
1627+ }
0a17908b 1628 }
1629
1630- if (word) {
1631- if ('@' == *word) /* no leading @'s */
1632- return 0;
1633-
1634- if ('#' == *word) { /* numeric index given? */
1635- for (word++; *word; word++) {
1636- if (!IsDigit(*word))
1637- return 0;
1638- }
1639- return 1;
1640- }
1641-
1642- /* normal hostmask, account for at most one '@' */
1643- for (; *word; word++) {
1644- if ('@' == *word) {
1645- i++;
1646- continue;
1647- }
1648- if (!IsHostChar(*word))
1649- return 0;
1650- }
1651- return (1 < i) ? 0 : 1; /* no more than on '@' */
1652- }
1653- return 0;
1654-}
1655-
1656- /*
1657- * IsVhost() - Check if given host is a valid spoofhost
1658- * (ie: configured thru a S:line)
1659- */
1660-static char *IsVhost(char *hostmask, int oper)
1661-{
1662- unsigned int i = 0, y = 0;
1663- struct sline *sconf;
1664-
1665- Debug((DEBUG_INFO, "IsVhost() %s", hostmask));
1666-
1667- if (EmptyString(hostmask))
1668- return NULL;
1669-
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))
1675- continue;
1676- if (y == ++i)
1677- return sconf->spoofhost;
1678- }
1679- return NULL;
34145209 1680+ /* check host chars
1681+ * IsSetHostChar allows -. 0-9 A-Z [\]^_ a-Z {|} ~ and :
1682+ */
04d03d60 1683+ for (i = 0; host[i]; i++) {
34145209 1684+ if (!IsSetHostChar(host[i]))
04d03d60 1685+ return 0;
1686 }
1687
0a17908b 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;
34145209 1692-
0a17908b 1693- return NULL;
1694-}
34145209 1695-
0a17908b 1696- /*
1697- * IsVhostPass() - Check if given spoofhost has a password
1698- * associated with it, and if, return the password (cleartext)
1699- */
1700-static char *IsVhostPass(char *hostmask)
1701-{
1702- struct sline *sconf;
1703-
1704- Debug((DEBUG_INFO, "IsVhostPass() %s", hostmask));
1705-
1706- if (EmptyString(hostmask))
1707- return NULL;
1708-
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;
1713- }
1714-
1715- return NULL;
34145209 1716+ /* valid */
0a17908b 1717+ return 1;
1718 }
1719
1720 /** Update snomask \a oldmask according to \a arg and \a what.
6fe1b135
P
1721diff -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
0a17908b 1724@@ -281,7 +281,7 @@
1725 {
1726 case MATCH_HOST:
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));
1730 case MATCH_SERVER:
1731 default:
1732 return (match(mask, cli_name(cli_user(one)->server)) == 0);
6fe1b135
P
1733diff -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
0a17908b 1736@@ -134,7 +134,7 @@
1737
1738 if (fields & WHO_FIELD_NIP)
1739 {
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));
1744 *(p1++) = ' ';
1745@@ -210,7 +210,7 @@
1746 *(p1++) = 'w';
1747 if (SendDebug(acptr))
1748 *(p1++) = 'g';
1749- if (HasSetHost(acptr))
1750+ if (IsSetHost(acptr))
1751 *(p1++) = 'h';
1752 }
1753 if (HasHiddenHost(acptr))