]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blob - sethost.patch
nickgline: include nick! bit in gline loggin
[irc/quakenet/snircd-patchqueue.git] / sethost.patch
1 sethost patch: minor overhaul of sethost system
2
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
7
8 makes usermode +h visible to clients
9
10 removes HasSetHost() macro (was same as IsSetHost())
11
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)
14
15 change syntax to "SETHOST [<user>@]<host> [<password>]"
16
17 disallow client to use MODE +h [<user>@]<host> [<pass>] (bug: mode +h took 2 parameters, even from remote users!)
18
19 sethost can only be unset with "MODE <nick> -h"
20 and only if the sethost was not remotely set by a service (unless the user is an oper)
21 and only if the user has an account set, and is +x (or is allowed to set +x)
22 so the +x host becomes visible, and never the realhost
23
24 sethost #N no longer supported (N being the Nth configured spoof block)
25
26 remote sethost can now be undone by using 0 as username and host,
27 but only when the user has an account set and is allowed by server settings to set mode +x,
28 to avoid revealing the real host out of the blue
29
30 SETHOST now same as OPER
31 modes h and o can only be set with SETHOST and OPER
32 modes h and o are visible to clients
33 modes h and o can only be unset with MODE <nick> -ho
34
35 user sethosts are now also checked against their user@host/ip (and not just the password)
36
37 applying the sethost and syncing of clients (quit user, rejoin user, restore modes on user) is now done in one place
38
39 remote sethost can come from any server, does not need to have a Uworld block or be a service (ACCOUNT doesnt require that either)
40
41 allow chars -. 0-9 A-Z [\]^_ a-Z {|} ~: in user and host part of sethost (only change is that : is allowed because of IPv6)
42
43 STATS s
44 show if spoofhost is valid or not (S = valid, s = invalid)
45 removed numbering (not required anymore?)
46 merged showing of user@host
47
48 diff -r a771a07b5020 include/client.h
49 --- a/include/client.h Sat Jul 20 14:54:11 2013 +0100
50 +++ b/include/client.h Sat Jul 20 14:54:45 2013 +0100
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. */
55 -#define infousermodes "diOoswkgxRXInP"
56 +#define infousermodes "diOoswkghxRXInP"
57
58 /** Character to indicate no oper name available */
59 #define NOOPERNAMECHARACTER '-'
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 */
68 @@ -629,7 +630,8 @@
69 #define HasHiddenHost(x) (IsHiddenHost(x) && IsAccount(x))
70 /** Return non-zero if the client is using a spoofhost */
71 #define IsSetHost(x) HasFlag(x, FLAG_SETHOST)
72 -#define HasSetHost(x) (IsSetHost(x))
73 +/** Return non-zero if the client is using a spoofhost that was set by a service */
74 +#define IsRemoteSetHost(x) HasFlag(x, FLAG_REMOTESETHOST)
75
76 /** Mark a client as having an in-progress net.burst. */
77 #define SetBurst(x) SetFlag(x, FLAG_BURST)
78 @@ -673,6 +675,8 @@
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). */
87 @@ -718,6 +722,8 @@
88 #define ClearHiddenHost(x) ClrFlag(x, FLAG_HIDDENHOST)
89 /** Remove mode +h (spoofhost) from a client. */
90 #define ClearSetHost(x) ClrFlag(x, FLAG_SETHOST)
91 +/** Clear the client's remote SETHOST flag. */
92 +#define ClearRemoteSetHost(x) ClrFlag(x, FLAG_REMOTESETHOST)
93 /** Remove mode +X (xtraop) from a client. */
94 #define ClearXtraOp(x) ClrFlag(x, FLAG_XTRAOP)
95 /** Remove mode +n (hide channels) from a client. */
96 diff -r a771a07b5020 include/ircd_chattr.h
97 --- a/include/ircd_chattr.h Sat Jul 20 14:54:11 2013 +0100
98 +++ b/include/ircd_chattr.h Sat Jul 20 14:54:45 2013 +0100
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)
103 +/** Test whether a character is valid in a sethost - snircd */
104 +#define IsSetHostChar(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & (NTL_IRCHN|NTL_IRCIP6))
105 /** Test whether a character is valid in an IPv4 address. */
106 #define IsIPChar(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCIP)
107 /** Test whether a character is valid in an IPv6 address. */
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 */
114 diff -r a771a07b5020 include/numeric.h
115 --- a/include/numeric.h Sat Jul 20 14:54:11 2013 +0100
116 +++ b/include/numeric.h Sat Jul 20 14:54:45 2013 +0100
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
126 diff -r a771a07b5020 include/s_conf.h
127 --- a/include/s_conf.h Sat Jul 20 14:54:11 2013 +0100
128 +++ b/include/s_conf.h Sat Jul 20 14:54:45 2013 +0100
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);
134 +extern struct sline *find_spoofblock(struct Client *cptr, char *host, char *password);
135 +extern int apply_spoofblock(struct Client *cptr);
136 extern void free_spoofhost(struct sline *spoof);
137
138 extern void yyerror(const char *msg);
139 diff -r a771a07b5020 include/s_user.h
140 --- a/include/s_user.h Sat Jul 20 14:54:11 2013 +0100
141 +++ b/include/s_user.h Sat Jul 20 14:54:45 2013 +0100
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);
157 +extern int is_validsethost(char *user, char *host);
158 extern int set_user_mode(struct Client *cptr, struct Client *sptr,
159 int parc, char *parv[], int allow_modes);
160 extern int is_silenced(struct Client *sptr, struct Client *acptr);
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,
170 diff -r a771a07b5020 ircd/channel.c
171 --- a/ircd/channel.c Sat Jul 20 14:54:11 2013 +0100
172 +++ b/ircd/channel.c Sat Jul 20 14:54:45 2013 +0100
173 @@ -384,12 +384,12 @@
174 ircd_ntoa_r(iphost, &cli_ip(cptr));
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",
188 diff -r a771a07b5020 ircd/m_oper.c
189 --- a/ircd/m_oper.c Sat Jul 20 14:54:11 2013 +0100
190 +++ b/ircd/m_oper.c Sat Jul 20 14:54:45 2013 +0100
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",
200 diff -r a771a07b5020 ircd/m_remotemode.c
201 --- a/ircd/m_remotemode.c Sat Jul 20 14:54:11 2013 +0100
202 +++ b/ircd/m_remotemode.c Sat Jul 20 14:54:45 2013 +0100
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 }
264 diff -r a771a07b5020 ircd/m_sethost.c
265 --- a/ircd/m_sethost.c Sat Jul 20 14:54:11 2013 +0100
266 +++ b/ircd/m_sethost.c Sat Jul 20 14:54:45 2013 +0100
267 @@ -82,175 +82,233 @@
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 + */
338 + if (parc < 2 || *parv[1] == 0 || (parc < 3 && !IsAnOper(sptr)))
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 +
351 + /* got a pasword and not empty */
352 + if (parc > 2 && *parv[2])
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 */
362 + if (!is_validsethost(user, host))
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");
383 + /* already +h, clear flag to force mode +h to be sent out again, and clear remote sethost flag */
384 + if (IsSetHost(sptr)) {
385 + FlagClr(&setflags, FLAG_SETHOST);
386 + alreadyh = 1;
387 + ClearRemoteSetHost(sptr);
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 */
436 + if (freeform) {
437 +
438 + sendto_opmask_butone(0, SNO_OLDSNO,
439 + "%C SETHOST %s%s%s (freeform)", sptr,
440 + user ? user : "", user ? "@" : "", host);
441 +
442 + log_write(LS_SETHOST, L_NOTICE, LOG_NOSNOTICE,
443 + "%s SETHOST %s%s%s (freeform)", get_client_name(sptr, SHOW_IP),
444 + user ? user : "", user ? "@" : "", host);
445 + }
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
482 + /* not from a server */
483 + if (!IsServer(sptr))
484 + return protocol_violation(cptr, "Received SETHOST from user %C", sptr);
485 +
486 + /* check paramaters */
487 if (parc < 4)
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);
490
491 - if (!IsServer(sptr))
492 - return protocol_violation(cptr, "SETHOST from non-server %s",
493 - cli_name(sptr));
494 + target = parv[1];
495 + user = parv[2];
496 + host = parv[3];
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 */
526 + if (!is_validsethost(user, host))
527 + return protocol_violation(cptr,
528 + "Received SETHOST for %C with invalid user host '%s %s' from %C",
529 + acptr, user, host, sptr);
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 + *
537 + * user has +h - their host is hidden, do not remove it
538 + * unless the user has an account set
539 + * we should not out of the blue expose the real host
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);
603 + /* setting remote sethost, set flag */
604 + if (host)
605 + SetRemoteSetHost(acptr);
606 +
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 }
615
616 diff -r a771a07b5020 ircd/m_userhost.c
617 --- a/ircd/m_userhost.c Sat Jul 20 14:54:11 2013 +0100
618 +++ b/ircd/m_userhost.c Sat Jul 20 14:54:45 2013 +0100
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
628 diff -r a771a07b5020 ircd/m_userip.c
629 --- a/ircd/m_userip.c Sat Jul 20 14:54:11 2013 +0100
630 +++ b/ircd/m_userip.c Sat Jul 20 14:54:45 2013 +0100
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 }
640 diff -r a771a07b5020 ircd/m_who.c
641 --- a/ircd/m_who.c Sat Jul 20 14:54:11 2013 +0100
642 +++ b/ircd/m_who.c Sat Jul 20 14:54:45 2013 +0100
643 @@ -395,14 +395,14 @@
644 && ((!(matchsel & WHO_FIELD_HOS))
645 || matchexec(cli_user(acptr)->host, mymask, minlen))
646 && ((!(matchsel & WHO_FIELD_HOS))
647 - || !HasSetHost(acptr)
648 + || !IsSetHost(acptr)
649 || !HasHiddenHost(acptr)
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)))
660 @@ -434,14 +434,14 @@
661 && ((!(matchsel & WHO_FIELD_HOS))
662 || matchexec(cli_user(acptr)->host, mymask, minlen))
663 && ((!(matchsel & WHO_FIELD_HOS))
664 - || !HasSetHost(acptr)
665 + || !IsSetHost(acptr)
666 || !HasHiddenHost(acptr)
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)))
677 diff -r a771a07b5020 ircd/m_whois.c
678 --- a/ircd/m_whois.c Sat Jul 20 14:54:11 2013 +0100
679 +++ b/ircd/m_whois.c Sat Jul 20 14:54:45 2013 +0100
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
689 diff -r a771a07b5020 ircd/s_conf.c
690 --- a/ircd/s_conf.c Sat Jul 20 14:54:11 2013 +0100
691 +++ b/ircd/s_conf.c Sat Jul 20 14:54:45 2013 +0100
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"
700 @@ -1204,6 +1205,10 @@
701 return 0;
702 }
703
704 +/**
705 + * clear spoof blocks
706 + *
707 + */
708 void clear_slines(void)
709 {
710 struct sline *sline;
711 @@ -1220,61 +1225,164 @@
712 }
713 }
714
715 -/*
716 - * conf_check_slines()
717 +/**
718 + * find_spoofblock
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.
722 + * Find matching spoof block for a user for the given spoofhost and password
723 *
724 - * Precondition
725 - * cptr != NULL
726 + * @param cptr User wanting to get a spoof host.
727 + * @param host Spoof host to look for.
728 + * @param password Password given by user (can be NULL).
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
736 + * @return pointer to the matching spoofblock is found, else NULL
737 *
738 */
739 +struct sline *find_spoofblock(struct Client *cptr, char *host, char *password) {
740
741 -int
742 -conf_check_slines(struct Client *cptr)
743 -{
744 struct sline *sconf;
745 - char *hostonly;
746 + int result = 0;
747 + int r = 0;
748 + char *error;
749 +
750 + Debug((DEBUG_INFO, "find_spoofblock() cptr=%C host=%s password=%s",
751 + cptr, host, password));
752
753 for (sconf = GlobalSList; sconf; sconf = sconf->next) {
754 +
755 + /* check result of previous loop */
756 + if (r > result)
757 + result = r;
758 +
759 + /* check spoofhost */
760 + if (strcasecmp(sconf->spoofhost, host) != 0)
761 + continue;
762 + r = 1;
763 +
764 + /* check cptr's host */
765 + /* cidr mask */
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 {
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 */
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;
789 + /* not cidr or hostname.. */
790 + else
791 + continue;
792 + r = 2;
793
794 - if(!*hostonly)
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 */
801 + if (!EmptyString(password)) {
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 */
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");
814 + return sconf;
815 + }
816 +
817 + /* set error messages */
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 + }
834 +
835 + /* TODO: lookup LOG stuff */
836 + /* TODO: L_INFO LOG_NOSNOTICE */
837 + /* log best result we got */
838 + log_write(LS_SETHOST, L_INFO, 0, "%s SETHOST %s (failed: %s) [password: %s]",
839 + get_client_name(cptr, SHOW_IP), host,
840 + error, password ? "yes" : "no");
841 + return NULL;
842 +}
843 +
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 + */
852 +int
853 +apply_spoofblock(struct Client *cptr)
854 +{
855 + struct sline *sconf;
856 +
857 + /* disabled */
858 + if(!feature_bool(FEAT_SETHOST_AUTO))
859 + return 0;
860 +
861 + /* go over spoof blocks */
862 + for (sconf = GlobalSList; sconf; sconf = sconf->next) {
863 +
864 + /* check IP */
865 + if (sconf->flags == SLINE_FLAGS_IP) {
866 + if (!ipmask_check(&(cli_ip(cptr)), &(sconf->address), sconf->bits))
867 continue;
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 - }
874 + /* check host */
875 + } else if (sconf->flags == SLINE_FLAGS_HOSTNAME) {
876 + if ((match(sconf->realhost, cli_sockhost(cptr)) != 0) &&
877 + (match(sconf->realhost, cli_sock_ip(cptr)) != 0)) /* wildcarded IP address */
878 + continue;
879 + } else
880 + continue;
881 +
882 + /* check username */
883 + if (match(sconf->username, cli_user(cptr)->realusername) != 0)
884 + continue;
885 +
886 + /* invalid */
887 + if (!is_validsethost(NULL, sconf->spoofhost))
888 + continue;
889 +
890 + /* do it */
891 + set_hostmask(cptr, NULL, sconf->spoofhost);
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);
897 + return 1;
898 }
899 return 0;
900 }
901
902 +/**
903 + * free a spoofblock
904 + *
905 + */
906 void free_spoofhost(struct sline *spoof) {
907 MyFree(spoof->spoofhost);
908 MyFree(spoof->passwd);
909 diff -r a771a07b5020 ircd/s_err.c
910 --- a/ircd/s_err.c Sat Jul 20 14:54:11 2013 +0100
911 +++ b/ircd/s_err.c Sat Jul 20 14:54:45 2013 +0100
912 @@ -824,13 +824,13 @@
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 */
941 diff -r a771a07b5020 ircd/s_stats.c
942 --- a/ircd/s_stats.c Sat Jul 20 14:54:11 2013 +0100
943 +++ b/ircd/s_stats.c Sat Jul 20 14:54:45 2013 +0100
944 @@ -400,41 +400,37 @@
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,
995 + is_validsethost(NULL, sline->spoofhost) ? 'S' : 's', /* valid show S else s */
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);
1001 + else if (!EmptyString(sline->passwd) && is_validsethost(NULL, sline->spoofhost))
1002 + send_reply(to, RPL_STATSSLINE, 'S', "User", sline->spoofhost, "", "", "");
1003 }
1004 }
1005
1006 diff -r a771a07b5020 ircd/s_user.c
1007 --- a/ircd/s_user.c Sat Jul 20 14:54:11 2013 +0100
1008 +++ b/ircd/s_user.c Sat Jul 20 14:54:45 2013 +0100
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;
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 +
1154 + /* clear flags */
1155 + ClearSetHost(cptr);
1156 + ClearRemoteSetHost(cptr);
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))
1438 + protocol_violation(cptr, "Received MODE +h for %C without sethost parameter", sptr);
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':
1454 @@ -1468,6 +1362,23 @@
1455 if (!FlagHas(&setflags, FLAG_PARANOID) && !(IsOper(sptr) && HasPriv(sptr, PRIV_PARANOID)))
1456 ClearParanoid(sptr);
1457
1458 + /* TODO: */
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 + }
1474 +
1475 /*
1476 * only send wallops to opers
1477 */
1478 @@ -1524,11 +1435,38 @@
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 +
1503 + /* dont check if sethost from remote users is valid with is_validsethost(),
1504 + * do check that user and host are not emtpy and
1505 + * do check if they start with a : as things go horribly wrong then
1506 + */
1507 + if (*user == 0 || user[0] == ':' || *host == 0 || host[0] == ':')
1508 + protocol_violation(cptr, "Received MODE +h for %C with an invalid user@host '%s@%s'",
1509 + sptr, user ? user : "", host ? host : "");
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)) {
1521 @@ -1580,7 +1518,7 @@
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;
1530 @@ -1655,9 +1593,11 @@
1531 * @param[in] old Pre-change set of modes for \a sptr.
1532 * @param[in] sendset One of ALL_UMODES, SEND_UMODES_BUT_OPER,
1533 * SEND_UMODES, to select which changed user modes to send.
1534 + * @param[in] opernames Include opername parameter.
1535 + * @param[in] alreadyh Client already has +h set, do not show +h change.
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;
1543 @@ -1700,12 +1640,15 @@
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))
1565 @@ -1744,7 +1687,7 @@
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';
1574 @@ -1772,108 +1715,53 @@
1575 return 0;
1576 }
1577
1578 - /*
1579 - * Check to see if it resembles a valid hostmask.
1580 - */
1581 -int is_hostmask(char *word)
1582 +/* TODO: */
1583 +/**
1584 + * Check to see if it resembles a valid sethost.
1585 + *
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
1589 + *
1590 + */
1591 +int is_validsethost(char *user, char *host)
1592 {
1593 - int i = 0;
1594 - char *host;
1595 + int i; /* loop variable */
1596
1597 - Debug((DEBUG_INFO, "is_hostmask() %s", word));
1598 + assert(host != NULL);
1599
1600 - if (strlen(word) > (HOSTLEN + USERLEN + 1) || strlen(word) <= 0)
1601 + /* must not be empty, not longer than HOSTLEN, not start with a : */
1602 + if (*host == 0 || strlen(host) > HOSTLEN || host[0] == ':')
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;
1612 + /* got a user part */
1613 + if (user) {
1614 +
1615 + /* must not be empty, not longer than USERLEN, not start with a : */
1616 + if (*user == 0 || strlen(user) > USERLEN || user[0] == ':')
1617 + return 0;
1618 +
1619 + /* check user chars
1620 + * use IsSetHostChar instead of IsUserChar
1621 + * as the latter allows a lot more chars
1622 + * we dont want in a sethost
1623 + */
1624 + for (i = 0; user[i]; i++) {
1625 + if (!IsSetHostChar(user[i]))
1626 + return 0;
1627 + }
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;
1680 + /* check host chars
1681 + * IsSetHostChar allows -. 0-9 A-Z [\]^_ a-Z {|} ~ and :
1682 + */
1683 + for (i = 0; host[i]; i++) {
1684 + if (!IsSetHostChar(host[i]))
1685 + return 0;
1686 }
1687
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;
1692 -
1693 - return NULL;
1694 -}
1695 -
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;
1716 + /* valid */
1717 + return 1;
1718 }
1719
1720 /** Update snomask \a oldmask according to \a arg and \a what.
1721 diff -r a771a07b5020 ircd/send.c
1722 --- a/ircd/send.c Sat Jul 20 14:54:11 2013 +0100
1723 +++ b/ircd/send.c Sat Jul 20 14:54:45 2013 +0100
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);
1733 diff -r a771a07b5020 ircd/whocmds.c
1734 --- a/ircd/whocmds.c Sat Jul 20 14:54:11 2013 +0100
1735 +++ b/ircd/whocmds.c Sat Jul 20 14:54:45 2013 +0100
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))