3
0
mirror of https://github.com/jlu5/PyLink.git synced 2024-12-25 04:02:45 +01:00

nefarious: implement account & vhost checking

Many thanks to @jobe1986 again, for giving me the specifics on how all of this works. :)
This commit is contained in:
James Lu 2016-04-17 22:23:44 -07:00
parent 38441f0302
commit c379287482

View File

@ -738,7 +738,7 @@ class P10Protocol(Protocol):
'host=%s realname=%s realhost=%s ip=%s', self.irc.name, nick, ts, uid,
ident, host, realname, realhost, ip)
self.irc.users[uid] = IrcUser(nick, ts, uid, ident, host, realname, realhost, ip)
uobj = self.irc.users[uid] = IrcUser(nick, ts, uid, ident, host, realname, realhost, ip)
self.irc.servers[source].users.add(uid)
# https://github.com/evilnet/nefarious2/blob/master/doc/p10.txt#L708
@ -750,13 +750,17 @@ class P10Protocol(Protocol):
parsedmodes = utils.parseModes(self.irc, uid, modes)
utils.applyModes(self.irc, uid, parsedmodes)
for modepair in parsedmodes:
if modepair[0][-1] == 'r':
# Parse account registrations, sent as usermode "+r accountname:TS"
accountname = modepair[1].split(':', 1)[0]
self.irc.callHooks([uid, 'CLIENT_SERVICES_LOGIN', {'text': accountname}])
# Call the OPERED UP hook if +o is being added to the mode list.
if ('+o', None) in parsedmodes:
self.irc.callHooks([uid, 'CLIENT_OPERED', {'text': 'IRC Operator'}])
# Set the accountname if present
#if accountname != "*":
# self.irc.callHooks([uid, 'CLIENT_SERVICES_LOGIN', {'text': accountname}])
self.checkCloakChange(uid)
return {'uid': uid, 'ts': ts, 'nick': nick, 'realhost': realhost, 'host': host, 'ident': ident, 'ip': ip}
@ -766,6 +770,64 @@ class P10Protocol(Protocol):
newnick = self.irc.users[source].nick = args[0]
return {'newnick': newnick, 'oldnick': oldnick, 'ts': int(args[1])}
def checkCloakChange(self, uid):
"""Checks for cloak changes on the given UID."""
uobj = self.irc.users[uid]
modes = dict(uobj.modes)
log.debug('(%s) checkCloakChange: modes of %s are %s', self.irc.name, uid, modes)
if 'x' not in modes: # +x isn't set, so cloaking is disabled.
newhost = uobj.realhost
else:
if 'h' in modes:
# +h represents the hidden (/sethost) host of the user. It overrides
# everything else.
newhost = modes['h']
elif 'f' in modes:
# +f represents another way of setting vHosts, via a command called FAKE.
# Atheme uses this for vHosts, afaik.
newhost = modes['f']
elif uobj.services_account and self.irc.serverdata.get('use_account_cloaks'):
# The user is registered. However, if account cloaks are enabled, we have to figure
# out their new cloaked host. There can be oper cloaks and user cloaks, each with
# a different suffix. Account cloaks take the format of <accountname>.<suffix>.
# e.g. someone logged in as "person1" might get cloak "person1.users.somenet.org"
# someone opered and logged in as "person2" might get cloak "person.opers.somenet.org"
# This is a lot of extra configuration on the services' side, but there's nothing else
# we can do about it.
if self.irc.serverdata.get('use_oper_account_cloaks') and 'o' in modes:
try:
# These errors should be fatal.
suffix = self.irc.serverdata['oper_cloak_suffix']
except KeyError:
raise ProtocolError("(%s) use_oper_account_cloaks was enabled, but "
"oper_cloak_suffix was not defined!" % self.irc.name)
else:
try:
suffix = self.irc.serverdata['cloak_suffix']
except KeyError:
raise ProtocolError("(%s) use_account_cloaks was enabled, but "
"cloak_suffix was not defined!" % self.irc.name)
accountname = uobj.services_account
newhost = "%s.%s" % (accountname, suffix)
elif 'C' in modes and self.irc.serverdata.get('use_account_cloaks'):
# +C propagates hashed IP cloaks, similar to UnrealIRCd. (thank god we don't
# need to generate these ourselves)
newhost = modes['C']
else:
# No cloaking mechanism matched, fall back to the real host.
newhost = uobj.realhost
# Propagate a hostname update to plugins, but only if the changed host is different.
if newhost != uobj.host:
self.irc.callHooks([uid, 'CHGHOST', {'target': uid, 'newhost': newhost}])
uobj.host = newhost
return newhost
def handle_ping(self, source, command, args):
"""Handles incoming PING requests."""
# Snippet from Jobe @ evilnet, thanks! AFAIK, the P10 docs are out of date and don't
@ -953,6 +1015,10 @@ class P10Protocol(Protocol):
if ('+o', None) in changedmodes and target in self.irc.users:
self.irc.callHooks([target, 'CLIENT_OPERED', {'text': 'IRC Operator'}])
if target in self.irc.users:
# Target was a user. Check for any cloak changes.
self.checkCloakChange(target)
return {'target': target, 'modes': changedmodes}
# OPMODE is like SAMODE on other IRCds, and it follows the same modesetting syntax.
handle_opmode = handle_mode
@ -1117,4 +1183,41 @@ class P10Protocol(Protocol):
utils.applyModes(self.irc, channel, changedmodes)
return {'target': channel, 'modes': changedmodes, 'oldchan': oldobj}
def handle_account(self, numeric, command, args):
"""Handles services account changes."""
# ACCOUNT has two possible syntaxes in P10, one with extended accounts
# and one without.
target = args[0]
if self.irc.serverdata.get('use_extended_accounts'):
# Registration: <- AA AC ABAAA R GL 1459019072
# Logout: <- AA AC ABAAA U
# 1 <target user numeric>
# 2 <subcommand>
# 3+ [<subcommand parameters>]
# Any other subcommands listed at https://github.com/evilnet/nefarious2/blob/master/doc/p10.txt#L354
# shouldn't apply to us.
if args[1] in ('R', 'M'):
accountname = args[2]
elif args[1] == 'U':
accountname = '' # logout
else:
# ircu or nefarious with F:EXTENDED_ACCOUNTS = FALSE
# 1 <target user numeric>
# 2 <account name>
# 3 [<account timestamp>]
accountname = args[1]
# Call this manually because we need the UID to be the sender.
self.irc.callHooks([target, 'CLIENT_SERVICES_LOGIN', {'text': accountname}])
# Check for any cloak changes now.
self.checkCloakChange(target)
Class = P10Protocol