1 | //go:build !windows
|
---|
2 | // +build !windows
|
---|
3 |
|
---|
4 | package pq
|
---|
5 |
|
---|
6 | import (
|
---|
7 | "errors"
|
---|
8 | "os"
|
---|
9 | "syscall"
|
---|
10 | )
|
---|
11 |
|
---|
12 | const (
|
---|
13 | rootUserID = uint32(0)
|
---|
14 |
|
---|
15 | // The maximum permissions that a private key file owned by a regular user
|
---|
16 | // is allowed to have. This translates to u=rw.
|
---|
17 | maxUserOwnedKeyPermissions os.FileMode = 0600
|
---|
18 |
|
---|
19 | // The maximum permissions that a private key file owned by root is allowed
|
---|
20 | // to have. This translates to u=rw,g=r.
|
---|
21 | maxRootOwnedKeyPermissions os.FileMode = 0640
|
---|
22 | )
|
---|
23 |
|
---|
24 | var (
|
---|
25 | errSSLKeyHasUnacceptableUserPermissions = errors.New("permissions for files not owned by root should be u=rw (0600) or less")
|
---|
26 | errSSLKeyHasUnacceptableRootPermissions = errors.New("permissions for root owned files should be u=rw,g=r (0640) or less")
|
---|
27 | )
|
---|
28 |
|
---|
29 | // sslKeyPermissions checks the permissions on user-supplied ssl key files.
|
---|
30 | // The key file should have very little access.
|
---|
31 | //
|
---|
32 | // libpq does not check key file permissions on Windows.
|
---|
33 | func sslKeyPermissions(sslkey string) error {
|
---|
34 | info, err := os.Stat(sslkey)
|
---|
35 | if err != nil {
|
---|
36 | return err
|
---|
37 | }
|
---|
38 |
|
---|
39 | err = hasCorrectPermissions(info)
|
---|
40 |
|
---|
41 | // return ErrSSLKeyHasWorldPermissions for backwards compatability with
|
---|
42 | // existing code.
|
---|
43 | if err == errSSLKeyHasUnacceptableUserPermissions || err == errSSLKeyHasUnacceptableRootPermissions {
|
---|
44 | err = ErrSSLKeyHasWorldPermissions
|
---|
45 | }
|
---|
46 | return err
|
---|
47 | }
|
---|
48 |
|
---|
49 | // hasCorrectPermissions checks the file info (and the unix-specific stat_t
|
---|
50 | // output) to verify that the permissions on the file are correct.
|
---|
51 | //
|
---|
52 | // If the file is owned by the same user the process is running as,
|
---|
53 | // the file should only have 0600 (u=rw). If the file is owned by root,
|
---|
54 | // and the group matches the group that the process is running in, the
|
---|
55 | // permissions cannot be more than 0640 (u=rw,g=r). The file should
|
---|
56 | // never have world permissions.
|
---|
57 | //
|
---|
58 | // Returns an error when the permission check fails.
|
---|
59 | func hasCorrectPermissions(info os.FileInfo) error {
|
---|
60 | // if file's permission matches 0600, allow access.
|
---|
61 | userPermissionMask := (os.FileMode(0777) ^ maxUserOwnedKeyPermissions)
|
---|
62 |
|
---|
63 | // regardless of if we're running as root or not, 0600 is acceptable,
|
---|
64 | // so we return if we match the regular user permission mask.
|
---|
65 | if info.Mode().Perm()&userPermissionMask == 0 {
|
---|
66 | return nil
|
---|
67 | }
|
---|
68 |
|
---|
69 | // We need to pull the Unix file information to get the file's owner.
|
---|
70 | // If we can't access it, there's some sort of operating system level error
|
---|
71 | // and we should fail rather than attempting to use faulty information.
|
---|
72 | sysInfo := info.Sys()
|
---|
73 | if sysInfo == nil {
|
---|
74 | return ErrSSLKeyUnknownOwnership
|
---|
75 | }
|
---|
76 |
|
---|
77 | unixStat, ok := sysInfo.(*syscall.Stat_t)
|
---|
78 | if !ok {
|
---|
79 | return ErrSSLKeyUnknownOwnership
|
---|
80 | }
|
---|
81 |
|
---|
82 | // if the file is owned by root, we allow 0640 (u=rw,g=r) to match what
|
---|
83 | // Postgres does.
|
---|
84 | if unixStat.Uid == rootUserID {
|
---|
85 | rootPermissionMask := (os.FileMode(0777) ^ maxRootOwnedKeyPermissions)
|
---|
86 | if info.Mode().Perm()&rootPermissionMask != 0 {
|
---|
87 | return errSSLKeyHasUnacceptableRootPermissions
|
---|
88 | }
|
---|
89 | return nil
|
---|
90 | }
|
---|
91 |
|
---|
92 | return errSSLKeyHasUnacceptableUserPermissions
|
---|
93 | }
|
---|