Implement authorized keys command

This commit is contained in:
Drew DeVault 2017-04-02 06:51:26 -04:00
parent cb938b7fca
commit 0decd5a1db
11 changed files with 168 additions and 0 deletions

1
.gitignore vendored
View File

@ -13,3 +13,4 @@ pip-selfcheck.json
.sass-cache/
overrides/
.pgp
build

View File

@ -1,2 +1,3 @@
SRHT_PATH?=/usr/lib/python3.6/site-packages/srht
MODULE=gitsrht/
include ${SRHT_PATH}/Makefile

132
git-srht-keys Executable file
View File

@ -0,0 +1,132 @@
#!/usr/bin/env python3
# AuthorizedKeysCommand=/usr/bin/git-srht-keys "%u" "%h" "%k"
# AuthorizedKeysUser=root
import sys
import os
import shlex
import requests
from datetime import datetime
from pwd import getpwnam
from grp import getgrnam
from srht.config import cfg, cfgi, load_config
load_config("git")
_log = None
try:
_log = open("/var/log/git-srht-keys", "a")
except:
pass
def log(s, *args):
if isinstance(s, str):
s = s.format(*args)
else:
s = str(s)
s = "{} {}".format(datetime.now().isoformat(), s)
if _log:
_log.write(s + "\n")
else:
sys.stderr.write(s + "\n")
def auth_keys_error():
log("This command should be run by sshd's AuthorizedKeysCommand")
log('AuthorizedKeysCommand={} "%u" "%h" "%k"\nAuthorizedKeysUser=root',
os.path.abspath(sys.argv[0]))
sys.exit(1)
def drop_root():
if os.getuid() != git_uid or os.getgid() != git_gid:
log("setuid to {}", git_user)
os.setgid(git_gid)
os.setuid(git_uid)
git_user = cfg("git.sr.ht", "git-user").split(':')
git_uid, git_gid = getpwnam(git_user[0]).pw_uid, getgrnam(git_user[-1]).gr_gid
repos = cfg("cgit", "repos")
def auth_keys():
if len(sys.argv) != 5:
auth_keys_error()
user = sys.argv[2]
uid = getpwnam(user).pw_uid
homedir = sys.argv[3]
b64key = sys.argv[4]
authorized_keys_file = "{}/.ssh/authorized_keys".format(homedir)
log("user={} home={} b64key={}", user, homedir, b64key)
if user != git_user[0]:
log("Falling back to existing authorized keys file")
if not os.path.exists(authorized_keys_file):
sys.exit(0)
with open(authorized_keys_file, "r") as f:
authorized_keys = f.read()
print(authorized_keys)
sys.exit(0)
drop_root()
from srht.database import DbSession
db = DbSession(cfg("sr.ht", "connection-string"))
from gitsrht.types import User
db.init()
r = requests.get("{}/api/ssh-key/{}".format(
cfg("network", "meta"), b64key))
if r.status_code != 200:
log("meta.sr.ht returned 404 for this key")
sys.exit(0)
j = r.json()
username = j["user"]["username"]
u = User.query.filter(User.username == username).first()
if not u:
log("Unknown user {}", username)
log("Authorized user for login")
keys = "command=\"{} shell '{}' '{}'\",".format(sys.argv[0], u.id, b64key) + \
"no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty " + \
"ssh-rsa {} {}".format(b64key, username)
print(keys)
log(keys)
sys.exit(0)
def shell():
log("Starting up git.sr.ht shell")
drop_root()
_cmd = os.environ.get("SSH_ORIGINAL_COMMAND")
if not _cmd:
_cmd = ""
if len(sys.argv) < 3:
log("Error: expected 2 arguments from SSH")
user_id = sys.argv[2]
ssh_key = sys.argv[3]
from srht.database import DbSession
db = DbSession(cfg("sr.ht", "connection-string"))
from gitsrht.types import User
db.init()
user = User.query.filter(User.id == user_id).first()
if not user:
log("Unknown user ID {}", user_id)
log("User: {}", user.username)
log("Executing {}", _cmd)
cmd = shlex.split(_cmd)
valid_commands = ["git-receive-pack", "git-upload-pack", "git-upload-archive"]
if len(cmd) < 1 or not cmd[0] in valid_commands:
log("Not permitting unacceptable command")
print("Hi {}! You've successfully authenticated, ".format(user.username) +
"but I do not provide an interactive shell. Bye!")
sys.exit(128)
os.chdir(repos)
os.execv("/usr/bin/git-shell", ["/usr/bin/git-shell", "-c", _cmd])
with _log or sys.stdout:
if len(sys.argv) < 2:
auth_keys_error()
if sys.argv[1] == "auth":
auth_keys()
if sys.argv[1] == "shell":
shell()

View File

@ -37,7 +37,10 @@ def user_index(username):
if search:
repos = repos.filter(Repository.name.ilike("%" + search + "%"))
repos = repos.order_by(Repository.updated.desc())
total_repos = repos.count()
total_pages = repos.count() // 5 + 1
if total_repos % 5 == 0:
total_pages -= 1
if page:
try:
page = int(page) - 1

30
setup.py Executable file
View File

@ -0,0 +1,30 @@
#!/usr/bin/env python3
from distutils.core import setup
import subprocess
import glob
subprocess.call(["make"])
setup(
name = 'gitsrht',
packages = [
'gitsrht',
'gitsrht.types',
'gitsrht.blueprints',
],
version = subprocess.run(['git', 'describe', '--tags'],
stdout=subprocess.PIPE).stdout.decode().strip(),
description = 'git.sr.ht website',
author = 'Drew DeVault',
author_email = 'sir@cmpwn.com',
url = 'https://git.sr.ht/~sircmpwn/git.sr.ht',
requires = ['srht'],
license = 'GPL-2.0',
package_data={
'gitsrht': [
'templates/*.html',
'static/*',
]
},
scripts = ['git-srht-keys']
)

1
static Symbolic link
View File

@ -0,0 +1 @@
gitsrht/static/