Rewrite gitsrht-dispatch in Go
This commit is contained in:
parent
8c828abeb2
commit
c1f95e2a03
|
@ -1,67 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# AuthorizedKeysCommand=/usr/bin/git-srht-dispatch "%u" "%h" "%t" "%k"
|
||||
# AuthorizedKeysUser=root
|
||||
import sys
|
||||
import os
|
||||
try:
|
||||
f = open("/var/log/git-srht-dispatch", "a")
|
||||
os.close(sys.stderr.fileno())
|
||||
os.dup2(f.fileno(), sys.stderr.fileno())
|
||||
except Exception as ex:
|
||||
sys.stderr.write("Unable to open log for writing\n")
|
||||
sys.stderr.write(str(ex) + "\n")
|
||||
from collections import namedtuple
|
||||
from datetime import datetime
|
||||
from pwd import getpwnam
|
||||
from grp import getgrnam
|
||||
from srht.config import cfg, cfgkeys
|
||||
|
||||
def log(s, *args):
|
||||
sys.stderr.write("{} {}\n".format(datetime.now().isoformat(),
|
||||
s.format(*args) if isinstance(s, str) else str(s)))
|
||||
sys.stderr.flush()
|
||||
log("Running git-srht-dispatch")
|
||||
|
||||
def auth_keys_error():
|
||||
log("This command should be run by sshd's AuthorizedKeysCommand")
|
||||
log('AuthorizedKeysCommand={} "%u" "%h" "%t" "%k"\nAuthorizedKeysUser=root',
|
||||
os.path.abspath(sys.argv[0]))
|
||||
sys.exit(1)
|
||||
|
||||
Dispatcher = namedtuple("Dispatcher", ["cmd", "uid", "gid"])
|
||||
dispatchers = list()
|
||||
|
||||
for cmd in cfgkeys("git.sr.ht::dispatch"):
|
||||
user = cfg("git.sr.ht::dispatch", cmd).split(":")
|
||||
uid, gid = getpwnam(user[0]).pw_uid, getgrnam(user[-1]).gr_gid
|
||||
dispatchers.append(Dispatcher(cmd=cmd, uid=uid, gid=gid))
|
||||
log("registered dispatcher for {}:{}: {}", uid, gid, cmd)
|
||||
|
||||
if len(sys.argv) != 5:
|
||||
auth_keys_error()
|
||||
|
||||
user = sys.argv[1]
|
||||
uid = getpwnam(user).pw_uid
|
||||
homedir = sys.argv[2]
|
||||
key_type = sys.argv[3]
|
||||
b64key = sys.argv[4]
|
||||
authorized_keys_file = "{}/.ssh/authorized_keys".format(homedir)
|
||||
|
||||
log("authorizing user={} ({}) home={} b64key={} key_type={}",
|
||||
user, uid, homedir, b64key, key_type)
|
||||
|
||||
for dispatch in dispatchers:
|
||||
if dispatch.uid == uid:
|
||||
log("dispatching to {} with uid={}, gid={}",
|
||||
dispatch.cmd, dispatch.uid, dispatch.gid)
|
||||
os.setgid(dispatch.gid)
|
||||
os.setuid(dispatch.uid)
|
||||
os.execl(dispatch.cmd, *([dispatch.cmd] + sys.argv[1:]))
|
||||
|
||||
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)
|
|
@ -0,0 +1 @@
|
|||
gitsrht-dispatch
|
|
@ -0,0 +1,3 @@
|
|||
module git.sr.ht/~sircmpwn/git.sr.ht/gitsrht-dispatch
|
||||
|
||||
require github.com/vaughan0/go-ini v0.0.0-20130923145212-a98ad7ee00ec
|
|
@ -0,0 +1,2 @@
|
|||
github.com/vaughan0/go-ini v0.0.0-20130923145212-a98ad7ee00ec h1:DGmKwyZwEB8dI7tbLt/I/gQuP559o/0FrAkHKlQM/Ks=
|
||||
github.com/vaughan0/go-ini v0.0.0-20130923145212-a98ad7ee00ec/go.mod h1:owBmyHYMLkxyrugmfwE/DLJyW8Ro9mkphwuVErQ0iUw=
|
|
@ -0,0 +1,111 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"io"
|
||||
"os"
|
||||
osuser "os/user"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/vaughan0/go-ini"
|
||||
)
|
||||
|
||||
type Dispatcher struct {
|
||||
cmd string
|
||||
uid int
|
||||
gid int
|
||||
}
|
||||
|
||||
func main() {
|
||||
var (
|
||||
config ini.File
|
||||
err error
|
||||
logger *log.Logger
|
||||
)
|
||||
|
||||
logf, err := os.OpenFile("/var/log/gitsrht-dispatch",
|
||||
os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
|
||||
if err != nil {
|
||||
log.Printf("Warning: unable to open log file: %v " +
|
||||
"(using stderr instead)", err)
|
||||
logger = log.New(os.Stderr, "", log.LstdFlags)
|
||||
} else {
|
||||
logger = log.New(logf, "", log.LstdFlags)
|
||||
}
|
||||
|
||||
logger.Println("Running git.sr.ht dispatch")
|
||||
|
||||
for _, path := range []string{"../config.ini", "/etc/sr.ht/config.ini"} {
|
||||
config, err = ini.LoadFile(path)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
logger.Fatalf("Failed to load config file: %v", err)
|
||||
}
|
||||
|
||||
if len(os.Args) != 5 {
|
||||
logger.Fatalf(`Error: This command should be run by sshd's AuthorizedKeysCommand:
|
||||
|
||||
AuthorizedKeysCommand=%s "%%u" "%%h" "%%t" "%%k"
|
||||
AuthorizedKeysUser=root`, os.Args[0])
|
||||
}
|
||||
|
||||
// Map uid -> dispatcher
|
||||
dispatchers := make(map[int]Dispatcher)
|
||||
for cmd, value := range config.Section("git.sr.ht::dispatch") {
|
||||
spec := strings.Split(value, ":")
|
||||
if len(spec) != 2 {
|
||||
logger.Fatalf("Expected %s=user:group", cmd)
|
||||
}
|
||||
user, err := osuser.Lookup(spec[0])
|
||||
if err != nil {
|
||||
logger.Fatalf("Error looking up user %s: %v", spec[0], err)
|
||||
}
|
||||
group, err := osuser.LookupGroup(spec[1])
|
||||
if err != nil {
|
||||
logger.Fatalf("Error looking up group %s: %v", spec[1], err)
|
||||
}
|
||||
uid, _ := strconv.Atoi(user.Uid)
|
||||
gid, _ := strconv.Atoi(group.Gid)
|
||||
dispatchers[uid] = Dispatcher{cmd, uid, gid}
|
||||
logger.Printf("Registered dispatcher for %s(%d):%s(%d): %s",
|
||||
spec[0], uid, spec[1], gid, cmd)
|
||||
}
|
||||
|
||||
var user *osuser.User
|
||||
username := os.Args[1]
|
||||
if user, err = osuser.Lookup(username); err != nil {
|
||||
logger.Fatalf("Unknown user %s", username)
|
||||
}
|
||||
homedir := os.Args[2]
|
||||
key_type := os.Args[3]
|
||||
b64key := os.Args[4]
|
||||
authorized_keys_file := fmt.Sprintf("%s/.ssh/authorized_keys", homedir)
|
||||
uid, _ := strconv.Atoi(user.Uid)
|
||||
|
||||
logger.Printf("Authorizing user %s (%d); home=%s; b64key=%s; key_type=%s",
|
||||
username, uid, homedir, b64key, key_type)
|
||||
|
||||
if dispatcher, ok := dispatchers[uid]; ok {
|
||||
logger.Printf("Dispatching to %s", dispatcher.cmd)
|
||||
syscall.Setgid(dispatcher.gid)
|
||||
syscall.Setuid(dispatcher.uid)
|
||||
if err := syscall.Exec(dispatcher.cmd, append([]string{
|
||||
dispatcher.cmd,
|
||||
}, os.Args[1:]...), os.Environ()); err != nil {
|
||||
logger.Fatalf("Error exec'ing into %s: %v", dispatcher.cmd, err)
|
||||
}
|
||||
}
|
||||
|
||||
logger.Println("Falling back to authorized_keys file")
|
||||
akf, err := os.Open(authorized_keys_file)
|
||||
if err != nil {
|
||||
logger.Fatalf("Error opening authorized_keys: %v", err)
|
||||
}
|
||||
io.Copy(os.Stdout, akf)
|
||||
}
|
|
@ -46,7 +46,7 @@ class GitOAuthService(AbstractOAuthService):
|
|||
webhooks.update({
|
||||
webhook_url: ["ssh-key:add", "ssh-key:remove"]
|
||||
})
|
||||
super().ensure_meta_webhooks(user, webhooks)
|
||||
return super().ensure_meta_webhooks(user, webhooks)
|
||||
|
||||
def lookup_or_register(self, token, token_expires, scopes):
|
||||
user = super().lookup_or_register(token, token_expires, scopes)
|
||||
|
|
Loading…
Reference in New Issue