]> ruderich.org/simon Gitweb - safcm/safcm.git/blob - cmd/safcm/config/permissions.go
Use SPDX license identifiers
[safcm/safcm.git] / cmd / safcm / config / permissions.go
1 // Config: parse permissions.yaml
2
3 // SPDX-License-Identifier: GPL-3.0-or-later
4 // Copyright (C) 2021-2024  Simon Ruderich
5
6 package config
7
8 import (
9         "fmt"
10         "io/fs"
11         "os"
12         "path/filepath"
13         "strconv"
14         "strings"
15
16         "gopkg.in/yaml.v2"
17
18         "ruderich.org/simon/safcm"
19 )
20
21 func LoadPermissions(group string, files map[string]*safcm.File) error {
22         path := filepath.Join(group, "permissions.yaml")
23
24         var cfg map[string]string
25         x, err := os.ReadFile(path)
26         if err != nil {
27                 if os.IsNotExist(err) {
28                         return nil
29                 }
30                 return err
31         }
32         err = yaml.UnmarshalStrict(x, &cfg)
33         if err != nil {
34                 return fmt.Errorf("%s: failed to load: %v", path, err)
35         }
36
37         for p, x := range cfg {
38                 _, ok := files[p]
39                 if !ok {
40                         return fmt.Errorf("%s: %q does not exist in files/",
41                                 path, p)
42                 }
43
44                 xs := strings.Fields(x)
45                 if len(xs) != 1 && len(xs) != 3 {
46                         return fmt.Errorf("%s: invalid line %q "+
47                                 "(expected <perm> [<user> <group>])",
48                                 path, x)
49                 }
50                 perm, err := strconv.ParseInt(xs[0], 8, 32)
51                 if err != nil {
52                         return fmt.Errorf("%s: invalid permission %q "+
53                                 "(expected e.g. %q or %q)",
54                                 path, xs[0], "0644", "01777")
55                 }
56                 if perm < 0 || perm > 07777 {
57                         return fmt.Errorf("%s: invalid permission %#o "+
58                                 "(expected e.g. %#o or %#o)",
59                                 path, perm, 0644, 01777)
60                 }
61
62                 file := files[p]
63                 // Sanity check
64                 if file.Mode.Perm()&0111 != 0 && perm&0111 == 0 {
65                         return fmt.Errorf(
66                                 "%s: %q: trying to remove +x from file, "+
67                                         "manually chmod -x in files/",
68                                 path, p)
69                 }
70                 file.Mode = file.Mode.Type() | FullPermToFileMode(int(perm))
71                 if len(xs) == 3 {
72                         file.User = xs[1]
73                         file.Group = xs[2]
74                 }
75         }
76
77         return nil
78 }
79
80 func FileModeToFullPerm(mode fs.FileMode) int {
81         perm := mode.Perm()
82         if mode&fs.ModeSticky != 0 {
83                 perm |= 01000
84         }
85         if mode&fs.ModeSetgid != 0 {
86                 perm |= 02000
87         }
88         if mode&fs.ModeSetuid != 0 {
89                 perm |= 04000
90         }
91         return int(perm)
92 }
93
94 func FullPermToFileMode(perm int) fs.FileMode {
95         mode := fs.FileMode(perm & 0777)
96         if perm&01000 != 0 {
97                 mode |= fs.ModeSticky
98         }
99         if perm&02000 != 0 {
100                 mode |= fs.ModeSetgid
101         }
102         if perm&04000 != 0 {
103                 mode |= fs.ModeSetuid
104         }
105         return mode
106 }