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