From 18e8dc3fbf28de9f9428e44cc0635dcc4544b067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=28=D0=A5?= =?UTF-8?q?=D1=80=D0=B0=D0=BC=D1=8B=D1=87=D0=AA=29=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Sun, 21 Sep 2025 01:08:26 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BB=D0=BE=D0=B3=D0=B8=D0=BA=D0=B8?= =?UTF-8?q?=20=D0=BE=D0=BF=D1=80=D0=B5=D0=B4=D0=B5=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BF=D1=80=D0=B8=D0=B2=D0=B8=D0=BB=D0=B5=D0=B3=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=BD=D0=BE=D0=B9=20=D0=B3=D1=80?= =?UTF-8?q?=D1=83=D0=BF=D0=BF=D1=8B=20=D0=B4=D0=BB=D1=8F=20debian=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B8=D0=B7=D0=B2=D0=BE=D0=B4=D0=BD=D1=8B=D1=85=20?= =?UTF-8?q?=D0=B4=D0=B8=D1=81=D1=82=D1=80=D0=B8=D0=B1=D1=83=D1=82=D0=B8?= =?UTF-8?q?=D0=B2=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/constants/constants.go | 3 +- internal/utils/cmd.go | 6 +-- internal/utils/privileged_group.go | 76 ++++++++++++++++++++++++++++++ internal/utils/utils.go | 12 ++--- 4 files changed, 87 insertions(+), 10 deletions(-) create mode 100644 internal/utils/privileged_group.go diff --git a/internal/constants/constants.go b/internal/constants/constants.go index 5223368..373ffb9 100644 --- a/internal/constants/constants.go +++ b/internal/constants/constants.go @@ -20,5 +20,6 @@ const ( SystemConfigPath = "/etc/alr/alr.toml" SystemCachePath = "/var/cache/alr" TempDir = "/tmp/alr" - PrivilegedGroup = "wheel" + // PrivilegedGroup - устарело, используйте GetPrivilegedGroup() + PrivilegedGroup = "wheel" // оставлено для обратной совместимости ) diff --git a/internal/utils/cmd.go b/internal/utils/cmd.go index f3af2c4..b2c9fe2 100644 --- a/internal/utils/cmd.go +++ b/internal/utils/cmd.go @@ -26,7 +26,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/constants" ) // IsNotRoot проверяет, что текущий пользователь не является root @@ -51,7 +50,8 @@ func EnuseIsPrivilegedGroupMember() error { return err } - group, err := user.LookupGroup(constants.PrivilegedGroup) + privilegedGroup := GetPrivilegedGroup() + group, err := user.LookupGroup(privilegedGroup) if err != nil { return err } @@ -66,7 +66,7 @@ func EnuseIsPrivilegedGroupMember() error { return nil } } - return cliutils.FormatCliExit(gotext.Get("You need to be a %s member to perform this action", constants.PrivilegedGroup), nil) + return cliutils.FormatCliExit(gotext.Get("You need to be a %s member to perform this action", privilegedGroup), nil) } func RootNeededAction(f cli.ActionFunc) cli.ActionFunc { diff --git a/internal/utils/privileged_group.go b/internal/utils/privileged_group.go new file mode 100644 index 0000000..91916fd --- /dev/null +++ b/internal/utils/privileged_group.go @@ -0,0 +1,76 @@ +// ALR - Any Linux Repository +// Copyright (C) 2025 The ALR Authors +// +// 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 utils + +import ( + "context" + "os/user" + "sync" + + "gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro" +) + +var ( + privilegedGroupCache string + privilegedGroupOnce sync.Once +) + +// GetPrivilegedGroup определяет правильную привилегированную группу для текущего дистрибутива. +// Дистрибутивы на базе Debian/Ubuntu используют группу "sudo", остальные - "wheel". +func GetPrivilegedGroup() string { + privilegedGroupOnce.Do(func() { + privilegedGroupCache = detectPrivilegedGroup() + }) + return privilegedGroupCache +} + +func detectPrivilegedGroup() string { + // Попробуем определить дистрибутив + ctx := context.Background() + osInfo, err := distro.ParseOSRelease(ctx) + if err != nil { + // Если не можем определить дистрибутив, проверяем какие группы существуют + return detectGroupByAvailability() + } + + // Проверяем ID и семейство дистрибутива + // Debian и его производные (Ubuntu, Mint, PopOS и т.д.) используют sudo + if osInfo.ID == "debian" || osInfo.ID == "ubuntu" { + return "sudo" + } + + // Проверяем семейство дистрибутива через ID_LIKE + for _, like := range osInfo.Like { + if like == "debian" || like == "ubuntu" { + return "sudo" + } + } + + // Для остальных дистрибутивов (Fedora, RHEL, Arch, openSUSE, ALT Linux) используется wheel + return "wheel" +} + +// detectGroupByAvailability проверяет существование групп в системе +func detectGroupByAvailability() string { + // Сначала проверяем группу sudo (более распространена) + if _, err := user.LookupGroup("sudo"); err == nil { + return "sudo" + } + + // Если sudo не найдена, возвращаем wheel + return "wheel" +} \ No newline at end of file diff --git a/internal/utils/utils.go b/internal/utils/utils.go index 1696161..b62f1ff 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -28,8 +28,8 @@ func NoNewPrivs() error { return unix.Prctl(unix.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) } -// EnsureTempDirWithRootOwner создает каталог в /tmp/alr с правами для группы wheel -// Все каталоги в /tmp/alr принадлежат root:wheel с правами 775 +// EnsureTempDirWithRootOwner создает каталог в /tmp/alr с правами для привилегированной группы +// Все каталоги в /tmp/alr принадлежат root:привилегированная_группа с правами 775 // Для других каталогов использует стандартные права func EnsureTempDirWithRootOwner(path string, mode os.FileMode) error { if strings.HasPrefix(path, "/tmp/alr") { @@ -52,9 +52,9 @@ func EnsureTempDirWithRootOwner(path string, mode os.FileMode) error { return nil } - // Для обычной работы устанавливаем права и группу wheel + // Для обычной работы устанавливаем права и привилегированную группу permissions := "2775" - group := "wheel" + group := GetPrivilegedGroup() var chmodCmd, chownCmd *exec.Cmd if isRoot { @@ -70,7 +70,7 @@ func EnsureTempDirWithRootOwner(path string, mode os.FileMode) error { // Устанавливаем права с setgid битом err = chmodCmd.Run() if err != nil { - // Для root игнорируем ошибки, если группа wheel не существует + // Для root игнорируем ошибки, если группа не существует if !isRoot { return err } @@ -79,7 +79,7 @@ func EnsureTempDirWithRootOwner(path string, mode os.FileMode) error { // Устанавливаем владельца root:wheel err = chownCmd.Run() if err != nil { - // Для root игнорируем ошибки, если группа wheel не существует + // Для root игнорируем ошибки, если группа не существует if !isRoot { return err }