forked from Plemya-x/ALR
265 lines
6.5 KiB
Go
265 lines
6.5 KiB
Go
// 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 <http://www.gnu.org/licenses/>.
|
|
|
|
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
|
|
},
|
|
}
|
|
}
|