github.com/coreos/rocket@v1.30.1-0.20200224141603-171c416fac02/pkg/acl/acl.go (about)

     1  // Copyright 2016 The rkt Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Copyright 2015 Joseph Naegele
    16  //
    17  // Portions of this code are derived from go-acl by Joseph Naegele
    18  // (https://github.com/naegeldjd/go-acl) which is under an MIT license that can
    19  // be found in the accompanying LICENSE.MIT file
    20  //
    21  
    22  //+build linux
    23  
    24  // Package acl is a wrapper over libacl that dlopens it instead of being linked
    25  // to it. The code is based on go-acl by Joseph Naegele
    26  // (https://github.com/naegelejd/go-acl).
    27  package acl
    28  
    29  // #cgo LDFLAGS: -ldl
    30  // #include <stdlib.h>
    31  // #include <dlfcn.h>
    32  // #include <stdio.h>
    33  // #include <sys/acl.h>
    34  // #include <sys/types.h>
    35  // #include <unistd.h>
    36  //
    37  // acl_t
    38  // my_acl_from_text(void *f, const char *acl)
    39  // {
    40  //   acl_t (*acl_from_text)(const char *);
    41  //
    42  //   acl_from_text = f;
    43  //   return acl_from_text(acl);
    44  // }
    45  //
    46  // int
    47  // my_acl_set_file(void *f, const char *path_p, acl_type_t type, acl_t acl)
    48  // {
    49  //   int (*acl_set_file)(const char *, acl_type_t, acl_t);
    50  //
    51  //   acl_set_file = f;
    52  //   return acl_set_file(path_p, type, acl);
    53  // }
    54  //
    55  // int
    56  // my_acl_free(void *f, acl_t acl)
    57  // {
    58  //   int (*acl_free)(acl_t);
    59  //
    60  //   acl_free = f;
    61  //   return acl_free(acl);
    62  // }
    63  //
    64  // int
    65  // my_acl_valid(void *f, acl_t acl)
    66  // {
    67  //   int (*acl_valid)(acl_t);
    68  //
    69  //   acl_valid = f;
    70  //   return acl_valid(acl);
    71  // }
    72  //
    73  // int
    74  // my_acl_create_entry(void *f, acl_t *acl_p, acl_entry_t *entry_p)
    75  // {
    76  //   int (*acl_create_entry)(acl_t *, acl_entry_t *);
    77  //
    78  //   acl_create_entry = f;
    79  //   return acl_create_entry(acl_p, entry_p);
    80  // }
    81  //
    82  // int
    83  // my_acl_set_tag_type(void *f, acl_entry_t entry_d, acl_tag_t tag_type)
    84  // {
    85  //   int (*acl_set_tag_type)(acl_entry_t, acl_tag_t);
    86  //
    87  //   acl_set_tag_type = f;
    88  //   return acl_set_tag_type(entry_d, tag_type);
    89  // }
    90  //
    91  // int
    92  // my_acl_get_permset(void *f, acl_entry_t entry_d, acl_permset_t *permset_p)
    93  // {
    94  //   int (*acl_get_permset)(acl_entry_t, acl_permset_t *);
    95  //
    96  //   acl_get_permset = f;
    97  //   return acl_get_permset(entry_d, permset_p);
    98  // }
    99  //
   100  // int
   101  // my_acl_add_perm(void *f, acl_permset_t permset_d, acl_perm_t perm)
   102  // {
   103  //   int (*acl_add_perm)(acl_permset_t, acl_perm_t);
   104  //
   105  //   acl_add_perm = f;
   106  //   return acl_add_perm(permset_d, perm);
   107  // }
   108  import "C"
   109  
   110  import (
   111  	"errors"
   112  	"fmt"
   113  	"os"
   114  	"unsafe"
   115  
   116  	"github.com/hashicorp/errwrap"
   117  )
   118  
   119  const (
   120  	otherExec = 1 << iota
   121  	otherWrite
   122  	otherRead
   123  	groupExec
   124  	groupWrite
   125  	groupRead
   126  	userExec
   127  	userWrite
   128  	userRead
   129  )
   130  
   131  const (
   132  	TagUserObj  Tag = C.ACL_USER_OBJ
   133  	TagUser         = C.ACL_USER
   134  	TagGroupObj     = C.ACL_GROUP_OBJ
   135  	TagGroup        = C.ACL_GROUP
   136  	TagMask         = C.ACL_MASK
   137  	TagOther        = C.ACL_OTHER
   138  )
   139  
   140  const (
   141  	PermRead    Perm = C.ACL_READ
   142  	PermWrite        = C.ACL_WRITE
   143  	PermExecute      = C.ACL_EXECUTE
   144  )
   145  
   146  type ACL struct {
   147  	lib *libHandle
   148  	a   C.acl_t
   149  }
   150  
   151  // Entry is an entry in an ACL.
   152  type Entry struct {
   153  	a *ACL
   154  	e C.acl_entry_t
   155  }
   156  
   157  // Permset is a set of permissions.
   158  type Permset struct {
   159  	a *ACL
   160  	p C.acl_permset_t
   161  }
   162  
   163  // Perm represents a permission in the e_perm ACL field
   164  type Perm int
   165  
   166  // Tag represents an ACL e_tag entry
   167  type Tag int
   168  
   169  var ErrSoNotFound = errors.New("unable to open a handle to libacl")
   170  
   171  type libHandle struct {
   172  	handle  unsafe.Pointer
   173  	libname string
   174  }
   175  
   176  func getHandle() (*libHandle, error) {
   177  	for _, name := range []string{
   178  		"libacl.so.1",
   179  		"libacl.so",
   180  	} {
   181  		libname := C.CString(name)
   182  		defer C.free(unsafe.Pointer(libname))
   183  		handle := C.dlopen(libname, C.RTLD_LAZY)
   184  		if handle != nil {
   185  			h := &libHandle{
   186  				handle:  handle,
   187  				libname: name,
   188  			}
   189  			return h, nil
   190  		}
   191  	}
   192  	return nil, ErrSoNotFound
   193  }
   194  
   195  func getSymbolPointer(handle unsafe.Pointer, symbol string) (unsafe.Pointer, error) {
   196  	sym := C.CString(symbol)
   197  	defer C.free(unsafe.Pointer(sym))
   198  
   199  	C.dlerror()
   200  	p := C.dlsym(handle, sym)
   201  	e := C.dlerror()
   202  	if e != nil {
   203  		return nil, errwrap.Wrap(fmt.Errorf("error resolving symbol %q", symbol), errors.New(C.GoString(e)))
   204  	}
   205  
   206  	return p, nil
   207  }
   208  
   209  func (h *libHandle) close() error {
   210  	C.dlerror()
   211  	C.dlclose(h.handle)
   212  	e := C.dlerror()
   213  	if e != nil {
   214  		return errwrap.Wrap(fmt.Errorf("error closing %v", h.libname), errors.New(C.GoString(e)))
   215  	}
   216  	return nil
   217  }
   218  
   219  // InitACL dlopens libacl and returns an ACL object if successful.
   220  func InitACL() (*ACL, error) {
   221  	h, err := getHandle()
   222  	if err != nil {
   223  		return nil, err
   224  	}
   225  
   226  	return &ACL{lib: h}, nil
   227  }
   228  
   229  // ParseACL parses a string representation of an ACL.
   230  func (a *ACL) ParseACL(acl string) error {
   231  	acl_from_text, err := getSymbolPointer(a.lib.handle, "acl_from_text")
   232  	if err != nil {
   233  		return err
   234  	}
   235  	cacl := C.CString(acl)
   236  	defer C.free(unsafe.Pointer(cacl))
   237  
   238  	retACL, err := C.my_acl_from_text(acl_from_text, cacl)
   239  	if retACL == nil {
   240  		return errwrap.Wrap(errors.New("error calling acl_from_text"), err)
   241  	}
   242  
   243  	a.a = retACL
   244  
   245  	return nil
   246  }
   247  
   248  // Free frees libacl's internal structures and closes libacl.
   249  func (a *ACL) Free() error {
   250  	acl_free, err := getSymbolPointer(a.lib.handle, "acl_free")
   251  	if err != nil {
   252  		return err
   253  	}
   254  
   255  	ret, err := C.my_acl_free(acl_free, a.a)
   256  	if ret < 0 {
   257  		return errwrap.Wrap(errors.New("error calling acl_free"), err)
   258  	}
   259  
   260  	return a.lib.close()
   261  }
   262  
   263  // SetFileACLDefault sets the "default" ACL for path.
   264  func (a *ACL) SetFileACLDefault(path string) error {
   265  	acl_set_file, err := getSymbolPointer(a.lib.handle, "acl_set_file")
   266  	if err != nil {
   267  		return err
   268  	}
   269  
   270  	cpath := C.CString(path)
   271  	defer C.free(unsafe.Pointer(cpath))
   272  
   273  	ret, err := C.my_acl_set_file(acl_set_file, cpath, C.ACL_TYPE_DEFAULT, a.a)
   274  	if ret < 0 {
   275  		return errwrap.Wrap(errors.New("error calling acl_set_file"), err)
   276  	}
   277  
   278  	return nil
   279  }
   280  
   281  // Valid checks whether the ACL is valid.
   282  func (a *ACL) Valid() error {
   283  	acl_valid, err := getSymbolPointer(a.lib.handle, "acl_valid")
   284  	if err != nil {
   285  		return err
   286  	}
   287  
   288  	ret, err := C.my_acl_valid(acl_valid, a.a)
   289  	if ret < 0 {
   290  		return errwrap.Wrap(errors.New("invalid acl"), err)
   291  	}
   292  	return nil
   293  }
   294  
   295  // AddBaseEntries adds the base ACL entries from the file permissions.
   296  func (a *ACL) AddBaseEntries(path string) error {
   297  	fi, err := os.Lstat(path)
   298  	if err != nil {
   299  		return err
   300  	}
   301  	mode := fi.Mode().Perm()
   302  	var r, w, x bool
   303  
   304  	// set USER_OBJ entry
   305  	r = mode&userRead == userRead
   306  	w = mode&userWrite == userWrite
   307  	x = mode&userExec == userExec
   308  	if err := a.addBaseEntryFromMode(TagUserObj, r, w, x); err != nil {
   309  		return err
   310  	}
   311  
   312  	// set GROUP_OBJ entry
   313  	r = mode&groupRead == groupRead
   314  	w = mode&groupWrite == groupWrite
   315  	x = mode&groupExec == groupExec
   316  	if err := a.addBaseEntryFromMode(TagGroupObj, r, w, x); err != nil {
   317  		return err
   318  	}
   319  
   320  	// set OTHER entry
   321  	r = mode&otherRead == otherRead
   322  	w = mode&otherWrite == otherWrite
   323  	x = mode&otherExec == otherExec
   324  	if err := a.addBaseEntryFromMode(TagOther, r, w, x); err != nil {
   325  		return err
   326  	}
   327  
   328  	return nil
   329  }
   330  
   331  func (a *ACL) createEntry() (*Entry, error) {
   332  	acl_create_entry, err := getSymbolPointer(a.lib.handle, "acl_create_entry")
   333  	if err != nil {
   334  		return nil, err
   335  	}
   336  
   337  	var e C.acl_entry_t
   338  
   339  	rv, err := C.my_acl_create_entry(acl_create_entry, &a.a, &e)
   340  	if rv < 0 {
   341  		return nil, errwrap.Wrap(errors.New("unable to create entry"), err)
   342  	}
   343  	return &Entry{a, e}, nil
   344  }
   345  
   346  func (a *ACL) addBaseEntryFromMode(tag Tag, read, write, execute bool) error {
   347  	e, err := a.createEntry()
   348  	if err != nil {
   349  		return err
   350  	}
   351  	if err = e.setTag(tag); err != nil {
   352  		return err
   353  	}
   354  	p, err := e.getPermset(a)
   355  	if err != nil {
   356  		return err
   357  	}
   358  	if err := p.addPermsFromMode(read, write, execute); err != nil {
   359  		return err
   360  	}
   361  	return nil
   362  }
   363  
   364  func (entry *Entry) getPermset(a *ACL) (*Permset, error) {
   365  	acl_get_permset, err := getSymbolPointer(a.lib.handle, "acl_get_permset")
   366  	if err != nil {
   367  		return nil, err
   368  	}
   369  
   370  	var ps C.acl_permset_t
   371  	rv, err := C.my_acl_get_permset(acl_get_permset, entry.e, &ps)
   372  	if rv < 0 {
   373  		return nil, errwrap.Wrap(errors.New("unable to get permset"), err)
   374  	}
   375  	return &Permset{a, ps}, nil
   376  }
   377  
   378  func (entry *Entry) setTag(t Tag) error {
   379  	acl_set_tag_type, err := getSymbolPointer(entry.a.lib.handle, "acl_set_tag_type")
   380  	if err != nil {
   381  		return err
   382  	}
   383  
   384  	rv, err := C.my_acl_set_tag_type(acl_set_tag_type, entry.e, C.acl_tag_t(t))
   385  	if rv < 0 {
   386  		return errwrap.Wrap(errors.New("unable to set tag"), err)
   387  	}
   388  
   389  	return nil
   390  }
   391  
   392  func (pset *Permset) addPerm(perm Perm) error {
   393  	acl_add_perm, err := getSymbolPointer(pset.a.lib.handle, "acl_add_perm")
   394  	if err != nil {
   395  		return err
   396  	}
   397  
   398  	rv, err := C.my_acl_add_perm(acl_add_perm, pset.p, C.acl_perm_t(perm))
   399  	if rv < 0 {
   400  		return errwrap.Wrap(errors.New("unable to add perm to permset"), err)
   401  	}
   402  	return nil
   403  }
   404  
   405  func (p *Permset) addPermsFromMode(read, write, execute bool) error {
   406  	if read {
   407  		if err := p.addPerm(PermRead); err != nil {
   408  			return err
   409  		}
   410  	}
   411  	if write {
   412  		if err := p.addPerm(PermWrite); err != nil {
   413  			return err
   414  		}
   415  	}
   416  	if execute {
   417  		if err := p.addPerm(PermExecute); err != nil {
   418  			return err
   419  		}
   420  	}
   421  	return nil
   422  }