]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blame - sethost
Remove topic_reveal.patch. This has been fixed in IRCU and ircu patch is correct...
[irc/quakenet/snircd-patchqueue.git] / sethost
CommitLineData
edb26b39
P
1# HG changeset patch
2# Parent 6fd814ecf94bb1713ebf96bffcab63d6c3bdd72b
3
4diff -r 6fd814ecf94b include/client.h
5--- a/include/client.h Fri Jul 19 21:53:51 2013 +0100
6+++ b/include/client.h Fri Jul 19 22:26:20 2013 +0100
7@@ -168,6 +168,7 @@
8 FLAG_ACCOUNTONLY, /**< ASUKA_R: hide privmsgs/notices if
9 user is not authed or opered */
10 FLAG_HIDDENHOST, /**< user's host is hidden */
11+ FLAG_SETHOST, /**< ASUKA_h: oper's host is changed */
12 FLAG_NOCHAN, /**< user's channels are hidden */
13 FLAG_NOIDLE, /**< user's idletime is hidden */
14 FLAG_XTRAOP, /**< oper has special powers */
15@@ -601,6 +602,9 @@
16 #define IsPrivileged(x) (IsAnOper(x) || IsServer(x))
17 /** Return non-zero if the client's host is hidden. */
18 #define HasHiddenHost(x) (IsHiddenHost(x) && IsAccount(x))
19+/** Return non-zero if the client is using a spoofhost */
20+#define IsSetHost(x) HasFlag(x, FLAG_SETHOST)
21+#define HasSetHost(x) (IsSetHost(x))
22
23 /** Mark a client as having an in-progress net.burst. */
24 #define SetBurst(x) SetFlag(x, FLAG_BURST)
25@@ -640,6 +644,8 @@
26 #define SetAccount(x) SetFlag(x, FLAG_ACCOUNT)
27 /** Mark a client as having mode +x (hidden host). */
28 #define SetHiddenHost(x) SetFlag(x, FLAG_HIDDENHOST)
29+/** Mark a client as having mode +h (spoofhost). */
30+#define SetSetHost(x) SetFlag(x, FLAG_SETHOST)
31 /** Mark a client as having mode +X (xtraop). */
32 #define SetXtraOp(x) SetFlag(x, FLAG_XTRAOP)
33 /** Mark a client as having mode +n (hide channels). */
34@@ -681,6 +687,8 @@
35 #define ClearServNotice(x) ClrFlag(x, FLAG_SERVNOTICE)
36 /** Remove mode +x (hidden host) from the client. */
37 #define ClearHiddenHost(x) ClrFlag(x, FLAG_HIDDENHOST)
38+/** Remove mode +h (spoofhost) from a client. */
39+#define ClearSetHost(x) ClrFlag(x, FLAG_SETHOST)
40 /** Remove mode +X (xtraop) from a client. */
41 #define ClearXtraOp(x) ClrFlag(x, FLAG_XTRAOP)
42 /** Remove mode +n (hide channels) from a client. */
43diff -r 6fd814ecf94b include/handlers.h
44--- a/include/handlers.h Fri Jul 19 21:53:51 2013 +0100
45+++ b/include/handlers.h Fri Jul 19 22:26:20 2013 +0100
46@@ -124,6 +124,7 @@
47 extern int m_pseudo(struct Client*, struct Client*, int, char*[]);
48 extern int m_quit(struct Client*, struct Client*, int, char*[]);
49 extern int m_registered(struct Client*, struct Client*, int, char*[]);
50+extern int m_sethost(struct Client*, struct Client*, int, char*[]);
51 extern int m_silence(struct Client*, struct Client*, int, char*[]);
52 extern int m_stats(struct Client*, struct Client*, int, char*[]);
53 extern int m_time(struct Client*, struct Client*, int, char*[]);
54@@ -213,6 +214,7 @@
55 extern int ms_rping(struct Client*, struct Client*, int, char*[]);
56 extern int ms_rpong(struct Client*, struct Client*, int, char*[]);
57 extern int ms_server(struct Client*, struct Client*, int, char*[]);
58+extern int ms_sethost(struct Client*, struct Client*, int, char*[]);
59 extern int ms_settime(struct Client*, struct Client*, int, char*[]);
60 extern int ms_silence(struct Client*, struct Client*, int, char*[]);
61 extern int ms_squit(struct Client*, struct Client*, int, char*[]);
62diff -r 6fd814ecf94b include/ircd_features.h
63--- a/include/ircd_features.h Fri Jul 19 21:53:51 2013 +0100
64+++ b/include/ircd_features.h Fri Jul 19 22:26:20 2013 +0100
65@@ -103,6 +103,9 @@
66
67 /* features that affect all operators */
68 FEAT_CONFIG_OPERCMDS,
69+ FEAT_SETHOST,
70+ FEAT_SETHOST_USER,
71+ FEAT_SETHOST_AUTO,
72
73 /* HEAD_IN_SAND Features */
74 FEAT_HIS_SNOTICES,
75@@ -131,6 +134,7 @@
76 FEAT_HIS_STATS_q,
77 FEAT_HIS_STATS_R,
78 FEAT_HIS_STATS_r,
79+ FEAT_HIS_STATS_s,
80 FEAT_HIS_STATS_t,
81 FEAT_HIS_STATS_T,
82 FEAT_HIS_STATS_u,
83diff -r 6fd814ecf94b include/ircd_log.h
84--- a/include/ircd_log.h Fri Jul 19 21:53:51 2013 +0100
85+++ b/include/ircd_log.h Fri Jul 19 22:26:20 2013 +0100
86@@ -65,6 +65,7 @@
87 LS_SOCKET, /**< Unexpected socket operation errors. */
88 LS_IAUTH, /**< IAuth status. */
89 LS_DEBUG, /**< Debug messages. */
90+ LS_SETHOST, /**< Usage of the sethost command. */
91 LS_LAST_SYSTEM /**< Count of valid LogSys values. */
92 };
93
94diff -r 6fd814ecf94b include/msg.h
95--- a/include/msg.h Fri Jul 19 21:53:51 2013 +0100
96+++ b/include/msg.h Fri Jul 19 22:26:20 2013 +0100
97@@ -356,6 +356,10 @@
98 #define TOK_PRIVS "PR"
99 #define CMD_PRIVS MSG_PRIVS, TOK_PRIVS
100
101+#define MSG_SETHOST "SETHOST" /* SETHOST */
102+#define TOK_SETHOST "SH"
103+#define CMD_SETHOST MSG_SETHOST, TOK_SETHOST
104+
105 #define MSG_CAP "CAP"
106 #define TOK_CAP "CAP"
107 #define CMD_CAP MSG_CAP, TOK_CAP
108diff -r 6fd814ecf94b include/numeric.h
109--- a/include/numeric.h Fri Jul 19 21:53:51 2013 +0100
110+++ b/include/numeric.h Fri Jul 19 22:26:20 2013 +0100
111@@ -207,7 +207,7 @@
112 #define RPL_AWAY 301
113 #define RPL_USERHOST 302
114 #define RPL_ISON 303
115-/* RPL_TEXT 304 unused */
116+#define RPL_TEXT 304 /* unused */
117 #define RPL_UNAWAY 305
118 #define RPL_NOWAWAY 306
119 /* NotAway, aircd */
120@@ -312,6 +312,8 @@
121 /* RPL_END_USERS 394 Dalnet/EFnet/IRCnet */
122 /* RPL_NOUSERS 395 Dalnet/EFnet/IRCnet */
123 #define RPL_HOSTHIDDEN 396 /* UMODE +x completed succesfuly */
124+#define RPL_STATSSLINE 398 /* QuakeNet extension -froo */
125+#define RPL_USINGSLINE 399 /* QuakeNet extension -froo */
126
127 /*
128 * Errors are in the range from 400-599 currently and are grouped by what
129@@ -461,6 +463,9 @@
130 #define ERR_QUARANTINED 524 /* Undernet extension -Vampire */
131 #define ERR_INVALIDKEY 525 /* Undernet extension */
132
133+#define ERR_BADHOSTMASK 530 /* QuakeNet extension -froo */
134+#define ERR_HOSTUNAVAIL 531 /* QuakeNet extension -froo */
135+
136 #define ERR_NOTLOWEROPLEVEL 560 /* Undernet extension */
137 #define ERR_NOTMANAGER 561 /* Undernet extension */
138 #define ERR_CHANSECURED 562 /* Undernet extension */
139diff -r 6fd814ecf94b include/s_conf.h
140--- a/include/s_conf.h Fri Jul 19 21:53:51 2013 +0100
141+++ b/include/s_conf.h Fri Jul 19 22:26:20 2013 +0100
142@@ -80,6 +80,20 @@
143 char *reason; /**< Reason for quarantine. */
144 };
145
146+struct sline {
147+ struct sline *next;
148+ char *spoofhost;
149+ char *passwd;
150+ char *realhost;
151+ char *username;
152+ struct irc_in_addr address;
153+ unsigned int flags;
154+ char bits; /* Number of bits for CIDR match on realhost */
155+};
156+
157+#define SLINE_FLAGS_HOSTNAME 0x0001 /* S-line by hostname */
158+#define SLINE_FLAGS_IP 0x0002 /* S-line by IP address/CIDR */
159+
160 /** Local K-line structure. */
161 struct DenyConf {
162 struct DenyConf* next; /**< Next DenyConf in #denyConfList. */
163@@ -157,6 +171,7 @@
164 extern int GlobalConfCount;
165 extern struct s_map* GlobalServiceMapList;
166 extern struct qline* GlobalQuarantineList;
167+extern struct sline* GlobalSList;
168
169 /*
170 * Proto types
171@@ -188,6 +203,11 @@
172 extern struct ConfItem *conf_debug_iline(const char *client);
173 extern void free_mapping(struct s_map *smap);
174
175+extern void conf_add_sline(const char* const* fields, int count);
176+extern void clear_slines(void);
177+extern int conf_check_slines(struct Client *cptr);
178+extern void free_spoofhost(struct sline *spoof);
179+
180 extern void yyerror(const char *msg);
181
182 #endif /* INCLUDED_s_conf_h */
183diff -r 6fd814ecf94b include/s_user.h
184--- a/include/s_user.h Fri Jul 19 21:53:51 2013 +0100
185+++ b/include/s_user.h Fri Jul 19 22:26:20 2013 +0100
186@@ -80,6 +80,8 @@
187 InfoFormatter fmt);
188
189 extern int hide_hostmask(struct Client *cptr, unsigned int flags);
190+extern int set_hostmask(struct Client *cptr, char *hostmask, char *password);
191+extern int is_hostmask(char *word);
192 extern int set_user_mode(struct Client *cptr, struct Client *sptr,
193 int parc, char *parv[], int allow_modes);
194 extern int is_silenced(struct Client *sptr, struct Client *acptr);
195diff -r 6fd814ecf94b include/struct.h
196--- a/include/struct.h Fri Jul 19 21:53:51 2013 +0100
197+++ b/include/struct.h Fri Jul 19 22:26:20 2013 +0100
198@@ -80,10 +80,11 @@
199 * overwritten with the ident response.
200 */
201 char username[USERLEN + 1];
202- char host[HOSTLEN + 1]; /**< displayed hostname */
203- char realhost[HOSTLEN + 1]; /**< actual hostname */
204- char account[ACCOUNTLEN + 1]; /**< IRC account name */
205- time_t acc_create; /**< IRC account timestamp */
206+ char host[HOSTLEN + 1]; /**< displayed hostname */
207+ char realusername[USERLEN + 1]; /**< actual username */
208+ char realhost[HOSTLEN + 1]; /**< actual hostname */
209+ char account[ACCOUNTLEN + 1]; /**< IRC account name */
210+ time_t acc_create; /**< IRC account timestamp */
211 };
212
213 #endif /* INCLUDED_struct_h */
214diff -r 6fd814ecf94b ircd/Makefile.in
215--- a/ircd/Makefile.in Fri Jul 19 21:53:51 2013 +0100
216+++ b/ircd/Makefile.in Fri Jul 19 22:26:20 2013 +0100
217@@ -167,6 +167,7 @@
218 m_rpong.c \
219 m_server.c \
220 m_set.c \
221+ m_sethost.c \
222 m_settime.c \
223 m_silence.c \
224 m_squit.c \
225diff -r 6fd814ecf94b ircd/channel.c
226--- a/ircd/channel.c Fri Jul 19 21:53:51 2013 +0100
227+++ b/ircd/channel.c Fri Jul 19 22:26:20 2013 +0100
228@@ -374,22 +374,28 @@
229 char tmphost[HOSTLEN + 1];
230 char iphost[SOCKIPLEN + 1];
231 char *hostmask;
232- char *sr;
233+ char *sr = NULL;
234+ char *sa = NULL;
235 struct Ban *found;
236
237 /* Build nick!user and alternate host names. */
238 ircd_snprintf(0, nu, sizeof(nu), "%s!%s",
239 cli_name(cptr), cli_user(cptr)->username);
240 ircd_ntoa_r(iphost, &cli_ip(cptr));
241- if (!IsAccount(cptr))
242- sr = NULL;
243- else if (HasHiddenHost(cptr))
244+
245+ /* sr is real host if +h */
246+ if (HasSetHost(cptr))
247 sr = cli_user(cptr)->realhost;
248- else
249- {
250- ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
251- cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
252- sr = tmphost;
253+
254+ /* if +x and not +h sa is real host, if -x or +h sa is the account host */
255+ if (IsAccount(cptr)) {
256+ if (HasHiddenHost(cptr) && !HasSetHost(cptr)) {
257+ sa = cli_user(cptr)->realhost;
258+ } else {
259+ ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
260+ cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
261+ sa = tmphost;
262+ }
263 }
264
265 /* Walk through ban list. */
266@@ -409,7 +415,8 @@
267 if (!((banlist->flags & BAN_IPMASK)
268 && ipmask_check(&cli_ip(cptr), &banlist->address, banlist->addrbits))
269 && match(hostmask, cli_user(cptr)->host)
270- && !(sr && !match(hostmask, sr)))
271+ && !(sr && !match(hostmask, sr))
272+ && !(sa && !match(hostmask, sa)))
273 continue;
274 /* If an exception matches, no ban can match. */
275 if (banlist->flags & BAN_EXCEPTION)
276diff -r 6fd814ecf94b ircd/gline.c
277--- a/ircd/gline.c Fri Jul 19 21:53:51 2013 +0100
278+++ b/ircd/gline.c Fri Jul 19 22:26:20 2013 +0100
279@@ -221,7 +221,7 @@
280 Debug((DEBUG_DEBUG,"Matched!"));
281 } else { /* Host/IP gline */
282 if (cli_user(acptr)->username &&
283- match(gline->gl_user, (cli_user(acptr))->username) != 0)
284+ match(gline->gl_user, (cli_user(acptr))->realusername) != 0)
285 continue;
286
287 if (GlineIsIpMask(gline)) {
288diff -r 6fd814ecf94b ircd/ircd_features.c
289--- a/ircd/ircd_features.c Fri Jul 19 21:53:51 2013 +0100
290+++ b/ircd/ircd_features.c Fri Jul 19 22:26:20 2013 +0100
291@@ -368,6 +368,9 @@
292
293 /* features that affect all operators */
294 F_B(CONFIG_OPERCMDS, 0, 0, 0),
295+ F_B(SETHOST, 0, 0, 0),
296+ F_B(SETHOST_USER, 0, 0, 0),
297+ F_B(SETHOST_AUTO, 0, 0, 0),
298
299 /* HEAD_IN_SAND Features */
300 F_B(HIS_SNOTICES, 0, 1, 0),
301@@ -396,6 +399,7 @@
302 F_B(HIS_STATS_q, 0, 1, 0),
303 F_B(HIS_STATS_R, 0, 1, 0),
304 F_B(HIS_STATS_r, 0, 1, 0),
305+ F_B(HIS_STATS_s, 0, 1, 0),
306 F_B(HIS_STATS_t, 0, 1, 0),
307 F_B(HIS_STATS_T, 0, 1, 0),
308 F_B(HIS_STATS_u, 0, 0, 0),
309diff -r 6fd814ecf94b ircd/ircd_lexer.l
310--- a/ircd/ircd_lexer.l Fri Jul 19 21:53:51 2013 +0100
311+++ b/ircd/ircd_lexer.l Fri Jul 19 22:26:20 2013 +0100
312@@ -103,6 +103,7 @@
313 TOKEN(USERMODE),
314 TOKEN(FAST),
315 TOKEN(AUTOCONNECT),
316+ TOKEN(SPOOFHOST),
317 TOKEN(PROGRAM),
318 TOKEN(DNS),
319 #undef TOKEN
320diff -r 6fd814ecf94b ircd/ircd_log.c
321--- a/ircd/ircd_log.c Fri Jul 19 21:53:51 2013 +0100
322+++ b/ircd/ircd_log.c Fri Jul 19 22:26:20 2013 +0100
323@@ -164,6 +164,7 @@
324 S(SOCKET, -1, 0),
325 S(IAUTH, -1, SNO_NETWORK),
326 S(DEBUG, -1, SNO_DEBUG),
327+ S(SETHOST, -1, SNO_OLDSNO),
328 #undef S
329 { LS_LAST_SYSTEM, 0, 0, -1, 0, -1, 0 }
330 };
331diff -r 6fd814ecf94b ircd/ircd_parser.y
332--- a/ircd/ircd_parser.y Fri Jul 19 21:53:51 2013 +0100
333+++ b/ircd/ircd_parser.y Fri Jul 19 22:26:20 2013 +0100
334@@ -69,6 +69,7 @@
335 extern struct ServerConf* serverConfList;
336 extern struct s_map* GlobalServiceMapList;
337 extern struct qline* GlobalQuarantineList;
338+ extern struct sline* GlobalSList;
339
340 int yylex(void);
341 /* Now all the globals we need :/... */
342@@ -81,6 +82,7 @@
343 struct DenyConf *dconf;
344 struct ServerConf *sconf;
345 struct s_map *smap;
346+ struct sline *spoof;
347 struct Privs privs;
348 struct Privs privs_dirty;
349
350@@ -173,6 +175,7 @@
351 %token FAST
352 %token AUTOCONNECT
353 %token PROGRAM
354+%token SPOOFHOST
355 %token TOK_IPV4 TOK_IPV6
356 %token DNS
357 /* and now a lot of privileges... */
358@@ -202,7 +205,7 @@
359 block: adminblock | generalblock | classblock | connectblock |
360 uworldblock | operblock | portblock | jupeblock | clientblock |
361 killblock | cruleblock | motdblock | featuresblock | quarantineblock |
362- pseudoblock | iauthblock | error ';';
363+ pseudoblock | iauthblock | spoofblock | error ';';
364
365 /* The timespec, sizespec and expr was ripped straight from
366 * ircd-hybrid-7. */
367@@ -1160,3 +1163,71 @@
368 MyFree(stringlist[stringno]);
369 }
370 } stringlist ';';
371+
372+spoofblock: SPOOFHOST QSTRING '{'
373+{
374+ spoof = MyCalloc(1, sizeof(struct sline));
375+ spoof->spoofhost = $2;
376+ spoof->passwd = NULL;
377+ spoof->realhost = NULL;
378+ spoof->username = NULL;
379+}
380+spoofitems '}' ';'
381+{
382+ struct irc_in_addr ip;
383+ char bits;
384+ int valid = 0;
385+
386+ if (spoof->username == NULL && spoof->realhost) {
387+ parse_error("Username missing in spoofhost.");
388+ } else if (spoof->realhost == NULL && spoof->username) {
389+ parse_error("Realhost missing in spoofhost.");
390+ } else
391+ valid = 1;
392+
393+ if (valid) {
394+ if (spoof->realhost) {
395+ if (!string_has_wildcards(spoof->realhost)) {
396+ if (ipmask_parse(spoof->realhost, &ip, &bits) != 0) {
397+ spoof->address = ip;
398+ spoof->bits = bits;
399+ spoof->flags = SLINE_FLAGS_IP;
400+ } else {
401+ Debug((DEBUG_DEBUG, "S-Line: \"%s\" appears not to be a valid IP address, might be wildcarded.", spoof->realhost));
402+ spoof->flags = SLINE_FLAGS_HOSTNAME;
403+ }
404+ } else
405+ spoof->flags = SLINE_FLAGS_HOSTNAME;
406+ } else
407+ spoof->flags = 0;
408+
409+ spoof->next = GlobalSList;
410+ GlobalSList = spoof;
411+ } else {
412+ MyFree(spoof->spoofhost);
413+ MyFree(spoof->passwd);
414+ MyFree(spoof->realhost);
415+ MyFree(spoof->username);
416+ MyFree(spoof);
417+ }
418+ spoof = NULL;
419+};
420+
421+spoofitems: spoofitem spoofitems | spoofitem;
422+spoofitem: spoofpassword | spoofrealhost | spoofrealident;
423+spoofpassword: PASS '=' QSTRING ';'
424+{
425+ MyFree(spoof->passwd);
426+ spoof->passwd = $3;
427+};
428+spoofrealhost: HOST '=' QSTRING ';'
429+{
430+ MyFree(spoof->realhost);
431+ spoof->realhost = $3;
432+};
433+spoofrealident: USERNAME '=' QSTRING ';'
434+{
435+ MyFree(spoof->username);
436+ spoof->username = $3;
437+};
438+
439diff -r 6fd814ecf94b ircd/ircd_snprintf.c
440--- a/ircd/ircd_snprintf.c Fri Jul 19 21:53:51 2013 +0100
441+++ b/ircd/ircd_snprintf.c Fri Jul 19 22:26:20 2013 +0100
442@@ -180,8 +180,8 @@
443 #define CONV_VARARGS 0x05000000 /**< convert a %v */
444 #define CONV_CLIENT 0x06000000 /**< convert a struct Client */
445 #define CONV_CHANNEL 0x07000000 /**< convert a struct Channel */
446+#define CONV_REAL 0x08000000 /**< convert a struct Client and show realhost */
447
448-#define CONV_RESERVED7 0x08000000 /**< reserved for future expansion */
449 #define CONV_RESERVED6 0x09000000 /**< reserved for future expansion */
450 #define CONV_RESERVED5 0x0a000000 /**< reserved for future expansion */
451 #define CONV_RESERVED4 0x0b000000 /**< reserved for future expansion */
452@@ -1778,6 +1778,11 @@
453 fld_s.flags |= ARG_PTR | CONV_CLIENT;
454 break;
455
456+ case 'R': /* convert a client name... */
457+ fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_ZERO | TYPE_MASK);
458+ fld_s.flags |= ARG_PTR | CONV_REAL;
459+ break;
460+
461 case 'H': /* convert a channel name... */
462 fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_ALT | FLAG_ZERO |
463 FLAG_COLON | TYPE_MASK);
464@@ -2038,7 +2043,8 @@
465
466 vdata->vd_chars = buf_s.buf_loc; /* return relevant data */
467 vdata->vd_overflow = SNP_MAX(buf_s.buf_overflow, buf_s.overflow);
468- } else if ((fld_s.flags & CONV_MASK) == CONV_CLIENT) {
469+ } else if (((fld_s.flags & CONV_MASK) == CONV_CLIENT) ||
470+ ((fld_s.flags & CONV_MASK) == CONV_REAL)) {
471 struct Client *cptr = (struct Client*) fld_s.value.v_ptr;
472 const char *str1 = 0, *str2 = 0, *str3 = 0;
473 int slen1 = 0, slen2 = 0, slen3 = 0, elen = 0, plen = 0;
474@@ -2057,8 +2063,13 @@
475 if (!IsServer(cptr) && !IsMe(cptr) && fld_s.flags & FLAG_ALT) {
476 assert(0 != cli_user(cptr));
477 assert(0 != *(cli_name(cptr)));
478- str2 = cli_user(cptr)->username;
479- str3 = cli_user(cptr)->host;
480+ if ((fld_s.flags & CONV_MASK) == CONV_REAL) {
481+ str2 = cli_user(cptr)->realusername;
482+ str3 = cli_user(cptr)->realhost;
483+ } else {
484+ str2 = cli_user(cptr)->username;
485+ str3 = cli_user(cptr)->host;
486+ }
487 } else
488 fld_s.flags &= ~FLAG_ALT;
489 }
490diff -r 6fd814ecf94b ircd/m_oper.c
491--- a/ircd/m_oper.c Fri Jul 19 21:53:51 2013 +0100
492+++ b/ircd/m_oper.c Fri Jul 19 22:26:20 2013 +0100
493@@ -151,7 +151,7 @@
494 {
495 send_reply(sptr, ERR_NOOPERHOST);
496 sendto_opmask_butone(0, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s)",
497- parv[0], cli_user(sptr)->username, cli_sockhost(sptr));
498+ parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr));
499 return 0;
500 }
501 assert(0 != (aconf->status & CONF_OPERATOR));
502@@ -163,7 +163,7 @@
503 if (ACR_OK != attach_conf(sptr, aconf)) {
504 send_reply(sptr, ERR_NOOPERHOST);
505 sendto_opmask_butone(0, SNO_OLDREALOP, "Failed OPER attempt by %s "
506- "(%s@%s)", parv[0], cli_user(sptr)->username,
507+ "(%s@%s)", parv[0], cli_user(sptr)->realusername,
508 cli_sockhost(sptr));
509 return 0;
510 }
511@@ -187,16 +187,16 @@
512 send_reply(sptr, RPL_YOUREOPER);
513
514 sendto_opmask_butone(0, SNO_OLDSNO, "%s (%s@%s) is now operator (%c)",
515- parv[0], cli_user(sptr)->username, cli_sockhost(sptr),
516+ parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr),
517 IsOper(sptr) ? 'O' : 'o');
518
519- log_write(LS_OPER, L_INFO, 0, "OPER (%s) by (%#C)", name, sptr);
520+ log_write(LS_OPER, L_INFO, 0, "OPER (%s) by (%#R)", name, sptr);
521 }
522 else
523 {
524 send_reply(sptr, ERR_PASSWDMISMATCH);
525 sendto_opmask_butone(0, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s)",
526- parv[0], cli_user(sptr)->username, cli_sockhost(sptr));
527+ parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr));
528 }
529 return 0;
530 }
531diff -r 6fd814ecf94b ircd/m_sethost.c
532--- /dev/null Thu Jan 01 00:00:00 1970 +0000
533+++ b/ircd/m_sethost.c Fri Jul 19 22:26:20 2013 +0100
534@@ -0,0 +1,256 @@
535+/*
536+ * IRC - Internet Relay Chat, ircd/m_sethost.c
537+ * Copyright (C) 1990 Jarkko Oikarinen and
538+ * University of Oulu, Computing Center
539+ *
540+ * See file AUTHORS in IRC package for additional names of
541+ * the programmers.
542+ *
543+ * This program is free software; you can redistribute it and/or modify
544+ * it under the terms of the GNU General Public License as published by
545+ * the Free Software Foundation; either version 1, or (at your option)
546+ * any later version.
547+ *
548+ * This program is distributed in the hope that it will be useful,
549+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
550+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
551+ * GNU General Public License for more details.
552+ *
553+ * You should have received a copy of the GNU General Public License
554+ * along with this program; if not, write to the Free Software
555+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
556+ *
557+ * $Id: asuka-sethost.patch,v 1.27 2005/02/13 17:28:11 froo Exp $
558+ */
559+
560+/*
561+ * m_functions execute protocol messages on this server:
562+ *
563+ * cptr is always NON-NULL, pointing to a *LOCAL* client
564+ * structure (with an open socket connected!). This
565+ * identifies the physical socket where the message
566+ * originated (or which caused the m_function to be
567+ * executed--some m_functions may call others...).
568+ *
569+ * sptr is the source of the message, defined by the
570+ * prefix part of the message if present. If not
571+ * or prefix not found, then sptr==cptr.
572+ *
573+ * (!IsServer(cptr)) => (cptr == sptr), because
574+ * prefixes are taken *only* from servers...
575+ *
576+ * (IsServer(cptr))
577+ * (sptr == cptr) => the message didn't
578+ * have the prefix.
579+ *
580+ * (sptr != cptr && IsServer(sptr) means
581+ * the prefix specified servername. (?)
582+ *
583+ * (sptr != cptr && !IsServer(sptr) means
584+ * that message originated from a remote
585+ * user (not local).
586+ *
587+ * combining
588+ *
589+ * (!IsServer(sptr)) means that, sptr can safely
590+ * taken as defining the target structure of the
591+ * message in this server.
592+ *
593+ * *Always* true (if 'parse' and others are working correct):
594+ *
595+ * 1) sptr->from == cptr (note: cptr->from == cptr)
596+ *
597+ * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
598+ * *cannot* be a local connection, unless it's
599+ * actually cptr!). [MyConnect(x) should probably
600+ * be defined as (x == x->from) --msa ]
601+ *
602+ * parc number of variable parameter strings (if zero,
603+ * parv is allowed to be NULL)
604+ *
605+ * parv a NULL terminated list of parameter pointers,
606+ *
607+ * parv[0], sender (prefix string), if not present
608+ * this points to an empty string.
609+ * parv[1]...parv[parc-1]
610+ * pointers to additional parameters
611+ * parv[parc] == NULL, *always*
612+ *
613+ * note: it is guaranteed that parv[0]..parv[parc-1] are all
614+ * non-NULL pointers.
615+ */
616+#include "config.h"
617+
618+#include "client.h"
619+#include "ircd_reply.h"
620+#include "ircd_string.h"
621+#include "ircd_snprintf.h"
622+#include "ircd_features.h"
623+#include "msgq.h"
624+#include "numeric.h"
625+#include "s_conf.h"
626+#include "s_user.h"
627+#include "s_debug.h"
628+#include "send.h"
629+#include "struct.h"
630+#include "numnicks.h"
631+
632+#include "channel.h"
633+#include "msg.h"
634+
635+#include <assert.h>
636+#include <stdlib.h>
637+
638+/*
639+ * m_sethost - generic message handler
640+ *
641+ * mimic old lain syntax:
642+ *
643+ * (Oper) /SETHOST ident host.cc [quit-message]
644+ * (User) /SETHOST host.cc password
645+ * (Both) /SETHOST undo
646+ *
647+ * check for undo, prepend parv w. <nick> -h or +h
648+ */
649+int m_sethost(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
650+{
651+ char hostmask[USERLEN + HOSTLEN + 2];
652+ char curhostmask[USERLEN + HOSTLEN + 2];
653+
654+ struct Flags setflags;
655+
656+ /* Back up the flags first */
657+ setflags = cli_flags(sptr);
658+
659+ if (parc < 2)
660+ return need_more_params(sptr, "SETHOST");
661+
662+ if (0 == ircd_strcmp("undo", parv[1])) {
663+ set_hostmask(sptr, NULL, NULL);
664+ } else {
665+ if (parc<3)
666+ return need_more_params(sptr, "SETHOST");
667+ if (IsAnOper(sptr)) {
668+ ircd_snprintf(0, hostmask, USERLEN + HOSTLEN + 2, "%s@%s", parv[1], parv[2]);
669+ if (!is_hostmask(hostmask)) {
670+ send_reply(sptr, ERR_BADHOSTMASK, hostmask);
671+ return 0;
672+ }
673+ if (IsSetHost(sptr) || IsAccount(sptr)) {
674+ ircd_snprintf(0, curhostmask, USERLEN + HOSTLEN + 2, "%s@%s", sptr->cli_user->username, sptr->cli_user->host);
675+ if (0 == strcmp(hostmask, curhostmask)) {
676+ send_reply(sptr, RPL_HOSTHIDDEN, curhostmask);
677+ return 0;
678+ }
679+ }
680+ if (set_hostmask(sptr, hostmask, NULL))
681+ FlagClr(&setflags, FLAG_SETHOST);
682+ } else {
683+ if (!is_hostmask(parv[1])) {
684+ send_reply(sptr, ERR_BADHOSTMASK, parv[1]);
685+ return 0;
686+ }
687+ if (IsSetHost(sptr) || IsAccount(sptr)) {
688+ if (0 == strcmp(parv[1], sptr->cli_user->host)) {
689+ send_reply(sptr, RPL_HOSTHIDDEN, parv[1]);
690+ return 0;
691+ }
692+ }
693+ if (set_hostmask(sptr, parv[1], parv[2]))
694+ FlagClr(&setflags, FLAG_SETHOST);
695+ }
696+ }
697+
698+ send_umode_out(cptr, sptr, &setflags, 0);
699+ return 0;
700+}
701+
702+
703+/*
704+ * ms_sethost - sethost server message handler
705+ *
706+ * parv[0] = sender prefix
707+ * parv[1] = target user numeric
708+ * parv[2] = target user's new ident
709+ * parv[3] = target user's new host
710+ */
711+int ms_sethost(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
712+{
713+ struct Client *target;
714+ char hostmask[USERLEN + HOSTLEN + 2];
715+ struct Membership *chan;
716+ struct Flags setflags;
717+
718+ if (parc < 4)
719+ return need_more_params(sptr, "SETHOST");
720+
721+ if (!IsServer(sptr))
722+ return protocol_violation(cptr, "SETHOST from non-server %s",
723+ cli_name(sptr));
724+
725+ /* Locate our target user; ignore the message if we can't */
726+ if(!(target = findNUser(parv[1])))
727+ return 0;
728+
729+ /* Fake host assignments must be from services */
730+ if (!find_conf_byhost(cli_confs(sptr), cli_name(sptr), CONF_UWORLD))
731+ return protocol_violation(cptr, "Non-U:lined server %s set fake host on user %s", cli_name(sptr), cli_name(target));
732+
733+ if (!MyConnect(target)) {
734+ sendcmdto_one(sptr, CMD_SETHOST, cli_user(target)->server, "%C %s %s", target,
735+ parv[2], parv[3]);
736+ return 0;
737+ }
738+
739+ /* Back up the flags first */
740+ setflags = cli_flags(target);
741+ FlagClr(&setflags, FLAG_SETHOST);
742+
743+ if (IsSetHost(target) || IsAccount(target)) {
744+ if ((0 == strcmp(parv[2], target->cli_user->username)) && (0 == strcmp(parv[3], target->cli_user->host)))
745+ return 0;
746+ }
747+
748+ ircd_snprintf(0, hostmask, USERLEN + HOSTLEN + 2, "%s@%s", parv[2], parv[3]);
749+ if (!is_hostmask(hostmask))
750+ return protocol_violation(cptr, "Bad Host mask %s for user %s", hostmask, cli_name(target));
751+
752+ sendcmdto_common_channels_butone(target, CMD_QUIT, target, ":Host change");
753+
754+ /* Assign and propagate the fakehost */
755+ SetSetHost(target);
756+ ircd_strncpy(cli_user(target)->username, parv[2], USERLEN);
757+ ircd_strncpy(cli_user(target)->host, parv[3], HOSTLEN);
758+
759+ send_reply(target, RPL_HOSTHIDDEN, hostmask);
760+
761+ /*
762+ * Go through all channels the client was on, rejoin him
763+ * and set the modes, if any
764+ */
765+ for (chan = cli_user(target)->channel; chan; chan = chan->next_channel) {
766+ if (IsZombie(chan))
767+ continue;
768+ /* If this channel has delayed joins and the user has no modes, just set
769+ * the delayed join flag rather than showing the join, even if the user
770+ * was visible before */
771+ if (!IsChanOp(chan) && !HasVoice(chan)
772+ && (chan->channel->mode.mode & MODE_DELJOINS)) {
773+ SetDelayedJoin(chan);
774+ } else {
775+ sendcmdto_channel_butserv_butone(target, CMD_JOIN, chan->channel, target, 0,
776+ "%H", chan->channel);
777+ }
778+ if (IsChanOp(chan) && HasVoice(chan)) {
779+ sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, target, 0,
780+ "%H +ov %C %C", chan->channel, target, target);
781+ } else if (IsChanOp(chan) || HasVoice(chan)) {
782+ sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, target, 0,
783+ "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', target);
784+ }
785+ }
786+
787+ send_umode_out(target, target, &setflags, 0);
788+ return 0;
789+}
790+
791diff -r 6fd814ecf94b ircd/m_userhost.c
792--- a/ircd/m_userhost.c Fri Jul 19 21:53:51 2013 +0100
793+++ b/ircd/m_userhost.c Fri Jul 19 22:26:20 2013 +0100
794@@ -104,7 +104,7 @@
795 * of +x. If an oper wants the real host, he should go to
796 * /whois to get it.
797 */
798- HasHiddenHost(cptr) && (sptr != cptr) ?
799+ !IsAnOper(sptr) ?
800 cli_user(cptr)->host : cli_user(cptr)->realhost);
801 }
802
803diff -r 6fd814ecf94b ircd/m_userip.c
804--- a/ircd/m_userip.c Fri Jul 19 21:53:51 2013 +0100
805+++ b/ircd/m_userip.c Fri Jul 19 22:26:20 2013 +0100
806@@ -95,6 +95,7 @@
807
808 static void userip_formatter(struct Client* cptr, struct Client *sptr, struct MsgBuf* mb)
809 {
810+ /* !!FIXME!! */
811 assert(IsUser(cptr));
812 msgq_append(0, mb, "%s%s=%c%s@%s", cli_name(cptr),
813 SeeOper(sptr,cptr) ? "*" : "",
814@@ -105,7 +106,7 @@
815 * of +x. If an oper wants the real IP, he should go to
816 * /whois to get it.
817 */
818- HasHiddenHost(cptr) && (sptr != cptr) ?
819+ (HasHiddenHost(cptr) || HasSetHost(cptr)) && !IsAnOper(sptr) ?
820 feature_str(FEAT_HIDDEN_IP) :
821 ircd_ntoa(&cli_ip(cptr)));
822 }
823diff -r 6fd814ecf94b ircd/m_who.c
824--- a/ircd/m_who.c Fri Jul 19 21:53:51 2013 +0100
825+++ b/ircd/m_who.c Fri Jul 19 22:26:20 2013 +0100
826@@ -408,13 +408,14 @@
827 && ((!(matchsel & WHO_FIELD_HOS))
828 || matchexec(cli_user(acptr)->host, mymask, minlen))
829 && ((!(matchsel & WHO_FIELD_HOS))
830+ || !HasSetHost(acptr)
831 || !HasHiddenHost(acptr)
832 || !IsAnOper(sptr)
833 || matchexec(cli_user(acptr)->realhost, mymask, minlen))
834 && ((!(matchsel & WHO_FIELD_REN))
835 || matchexec(cli_info(acptr), mymask, minlen))
836 && ((!(matchsel & WHO_FIELD_NIP))
837- || (HasHiddenHost(acptr) && !IsAnOper(sptr))
838+ || ((HasHiddenHost(acptr) || HasSetHost(acptr)) && !IsAnOper(sptr))
839 || !ipmask_check(&cli_ip(acptr), &imask, ibits))
840 && ((!(matchsel & WHO_FIELD_ACC))
841 || matchexec(cli_user(acptr)->account, mymask, minlen)))
842@@ -446,13 +447,14 @@
843 && ((!(matchsel & WHO_FIELD_HOS))
844 || matchexec(cli_user(acptr)->host, mymask, minlen))
845 && ((!(matchsel & WHO_FIELD_HOS))
846+ || !HasSetHost(acptr)
847 || !HasHiddenHost(acptr)
848 || !IsAnOper(sptr)
849 || matchexec(cli_user(acptr)->realhost, mymask, minlen))
850 && ((!(matchsel & WHO_FIELD_REN))
851 || matchexec(cli_info(acptr), mymask, minlen))
852 && ((!(matchsel & WHO_FIELD_NIP))
853- || (HasHiddenHost(acptr) && !IsAnOper(sptr))
854+ || ((HasHiddenHost(acptr) || HasSetHost(acptr)) && !IsAnOper(sptr))
855 || !ipmask_check(&cli_ip(acptr), &imask, ibits))
856 && ((!(matchsel & WHO_FIELD_ACC))
857 || matchexec(cli_user(acptr)->account, mymask, minlen)))
858diff -r 6fd814ecf94b ircd/m_whois.c
859--- a/ircd/m_whois.c Fri Jul 19 21:53:51 2013 +0100
860+++ b/ircd/m_whois.c Fri Jul 19 22:26:20 2013 +0100
861@@ -211,8 +211,8 @@
862 if (IsAccount(acptr))
863 send_reply(sptr, RPL_WHOISACCOUNT, name, user->account);
864
865- if (HasHiddenHost(acptr) && (IsAnOper(sptr) || acptr == sptr))
866- send_reply(sptr, RPL_WHOISACTUALLY, name, user->username,
867+ if ((HasHiddenHost(acptr) || HasSetHost(acptr)) && (IsAnOper(sptr) || acptr == sptr))
868+ send_reply(sptr, RPL_WHOISACTUALLY, name, user->realusername,
869 user->realhost, ircd_ntoa(&cli_ip(acptr)));
870
871 /* Hint: if your looking to add more flags to a user, eg +h, here's
872diff -r 6fd814ecf94b ircd/parse.c
873--- a/ircd/parse.c Fri Jul 19 21:53:51 2013 +0100
874+++ b/ircd/parse.c Fri Jul 19 22:26:20 2013 +0100
875@@ -618,6 +618,13 @@
876 { m_ignore, m_not_oper, ms_asll, mo_asll, m_ignore }
877 },
878 {
879+ MSG_SETHOST,
880+ TOK_SETHOST,
881+ 0, MAXPARA, MFLG_SLOW, 0, NULL,
882+ /* UNREG, CLIENT, SERVER, OPER, SERVICE */
883+ { m_unregistered, m_sethost, ms_sethost, m_sethost, m_ignore }
884+ },
885+ {
886 MSG_XQUERY,
887 TOK_XQUERY,
888 0, MAXPARA, MFLG_SLOW, 0, NULL,
889diff -r 6fd814ecf94b ircd/s_conf.c
890--- a/ircd/s_conf.c Fri Jul 19 21:53:51 2013 +0100
891+++ b/ircd/s_conf.c Fri Jul 19 22:26:20 2013 +0100
892@@ -74,6 +74,8 @@
893 struct s_map *GlobalServiceMapList;
894 /** Global list of channel quarantines. */
895 struct qline *GlobalQuarantineList;
896+/** Global list of spoofhosts. */
897+struct sline *GlobalSList = 0;
898
899 /** Current line number in scanner input. */
900 int lineno;
901@@ -943,6 +945,7 @@
902 clearNickJupes();
903
904 clear_quarantines();
905+ clear_slines();
906
907 class_mark_delete();
908 mark_listeners_closing();
909@@ -1193,3 +1196,81 @@
910 return 0;
911 }
912
913+void clear_slines(void)
914+{
915+ struct sline *sline;
916+ while ((sline = GlobalSList)) {
917+ GlobalSList = sline->next;
918+ MyFree(sline->spoofhost);
919+ if (!EmptyString(sline->passwd))
920+ MyFree(sline->passwd);
921+ if (!EmptyString(sline->realhost))
922+ MyFree(sline->realhost);
923+ if (!EmptyString(sline->username))
924+ MyFree(sline->username);
925+ MyFree(sline);
926+ }
927+}
928+
929+/*
930+ * conf_check_slines()
931+ *
932+ * Check S lines for the specified client, passed in cptr struct.
933+ * If the client's IP is S-lined, process the substitution here.
934+ *
935+ * Precondition
936+ * cptr != NULL
937+ *
938+ * Returns
939+ * 0 = No S-line found
940+ * 1 = S-line found and substitution done.
941+ *
942+ * -mbuna 9/2001
943+ * -froo 1/2003
944+ *
945+ */
946+
947+int
948+conf_check_slines(struct Client *cptr)
949+{
950+ struct sline *sconf;
951+ char *hostonly;
952+
953+ for (sconf = GlobalSList; sconf; sconf = sconf->next) {
954+ if (sconf->flags == SLINE_FLAGS_IP) {
955+ if (!ipmask_check(&(cli_ip(cptr)), &(sconf->address), sconf->bits))
956+ continue;
957+ } else if (sconf->flags == SLINE_FLAGS_HOSTNAME) {
958+ if ((match(sconf->realhost, cli_sockhost(cptr)) != 0) &&
959+ (match(sconf->realhost, cli_sock_ip(cptr)) != 0)) /* wildcarded IP address */
960+ continue;
961+ } else {
962+ continue;
963+ }
964+
965+ if (match(sconf->username, cli_user(cptr)->username) == 0) {
966+ /* Ignore user part if u@h. */
967+ if ((hostonly = strchr(sconf->spoofhost, '@')))
968+ hostonly++;
969+ else
970+ hostonly = sconf->spoofhost;
971+
972+ if(!*hostonly)
973+ continue;
974+
975+ ircd_strncpy(cli_user(cptr)->host, hostonly, HOSTLEN);
976+ log_write(LS_USER, L_INFO, LOG_NOSNOTICE, "S-Line (%s@%s) by (%#R)",
977+ cli_user(cptr)->username, hostonly, cptr);
978+ return 1;
979+ }
980+ }
981+ return 0;
982+}
983+
984+void free_spoofhost(struct sline *spoof) {
985+ MyFree(spoof->spoofhost);
986+ MyFree(spoof->passwd);
987+ MyFree(spoof->realhost);
988+ MyFree(spoof->username);
989+ MyFree(spoof);
990+}
991diff -r 6fd814ecf94b ircd/s_err.c
992--- a/ircd/s_err.c Fri Jul 19 21:53:51 2013 +0100
993+++ b/ircd/s_err.c Fri Jul 19 22:26:20 2013 +0100
994@@ -640,7 +640,7 @@
995 /* 303 */
996 { RPL_ISON, ":", "303" },
997 /* 304 */
998- { 0 },
999+ { RPL_TEXT, "%s", "304" },
1000 /* 305 */
1001 { RPL_UNAWAY, ":You are no longer marked as being away", "305" },
1002 /* 306 */
1003@@ -828,9 +828,9 @@
1004 /* 397 */
1005 { 0 },
1006 /* 398 */
1007- { 0 },
1008+ { RPL_STATSSLINE, "%d %s %s %s %s", "398" },
1009 /* 399 */
1010- { 0 },
1011+ { RPL_USINGSLINE, ":Using S-line privilege", "399" },
1012 /* 400 */
1013 { 0 },
1014 /* 401 */
1015@@ -1092,9 +1092,9 @@
1016 /* 529 */
1017 { 0 },
1018 /* 530 */
1019- { 0 },
1020+ { ERR_BADHOSTMASK, "%s :Invalid username/hostmask", "530" },
1021 /* 531 */
1022- { 0 },
1023+ { ERR_HOSTUNAVAIL, "%s :sethost not found", "531" },
1024 /* 532 */
1025 { 0 },
1026 /* 533 */
1027diff -r 6fd814ecf94b ircd/s_serv.c
1028--- a/ircd/s_serv.c Fri Jul 19 21:53:51 2013 +0100
1029+++ b/ircd/s_serv.c Fri Jul 19 22:26:20 2013 +0100
1030@@ -247,7 +247,7 @@
1031 sendcmdto_one(cli_user(acptr)->server, CMD_NICK, cptr,
1032 "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
1033 cli_name(acptr), cli_hopcount(acptr) + 1, cli_lastnick(acptr),
1034- cli_user(acptr)->username, cli_user(acptr)->realhost,
1035+ cli_user(acptr)->realusername, cli_user(acptr)->realhost,
1036 *s ? "+" : "", s, *s ? " " : "",
1037 iptobase64(xxx_buf, &cli_ip(acptr), sizeof(xxx_buf), IsIPv6(cptr)),
1038 NumNick(acptr), cli_info(acptr));
1039diff -r 6fd814ecf94b ircd/s_stats.c
1040--- a/ircd/s_stats.c Fri Jul 19 21:53:51 2013 +0100
1041+++ b/ircd/s_stats.c Fri Jul 19 22:26:20 2013 +0100
1042@@ -400,6 +400,44 @@
1043 }
1044 }
1045
1046+static void
1047+stats_sline(struct Client* to, const struct StatDesc* sd, char* param)
1048+{
1049+ int y = 1, i = 1;
1050+ struct sline *sline;
1051+
1052+ if (IsAnOper(to))
1053+ send_reply(to, SND_EXPLICIT | RPL_TEXT, "# Type Spoofhost Realhost Ident");
1054+ else
1055+ send_reply(to, SND_EXPLICIT | RPL_TEXT, "# Type Spoofhost");
1056+
1057+ for (sline = GlobalSList; sline; sline = sline->next) {
1058+ if (param && match(param, sline->spoofhost)) { /* narrow search */
1059+ if (IsAnOper(to))
1060+ y++;
1061+ else
1062+ if (!EmptyString(sline->passwd))
1063+ y++;
1064+ continue;
1065+ }
1066+
1067+ if (IsAnOper(to)) {
1068+ send_reply(to, RPL_STATSSLINE, (param) ? y : i,
1069+ (EmptyString(sline->passwd)) ? "oper" : "user",
1070+ sline->spoofhost,
1071+ (EmptyString(sline->realhost)) ? "" : sline->realhost,
1072+ (EmptyString(sline->username)) ? "" : sline->username);
1073+ i++;
1074+ } else {
1075+ if (!EmptyString(sline->passwd)) {
1076+ send_reply(to, RPL_STATSSLINE, (param) ? y : i, "user", sline->spoofhost,
1077+ "", "", "");
1078+ i++;
1079+ }
1080+ }
1081+ }
1082+}
1083+
1084 /** List service pseudo-command mappings.
1085 * @param[in] to Client requesting statistics.
1086 * @param[in] sd Stats descriptor for request (ignored).
1087@@ -593,6 +631,9 @@
1088 send_usage, 0,
1089 "System resource usage (Debug only)." },
1090 #endif
1091+ { 's', "spoofhosts", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_s,
1092+ stats_sline, 0,
1093+ "Spoofed hosts information." },
1094 { 'T', "motds", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_T,
1095 motd_report, 0,
1096 "Configured Message Of The Day files." },
1097diff -r 6fd814ecf94b ircd/s_user.c
1098--- a/ircd/s_user.c Fri Jul 19 21:53:51 2013 +0100
1099+++ b/ircd/s_user.c Fri Jul 19 22:26:20 2013 +0100
1100@@ -73,6 +73,9 @@
1101 #include <string.h>
1102 #include <sys/stat.h>
1103
1104+static char *IsVhost(char *hostmask, int oper);
1105+static char *IsVhostPass(char *hostmask);
1106+
1107 /** Count of allocated User structures. */
1108 static int userCount = 0;
1109
1110@@ -368,6 +371,13 @@
1111 if (feature_bool(FEAT_AUTOINVISIBLE))
1112 SetInvisible(sptr);
1113
1114+ if(feature_bool(FEAT_SETHOST_AUTO)) {
1115+ if (conf_check_slines(sptr)) {
1116+ send_reply(sptr, RPL_USINGSLINE);
1117+ SetSetHost(sptr);
1118+ }
1119+ }
1120+
1121 SetUser(sptr);
1122 cli_handler(sptr) = CLIENT_HANDLER;
1123 SetLocalNumNick(sptr);
1124@@ -433,6 +443,7 @@
1125 sptr, cli_name(&me));
1126 return exit_client(cptr, sptr, &me,"Too many connections from your host -- throttled");
1127 }
1128+
1129 SetUser(sptr);
1130 }
1131
1132@@ -454,7 +465,7 @@
1133 "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
1134 cli_name(sptr), cli_hopcount(sptr) + 1,
1135 cli_lastnick(sptr),
1136- user->username, user->realhost,
1137+ user->realusername, user->realhost,
1138 *tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
1139 iptobase64(ip_base64, &cli_ip(sptr), sizeof(ip_base64), 1),
1140 NumNick(sptr), cli_info(sptr));
1141@@ -464,7 +475,7 @@
1142 "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
1143 cli_name(sptr), cli_hopcount(sptr) + 1,
1144 cli_lastnick(sptr),
1145- user->username, user->realhost,
1146+ user->realusername, user->realhost,
1147 *tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
1148 iptobase64(ip_base64, &cli_ip(sptr), sizeof(ip_base64), 0),
1149 NumNick(sptr), cli_info(sptr));
1150@@ -506,7 +517,8 @@
1151 { FLAG_ACCOUNTONLY, 'R' },
1152 { FLAG_XTRAOP, 'X' },
1153 { FLAG_NOCHAN, 'n' },
1154- { FLAG_NOIDLE, 'I' }
1155+ { FLAG_NOIDLE, 'I' },
1156+ { FLAG_SETHOST, 'h' }
1157 };
1158
1159 /** Length of #userModeList. */
1160@@ -559,6 +571,7 @@
1161 cli_serv(sptr)->ghost = 0; /* :server NICK means end of net.burst */
1162 ircd_strncpy(cli_username(new_client), parv[4], USERLEN);
1163 ircd_strncpy(cli_user(new_client)->username, parv[4], USERLEN);
1164+ ircd_strncpy(cli_user(new_client)->realusername, parv[4], USERLEN);
1165 ircd_strncpy(cli_user(new_client)->host, parv[5], HOSTLEN);
1166 ircd_strncpy(cli_user(new_client)->realhost, parv[5], HOSTLEN);
1167 ircd_strncpy(cli_info(new_client), parv[parc - 1], REALLEN);
1168@@ -837,7 +850,7 @@
1169 {
1170 if ((acptr = LocalClientArray[i]) && IsServer(acptr) &&
1171 (acptr != cptr) && (acptr != sptr) && *umodeBuf)
1172- sendcmdto_one(sptr, CMD_MODE, acptr, "%s :%s", cli_name(sptr), umodeBuf);
1173+ sendcmdto_one(sptr, CMD_MODE, acptr, "%s %s", cli_name(sptr), umodeBuf);
1174 }
1175 if (cptr && MyUser(cptr))
1176 send_umode(cptr, sptr, old, ALL_UMODES);
1177@@ -905,7 +918,7 @@
1178 }
1179
1180 SetFlag(cptr, flag);
1181- if (!HasFlag(cptr, FLAG_HIDDENHOST) || !HasFlag(cptr, FLAG_ACCOUNT))
1182+ if (!HasFlag(cptr, FLAG_HIDDENHOST) || !HasFlag(cptr, FLAG_ACCOUNT) || HasSetHost(cptr))
1183 return 0;
1184
1185 sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Registered");
1186@@ -939,6 +952,190 @@
1187 return 0;
1188 }
1189
1190+/*
1191+ * set_hostmask() - derived from hide_hostmask()
1192+ *
1193+ */
1194+int set_hostmask(struct Client *cptr, char *hostmask, char *password)
1195+{
1196+ int restore = 0;
1197+ int freeform = 0;
1198+ char *host, *new_vhost, *vhost_pass;
1199+ char hiddenhost[USERLEN + HOSTLEN + 2];
1200+ struct Membership *chan;
1201+
1202+ Debug((DEBUG_INFO, "set_hostmask() %C, %s, %s", cptr, hostmask, password));
1203+
1204+ /* sethost enabled? */
1205+ if (MyConnect(cptr) && !feature_bool(FEAT_SETHOST)) {
1206+ send_reply(cptr, ERR_DISABLED, "SETHOST");
1207+ return 0;
1208+ }
1209+
1210+ /* sethost enabled for users? */
1211+ if (MyConnect(cptr) && !IsAnOper(cptr) && !feature_bool(FEAT_SETHOST_USER)) {
1212+ send_reply(cptr, ERR_NOPRIVILEGES);
1213+ return 0;
1214+ }
1215+
1216+ /* MODE_DEL: restore original hostmask */
1217+ if (EmptyString(hostmask)) {
1218+ /* is already sethost'ed? and only opers can remove a sethost */
1219+ if (IsSetHost(cptr) && IsAnOper(cptr)) {
1220+ restore = 1;
1221+ sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
1222+ /* If they are +rx, we need to return to their +x host, not their "real" host */
1223+ if (HasHiddenHost(cptr))
1224+ ircd_snprintf(0, cli_user(cptr)->host, HOSTLEN, "%s.%s",
1225+ cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
1226+ else
1227+ strncpy(cli_user(cptr)->host, cli_user(cptr)->realhost, HOSTLEN);
1228+ strncpy(cli_user(cptr)->username, cli_user(cptr)->realusername, USERLEN);
1229+ /* log it */
1230+ if (MyConnect(cptr))
1231+ log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE,
1232+ "SETHOST (%s@%s) by (%#R): restoring real hostmask",
1233+ cli_user(cptr)->username, cli_user(cptr)->host, cptr);
1234+ } else
1235+ return 0;
1236+ /* MODE_ADD: set a new hostmask */
1237+ } else {
1238+ /* chop up ident and host.cc */
1239+ if ((host = strrchr(hostmask, '@'))) /* oper can specifiy ident@host.cc */
1240+ *host++ = '\0';
1241+ else /* user can only specifiy host.cc [password] */
1242+ host = hostmask;
1243+ /*
1244+ * Oper sethost
1245+ */
1246+ if (MyConnect(cptr)) {
1247+ if (IsAnOper(cptr)) {
1248+ if ((new_vhost = IsVhost(host, 1)) == NULL) {
1249+ if (!feature_bool(FEAT_SETHOST_FREEFORM)) {
1250+ send_reply(cptr, ERR_HOSTUNAVAIL, hostmask);
1251+ log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE,
1252+ "SETHOST (%s@%s) by (%#R): no such s-line",
1253+ (host != hostmask) ? hostmask : cli_user(cptr)->username, host, cptr);
1254+ return 0;
1255+ } else /* freeform active, log and go */
1256+ freeform = 1;
1257+ }
1258+ sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
1259+ /* set the new ident and host */
1260+ if (host != hostmask) /* oper only specified host.cc */
1261+ strncpy(cli_user(cptr)->username, hostmask, USERLEN);
1262+ strncpy(cli_user(cptr)->host, host, HOSTLEN);
1263+ /* log it */
1264+ log_write(LS_SETHOST, (freeform) ? L_NOTICE : L_INFO,
1265+ (freeform) ? 0 : LOG_NOSNOTICE, "SETHOST (%s@%s) by (%#R)%s",
1266+ cli_user(cptr)->username, cli_user(cptr)->host, cptr,
1267+ (freeform) ? ": using freeform" : "");
1268+ /*
1269+ * plain user sethost, handled here
1270+ */
1271+ } else {
1272+ /* empty password? */
1273+ if (EmptyString(password)) {
1274+ send_reply(cptr, ERR_NEEDMOREPARAMS, "MODE");
1275+ return 0;
1276+ }
1277+ /* no such s-line */
1278+ if ((new_vhost = IsVhost(host, 0)) == NULL) {
1279+ send_reply(cptr, ERR_HOSTUNAVAIL, hostmask);
1280+ log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE, "SETHOST (%s@%s %s) by (%#R): no such s-line",
1281+ cli_user(cptr)->username, host, password, cptr);
1282+ return 0;
1283+ }
1284+ /* no password */
1285+ if ((vhost_pass = IsVhostPass(new_vhost)) == NULL) {
1286+ send_reply(cptr, ERR_PASSWDMISMATCH);
1287+ log_write(LS_SETHOST, L_INFO, 0, "SETHOST (%s@%s %s) by (%#R): trying to use an oper s-line",
1288+ cli_user(cptr)->username, host, password, cptr);
1289+ return 0;
1290+ }
1291+ /* incorrect password */
1292+ if (strCasediff(vhost_pass, password)) {
1293+ send_reply(cptr, ERR_PASSWDMISMATCH);
1294+ log_write(LS_SETHOST, L_NOTICE, 0, "SETHOST (%s@%s %s) by (%#R): incorrect password",
1295+ cli_user(cptr)->username, host, password, cptr);
1296+ return 0;
1297+ }
1298+ sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
1299+ /* set the new host */
1300+ strncpy(cli_user(cptr)->host, new_vhost, HOSTLEN);
1301+ /* log it */
1302+ log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE, "SETHOST (%s@%s) by (%#R)",
1303+ cli_user(cptr)->username, cli_user(cptr)->host, cptr);
1304+ }
1305+ } else { /* remote user */
1306+ sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
1307+ if (host != hostmask) /* oper only specified host.cc */
1308+ strncpy(cli_user(cptr)->username, hostmask, USERLEN);
1309+ strncpy(cli_user(cptr)->host, host, HOSTLEN);
1310+ }
1311+ }
1312+
1313+ if (restore)
1314+ ClearSetHost(cptr);
1315+ else
1316+ SetSetHost(cptr);
1317+
1318+ if (MyConnect(cptr)) {
1319+ ircd_snprintf(0, hiddenhost, HOSTLEN + USERLEN + 2, "%s@%s",
1320+ cli_user(cptr)->username, cli_user(cptr)->host);
1321+ send_reply(cptr, RPL_HOSTHIDDEN, hiddenhost);
1322+ }
1323+
1324+#if 0
1325+ /* Code copied from hide_hostmask(). This is the old (pre-delayedjoin)
1326+ * version. Switch this in if you're not using the delayed join patch. */
1327+ /*
1328+ * Go through all channels the client was on, rejoin him
1329+ * and set the modes, if any
1330+ */
1331+ for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) {
1332+ if (IsZombie(chan))
1333+ continue;
1334+ sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr,
1335+ "%H", chan->channel);
1336+ if (IsChanOp(chan) && HasVoice(chan)) {
1337+ sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr,
1338+ "%H +ov %C %C", chan->channel, cptr, cptr);
1339+ } else if (IsChanOp(chan) || HasVoice(chan)) {
1340+ sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr,
1341+ "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr);
1342+ }
1343+ }
1344+#endif
1345+
1346+ /*
1347+ * Go through all channels the client was on, rejoin him
1348+ * and set the modes, if any
1349+ */
1350+ for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) {
1351+ if (IsZombie(chan))
1352+ continue;
1353+ /* If this channel has delayed joins and the user has no modes, just set
1354+ * the delayed join flag rather than showing the join, even if the user
1355+ * was visible before */
1356+ if (!IsChanOp(chan) && !HasVoice(chan)
1357+ && (chan->channel->mode.mode & MODE_DELJOINS)) {
1358+ SetDelayedJoin(chan);
1359+ } else {
1360+ sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr, 0,
1361+ "%H", chan->channel);
1362+ }
1363+ if (IsChanOp(chan) && HasVoice(chan)) {
1364+ sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr, 0,
1365+ "%H +ov %C %C", chan->channel, cptr, cptr);
1366+ } else if (IsChanOp(chan) || HasVoice(chan)) {
1367+ sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr, 0,
1368+ "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr);
1369+ }
1370+ }
1371+ return 1;
1372+}
1373+
1374 /** Set a user's mode. This function checks that \a cptr is trying to
1375 * set his own mode, prevents local users from setting inappropriate
1376 * modes through this function, and applies any other side effects of
1377@@ -965,6 +1162,7 @@
1378 char buf[BUFSIZE];
1379 int prop = 0;
1380 int do_host_hiding = 0;
1381+ int do_set_host = 0;
1382 char* account = NULL;
1383
1384 what = MODE_ADD;
1385@@ -976,7 +1174,8 @@
1386 for (i = 0; i < USERMODELIST_SIZE; i++)
1387 {
1388 if (HasFlag(sptr, userModeList[i].flag) &&
1389- userModeList[i].flag != FLAG_ACCOUNT)
1390+ ((userModeList[i].flag != FLAG_ACCOUNT) &&
1391+ (userModeList[i].flag != FLAG_SETHOST)))
1392 *m++ = userModeList[i].c;
1393 }
1394 *m = '\0';
1395@@ -1103,6 +1302,30 @@
1396 if (what == MODE_ADD)
1397 do_host_hiding = 1;
1398 break;
1399+ case 'h':
1400+ if (what == MODE_ADD) {
1401+ if (*(p + 1) && is_hostmask(*(p + 1))) {
1402+ do_set_host = 1;
1403+ hostmask = *++p;
1404+ /* DON'T step p onto the trailing NULL in the parameter array! - splidge */
1405+ if (*(p+1))
1406+ password = *++p;
1407+ else
1408+ password = NULL;
1409+ } else {
1410+ if (!*(p+1))
1411+ send_reply(sptr, ERR_NEEDMOREPARAMS, "SETHOST");
1412+ else {
1413+ send_reply(sptr, ERR_BADHOSTMASK, *(p+1));
1414+ p++; /* Swallow the arg anyway */
1415+ }
1416+ }
1417+ } else { /* MODE_DEL */
1418+ do_set_host = 1;
1419+ hostmask = NULL;
1420+ password = NULL;
1421+ }
1422+ break;
1423 case 'r':
1424 if (*(p + 1) && (what == MODE_ADD)) {
1425 account = *(++p);
1426@@ -1269,10 +1492,15 @@
1427 while ((*m++ = *t++))
1428 ; /* Empty loop */
1429 }
1430+ m--; /* Step back over the '\0' */
1431 }
1432
1433- *m = '\0';
1434-
1435+ if (IsSetHost(cptr)) {
1436+ *m++ = ' ';
1437+ ircd_snprintf(0, m, USERLEN + HOSTLEN + 2, "%s@%s", cli_user(cptr)->username,
1438+ cli_user(cptr)->host);
1439+ } else
1440+ *m = '\0';
1441 return umodeBuf; /* Note: static buffer, gets
1442 overwritten by send_umode() */
1443 }
1444@@ -1289,6 +1517,7 @@
1445 {
1446 int i;
1447 int flag;
1448+ int needhost = 0;
1449 char *m;
1450 int what = MODE_NULL;
1451
1452@@ -1318,6 +1547,16 @@
1453 continue;
1454 break;
1455 }
1456+ /* Special case for SETHOST.. */
1457+ if (flag == FLAG_SETHOST) {
1458+ /* Don't send to users */
1459+ if (cptr && MyUser(cptr))
1460+ continue;
1461+
1462+ /* If we're setting +h, add the parameter later */
1463+ if (!FlagHas(old, flag))
1464+ needhost++;
1465+ }
1466 if (FlagHas(old, flag))
1467 {
1468 if (what == MODE_DEL)
1469@@ -1341,9 +1580,14 @@
1470 }
1471 }
1472 }
1473- *m = '\0';
1474+ if (needhost) {
1475+ *m++ = ' ';
1476+ ircd_snprintf(0, m, USERLEN + HOSTLEN + 1, "%s@%s", cli_user(sptr)->username,
1477+ cli_user(sptr)->host);
1478+ } else
1479+ *m = '\0';
1480 if (*umodeBuf && cptr)
1481- sendcmdto_one(sptr, CMD_MODE, cptr, "%s :%s", cli_name(sptr), umodeBuf);
1482+ sendcmdto_one(sptr, CMD_MODE, cptr, "%s %s", cli_name(sptr), umodeBuf);
1483 }
1484
1485 /**
1486@@ -1366,6 +1610,110 @@
1487 return 0;
1488 }
1489
1490+ /*
1491+ * Check to see if it resembles a valid hostmask.
1492+ */
1493+int is_hostmask(char *word)
1494+{
1495+ int i = 0;
1496+ char *host;
1497+
1498+ Debug((DEBUG_INFO, "is_hostmask() %s", word));
1499+
1500+ if (strlen(word) > (HOSTLEN + USERLEN + 1) || strlen(word) <= 0)
1501+ return 0;
1502+
1503+ /* if a host is specified, make sure it's valid */
1504+ host = strrchr(word, '@');
1505+ if (host) {
1506+ if (strlen(++host) < 1)
1507+ return 0;
1508+ if (strlen(host) > HOSTLEN)
1509+ return 0;
1510+ }
1511+
1512+ if (word) {
1513+ if ('@' == *word) /* no leading @'s */
1514+ return 0;
1515+
1516+ if ('#' == *word) { /* numeric index given? */
1517+ for (word++; *word; word++) {
1518+ if (!IsDigit(*word))
1519+ return 0;
1520+ }
1521+ return 1;
1522+ }
1523+
1524+ /* normal hostmask, account for at most one '@' */
1525+ for (; *word; word++) {
1526+ if ('@' == *word) {
1527+ i++;
1528+ continue;
1529+ }
1530+ if (!IsHostChar(*word))
1531+ return 0;
1532+ }
1533+ return (1 < i) ? 0 : 1; /* no more than on '@' */
1534+ }
1535+ return 0;
1536+}
1537+
1538+ /*
1539+ * IsVhost() - Check if given host is a valid spoofhost
1540+ * (ie: configured thru a S:line)
1541+ */
1542+static char *IsVhost(char *hostmask, int oper)
1543+{
1544+ unsigned int i = 0, y = 0;
1545+ struct sline *sconf;
1546+
1547+ Debug((DEBUG_INFO, "IsVhost() %s", hostmask));
1548+
1549+ if (EmptyString(hostmask))
1550+ return NULL;
1551+
1552+ /* spoofhost specified as index, ie: #27 */
1553+ if ('#' == hostmask[0]) {
1554+ y = atoi(hostmask + 1);
1555+ for (i = 0, sconf = GlobalSList; sconf; sconf = sconf->next) {
1556+ if (!oper && EmptyString(sconf->passwd))
1557+ continue;
1558+ if (y == ++i)
1559+ return sconf->spoofhost;
1560+ }
1561+ return NULL;
1562+ }
1563+
1564+ /* spoofhost specified as host, ie: host.cc */
1565+ for (sconf = GlobalSList; sconf; sconf = sconf->next)
1566+ if (strCasediff(hostmask, sconf->spoofhost) == 0)
1567+ return sconf->spoofhost;
1568+
1569+ return NULL;
1570+}
1571+
1572+ /*
1573+ * IsVhostPass() - Check if given spoofhost has a password
1574+ * associated with it, and if, return the password (cleartext)
1575+ */
1576+static char *IsVhostPass(char *hostmask)
1577+{
1578+ struct sline *sconf;
1579+
1580+ Debug((DEBUG_INFO, "IsVhostPass() %s", hostmask));
1581+
1582+ if (EmptyString(hostmask))
1583+ return NULL;
1584+
1585+ for (sconf = GlobalSList; sconf; sconf = sconf->next)
1586+ if (strCasediff(hostmask, sconf->spoofhost) == 0) {
1587+ Debug((DEBUG_INFO, "sconf->passwd %s", sconf->passwd));
1588+ return EmptyString(sconf->passwd) ? NULL : sconf->passwd;
1589+ }
1590+
1591+ return NULL;
1592+}
1593+
1594 /** Update snomask \a oldmask according to \a arg and \a what.
1595 * @param[in] oldmask Original user mask.
1596 * @param[in] arg Update string (either a number or '+'/'-' followed by a number).
1597diff -r 6fd814ecf94b ircd/send.c
1598--- a/ircd/send.c Fri Jul 19 21:53:51 2013 +0100
1599+++ b/ircd/send.c Fri Jul 19 22:26:20 2013 +0100
1600@@ -281,7 +281,7 @@
1601 {
1602 case MATCH_HOST:
1603 return (match(mask, cli_user(one)->host) == 0 ||
1604- (HasHiddenHost(one) && match(mask, cli_user(one)->realhost) == 0));
1605+ ((HasHiddenHost(one) || HasSetHost(one)) && match(mask, cli_user(one)->realhost) == 0));
1606 case MATCH_SERVER:
1607 default:
1608 return (match(mask, cli_name(cli_user(one)->server)) == 0);
1609diff -r 6fd814ecf94b ircd/whocmds.c
1610--- a/ircd/whocmds.c Fri Jul 19 21:53:51 2013 +0100
1611+++ b/ircd/whocmds.c Fri Jul 19 22:26:20 2013 +0100
1612@@ -129,7 +129,7 @@
1613
1614 if (fields & WHO_FIELD_NIP)
1615 {
1616- const char* p2 = HasHiddenHost(acptr) && !IsAnOper(sptr) ?
1617+ const char* p2 = (HasHiddenHost(acptr) || HasSetHost(acptr)) && !IsAnOper(sptr) ?
1618 feature_str(FEAT_HIDDEN_IP) :
1619 ircd_ntoa(&cli_ip(acptr));
1620 *(p1++) = ' ';
1621@@ -205,6 +205,8 @@
1622 *(p1++) = 'w';
1623 if (SendDebug(acptr))
1624 *(p1++) = 'g';
1625+ if (HasSetHost(acptr))
1626+ *(p1++) = 'h';
1627 }
1628 if (HasHiddenHost(acptr))
1629 *(p1++) = 'x';
1630diff -r 6fd814ecf94b tools/convert_slines.sh
1631--- /dev/null Thu Jan 01 00:00:00 1970 +0000
1632+++ b/tools/convert_slines.sh Fri Jul 19 22:26:20 2013 +0100
1633@@ -0,0 +1,50 @@
1634+#!/bin/sh
1635+#
1636+# $Id: asuka-sethost.patch,v 1.29 2005/02/24 01:06:52 froo Exp $
1637+#
1638+# aid in converting S: and F:lines from old lain configs
1639+# to the new "super S:line" format of asuka.
1640+#
1641+# When Who What
1642+# 2003-01-05 froo@quakenet.org Created.
1643+
1644+PATH=/bin:/usr/bin
1645+PROG=`basename $0`
1646+USAGE="Usage: $PROG </path/to/ircd.cfg>"
1647+
1648+if [ $# -lt 1 ]; then
1649+ echo $USAGE
1650+ exit
1651+fi
1652+
1653+CONFIG=$1
1654+
1655+if [ ! -f $CONFIG ]; then
1656+ echo "Can't open \"$CONFIG\", bailing out."
1657+ exit
1658+fi
1659+
1660+{
1661+for LINE in `grep -E "^F:" $CONFIG`
1662+do
1663+ IDENT=`echo $LINE | cut -f2 -d:`
1664+ REALHOST=`echo $LINE | cut -f3 -d:`
1665+ SPOOFHOST=`echo $LINE | cut -f4 -d:`
1666+
1667+ IDENT=`echo $IDENT | sed -e 's,^~,\*,'`
1668+
1669+ echo "S:$SPOOFHOST::$REALHOST:$IDENT"
1670+done
1671+
1672+for LINE in `grep -E "^S:" $CONFIG`
1673+do
1674+ SPOOFHOST=`echo $LINE | cut -f2 -d:`
1675+ PASSWD=`echo $LINE | cut -f3 -d:`
1676+
1677+ IDENT=`echo $IDENT | sed -e 's,^~,\*,'`
1678+
1679+ echo "S:$SPOOFHOST:$PASSWD::"
1680+done
1681+} | sort
1682+
1683+exit 0