Note: check - corrupted patch file manually applied.
FLAG_ACCOUNTONLY, /**< ASUKA_R: hide privmsgs/notices if
user is not authed or opered */
FLAG_HIDDENHOST, /**< user's host is hidden */
+ FLAG_SETHOST, /**< ASUKA_h: oper's host is changed */
FLAG_NOCHAN, /**< user's channels are hidden */
FLAG_NOIDLE, /**< user's idletime is hidden */
FLAG_XTRAOP, /**< oper has special powers */
#define IsPrivileged(x) (IsAnOper(x) || IsServer(x))
/** Return non-zero if the client's host is hidden. */
#define HasHiddenHost(x) (IsHiddenHost(x) && IsAccount(x))
+/** Return non-zero if the client is using a spoofhost */
+#define IsSetHost(x) HasFlag(x, FLAG_SETHOST)
+#define HasSetHost(x) (IsSetHost(x))
/** Mark a client as having an in-progress net.burst. */
#define SetBurst(x) SetFlag(x, FLAG_BURST)
#define SetAccount(x) SetFlag(x, FLAG_ACCOUNT)
/** Mark a client as having mode +x (hidden host). */
#define SetHiddenHost(x) SetFlag(x, FLAG_HIDDENHOST)
+/** Mark a client as having mode +h (spoofhost). */
+#define SetSetHost(x) SetFlag(x, FLAG_SETHOST)
/** Mark a client as having mode +X (xtraop). */
#define SetXtraOp(x) SetFlag(x, FLAG_XTRAOP)
/** Mark a client as having mode +n (hide channels). */
#define ClearServNotice(x) ClrFlag(x, FLAG_SERVNOTICE)
/** Remove mode +x (hidden host) from the client. */
#define ClearHiddenHost(x) ClrFlag(x, FLAG_HIDDENHOST)
+/** Remove mode +h (spoofhost) from a client. */
+#define ClearSetHost(x) ClrFlag(x, FLAG_SETHOST)
/** Remove mode +X (xtraop) from a client. */
#define ClearXtraOp(x) ClrFlag(x, FLAG_XTRAOP)
/** Remove mode +n (hide channels) from a client. */
extern int m_pseudo(struct Client*, struct Client*, int, char*[]);
extern int m_quit(struct Client*, struct Client*, int, char*[]);
extern int m_registered(struct Client*, struct Client*, int, char*[]);
+extern int m_sethost(struct Client*, struct Client*, int, char*[]);
extern int m_silence(struct Client*, struct Client*, int, char*[]);
extern int m_stats(struct Client*, struct Client*, int, char*[]);
extern int m_time(struct Client*, struct Client*, int, char*[]);
/* features that affect all operators */
FEAT_CONFIG_OPERCMDS,
+ FEAT_SETHOST,
+ FEAT_SETHOST_FREEFORM,
+ FEAT_SETHOST_USER,
+ FEAT_SETHOST_AUTO,
/* HEAD_IN_SAND Features */
FEAT_HIS_SNOTICES,
FEAT_HIS_STATS_q,
FEAT_HIS_STATS_R,
FEAT_HIS_STATS_r,
+ FEAT_HIS_STATS_s,
FEAT_HIS_STATS_t,
FEAT_HIS_STATS_T,
FEAT_HIS_STATS_u,
LS_SOCKET, /**< Unexpected socket operation errors. */
LS_IAUTH, /**< IAuth status. */
LS_DEBUG, /**< Debug messages. */
+ LS_SETHOST, /**< Usage of the sethost command. */
LS_LAST_SYSTEM /**< Count of valid LogSys values. */
};
#define TOK_PRIVS "PR"
#define CMD_PRIVS MSG_PRIVS, TOK_PRIVS
+#define MSG_SETHOST "SETHOST" /* SETHOST */
+#define TOK_SETHOST "SH"
+#define CMD_SETHOST MSG_SETHOST, TOK_SETHOST
+
#define MSG_CAP "CAP"
#define TOK_CAP "CAP"
#define CMD_CAP MSG_CAP, TOK_CAP
#define RPL_AWAY 301
#define RPL_USERHOST 302
#define RPL_ISON 303
-/* RPL_TEXT 304 unused */
+#define RPL_TEXT 304 /* unused */
#define RPL_UNAWAY 305
#define RPL_NOWAWAY 306
/* NotAway, aircd */
/* RPL_END_USERS 394 Dalnet/EFnet/IRCnet */
/* RPL_NOUSERS 395 Dalnet/EFnet/IRCnet */
#define RPL_HOSTHIDDEN 396 /* UMODE +x completed succesfuly */
+#define RPL_STATSSLINE 398 /* QuakeNet extension -froo */
+#define RPL_USINGSLINE 399 /* QuakeNet extension -froo */
/*
* Errors are in the range from 400-599 currently and are grouped by what
ERR_LISTSYNTAX 521 dalnet
ERR_WHOSYNTAX 522 dalnet
ERR_WHOLIMEXCEED 523 dalnet */
-#define ERR_QUARANTINED 524 /* Undernet extension -Vampire */
+#define ERR_QUARANTINED 524 /* Undernet extension -Vampire */
+#define ERR_BADHOSTMASK 530 /* QuakeNet extension -froo */
+#define ERR_HOSTUNAVAIL 531 /* QuakeNet extension -froo */
#define ERR_NOTLOWEROPLEVEL 560 /* Undernet extension */
#define ERR_NOTMANAGER 561 /* Undernet extension */
char *reason; /**< Reason for quarantine. */
};
+struct sline {
+ struct sline *next;
+ char *spoofhost;
+ char *passwd;
+ char *realhost;
+ char *username;
+ struct irc_in_addr address;
+ unsigned int flags;
+ char bits; /* Number of bits for CIDR match on realhost */
+};
+
+#define SLINE_FLAGS_HOSTNAME 0x0001 /* S-line by hostname */
+#define SLINE_FLAGS_IP 0x0002 /* S-line by IP address/CIDR */
+
/** Local K-line structure. */
struct DenyConf {
struct DenyConf* next; /**< Next DenyConf in #denyConfList. */
extern int GlobalConfCount;
extern struct s_map* GlobalServiceMapList;
extern struct qline* GlobalQuarantineList;
+extern struct sline* GlobalSList;
/*
* Proto types
extern struct ConfItem *conf_debug_iline(const char *client);
extern void free_mapping(struct s_map *smap);
+extern void conf_add_sline(const char* const* fields, int count);
+extern void clear_slines(void);
+extern int conf_check_slines(struct Client *cptr);
+extern void free_spoofhost(struct sline *spoof);
+
extern void yyerror(const char *msg);
#endif /* INCLUDED_s_conf_h */
InfoFormatter fmt);
extern int hide_hostmask(struct Client *cptr, unsigned int flags);
+extern int set_hostmask(struct Client *cptr, char *hostmask, char *password);
+extern int is_hostmask(char *word);
extern int set_user_mode(struct Client *cptr, struct Client *sptr,
int parc, char *parv[]);
extern int is_silenced(struct Client *sptr, struct Client *acptr);
* overwritten with the ident response.
*/
char username[USERLEN + 1];
- char host[HOSTLEN + 1]; /**< displayed hostname */
- char realhost[HOSTLEN + 1]; /**< actual hostname */
- char account[ACCOUNTLEN + 1]; /**< IRC account name */
- time_t acc_create; /**< IRC account timestamp */
+ char host[HOSTLEN + 1]; /**< displayed hostname */
+ char realusername[USERLEN + 1]; /**< actual username */
+ char realhost[HOSTLEN + 1]; /**< actual hostname */
+ char account[ACCOUNTLEN + 1]; /**< IRC account name */
+ time_t acc_create; /**< IRC account timestamp */
};
#endif /* INCLUDED_struct_h */
m_rpong.c \
m_server.c \
m_set.c \
+ m_sethost.c \
m_settime.c \
m_silence.c \
m_squit.c \
ircd_ntoa_r(iphost, &cli_ip(cptr));
if (!IsAccount(cptr))
sr = NULL;
- else if (HasHiddenHost(cptr))
+ else if (HasHiddenHost(cptr) || HasSetHost(cptr))
sr = cli_user(cptr)->realhost;
else
{
Debug((DEBUG_DEBUG,"Matched!"));
} else { /* Host/IP gline */
if (cli_user(acptr)->username &&
- match(gline->gl_user, (cli_user(acptr))->username) != 0)
+ match(gline->gl_user, (cli_user(acptr))->realusername) != 0)
continue;
if (GlineIsIpMask(gline)) {
/* features that affect all operators */
F_B(CONFIG_OPERCMDS, 0, 0, 0),
+ F_B(SETHOST, 0, 0, 0),
+ F_B(SETHOST_FREEFORM, 0, 0, 0),
+ F_B(SETHOST_USER, 0, 0, 0),
+ F_B(SETHOST_AUTO, 0, 0, 0),
/* HEAD_IN_SAND Features */
F_B(HIS_SNOTICES, 0, 1, 0),
F_B(HIS_STATS_q, 0, 1, 0),
F_B(HIS_STATS_R, 0, 1, 0),
F_B(HIS_STATS_r, 0, 1, 0),
+ F_B(HIS_STATS_s, 0, 1, 0),
F_B(HIS_STATS_t, 0, 1, 0),
F_B(HIS_STATS_T, 0, 1, 0),
F_B(HIS_STATS_u, 0, 0, 0),
TOKEN(USERMODE),
TOKEN(FAST),
TOKEN(AUTOCONNECT),
+ TOKEN(SPOOFHOST),
#undef TOKEN
{ "administrator", ADMIN },
{ "apass_opmode", TPRIV_APASS_OPMODE },
S(SOCKET, -1, 0),
S(IAUTH, -1, SNO_NETWORK),
S(DEBUG, -1, SNO_DEBUG),
+ S(SETHOST, -1, SNO_OLDSNO),
#undef S
{ LS_LAST_SYSTEM, 0, 0, -1, 0, -1, 0 }
};
extern struct ServerConf* serverConfList;
extern struct s_map* GlobalServiceMapList;
extern struct qline* GlobalQuarantineList;
+ extern struct sline* GlobalSList;
int yylex(void);
/* Now all the globals we need :/... */
struct DenyConf *dconf;
struct ServerConf *sconf;
struct s_map *smap;
+ struct sline *spoof;
struct Privs privs;
struct Privs privs_dirty;
%token TIMEOUT
%token FAST
%token AUTOCONNECT
+%token SPOOFHOST
/* and now a lot of privileges... */
%token TPRIV_CHAN_LIMIT TPRIV_MODE_LCHAN TPRIV_DEOP_LCHAN TPRIV_WALK_LCHAN
%token TPRIV_LOCAL_KILL TPRIV_REHASH TPRIV_RESTART TPRIV_DIE
block: adminblock | generalblock | classblock | connectblock |
uworldblock | operblock | portblock | jupeblock | clientblock |
killblock | cruleblock | motdblock | featuresblock | quarantineblock |
- pseudoblock | iauthblock | error ';';
+ pseudoblock | iauthblock | spoofblock | error ';';
/* The timespec, sizespec and expr was ripped straight from
* ircd-hybrid-7. */
{
tping = $3;
};
+
+spoofblock: SPOOFHOST QSTRING '{'
+{
+ spoof = MyCalloc(1, sizeof(struct sline));
+ spoof->spoofhost = $2;
+ spoof->passwd = NULL;
+ spoof->realhost = NULL;
+ spoof->username = NULL;
+}
+spoofitems '}' ';'
+{
+ struct irc_in_addr ip;
+ char bits;
+
+ if (spoof->username == NULL && spoof->realhost) {
+ parse_error("Username missing in spoofhost.");
+ } else if (spoof->realhost == NULL && spoof->username) {
+ parse_error("Realhost missing in spoofhost.");
+ }
+
+ if (spoof->realhost) {
+ if (!string_has_wildcards(spoof->realhost)) {
+ if (ipmask_parse(spoof->realhost, &ip, &bits) != 0) {
+ spoof->address = ip;
+ spoof->bits = bits;
+ spoof->flags = SLINE_FLAGS_IP;
+ } else {
+ Debug((DEBUG_DEBUG, "S-Line: \"%s\" appears not to be a valid IP address, might be wildcarded.", spoof->realhost));
+ spoof->flags = SLINE_FLAGS_HOSTNAME;
+ }
+ } else
+ spoof->flags = SLINE_FLAGS_HOSTNAME;
+ } else
+ spoof->flags = 0;
+
+
+ spoof->next = GlobalSList;
+ GlobalSList = spoof;
+
+ spoof = NULL;
+};
+
+spoofitems: spoofitem spoofitems | spoofitem;
+spoofitem: spoofpassword | spoofrealhost | spoofrealident;
+spoofpassword: PASS '=' QSTRING ';'
+{
+ MyFree(spoof->passwd);
+ spoof->passwd = $3;
+};
+spoofrealhost: HOST '=' QSTRING ';'
+{
+ MyFree(spoof->realhost);
+ spoof->realhost = $3;
+};
+spoofrealident: USERNAME '=' QSTRING ';'
+{
+ MyFree(spoof->username);
+ spoof->username = $3;
+};
#define CONV_VARARGS 0x05000000 /**< convert a %v */
#define CONV_CLIENT 0x06000000 /**< convert a struct Client */
#define CONV_CHANNEL 0x07000000 /**< convert a struct Channel */
+#define CONV_REAL 0x08000000 /**< convert a struct Client and show realhost */
-#define CONV_RESERVED7 0x08000000 /**< reserved for future expansion */
#define CONV_RESERVED6 0x09000000 /**< reserved for future expansion */
#define CONV_RESERVED5 0x0a000000 /**< reserved for future expansion */
#define CONV_RESERVED4 0x0b000000 /**< reserved for future expansion */
fld_s.flags |= ARG_PTR | CONV_CLIENT;
break;
+ case 'R': /* convert a client name... */
+ fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_ZERO | TYPE_MASK);
+ fld_s.flags |= ARG_PTR | CONV_REAL;
+ break;
+
case 'H': /* convert a channel name... */
fld_s.flags &= ~(FLAG_PLUS | FLAG_SPACE | FLAG_ALT | FLAG_ZERO |
FLAG_COLON | TYPE_MASK);
vdata->vd_chars = buf_s.buf_loc; /* return relevant data */
vdata->vd_overflow = SNP_MAX(buf_s.buf_overflow, buf_s.overflow);
- } else if ((fld_s.flags & CONV_MASK) == CONV_CLIENT) {
+ } else if (((fld_s.flags & CONV_MASK) == CONV_CLIENT) ||
+ ((fld_s.flags & CONV_MASK) == CONV_REAL)) {
struct Client *cptr = (struct Client*) fld_s.value.v_ptr;
const char *str1 = 0, *str2 = 0, *str3 = 0;
int slen1 = 0, slen2 = 0, slen3 = 0, elen = 0, plen = 0;
if (!IsServer(cptr) && !IsMe(cptr) && fld_s.flags & FLAG_ALT) {
assert(0 != cli_user(cptr));
assert(0 != *(cli_name(cptr)));
- str2 = cli_user(cptr)->username;
- str3 = cli_user(cptr)->host;
+ if ((fld_s.flags & CONV_MASK) == CONV_REAL) {
+ str2 = cli_user(cptr)->realusername;
+ str3 = cli_user(cptr)->realhost;
+ } else {
+ str2 = cli_user(cptr)->username;
+ str3 = cli_user(cptr)->host;
+ }
} else
fld_s.flags &= ~FLAG_ALT;
}
{
send_reply(sptr, ERR_NOOPERHOST);
sendto_opmask_butone(0, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s)",
- parv[0], cli_user(sptr)->username, cli_sockhost(sptr));
+ parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr));
return 0;
}
assert(0 != (aconf->status & CONF_OPERATOR));
if (ACR_OK != attach_conf(sptr, aconf)) {
send_reply(sptr, ERR_NOOPERHOST);
sendto_opmask_butone(0, SNO_OLDREALOP, "Failed OPER attempt by %s "
- "(%s@%s)", parv[0], cli_user(sptr)->username,
+ "(%s@%s)", parv[0], cli_user(sptr)->realusername,
cli_sockhost(sptr));
return 0;
}
send_reply(sptr, RPL_YOUREOPER);
sendto_opmask_butone(0, SNO_OLDSNO, "%s (%s@%s) is now operator (%c)",
- parv[0], cli_user(sptr)->username, cli_sockhost(sptr),
+ parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr),
IsOper(sptr) ? 'O' : 'o');
- log_write(LS_OPER, L_INFO, 0, "OPER (%s) by (%#C)", name, sptr);
+ log_write(LS_OPER, L_INFO, 0, "OPER (%s) by (%#R)", name, sptr);
}
else
{
send_reply(sptr, ERR_PASSWDMISMATCH);
sendto_opmask_butone(0, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s)",
- parv[0], cli_user(sptr)->username, cli_sockhost(sptr));
+ parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr));
}
return 0;
}
--- /dev/null
+/*
+ * IRC - Internet Relay Chat, ircd/m_sethost.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: asuka-sethost.patch,v 1.27 2005/02/13 17:28:11 froo Exp $
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ * cptr is always NON-NULL, pointing to a *LOCAL* client
+ * structure (with an open socket connected!). This
+ * identifies the physical socket where the message
+ * originated (or which caused the m_function to be
+ * executed--some m_functions may call others...).
+ *
+ * sptr is the source of the message, defined by the
+ * prefix part of the message if present. If not
+ * or prefix not found, then sptr==cptr.
+ *
+ * (!IsServer(cptr)) => (cptr == sptr), because
+ * prefixes are taken *only* from servers...
+ *
+ * (IsServer(cptr))
+ * (sptr == cptr) => the message didn't
+ * have the prefix.
+ *
+ * (sptr != cptr && IsServer(sptr) means
+ * the prefix specified servername. (?)
+ *
+ * (sptr != cptr && !IsServer(sptr) means
+ * that message originated from a remote
+ * user (not local).
+ *
+ * combining
+ *
+ * (!IsServer(sptr)) means that, sptr can safely
+ * taken as defining the target structure of the
+ * message in this server.
+ *
+ * *Always* true (if 'parse' and others are working correct):
+ *
+ * 1) sptr->from == cptr (note: cptr->from == cptr)
+ *
+ * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ * *cannot* be a local connection, unless it's
+ * actually cptr!). [MyConnect(x) should probably
+ * be defined as (x == x->from) --msa ]
+ *
+ * parc number of variable parameter strings (if zero,
+ * parv is allowed to be NULL)
+ *
+ * parv a NULL terminated list of parameter pointers,
+ *
+ * parv[0], sender (prefix string), if not present
+ * this points to an empty string.
+ * parv[1]...parv[parc-1]
+ * pointers to additional parameters
+ * parv[parc] == NULL, *always*
+ *
+ * note: it is guaranteed that parv[0]..parv[parc-1] are all
+ * non-NULL pointers.
+ */
+#include "config.h"
+
+#include "client.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "ircd_features.h"
+#include "msgq.h"
+#include "numeric.h"
+#include "s_user.h"
+#include "s_debug.h"
+#include "struct.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+/*
+ * m_sethost - generic message handler
+ *
+ * mimic old lain syntax:
+ *
+ * (Oper) /SETHOST ident host.cc [quit-message]
+ * (User) /SETHOST host.cc password
+ * (Both) /SETHOST undo
+ *
+ * check for undo, prepend parv w. <nick> -h or +h
+ */
+int m_sethost(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+ char hostmask[512];
+ struct Flags setflags;
+
+ /* Back up the flags first */
+ setflags = cli_flags(sptr);
+
+ if (parc < 2)
+ return need_more_params(sptr, "SETHOST");
+
+ if (0 == ircd_strcmp("undo", parv[1])) {
+ set_hostmask(sptr, NULL, NULL);
+ } else {
+ if (parc<3)
+ return need_more_params(sptr, "SETHOST");
+ if (IsAnOper(sptr)) {
+ ircd_snprintf(0, hostmask, USERLEN + HOSTLEN + 1, "%s@%s", parv[1], parv[2]);
+ if (!is_hostmask(hostmask)) {
+ send_reply(sptr, ERR_BADHOSTMASK, hostmask);
+ return 0;
+ }
+ if (set_hostmask(sptr, hostmask, NULL))
+ FlagClr(&setflags, FLAG_SETHOST);
+ } else {
+ if (!is_hostmask(parv[1])) {
+ send_reply(sptr, ERR_BADHOSTMASK, parv[1]);
+ return 0;
+ }
+ if (set_hostmask(sptr, parv[1], parv[2]))
+ FlagClr(&setflags, FLAG_SETHOST);
+ }
+ }
+
+ send_umode_out(cptr, sptr, &setflags, 0);
+}
* of +x. If an oper wants the real host, he should go to
* /whois to get it.
*/
- HasHiddenHost(cptr) && (sptr != cptr) ?
+ !IsAnOper(sptr) ?
cli_user(cptr)->host : cli_user(cptr)->realhost);
}
static void userip_formatter(struct Client* cptr, struct Client *sptr, struct MsgBuf* mb)
{
+ /* !!FIXME!! */
assert(IsUser(cptr));
msgq_append(0, mb, "%s%s=%c%s@%s", cli_name(cptr),
SeeOper(sptr,cptr) ? "*" : "",
* of +x. If an oper wants the real IP, he should go to
* /whois to get it.
*/
- HasHiddenHost(cptr) && (sptr != cptr) ?
+ (HasHiddenHost(cptr) || HasSetHost(cptr)) && !IsAnOper(sptr) ?
feature_str(FEAT_HIDDEN_IP) :
ircd_ntoa(&cli_ip(cptr)));
}
&& ((!(matchsel & WHO_FIELD_HOS))
|| matchexec(cli_user(acptr)->host, mymask, minlen))
&& ((!(matchsel & WHO_FIELD_HOS))
+ || !HasSetHost(acptr)
|| !HasHiddenHost(acptr)
|| !IsAnOper(sptr)
|| matchexec(cli_user(acptr)->realhost, mymask, minlen))
&& ((!(matchsel & WHO_FIELD_REN))
|| matchexec(cli_info(acptr), mymask, minlen))
&& ((!(matchsel & WHO_FIELD_NIP))
- || (HasHiddenHost(acptr) && !IsAnOper(sptr))
+ || ((HasHiddenHost(acptr) || HasSetHost(acptr)) && !IsAnOper(sptr))
|| !ipmask_check(&cli_ip(acptr), &imask, ibits))
&& ((!(matchsel & WHO_FIELD_ACC))
|| matchexec(cli_user(acptr)->account, mymask, minlen)))
&& ((!(matchsel & WHO_FIELD_HOS))
|| matchexec(cli_user(acptr)->host, mymask, minlen))
&& ((!(matchsel & WHO_FIELD_HOS))
+ || !HasSetHost(acptr)
|| !HasHiddenHost(acptr)
|| !IsAnOper(sptr)
|| matchexec(cli_user(acptr)->realhost, mymask, minlen))
&& ((!(matchsel & WHO_FIELD_REN))
|| matchexec(cli_info(acptr), mymask, minlen))
&& ((!(matchsel & WHO_FIELD_NIP))
- || (HasHiddenHost(acptr) && !IsAnOper(sptr))
+ || ((HasHiddenHost(acptr) || HasSetHost(acptr)) && !IsAnOper(sptr))
|| !ipmask_check(&cli_ip(acptr), &imask, ibits))
&& ((!(matchsel & WHO_FIELD_ACC))
|| matchexec(cli_user(acptr)->account, mymask, minlen)))
if (IsAccount(acptr))
send_reply(sptr, RPL_WHOISACCOUNT, name, user->account);
- if (HasHiddenHost(acptr) && (IsAnOper(sptr) || acptr == sptr))
- send_reply(sptr, RPL_WHOISACTUALLY, name, user->username,
+ if ((HasHiddenHost(acptr) || HasSetHost(acptr)) && (IsAnOper(sptr) || acptr == sptr))
+ send_reply(sptr, RPL_WHOISACTUALLY, name, user->realusername,
user->realhost, ircd_ntoa(&cli_ip(acptr)));
/* Hint: if your looking to add more flags to a user, eg +h, here's
/* UNREG, CLIENT, SERVER, OPER, SERVICE */
{ m_ignore, m_not_oper, ms_asll, mo_asll, m_ignore }
},
+ {
+ MSG_SETHOST,
+ TOK_SETHOST,
+ 0, MAXPARA, MFLG_SLOW, 0, NULL,
+ /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+ { m_unregistered, m_sethost, m_ignore, m_sethost, m_ignore }
+ },
#if WE_HAVE_A_REAL_CAPABILITY_NOW
{
MSG_CAP,
#include "querycmds.h"
#include "res.h"
#include "s_bsd.h"
+#include "s_conf.h"
#include "s_debug.h"
#include "s_misc.h"
#include "send.h"
struct s_map *GlobalServiceMapList;
/** Global list of channel quarantines. */
struct qline *GlobalQuarantineList;
+/** Global list of spoofhosts. */
+struct sline *GlobalSList = 0;
/** Current line number in scanner input. */
int lineno;
clearNickJupes();
clear_quarantines();
+ clear_slines();
if (sig != 2)
restart_resolver();
return 0;
}
+void clear_slines(void)
+{
+ struct sline *sline;
+ while ((sline = GlobalSList)) {
+ GlobalSList = sline->next;
+ MyFree(sline->spoofhost);
+ if (!EmptyString(sline->passwd))
+ MyFree(sline->passwd);
+ if (!EmptyString(sline->realhost))
+ MyFree(sline->realhost);
+ if (!EmptyString(sline->username))
+ MyFree(sline->username);
+ MyFree(sline);
+ }
+}
+
+/*
+ * conf_check_slines()
+ *
+ * Check S lines for the specified client, passed in cptr struct.
+ * If the client's IP is S-lined, process the substitution here.
+ *
+ * Precondition
+ * cptr != NULL
+ *
+ * Returns
+ * 0 = No S-line found
+ * 1 = S-line found and substitution done.
+ *
+ * -mbuna 9/2001
+ * -froo 1/2003
+ *
+ */
+
+int
+conf_check_slines(struct Client *cptr)
+{
+ struct sline *sconf;
+ char *hostonly;
+
+ for (sconf = GlobalSList; sconf; sconf = sconf->next) {
+ if (sconf->flags == SLINE_FLAGS_IP) {
+ if (!ipmask_check(&(cli_ip(cptr)), &(sconf->address), sconf->bits))
+ continue;
+ } else if (sconf->flags == SLINE_FLAGS_HOSTNAME) {
+ if ((match(sconf->realhost, cli_sockhost(cptr)) != 0) &&
+ (match(sconf->realhost, cli_sock_ip(cptr)) != 0)) /* wildcarded IP address */
+ continue;
+ } else {
+ continue;
+ }
+
+ if (match(sconf->username, cli_user(cptr)->username) == 0) {
+ /* Ignore user part if u@h. */
+ if ((hostonly = strchr(sconf->spoofhost, '@')))
+ hostonly++;
+ else
+ hostonly = sconf->spoofhost;
+
+ if(!*hostonly)
+ continue;
+
+ ircd_strncpy(cli_user(cptr)->host, hostonly, HOSTLEN);
+ log_write(LS_USER, L_INFO, LOG_NOSNOTICE, "S-Line (%s@%s) by (%#R)",
+ cli_user(cptr)->username, hostonly, cptr);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void free_spoofhost(struct sline *spoof) {
+ MyFree(spoof->spoofhost);
+ MyFree(spoof->passwd);
+ MyFree(spoof->realhost);
+ MyFree(spoof->username);
+ MyFree(spoof);
+}
/* 303 */
{ RPL_ISON, ":", "303" },
/* 304 */
- { 0 },
+ { RPL_TEXT, "%s", "304" },
/* 305 */
{ RPL_UNAWAY, ":You are no longer marked as being away", "305" },
/* 306 */
/* 397 */
{ 0 },
/* 398 */
- { 0 },
+ { RPL_STATSSLINE, "%d %s %s %s %s", "398" },
/* 399 */
- { 0 },
+ { RPL_USINGSLINE, ":Using S-line privilege", "399" },
/* 400 */
{ 0 },
/* 401 */
/* 529 */
{ 0 },
/* 530 */
- { 0 },
+ { ERR_BADHOSTMASK, "%s :Invalid username/hostmask", "530" },
/* 531 */
- { 0 },
+ { ERR_HOSTUNAVAIL, "%s :sethost not found", "531" },
/* 532 */
{ 0 },
/* 533 */
sendcmdto_one(cli_user(acptr)->server, CMD_NICK, cptr,
"%s %d %Tu %s %s %s%s%s%s %s%s :%s",
cli_name(acptr), cli_hopcount(acptr) + 1, cli_lastnick(acptr),
- cli_user(acptr)->username, cli_user(acptr)->realhost,
+ cli_user(acptr)->realusername, cli_user(acptr)->realhost,
*s ? "+" : "", s, *s ? " " : "",
iptobase64(xxx_buf, &cli_ip(acptr), sizeof(xxx_buf), IsIPv6(cptr)),
NumNick(acptr), cli_info(acptr));
}
}
+static void
+stats_sline(struct Client* to, const struct StatDesc* sd, char* param)
+{
+ int y = 1, i = 1;
+ struct sline *sline;
+
+ if (IsAnOper(to))
+ send_reply(to, SND_EXPLICIT | RPL_TEXT, "# Type Spoofhost Realhost Ident");
+ else
+ send_reply(to, SND_EXPLICIT | RPL_TEXT, "# Type Spoofhost");
+
+ for (sline = GlobalSList; sline; sline = sline->next) {
+ if (param && match(param, sline->spoofhost)) { /* narrow search */
+ if (IsAnOper(to))
+ y++;
+ else
+ if (!EmptyString(sline->passwd))
+ y++;
+ continue;
+ }
+
+ if (IsAnOper(to)) {
+ send_reply(to, RPL_STATSSLINE, (param) ? y : i,
+ (EmptyString(sline->passwd)) ? "oper" : "user",
+ sline->spoofhost,
+ (EmptyString(sline->realhost)) ? "" : sline->realhost,
+ (EmptyString(sline->username)) ? "" : sline->username);
+ i++;
+ } else {
+ if (!EmptyString(sline->passwd)) {
+ send_reply(to, RPL_STATSSLINE, (param) ? y : i, "user", sline->spoofhost,
+ "", "", "");
+ i++;
+ }
+ }
+ }
+}
+
/** List service pseudo-command mappings.
* @param[in] to Client requesting statistics.
* @param[in] sd Stats descriptor for request (ignored).
send_usage, 0,
"System resource usage (Debug only)." },
#endif
+ { 's', "spoofhosts", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_s,
+ stats_sline, 0,
+ "Spoofed hosts information." },
{ 'T', "motds", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_T,
motd_report, 0,
"Configured Message Of The Day files." },
#include <string.h>
#include <sys/stat.h>
+static char *IsVhost(char *hostmask, int oper);
+static char *IsVhostPass(char *hostmask);
+
/** Count of allocated User structures. */
static int userCount = 0;
clean_user_id(user->username,
HasFlag(sptr, FLAG_GOTID) ? cli_username(sptr) : username,
- HasFlag(sptr, FLAG_DOID) && !HasFlag(sptr, FLAG_GOTID));
+ HasFlag(sptr, FLAG_DOID) && !HasFlag(sptr, FLAG_GOTID)
+ && !(HasSetHost(sptr))); /* No tilde for S-lined users. */
+
+ /* Have to set up "realusername" before doing the gline check below */
+ ircd_strncpy(user->realusername, user->username, USERLEN);
if ((user->username[0] == '\0')
|| ((user->username[0] == '~') && (user->username[1] == '\000')))
if (MyConnect(sptr) && feature_bool(FEAT_AUTOINVISIBLE))
SetInvisible(sptr);
+ if(MyConnect(sptr) && feature_bool(FEAT_SETHOST_AUTO)) {
+ if (conf_check_slines(sptr)) {
+ send_reply(sptr, RPL_USINGSLINE);
+ SetSetHost(sptr);
+ }
+ }
+
SetUser(sptr);
cli_handler(sptr) = CLIENT_HANDLER;
SetLocalNumNick(sptr);
sptr, cli_name(&me));
return exit_client(cptr, sptr, &me,"Too many connections from your host -- throttled");
}
+
+ if(MyConnect(sptr) && feature_bool(FEAT_SETHOST_AUTO)) {
+ if (conf_check_slines(sptr)) {
+ send_reply(sptr, RPL_USINGSLINE);
+ SetSetHost(sptr);
+ }
+ }
+
SetUser(sptr);
}
FLAG_IPV6, FLAG_LAST_FLAG,
"%s %d %Tu %s %s %s%s%s%s %s%s :%s",
nick, cli_hopcount(sptr) + 1, cli_lastnick(sptr),
- user->username, user->realhost,
+ user->realusername, user->realhost,
*tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
iptobase64(ip_base64, &cli_ip(sptr), sizeof(ip_base64), 1),
NumNick(sptr), cli_info(sptr));
FLAG_LAST_FLAG, FLAG_IPV6,
"%s %d %Tu %s %s %s%s%s%s %s%s :%s",
nick, cli_hopcount(sptr) + 1, cli_lastnick(sptr),
- user->username, user->realhost,
+ user->realusername, user->realhost,
*tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
iptobase64(ip_base64, &cli_ip(sptr), sizeof(ip_base64), 0),
NumNick(sptr), cli_info(sptr));
{ FLAG_ACCOUNTONLY, 'R' },
{ FLAG_XTRAOP, 'X' },
{ FLAG_NOCHAN, 'n' },
- { FLAG_NOIDLE, 'I' }
+ { FLAG_NOIDLE, 'I' },
+ { FLAG_SETHOST, 'h' }
};
/** Length of #userModeList. */
if (IsServer(sptr)) {
int i;
const char* account = 0;
+ char* hostmask = 0;
+ char* host = 0;
const char* p;
/*
SetFlag(new_client, userModeList[i].flag);
if (userModeList[i].flag == FLAG_ACCOUNT)
account = parv[7];
+ if (userModeList[i].flag == FLAG_SETHOST)
+ hostmask = parv[parc - 4];
break;
}
}
cli_serv(sptr)->ghost = 0; /* :server NICK means end of net.burst */
ircd_strncpy(cli_username(new_client), parv[4], USERLEN);
+ ircd_strncpy(cli_user(new_client)->realusername, parv[4], USERLEN);
ircd_strncpy(cli_user(new_client)->host, parv[5], HOSTLEN);
ircd_strncpy(cli_user(new_client)->realhost, parv[5], HOSTLEN);
ircd_strncpy(cli_info(new_client), parv[parc - 1], REALLEN);
if (HasHiddenHost(new_client))
ircd_snprintf(0, cli_user(new_client)->host, HOSTLEN, "%s.%s",
account, feature_str(FEAT_HIDDEN_HOST));
+ if (HasSetHost(new_client)) {
+ if ((host = strrchr(hostmask, '@')) != NULL) {
+ *host++ = '\0';
+ ircd_strncpy(cli_username(new_client), hostmask, USERLEN);
+ ircd_strncpy(cli_user(new_client)->host, host, HOSTLEN);
+ }
+ }
- return register_user(cptr, new_client, cli_name(new_client), parv[4]);
+ return register_user(cptr, new_client, cli_name(new_client), cli_username(new_client));
}
else if ((cli_name(sptr))[0]) {
/*
{
if ((acptr = LocalClientArray[i]) && IsServer(acptr) &&
(acptr != cptr) && (acptr != sptr) && *umodeBuf)
- sendcmdto_one(sptr, CMD_MODE, acptr, "%s :%s", cli_name(sptr), umodeBuf);
+ sendcmdto_one(sptr, CMD_MODE, acptr, "%s %s", cli_name(sptr), umodeBuf);
}
if (cptr && MyUser(cptr))
send_umode(cptr, sptr, old, ALL_UMODES);
/* Local users cannot set +x unless FEAT_HOST_HIDING is true. */
if (MyConnect(cptr) && !feature_bool(FEAT_HOST_HIDING))
return 0;
+ /* If the user is +h, we don't hide the hostmask. Set the flag to keep sync though */
+ if (HasSetHost(cptr)) {
+ SetFlag(cptr, flag);
+ return 0;
+ }
break;
case FLAG_ACCOUNT:
/* Invalidate all bans against the user so we check them again */
return 0;
}
+/*
+ * set_hostmask() - derived from hide_hostmask()
+ *
+ */
+int set_hostmask(struct Client *cptr, char *hostmask, char *password)
+{
+ int restore = 0;
+ int freeform = 0;
+ char *host, *new_vhost, *vhost_pass;
+ char hiddenhost[USERLEN + HOSTLEN + 2];
+ struct Membership *chan;
+
+ Debug((DEBUG_INFO, "set_hostmask() %C, %s, %s", cptr, hostmask, password));
+
+ /* sethost enabled? */
+ if (MyConnect(cptr) && !feature_bool(FEAT_SETHOST)) {
+ send_reply(cptr, ERR_DISABLED, "SETHOST");
+ return 0;
+ }
+
+ /* sethost enabled for users? */
+ if (MyConnect(cptr) && !IsAnOper(cptr) && !feature_bool(FEAT_SETHOST_USER)) {
+ send_reply(cptr, ERR_NOPRIVILEGES);
+ return 0;
+ }
+
+ /* MODE_DEL: restore original hostmask */
+ if (EmptyString(hostmask)) {
+ /* is already sethost'ed? */
+ if (IsSetHost(cptr)) {
+ restore = 1;
+ sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
+ /* If they are +rx, we need to return to their +x host, not their "real" host */
+ if (HasHiddenHost(cptr))
+ ircd_snprintf(0, cli_user(cptr)->host, HOSTLEN, "%s.%s",
+ cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
+ else
+ strncpy(cli_user(cptr)->host, cli_user(cptr)->realhost, HOSTLEN);
+ strncpy(cli_user(cptr)->username, cli_user(cptr)->realusername, USERLEN);
+ /* log it */
+ if (MyConnect(cptr))
+ log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE,
+ "SETHOST (%s@%s) by (%#R): restoring real hostmask",
+ cli_user(cptr)->username, cli_user(cptr)->host, cptr);
+ } else
+ return 0;
+ /* MODE_ADD: set a new hostmask */
+ } else {
+ /* chop up ident and host.cc */
+ if ((host = strrchr(hostmask, '@'))) /* oper can specifiy ident@host.cc */
+ *host++ = '\0';
+ else /* user can only specifiy host.cc [password] */
+ host = hostmask;
+ /*
+ * Oper sethost
+ */
+ if (MyConnect(cptr)) {
+ if (IsAnOper(cptr)) {
+ if ((new_vhost = IsVhost(host, 1)) == NULL) {
+ if (!feature_bool(FEAT_SETHOST_FREEFORM)) {
+ send_reply(cptr, ERR_HOSTUNAVAIL, hostmask);
+ log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE,
+ "SETHOST (%s@%s) by (%#R): no such s-line",
+ (host != hostmask) ? hostmask : cli_user(cptr)->username, host, cptr);
+ return 0;
+ } else /* freeform active, log and go */
+ freeform = 1;
+ }
+ sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
+ /* set the new ident and host */
+ if (host != hostmask) /* oper only specified host.cc */
+ strncpy(cli_user(cptr)->username, hostmask, USERLEN);
+ strncpy(cli_user(cptr)->host, host, HOSTLEN);
+ /* log it */
+ log_write(LS_SETHOST, (freeform) ? L_NOTICE : L_INFO,
+ (freeform) ? 0 : LOG_NOSNOTICE, "SETHOST (%s@%s) by (%#R)%s",
+ cli_user(cptr)->username, cli_user(cptr)->host, cptr,
+ (freeform) ? ": using freeform" : "");
+ /*
+ * plain user sethost, handled here
+ */
+ } else {
+ /* empty password? */
+ if (EmptyString(password)) {
+ send_reply(cptr, ERR_NEEDMOREPARAMS, "MODE");
+ return 0;
+ }
+ /* no such s-line */
+ if ((new_vhost = IsVhost(host, 0)) == NULL) {
+ send_reply(cptr, ERR_HOSTUNAVAIL, hostmask);
+ log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE, "SETHOST (%s@%s %s) by (%#R): no such s-line",
+ cli_user(cptr)->username, host, password, cptr);
+ return 0;
+ }
+ /* no password */
+ if ((vhost_pass = IsVhostPass(new_vhost)) == NULL) {
+ send_reply(cptr, ERR_PASSWDMISMATCH);
+ log_write(LS_SETHOST, L_INFO, 0, "SETHOST (%s@%s %s) by (%#R): trying to use an oper s-line",
+ cli_user(cptr)->username, host, password, cptr);
+ return 0;
+ }
+ /* incorrect password */
+ if (strCasediff(vhost_pass, password)) {
+ send_reply(cptr, ERR_PASSWDMISMATCH);
+ log_write(LS_SETHOST, L_NOTICE, 0, "SETHOST (%s@%s %s) by (%#R): incorrect password",
+ cli_user(cptr)->username, host, password, cptr);
+ return 0;
+ }
+ sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
+ /* set the new host */
+ strncpy(cli_user(cptr)->host, new_vhost, HOSTLEN);
+ /* log it */
+ log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE, "SETHOST (%s@%s) by (%#R)",
+ cli_user(cptr)->username, cli_user(cptr)->host, cptr);
+ }
+ } else { /* remote user */
+ sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
+ if (host != hostmask) /* oper only specified host.cc */
+ strncpy(cli_user(cptr)->username, hostmask, USERLEN);
+ strncpy(cli_user(cptr)->host, host, HOSTLEN);
+ }
+ }
+
+ if (restore)
+ ClearSetHost(cptr);
+ else
+ SetSetHost(cptr);
+
+ if (MyConnect(cptr)) {
+ ircd_snprintf(0, hiddenhost, HOSTLEN + USERLEN + 2, "%s@%s",
+ cli_user(cptr)->username, cli_user(cptr)->host);
+ send_reply(cptr, RPL_HOSTHIDDEN, hiddenhost);
+ }
+
+#if 0
+ /* Code copied from hide_hostmask(). This is the old (pre-delayedjoin)
+ * version. Switch this in if you're not using the delayed join patch. */
+ /*
+ * Go through all channels the client was on, rejoin him
+ * and set the modes, if any
+ */
+ for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) {
+ if (IsZombie(chan))
+ continue;
+ sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr,
+ "%H", chan->channel);
+ if (IsChanOp(chan) && HasVoice(chan)) {
+ sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr,
+ "%H +ov %C %C", chan->channel, cptr, cptr);
+ } else if (IsChanOp(chan) || HasVoice(chan)) {
+ sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr,
+ "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr);
+ }
+ }
+#endif
+
+ /*
+ * Go through all channels the client was on, rejoin him
+ * and set the modes, if any
+ */
+ for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) {
+ if (IsZombie(chan))
+ continue;
+ /* If this channel has delayed joins and the user has no modes, just set
+ * the delayed join flag rather than showing the join, even if the user
+ * was visible before */
+ if (!IsChanOp(chan) && !HasVoice(chan)
+ && (chan->channel->mode.mode & MODE_DELJOINS)) {
+ SetDelayedJoin(chan);
+ } else {
+ sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr, 0,
+ "%H", chan->channel);
+ }
+ if (IsChanOp(chan) && HasVoice(chan)) {
+ sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr, 0,
+ "%H +ov %C %C", chan->channel, cptr, cptr);
+ } else if (IsChanOp(chan) || HasVoice(chan)) {
+ sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr, 0,
+ "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr);
+ }
+ }
+ return 1;
+}
+
/** Set a user's mode. This function checks that \a cptr is trying to
* set his own mode, prevents local users from setting inappropriate
* modes through this function, and applies any other side effects of
unsigned int tmpmask = 0;
int snomask_given = 0;
char buf[BUFSIZE];
+ char *hostmask, *password;
int prop = 0;
int do_host_hiding = 0;
+ int do_set_host = 0;
+ hostmask = password = NULL;
what = MODE_ADD;
if (parc < 2)
for (i = 0; i < USERMODELIST_SIZE; i++)
{
if (HasFlag(sptr, userModeList[i].flag) &&
- userModeList[i].flag != FLAG_ACCOUNT)
+ ((userModeList[i].flag != FLAG_ACCOUNT) &&
+ (userModeList[i].flag != FLAG_SETHOST)))
*m++ = userModeList[i].c;
}
*m = '\0';
break;
case 'x':
if (what == MODE_ADD)
- do_host_hiding = 1;
- break;
+ do_host_hiding = 1;
+ break;
+ case 'h':
+ if (what == MODE_ADD) {
+ if (*(p + 1) && is_hostmask(*(p + 1))) {
+ do_set_host = 1;
+ hostmask = *++p;
+ /* DON'T step p onto the trailing NULL in the parameter array! - splidge */
+ if (*(p+1))
+ password = *++p;
+ else
+ password = NULL;
+ } else {
+ if (!*(p+1))
+ send_reply(sptr, ERR_NEEDMOREPARAMS, "SETHOST");
+ else {
+ send_reply(sptr, ERR_BADHOSTMASK, *(p+1));
+ p++; /* Swallow the arg anyway */
+ }
+ }
+ } else { /* MODE_DEL */
+ do_set_host = 1;
+ hostmask = NULL;
+ password = NULL;
+ }
+ break;
case 'R':
if (what == MODE_ADD)
SetAccountOnly(sptr);
++UserStats.inv_clients;
if (!FlagHas(&setflags, FLAG_HIDDENHOST) && do_host_hiding)
hide_hostmask(sptr, FLAG_HIDDENHOST);
+ if (do_set_host) {
+ /* We clear the flag in the old mask, so that the +h will be sent */
+ /* Only do this if we're SETTING +h and it succeeded */
+ if (set_hostmask(sptr, hostmask, password) && hostmask)
+ FlagClr(&setflags, FLAG_SETHOST);
+ }
send_umode_out(cptr, sptr, &setflags, prop);
return 0;
while ((*m++ = *t++))
; /* Empty loop */
}
+ m--; /* Step back over the '\0' */
}
- *m = '\0';
-
+ if (IsSetHost(cptr)) {
+ *m++ = ' ';
+ ircd_snprintf(0, m, USERLEN + HOSTLEN + 2, "%s@%s", cli_user(cptr)->username,
+ cli_user(cptr)->host);
+ } else
+ *m = '\0';
return umodeBuf; /* Note: static buffer, gets
overwritten by send_umode() */
}
{
int i;
int flag;
+ int needhost = 0;
char *m;
int what = MODE_NULL;
continue;
break;
}
+ /* Special case for SETHOST.. */
+ if (flag == FLAG_SETHOST) {
+ /* Don't send to users */
+ if (cptr && MyUser(cptr))
+ continue;
+
+ /* If we're setting +h, add the parameter later */
+ if (!FlagHas(old, flag))
+ needhost++;
+ }
if (FlagHas(old, flag))
{
if (what == MODE_DEL)
}
}
}
- *m = '\0';
+ if (needhost) {
+ *m++ = ' ';
+ ircd_snprintf(0, m, USERLEN + HOSTLEN + 1, "%s@%s", cli_user(sptr)->username,
+ cli_user(sptr)->host);
+ } else
+ *m = '\0';
if (*umodeBuf && cptr)
- sendcmdto_one(sptr, CMD_MODE, cptr, "%s :%s", cli_name(sptr), umodeBuf);
+ sendcmdto_one(sptr, CMD_MODE, cptr, "%s %s", cli_name(sptr), umodeBuf);
}
/**
return 0;
}
+ /*
+ * Check to see if it resembles a valid hostmask.
+ */
+int is_hostmask(char *word)
+{
+ int i = 0;
+ char *host;
+
+ Debug((DEBUG_INFO, "is_hostmask() %s", word));
+
+ if (strlen(word) > (HOSTLEN + USERLEN + 1) || strlen(word) <= 0)
+ return 0;
+
+ /* if a host is specified, make sure it's valid */
+ host = strrchr(word, '@');
+ if (host) {
+ if (strlen(++host) < 1)
+ return 0;
+ if (strlen(host) > HOSTLEN)
+ return 0;
+ }
+
+ if (word) {
+ if ('@' == *word) /* no leading @'s */
+ return 0;
+
+ if ('#' == *word) { /* numeric index given? */
+ for (word++; *word; word++) {
+ if (!IsDigit(*word))
+ return 0;
+ }
+ return 1;
+ }
+
+ /* normal hostmask, account for at most one '@' */
+ for (; *word; word++) {
+ if ('@' == *word) {
+ i++;
+ continue;
+ }
+ if (!IsHostChar(*word))
+ return 0;
+ }
+ return (1 < i) ? 0 : 1; /* no more than on '@' */
+ }
+ return 0;
+}
+
+ /*
+ * IsVhost() - Check if given host is a valid spoofhost
+ * (ie: configured thru a S:line)
+ */
+static char *IsVhost(char *hostmask, int oper)
+{
+ unsigned int i = 0, y = 0;
+ struct sline *sconf;
+
+ Debug((DEBUG_INFO, "IsVhost() %s", hostmask));
+
+ if (EmptyString(hostmask))
+ return NULL;
+
+ /* spoofhost specified as index, ie: #27 */
+ if ('#' == hostmask[0]) {
+ y = atoi(hostmask + 1);
+ for (i = 0, sconf = GlobalSList; sconf; sconf = sconf->next) {
+ if (!oper && EmptyString(sconf->passwd))
+ continue;
+ if (y == ++i)
+ return sconf->spoofhost;
+ }
+ return NULL;
+ }
+
+ /* spoofhost specified as host, ie: host.cc */
+ for (sconf = GlobalSList; sconf; sconf = sconf->next)
+ if (strCasediff(hostmask, sconf->spoofhost) == 0)
+ return sconf->spoofhost;
+
+ return NULL;
+}
+
+ /*
+ * IsVhostPass() - Check if given spoofhost has a password
+ * associated with it, and if, return the password (cleartext)
+ */
+static char *IsVhostPass(char *hostmask)
+{
+ struct sline *sconf;
+
+ Debug((DEBUG_INFO, "IsVhostPass() %s", hostmask));
+
+ if (EmptyString(hostmask))
+ return NULL;
+
+ for (sconf = GlobalSList; sconf; sconf = sconf->next)
+ if (strCasediff(hostmask, sconf->spoofhost) == 0) {
+ Debug((DEBUG_INFO, "sconf->passwd %s", sconf->passwd));
+ return EmptyString(sconf->passwd) ? NULL : sconf->passwd;
+ }
+
+ return NULL;
+}
+
/** Update snomask \a oldmask according to \a arg and \a what.
* @param[in] oldmask Original user mask.
* @param[in] arg Update string (either a number or '+'/'-' followed by a number).
{
case MATCH_HOST:
return (match(mask, cli_user(one)->host) == 0 ||
- (HasHiddenHost(one) && match(mask, cli_user(one)->realhost) == 0));
+ ((HasHiddenHost(one) || HasSetHost(one)) && match(mask, cli_user(one)->realhost) == 0));
case MATCH_SERVER:
default:
return (match(mask, cli_name(cli_user(one)->server)) == 0);
if (fields & WHO_FIELD_NIP)
{
- const char* p2 = HasHiddenHost(acptr) && !IsAnOper(sptr) ?
+ const char* p2 = (HasHiddenHost(acptr) || HasSetHost(acptr)) && !IsAnOper(sptr) ?
feature_str(FEAT_HIDDEN_IP) :
ircd_ntoa(&cli_ip(acptr));
*(p1++) = ' ';
*(p1++) = 'w';
if (SendDebug(acptr))
*(p1++) = 'g';
+ if (HasSetHost(acptr))
+ *(p1++) = 'h';
}
if (HasHiddenHost(acptr))
*(p1++) = 'x';
--- /dev/null
+#!/bin/sh
+#
+# $Id: asuka-sethost.patch,v 1.29 2005/02/24 01:06:52 froo Exp $
+#
+# aid in converting S: and F:lines from old lain configs
+# to the new "super S:line" format of asuka.
+#
+# When Who What
+# 2003-01-05 froo@quakenet.org Created.
+
+PATH=/bin:/usr/bin
+PROG=`basename $0`
+USAGE="Usage: $PROG </path/to/ircd.cfg>"
+
+if [ $# -lt 1 ]; then
+ echo $USAGE
+ exit
+fi
+
+CONFIG=$1
+
+if [ ! -f $CONFIG ]; then
+ echo "Can't open \"$CONFIG\", bailing out."
+ exit
+fi
+
+{
+for LINE in `grep -E "^F:" $CONFIG`
+do
+ IDENT=`echo $LINE | cut -f2 -d:`
+ REALHOST=`echo $LINE | cut -f3 -d:`
+ SPOOFHOST=`echo $LINE | cut -f4 -d:`
+
+ IDENT=`echo $IDENT | sed -e 's,^~,\*,'`
+
+ echo "S:$SPOOFHOST::$REALHOST:$IDENT"
+done
+
+for LINE in `grep -E "^S:" $CONFIG`
+do
+ SPOOFHOST=`echo $LINE | cut -f2 -d:`
+ PASSWD=`echo $LINE | cut -f3 -d:`
+
+ IDENT=`echo $IDENT | sed -e 's,^~,\*,'`
+
+ echo "S:$SPOOFHOST:$PASSWD::"
+done
+} | sort
+
+exit 0