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 }