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 }