mirror of
https://github.com/markqvist/rnsh.git
synced 2024-10-01 01:15:37 -04:00
Merge pull request #25 from markqvist/identities_file
Allowed Identities File
This commit is contained in:
commit
13352ee4e2
@ -20,7 +20,7 @@ usage = \
|
|||||||
Usage:
|
Usage:
|
||||||
rnsh -l [-c <configdir>] [-i <identityfile> | -s <service_name>] [-v... | -q...] -p
|
rnsh -l [-c <configdir>] [-i <identityfile> | -s <service_name>] [-v... | -q...] -p
|
||||||
rnsh -l [-c <configdir>] [-i <identityfile> | -s <service_name>] [-v... | -q...]
|
rnsh -l [-c <configdir>] [-i <identityfile> | -s <service_name>] [-v... | -q...]
|
||||||
[-b <period>] (-n | -a <identity_hash> [-a <identity_hash>] ...) [-A | -C]
|
[-b <period>] [-n] [-a <identity_hash>] ([-a <identity_hash>] ...) [-A | -C]
|
||||||
[[--] <program> [<arg> ...]]
|
[[--] <program> [<arg> ...]]
|
||||||
rnsh [-c <configdir>] [-i <identityfile>] [-v... | -q...] -p
|
rnsh [-c <configdir>] [-i <identityfile>] [-v... | -q...] -p
|
||||||
rnsh [-c <configdir>] [-i <identityfile>] [-v... | -q...] [-N] [-m] [-w <timeout>]
|
rnsh [-c <configdir>] [-i <identityfile>] [-v... | -q...] [-N] [-m] [-w <timeout>]
|
||||||
@ -40,7 +40,9 @@ Options:
|
|||||||
user rnsh is running under will be used.
|
user rnsh is running under will be used.
|
||||||
-b --announce PERIOD Announce on startup and every PERIOD seconds
|
-b --announce PERIOD Announce on startup and every PERIOD seconds
|
||||||
Specify 0 for PERIOD to announce on startup only.
|
Specify 0 for PERIOD to announce on startup only.
|
||||||
-a HASH --allowed HASH Specify identities allowed to connect
|
-a HASH --allowed HASH Specify identities allowed to connect. Allowed identities
|
||||||
|
can also be specified in ~/.rnsh/allowed_identities or
|
||||||
|
~/.config/rnsh/allowed_identities, one hash per line.
|
||||||
-n --no-auth Disable authentication
|
-n --no-auth Disable authentication
|
||||||
-N --no-id Disable identify on connect
|
-N --no-id Disable identify on connect
|
||||||
-A --remote-command-as-args Concatenate remote command to argument list of <program>/shell
|
-A --remote-command-as-args Concatenate remote command to argument list of <program>/shell
|
||||||
|
@ -64,7 +64,9 @@ def _get_logger(name: str):
|
|||||||
_identity = None
|
_identity = None
|
||||||
_reticulum = None
|
_reticulum = None
|
||||||
_allow_all = False
|
_allow_all = False
|
||||||
|
_allowed_file = None
|
||||||
_allowed_identity_hashes = []
|
_allowed_identity_hashes = []
|
||||||
|
_allowed_file_identity_hashes = []
|
||||||
_cmd: [str] | None = None
|
_cmd: [str] | None = None
|
||||||
DATA_AVAIL_MSG = "data available"
|
DATA_AVAIL_MSG = "data available"
|
||||||
_finished: asyncio.Event = None
|
_finished: asyncio.Event = None
|
||||||
@ -88,12 +90,37 @@ def _sigint_handler(sig, loop):
|
|||||||
else:
|
else:
|
||||||
raise KeyboardInterrupt()
|
raise KeyboardInterrupt()
|
||||||
|
|
||||||
|
def _reload_allowed_file():
|
||||||
|
global _allowed_file, _allowed_file_identity_hashes
|
||||||
|
log = _get_logger("_listen")
|
||||||
|
if _allowed_file != None:
|
||||||
|
try:
|
||||||
|
with open(_allowed_file, "r") as file:
|
||||||
|
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH // 8) * 2
|
||||||
|
added = 0
|
||||||
|
line = 0
|
||||||
|
_allowed_file_identity_hashes = []
|
||||||
|
for allow in file.read().replace("\r", "").split("\n"):
|
||||||
|
line += 1
|
||||||
|
if len(allow) == dest_len:
|
||||||
|
try:
|
||||||
|
destination_hash = bytes.fromhex(allow)
|
||||||
|
_allowed_file_identity_hashes.append(destination_hash)
|
||||||
|
added += 1
|
||||||
|
except Exception:
|
||||||
|
log.debug(f"Discarded invalid Identity hash in {_allowed_file} at line {line}")
|
||||||
|
|
||||||
|
ms = "y" if added == 1 else "ies"
|
||||||
|
log.debug(f"Loaded {added} allowed identit{ms} from "+str(_allowed_file))
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f"Error while reloading allowed indetities file: {e}")
|
||||||
|
|
||||||
|
|
||||||
async def listen(configdir, command, identitypath=None, service_name=None, verbosity=0, quietness=0, allowed=None,
|
async def listen(configdir, command, identitypath=None, service_name=None, verbosity=0, quietness=0, allowed=None,
|
||||||
disable_auth=None, announce_period=900, no_remote_command=True, remote_cmd_as_args=False,
|
allowed_file=None, disable_auth=None, announce_period=900, no_remote_command=True, remote_cmd_as_args=False,
|
||||||
loop: asyncio.AbstractEventLoop = None):
|
loop: asyncio.AbstractEventLoop = None):
|
||||||
global _identity, _allow_all, _allowed_identity_hashes, _reticulum, _cmd, _destination, _no_remote_command
|
global _identity, _allow_all, _allowed_identity_hashes, _allowed_file, _allowed_file_identity_hashes
|
||||||
global _remote_cmd_as_args, _finished
|
global _reticulum, _cmd, _destination, _no_remote_command, _remote_cmd_as_args, _finished
|
||||||
log = _get_logger("_listen")
|
log = _get_logger("_listen")
|
||||||
if not loop:
|
if not loop:
|
||||||
loop = asyncio.get_running_loop()
|
loop = asyncio.get_running_loop()
|
||||||
@ -135,6 +162,10 @@ async def listen(configdir, command, identitypath=None, service_name=None, verbo
|
|||||||
_allow_all = True
|
_allow_all = True
|
||||||
session.ListenerSession.allow_all = True
|
session.ListenerSession.allow_all = True
|
||||||
else:
|
else:
|
||||||
|
if allowed_file is not None:
|
||||||
|
_allowed_file = allowed_file
|
||||||
|
_reload_allowed_file()
|
||||||
|
|
||||||
if allowed is not None:
|
if allowed is not None:
|
||||||
for a in allowed:
|
for a in allowed:
|
||||||
try:
|
try:
|
||||||
@ -154,10 +185,13 @@ async def listen(configdir, command, identitypath=None, service_name=None, verbo
|
|||||||
log.error(str(e))
|
log.error(str(e))
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
if len(_allowed_identity_hashes) < 1 and not disable_auth:
|
if (len(_allowed_identity_hashes) < 1 and len(_allowed_file_identity_hashes) < 1) and not disable_auth:
|
||||||
log.warning("Warning: No allowed identities configured, rnsh will not accept any connections!")
|
log.warning("Warning: No allowed identities configured, rnsh will not accept any connections!")
|
||||||
|
|
||||||
def link_established(lnk: RNS.Link):
|
def link_established(lnk: RNS.Link):
|
||||||
|
_reload_allowed_file()
|
||||||
|
session.ListenerSession.allowed_file_identity_hashes = _allowed_file_identity_hashes
|
||||||
|
print(str(_allowed_file_identity_hashes))
|
||||||
session.ListenerSession(session.RNSOutlet.get_outlet(lnk), lnk.get_channel(), loop)
|
session.ListenerSession(session.RNSOutlet.get_outlet(lnk), lnk.get_channel(), loop)
|
||||||
_destination.set_link_established_callback(link_established)
|
_destination.set_link_established_callback(link_established)
|
||||||
|
|
||||||
|
@ -117,7 +117,13 @@ async def _rnsh_cli_main():
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
if args.listen:
|
if args.listen:
|
||||||
# log.info("command " + args.command)
|
allowed_file = None
|
||||||
|
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
|
||||||
|
if os.path.isfile(os.path.expanduser("~/.config/rnsh/allowed_identities")):
|
||||||
|
allowed_file = os.path.expanduser("~/.config/rnsh/allowed_identities")
|
||||||
|
elif os.path.isfile(os.path.expanduser("~/.rnsh/allowed_identities")):
|
||||||
|
allowed_file = os.path.expanduser("~/.rnsh/allowed_identities")
|
||||||
|
|
||||||
await listener.listen(configdir=args.config,
|
await listener.listen(configdir=args.config,
|
||||||
command=args.command_line,
|
command=args.command_line,
|
||||||
identitypath=args.identity,
|
identitypath=args.identity,
|
||||||
@ -125,6 +131,7 @@ async def _rnsh_cli_main():
|
|||||||
verbosity=args.verbose,
|
verbosity=args.verbose,
|
||||||
quietness=args.quiet,
|
quietness=args.quiet,
|
||||||
allowed=args.allowed,
|
allowed=args.allowed,
|
||||||
|
allowed_file=allowed_file,
|
||||||
disable_auth=args.no_auth,
|
disable_auth=args.no_auth,
|
||||||
announce_period=args.announce,
|
announce_period=args.announce,
|
||||||
no_remote_command=args.no_remote_cmd,
|
no_remote_command=args.no_remote_cmd,
|
||||||
|
@ -69,6 +69,7 @@ class LSOutletBase(ABC):
|
|||||||
class ListenerSession:
|
class ListenerSession:
|
||||||
sessions: List[ListenerSession] = []
|
sessions: List[ListenerSession] = []
|
||||||
allowed_identity_hashes: [any] = []
|
allowed_identity_hashes: [any] = []
|
||||||
|
allowed_file_identity_hashes: [any] = []
|
||||||
allow_all: bool = False
|
allow_all: bool = False
|
||||||
allow_remote_command: bool = False
|
allow_remote_command: bool = False
|
||||||
default_command: [str] = []
|
default_command: [str] = []
|
||||||
@ -183,7 +184,7 @@ class ListenerSession:
|
|||||||
if self.state not in [LSState.LSSTATE_WAIT_IDENT, LSState.LSSTATE_WAIT_VERS]:
|
if self.state not in [LSState.LSSTATE_WAIT_IDENT, LSState.LSSTATE_WAIT_VERS]:
|
||||||
self._protocol_error(LSState.LSSTATE_WAIT_IDENT.name)
|
self._protocol_error(LSState.LSSTATE_WAIT_IDENT.name)
|
||||||
|
|
||||||
if not self.allow_all and identity.hash not in self.allowed_identity_hashes:
|
if not self.allow_all and identity.hash not in self.allowed_identity_hashes and identity.hash not in self.allowed_file_identity_hashes:
|
||||||
self.terminate("Identity is not allowed.")
|
self.terminate("Identity is not allowed.")
|
||||||
|
|
||||||
self.remote_identity = identity
|
self.remote_identity = identity
|
||||||
|
Loading…
Reference in New Issue
Block a user