UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2013 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <unistd.h> 32 33 #include "../util/util.h" 34 #include "../util/pool.h" 35 #include "../util/pblock.h" 36 #include "../safs/auth.h" 37 #include "log.h" 38 #include "acl.h" 39 40 #define AUTH_TYPE_BASIC "basic" 41 42 void acllist_createhandle(Session *sn, Request *rq) { 43 ACLListHandle *handle = pool_malloc(sn->pool, sizeof(ACLListHandle)); 44 handle->defaultauthdb = NULL; 45 handle->listhead = NULL; 46 handle->listtail = NULL; 47 rq->acllist = handle; 48 } 49 50 /* 51 * append or prepend an ACL 52 */ 53 void acllist_add(Session *sn, Request *rq, ACLList *acl, int append) { 54 if(!rq->acllist) { 55 acllist_createhandle(sn, rq); 56 } 57 ACLListHandle *list = rq->acllist; 58 59 if(!list->defaultauthdb && acl->authdb) { 60 list->defaultauthdb = acl->authdb; 61 } 62 63 ACLListElm *elm = pool_malloc(sn->pool, sizeof(ACLListElm)); 64 elm->acl = acl; 65 elm->next = NULL; 66 if(list->listhead == NULL) { 67 list->listhead = elm; 68 list->listtail = elm; 69 } else { 70 if(append) { 71 list->listtail->next = elm; 72 list->listtail = elm; 73 } else { 74 elm->next = list->listhead; 75 list->listhead = elm; 76 } 77 } 78 } 79 80 void acllist_append(Session *sn, Request *rq, ACLList *acl) { 81 acllist_add(sn, rq, acl, 1); 82 } 83 84 void acllist_prepend(Session *sn, Request *rq, ACLList *acl) { 85 acllist_add(sn, rq, acl, 0); 86 } 87 88 uint32_t acl_oflag2mask(int oflags) { 89 /* TODO: 90 * maybe there is a plattform where O_RDWR is not O_RDONLY | O_WRONLY 91 */ 92 uint32_t access_mask = 0; 93 if((oflags & O_RDONLY) == O_RDONLY) { 94 access_mask |= ACL_READ_DATA; 95 } 96 if((oflags & O_WRONLY) == O_WRONLY) { 97 access_mask |= ACL_WRITE_DATA; 98 } 99 return access_mask; 100 } 101 102 User* acllist_getuser(Session *sn, Request *rq, ACLListHandle *list) { 103 if(!sn || !rq || !list) { 104 return NULL; 105 } 106 107 // get user 108 User *user = NULL; 109 if(list->defaultauthdb) { 110 char *usr; 111 char *pw; 112 if(!basicauth_getuser(sn, rq, &usr, &pw)) { 113 int pwok; 114 user = authdb_get_and_verify(list->defaultauthdb, usr, pw, &pwok); 115 if(!user) { 116 // wrong user or wrong password 117 return NULL; 118 } 119 // ok - user is authenticated 120 pblock_kvinsert( 121 pb_key_auth_user, 122 user->name, 123 strlen(user->name), 124 rq->vars); 125 pblock_kvinsert( 126 pb_key_auth_type, 127 AUTH_TYPE_BASIC, 128 sizeof(AUTH_TYPE_BASIC)-1, 129 rq->vars); 130 } 131 } 132 133 return user; 134 } 135 136 void acl_set_error_status(Session *sn, Request *rq, ACLList *acl, User *user) { 137 if(sn == NULL || rq == NULL) { 138 return; 139 } 140 141 if(!user) { 142 char *value = NULL; 143 if(acl->authprompt) { 144 size_t realmlen = strlen(acl->authprompt); 145 size_t len = realmlen + 16; 146 value = pool_malloc(sn->pool, len); 147 if(value) { 148 snprintf( 149 value, 150 len, 151 "Basic realm=\"%s\"", 152 acl->authprompt); 153 } 154 } 155 if(!value) { 156 value = "Basic realm=\"login\""; 157 } 158 pblock_nvinsert("www-authenticate", value, rq->srvhdrs); 159 protocol_status(sn, rq, PROTOCOL_UNAUTHORIZED, NULL); 160 } else { 161 protocol_status(sn, rq, PROTOCOL_FORBIDDEN, NULL); 162 } 163 } 164 165 int acl_evaluate(Session *sn, Request *rq, int access_mask) { 166 ACLListHandle *list = rq->acllist; 167 if(!list) { 168 return REQ_PROCEED; 169 } 170 171 // we combine access_mask with the required access rights 172 access_mask |= rq->aclreqaccess; 173 174 // get user 175 User *user = acllist_getuser(sn, rq, list); 176 177 // evalutate all ACLs 178 ACLList *acl = acl_evallist(list, user, access_mask, NULL); 179 if(acl) { 180 acl_set_error_status(sn, rq, acl, user); 181 // TODO: don't free the user here 182 if(user) { 183 user->free(user); 184 } 185 return REQ_ABORTED; 186 } 187 188 // access allowed, we can free the user 189 if(user) { 190 user->free(user); 191 } 192 193 return REQ_PROCEED; 194 } 195 196 ACLList* acl_evallist( 197 ACLListHandle *list, 198 User *user, 199 int access_mask, 200 ACLList **externacl) 201 { 202 if(!list) { 203 return NULL; 204 } 205 if(externacl) { 206 *externacl = NULL; 207 } 208 209 // evaluate each acl until one denies access 210 ACLListElm *elm = list->listhead; 211 while(elm) { 212 ACLList *acl = elm->acl; 213 if(acl->isextern) { 214 // set externacl to the first external acl 215 if(externacl && *externacl == NULL) { 216 *externacl = acl; 217 } 218 } else if(!acl->check(acl, user, access_mask)) { 219 // the acl denies access 220 return acl; 221 } 222 elm = elm->next; 223 } 224 225 // ok - all acls allowed access 226 227 return NULL; 228 } 229 230 int wsacl_affects_user(WSAce *ace, User *user) { 231 int check_access = 0; 232 233 /* 234 * an ace can affect 235 * a named user or group (ace->who is set) 236 * the owner of the resource (ACL_OWNER is set) 237 * the owning group of the resource (ACL_GROUP is set) 238 * everyone (ACL_EVERYONE is set) 239 * 240 * Only one of this conditions should be true. The behavior on 241 * illegal flag combination is undefined. We assume that the acls 242 * are created correctly by the configuration loader. 243 */ 244 245 if(ace->who && user) { 246 // this ace is defined for a named user or group 247 if((ace->flags & ACL_IDENTIFIER_GROUP) == ACL_IDENTIFIER_GROUP) { 248 if(user->check_group(user, ace->who)) { 249 // the user is in the group 250 check_access = 1; 251 } 252 } else { 253 if(!strcmp(user->name, ace->who)) { 254 check_access = 1; 255 } 256 } 257 } else if((ace->flags & ACL_OWNER) == ACL_OWNER) { 258 // TODO 259 } else if((ace->flags & ACL_GROUP) == ACL_GROUP) { 260 // TODO 261 } else if((ace->flags & ACL_EVERYONE) == ACL_EVERYONE) { 262 check_access = 1; 263 } 264 265 return check_access; 266 } 267 268 int wsacl_check(WSAcl *acl, User *user, int access_mask) { 269 int allow = 0; 270 uint32_t allowed_access = 0; 271 // check each access control entry 272 for(int i=0;i<acl->acenum;i++) { 273 WSAce *ace = acl->ace[i]; 274 if(wsacl_affects_user(ace, user)) { 275 if(ace->type == ACL_TYPE_ALLOWED) { 276 // add all new access rights 277 allowed_access |= (access_mask & ace->access_mask); 278 // check if we have all requested rights 279 if((allowed_access & access_mask) == access_mask) { 280 allow = 1; 281 break; 282 } 283 } else { 284 // ACL_TYPE_DENIED 285 286 if((ace->access_mask & access_mask) != 0) { 287 // access denied 288 break; 289 } 290 } 291 } 292 } 293 294 // TODO: events 295 296 return allow; // allow is 0, if no ace set it to 1 297 } 298 299 300 /* filesystem acl functions */ 301 302 #if defined (__SVR4) && defined (__sun) 303 304 #include <sys/acl.h> 305 306 int solaris_acl_check( 307 char *path, 308 struct stat *s, 309 uint32_t mask, 310 uid_t uid, 311 gid_t gid); 312 int solaris_acl_affects_user( 313 ace_t *ace, 314 uid_t uid, 315 gid_t gid, 316 uid_t owner, 317 gid_t owninggroup); 318 319 int fs_acl_check(SysACL *acl, User *user, char *path, uint32_t access_mask) { 320 sstr_t p; 321 if(path[0] != '/') { 322 size_t n = 128; 323 char *cwd = malloc(n); 324 while(!getcwd(cwd, n)) { 325 if(errno == ERANGE) { 326 n *= 2; 327 cwd = realloc(cwd, n); 328 } else { 329 free(cwd); 330 return 0; 331 } 332 } 333 sstr_t wd = sstr(cwd); 334 sstr_t pp = sstr(path); 335 336 p = sstrcat(3, wd, sstrn("/", 1), pp); 337 } else { 338 p = sstrdup(sstr(path)); 339 } 340 if(p.ptr[p.length-1] == '/') { 341 p.ptr[p.length-1] = 0; 342 p.length--; 343 } 344 345 // get uid/gid 346 struct passwd pw; 347 if(user) { 348 char *pwbuf = malloc(DEF_PWBUF); 349 if(pwbuf == NULL) { 350 free(p.ptr); 351 return 0; 352 } 353 if(!util_getpwnam(user->name, &pw, pwbuf, DEF_PWBUF)) { 354 free(pwbuf); 355 free(p.ptr); 356 return 0; 357 } 358 free(pwbuf); 359 acl->user_uid = pw.pw_uid; 360 acl->user_gid = pw.pw_gid; 361 } else { 362 acl->user_uid = -1; 363 acl->user_gid = -1; 364 } 365 366 // translate access_mask 367 uint32_t mask = 0; 368 if((access_mask & ACL_READ_DATA) == ACL_READ_DATA) { 369 mask |= ACE_READ_DATA; 370 } 371 if((access_mask & ACL_WRITE_DATA) == ACL_WRITE_DATA) { 372 mask |= ACE_WRITE_DATA; 373 } 374 if((access_mask & ACL_ADD_FILE) == ACL_ADD_FILE) { 375 mask |= ACE_ADD_FILE; 376 } 377 if((access_mask & ACL_READ_XATTR) == ACL_READ_XATTR) { 378 mask |= ACE_READ_NAMED_ATTRS; 379 } 380 if((access_mask & ACL_WRITE_XATTR) == ACL_WRITE_XATTR) { 381 mask |= ACE_WRITE_NAMED_ATTRS; 382 } 383 if((access_mask & ACL_EXECUTE) == ACL_EXECUTE) { 384 mask |= ACE_EXECUTE; 385 } 386 if((access_mask & ACL_DELETE) == ACL_DELETE) { 387 mask |= ACE_DELETE_CHILD; 388 } 389 if((access_mask & ACL_READ_ATTRIBUTES) == ACL_READ_ATTRIBUTES) { 390 mask |= ACE_READ_ATTRIBUTES; 391 } 392 if((access_mask & ACL_WRITE_ATTRIBUTES) == ACL_WRITE_ATTRIBUTES) { 393 mask |= ACE_WRITE_ATTRIBUTES; 394 } 395 if((access_mask & ACL_LIST) == ACL_LIST) { 396 mask |= ACE_LIST_DIRECTORY; 397 } 398 if((access_mask & ACL_READ_ACL) == ACL_READ_ACL) { 399 mask |= ACE_READ_ACL; 400 } 401 if((access_mask & ACL_WRITE_ACL) == ACL_WRITE_ACL) { 402 mask |= ACE_WRITE_ACL; 403 } 404 if((access_mask & ACL_WRITE_OWNER) == ACL_WRITE_OWNER) { 405 mask |= ACE_WRITE_OWNER; 406 } 407 if((access_mask & ACL_SYNCHRONIZE) == ACL_SYNCHRONIZE) { 408 mask |= ACE_SYNCHRONIZE; 409 } 410 411 /* 412 * If the vfs wants to create new files, path does not name an existing 413 * file. In this case, we check if the user has the ACE_ADD_FILE 414 * permission for the parent directory 415 */ 416 struct stat s; 417 if(stat(p.ptr, &s)) { 418 if(errno != ENOENT) { 419 perror("fs_acl_check: stat"); 420 free(p.ptr); 421 return 0; 422 } else { 423 mask = ACE_ADD_FILE; 424 p = util_path_remove_last(p); 425 if(stat(p.ptr, &s)) { 426 free(p.ptr); 427 return 0; 428 } 429 } 430 } 431 432 /* 433 * perform a acl check for the path and each parent directory 434 * we don't check the file system root 435 * 436 * after the first check, we check only search permission for the 437 * directories 438 */ 439 if(!solaris_acl_check(p.ptr, &s, mask, pw.pw_uid, pw.pw_gid)) { 440 free(p.ptr); 441 return 0; 442 } 443 444 p = util_path_remove_last(p); 445 mask = ACE_LIST_DIRECTORY; 446 while(p.length > 1) { 447 if(stat(p.ptr, &s)) { 448 free(p.ptr); 449 return 0; 450 } 451 if(!solaris_acl_check(p.ptr, &s, mask, pw.pw_uid, pw.pw_gid)) { 452 free(p.ptr); 453 return 0; 454 } 455 456 // cut the last file name from the path 457 p = util_path_remove_last(p); 458 } 459 460 461 return 1; 462 } 463 464 int solaris_acl_check( 465 char *path, 466 struct stat *s, 467 uint32_t mask, 468 uid_t uid, 469 gid_t gid) 470 { 471 //printf("solaris_acl_check %s\n", path); 472 473 int nace = acl(path, ACE_GETACLCNT, 0, NULL); 474 if(nace == -1) { 475 perror("acl: ACE_GETACLCNT"); 476 // TODO: log error 477 return 0; 478 } 479 ace_t *aces = calloc(nace, sizeof(ace_t)); 480 if(acl(path, ACE_GETACL, nace, aces) == 1) { 481 perror("acl: ACE_GETACL"); 482 // TODO: log error 483 free(aces); 484 return 0; 485 } 486 487 int allow = 0; 488 uint32_t allowed_access = 0; 489 for(int i=0;i<nace;i++) { 490 ace_t ace = aces[i]; 491 if(solaris_acl_affects_user(&ace, uid, gid, s->st_uid, s->st_gid)) { 492 if(ace.a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) { 493 // add all new access rights 494 allowed_access |= (mask & ace.a_access_mask); 495 // check if we have all requested rights 496 if((allowed_access & mask) == mask) { 497 allow = 1; 498 break; 499 } 500 } else if(ace.a_type == ACE_ACCESS_DENIED_ACE_TYPE) { 501 // ACL_TYPE_DENIED 502 503 if((ace.a_access_mask & mask) != 0) { 504 // access denied 505 break; 506 } 507 } 508 } 509 } 510 511 free(aces); 512 513 //printf("return %d\n", allow); 514 return allow; 515 } 516 517 int solaris_acl_affects_user( 518 ace_t *ace, 519 uid_t uid, 520 gid_t gid, 521 uid_t owner, 522 gid_t owninggroup) 523 { 524 /* 525 * mostly the same as wsacl_affects_user 526 */ 527 528 int check_access = 0; 529 530 if((ace->a_flags & ACE_OWNER) == ACE_OWNER) { 531 if(uid == owner) { 532 check_access = 1; 533 } 534 } else if((ace->a_flags & ACE_GROUP) == ACE_GROUP) { 535 if(gid == owninggroup) { 536 check_access = 1; 537 } 538 } else if((ace->a_flags & ACE_EVERYONE) == ACE_EVERYONE) { 539 check_access = 1; 540 } else if(ace->a_who != -1 && uid != 0) { 541 // this ace is defined for a named user or group 542 if((ace->a_flags & ACE_IDENTIFIER_GROUP) == ACE_IDENTIFIER_GROUP) { 543 // TODO: check all groups 544 if(ace->a_who == gid) { 545 // the user is in the group 546 check_access = 1; 547 } 548 } else { 549 if(ace->a_who == uid) { 550 check_access = 1; 551 } 552 } 553 } 554 555 return check_access; 556 } 557 558 void fs_acl_finish() { 559 560 } 561 562 #endif 563 564 /* 565 * generic code for all non acl unices 566 * TODO: don't use OSX in the preprocessor directive 567 */ 568 #ifdef OSX 569 570 int fs_acl_check(SysACL *acl, User *user, char *path, uint32_t access_mask) { 571 return 1; 572 } 573 574 void fs_acl_finish() { 575 576 } 577 578 #endif 579 580 #ifdef BSD 581 582 int fs_acl_check(SysACL *acl, User *user, char *path, uint32_t access_mask) { 583 return 1; 584 } 585 586 void fs_acl_finish() { 587 588 } 589 590 #endif 591 592 593 #ifdef LINUX 594 595 #include <sys/fsuid.h> 596 597 int fs_acl_check(SysACL *acl, User *user, char *path, uint32_t access_mask) { 598 struct passwd *ws_pw = conf_getglobals()->Vuserpw; 599 if(!ws_pw) { 600 log_ereport(LOG_FAILURE, "fs_acl_check: unknown webserver uid/gid"); 601 return 1; 602 } 603 604 // get uid/gid 605 struct passwd pw; 606 if(user) { 607 char *pwbuf = malloc(DEF_PWBUF); 608 if(pwbuf == NULL) { 609 return 0; 610 } 611 if(!util_getpwnam(user->name, &pw, pwbuf, DEF_PWBUF)) { 612 free(pwbuf); 613 return 0; 614 } 615 free(pwbuf); 616 acl->user_uid = pw.pw_uid; 617 acl->user_gid = pw.pw_gid; 618 } else { 619 acl->user_uid = 0; 620 acl->user_gid = 0; 621 } 622 623 // set fs uid/gid 624 if(acl->user_uid != 0) { 625 if(setfsuid(pw.pw_uid)) { 626 log_ereport( 627 LOG_FAILURE, 628 "Cannot set fsuid to uid: %u", pw.pw_uid); 629 } 630 if(setfsgid(pw.pw_gid)) { 631 log_ereport( 632 LOG_FAILURE, 633 "Cannot set fsgid to gid: %u", pw.pw_gid); 634 } 635 } 636 637 638 return 1; 639 } 640 641 void fs_acl_finish() { 642 struct passwd *pw = conf_getglobals()->Vuserpw; 643 if(!pw) { 644 log_ereport( 645 LOG_FAILURE, 646 "global configuration broken (Vuserpw is null)"); 647 return; 648 } 649 if(setfsuid(pw->pw_uid)) { 650 log_ereport( 651 LOG_FAILURE, 652 "Cannot set fsuid back to server uid: %u", pw->pw_uid); 653 } 654 if(setfsgid(pw->pw_gid)) { 655 log_ereport( 656 LOG_FAILURE, 657 "Cannot set fsgid back to server gid: %u", pw->pw_gid); 658 } 659 } 660 661 #endif 662