From 57225e05bd7e9d33679ec5643b7429a6f6fafb08 Mon Sep 17 00:00:00 2001 From: Maxim Slipenko Date: Tue, 15 Apr 2025 17:52:50 +0300 Subject: [PATCH] wip --- build.go | 21 +++++++++- fix.go | 2 +- install.go | 55 +++++++++++++++++--------- internal/translations/default.pot | 38 +++++++++--------- internal/translations/po/ru/default.po | 38 +++++++++--------- internal/utils/cmd.go | 26 ++++++++++-- list.go | 2 +- pkg/build/main_build.go | 51 +++--------------------- pkg/build/safe_installer.go | 24 +++++------ pkg/build/safe_script_executor.go | 25 ++++++------ repo.go | 2 +- search.go | 2 +- upgrade.go | 42 ++++++++++++-------- 13 files changed, 176 insertions(+), 152 deletions(-) diff --git a/build.go b/build.go index 2d6e5d0..7e36546 100644 --- a/build.go +++ b/build.go @@ -175,15 +175,32 @@ func BuildCmd() *cli.Command { return err } - builder, cleanup, err := build.NewMainBuilder( + installer, installerClose, err := build.GetSafeInstaller() + if err != nil { + return err + } + defer installerClose() + + if err := utils.ExitIfCantSetNoNewPrivs(); err != nil { + return err + } + + scripter, scripterClose, err := build.GetSafeScriptExecutor() + if err != nil { + return err + } + defer scripterClose() + + builder, err := build.NewMainBuilder( deps.Cfg, deps.Manager, deps.Repos, + scripter, + installer, ) if err != nil { return err } - defer cleanup() if scriptArgs != nil { res, err = builder.BuildPackageFromScript( diff --git a/fix.go b/fix.go index 05cd2ae..4d3be5f 100644 --- a/fix.go +++ b/fix.go @@ -37,7 +37,7 @@ func FixCmd() *cli.Command { Name: "fix", Usage: gotext.Get("Attempt to fix problems with ALR"), Action: func(c *cli.Context) error { - if err := utils.ExitIfCantDropCapsToAlrUser(); err != nil { + if err := utils.ExitIfCantDropCapsToAlrUserNoPrivs(); err != nil { return err } diff --git a/install.go b/install.go index f056760..95beb11 100644 --- a/install.go +++ b/install.go @@ -51,17 +51,33 @@ func InstallCmd() *cli.Command { return err } - if err := utils.ExitIfCantDropCapsToAlrUser(); err != nil { - return err - } - - ctx := c.Context - args := c.Args() if args.Len() < 1 { return cliutils.FormatCliExit(gotext.Get("Command install expected at least 1 argument, got %d", args.Len()), nil) } + if err := utils.ExitIfCantDropCapsToAlrUser(); err != nil { + return err + } + + installer, installerClose, err := build.GetSafeInstaller() + if err != nil { + return err + } + defer installerClose() + + if err := utils.ExitIfCantSetNoNewPrivs(); err != nil { + return err + } + + scripter, scripterClose, err := build.GetSafeScriptExecutor() + if err != nil { + return err + } + defer scripterClose() + + ctx := c.Context + deps, err := appbuilder. New(ctx). WithConfig(). @@ -75,15 +91,16 @@ func InstallCmd() *cli.Command { } defer deps.Defer() - builder, cleanup, err := build.NewMainBuilder( + builder, err := build.NewMainBuilder( deps.Cfg, deps.Manager, deps.Repos, + scripter, + installer, ) if err != nil { return err } - defer cleanup() err = builder.InstallPkgs( ctx, @@ -152,6 +169,7 @@ func RemoveCmd() *cli.Command { New(ctx). WithConfig(). WithDB(). + WithManager(). Build() if err != nil { return cli.Exit(err, 1) @@ -159,11 +177,7 @@ func RemoveCmd() *cli.Command { defer deps.Defer() installedAlrPackages := map[string]string{} - mgr := manager.Detect() - if mgr == nil { - return cliutils.FormatCliExit(gotext.Get("Unable to detect a supported package manager on the system"), nil) - } - installed, err := mgr.ListInstalled(&manager.Opts{AsRoot: false}) + installed, err := deps.Manager.ListInstalled(&manager.Opts{AsRoot: false}) if err != nil { return cliutils.FormatCliExit(gotext.Get("Error listing installed packages"), err) } @@ -209,16 +223,19 @@ func RemoveCmd() *cli.Command { return cliutils.FormatCliExit(gotext.Get("Command remove expected at least 1 argument, got %d", args.Len()), nil) } - mgr := manager.Detect() - if mgr == nil { - return cliutils.FormatCliExit(gotext.Get("Unable to detect a supported package manager on the system"), nil) + deps, err := appbuilder. + New(c.Context). + WithManager(). + Build() + if err != nil { + return err } + defer deps.Defer() - err := mgr.Remove(&manager.Opts{ + if err := deps.Manager.Remove(&manager.Opts{ AsRoot: true, NoConfirm: !c.Bool("interactive"), - }, c.Args().Slice()...) - if err != nil { + }, c.Args().Slice()...); err != nil { return cliutils.FormatCliExit(gotext.Get("Error removing packages"), err) } diff --git a/internal/translations/default.pot b/internal/translations/default.pot index 843f2d2..3846916 100644 --- a/internal/translations/default.pot +++ b/internal/translations/default.pot @@ -46,15 +46,15 @@ msgstr "" msgid "Nothing to build" msgstr "" -#: build.go:201 +#: build.go:218 msgid "Error building package" msgstr "" -#: build.go:208 +#: build.go:225 msgid "Error moving the package" msgstr "" -#: build.go:212 +#: build.go:229 msgid "Done" msgstr "" @@ -154,31 +154,27 @@ msgstr "" msgid "Install a new package" msgstr "" -#: install.go:62 +#: install.go:56 msgid "Command install expected at least 1 argument, got %d" msgstr "" -#: install.go:101 +#: install.go:118 msgid "Error parsing os release" msgstr "" -#: install.go:146 +#: install.go:163 msgid "Remove an installed package" msgstr "" -#: install.go:164 install.go:214 -msgid "Unable to detect a supported package manager on the system" -msgstr "" - -#: install.go:168 +#: install.go:182 msgid "Error listing installed packages" msgstr "" -#: install.go:209 +#: install.go:223 msgid "Command remove expected at least 1 argument, got %d" msgstr "" -#: install.go:222 +#: install.go:239 msgid "Error removing packages" msgstr "" @@ -194,6 +190,10 @@ msgstr "" msgid "Error pulling repositories" msgstr "" +#: internal/cliutils/app_builder/builder.go:165 +msgid "Unable to detect a supported package manager on the system" +msgstr "" + #: internal/cliutils/prompt.go:60 msgid "Would you like to view the build script for %s" msgstr "" @@ -311,15 +311,15 @@ msgstr "" msgid "ERROR" msgstr "" -#: internal/utils/cmd.go:83 +#: internal/utils/cmd.go:95 msgid "Error dropping capabilities" msgstr "" -#: internal/utils/cmd.go:103 +#: internal/utils/cmd.go:123 msgid "You need to be root to perform this action" msgstr "" -#: internal/utils/cmd.go:145 +#: internal/utils/cmd.go:165 msgid "You need to be a %s member to perform this action" msgstr "" @@ -507,14 +507,14 @@ msgstr "" msgid "Error executing template" msgstr "" -#: upgrade.go:50 +#: upgrade.go:47 msgid "Upgrade all installed packages" msgstr "" -#: upgrade.go:99 upgrade.go:116 +#: upgrade.go:109 upgrade.go:126 msgid "Error checking for updates" msgstr "" -#: upgrade.go:119 +#: upgrade.go:129 msgid "There is nothing to do." msgstr "" diff --git a/internal/translations/po/ru/default.po b/internal/translations/po/ru/default.po index e2304db..c46f947 100644 --- a/internal/translations/po/ru/default.po +++ b/internal/translations/po/ru/default.po @@ -54,15 +54,15 @@ msgstr "Пакет не найден" msgid "Nothing to build" msgstr "Исполнение build()" -#: build.go:201 +#: build.go:218 msgid "Error building package" msgstr "Ошибка при сборке пакета" -#: build.go:208 +#: build.go:225 msgid "Error moving the package" msgstr "Ошибка при перемещении пакета" -#: build.go:212 +#: build.go:229 msgid "Done" msgstr "Сделано" @@ -167,31 +167,27 @@ msgstr "Ошибка кодирования переменных скрита" msgid "Install a new package" msgstr "Установить новый пакет" -#: install.go:62 +#: install.go:56 msgid "Command install expected at least 1 argument, got %d" msgstr "Для команды install ожидался хотя бы 1 аргумент, получено %d" -#: install.go:101 +#: install.go:118 msgid "Error parsing os release" msgstr "Ошибка при разборе файла выпуска операционной системы" -#: install.go:146 +#: install.go:163 msgid "Remove an installed package" msgstr "Удалить установленный пакет" -#: install.go:164 install.go:214 -msgid "Unable to detect a supported package manager on the system" -msgstr "Не удалось обнаружить поддерживаемый менеджер пакетов в системе" - -#: install.go:168 +#: install.go:182 msgid "Error listing installed packages" msgstr "Ошибка при составлении списка установленных пакетов" -#: install.go:209 +#: install.go:223 msgid "Command remove expected at least 1 argument, got %d" msgstr "Для команды remove ожидался хотя бы 1 аргумент, получено %d" -#: install.go:222 +#: install.go:239 msgid "Error removing packages" msgstr "Ошибка при удалении пакетов" @@ -208,6 +204,10 @@ msgstr "Ошибка инициализации базы данных" msgid "Error pulling repositories" msgstr "Ошибка при извлечении репозиториев" +#: internal/cliutils/app_builder/builder.go:165 +msgid "Unable to detect a supported package manager on the system" +msgstr "Не удалось обнаружить поддерживаемый менеджер пакетов в системе" + #: internal/cliutils/prompt.go:60 msgid "Would you like to view the build script for %s" msgstr "Показать скрипт для пакета %s" @@ -326,16 +326,16 @@ msgstr "%s %s загружается — %s/с\n" msgid "ERROR" msgstr "ОШИБКА" -#: internal/utils/cmd.go:83 +#: internal/utils/cmd.go:95 #, fuzzy msgid "Error dropping capabilities" msgstr "Ошибка при открытии базы данных" -#: internal/utils/cmd.go:103 +#: internal/utils/cmd.go:123 msgid "You need to be root to perform this action" msgstr "" -#: internal/utils/cmd.go:145 +#: internal/utils/cmd.go:165 msgid "You need to be a %s member to perform this action" msgstr "" @@ -533,15 +533,15 @@ msgstr "Ошибка при разборе шаблона" msgid "Error executing template" msgstr "Ошибка при выполнении шаблона" -#: upgrade.go:50 +#: upgrade.go:47 msgid "Upgrade all installed packages" msgstr "Обновить все установленные пакеты" -#: upgrade.go:99 upgrade.go:116 +#: upgrade.go:109 upgrade.go:126 msgid "Error checking for updates" msgstr "Ошибка при проверке обновлений" -#: upgrade.go:119 +#: upgrade.go:129 msgid "There is nothing to do." msgstr "Здесь нечего делать." diff --git a/internal/utils/cmd.go b/internal/utils/cmd.go index d217561..455e5fb 100644 --- a/internal/utils/cmd.go +++ b/internal/utils/cmd.go @@ -73,6 +73,18 @@ func DropCapsToAlrUser() error { return EnsureIsAlrUser() } +func ExitIfCantDropGidToAlr() cli.ExitCoder { + _, gid, err := GetUidGidAlrUser() + if err != nil { + return cliutils.FormatCliExit("cannot get gid alr", err) + } + err = syscall.Setgid(gid) + if err != nil { + return cliutils.FormatCliExit("cannot get setgid alr", err) + } + return nil +} + // ExitIfCantDropCapsToAlrUser attempts to drop capabilities to the already // running user. Returns a cli.ExitCoder with an error if the operation fails. // See also [ExitIfCantDropCapsToAlrUserNoPrivs] for a version that also applies @@ -85,14 +97,22 @@ func ExitIfCantDropCapsToAlrUser() cli.ExitCoder { return nil } -// ExitIfCantDropCapsToAlrUserNoPrivs combines [ExitIfCantDropCapsToAlrUser] with [NoNewPrivs] +func ExitIfCantSetNoNewPrivs() cli.ExitCoder { + if err := NoNewPrivs(); err != nil { + return cliutils.FormatCliExit("error no new privs", err) + } + + return nil +} + +// ExitIfCantDropCapsToAlrUserNoPrivs combines [ExitIfCantDropCapsToAlrUser] with [ExitIfCantSetNoNewPrivs] func ExitIfCantDropCapsToAlrUserNoPrivs() cli.ExitCoder { if err := ExitIfCantDropCapsToAlrUser(); err != nil { return err } - if err := NoNewPrivs(); err != nil { - return cliutils.FormatCliExit("error no new privs", err) + if err := ExitIfCantSetNoNewPrivs(); err != nil { + return err } return nil diff --git a/list.go b/list.go index 304464c..4b12dce 100644 --- a/list.go +++ b/list.go @@ -47,7 +47,7 @@ func ListCmd() *cli.Command { }, }, Action: func(c *cli.Context) error { - if err := utils.ExitIfCantDropCapsToAlrUser(); err != nil { + if err := utils.ExitIfCantDropCapsToAlrUserNoPrivs(); err != nil { return err } diff --git a/pkg/build/main_build.go b/pkg/build/main_build.go index 98a6b28..aecd866 100644 --- a/pkg/build/main_build.go +++ b/pkg/build/main_build.go @@ -17,10 +17,6 @@ package build import ( - "log/slog" - "sync" - - "gitea.plemya-x.ru/Plemya-x/ALR/internal/utils" "gitea.plemya-x.ru/Plemya-x/ALR/pkg/manager" ) @@ -28,48 +24,11 @@ func NewMainBuilder( cfg Config, mgr manager.Manager, repos PackageFinder, -) (*Builder, func(), error) { - var err error - - var safeInstallerClose, safeScriptExecutorClose func() - - var cleanupOnce sync.Once - cleanup := func() { - cleanupOnce.Do(func() { - if safeScriptExecutorClose != nil { - safeScriptExecutorClose() - } - if safeInstallerClose != nil { - safeInstallerClose() - } - }) - } - - defer func() { - if err != nil { - slog.Debug("close executors") - cleanup() - } - }() - - installerExecutor, safeInstallerClose, err := GetSafeInstaller() - if err != nil { - return nil, nil, err - } - - // It is very important! - // See https://stackoverflow.com/questions/47296408/cannot-open-uid-map-for-writing-from-an-app-with-cap-setuid-capability-set - if err = utils.NoNewPrivs(); err != nil { - return nil, nil, err - } - - s, safeScriptExecutorClose, err := GetSafeScriptExecutor() - if err != nil { - return nil, nil, err - } - + scriptExecutor ScriptExecutor, + installerExecutor InstallerExecutor, +) (*Builder, error) { builder := &Builder{ - scriptExecutor: s, + scriptExecutor: scriptExecutor, cacheExecutor: &Cache{ cfg, }, @@ -89,5 +48,5 @@ func NewMainBuilder( repos: repos, } - return builder, cleanup, nil + return builder, nil } diff --git a/pkg/build/safe_installer.go b/pkg/build/safe_installer.go index 445a022..2d143e4 100644 --- a/pkg/build/safe_installer.go +++ b/pkg/build/safe_installer.go @@ -28,7 +28,6 @@ import ( "github.com/hashicorp/go-plugin" "gitea.plemya-x.ru/Plemya-x/ALR/internal/logger" - "gitea.plemya-x.ru/Plemya-x/ALR/internal/utils" ) type InstallerPlugin struct { @@ -99,17 +98,20 @@ func GetSafeInstaller() (InstallerExecutor, func(), error) { "ALR_LOG_LEVEL=DEBUG", } - uid, gid, err := utils.GetUidGidAlrUser() - if err != nil { - return nil, nil, err - } + /* + uid, gid, err := utils.GetUidGidAlrUser() + if err != nil { + return nil, nil, err + } - cmd.SysProcAttr = &syscall.SysProcAttr{ - Credential: &syscall.Credential{ - Uid: uint32(uid), - Gid: uint32(gid), - }, - } + + cmd.SysProcAttr = &syscall.SysProcAttr{ + Credential: &syscall.Credential{ + Uid: uint32(uid), + Gid: uint32(gid), + }, + } + */ slog.Debug("safe installer setup", "uid", syscall.Getuid(), "gid", syscall.Getgid()) diff --git a/pkg/build/safe_script_executor.go b/pkg/build/safe_script_executor.go index 75201e4..a9b1cb7 100644 --- a/pkg/build/safe_script_executor.go +++ b/pkg/build/safe_script_executor.go @@ -24,13 +24,11 @@ import ( "os" "os/exec" "sync" - "syscall" "github.com/hashicorp/go-plugin" "gitea.plemya-x.ru/Plemya-x/ALR/internal/logger" "gitea.plemya-x.ru/Plemya-x/ALR/internal/types" - "gitea.plemya-x.ru/Plemya-x/ALR/internal/utils" ) var HandshakeConfig = plugin.HandshakeConfig{ @@ -235,16 +233,19 @@ func GetSafeScriptExecutor() (ScriptExecutor, func(), error) { "PATH=/usr/bin:/bin:/usr/local/bin", "ALR_LOG_LEVEL=DEBUG", } - uid, gid, err := utils.GetUidGidAlrUser() - if err != nil { - return nil, nil, err - } - cmd.SysProcAttr = &syscall.SysProcAttr{ - Credential: &syscall.Credential{ - Uid: uint32(uid), - Gid: uint32(gid), - }, - } + /* + uid, gid, err := utils.GetUidGidAlrUser() + if err != nil { + return nil, nil, err + } + + cmd.SysProcAttr = &syscall.SysProcAttr{ + Credential: &syscall.Credential{ + Uid: uint32(uid), + Gid: uint32(gid), + }, + } + */ client := plugin.NewClient(&plugin.ClientConfig{ HandshakeConfig: HandshakeConfig, diff --git a/repo.go b/repo.go index 1a973ad..4a84986 100644 --- a/repo.go +++ b/repo.go @@ -90,7 +90,7 @@ func AddRepoCmd() *cli.Command { return cliutils.FormatCliExit(gotext.Get("Error saving config"), err) } - if err := utils.ExitIfCantDropCapsToAlrUser(); err != nil { + if err := utils.ExitIfCantDropCapsToAlrUserNoPrivs(); err != nil { return err } diff --git a/search.go b/search.go index 8724b68..4dad507 100644 --- a/search.go +++ b/search.go @@ -63,7 +63,7 @@ func SearchCmd() *cli.Command { }, }, Action: func(c *cli.Context) error { - if err := utils.ExitIfCantDropCapsToAlrUser(); err != nil { + if err := utils.ExitIfCantDropCapsToAlrUserNoPrivs(); err != nil { return err } diff --git a/upgrade.go b/upgrade.go index dfd39f5..2e12a05 100644 --- a/upgrade.go +++ b/upgrade.go @@ -23,7 +23,6 @@ import ( "context" "fmt" "log/slog" - "syscall" "github.com/leonelquinteros/gotext" "github.com/urfave/cli/v2" @@ -32,7 +31,6 @@ import ( "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils" appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder" - "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/overrides" "gitea.plemya-x.ru/Plemya-x/ALR/internal/types" @@ -40,7 +38,6 @@ import ( "gitea.plemya-x.ru/Plemya-x/ALR/pkg/build" "gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" "gitea.plemya-x.ru/Plemya-x/ALR/pkg/manager" - "gitea.plemya-x.ru/Plemya-x/ALR/pkg/repos" "gitea.plemya-x.ru/Plemya-x/ALR/pkg/search" ) @@ -61,13 +58,33 @@ func UpgradeCmd() *cli.Command { return err } + if err := utils.ExitIfCantDropCapsToAlrUser(); err != nil { + return err + } + + installer, installerClose, err := build.GetSafeInstaller() + if err != nil { + return err + } + defer installerClose() + + if err := utils.ExitIfCantSetNoNewPrivs(); err != nil { + return err + } + + scripter, scripterClose, err := build.GetSafeScriptExecutor() + if err != nil { + return err + } + defer scripterClose() + ctx := c.Context deps, err := appbuilder. New(ctx). WithConfig(). WithDB(). - WithReposNoPull(). + WithRepos(). WithDistroInfo(). WithManager(). Build() @@ -76,25 +93,18 @@ func UpgradeCmd() *cli.Command { } defer deps.Defer() - builder, cleanup, err := build.NewMainBuilder( + builder, err := build.NewMainBuilder( deps.Cfg, deps.Manager, deps.Repos, + scripter, + installer, ) if err != nil { return err } - defer cleanup() - slog.Warn("", "uid", syscall.Getuid(), "gid", syscall.Getgid()) - - if deps.Cfg.AutoPull() { - if err := deps.Repos.Pull(ctx, deps.Cfg.Repos()); err != nil { - return cliutils.FormatCliExit(gotext.Get("Error pulling repositories"), err) - } - } - - updates, err := checkForUpdates(ctx, deps.Manager, deps.Cfg, deps.DB, deps.Repos, deps.Info) + updates, err := checkForUpdates(ctx, deps.Manager, deps.DB, deps.Info) if err != nil { return cliutils.FormatCliExit(gotext.Get("Error checking for updates"), err) } @@ -127,9 +137,7 @@ func UpgradeCmd() *cli.Command { func checkForUpdates( ctx context.Context, mgr manager.Manager, - cfg *config.ALRConfig, db *database.Database, - rs *repos.Repos, info *distro.OSRelease, ) ([]database.Package, error) { installed, err := mgr.ListInstalled(nil)