// ALR - Any Linux Repository // Copyright (C) 2025 Евгений Храмов // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . package main import ( "fmt" "log/slog" "os" "os/exec" "os/user" "path/filepath" "strings" "syscall" "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-plugin" "github.com/leonelquinteros/gotext" "github.com/urfave/cli/v2" "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils" "gitea.plemya-x.ru/Plemya-x/ALR/internal/config" database "gitea.plemya-x.ru/Plemya-x/ALR/internal/db" "gitea.plemya-x.ru/Plemya-x/ALR/internal/logger" "gitea.plemya-x.ru/Plemya-x/ALR/internal/utils" "gitea.plemya-x.ru/Plemya-x/ALR/pkg/build" "gitea.plemya-x.ru/Plemya-x/ALR/pkg/manager" "gitea.plemya-x.ru/Plemya-x/ALR/pkg/repos" ) func InternalBuildCmd() *cli.Command { return &cli.Command{ Name: "_internal-safe-script-executor", HideHelp: true, Hidden: true, Action: func(c *cli.Context) error { logger.SetupForGoPlugin() err := utils.DropCapsToAlrUser() if err != nil { slog.Error("aa", "err", err) os.Exit(1) } cfg := config.New() err = cfg.Load() if err != nil { return cliutils.FormatCliExit(gotext.Get("Error loading config"), err) } logger := hclog.New(&hclog.LoggerOptions{ Name: "plugin", Output: os.Stderr, Level: hclog.Debug, JSONFormat: false, DisableTime: true, }) plugin.Serve(&plugin.ServeConfig{ HandshakeConfig: build.HandshakeConfig, Plugins: map[string]plugin.Plugin{ "script-executor": &build.ScriptExecutorPlugin{ Impl: build.NewLocalScriptExecutor(cfg), }, }, Logger: logger, }) return nil }, } } func InternalInstallCmd() *cli.Command { return &cli.Command{ Name: "_internal-installer", HideHelp: true, Hidden: true, Action: func(c *cli.Context) error { logger.SetupForGoPlugin() err := syscall.Setuid(0) if err != nil { slog.Error("err") os.Exit(1) } cfg := config.New() err = cfg.Load() if err != nil { return cliutils.FormatCliExit(gotext.Get("Error loading config"), err) } db := database.New(cfg) rs := repos.New(cfg, db) err = db.Init(c.Context) if err != nil { return cliutils.FormatCliExit(gotext.Get("Error initialization database"), err) } logger := hclog.New(&hclog.LoggerOptions{ Name: "plugin", Output: os.Stderr, Level: hclog.Trace, JSONFormat: true, DisableTime: true, }) plugin.Serve(&plugin.ServeConfig{ HandshakeConfig: build.HandshakeConfig, Plugins: map[string]plugin.Plugin{ "installer": &build.InstallerPlugin{ Impl: build.NewInstaller( rs, manager.Detect(), ), }, }, Logger: logger, }) return nil }, } } func InternalMountCmd() *cli.Command { return &cli.Command{ Name: "_internal-mount", HideHelp: true, Hidden: true, Action: func(c *cli.Context) error { sourceDir := c.Args().First() u, _ := user.Current() logger.SetupForGoPlugin() err := syscall.Setuid(0) if err != nil { slog.Error("Failed to setuid(0)", "err", err) os.Exit(1) } alrRunDir := "/var/run/alr" err = os.MkdirAll(alrRunDir, 0o750) if err != nil { slog.Error("Error creating /var/run/alr directory", "err", err) os.Exit(1) } _, gid, _ := utils.GetUidGidAlrUser() // Меняем группу на alr и права err = os.Chown(alrRunDir, 0, gid) // root:alr if err != nil { slog.Error("Failed to chown /var/run/alr", "err", err) os.Exit(1) } // Создаем поддиректорию для bindfs targetDir := filepath.Join(alrRunDir, fmt.Sprintf("bindfs-%d", os.Getpid())) err = os.MkdirAll(targetDir, 0o750) // 0750: владелец (root) и группа (alr) имеют доступ if err != nil { slog.Error("Error creating bindfs target directory", "err", err) os.Exit(1) } // Устанавливаем владельца и группу (root:alr) err = os.Chown(targetDir, 0, gid) if err != nil { slog.Error("Failed to chown bindfs directory", "err", err) os.Exit(1) } bindfsCmd := exec.Command( "bindfs", fmt.Sprintf("--map=%s/alr:@%s/@alr", u.Uid, u.Gid), sourceDir, targetDir, ) bindfsCmd.Stderr = os.Stderr if err := bindfsCmd.Start(); err != nil { slog.Error("Error starting bindfs", "err", err) os.Exit(1) } fmt.Print(targetDir) return nil }, } } func InternalUnmountCmd() *cli.Command { return &cli.Command{ Name: "_internal-umount", HideHelp: true, Hidden: true, Action: func(c *cli.Context) error { currentUser, err := user.Current() if err != nil { slog.Error("Failed to get current user", "err", err) os.Exit(1) } uid, gid, err := utils.GetUidGidAlrUserString() if err != nil { slog.Error("Failed to get alr user info", "err", err) os.Exit(1) } if currentUser.Uid != uid && currentUser.Gid != gid { slog.Error("Only alr user can unmount these directories") os.Exit(1) } targetDir := c.Args().First() if targetDir == "" { slog.Error("No target directory specified") os.Exit(1) } if !strings.HasPrefix(targetDir, "/var/run/alr/") { slog.Error("Can only unmount directories under /var/run/alr") os.Exit(1) } if _, err := os.Stat(targetDir); os.IsNotExist(err) { slog.Error("Target directory does not exist", "dir", targetDir) os.Exit(1) } err = syscall.Setuid(0) if err != nil { slog.Error("Failed to setuid(0)", "err", err) os.Exit(1) } umountCmd := exec.Command("umount", targetDir) umountCmd.Stderr = os.Stderr if err := umountCmd.Run(); err != nil { slog.Error("Error unmounting directory", "dir", targetDir, "err", err) os.Exit(1) } if err := os.Remove(targetDir); err != nil { slog.Error("Error removing directory", "dir", targetDir, "err", err) os.Exit(1) } return nil }, } }