1/* 2 Unix SMB/Netbios implementation. 3 VFS module to get and set Solaris ACLs 4 Copyright (C) Michael Adam 2006 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*/ 20 21 22#include "includes.h" 23 24 25/* typedef struct acl SOLARIS_ACE_T; */ 26typedef aclent_t SOLARIS_ACE_T; 27typedef aclent_t *SOLARIS_ACL_T; 28typedef int SOLARIS_ACL_TAG_T; /* the type of an ACL entry */ 29typedef o_mode_t SOLARIS_PERM_T; 30 31/* for convenience: check if solaris acl entry is a default entry? */ 32#define _IS_DEFAULT(ace) ((ace).a_type & ACL_DEFAULT) 33#define _IS_OF_TYPE(ace, type) ( \ 34 (((type) == SMB_ACL_TYPE_ACCESS) && !_IS_DEFAULT(ace)) \ 35 || \ 36 (((type) == SMB_ACL_TYPE_DEFAULT) && _IS_DEFAULT(ace)) \ 37) 38 39 40/* prototypes for private functions */ 41 42static SOLARIS_ACL_T solaris_acl_init(int count); 43static BOOL smb_acl_to_solaris_acl(SMB_ACL_T smb_acl, 44 SOLARIS_ACL_T *solariacl, int *count, 45 SMB_ACL_TYPE_T type); 46static SMB_ACL_T solaris_acl_to_smb_acl(SOLARIS_ACL_T solarisacl, int count, 47 SMB_ACL_TYPE_T type); 48static SOLARIS_ACL_TAG_T smb_tag_to_solaris_tag(SMB_ACL_TAG_T smb_tag); 49static SMB_ACL_TAG_T solaris_tag_to_smb_tag(SOLARIS_ACL_TAG_T solaris_tag); 50static BOOL solaris_add_to_acl(SOLARIS_ACL_T *solaris_acl, int *count, 51 SOLARIS_ACL_T add_acl, int add_count, SMB_ACL_TYPE_T type); 52static BOOL solaris_acl_get_file(const char *name, SOLARIS_ACL_T *solarisacl, 53 int *count); 54static BOOL solaris_acl_get_fd(int fd, SOLARIS_ACL_T *solarisacl, int *count); 55static BOOL solaris_acl_sort(SOLARIS_ACL_T acl, int count); 56static SMB_ACL_PERM_T solaris_perm_to_smb_perm(const SOLARIS_PERM_T perm); 57static SOLARIS_PERM_T smb_perm_to_solaris_perm(const SMB_ACL_PERM_T perm); 58static BOOL solaris_acl_check(SOLARIS_ACL_T solaris_acl, int count); 59 60 61/* public functions - the api */ 62 63SMB_ACL_T solarisacl_sys_acl_get_file(vfs_handle_struct *handle, 64 const char *path_p, 65 SMB_ACL_TYPE_T type) 66{ 67 SMB_ACL_T result = NULL; 68 int count; 69 SOLARIS_ACL_T solaris_acl = NULL; 70 71 DEBUG(10, ("solarisacl_sys_acl_get_file called for file '%s'.\n", 72 path_p)); 73 74 if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) { 75 DEBUG(10, ("invalid SMB_ACL_TYPE given (%d)\n", type)); 76 errno = EINVAL; 77 goto done; 78 } 79 80 DEBUGADD(10, ("getting %s acl\n", 81 ((type == SMB_ACL_TYPE_ACCESS) ? "access" : "default"))); 82 83 if (!solaris_acl_get_file(path_p, &solaris_acl, &count)) { 84 goto done; 85 } 86 result = solaris_acl_to_smb_acl(solaris_acl, count, type); 87 if (result == NULL) { 88 DEBUG(10, ("conversion solaris_acl -> smb_acl failed (%s).\n", 89 strerror(errno))); 90 } 91 92 done: 93 DEBUG(10, ("solarisacl_sys_acl_get_file %s.\n", 94 ((result == NULL) ? "failed" : "succeeded" ))); 95 SAFE_FREE(solaris_acl); 96 return result; 97} 98 99 100/* 101 * get the access ACL of a file referred to by a fd 102 */ 103SMB_ACL_T solarisacl_sys_acl_get_fd(vfs_handle_struct *handle, 104 files_struct *fsp, 105 int fd) 106{ 107 SMB_ACL_T result = NULL; 108 int count; 109 SOLARIS_ACL_T solaris_acl = NULL; 110 111 DEBUG(10, ("entering solarisacl_sys_acl_get_fd.\n")); 112 113 if (!solaris_acl_get_fd(fd, &solaris_acl, &count)) { 114 goto done; 115 } 116 /* 117 * The facl call returns both ACCESS and DEFAULT acls (as present). 118 * The posix acl_get_fd function returns only the 119 * access acl. So we need to filter this out here. 120 */ 121 result = solaris_acl_to_smb_acl(solaris_acl, count, 122 SMB_ACL_TYPE_ACCESS); 123 if (result == NULL) { 124 DEBUG(10, ("conversion solaris_acl -> smb_acl failed (%s).\n", 125 strerror(errno))); 126 } 127 128 done: 129 DEBUG(10, ("solarisacl_sys_acl_get_fd %s.\n", 130 ((result == NULL) ? "failed" : "succeeded"))); 131 SAFE_FREE(solaris_acl); 132 return NULL; 133} 134 135int solarisacl_sys_acl_set_file(vfs_handle_struct *handle, 136 const char *name, 137 SMB_ACL_TYPE_T type, 138 SMB_ACL_T theacl) 139{ 140 int ret = -1; 141 struct stat s; 142 SOLARIS_ACL_T solaris_acl = NULL; 143 int count; 144 145 DEBUG(10, ("solarisacl_sys_acl_set_file called for file '%s'\n", 146 name)); 147 148 if ((type != SMB_ACL_TYPE_ACCESS) && (type != SMB_ACL_TYPE_DEFAULT)) { 149 errno = EINVAL; 150 DEBUG(10, ("invalid smb acl type given (%d).\n", type)); 151 goto done; 152 } 153 DEBUGADD(10, ("setting %s acl\n", 154 ((type == SMB_ACL_TYPE_ACCESS) ? "access" : "default"))); 155 156 if(!smb_acl_to_solaris_acl(theacl, &solaris_acl, &count, type)) { 157 DEBUG(10, ("conversion smb_acl -> solaris_acl failed (%s).\n", 158 strerror(errno))); 159 goto done; 160 } 161 162 /* 163 * if the file is a directory, there is extra work to do: 164 * since the solaris acl call stores both the access acl and 165 * the default acl as provided, we have to get the acl part 166 * that has not been specified in "type" from the file first 167 * and concatenate it with the acl provided. 168 */ 169 if (SMB_VFS_STAT(handle->conn, name, &s) != 0) { 170 DEBUG(10, ("Error in stat call: %s\n", strerror(errno))); 171 goto done; 172 } 173 if (S_ISDIR(s.st_mode)) { 174 SOLARIS_ACL_T other_acl; 175 int other_count; 176 SMB_ACL_TYPE_T other_type; 177 178 other_type = (type == SMB_ACL_TYPE_ACCESS) 179 ? SMB_ACL_TYPE_DEFAULT 180 : SMB_ACL_TYPE_ACCESS; 181 DEBUGADD(10, ("getting acl from filesystem\n")); 182 if (!solaris_acl_get_file(name, &other_acl, &other_count)) { 183 DEBUG(10, ("error getting acl from directory\n")); 184 goto done; 185 } 186 DEBUG(10, ("adding %s part of fs acl to given acl\n", 187 ((other_type == SMB_ACL_TYPE_ACCESS) 188 ? "access" 189 : "default"))); 190 if (!solaris_add_to_acl(&solaris_acl, &count, other_acl, 191 other_count, other_type)) 192 { 193 DEBUG(10, ("error adding other acl.\n")); 194 SAFE_FREE(other_acl); 195 goto done; 196 } 197 SAFE_FREE(other_acl); 198 } 199 else if (type != SMB_ACL_TYPE_ACCESS) { 200 errno = EINVAL; 201 goto done; 202 } 203 204 if (!solaris_acl_sort(solaris_acl, count)) { 205 DEBUG(10, ("resulting acl is not valid!\n")); 206 goto done; 207 } 208 209 ret = acl(name, SETACL, count, solaris_acl); 210 211 done: 212 DEBUG(10, ("solarisacl_sys_acl_set_file %s.\n", 213 ((ret != 0) ? "failed" : "succeeded"))); 214 SAFE_FREE(solaris_acl); 215 return ret; 216} 217 218/* 219 * set the access ACL on the file referred to by a fd 220 */ 221int solarisacl_sys_acl_set_fd(vfs_handle_struct *handle, 222 files_struct *fsp, 223 int fd, SMB_ACL_T theacl) 224{ 225 SOLARIS_ACL_T solaris_acl = NULL; 226 SOLARIS_ACL_T default_acl = NULL; 227 int count, default_count; 228 int ret = -1; 229 230 DEBUG(10, ("entering solarisacl_sys_acl_set_fd\n")); 231 232 /* 233 * the posix acl_set_fd call sets the access acl of the 234 * file referred to by fd. the solaris facl-SETACL call 235 * sets the access and default acl as provided, so we 236 * have to retrieve the default acl of the file and 237 * concatenate it with the access acl provided. 238 */ 239 if (!smb_acl_to_solaris_acl(theacl, &solaris_acl, &count, 240 SMB_ACL_TYPE_ACCESS)) 241 { 242 DEBUG(10, ("conversion smb_acl -> solaris_acl failed (%s).\n", 243 strerror(errno))); 244 goto done; 245 } 246 if (!solaris_acl_get_fd(fd, &default_acl, &default_count)) { 247 DEBUG(10, ("error getting (default) acl from fd\n")); 248 goto done; 249 } 250 if (!solaris_add_to_acl(&solaris_acl, &count, 251 default_acl, default_count, 252 SMB_ACL_TYPE_DEFAULT)) 253 { 254 DEBUG(10, ("error adding default acl to solaris acl\n")); 255 goto done; 256 } 257 if (!solaris_acl_sort(solaris_acl, count)) { 258 DEBUG(10, ("resulting acl is not valid!\n")); 259 goto done; 260 } 261 262 ret = facl(fd, SETACL, count, solaris_acl); 263 if (ret != 0) { 264 DEBUG(10, ("call of facl failed (%s).\n", strerror(errno))); 265 } 266 267 done: 268 DEBUG(10, ("solarisacl_sys_acl_st_fd %s.\n", 269 ((ret == 0) ? "succeded" : "failed" ))); 270 SAFE_FREE(solaris_acl); 271 SAFE_FREE(default_acl); 272 return ret; 273} 274 275/* 276 * delete the default ACL of a directory 277 * 278 * This is achieved by fetching the access ACL and rewriting it 279 * directly, via the solaris system call: the SETACL call on 280 * directories writes both the access and the default ACL as provided. 281 * 282 * XXX: posix acl_delete_def_file returns an error if 283 * the file referred to by path is not a directory. 284 * this function does not complain but the actions 285 * have no effect on a file other than a directory. 286 * But sys_acl_delete_default_file is only called in 287 * smbd/posixacls.c after having checked that the file 288 * is a directory, anyways. So implementing the extra 289 * check is considered unnecessary. --- Agreed? XXX 290 */ 291int solarisacl_sys_acl_delete_def_file(vfs_handle_struct *handle, 292 const char *path) 293{ 294 SMB_ACL_T smb_acl; 295 int ret = -1; 296 SOLARIS_ACL_T solaris_acl = NULL; 297 int count; 298 299 DEBUG(10, ("entering solarisacl_sys_acl_delete_def_file.\n")); 300 301 smb_acl = solarisacl_sys_acl_get_file(handle, path, 302 SMB_ACL_TYPE_ACCESS); 303 if (smb_acl == NULL) { 304 DEBUG(10, ("getting file acl failed!\n")); 305 goto done; 306 } 307 if (!smb_acl_to_solaris_acl(smb_acl, &solaris_acl, &count, 308 SMB_ACL_TYPE_ACCESS)) 309 { 310 DEBUG(10, ("conversion smb_acl -> solaris_acl failed.\n")); 311 goto done; 312 } 313 if (!solaris_acl_sort(solaris_acl, count)) { 314 DEBUG(10, ("resulting acl is not valid!\n")); 315 goto done; 316 } 317 ret = acl(path, SETACL, count, solaris_acl); 318 if (ret != 0) { 319 DEBUG(10, ("settinge file acl failed!\n")); 320 } 321 322 done: 323 DEBUG(10, ("solarisacl_sys_acl_delete_def_file %s.\n", 324 ((ret != 0) ? "failed" : "succeeded" ))); 325 SAFE_FREE(smb_acl); 326 return ret; 327} 328 329 330/* private functions */ 331 332static SOLARIS_ACL_T solaris_acl_init(int count) 333{ 334 SOLARIS_ACL_T solaris_acl = 335 (SOLARIS_ACL_T)SMB_MALLOC(sizeof(aclent_t) * count); 336 if (solaris_acl == NULL) { 337 errno = ENOMEM; 338 } 339 return solaris_acl; 340} 341 342/* 343 * Convert the SMB acl to the ACCESS or DEFAULT part of a 344 * solaris ACL, as desired. 345 */ 346static BOOL smb_acl_to_solaris_acl(SMB_ACL_T smb_acl, 347 SOLARIS_ACL_T *solaris_acl, int *count, 348 SMB_ACL_TYPE_T type) 349{ 350 BOOL ret = False; 351 int i; 352 int check_which, check_rc; 353 354 DEBUG(10, ("entering smb_acl_to_solaris_acl\n")); 355 356 *solaris_acl = NULL; 357 *count = 0; 358 359 for (i = 0; i < smb_acl->count; i++) { 360 const struct smb_acl_entry *smb_entry = &(smb_acl->acl[i]); 361 SOLARIS_ACE_T solaris_entry; 362 363 ZERO_STRUCT(solaris_entry); 364 365 solaris_entry.a_type = smb_tag_to_solaris_tag(smb_entry->a_type); 366 if (solaris_entry.a_type == 0) { 367 DEBUG(10, ("smb_tag to solaris_tag failed\n")); 368 goto fail; 369 } 370 switch(solaris_entry.a_type) { 371 case USER: 372 DEBUG(10, ("got tag type USER with uid %d\n", 373 smb_entry->uid)); 374 solaris_entry.a_id = (uid_t)smb_entry->uid; 375 break; 376 case GROUP: 377 DEBUG(10, ("got tag type GROUP with gid %d\n", 378 smb_entry->gid)); 379 solaris_entry.a_id = (uid_t)smb_entry->gid; 380 break; 381 default: 382 break; 383 } 384 if (type == SMB_ACL_TYPE_DEFAULT) { 385 DEBUG(10, ("adding default bit to solaris ace\n")); 386 solaris_entry.a_type |= ACL_DEFAULT; 387 } 388 389 solaris_entry.a_perm = 390 smb_perm_to_solaris_perm(smb_entry->a_perm); 391 DEBUG(10, ("assembled the following solaris ace:\n")); 392 DEBUGADD(10, (" - type: 0x%04x\n", solaris_entry.a_type)); 393 DEBUGADD(10, (" - id: %d\n", solaris_entry.a_id)); 394 DEBUGADD(10, (" - perm: o%o\n", solaris_entry.a_perm)); 395 if (!solaris_add_to_acl(solaris_acl, count, &solaris_entry, 396 1, type)) 397 { 398 DEBUG(10, ("error adding acl entry\n")); 399 goto fail; 400 } 401 DEBUG(10, ("count after adding: %d (i: %d)\n", *count, i)); 402 DEBUG(10, ("test, if entry has been copied into acl:\n")); 403 DEBUGADD(10, (" - type: 0x%04x\n", 404 (*solaris_acl)[(*count)-1].a_type)); 405 DEBUGADD(10, (" - id: %d\n", 406 (*solaris_acl)[(*count)-1].a_id)); 407 DEBUGADD(10, (" - perm: o%o\n", 408 (*solaris_acl)[(*count)-1].a_perm)); 409 } 410 411 ret = True; 412 goto done; 413 414 fail: 415 SAFE_FREE(*solaris_acl); 416 done: 417 DEBUG(10, ("smb_acl_to_solaris_acl %s\n", 418 ((ret == True) ? "succeeded" : "failed"))); 419 return ret; 420} 421 422/* 423 * convert either the access or the default part of a 424 * soaris acl to the SMB_ACL format. 425 */ 426static SMB_ACL_T solaris_acl_to_smb_acl(SOLARIS_ACL_T solaris_acl, int count, 427 SMB_ACL_TYPE_T type) 428{ 429 SMB_ACL_T result; 430 int i; 431 432 if ((result = sys_acl_init(0)) == NULL) { 433 DEBUG(10, ("error allocating memory for SMB_ACL\n")); 434 goto fail; 435 } 436 for (i = 0; i < count; i++) { 437 SMB_ACL_ENTRY_T smb_entry; 438 SMB_ACL_PERM_T smb_perm; 439 440 if (!_IS_OF_TYPE(solaris_acl[i], type)) { 441 continue; 442 } 443 result = SMB_REALLOC(result, 444 sizeof(struct smb_acl_t) + 445 (sizeof(struct smb_acl_entry) * 446 (result->count + 1))); 447 if (result == NULL) { 448 DEBUG(10, ("error reallocating memory for SMB_ACL\n")); 449 goto fail; 450 } 451 smb_entry = &result->acl[result->count]; 452 if (sys_acl_set_tag_type(smb_entry, 453 solaris_tag_to_smb_tag(solaris_acl[i].a_type)) != 0) 454 { 455 DEBUG(10, ("invalid tag type given: 0x%04x\n", 456 solaris_acl[i].a_type)); 457 goto fail; 458 } 459 /* intentionally not checking return code here: */ 460 sys_acl_set_qualifier(smb_entry, (void *)&solaris_acl[i].a_id); 461 smb_perm = solaris_perm_to_smb_perm(solaris_acl[i].a_perm); 462 if (sys_acl_set_permset(smb_entry, &smb_perm) != 0) { 463 DEBUG(10, ("invalid permset given: %d\n", 464 solaris_acl[i].a_perm)); 465 goto fail; 466 } 467 result->count += 1; 468 } 469 goto done; 470 471 fail: 472 SAFE_FREE(result); 473 done: 474 DEBUG(10, ("solaris_acl_to_smb_acl %s\n", 475 ((result == NULL) ? "failed" : "succeeded"))); 476 return result; 477} 478 479 480 481static SOLARIS_ACL_TAG_T smb_tag_to_solaris_tag(SMB_ACL_TAG_T smb_tag) 482{ 483 SOLARIS_ACL_TAG_T solaris_tag = 0; 484 485 DEBUG(10, ("smb_tag_to_solaris_tag\n")); 486 DEBUGADD(10, (" --> got smb tag 0x%04x\n", smb_tag)); 487 488 switch (smb_tag) { 489 case SMB_ACL_USER: 490 solaris_tag = USER; 491 break; 492 case SMB_ACL_USER_OBJ: 493 solaris_tag = USER_OBJ; 494 break; 495 case SMB_ACL_GROUP: 496 solaris_tag = GROUP; 497 break; 498 case SMB_ACL_GROUP_OBJ: 499 solaris_tag = GROUP_OBJ; 500 break; 501 case SMB_ACL_OTHER: 502 solaris_tag = OTHER_OBJ; 503 break; 504 case SMB_ACL_MASK: 505 solaris_tag = CLASS_OBJ; 506 break; 507 default: 508 DEBUGADD(10, (" !!! unknown smb tag type 0x%04x\n", smb_tag)); 509 break; 510 } 511 512 DEBUGADD(10, (" --> determined solaris tag 0x%04x\n", solaris_tag)); 513 514 return solaris_tag; 515} 516 517static SMB_ACL_TAG_T solaris_tag_to_smb_tag(SOLARIS_ACL_TAG_T solaris_tag) 518{ 519 SMB_ACL_TAG_T smb_tag = 0; 520 521 DEBUG(10, ("solaris_tag_to_smb_tag:\n")); 522 DEBUGADD(10, (" --> got solaris tag 0x%04x\n", solaris_tag)); 523 524 solaris_tag &= ~ACL_DEFAULT; 525 526 switch (solaris_tag) { 527 case USER: 528 smb_tag = SMB_ACL_USER; 529 break; 530 case USER_OBJ: 531 smb_tag = SMB_ACL_USER_OBJ; 532 break; 533 case GROUP: 534 smb_tag = SMB_ACL_GROUP; 535 break; 536 case GROUP_OBJ: 537 smb_tag = SMB_ACL_GROUP_OBJ; 538 break; 539 case OTHER_OBJ: 540 smb_tag = SMB_ACL_OTHER; 541 break; 542 case CLASS_OBJ: 543 smb_tag = SMB_ACL_MASK; 544 break; 545 default: 546 DEBUGADD(10, (" !!! unknown solaris tag type: 0x%04x\n", 547 solaris_tag)); 548 break; 549 } 550 551 DEBUGADD(10, (" --> determined smb tag 0x%04x\n", smb_tag)); 552 553 return smb_tag; 554} 555 556 557static SMB_ACL_PERM_T solaris_perm_to_smb_perm(const SOLARIS_PERM_T perm) 558{ 559 SMB_ACL_PERM_T smb_perm = 0; 560 smb_perm |= ((perm & SMB_ACL_READ) ? SMB_ACL_READ : 0); 561 smb_perm |= ((perm & SMB_ACL_WRITE) ? SMB_ACL_WRITE : 0); 562 smb_perm |= ((perm & SMB_ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0); 563 return smb_perm; 564} 565 566 567static SOLARIS_PERM_T smb_perm_to_solaris_perm(const SMB_ACL_PERM_T perm) 568{ 569 SOLARIS_PERM_T solaris_perm = 0; 570 solaris_perm |= ((perm & SMB_ACL_READ) ? SMB_ACL_READ : 0); 571 solaris_perm |= ((perm & SMB_ACL_WRITE) ? SMB_ACL_WRITE : 0); 572 solaris_perm |= ((perm & SMB_ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0); 573 return solaris_perm; 574} 575 576 577static BOOL solaris_acl_get_file(const char *name, SOLARIS_ACL_T *solaris_acl, 578 int *count) 579{ 580 BOOL result = False; 581 582 DEBUG(10, ("solaris_acl_get_file called for file '%s'\n", name)); 583 584 /* 585 * The original code tries some INITIAL_ACL_SIZE 586 * and only did the GETACLCNT call upon failure 587 * (for performance reasons). 588 * For the sake of simplicity, I skip this for now. 589 */ 590 *count = acl(name, GETACLCNT, 0, NULL); 591 if (*count < 0) { 592 DEBUG(10, ("acl GETACLCNT failed: %s\n", strerror(errno))); 593 goto done; 594 } 595 *solaris_acl = solaris_acl_init(*count); 596 if (*solaris_acl == NULL) { 597 DEBUG(10, ("error allocating memory for solaris acl...\n")); 598 goto done; 599 } 600 *count = acl(name, GETACL, *count, *solaris_acl); 601 if (*count < 0) { 602 DEBUG(10, ("acl GETACL failed: %s\n", strerror(errno))); 603 goto done; 604 } 605 result = True; 606 607 done: 608 DEBUG(10, ("solaris_acl_get_file %s.\n", 609 ((result == True) ? "succeeded" : "failed" ))); 610 return result; 611} 612 613 614static BOOL solaris_acl_get_fd(int fd, SOLARIS_ACL_T *solaris_acl, int *count) 615{ 616 BOOL ret = False; 617 618 DEBUG(10, ("entering solaris_acl_get_fd\n")); 619 620 /* 621 * see solaris_acl_get_file for comment about omission 622 * of INITIAL_ACL_SIZE... 623 */ 624 *count = facl(fd, GETACLCNT, 0, NULL); 625 if (*count < 0) { 626 DEBUG(10, ("facl GETACLCNT failed: %s\n", strerror(errno))); 627 goto done; 628 } 629 *solaris_acl = solaris_acl_init(*count); 630 if (*solaris_acl == NULL) { 631 DEBUG(10, ("error allocating memory for solaris acl...\n")); 632 goto done; 633 } 634 *count = facl(fd, GETACL, *count, *solaris_acl); 635 if (*count < 0) { 636 DEBUG(10, ("facl GETACL failed: %s\n", strerror(errno))); 637 goto done; 638 } 639 ret = True; 640 641 done: 642 DEBUG(10, ("solaris_acl_get_fd %s\n", 643 ((ret == True) ? "succeeded" : "failed"))); 644 return ret; 645} 646 647 648 649/* 650 * Add entries to a solaris ACL. 651 * 652 * Entries are directly added to the solarisacl parameter. 653 * if memory allocation fails, this may result in solarisacl 654 * being NULL. if the resulting acl is to be checked and is 655 * not valid, it is kept in solarisacl but False is returned. 656 * 657 * The type of ACEs (access/default) to be added to the ACL can 658 * be selected via the type parameter. 659 * I use the SMB_ACL_TYPE_T type here. Since SMB_ACL_TYPE_ACCESS 660 * is defined as "0", this means that one can only add either 661 * access or default ACEs, not both at the same time. If it 662 * should become necessary to add all of an ACL, one would have 663 * to replace this parameter by another type. 664 */ 665static BOOL solaris_add_to_acl(SOLARIS_ACL_T *solaris_acl, int *count, 666 SOLARIS_ACL_T add_acl, int add_count, 667 SMB_ACL_TYPE_T type) 668{ 669 int i; 670 671 if ((type != SMB_ACL_TYPE_ACCESS) && (type != SMB_ACL_TYPE_DEFAULT)) 672 { 673 DEBUG(10, ("invalid acl type given: %d\n", type)); 674 errno = EINVAL; 675 return False; 676 } 677 for (i = 0; i < add_count; i++) { 678 if (!_IS_OF_TYPE(add_acl[i], type)) { 679 continue; 680 } 681 ADD_TO_ARRAY(NULL, SOLARIS_ACE_T, add_acl[i], 682 solaris_acl, count); 683 if (solaris_acl == NULL) { 684 DEBUG(10, ("error enlarging acl.\n")); 685 errno = ENOMEM; 686 return False; 687 } 688 } 689 return True; 690} 691 692 693/* 694 * sort the ACL and check it for validity 695 * 696 * [original comment from lib/sysacls.c:] 697 * 698 * if it's a minimal ACL with only 4 entries then we 699 * need to recalculate the mask permissions to make 700 * sure that they are the same as the GROUP_OBJ 701 * permissions as required by the UnixWare acl() system call. 702 * 703 * (note: since POSIX allows minimal ACLs which only contain 704 * 3 entries - ie there is no mask entry - we should, in theory, 705 * check for this and add a mask entry if necessary - however 706 * we "know" that the caller of this interface always specifies 707 * a mask, so in practice "this never happens" (tm) - if it *does* 708 * happen aclsort() will fail and return an error and someone will 709 * have to fix it...) 710 */ 711static BOOL solaris_acl_sort(SOLARIS_ACL_T solaris_acl, int count) 712{ 713 int fixmask = (count <= 4); 714 715 if (aclsort(count, fixmask, solaris_acl) != 0) { 716 errno = EINVAL; 717 return False; 718 } 719 return True; 720} 721 722/* 723 * acl check function: 724 * unused at the moment but could be used to get more 725 * concrete error messages for debugging... 726 * (acl sort just says that the acl is invalid...) 727 */ 728static BOOL solaris_acl_check(SOLARIS_ACL_T solaris_acl, int count) 729{ 730 int check_rc; 731 int check_which; 732 733 check_rc = aclcheck(solaris_acl, count, &check_which); 734 if (check_rc != 0) { 735 DEBUG(10, ("acl is not valid:\n")); 736 DEBUGADD(10, (" - return code: %d\n", check_rc)); 737 DEBUGADD(10, (" - which: %d\n", check_which)); 738 if (check_which != -1) { 739 DEBUGADD(10, (" - invalid entry:\n")); 740 DEBUGADD(10, (" * type: %d:\n", 741 solaris_acl[check_which].a_type)); 742 DEBUGADD(10, (" * id: %d\n", 743 solaris_acl[check_which].a_id)); 744 DEBUGADD(10, (" * perm: 0o%o\n", 745 solaris_acl[check_which].a_perm)); 746 } 747 return False; 748 } 749 return True; 750} 751 752 753/* VFS operations structure */ 754 755static vfs_op_tuple solarisacl_op_tuples[] = { 756 /* Disk operations */ 757 {SMB_VFS_OP(solarisacl_sys_acl_get_file), 758 SMB_VFS_OP_SYS_ACL_GET_FILE, 759 SMB_VFS_LAYER_TRANSPARENT}, 760 761 {SMB_VFS_OP(solarisacl_sys_acl_get_fd), 762 SMB_VFS_OP_SYS_ACL_GET_FD, 763 SMB_VFS_LAYER_TRANSPARENT}, 764 765 {SMB_VFS_OP(solarisacl_sys_acl_set_file), 766 SMB_VFS_OP_SYS_ACL_SET_FILE, 767 SMB_VFS_LAYER_TRANSPARENT}, 768 769 {SMB_VFS_OP(solarisacl_sys_acl_set_fd), 770 SMB_VFS_OP_SYS_ACL_SET_FD, 771 SMB_VFS_LAYER_TRANSPARENT}, 772 773 {SMB_VFS_OP(solarisacl_sys_acl_delete_def_file), 774 SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE, 775 SMB_VFS_LAYER_TRANSPARENT}, 776 777 {SMB_VFS_OP(NULL), 778 SMB_VFS_OP_NOOP, 779 SMB_VFS_LAYER_NOOP} 780}; 781 782NTSTATUS vfs_solarisacl_init(void); 783NTSTATUS vfs_solarisacl_init(void) 784{ 785 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "solarisacl", 786 solarisacl_op_tuples); 787} 788 789/* ENTE */ 790