krz/gitbay

A CLI-first git forge.

clone: git clone https://gitbay.org/krz/gitbay.git

main: cmd/gitbayd/system.go · raw

  1package main
  2
  3import (
  4	"fmt"
  5	"os"
  6
  7	"github.com/spf13/cobra"
  8	"golang.org/x/crypto/ssh"
  9
 10	"gitbay.org/gitbay/internal/config"
 11	"gitbay.org/gitbay/internal/protocol"
 12	"gitbay.org/gitbay/internal/sshd"
 13)
 14
 15// authorizedKeysCmd backs sshd's AuthorizedKeysCommand in system mode:
 16//
 17//	AuthorizedKeysCommand /usr/bin/gitbayd --config /etc/gitbay/config.toml authorized-keys %t %k
 18//	AuthorizedKeysCommandUser git
 19//
 20// It prints a forced-command authorized_keys line for registered keys and
 21// nothing for unknown ones — so unknown keys fail authentication inside
 22// sshd, before any forge code runs. That is why system mode requires
 23// registration = "closed".
 24func authorizedKeysCmd() *cobra.Command {
 25	return &cobra.Command{
 26		Use:    "authorized-keys <key-type> <key-base64>",
 27		Hidden: true,
 28		Args:   cobra.ExactArgs(2),
 29		RunE: func(cmd *cobra.Command, args []string) error {
 30			cfg, err := config.Load(configPath)
 31			if err != nil {
 32				return err
 33			}
 34			st, err := openStore(cfg)
 35			if err != nil {
 36				return err
 37			}
 38			defer st.Close()
 39
 40			pub, _, _, _, err := ssh.ParseAuthorizedKey([]byte(args[0] + " " + args[1]))
 41			if err != nil {
 42				return nil // unparseable key: no output, auth fails
 43			}
 44			key, err := st.SSHKeyByFingerprint(ssh.FingerprintSHA256(pub))
 45			if err != nil {
 46				return nil // unknown key: no output, auth fails
 47			}
 48			self, err := os.Executable()
 49			if err != nil {
 50				return err
 51			}
 52			fmt.Printf("restrict,command=\"%s --config %s shell --key-id %d\" %s %s\n",
 53				self, configPath, key.ID, args[0], args[1])
 54			return nil
 55		},
 56	}
 57}
 58
 59// shellCmd is the forced command sshd runs for an authenticated key. The
 60// original client command arrives in SSH_ORIGINAL_COMMAND; dispatch is the
 61// same code path as the embedded listener.
 62func shellCmd() *cobra.Command {
 63	var keyID int64
 64	cmd := &cobra.Command{
 65		Use:    "shell",
 66		Hidden: true,
 67		Args:   cobra.NoArgs,
 68		RunE: func(cmd *cobra.Command, args []string) error {
 69			cfg, err := config.Load(configPath)
 70			if err != nil {
 71				return err
 72			}
 73			st, err := openStore(cfg)
 74			if err != nil {
 75				return err
 76			}
 77			defer st.Close()
 78
 79			key, err := st.SSHKeyByID(keyID)
 80			if err != nil {
 81				fmt.Fprintln(os.Stderr, "key no longer registered")
 82				os.Exit(protocol.ExitDenied)
 83			}
 84			user, err := st.UserByID(key.UserID)
 85			if err != nil {
 86				fmt.Fprintln(os.Stderr, "account no longer exists")
 87				os.Exit(protocol.ExitDenied)
 88			}
 89			_ = st.TouchSSHKey(key.ID)
 90
 91			cmdline := os.Getenv("SSH_ORIGINAL_COMMAND")
 92			if cmdline == "" {
 93				fmt.Fprintf(os.Stderr, "gitbay control plane: interactive shells are not available.\nTry: ssh <host> help\n")
 94				os.Exit(protocol.ExitUsage)
 95			}
 96			code := sshd.Exec(cfg, st, user, key.Scope, cmdline, os.Stdin, os.Stdout, os.Stderr)
 97			st.Close()
 98			os.Exit(code)
 99			return nil
100		},
101	}
102	cmd.Flags().Int64Var(&keyID, "key-id", 0, "registered key id (set by authorized-keys)")
103	cmd.MarkFlagRequired("key-id")
104	return cmd
105}