#!/usr/bin/env python

# Should work with python 2 or 3
# Iain Murray, 2019

"""
Use like scp(1) but get root permissions (obtained by sudo) at the remote end.

You can override which scp command to use at the local and remote ends by
setting the LOCAL_SCP_CMD and REMOTE_SCP_CMD environment variables.

This wrapper needs to be able to use sudo without a password at the remote end,
as is enabled by default on (for example) most AWS instances.

You can configure sudo not to need a password by running "sudo visudo" on the
remote host and adding:
yourusername    ALL=(ALL) NOPASSWD:/usr/bin/scp
to the last line. This change is dangerous! scp can overwrite any file, so
a malicious process running as yourusername can now easily escalate its
permissions.

You could instead get a password to sudo, by setting REMOTE_SCP_CMD to point to
a script on the remote host with something like the following:
    #!/bin/sh
    export SUDO_ASKPASS=some_command_to_get_password
    sudo -A scp "$@"
But you'll need to write a some_command_to_get_password script to get the
password. You won't be able to interact directly with this command!
Maybe you'll communicate with it over a forwarded port, or by ssh-ing
in separately?
"""


import os, sys

args = sys.argv[:]

if (len(args) < 2) or (args[1] == '-h') or (args[1] == '--help'):
    sys.stderr.write("Help for %s\n" % sys.argv[0] + __doc__ + '\n')
    sys.exit(1)

if os.getenv('SCP_SUDO_DO_SSH', False):
    # Wrap ssh, but rewrite scp command to use sudo
    SSH = os.getenv('SCP_SUDO_SSH', 'ssh')
    try:
        idx = args.index('--') + 2
        assert((args[idx] == 'scp') or (args[idx].startswith('scp ')))
        args[idx] = os.getenv('REMOTE_SCP_CMD', 'sudo scp') + args[idx][3:]
    except:
        sys.stderr.write("\n%s error\n" % sys.argv[0])
        sys.stderr.write("ssh command-line arguments don't seem to be from scp?:\n\n")
        sys.stderr.write('\n'.join(args) + '\n\n')
        sys.exit(255)
    
    args[0] = SSH
    os.execvp(SSH, args)
else:
    # Call scp, telling it to use this script as the ssh command
    # (wrapping any existing custom ssh command)
    SCP = os.getenv('LOCAL_SCP_CMD', 'scp')
    args[0] = SCP
    set_ssh = False
    for idx, opt in enumerate(args):
        if opt == '--':
            break
        if opt == '-S':
            set_ssh = True
            os.environ['SCP_SUDO_SSH'] = args[idx + 1]
            args[idx + 1] = sys.argv[0]
        elif opt.startswith('-S'):
            set_ssh = True
            os.environ['SCP_SUDO_SSH'] = opt[2:]
            args[idx] = '-S' + sys.argv[0]
    if not set_ssh:
        args = [args[0], '-S', sys.argv[0]] + args[1:]
    os.environ['SCP_SUDO_DO_SSH'] = '1'
    os.execvp(SCP, args)

