...
Tawesoft Logo

Package drop

import "tawesoft.co.uk/go/drop"
Overview
Index
Subdirectories

Overview ▾

Package drop implements the ability to start a process as root, open privileged resources as files, drop privileges to become a given user account, and inherit file handles across the dropping of privileges.

NOTE: This package has only been tested on Linux. YMMV.

NOTE: This package WILL NOT WORK on Windows.

WARNING: if a process opens a config file as root, that file must be writable by root or system accounts only. The safest way to do this is change it to be root-owned with permissions 0644 (or 0600).

Examples

Opens privileged files and ports as root, then drops privileges

https://www.tawesoft.co.uk/go/doc/drop/examples/drop/

Package Information

License: MIT (see LICENSE.txt)

Stable: candidate

For more information, documentation, source code, examples, support, links, etc. please see https://www.tawesoft.co.uk/go and https://www.tawesoft.co.uk/go/drop

2021-07-09

    * The Inheritable interface has changed. It now has a Close() method. The
      Name() method has also been renamed String() to satisfy the stringer
      interface.

    * The Drop() function now returns an extra value before the error value.
      This `closer` can be used by the child process to close all Inheritable
      handles. Alternatively, it is possible to ignore this and close each
      handle by calling their Close() method.

    * The package now exports the builtins InheritableFile and
      InheritableNetListener that implement the Inheritable interface for
      Files and net.Listeners. These are created by the functions
      NewInheritableFile, NewInheritableTCPListener and
      NewInheritableUnixListener.

    * Drop() no longer panics on non-Linux platforms. However, it has only been
      tested on Linux so YMMV. It will continue to panic on Windows. Listeners
      also cannot be inherited on the JS platform target as they are not backed
      by files.

2021-03-17

    * Drop() now returns a (bool, error) 2-tuple. The first return value,
      if true, indicates that the caller should immediately exit.

2020-11-27

    * Drop() functionality has been moved to tawesoft.co.uk/go/drop with
      changes to Inheritables from a struct to an interface.

func Drop

func Drop(username string, files ...Inheritable) (bool, func() []error, error)

Drop works in two ways, depending on the privileges of the current process.

As the superuser (root), drop executes a new copy of the running program as the given user, blocks until that child program exits, then returns.

As the child process, drop returns without blocking. The current stdio streams, and zero-or-more "inheritable" files, are persisted and inherited by the new process.

If the first return argument is true, the caller is the root process and should exit immediately (e.g. by returning from main(), with os.Exit(), etc.)

The second return argument is a function. It is nil if the third argument is an error. In the child process, this calls the Close() method on each of the supplied Inheritable files. The caller may either Close() each Inheritable manually or typically simply defer this returned function. The returned []error argument from this function contains the errors returned by Inheritable Close() methods. In the root process, this returned function is always a no-op and does not need to be called.

func IsSuperuser

func IsSuperuser() bool

IsSuperuser returns true iff the current user is root

func UserLookup

func UserLookup(username string) (uid int, gid int, gids []int, err error)

UserLookup returns UID, GID, and Supplementary Group IDs

type Inheritable

Inheritable interface describes a File-based handle that can be passed between a parent and child process across a dropping of privileges.

type Inheritable interface {
    // String returns some description of the resource.
    String() string

    // Open is called by the root process
    Open() (*os.File, error)

    // Inherit is called by the child process
    Inherit(*os.File) error

    // Close closes any resource generated by a call to Open or Inherit.
    Close() error
}

type InheritableFile

InheritableFile is a file handle that survives a dropping of privileges.

type InheritableFile struct {
    // contains filtered or unexported fields
}

func NewInheritableFile

func NewInheritableFile(path string, flags int, uid int, gid int, mode os.FileMode) *InheritableFile

NewInheritableFile returns an InhertiableFile that wraps a file handle that survives a dropping of privileges.

The parameters uid, gid, and mode, unless equal to -1, -1, or 0, set the user, group, and permissions of the file after it has been opened.

WARNING: if these values are supplied from a config file, that config file should be writable to root or system accounts only - otherwise, an attacker may edit the config file in such a way as to set the permissions of arbitrary files.

func (InheritableFile) Close

func (h InheritableFile) Close() error

func (InheritableFile) Handle

func (h InheritableFile) Handle() *os.File

func (*InheritableFile) Inherit

func (h *InheritableFile) Inherit(f *os.File) error

func (*InheritableFile) Open

func (h *InheritableFile) Open() (*os.File, error)

func (InheritableFile) String

func (h InheritableFile) String() string

type InheritableNetListener

InheritableNetListener is a net.Listener that survives a dropping of privileges.

Note that On JS and Windows, the File method of most Listeners are not implemented, so this will not work.

type InheritableNetListener struct {
    // contains filtered or unexported fields
}

func NewInheritableTCPListener

func NewInheritableTCPListener(address string) *InheritableNetListener

func NewInheritableUnixListener

func NewInheritableUnixListener(address string, uid int, gid int, mode os.FileMode) *InheritableNetListener

NewInheritableUnixListener returns an InheritableNetListener for a UNIX socket.

The parameters uid, gid, and mode, unless equal to -1, -1, or 0, set the user, group, and permissions of the socket after it has been opened.

WARNING: if these values are supplied from a config file, that config file should be writable to root or system accounts only - otherwise, an attacker may edit the config file in such a way as to set the permissions of arbitrary files.

func (*InheritableNetListener) Close

func (h *InheritableNetListener) Close() error

func (InheritableNetListener) Handle

func (h InheritableNetListener) Handle() net.Listener

func (*InheritableNetListener) Inherit

func (h *InheritableNetListener) Inherit(f *os.File) error

func (*InheritableNetListener) Open

func (h *InheritableNetListener) Open() (*os.File, error)

func (InheritableNetListener) String

func (h InheritableNetListener) String() string

Subdirectories

Name Synopsis
examples
drop Opens privileged files and ports as root, then drops privileges