1/* 2 Unix SMB/CIFS implementation. 3 SMB NT Security Descriptor / Unix permission conversion. 4 Copyright (C) Jeremy Allison 1994-2000. 5 Copyright (C) Andreas Gruenbacher 2002. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20*/ 21 22#include "includes.h" 23 24#undef DBGC_CLASS 25#define DBGC_CLASS DBGC_ACLS 26 27/**************************************************************************** 28 Data structures representing the internal ACE format. 29****************************************************************************/ 30 31enum ace_owner {UID_ACE, GID_ACE, WORLD_ACE}; 32enum ace_attribute {ALLOW_ACE, DENY_ACE}; /* Used for incoming NT ACLS. */ 33 34typedef union posix_id { 35 uid_t uid; 36 gid_t gid; 37 int world; 38} posix_id; 39 40typedef struct canon_ace { 41 struct canon_ace *next, *prev; 42 SMB_ACL_TAG_T type; 43 mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */ 44 DOM_SID trustee; 45 enum ace_owner owner_type; 46 enum ace_attribute attr; 47 posix_id unix_ug; 48 BOOL inherited; 49} canon_ace; 50 51#define ALL_ACE_PERMS (S_IRUSR|S_IWUSR|S_IXUSR) 52 53/* 54 * EA format of user.SAMBA_PAI (Samba_Posix_Acl_Interitance) 55 * attribute on disk. 56 * 57 * | 1 | 1 | 2 | 2 | .... 58 * +------+------+-------------+---------------------+-------------+--------------------+ 59 * | vers | flag | num_entries | num_default_entries | ..entries.. | default_entries... | 60 * +------+------+-------------+---------------------+-------------+--------------------+ 61 */ 62 63#define PAI_VERSION_OFFSET 0 64#define PAI_FLAG_OFFSET 1 65#define PAI_NUM_ENTRIES_OFFSET 2 66#define PAI_NUM_DEFAULT_ENTRIES_OFFSET 4 67#define PAI_ENTRIES_BASE 6 68 69#define PAI_VERSION 1 70#define PAI_ACL_FLAG_PROTECTED 0x1 71#define PAI_ENTRY_LENGTH 5 72 73/* 74 * In memory format of user.SAMBA_PAI attribute. 75 */ 76 77struct pai_entry { 78 struct pai_entry *next, *prev; 79 enum ace_owner owner_type; 80 posix_id unix_ug; 81}; 82 83struct pai_val { 84 BOOL protected; 85 unsigned int num_entries; 86 struct pai_entry *entry_list; 87 unsigned int num_def_entries; 88 struct pai_entry *def_entry_list; 89}; 90 91/************************************************************************ 92 Return a uint32 of the pai_entry principal. 93************************************************************************/ 94 95static uint32 get_pai_entry_val(struct pai_entry *paie) 96{ 97 switch (paie->owner_type) { 98 case UID_ACE: 99 DEBUG(10,("get_pai_entry_val: uid = %u\n", (unsigned int)paie->unix_ug.uid )); 100 return (uint32)paie->unix_ug.uid; 101 case GID_ACE: 102 DEBUG(10,("get_pai_entry_val: gid = %u\n", (unsigned int)paie->unix_ug.gid )); 103 return (uint32)paie->unix_ug.gid; 104 case WORLD_ACE: 105 default: 106 DEBUG(10,("get_pai_entry_val: world ace\n")); 107 return (uint32)-1; 108 } 109} 110 111/************************************************************************ 112 Return a uint32 of the entry principal. 113************************************************************************/ 114 115static uint32 get_entry_val(canon_ace *ace_entry) 116{ 117 switch (ace_entry->owner_type) { 118 case UID_ACE: 119 DEBUG(10,("get_entry_val: uid = %u\n", (unsigned int)ace_entry->unix_ug.uid )); 120 return (uint32)ace_entry->unix_ug.uid; 121 case GID_ACE: 122 DEBUG(10,("get_entry_val: gid = %u\n", (unsigned int)ace_entry->unix_ug.gid )); 123 return (uint32)ace_entry->unix_ug.gid; 124 case WORLD_ACE: 125 default: 126 DEBUG(10,("get_entry_val: world ace\n")); 127 return (uint32)-1; 128 } 129} 130 131/************************************************************************ 132 Count the inherited entries. 133************************************************************************/ 134 135static unsigned int num_inherited_entries(canon_ace *ace_list) 136{ 137 unsigned int num_entries = 0; 138 139 for (; ace_list; ace_list = ace_list->next) 140 if (ace_list->inherited) 141 num_entries++; 142 return num_entries; 143} 144 145/************************************************************************ 146 Create the on-disk format. Caller must free. 147************************************************************************/ 148 149static char *create_pai_buf(canon_ace *file_ace_list, canon_ace *dir_ace_list, BOOL protected, size_t *store_size) 150{ 151 char *pai_buf = NULL; 152 canon_ace *ace_list = NULL; 153 char *entry_offset = NULL; 154 unsigned int num_entries = 0; 155 unsigned int num_def_entries = 0; 156 157 for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) 158 if (ace_list->inherited) 159 num_entries++; 160 161 for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next) 162 if (ace_list->inherited) 163 num_def_entries++; 164 165 DEBUG(10,("create_pai_buf: num_entries = %u, num_def_entries = %u\n", num_entries, num_def_entries )); 166 167 *store_size = PAI_ENTRIES_BASE + ((num_entries + num_def_entries)*PAI_ENTRY_LENGTH); 168 169 pai_buf = SMB_MALLOC(*store_size); 170 if (!pai_buf) { 171 return NULL; 172 } 173 174 /* Set up the header. */ 175 memset(pai_buf, '\0', PAI_ENTRIES_BASE); 176 SCVAL(pai_buf,PAI_VERSION_OFFSET,PAI_VERSION); 177 SCVAL(pai_buf,PAI_FLAG_OFFSET,(protected ? PAI_ACL_FLAG_PROTECTED : 0)); 178 SSVAL(pai_buf,PAI_NUM_ENTRIES_OFFSET,num_entries); 179 SSVAL(pai_buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET,num_def_entries); 180 181 entry_offset = pai_buf + PAI_ENTRIES_BASE; 182 183 for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) { 184 if (ace_list->inherited) { 185 uint8 type_val = (unsigned char)ace_list->owner_type; 186 uint32 entry_val = get_entry_val(ace_list); 187 188 SCVAL(entry_offset,0,type_val); 189 SIVAL(entry_offset,1,entry_val); 190 entry_offset += PAI_ENTRY_LENGTH; 191 } 192 } 193 194 for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next) { 195 if (ace_list->inherited) { 196 uint8 type_val = (unsigned char)ace_list->owner_type; 197 uint32 entry_val = get_entry_val(ace_list); 198 199 SCVAL(entry_offset,0,type_val); 200 SIVAL(entry_offset,1,entry_val); 201 entry_offset += PAI_ENTRY_LENGTH; 202 } 203 } 204 205 return pai_buf; 206} 207 208/************************************************************************ 209 Store the user.SAMBA_PAI attribute on disk. 210************************************************************************/ 211 212static void store_inheritance_attributes(files_struct *fsp, canon_ace *file_ace_list, 213 canon_ace *dir_ace_list, BOOL protected) 214{ 215 int ret; 216 size_t store_size; 217 char *pai_buf; 218 219 if (!lp_map_acl_inherit(SNUM(fsp->conn))) 220 return; 221 222 /* 223 * Don't store if this ACL isn't protected and 224 * none of the entries in it are marked as inherited. 225 */ 226 227 if (!protected && num_inherited_entries(file_ace_list) == 0 && num_inherited_entries(dir_ace_list) == 0) { 228 /* Instead just remove the attribute if it exists. */ 229 if (fsp->fd != -1) 230 SMB_VFS_FREMOVEXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME); 231 else 232 SMB_VFS_REMOVEXATTR(fsp->conn, fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME); 233 return; 234 } 235 236 pai_buf = create_pai_buf(file_ace_list, dir_ace_list, protected, &store_size); 237 238 if (fsp->fd != -1) 239 ret = SMB_VFS_FSETXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME, 240 pai_buf, store_size, 0); 241 else 242 ret = SMB_VFS_SETXATTR(fsp->conn,fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME, 243 pai_buf, store_size, 0); 244 245 SAFE_FREE(pai_buf); 246 247 DEBUG(10,("store_inheritance_attribute:%s for file %s\n", protected ? " (protected)" : "", fsp->fsp_name)); 248 if (ret == -1 && !no_acl_syscall_error(errno)) 249 DEBUG(1,("store_inheritance_attribute: Error %s\n", strerror(errno) )); 250} 251 252/************************************************************************ 253 Delete the in memory inheritance info. 254************************************************************************/ 255 256static void free_inherited_info(struct pai_val *pal) 257{ 258 if (pal) { 259 struct pai_entry *paie, *paie_next; 260 for (paie = pal->entry_list; paie; paie = paie_next) { 261 paie_next = paie->next; 262 SAFE_FREE(paie); 263 } 264 for (paie = pal->def_entry_list; paie; paie = paie_next) { 265 paie_next = paie->next; 266 SAFE_FREE(paie); 267 } 268 SAFE_FREE(pal); 269 } 270} 271 272/************************************************************************ 273 Was this ACL protected ? 274************************************************************************/ 275 276static BOOL get_protected_flag(struct pai_val *pal) 277{ 278 if (!pal) 279 return False; 280 return pal->protected; 281} 282 283/************************************************************************ 284 Was this ACE inherited ? 285************************************************************************/ 286 287static BOOL get_inherited_flag(struct pai_val *pal, canon_ace *ace_entry, BOOL default_ace) 288{ 289 struct pai_entry *paie; 290 291 if (!pal) 292 return False; 293 294 /* If the entry exists it is inherited. */ 295 for (paie = (default_ace ? pal->def_entry_list : pal->entry_list); paie; paie = paie->next) { 296 if (ace_entry->owner_type == paie->owner_type && 297 get_entry_val(ace_entry) == get_pai_entry_val(paie)) 298 return True; 299 } 300 return False; 301} 302 303/************************************************************************ 304 Ensure an attribute just read is valid. 305************************************************************************/ 306 307static BOOL check_pai_ok(char *pai_buf, size_t pai_buf_data_size) 308{ 309 uint16 num_entries; 310 uint16 num_def_entries; 311 312 if (pai_buf_data_size < PAI_ENTRIES_BASE) { 313 /* Corrupted - too small. */ 314 return False; 315 } 316 317 if (CVAL(pai_buf,PAI_VERSION_OFFSET) != PAI_VERSION) 318 return False; 319 320 num_entries = SVAL(pai_buf,PAI_NUM_ENTRIES_OFFSET); 321 num_def_entries = SVAL(pai_buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET); 322 323 /* Check the entry lists match. */ 324 /* Each entry is 5 bytes (type plus 4 bytes of uid or gid). */ 325 326 if (((num_entries + num_def_entries)*PAI_ENTRY_LENGTH) + PAI_ENTRIES_BASE != pai_buf_data_size) 327 return False; 328 329 return True; 330} 331 332 333/************************************************************************ 334 Convert to in-memory format. 335************************************************************************/ 336 337static struct pai_val *create_pai_val(char *buf, size_t size) 338{ 339 char *entry_offset; 340 struct pai_val *paiv = NULL; 341 int i; 342 343 if (!check_pai_ok(buf, size)) 344 return NULL; 345 346 paiv = SMB_MALLOC_P(struct pai_val); 347 if (!paiv) 348 return NULL; 349 350 memset(paiv, '\0', sizeof(struct pai_val)); 351 352 paiv->protected = (CVAL(buf,PAI_FLAG_OFFSET) == PAI_ACL_FLAG_PROTECTED); 353 354 paiv->num_entries = SVAL(buf,PAI_NUM_ENTRIES_OFFSET); 355 paiv->num_def_entries = SVAL(buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET); 356 357 entry_offset = buf + PAI_ENTRIES_BASE; 358 359 DEBUG(10,("create_pai_val:%s num_entries = %u, num_def_entries = %u\n", 360 paiv->protected ? " (protected)" : "", paiv->num_entries, paiv->num_def_entries )); 361 362 for (i = 0; i < paiv->num_entries; i++) { 363 struct pai_entry *paie; 364 365 paie = SMB_MALLOC_P(struct pai_entry); 366 if (!paie) { 367 free_inherited_info(paiv); 368 return NULL; 369 } 370 371 paie->owner_type = (enum ace_owner)CVAL(entry_offset,0); 372 switch( paie->owner_type) { 373 case UID_ACE: 374 paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1); 375 DEBUG(10,("create_pai_val: uid = %u\n", (unsigned int)paie->unix_ug.uid )); 376 break; 377 case GID_ACE: 378 paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1); 379 DEBUG(10,("create_pai_val: gid = %u\n", (unsigned int)paie->unix_ug.gid )); 380 break; 381 case WORLD_ACE: 382 paie->unix_ug.world = -1; 383 DEBUG(10,("create_pai_val: world ace\n")); 384 break; 385 default: 386 free_inherited_info(paiv); 387 return NULL; 388 } 389 entry_offset += PAI_ENTRY_LENGTH; 390 DLIST_ADD(paiv->entry_list, paie); 391 } 392 393 for (i = 0; i < paiv->num_def_entries; i++) { 394 struct pai_entry *paie; 395 396 paie = SMB_MALLOC_P(struct pai_entry); 397 if (!paie) { 398 free_inherited_info(paiv); 399 return NULL; 400 } 401 402 paie->owner_type = (enum ace_owner)CVAL(entry_offset,0); 403 switch( paie->owner_type) { 404 case UID_ACE: 405 paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1); 406 DEBUG(10,("create_pai_val: (def) uid = %u\n", (unsigned int)paie->unix_ug.uid )); 407 break; 408 case GID_ACE: 409 paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1); 410 DEBUG(10,("create_pai_val: (def) gid = %u\n", (unsigned int)paie->unix_ug.gid )); 411 break; 412 case WORLD_ACE: 413 paie->unix_ug.world = -1; 414 DEBUG(10,("create_pai_val: (def) world ace\n")); 415 break; 416 default: 417 free_inherited_info(paiv); 418 return NULL; 419 } 420 entry_offset += PAI_ENTRY_LENGTH; 421 DLIST_ADD(paiv->def_entry_list, paie); 422 } 423 424 return paiv; 425} 426 427/************************************************************************ 428 Load the user.SAMBA_PAI attribute. 429************************************************************************/ 430 431static struct pai_val *load_inherited_info(files_struct *fsp) 432{ 433 char *pai_buf; 434 size_t pai_buf_size = 1024; 435 struct pai_val *paiv = NULL; 436 ssize_t ret; 437 438 if (!lp_map_acl_inherit(SNUM(fsp->conn))) 439 return NULL; 440 441 if ((pai_buf = SMB_MALLOC(pai_buf_size)) == NULL) 442 return NULL; 443 444 do { 445 if (fsp->fd != -1) 446 ret = SMB_VFS_FGETXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME, 447 pai_buf, pai_buf_size); 448 else 449 ret = SMB_VFS_GETXATTR(fsp->conn,fsp->fsp_name,SAMBA_POSIX_INHERITANCE_EA_NAME, 450 pai_buf, pai_buf_size); 451 452 if (ret == -1) { 453 if (errno != ERANGE) { 454 break; 455 } 456 /* Buffer too small - enlarge it. */ 457 pai_buf_size *= 2; 458 SAFE_FREE(pai_buf); 459 if (pai_buf_size > 1024*1024) { 460 return NULL; /* Limit malloc to 1mb. */ 461 } 462 if ((pai_buf = SMB_MALLOC(pai_buf_size)) == NULL) 463 return NULL; 464 } 465 } while (ret == -1); 466 467 DEBUG(10,("load_inherited_info: ret = %lu for file %s\n", (unsigned long)ret, fsp->fsp_name)); 468 469 if (ret == -1) { 470 /* No attribute or not supported. */ 471#if defined(ENOATTR) 472 if (errno != ENOATTR) 473 DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) )); 474#else 475 if (errno != ENOSYS) 476 DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) )); 477#endif 478 SAFE_FREE(pai_buf); 479 return NULL; 480 } 481 482 paiv = create_pai_val(pai_buf, ret); 483 484 if (paiv && paiv->protected) 485 DEBUG(10,("load_inherited_info: ACL is protected for file %s\n", fsp->fsp_name)); 486 487 SAFE_FREE(pai_buf); 488 return paiv; 489} 490 491/**************************************************************************** 492 Functions to manipulate the internal ACE format. 493****************************************************************************/ 494 495/**************************************************************************** 496 Count a linked list of canonical ACE entries. 497****************************************************************************/ 498 499static size_t count_canon_ace_list( canon_ace *list_head ) 500{ 501 size_t count = 0; 502 canon_ace *ace; 503 504 for (ace = list_head; ace; ace = ace->next) 505 count++; 506 507 return count; 508} 509 510/**************************************************************************** 511 Free a linked list of canonical ACE entries. 512****************************************************************************/ 513 514static void free_canon_ace_list( canon_ace *list_head ) 515{ 516 while (list_head) { 517 canon_ace *old_head = list_head; 518 DLIST_REMOVE(list_head, list_head); 519 SAFE_FREE(old_head); 520 } 521} 522 523/**************************************************************************** 524 Function to duplicate a canon_ace entry. 525****************************************************************************/ 526 527static canon_ace *dup_canon_ace( canon_ace *src_ace) 528{ 529 canon_ace *dst_ace = SMB_MALLOC_P(canon_ace); 530 531 if (dst_ace == NULL) 532 return NULL; 533 534 *dst_ace = *src_ace; 535 dst_ace->prev = dst_ace->next = NULL; 536 return dst_ace; 537} 538 539/**************************************************************************** 540 Print out a canon ace. 541****************************************************************************/ 542 543static void print_canon_ace(canon_ace *pace, int num) 544{ 545 fstring str; 546 547 dbgtext( "canon_ace index %d. Type = %s ", num, pace->attr == ALLOW_ACE ? "allow" : "deny" ); 548 dbgtext( "SID = %s ", sid_to_string( str, &pace->trustee)); 549 if (pace->owner_type == UID_ACE) { 550 const char *u_name = uidtoname(pace->unix_ug.uid); 551 dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.uid, u_name ); 552 } else if (pace->owner_type == GID_ACE) { 553 char *g_name = gidtoname(pace->unix_ug.gid); 554 dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.gid, g_name ); 555 } else 556 dbgtext( "other "); 557 switch (pace->type) { 558 case SMB_ACL_USER: 559 dbgtext( "SMB_ACL_USER "); 560 break; 561 case SMB_ACL_USER_OBJ: 562 dbgtext( "SMB_ACL_USER_OBJ "); 563 break; 564 case SMB_ACL_GROUP: 565 dbgtext( "SMB_ACL_GROUP "); 566 break; 567 case SMB_ACL_GROUP_OBJ: 568 dbgtext( "SMB_ACL_GROUP_OBJ "); 569 break; 570 case SMB_ACL_OTHER: 571 dbgtext( "SMB_ACL_OTHER "); 572 break; 573 } 574 if (pace->inherited) 575 dbgtext( "(inherited) "); 576 dbgtext( "perms "); 577 dbgtext( "%c", pace->perms & S_IRUSR ? 'r' : '-'); 578 dbgtext( "%c", pace->perms & S_IWUSR ? 'w' : '-'); 579 dbgtext( "%c\n", pace->perms & S_IXUSR ? 'x' : '-'); 580} 581 582/**************************************************************************** 583 Print out a canon ace list. 584****************************************************************************/ 585 586static void print_canon_ace_list(const char *name, canon_ace *ace_list) 587{ 588 int count = 0; 589 590 if( DEBUGLVL( 10 )) { 591 dbgtext( "print_canon_ace_list: %s\n", name ); 592 for (;ace_list; ace_list = ace_list->next, count++) 593 print_canon_ace(ace_list, count ); 594 } 595} 596 597/**************************************************************************** 598 Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits). 599****************************************************************************/ 600 601static mode_t convert_permset_to_mode_t(connection_struct *conn, SMB_ACL_PERMSET_T permset) 602{ 603 mode_t ret = 0; 604 605 ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRUSR : 0); 606 ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWUSR : 0); 607 ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0); 608 609 return ret; 610} 611 612/**************************************************************************** 613 Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits). 614****************************************************************************/ 615 616static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask) 617{ 618 mode_t ret = 0; 619 620 if (mode & r_mask) 621 ret |= S_IRUSR; 622 if (mode & w_mask) 623 ret |= S_IWUSR; 624 if (mode & x_mask) 625 ret |= S_IXUSR; 626 627 return ret; 628} 629 630/**************************************************************************** 631 Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to 632 an SMB_ACL_PERMSET_T. 633****************************************************************************/ 634 635static int map_acl_perms_to_permset(connection_struct *conn, mode_t mode, SMB_ACL_PERMSET_T *p_permset) 636{ 637 if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) == -1) 638 return -1; 639 if (mode & S_IRUSR) { 640 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1) 641 return -1; 642 } 643 if (mode & S_IWUSR) { 644 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1) 645 return -1; 646 } 647 if (mode & S_IXUSR) { 648 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1) 649 return -1; 650 } 651 return 0; 652} 653/**************************************************************************** 654 Function to create owner and group SIDs from a SMB_STRUCT_STAT. 655****************************************************************************/ 656 657static void create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid) 658{ 659 uid_to_sid( powner_sid, psbuf->st_uid ); 660 gid_to_sid( pgroup_sid, psbuf->st_gid ); 661} 662 663/**************************************************************************** 664 Merge aces with a common sid - if both are allow or deny, OR the permissions together and 665 delete the second one. If the first is deny, mask the permissions off and delete the allow 666 if the permissions become zero, delete the deny if the permissions are non zero. 667****************************************************************************/ 668 669static void merge_aces( canon_ace **pp_list_head ) 670{ 671 canon_ace *list_head = *pp_list_head; 672 canon_ace *curr_ace_outer; 673 canon_ace *curr_ace_outer_next; 674 675 /* 676 * First, merge allow entries with identical SIDs, and deny entries 677 * with identical SIDs. 678 */ 679 680 for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) { 681 canon_ace *curr_ace; 682 canon_ace *curr_ace_next; 683 684 curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */ 685 686 for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) { 687 688 curr_ace_next = curr_ace->next; /* Save the link in case of delete. */ 689 690 if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) && 691 (curr_ace->attr == curr_ace_outer->attr)) { 692 693 if( DEBUGLVL( 10 )) { 694 dbgtext("merge_aces: Merging ACE's\n"); 695 print_canon_ace( curr_ace_outer, 0); 696 print_canon_ace( curr_ace, 0); 697 } 698 699 /* Merge two allow or two deny ACE's. */ 700 701 curr_ace_outer->perms |= curr_ace->perms; 702 DLIST_REMOVE(list_head, curr_ace); 703 SAFE_FREE(curr_ace); 704 curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */ 705 } 706 } 707 } 708 709 /* 710 * Now go through and mask off allow permissions with deny permissions. 711 * We can delete either the allow or deny here as we know that each SID 712 * appears only once in the list. 713 */ 714 715 for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) { 716 canon_ace *curr_ace; 717 canon_ace *curr_ace_next; 718 719 curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */ 720 721 for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) { 722 723 curr_ace_next = curr_ace->next; /* Save the link in case of delete. */ 724 725 /* 726 * Subtract ACE's with different entries. Due to the ordering constraints 727 * we've put on the ACL, we know the deny must be the first one. 728 */ 729 730 if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) && 731 (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) { 732 733 if( DEBUGLVL( 10 )) { 734 dbgtext("merge_aces: Masking ACE's\n"); 735 print_canon_ace( curr_ace_outer, 0); 736 print_canon_ace( curr_ace, 0); 737 } 738 739 curr_ace->perms &= ~curr_ace_outer->perms; 740 741 if (curr_ace->perms == 0) { 742 743 /* 744 * The deny overrides the allow. Remove the allow. 745 */ 746 747 DLIST_REMOVE(list_head, curr_ace); 748 SAFE_FREE(curr_ace); 749 curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */ 750 751 } else { 752 753 /* 754 * Even after removing permissions, there 755 * are still allow permissions - delete the deny. 756 * It is safe to delete the deny here, 757 * as we are guarenteed by the deny first 758 * ordering that all the deny entries for 759 * this SID have already been merged into one 760 * before we can get to an allow ace. 761 */ 762 763 DLIST_REMOVE(list_head, curr_ace_outer); 764 SAFE_FREE(curr_ace_outer); 765 break; 766 } 767 } 768 769 } /* end for curr_ace */ 770 } /* end for curr_ace_outer */ 771 772 /* We may have modified the list. */ 773 774 *pp_list_head = list_head; 775} 776 777/**************************************************************************** 778 Check if we need to return NT4.x compatible ACL entries. 779****************************************************************************/ 780 781static BOOL nt4_compatible_acls(void) 782{ 783 const char *compat = lp_acl_compatibility(); 784 785 if (*compat == '\0') { 786 enum remote_arch_types ra_type = get_remote_arch(); 787 788 /* Automatically adapt to client */ 789 return (ra_type <= RA_WINNT); 790 } else 791 return (strequal(compat, "winnt")); 792} 793 794 795/**************************************************************************** 796 Map canon_ace perms to permission bits NT. 797 The attr element is not used here - we only process deny entries on set, 798 not get. Deny entries are implicit on get with ace->perms = 0. 799****************************************************************************/ 800 801static SEC_ACCESS map_canon_ace_perms(int *pacl_type, DOM_SID *powner_sid, canon_ace *ace) 802{ 803 SEC_ACCESS sa; 804 uint32 nt_mask = 0; 805 806 *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED; 807 808 if ((ace->perms & ALL_ACE_PERMS) == ALL_ACE_PERMS) { 809 nt_mask = UNIX_ACCESS_RWX; 810 } else if ((ace->perms & ALL_ACE_PERMS) == (mode_t)0) { 811 /* 812 * Windows NT refuses to display ACEs with no permissions in them (but 813 * they are perfectly legal with Windows 2000). If the ACE has empty 814 * permissions we cannot use 0, so we use the otherwise unused 815 * WRITE_OWNER permission, which we ignore when we set an ACL. 816 * We abstract this into a #define of UNIX_ACCESS_NONE to allow this 817 * to be changed in the future. 818 */ 819 820 if (nt4_compatible_acls()) 821 nt_mask = UNIX_ACCESS_NONE; 822 else 823 nt_mask = 0; 824 } else { 825 nt_mask |= ((ace->perms & S_IRUSR) ? UNIX_ACCESS_R : 0 ); 826 nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_ACCESS_W : 0 ); 827 nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_ACCESS_X : 0 ); 828 } 829 830 DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n", 831 (unsigned int)ace->perms, (unsigned int)nt_mask )); 832 833 init_sec_access(&sa,nt_mask); 834 return sa; 835} 836 837/**************************************************************************** 838 Map NT perms to a UNIX mode_t. 839****************************************************************************/ 840 841#define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES) 842#define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES) 843#define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE) 844 845static mode_t map_nt_perms( SEC_ACCESS sec_access, int type) 846{ 847 mode_t mode = 0; 848 849 switch(type) { 850 case S_IRUSR: 851 if(sec_access.mask & GENERIC_ALL_ACCESS) 852 mode = S_IRUSR|S_IWUSR|S_IXUSR; 853 else { 854 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0; 855 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0; 856 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0; 857 } 858 break; 859 case S_IRGRP: 860 if(sec_access.mask & GENERIC_ALL_ACCESS) 861 mode = S_IRGRP|S_IWGRP|S_IXGRP; 862 else { 863 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0; 864 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0; 865 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0; 866 } 867 break; 868 case S_IROTH: 869 if(sec_access.mask & GENERIC_ALL_ACCESS) 870 mode = S_IROTH|S_IWOTH|S_IXOTH; 871 else { 872 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0; 873 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0; 874 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0; 875 } 876 break; 877 } 878 879 return mode; 880} 881 882/**************************************************************************** 883 Unpack a SEC_DESC into a UNIX owner and group. 884****************************************************************************/ 885 886static BOOL unpack_nt_owners(int snum, SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd) 887{ 888 DOM_SID owner_sid; 889 DOM_SID grp_sid; 890 891 *puser = (uid_t)-1; 892 *pgrp = (gid_t)-1; 893 894 if(security_info_sent == 0) { 895 DEBUG(0,("unpack_nt_owners: no security info sent !\n")); 896 return True; 897 } 898 899 /* 900 * Validate the owner and group SID's. 901 */ 902 903 memset(&owner_sid, '\0', sizeof(owner_sid)); 904 memset(&grp_sid, '\0', sizeof(grp_sid)); 905 906 DEBUG(5,("unpack_nt_owners: validating owner_sids.\n")); 907 908 /* 909 * Don't immediately fail if the owner sid cannot be validated. 910 * This may be a group chown only set. 911 */ 912 913 if (security_info_sent & OWNER_SECURITY_INFORMATION) { 914 sid_copy(&owner_sid, psd->owner_sid); 915 if (!NT_STATUS_IS_OK(sid_to_uid(&owner_sid, puser))) { 916 if (lp_force_unknown_acl_user(snum)) { 917 /* this allows take ownership to work 918 * reasonably */ 919 extern struct current_user current_user; 920 *puser = current_user.uid; 921 } else { 922 DEBUG(3,("unpack_nt_owners: unable to validate" 923 " owner sid for %s\n", 924 sid_string_static(&owner_sid))); 925 return False; 926 } 927 } 928 } 929 930 /* 931 * Don't immediately fail if the group sid cannot be validated. 932 * This may be an owner chown only set. 933 */ 934 935 if (security_info_sent & GROUP_SECURITY_INFORMATION) { 936 sid_copy(&grp_sid, psd->grp_sid); 937 if (!NT_STATUS_IS_OK(sid_to_gid( &grp_sid, pgrp))) { 938 if (lp_force_unknown_acl_user(snum)) { 939 /* this allows take group ownership to work 940 * reasonably */ 941 extern struct current_user current_user; 942 *pgrp = current_user.gid; 943 } else { 944 DEBUG(3,("unpack_nt_owners: unable to validate" 945 " group sid.\n")); 946 return False; 947 } 948 } 949 } 950 951 DEBUG(5,("unpack_nt_owners: owner_sids validated.\n")); 952 953 return True; 954} 955 956/**************************************************************************** 957 Ensure the enforced permissions for this share apply. 958****************************************************************************/ 959 960static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type) 961{ 962 int snum = SNUM(fsp->conn); 963 mode_t and_bits = (mode_t)0; 964 mode_t or_bits = (mode_t)0; 965 966 /* Get the initial bits to apply. */ 967 968 if (fsp->is_directory) { 969 and_bits = lp_dir_security_mask(snum); 970 or_bits = lp_force_dir_security_mode(snum); 971 } else { 972 and_bits = lp_security_mask(snum); 973 or_bits = lp_force_security_mode(snum); 974 } 975 976 /* Now bounce them into the S_USR space. */ 977 switch(type) { 978 case S_IRUSR: 979 /* Ensure owner has read access. */ 980 pace->perms |= S_IRUSR; 981 if (fsp->is_directory) 982 pace->perms |= (S_IWUSR|S_IXUSR); 983 and_bits = unix_perms_to_acl_perms(and_bits, S_IRUSR, S_IWUSR, S_IXUSR); 984 or_bits = unix_perms_to_acl_perms(or_bits, S_IRUSR, S_IWUSR, S_IXUSR); 985 break; 986 case S_IRGRP: 987 and_bits = unix_perms_to_acl_perms(and_bits, S_IRGRP, S_IWGRP, S_IXGRP); 988 or_bits = unix_perms_to_acl_perms(or_bits, S_IRGRP, S_IWGRP, S_IXGRP); 989 break; 990 case S_IROTH: 991 and_bits = unix_perms_to_acl_perms(and_bits, S_IROTH, S_IWOTH, S_IXOTH); 992 or_bits = unix_perms_to_acl_perms(or_bits, S_IROTH, S_IWOTH, S_IXOTH); 993 break; 994 } 995 996 pace->perms = ((pace->perms & and_bits)|or_bits); 997} 998 999/**************************************************************************** 1000 Check if a given uid/SID is in a group gid/SID. This is probably very 1001 expensive and will need optimisation. A *lot* of optimisation :-). JRA. 1002****************************************************************************/ 1003 1004static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace ) 1005{ 1006 extern DOM_SID global_sid_World; 1007 fstring u_name; 1008 fstring g_name; 1009 extern struct current_user current_user; 1010 1011 /* "Everyone" always matches every uid. */ 1012 1013 if (sid_equal(&group_ace->trustee, &global_sid_World)) 1014 return True; 1015 1016 /* Assume that the current user is in the current group (force group) */ 1017 1018 if (uid_ace->unix_ug.uid == current_user.uid && group_ace->unix_ug.gid == current_user.gid) 1019 return True; 1020 1021 fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid)); 1022 fstrcpy(g_name, gidtoname(group_ace->unix_ug.gid)); 1023 1024 /* 1025 * Due to the winbind interfaces we need to do this via names, 1026 * not uids/gids. 1027 */ 1028 1029 return user_in_group_list(u_name, g_name, NULL, 0); 1030} 1031 1032/**************************************************************************** 1033 A well formed POSIX file or default ACL has at least 3 entries, a 1034 SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ. 1035 In addition, the owner must always have at least read access. 1036 When using this call on get_acl, the pst struct is valid and contains 1037 the mode of the file. When using this call on set_acl, the pst struct has 1038 been modified to have a mode containing the default for this file or directory 1039 type. 1040****************************************************************************/ 1041 1042static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, 1043 files_struct *fsp, 1044 DOM_SID *pfile_owner_sid, 1045 DOM_SID *pfile_grp_sid, 1046 SMB_STRUCT_STAT *pst, 1047 BOOL setting_acl) 1048{ 1049 extern DOM_SID global_sid_World; 1050 canon_ace *pace; 1051 BOOL got_user = False; 1052 BOOL got_grp = False; 1053 BOOL got_other = False; 1054 canon_ace *pace_other = NULL; 1055 canon_ace *pace_group = NULL; 1056 1057 for (pace = *pp_ace; pace; pace = pace->next) { 1058 if (pace->type == SMB_ACL_USER_OBJ) { 1059 1060 if (setting_acl) 1061 apply_default_perms(fsp, pace, S_IRUSR); 1062 got_user = True; 1063 1064 } else if (pace->type == SMB_ACL_GROUP_OBJ) { 1065 1066 /* 1067 * Ensure create mask/force create mode is respected on set. 1068 */ 1069 1070 if (setting_acl) 1071 apply_default_perms(fsp, pace, S_IRGRP); 1072 got_grp = True; 1073 pace_group = pace; 1074 1075 } else if (pace->type == SMB_ACL_OTHER) { 1076 1077 /* 1078 * Ensure create mask/force create mode is respected on set. 1079 */ 1080 1081 if (setting_acl) 1082 apply_default_perms(fsp, pace, S_IROTH); 1083 got_other = True; 1084 pace_other = pace; 1085 } 1086 } 1087 1088 if (!got_user) { 1089 if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) { 1090 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n")); 1091 return False; 1092 } 1093 1094 ZERO_STRUCTP(pace); 1095 pace->type = SMB_ACL_USER_OBJ; 1096 pace->owner_type = UID_ACE; 1097 pace->unix_ug.uid = pst->st_uid; 1098 pace->trustee = *pfile_owner_sid; 1099 pace->attr = ALLOW_ACE; 1100 1101 if (setting_acl) { 1102 /* If we only got an "everyone" perm, just use that. */ 1103 if (!got_grp && got_other) 1104 pace->perms = pace_other->perms; 1105 else if (got_grp && uid_entry_in_group(pace, pace_group)) 1106 pace->perms = pace_group->perms; 1107 else 1108 pace->perms = 0; 1109 1110 apply_default_perms(fsp, pace, S_IRUSR); 1111 } else { 1112 pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR); 1113 } 1114 1115 DLIST_ADD(*pp_ace, pace); 1116 } 1117 1118 if (!got_grp) { 1119 if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) { 1120 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n")); 1121 return False; 1122 } 1123 1124 ZERO_STRUCTP(pace); 1125 pace->type = SMB_ACL_GROUP_OBJ; 1126 pace->owner_type = GID_ACE; 1127 pace->unix_ug.uid = pst->st_gid; 1128 pace->trustee = *pfile_grp_sid; 1129 pace->attr = ALLOW_ACE; 1130 if (setting_acl) { 1131 /* If we only got an "everyone" perm, just use that. */ 1132 if (got_other) 1133 pace->perms = pace_other->perms; 1134 else 1135 pace->perms = 0; 1136 apply_default_perms(fsp, pace, S_IRGRP); 1137 } else { 1138 pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP); 1139 } 1140 1141 DLIST_ADD(*pp_ace, pace); 1142 } 1143 1144 if (!got_other) { 1145 if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) { 1146 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n")); 1147 return False; 1148 } 1149 1150 ZERO_STRUCTP(pace); 1151 pace->type = SMB_ACL_OTHER; 1152 pace->owner_type = WORLD_ACE; 1153 pace->unix_ug.world = -1; 1154 pace->trustee = global_sid_World; 1155 pace->attr = ALLOW_ACE; 1156 if (setting_acl) { 1157 pace->perms = 0; 1158 apply_default_perms(fsp, pace, S_IROTH); 1159 } else 1160 pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH); 1161 1162 DLIST_ADD(*pp_ace, pace); 1163 } 1164 1165 return True; 1166} 1167 1168/**************************************************************************** 1169 Check if a POSIX ACL has the required SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries. 1170 If it does not have them, check if there are any entries where the trustee is the 1171 file owner or the owning group, and map these to SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ. 1172****************************************************************************/ 1173 1174static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid) 1175{ 1176 BOOL got_user_obj, got_group_obj; 1177 canon_ace *current_ace; 1178 int i, entries; 1179 1180 entries = count_canon_ace_list(ace); 1181 got_user_obj = False; 1182 got_group_obj = False; 1183 1184 for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) { 1185 if (current_ace->type == SMB_ACL_USER_OBJ) 1186 got_user_obj = True; 1187 else if (current_ace->type == SMB_ACL_GROUP_OBJ) 1188 got_group_obj = True; 1189 } 1190 if (got_user_obj && got_group_obj) { 1191 DEBUG(10,("check_owning_objs: ACL had owning user/group entries.\n")); 1192 return; 1193 } 1194 1195 for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) { 1196 if (!got_user_obj && current_ace->owner_type == UID_ACE && 1197 sid_equal(¤t_ace->trustee, pfile_owner_sid)) { 1198 current_ace->type = SMB_ACL_USER_OBJ; 1199 got_user_obj = True; 1200 } 1201 if (!got_group_obj && current_ace->owner_type == GID_ACE && 1202 sid_equal(¤t_ace->trustee, pfile_grp_sid)) { 1203 current_ace->type = SMB_ACL_GROUP_OBJ; 1204 got_group_obj = True; 1205 } 1206 } 1207 if (!got_user_obj) 1208 DEBUG(10,("check_owning_objs: ACL is missing an owner entry.\n")); 1209 if (!got_group_obj) 1210 DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n")); 1211} 1212 1213/**************************************************************************** 1214 Unpack a SEC_DESC into two canonical ace lists. 1215****************************************************************************/ 1216 1217static BOOL create_canon_ace_lists(files_struct *fsp, SMB_STRUCT_STAT *pst, 1218 DOM_SID *pfile_owner_sid, 1219 DOM_SID *pfile_grp_sid, 1220 canon_ace **ppfile_ace, canon_ace **ppdir_ace, 1221 SEC_ACL *dacl) 1222{ 1223 extern DOM_SID global_sid_Creator_Owner; 1224 extern DOM_SID global_sid_Creator_Group; 1225 extern DOM_SID global_sid_World; 1226 extern struct generic_mapping file_generic_mapping; 1227 BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False); 1228 canon_ace *file_ace = NULL; 1229 canon_ace *dir_ace = NULL; 1230 canon_ace *tmp_ace = NULL; 1231 canon_ace *current_ace = NULL; 1232 BOOL got_dir_allow = False; 1233 BOOL got_file_allow = False; 1234 int i, j; 1235 1236 *ppfile_ace = NULL; 1237 *ppdir_ace = NULL; 1238 1239 /* 1240 * Convert the incoming ACL into a more regular form. 1241 */ 1242 1243 for(i = 0; i < dacl->num_aces; i++) { 1244 SEC_ACE *psa = &dacl->ace[i]; 1245 1246 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) { 1247 DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n")); 1248 return False; 1249 } 1250 1251 if (nt4_compatible_acls()) { 1252 /* 1253 * The security mask may be UNIX_ACCESS_NONE which should map into 1254 * no permissions (we overload the WRITE_OWNER bit for this) or it 1255 * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this 1256 * to be so. Any other bits override the UNIX_ACCESS_NONE bit. 1257 */ 1258 1259 /* 1260 * Convert GENERIC bits to specific bits. 1261 */ 1262 1263 se_map_generic(&psa->info.mask, &file_generic_mapping); 1264 1265 psa->info.mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS); 1266 1267 if(psa->info.mask != UNIX_ACCESS_NONE) 1268 psa->info.mask &= ~UNIX_ACCESS_NONE; 1269 } 1270 } 1271 1272 /* 1273 * Deal with the fact that NT 4.x re-writes the canonical format 1274 * that we return for default ACLs. If a directory ACE is identical 1275 * to a inherited directory ACE then NT changes the bits so that the 1276 * first ACE is set to OI|IO and the second ACE for this SID is set 1277 * to CI. We need to repair this. JRA. 1278 */ 1279 1280 for(i = 0; i < dacl->num_aces; i++) { 1281 SEC_ACE *psa1 = &dacl->ace[i]; 1282 1283 for (j = i + 1; j < dacl->num_aces; j++) { 1284 SEC_ACE *psa2 = &dacl->ace[j]; 1285 1286 if (psa1->info.mask != psa2->info.mask) 1287 continue; 1288 1289 if (!sid_equal(&psa1->trustee, &psa2->trustee)) 1290 continue; 1291 1292 /* 1293 * Ok - permission bits and SIDs are equal. 1294 * Check if flags were re-written. 1295 */ 1296 1297 if (psa1->flags & SEC_ACE_FLAG_INHERIT_ONLY) { 1298 1299 psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT)); 1300 psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT); 1301 1302 } else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) { 1303 1304 psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT)); 1305 psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT); 1306 1307 } 1308 } 1309 } 1310 1311 for(i = 0; i < dacl->num_aces; i++) { 1312 SEC_ACE *psa = &dacl->ace[i]; 1313 1314 /* 1315 * Ignore non-mappable SIDs (NT Authority, BUILTIN etc). 1316 */ 1317 1318 if (non_mappable_sid(&psa->trustee)) { 1319 fstring str; 1320 DEBUG(10,("create_canon_ace_lists: ignoring non-mappable SID %s\n", 1321 sid_to_string(str, &psa->trustee) )); 1322 continue; 1323 } 1324 1325 /* 1326 * Create a cannon_ace entry representing this NT DACL ACE. 1327 */ 1328 1329 if ((current_ace = SMB_MALLOC_P(canon_ace)) == NULL) { 1330 free_canon_ace_list(file_ace); 1331 free_canon_ace_list(dir_ace); 1332 DEBUG(0,("create_canon_ace_lists: malloc fail.\n")); 1333 return False; 1334 } 1335 1336 ZERO_STRUCTP(current_ace); 1337 1338 sid_copy(¤t_ace->trustee, &psa->trustee); 1339 1340 /* 1341 * Try and work out if the SID is a user or group 1342 * as we need to flag these differently for POSIX. 1343 * Note what kind of a POSIX ACL this should map to. 1344 */ 1345 1346 if( sid_equal(¤t_ace->trustee, &global_sid_World)) { 1347 current_ace->owner_type = WORLD_ACE; 1348 current_ace->unix_ug.world = -1; 1349 current_ace->type = SMB_ACL_OTHER; 1350 } else if (sid_equal(¤t_ace->trustee, &global_sid_Creator_Owner)) { 1351 current_ace->owner_type = UID_ACE; 1352 current_ace->unix_ug.uid = pst->st_uid; 1353 current_ace->type = SMB_ACL_USER_OBJ; 1354 1355 /* 1356 * The Creator Owner entry only specifies inheritable permissions, 1357 * never access permissions. WinNT doesn't always set the ACE to 1358 *INHERIT_ONLY, though. 1359 */ 1360 1361 if (nt4_compatible_acls()) 1362 psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY; 1363 } else if (sid_equal(¤t_ace->trustee, &global_sid_Creator_Group)) { 1364 current_ace->owner_type = GID_ACE; 1365 current_ace->unix_ug.gid = pst->st_gid; 1366 current_ace->type = SMB_ACL_GROUP_OBJ; 1367 1368 /* 1369 * The Creator Group entry only specifies inheritable permissions, 1370 * never access permissions. WinNT doesn't always set the ACE to 1371 *INHERIT_ONLY, though. 1372 */ 1373 if (nt4_compatible_acls()) 1374 psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY; 1375 1376 } else if (NT_STATUS_IS_OK(sid_to_uid( ¤t_ace->trustee, ¤t_ace->unix_ug.uid))) { 1377 current_ace->owner_type = UID_ACE; 1378 current_ace->type = SMB_ACL_USER; 1379 } else if (NT_STATUS_IS_OK(sid_to_gid( ¤t_ace->trustee, ¤t_ace->unix_ug.gid))) { 1380 current_ace->owner_type = GID_ACE; 1381 current_ace->type = SMB_ACL_GROUP; 1382 } else { 1383 fstring str; 1384 1385 free_canon_ace_list(file_ace); 1386 free_canon_ace_list(dir_ace); 1387 DEBUG(0,("create_canon_ace_lists: unable to map SID %s to uid or gid.\n", 1388 sid_to_string(str, ¤t_ace->trustee) )); 1389 SAFE_FREE(current_ace); 1390 return False; 1391 } 1392 1393 /* 1394 * Map the given NT permissions into a UNIX mode_t containing only 1395 * S_I(R|W|X)USR bits. 1396 */ 1397 1398 current_ace->perms |= map_nt_perms( psa->info, S_IRUSR); 1399 current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE; 1400 current_ace->inherited = ((psa->flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False); 1401 1402 /* 1403 * Now add the created ace to either the file list, the directory 1404 * list, or both. We *MUST* preserve the order here (hence we use 1405 * DLIST_ADD_END) as NT ACLs are order dependent. 1406 */ 1407 1408 if (fsp->is_directory) { 1409 1410 /* 1411 * We can only add to the default POSIX ACE list if the ACE is 1412 * designed to be inherited by both files and directories. 1413 */ 1414 1415 if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) == 1416 (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) { 1417 1418 DLIST_ADD_END(dir_ace, current_ace, tmp_ace); 1419 1420 /* 1421 * Note if this was an allow ace. We can't process 1422 * any further deny ace's after this. 1423 */ 1424 1425 if (current_ace->attr == ALLOW_ACE) 1426 got_dir_allow = True; 1427 1428 if ((current_ace->attr == DENY_ACE) && got_dir_allow) { 1429 DEBUG(0,("create_canon_ace_lists: malformed ACL in inheritable ACL ! \ 1430Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name )); 1431 free_canon_ace_list(file_ace); 1432 free_canon_ace_list(dir_ace); 1433 SAFE_FREE(current_ace); 1434 return False; 1435 } 1436 1437 if( DEBUGLVL( 10 )) { 1438 dbgtext("create_canon_ace_lists: adding dir ACL:\n"); 1439 print_canon_ace( current_ace, 0); 1440 } 1441 1442 /* 1443 * If this is not an inherit only ACE we need to add a duplicate 1444 * to the file acl. 1445 */ 1446 1447 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) { 1448 canon_ace *dup_ace = dup_canon_ace(current_ace); 1449 1450 if (!dup_ace) { 1451 DEBUG(0,("create_canon_ace_lists: malloc fail !\n")); 1452 free_canon_ace_list(file_ace); 1453 free_canon_ace_list(dir_ace); 1454 return False; 1455 } 1456 1457 /* 1458 * We must not free current_ace here as its 1459 * pointer is now owned by the dir_ace list. 1460 */ 1461 current_ace = dup_ace; 1462 } else { 1463 /* 1464 * We must not free current_ace here as its 1465 * pointer is now owned by the dir_ace list. 1466 */ 1467 current_ace = NULL; 1468 } 1469 } 1470 } 1471 1472 /* 1473 * Only add to the file ACL if not inherit only. 1474 */ 1475 1476 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) { 1477 DLIST_ADD_END(file_ace, current_ace, tmp_ace); 1478 1479 /* 1480 * Note if this was an allow ace. We can't process 1481 * any further deny ace's after this. 1482 */ 1483 1484 if (current_ace->attr == ALLOW_ACE) 1485 got_file_allow = True; 1486 1487 if ((current_ace->attr == DENY_ACE) && got_file_allow) { 1488 DEBUG(0,("create_canon_ace_lists: malformed ACL in file ACL ! \ 1489Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name )); 1490 free_canon_ace_list(file_ace); 1491 free_canon_ace_list(dir_ace); 1492 SAFE_FREE(current_ace); 1493 return False; 1494 } 1495 1496 if( DEBUGLVL( 10 )) { 1497 dbgtext("create_canon_ace_lists: adding file ACL:\n"); 1498 print_canon_ace( current_ace, 0); 1499 } 1500 all_aces_are_inherit_only = False; 1501 /* 1502 * We must not free current_ace here as its 1503 * pointer is now owned by the file_ace list. 1504 */ 1505 current_ace = NULL; 1506 } 1507 1508 /* 1509 * Free if ACE was not added. 1510 */ 1511 1512 SAFE_FREE(current_ace); 1513 } 1514 1515 if (fsp->is_directory && all_aces_are_inherit_only) { 1516 /* 1517 * Windows 2000 is doing one of these weird 'inherit acl' 1518 * traverses to conserve NTFS ACL resources. Just pretend 1519 * there was no DACL sent. JRA. 1520 */ 1521 1522 DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n")); 1523 free_canon_ace_list(file_ace); 1524 free_canon_ace_list(dir_ace); 1525 file_ace = NULL; 1526 dir_ace = NULL; 1527 } else { 1528 /* 1529 * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in each 1530 * ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP 1531 * entries can be converted to *_OBJ. Usually we will already have these 1532 * entries in the Default ACL, and the Access ACL will not have them. 1533 */ 1534 check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid); 1535 check_owning_objs(dir_ace, pfile_owner_sid, pfile_grp_sid); 1536 } 1537 1538 *ppfile_ace = file_ace; 1539 *ppdir_ace = dir_ace; 1540 1541 return True; 1542} 1543 1544/**************************************************************************** 1545 ASCII art time again... JRA :-). 1546 1547 We have 4 cases to process when moving from an NT ACL to a POSIX ACL. Firstly, 1548 we insist the ACL is in canonical form (ie. all DENY entries preceede ALLOW 1549 entries). Secondly, the merge code has ensured that all duplicate SID entries for 1550 allow or deny have been merged, so the same SID can only appear once in the deny 1551 list or once in the allow list. 1552 1553 We then process as follows : 1554 1555 --------------------------------------------------------------------------- 1556 First pass - look for a Everyone DENY entry. 1557 1558 If it is deny all (rwx) trunate the list at this point. 1559 Else, walk the list from this point and use the deny permissions of this 1560 entry as a mask on all following allow entries. Finally, delete 1561 the Everyone DENY entry (we have applied it to everything possible). 1562 1563 In addition, in this pass we remove any DENY entries that have 1564 no permissions (ie. they are a DENY nothing). 1565 --------------------------------------------------------------------------- 1566 Second pass - only deal with deny user entries. 1567 1568 DENY user1 (perms XXX) 1569 1570 new_perms = 0 1571 for all following allow group entries where user1 is in group 1572 new_perms |= group_perms; 1573 1574 user1 entry perms = new_perms & ~ XXX; 1575 1576 Convert the deny entry to an allow entry with the new perms and 1577 push to the end of the list. Note if the user was in no groups 1578 this maps to a specific allow nothing entry for this user. 1579 1580 The common case from the NT ACL choser (userX deny all) is 1581 optimised so we don't do the group lookup - we just map to 1582 an allow nothing entry. 1583 1584 What we're doing here is inferring the allow permissions the 1585 person setting the ACE on user1 wanted by looking at the allow 1586 permissions on the groups the user is currently in. This will 1587 be a snapshot, depending on group membership but is the best 1588 we can do and has the advantage of failing closed rather than 1589 open. 1590 --------------------------------------------------------------------------- 1591 Third pass - only deal with deny group entries. 1592 1593 DENY group1 (perms XXX) 1594 1595 for all following allow user entries where user is in group1 1596 user entry perms = user entry perms & ~ XXX; 1597 1598 If there is a group Everyone allow entry with permissions YYY, 1599 convert the group1 entry to an allow entry and modify its 1600 permissions to be : 1601 1602 new_perms = YYY & ~ XXX 1603 1604 and push to the end of the list. 1605 1606 If there is no group Everyone allow entry then convert the 1607 group1 entry to a allow nothing entry and push to the end of the list. 1608 1609 Note that the common case from the NT ACL choser (groupX deny all) 1610 cannot be optimised here as we need to modify user entries who are 1611 in the group to change them to a deny all also. 1612 1613 What we're doing here is modifying the allow permissions of 1614 user entries (which are more specific in POSIX ACLs) to mask 1615 out the explicit deny set on the group they are in. This will 1616 be a snapshot depending on current group membership but is the 1617 best we can do and has the advantage of failing closed rather 1618 than open. 1619 --------------------------------------------------------------------------- 1620 Fourth pass - cope with cumulative permissions. 1621 1622 for all allow user entries, if there exists an allow group entry with 1623 more permissive permissions, and the user is in that group, rewrite the 1624 allow user permissions to contain both sets of permissions. 1625 1626 Currently the code for this is #ifdef'ed out as these semantics make 1627 no sense to me. JRA. 1628 --------------------------------------------------------------------------- 1629 1630 Note we *MUST* do the deny user pass first as this will convert deny user 1631 entries into allow user entries which can then be processed by the deny 1632 group pass. 1633 1634 The above algorithm took a *lot* of thinking about - hence this 1635 explaination :-). JRA. 1636****************************************************************************/ 1637 1638/**************************************************************************** 1639 Process a canon_ace list entries. This is very complex code. We need 1640 to go through and remove the "deny" permissions from any allow entry that matches 1641 the id of this entry. We have already refused any NT ACL that wasn't in correct 1642 order (DENY followed by ALLOW). If any allow entry ends up with zero permissions, 1643 we just remove it (to fail safe). We have already removed any duplicate ace 1644 entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all 1645 allow entries. 1646****************************************************************************/ 1647 1648static void process_deny_list( canon_ace **pp_ace_list ) 1649{ 1650 extern DOM_SID global_sid_World; 1651 canon_ace *ace_list = *pp_ace_list; 1652 canon_ace *curr_ace = NULL; 1653 canon_ace *curr_ace_next = NULL; 1654 1655 /* Pass 1 above - look for an Everyone, deny entry. */ 1656 1657 for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) { 1658 canon_ace *allow_ace_p; 1659 1660 curr_ace_next = curr_ace->next; /* So we can't lose the link. */ 1661 1662 if (curr_ace->attr != DENY_ACE) 1663 continue; 1664 1665 if (curr_ace->perms == (mode_t)0) { 1666 1667 /* Deny nothing entry - delete. */ 1668 1669 DLIST_REMOVE(ace_list, curr_ace); 1670 continue; 1671 } 1672 1673 if (!sid_equal(&curr_ace->trustee, &global_sid_World)) 1674 continue; 1675 1676 /* JRATEST - assert. */ 1677 SMB_ASSERT(curr_ace->owner_type == WORLD_ACE); 1678 1679 if (curr_ace->perms == ALL_ACE_PERMS) { 1680 1681 /* 1682 * Optimisation. This is a DENY_ALL to Everyone. Truncate the 1683 * list at this point including this entry. 1684 */ 1685 1686 canon_ace *prev_entry = curr_ace->prev; 1687 1688 free_canon_ace_list( curr_ace ); 1689 if (prev_entry) 1690 prev_entry->next = NULL; 1691 else { 1692 /* We deleted the entire list. */ 1693 ace_list = NULL; 1694 } 1695 break; 1696 } 1697 1698 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) { 1699 1700 /* 1701 * Only mask off allow entries. 1702 */ 1703 1704 if (allow_ace_p->attr != ALLOW_ACE) 1705 continue; 1706 1707 allow_ace_p->perms &= ~curr_ace->perms; 1708 } 1709 1710 /* 1711 * Now it's been applied, remove it. 1712 */ 1713 1714 DLIST_REMOVE(ace_list, curr_ace); 1715 } 1716 1717 /* Pass 2 above - deal with deny user entries. */ 1718 1719 for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) { 1720 mode_t new_perms = (mode_t)0; 1721 canon_ace *allow_ace_p; 1722 canon_ace *tmp_ace; 1723 1724 curr_ace_next = curr_ace->next; /* So we can't lose the link. */ 1725 1726 if (curr_ace->attr != DENY_ACE) 1727 continue; 1728 1729 if (curr_ace->owner_type != UID_ACE) 1730 continue; 1731 1732 if (curr_ace->perms == ALL_ACE_PERMS) { 1733 1734 /* 1735 * Optimisation - this is a deny everything to this user. 1736 * Convert to an allow nothing and push to the end of the list. 1737 */ 1738 1739 curr_ace->attr = ALLOW_ACE; 1740 curr_ace->perms = (mode_t)0; 1741 DLIST_DEMOTE(ace_list, curr_ace, tmp_ace); 1742 continue; 1743 } 1744 1745 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) { 1746 1747 if (allow_ace_p->attr != ALLOW_ACE) 1748 continue; 1749 1750 /* We process GID_ACE and WORLD_ACE entries only. */ 1751 1752 if (allow_ace_p->owner_type == UID_ACE) 1753 continue; 1754 1755 if (uid_entry_in_group( curr_ace, allow_ace_p)) 1756 new_perms |= allow_ace_p->perms; 1757 } 1758 1759 /* 1760 * Convert to a allow entry, modify the perms and push to the end 1761 * of the list. 1762 */ 1763 1764 curr_ace->attr = ALLOW_ACE; 1765 curr_ace->perms = (new_perms & ~curr_ace->perms); 1766 DLIST_DEMOTE(ace_list, curr_ace, tmp_ace); 1767 } 1768 1769 /* Pass 3 above - deal with deny group entries. */ 1770 1771 for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) { 1772 canon_ace *tmp_ace; 1773 canon_ace *allow_ace_p; 1774 canon_ace *allow_everyone_p = NULL; 1775 1776 curr_ace_next = curr_ace->next; /* So we can't lose the link. */ 1777 1778 if (curr_ace->attr != DENY_ACE) 1779 continue; 1780 1781 if (curr_ace->owner_type != GID_ACE) 1782 continue; 1783 1784 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) { 1785 1786 if (allow_ace_p->attr != ALLOW_ACE) 1787 continue; 1788 1789 /* Store a pointer to the Everyone allow, if it exists. */ 1790 if (allow_ace_p->owner_type == WORLD_ACE) 1791 allow_everyone_p = allow_ace_p; 1792 1793 /* We process UID_ACE entries only. */ 1794 1795 if (allow_ace_p->owner_type != UID_ACE) 1796 continue; 1797 1798 /* Mask off the deny group perms. */ 1799 1800 if (uid_entry_in_group( allow_ace_p, curr_ace)) 1801 allow_ace_p->perms &= ~curr_ace->perms; 1802 } 1803 1804 /* 1805 * Convert the deny to an allow with the correct perms and 1806 * push to the end of the list. 1807 */ 1808 1809 curr_ace->attr = ALLOW_ACE; 1810 if (allow_everyone_p) 1811 curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms; 1812 else 1813 curr_ace->perms = (mode_t)0; 1814 DLIST_DEMOTE(ace_list, curr_ace, tmp_ace); 1815 1816 } 1817 1818 /* Doing this fourth pass allows Windows semantics to be layered 1819 * on top of POSIX semantics. I'm not sure if this is desirable. 1820 * For example, in W2K ACLs there is no way to say, "Group X no 1821 * access, user Y full access" if user Y is a member of group X. 1822 * This seems completely broken semantics to me.... JRA. 1823 */ 1824 1825#if 0 1826 /* Pass 4 above - deal with allow entries. */ 1827 1828 for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) { 1829 canon_ace *allow_ace_p; 1830 1831 curr_ace_next = curr_ace->next; /* So we can't lose the link. */ 1832 1833 if (curr_ace->attr != ALLOW_ACE) 1834 continue; 1835 1836 if (curr_ace->owner_type != UID_ACE) 1837 continue; 1838 1839 for (allow_ace_p = ace_list; allow_ace_p; allow_ace_p = allow_ace_p->next) { 1840 1841 if (allow_ace_p->attr != ALLOW_ACE) 1842 continue; 1843 1844 /* We process GID_ACE entries only. */ 1845 1846 if (allow_ace_p->owner_type != GID_ACE) 1847 continue; 1848 1849 /* OR in the group perms. */ 1850 1851 if (uid_entry_in_group( curr_ace, allow_ace_p)) 1852 curr_ace->perms |= allow_ace_p->perms; 1853 } 1854 } 1855#endif 1856 1857 *pp_ace_list = ace_list; 1858} 1859 1860/**************************************************************************** 1861 Create a default mode that will be used if a security descriptor entry has 1862 no user/group/world entries. 1863****************************************************************************/ 1864 1865static mode_t create_default_mode(files_struct *fsp, BOOL interitable_mode) 1866{ 1867 int snum = SNUM(fsp->conn); 1868 mode_t and_bits = (mode_t)0; 1869 mode_t or_bits = (mode_t)0; 1870 mode_t mode = interitable_mode ? unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name, False) : S_IRUSR; 1871 1872 if (fsp->is_directory) 1873 mode |= (S_IWUSR|S_IXUSR); 1874 1875 /* 1876 * Now AND with the create mode/directory mode bits then OR with the 1877 * force create mode/force directory mode bits. 1878 */ 1879 1880 if (fsp->is_directory) { 1881 and_bits = lp_dir_security_mask(snum); 1882 or_bits = lp_force_dir_security_mode(snum); 1883 } else { 1884 and_bits = lp_security_mask(snum); 1885 or_bits = lp_force_security_mode(snum); 1886 } 1887 1888 return ((mode & and_bits)|or_bits); 1889} 1890 1891/**************************************************************************** 1892 Unpack a SEC_DESC into two canonical ace lists. We don't depend on this 1893 succeeding. 1894****************************************************************************/ 1895 1896static BOOL unpack_canon_ace(files_struct *fsp, 1897 SMB_STRUCT_STAT *pst, 1898 DOM_SID *pfile_owner_sid, 1899 DOM_SID *pfile_grp_sid, 1900 canon_ace **ppfile_ace, canon_ace **ppdir_ace, 1901 uint32 security_info_sent, SEC_DESC *psd) 1902{ 1903 canon_ace *file_ace = NULL; 1904 canon_ace *dir_ace = NULL; 1905 1906 *ppfile_ace = NULL; 1907 *ppdir_ace = NULL; 1908 1909 if(security_info_sent == 0) { 1910 DEBUG(0,("unpack_canon_ace: no security info sent !\n")); 1911 return False; 1912 } 1913 1914 /* 1915 * If no DACL then this is a chown only security descriptor. 1916 */ 1917 1918 if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !psd->dacl) 1919 return True; 1920 1921 /* 1922 * Now go through the DACL and create the canon_ace lists. 1923 */ 1924 1925 if (!create_canon_ace_lists( fsp, pst, pfile_owner_sid, pfile_grp_sid, 1926 &file_ace, &dir_ace, psd->dacl)) 1927 return False; 1928 1929 if ((file_ace == NULL) && (dir_ace == NULL)) { 1930 /* W2K traverse DACL set - ignore. */ 1931 return True; 1932 } 1933 1934 /* 1935 * Go through the canon_ace list and merge entries 1936 * belonging to identical users of identical allow or deny type. 1937 * We can do this as all deny entries come first, followed by 1938 * all allow entries (we have mandated this before accepting this acl). 1939 */ 1940 1941 print_canon_ace_list( "file ace - before merge", file_ace); 1942 merge_aces( &file_ace ); 1943 1944 print_canon_ace_list( "dir ace - before merge", dir_ace); 1945 merge_aces( &dir_ace ); 1946 1947 /* 1948 * NT ACLs are order dependent. Go through the acl lists and 1949 * process DENY entries by masking the allow entries. 1950 */ 1951 1952 print_canon_ace_list( "file ace - before deny", file_ace); 1953 process_deny_list( &file_ace); 1954 1955 print_canon_ace_list( "dir ace - before deny", dir_ace); 1956 process_deny_list( &dir_ace); 1957 1958 /* 1959 * A well formed POSIX file or default ACL has at least 3 entries, a 1960 * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ 1961 * and optionally a mask entry. Ensure this is the case. 1962 */ 1963 1964 print_canon_ace_list( "file ace - before valid", file_ace); 1965 1966 /* 1967 * A default 3 element mode entry for a file should be r-- --- ---. 1968 * A default 3 element mode entry for a directory should be rwx --- ---. 1969 */ 1970 1971 pst->st_mode = create_default_mode(fsp, False); 1972 1973 if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) { 1974 free_canon_ace_list(file_ace); 1975 free_canon_ace_list(dir_ace); 1976 return False; 1977 } 1978 1979 print_canon_ace_list( "dir ace - before valid", dir_ace); 1980 1981 /* 1982 * A default inheritable 3 element mode entry for a directory should be the 1983 * mode Samba will use to create a file within. Ensure user rwx bits are set if 1984 * it's a directory. 1985 */ 1986 1987 pst->st_mode = create_default_mode(fsp, True); 1988 1989 if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) { 1990 free_canon_ace_list(file_ace); 1991 free_canon_ace_list(dir_ace); 1992 return False; 1993 } 1994 1995 print_canon_ace_list( "file ace - return", file_ace); 1996 print_canon_ace_list( "dir ace - return", dir_ace); 1997 1998 *ppfile_ace = file_ace; 1999 *ppdir_ace = dir_ace; 2000 return True; 2001 2002} 2003 2004/****************************************************************************** 2005 When returning permissions, try and fit NT display 2006 semantics if possible. Note the the canon_entries here must have been malloced. 2007 The list format should be - first entry = owner, followed by group and other user 2008 entries, last entry = other. 2009 2010 Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries 2011 are not ordered, and match on the most specific entry rather than walking a list, 2012 then a simple POSIX permission of rw-r--r-- should really map to 5 entries, 2013 2014 Entry 0: owner : deny all except read and write. 2015 Entry 1: group : deny all except read. 2016 Entry 2: owner : allow read and write. 2017 Entry 3: group : allow read. 2018 Entry 4: Everyone : allow read. 2019 2020 But NT cannot display this in their ACL editor ! 2021********************************************************************************/ 2022 2023static void arrange_posix_perms( char *filename, canon_ace **pp_list_head) 2024{ 2025 canon_ace *list_head = *pp_list_head; 2026 canon_ace *owner_ace = NULL; 2027 canon_ace *other_ace = NULL; 2028 canon_ace *ace = NULL; 2029 2030 for (ace = list_head; ace; ace = ace->next) { 2031 if (ace->type == SMB_ACL_USER_OBJ) 2032 owner_ace = ace; 2033 else if (ace->type == SMB_ACL_OTHER) { 2034 /* Last ace - this is "other" */ 2035 other_ace = ace; 2036 } 2037 } 2038 2039 if (!owner_ace || !other_ace) { 2040 DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n", 2041 filename )); 2042 return; 2043 } 2044 2045 /* 2046 * The POSIX algorithm applies to owner first, and other last, 2047 * so ensure they are arranged in this order. 2048 */ 2049 2050 if (owner_ace) { 2051 DLIST_PROMOTE(list_head, owner_ace); 2052 } 2053 2054 if (other_ace) { 2055 DLIST_DEMOTE(list_head, other_ace, ace); 2056 } 2057 2058 /* We have probably changed the head of the list. */ 2059 2060 *pp_list_head = list_head; 2061} 2062 2063/**************************************************************************** 2064 Create a linked list of canonical ACE entries. 2065****************************************************************************/ 2066 2067static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf, 2068 DOM_SID *powner, DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type) 2069{ 2070 extern DOM_SID global_sid_World; 2071 connection_struct *conn = fsp->conn; 2072 mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR); 2073 canon_ace *list_head = NULL; 2074 canon_ace *ace = NULL; 2075 canon_ace *next_ace = NULL; 2076 int entry_id = SMB_ACL_FIRST_ENTRY; 2077 SMB_ACL_ENTRY_T entry; 2078 size_t ace_count; 2079 2080 while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) { 2081 SMB_ACL_TAG_T tagtype; 2082 SMB_ACL_PERMSET_T permset; 2083 DOM_SID sid; 2084 posix_id unix_ug; 2085 enum ace_owner owner_type; 2086 2087 /* get_next... */ 2088 if (entry_id == SMB_ACL_FIRST_ENTRY) 2089 entry_id = SMB_ACL_NEXT_ENTRY; 2090 2091 /* Is this a MASK entry ? */ 2092 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) 2093 continue; 2094 2095 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) 2096 continue; 2097 2098 /* Decide which SID to use based on the ACL type. */ 2099 switch(tagtype) { 2100 case SMB_ACL_USER_OBJ: 2101 /* Get the SID from the owner. */ 2102 sid_copy(&sid, powner); 2103 unix_ug.uid = psbuf->st_uid; 2104 owner_type = UID_ACE; 2105 break; 2106 case SMB_ACL_USER: 2107 { 2108 uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry); 2109 if (puid == NULL) { 2110 DEBUG(0,("canonicalise_acl: Failed to get uid.\n")); 2111 continue; 2112 } 2113 /* 2114 * A SMB_ACL_USER entry for the owner is shadowed by the 2115 * SMB_ACL_USER_OBJ entry and Windows also cannot represent 2116 * that entry, so we ignore it. We also don't create such 2117 * entries out of the blue when setting ACLs, so a get/set 2118 * cycle will drop them. 2119 */ 2120 if (the_acl_type == SMB_ACL_TYPE_ACCESS && *puid == psbuf->st_uid) { 2121 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype); 2122 continue; 2123 } 2124 uid_to_sid( &sid, *puid); 2125 unix_ug.uid = *puid; 2126 owner_type = UID_ACE; 2127 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype); 2128 break; 2129 } 2130 case SMB_ACL_GROUP_OBJ: 2131 /* Get the SID from the owning group. */ 2132 sid_copy(&sid, pgroup); 2133 unix_ug.gid = psbuf->st_gid; 2134 owner_type = GID_ACE; 2135 break; 2136 case SMB_ACL_GROUP: 2137 { 2138 gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry); 2139 if (pgid == NULL) { 2140 DEBUG(0,("canonicalise_acl: Failed to get gid.\n")); 2141 continue; 2142 } 2143 gid_to_sid( &sid, *pgid); 2144 unix_ug.gid = *pgid; 2145 owner_type = GID_ACE; 2146 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype); 2147 break; 2148 } 2149 case SMB_ACL_MASK: 2150 acl_mask = convert_permset_to_mode_t(conn, permset); 2151 continue; /* Don't count the mask as an entry. */ 2152 case SMB_ACL_OTHER: 2153 /* Use the Everyone SID */ 2154 sid = global_sid_World; 2155 unix_ug.world = -1; 2156 owner_type = WORLD_ACE; 2157 break; 2158 default: 2159 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype)); 2160 continue; 2161 } 2162 2163 /* 2164 * Add this entry to the list. 2165 */ 2166 2167 if ((ace = SMB_MALLOC_P(canon_ace)) == NULL) 2168 goto fail; 2169 2170 ZERO_STRUCTP(ace); 2171 ace->type = tagtype; 2172 ace->perms = convert_permset_to_mode_t(conn, permset); 2173 ace->attr = ALLOW_ACE; 2174 ace->trustee = sid; 2175 ace->unix_ug = unix_ug; 2176 ace->owner_type = owner_type; 2177 ace->inherited = get_inherited_flag(pal, ace, (the_acl_type == SMB_ACL_TYPE_DEFAULT)); 2178 2179 DLIST_ADD(list_head, ace); 2180 } 2181 2182 /* 2183 * This next call will ensure we have at least a user/group/world set. 2184 */ 2185 2186 if (!ensure_canon_entry_valid(&list_head, fsp, powner, pgroup, psbuf, False)) 2187 goto fail; 2188 2189 /* 2190 * Now go through the list, masking the permissions with the 2191 * acl_mask. Ensure all DENY Entries are at the start of the list. 2192 */ 2193 2194 DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", the_acl_type == SMB_ACL_TYPE_ACCESS ? "Access" : "Default" )); 2195 2196 for ( ace_count = 0, ace = list_head; ace; ace = next_ace, ace_count++) { 2197 next_ace = ace->next; 2198 2199 /* Masks are only applied to entries other than USER_OBJ and OTHER. */ 2200 if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ) 2201 ace->perms &= acl_mask; 2202 2203 if (ace->perms == 0) { 2204 DLIST_PROMOTE(list_head, ace); 2205 } 2206 2207 if( DEBUGLVL( 10 ) ) { 2208 print_canon_ace(ace, ace_count); 2209 } 2210 } 2211 2212 arrange_posix_perms(fsp->fsp_name,&list_head ); 2213 2214 print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head ); 2215 2216 return list_head; 2217 2218 fail: 2219 2220 free_canon_ace_list(list_head); 2221 return NULL; 2222} 2223 2224/**************************************************************************** 2225 Attempt to apply an ACL to a file or directory. 2226****************************************************************************/ 2227 2228static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, BOOL *pacl_set_support) 2229{ 2230 connection_struct *conn = fsp->conn; 2231 BOOL ret = False; 2232 SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, (int)count_canon_ace_list(the_ace) + 1); 2233 canon_ace *p_ace; 2234 int i; 2235 SMB_ACL_ENTRY_T mask_entry; 2236 BOOL got_mask_entry = False; 2237 SMB_ACL_PERMSET_T mask_permset; 2238 SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS); 2239 BOOL needs_mask = False; 2240 mode_t mask_perms = 0; 2241 2242#if defined(POSIX_ACL_NEEDS_MASK) 2243 /* HP-UX always wants to have a mask (called "class" there). */ 2244 needs_mask = True; 2245#endif 2246 2247 if (the_acl == NULL) { 2248 2249 if (!no_acl_syscall_error(errno)) { 2250 /* 2251 * Only print this error message if we have some kind of ACL 2252 * support that's not working. Otherwise we would always get this. 2253 */ 2254 DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n", 2255 default_ace ? "default" : "file", strerror(errno) )); 2256 } 2257 *pacl_set_support = False; 2258 return False; 2259 } 2260 2261 if( DEBUGLVL( 10 )) { 2262 dbgtext("set_canon_ace_list: setting ACL:\n"); 2263 for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) { 2264 print_canon_ace( p_ace, i); 2265 } 2266 } 2267 2268 for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) { 2269 SMB_ACL_ENTRY_T the_entry; 2270 SMB_ACL_PERMSET_T the_permset; 2271 2272 /* 2273 * ACLs only "need" an ACL_MASK entry if there are any named user or 2274 * named group entries. But if there is an ACL_MASK entry, it applies 2275 * to ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. Set the mask 2276 * so that it doesn't deny (i.e., mask off) any permissions. 2277 */ 2278 2279 if (p_ace->type == SMB_ACL_USER || p_ace->type == SMB_ACL_GROUP) { 2280 needs_mask = True; 2281 mask_perms |= p_ace->perms; 2282 } else if (p_ace->type == SMB_ACL_GROUP_OBJ) { 2283 mask_perms |= p_ace->perms; 2284 } 2285 2286 /* 2287 * Get the entry for this ACE. 2288 */ 2289 2290 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) { 2291 DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n", 2292 i, strerror(errno) )); 2293 goto done; 2294 } 2295 2296 if (p_ace->type == SMB_ACL_MASK) { 2297 mask_entry = the_entry; 2298 got_mask_entry = True; 2299 } 2300 2301 /* 2302 * Ok - we now know the ACL calls should be working, don't 2303 * allow fallback to chmod. 2304 */ 2305 2306 *pacl_set_support = True; 2307 2308 /* 2309 * Initialise the entry from the canon_ace. 2310 */ 2311 2312 /* 2313 * First tell the entry what type of ACE this is. 2314 */ 2315 2316 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, p_ace->type) == -1) { 2317 DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n", 2318 i, strerror(errno) )); 2319 goto done; 2320 } 2321 2322 /* 2323 * Only set the qualifier (user or group id) if the entry is a user 2324 * or group id ACE. 2325 */ 2326 2327 if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) { 2328 if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&p_ace->unix_ug.uid) == -1) { 2329 DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n", 2330 i, strerror(errno) )); 2331 goto done; 2332 } 2333 } 2334 2335 /* 2336 * Convert the mode_t perms in the canon_ace to a POSIX permset. 2337 */ 2338 2339 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) { 2340 DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n", 2341 i, strerror(errno) )); 2342 goto done; 2343 } 2344 2345 if (map_acl_perms_to_permset(conn, p_ace->perms, &the_permset) == -1) { 2346 DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n", 2347 (unsigned int)p_ace->perms, i, strerror(errno) )); 2348 goto done; 2349 } 2350 2351 /* 2352 * ..and apply them to the entry. 2353 */ 2354 2355 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) { 2356 DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n", 2357 i, strerror(errno) )); 2358 goto done; 2359 } 2360 2361 if( DEBUGLVL( 10 )) 2362 print_canon_ace( p_ace, i); 2363 2364 } 2365 2366 if (needs_mask && !got_mask_entry) { 2367 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &mask_entry) == -1) { 2368 DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) )); 2369 goto done; 2370 } 2371 2372 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, mask_entry, SMB_ACL_MASK) == -1) { 2373 DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) )); 2374 goto done; 2375 } 2376 2377 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, mask_entry, &mask_permset) == -1) { 2378 DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) )); 2379 goto done; 2380 } 2381 2382 if (map_acl_perms_to_permset(conn, S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) { 2383 DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) )); 2384 goto done; 2385 } 2386 2387 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, mask_entry, mask_permset) == -1) { 2388 DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) )); 2389 goto done; 2390 } 2391 } 2392 2393 /* 2394 * Check if the ACL is valid. 2395 */ 2396 2397 if (SMB_VFS_SYS_ACL_VALID(conn, the_acl) == -1) { 2398 DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n", 2399 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file", 2400 strerror(errno) )); 2401 goto done; 2402 } 2403 2404 /* 2405 * Finally apply it to the file or directory. 2406 */ 2407 2408 if(default_ace || fsp->is_directory || fsp->fd == -1) { 2409 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl) == -1) { 2410 /* 2411 * Some systems allow all the above calls and only fail with no ACL support 2412 * when attempting to apply the acl. HPUX with HFS is an example of this. JRA. 2413 */ 2414 if (no_acl_syscall_error(errno)) { 2415 *pacl_set_support = False; 2416 } 2417 2418 DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n", 2419 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file", 2420 fsp->fsp_name, strerror(errno) )); 2421 goto done; 2422 } 2423 } else { 2424 if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fd, the_acl) == -1) { 2425 /* 2426 * Some systems allow all the above calls and only fail with no ACL support 2427 * when attempting to apply the acl. HPUX with HFS is an example of this. JRA. 2428 */ 2429 if (no_acl_syscall_error(errno)) { 2430 *pacl_set_support = False; 2431 } 2432 2433 DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n", 2434 fsp->fsp_name, strerror(errno) )); 2435 goto done; 2436 } 2437 } 2438 2439 ret = True; 2440 2441 done: 2442 2443 if (the_acl != NULL) 2444 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl); 2445 2446 return ret; 2447} 2448 2449/**************************************************************************** 2450 Find a particular canon_ace entry. 2451****************************************************************************/ 2452 2453static struct canon_ace *canon_ace_entry_for(struct canon_ace *list, SMB_ACL_TAG_T type, posix_id *id) 2454{ 2455 while (list) { 2456 if (list->type == type && ((type != SMB_ACL_USER && type != SMB_ACL_GROUP) || 2457 (type == SMB_ACL_USER && id && id->uid == list->unix_ug.uid) || 2458 (type == SMB_ACL_GROUP && id && id->gid == list->unix_ug.gid))) 2459 break; 2460 list = list->next; 2461 } 2462 return list; 2463} 2464 2465/**************************************************************************** 2466 2467****************************************************************************/ 2468 2469SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl) 2470{ 2471 SMB_ACL_ENTRY_T entry; 2472 2473 if (!the_acl) 2474 return NULL; 2475 if (SMB_VFS_SYS_ACL_GET_ENTRY(conn, the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) { 2476 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl); 2477 return NULL; 2478 } 2479 return the_acl; 2480} 2481 2482/**************************************************************************** 2483 Convert a canon_ace to a generic 3 element permission - if possible. 2484****************************************************************************/ 2485 2486#define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 ) 2487 2488static BOOL convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms) 2489{ 2490 int snum = SNUM(fsp->conn); 2491 size_t ace_count = count_canon_ace_list(file_ace_list); 2492 canon_ace *ace_p; 2493 canon_ace *owner_ace = NULL; 2494 canon_ace *group_ace = NULL; 2495 canon_ace *other_ace = NULL; 2496 mode_t and_bits; 2497 mode_t or_bits; 2498 2499 if (ace_count != 3) { 2500 DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \ 2501posix perms.\n", fsp->fsp_name )); 2502 return False; 2503 } 2504 2505 for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) { 2506 if (ace_p->owner_type == UID_ACE) 2507 owner_ace = ace_p; 2508 else if (ace_p->owner_type == GID_ACE) 2509 group_ace = ace_p; 2510 else if (ace_p->owner_type == WORLD_ACE) 2511 other_ace = ace_p; 2512 } 2513 2514 if (!owner_ace || !group_ace || !other_ace) { 2515 DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n", 2516 fsp->fsp_name )); 2517 return False; 2518 } 2519 2520 *posix_perms = (mode_t)0; 2521 2522 *posix_perms |= owner_ace->perms; 2523 *posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP); 2524 *posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP); 2525 *posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP); 2526 *posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH); 2527 *posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH); 2528 *posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH); 2529 2530 /* The owner must have at least read access. */ 2531 2532 *posix_perms |= S_IRUSR; 2533 if (fsp->is_directory) 2534 *posix_perms |= (S_IWUSR|S_IXUSR); 2535 2536 /* If requested apply the masks. */ 2537 2538 /* Get the initial bits to apply. */ 2539 2540 if (fsp->is_directory) { 2541 and_bits = lp_dir_security_mask(snum); 2542 or_bits = lp_force_dir_security_mode(snum); 2543 } else { 2544 and_bits = lp_security_mask(snum); 2545 or_bits = lp_force_security_mode(snum); 2546 } 2547 2548 *posix_perms = (((*posix_perms) & and_bits)|or_bits); 2549 2550 DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n", 2551 (int)owner_ace->perms, (int)group_ace->perms, (int)other_ace->perms, (int)*posix_perms, 2552 fsp->fsp_name )); 2553 2554 return True; 2555} 2556 2557/**************************************************************************** 2558 Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and 2559 a normal POSIX acl. Win2k needs these split acls re-merging into one ACL 2560 with CI|OI set so it is inherited and also applies to the directory. 2561 Based on code from "Jim McDonough" <jmcd@us.ibm.com>. 2562****************************************************************************/ 2563 2564static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces) 2565{ 2566 size_t i, j; 2567 2568 for (i = 0; i < num_aces; i++) { 2569 for (j = i+1; j < num_aces; j++) { 2570 uint32 i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE); 2571 uint32 j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE); 2572 BOOL i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False; 2573 BOOL j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False; 2574 2575 /* We know the lower number ACE's are file entries. */ 2576 if ((nt_ace_list[i].type == nt_ace_list[j].type) && 2577 (nt_ace_list[i].size == nt_ace_list[j].size) && 2578 (nt_ace_list[i].info.mask == nt_ace_list[j].info.mask) && 2579 sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) && 2580 (i_inh == j_inh) && 2581 (i_flags_ni == 0) && 2582 (j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT| 2583 SEC_ACE_FLAG_CONTAINER_INHERIT| 2584 SEC_ACE_FLAG_INHERIT_ONLY))) { 2585 /* 2586 * W2K wants to have access allowed zero access ACE's 2587 * at the end of the list. If the mask is zero, merge 2588 * the non-inherited ACE onto the inherited ACE. 2589 */ 2590 2591 if (nt_ace_list[i].info.mask == 0) { 2592 nt_ace_list[j].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT| 2593 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0); 2594 if (num_aces - i - 1 > 0) 2595 memmove(&nt_ace_list[i], &nt_ace_list[i+1], (num_aces-i-1) * 2596 sizeof(SEC_ACE)); 2597 2598 DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n", 2599 (unsigned int)i, (unsigned int)j )); 2600 } else { 2601 /* 2602 * These are identical except for the flags. 2603 * Merge the inherited ACE onto the non-inherited ACE. 2604 */ 2605 2606 nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT| 2607 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0); 2608 if (num_aces - j - 1 > 0) 2609 memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) * 2610 sizeof(SEC_ACE)); 2611 2612 DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n", 2613 (unsigned int)j, (unsigned int)i )); 2614 } 2615 num_aces--; 2616 break; 2617 } 2618 } 2619 } 2620 2621 return num_aces; 2622} 2623/**************************************************************************** 2624 Reply to query a security descriptor from an fsp. If it succeeds it allocates 2625 the space for the return elements and returns the size needed to return the 2626 security descriptor. This should be the only external function needed for 2627 the UNIX style get ACL. 2628****************************************************************************/ 2629 2630size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) 2631{ 2632 extern DOM_SID global_sid_Builtin_Administrators; 2633 extern DOM_SID global_sid_Builtin_Users; 2634 extern DOM_SID global_sid_Creator_Owner; 2635 extern DOM_SID global_sid_Creator_Group; 2636 connection_struct *conn = fsp->conn; 2637 SMB_STRUCT_STAT sbuf; 2638 SEC_ACE *nt_ace_list = NULL; 2639 DOM_SID owner_sid; 2640 DOM_SID group_sid; 2641 size_t sd_size = 0; 2642 SEC_ACL *psa = NULL; 2643 size_t num_acls = 0; 2644 size_t num_def_acls = 0; 2645 size_t num_aces = 0; 2646 SMB_ACL_T posix_acl = NULL; 2647 SMB_ACL_T def_acl = NULL; 2648 canon_ace *file_ace = NULL; 2649 canon_ace *dir_ace = NULL; 2650 size_t num_profile_acls = 0; 2651 struct pai_val *pal = NULL; 2652 SEC_DESC *psd = NULL; 2653 2654 *ppdesc = NULL; 2655 2656 DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name )); 2657 2658 if(fsp->is_directory || fsp->fd == -1) { 2659 2660 /* Get the stat struct for the owner info. */ 2661 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) { 2662 return 0; 2663 } 2664 /* 2665 * Get the ACL from the path. 2666 */ 2667 2668 posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_ACCESS); 2669 2670 /* 2671 * If it's a directory get the default POSIX ACL. 2672 */ 2673 2674 if(fsp->is_directory) { 2675 def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT); 2676 def_acl = free_empty_sys_acl(conn, def_acl); 2677 } 2678 2679 } else { 2680 2681 /* Get the stat struct for the owner info. */ 2682 if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) { 2683 return 0; 2684 } 2685 /* 2686 * Get the ACL from the fd. 2687 */ 2688 posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd); 2689 } 2690 2691 DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n", 2692 posix_acl ? "present" : "absent", 2693 def_acl ? "present" : "absent" )); 2694 2695 pal = load_inherited_info(fsp); 2696 2697 /* 2698 * Get the owner, group and world SIDs. 2699 */ 2700 2701 if (lp_profile_acls(SNUM(fsp->conn))) { 2702 /* For WXP SP1 the owner must be administrators. */ 2703 sid_copy(&owner_sid, &global_sid_Builtin_Administrators); 2704 sid_copy(&group_sid, &global_sid_Builtin_Users); 2705 num_profile_acls = 2; 2706 } else { 2707 create_file_sids(&sbuf, &owner_sid, &group_sid); 2708 } 2709 2710 if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) { 2711 2712 /* 2713 * In the optimum case Creator Owner and Creator Group would be used for 2714 * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this 2715 * would lead to usability problems under Windows: The Creator entries 2716 * are only available in browse lists of directories and not for files; 2717 * additionally the identity of the owning group couldn't be determined. 2718 * We therefore use those identities only for Default ACLs. 2719 */ 2720 2721 /* Create the canon_ace lists. */ 2722 file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid, pal, SMB_ACL_TYPE_ACCESS ); 2723 2724 /* We must have *some* ACLS. */ 2725 2726 if (count_canon_ace_list(file_ace) == 0) { 2727 DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name )); 2728 return 0; 2729 } 2730 2731 if (fsp->is_directory && def_acl) { 2732 dir_ace = canonicalise_acl(fsp, def_acl, &sbuf, 2733 &global_sid_Creator_Owner, 2734 &global_sid_Creator_Group, pal, SMB_ACL_TYPE_DEFAULT ); 2735 } 2736 2737 /* 2738 * Create the NT ACE list from the canonical ace lists. 2739 */ 2740 2741 { 2742 canon_ace *ace; 2743 int nt_acl_type; 2744 int i; 2745 2746 if (nt4_compatible_acls() && dir_ace) { 2747 /* 2748 * NT 4 chokes if an ACL contains an INHERIT_ONLY entry 2749 * but no non-INHERIT_ONLY entry for one SID. So we only 2750 * remove entries from the Access ACL if the 2751 * corresponding Default ACL entries have also been 2752 * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP 2753 * are exceptions. We can do nothing 2754 * intelligent if the Default ACL contains entries that 2755 * are not also contained in the Access ACL, so this 2756 * case will still fail under NT 4. 2757 */ 2758 2759 ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL); 2760 if (ace && !ace->perms) { 2761 DLIST_REMOVE(dir_ace, ace); 2762 SAFE_FREE(ace); 2763 2764 ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL); 2765 if (ace && !ace->perms) { 2766 DLIST_REMOVE(file_ace, ace); 2767 SAFE_FREE(ace); 2768 } 2769 } 2770 2771 /* 2772 * WinNT doesn't usually have Creator Group 2773 * in browse lists, so we send this entry to 2774 * WinNT even if it contains no relevant 2775 * permissions. Once we can add 2776 * Creator Group to browse lists we can 2777 * re-enable this. 2778 */ 2779 2780#if 0 2781 ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL); 2782 if (ace && !ace->perms) { 2783 DLIST_REMOVE(dir_ace, ace); 2784 SAFE_FREE(ace); 2785 } 2786#endif 2787 2788 ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL); 2789 if (ace && !ace->perms) { 2790 DLIST_REMOVE(file_ace, ace); 2791 SAFE_FREE(ace); 2792 } 2793 } 2794 2795 num_acls = count_canon_ace_list(file_ace); 2796 num_def_acls = count_canon_ace_list(dir_ace); 2797 2798 /* Allocate the ace list. */ 2799 if ((nt_ace_list = SMB_MALLOC_ARRAY(SEC_ACE,num_acls + num_profile_acls + num_def_acls)) == NULL) { 2800 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n")); 2801 goto done; 2802 } 2803 2804 memset(nt_ace_list, '\0', (num_acls + num_def_acls) * sizeof(SEC_ACE) ); 2805 2806 /* 2807 * Create the NT ACE list from the canonical ace lists. 2808 */ 2809 2810 ace = file_ace; 2811 2812 for (i = 0; i < num_acls; i++, ace = ace->next) { 2813 SEC_ACCESS acc; 2814 2815 acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace ); 2816 init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0); 2817 } 2818 2819 /* The User must have access to a profile share - even if we can't map the SID. */ 2820 if (lp_profile_acls(SNUM(fsp->conn))) { 2821 SEC_ACCESS acc; 2822 2823 init_sec_access(&acc,FILE_GENERIC_ALL); 2824 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, 2825 acc, 0); 2826 } 2827 2828 ace = dir_ace; 2829 2830 for (i = 0; i < num_def_acls; i++, ace = ace->next) { 2831 SEC_ACCESS acc; 2832 2833 acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace ); 2834 init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, 2835 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT| 2836 SEC_ACE_FLAG_INHERIT_ONLY| 2837 (ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0)); 2838 } 2839 2840 /* The User must have access to a profile share - even if we can't map the SID. */ 2841 if (lp_profile_acls(SNUM(fsp->conn))) { 2842 SEC_ACCESS acc; 2843 2844 init_sec_access(&acc,FILE_GENERIC_ALL); 2845 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc, 2846 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT| 2847 SEC_ACE_FLAG_INHERIT_ONLY|0); 2848 } 2849 2850 /* 2851 * Merge POSIX default ACLs and normal ACLs into one NT ACE. 2852 * Win2K needs this to get the inheritance correct when replacing ACLs 2853 * on a directory tree. Based on work by Jim @ IBM. 2854 */ 2855 2856 num_aces = merge_default_aces(nt_ace_list, num_aces); 2857 2858 } 2859 2860 if (num_aces) { 2861 if((psa = make_sec_acl( main_loop_talloc_get(), NT4_ACL_REVISION, num_aces, nt_ace_list)) == NULL) { 2862 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n")); 2863 goto done; 2864 } 2865 } 2866 } /* security_info & DACL_SECURITY_INFORMATION */ 2867 2868 psd = make_standard_sec_desc( main_loop_talloc_get(), 2869 (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL, 2870 (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL, 2871 psa, 2872 &sd_size); 2873 2874 if(!psd) { 2875 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n")); 2876 sd_size = 0; 2877 } else { 2878 /* 2879 * Windows 2000: The DACL_PROTECTED flag in the security 2880 * descriptor marks the ACL as non-inheriting, i.e., no 2881 * ACEs from higher level directories propagate to this 2882 * ACL. In the POSIX ACL model permissions are only 2883 * inherited at file create time, so ACLs never contain 2884 * any ACEs that are inherited dynamically. The DACL_PROTECTED 2885 * flag doesn't seem to bother Windows NT. 2886 * Always set this if map acl inherit is turned off. 2887 */ 2888 if (get_protected_flag(pal) || !lp_map_acl_inherit(SNUM(conn))) { 2889 psd->type |= SE_DESC_DACL_PROTECTED; 2890 } 2891 } 2892 2893 if (psd->dacl) 2894 dacl_sort_into_canonical_order(psd->dacl->ace, (unsigned int)psd->dacl->num_aces); 2895 2896 *ppdesc = psd; 2897 2898 done: 2899 2900 if (posix_acl) 2901 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl); 2902 if (def_acl) 2903 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl); 2904 free_canon_ace_list(file_ace); 2905 free_canon_ace_list(dir_ace); 2906 free_inherited_info(pal); 2907 SAFE_FREE(nt_ace_list); 2908 2909 return sd_size; 2910} 2911 2912/**************************************************************************** 2913 Try to chown a file. We will be able to chown it under the following conditions. 2914 2915 1) If we have root privileges, then it will just work. 2916 2) If we have write permission to the file and dos_filemodes is set 2917 then allow chown to the currently authenticated user. 2918****************************************************************************/ 2919 2920static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid) 2921{ 2922 int ret; 2923 extern struct current_user current_user; 2924 files_struct *fsp; 2925 SMB_STRUCT_STAT st; 2926 2927 /* try the direct way first */ 2928 ret = SMB_VFS_CHOWN(conn, fname, uid, gid); 2929 if (ret == 0) 2930 return 0; 2931 2932 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn))) 2933 return -1; 2934 2935 if (SMB_VFS_STAT(conn,fname,&st)) 2936 return -1; 2937 2938 fsp = open_file_fchmod(conn,fname,&st); 2939 if (!fsp) 2940 return -1; 2941 2942 /* only allow chown to the current user. This is more secure, 2943 and also copes with the case where the SID in a take ownership ACL is 2944 a local SID on the users workstation 2945 */ 2946 uid = current_user.uid; 2947 2948 become_root(); 2949 /* Keep the current file gid the same. */ 2950 ret = SMB_VFS_FCHOWN(fsp, fsp->fd, uid, (gid_t)-1); 2951 unbecome_root(); 2952 2953 close_file_fchmod(fsp); 2954 2955 return ret; 2956} 2957 2958/**************************************************************************** 2959 Reply to set a security descriptor on an fsp. security_info_sent is the 2960 description of the following NT ACL. 2961 This should be the only external function needed for the UNIX style set ACL. 2962****************************************************************************/ 2963 2964BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) 2965{ 2966 connection_struct *conn = fsp->conn; 2967 uid_t user = (uid_t)-1; 2968 gid_t grp = (gid_t)-1; 2969 SMB_STRUCT_STAT sbuf; 2970 DOM_SID file_owner_sid; 2971 DOM_SID file_grp_sid; 2972 canon_ace *file_ace_list = NULL; 2973 canon_ace *dir_ace_list = NULL; 2974 BOOL acl_perms = False; 2975 mode_t orig_mode = (mode_t)0; 2976 uid_t orig_uid; 2977 gid_t orig_gid; 2978 BOOL need_chown = False; 2979 extern struct current_user current_user; 2980 2981 DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name )); 2982 2983 if (!CAN_WRITE(conn)) { 2984 DEBUG(10,("set acl rejected on read-only share\n")); 2985 return False; 2986 } 2987 2988 /* 2989 * Get the current state of the file. 2990 */ 2991 2992 if(fsp->is_directory || fsp->fd == -1) { 2993 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) 2994 return False; 2995 } else { 2996 if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) 2997 return False; 2998 } 2999 3000 /* Save the original elements we check against. */ 3001 orig_mode = sbuf.st_mode; 3002 orig_uid = sbuf.st_uid; 3003 orig_gid = sbuf.st_gid; 3004 3005 /* 3006 * Unpack the user/group/world id's. 3007 */ 3008 3009 if (!unpack_nt_owners( SNUM(conn), &sbuf, &user, &grp, security_info_sent, psd)) 3010 return False; 3011 3012 /* 3013 * Do we need to chown ? 3014 */ 3015 3016 if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp))) 3017 need_chown = True; 3018 3019 /* 3020 * Chown before setting ACL only if we don't change the user, or 3021 * if we change to the current user, but not if we want to give away 3022 * the file. 3023 */ 3024 3025 if (need_chown && (user == (uid_t)-1 || user == current_user.uid)) { 3026 3027 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n", 3028 fsp->fsp_name, (unsigned int)user, (unsigned int)grp )); 3029 3030 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) { 3031 DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n", 3032 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) )); 3033 return False; 3034 } 3035 3036 /* 3037 * Recheck the current state of the file, which may have changed. 3038 * (suid/sgid bits, for instance) 3039 */ 3040 3041 if(fsp->is_directory) { 3042 if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf) != 0) { 3043 return False; 3044 } 3045 } else { 3046 3047 int ret; 3048 3049 if(fsp->fd == -1) 3050 ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf); 3051 else 3052 ret = SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf); 3053 3054 if(ret != 0) 3055 return False; 3056 } 3057 3058 /* Save the original elements we check against. */ 3059 orig_mode = sbuf.st_mode; 3060 orig_uid = sbuf.st_uid; 3061 orig_gid = sbuf.st_gid; 3062 3063 /* We did it, don't try again */ 3064 need_chown = False; 3065 } 3066 3067 create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid); 3068 3069 acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid, 3070 &file_ace_list, &dir_ace_list, security_info_sent, psd); 3071 3072 /* Ignore W2K traverse DACL set. */ 3073 if (file_ace_list || dir_ace_list) { 3074 3075 if (!acl_perms) { 3076 DEBUG(3,("set_nt_acl: cannot set permissions\n")); 3077 free_canon_ace_list(file_ace_list); 3078 free_canon_ace_list(dir_ace_list); 3079 return False; 3080 } 3081 3082 /* 3083 * Only change security if we got a DACL. 3084 */ 3085 3086 if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) { 3087 3088 BOOL acl_set_support = False; 3089 BOOL ret = False; 3090 3091 /* 3092 * Try using the POSIX ACL set first. Fall back to chmod if 3093 * we have no ACL support on this filesystem. 3094 */ 3095 3096 if (acl_perms && file_ace_list) { 3097 ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support); 3098 if (acl_set_support && ret == False) { 3099 DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) )); 3100 free_canon_ace_list(file_ace_list); 3101 free_canon_ace_list(dir_ace_list); 3102 return False; 3103 } 3104 } 3105 3106 if (acl_perms && acl_set_support && fsp->is_directory) { 3107 if (dir_ace_list) { 3108 if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) { 3109 DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) )); 3110 free_canon_ace_list(file_ace_list); 3111 free_canon_ace_list(dir_ace_list); 3112 return False; 3113 } 3114 } else { 3115 3116 /* 3117 * No default ACL - delete one if it exists. 3118 */ 3119 3120 if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name) == -1) { 3121 DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno))); 3122 free_canon_ace_list(file_ace_list); 3123 free_canon_ace_list(dir_ace_list); 3124 return False; 3125 } 3126 } 3127 } 3128 3129 if (acl_set_support) 3130 store_inheritance_attributes(fsp, file_ace_list, dir_ace_list, 3131 (psd->type & SE_DESC_DACL_PROTECTED) ? True : False); 3132 3133 /* 3134 * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod. 3135 */ 3136 3137 if(!acl_set_support && acl_perms) { 3138 mode_t posix_perms; 3139 3140 if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) { 3141 free_canon_ace_list(file_ace_list); 3142 free_canon_ace_list(dir_ace_list); 3143 DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n", 3144 fsp->fsp_name )); 3145 return False; 3146 } 3147 3148 if (orig_mode != posix_perms) { 3149 3150 DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n", 3151 fsp->fsp_name, (unsigned int)posix_perms )); 3152 3153 if(SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms) == -1) { 3154 DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n", 3155 fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) )); 3156 free_canon_ace_list(file_ace_list); 3157 free_canon_ace_list(dir_ace_list); 3158 return False; 3159 } 3160 } 3161 } 3162 } 3163 3164 free_canon_ace_list(file_ace_list); 3165 free_canon_ace_list(dir_ace_list); 3166 } 3167 3168 /* Any chown pending? */ 3169 if (need_chown) { 3170 3171 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n", 3172 fsp->fsp_name, (unsigned int)user, (unsigned int)grp )); 3173 3174 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) { 3175 DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n", 3176 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) )); 3177 return False; 3178 } 3179 } 3180 3181 return True; 3182} 3183 3184/**************************************************************************** 3185 Get the actual group bits stored on a file with an ACL. Has no effect if 3186 the file has no ACL. Needed in dosmode code where the stat() will return 3187 the mask bits, not the real group bits, for a file with an ACL. 3188****************************************************************************/ 3189 3190int get_acl_group_bits( connection_struct *conn, const char *fname, mode_t *mode ) 3191{ 3192 int entry_id = SMB_ACL_FIRST_ENTRY; 3193 SMB_ACL_ENTRY_T entry; 3194 SMB_ACL_T posix_acl; 3195 int result = -1; 3196 3197 posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS); 3198 if (posix_acl == (SMB_ACL_T)NULL) 3199 return -1; 3200 3201 while (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) { 3202 SMB_ACL_TAG_T tagtype; 3203 SMB_ACL_PERMSET_T permset; 3204 3205 /* get_next... */ 3206 if (entry_id == SMB_ACL_FIRST_ENTRY) 3207 entry_id = SMB_ACL_NEXT_ENTRY; 3208 3209 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) ==-1) 3210 break; 3211 3212 if (tagtype == SMB_ACL_GROUP_OBJ) { 3213 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) { 3214 break; 3215 } else { 3216 *mode &= ~(S_IRGRP|S_IWGRP|S_IXGRP); 3217 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRGRP : 0); 3218 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWGRP : 0); 3219 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXGRP : 0); 3220 result = 0; 3221 break; 3222 } 3223 } 3224 } 3225 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl); 3226 return result; 3227} 3228 3229/**************************************************************************** 3230 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL 3231 and set the mask to rwx. Needed to preserve complex ACLs set by NT. 3232****************************************************************************/ 3233 3234static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mode_t mode) 3235{ 3236 int entry_id = SMB_ACL_FIRST_ENTRY; 3237 SMB_ACL_ENTRY_T entry; 3238 int num_entries = 0; 3239 3240 while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) { 3241 SMB_ACL_TAG_T tagtype; 3242 SMB_ACL_PERMSET_T permset; 3243 mode_t perms; 3244 3245 /* get_next... */ 3246 if (entry_id == SMB_ACL_FIRST_ENTRY) 3247 entry_id = SMB_ACL_NEXT_ENTRY; 3248 3249 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) 3250 return -1; 3251 3252 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) 3253 return -1; 3254 3255 num_entries++; 3256 3257 switch(tagtype) { 3258 case SMB_ACL_USER_OBJ: 3259 perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR); 3260 break; 3261 case SMB_ACL_GROUP_OBJ: 3262 perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP); 3263 break; 3264 case SMB_ACL_MASK: 3265 /* 3266 * FIXME: The ACL_MASK entry permissions should really be set to 3267 * the union of the permissions of all ACL_USER, 3268 * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what 3269 * acl_calc_mask() does, but Samba ACLs doesn't provide it. 3270 */ 3271 perms = S_IRUSR|S_IWUSR|S_IXUSR; 3272 break; 3273 case SMB_ACL_OTHER: 3274 perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH); 3275 break; 3276 default: 3277 continue; 3278 } 3279 3280 if (map_acl_perms_to_permset(conn, perms, &permset) == -1) 3281 return -1; 3282 3283 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) == -1) 3284 return -1; 3285 } 3286 3287 /* 3288 * If this is a simple 3 element ACL or no elements then it's a standard 3289 * UNIX permission set. Just use chmod... 3290 */ 3291 3292 if ((num_entries == 3) || (num_entries == 0)) 3293 return -1; 3294 3295 return 0; 3296} 3297 3298/**************************************************************************** 3299 Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ, 3300 GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the 3301 resulting ACL on TO. Note that name is in UNIX character set. 3302****************************************************************************/ 3303 3304static int copy_access_acl(connection_struct *conn, const char *from, const char *to, mode_t mode) 3305{ 3306 SMB_ACL_T posix_acl = NULL; 3307 int ret = -1; 3308 3309 if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL) 3310 return -1; 3311 3312 if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1) 3313 goto done; 3314 3315 ret = SMB_VFS_SYS_ACL_SET_FILE(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl); 3316 3317 done: 3318 3319 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl); 3320 return ret; 3321} 3322 3323/**************************************************************************** 3324 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL 3325 and set the mask to rwx. Needed to preserve complex ACLs set by NT. 3326 Note that name is in UNIX character set. 3327****************************************************************************/ 3328 3329int chmod_acl(connection_struct *conn, const char *name, mode_t mode) 3330{ 3331 return copy_access_acl(conn, name, name, mode); 3332} 3333 3334/**************************************************************************** 3335 If "inherit permissions" is set and the parent directory has no default 3336 ACL but it does have an Access ACL, inherit this Access ACL to file name. 3337****************************************************************************/ 3338 3339int inherit_access_acl(connection_struct *conn, const char *name, mode_t mode) 3340{ 3341 pstring dirname; 3342 pstrcpy(dirname, parent_dirname(name)); 3343 3344 if (!lp_inherit_perms(SNUM(conn)) || directory_has_default_acl(conn, dirname)) 3345 return 0; 3346 3347 return copy_access_acl(conn, dirname, name, mode); 3348} 3349 3350/**************************************************************************** 3351 Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL 3352 and set the mask to rwx. Needed to preserve complex ACLs set by NT. 3353****************************************************************************/ 3354 3355int fchmod_acl(files_struct *fsp, int fd, mode_t mode) 3356{ 3357 connection_struct *conn = fsp->conn; 3358 SMB_ACL_T posix_acl = NULL; 3359 int ret = -1; 3360 3361 if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fd)) == NULL) 3362 return -1; 3363 3364 if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1) 3365 goto done; 3366 3367 ret = SMB_VFS_SYS_ACL_SET_FD(fsp, fd, posix_acl); 3368 3369 done: 3370 3371 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl); 3372 return ret; 3373} 3374 3375/**************************************************************************** 3376 Check for an existing default POSIX ACL on a directory. 3377****************************************************************************/ 3378 3379BOOL directory_has_default_acl(connection_struct *conn, const char *fname) 3380{ 3381 SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT); 3382 BOOL has_acl = False; 3383 SMB_ACL_ENTRY_T entry; 3384 3385 if (def_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, def_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) { 3386 has_acl = True; 3387 } 3388 3389 if (def_acl) { 3390 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl); 3391 } 3392 return has_acl; 3393} 3394 3395/**************************************************************************** 3396 Map from wire type to permset. 3397****************************************************************************/ 3398 3399static BOOL unix_ex_wire_to_permset(connection_struct *conn, unsigned char wire_perm, SMB_ACL_PERMSET_T *p_permset) 3400{ 3401 if (wire_perm & ~(SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE)) { 3402 return False; 3403 } 3404 3405 if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) == -1) { 3406 return False; 3407 } 3408 3409 if (wire_perm & SMB_POSIX_ACL_READ) { 3410 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1) { 3411 return False; 3412 } 3413 } 3414 if (wire_perm & SMB_POSIX_ACL_WRITE) { 3415 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1) { 3416 return False; 3417 } 3418 } 3419 if (wire_perm & SMB_POSIX_ACL_EXECUTE) { 3420 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1) { 3421 return False; 3422 } 3423 } 3424 return True; 3425} 3426 3427/**************************************************************************** 3428 Map from wire type to tagtype. 3429****************************************************************************/ 3430 3431static BOOL unix_ex_wire_to_tagtype(unsigned char wire_tt, SMB_ACL_TAG_T *p_tt) 3432{ 3433 switch (wire_tt) { 3434 case SMB_POSIX_ACL_USER_OBJ: 3435 *p_tt = SMB_ACL_USER_OBJ; 3436 break; 3437 case SMB_POSIX_ACL_USER: 3438 *p_tt = SMB_ACL_USER; 3439 break; 3440 case SMB_POSIX_ACL_GROUP_OBJ: 3441 *p_tt = SMB_ACL_GROUP_OBJ; 3442 break; 3443 case SMB_POSIX_ACL_GROUP: 3444 *p_tt = SMB_ACL_GROUP; 3445 break; 3446 case SMB_POSIX_ACL_MASK: 3447 *p_tt = SMB_ACL_MASK; 3448 break; 3449 case SMB_POSIX_ACL_OTHER: 3450 *p_tt = SMB_ACL_OTHER; 3451 break; 3452 default: 3453 return False; 3454 } 3455 return True; 3456} 3457 3458/**************************************************************************** 3459 Create a new POSIX acl from wire permissions. 3460 FIXME ! How does the share mask/mode fit into this.... ? 3461****************************************************************************/ 3462 3463static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_acls, const char *pdata) 3464{ 3465 unsigned int i; 3466 SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, num_acls); 3467 3468 if (the_acl == NULL) { 3469 return NULL; 3470 } 3471 3472 for (i = 0; i < num_acls; i++) { 3473 SMB_ACL_ENTRY_T the_entry; 3474 SMB_ACL_PERMSET_T the_permset; 3475 SMB_ACL_TAG_T tag_type; 3476 3477 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) { 3478 DEBUG(0,("create_posix_acl_from_wire: Failed to create entry %u. (%s)\n", 3479 i, strerror(errno) )); 3480 goto fail; 3481 } 3482 3483 if (!unix_ex_wire_to_tagtype(CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), &tag_type)) { 3484 DEBUG(0,("create_posix_acl_from_wire: invalid wire tagtype %u on entry %u.\n", 3485 CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), i )); 3486 goto fail; 3487 } 3488 3489 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, tag_type) == -1) { 3490 DEBUG(0,("create_posix_acl_from_wire: Failed to set tagtype on entry %u. (%s)\n", 3491 i, strerror(errno) )); 3492 goto fail; 3493 } 3494 3495 /* Get the permset pointer from the new ACL entry. */ 3496 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) { 3497 DEBUG(0,("create_posix_acl_from_wire: Failed to get permset on entry %u. (%s)\n", 3498 i, strerror(errno) )); 3499 goto fail; 3500 } 3501 3502 /* Map from wire to permissions. */ 3503 if (!unix_ex_wire_to_permset(conn, CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+1), &the_permset)) { 3504 DEBUG(0,("create_posix_acl_from_wire: invalid permset %u on entry %u.\n", 3505 CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE) + 1), i )); 3506 goto fail; 3507 } 3508 3509 /* Now apply to the new ACL entry. */ 3510 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) { 3511 DEBUG(0,("create_posix_acl_from_wire: Failed to add permset on entry %u. (%s)\n", 3512 i, strerror(errno) )); 3513 goto fail; 3514 } 3515 3516 if (tag_type == SMB_ACL_USER) { 3517 uint32 uidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2); 3518 uid_t uid = (uid_t)uidval; 3519 if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&uid) == -1) { 3520 DEBUG(0,("create_posix_acl_from_wire: Failed to set uid %u on entry %u. (%s)\n", 3521 (unsigned int)uid, i, strerror(errno) )); 3522 goto fail; 3523 } 3524 } 3525 3526 if (tag_type == SMB_ACL_GROUP) { 3527 uint32 gidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2); 3528 gid_t gid = (uid_t)gidval; 3529 if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&gid) == -1) { 3530 DEBUG(0,("create_posix_acl_from_wire: Failed to set gid %u on entry %u. (%s)\n", 3531 (unsigned int)gid, i, strerror(errno) )); 3532 goto fail; 3533 } 3534 } 3535 } 3536 3537 return the_acl; 3538 3539 fail: 3540 3541 if (the_acl != NULL) { 3542 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl); 3543 } 3544 return NULL; 3545} 3546 3547/**************************************************************************** 3548 Calls from UNIX extensions - Default POSIX ACL set. 3549 If num_def_acls == 0 and not a directory just return. If it is a directory 3550 and num_def_acls == 0 then remove the default acl. Else set the default acl 3551 on the directory. 3552****************************************************************************/ 3553 3554BOOL set_unix_posix_default_acl(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, 3555 uint16 num_def_acls, const char *pdata) 3556{ 3557 SMB_ACL_T def_acl = NULL; 3558 3559 if (num_def_acls && !S_ISDIR(psbuf->st_mode)) { 3560 DEBUG(5,("set_unix_posix_default_acl: Can't set default ACL on non-directory file %s\n", fname )); 3561 errno = EISDIR; 3562 return False; 3563 } 3564 3565 if (!num_def_acls) { 3566 /* Remove the default ACL. */ 3567 if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fname) == -1) { 3568 DEBUG(5,("set_unix_posix_default_acl: acl_delete_def_file failed on directory %s (%s)\n", 3569 fname, strerror(errno) )); 3570 return False; 3571 } 3572 return True; 3573 } 3574 3575 if ((def_acl = create_posix_acl_from_wire(conn, num_def_acls, pdata)) == NULL) { 3576 return False; 3577 } 3578 3579 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT, def_acl) == -1) { 3580 DEBUG(5,("set_unix_posix_default_acl: acl_set_file failed on directory %s (%s)\n", 3581 fname, strerror(errno) )); 3582 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl); 3583 return False; 3584 } 3585 3586 DEBUG(10,("set_unix_posix_default_acl: set default acl for file %s\n", fname )); 3587 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl); 3588 return True; 3589} 3590 3591/**************************************************************************** 3592 Remove an ACL from a file. As we don't have acl_delete_entry() available 3593 we must read the current acl and copy all entries except MASK, USER and GROUP 3594 to a new acl, then set that. This (at least on Linux) causes any ACL to be 3595 removed. 3596 FIXME ! How does the share mask/mode fit into this.... ? 3597****************************************************************************/ 3598 3599static BOOL remove_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname) 3600{ 3601 SMB_ACL_T file_acl = NULL; 3602 int entry_id = SMB_ACL_FIRST_ENTRY; 3603 SMB_ACL_ENTRY_T entry; 3604 BOOL ret = False; 3605 /* Create a new ACL with only 3 entries, u/g/w. */ 3606 SMB_ACL_T new_file_acl = SMB_VFS_SYS_ACL_INIT(conn, 3); 3607 SMB_ACL_ENTRY_T user_ent = NULL; 3608 SMB_ACL_ENTRY_T group_ent = NULL; 3609 SMB_ACL_ENTRY_T other_ent = NULL; 3610 3611 if (new_file_acl == NULL) { 3612 DEBUG(5,("remove_posix_acl: failed to init new ACL with 3 entries for file %s.\n", fname)); 3613 return False; 3614 } 3615 3616 /* Now create the u/g/w entries. */ 3617 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &user_ent) == -1) { 3618 DEBUG(5,("remove_posix_acl: Failed to create user entry for file %s. (%s)\n", 3619 fname, strerror(errno) )); 3620 goto done; 3621 } 3622 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, user_ent, SMB_ACL_USER_OBJ) == -1) { 3623 DEBUG(5,("remove_posix_acl: Failed to set user entry for file %s. (%s)\n", 3624 fname, strerror(errno) )); 3625 goto done; 3626 } 3627 3628 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &group_ent) == -1) { 3629 DEBUG(5,("remove_posix_acl: Failed to create group entry for file %s. (%s)\n", 3630 fname, strerror(errno) )); 3631 goto done; 3632 } 3633 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, group_ent, SMB_ACL_GROUP_OBJ) == -1) { 3634 DEBUG(5,("remove_posix_acl: Failed to set group entry for file %s. (%s)\n", 3635 fname, strerror(errno) )); 3636 goto done; 3637 } 3638 3639 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &other_ent) == -1) { 3640 DEBUG(5,("remove_posix_acl: Failed to create other entry for file %s. (%s)\n", 3641 fname, strerror(errno) )); 3642 goto done; 3643 } 3644 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, other_ent, SMB_ACL_OTHER) == -1) { 3645 DEBUG(5,("remove_posix_acl: Failed to set other entry for file %s. (%s)\n", 3646 fname, strerror(errno) )); 3647 goto done; 3648 } 3649 3650 /* Get the current file ACL. */ 3651 if (fsp && fsp->fd != -1) { 3652 file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd); 3653 } else { 3654 file_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_ACCESS); 3655 } 3656 3657 if (file_acl == NULL) { 3658 /* This is only returned if an error occurred. Even for a file with 3659 no acl a u/g/w acl should be returned. */ 3660 DEBUG(5,("remove_posix_acl: failed to get ACL from file %s (%s).\n", 3661 fname, strerror(errno) )); 3662 goto done; 3663 } 3664 3665 while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, file_acl, entry_id, &entry) == 1) { 3666 SMB_ACL_TAG_T tagtype; 3667 SMB_ACL_PERMSET_T permset; 3668 3669 /* get_next... */ 3670 if (entry_id == SMB_ACL_FIRST_ENTRY) 3671 entry_id = SMB_ACL_NEXT_ENTRY; 3672 3673 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) { 3674 DEBUG(5,("remove_posix_acl: failed to get tagtype from ACL on file %s (%s).\n", 3675 fname, strerror(errno) )); 3676 goto done; 3677 } 3678 3679 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) { 3680 DEBUG(5,("remove_posix_acl: failed to get permset from ACL on file %s (%s).\n", 3681 fname, strerror(errno) )); 3682 goto done; 3683 } 3684 3685 if (tagtype == SMB_ACL_USER_OBJ) { 3686 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, user_ent, permset) == -1) { 3687 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n", 3688 fname, strerror(errno) )); 3689 } 3690 } else if (tagtype == SMB_ACL_GROUP_OBJ) { 3691 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, group_ent, permset) == -1) { 3692 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n", 3693 fname, strerror(errno) )); 3694 } 3695 } else if (tagtype == SMB_ACL_OTHER) { 3696 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, other_ent, permset) == -1) { 3697 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n", 3698 fname, strerror(errno) )); 3699 } 3700 } 3701 } 3702 3703 ret = True; 3704 3705 done: 3706 3707 if (file_acl) { 3708 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl); 3709 } 3710 if (new_file_acl) { 3711 SMB_VFS_SYS_ACL_FREE_ACL(conn, new_file_acl); 3712 } 3713 return ret; 3714} 3715 3716/**************************************************************************** 3717 Calls from UNIX extensions - POSIX ACL set. 3718 If num_def_acls == 0 then read/modify/write acl after removing all entries 3719 except SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER. 3720****************************************************************************/ 3721 3722BOOL set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname, uint16 num_acls, const char *pdata) 3723{ 3724 SMB_ACL_T file_acl = NULL; 3725 3726 if (!num_acls) { 3727 /* Remove the ACL from the file. */ 3728 return remove_posix_acl(conn, fsp, fname); 3729 } 3730 3731 if ((file_acl = create_posix_acl_from_wire(conn, num_acls, pdata)) == NULL) { 3732 return False; 3733 } 3734 3735 if (fsp && fsp->fd != -1) { 3736 /* The preferred way - use an open fd. */ 3737 if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fd, file_acl) == -1) { 3738 DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n", 3739 fname, strerror(errno) )); 3740 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl); 3741 return False; 3742 } 3743 } else { 3744 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, file_acl) == -1) { 3745 DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n", 3746 fname, strerror(errno) )); 3747 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl); 3748 return False; 3749 } 3750 } 3751 3752 DEBUG(10,("set_unix_posix_acl: set acl for file %s\n", fname )); 3753 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl); 3754 return True; 3755} 3756 3757/**************************************************************************** 3758 Check for POSIX group ACLs. If none use stat entry. 3759****************************************************************************/ 3760 3761static int check_posix_acl_group_write(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *psbuf) 3762{ 3763 extern struct current_user current_user; 3764 SMB_ACL_T posix_acl = NULL; 3765 int entry_id = SMB_ACL_FIRST_ENTRY; 3766 SMB_ACL_ENTRY_T entry; 3767 int i; 3768 int ret = -1; 3769 3770 if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, dname, SMB_ACL_TYPE_ACCESS)) == NULL) { 3771 goto check_stat; 3772 } 3773 3774 /* First ensure the group mask allows group read. */ 3775 while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) { 3776 SMB_ACL_TAG_T tagtype; 3777 SMB_ACL_PERMSET_T permset; 3778 3779 /* get_next... */ 3780 if (entry_id == SMB_ACL_FIRST_ENTRY) 3781 entry_id = SMB_ACL_NEXT_ENTRY; 3782 3783 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) { 3784 goto check_stat; 3785 } 3786 3787 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) { 3788 goto check_stat; 3789 } 3790 3791 switch(tagtype) { 3792 case SMB_ACL_MASK: 3793 if (!SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE)) { 3794 /* We don't have group write permission. */ 3795 ret = -1; /* Allow caller to check "other" permissions. */ 3796 goto done; 3797 } 3798 break; 3799 default: 3800 continue; 3801 } 3802 } 3803 3804 /* Now check all group entries. */ 3805 entry_id = SMB_ACL_FIRST_ENTRY; 3806 while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) { 3807 SMB_ACL_TAG_T tagtype; 3808 SMB_ACL_PERMSET_T permset; 3809 int have_write = -1; 3810 3811 /* get_next... */ 3812 if (entry_id == SMB_ACL_FIRST_ENTRY) 3813 entry_id = SMB_ACL_NEXT_ENTRY; 3814 3815 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) { 3816 goto check_stat; 3817 } 3818 3819 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) { 3820 goto check_stat; 3821 } 3822 3823 have_write = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE); 3824 if (have_write == -1) { 3825 goto check_stat; 3826 } 3827 3828 switch(tagtype) { 3829 case SMB_ACL_USER: 3830 { 3831 /* Check against current_user.uid. */ 3832 uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry); 3833 if (puid == NULL) { 3834 goto check_stat; 3835 } 3836 if (current_user.uid == *puid) { 3837 /* We're done now we have a uid match. */ 3838 ret = have_write; 3839 goto done; 3840 } 3841 } 3842 break; 3843 case SMB_ACL_GROUP: 3844 { 3845 gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry); 3846 if (pgid == NULL) { 3847 goto check_stat; 3848 } 3849 for (i = 0; i < current_user.ngroups; i++) { 3850 if (current_user.groups[i] == *pgid) { 3851 /* We're done now we have a gid match. */ 3852 ret = have_write; 3853 goto done; 3854 } 3855 } 3856 } 3857 break; 3858 default: 3859 continue; 3860 } 3861 } 3862 3863 3864 check_stat: 3865 3866 for (i = 0; i < current_user.ngroups; i++) { 3867 if (current_user.groups[i] == psbuf->st_gid) { 3868 ret = (psbuf->st_mode & S_IWGRP) ? 1 : 0; 3869 break; 3870 } 3871 } 3872 3873 done: 3874 3875 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl); 3876 return ret; 3877} 3878 3879/**************************************************************************** 3880 Actually emulate the in-kernel access checking for write access. We need 3881 this to successfully return ACCESS_DENIED on a file open for delete access. 3882****************************************************************************/ 3883 3884BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname) 3885{ 3886 extern struct current_user current_user; 3887 SMB_STRUCT_STAT sbuf; 3888 pstring dname; 3889 int ret; 3890 3891 pstrcpy(dname, parent_dirname(fname)); 3892 if(SMB_VFS_STAT(conn, dname, &sbuf) != 0) { 3893 return False; 3894 } 3895 if (!S_ISDIR(sbuf.st_mode)) { 3896 return False; 3897 } 3898 if (current_user.uid == 0) { 3899 /* I'm sorry sir, I didn't know you were root... */ 3900 return True; 3901 } 3902 3903 if (current_user.uid == sbuf.st_uid) { 3904 return (sbuf.st_mode & S_IWUSR) ? True : False; 3905 } 3906 3907#ifdef S_ISVTX 3908 /* sticky bit means delete only by owner or root. */ 3909 if (sbuf.st_mode & S_ISVTX) { 3910 SMB_STRUCT_STAT sbuf_file; 3911 if(SMB_VFS_STAT(conn, fname, &sbuf_file) != 0) { 3912 return False; 3913 } 3914 if (current_user.uid == sbuf_file.st_uid) { 3915 return True; 3916 } 3917 return False; 3918 } 3919#endif 3920 3921 /* Check group ownership. */ 3922 ret = check_posix_acl_group_write(conn, dname, &sbuf); 3923 if (ret == 0 || ret == 1) { 3924 return ret ? True : False; 3925 } 3926 3927 return (sbuf.st_mode & S_IWOTH) ? True : False; 3928} 3929