返回 DeepSeek-Reasonix
credential_diagnostics_unix.go
根目录 / internal / config / credential_diagnostics_unix.go
1 //go:build !windows
2
3 package config
4
5 import (
6 "errors"
7 "fmt"
8 "os"
9 "syscall"
10 )
11
12 func credentialPlatformInspect(_ string, info os.FileInfo) (string, bool, bool, bool, error) {
13 stat, ok := info.Sys().(*syscall.Stat_t)
14 if !ok {
15 return "owner unavailable", false, info.Mode().Perm()&0o200 == 0, false, fmt.Errorf("owner information unavailable")
16 }
17 current := int(stat.Uid) == os.Geteuid()
18 return fmt.Sprintf("uid %d (current uid %d)", stat.Uid, os.Geteuid()), current, info.Mode().Perm()&0o200 == 0, false, nil
19 }
20
21 func credentialPlatformRepair(path string, expected os.FileInfo, verify func() error) ([]string, error) {
22 // Mutate the inspected inode, never a path that can be replaced between
23 // inspection, chmod and rollback. No-follow and nonblocking reject links/FIFOs.
24 f, err := os.OpenFile(path, os.O_RDONLY|syscall.O_NOFOLLOW|syscall.O_NONBLOCK, 0)
25 if err != nil {
26 return nil, err
27 }
28 defer f.Close()
29 info, err := f.Stat()
30 if err != nil {
31 return nil, err
32 }
33 if !os.SameFile(expected, info) {
34 return nil, fmt.Errorf("credential file identity changed")
35 }
36 _, owned, _, _, err := credentialPlatformInspect(path, info)
37 if err != nil || !owned {
38 return nil, fmt.Errorf("credential owner could not be verified")
39 }
40 before := info.Mode().Perm()
41 after := before | 0o600
42 if err := f.Chmod(after); err != nil {
43 return nil, err
44 }
45 actions := []string{}
46 if after != before {
47 actions = append(actions, "added owner read/write permission")
48 }
49 if err := verify(); err != nil {
50 if rollbackErr := f.Chmod(before); rollbackErr != nil {
51 return nil, errors.Join(
52 fmt.Errorf("verification failed: %w", err),
53 fmt.Errorf("rollback failed: %w", rollbackErr),
54 )
55 }
56 return nil, fmt.Errorf("verification failed: %w; changed attributes were restored", err)
57 }
58 return actions, nil
59 }
60
60 lines GO