perm.go (2121B)
1 //go:build !windows && !plan9 2 3 package pqutil 4 5 import ( 6 "errors" 7 "os" 8 "syscall" 9 ) 10 11 var ( 12 ErrSSLKeyUnknownOwnership = errors.New("pq: could not get owner information for private key, may not be properly protected") 13 ErrSSLKeyHasWorldPermissions = errors.New("pq: private key has world access; permissions should be u=rw,g=r (0640) if owned by root, or u=rw (0600), or less") 14 ) 15 16 // SSLKeyPermissions checks the permissions on user-supplied SSL key files, 17 // which should have very little access. libpq does not check key file 18 // permissions on Windows. 19 // 20 // If the file is owned by the same user the process is running as, the file 21 // should only have 0600. If the file is owned by root, and the group matches 22 // the group that the process is running in, the permissions cannot be more than 23 // 0640. The file should never have world permissions. 24 // 25 // Returns an error when the permission check fails. 26 func SSLKeyPermissions(sslkey string) error { 27 fi, err := os.Stat(sslkey) 28 if err != nil { 29 return err 30 } 31 32 return CheckPermissions(fi) 33 } 34 35 func CheckPermissions(fi os.FileInfo) error { 36 // The maximum permissions that a private key file owned by a regular user 37 // is allowed to have. This translates to u=rw. Regardless of if we're 38 // running as root or not, 0600 is acceptable, so we return if no bits 39 // beyond the regular user permission mask are set. 40 if fi.Mode().Perm()&^os.FileMode(0o600) == 0 { 41 return nil 42 } 43 44 // We need to pull the Unix file information to get the file's owner. 45 // If we can't access it, there's some sort of operating system level error 46 // and we should fail rather than attempting to use faulty information. 47 sys, ok := fi.Sys().(*syscall.Stat_t) 48 if !ok { 49 return ErrSSLKeyUnknownOwnership 50 } 51 52 // if the file is owned by root, we allow 0640 (u=rw,g=r) to match what 53 // Postgres does. 54 if sys.Uid == 0 { 55 // The maximum permissions that a private key file owned by root is 56 // allowed to have. This translates to u=rw,g=r. 57 if fi.Mode().Perm()&^os.FileMode(0o640) != 0 { 58 return ErrSSLKeyHasWorldPermissions 59 } 60 return nil 61 } 62 63 return ErrSSLKeyHasWorldPermissions 64 }