...

Source file src/github.com/lib/pq/ssl_permissions.go

Documentation: github.com/lib/pq

     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  }
    94  

View as plain text