用户权限检查GO
#file #go #perm

本文是我个人博客上的originally published

问题

在处理我的go-pf模块时,我面临问题,以确保/dev/pf设备可读和写作。虽然其他语言(例如Shell或Perl)提供测试功能来检查当前的用户/进程是否已在特定文件上进行读取/写入/execrissions,但在GO中,此任务并不小。

这是我们可以用perl做到的:

#!/usr/bin/env perl

my $file = "test.txt";
if(!-r $file || !-w $file) {
    print $file . " is not read- and/or writable to the process\n";
    exit(1);
}
print "We're all good!\n"

如果我们在外壳中运行快速的单线线,我们可以看到脚本的工作方式:

$ for i in 100 200 400 500 600 700; do echo "chmod: $i"; \
    chmod $i test.txt; perl test.pl; done
chmod: 100
test.txt is not read- and/or writable to the process
chmod: 200
test.txt is not read- and/or writable to the process
chmod: 400
test.txt is not read- and/or writable to the process
chmod: 500
test.txt is not read- and/or writable to the process
chmod: 600
We're all good!
chmod: 700
We're all good!

在Go中,我们需要依靠os.Lstat,然后为我们提供Mode().Perm()方法,我们可以用来获得文件的文件模式。但这只是租金的一半。仅仅因为文件可能返回700的文件模式,这基本上意味着给出了读取和写入权限,因此我们可能无法由我们所有。当我们需要考虑到我们还拥有组和“其他”文件权限时,它会变得更加复杂。

解决方案

由于我找不到现成的解决方案,所以我完成了解决问题的任务 - 最好以同样简单的方式,例如在perl中。

如前所述,我们可以利用os.Lstat作为我们的起点。使用文件权限和一些位移,我们可以轻松弄清楚是否可以为“其他”,组和用户读取/写入/执行文件。借助此信息,下一步是找出所有者和所讨论的文件组。对于类似于Unix的操作系统,GO为我们在FileInfo上提供了os.Lstat上的Sys()方法,该方法由os.Lstat返回。我们可以尝试将Sys()的结果键入*syscall.Stat_t指针。如果成功成功,我们将获得所需的信息,即UidGid属性。

问题第一,我们可以看到谁拥有该文件,并检查我们当前的用户是否确实是所有者。 os/user.Current方法可以帮助我们。我们的下一个任务是组所有权 - 同样,这不是一个琐碎的任务,因为用户可以参与几个组的一部分。同样,GO标准库为我们提供了User.GroupIds方法形式所需的工具,该工具将为我们提供用户参与的组的列表。使用此列表,很容易弄清楚我们的用户是否是文件组的一部分。第二个问题也解决了。对于“其他”许可,我们可以再次进行一些转移。

去填充

您可能已经猜到了,我从所有这些中构建了一些东西。 go-fileperm将我之前讨论过的所有信息都用于一个易于使用的GO模块。让我们看看

首先,我们使用New()方法获取类型UserPerm的实例。 New将字符串作为参数,这是有关文件的途径。如果成功,该模块将为您提供几种检查文件访问权限(所有返回布尔值)的方法:

  • UserExecutable():如果当前用户/进程已在相关文件中执行权限,则返回true。
  • UserWritable():如果当前的用户/进程已在有问题的文件上写入权限,则返回true。
  • UserReadable():如果当前的用户/进程已在有关文件中读取权限,则返回true。
  • UserWriteExecutable():如果当前用户/进程已在此处写入和执行权限,则返回true 档案。
  • UserReadExecutable():如果当前用户/进程已读取和执行权限,则返回true 档案。
  • UserWriteReadExecutable():如果当前用户/进程已读取,写入和执行权限,则返回true 在有关文件上。

表现

由于Go-Fileperm主要利用位移动,因此模块的性能非常快。另外,我们无效分配,这总是一个加上的:)

goos: darwin
goarch: arm64
pkg: github.com/wneessen/go-fileperm
BenchmarkPermUser_UserReadable
BenchmarkPermUser_UserReadable-8                 7364846               143.6 ns/op             0 B/op          0 allocs/op
BenchmarkPermUser_UserWritable
BenchmarkPermUser_UserWritable-8                 7803267               154.9 ns/op             0 B/op          0 allocs/op
BenchmarkPermUser_UserExecutable
BenchmarkPermUser_UserExecutable-8               7922624               149.2 ns/op             0 B/op          0 allocs/op
BenchmarkPermUser_UserWriteReadable
BenchmarkPermUser_UserWriteReadable-8            6494815               186.1 ns/op             0 B/op          0 allocs/op
BenchmarkPermUser_UserWriteExecutable
BenchmarkPermUser_UserWriteExecutable-8          6590229               181.0 ns/op             0 B/op          0 allocs/op
BenchmarkPermUser_UserReadExecutable
BenchmarkPermUser_UserReadExecutable-8           6190532               184.7 ns/op             0 B/op          0 allocs/op
BenchmarkPermUser_UserWriteReadExecutable
BenchmarkPermUser_UserWriteReadExecutable-8      5728713               208.8 ns/op             0 B/op          0 allocs/op
PASS

完整的代码示例

让我们检查一个完整的代码示例,并应用我们在开始时使用的单线。

package main

import (
    "fmt"
    "log"

    "github.com/wneessen/go-fileperm"
)

func main() {
    p, err := fileperm.New("test.txt")
    if err != nil {
        log.Fatalf("failed to create UserPerm instance: %s", err)
    }
    fmt.Printf("test.txt is user-readable:              %t\n", p.UserReadable())
    fmt.Printf("test.txt is user-writable:              %t\n", p.UserWritable())
    fmt.Printf("test.txt is user-executable:            %t\n", p.UserExecutable())
    fmt.Printf("test.txt is user-read/writable:         %t\n", p.UserWriteReadable())
    fmt.Printf("test.txt is user-read/executable:       %t\n", p.UserReadExecutable())
    fmt.Printf("test.txt is user-write/executable:      %t\n", p.UserWriteExecutable())
    fmt.Printf("test.txt is user-read/write/executable: %t\n", p.UserWriteReadExecutable())
}
$ for i in 100 200 400 500 600 700; do echo "chmod: $i"; \
    chmod $i test.txt; go run main.go; done

chmod: 100
test.txt is user-readable:              false
test.txt is user-writable:              false
test.txt is user-executable:            true
test.txt is user-read/writable:         false
test.txt is user-read/executable:       false
test.txt is user-write/executable:      false
test.txt is user-read/write/executable: false
chmod: 200
test.txt is user-readable:              false
test.txt is user-writable:              true
test.txt is user-executable:            false
test.txt is user-read/writable:         false
test.txt is user-read/executable:       false
test.txt is user-write/executable:      false
test.txt is user-read/write/executable: false
chmod: 400
test.txt is user-readable:              true
test.txt is user-writable:              false
test.txt is user-executable:            false
test.txt is user-read/writable:         false
test.txt is user-read/executable:       false
test.txt is user-write/executable:      false
test.txt is user-read/write/executable: false
chmod: 500
test.txt is user-readable:              true
test.txt is user-writable:              false
test.txt is user-executable:            true
test.txt is user-read/writable:         false
test.txt is user-read/executable:       true
test.txt is user-write/executable:      false
test.txt is user-read/write/executable: false
chmod: 600
test.txt is user-readable:              true
test.txt is user-writable:              true
test.txt is user-executable:            false
test.txt is user-read/writable:         true
test.txt is user-read/executable:       false
test.txt is user-write/executable:      false
test.txt is user-read/write/executable: false
chmod: 700
test.txt is user-readable:              true
test.txt is user-writable:              true
test.txt is user-executable:            true
test.txt is user-read/writable:         true
test.txt is user-read/executable:       true
test.txt is user-write/executable:      true
test.txt is user-read/write/executable: true

结论

您可以看到,该模块非常易于使用,希望对某些人来说是一个有用的工具。像往常一样,我已经根据MIT许可在GitHub上发布了它,因此,如果您认为有一些需要改进的事情,请随时尝试甚至做出贡献。