mirror of
https://github.com/fosrl/newt.git
synced 2026-02-20 11:56:39 +00:00
151 lines
3.8 KiB
Go
151 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"runtime"
|
|
|
|
"github.com/fosrl/newt/authdaemon"
|
|
"github.com/fosrl/newt/logger"
|
|
)
|
|
|
|
const (
|
|
defaultPrincipalsPath = "/var/run/auth-daemon/principals"
|
|
defaultCACertPath = "/etc/ssh/ca.pem"
|
|
)
|
|
|
|
var (
|
|
errPresharedKeyRequired = errors.New("auth-daemon-key is required when --auth-daemon is enabled")
|
|
errRootRequired = errors.New("auth-daemon must be run as root (use sudo)")
|
|
authDaemonServer *authdaemon.Server // Global auth daemon server instance
|
|
)
|
|
|
|
// startAuthDaemon initializes and starts the auth daemon in the background.
|
|
// It validates requirements (Linux, root, preshared key) and starts the server
|
|
// in a goroutine so it runs alongside normal newt operation.
|
|
func startAuthDaemon(ctx context.Context) error {
|
|
// Validation
|
|
if runtime.GOOS != "linux" {
|
|
return fmt.Errorf("auth-daemon is only supported on Linux, not %s", runtime.GOOS)
|
|
}
|
|
if os.Geteuid() != 0 {
|
|
return errRootRequired
|
|
}
|
|
|
|
// Use defaults if not set
|
|
principalsFile := authDaemonPrincipalsFile
|
|
if principalsFile == "" {
|
|
principalsFile = defaultPrincipalsPath
|
|
}
|
|
caCertPath := authDaemonCACertPath
|
|
if caCertPath == "" {
|
|
caCertPath = defaultCACertPath
|
|
}
|
|
|
|
// Create auth daemon server
|
|
cfg := authdaemon.Config{
|
|
DisableHTTPS: true, // We run without HTTP server in newt
|
|
PresharedKey: "this-key-is-not-used", // Not used in embedded mode, but set to non-empty to satisfy validation
|
|
PrincipalsFilePath: principalsFile,
|
|
CACertPath: caCertPath,
|
|
Force: true,
|
|
}
|
|
|
|
srv, err := authdaemon.NewServer(cfg)
|
|
if err != nil {
|
|
return fmt.Errorf("create auth daemon server: %w", err)
|
|
}
|
|
|
|
authDaemonServer = srv
|
|
|
|
// Start the auth daemon in a goroutine so it runs alongside newt
|
|
go func() {
|
|
logger.Info("Auth daemon starting (native mode, no HTTP server)")
|
|
if err := srv.Run(ctx); err != nil {
|
|
logger.Error("Auth daemon error: %v", err)
|
|
}
|
|
logger.Info("Auth daemon stopped")
|
|
}()
|
|
|
|
return nil
|
|
}
|
|
|
|
|
|
|
|
// runPrincipalsCmd executes the principals subcommand logic
|
|
func runPrincipalsCmd(args []string) {
|
|
opts := struct {
|
|
PrincipalsFile string
|
|
Username string
|
|
}{
|
|
PrincipalsFile: defaultPrincipalsPath,
|
|
}
|
|
|
|
// Parse flags manually
|
|
for i := 0; i < len(args); i++ {
|
|
switch args[i] {
|
|
case "--principals-file":
|
|
if i+1 >= len(args) {
|
|
fmt.Fprintf(os.Stderr, "Error: --principals-file requires a value\n")
|
|
os.Exit(1)
|
|
}
|
|
opts.PrincipalsFile = args[i+1]
|
|
i++
|
|
case "--username":
|
|
if i+1 >= len(args) {
|
|
fmt.Fprintf(os.Stderr, "Error: --username requires a value\n")
|
|
os.Exit(1)
|
|
}
|
|
opts.Username = args[i+1]
|
|
i++
|
|
case "--help", "-h":
|
|
printPrincipalsHelp()
|
|
os.Exit(0)
|
|
default:
|
|
fmt.Fprintf(os.Stderr, "Error: unknown flag: %s\n", args[i])
|
|
printPrincipalsHelp()
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
// Validation
|
|
if opts.Username == "" {
|
|
fmt.Fprintf(os.Stderr, "Error: username is required\n")
|
|
printPrincipalsHelp()
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Get principals
|
|
list, err := authdaemon.GetPrincipals(opts.PrincipalsFile, opts.Username)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
if len(list) == 0 {
|
|
fmt.Println("")
|
|
return
|
|
}
|
|
for _, principal := range list {
|
|
fmt.Println(principal)
|
|
}
|
|
}
|
|
|
|
func printPrincipalsHelp() {
|
|
fmt.Fprintf(os.Stderr, `Usage: newt principals [flags]
|
|
|
|
Output principals for a username (for AuthorizedPrincipalsCommand in sshd_config).
|
|
Read the principals file and print principals that match the given username, one per line.
|
|
Configure in sshd_config with AuthorizedPrincipalsCommand and %%u for the username.
|
|
|
|
Flags:
|
|
--principals-file string Path to the principals file (default "%s")
|
|
--username string Username to look up (required)
|
|
--help, -h Show this help message
|
|
|
|
Example:
|
|
newt principals --username alice
|
|
|
|
`, defaultPrincipalsPath)
|
|
} |