2 # Parent 6fd814ecf94bb1713ebf96bffcab63d6c3bdd72b
4 diff -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
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 */
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))
23 /** Mark a client as having an in-progress net.burst. */
24 #define SetBurst(x) SetFlag(x, FLAG_BURST)
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). */
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. */
43 diff -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
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*[]);
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*[]);
62 diff -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
67 /* features that affect all operators */
73 /* HEAD_IN_SAND Features */
83 diff -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
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. */
94 diff -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
98 #define TOK_PRIVS "PR"
99 #define CMD_PRIVS MSG_PRIVS, TOK_PRIVS
101 +#define MSG_SETHOST "SETHOST" /* SETHOST */
102 +#define TOK_SETHOST "SH"
103 +#define CMD_SETHOST MSG_SETHOST, TOK_SETHOST
105 #define MSG_CAP "CAP"
106 #define TOK_CAP "CAP"
107 #define CMD_CAP MSG_CAP, TOK_CAP
108 diff -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
113 #define RPL_USERHOST 302
115 -/* RPL_TEXT 304 unused */
116 +#define RPL_TEXT 304 /* unused */
117 #define RPL_UNAWAY 305
118 #define RPL_NOWAWAY 306
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 */
128 * Errors are in the range from 400-599 currently and are grouped by what
130 #define ERR_QUARANTINED 524 /* Undernet extension -Vampire */
131 #define ERR_INVALIDKEY 525 /* Undernet extension */
133 +#define ERR_BADHOSTMASK 530 /* QuakeNet extension -froo */
134 +#define ERR_HOSTUNAVAIL 531 /* QuakeNet extension -froo */
136 #define ERR_NOTLOWEROPLEVEL 560 /* Undernet extension */
137 #define ERR_NOTMANAGER 561 /* Undernet extension */
138 #define ERR_CHANSECURED 562 /* Undernet extension */
139 diff -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
143 char *reason; /**< Reason for quarantine. */
147 + struct sline *next;
152 + struct irc_in_addr address;
153 + unsigned int flags;
154 + char bits; /* Number of bits for CIDR match on realhost */
157 +#define SLINE_FLAGS_HOSTNAME 0x0001 /* S-line by hostname */
158 +#define SLINE_FLAGS_IP 0x0002 /* S-line by IP address/CIDR */
160 /** Local K-line structure. */
162 struct DenyConf* next; /**< Next DenyConf in #denyConfList. */
164 extern int GlobalConfCount;
165 extern struct s_map* GlobalServiceMapList;
166 extern struct qline* GlobalQuarantineList;
167 +extern struct sline* GlobalSList;
172 extern struct ConfItem *conf_debug_iline(const char *client);
173 extern void free_mapping(struct s_map *smap);
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);
180 extern void yyerror(const char *msg);
182 #endif /* INCLUDED_s_conf_h */
183 diff -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
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);
195 diff -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
199 * overwritten with the ident response.
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 */
213 #endif /* INCLUDED_struct_h */
214 diff -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
225 diff -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];
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))
243 - else if (HasHiddenHost(cptr))
245 + /* sr is real host if +h */
246 + if (HasSetHost(cptr))
247 sr = cli_user(cptr)->realhost;
250 - ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
251 - cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
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;
259 + ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
260 + cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
265 /* Walk through ban list. */
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)))
274 /* If an exception matches, no ban can match. */
275 if (banlist->flags & BAN_EXCEPTION)
276 diff -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
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)
287 if (GlineIsIpMask(gline)) {
288 diff -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
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),
299 /* HEAD_IN_SAND Features */
300 F_B(HIS_SNOTICES, 0, 1, 0),
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),
309 diff -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
320 diff -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
325 S(IAUTH, -1, SNO_NETWORK),
326 S(DEBUG, -1, SNO_DEBUG),
327 + S(SETHOST, -1, SNO_OLDSNO),
329 { LS_LAST_SYSTEM, 0, 0, -1, 0, -1, 0 }
331 diff -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
335 extern struct ServerConf* serverConfList;
336 extern struct s_map* GlobalServiceMapList;
337 extern struct qline* GlobalQuarantineList;
338 + extern struct sline* GlobalSList;
341 /* Now all the globals we need :/... */
343 struct DenyConf *dconf;
344 struct ServerConf *sconf;
346 + struct sline *spoof;
348 struct Privs privs_dirty;
355 %token TOK_IPV4 TOK_IPV6
357 /* and now a lot of privileges... */
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 ';';
365 /* The timespec, sizespec and expr was ripped straight from
367 @@ -1160,3 +1163,71 @@
368 MyFree(stringlist[stringno]);
372 +spoofblock: SPOOFHOST QSTRING '{'
374 + spoof = MyCalloc(1, sizeof(struct sline));
375 + spoof->spoofhost = $2;
376 + spoof->passwd = NULL;
377 + spoof->realhost = NULL;
378 + spoof->username = NULL;
382 + struct irc_in_addr ip;
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.");
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;
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;
405 + spoof->flags = SLINE_FLAGS_HOSTNAME;
409 + spoof->next = GlobalSList;
410 + GlobalSList = spoof;
412 + MyFree(spoof->spoofhost);
413 + MyFree(spoof->passwd);
414 + MyFree(spoof->realhost);
415 + MyFree(spoof->username);
421 +spoofitems: spoofitem spoofitems | spoofitem;
422 +spoofitem: spoofpassword | spoofrealhost | spoofrealident;
423 +spoofpassword: PASS '=' QSTRING ';'
425 + MyFree(spoof->passwd);
426 + spoof->passwd = $3;
428 +spoofrealhost: HOST '=' QSTRING ';'
430 + MyFree(spoof->realhost);
431 + spoof->realhost = $3;
433 +spoofrealident: USERNAME '=' QSTRING ';'
435 + MyFree(spoof->username);
436 + spoof->username = $3;
439 diff -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
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 */
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;
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;
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 @@
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;
484 + str2 = cli_user(cptr)->username;
485 + str3 = cli_user(cptr)->host;
488 fld_s.flags &= ~FLAG_ALT;
490 diff -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
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));
501 assert(0 != (aconf->status & CONF_OPERATOR));
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,
511 @@ -187,16 +187,16 @@
512 send_reply(sptr, RPL_YOUREOPER);
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');
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);
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));
531 diff -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
536 + * IRC - Internet Relay Chat, ircd/m_sethost.c
537 + * Copyright (C) 1990 Jarkko Oikarinen and
538 + * University of Oulu, Computing Center
540 + * See file AUTHORS in IRC package for additional names of
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.
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.
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.
557 + * $Id: asuka-sethost.patch,v 1.27 2005/02/13 17:28:11 froo Exp $
561 + * m_functions execute protocol messages on this server:
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...).
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.
573 + * (!IsServer(cptr)) => (cptr == sptr), because
574 + * prefixes are taken *only* from servers...
577 + * (sptr == cptr) => the message didn't
580 + * (sptr != cptr && IsServer(sptr) means
581 + * the prefix specified servername. (?)
583 + * (sptr != cptr && !IsServer(sptr) means
584 + * that message originated from a remote
585 + * user (not local).
589 + * (!IsServer(sptr)) means that, sptr can safely
590 + * taken as defining the target structure of the
591 + * message in this server.
593 + * *Always* true (if 'parse' and others are working correct):
595 + * 1) sptr->from == cptr (note: cptr->from == cptr)
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 ]
602 + * parc number of variable parameter strings (if zero,
603 + * parv is allowed to be NULL)
605 + * parv a NULL terminated list of parameter pointers,
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*
613 + * note: it is guaranteed that parv[0]..parv[parc-1] are all
614 + * non-NULL pointers.
619 +#include "ircd_reply.h"
620 +#include "ircd_string.h"
621 +#include "ircd_snprintf.h"
622 +#include "ircd_features.h"
624 +#include "numeric.h"
627 +#include "s_debug.h"
630 +#include "numnicks.h"
632 +#include "channel.h"
639 + * m_sethost - generic message handler
641 + * mimic old lain syntax:
643 + * (Oper) /SETHOST ident host.cc [quit-message]
644 + * (User) /SETHOST host.cc password
645 + * (Both) /SETHOST undo
647 + * check for undo, prepend parv w. <nick> -h or +h
649 +int m_sethost(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
651 + char hostmask[USERLEN + HOSTLEN + 2];
652 + char curhostmask[USERLEN + HOSTLEN + 2];
654 + struct Flags setflags;
656 + /* Back up the flags first */
657 + setflags = cli_flags(sptr);
660 + return need_more_params(sptr, "SETHOST");
662 + if (0 == ircd_strcmp("undo", parv[1])) {
663 + set_hostmask(sptr, NULL, NULL);
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);
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);
680 + if (set_hostmask(sptr, hostmask, NULL))
681 + FlagClr(&setflags, FLAG_SETHOST);
683 + if (!is_hostmask(parv[1])) {
684 + send_reply(sptr, ERR_BADHOSTMASK, parv[1]);
687 + if (IsSetHost(sptr) || IsAccount(sptr)) {
688 + if (0 == strcmp(parv[1], sptr->cli_user->host)) {
689 + send_reply(sptr, RPL_HOSTHIDDEN, parv[1]);
693 + if (set_hostmask(sptr, parv[1], parv[2]))
694 + FlagClr(&setflags, FLAG_SETHOST);
698 + send_umode_out(cptr, sptr, &setflags, 0);
704 + * ms_sethost - sethost server message handler
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
711 +int ms_sethost(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
713 + struct Client *target;
714 + char hostmask[USERLEN + HOSTLEN + 2];
715 + struct Membership *chan;
716 + struct Flags setflags;
719 + return need_more_params(sptr, "SETHOST");
721 + if (!IsServer(sptr))
722 + return protocol_violation(cptr, "SETHOST from non-server %s",
725 + /* Locate our target user; ignore the message if we can't */
726 + if(!(target = findNUser(parv[1])))
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));
733 + if (!MyConnect(target)) {
734 + sendcmdto_one(sptr, CMD_SETHOST, cli_user(target)->server, "%C %s %s", target,
739 + /* Back up the flags first */
740 + setflags = cli_flags(target);
741 + FlagClr(&setflags, FLAG_SETHOST);
743 + if (IsSetHost(target) || IsAccount(target)) {
744 + if ((0 == strcmp(parv[2], target->cli_user->username)) && (0 == strcmp(parv[3], target->cli_user->host)))
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));
752 + sendcmdto_common_channels_butone(target, CMD_QUIT, target, ":Host change");
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);
759 + send_reply(target, RPL_HOSTHIDDEN, hostmask);
762 + * Go through all channels the client was on, rejoin him
763 + * and set the modes, if any
765 + for (chan = cli_user(target)->channel; chan; chan = chan->next_channel) {
766 + if (IsZombie(chan))
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);
775 + sendcmdto_channel_butserv_butone(target, CMD_JOIN, chan->channel, target, 0,
776 + "%H", chan->channel);
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);
787 + send_umode_out(target, target, &setflags, 0);
791 diff -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
795 * of +x. If an oper wants the real host, he should go to
798 - HasHiddenHost(cptr) && (sptr != cptr) ?
800 cli_user(cptr)->host : cli_user(cptr)->realhost);
803 diff -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
808 static void userip_formatter(struct Client* cptr, struct Client *sptr, struct MsgBuf* mb)
811 assert(IsUser(cptr));
812 msgq_append(0, mb, "%s%s=%c%s@%s", cli_name(cptr),
813 SeeOper(sptr,cptr) ? "*" : "",
815 * of +x. If an oper wants the real IP, he should go to
818 - HasHiddenHost(cptr) && (sptr != cptr) ?
819 + (HasHiddenHost(cptr) || HasSetHost(cptr)) && !IsAnOper(sptr) ?
820 feature_str(FEAT_HIDDEN_IP) :
821 ircd_ntoa(&cli_ip(cptr)));
823 diff -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)
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)
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)))
858 diff -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
862 if (IsAccount(acptr))
863 send_reply(sptr, RPL_WHOISACCOUNT, name, user->account);
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)));
871 /* Hint: if your looking to add more flags to a user, eg +h, here's
872 diff -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
876 { m_ignore, m_not_oper, ms_asll, mo_asll, m_ignore }
881 + 0, MAXPARA, MFLG_SLOW, 0, NULL,
882 + /* UNREG, CLIENT, SERVER, OPER, SERVICE */
883 + { m_unregistered, m_sethost, ms_sethost, m_sethost, m_ignore }
888 0, MAXPARA, MFLG_SLOW, 0, NULL,
889 diff -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
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;
899 /** Current line number in scanner input. */
908 mark_listeners_closing();
909 @@ -1193,3 +1196,81 @@
913 +void clear_slines(void)
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);
930 + * conf_check_slines()
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.
939 + * 0 = No S-line found
940 + * 1 = S-line found and substitution done.
948 +conf_check_slines(struct Client *cptr)
950 + struct sline *sconf;
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))
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 */
965 + if (match(sconf->username, cli_user(cptr)->username) == 0) {
966 + /* Ignore user part if u@h. */
967 + if ((hostonly = strchr(sconf->spoofhost, '@')))
970 + hostonly = sconf->spoofhost;
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);
984 +void free_spoofhost(struct sline *spoof) {
985 + MyFree(spoof->spoofhost);
986 + MyFree(spoof->passwd);
987 + MyFree(spoof->realhost);
988 + MyFree(spoof->username);
991 diff -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
996 { RPL_ISON, ":", "303" },
999 + { RPL_TEXT, "%s", "304" },
1001 { RPL_UNAWAY, ":You are no longer marked as being away", "305" },
1008 + { RPL_STATSSLINE, "%d %s %s %s %s", "398" },
1011 + { RPL_USINGSLINE, ":Using S-line privilege", "399" },
1015 @@ -1092,9 +1092,9 @@
1020 + { ERR_BADHOSTMASK, "%s :Invalid username/hostmask", "530" },
1023 + { ERR_HOSTUNAVAIL, "%s :sethost not found", "531" },
1027 diff -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
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));
1039 diff -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 @@
1047 +stats_sline(struct Client* to, const struct StatDesc* sd, char* param)
1050 + struct sline *sline;
1053 + send_reply(to, SND_EXPLICIT | RPL_TEXT, "# Type Spoofhost Realhost Ident");
1055 + send_reply(to, SND_EXPLICIT | RPL_TEXT, "# Type Spoofhost");
1057 + for (sline = GlobalSList; sline; sline = sline->next) {
1058 + if (param && match(param, sline->spoofhost)) { /* narrow search */
1062 + if (!EmptyString(sline->passwd))
1067 + if (IsAnOper(to)) {
1068 + send_reply(to, RPL_STATSSLINE, (param) ? y : i,
1069 + (EmptyString(sline->passwd)) ? "oper" : "user",
1071 + (EmptyString(sline->realhost)) ? "" : sline->realhost,
1072 + (EmptyString(sline->username)) ? "" : sline->username);
1075 + if (!EmptyString(sline->passwd)) {
1076 + send_reply(to, RPL_STATSSLINE, (param) ? y : i, "user", sline->spoofhost,
1084 /** List service pseudo-command mappings.
1085 * @param[in] to Client requesting statistics.
1086 * @param[in] sd Stats descriptor for request (ignored).
1089 "System resource usage (Debug only)." },
1091 + { 's', "spoofhosts", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_s,
1093 + "Spoofed hosts information." },
1094 { 'T', "motds", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_T,
1096 "Configured Message Of The Day files." },
1097 diff -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
1102 #include <sys/stat.h>
1104 +static char *IsVhost(char *hostmask, int oper);
1105 +static char *IsVhostPass(char *hostmask);
1107 /** Count of allocated User structures. */
1108 static int userCount = 0;
1110 @@ -368,6 +371,13 @@
1111 if (feature_bool(FEAT_AUTOINVISIBLE))
1114 + if(feature_bool(FEAT_SETHOST_AUTO)) {
1115 + if (conf_check_slines(sptr)) {
1116 + send_reply(sptr, RPL_USINGSLINE);
1122 cli_handler(sptr) = CLIENT_HANDLER;
1123 SetLocalNumNick(sptr);
1125 sptr, cli_name(&me));
1126 return exit_client(cptr, sptr, &me,"Too many connections from your host -- throttled");
1133 "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
1134 cli_name(sptr), cli_hopcount(sptr) + 1,
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));
1142 "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
1143 cli_name(sptr), cli_hopcount(sptr) + 1,
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));
1151 { FLAG_ACCOUNTONLY, 'R' },
1152 { FLAG_XTRAOP, 'X' },
1153 { FLAG_NOCHAN, 'n' },
1154 - { FLAG_NOIDLE, 'I' }
1155 + { FLAG_NOIDLE, 'I' },
1156 + { FLAG_SETHOST, 'h' }
1159 /** Length of #userModeList. */
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);
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);
1175 if (cptr && MyUser(cptr))
1176 send_umode(cptr, sptr, old, ALL_UMODES);
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))
1185 sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Registered");
1186 @@ -939,6 +952,190 @@
1191 + * set_hostmask() - derived from hide_hostmask()
1194 +int set_hostmask(struct Client *cptr, char *hostmask, char *password)
1198 + char *host, *new_vhost, *vhost_pass;
1199 + char hiddenhost[USERLEN + HOSTLEN + 2];
1200 + struct Membership *chan;
1202 + Debug((DEBUG_INFO, "set_hostmask() %C, %s, %s", cptr, hostmask, password));
1204 + /* sethost enabled? */
1205 + if (MyConnect(cptr) && !feature_bool(FEAT_SETHOST)) {
1206 + send_reply(cptr, ERR_DISABLED, "SETHOST");
1210 + /* sethost enabled for users? */
1211 + if (MyConnect(cptr) && !IsAnOper(cptr) && !feature_bool(FEAT_SETHOST_USER)) {
1212 + send_reply(cptr, ERR_NOPRIVILEGES);
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)) {
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));
1227 + strncpy(cli_user(cptr)->host, cli_user(cptr)->realhost, HOSTLEN);
1228 + strncpy(cli_user(cptr)->username, cli_user(cptr)->realusername, USERLEN);
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);
1236 + /* MODE_ADD: set a new hostmask */
1238 + /* chop up ident and host.cc */
1239 + if ((host = strrchr(hostmask, '@'))) /* oper can specifiy ident@host.cc */
1241 + else /* user can only specifiy host.cc [password] */
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);
1255 + } else /* freeform active, log and go */
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);
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" : "");
1269 + * plain user sethost, handled here
1272 + /* empty password? */
1273 + if (EmptyString(password)) {
1274 + send_reply(cptr, ERR_NEEDMOREPARAMS, "MODE");
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);
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);
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);
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);
1302 + log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE, "SETHOST (%s@%s) by (%#R)",
1303 + cli_user(cptr)->username, cli_user(cptr)->host, cptr);
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);
1314 + ClearSetHost(cptr);
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);
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. */
1328 + * Go through all channels the client was on, rejoin him
1329 + * and set the modes, if any
1331 + for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) {
1332 + if (IsZombie(chan))
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);
1347 + * Go through all channels the client was on, rejoin him
1348 + * and set the modes, if any
1350 + for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) {
1351 + if (IsZombie(chan))
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);
1360 + sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr, 0,
1361 + "%H", chan->channel);
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);
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 @@
1380 int do_host_hiding = 0;
1381 + int do_set_host = 0;
1382 char* account = NULL;
1385 @@ -976,7 +1174,8 @@
1386 for (i = 0; i < USERMODELIST_SIZE; i++)
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;
1395 @@ -1103,6 +1302,30 @@
1396 if (what == MODE_ADD)
1400 + if (what == MODE_ADD) {
1401 + if (*(p + 1) && is_hostmask(*(p + 1))) {
1404 + /* DON'T step p onto the trailing NULL in the parameter array! - splidge */
1411 + send_reply(sptr, ERR_NEEDMOREPARAMS, "SETHOST");
1413 + send_reply(sptr, ERR_BADHOSTMASK, *(p+1));
1414 + p++; /* Swallow the arg anyway */
1417 + } else { /* MODE_DEL */
1424 if (*(p + 1) && (what == MODE_ADD)) {
1426 @@ -1269,10 +1492,15 @@
1427 while ((*m++ = *t++))
1430 + m--; /* Step back over the '\0' */
1435 + if (IsSetHost(cptr)) {
1437 + ircd_snprintf(0, m, USERLEN + HOSTLEN + 2, "%s@%s", cli_user(cptr)->username,
1438 + cli_user(cptr)->host);
1441 return umodeBuf; /* Note: static buffer, gets
1442 overwritten by send_umode() */
1444 @@ -1289,6 +1517,7 @@
1450 int what = MODE_NULL;
1452 @@ -1318,6 +1547,16 @@
1456 + /* Special case for SETHOST.. */
1457 + if (flag == FLAG_SETHOST) {
1458 + /* Don't send to users */
1459 + if (cptr && MyUser(cptr))
1462 + /* If we're setting +h, add the parameter later */
1463 + if (!FlagHas(old, flag))
1466 if (FlagHas(old, flag))
1468 if (what == MODE_DEL)
1469 @@ -1341,9 +1580,14 @@
1476 + ircd_snprintf(0, m, USERLEN + HOSTLEN + 1, "%s@%s", cli_user(sptr)->username,
1477 + cli_user(sptr)->host);
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);
1486 @@ -1366,6 +1610,110 @@
1491 + * Check to see if it resembles a valid hostmask.
1493 +int is_hostmask(char *word)
1498 + Debug((DEBUG_INFO, "is_hostmask() %s", word));
1500 + if (strlen(word) > (HOSTLEN + USERLEN + 1) || strlen(word) <= 0)
1503 + /* if a host is specified, make sure it's valid */
1504 + host = strrchr(word, '@');
1506 + if (strlen(++host) < 1)
1508 + if (strlen(host) > HOSTLEN)
1513 + if ('@' == *word) /* no leading @'s */
1516 + if ('#' == *word) { /* numeric index given? */
1517 + for (word++; *word; word++) {
1518 + if (!IsDigit(*word))
1524 + /* normal hostmask, account for at most one '@' */
1525 + for (; *word; word++) {
1526 + if ('@' == *word) {
1530 + if (!IsHostChar(*word))
1533 + return (1 < i) ? 0 : 1; /* no more than on '@' */
1539 + * IsVhost() - Check if given host is a valid spoofhost
1540 + * (ie: configured thru a S:line)
1542 +static char *IsVhost(char *hostmask, int oper)
1544 + unsigned int i = 0, y = 0;
1545 + struct sline *sconf;
1547 + Debug((DEBUG_INFO, "IsVhost() %s", hostmask));
1549 + if (EmptyString(hostmask))
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))
1559 + return sconf->spoofhost;
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;
1573 + * IsVhostPass() - Check if given spoofhost has a password
1574 + * associated with it, and if, return the password (cleartext)
1576 +static char *IsVhostPass(char *hostmask)
1578 + struct sline *sconf;
1580 + Debug((DEBUG_INFO, "IsVhostPass() %s", hostmask));
1582 + if (EmptyString(hostmask))
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;
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).
1597 diff -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
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));
1608 return (match(mask, cli_name(cli_user(one)->server)) == 0);
1609 diff -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
1614 if (fields & WHO_FIELD_NIP)
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));
1623 if (SendDebug(acptr))
1625 + if (HasSetHost(acptr))
1628 if (HasHiddenHost(acptr))
1630 diff -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
1636 +# $Id: asuka-sethost.patch,v 1.29 2005/02/24 01:06:52 froo Exp $
1638 +# aid in converting S: and F:lines from old lain configs
1639 +# to the new "super S:line" format of asuka.
1642 +# 2003-01-05 froo@quakenet.org Created.
1646 +USAGE="Usage: $PROG </path/to/ircd.cfg>"
1648 +if [ $# -lt 1 ]; then
1655 +if [ ! -f $CONFIG ]; then
1656 + echo "Can't open \"$CONFIG\", bailing out."
1661 +for LINE in `grep -E "^F:" $CONFIG`
1663 + IDENT=`echo $LINE | cut -f2 -d:`
1664 + REALHOST=`echo $LINE | cut -f3 -d:`
1665 + SPOOFHOST=`echo $LINE | cut -f4 -d:`
1667 + IDENT=`echo $IDENT | sed -e 's,^~,\*,'`
1669 + echo "S:$SPOOFHOST::$REALHOST:$IDENT"
1672 +for LINE in `grep -E "^S:" $CONFIG`
1674 + SPOOFHOST=`echo $LINE | cut -f2 -d:`
1675 + PASSWD=`echo $LINE | cut -f3 -d:`
1677 + IDENT=`echo $IDENT | sed -e 's,^~,\*,'`
1679 + echo "S:$SPOOFHOST:$PASSWD::"