1To use this patch, run these commands for a successful build: 2 3 patch -p1 <patches/acls.diff 4 ./prepare-source 5 ./configure --enable-acl-support 6 make 7 8See the --acls (-A) option in the revised man page for a note on using this 9latest ACL-enabling patch to send files to an older ACL-enabled rsync. 10 11--- old/Makefile.in 12+++ new/Makefile.in 13@@ -26,15 +26,15 @@ VERSION=@VERSION@ 14 .SUFFIXES: 15 .SUFFIXES: .c .o 16 17-HEADERS=byteorder.h config.h errcode.h proto.h rsync.h lib/pool_alloc.h 18+HEADERS=byteorder.h config.h errcode.h proto.h rsync.h smb_acls.h lib/pool_alloc.h 19 LIBOBJ=lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o \ 20- lib/permstring.o lib/pool_alloc.o @LIBOBJS@ 21+ lib/permstring.o lib/pool_alloc.o lib/sysacls.o @LIBOBJS@ 22 ZLIBOBJ=zlib/deflate.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o \ 23 zlib/trees.o zlib/zutil.o zlib/adler32.o zlib/compress.o zlib/crc32.o 24 OBJS1=rsync.o generator.o receiver.o cleanup.o sender.o exclude.o util.o \ 25 main.o checksum.o match.o syscall.o log.o backup.o 26 OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o \ 27- fileio.o batch.o clientname.o chmod.o 28+ fileio.o batch.o clientname.o chmod.o acls.o 29 OBJS3=progress.o pipe.o 30 DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o 31 popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \ 32--- old/acls.c 33+++ new/acls.c 34@@ -0,0 +1,1098 @@ 35+/* 36+ * Handle passing Access Control Lists between systems. 37+ * 38+ * Copyright (C) 1996 Andrew Tridgell 39+ * Copyright (C) 1996 Paul Mackerras 40+ * Copyright (C) 2006 Wayne Davison 41+ * 42+ * This program is free software; you can redistribute it and/or modify 43+ * it under the terms of the GNU General Public License as published by 44+ * the Free Software Foundation; either version 2 of the License, or 45+ * (at your option) any later version. 46+ * 47+ * This program is distributed in the hope that it will be useful, 48+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 49+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 50+ * GNU General Public License for more details. 51+ * 52+ * You should have received a copy of the GNU General Public License along 53+ * with this program; if not, write to the Free Software Foundation, Inc., 54+ * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 55+ */ 56+ 57+#include "rsync.h" 58+#include "lib/sysacls.h" 59+ 60+#ifdef SUPPORT_ACLS 61+ 62+extern int dry_run; 63+extern int read_only; 64+extern int list_only; 65+extern int orig_umask; 66+extern int preserve_acls; 67+extern unsigned int file_struct_len; 68+ 69+/* === ACL structures === */ 70+ 71+typedef struct { 72+ id_t id; 73+ uchar access; 74+} id_access; 75+ 76+typedef struct { 77+ id_access *idas; 78+ int count; 79+} ida_entries; 80+ 81+#define NO_ENTRY ((uchar)0x80) 82+typedef struct rsync_acl { 83+ ida_entries users; 84+ ida_entries groups; 85+ /* These will be NO_ENTRY if there's no such entry. */ 86+ uchar user_obj; 87+ uchar group_obj; 88+ uchar mask; 89+ uchar other; 90+} rsync_acl; 91+ 92+typedef struct { 93+ rsync_acl racl; 94+ SMB_ACL_T sacl; 95+} acl_duo; 96+ 97+static const rsync_acl empty_rsync_acl = { 98+ {NULL, 0}, {NULL, 0}, NO_ENTRY, NO_ENTRY, NO_ENTRY, NO_ENTRY 99+}; 100+ 101+static item_list access_acl_list = EMPTY_ITEM_LIST; 102+static item_list default_acl_list = EMPTY_ITEM_LIST; 103+ 104+/* === Calculations on ACL types === */ 105+ 106+static const char *str_acl_type(SMB_ACL_TYPE_T type) 107+{ 108+ return type == SMB_ACL_TYPE_ACCESS ? "SMB_ACL_TYPE_ACCESS" 109+ : type == SMB_ACL_TYPE_DEFAULT ? "SMB_ACL_TYPE_DEFAULT" 110+ : "unknown SMB_ACL_TYPE_T"; 111+} 112+ 113+#define OTHER_TYPE(t) (SMB_ACL_TYPE_ACCESS+SMB_ACL_TYPE_DEFAULT-(t)) 114+#define BUMP_TYPE(t) ((t = OTHER_TYPE(t)) == SMB_ACL_TYPE_DEFAULT) 115+ 116+static int count_racl_entries(const rsync_acl *racl) 117+{ 118+ return racl->users.count + racl->groups.count 119+ + (racl->user_obj != NO_ENTRY) 120+ + (racl->group_obj != NO_ENTRY) 121+ + (racl->mask != NO_ENTRY) 122+ + (racl->other != NO_ENTRY); 123+} 124+ 125+static int calc_sacl_entries(const rsync_acl *racl) 126+{ 127+ /* A System ACL always gets user/group/other permission entries. */ 128+ return racl->users.count + racl->groups.count 129+#ifdef ACLS_NEED_MASK 130+ + 4; 131+#else 132+ + (racl->mask != NO_ENTRY) + 3; 133+#endif 134+} 135+ 136+/* Extracts and returns the permission bits from the ACL. This cannot be 137+ * called on an rsync_acl that has NO_ENTRY in any spot but the mask. */ 138+static int rsync_acl_get_perms(const rsync_acl *racl) 139+{ 140+ return (racl->user_obj << 6) 141+ + ((racl->mask != NO_ENTRY ? racl->mask : racl->group_obj) << 3) 142+ + racl->other; 143+} 144+ 145+/* Removes the permission-bit entries from the ACL because these 146+ * can be reconstructed from the file's mode. */ 147+static void rsync_acl_strip_perms(rsync_acl *racl) 148+{ 149+ racl->user_obj = NO_ENTRY; 150+ if (racl->mask == NO_ENTRY) 151+ racl->group_obj = NO_ENTRY; 152+ else { 153+ if (racl->group_obj == racl->mask) 154+ racl->group_obj = NO_ENTRY; 155+ racl->mask = NO_ENTRY; 156+ } 157+ racl->other = NO_ENTRY; 158+} 159+ 160+/* Given an empty rsync_acl, fake up the permission bits. */ 161+static void rsync_acl_fake_perms(rsync_acl *racl, mode_t mode) 162+{ 163+ racl->user_obj = (mode >> 6) & 7; 164+ racl->group_obj = (mode >> 3) & 7; 165+ racl->other = mode & 7; 166+} 167+ 168+/* === Rsync ACL functions === */ 169+ 170+static BOOL ida_entries_equal(const ida_entries *ial1, const ida_entries *ial2) 171+{ 172+ id_access *ida1, *ida2; 173+ int count = ial1->count; 174+ if (count != ial2->count) 175+ return False; 176+ ida1 = ial1->idas; 177+ ida2 = ial2->idas; 178+ for (; count--; ida1++, ida2++) { 179+ if (ida1->access != ida2->access || ida1->id != ida2->id) 180+ return False; 181+ } 182+ return True; 183+} 184+ 185+static BOOL rsync_acl_equal(const rsync_acl *racl1, const rsync_acl *racl2) 186+{ 187+ return racl1->user_obj == racl2->user_obj 188+ && racl1->group_obj == racl2->group_obj 189+ && racl1->mask == racl2->mask 190+ && racl1->other == racl2->other 191+ && ida_entries_equal(&racl1->users, &racl2->users) 192+ && ida_entries_equal(&racl1->groups, &racl2->groups); 193+} 194+ 195+/* Are the extended (non-permission-bit) entries equal? If so, the rest of 196+ * the ACL will be handled by the normal mode-preservation code. This is 197+ * only meaningful for access ACLs! Note: the 1st arg is a fully-populated 198+ * rsync_acl, but the 2nd parameter can be a condensed rsync_acl, which means 199+ * that it might have several of its permission objects set to NO_ENTRY. */ 200+static BOOL rsync_acl_equal_enough(const rsync_acl *racl1, 201+ const rsync_acl *racl2, mode_t m) 202+{ 203+ if ((racl1->mask ^ racl2->mask) & NO_ENTRY) 204+ return False; /* One has a mask and the other doesn't */ 205+ 206+ /* When there's a mask, the group_obj becomes an extended entry. */ 207+ if (racl1->mask != NO_ENTRY) { 208+ /* A condensed rsync_acl with a mask can only have no 209+ * group_obj when it was identical to the mask. This 210+ * means that it was also identical to the group attrs 211+ * from the mode. */ 212+ if (racl2->group_obj == NO_ENTRY) { 213+ if (racl1->group_obj != ((m >> 3) & 7)) 214+ return False; 215+ } else if (racl1->group_obj != racl2->group_obj) 216+ return False; 217+ } 218+ return ida_entries_equal(&racl1->users, &racl2->users) 219+ && ida_entries_equal(&racl1->groups, &racl2->groups); 220+} 221+ 222+static void rsync_acl_free(rsync_acl *racl) 223+{ 224+ if (racl->users.idas) 225+ free(racl->users.idas); 226+ if (racl->groups.idas) 227+ free(racl->groups.idas); 228+ *racl = empty_rsync_acl; 229+} 230+ 231+void free_acl(statx *sxp) 232+{ 233+ if (sxp->acc_acl) { 234+ rsync_acl_free(sxp->acc_acl); 235+ free(sxp->acc_acl); 236+ sxp->acc_acl = NULL; 237+ } 238+ if (sxp->def_acl) { 239+ rsync_acl_free(sxp->def_acl); 240+ free(sxp->def_acl); 241+ sxp->def_acl = NULL; 242+ } 243+} 244+ 245+static int id_access_sorter(const void *r1, const void *r2) 246+{ 247+ id_access *ida1 = (id_access *)r1; 248+ id_access *ida2 = (id_access *)r2; 249+ id_t rid1 = ida1->id, rid2 = ida2->id; 250+ return rid1 == rid2 ? 0 : rid1 < rid2 ? -1 : 1; 251+} 252+ 253+static void sort_ida_entries(ida_entries *idal) 254+{ 255+ if (!idal->count) 256+ return; 257+ qsort(idal->idas, idal->count, sizeof idal->idas[0], id_access_sorter); 258+} 259+ 260+/* Transfer the count id_access items out of the temp_ida_list into either 261+ * the users or groups ida_entries list in racl. */ 262+static void save_idas(item_list *temp_ida_list, rsync_acl *racl, SMB_ACL_TAG_T type) 263+{ 264+ id_access *idas; 265+ ida_entries *ent; 266+ 267+ if (temp_ida_list->count) { 268+ int cnt = temp_ida_list->count; 269+ id_access *temp_idas = temp_ida_list->items; 270+ if (!(idas = new_array(id_access, cnt))) 271+ out_of_memory("save_idas"); 272+ memcpy(idas, temp_idas, cnt * sizeof *temp_idas); 273+ } else 274+ idas = NULL; 275+ 276+ ent = type == SMB_ACL_USER ? &racl->users : &racl->groups; 277+ 278+ if (ent->count) { 279+ rprintf(FERROR, "save_idas: disjoint list found for type %d\n", type); 280+ exit_cleanup(RERR_UNSUPPORTED); 281+ } 282+ ent->count = temp_ida_list->count; 283+ ent->idas = idas; 284+ 285+ /* Truncate the temporary list now that its idas have been saved. */ 286+ temp_ida_list->count = 0; 287+} 288+ 289+/* === System ACLs === */ 290+ 291+/* Unpack system ACL -> rsync ACL verbatim. Return whether we succeeded. */ 292+static BOOL unpack_smb_acl(rsync_acl *racl, SMB_ACL_T sacl) 293+{ 294+ static item_list temp_ida_list = EMPTY_ITEM_LIST; 295+ SMB_ACL_TAG_T prior_list_type = 0; 296+ SMB_ACL_ENTRY_T entry; 297+ const char *errfun; 298+ int rc; 299+ 300+ errfun = "sys_acl_get_entry"; 301+ for (rc = sys_acl_get_entry(sacl, SMB_ACL_FIRST_ENTRY, &entry); 302+ rc == 1; 303+ rc = sys_acl_get_entry(sacl, SMB_ACL_NEXT_ENTRY, &entry)) { 304+ SMB_ACL_TAG_T tag_type; 305+ SMB_ACL_PERMSET_T permset; 306+ uchar access; 307+ void *qualifier; 308+ id_access *ida; 309+ if ((rc = sys_acl_get_tag_type(entry, &tag_type))) { 310+ errfun = "sys_acl_get_tag_type"; 311+ break; 312+ } 313+ if ((rc = sys_acl_get_permset(entry, &permset))) { 314+ errfun = "sys_acl_get_tag_type"; 315+ break; 316+ } 317+ access = (sys_acl_get_perm(permset, SMB_ACL_READ) ? 4 : 0) 318+ | (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? 2 : 0) 319+ | (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? 1 : 0); 320+ /* continue == done with entry; break == store in temporary ida list */ 321+ switch (tag_type) { 322+ case SMB_ACL_USER_OBJ: 323+ if (racl->user_obj == NO_ENTRY) 324+ racl->user_obj = access; 325+ else 326+ rprintf(FINFO, "unpack_smb_acl: warning: duplicate USER_OBJ entry ignored\n"); 327+ continue; 328+ case SMB_ACL_USER: 329+ break; 330+ case SMB_ACL_GROUP_OBJ: 331+ if (racl->group_obj == NO_ENTRY) 332+ racl->group_obj = access; 333+ else 334+ rprintf(FINFO, "unpack_smb_acl: warning: duplicate GROUP_OBJ entry ignored\n"); 335+ continue; 336+ case SMB_ACL_GROUP: 337+ break; 338+ case SMB_ACL_MASK: 339+ if (racl->mask == NO_ENTRY) 340+ racl->mask = access; 341+ else 342+ rprintf(FINFO, "unpack_smb_acl: warning: duplicate MASK entry ignored\n"); 343+ continue; 344+ case SMB_ACL_OTHER: 345+ if (racl->other == NO_ENTRY) 346+ racl->other = access; 347+ else 348+ rprintf(FINFO, "unpack_smb_acl: warning: duplicate OTHER entry ignored\n"); 349+ continue; 350+ default: 351+ rprintf(FINFO, "unpack_smb_acl: warning: entry with unrecognized tag type ignored\n"); 352+ continue; 353+ } 354+ if (!(qualifier = sys_acl_get_qualifier(entry))) { 355+ errfun = "sys_acl_get_tag_type"; 356+ rc = EINVAL; 357+ break; 358+ } 359+ if (tag_type != prior_list_type) { 360+ if (prior_list_type) 361+ save_idas(&temp_ida_list, racl, prior_list_type); 362+ prior_list_type = tag_type; 363+ } 364+ ida = EXPAND_ITEM_LIST(&temp_ida_list, id_access, -10); 365+ ida->id = *((id_t *)qualifier); 366+ ida->access = access; 367+ sys_acl_free_qualifier(qualifier, tag_type); 368+ } 369+ if (rc) { 370+ rsyserr(FERROR, errno, "unpack_smb_acl: %s()", errfun); 371+ rsync_acl_free(racl); 372+ return False; 373+ } 374+ if (prior_list_type) 375+ save_idas(&temp_ida_list, racl, prior_list_type); 376+ 377+ sort_ida_entries(&racl->users); 378+ sort_ida_entries(&racl->groups); 379+ 380+#ifdef ACLS_NEED_MASK 381+ if (!racl->users.count && !racl->groups.count && racl->mask != NO_ENTRY) { 382+ /* Throw away a superfluous mask, but mask off the 383+ * group perms with it first. */ 384+ racl->group_obj &= racl->mask; 385+ racl->mask = NO_ENTRY; 386+ } 387+#endif 388+ 389+ return True; 390+} 391+ 392+/* Synactic sugar for system calls */ 393+ 394+#define CALL_OR_ERROR(func,args,str) \ 395+ do { \ 396+ if (func args) { \ 397+ errfun = str; \ 398+ goto error_exit; \ 399+ } \ 400+ } while (0) 401+ 402+#define COE(func,args) CALL_OR_ERROR(func,args,#func) 403+#define COE2(func,args) CALL_OR_ERROR(func,args,NULL) 404+ 405+/* Store the permissions in the system ACL entry. */ 406+static int store_access_in_entry(uchar access, SMB_ACL_ENTRY_T entry) 407+{ 408+ const char *errfun = NULL; 409+ SMB_ACL_PERMSET_T permset; 410+ 411+ COE( sys_acl_get_permset,(entry, &permset) ); 412+ COE( sys_acl_clear_perms,(permset) ); 413+ if (access & 4) 414+ COE( sys_acl_add_perm,(permset, SMB_ACL_READ) ); 415+ if (access & 2) 416+ COE( sys_acl_add_perm,(permset, SMB_ACL_WRITE) ); 417+ if (access & 1) 418+ COE( sys_acl_add_perm,(permset, SMB_ACL_EXECUTE) ); 419+ COE( sys_acl_set_permset,(entry, permset) ); 420+ 421+ return 0; 422+ 423+ error_exit: 424+ rsyserr(FERROR, errno, "store_access_in_entry %s()", errfun); 425+ return -1; 426+} 427+ 428+/* Pack rsync ACL -> system ACL verbatim. Return whether we succeeded. */ 429+static BOOL pack_smb_acl(SMB_ACL_T *smb_acl, const rsync_acl *racl) 430+{ 431+#ifdef ACLS_NEED_MASK 432+ uchar mask_bits; 433+#endif 434+ size_t count; 435+ id_access *ida; 436+ const char *errfun = NULL; 437+ SMB_ACL_ENTRY_T entry; 438+ 439+ if (!(*smb_acl = sys_acl_init(calc_sacl_entries(racl)))) { 440+ rsyserr(FERROR, errno, "pack_smb_acl: sys_acl_init()"); 441+ return False; 442+ } 443+ 444+ COE( sys_acl_create_entry,(smb_acl, &entry) ); 445+ COE( sys_acl_set_tag_type,(entry, SMB_ACL_USER_OBJ) ); 446+ COE2( store_access_in_entry,(racl->user_obj & 7, entry) ); 447+ 448+ for (ida = racl->users.idas, count = racl->users.count; count--; ida++) { 449+ COE( sys_acl_create_entry,(smb_acl, &entry) ); 450+ COE( sys_acl_set_tag_type,(entry, SMB_ACL_USER) ); 451+ COE( sys_acl_set_qualifier,(entry, (void*)&ida->id) ); 452+ COE2( store_access_in_entry,(ida->access, entry) ); 453+ } 454+ 455+ COE( sys_acl_create_entry,(smb_acl, &entry) ); 456+ COE( sys_acl_set_tag_type,(entry, SMB_ACL_GROUP_OBJ) ); 457+ COE2( store_access_in_entry,(racl->group_obj & 7, entry) ); 458+ 459+ for (ida = racl->groups.idas, count = racl->groups.count; count--; ida++) { 460+ COE( sys_acl_create_entry,(smb_acl, &entry) ); 461+ COE( sys_acl_set_tag_type,(entry, SMB_ACL_GROUP) ); 462+ COE( sys_acl_set_qualifier,(entry, (void*)&ida->id) ); 463+ COE2( store_access_in_entry,(ida->access, entry) ); 464+ } 465+ 466+#ifdef ACLS_NEED_MASK 467+ mask_bits = racl->mask == NO_ENTRY ? racl->group_obj & 7 : racl->mask; 468+ COE( sys_acl_create_entry,(smb_acl, &entry) ); 469+ COE( sys_acl_set_tag_type,(entry, SMB_ACL_MASK) ); 470+ COE2( store_access_in_entry,(mask_bits, entry) ); 471+#else 472+ if (racl->mask != NO_ENTRY) { 473+ COE( sys_acl_create_entry,(smb_acl, &entry) ); 474+ COE( sys_acl_set_tag_type,(entry, SMB_ACL_MASK) ); 475+ COE2( store_access_in_entry,(racl->mask, entry) ); 476+ } 477+#endif 478+ 479+ COE( sys_acl_create_entry,(smb_acl, &entry) ); 480+ COE( sys_acl_set_tag_type,(entry, SMB_ACL_OTHER) ); 481+ COE2( store_access_in_entry,(racl->other & 7, entry) ); 482+ 483+#ifdef DEBUG 484+ if (sys_acl_valid(*smb_acl) < 0) 485+ rprintf(FERROR, "pack_smb_acl: warning: system says the ACL I packed is invalid\n"); 486+#endif 487+ 488+ return True; 489+ 490+ error_exit: 491+ if (errfun) { 492+ rsyserr(FERROR, errno, "pack_smb_acl %s()", errfun); 493+ } 494+ sys_acl_free_acl(*smb_acl); 495+ return False; 496+} 497+ 498+static int find_matching_rsync_acl(SMB_ACL_TYPE_T type, 499+ const item_list *racl_list, 500+ const rsync_acl *racl) 501+{ 502+ static int access_match = -1, default_match = -1; 503+ int *match = type == SMB_ACL_TYPE_ACCESS ? &access_match : &default_match; 504+ size_t count = racl_list->count; 505+ 506+ /* If this is the first time through or we didn't match the last 507+ * time, then start at the end of the list, which should be the 508+ * best place to start hunting. */ 509+ if (*match == -1) 510+ *match = racl_list->count - 1; 511+ while (count--) { 512+ rsync_acl *base = racl_list->items; 513+ if (rsync_acl_equal(base + *match, racl)) 514+ return *match; 515+ if (!(*match)--) 516+ *match = racl_list->count - 1; 517+ } 518+ 519+ *match = -1; 520+ return *match; 521+} 522+ 523+/* Return the Access Control List for the given filename. */ 524+int get_acl(const char *fname, statx *sxp) 525+{ 526+ SMB_ACL_TYPE_T type; 527+ 528+ if (S_ISLNK(sxp->st.st_mode)) 529+ return 0; 530+ 531+ type = SMB_ACL_TYPE_ACCESS; 532+ do { 533+ SMB_ACL_T sacl = sys_acl_get_file(fname, type); 534+ rsync_acl *racl = new(rsync_acl); 535+ 536+ if (!racl) 537+ out_of_memory("get_acl"); 538+ *racl = empty_rsync_acl; 539+ if (type == SMB_ACL_TYPE_ACCESS) 540+ sxp->acc_acl = racl; 541+ else 542+ sxp->def_acl = racl; 543+ 544+ if (sacl) { 545+ BOOL ok = unpack_smb_acl(racl, sacl); 546+ 547+ sys_acl_free_acl(sacl); 548+ if (!ok) { 549+ free_acl(sxp); 550+ return -1; 551+ } 552+ } else if (errno == ENOTSUP) { 553+ /* ACLs are not supported, so pretend we have a basic ACL. */ 554+ if (type == SMB_ACL_TYPE_ACCESS) 555+ rsync_acl_fake_perms(racl, sxp->st.st_mode); 556+ } else { 557+ rsyserr(FERROR, errno, "get_acl: sys_acl_get_file(%s, %s)", 558+ fname, str_acl_type(type)); 559+ free_acl(sxp); 560+ return -1; 561+ } 562+ } while (BUMP_TYPE(type) && S_ISDIR(sxp->st.st_mode)); 563+ 564+ return 0; 565+} 566+ 567+/* === Send functions === */ 568+ 569+/* The general strategy with the tag_type <-> character mapping is that 570+ * lowercase implies that no qualifier follows, where uppercase does. 571+ * A similar idiom for the ACL type (access or default) itself, but 572+ * lowercase in this instance means there's no ACL following, so the 573+ * ACL is a repeat, so the receiver should reuse the last of the same 574+ * type ACL. */ 575+ 576+/* Send the ida list over the file descriptor. */ 577+static void send_ida_entries(int f, const ida_entries *idal, char tag_char) 578+{ 579+ id_access *ida; 580+ size_t count = idal->count; 581+ for (ida = idal->idas; count--; ida++) { 582+ write_byte(f, tag_char); 583+ write_byte(f, ida->access); 584+ write_int(f, ida->id); 585+ /* FIXME: sorta wasteful: we should maybe buffer as 586+ * many ids as max(ACL_USER + ACL_GROUP) objects to 587+ * keep from making so many calls. */ 588+ if (tag_char == 'U') 589+ add_uid(ida->id); 590+ else 591+ add_gid(ida->id); 592+ } 593+} 594+ 595+/* Send an rsync ACL over the file descriptor. */ 596+static void send_rsync_acl(int f, const rsync_acl *racl) 597+{ 598+ size_t count = count_racl_entries(racl); 599+ write_int(f, count); 600+ if (racl->user_obj != NO_ENTRY) { 601+ write_byte(f, 'u'); 602+ write_byte(f, racl->user_obj); 603+ } 604+ send_ida_entries(f, &racl->users, 'U'); 605+ if (racl->group_obj != NO_ENTRY) { 606+ write_byte(f, 'g'); 607+ write_byte(f, racl->group_obj); 608+ } 609+ send_ida_entries(f, &racl->groups, 'G'); 610+ if (racl->mask != NO_ENTRY) { 611+ write_byte(f, 'm'); 612+ write_byte(f, racl->mask); 613+ } 614+ if (racl->other != NO_ENTRY) { 615+ write_byte(f, 'o'); 616+ write_byte(f, racl->other); 617+ } 618+} 619+ 620+/* Send the ACL from the statx structure down the indicated file descriptor. 621+ * This also frees the ACL data. */ 622+void send_acl(statx *sxp, int f) 623+{ 624+ SMB_ACL_TYPE_T type; 625+ rsync_acl *racl, *new_racl; 626+ item_list *racl_list; 627+ int ndx; 628+ 629+ if (S_ISLNK(sxp->st.st_mode)) 630+ return; 631+ 632+ type = SMB_ACL_TYPE_ACCESS; 633+ racl = sxp->acc_acl; 634+ racl_list = &access_acl_list; 635+ do { 636+ if (!racl) { 637+ racl = new(rsync_acl); 638+ if (!racl) 639+ out_of_memory("send_acl"); 640+ *racl = empty_rsync_acl; 641+ if (type == SMB_ACL_TYPE_ACCESS) { 642+ rsync_acl_fake_perms(racl, sxp->st.st_mode); 643+ sxp->acc_acl = racl; 644+ } else 645+ sxp->def_acl = racl; 646+ } 647+ 648+ /* Avoid sending values that can be inferred from other data, 649+ * but only when preserve_acls == 1 (it is 2 when we must be 650+ * backward compatible with older acls.diff versions). */ 651+ if (type == SMB_ACL_TYPE_ACCESS && preserve_acls == 1) 652+ rsync_acl_strip_perms(racl); 653+ if ((ndx = find_matching_rsync_acl(type, racl_list, racl)) != -1) { 654+ write_byte(f, type == SMB_ACL_TYPE_ACCESS ? 'a' : 'd'); 655+ write_int(f, ndx); 656+ } else { 657+ new_racl = EXPAND_ITEM_LIST(racl_list, rsync_acl, 1000); 658+ write_byte(f, type == SMB_ACL_TYPE_ACCESS ? 'A' : 'D'); 659+ send_rsync_acl(f, racl); 660+ *new_racl = *racl; 661+ *racl = empty_rsync_acl; 662+ } 663+ racl = sxp->def_acl; 664+ racl_list = &default_acl_list; 665+ } while (BUMP_TYPE(type) && S_ISDIR(sxp->st.st_mode)); 666+ 667+ free_acl(sxp); 668+} 669+ 670+/* === Receive functions === */ 671+ 672+static void receive_rsync_acl(rsync_acl *racl, int f, SMB_ACL_TYPE_T type) 673+{ 674+ static item_list temp_ida_list = EMPTY_ITEM_LIST; 675+ SMB_ACL_TAG_T tag_type = 0, prior_list_type = 0; 676+ uchar computed_mask_bits = 0; 677+ id_access *ida; 678+ size_t count; 679+ 680+ if (!(count = read_int(f))) 681+ return; 682+ 683+ while (count--) { 684+ char tag = read_byte(f); 685+ uchar access = read_byte(f); 686+ if (access & ~ (4 | 2 | 1)) { 687+ rprintf(FERROR, "receive_rsync_acl: bogus permset %o\n", 688+ access); 689+ exit_cleanup(RERR_STREAMIO); 690+ } 691+ switch (tag) { 692+ case 'u': 693+ if (racl->user_obj != NO_ENTRY) { 694+ rprintf(FERROR, "receive_rsync_acl: error: duplicate USER_OBJ entry\n"); 695+ exit_cleanup(RERR_STREAMIO); 696+ } 697+ racl->user_obj = access; 698+ continue; 699+ case 'U': 700+ tag_type = SMB_ACL_USER; 701+ break; 702+ case 'g': 703+ if (racl->group_obj != NO_ENTRY) { 704+ rprintf(FERROR, "receive_rsync_acl: error: duplicate GROUP_OBJ entry\n"); 705+ exit_cleanup(RERR_STREAMIO); 706+ } 707+ racl->group_obj = access; 708+ continue; 709+ case 'G': 710+ tag_type = SMB_ACL_GROUP; 711+ break; 712+ case 'm': 713+ if (racl->mask != NO_ENTRY) { 714+ rprintf(FERROR, "receive_rsync_acl: error: duplicate MASK entry\n"); 715+ exit_cleanup(RERR_STREAMIO); 716+ } 717+ racl->mask = access; 718+ continue; 719+ case 'o': 720+ if (racl->other != NO_ENTRY) { 721+ rprintf(FERROR, "receive_rsync_acl: error: duplicate OTHER entry\n"); 722+ exit_cleanup(RERR_STREAMIO); 723+ } 724+ racl->other = access; 725+ continue; 726+ default: 727+ rprintf(FERROR, "receive_rsync_acl: unknown tag %c\n", 728+ tag); 729+ exit_cleanup(RERR_STREAMIO); 730+ } 731+ if (tag_type != prior_list_type) { 732+ if (prior_list_type) 733+ save_idas(&temp_ida_list, racl, prior_list_type); 734+ prior_list_type = tag_type; 735+ } 736+ ida = EXPAND_ITEM_LIST(&temp_ida_list, id_access, -10); 737+ ida->access = access; 738+ ida->id = read_int(f); 739+ computed_mask_bits |= access; 740+ } 741+ if (prior_list_type) 742+ save_idas(&temp_ida_list, racl, prior_list_type); 743+ 744+ if (type == SMB_ACL_TYPE_DEFAULT) { 745+ /* Ensure that these are never unset. */ 746+ if (racl->user_obj == NO_ENTRY) 747+ racl->user_obj = 7; 748+ if (racl->group_obj == NO_ENTRY) 749+ racl->group_obj = 0; 750+ if (racl->other == NO_ENTRY) 751+ racl->other = 0; 752+ } 753+ 754+ if (!racl->users.count && !racl->groups.count) { 755+ /* If we received a superfluous mask, throw it away. */ 756+ if (racl->mask != NO_ENTRY) { 757+ /* Mask off the group perms with it first. */ 758+ racl->group_obj &= racl->mask | NO_ENTRY; 759+ racl->mask = NO_ENTRY; 760+ } 761+ } else if (racl->mask == NO_ENTRY) /* Must be non-empty with lists. */ 762+ racl->mask = computed_mask_bits | (racl->group_obj & 7); 763+} 764+ 765+/* Receive the ACL info the sender has included for this file-list entry. */ 766+void receive_acl(struct file_struct *file, int f) 767+{ 768+ SMB_ACL_TYPE_T type; 769+ item_list *racl_list; 770+ char *ndx_ptr; 771+ 772+ if (S_ISLNK(file->mode)) 773+ return; 774+ 775+ type = SMB_ACL_TYPE_ACCESS; 776+ racl_list = &access_acl_list; 777+ ndx_ptr = (char*)file + file_struct_len; 778+ do { 779+ char tag = read_byte(f); 780+ int ndx; 781+ 782+ if (tag == 'A' || tag == 'a') { 783+ if (type != SMB_ACL_TYPE_ACCESS) { 784+ rprintf(FERROR, "receive_acl %s: duplicate access ACL\n", 785+ f_name(file, NULL)); 786+ exit_cleanup(RERR_STREAMIO); 787+ } 788+ } else if (tag == 'D' || tag == 'd') { 789+ if (type == SMB_ACL_TYPE_ACCESS) { 790+ rprintf(FERROR, "receive_acl %s: expecting access ACL; got default\n", 791+ f_name(file, NULL)); 792+ exit_cleanup(RERR_STREAMIO); 793+ } 794+ } else { 795+ rprintf(FERROR, "receive_acl %s: unknown ACL type tag: %c\n", 796+ f_name(file, NULL), tag); 797+ exit_cleanup(RERR_STREAMIO); 798+ } 799+ if (tag == 'A' || tag == 'D') { 800+ acl_duo *duo_item; 801+ ndx = racl_list->count; 802+ duo_item = EXPAND_ITEM_LIST(racl_list, acl_duo, 1000); 803+ duo_item->racl = empty_rsync_acl; 804+ receive_rsync_acl(&duo_item->racl, f, type); 805+ duo_item->sacl = NULL; 806+ } else { 807+ ndx = read_int(f); 808+ if (ndx < 0 || (size_t)ndx >= racl_list->count) { 809+ rprintf(FERROR, "receive_acl %s: %s ACL index %d out of range\n", 810+ f_name(file, NULL), str_acl_type(type), ndx); 811+ exit_cleanup(RERR_STREAMIO); 812+ } 813+ } 814+ SIVAL(ndx_ptr, 0, ndx); 815+ racl_list = &default_acl_list; 816+ ndx_ptr += 4; 817+ } while (BUMP_TYPE(type) && S_ISDIR(file->mode)); 818+} 819+ 820+/* Turn the ACL data in statx into cached ACL data, setting the index 821+ * values in the file struct. */ 822+void cache_acl(struct file_struct *file, statx *sxp) 823+{ 824+ SMB_ACL_TYPE_T type; 825+ rsync_acl *racl; 826+ item_list *racl_list; 827+ char *ndx_ptr; 828+ int ndx; 829+ 830+ if (S_ISLNK(file->mode)) 831+ return; 832+ 833+ type = SMB_ACL_TYPE_ACCESS; 834+ racl = sxp->acc_acl; 835+ racl_list = &access_acl_list; 836+ ndx_ptr = (char*)file + file_struct_len; 837+ do { 838+ if (!racl) 839+ ndx = -1; 840+ else if ((ndx = find_matching_rsync_acl(type, racl_list, racl)) == -1) { 841+ acl_duo *new_duo; 842+ ndx = racl_list->count; 843+ new_duo = EXPAND_ITEM_LIST(racl_list, acl_duo, 1000); 844+ new_duo->racl = *racl; 845+ new_duo->sacl = NULL; 846+ *racl = empty_rsync_acl; 847+ } 848+ SIVAL(ndx_ptr, 0, ndx); 849+ racl = sxp->def_acl; 850+ racl_list = &default_acl_list; 851+ ndx_ptr += 4; 852+ } while (BUMP_TYPE(type) && S_ISDIR(sxp->st.st_mode)); 853+ 854+ free_acl(sxp); 855+} 856+ 857+static mode_t change_sacl_perms(SMB_ACL_T sacl, rsync_acl *racl, mode_t old_mode, mode_t mode) 858+{ 859+ SMB_ACL_ENTRY_T entry; 860+ const char *errfun; 861+ int rc; 862+ 863+ if (S_ISDIR(mode)) { 864+ /* If the sticky bit is going on, it's not safe to allow all 865+ * the new ACL to go into effect before it gets set. */ 866+#ifdef SMB_ACL_LOSES_SPECIAL_MODE_BITS 867+ if (mode & S_ISVTX) 868+ mode &= ~0077; 869+#else 870+ if (mode & S_ISVTX && !(old_mode & S_ISVTX)) 871+ mode &= ~0077; 872+ } else { 873+ /* If setuid or setgid is going off, it's not safe to allow all 874+ * the new ACL to go into effect before they get cleared. */ 875+ if ((old_mode & S_ISUID && !(mode & S_ISUID)) 876+ || (old_mode & S_ISGID && !(mode & S_ISGID))) 877+ mode &= ~0077; 878+#endif 879+ } 880+ 881+ errfun = "sys_acl_get_entry"; 882+ for (rc = sys_acl_get_entry(sacl, SMB_ACL_FIRST_ENTRY, &entry); 883+ rc == 1; 884+ rc = sys_acl_get_entry(sacl, SMB_ACL_NEXT_ENTRY, &entry)) { 885+ SMB_ACL_TAG_T tag_type; 886+ if ((rc = sys_acl_get_tag_type(entry, &tag_type))) { 887+ errfun = "sys_acl_get_tag_type"; 888+ break; 889+ } 890+ switch (tag_type) { 891+ case SMB_ACL_USER_OBJ: 892+ COE2( store_access_in_entry,((mode >> 6) & 7, entry) ); 893+ break; 894+ case SMB_ACL_GROUP_OBJ: 895+ /* group is only empty when identical to group perms. */ 896+ if (racl->group_obj != NO_ENTRY) 897+ break; 898+ COE2( store_access_in_entry,((mode >> 3) & 7, entry) ); 899+ break; 900+ case SMB_ACL_MASK: 901+#ifndef ACLS_NEED_MASK 902+ /* mask is only empty when we don't need it. */ 903+ if (racl->mask == NO_ENTRY) 904+ break; 905+#endif 906+ COE2( store_access_in_entry,((mode >> 3) & 7, entry) ); 907+ break; 908+ case SMB_ACL_OTHER: 909+ COE2( store_access_in_entry,(mode & 7, entry) ); 910+ break; 911+ } 912+ } 913+ if (rc) { 914+ error_exit: 915+ if (errfun) { 916+ rsyserr(FERROR, errno, "change_sacl_perms: %s()", 917+ errfun); 918+ } 919+ return (mode_t)~0; 920+ } 921+ 922+#ifdef SMB_ACL_LOSES_SPECIAL_MODE_BITS 923+ /* Ensure that chmod() will be called to restore any lost setid bits. */ 924+ if (old_mode & (S_ISUID | S_ISGID | S_ISVTX) 925+ && (old_mode & CHMOD_BITS) == (mode & CHMOD_BITS)) 926+ old_mode &= ~(S_ISUID | S_ISGID | S_ISVTX); 927+#endif 928+ 929+ /* Return the mode of the file on disk, as we will set them. */ 930+ return (old_mode & ~ACCESSPERMS) | (mode & ACCESSPERMS); 931+} 932+ 933+/* Set ACL on indicated filename. 934+ * 935+ * This sets extended access ACL entries and default ACL. If convenient, 936+ * it sets permission bits along with the access ACL and signals having 937+ * done so by modifying sxp->st.st_mode. 938+ * 939+ * Returns 1 for unchanged, 0 for changed, -1 for failed. Call this 940+ * with fname set to NULL to just check if the ACL is unchanged. */ 941+int set_acl(const char *fname, const struct file_struct *file, statx *sxp) 942+{ 943+ int unchanged = 1; 944+ SMB_ACL_TYPE_T type; 945+ char *ndx_ptr; 946+ 947+ if (!dry_run && (read_only || list_only)) { 948+ errno = EROFS; 949+ return -1; 950+ } 951+ 952+ if (S_ISLNK(file->mode)) 953+ return 1; 954+ 955+ type = SMB_ACL_TYPE_ACCESS; 956+ ndx_ptr = (char*)file + file_struct_len; 957+ do { 958+ acl_duo *duo_item; 959+ BOOL eq; 960+ int32 ndx = IVAL(ndx_ptr, 0); 961+ 962+ ndx_ptr += 4; 963+ 964+ if (type == SMB_ACL_TYPE_ACCESS) { 965+ if (ndx < 0 || (size_t)ndx >= access_acl_list.count) 966+ continue; 967+ duo_item = access_acl_list.items; 968+ duo_item += ndx; 969+ eq = sxp->acc_acl 970+ && rsync_acl_equal_enough(sxp->acc_acl, &duo_item->racl, file->mode); 971+ } else { 972+ if (ndx < 0 || (size_t)ndx >= default_acl_list.count) 973+ continue; 974+ duo_item = default_acl_list.items; 975+ duo_item += ndx; 976+ eq = sxp->def_acl 977+ && rsync_acl_equal(sxp->def_acl, &duo_item->racl); 978+ } 979+ if (eq) 980+ continue; 981+ if (!dry_run && fname) { 982+ if (type == SMB_ACL_TYPE_DEFAULT 983+ && duo_item->racl.user_obj == NO_ENTRY) { 984+ if (sys_acl_delete_def_file(fname) < 0) { 985+ rsyserr(FERROR, errno, "set_acl: sys_acl_delete_def_file(%s)", 986+ fname); 987+ unchanged = -1; 988+ continue; 989+ } 990+ } else { 991+ mode_t cur_mode = sxp->st.st_mode; 992+ if (!duo_item->sacl 993+ && !pack_smb_acl(&duo_item->sacl, &duo_item->racl)) { 994+ unchanged = -1; 995+ continue; 996+ } 997+ if (type == SMB_ACL_TYPE_ACCESS) { 998+ cur_mode = change_sacl_perms(duo_item->sacl, &duo_item->racl, 999+ cur_mode, file->mode); 1000+ if (cur_mode == (mode_t)~0) 1001+ continue; 1002+ } 1003+ if (sys_acl_set_file(fname, type, duo_item->sacl) < 0) { 1004+ rsyserr(FERROR, errno, "set_acl: sys_acl_set_file(%s, %s)", 1005+ fname, str_acl_type(type)); 1006+ unchanged = -1; 1007+ continue; 1008+ } 1009+ if (type == SMB_ACL_TYPE_ACCESS) 1010+ sxp->st.st_mode = cur_mode; 1011+ } 1012+ } 1013+ if (unchanged == 1) 1014+ unchanged = 0; 1015+ } while (BUMP_TYPE(type) && S_ISDIR(file->mode)); 1016+ 1017+ return unchanged; 1018+} 1019+ 1020+/* === Enumeration functions for uid mapping === */ 1021+ 1022+/* Context -- one and only one. Should be cycled through once on uid 1023+ * mapping and once on gid mapping. */ 1024+static item_list *_enum_racl_lists[] = { 1025+ &access_acl_list, &default_acl_list, NULL 1026+}; 1027+ 1028+static item_list **enum_racl_list = &_enum_racl_lists[0]; 1029+static int enum_ida_index = 0; 1030+static size_t enum_racl_index = 0; 1031+ 1032+/* This returns the next tag_type id from the given ACL for the next entry, 1033+ * or it returns 0 if there are no more tag_type ids in the acl. */ 1034+static id_t *next_ace_id(SMB_ACL_TAG_T tag_type, const rsync_acl *racl) 1035+{ 1036+ const ida_entries *idal = tag_type == SMB_ACL_USER ? &racl->users : &racl->groups; 1037+ if (enum_ida_index < idal->count) { 1038+ id_access *ida = &idal->idas[enum_ida_index++]; 1039+ return &ida->id; 1040+ } 1041+ enum_ida_index = 0; 1042+ return NULL; 1043+} 1044+ 1045+static id_t *next_acl_id(SMB_ACL_TAG_T tag_type, const item_list *racl_list) 1046+{ 1047+ for (; enum_racl_index < racl_list->count; enum_racl_index++) { 1048+ id_t *id; 1049+ acl_duo *duo_item = racl_list->items; 1050+ duo_item += enum_racl_index; 1051+ if ((id = next_ace_id(tag_type, &duo_item->racl)) != NULL) 1052+ return id; 1053+ } 1054+ enum_racl_index = 0; 1055+ return NULL; 1056+} 1057+ 1058+static id_t *next_acl_list_id(SMB_ACL_TAG_T tag_type) 1059+{ 1060+ for (; *enum_racl_list; enum_racl_list++) { 1061+ id_t *id = next_acl_id(tag_type, *enum_racl_list); 1062+ if (id) 1063+ return id; 1064+ } 1065+ enum_racl_list = &_enum_racl_lists[0]; 1066+ return NULL; 1067+} 1068+ 1069+id_t *next_acl_uid() 1070+{ 1071+ return next_acl_list_id(SMB_ACL_USER); 1072+} 1073+ 1074+id_t *next_acl_gid() 1075+{ 1076+ return next_acl_list_id(SMB_ACL_GROUP); 1077+} 1078+ 1079+/* This is used by dest_mode(). */ 1080+int default_perms_for_dir(const char *dir) 1081+{ 1082+ rsync_acl racl; 1083+ SMB_ACL_T sacl; 1084+ BOOL ok; 1085+ int perms; 1086+ 1087+ if (dir == NULL) 1088+ dir = "."; 1089+ perms = ACCESSPERMS & ~orig_umask; 1090+ /* Read the directory's default ACL. If it has none, this will successfully return an empty ACL. */ 1091+ sacl = sys_acl_get_file(dir, SMB_ACL_TYPE_DEFAULT); 1092+ if (sacl == NULL) { 1093+ /* Couldn't get an ACL. Darn. */ 1094+ switch (errno) { 1095+ case ENOTSUP: 1096+ /* ACLs are disabled. We could yell at the user to turn them on, but... */ 1097+ break; 1098+ case ENOENT: 1099+ if (dry_run) { 1100+ /* We're doing a dry run, so the containing directory 1101+ * wasn't actually created. Don't worry about it. */ 1102+ break; 1103+ } 1104+ /* Otherwise fall through. */ 1105+ default: 1106+ rprintf(FERROR, "default_perms_for_dir: sys_acl_get_file(%s, %s): %s, falling back on umask\n", 1107+ dir, str_acl_type(SMB_ACL_TYPE_DEFAULT), strerror(errno)); 1108+ } 1109+ return perms; 1110+ } 1111+ 1112+ /* Convert it. */ 1113+ racl = empty_rsync_acl; 1114+ ok = unpack_smb_acl(&racl, sacl); 1115+ sys_acl_free_acl(sacl); 1116+ if (!ok) { 1117+ rprintf(FERROR, "default_perms_for_dir: unpack_smb_acl failed, falling back on umask\n"); 1118+ return perms; 1119+ } 1120+ 1121+ /* Apply the permission-bit entries of the default ACL, if any. */ 1122+ if (racl.user_obj != NO_ENTRY) { 1123+ perms = rsync_acl_get_perms(&racl); 1124+ if (verbose > 2) 1125+ rprintf(FINFO, "got ACL-based default perms %o for directory %s\n", perms, dir); 1126+ } 1127+ 1128+ rsync_acl_free(&racl); 1129+ return perms; 1130+} 1131+ 1132+#endif /* SUPPORT_ACLS */ 1133--- old/backup.c 1134+++ new/backup.c 1135@@ -29,6 +29,7 @@ extern char *backup_suffix; 1136 extern char *backup_dir; 1137 1138 extern int am_root; 1139+extern int preserve_acls; 1140 extern int preserve_devices; 1141 extern int preserve_specials; 1142 extern int preserve_links; 1143@@ -94,7 +95,8 @@ path 1144 ****************************************************************************/ 1145 static int make_bak_dir(char *fullpath) 1146 { 1147- STRUCT_STAT st; 1148+ statx sx; 1149+ struct file_struct *file; 1150 char *rel = fullpath + backup_dir_len; 1151 char *end = rel + strlen(rel); 1152 char *p = end; 1153@@ -126,13 +128,24 @@ static int make_bak_dir(char *fullpath) 1154 if (p >= rel) { 1155 /* Try to transfer the directory settings of the 1156 * actual dir that the files are coming from. */ 1157- if (do_stat(rel, &st) < 0) { 1158+ if (do_stat(rel, &sx.st) < 0) { 1159 rsyserr(FERROR, errno, 1160 "make_bak_dir stat %s failed", 1161 full_fname(rel)); 1162 } else { 1163- do_lchown(fullpath, st.st_uid, st.st_gid); 1164- do_chmod(fullpath, st.st_mode); 1165+#ifdef SUPPORT_ACLS 1166+ sx.acc_acl = sx.def_acl = NULL; 1167+#endif 1168+ if (!(file = make_file(rel, NULL, NULL, 0, NO_FILTERS))) 1169+ continue; 1170+#ifdef SUPPORT_ACLS 1171+ if (preserve_acls) { 1172+ get_acl(rel, &sx); 1173+ cache_acl(file, &sx); 1174+ } 1175+#endif 1176+ set_file_attrs(fullpath, file, NULL, 0); 1177+ free(file); 1178 } 1179 } 1180 *p = '/'; 1181@@ -170,15 +183,18 @@ static int robust_move(char *src, char * 1182 * We will move the file to be deleted into a parallel directory tree. */ 1183 static int keep_backup(char *fname) 1184 { 1185- STRUCT_STAT st; 1186+ statx sx; 1187 struct file_struct *file; 1188 char *buf; 1189 int kept = 0; 1190 int ret_code; 1191 1192 /* return if no file to keep */ 1193- if (do_lstat(fname, &st) < 0) 1194+ if (do_lstat(fname, &sx.st) < 0) 1195 return 1; 1196+#ifdef SUPPORT_ACLS 1197+ sx.acc_acl = sx.def_acl = NULL; 1198+#endif 1199 1200 if (!(file = make_file(fname, NULL, NULL, 0, NO_FILTERS))) 1201 return 1; /* the file could have disappeared */ 1202@@ -186,6 +202,13 @@ static int keep_backup(char *fname) 1203 if (!(buf = get_backup_name(fname))) 1204 return 0; 1205 1206+#ifdef SUPPORT_ACLS 1207+ if (preserve_acls) { 1208+ get_acl(fname, &sx); 1209+ cache_acl(file, &sx); 1210+ } 1211+#endif 1212+ 1213 /* Check to see if this is a device file, or link */ 1214 if ((am_root && preserve_devices && IS_DEVICE(file->mode)) 1215 || (preserve_specials && IS_SPECIAL(file->mode))) { 1216@@ -254,7 +277,7 @@ static int keep_backup(char *fname) 1217 if (robust_move(fname, buf) != 0) { 1218 rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"", 1219 full_fname(fname), buf); 1220- } else if (st.st_nlink > 1) { 1221+ } else if (sx.st.st_nlink > 1) { 1222 /* If someone has hard-linked the file into the backup 1223 * dir, rename() might return success but do nothing! */ 1224 robust_unlink(fname); /* Just in case... */ 1225--- old/configure.in 1226+++ new/configure.in 1227@@ -515,6 +515,11 @@ if test x"$ac_cv_func_strcasecmp" = x"no 1228 AC_CHECK_LIB(resolv, strcasecmp) 1229 fi 1230 1231+AC_CHECK_FUNCS(aclsort) 1232+if test x"$ac_cv_func_aclsort" = x"no"; then 1233+ AC_CHECK_LIB(sec, aclsort) 1234+fi 1235+ 1236 dnl At the moment we don't test for a broken memcmp(), because all we 1237 dnl need to do is test for equality, not comparison, and it seems that 1238 dnl every platform has a memcmp that can do at least that. 1239@@ -779,6 +784,78 @@ AC_SUBST(OBJ_RESTORE) 1240 AC_SUBST(CC_SHOBJ_FLAG) 1241 AC_SUBST(BUILD_POPT) 1242 1243+AC_CHECK_HEADERS(sys/acl.h acl/libacl.h) 1244+AC_CHECK_FUNCS(_acl __acl _facl __facl) 1245+################################################# 1246+# check for ACL support 1247+ 1248+AC_MSG_CHECKING(whether to support ACLs) 1249+AC_ARG_ENABLE(acl-support, 1250+AC_HELP_STRING([--enable-acl-support], [Include ACL support (default=no)]), 1251+[ case "$enableval" in 1252+ yes) 1253+ 1254+ case "$host_os" in 1255+ *sysv5*) 1256+ AC_MSG_RESULT(Using UnixWare ACLs) 1257+ AC_DEFINE(HAVE_UNIXWARE_ACLS, 1, [true if you have UnixWare ACLs]) 1258+ ;; 1259+ *solaris*|*cygwin*) 1260+ AC_MSG_RESULT(Using solaris ACLs) 1261+ AC_DEFINE(HAVE_SOLARIS_ACLS, 1, [true if you have solaris ACLs]) 1262+ ;; 1263+ *hpux*) 1264+ AC_MSG_RESULT(Using HPUX ACLs) 1265+ AC_DEFINE(HAVE_HPUX_ACLS, 1, [true if you have HPUX ACLs]) 1266+ ;; 1267+ *irix*) 1268+ AC_MSG_RESULT(Using IRIX ACLs) 1269+ AC_DEFINE(HAVE_IRIX_ACLS, 1, [true if you have IRIX ACLs]) 1270+ ;; 1271+ *aix*) 1272+ AC_MSG_RESULT(Using AIX ACLs) 1273+ AC_DEFINE(HAVE_AIX_ACLS, 1, [true if you have AIX ACLs]) 1274+ ;; 1275+ *osf*) 1276+ AC_MSG_RESULT(Using Tru64 ACLs) 1277+ AC_DEFINE(HAVE_TRU64_ACLS, 1, [true if you have Tru64 ACLs]) 1278+ LIBS="$LIBS -lpacl" 1279+ ;; 1280+ *) 1281+ AC_MSG_RESULT(ACLs requested -- running tests) 1282+ AC_CHECK_LIB(acl,acl_get_file) 1283+ AC_CACHE_CHECK([for ACL support],samba_cv_HAVE_POSIX_ACLS,[ 1284+ AC_TRY_LINK([#include <sys/types.h> 1285+#include <sys/acl.h>], 1286+[ acl_t acl; int entry_id; acl_entry_t *entry_p; return acl_get_entry( acl, entry_id, entry_p);], 1287+samba_cv_HAVE_POSIX_ACLS=yes,samba_cv_HAVE_POSIX_ACLS=no)]) 1288+ AC_MSG_CHECKING(ACL test results) 1289+ if test x"$samba_cv_HAVE_POSIX_ACLS" = x"yes"; then 1290+ AC_MSG_RESULT(Using posix ACLs) 1291+ AC_DEFINE(HAVE_POSIX_ACLS, 1, [true if you have posix ACLs]) 1292+ AC_CACHE_CHECK([for acl_get_perm_np],samba_cv_HAVE_ACL_GET_PERM_NP,[ 1293+ AC_TRY_LINK([#include <sys/types.h> 1294+#include <sys/acl.h>], 1295+[ acl_permset_t permset_d; acl_perm_t perm; return acl_get_perm_np( permset_d, perm);], 1296+samba_cv_HAVE_ACL_GET_PERM_NP=yes,samba_cv_HAVE_ACL_GET_PERM_NP=no)]) 1297+ if test x"$samba_cv_HAVE_ACL_GET_PERM_NP" = x"yes"; then 1298+ AC_DEFINE(HAVE_ACL_GET_PERM_NP, 1, [true if you have acl_get_perm_np]) 1299+ fi 1300+ else 1301+ AC_MSG_ERROR(Failed to find ACL support) 1302+ fi 1303+ ;; 1304+ esac 1305+ ;; 1306+ *) 1307+ AC_MSG_RESULT(no) 1308+ AC_DEFINE(HAVE_NO_ACLS, 1, [true if you don't have ACLs]) 1309+ ;; 1310+ esac ], 1311+ AC_DEFINE(HAVE_NO_ACLS, 1, [true if you don't have ACLs]) 1312+ AC_MSG_RESULT(no) 1313+) 1314+ 1315 AC_CONFIG_FILES([Makefile lib/dummy zlib/dummy popt/dummy shconfig]) 1316 AC_OUTPUT 1317 1318--- old/flist.c 1319+++ new/flist.c 1320@@ -40,6 +40,7 @@ extern int filesfrom_fd; 1321 extern int one_file_system; 1322 extern int copy_dirlinks; 1323 extern int keep_dirlinks; 1324+extern int preserve_acls; 1325 extern int preserve_links; 1326 extern int preserve_hard_links; 1327 extern int preserve_devices; 1328@@ -133,6 +134,8 @@ static void list_file_entry(struct file_ 1329 1330 permstring(permbuf, f->mode); 1331 1332+ /* TODO: indicate '+' if the entry has an ACL. */ 1333+ 1334 #ifdef SUPPORT_LINKS 1335 if (preserve_links && S_ISLNK(f->mode)) { 1336 rprintf(FINFO, "%s %11.0f %s %s -> %s\n", 1337@@ -495,6 +498,9 @@ static struct file_struct *receive_file_ 1338 char thisname[MAXPATHLEN]; 1339 unsigned int l1 = 0, l2 = 0; 1340 int alloc_len, basename_len, dirname_len, linkname_len, sum_len; 1341+#ifdef SUPPORT_ACLS 1342+ int xtra_len; 1343+#endif 1344 OFF_T file_length; 1345 char *basename, *dirname, *bp; 1346 struct file_struct *file; 1347@@ -598,13 +604,27 @@ static struct file_struct *receive_file_ 1348 1349 sum_len = always_checksum && S_ISREG(mode) ? MD4_SUM_LENGTH : 0; 1350 1351+#ifdef SUPPORT_ACLS 1352+ /* We need one or two index int32s when we're preserving ACLs. */ 1353+ if (preserve_acls) 1354+ xtra_len = (S_ISDIR(mode) ? 2 : 1) * 4; 1355+ else 1356+ xtra_len = 0; 1357+#endif 1358+ 1359 alloc_len = file_struct_len + dirname_len + basename_len 1360+#ifdef SUPPORT_ACLS 1361+ + xtra_len 1362+#endif 1363 + linkname_len + sum_len; 1364 bp = pool_alloc(flist->file_pool, alloc_len, "receive_file_entry"); 1365 1366 file = (struct file_struct *)bp; 1367 memset(bp, 0, file_struct_len); 1368 bp += file_struct_len; 1369+#ifdef SUPPORT_ACLS 1370+ bp += xtra_len; 1371+#endif 1372 1373 file->modtime = modtime; 1374 file->length = file_length; 1375@@ -699,6 +719,11 @@ static struct file_struct *receive_file_ 1376 read_buf(f, sum, checksum_len); 1377 } 1378 1379+#ifdef SUPPORT_ACLS 1380+ if (preserve_acls) 1381+ receive_acl(file, f); 1382+#endif 1383+ 1384 return file; 1385 } 1386 1387@@ -949,6 +974,9 @@ static struct file_struct *send_file_nam 1388 unsigned short flags) 1389 { 1390 struct file_struct *file; 1391+#ifdef SUPPORT_ACLS 1392+ statx sx; 1393+#endif 1394 1395 file = make_file(fname, flist, stp, flags, 1396 f == -2 ? SERVER_FILTERS : ALL_FILTERS); 1397@@ -958,6 +986,15 @@ static struct file_struct *send_file_nam 1398 if (chmod_modes && !S_ISLNK(file->mode)) 1399 file->mode = tweak_mode(file->mode, chmod_modes); 1400 1401+#ifdef SUPPORT_ACLS 1402+ if (preserve_acls) { 1403+ sx.st.st_mode = file->mode; 1404+ sx.acc_acl = sx.def_acl = NULL; 1405+ if (get_acl(fname, &sx) < 0) 1406+ return NULL; 1407+ } 1408+#endif 1409+ 1410 maybe_emit_filelist_progress(flist->count + flist_count_offset); 1411 1412 flist_expand(flist); 1413@@ -965,6 +1002,15 @@ static struct file_struct *send_file_nam 1414 if (file->basename[0]) { 1415 flist->files[flist->count++] = file; 1416 send_file_entry(file, f); 1417+#ifdef SUPPORT_ACLS 1418+ if (preserve_acls) 1419+ send_acl(&sx, f); 1420+#endif 1421+ } else { 1422+#ifdef SUPPORT_ACLS 1423+ if (preserve_acls) 1424+ free_acl(&sx); 1425+#endif 1426 } 1427 return file; 1428 } 1429--- old/generator.c 1430+++ new/generator.c 1431@@ -35,6 +35,7 @@ extern int do_progress; 1432 extern int relative_paths; 1433 extern int implied_dirs; 1434 extern int keep_dirlinks; 1435+extern int preserve_acls; 1436 extern int preserve_links; 1437 extern int preserve_devices; 1438 extern int preserve_specials; 1439@@ -85,6 +86,7 @@ extern long block_size; /* "long" becaus 1440 extern int max_delete; 1441 extern int force_delete; 1442 extern int one_file_system; 1443+extern mode_t orig_umask; 1444 extern struct stats stats; 1445 extern dev_t filesystem_dev; 1446 extern char *backup_dir; 1447@@ -317,22 +319,27 @@ static void do_delete_pass(struct file_l 1448 rprintf(FINFO, " \r"); 1449 } 1450 1451-int unchanged_attrs(struct file_struct *file, STRUCT_STAT *st) 1452+int unchanged_attrs(struct file_struct *file, statx *sxp) 1453 { 1454 if (preserve_perms 1455- && (st->st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS)) 1456+ && (sxp->st.st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS)) 1457 return 0; 1458 1459- if (am_root && preserve_uid && st->st_uid != file->uid) 1460+ if (am_root && preserve_uid && sxp->st.st_uid != file->uid) 1461 return 0; 1462 1463- if (preserve_gid && file->gid != GID_NONE && st->st_gid != file->gid) 1464+ if (preserve_gid && file->gid != GID_NONE && sxp->st.st_gid != file->gid) 1465+ return 0; 1466+ 1467+#ifdef SUPPORT_ACLS 1468+ if (preserve_acls && set_acl(NULL, file, sxp) == 0) 1469 return 0; 1470+#endif 1471 1472 return 1; 1473 } 1474 1475-void itemize(struct file_struct *file, int ndx, int statret, STRUCT_STAT *st, 1476+void itemize(struct file_struct *file, int ndx, int statret, statx *sxp, 1477 int32 iflags, uchar fnamecmp_type, char *xname) 1478 { 1479 if (statret >= 0) { /* A from-dest-dir statret can == 1! */ 1480@@ -340,19 +347,23 @@ void itemize(struct file_struct *file, i 1481 : S_ISDIR(file->mode) ? !omit_dir_times 1482 : !S_ISLNK(file->mode); 1483 1484- if (S_ISREG(file->mode) && file->length != st->st_size) 1485+ if (S_ISREG(file->mode) && file->length != sxp->st.st_size) 1486 iflags |= ITEM_REPORT_SIZE; 1487 if ((iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !keep_time 1488 && (!(iflags & ITEM_XNAME_FOLLOWS) || *xname)) 1489- || (keep_time && cmp_time(file->modtime, st->st_mtime) != 0)) 1490+ || (keep_time && cmp_time(file->modtime, sxp->st.st_mtime) != 0)) 1491 iflags |= ITEM_REPORT_TIME; 1492- if ((file->mode & CHMOD_BITS) != (st->st_mode & CHMOD_BITS)) 1493+ if ((file->mode & CHMOD_BITS) != (sxp->st.st_mode & CHMOD_BITS)) 1494 iflags |= ITEM_REPORT_PERMS; 1495- if (preserve_uid && am_root && file->uid != st->st_uid) 1496+ if (preserve_uid && am_root && file->uid != sxp->st.st_uid) 1497 iflags |= ITEM_REPORT_OWNER; 1498 if (preserve_gid && file->gid != GID_NONE 1499- && st->st_gid != file->gid) 1500+ && sxp->st.st_gid != file->gid) 1501 iflags |= ITEM_REPORT_GROUP; 1502+#ifdef SUPPORT_ACLS 1503+ if (preserve_acls && set_acl(NULL, file, sxp) == 0) 1504+ iflags |= ITEM_REPORT_ACL; 1505+#endif 1506 } else 1507 iflags |= ITEM_IS_NEW; 1508 1509@@ -605,7 +616,7 @@ void check_for_finished_hlinks(int itemi 1510 * handling the file, -1 if no dest-linking occurred, or a non-negative 1511 * value if we found an alternate basis file. */ 1512 static int try_dests_reg(struct file_struct *file, char *fname, int ndx, 1513- char *cmpbuf, STRUCT_STAT *stp, int itemizing, 1514+ char *cmpbuf, statx *sxp, int itemizing, 1515 int maybe_ATTRS_REPORT, enum logcode code) 1516 { 1517 int best_match = -1; 1518@@ -614,7 +625,7 @@ static int try_dests_reg(struct file_str 1519 1520 do { 1521 pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname); 1522- if (link_stat(cmpbuf, stp, 0) < 0 || !S_ISREG(stp->st_mode)) 1523+ if (link_stat(cmpbuf, &sxp->st, 0) < 0 || !S_ISREG(sxp->st.st_mode)) 1524 continue; 1525 switch (match_level) { 1526 case 0: 1527@@ -622,16 +633,20 @@ static int try_dests_reg(struct file_str 1528 match_level = 1; 1529 /* FALL THROUGH */ 1530 case 1: 1531- if (!unchanged_file(cmpbuf, file, stp)) 1532+ if (!unchanged_file(cmpbuf, file, &sxp->st)) 1533 continue; 1534 best_match = j; 1535 match_level = 2; 1536 /* FALL THROUGH */ 1537 case 2: 1538- if (!unchanged_attrs(file, stp)) 1539+#ifdef SUPPORT_ACLS 1540+ if (preserve_acls) 1541+ get_acl(cmpbuf, sxp); 1542+#endif 1543+ if (!unchanged_attrs(file, sxp)) 1544 continue; 1545 if (always_checksum && preserve_times 1546- && cmp_time(stp->st_mtime, file->modtime)) 1547+ && cmp_time(sxp->st.st_mtime, file->modtime)) 1548 continue; 1549 best_match = j; 1550 match_level = 3; 1551@@ -646,14 +661,14 @@ static int try_dests_reg(struct file_str 1552 if (j != best_match) { 1553 j = best_match; 1554 pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname); 1555- if (link_stat(cmpbuf, stp, 0) < 0) 1556+ if (link_stat(cmpbuf, &sxp->st, 0) < 0) 1557 return -1; 1558 } 1559 1560 if (match_level == 3 && !copy_dest) { 1561 #ifdef SUPPORT_HARD_LINKS 1562 if (link_dest) { 1563- if (hard_link_one(file, ndx, fname, 0, stp, 1564+ if (hard_link_one(file, ndx, fname, 0, sxp, 1565 cmpbuf, 1, 1566 itemizing && verbose > 1, 1567 code) < 0) 1568@@ -665,8 +680,13 @@ static int try_dests_reg(struct file_str 1569 } 1570 } else 1571 #endif 1572- if (itemizing) 1573- itemize(file, ndx, 0, stp, 0, 0, NULL); 1574+ if (itemizing) { 1575+#ifdef SUPPORT_ACLS 1576+ if (preserve_acls && !ACL_READY(*sxp)) 1577+ get_acl(fname, sxp); 1578+#endif 1579+ itemize(file, ndx, 0, sxp, 0, 0, NULL); 1580+ } 1581 if (verbose > 1 && maybe_ATTRS_REPORT) { 1582 rprintf(FCLIENT, "%s is uptodate\n", fname); 1583 } 1584@@ -682,8 +702,13 @@ static int try_dests_reg(struct file_str 1585 } 1586 return -1; 1587 } 1588- if (itemizing) 1589- itemize(file, ndx, 0, stp, ITEM_LOCAL_CHANGE, 0, NULL); 1590+ if (itemizing) { 1591+#ifdef SUPPORT_ACLS 1592+ if (preserve_acls && !ACL_READY(*sxp)) 1593+ get_acl(fname, sxp); 1594+#endif 1595+ itemize(file, ndx, 0, sxp, ITEM_LOCAL_CHANGE, 0, NULL); 1596+ } 1597 set_file_attrs(fname, file, NULL, 0); 1598 if (maybe_ATTRS_REPORT 1599 && ((!itemizing && verbose && match_level == 2) 1600@@ -707,13 +732,18 @@ static int try_dests_non(struct file_str 1601 enum logcode code) 1602 { 1603 char fnamebuf[MAXPATHLEN]; 1604- STRUCT_STAT st; 1605+ statx sx; 1606 int i = 0; 1607 1608 do { 1609 pathjoin(fnamebuf, MAXPATHLEN, basis_dir[i], fname); 1610- if (link_stat(fnamebuf, &st, 0) < 0 || S_ISDIR(st.st_mode) 1611- || !unchanged_attrs(file, &st)) 1612+ if (link_stat(fnamebuf, &sx.st, 0) < 0 || S_ISDIR(sx.st.st_mode)) 1613+ continue; 1614+#ifdef SUPPORT_ACLS 1615+ if (preserve_acls) 1616+ get_acl(fnamebuf, &sx); 1617+#endif 1618+ if (!unchanged_attrs(file, &sx)) 1619 continue; 1620 if (S_ISLNK(file->mode)) { 1621 #ifdef SUPPORT_LINKS 1622@@ -726,10 +756,10 @@ static int try_dests_non(struct file_str 1623 #endif 1624 continue; 1625 } else if (IS_SPECIAL(file->mode)) { 1626- if (!IS_SPECIAL(st.st_mode) || st.st_rdev != file->u.rdev) 1627+ if (!IS_SPECIAL(sx.st.st_mode) || sx.st.st_rdev != file->u.rdev) 1628 continue; 1629 } else if (IS_DEVICE(file->mode)) { 1630- if (!IS_DEVICE(st.st_mode) || st.st_rdev != file->u.rdev) 1631+ if (!IS_DEVICE(sx.st.st_mode) || sx.st.st_rdev != file->u.rdev) 1632 continue; 1633 } else { 1634 rprintf(FERROR, 1635@@ -760,7 +790,15 @@ static int try_dests_non(struct file_str 1636 int changes = compare_dest ? 0 : ITEM_LOCAL_CHANGE 1637 + (link_dest ? ITEM_XNAME_FOLLOWS : 0); 1638 char *lp = link_dest ? "" : NULL; 1639- itemize(file, ndx, 0, &st, changes, 0, lp); 1640+#ifdef SUPPORT_ACLS 1641+ if (preserve_acls) 1642+ get_acl(fname, &sx); 1643+#endif 1644+ itemize(file, ndx, 0, &sx, changes, 0, lp); 1645+#ifdef SUPPORT_ACLS 1646+ if (preserve_acls) 1647+ free_acl(&sx); 1648+#endif 1649 } 1650 if (verbose > 1 && maybe_ATTRS_REPORT) { 1651 rprintf(FCLIENT, "%s is uptodate\n", fname); 1652@@ -772,6 +810,7 @@ static int try_dests_non(struct file_str 1653 } 1654 1655 static int phase = 0; 1656+static int dflt_perms; 1657 1658 /* Acts on the_file_list->file's ndx'th item, whose name is fname. If a dir, 1659 * make sure it exists, and has the right permissions/timestamp info. For 1660@@ -793,7 +832,8 @@ static void recv_generator(char *fname, 1661 static int need_fuzzy_dirlist = 0; 1662 struct file_struct *fuzzy_file = NULL; 1663 int fd = -1, f_copy = -1; 1664- STRUCT_STAT st, real_st, partial_st; 1665+ statx sx, real_sx; 1666+ STRUCT_STAT partial_st; 1667 struct file_struct *back_file = NULL; 1668 int statret, real_ret, stat_errno; 1669 char *fnamecmp, *partialptr, *backupptr = NULL; 1670@@ -849,6 +889,9 @@ static void recv_generator(char *fname, 1671 } else if (!dry_run) 1672 return; 1673 } 1674+#ifdef SUPPORT_ACLS 1675+ sx.acc_acl = sx.def_acl = NULL; 1676+#endif 1677 if (dry_run > 1) { 1678 statret = -1; 1679 stat_errno = ENOENT; 1680@@ -856,7 +899,7 @@ static void recv_generator(char *fname, 1681 char *dn = file->dirname ? file->dirname : "."; 1682 if (parent_dirname != dn && strcmp(parent_dirname, dn) != 0) { 1683 if (relative_paths && !implied_dirs 1684- && do_stat(dn, &st) < 0 1685+ && do_stat(dn, &sx.st) < 0 1686 && create_directory_path(fname) < 0) { 1687 rsyserr(FERROR, errno, 1688 "recv_generator: mkdir %s failed", 1689@@ -868,6 +911,10 @@ static void recv_generator(char *fname, 1690 } 1691 if (fuzzy_basis) 1692 need_fuzzy_dirlist = 1; 1693+#ifdef SUPPORT_ACLS 1694+ if (!preserve_perms) 1695+ dflt_perms = default_perms_for_dir(dn); 1696+#endif 1697 } 1698 parent_dirname = dn; 1699 1700@@ -876,7 +923,7 @@ static void recv_generator(char *fname, 1701 need_fuzzy_dirlist = 0; 1702 } 1703 1704- statret = link_stat(fname, &st, 1705+ statret = link_stat(fname, &sx.st, 1706 keep_dirlinks && S_ISDIR(file->mode)); 1707 stat_errno = errno; 1708 } 1709@@ -894,8 +941,9 @@ static void recv_generator(char *fname, 1710 * mode based on the local permissions and some heuristics. */ 1711 if (!preserve_perms) { 1712 int exists = statret == 0 1713- && S_ISDIR(st.st_mode) == S_ISDIR(file->mode); 1714- file->mode = dest_mode(file->mode, st.st_mode, exists); 1715+ && S_ISDIR(sx.st.st_mode) == S_ISDIR(file->mode); 1716+ file->mode = dest_mode(file->mode, sx.st.st_mode, dflt_perms, 1717+ exists); 1718 } 1719 1720 if (S_ISDIR(file->mode)) { 1721@@ -904,8 +952,8 @@ static void recv_generator(char *fname, 1722 * file of that name and it is *not* a directory, then 1723 * we need to delete it. If it doesn't exist, then 1724 * (perhaps recursively) create it. */ 1725- if (statret == 0 && !S_ISDIR(st.st_mode)) { 1726- if (delete_item(fname, st.st_mode, del_opts) < 0) 1727+ if (statret == 0 && !S_ISDIR(sx.st.st_mode)) { 1728+ if (delete_item(fname, sx.st.st_mode, del_opts) < 0) 1729 return; 1730 statret = -1; 1731 } 1732@@ -920,7 +968,11 @@ static void recv_generator(char *fname, 1733 sr = -1; 1734 new_root_dir = 0; 1735 } 1736- itemize(file, ndx, sr, &st, 1737+#ifdef SUPPORT_ACLS 1738+ if (preserve_acls && sr == 0) 1739+ get_acl(fname, &sx); 1740+#endif 1741+ itemize(file, ndx, sr, &sx, 1742 sr ? ITEM_LOCAL_CHANGE : 0, 0, NULL); 1743 } 1744 if (statret != 0 && do_mkdir(fname,file->mode) < 0 && errno != EEXIST) { 1745@@ -940,19 +992,19 @@ static void recv_generator(char *fname, 1746 return; 1747 } 1748 } 1749- if (set_file_attrs(fname, file, statret ? NULL : &st, 0) 1750+ if (set_file_attrs(fname, file, statret ? NULL : &sx, 0) 1751 && verbose && code != FNONE && f_out != -1) 1752 rprintf(code, "%s/\n", fname); 1753 if (delete_during && f_out != -1 && !phase && dry_run < 2 1754 && (file->flags & FLAG_DEL_HERE)) 1755- delete_in_dir(the_file_list, fname, file, &st); 1756- return; 1757+ delete_in_dir(the_file_list, fname, file, &sx.st); 1758+ goto cleanup; 1759 } 1760 1761 if (preserve_hard_links && file->link_u.links 1762- && hard_link_check(file, ndx, fname, statret, &st, 1763+ && hard_link_check(file, ndx, fname, statret, &sx, 1764 itemizing, code, HL_CHECK_MASTER)) 1765- return; 1766+ goto cleanup; 1767 1768 if (preserve_links && S_ISLNK(file->mode)) { 1769 #ifdef SUPPORT_LINKS 1770@@ -970,7 +1022,7 @@ static void recv_generator(char *fname, 1771 char lnk[MAXPATHLEN]; 1772 int len; 1773 1774- if (!S_ISDIR(st.st_mode) 1775+ if (!S_ISDIR(sx.st.st_mode) 1776 && (len = readlink(fname, lnk, MAXPATHLEN-1)) > 0) { 1777 lnk[len] = 0; 1778 /* A link already pointing to the 1779@@ -978,10 +1030,10 @@ static void recv_generator(char *fname, 1780 * required. */ 1781 if (strcmp(lnk, file->u.link) == 0) { 1782 if (itemizing) { 1783- itemize(file, ndx, 0, &st, 0, 1784+ itemize(file, ndx, 0, &sx, 0, 1785 0, NULL); 1786 } 1787- set_file_attrs(fname, file, &st, 1788+ set_file_attrs(fname, file, &sx, 1789 maybe_ATTRS_REPORT); 1790 if (preserve_hard_links 1791 && file->link_u.links) { 1792@@ -996,9 +1048,9 @@ static void recv_generator(char *fname, 1793 } 1794 /* Not the right symlink (or not a symlink), so 1795 * delete it. */ 1796- if (delete_item(fname, st.st_mode, del_opts) < 0) 1797+ if (delete_item(fname, sx.st.st_mode, del_opts) < 0) 1798 return; 1799- if (!S_ISLNK(st.st_mode)) 1800+ if (!S_ISLNK(sx.st.st_mode)) 1801 statret = -1; 1802 } else if (basis_dir[0] != NULL) { 1803 if (try_dests_non(file, fname, ndx, itemizing, 1804@@ -1015,7 +1067,7 @@ static void recv_generator(char *fname, 1805 } 1806 } 1807 if (preserve_hard_links && file->link_u.links 1808- && hard_link_check(file, ndx, fname, -1, &st, 1809+ && hard_link_check(file, ndx, fname, -1, &sx, 1810 itemizing, code, HL_SKIP)) 1811 return; 1812 if (do_symlink(file->u.link,fname) != 0) { 1813@@ -1024,7 +1076,7 @@ static void recv_generator(char *fname, 1814 } else { 1815 set_file_attrs(fname, file, NULL, 0); 1816 if (itemizing) { 1817- itemize(file, ndx, statret, &st, 1818+ itemize(file, ndx, statret, &sx, 1819 ITEM_LOCAL_CHANGE, 0, NULL); 1820 } 1821 if (code != FNONE && verbose) { 1822@@ -1059,18 +1111,22 @@ static void recv_generator(char *fname, 1823 code = FNONE; 1824 } 1825 } 1826+#ifdef SUPPORT_ACLS 1827+ if (preserve_acls && statret == 0) 1828+ get_acl(fname, &sx); 1829+#endif 1830 if (statret != 0 1831- || (st.st_mode & ~CHMOD_BITS) != (file->mode & ~CHMOD_BITS) 1832- || st.st_rdev != file->u.rdev) { 1833+ || (sx.st.st_mode & ~CHMOD_BITS) != (file->mode & ~CHMOD_BITS) 1834+ || sx.st.st_rdev != file->u.rdev) { 1835 if (statret == 0 1836- && delete_item(fname, st.st_mode, del_opts) < 0) 1837- return; 1838+ && delete_item(fname, sx.st.st_mode, del_opts) < 0) 1839+ goto cleanup; 1840 if (preserve_hard_links && file->link_u.links 1841- && hard_link_check(file, ndx, fname, -1, &st, 1842+ && hard_link_check(file, ndx, fname, -1, &sx, 1843 itemizing, code, HL_SKIP)) 1844- return; 1845- if ((IS_DEVICE(file->mode) && !IS_DEVICE(st.st_mode)) 1846- || (IS_SPECIAL(file->mode) && !IS_SPECIAL(st.st_mode))) 1847+ goto cleanup; 1848+ if ((IS_DEVICE(file->mode) && !IS_DEVICE(sx.st.st_mode)) 1849+ || (IS_SPECIAL(file->mode) && !IS_SPECIAL(sx.st.st_mode))) 1850 statret = -1; 1851 if (verbose > 2) { 1852 rprintf(FINFO,"mknod(%s,0%o,0x%x)\n", 1853@@ -1083,7 +1139,7 @@ static void recv_generator(char *fname, 1854 } else { 1855 set_file_attrs(fname, file, NULL, 0); 1856 if (itemizing) { 1857- itemize(file, ndx, statret, &st, 1858+ itemize(file, ndx, statret, &sx, 1859 ITEM_LOCAL_CHANGE, 0, NULL); 1860 } 1861 if (code != FNONE && verbose) 1862@@ -1097,14 +1153,14 @@ static void recv_generator(char *fname, 1863 } 1864 } else { 1865 if (itemizing) 1866- itemize(file, ndx, statret, &st, 0, 0, NULL); 1867- set_file_attrs(fname, file, &st, maybe_ATTRS_REPORT); 1868+ itemize(file, ndx, statret, &sx, 0, 0, NULL); 1869+ set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT); 1870 if (preserve_hard_links && file->link_u.links) 1871 hard_link_cluster(file, ndx, itemizing, code); 1872 if (remove_source_files == 1) 1873 goto return_with_success; 1874 } 1875- return; 1876+ goto cleanup; 1877 } 1878 1879 if (!S_ISREG(file->mode)) { 1880@@ -1138,7 +1194,7 @@ static void recv_generator(char *fname, 1881 } 1882 1883 if (update_only && statret == 0 1884- && cmp_time(st.st_mtime, file->modtime) > 0) { 1885+ && cmp_time(sx.st.st_mtime, file->modtime) > 0) { 1886 if (verbose > 1) 1887 rprintf(FINFO, "%s is newer\n", fname); 1888 return; 1889@@ -1147,20 +1203,20 @@ static void recv_generator(char *fname, 1890 fnamecmp = fname; 1891 fnamecmp_type = FNAMECMP_FNAME; 1892 1893- if (statret == 0 && !S_ISREG(st.st_mode)) { 1894- if (delete_item(fname, st.st_mode, del_opts) != 0) 1895+ if (statret == 0 && !S_ISREG(sx.st.st_mode)) { 1896+ if (delete_item(fname, sx.st.st_mode, del_opts) != 0) 1897 return; 1898 statret = -1; 1899 stat_errno = ENOENT; 1900 } 1901 1902 if (statret != 0 && basis_dir[0] != NULL) { 1903- int j = try_dests_reg(file, fname, ndx, fnamecmpbuf, &st, 1904+ int j = try_dests_reg(file, fname, ndx, fnamecmpbuf, &sx, 1905 itemizing, maybe_ATTRS_REPORT, code); 1906 if (j == -2) { 1907 if (remove_source_files == 1) 1908 goto return_with_success; 1909- return; 1910+ goto cleanup; 1911 } 1912 if (j >= 0) { 1913 fnamecmp = fnamecmpbuf; 1914@@ -1170,7 +1226,7 @@ static void recv_generator(char *fname, 1915 } 1916 1917 real_ret = statret; 1918- real_st = st; 1919+ real_sx = sx; 1920 1921 if (partial_dir && (partialptr = partial_dir_fname(fname)) != NULL 1922 && link_stat(partialptr, &partial_st, 0) == 0 1923@@ -1189,7 +1245,7 @@ static void recv_generator(char *fname, 1924 rprintf(FINFO, "fuzzy basis selected for %s: %s\n", 1925 fname, fnamecmpbuf); 1926 } 1927- st.st_size = fuzzy_file->length; 1928+ sx.st.st_size = fuzzy_file->length; 1929 statret = 0; 1930 fnamecmp = fnamecmpbuf; 1931 fnamecmp_type = FNAMECMP_FUZZY; 1932@@ -1198,7 +1254,7 @@ static void recv_generator(char *fname, 1933 1934 if (statret != 0) { 1935 if (preserve_hard_links && file->link_u.links 1936- && hard_link_check(file, ndx, fname, statret, &st, 1937+ && hard_link_check(file, ndx, fname, statret, &sx, 1938 itemizing, code, HL_SKIP)) 1939 return; 1940 if (stat_errno == ENOENT) 1941@@ -1208,39 +1264,52 @@ static void recv_generator(char *fname, 1942 return; 1943 } 1944 1945- if (append_mode && st.st_size > file->length) 1946+ if (append_mode && sx.st.st_size > file->length) 1947 return; 1948 1949 if (fnamecmp_type <= FNAMECMP_BASIS_DIR_HIGH) 1950 ; 1951 else if (fnamecmp_type == FNAMECMP_FUZZY) 1952 ; 1953- else if (unchanged_file(fnamecmp, file, &st)) { 1954+ else if (unchanged_file(fnamecmp, file, &sx.st)) { 1955 if (partialptr) { 1956 do_unlink(partialptr); 1957 handle_partial_dir(partialptr, PDIR_DELETE); 1958 } 1959 if (itemizing) { 1960- itemize(file, ndx, real_ret, &real_st, 1961+#ifdef SUPPORT_ACLS 1962+ if (preserve_acls && real_ret == 0) 1963+ get_acl(fnamecmp, &real_sx); 1964+#endif 1965+ itemize(file, ndx, real_ret, &real_sx, 1966 0, 0, NULL); 1967+#ifdef SUPPORT_ACLS 1968+ if (preserve_acls) { 1969+ if (fnamecmp_type == FNAMECMP_FNAME) { 1970+ sx.acc_acl = real_sx.acc_acl; 1971+ sx.def_acl = real_sx.def_acl; 1972+ } else 1973+ free_acl(&real_sx); 1974+ } 1975+#endif 1976 } 1977- set_file_attrs(fname, file, &st, maybe_ATTRS_REPORT); 1978+ set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT); 1979 if (preserve_hard_links && file->link_u.links) 1980 hard_link_cluster(file, ndx, itemizing, code); 1981 if (remove_source_files != 1) 1982- return; 1983+ goto cleanup; 1984 return_with_success: 1985 if (!dry_run) { 1986 char numbuf[4]; 1987 SIVAL(numbuf, 0, ndx); 1988 send_msg(MSG_SUCCESS, numbuf, 4); 1989 } 1990- return; 1991+ goto cleanup; 1992 } 1993 1994 prepare_to_open: 1995 if (partialptr) { 1996- st = partial_st; 1997+ sx.st = partial_st; 1998 fnamecmp = partialptr; 1999 fnamecmp_type = FNAMECMP_PARTIAL_DIR; 2000 statret = 0; 2001@@ -1264,17 +1333,21 @@ static void recv_generator(char *fname, 2002 pretend_missing: 2003 /* pretend the file didn't exist */ 2004 if (preserve_hard_links && file->link_u.links 2005- && hard_link_check(file, ndx, fname, statret, &st, 2006+ && hard_link_check(file, ndx, fname, statret, &sx, 2007 itemizing, code, HL_SKIP)) 2008- return; 2009+ goto cleanup; 2010 statret = real_ret = -1; 2011+#ifdef SUPPORT_ACLS 2012+ if (preserve_acls && ACL_READY(sx)) 2013+ free_acl(&sx); 2014+#endif 2015 goto notify_others; 2016 } 2017 2018 if (inplace && make_backups && fnamecmp_type == FNAMECMP_FNAME) { 2019 if (!(backupptr = get_backup_name(fname))) { 2020 close(fd); 2021- return; 2022+ goto cleanup; 2023 } 2024 if (!(back_file = make_file(fname, NULL, NULL, 0, NO_FILTERS))) { 2025 close(fd); 2026@@ -1285,7 +1358,7 @@ static void recv_generator(char *fname, 2027 full_fname(backupptr)); 2028 free(back_file); 2029 close(fd); 2030- return; 2031+ goto cleanup; 2032 } 2033 if ((f_copy = do_open(backupptr, 2034 O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0) { 2035@@ -1293,14 +1366,14 @@ static void recv_generator(char *fname, 2036 full_fname(backupptr)); 2037 free(back_file); 2038 close(fd); 2039- return; 2040+ goto cleanup; 2041 } 2042 fnamecmp_type = FNAMECMP_BACKUP; 2043 } 2044 2045 if (verbose > 3) { 2046 rprintf(FINFO, "gen mapped %s of size %.0f\n", 2047- fnamecmp, (double)st.st_size); 2048+ fnamecmp, (double)sx.st.st_size); 2049 } 2050 2051 if (verbose > 2) 2052@@ -1318,24 +1391,32 @@ static void recv_generator(char *fname, 2053 iflags |= ITEM_BASIS_TYPE_FOLLOWS; 2054 if (fnamecmp_type == FNAMECMP_FUZZY) 2055 iflags |= ITEM_XNAME_FOLLOWS; 2056- itemize(file, -1, real_ret, &real_st, iflags, fnamecmp_type, 2057+#ifdef SUPPORT_ACLS 2058+ if (preserve_acls && real_ret == 0) 2059+ get_acl(fnamecmp, &real_sx); 2060+#endif 2061+ itemize(file, -1, real_ret, &real_sx, iflags, fnamecmp_type, 2062 fuzzy_file ? fuzzy_file->basename : NULL); 2063+#ifdef SUPPORT_ACLS 2064+ if (preserve_acls) 2065+ free_acl(&real_sx); 2066+#endif 2067 } 2068 2069 if (!do_xfers) { 2070 if (preserve_hard_links && file->link_u.links) 2071 hard_link_cluster(file, ndx, itemizing, code); 2072- return; 2073+ goto cleanup; 2074 } 2075 if (read_batch) 2076- return; 2077+ goto cleanup; 2078 2079 if (statret != 0 || whole_file) { 2080 write_sum_head(f_out, NULL); 2081- return; 2082+ goto cleanup; 2083 } 2084 2085- generate_and_send_sums(fd, st.st_size, f_out, f_copy); 2086+ generate_and_send_sums(fd, sx.st.st_size, f_out, f_copy); 2087 2088 if (f_copy >= 0) { 2089 close(f_copy); 2090@@ -1348,6 +1429,13 @@ static void recv_generator(char *fname, 2091 } 2092 2093 close(fd); 2094+ 2095+ cleanup: 2096+#ifdef SUPPORT_ACLS 2097+ if (preserve_acls) 2098+ free_acl(&sx); 2099+#endif 2100+ return; 2101 } 2102 2103 void generate_files(int f_out, struct file_list *flist, char *local_name) 2104@@ -1407,6 +1495,8 @@ void generate_files(int f_out, struct fi 2105 * notice that and let us know via the redo pipe (or its closing). */ 2106 ignore_timeout = 1; 2107 2108+ dflt_perms = (ACCESSPERMS & ~orig_umask); 2109+ 2110 for (i = 0; i < flist->count; i++) { 2111 struct file_struct *file = flist->files[i]; 2112 2113--- old/hlink.c 2114+++ new/hlink.c 2115@@ -26,6 +26,7 @@ 2116 extern int verbose; 2117 extern int do_xfers; 2118 extern int link_dest; 2119+extern int preserve_acls; 2120 extern int make_backups; 2121 extern int remove_source_files; 2122 extern int stdout_format_has_i; 2123@@ -147,15 +148,19 @@ void init_hard_links(void) 2124 2125 #ifdef SUPPORT_HARD_LINKS 2126 static int maybe_hard_link(struct file_struct *file, int ndx, 2127- char *fname, int statret, STRUCT_STAT *st, 2128+ char *fname, int statret, statx *sxp, 2129 char *toname, STRUCT_STAT *to_st, 2130 int itemizing, enum logcode code) 2131 { 2132 if (statret == 0) { 2133- if (st->st_dev == to_st->st_dev 2134- && st->st_ino == to_st->st_ino) { 2135+ if (sxp->st.st_dev == to_st->st_dev 2136+ && sxp->st.st_ino == to_st->st_ino) { 2137 if (itemizing) { 2138- itemize(file, ndx, statret, st, 2139+#ifdef SUPPORT_ACLS 2140+ if (preserve_acls && !ACL_READY(*sxp)) 2141+ get_acl(fname, sxp); 2142+#endif 2143+ itemize(file, ndx, statret, sxp, 2144 ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 2145 0, ""); 2146 } 2147@@ -170,13 +175,13 @@ static int maybe_hard_link(struct file_s 2148 return -1; 2149 } 2150 } 2151- return hard_link_one(file, ndx, fname, statret, st, toname, 2152+ return hard_link_one(file, ndx, fname, statret, sxp, toname, 2153 0, itemizing, code); 2154 } 2155 #endif 2156 2157 int hard_link_check(struct file_struct *file, int ndx, char *fname, 2158- int statret, STRUCT_STAT *st, int itemizing, 2159+ int statret, statx *sxp, int itemizing, 2160 enum logcode code, int skip) 2161 { 2162 #ifdef SUPPORT_HARD_LINKS 2163@@ -217,7 +222,7 @@ int hard_link_check(struct file_struct * 2164 || st2.st_ino != st3.st_ino) 2165 continue; 2166 statret = 1; 2167- st = &st3; 2168+ sxp->st = st3; 2169 if (verbose < 2 || !stdout_format_has_i) { 2170 itemizing = 0; 2171 code = FNONE; 2172@@ -227,12 +232,16 @@ int hard_link_check(struct file_struct * 2173 if (!unchanged_file(cmpbuf, file, &st3)) 2174 continue; 2175 statret = 1; 2176- st = &st3; 2177- if (unchanged_attrs(file, &st3)) 2178+ sxp->st = st3; 2179+#ifdef SUPPORT_ACLS 2180+ if (preserve_acls) 2181+ get_acl(cmpbuf, sxp); 2182+#endif 2183+ if (unchanged_attrs(file, sxp)) 2184 break; 2185 } while (basis_dir[++j] != NULL); 2186 } 2187- maybe_hard_link(file, ndx, fname, statret, st, 2188+ maybe_hard_link(file, ndx, fname, statret, sxp, 2189 toname, &st2, itemizing, code); 2190 if (remove_source_files == 1 && do_xfers) { 2191 char numbuf[4]; 2192@@ -250,7 +259,7 @@ int hard_link_check(struct file_struct * 2193 2194 #ifdef SUPPORT_HARD_LINKS 2195 int hard_link_one(struct file_struct *file, int ndx, char *fname, 2196- int statret, STRUCT_STAT *st, char *toname, int terse, 2197+ int statret, statx *sxp, char *toname, int terse, 2198 int itemizing, enum logcode code) 2199 { 2200 if (do_link(toname, fname)) { 2201@@ -266,7 +275,11 @@ int hard_link_one(struct file_struct *fi 2202 } 2203 2204 if (itemizing) { 2205- itemize(file, ndx, statret, st, 2206+#ifdef SUPPORT_ACLS 2207+ if (preserve_acls && statret == 0 && !ACL_READY(*sxp)) 2208+ get_acl(fname, sxp); 2209+#endif 2210+ itemize(file, ndx, statret, sxp, 2211 ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0, 2212 terse ? "" : toname); 2213 } 2214@@ -283,11 +296,12 @@ void hard_link_cluster(struct file_struc 2215 #ifdef SUPPORT_HARD_LINKS 2216 char hlink1[MAXPATHLEN]; 2217 char *hlink2; 2218- STRUCT_STAT st1, st2; 2219+ statx sx; 2220+ STRUCT_STAT st; 2221 int statret, ndx = master; 2222 2223 file->F_HLINDEX = FINISHED_LINK; 2224- if (link_stat(f_name(file, hlink1), &st1, 0) < 0) 2225+ if (link_stat(f_name(file, hlink1), &st, 0) < 0) 2226 return; 2227 if (!(file->flags & FLAG_HLINK_TOL)) { 2228 while (!(file->flags & FLAG_HLINK_EOL)) { 2229@@ -301,9 +315,13 @@ void hard_link_cluster(struct file_struc 2230 if (file->F_HLINDEX != SKIPPED_LINK) 2231 continue; 2232 hlink2 = f_name(file, NULL); 2233- statret = link_stat(hlink2, &st2, 0); 2234- maybe_hard_link(file, ndx, hlink2, statret, &st2, 2235- hlink1, &st1, itemizing, code); 2236+ statret = link_stat(hlink2, &sx.st, 0); 2237+ maybe_hard_link(file, ndx, hlink2, statret, &sx, 2238+ hlink1, &st, itemizing, code); 2239+#ifdef SUPPORT_ACLS 2240+ if (preserve_acls) 2241+ free_acl(&sx); 2242+#endif 2243 if (remove_source_files == 1 && do_xfers) { 2244 char numbuf[4]; 2245 SIVAL(numbuf, 0, ndx); 2246--- old/lib/sysacls.c 2247+++ new/lib/sysacls.c 2248@@ -0,0 +1,3251 @@ 2249+/* 2250+ Unix SMB/CIFS implementation. 2251+ Samba system utilities for ACL support. 2252+ Copyright (C) Jeremy Allison 2000. 2253+ 2254+ This program is free software; you can redistribute it and/or modify 2255+ it under the terms of the GNU General Public License as published by 2256+ the Free Software Foundation; either version 2 of the License, or 2257+ (at your option) any later version. 2258+ 2259+ This program is distributed in the hope that it will be useful, 2260+ but WITHOUT ANY WARRANTY; without even the implied warranty of 2261+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2262+ GNU General Public License for more details. 2263+ 2264+ You should have received a copy of the GNU General Public License 2265+ along with this program; if not, write to the Free Software 2266+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 2267+*/ 2268+ 2269+#include "rsync.h" 2270+#include "sysacls.h" /****** ADDED ******/ 2271+ 2272+#ifdef SUPPORT_ACLS 2273+ 2274+/****** EXTRAS -- THESE ITEMS ARE NOT FROM THE SAMBA SOURCE ******/ 2275+#ifdef DEBUG 2276+#undef DEBUG 2277+#endif 2278+#define DEBUG(x,y) 2279+ 2280+void SAFE_FREE(void *mem) 2281+{ 2282+ if (mem) 2283+ free(mem); 2284+} 2285+ 2286+char *uidtoname(uid_t uid) 2287+{ 2288+ static char idbuf[12]; 2289+ struct passwd *pw; 2290+ 2291+ if ((pw = getpwuid(uid)) == NULL) { 2292+ slprintf(idbuf, sizeof(idbuf)-1, "%ld", (long)uid); 2293+ return idbuf; 2294+ } 2295+ return pw->pw_name; 2296+} 2297+/****** EXTRAS -- END ******/ 2298+ 2299+/* 2300+ This file wraps all differing system ACL interfaces into a consistent 2301+ one based on the POSIX interface. It also returns the correct errors 2302+ for older UNIX systems that don't support ACLs. 2303+ 2304+ The interfaces that each ACL implementation must support are as follows : 2305+ 2306+ int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p) 2307+ int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p) 2308+ int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p 2309+ void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d) 2310+ SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type) 2311+ SMB_ACL_T sys_acl_get_fd(int fd) 2312+ int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset); 2313+ int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm); 2314+ char *sys_acl_to_text( SMB_ACL_T theacl, ssize_t *plen) 2315+ SMB_ACL_T sys_acl_init( int count) 2316+ int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry) 2317+ int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype) 2318+ int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual) 2319+ int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset) 2320+ int sys_acl_valid( SMB_ACL_T theacl ) 2321+ int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) 2322+ int sys_acl_set_fd( int fd, SMB_ACL_T theacl) 2323+ int sys_acl_delete_def_file(const char *path) 2324+ 2325+ This next one is not POSIX complient - but we *have* to have it ! 2326+ More POSIX braindamage. 2327+ 2328+ int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm) 2329+ 2330+ The generic POSIX free is the following call. We split this into 2331+ several different free functions as we may need to add tag info 2332+ to structures when emulating the POSIX interface. 2333+ 2334+ int sys_acl_free( void *obj_p) 2335+ 2336+ The calls we actually use are : 2337+ 2338+ int sys_acl_free_text(char *text) - free acl_to_text 2339+ int sys_acl_free_acl(SMB_ACL_T posix_acl) 2340+ int sys_acl_free_qualifier(void *qualifier, SMB_ACL_TAG_T tagtype) 2341+ 2342+*/ 2343+ 2344+#if defined(HAVE_POSIX_ACLS) 2345+ 2346+/* Identity mapping - easy. */ 2347+ 2348+int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p) 2349+{ 2350+ return acl_get_entry( the_acl, entry_id, entry_p); 2351+} 2352+ 2353+int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p) 2354+{ 2355+ return acl_get_tag_type( entry_d, tag_type_p); 2356+} 2357+ 2358+int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p) 2359+{ 2360+ return acl_get_permset( entry_d, permset_p); 2361+} 2362+ 2363+void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d) 2364+{ 2365+ return acl_get_qualifier( entry_d); 2366+} 2367+ 2368+SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type) 2369+{ 2370+ return acl_get_file( path_p, type); 2371+} 2372+ 2373+SMB_ACL_T sys_acl_get_fd(int fd) 2374+{ 2375+ return acl_get_fd(fd); 2376+} 2377+ 2378+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset) 2379+{ 2380+ return acl_clear_perms(permset); 2381+} 2382+ 2383+int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm) 2384+{ 2385+ return acl_add_perm(permset, perm); 2386+} 2387+ 2388+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm) 2389+{ 2390+#if defined(HAVE_ACL_GET_PERM_NP) 2391+ /* 2392+ * Required for TrustedBSD-based ACL implementations where 2393+ * non-POSIX.1e functions are denoted by a _np (non-portable) 2394+ * suffix. 2395+ */ 2396+ return acl_get_perm_np(permset, perm); 2397+#else 2398+ return acl_get_perm(permset, perm); 2399+#endif 2400+} 2401+ 2402+char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen) 2403+{ 2404+ return acl_to_text( the_acl, plen); 2405+} 2406+ 2407+SMB_ACL_T sys_acl_init( int count) 2408+{ 2409+ return acl_init(count); 2410+} 2411+ 2412+int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry) 2413+{ 2414+ return acl_create_entry(pacl, pentry); 2415+} 2416+ 2417+int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype) 2418+{ 2419+ return acl_set_tag_type(entry, tagtype); 2420+} 2421+ 2422+int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual) 2423+{ 2424+ return acl_set_qualifier(entry, qual); 2425+} 2426+ 2427+int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset) 2428+{ 2429+ return acl_set_permset(entry, permset); 2430+} 2431+ 2432+int sys_acl_valid( SMB_ACL_T theacl ) 2433+{ 2434+ return acl_valid(theacl); 2435+} 2436+ 2437+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) 2438+{ 2439+ return acl_set_file(name, acltype, theacl); 2440+} 2441+ 2442+int sys_acl_set_fd( int fd, SMB_ACL_T theacl) 2443+{ 2444+ return acl_set_fd(fd, theacl); 2445+} 2446+ 2447+int sys_acl_delete_def_file(const char *name) 2448+{ 2449+ return acl_delete_def_file(name); 2450+} 2451+ 2452+int sys_acl_free_text(char *text) 2453+{ 2454+ return acl_free(text); 2455+} 2456+ 2457+int sys_acl_free_acl(SMB_ACL_T the_acl) 2458+{ 2459+ return acl_free(the_acl); 2460+} 2461+ 2462+int sys_acl_free_qualifier(void *qual, UNUSED(SMB_ACL_TAG_T tagtype)) 2463+{ 2464+ return acl_free(qual); 2465+} 2466+ 2467+#elif defined(HAVE_TRU64_ACLS) 2468+/* 2469+ * The interface to DEC/Compaq Tru64 UNIX ACLs 2470+ * is based on Draft 13 of the POSIX spec which is 2471+ * slightly different from the Draft 16 interface. 2472+ * 2473+ * Also, some of the permset manipulation functions 2474+ * such as acl_clear_perm() and acl_add_perm() appear 2475+ * to be broken on Tru64 so we have to manipulate 2476+ * the permission bits in the permset directly. 2477+ */ 2478+int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p) 2479+{ 2480+ SMB_ACL_ENTRY_T entry; 2481+ 2482+ if (entry_id == SMB_ACL_FIRST_ENTRY && acl_first_entry(the_acl) != 0) { 2483+ return -1; 2484+ } 2485+ 2486+ errno = 0; 2487+ if ((entry = acl_get_entry(the_acl)) != NULL) { 2488+ *entry_p = entry; 2489+ return 1; 2490+ } 2491+ 2492+ return errno ? -1 : 0; 2493+} 2494+ 2495+int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p) 2496+{ 2497+ return acl_get_tag_type( entry_d, tag_type_p); 2498+} 2499+ 2500+int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p) 2501+{ 2502+ return acl_get_permset( entry_d, permset_p); 2503+} 2504+ 2505+void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d) 2506+{ 2507+ return acl_get_qualifier( entry_d); 2508+} 2509+ 2510+SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type) 2511+{ 2512+ return acl_get_file((char *)path_p, type); 2513+} 2514+ 2515+SMB_ACL_T sys_acl_get_fd(int fd) 2516+{ 2517+ return acl_get_fd(fd, ACL_TYPE_ACCESS); 2518+} 2519+ 2520+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset) 2521+{ 2522+ *permset = 0; /* acl_clear_perm() is broken on Tru64 */ 2523+ 2524+ return 0; 2525+} 2526+ 2527+int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm) 2528+{ 2529+ if (perm & ~(SMB_ACL_READ | SMB_ACL_WRITE | SMB_ACL_EXECUTE)) { 2530+ errno = EINVAL; 2531+ return -1; 2532+ } 2533+ 2534+ *permset |= perm; /* acl_add_perm() is broken on Tru64 */ 2535+ 2536+ return 0; 2537+} 2538+ 2539+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm) 2540+{ 2541+ return *permset & perm; /* Tru64 doesn't have acl_get_perm() */ 2542+} 2543+ 2544+char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen) 2545+{ 2546+ return acl_to_text( the_acl, plen); 2547+} 2548+ 2549+SMB_ACL_T sys_acl_init( int count) 2550+{ 2551+ return acl_init(count); 2552+} 2553+ 2554+int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry) 2555+{ 2556+ SMB_ACL_ENTRY_T entry; 2557+ 2558+ if ((entry = acl_create_entry(pacl)) == NULL) { 2559+ return -1; 2560+ } 2561+ 2562+ *pentry = entry; 2563+ return 0; 2564+} 2565+ 2566+int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype) 2567+{ 2568+ return acl_set_tag_type(entry, tagtype); 2569+} 2570+ 2571+int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual) 2572+{ 2573+ return acl_set_qualifier(entry, qual); 2574+} 2575+ 2576+int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset) 2577+{ 2578+ return acl_set_permset(entry, permset); 2579+} 2580+ 2581+int sys_acl_valid( SMB_ACL_T theacl ) 2582+{ 2583+ acl_entry_t entry; 2584+ 2585+ return acl_valid(theacl, &entry); 2586+} 2587+ 2588+int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) 2589+{ 2590+ return acl_set_file((char *)name, acltype, theacl); 2591+} 2592+ 2593+int sys_acl_set_fd( int fd, SMB_ACL_T theacl) 2594+{ 2595+ return acl_set_fd(fd, ACL_TYPE_ACCESS, theacl); 2596+} 2597+ 2598+int sys_acl_delete_def_file(const char *name) 2599+{ 2600+ return acl_delete_def_file((char *)name); 2601+} 2602+ 2603+int sys_acl_free_text(char *text) 2604+{ 2605+ /* 2606+ * (void) cast and explicit return 0 are for DEC UNIX 2607+ * which just #defines acl_free_text() to be free() 2608+ */ 2609+ (void) acl_free_text(text); 2610+ return 0; 2611+} 2612+ 2613+int sys_acl_free_acl(SMB_ACL_T the_acl) 2614+{ 2615+ return acl_free(the_acl); 2616+} 2617+ 2618+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype) 2619+{ 2620+ return acl_free_qualifier(qual, tagtype); 2621+} 2622+ 2623+#elif defined(HAVE_UNIXWARE_ACLS) || defined(HAVE_SOLARIS_ACLS) 2624+ 2625+/* 2626+ * Donated by Michael Davidson <md@sco.COM> for UnixWare / OpenUNIX. 2627+ * Modified by Toomas Soome <tsoome@ut.ee> for Solaris. 2628+ */ 2629+ 2630+/* 2631+ * Note that while this code implements sufficient functionality 2632+ * to support the sys_acl_* interfaces it does not provide all 2633+ * of the semantics of the POSIX ACL interfaces. 2634+ * 2635+ * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned 2636+ * from a call to sys_acl_get_entry() should not be assumed to be 2637+ * valid after calling any of the following functions, which may 2638+ * reorder the entries in the ACL. 2639+ * 2640+ * sys_acl_valid() 2641+ * sys_acl_set_file() 2642+ * sys_acl_set_fd() 2643+ */ 2644+ 2645+/* 2646+ * The only difference between Solaris and UnixWare / OpenUNIX is 2647+ * that the #defines for the ACL operations have different names 2648+ */ 2649+#if defined(HAVE_UNIXWARE_ACLS) 2650+ 2651+#define SETACL ACL_SET 2652+#define GETACL ACL_GET 2653+#define GETACLCNT ACL_CNT 2654+ 2655+#endif 2656+ 2657+ 2658+int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p) 2659+{ 2660+ if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) { 2661+ errno = EINVAL; 2662+ return -1; 2663+ } 2664+ 2665+ if (entry_p == NULL) { 2666+ errno = EINVAL; 2667+ return -1; 2668+ } 2669+ 2670+ if (entry_id == SMB_ACL_FIRST_ENTRY) { 2671+ acl_d->next = 0; 2672+ } 2673+ 2674+ if (acl_d->next < 0) { 2675+ errno = EINVAL; 2676+ return -1; 2677+ } 2678+ 2679+ if (acl_d->next >= acl_d->count) { 2680+ return 0; 2681+ } 2682+ 2683+ *entry_p = &acl_d->acl[acl_d->next++]; 2684+ 2685+ return 1; 2686+} 2687+ 2688+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p) 2689+{ 2690+ *type_p = entry_d->a_type; 2691+ 2692+ return 0; 2693+} 2694+ 2695+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p) 2696+{ 2697+ *permset_p = &entry_d->a_perm; 2698+ 2699+ return 0; 2700+} 2701+ 2702+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d) 2703+{ 2704+ if (entry_d->a_type != SMB_ACL_USER 2705+ && entry_d->a_type != SMB_ACL_GROUP) { 2706+ errno = EINVAL; 2707+ return NULL; 2708+ } 2709+ 2710+ return &entry_d->a_id; 2711+} 2712+ 2713+/* 2714+ * There is no way of knowing what size the ACL returned by 2715+ * GETACL will be unless you first call GETACLCNT which means 2716+ * making an additional system call. 2717+ * 2718+ * In the hope of avoiding the cost of the additional system 2719+ * call in most cases, we initially allocate enough space for 2720+ * an ACL with INITIAL_ACL_SIZE entries. If this turns out to 2721+ * be too small then we use GETACLCNT to find out the actual 2722+ * size, reallocate the ACL buffer, and then call GETACL again. 2723+ */ 2724+ 2725+#define INITIAL_ACL_SIZE 16 2726+ 2727+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type) 2728+{ 2729+ SMB_ACL_T acl_d; 2730+ int count; /* # of ACL entries allocated */ 2731+ int naccess; /* # of access ACL entries */ 2732+ int ndefault; /* # of default ACL entries */ 2733+ 2734+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) { 2735+ errno = EINVAL; 2736+ return NULL; 2737+ } 2738+ 2739+ count = INITIAL_ACL_SIZE; 2740+ if ((acl_d = sys_acl_init(count)) == NULL) { 2741+ return NULL; 2742+ } 2743+ 2744+ /* 2745+ * If there isn't enough space for the ACL entries we use 2746+ * GETACLCNT to determine the actual number of ACL entries 2747+ * reallocate and try again. This is in a loop because it 2748+ * is possible that someone else could modify the ACL and 2749+ * increase the number of entries between the call to 2750+ * GETACLCNT and the call to GETACL. 2751+ */ 2752+ while ((count = acl(path_p, GETACL, count, &acl_d->acl[0])) < 0 2753+ && errno == ENOSPC) { 2754+ 2755+ sys_acl_free_acl(acl_d); 2756+ 2757+ if ((count = acl(path_p, GETACLCNT, 0, NULL)) < 0) { 2758+ return NULL; 2759+ } 2760+ 2761+ if ((acl_d = sys_acl_init(count)) == NULL) { 2762+ return NULL; 2763+ } 2764+ } 2765+ 2766+ if (count < 0) { 2767+ sys_acl_free_acl(acl_d); 2768+ return NULL; 2769+ } 2770+ 2771+ /* 2772+ * calculate the number of access and default ACL entries 2773+ * 2774+ * Note: we assume that the acl() system call returned a 2775+ * well formed ACL which is sorted so that all of the 2776+ * access ACL entries preceed any default ACL entries 2777+ */ 2778+ for (naccess = 0; naccess < count; naccess++) { 2779+ if (acl_d->acl[naccess].a_type & ACL_DEFAULT) 2780+ break; 2781+ } 2782+ ndefault = count - naccess; 2783+ 2784+ /* 2785+ * if the caller wants the default ACL we have to copy 2786+ * the entries down to the start of the acl[] buffer 2787+ * and mask out the ACL_DEFAULT flag from the type field 2788+ */ 2789+ if (type == SMB_ACL_TYPE_DEFAULT) { 2790+ int i, j; 2791+ 2792+ for (i = 0, j = naccess; i < ndefault; i++, j++) { 2793+ acl_d->acl[i] = acl_d->acl[j]; 2794+ acl_d->acl[i].a_type &= ~ACL_DEFAULT; 2795+ } 2796+ 2797+ acl_d->count = ndefault; 2798+ } else { 2799+ acl_d->count = naccess; 2800+ } 2801+ 2802+ return acl_d; 2803+} 2804+ 2805+SMB_ACL_T sys_acl_get_fd(int fd) 2806+{ 2807+ SMB_ACL_T acl_d; 2808+ int count; /* # of ACL entries allocated */ 2809+ int naccess; /* # of access ACL entries */ 2810+ 2811+ count = INITIAL_ACL_SIZE; 2812+ if ((acl_d = sys_acl_init(count)) == NULL) { 2813+ return NULL; 2814+ } 2815+ 2816+ while ((count = facl(fd, GETACL, count, &acl_d->acl[0])) < 0 2817+ && errno == ENOSPC) { 2818+ 2819+ sys_acl_free_acl(acl_d); 2820+ 2821+ if ((count = facl(fd, GETACLCNT, 0, NULL)) < 0) { 2822+ return NULL; 2823+ } 2824+ 2825+ if ((acl_d = sys_acl_init(count)) == NULL) { 2826+ return NULL; 2827+ } 2828+ } 2829+ 2830+ if (count < 0) { 2831+ sys_acl_free_acl(acl_d); 2832+ return NULL; 2833+ } 2834+ 2835+ /* 2836+ * calculate the number of access ACL entries 2837+ */ 2838+ for (naccess = 0; naccess < count; naccess++) { 2839+ if (acl_d->acl[naccess].a_type & ACL_DEFAULT) 2840+ break; 2841+ } 2842+ 2843+ acl_d->count = naccess; 2844+ 2845+ return acl_d; 2846+} 2847+ 2848+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d) 2849+{ 2850+ *permset_d = 0; 2851+ 2852+ return 0; 2853+} 2854+ 2855+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm) 2856+{ 2857+ if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE 2858+ && perm != SMB_ACL_EXECUTE) { 2859+ errno = EINVAL; 2860+ return -1; 2861+ } 2862+ 2863+ if (permset_d == NULL) { 2864+ errno = EINVAL; 2865+ return -1; 2866+ } 2867+ 2868+ *permset_d |= perm; 2869+ 2870+ return 0; 2871+} 2872+ 2873+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm) 2874+{ 2875+ return *permset_d & perm; 2876+} 2877+ 2878+char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p) 2879+{ 2880+ int i; 2881+ int len, maxlen; 2882+ char *text; 2883+ 2884+ /* 2885+ * use an initial estimate of 20 bytes per ACL entry 2886+ * when allocating memory for the text representation 2887+ * of the ACL 2888+ */ 2889+ len = 0; 2890+ maxlen = 20 * acl_d->count; 2891+ if ((text = SMB_MALLOC(maxlen)) == NULL) { 2892+ errno = ENOMEM; 2893+ return NULL; 2894+ } 2895+ 2896+ for (i = 0; i < acl_d->count; i++) { 2897+ struct acl *ap = &acl_d->acl[i]; 2898+ struct group *gr; 2899+ char tagbuf[12]; 2900+ char idbuf[12]; 2901+ char *tag; 2902+ char *id = ""; 2903+ char perms[4]; 2904+ int nbytes; 2905+ 2906+ switch (ap->a_type) { 2907+ /* 2908+ * for debugging purposes it's probably more 2909+ * useful to dump unknown tag types rather 2910+ * than just returning an error 2911+ */ 2912+ default: 2913+ slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x", 2914+ ap->a_type); 2915+ tag = tagbuf; 2916+ slprintf(idbuf, sizeof(idbuf)-1, "%ld", 2917+ (long)ap->a_id); 2918+ id = idbuf; 2919+ break; 2920+ 2921+ case SMB_ACL_USER: 2922+ id = uidtoname(ap->a_id); 2923+ case SMB_ACL_USER_OBJ: 2924+ tag = "user"; 2925+ break; 2926+ 2927+ case SMB_ACL_GROUP: 2928+ if ((gr = getgrgid(ap->a_id)) == NULL) { 2929+ slprintf(idbuf, sizeof(idbuf)-1, "%ld", 2930+ (long)ap->a_id); 2931+ id = idbuf; 2932+ } else { 2933+ id = gr->gr_name; 2934+ } 2935+ case SMB_ACL_GROUP_OBJ: 2936+ tag = "group"; 2937+ break; 2938+ 2939+ case SMB_ACL_OTHER: 2940+ tag = "other"; 2941+ break; 2942+ 2943+ case SMB_ACL_MASK: 2944+ tag = "mask"; 2945+ break; 2946+ 2947+ } 2948+ 2949+ perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-'; 2950+ perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-'; 2951+ perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-'; 2952+ perms[3] = '\0'; 2953+ 2954+ /* <tag> : <qualifier> : rwx \n \0 */ 2955+ nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1; 2956+ 2957+ /* 2958+ * If this entry would overflow the buffer 2959+ * allocate enough additional memory for this 2960+ * entry and an estimate of another 20 bytes 2961+ * for each entry still to be processed 2962+ */ 2963+ if ((len + nbytes) > maxlen) { 2964+ char *oldtext = text; 2965+ 2966+ maxlen += nbytes + 20 * (acl_d->count - i); 2967+ 2968+ if ((text = SMB_REALLOC(oldtext, maxlen)) == NULL) { 2969+ SAFE_FREE(oldtext); 2970+ errno = ENOMEM; 2971+ return NULL; 2972+ } 2973+ } 2974+ 2975+ slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms); 2976+ len += nbytes - 1; 2977+ } 2978+ 2979+ if (len_p) 2980+ *len_p = len; 2981+ 2982+ return text; 2983+} 2984+ 2985+SMB_ACL_T sys_acl_init(int count) 2986+{ 2987+ SMB_ACL_T a; 2988+ 2989+ if (count < 0) { 2990+ errno = EINVAL; 2991+ return NULL; 2992+ } 2993+ 2994+ /* 2995+ * note that since the definition of the structure pointed 2996+ * to by the SMB_ACL_T includes the first element of the 2997+ * acl[] array, this actually allocates an ACL with room 2998+ * for (count+1) entries 2999+ */ 3000+ if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof(struct SMB_ACL_T) + count * sizeof(struct acl))) == NULL) { 3001+ errno = ENOMEM; 3002+ return NULL; 3003+ } 3004+ 3005+ a->size = count + 1; 3006+ a->count = 0; 3007+ a->next = -1; 3008+ 3009+ return a; 3010+} 3011+ 3012+ 3013+int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p) 3014+{ 3015+ SMB_ACL_T acl_d; 3016+ SMB_ACL_ENTRY_T entry_d; 3017+ 3018+ if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) { 3019+ errno = EINVAL; 3020+ return -1; 3021+ } 3022+ 3023+ if (acl_d->count >= acl_d->size) { 3024+ errno = ENOSPC; 3025+ return -1; 3026+ } 3027+ 3028+ entry_d = &acl_d->acl[acl_d->count++]; 3029+ entry_d->a_type = 0; 3030+ entry_d->a_id = -1; 3031+ entry_d->a_perm = 0; 3032+ *entry_p = entry_d; 3033+ 3034+ return 0; 3035+} 3036+ 3037+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type) 3038+{ 3039+ switch (tag_type) { 3040+ case SMB_ACL_USER: 3041+ case SMB_ACL_USER_OBJ: 3042+ case SMB_ACL_GROUP: 3043+ case SMB_ACL_GROUP_OBJ: 3044+ case SMB_ACL_OTHER: 3045+ case SMB_ACL_MASK: 3046+ entry_d->a_type = tag_type; 3047+ break; 3048+ default: 3049+ errno = EINVAL; 3050+ return -1; 3051+ } 3052+ 3053+ return 0; 3054+} 3055+ 3056+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p) 3057+{ 3058+ if (entry_d->a_type != SMB_ACL_GROUP 3059+ && entry_d->a_type != SMB_ACL_USER) { 3060+ errno = EINVAL; 3061+ return -1; 3062+ } 3063+ 3064+ entry_d->a_id = *((id_t *)qual_p); 3065+ 3066+ return 0; 3067+} 3068+ 3069+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d) 3070+{ 3071+ if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) { 3072+ return EINVAL; 3073+ } 3074+ 3075+ entry_d->a_perm = *permset_d; 3076+ 3077+ return 0; 3078+} 3079+ 3080+/* 3081+ * sort the ACL and check it for validity 3082+ * 3083+ * if it's a minimal ACL with only 4 entries then we 3084+ * need to recalculate the mask permissions to make 3085+ * sure that they are the same as the GROUP_OBJ 3086+ * permissions as required by the UnixWare acl() system call. 3087+ * 3088+ * (note: since POSIX allows minimal ACLs which only contain 3089+ * 3 entries - ie there is no mask entry - we should, in theory, 3090+ * check for this and add a mask entry if necessary - however 3091+ * we "know" that the caller of this interface always specifies 3092+ * a mask so, in practice "this never happens" (tm) - if it *does* 3093+ * happen aclsort() will fail and return an error and someone will 3094+ * have to fix it ...) 3095+ */ 3096+ 3097+static int acl_sort(SMB_ACL_T acl_d) 3098+{ 3099+ int fixmask = (acl_d->count <= 4); 3100+ 3101+ if (aclsort(acl_d->count, fixmask, acl_d->acl) != 0) { 3102+ errno = EINVAL; 3103+ return -1; 3104+ } 3105+ return 0; 3106+} 3107+ 3108+int sys_acl_valid(SMB_ACL_T acl_d) 3109+{ 3110+ return acl_sort(acl_d); 3111+} 3112+ 3113+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d) 3114+{ 3115+ struct stat s; 3116+ struct acl *acl_p; 3117+ int acl_count; 3118+ struct acl *acl_buf = NULL; 3119+ int ret; 3120+ 3121+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) { 3122+ errno = EINVAL; 3123+ return -1; 3124+ } 3125+ 3126+ if (acl_sort(acl_d) != 0) { 3127+ return -1; 3128+ } 3129+ 3130+ acl_p = &acl_d->acl[0]; 3131+ acl_count = acl_d->count; 3132+ 3133+ /* 3134+ * if it's a directory there is extra work to do 3135+ * since the acl() system call will replace both 3136+ * the access ACLs and the default ACLs (if any) 3137+ */ 3138+ if (stat(name, &s) != 0) { 3139+ return -1; 3140+ } 3141+ if (S_ISDIR(s.st_mode)) { 3142+ SMB_ACL_T acc_acl; 3143+ SMB_ACL_T def_acl; 3144+ SMB_ACL_T tmp_acl; 3145+ int i; 3146+ 3147+ if (type == SMB_ACL_TYPE_ACCESS) { 3148+ acc_acl = acl_d; 3149+ def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT); 3150+ 3151+ } else { 3152+ def_acl = acl_d; 3153+ acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS); 3154+ } 3155+ 3156+ if (tmp_acl == NULL) { 3157+ return -1; 3158+ } 3159+ 3160+ /* 3161+ * allocate a temporary buffer for the complete ACL 3162+ */ 3163+ acl_count = acc_acl->count + def_acl->count; 3164+ acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count); 3165+ 3166+ if (acl_buf == NULL) { 3167+ sys_acl_free_acl(tmp_acl); 3168+ errno = ENOMEM; 3169+ return -1; 3170+ } 3171+ 3172+ /* 3173+ * copy the access control and default entries into the buffer 3174+ */ 3175+ memcpy(&acl_buf[0], &acc_acl->acl[0], 3176+ acc_acl->count * sizeof(acl_buf[0])); 3177+ 3178+ memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0], 3179+ def_acl->count * sizeof(acl_buf[0])); 3180+ 3181+ /* 3182+ * set the ACL_DEFAULT flag on the default entries 3183+ */ 3184+ for (i = acc_acl->count; i < acl_count; i++) { 3185+ acl_buf[i].a_type |= ACL_DEFAULT; 3186+ } 3187+ 3188+ sys_acl_free_acl(tmp_acl); 3189+ 3190+ } else if (type != SMB_ACL_TYPE_ACCESS) { 3191+ errno = EINVAL; 3192+ return -1; 3193+ } 3194+ 3195+ ret = acl(name, SETACL, acl_count, acl_p); 3196+ 3197+ SAFE_FREE(acl_buf); 3198+ 3199+ return ret; 3200+} 3201+ 3202+int sys_acl_set_fd(int fd, SMB_ACL_T acl_d) 3203+{ 3204+ if (acl_sort(acl_d) != 0) { 3205+ return -1; 3206+ } 3207+ 3208+ return facl(fd, SETACL, acl_d->count, &acl_d->acl[0]); 3209+} 3210+ 3211+int sys_acl_delete_def_file(const char *path) 3212+{ 3213+ SMB_ACL_T acl_d; 3214+ int ret; 3215+ 3216+ /* 3217+ * fetching the access ACL and rewriting it has 3218+ * the effect of deleting the default ACL 3219+ */ 3220+ if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) { 3221+ return -1; 3222+ } 3223+ 3224+ ret = acl(path, SETACL, acl_d->count, acl_d->acl); 3225+ 3226+ sys_acl_free_acl(acl_d); 3227+ 3228+ return ret; 3229+} 3230+ 3231+int sys_acl_free_text(char *text) 3232+{ 3233+ SAFE_FREE(text); 3234+ return 0; 3235+} 3236+ 3237+int sys_acl_free_acl(SMB_ACL_T acl_d) 3238+{ 3239+ SAFE_FREE(acl_d); 3240+ return 0; 3241+} 3242+ 3243+int sys_acl_free_qualifier(UNUSED(void *qual), UNUSED(SMB_ACL_TAG_T tagtype)) 3244+{ 3245+ return 0; 3246+} 3247+ 3248+#elif defined(HAVE_HPUX_ACLS) 3249+#include <dl.h> 3250+ 3251+/* 3252+ * Based on the Solaris/SCO code - with modifications. 3253+ */ 3254+ 3255+/* 3256+ * Note that while this code implements sufficient functionality 3257+ * to support the sys_acl_* interfaces it does not provide all 3258+ * of the semantics of the POSIX ACL interfaces. 3259+ * 3260+ * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned 3261+ * from a call to sys_acl_get_entry() should not be assumed to be 3262+ * valid after calling any of the following functions, which may 3263+ * reorder the entries in the ACL. 3264+ * 3265+ * sys_acl_valid() 3266+ * sys_acl_set_file() 3267+ * sys_acl_set_fd() 3268+ */ 3269+ 3270+/* This checks if the POSIX ACL system call is defined */ 3271+/* which basically corresponds to whether JFS 3.3 or */ 3272+/* higher is installed. If acl() was called when it */ 3273+/* isn't defined, it causes the process to core dump */ 3274+/* so it is important to check this and avoid acl() */ 3275+/* calls if it isn't there. */ 3276+ 3277+static BOOL hpux_acl_call_presence(void) 3278+{ 3279+ 3280+ shl_t handle = NULL; 3281+ void *value; 3282+ int ret_val=0; 3283+ static BOOL already_checked=0; 3284+ 3285+ if(already_checked) 3286+ return True; 3287+ 3288+ 3289+ ret_val = shl_findsym(&handle, "acl", TYPE_PROCEDURE, &value); 3290+ 3291+ if(ret_val != 0) { 3292+ DEBUG(5, ("hpux_acl_call_presence: shl_findsym() returned %d, errno = %d, error %s\n", 3293+ ret_val, errno, strerror(errno))); 3294+ DEBUG(5,("hpux_acl_call_presence: acl() system call is not present. Check if you have JFS 3.3 and above?\n")); 3295+ return False; 3296+ } 3297+ 3298+ DEBUG(10,("hpux_acl_call_presence: acl() system call is present. We have JFS 3.3 or above \n")); 3299+ 3300+ already_checked = True; 3301+ return True; 3302+} 3303+ 3304+int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p) 3305+{ 3306+ if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) { 3307+ errno = EINVAL; 3308+ return -1; 3309+ } 3310+ 3311+ if (entry_p == NULL) { 3312+ errno = EINVAL; 3313+ return -1; 3314+ } 3315+ 3316+ if (entry_id == SMB_ACL_FIRST_ENTRY) { 3317+ acl_d->next = 0; 3318+ } 3319+ 3320+ if (acl_d->next < 0) { 3321+ errno = EINVAL; 3322+ return -1; 3323+ } 3324+ 3325+ if (acl_d->next >= acl_d->count) { 3326+ return 0; 3327+ } 3328+ 3329+ *entry_p = &acl_d->acl[acl_d->next++]; 3330+ 3331+ return 1; 3332+} 3333+ 3334+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p) 3335+{ 3336+ *type_p = entry_d->a_type; 3337+ 3338+ return 0; 3339+} 3340+ 3341+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p) 3342+{ 3343+ *permset_p = &entry_d->a_perm; 3344+ 3345+ return 0; 3346+} 3347+ 3348+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d) 3349+{ 3350+ if (entry_d->a_type != SMB_ACL_USER 3351+ && entry_d->a_type != SMB_ACL_GROUP) { 3352+ errno = EINVAL; 3353+ return NULL; 3354+ } 3355+ 3356+ return &entry_d->a_id; 3357+} 3358+ 3359+/* 3360+ * There is no way of knowing what size the ACL returned by 3361+ * ACL_GET will be unless you first call ACL_CNT which means 3362+ * making an additional system call. 3363+ * 3364+ * In the hope of avoiding the cost of the additional system 3365+ * call in most cases, we initially allocate enough space for 3366+ * an ACL with INITIAL_ACL_SIZE entries. If this turns out to 3367+ * be too small then we use ACL_CNT to find out the actual 3368+ * size, reallocate the ACL buffer, and then call ACL_GET again. 3369+ */ 3370+ 3371+#define INITIAL_ACL_SIZE 16 3372+ 3373+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type) 3374+{ 3375+ SMB_ACL_T acl_d; 3376+ int count; /* # of ACL entries allocated */ 3377+ int naccess; /* # of access ACL entries */ 3378+ int ndefault; /* # of default ACL entries */ 3379+ 3380+ if(hpux_acl_call_presence() == False) { 3381+ /* Looks like we don't have the acl() system call on HPUX. 3382+ * May be the system doesn't have the latest version of JFS. 3383+ */ 3384+ return NULL; 3385+ } 3386+ 3387+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) { 3388+ errno = EINVAL; 3389+ return NULL; 3390+ } 3391+ 3392+ count = INITIAL_ACL_SIZE; 3393+ if ((acl_d = sys_acl_init(count)) == NULL) { 3394+ return NULL; 3395+ } 3396+ 3397+ /* 3398+ * If there isn't enough space for the ACL entries we use 3399+ * ACL_CNT to determine the actual number of ACL entries 3400+ * reallocate and try again. This is in a loop because it 3401+ * is possible that someone else could modify the ACL and 3402+ * increase the number of entries between the call to 3403+ * ACL_CNT and the call to ACL_GET. 3404+ */ 3405+ while ((count = acl(path_p, ACL_GET, count, &acl_d->acl[0])) < 0 && errno == ENOSPC) { 3406+ 3407+ sys_acl_free_acl(acl_d); 3408+ 3409+ if ((count = acl(path_p, ACL_CNT, 0, NULL)) < 0) { 3410+ return NULL; 3411+ } 3412+ 3413+ if ((acl_d = sys_acl_init(count)) == NULL) { 3414+ return NULL; 3415+ } 3416+ } 3417+ 3418+ if (count < 0) { 3419+ sys_acl_free_acl(acl_d); 3420+ return NULL; 3421+ } 3422+ 3423+ /* 3424+ * calculate the number of access and default ACL entries 3425+ * 3426+ * Note: we assume that the acl() system call returned a 3427+ * well formed ACL which is sorted so that all of the 3428+ * access ACL entries preceed any default ACL entries 3429+ */ 3430+ for (naccess = 0; naccess < count; naccess++) { 3431+ if (acl_d->acl[naccess].a_type & ACL_DEFAULT) 3432+ break; 3433+ } 3434+ ndefault = count - naccess; 3435+ 3436+ /* 3437+ * if the caller wants the default ACL we have to copy 3438+ * the entries down to the start of the acl[] buffer 3439+ * and mask out the ACL_DEFAULT flag from the type field 3440+ */ 3441+ if (type == SMB_ACL_TYPE_DEFAULT) { 3442+ int i, j; 3443+ 3444+ for (i = 0, j = naccess; i < ndefault; i++, j++) { 3445+ acl_d->acl[i] = acl_d->acl[j]; 3446+ acl_d->acl[i].a_type &= ~ACL_DEFAULT; 3447+ } 3448+ 3449+ acl_d->count = ndefault; 3450+ } else { 3451+ acl_d->count = naccess; 3452+ } 3453+ 3454+ return acl_d; 3455+} 3456+ 3457+SMB_ACL_T sys_acl_get_fd(int fd) 3458+{ 3459+ /* 3460+ * HPUX doesn't have the facl call. Fake it using the path.... JRA. 3461+ */ 3462+ 3463+ files_struct *fsp = file_find_fd(fd); 3464+ 3465+ if (fsp == NULL) { 3466+ errno = EBADF; 3467+ return NULL; 3468+ } 3469+ 3470+ /* 3471+ * We know we're in the same conn context. So we 3472+ * can use the relative path. 3473+ */ 3474+ 3475+ return sys_acl_get_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS); 3476+} 3477+ 3478+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d) 3479+{ 3480+ *permset_d = 0; 3481+ 3482+ return 0; 3483+} 3484+ 3485+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm) 3486+{ 3487+ if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE 3488+ && perm != SMB_ACL_EXECUTE) { 3489+ errno = EINVAL; 3490+ return -1; 3491+ } 3492+ 3493+ if (permset_d == NULL) { 3494+ errno = EINVAL; 3495+ return -1; 3496+ } 3497+ 3498+ *permset_d |= perm; 3499+ 3500+ return 0; 3501+} 3502+ 3503+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm) 3504+{ 3505+ return *permset_d & perm; 3506+} 3507+ 3508+char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p) 3509+{ 3510+ int i; 3511+ int len, maxlen; 3512+ char *text; 3513+ 3514+ /* 3515+ * use an initial estimate of 20 bytes per ACL entry 3516+ * when allocating memory for the text representation 3517+ * of the ACL 3518+ */ 3519+ len = 0; 3520+ maxlen = 20 * acl_d->count; 3521+ if ((text = SMB_MALLOC(maxlen)) == NULL) { 3522+ errno = ENOMEM; 3523+ return NULL; 3524+ } 3525+ 3526+ for (i = 0; i < acl_d->count; i++) { 3527+ struct acl *ap = &acl_d->acl[i]; 3528+ struct group *gr; 3529+ char tagbuf[12]; 3530+ char idbuf[12]; 3531+ char *tag; 3532+ char *id = ""; 3533+ char perms[4]; 3534+ int nbytes; 3535+ 3536+ switch (ap->a_type) { 3537+ /* 3538+ * for debugging purposes it's probably more 3539+ * useful to dump unknown tag types rather 3540+ * than just returning an error 3541+ */ 3542+ default: 3543+ slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x", 3544+ ap->a_type); 3545+ tag = tagbuf; 3546+ slprintf(idbuf, sizeof(idbuf)-1, "%ld", 3547+ (long)ap->a_id); 3548+ id = idbuf; 3549+ break; 3550+ 3551+ case SMB_ACL_USER: 3552+ id = uidtoname(ap->a_id); 3553+ case SMB_ACL_USER_OBJ: 3554+ tag = "user"; 3555+ break; 3556+ 3557+ case SMB_ACL_GROUP: 3558+ if ((gr = getgrgid(ap->a_id)) == NULL) { 3559+ slprintf(idbuf, sizeof(idbuf)-1, "%ld", 3560+ (long)ap->a_id); 3561+ id = idbuf; 3562+ } else { 3563+ id = gr->gr_name; 3564+ } 3565+ case SMB_ACL_GROUP_OBJ: 3566+ tag = "group"; 3567+ break; 3568+ 3569+ case SMB_ACL_OTHER: 3570+ tag = "other"; 3571+ break; 3572+ 3573+ case SMB_ACL_MASK: 3574+ tag = "mask"; 3575+ break; 3576+ 3577+ } 3578+ 3579+ perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-'; 3580+ perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-'; 3581+ perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-'; 3582+ perms[3] = '\0'; 3583+ 3584+ /* <tag> : <qualifier> : rwx \n \0 */ 3585+ nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1; 3586+ 3587+ /* 3588+ * If this entry would overflow the buffer 3589+ * allocate enough additional memory for this 3590+ * entry and an estimate of another 20 bytes 3591+ * for each entry still to be processed 3592+ */ 3593+ if ((len + nbytes) > maxlen) { 3594+ char *oldtext = text; 3595+ 3596+ maxlen += nbytes + 20 * (acl_d->count - i); 3597+ 3598+ if ((text = SMB_REALLOC(oldtext, maxlen)) == NULL) { 3599+ free(oldtext); 3600+ errno = ENOMEM; 3601+ return NULL; 3602+ } 3603+ } 3604+ 3605+ slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms); 3606+ len += nbytes - 1; 3607+ } 3608+ 3609+ if (len_p) 3610+ *len_p = len; 3611+ 3612+ return text; 3613+} 3614+ 3615+SMB_ACL_T sys_acl_init(int count) 3616+{ 3617+ SMB_ACL_T a; 3618+ 3619+ if (count < 0) { 3620+ errno = EINVAL; 3621+ return NULL; 3622+ } 3623+ 3624+ /* 3625+ * note that since the definition of the structure pointed 3626+ * to by the SMB_ACL_T includes the first element of the 3627+ * acl[] array, this actually allocates an ACL with room 3628+ * for (count+1) entries 3629+ */ 3630+ if ((a = SMB_MALLOC(sizeof(struct SMB_ACL_T) + count * sizeof(struct acl))) == NULL) { 3631+ errno = ENOMEM; 3632+ return NULL; 3633+ } 3634+ 3635+ a->size = count + 1; 3636+ a->count = 0; 3637+ a->next = -1; 3638+ 3639+ return a; 3640+} 3641+ 3642+ 3643+int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p) 3644+{ 3645+ SMB_ACL_T acl_d; 3646+ SMB_ACL_ENTRY_T entry_d; 3647+ 3648+ if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) { 3649+ errno = EINVAL; 3650+ return -1; 3651+ } 3652+ 3653+ if (acl_d->count >= acl_d->size) { 3654+ errno = ENOSPC; 3655+ return -1; 3656+ } 3657+ 3658+ entry_d = &acl_d->acl[acl_d->count++]; 3659+ entry_d->a_type = 0; 3660+ entry_d->a_id = -1; 3661+ entry_d->a_perm = 0; 3662+ *entry_p = entry_d; 3663+ 3664+ return 0; 3665+} 3666+ 3667+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type) 3668+{ 3669+ switch (tag_type) { 3670+ case SMB_ACL_USER: 3671+ case SMB_ACL_USER_OBJ: 3672+ case SMB_ACL_GROUP: 3673+ case SMB_ACL_GROUP_OBJ: 3674+ case SMB_ACL_OTHER: 3675+ case SMB_ACL_MASK: 3676+ entry_d->a_type = tag_type; 3677+ break; 3678+ default: 3679+ errno = EINVAL; 3680+ return -1; 3681+ } 3682+ 3683+ return 0; 3684+} 3685+ 3686+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p) 3687+{ 3688+ if (entry_d->a_type != SMB_ACL_GROUP 3689+ && entry_d->a_type != SMB_ACL_USER) { 3690+ errno = EINVAL; 3691+ return -1; 3692+ } 3693+ 3694+ entry_d->a_id = *((id_t *)qual_p); 3695+ 3696+ return 0; 3697+} 3698+ 3699+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d) 3700+{ 3701+ if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) { 3702+ return EINVAL; 3703+ } 3704+ 3705+ entry_d->a_perm = *permset_d; 3706+ 3707+ return 0; 3708+} 3709+ 3710+/* Structure to capture the count for each type of ACE. */ 3711+ 3712+struct hpux_acl_types { 3713+ int n_user; 3714+ int n_def_user; 3715+ int n_user_obj; 3716+ int n_def_user_obj; 3717+ 3718+ int n_group; 3719+ int n_def_group; 3720+ int n_group_obj; 3721+ int n_def_group_obj; 3722+ 3723+ int n_other; 3724+ int n_other_obj; 3725+ int n_def_other_obj; 3726+ 3727+ int n_class_obj; 3728+ int n_def_class_obj; 3729+ 3730+ int n_illegal_obj; 3731+}; 3732+ 3733+/* count_obj: 3734+ * Counts the different number of objects in a given array of ACL 3735+ * structures. 3736+ * Inputs: 3737+ * 3738+ * acl_count - Count of ACLs in the array of ACL strucutres. 3739+ * aclp - Array of ACL structures. 3740+ * acl_type_count - Pointer to acl_types structure. Should already be 3741+ * allocated. 3742+ * Output: 3743+ * 3744+ * acl_type_count - This structure is filled up with counts of various 3745+ * acl types. 3746+ */ 3747+ 3748+static int hpux_count_obj(int acl_count, struct acl *aclp, struct hpux_acl_types *acl_type_count) 3749+{ 3750+ int i; 3751+ 3752+ memset(acl_type_count, 0, sizeof(struct hpux_acl_types)); 3753+ 3754+ for(i=0;i<acl_count;i++) { 3755+ switch(aclp[i].a_type) { 3756+ case USER: 3757+ acl_type_count->n_user++; 3758+ break; 3759+ case USER_OBJ: 3760+ acl_type_count->n_user_obj++; 3761+ break; 3762+ case DEF_USER_OBJ: 3763+ acl_type_count->n_def_user_obj++; 3764+ break; 3765+ case GROUP: 3766+ acl_type_count->n_group++; 3767+ break; 3768+ case GROUP_OBJ: 3769+ acl_type_count->n_group_obj++; 3770+ break; 3771+ case DEF_GROUP_OBJ: 3772+ acl_type_count->n_def_group_obj++; 3773+ break; 3774+ case OTHER_OBJ: 3775+ acl_type_count->n_other_obj++; 3776+ break; 3777+ case DEF_OTHER_OBJ: 3778+ acl_type_count->n_def_other_obj++; 3779+ break; 3780+ case CLASS_OBJ: 3781+ acl_type_count->n_class_obj++; 3782+ break; 3783+ case DEF_CLASS_OBJ: 3784+ acl_type_count->n_def_class_obj++; 3785+ break; 3786+ case DEF_USER: 3787+ acl_type_count->n_def_user++; 3788+ break; 3789+ case DEF_GROUP: 3790+ acl_type_count->n_def_group++; 3791+ break; 3792+ default: 3793+ acl_type_count->n_illegal_obj++; 3794+ break; 3795+ } 3796+ } 3797+} 3798+ 3799+/* swap_acl_entries: Swaps two ACL entries. 3800+ * 3801+ * Inputs: aclp0, aclp1 - ACL entries to be swapped. 3802+ */ 3803+ 3804+static void hpux_swap_acl_entries(struct acl *aclp0, struct acl *aclp1) 3805+{ 3806+ struct acl temp_acl; 3807+ 3808+ temp_acl.a_type = aclp0->a_type; 3809+ temp_acl.a_id = aclp0->a_id; 3810+ temp_acl.a_perm = aclp0->a_perm; 3811+ 3812+ aclp0->a_type = aclp1->a_type; 3813+ aclp0->a_id = aclp1->a_id; 3814+ aclp0->a_perm = aclp1->a_perm; 3815+ 3816+ aclp1->a_type = temp_acl.a_type; 3817+ aclp1->a_id = temp_acl.a_id; 3818+ aclp1->a_perm = temp_acl.a_perm; 3819+} 3820+ 3821+/* prohibited_duplicate_type 3822+ * Identifies if given ACL type can have duplicate entries or 3823+ * not. 3824+ * 3825+ * Inputs: acl_type - ACL Type. 3826+ * 3827+ * Outputs: 3828+ * 3829+ * Return.. 3830+ * 3831+ * True - If the ACL type matches any of the prohibited types. 3832+ * False - If the ACL type doesn't match any of the prohibited types. 3833+ */ 3834+ 3835+static BOOL hpux_prohibited_duplicate_type(int acl_type) 3836+{ 3837+ switch(acl_type) { 3838+ case USER: 3839+ case GROUP: 3840+ case DEF_USER: 3841+ case DEF_GROUP: 3842+ return True; 3843+ default: 3844+ return False; 3845+ } 3846+} 3847+ 3848+/* get_needed_class_perm 3849+ * Returns the permissions of a ACL structure only if the ACL 3850+ * type matches one of the pre-determined types for computing 3851+ * CLASS_OBJ permissions. 3852+ * 3853+ * Inputs: aclp - Pointer to ACL structure. 3854+ */ 3855+ 3856+static int hpux_get_needed_class_perm(struct acl *aclp) 3857+{ 3858+ switch(aclp->a_type) { 3859+ case USER: 3860+ case GROUP_OBJ: 3861+ case GROUP: 3862+ case DEF_USER_OBJ: 3863+ case DEF_USER: 3864+ case DEF_GROUP_OBJ: 3865+ case DEF_GROUP: 3866+ case DEF_CLASS_OBJ: 3867+ case DEF_OTHER_OBJ: 3868+ return aclp->a_perm; 3869+ default: 3870+ return 0; 3871+ } 3872+} 3873+ 3874+/* acl_sort for HPUX. 3875+ * Sorts the array of ACL structures as per the description in 3876+ * aclsort man page. Refer to aclsort man page for more details 3877+ * 3878+ * Inputs: 3879+ * 3880+ * acl_count - Count of ACLs in the array of ACL structures. 3881+ * calclass - If this is not zero, then we compute the CLASS_OBJ 3882+ * permissions. 3883+ * aclp - Array of ACL structures. 3884+ * 3885+ * Outputs: 3886+ * 3887+ * aclp - Sorted array of ACL structures. 3888+ * 3889+ * Outputs: 3890+ * 3891+ * Returns 0 for success -1 for failure. Prints a message to the Samba 3892+ * debug log in case of failure. 3893+ */ 3894+ 3895+static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp) 3896+{ 3897+#if !defined(HAVE_HPUX_ACLSORT) 3898+ /* 3899+ * The aclsort() system call is availabe on the latest HPUX General 3900+ * Patch Bundles. So for HPUX, we developed our version of acl_sort 3901+ * function. Because, we don't want to update to a new 3902+ * HPUX GR bundle just for aclsort() call. 3903+ */ 3904+ 3905+ struct hpux_acl_types acl_obj_count; 3906+ int n_class_obj_perm = 0; 3907+ int i, j; 3908+ 3909+ if(!acl_count) { 3910+ DEBUG(10,("Zero acl count passed. Returning Success\n")); 3911+ return 0; 3912+ } 3913+ 3914+ if(aclp == NULL) { 3915+ DEBUG(0,("Null ACL pointer in hpux_acl_sort. Returning Failure. \n")); 3916+ return -1; 3917+ } 3918+ 3919+ /* Count different types of ACLs in the ACLs array */ 3920+ 3921+ hpux_count_obj(acl_count, aclp, &acl_obj_count); 3922+ 3923+ /* There should be only one entry each of type USER_OBJ, GROUP_OBJ, 3924+ * CLASS_OBJ and OTHER_OBJ 3925+ */ 3926+ 3927+ if( (acl_obj_count.n_user_obj != 1) || 3928+ (acl_obj_count.n_group_obj != 1) || 3929+ (acl_obj_count.n_class_obj != 1) || 3930+ (acl_obj_count.n_other_obj != 1) 3931+ ) { 3932+ DEBUG(0,("hpux_acl_sort: More than one entry or no entries for \ 3933+USER OBJ or GROUP_OBJ or OTHER_OBJ or CLASS_OBJ\n")); 3934+ return -1; 3935+ } 3936+ 3937+ /* If any of the default objects are present, there should be only 3938+ * one of them each. 3939+ */ 3940+ 3941+ if( (acl_obj_count.n_def_user_obj > 1) || (acl_obj_count.n_def_group_obj > 1) || 3942+ (acl_obj_count.n_def_other_obj > 1) || (acl_obj_count.n_def_class_obj > 1) ) { 3943+ DEBUG(0,("hpux_acl_sort: More than one entry for DEF_CLASS_OBJ \ 3944+or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n")); 3945+ return -1; 3946+ } 3947+ 3948+ /* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl 3949+ * structures. 3950+ * 3951+ * Sorting crieteria - First sort by ACL type. If there are multiple entries of 3952+ * same ACL type, sort by ACL id. 3953+ * 3954+ * I am using the trival kind of sorting method here because, performance isn't 3955+ * really effected by the ACLs feature. More over there aren't going to be more 3956+ * than 17 entries on HPUX. 3957+ */ 3958+ 3959+ for(i=0; i<acl_count;i++) { 3960+ for (j=i+1; j<acl_count; j++) { 3961+ if( aclp[i].a_type > aclp[j].a_type ) { 3962+ /* ACL entries out of order, swap them */ 3963+ 3964+ hpux_swap_acl_entries((aclp+i), (aclp+j)); 3965+ 3966+ } else if ( aclp[i].a_type == aclp[j].a_type ) { 3967+ 3968+ /* ACL entries of same type, sort by id */ 3969+ 3970+ if(aclp[i].a_id > aclp[j].a_id) { 3971+ hpux_swap_acl_entries((aclp+i), (aclp+j)); 3972+ } else if (aclp[i].a_id == aclp[j].a_id) { 3973+ /* We have a duplicate entry. */ 3974+ if(hpux_prohibited_duplicate_type(aclp[i].a_type)) { 3975+ DEBUG(0, ("hpux_acl_sort: Duplicate entry: Type(hex): %x Id: %d\n", 3976+ aclp[i].a_type, aclp[i].a_id)); 3977+ return -1; 3978+ } 3979+ } 3980+ 3981+ } 3982+ } 3983+ } 3984+ 3985+ /* set the class obj permissions to the computed one. */ 3986+ if(calclass) { 3987+ int n_class_obj_index = -1; 3988+ 3989+ for(i=0;i<acl_count;i++) { 3990+ n_class_obj_perm |= hpux_get_needed_class_perm((aclp+i)); 3991+ 3992+ if(aclp[i].a_type == CLASS_OBJ) 3993+ n_class_obj_index = i; 3994+ } 3995+ aclp[n_class_obj_index].a_perm = n_class_obj_perm; 3996+ } 3997+ 3998+ return 0; 3999+#else 4000+ return aclsort(acl_count, calclass, aclp); 4001+#endif 4002+} 4003+ 4004+/* 4005+ * sort the ACL and check it for validity 4006+ * 4007+ * if it's a minimal ACL with only 4 entries then we 4008+ * need to recalculate the mask permissions to make 4009+ * sure that they are the same as the GROUP_OBJ 4010+ * permissions as required by the UnixWare acl() system call. 4011+ * 4012+ * (note: since POSIX allows minimal ACLs which only contain 4013+ * 3 entries - ie there is no mask entry - we should, in theory, 4014+ * check for this and add a mask entry if necessary - however 4015+ * we "know" that the caller of this interface always specifies 4016+ * a mask so, in practice "this never happens" (tm) - if it *does* 4017+ * happen aclsort() will fail and return an error and someone will 4018+ * have to fix it ...) 4019+ */ 4020+ 4021+static int acl_sort(SMB_ACL_T acl_d) 4022+{ 4023+ int fixmask = (acl_d->count <= 4); 4024+ 4025+ if (hpux_acl_sort(acl_d->count, fixmask, acl_d->acl) != 0) { 4026+ errno = EINVAL; 4027+ return -1; 4028+ } 4029+ return 0; 4030+} 4031+ 4032+int sys_acl_valid(SMB_ACL_T acl_d) 4033+{ 4034+ return acl_sort(acl_d); 4035+} 4036+ 4037+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d) 4038+{ 4039+ struct stat s; 4040+ struct acl *acl_p; 4041+ int acl_count; 4042+ struct acl *acl_buf = NULL; 4043+ int ret; 4044+ 4045+ if(hpux_acl_call_presence() == False) { 4046+ /* Looks like we don't have the acl() system call on HPUX. 4047+ * May be the system doesn't have the latest version of JFS. 4048+ */ 4049+ errno=ENOSYS; 4050+ return -1; 4051+ } 4052+ 4053+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) { 4054+ errno = EINVAL; 4055+ return -1; 4056+ } 4057+ 4058+ if (acl_sort(acl_d) != 0) { 4059+ return -1; 4060+ } 4061+ 4062+ acl_p = &acl_d->acl[0]; 4063+ acl_count = acl_d->count; 4064+ 4065+ /* 4066+ * if it's a directory there is extra work to do 4067+ * since the acl() system call will replace both 4068+ * the access ACLs and the default ACLs (if any) 4069+ */ 4070+ if (stat(name, &s) != 0) { 4071+ return -1; 4072+ } 4073+ if (S_ISDIR(s.st_mode)) { 4074+ SMB_ACL_T acc_acl; 4075+ SMB_ACL_T def_acl; 4076+ SMB_ACL_T tmp_acl; 4077+ int i; 4078+ 4079+ if (type == SMB_ACL_TYPE_ACCESS) { 4080+ acc_acl = acl_d; 4081+ def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT); 4082+ 4083+ } else { 4084+ def_acl = acl_d; 4085+ acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS); 4086+ } 4087+ 4088+ if (tmp_acl == NULL) { 4089+ return -1; 4090+ } 4091+ 4092+ /* 4093+ * allocate a temporary buffer for the complete ACL 4094+ */ 4095+ acl_count = acc_acl->count + def_acl->count; 4096+ acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count); 4097+ 4098+ if (acl_buf == NULL) { 4099+ sys_acl_free_acl(tmp_acl); 4100+ errno = ENOMEM; 4101+ return -1; 4102+ } 4103+ 4104+ /* 4105+ * copy the access control and default entries into the buffer 4106+ */ 4107+ memcpy(&acl_buf[0], &acc_acl->acl[0], 4108+ acc_acl->count * sizeof(acl_buf[0])); 4109+ 4110+ memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0], 4111+ def_acl->count * sizeof(acl_buf[0])); 4112+ 4113+ /* 4114+ * set the ACL_DEFAULT flag on the default entries 4115+ */ 4116+ for (i = acc_acl->count; i < acl_count; i++) { 4117+ acl_buf[i].a_type |= ACL_DEFAULT; 4118+ } 4119+ 4120+ sys_acl_free_acl(tmp_acl); 4121+ 4122+ } else if (type != SMB_ACL_TYPE_ACCESS) { 4123+ errno = EINVAL; 4124+ return -1; 4125+ } 4126+ 4127+ ret = acl(name, ACL_SET, acl_count, acl_p); 4128+ 4129+ if (acl_buf) { 4130+ free(acl_buf); 4131+ } 4132+ 4133+ return ret; 4134+} 4135+ 4136+int sys_acl_set_fd(int fd, SMB_ACL_T acl_d) 4137+{ 4138+ /* 4139+ * HPUX doesn't have the facl call. Fake it using the path.... JRA. 4140+ */ 4141+ 4142+ files_struct *fsp = file_find_fd(fd); 4143+ 4144+ if (fsp == NULL) { 4145+ errno = EBADF; 4146+ return NULL; 4147+ } 4148+ 4149+ if (acl_sort(acl_d) != 0) { 4150+ return -1; 4151+ } 4152+ 4153+ /* 4154+ * We know we're in the same conn context. So we 4155+ * can use the relative path. 4156+ */ 4157+ 4158+ return sys_acl_set_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS, acl_d); 4159+} 4160+ 4161+int sys_acl_delete_def_file(const char *path) 4162+{ 4163+ SMB_ACL_T acl_d; 4164+ int ret; 4165+ 4166+ /* 4167+ * fetching the access ACL and rewriting it has 4168+ * the effect of deleting the default ACL 4169+ */ 4170+ if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) { 4171+ return -1; 4172+ } 4173+ 4174+ ret = acl(path, ACL_SET, acl_d->count, acl_d->acl); 4175+ 4176+ sys_acl_free_acl(acl_d); 4177+ 4178+ return ret; 4179+} 4180+ 4181+int sys_acl_free_text(char *text) 4182+{ 4183+ free(text); 4184+ return 0; 4185+} 4186+ 4187+int sys_acl_free_acl(SMB_ACL_T acl_d) 4188+{ 4189+ free(acl_d); 4190+ return 0; 4191+} 4192+ 4193+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype) 4194+{ 4195+ return 0; 4196+} 4197+ 4198+#elif defined(HAVE_IRIX_ACLS) 4199+ 4200+int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p) 4201+{ 4202+ if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) { 4203+ errno = EINVAL; 4204+ return -1; 4205+ } 4206+ 4207+ if (entry_p == NULL) { 4208+ errno = EINVAL; 4209+ return -1; 4210+ } 4211+ 4212+ if (entry_id == SMB_ACL_FIRST_ENTRY) { 4213+ acl_d->next = 0; 4214+ } 4215+ 4216+ if (acl_d->next < 0) { 4217+ errno = EINVAL; 4218+ return -1; 4219+ } 4220+ 4221+ if (acl_d->next >= acl_d->aclp->acl_cnt) { 4222+ return 0; 4223+ } 4224+ 4225+ *entry_p = &acl_d->aclp->acl_entry[acl_d->next++]; 4226+ 4227+ return 1; 4228+} 4229+ 4230+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p) 4231+{ 4232+ *type_p = entry_d->ae_tag; 4233+ 4234+ return 0; 4235+} 4236+ 4237+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p) 4238+{ 4239+ *permset_p = entry_d; 4240+ 4241+ return 0; 4242+} 4243+ 4244+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d) 4245+{ 4246+ if (entry_d->ae_tag != SMB_ACL_USER 4247+ && entry_d->ae_tag != SMB_ACL_GROUP) { 4248+ errno = EINVAL; 4249+ return NULL; 4250+ } 4251+ 4252+ return &entry_d->ae_id; 4253+} 4254+ 4255+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type) 4256+{ 4257+ SMB_ACL_T a; 4258+ 4259+ if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) { 4260+ errno = ENOMEM; 4261+ return NULL; 4262+ } 4263+ if ((a->aclp = acl_get_file(path_p, type)) == NULL) { 4264+ SAFE_FREE(a); 4265+ return NULL; 4266+ } 4267+ a->next = -1; 4268+ a->freeaclp = True; 4269+ return a; 4270+} 4271+ 4272+SMB_ACL_T sys_acl_get_fd(int fd) 4273+{ 4274+ SMB_ACL_T a; 4275+ 4276+ if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) { 4277+ errno = ENOMEM; 4278+ return NULL; 4279+ } 4280+ if ((a->aclp = acl_get_fd(fd)) == NULL) { 4281+ SAFE_FREE(a); 4282+ return NULL; 4283+ } 4284+ a->next = -1; 4285+ a->freeaclp = True; 4286+ return a; 4287+} 4288+ 4289+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d) 4290+{ 4291+ permset_d->ae_perm = 0; 4292+ 4293+ return 0; 4294+} 4295+ 4296+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm) 4297+{ 4298+ if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE 4299+ && perm != SMB_ACL_EXECUTE) { 4300+ errno = EINVAL; 4301+ return -1; 4302+ } 4303+ 4304+ if (permset_d == NULL) { 4305+ errno = EINVAL; 4306+ return -1; 4307+ } 4308+ 4309+ permset_d->ae_perm |= perm; 4310+ 4311+ return 0; 4312+} 4313+ 4314+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm) 4315+{ 4316+ return permset_d->ae_perm & perm; 4317+} 4318+ 4319+char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p) 4320+{ 4321+ return acl_to_text(acl_d->aclp, len_p); 4322+} 4323+ 4324+SMB_ACL_T sys_acl_init(int count) 4325+{ 4326+ SMB_ACL_T a; 4327+ 4328+ if (count < 0) { 4329+ errno = EINVAL; 4330+ return NULL; 4331+ } 4332+ 4333+ if ((a = SMB_MALLOC(sizeof(struct SMB_ACL_T) + sizeof(struct acl))) == NULL) { 4334+ errno = ENOMEM; 4335+ return NULL; 4336+ } 4337+ 4338+ a->next = -1; 4339+ a->freeaclp = False; 4340+ a->aclp = (struct acl *)(&a->aclp + sizeof(struct acl *)); 4341+ a->aclp->acl_cnt = 0; 4342+ 4343+ return a; 4344+} 4345+ 4346+ 4347+int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p) 4348+{ 4349+ SMB_ACL_T acl_d; 4350+ SMB_ACL_ENTRY_T entry_d; 4351+ 4352+ if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) { 4353+ errno = EINVAL; 4354+ return -1; 4355+ } 4356+ 4357+ if (acl_d->aclp->acl_cnt >= ACL_MAX_ENTRIES) { 4358+ errno = ENOSPC; 4359+ return -1; 4360+ } 4361+ 4362+ entry_d = &acl_d->aclp->acl_entry[acl_d->aclp->acl_cnt++]; 4363+ entry_d->ae_tag = 0; 4364+ entry_d->ae_id = 0; 4365+ entry_d->ae_perm = 0; 4366+ *entry_p = entry_d; 4367+ 4368+ return 0; 4369+} 4370+ 4371+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type) 4372+{ 4373+ switch (tag_type) { 4374+ case SMB_ACL_USER: 4375+ case SMB_ACL_USER_OBJ: 4376+ case SMB_ACL_GROUP: 4377+ case SMB_ACL_GROUP_OBJ: 4378+ case SMB_ACL_OTHER: 4379+ case SMB_ACL_MASK: 4380+ entry_d->ae_tag = tag_type; 4381+ break; 4382+ default: 4383+ errno = EINVAL; 4384+ return -1; 4385+ } 4386+ 4387+ return 0; 4388+} 4389+ 4390+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p) 4391+{ 4392+ if (entry_d->ae_tag != SMB_ACL_GROUP 4393+ && entry_d->ae_tag != SMB_ACL_USER) { 4394+ errno = EINVAL; 4395+ return -1; 4396+ } 4397+ 4398+ entry_d->ae_id = *((id_t *)qual_p); 4399+ 4400+ return 0; 4401+} 4402+ 4403+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d) 4404+{ 4405+ if (permset_d->ae_perm & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) { 4406+ return EINVAL; 4407+ } 4408+ 4409+ entry_d->ae_perm = permset_d->ae_perm; 4410+ 4411+ return 0; 4412+} 4413+ 4414+int sys_acl_valid(SMB_ACL_T acl_d) 4415+{ 4416+ return acl_valid(acl_d->aclp); 4417+} 4418+ 4419+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d) 4420+{ 4421+ return acl_set_file(name, type, acl_d->aclp); 4422+} 4423+ 4424+int sys_acl_set_fd(int fd, SMB_ACL_T acl_d) 4425+{ 4426+ return acl_set_fd(fd, acl_d->aclp); 4427+} 4428+ 4429+int sys_acl_delete_def_file(const char *name) 4430+{ 4431+ return acl_delete_def_file(name); 4432+} 4433+ 4434+int sys_acl_free_text(char *text) 4435+{ 4436+ return acl_free(text); 4437+} 4438+ 4439+int sys_acl_free_acl(SMB_ACL_T acl_d) 4440+{ 4441+ if (acl_d->freeaclp) { 4442+ acl_free(acl_d->aclp); 4443+ } 4444+ acl_free(acl_d); 4445+ return 0; 4446+} 4447+ 4448+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype) 4449+{ 4450+ return 0; 4451+} 4452+ 4453+#elif defined(HAVE_AIX_ACLS) 4454+ 4455+/* Donated by Medha Date, mdate@austin.ibm.com, for IBM */ 4456+ 4457+int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p) 4458+{ 4459+ struct acl_entry_link *link; 4460+ struct new_acl_entry *entry; 4461+ int keep_going; 4462+ 4463+ DEBUG(10,("This is the count: %d\n",theacl->count)); 4464+ 4465+ /* Check if count was previously set to -1. * 4466+ * If it was, that means we reached the end * 4467+ * of the acl last time. */ 4468+ if(theacl->count == -1) 4469+ return(0); 4470+ 4471+ link = theacl; 4472+ /* To get to the next acl, traverse linked list until index * 4473+ * of acl matches the count we are keeping. This count is * 4474+ * incremented each time we return an acl entry. */ 4475+ 4476+ for(keep_going = 0; keep_going < theacl->count; keep_going++) 4477+ link = link->nextp; 4478+ 4479+ entry = *entry_p = link->entryp; 4480+ 4481+ DEBUG(10,("*entry_p is %d\n",entry_p)); 4482+ DEBUG(10,("*entry_p->ace_access is %d\n",entry->ace_access)); 4483+ 4484+ /* Increment count */ 4485+ theacl->count++; 4486+ if(link->nextp == NULL) 4487+ theacl->count = -1; 4488+ 4489+ return(1); 4490+} 4491+ 4492+int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p) 4493+{ 4494+ /* Initialize tag type */ 4495+ 4496+ *tag_type_p = -1; 4497+ DEBUG(10,("the tagtype is %d\n",entry_d->ace_id->id_type)); 4498+ 4499+ /* Depending on what type of entry we have, * 4500+ * return tag type. */ 4501+ switch(entry_d->ace_id->id_type) { 4502+ case ACEID_USER: 4503+ *tag_type_p = SMB_ACL_USER; 4504+ break; 4505+ case ACEID_GROUP: 4506+ *tag_type_p = SMB_ACL_GROUP; 4507+ break; 4508+ 4509+ case SMB_ACL_USER_OBJ: 4510+ case SMB_ACL_GROUP_OBJ: 4511+ case SMB_ACL_OTHER: 4512+ *tag_type_p = entry_d->ace_id->id_type; 4513+ break; 4514+ 4515+ default: 4516+ return(-1); 4517+ } 4518+ 4519+ return(0); 4520+} 4521+ 4522+int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p) 4523+{ 4524+ DEBUG(10,("Starting AIX sys_acl_get_permset\n")); 4525+ *permset_p = &entry_d->ace_access; 4526+ DEBUG(10,("**permset_p is %d\n",**permset_p)); 4527+ if(!(**permset_p & S_IXUSR) && 4528+ !(**permset_p & S_IWUSR) && 4529+ !(**permset_p & S_IRUSR) && 4530+ (**permset_p != 0)) 4531+ return(-1); 4532+ 4533+ DEBUG(10,("Ending AIX sys_acl_get_permset\n")); 4534+ return(0); 4535+} 4536+ 4537+void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d) 4538+{ 4539+ return(entry_d->ace_id->id_data); 4540+} 4541+ 4542+SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type) 4543+{ 4544+ struct acl *file_acl = (struct acl *)NULL; 4545+ struct acl_entry *acl_entry; 4546+ struct new_acl_entry *new_acl_entry; 4547+ struct ace_id *idp; 4548+ struct acl_entry_link *acl_entry_link; 4549+ struct acl_entry_link *acl_entry_link_head; 4550+ int i; 4551+ int rc = 0; 4552+ uid_t user_id; 4553+ 4554+ /* AIX has no DEFAULT */ 4555+ if ( type == SMB_ACL_TYPE_DEFAULT ) { 4556+ errno = ENOTSUP; 4557+ return NULL; 4558+ } 4559+ 4560+ /* Get the acl using statacl */ 4561+ 4562+ DEBUG(10,("Entering sys_acl_get_file\n")); 4563+ DEBUG(10,("path_p is %s\n",path_p)); 4564+ 4565+ file_acl = (struct acl *)SMB_MALLOC(BUFSIZ); 4566+ 4567+ if(file_acl == NULL) { 4568+ errno=ENOMEM; 4569+ DEBUG(0,("Error in AIX sys_acl_get_file: %d\n",errno)); 4570+ return(NULL); 4571+ } 4572+ 4573+ memset(file_acl,0,BUFSIZ); 4574+ 4575+ rc = statacl((char *)path_p,0,file_acl,BUFSIZ); 4576+ if(rc == -1) { 4577+ DEBUG(0,("statacl returned %d with errno %d\n",rc,errno)); 4578+ SAFE_FREE(file_acl); 4579+ return(NULL); 4580+ } 4581+ 4582+ DEBUG(10,("Got facl and returned it\n")); 4583+ 4584+ /* Point to the first acl entry in the acl */ 4585+ acl_entry = file_acl->acl_ext; 4586+ 4587+ /* Begin setting up the head of the linked list * 4588+ * that will be used for the storing the acl * 4589+ * in a way that is useful for the posix_acls.c * 4590+ * code. */ 4591+ 4592+ acl_entry_link_head = acl_entry_link = sys_acl_init(0); 4593+ if(acl_entry_link_head == NULL) 4594+ return(NULL); 4595+ 4596+ acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry); 4597+ if(acl_entry_link->entryp == NULL) { 4598+ SAFE_FREE(file_acl); 4599+ errno = ENOMEM; 4600+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno)); 4601+ return(NULL); 4602+ } 4603+ 4604+ DEBUG(10,("acl_entry is %d\n",acl_entry)); 4605+ DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl))); 4606+ 4607+ /* Check if the extended acl bit is on. * 4608+ * If it isn't, do not show the * 4609+ * contents of the acl since AIX intends * 4610+ * the extended info to remain unused */ 4611+ 4612+ if(file_acl->acl_mode & S_IXACL){ 4613+ /* while we are not pointing to the very end */ 4614+ while(acl_entry < acl_last(file_acl)) { 4615+ /* before we malloc anything, make sure this is */ 4616+ /* a valid acl entry and one that we want to map */ 4617+ idp = id_nxt(acl_entry->ace_id); 4618+ if((acl_entry->ace_type == ACC_SPECIFY || 4619+ (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) { 4620+ acl_entry = acl_nxt(acl_entry); 4621+ continue; 4622+ } 4623+ 4624+ idp = acl_entry->ace_id; 4625+ 4626+ /* Check if this is the first entry in the linked list. * 4627+ * The first entry needs to keep prevp pointing to NULL * 4628+ * and already has entryp allocated. */ 4629+ 4630+ if(acl_entry_link_head->count != 0) { 4631+ acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link); 4632+ 4633+ if(acl_entry_link->nextp == NULL) { 4634+ SAFE_FREE(file_acl); 4635+ errno = ENOMEM; 4636+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno)); 4637+ return(NULL); 4638+ } 4639+ 4640+ acl_entry_link->nextp->prevp = acl_entry_link; 4641+ acl_entry_link = acl_entry_link->nextp; 4642+ acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry); 4643+ if(acl_entry_link->entryp == NULL) { 4644+ SAFE_FREE(file_acl); 4645+ errno = ENOMEM; 4646+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno)); 4647+ return(NULL); 4648+ } 4649+ acl_entry_link->nextp = NULL; 4650+ } 4651+ 4652+ acl_entry_link->entryp->ace_len = acl_entry->ace_len; 4653+ 4654+ /* Don't really need this since all types are going * 4655+ * to be specified but, it's better than leaving it 0 */ 4656+ 4657+ acl_entry_link->entryp->ace_type = acl_entry->ace_type; 4658+ 4659+ acl_entry_link->entryp->ace_access = acl_entry->ace_access; 4660+ 4661+ memcpy(acl_entry_link->entryp->ace_id,idp,sizeof(struct ace_id)); 4662+ 4663+ /* The access in the acl entries must be left shifted by * 4664+ * three bites, because they will ultimately be compared * 4665+ * to S_IRUSR, S_IWUSR, and S_IXUSR. */ 4666+ 4667+ switch(acl_entry->ace_type){ 4668+ case ACC_PERMIT: 4669+ case ACC_SPECIFY: 4670+ acl_entry_link->entryp->ace_access = acl_entry->ace_access; 4671+ acl_entry_link->entryp->ace_access <<= 6; 4672+ acl_entry_link_head->count++; 4673+ break; 4674+ case ACC_DENY: 4675+ /* Since there is no way to return a DENY acl entry * 4676+ * change to PERMIT and then shift. */ 4677+ DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access)); 4678+ acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7; 4679+ DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access)); 4680+ acl_entry_link->entryp->ace_access <<= 6; 4681+ acl_entry_link_head->count++; 4682+ break; 4683+ default: 4684+ return(0); 4685+ } 4686+ 4687+ DEBUG(10,("acl_entry = %d\n",acl_entry)); 4688+ DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type)); 4689+ 4690+ acl_entry = acl_nxt(acl_entry); 4691+ } 4692+ } /* end of if enabled */ 4693+ 4694+ /* Since owner, group, other acl entries are not * 4695+ * part of the acl entries in an acl, they must * 4696+ * be dummied up to become part of the list. */ 4697+ 4698+ for( i = 1; i < 4; i++) { 4699+ DEBUG(10,("i is %d\n",i)); 4700+ if(acl_entry_link_head->count != 0) { 4701+ acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link); 4702+ if(acl_entry_link->nextp == NULL) { 4703+ SAFE_FREE(file_acl); 4704+ errno = ENOMEM; 4705+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno)); 4706+ return(NULL); 4707+ } 4708+ 4709+ acl_entry_link->nextp->prevp = acl_entry_link; 4710+ acl_entry_link = acl_entry_link->nextp; 4711+ acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry); 4712+ if(acl_entry_link->entryp == NULL) { 4713+ SAFE_FREE(file_acl); 4714+ errno = ENOMEM; 4715+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno)); 4716+ return(NULL); 4717+ } 4718+ } 4719+ 4720+ acl_entry_link->nextp = NULL; 4721+ 4722+ new_acl_entry = acl_entry_link->entryp; 4723+ idp = new_acl_entry->ace_id; 4724+ 4725+ new_acl_entry->ace_len = sizeof(struct acl_entry); 4726+ new_acl_entry->ace_type = ACC_PERMIT; 4727+ idp->id_len = sizeof(struct ace_id); 4728+ DEBUG(10,("idp->id_len = %d\n",idp->id_len)); 4729+ memset(idp->id_data,0,sizeof(uid_t)); 4730+ 4731+ switch(i) { 4732+ case 2: 4733+ new_acl_entry->ace_access = file_acl->g_access << 6; 4734+ idp->id_type = SMB_ACL_GROUP_OBJ; 4735+ break; 4736+ 4737+ case 3: 4738+ new_acl_entry->ace_access = file_acl->o_access << 6; 4739+ idp->id_type = SMB_ACL_OTHER; 4740+ break; 4741+ 4742+ case 1: 4743+ new_acl_entry->ace_access = file_acl->u_access << 6; 4744+ idp->id_type = SMB_ACL_USER_OBJ; 4745+ break; 4746+ 4747+ default: 4748+ return(NULL); 4749+ 4750+ } 4751+ 4752+ acl_entry_link_head->count++; 4753+ DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access)); 4754+ } 4755+ 4756+ acl_entry_link_head->count = 0; 4757+ SAFE_FREE(file_acl); 4758+ 4759+ return(acl_entry_link_head); 4760+} 4761+ 4762+SMB_ACL_T sys_acl_get_fd(int fd) 4763+{ 4764+ struct acl *file_acl = (struct acl *)NULL; 4765+ struct acl_entry *acl_entry; 4766+ struct new_acl_entry *new_acl_entry; 4767+ struct ace_id *idp; 4768+ struct acl_entry_link *acl_entry_link; 4769+ struct acl_entry_link *acl_entry_link_head; 4770+ int i; 4771+ int rc = 0; 4772+ uid_t user_id; 4773+ 4774+ /* Get the acl using fstatacl */ 4775+ 4776+ DEBUG(10,("Entering sys_acl_get_fd\n")); 4777+ DEBUG(10,("fd is %d\n",fd)); 4778+ file_acl = (struct acl *)SMB_MALLOC(BUFSIZ); 4779+ 4780+ if(file_acl == NULL) { 4781+ errno=ENOMEM; 4782+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno)); 4783+ return(NULL); 4784+ } 4785+ 4786+ memset(file_acl,0,BUFSIZ); 4787+ 4788+ rc = fstatacl(fd,0,file_acl,BUFSIZ); 4789+ if(rc == -1) { 4790+ DEBUG(0,("The fstatacl call returned %d with errno %d\n",rc,errno)); 4791+ SAFE_FREE(file_acl); 4792+ return(NULL); 4793+ } 4794+ 4795+ DEBUG(10,("Got facl and returned it\n")); 4796+ 4797+ /* Point to the first acl entry in the acl */ 4798+ 4799+ acl_entry = file_acl->acl_ext; 4800+ /* Begin setting up the head of the linked list * 4801+ * that will be used for the storing the acl * 4802+ * in a way that is useful for the posix_acls.c * 4803+ * code. */ 4804+ 4805+ acl_entry_link_head = acl_entry_link = sys_acl_init(0); 4806+ if(acl_entry_link_head == NULL){ 4807+ SAFE_FREE(file_acl); 4808+ return(NULL); 4809+ } 4810+ 4811+ acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry); 4812+ 4813+ if(acl_entry_link->entryp == NULL) { 4814+ errno = ENOMEM; 4815+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno)); 4816+ SAFE_FREE(file_acl); 4817+ return(NULL); 4818+ } 4819+ 4820+ DEBUG(10,("acl_entry is %d\n",acl_entry)); 4821+ DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl))); 4822+ 4823+ /* Check if the extended acl bit is on. * 4824+ * If it isn't, do not show the * 4825+ * contents of the acl since AIX intends * 4826+ * the extended info to remain unused */ 4827+ 4828+ if(file_acl->acl_mode & S_IXACL){ 4829+ /* while we are not pointing to the very end */ 4830+ while(acl_entry < acl_last(file_acl)) { 4831+ /* before we malloc anything, make sure this is */ 4832+ /* a valid acl entry and one that we want to map */ 4833+ 4834+ idp = id_nxt(acl_entry->ace_id); 4835+ if((acl_entry->ace_type == ACC_SPECIFY || 4836+ (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) { 4837+ acl_entry = acl_nxt(acl_entry); 4838+ continue; 4839+ } 4840+ 4841+ idp = acl_entry->ace_id; 4842+ 4843+ /* Check if this is the first entry in the linked list. * 4844+ * The first entry needs to keep prevp pointing to NULL * 4845+ * and already has entryp allocated. */ 4846+ 4847+ if(acl_entry_link_head->count != 0) { 4848+ acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link); 4849+ if(acl_entry_link->nextp == NULL) { 4850+ errno = ENOMEM; 4851+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno)); 4852+ SAFE_FREE(file_acl); 4853+ return(NULL); 4854+ } 4855+ acl_entry_link->nextp->prevp = acl_entry_link; 4856+ acl_entry_link = acl_entry_link->nextp; 4857+ acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry); 4858+ if(acl_entry_link->entryp == NULL) { 4859+ errno = ENOMEM; 4860+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno)); 4861+ SAFE_FREE(file_acl); 4862+ return(NULL); 4863+ } 4864+ 4865+ acl_entry_link->nextp = NULL; 4866+ } 4867+ 4868+ acl_entry_link->entryp->ace_len = acl_entry->ace_len; 4869+ 4870+ /* Don't really need this since all types are going * 4871+ * to be specified but, it's better than leaving it 0 */ 4872+ 4873+ acl_entry_link->entryp->ace_type = acl_entry->ace_type; 4874+ acl_entry_link->entryp->ace_access = acl_entry->ace_access; 4875+ 4876+ memcpy(acl_entry_link->entryp->ace_id, idp, sizeof(struct ace_id)); 4877+ 4878+ /* The access in the acl entries must be left shifted by * 4879+ * three bites, because they will ultimately be compared * 4880+ * to S_IRUSR, S_IWUSR, and S_IXUSR. */ 4881+ 4882+ switch(acl_entry->ace_type){ 4883+ case ACC_PERMIT: 4884+ case ACC_SPECIFY: 4885+ acl_entry_link->entryp->ace_access = acl_entry->ace_access; 4886+ acl_entry_link->entryp->ace_access <<= 6; 4887+ acl_entry_link_head->count++; 4888+ break; 4889+ case ACC_DENY: 4890+ /* Since there is no way to return a DENY acl entry * 4891+ * change to PERMIT and then shift. */ 4892+ DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access)); 4893+ acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7; 4894+ DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access)); 4895+ acl_entry_link->entryp->ace_access <<= 6; 4896+ acl_entry_link_head->count++; 4897+ break; 4898+ default: 4899+ return(0); 4900+ } 4901+ 4902+ DEBUG(10,("acl_entry = %d\n",acl_entry)); 4903+ DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type)); 4904+ 4905+ acl_entry = acl_nxt(acl_entry); 4906+ } 4907+ } /* end of if enabled */ 4908+ 4909+ /* Since owner, group, other acl entries are not * 4910+ * part of the acl entries in an acl, they must * 4911+ * be dummied up to become part of the list. */ 4912+ 4913+ for( i = 1; i < 4; i++) { 4914+ DEBUG(10,("i is %d\n",i)); 4915+ if(acl_entry_link_head->count != 0){ 4916+ acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link); 4917+ if(acl_entry_link->nextp == NULL) { 4918+ errno = ENOMEM; 4919+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno)); 4920+ SAFE_FREE(file_acl); 4921+ return(NULL); 4922+ } 4923+ 4924+ acl_entry_link->nextp->prevp = acl_entry_link; 4925+ acl_entry_link = acl_entry_link->nextp; 4926+ acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry); 4927+ 4928+ if(acl_entry_link->entryp == NULL) { 4929+ SAFE_FREE(file_acl); 4930+ errno = ENOMEM; 4931+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno)); 4932+ return(NULL); 4933+ } 4934+ } 4935+ 4936+ acl_entry_link->nextp = NULL; 4937+ 4938+ new_acl_entry = acl_entry_link->entryp; 4939+ idp = new_acl_entry->ace_id; 4940+ 4941+ new_acl_entry->ace_len = sizeof(struct acl_entry); 4942+ new_acl_entry->ace_type = ACC_PERMIT; 4943+ idp->id_len = sizeof(struct ace_id); 4944+ DEBUG(10,("idp->id_len = %d\n",idp->id_len)); 4945+ memset(idp->id_data,0,sizeof(uid_t)); 4946+ 4947+ switch(i) { 4948+ case 2: 4949+ new_acl_entry->ace_access = file_acl->g_access << 6; 4950+ idp->id_type = SMB_ACL_GROUP_OBJ; 4951+ break; 4952+ 4953+ case 3: 4954+ new_acl_entry->ace_access = file_acl->o_access << 6; 4955+ idp->id_type = SMB_ACL_OTHER; 4956+ break; 4957+ 4958+ case 1: 4959+ new_acl_entry->ace_access = file_acl->u_access << 6; 4960+ idp->id_type = SMB_ACL_USER_OBJ; 4961+ break; 4962+ 4963+ default: 4964+ return(NULL); 4965+ } 4966+ 4967+ acl_entry_link_head->count++; 4968+ DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access)); 4969+ } 4970+ 4971+ acl_entry_link_head->count = 0; 4972+ SAFE_FREE(file_acl); 4973+ 4974+ return(acl_entry_link_head); 4975+} 4976+ 4977+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset) 4978+{ 4979+ *permset = *permset & ~0777; 4980+ return(0); 4981+} 4982+ 4983+int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm) 4984+{ 4985+ if((perm != 0) && 4986+ (perm & (S_IXUSR | S_IWUSR | S_IRUSR)) == 0) 4987+ return(-1); 4988+ 4989+ *permset |= perm; 4990+ DEBUG(10,("This is the permset now: %d\n",*permset)); 4991+ return(0); 4992+} 4993+ 4994+char *sys_acl_to_text( SMB_ACL_T theacl, ssize_t *plen) 4995+{ 4996+ return(NULL); 4997+} 4998+ 4999+SMB_ACL_T sys_acl_init( int count) 5000+{ 5001+ struct acl_entry_link *theacl = NULL; 5002+ 5003+ DEBUG(10,("Entering sys_acl_init\n")); 5004+ 5005+ theacl = SMB_MALLOC_P(struct acl_entry_link); 5006+ if(theacl == NULL) { 5007+ errno = ENOMEM; 5008+ DEBUG(0,("Error in sys_acl_init is %d\n",errno)); 5009+ return(NULL); 5010+ } 5011+ 5012+ theacl->count = 0; 5013+ theacl->nextp = NULL; 5014+ theacl->prevp = NULL; 5015+ theacl->entryp = NULL; 5016+ DEBUG(10,("Exiting sys_acl_init\n")); 5017+ return(theacl); 5018+} 5019+ 5020+int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry) 5021+{ 5022+ struct acl_entry_link *theacl; 5023+ struct acl_entry_link *acl_entryp; 5024+ struct acl_entry_link *temp_entry; 5025+ int counting; 5026+ 5027+ DEBUG(10,("Entering the sys_acl_create_entry\n")); 5028+ 5029+ theacl = acl_entryp = *pacl; 5030+ 5031+ /* Get to the end of the acl before adding entry */ 5032+ 5033+ for(counting=0; counting < theacl->count; counting++){ 5034+ DEBUG(10,("The acl_entryp is %d\n",acl_entryp)); 5035+ temp_entry = acl_entryp; 5036+ acl_entryp = acl_entryp->nextp; 5037+ } 5038+ 5039+ if(theacl->count != 0){ 5040+ temp_entry->nextp = acl_entryp = SMB_MALLOC_P(struct acl_entry_link); 5041+ if(acl_entryp == NULL) { 5042+ errno = ENOMEM; 5043+ DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno)); 5044+ return(-1); 5045+ } 5046+ 5047+ DEBUG(10,("The acl_entryp is %d\n",acl_entryp)); 5048+ acl_entryp->prevp = temp_entry; 5049+ DEBUG(10,("The acl_entryp->prevp is %d\n",acl_entryp->prevp)); 5050+ } 5051+ 5052+ *pentry = acl_entryp->entryp = SMB_MALLOC_P(struct new_acl_entry); 5053+ if(*pentry == NULL) { 5054+ errno = ENOMEM; 5055+ DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno)); 5056+ return(-1); 5057+ } 5058+ 5059+ memset(*pentry,0,sizeof(struct new_acl_entry)); 5060+ acl_entryp->entryp->ace_len = sizeof(struct acl_entry); 5061+ acl_entryp->entryp->ace_type = ACC_PERMIT; 5062+ acl_entryp->entryp->ace_id->id_len = sizeof(struct ace_id); 5063+ acl_entryp->nextp = NULL; 5064+ theacl->count++; 5065+ DEBUG(10,("Exiting sys_acl_create_entry\n")); 5066+ return(0); 5067+} 5068+ 5069+int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype) 5070+{ 5071+ DEBUG(10,("Starting AIX sys_acl_set_tag_type\n")); 5072+ entry->ace_id->id_type = tagtype; 5073+ DEBUG(10,("The tag type is %d\n",entry->ace_id->id_type)); 5074+ DEBUG(10,("Ending AIX sys_acl_set_tag_type\n")); 5075+} 5076+ 5077+int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual) 5078+{ 5079+ DEBUG(10,("Starting AIX sys_acl_set_qualifier\n")); 5080+ memcpy(entry->ace_id->id_data,qual,sizeof(uid_t)); 5081+ DEBUG(10,("Ending AIX sys_acl_set_qualifier\n")); 5082+ return(0); 5083+} 5084+ 5085+int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset) 5086+{ 5087+ DEBUG(10,("Starting AIX sys_acl_set_permset\n")); 5088+ if(!(*permset & S_IXUSR) && 5089+ !(*permset & S_IWUSR) && 5090+ !(*permset & S_IRUSR) && 5091+ (*permset != 0)) 5092+ return(-1); 5093+ 5094+ entry->ace_access = *permset; 5095+ DEBUG(10,("entry->ace_access = %d\n",entry->ace_access)); 5096+ DEBUG(10,("Ending AIX sys_acl_set_permset\n")); 5097+ return(0); 5098+} 5099+ 5100+int sys_acl_valid( SMB_ACL_T theacl ) 5101+{ 5102+ int user_obj = 0; 5103+ int group_obj = 0; 5104+ int other_obj = 0; 5105+ struct acl_entry_link *acl_entry; 5106+ 5107+ for(acl_entry=theacl; acl_entry != NULL; acl_entry = acl_entry->nextp) { 5108+ user_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_USER_OBJ); 5109+ group_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_GROUP_OBJ); 5110+ other_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_OTHER); 5111+ } 5112+ 5113+ DEBUG(10,("user_obj=%d, group_obj=%d, other_obj=%d\n",user_obj,group_obj,other_obj)); 5114+ 5115+ if(user_obj != 1 || group_obj != 1 || other_obj != 1) 5116+ return(-1); 5117+ 5118+ return(0); 5119+} 5120+ 5121+int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) 5122+{ 5123+ struct acl_entry_link *acl_entry_link = NULL; 5124+ struct acl *file_acl = NULL; 5125+ struct acl *file_acl_temp = NULL; 5126+ struct acl_entry *acl_entry = NULL; 5127+ struct ace_id *ace_id = NULL; 5128+ uint id_type; 5129+ uint ace_access; 5130+ uint user_id; 5131+ uint acl_length; 5132+ uint rc; 5133+ 5134+ DEBUG(10,("Entering sys_acl_set_file\n")); 5135+ DEBUG(10,("File name is %s\n",name)); 5136+ 5137+ /* AIX has no default ACL */ 5138+ if(acltype == SMB_ACL_TYPE_DEFAULT) 5139+ return(0); 5140+ 5141+ acl_length = BUFSIZ; 5142+ file_acl = (struct acl *)SMB_MALLOC(BUFSIZ); 5143+ 5144+ if(file_acl == NULL) { 5145+ errno = ENOMEM; 5146+ DEBUG(0,("Error in sys_acl_set_file is %d\n",errno)); 5147+ return(-1); 5148+ } 5149+ 5150+ memset(file_acl,0,BUFSIZ); 5151+ 5152+ file_acl->acl_len = ACL_SIZ; 5153+ file_acl->acl_mode = S_IXACL; 5154+ 5155+ for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) { 5156+ acl_entry_link->entryp->ace_access >>= 6; 5157+ id_type = acl_entry_link->entryp->ace_id->id_type; 5158+ 5159+ switch(id_type) { 5160+ case SMB_ACL_USER_OBJ: 5161+ file_acl->u_access = acl_entry_link->entryp->ace_access; 5162+ continue; 5163+ case SMB_ACL_GROUP_OBJ: 5164+ file_acl->g_access = acl_entry_link->entryp->ace_access; 5165+ continue; 5166+ case SMB_ACL_OTHER: 5167+ file_acl->o_access = acl_entry_link->entryp->ace_access; 5168+ continue; 5169+ case SMB_ACL_MASK: 5170+ continue; 5171+ } 5172+ 5173+ if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) { 5174+ acl_length += sizeof(struct acl_entry); 5175+ file_acl_temp = (struct acl *)SMB_MALLOC(acl_length); 5176+ if(file_acl_temp == NULL) { 5177+ SAFE_FREE(file_acl); 5178+ errno = ENOMEM; 5179+ DEBUG(0,("Error in sys_acl_set_file is %d\n",errno)); 5180+ return(-1); 5181+ } 5182+ 5183+ memcpy(file_acl_temp,file_acl,file_acl->acl_len); 5184+ SAFE_FREE(file_acl); 5185+ file_acl = file_acl_temp; 5186+ } 5187+ 5188+ acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len); 5189+ file_acl->acl_len += sizeof(struct acl_entry); 5190+ acl_entry->ace_len = acl_entry_link->entryp->ace_len; 5191+ acl_entry->ace_access = acl_entry_link->entryp->ace_access; 5192+ 5193+ /* In order to use this, we'll need to wait until we can get denies */ 5194+ /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT) 5195+ acl_entry->ace_type = ACC_SPECIFY; */ 5196+ 5197+ acl_entry->ace_type = ACC_SPECIFY; 5198+ 5199+ ace_id = acl_entry->ace_id; 5200+ 5201+ ace_id->id_type = acl_entry_link->entryp->ace_id->id_type; 5202+ DEBUG(10,("The id type is %d\n",ace_id->id_type)); 5203+ ace_id->id_len = acl_entry_link->entryp->ace_id->id_len; 5204+ memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t)); 5205+ memcpy(acl_entry->ace_id->id_data, &user_id, sizeof(uid_t)); 5206+ } 5207+ 5208+ rc = chacl(name,file_acl,file_acl->acl_len); 5209+ DEBUG(10,("errno is %d\n",errno)); 5210+ DEBUG(10,("return code is %d\n",rc)); 5211+ SAFE_FREE(file_acl); 5212+ DEBUG(10,("Exiting the sys_acl_set_file\n")); 5213+ return(rc); 5214+} 5215+ 5216+int sys_acl_set_fd( int fd, SMB_ACL_T theacl) 5217+{ 5218+ struct acl_entry_link *acl_entry_link = NULL; 5219+ struct acl *file_acl = NULL; 5220+ struct acl *file_acl_temp = NULL; 5221+ struct acl_entry *acl_entry = NULL; 5222+ struct ace_id *ace_id = NULL; 5223+ uint id_type; 5224+ uint user_id; 5225+ uint acl_length; 5226+ uint rc; 5227+ 5228+ DEBUG(10,("Entering sys_acl_set_fd\n")); 5229+ acl_length = BUFSIZ; 5230+ file_acl = (struct acl *)SMB_MALLOC(BUFSIZ); 5231+ 5232+ if(file_acl == NULL) { 5233+ errno = ENOMEM; 5234+ DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno)); 5235+ return(-1); 5236+ } 5237+ 5238+ memset(file_acl,0,BUFSIZ); 5239+ 5240+ file_acl->acl_len = ACL_SIZ; 5241+ file_acl->acl_mode = S_IXACL; 5242+ 5243+ for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) { 5244+ acl_entry_link->entryp->ace_access >>= 6; 5245+ id_type = acl_entry_link->entryp->ace_id->id_type; 5246+ DEBUG(10,("The id_type is %d\n",id_type)); 5247+ 5248+ switch(id_type) { 5249+ case SMB_ACL_USER_OBJ: 5250+ file_acl->u_access = acl_entry_link->entryp->ace_access; 5251+ continue; 5252+ case SMB_ACL_GROUP_OBJ: 5253+ file_acl->g_access = acl_entry_link->entryp->ace_access; 5254+ continue; 5255+ case SMB_ACL_OTHER: 5256+ file_acl->o_access = acl_entry_link->entryp->ace_access; 5257+ continue; 5258+ case SMB_ACL_MASK: 5259+ continue; 5260+ } 5261+ 5262+ if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) { 5263+ acl_length += sizeof(struct acl_entry); 5264+ file_acl_temp = (struct acl *)SMB_MALLOC(acl_length); 5265+ if(file_acl_temp == NULL) { 5266+ SAFE_FREE(file_acl); 5267+ errno = ENOMEM; 5268+ DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno)); 5269+ return(-1); 5270+ } 5271+ 5272+ memcpy(file_acl_temp,file_acl,file_acl->acl_len); 5273+ SAFE_FREE(file_acl); 5274+ file_acl = file_acl_temp; 5275+ } 5276+ 5277+ acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len); 5278+ file_acl->acl_len += sizeof(struct acl_entry); 5279+ acl_entry->ace_len = acl_entry_link->entryp->ace_len; 5280+ acl_entry->ace_access = acl_entry_link->entryp->ace_access; 5281+ 5282+ /* In order to use this, we'll need to wait until we can get denies */ 5283+ /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT) 5284+ acl_entry->ace_type = ACC_SPECIFY; */ 5285+ 5286+ acl_entry->ace_type = ACC_SPECIFY; 5287+ 5288+ ace_id = acl_entry->ace_id; 5289+ 5290+ ace_id->id_type = acl_entry_link->entryp->ace_id->id_type; 5291+ DEBUG(10,("The id type is %d\n",ace_id->id_type)); 5292+ ace_id->id_len = acl_entry_link->entryp->ace_id->id_len; 5293+ memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t)); 5294+ memcpy(ace_id->id_data, &user_id, sizeof(uid_t)); 5295+ } 5296+ 5297+ rc = fchacl(fd,file_acl,file_acl->acl_len); 5298+ DEBUG(10,("errno is %d\n",errno)); 5299+ DEBUG(10,("return code is %d\n",rc)); 5300+ SAFE_FREE(file_acl); 5301+ DEBUG(10,("Exiting sys_acl_set_fd\n")); 5302+ return(rc); 5303+} 5304+ 5305+int sys_acl_delete_def_file(const char *name) 5306+{ 5307+ /* AIX has no default ACL */ 5308+ return 0; 5309+} 5310+ 5311+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm) 5312+{ 5313+ return(*permset & perm); 5314+} 5315+ 5316+int sys_acl_free_text(char *text) 5317+{ 5318+ return(0); 5319+} 5320+ 5321+int sys_acl_free_acl(SMB_ACL_T posix_acl) 5322+{ 5323+ struct acl_entry_link *acl_entry_link; 5324+ 5325+ for(acl_entry_link = posix_acl->nextp; acl_entry_link->nextp != NULL; acl_entry_link = acl_entry_link->nextp) { 5326+ SAFE_FREE(acl_entry_link->prevp->entryp); 5327+ SAFE_FREE(acl_entry_link->prevp); 5328+ } 5329+ 5330+ SAFE_FREE(acl_entry_link->prevp->entryp); 5331+ SAFE_FREE(acl_entry_link->prevp); 5332+ SAFE_FREE(acl_entry_link->entryp); 5333+ SAFE_FREE(acl_entry_link); 5334+ 5335+ return(0); 5336+} 5337+ 5338+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype) 5339+{ 5340+ return(0); 5341+} 5342+ 5343+#else /* No ACLs. */ 5344+ 5345+int sys_acl_get_entry(UNUSED(SMB_ACL_T the_acl), UNUSED(int entry_id), UNUSED(SMB_ACL_ENTRY_T *entry_p)) 5346+{ 5347+ errno = ENOSYS; 5348+ return -1; 5349+} 5350+ 5351+int sys_acl_get_tag_type(UNUSED(SMB_ACL_ENTRY_T entry_d), UNUSED(SMB_ACL_TAG_T *tag_type_p)) 5352+{ 5353+ errno = ENOSYS; 5354+ return -1; 5355+} 5356+ 5357+int sys_acl_get_permset(UNUSED(SMB_ACL_ENTRY_T entry_d), UNUSED(SMB_ACL_PERMSET_T *permset_p)) 5358+{ 5359+ errno = ENOSYS; 5360+ return -1; 5361+} 5362+ 5363+void *sys_acl_get_qualifier(UNUSED(SMB_ACL_ENTRY_T entry_d)) 5364+{ 5365+ errno = ENOSYS; 5366+ return NULL; 5367+} 5368+ 5369+SMB_ACL_T sys_acl_get_file(UNUSED(const char *path_p), UNUSED(SMB_ACL_TYPE_T type)) 5370+{ 5371+ errno = ENOSYS; 5372+ return (SMB_ACL_T)NULL; 5373+} 5374+ 5375+SMB_ACL_T sys_acl_get_fd(UNUSED(int fd)) 5376+{ 5377+ errno = ENOSYS; 5378+ return (SMB_ACL_T)NULL; 5379+} 5380+ 5381+int sys_acl_clear_perms(UNUSED(SMB_ACL_PERMSET_T permset)) 5382+{ 5383+ errno = ENOSYS; 5384+ return -1; 5385+} 5386+ 5387+int sys_acl_add_perm( UNUSED(SMB_ACL_PERMSET_T permset), UNUSED(SMB_ACL_PERM_T perm)) 5388+{ 5389+ errno = ENOSYS; 5390+ return -1; 5391+} 5392+ 5393+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm) 5394+{ 5395+ errno = ENOSYS; 5396+ return (permset & perm) ? 1 : 0; 5397+} 5398+ 5399+char *sys_acl_to_text(UNUSED(SMB_ACL_T the_acl), UNUSED(ssize_t *plen)) 5400+{ 5401+ errno = ENOSYS; 5402+ return NULL; 5403+} 5404+ 5405+int sys_acl_free_text(UNUSED(char *text)) 5406+{ 5407+ errno = ENOSYS; 5408+ return -1; 5409+} 5410+ 5411+SMB_ACL_T sys_acl_init(UNUSED(int count)) 5412+{ 5413+ errno = ENOSYS; 5414+ return NULL; 5415+} 5416+ 5417+int sys_acl_create_entry(UNUSED(SMB_ACL_T *pacl), UNUSED(SMB_ACL_ENTRY_T *pentry)) 5418+{ 5419+ errno = ENOSYS; 5420+ return -1; 5421+} 5422+ 5423+int sys_acl_set_tag_type(UNUSED(SMB_ACL_ENTRY_T entry), UNUSED(SMB_ACL_TAG_T tagtype)) 5424+{ 5425+ errno = ENOSYS; 5426+ return -1; 5427+} 5428+ 5429+int sys_acl_set_qualifier(UNUSED(SMB_ACL_ENTRY_T entry), UNUSED(void *qual)) 5430+{ 5431+ errno = ENOSYS; 5432+ return -1; 5433+} 5434+ 5435+int sys_acl_set_permset(UNUSED(SMB_ACL_ENTRY_T entry), UNUSED(SMB_ACL_PERMSET_T permset)) 5436+{ 5437+ errno = ENOSYS; 5438+ return -1; 5439+} 5440+ 5441+int sys_acl_valid(UNUSED(SMB_ACL_T theacl)) 5442+{ 5443+ errno = ENOSYS; 5444+ return -1; 5445+} 5446+ 5447+int sys_acl_set_file(UNUSED(const char *name), UNUSED(SMB_ACL_TYPE_T acltype), UNUSED(SMB_ACL_T theacl)) 5448+{ 5449+ errno = ENOSYS; 5450+ return -1; 5451+} 5452+ 5453+int sys_acl_set_fd(UNUSED(int fd), UNUSED(SMB_ACL_T theacl)) 5454+{ 5455+ errno = ENOSYS; 5456+ return -1; 5457+} 5458+ 5459+int sys_acl_delete_def_file(UNUSED(const char *name)) 5460+{ 5461+ errno = ENOSYS; 5462+ return -1; 5463+} 5464+ 5465+int sys_acl_free_acl(UNUSED(SMB_ACL_T the_acl)) 5466+{ 5467+ errno = ENOSYS; 5468+ return -1; 5469+} 5470+ 5471+int sys_acl_free_qualifier(UNUSED(void *qual), UNUSED(SMB_ACL_TAG_T tagtype)) 5472+{ 5473+ errno = ENOSYS; 5474+ return -1; 5475+} 5476+ 5477+#endif /* No ACLs. */ 5478+ 5479+/************************************************************************ 5480+ Deliberately outside the ACL defines. Return 1 if this is a "no acls" 5481+ errno, 0 if not. 5482+************************************************************************/ 5483+ 5484+int no_acl_syscall_error(int err) 5485+{ 5486+#if defined(ENOSYS) 5487+ if (err == ENOSYS) { 5488+ return 1; 5489+ } 5490+#endif 5491+#if defined(ENOTSUP) 5492+ if (err == ENOTSUP) { 5493+ return 1; 5494+ } 5495+#endif 5496+ return 0; 5497+} 5498+ 5499+#endif /* SUPPORT_ACLS */ 5500--- old/lib/sysacls.h 5501+++ new/lib/sysacls.h 5502@@ -0,0 +1,40 @@ 5503+#ifdef SUPPORT_ACLS 5504+ 5505+#ifdef HAVE_SYS_ACL_H 5506+#include <sys/acl.h> 5507+#endif 5508+#ifdef HAVE_ACL_LIBACL_H 5509+#include <acl/libacl.h> 5510+#endif 5511+#include "smb_acls.h" 5512+ 5513+#define SMB_MALLOC(cnt) new_array(char, cnt) 5514+#define SMB_MALLOC_P(obj) new_array(obj, 1) 5515+#define SMB_MALLOC_ARRAY(obj, cnt) new_array(obj, cnt) 5516+#define SMB_REALLOC(mem, cnt) realloc_array(mem, char, cnt) 5517+#define slprintf snprintf 5518+ 5519+int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p); 5520+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p); 5521+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p); 5522+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d); 5523+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type); 5524+SMB_ACL_T sys_acl_get_fd(int fd); 5525+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset); 5526+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm); 5527+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm); 5528+char *sys_acl_to_text(SMB_ACL_T the_acl, ssize_t *plen); 5529+SMB_ACL_T sys_acl_init(int count); 5530+int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry); 5531+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype); 5532+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry, void *qual); 5533+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset); 5534+int sys_acl_valid(SMB_ACL_T theacl); 5535+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl); 5536+int sys_acl_set_fd(int fd, SMB_ACL_T theacl); 5537+int sys_acl_delete_def_file(const char *name); 5538+int sys_acl_free_text(char *text); 5539+int sys_acl_free_acl(SMB_ACL_T the_acl); 5540+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype); 5541+ 5542+#endif /* SUPPORT_ACLS */ 5543--- old/log.c 5544+++ new/log.c 5545@@ -606,8 +606,10 @@ static void log_formatted(enum logcode c 5546 n[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p'; 5547 n[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o'; 5548 n[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g'; 5549- n[8] = '.'; 5550- n[9] = '\0'; 5551+ n[8] = !(iflags & ITEM_REPORT_ATIME) ? '.' : 'u'; 5552+ n[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a'; 5553+ n[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x'; 5554+ n[11] = '\0'; 5555 5556 if (iflags & (ITEM_IS_NEW|ITEM_MISSING_DATA)) { 5557 char ch = iflags & ITEM_IS_NEW ? '+' : '?'; 5558--- old/options.c 5559+++ new/options.c 5560@@ -47,6 +47,7 @@ int copy_dirlinks = 0; 5561 int copy_links = 0; 5562 int preserve_links = 0; 5563 int preserve_hard_links = 0; 5564+int preserve_acls = 0; 5565 int preserve_perms = 0; 5566 int preserve_executability = 0; 5567 int preserve_devices = 0; 5568@@ -199,6 +200,7 @@ static void print_rsync_version(enum log 5569 char const *got_socketpair = "no "; 5570 char const *have_inplace = "no "; 5571 char const *hardlinks = "no "; 5572+ char const *acls = "no "; 5573 char const *links = "no "; 5574 char const *ipv6 = "no "; 5575 STRUCT_STAT *dumstat; 5576@@ -215,6 +217,10 @@ static void print_rsync_version(enum log 5577 hardlinks = ""; 5578 #endif 5579 5580+#ifdef SUPPORT_ACLS 5581+ acls = ""; 5582+#endif 5583+ 5584 #ifdef SUPPORT_LINKS 5585 links = ""; 5586 #endif 5587@@ -227,17 +233,16 @@ static void print_rsync_version(enum log 5588 RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION); 5589 rprintf(f, "Copyright (C) 1996-2006 by Andrew Tridgell, Wayne Davison, and others.\n"); 5590 rprintf(f, "<http://rsync.samba.org/>\n"); 5591- rprintf(f, "Capabilities: %d-bit files, %ssocketpairs, " 5592- "%shard links, %ssymlinks, batchfiles,\n", 5593- (int) (sizeof (OFF_T) * 8), 5594- got_socketpair, hardlinks, links); 5595+ rprintf(f, "Capabilities: %d-bit files, %ssocketpairs, %shard links, %ssymlinks,\n", 5596+ (int) (sizeof (OFF_T) * 8), got_socketpair, hardlinks, links); 5597+ 5598+ rprintf(f, " batchfiles, %sinplace, %sIPv6, %sACLs,\n", 5599+ have_inplace, ipv6, acls); 5600 5601 /* Note that this field may not have type ino_t. It depends 5602 * on the complicated interaction between largefile feature 5603 * macros. */ 5604- rprintf(f, " %sinplace, %sIPv6, " 5605- "%d-bit system inums, %d-bit internal inums\n", 5606- have_inplace, ipv6, 5607+ rprintf(f, " %d-bit system inums, %d-bit internal inums\n", 5608 (int) (sizeof dumstat->st_ino * 8), 5609 (int) (sizeof (int64) * 8)); 5610 #ifdef MAINTAINER_MODE 5611@@ -284,7 +289,7 @@ void usage(enum logcode F) 5612 rprintf(F," -q, --quiet suppress non-error messages\n"); 5613 rprintf(F," --no-motd suppress daemon-mode MOTD (see manpage caveat)\n"); 5614 rprintf(F," -c, --checksum skip based on checksum, not mod-time & size\n"); 5615- rprintf(F," -a, --archive archive mode; same as -rlptgoD (no -H)\n"); 5616+ rprintf(F," -a, --archive archive mode; same as -rlptgoD (no -H, -A)\n"); 5617 rprintf(F," --no-OPTION turn off an implied OPTION (e.g. --no-D)\n"); 5618 rprintf(F," -r, --recursive recurse into directories\n"); 5619 rprintf(F," -R, --relative use relative path names\n"); 5620@@ -306,6 +311,9 @@ void usage(enum logcode F) 5621 rprintf(F," -p, --perms preserve permissions\n"); 5622 rprintf(F," -E, --executability preserve the file's executability\n"); 5623 rprintf(F," --chmod=CHMOD affect file and/or directory permissions\n"); 5624+#ifdef SUPPORT_ACLS 5625+ rprintf(F," -A, --acls preserve ACLs (implies --perms)\n"); 5626+#endif 5627 rprintf(F," -o, --owner preserve owner (super-user only)\n"); 5628 rprintf(F," -g, --group preserve group\n"); 5629 rprintf(F," --devices preserve device files (super-user only)\n"); 5630@@ -425,6 +433,9 @@ static struct poptOption long_options[] 5631 {"no-perms", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 }, 5632 {"no-p", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 }, 5633 {"executability", 'E', POPT_ARG_NONE, &preserve_executability, 0, 0, 0 }, 5634+ {"acls", 'A', POPT_ARG_NONE, 0, 'A', 0, 0 }, 5635+ {"no-acls", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 }, 5636+ {"no-A", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 }, 5637 {"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 }, 5638 {"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 }, 5639 {"no-t", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 }, 5640@@ -1089,6 +1100,24 @@ int parse_arguments(int *argc, const cha 5641 usage(FINFO); 5642 exit_cleanup(0); 5643 5644+ case 'A': 5645+#ifdef SUPPORT_ACLS 5646+ preserve_acls++; 5647+ preserve_perms = 1; 5648+ break; 5649+#else 5650+ /* FIXME: this should probably be ignored with a 5651+ * warning and then countermeasures taken to 5652+ * restrict group and other access in the presence 5653+ * of any more restrictive ACLs, but this is safe 5654+ * for now */ 5655+ snprintf(err_buf,sizeof(err_buf), 5656+ "ACLs are not supported on this %s\n", 5657+ am_server ? "server" : "client"); 5658+ return 0; 5659+#endif 5660+ 5661+ 5662 default: 5663 /* A large opt value means that set_refuse_options() 5664 * turned this option off. */ 5665@@ -1530,6 +1559,10 @@ void server_options(char **args,int *arg 5666 5667 if (preserve_hard_links) 5668 argstr[x++] = 'H'; 5669+#ifdef SUPPORT_ACLS 5670+ if (preserve_acls) 5671+ argstr[x++] = 'A'; 5672+#endif 5673 if (preserve_uid) 5674 argstr[x++] = 'o'; 5675 if (preserve_gid) 5676--- old/receiver.c 5677+++ new/receiver.c 5678@@ -47,6 +47,7 @@ extern int keep_partial; 5679 extern int checksum_seed; 5680 extern int inplace; 5681 extern int delay_updates; 5682+extern mode_t orig_umask; 5683 extern struct stats stats; 5684 extern char *stdout_format; 5685 extern char *tmpdir; 5686@@ -350,6 +351,10 @@ int recv_files(int f_in, struct file_lis 5687 int itemizing = am_server ? logfile_format_has_i : stdout_format_has_i; 5688 enum logcode log_code = log_before_transfer ? FLOG : FINFO; 5689 int max_phase = protocol_version >= 29 ? 2 : 1; 5690+ int dflt_perms = (ACCESSPERMS & ~orig_umask); 5691+#ifdef SUPPORT_ACLS 5692+ char *parent_dirname = ""; 5693+#endif 5694 int i, recv_ok; 5695 5696 if (verbose > 2) 5697@@ -553,7 +558,16 @@ int recv_files(int f_in, struct file_lis 5698 * mode based on the local permissions and some heuristics. */ 5699 if (!preserve_perms) { 5700 int exists = fd1 != -1; 5701- file->mode = dest_mode(file->mode, st.st_mode, exists); 5702+#ifdef SUPPORT_ACLS 5703+ char *dn = file->dirname ? file->dirname : "."; 5704+ if (parent_dirname != dn 5705+ && strcmp(parent_dirname, dn) != 0) { 5706+ dflt_perms = default_perms_for_dir(dn); 5707+ parent_dirname = dn; 5708+ } 5709+#endif 5710+ file->mode = dest_mode(file->mode, st.st_mode, 5711+ dflt_perms, exists); 5712 } 5713 5714 /* We now check to see if we are writing the file "inplace" */ 5715--- old/rsync.c 5716+++ new/rsync.c 5717@@ -32,6 +32,7 @@ 5718 5719 extern int verbose; 5720 extern int dry_run; 5721+extern int preserve_acls; 5722 extern int preserve_perms; 5723 extern int preserve_executability; 5724 extern int preserve_times; 5725@@ -47,7 +48,6 @@ extern int preserve_gid; 5726 extern int inplace; 5727 extern int keep_dirlinks; 5728 extern int make_backups; 5729-extern mode_t orig_umask; 5730 extern struct stats stats; 5731 extern struct chmod_mode_struct *daemon_chmod_modes; 5732 5733@@ -100,7 +100,8 @@ void free_sums(struct sum_struct *s) 5734 5735 /* This is only called when we aren't preserving permissions. Figure out what 5736 * the permissions should be and return them merged back into the mode. */ 5737-mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int exists) 5738+mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms, 5739+ int exists) 5740 { 5741 int new_mode; 5742 /* If the file already exists, we'll return the local permissions, 5743@@ -117,56 +118,65 @@ mode_t dest_mode(mode_t flist_mode, mode 5744 new_mode |= (new_mode & 0444) >> 2; 5745 } 5746 } else { 5747- /* Apply the umask and turn off special permissions. */ 5748- new_mode = flist_mode & (~CHMOD_BITS | (ACCESSPERMS & ~orig_umask)); 5749+ /* Apply destination default permissions and turn 5750+ * off special permissions. */ 5751+ new_mode = flist_mode & (~CHMOD_BITS | dflt_perms); 5752 } 5753 return new_mode; 5754 } 5755 5756-int set_file_attrs(char *fname, struct file_struct *file, STRUCT_STAT *st, 5757+int set_file_attrs(char *fname, struct file_struct *file, statx *sxp, 5758 int flags) 5759 { 5760 int updated = 0; 5761- STRUCT_STAT st2; 5762+ statx sx2; 5763 int change_uid, change_gid; 5764 mode_t new_mode = file->mode; 5765 5766- if (!st) { 5767+ if (!sxp) { 5768 if (dry_run) 5769 return 1; 5770- if (link_stat(fname, &st2, 0) < 0) { 5771+ if (link_stat(fname, &sx2.st, 0) < 0) { 5772 rsyserr(FERROR, errno, "stat %s failed", 5773 full_fname(fname)); 5774 return 0; 5775 } 5776- st = &st2; 5777+#ifdef SUPPORT_ACLS 5778+ sx2.acc_acl = sx2.def_acl = NULL; 5779+#endif 5780 if (!preserve_perms && S_ISDIR(new_mode) 5781- && st->st_mode & S_ISGID) { 5782+ && sx2.st.st_mode & S_ISGID) { 5783 /* We just created this directory and its setgid 5784 * bit is on, so make sure it stays on. */ 5785 new_mode |= S_ISGID; 5786 } 5787+ sxp = &sx2; 5788 } 5789 5790- if (!preserve_times || (S_ISDIR(st->st_mode) && omit_dir_times)) 5791+#ifdef SUPPORT_ACLS 5792+ if (preserve_acls && !ACL_READY(*sxp)) 5793+ get_acl(fname, sxp); 5794+#endif 5795+ 5796+ if (!preserve_times || (S_ISDIR(sxp->st.st_mode) && omit_dir_times)) 5797 flags |= ATTRS_SKIP_MTIME; 5798 if (!(flags & ATTRS_SKIP_MTIME) 5799- && cmp_time(st->st_mtime, file->modtime) != 0) { 5800- int ret = set_modtime(fname, file->modtime, st->st_mode); 5801+ && cmp_time(sxp->st.st_mtime, file->modtime) != 0) { 5802+ int ret = set_modtime(fname, file->modtime, sxp->st.st_mode); 5803 if (ret < 0) { 5804 rsyserr(FERROR, errno, "failed to set times on %s", 5805 full_fname(fname)); 5806- return 0; 5807+ goto cleanup; 5808 } 5809 if (ret == 0) /* ret == 1 if symlink could not be set */ 5810 updated = 1; 5811 } 5812 5813- change_uid = am_root && preserve_uid && st->st_uid != file->uid; 5814+ change_uid = am_root && preserve_uid && sxp->st.st_uid != file->uid; 5815 change_gid = preserve_gid && file->gid != GID_NONE 5816- && st->st_gid != file->gid; 5817+ && sxp->st.st_gid != file->gid; 5818 #if !defined HAVE_LCHOWN && !defined CHOWN_MODIFIES_SYMLINK 5819- if (S_ISLNK(st->st_mode)) 5820+ if (S_ISLNK(sxp->st.st_mode)) 5821 ; 5822 else 5823 #endif 5824@@ -176,45 +186,57 @@ int set_file_attrs(char *fname, struct f 5825 rprintf(FINFO, 5826 "set uid of %s from %ld to %ld\n", 5827 fname, 5828- (long)st->st_uid, (long)file->uid); 5829+ (long)sxp->st.st_uid, (long)file->uid); 5830 } 5831 if (change_gid) { 5832 rprintf(FINFO, 5833 "set gid of %s from %ld to %ld\n", 5834 fname, 5835- (long)st->st_gid, (long)file->gid); 5836+ (long)sxp->st.st_gid, (long)file->gid); 5837 } 5838 } 5839 if (do_lchown(fname, 5840- change_uid ? file->uid : st->st_uid, 5841- change_gid ? file->gid : st->st_gid) != 0) { 5842+ change_uid ? file->uid : sxp->st.st_uid, 5843+ change_gid ? file->gid : sxp->st.st_gid) != 0) { 5844 /* shouldn't have attempted to change uid or gid 5845 * unless have the privilege */ 5846 rsyserr(FERROR, errno, "%s %s failed", 5847 change_uid ? "chown" : "chgrp", 5848 full_fname(fname)); 5849- return 0; 5850+ goto cleanup; 5851 } 5852 /* a lchown had been done - we have to re-stat if the 5853 * destination had the setuid or setgid bits set due 5854 * to the side effect of the chown call */ 5855- if (st->st_mode & (S_ISUID | S_ISGID)) { 5856- link_stat(fname, st, 5857- keep_dirlinks && S_ISDIR(st->st_mode)); 5858+ if (sxp->st.st_mode & (S_ISUID | S_ISGID)) { 5859+ link_stat(fname, &sxp->st, 5860+ keep_dirlinks && S_ISDIR(sxp->st.st_mode)); 5861 } 5862 updated = 1; 5863 } 5864 5865 if (daemon_chmod_modes && !S_ISLNK(new_mode)) 5866 new_mode = tweak_mode(new_mode, daemon_chmod_modes); 5867+ 5868+#ifdef SUPPORT_ACLS 5869+ /* It's OK to call set_acl() now, even for a dir, as the generator 5870+ * will enable owner-writability using chmod, if necessary. 5871+ * 5872+ * If set_acl() changes permission bits in the process of setting 5873+ * an access ACL, it changes sxp->st.st_mode so we know whether we 5874+ * need to chmod(). */ 5875+ if (preserve_acls && set_acl(fname, file, sxp) == 0) 5876+ updated = 1; 5877+#endif 5878+ 5879 #ifdef HAVE_CHMOD 5880- if ((st->st_mode & CHMOD_BITS) != (new_mode & CHMOD_BITS)) { 5881+ if ((sxp->st.st_mode & CHMOD_BITS) != (new_mode & CHMOD_BITS)) { 5882 int ret = do_chmod(fname, new_mode); 5883 if (ret < 0) { 5884 rsyserr(FERROR, errno, 5885 "failed to set permissions on %s", 5886 full_fname(fname)); 5887- return 0; 5888+ goto cleanup; 5889 } 5890 if (ret == 0) /* ret == 1 if symlink could not be set */ 5891 updated = 1; 5892@@ -227,6 +249,11 @@ int set_file_attrs(char *fname, struct f 5893 else 5894 rprintf(FCLIENT, "%s is uptodate\n", fname); 5895 } 5896+ cleanup: 5897+#ifdef SUPPORT_ACLS 5898+ if (preserve_acls && sxp == &sx2) 5899+ free_acl(&sx2); 5900+#endif 5901 return updated; 5902 } 5903 5904--- old/rsync.h 5905+++ new/rsync.h 5906@@ -492,6 +492,14 @@ struct idev { 5907 #define IN_LOOPBACKNET 127 5908 #endif 5909 5910+#ifndef HAVE_NO_ACLS 5911+#define SUPPORT_ACLS 1 5912+#endif 5913+ 5914+#if HAVE_UNIXWARE_ACLS|HAVE_SOLARIS_ACLS|HAVE_HPUX_ACLS 5915+#define ACLS_NEED_MASK 1 5916+#endif 5917+ 5918 #define GID_NONE ((gid_t)-1) 5919 5920 #define HL_CHECK_MASTER 0 5921@@ -653,6 +661,17 @@ struct stats { 5922 5923 struct chmod_mode_struct; 5924 5925+#define EMPTY_ITEM_LIST {NULL, 0, 0} 5926+ 5927+typedef struct { 5928+ void *items; 5929+ size_t count; 5930+ size_t malloced; 5931+} item_list; 5932+ 5933+#define EXPAND_ITEM_LIST(lp, type, incr) \ 5934+ (type*)expand_item_list(lp, sizeof (type), #type, incr) 5935+ 5936 #include "byteorder.h" 5937 #include "lib/mdfour.h" 5938 #include "lib/wildmatch.h" 5939@@ -669,6 +688,16 @@ struct chmod_mode_struct; 5940 #define UNUSED(x) x __attribute__((__unused__)) 5941 #define NORETURN __attribute__((__noreturn__)) 5942 5943+typedef struct { 5944+ STRUCT_STAT st; 5945+#ifdef SUPPORT_ACLS 5946+ struct rsync_acl *acc_acl; /* access ACL */ 5947+ struct rsync_acl *def_acl; /* default ACL */ 5948+#endif 5949+} statx; 5950+ 5951+#define ACL_READY(sx) ((sx).acc_acl != NULL) 5952+ 5953 #include "proto.h" 5954 5955 /* We have replacement versions of these if they're missing. */ 5956--- old/rsync.yo 5957+++ new/rsync.yo 5958@@ -301,7 +301,7 @@ to the detailed description below for a 5959 -q, --quiet suppress non-error messages 5960 --no-motd suppress daemon-mode MOTD (see caveat) 5961 -c, --checksum skip based on checksum, not mod-time & size 5962- -a, --archive archive mode; same as -rlptgoD (no -H) 5963+ -a, --archive archive mode; same as -rlptgoD (no -H, -A) 5964 --no-OPTION turn off an implied OPTION (e.g. --no-D) 5965 -r, --recursive recurse into directories 5966 -R, --relative use relative path names 5967@@ -323,6 +323,7 @@ to the detailed description below for a 5968 -p, --perms preserve permissions 5969 -E, --executability preserve executability 5970 --chmod=CHMOD affect file and/or directory permissions 5971+ -A, --acls preserve ACLs (implies -p) [non-standard] 5972 -o, --owner preserve owner (super-user only) 5973 -g, --group preserve group 5974 --devices preserve device files (super-user only) 5975@@ -753,7 +754,9 @@ quote(itemization( 5976 permissions, though the bf(--executability) option might change just 5977 the execute permission for the file. 5978 it() New files get their "normal" permission bits set to the source 5979- file's permissions masked with the receiving end's umask setting, and 5980+ file's permissions masked with the receiving directory's default 5981+ permissions (either the receiving process's umask, or the permissions 5982+ specified via the destination directory's default ACL), and 5983 their special permission bits disabled except in the case where a new 5984 directory inherits a setgid bit from its parent directory. 5985 )) 5986@@ -784,9 +787,11 @@ The preservation of the destination's se 5987 directories when bf(--perms) is off was added in rsync 2.6.7. Older rsync 5988 versions erroneously preserved the three special permission bits for 5989 newly-created files when bf(--perms) was off, while overriding the 5990-destination's setgid bit setting on a newly-created directory. (Keep in 5991-mind that it is the version of the receiving rsync that affects this 5992-behavior.) 5993+destination's setgid bit setting on a newly-created directory. Default ACL 5994+observance was added to the ACL patch for rsync 2.6.7, so older (or 5995+non-ACL-enabled) rsyncs use the umask even if default ACLs are present. 5996+(Keep in mind that it is the version of the receiving rsync that affects 5997+these behaviors.) 5998 5999 dit(bf(-E, --executability)) This option causes rsync to preserve the 6000 executability (or non-executability) of regular files when bf(--perms) is 6001@@ -804,6 +809,15 @@ quote(itemization( 6002 6003 If bf(--perms) is enabled, this option is ignored. 6004 6005+dit(bf(-A, --acls)) This option causes rsync to update the destination 6006+ACLs to be the same as the source ACLs. This nonstandard option only 6007+works if the remote rsync also supports it. bf(--acls) implies bf(--perms). 6008+ 6009+Note also that an optimization of the ACL-sending protocol used by this 6010+version makes it incompatible with sending files to an older ACL-enabled 6011+rsync unless you double the bf(--acls) option (e.g. bf(-AA)). This 6012+doubling is not needed when pulling files from an older rsync. 6013+ 6014 dit(bf(--chmod)) This option tells rsync to apply one or more 6015 comma-separated "chmod" strings to the permission of the files in the 6016 transfer. The resulting value is treated as though it was the permissions 6017@@ -1389,8 +1403,8 @@ if the receiving rsync is at least versi 6018 with older versions of rsync, but that also turns on the output of other 6019 verbose messages). 6020 6021-The "%i" escape has a cryptic output that is 9 letters long. The general 6022-format is like the string bf(YXcstpogz), where bf(Y) is replaced by the 6023+The "%i" escape has a cryptic output that is 11 letters long. The general 6024+format is like the string bf(YXcstpoguax), where bf(Y) is replaced by the 6025 type of update being done, bf(X) is replaced by the file-type, and the 6026 other letters represent attributes that may be output if they are being 6027 modified. 6028@@ -1439,7 +1453,11 @@ quote(itemization( 6029 sender's value (requires bf(--owner) and super-user privileges). 6030 it() A bf(g) means the group is different and is being updated to the 6031 sender's value (requires bf(--group) and the authority to set the group). 6032- it() The bf(z) slot is reserved for future use. 6033+ it() The bf(u) slot is reserved for reporting update (access) time changes 6034+ (a feature that is not yet released). 6035+ it() The bf(a) means that the ACL information changed. 6036+ it() The bf(x) slot is reserved for reporting extended attribute changes 6037+ (a feature that is not yet released). 6038 )) 6039 6040 One other output is possible: when deleting files, the "%i" will output 6041--- old/smb_acls.h 6042+++ new/smb_acls.h 6043@@ -0,0 +1,281 @@ 6044+/* 6045+ Unix SMB/Netbios implementation. 6046+ Version 2.2.x 6047+ Portable SMB ACL interface 6048+ Copyright (C) Jeremy Allison 2000 6049+ 6050+ This program is free software; you can redistribute it and/or modify 6051+ it under the terms of the GNU General Public License as published by 6052+ the Free Software Foundation; either version 2 of the License, or 6053+ (at your option) any later version. 6054+ 6055+ This program is distributed in the hope that it will be useful, 6056+ but WITHOUT ANY WARRANTY; without even the implied warranty of 6057+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 6058+ GNU General Public License for more details. 6059+ 6060+ You should have received a copy of the GNU General Public License 6061+ along with this program; if not, write to the Free Software 6062+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 6063+*/ 6064+ 6065+#ifndef _SMB_ACLS_H 6066+#define _SMB_ACLS_H 6067+ 6068+#if defined HAVE_POSIX_ACLS 6069+ 6070+/* This is an identity mapping (just remove the SMB_). */ 6071+ 6072+#define SMB_ACL_TAG_T acl_tag_t 6073+#define SMB_ACL_TYPE_T acl_type_t 6074+#define SMB_ACL_PERMSET_T acl_permset_t 6075+#define SMB_ACL_PERM_T acl_perm_t 6076+#define SMB_ACL_READ ACL_READ 6077+#define SMB_ACL_WRITE ACL_WRITE 6078+#define SMB_ACL_EXECUTE ACL_EXECUTE 6079+ 6080+/* Types of ACLs. */ 6081+#define SMB_ACL_USER ACL_USER 6082+#define SMB_ACL_USER_OBJ ACL_USER_OBJ 6083+#define SMB_ACL_GROUP ACL_GROUP 6084+#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ 6085+#define SMB_ACL_OTHER ACL_OTHER 6086+#define SMB_ACL_MASK ACL_MASK 6087+ 6088+#define SMB_ACL_T acl_t 6089+ 6090+#define SMB_ACL_ENTRY_T acl_entry_t 6091+ 6092+#define SMB_ACL_FIRST_ENTRY ACL_FIRST_ENTRY 6093+#define SMB_ACL_NEXT_ENTRY ACL_NEXT_ENTRY 6094+ 6095+#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS 6096+#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT 6097+ 6098+#elif defined HAVE_TRU64_ACLS 6099+ 6100+/* This is for DEC/Compaq Tru64 UNIX */ 6101+ 6102+#define SMB_ACL_TAG_T acl_tag_t 6103+#define SMB_ACL_TYPE_T acl_type_t 6104+#define SMB_ACL_PERMSET_T acl_permset_t 6105+#define SMB_ACL_PERM_T acl_perm_t 6106+#define SMB_ACL_READ ACL_READ 6107+#define SMB_ACL_WRITE ACL_WRITE 6108+#define SMB_ACL_EXECUTE ACL_EXECUTE 6109+ 6110+/* Types of ACLs. */ 6111+#define SMB_ACL_USER ACL_USER 6112+#define SMB_ACL_USER_OBJ ACL_USER_OBJ 6113+#define SMB_ACL_GROUP ACL_GROUP 6114+#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ 6115+#define SMB_ACL_OTHER ACL_OTHER 6116+#define SMB_ACL_MASK ACL_MASK 6117+ 6118+#define SMB_ACL_T acl_t 6119+ 6120+#define SMB_ACL_ENTRY_T acl_entry_t 6121+ 6122+#define SMB_ACL_FIRST_ENTRY 0 6123+#define SMB_ACL_NEXT_ENTRY 1 6124+ 6125+#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS 6126+#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT 6127+ 6128+#elif defined HAVE_UNIXWARE_ACLS || defined HAVE_SOLARIS_ACLS 6129+/* 6130+ * Donated by Michael Davidson <md@sco.COM> for UnixWare / OpenUNIX. 6131+ * Modified by Toomas Soome <tsoome@ut.ee> for Solaris. 6132+ */ 6133+ 6134+/* SVR4.2 ES/MP ACLs */ 6135+typedef int SMB_ACL_TAG_T; 6136+typedef int SMB_ACL_TYPE_T; 6137+typedef ushort *SMB_ACL_PERMSET_T; 6138+typedef ushort SMB_ACL_PERM_T; 6139+#define SMB_ACL_READ 4 6140+#define SMB_ACL_WRITE 2 6141+#define SMB_ACL_EXECUTE 1 6142+ 6143+/* Types of ACLs. */ 6144+#define SMB_ACL_USER USER 6145+#define SMB_ACL_USER_OBJ USER_OBJ 6146+#define SMB_ACL_GROUP GROUP 6147+#define SMB_ACL_GROUP_OBJ GROUP_OBJ 6148+#define SMB_ACL_OTHER OTHER_OBJ 6149+#define SMB_ACL_MASK CLASS_OBJ 6150+ 6151+typedef struct SMB_ACL_T { 6152+ int size; 6153+ int count; 6154+ int next; 6155+ struct acl acl[1]; 6156+} *SMB_ACL_T; 6157+ 6158+typedef struct acl *SMB_ACL_ENTRY_T; 6159+ 6160+#define SMB_ACL_FIRST_ENTRY 0 6161+#define SMB_ACL_NEXT_ENTRY 1 6162+ 6163+#define SMB_ACL_TYPE_ACCESS 0 6164+#define SMB_ACL_TYPE_DEFAULT 1 6165+ 6166+#ifdef __CYGWIN__ 6167+#define SMB_ACL_LOSES_SPECIAL_MODE_BITS 6168+#endif 6169+ 6170+#elif defined HAVE_HPUX_ACLS 6171+ 6172+/* 6173+ * Based on the Solaris & UnixWare code. 6174+ */ 6175+ 6176+#undef GROUP 6177+#include <sys/aclv.h> 6178+ 6179+/* SVR4.2 ES/MP ACLs */ 6180+typedef int SMB_ACL_TAG_T; 6181+typedef int SMB_ACL_TYPE_T; 6182+typedef ushort *SMB_ACL_PERMSET_T; 6183+typedef ushort SMB_ACL_PERM_T; 6184+#define SMB_ACL_READ 4 6185+#define SMB_ACL_WRITE 2 6186+#define SMB_ACL_EXECUTE 1 6187+ 6188+/* Types of ACLs. */ 6189+#define SMB_ACL_USER USER 6190+#define SMB_ACL_USER_OBJ USER_OBJ 6191+#define SMB_ACL_GROUP GROUP 6192+#define SMB_ACL_GROUP_OBJ GROUP_OBJ 6193+#define SMB_ACL_OTHER OTHER_OBJ 6194+#define SMB_ACL_MASK CLASS_OBJ 6195+ 6196+typedef struct SMB_ACL_T { 6197+ int size; 6198+ int count; 6199+ int next; 6200+ struct acl acl[1]; 6201+} *SMB_ACL_T; 6202+ 6203+typedef struct acl *SMB_ACL_ENTRY_T; 6204+ 6205+#define SMB_ACL_FIRST_ENTRY 0 6206+#define SMB_ACL_NEXT_ENTRY 1 6207+ 6208+#define SMB_ACL_TYPE_ACCESS 0 6209+#define SMB_ACL_TYPE_DEFAULT 1 6210+ 6211+#elif defined HAVE_IRIX_ACLS 6212+ 6213+#define SMB_ACL_TAG_T acl_tag_t 6214+#define SMB_ACL_TYPE_T acl_type_t 6215+#define SMB_ACL_PERMSET_T acl_permset_t 6216+#define SMB_ACL_PERM_T acl_perm_t 6217+#define SMB_ACL_READ ACL_READ 6218+#define SMB_ACL_WRITE ACL_WRITE 6219+#define SMB_ACL_EXECUTE ACL_EXECUTE 6220+ 6221+/* Types of ACLs. */ 6222+#define SMB_ACL_USER ACL_USER 6223+#define SMB_ACL_USER_OBJ ACL_USER_OBJ 6224+#define SMB_ACL_GROUP ACL_GROUP 6225+#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ 6226+#define SMB_ACL_OTHER ACL_OTHER_OBJ 6227+#define SMB_ACL_MASK ACL_MASK 6228+ 6229+typedef struct SMB_ACL_T { 6230+ int next; 6231+ BOOL freeaclp; 6232+ struct acl *aclp; 6233+} *SMB_ACL_T; 6234+ 6235+#define SMB_ACL_ENTRY_T acl_entry_t 6236+ 6237+#define SMB_ACL_FIRST_ENTRY 0 6238+#define SMB_ACL_NEXT_ENTRY 1 6239+ 6240+#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS 6241+#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT 6242+ 6243+#elif defined HAVE_AIX_ACLS 6244+ 6245+/* Donated by Medha Date, mdate@austin.ibm.com, for IBM */ 6246+ 6247+#include "/usr/include/acl.h" 6248+ 6249+typedef uint *SMB_ACL_PERMSET_T; 6250+ 6251+struct acl_entry_link{ 6252+ struct acl_entry_link *prevp; 6253+ struct new_acl_entry *entryp; 6254+ struct acl_entry_link *nextp; 6255+ int count; 6256+}; 6257+ 6258+struct new_acl_entry{ 6259+ unsigned short ace_len; 6260+ unsigned short ace_type; 6261+ unsigned int ace_access; 6262+ struct ace_id ace_id[1]; 6263+}; 6264+ 6265+#define SMB_ACL_ENTRY_T struct new_acl_entry* 6266+#define SMB_ACL_T struct acl_entry_link* 6267+ 6268+#define SMB_ACL_TAG_T unsigned short 6269+#define SMB_ACL_TYPE_T int 6270+#define SMB_ACL_PERM_T uint 6271+#define SMB_ACL_READ S_IRUSR 6272+#define SMB_ACL_WRITE S_IWUSR 6273+#define SMB_ACL_EXECUTE S_IXUSR 6274+ 6275+/* Types of ACLs. */ 6276+#define SMB_ACL_USER ACEID_USER 6277+#define SMB_ACL_USER_OBJ 3 6278+#define SMB_ACL_GROUP ACEID_GROUP 6279+#define SMB_ACL_GROUP_OBJ 4 6280+#define SMB_ACL_OTHER 5 6281+#define SMB_ACL_MASK 6 6282+ 6283+ 6284+#define SMB_ACL_FIRST_ENTRY 1 6285+#define SMB_ACL_NEXT_ENTRY 2 6286+ 6287+#define SMB_ACL_TYPE_ACCESS 0 6288+#define SMB_ACL_TYPE_DEFAULT 1 6289+ 6290+#else /* No ACLs. */ 6291+ 6292+/* No ACLS - fake it. */ 6293+#define SMB_ACL_TAG_T int 6294+#define SMB_ACL_TYPE_T int 6295+#define SMB_ACL_PERMSET_T mode_t 6296+#define SMB_ACL_PERM_T mode_t 6297+#define SMB_ACL_READ S_IRUSR 6298+#define SMB_ACL_WRITE S_IWUSR 6299+#define SMB_ACL_EXECUTE S_IXUSR 6300+ 6301+/* Types of ACLs. */ 6302+#define SMB_ACL_USER 0 6303+#define SMB_ACL_USER_OBJ 1 6304+#define SMB_ACL_GROUP 2 6305+#define SMB_ACL_GROUP_OBJ 3 6306+#define SMB_ACL_OTHER 4 6307+#define SMB_ACL_MASK 5 6308+ 6309+typedef struct SMB_ACL_T { 6310+ int dummy; 6311+} *SMB_ACL_T; 6312+ 6313+typedef struct SMB_ACL_ENTRY_T { 6314+ int dummy; 6315+} *SMB_ACL_ENTRY_T; 6316+ 6317+#define SMB_ACL_FIRST_ENTRY 0 6318+#define SMB_ACL_NEXT_ENTRY 1 6319+ 6320+#define SMB_ACL_TYPE_ACCESS 0 6321+#define SMB_ACL_TYPE_DEFAULT 1 6322+ 6323+#endif /* No ACLs. */ 6324+#endif /* _SMB_ACLS_H */ 6325--- old/testsuite/acls.test 6326+++ new/testsuite/acls.test 6327@@ -0,0 +1,34 @@ 6328+#! /bin/sh 6329+ 6330+# This program is distributable under the terms of the GNU GPL (see 6331+# COPYING). 6332+ 6333+# Test that rsync handles basic ACL preservation. 6334+ 6335+. $srcdir/testsuite/rsync.fns 6336+ 6337+$RSYNC --version | grep ", ACLs" >/dev/null || test_skipped "Rsync is configured without ACL support" 6338+case "$setfacl_nodef" in 6339+true) test_skipped "I don't know how to use your setfacl command" ;; 6340+esac 6341+ 6342+makepath "$fromdir/foo" 6343+echo something >"$fromdir/file1" 6344+echo else >"$fromdir/file2" 6345+ 6346+files='foo file1 file2' 6347+ 6348+setfacl -m u:0:7 "$fromdir/foo" || test_skipped "Your filesystem has ACLs disabled" 6349+setfacl -m u:0:5 "$fromdir/file1" 6350+setfacl -m u:0:5 "$fromdir/file2" 6351+ 6352+$RSYNC -avvA "$fromdir/" "$todir/" 6353+ 6354+cd "$fromdir" 6355+getfacl $files >"$scratchdir/acls.txt" 6356+ 6357+cd "$todir" 6358+getfacl $files | diff $diffopt "$scratchdir/acls.txt" - 6359+ 6360+# The script would have aborted on error, so getting here means we've won. 6361+exit 0 6362--- old/testsuite/default-acls.test 6363+++ new/testsuite/default-acls.test 6364@@ -0,0 +1,65 @@ 6365+#! /bin/sh 6366+ 6367+# This program is distributable under the terms of the GNU GPL (see 6368+# COPYING). 6369+ 6370+# Test that rsync obeys default ACLs. -- Matt McCutchen 6371+ 6372+. $srcdir/testsuite/rsync.fns 6373+ 6374+$RSYNC --version | grep ", ACLs" >/dev/null || test_skipped "Rsync is configured without ACL support" 6375+case "$setfacl_nodef" in 6376+true) test_skipped "I don't know how to use your setfacl command" ;; 6377+*-k*) opts='-dm u::7,g::5,o:5' ;; 6378+*) opts='-m d:u::7,d:g::5,d:o:5' ;; 6379+esac 6380+setfacl $opts "$scratchdir" || test_skipped "Your filesystem has ACLs disabled" 6381+ 6382+# Call as: testit <dirname> <default-acl> <file-expected> <program-expected> 6383+testit() { 6384+ todir="$scratchdir/$1" 6385+ mkdir "$todir" 6386+ $setfacl_nodef "$todir" 6387+ if [ "$2" ]; then 6388+ case "$setfacl_nodef" in 6389+ *-k*) opts="-dm $2" ;; 6390+ *) opts="-m `echo $2 | sed 's/\([ugom]:\)/d:\1/g'`" 6391+ esac 6392+ setfacl $opts "$todir" 6393+ fi 6394+ # Make sure we obey ACLs when creating a directory to hold multiple transferred files, 6395+ # even though the directory itself is outside the transfer 6396+ $RSYNC -rvv "$scratchdir/dir" "$scratchdir/file" "$scratchdir/program" "$todir/to/" 6397+ check_perms "$todir/to" $4 "Target $1" 6398+ check_perms "$todir/to/dir" $4 "Target $1" 6399+ check_perms "$todir/to/file" $3 "Target $1" 6400+ check_perms "$todir/to/program" $4 "Target $1" 6401+ # Make sure get_local_name doesn't mess us up when transferring only one file 6402+ $RSYNC -rvv "$scratchdir/file" "$todir/to/anotherfile" 6403+ check_perms "$todir/to/anotherfile" $3 "Target $1" 6404+ # Make sure we obey default ACLs when not transferring a regular file 6405+ $RSYNC -rvv "$scratchdir/dir/" "$todir/to/anotherdir/" 6406+ check_perms "$todir/to/anotherdir" $4 "Target $1" 6407+} 6408+ 6409+mkdir "$scratchdir/dir" 6410+echo "File!" >"$scratchdir/file" 6411+echo "#!/bin/sh" >"$scratchdir/program" 6412+chmod 777 "$scratchdir/dir" 6413+chmod 666 "$scratchdir/file" 6414+chmod 777 "$scratchdir/program" 6415+ 6416+# Test some target directories 6417+umask 0077 6418+testit da777 u::7,g::7,o:7 rw-rw-rw- rwxrwxrwx 6419+testit da775 u::7,g::7,o:5 rw-rw-r-- rwxrwxr-x 6420+testit da750 u::7,g::5,o:0 rw-r----- rwxr-x--- 6421+testit da770mask u::7,u:0:7,g::0,m:7,o:0 rw-rw---- rwxrwx--- 6422+testit noda1 '' rw------- rwx------ 6423+umask 0000 6424+testit noda2 '' rw-rw-rw- rwxrwxrwx 6425+umask 0022 6426+testit noda3 '' rw-r--r-- rwxr-xr-x 6427+ 6428+# Hooray 6429+exit 0 6430--- old/testsuite/devices.test 6431+++ new/testsuite/devices.test 6432@@ -42,14 +42,14 @@ touch -r "$fromdir/block" "$fromdir/bloc 6433 $RSYNC -ai "$fromdir/block" "$todir/block2" \ 6434 | tee "$outfile" 6435 cat <<EOT >"$chkfile" 6436-cD+++++++ block 6437+cD+++++++++ block 6438 EOT 6439 diff $diffopt "$chkfile" "$outfile" || test_fail "test 1 failed" 6440 6441 $RSYNC -ai "$fromdir/block2" "$todir/block" \ 6442 | tee "$outfile" 6443 cat <<EOT >"$chkfile" 6444-cD+++++++ block2 6445+cD+++++++++ block2 6446 EOT 6447 diff $diffopt "$chkfile" "$outfile" || test_fail "test 2 failed" 6448 6449@@ -58,7 +58,7 @@ sleep 1 6450 $RSYNC -Di "$fromdir/block3" "$todir/block" \ 6451 | tee "$outfile" 6452 cat <<EOT >"$chkfile" 6453-cD..T.... block3 6454+cD..T...... block3 6455 EOT 6456 diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed" 6457 6458@@ -66,15 +66,15 @@ $RSYNC -aiHvv "$fromdir/" "$todir/" \ 6459 | tee "$outfile" 6460 filter_outfile 6461 cat <<EOT >"$chkfile" 6462-.d..t.... ./ 6463-cD..t.... block 6464-cD....... block2 6465-cD+++++++ block3 6466-hD+++++++ block2.5 => block3 6467-cD+++++++ char 6468-cD+++++++ char2 6469-cD+++++++ char3 6470-cS+++++++ fifo 6471+.d..t...... ./ 6472+cD..t...... block 6473+cD......... block2 6474+cD+++++++++ block3 6475+hD+++++++++ block2.5 => block3 6476+cD+++++++++ char 6477+cD+++++++++ char2 6478+cD+++++++++ char3 6479+cS+++++++++ fifo 6480 EOT 6481 if test ! -b "$fromdir/block2.5"; then 6482 sed -e '/block2\.5/d' \ 6483--- old/testsuite/itemize.test 6484+++ new/testsuite/itemize.test 6485@@ -29,15 +29,15 @@ ln "$fromdir/foo/config1" "$fromdir/foo/ 6486 $RSYNC -iplr "$fromdir/" "$todir/" \ 6487 | tee "$outfile" 6488 cat <<EOT >"$chkfile" 6489-cd+++++++ ./ 6490-cd+++++++ bar/ 6491-cd+++++++ bar/baz/ 6492->f+++++++ bar/baz/rsync 6493-cd+++++++ foo/ 6494->f+++++++ foo/config1 6495->f+++++++ foo/config2 6496->f+++++++ foo/extra 6497-cL+++++++ foo/sym -> ../bar/baz/rsync 6498+cd+++++++++ ./ 6499+cd+++++++++ bar/ 6500+cd+++++++++ bar/baz/ 6501+>f+++++++++ bar/baz/rsync 6502+cd+++++++++ foo/ 6503+>f+++++++++ foo/config1 6504+>f+++++++++ foo/config2 6505+>f+++++++++ foo/extra 6506+cL+++++++++ foo/sym -> ../bar/baz/rsync 6507 EOT 6508 diff $diffopt "$chkfile" "$outfile" || test_fail "test 1 failed" 6509 6510@@ -49,10 +49,10 @@ chmod 601 "$fromdir/foo/config2" 6511 $RSYNC -iplrH "$fromdir/" "$todir/" \ 6512 | tee "$outfile" 6513 cat <<EOT >"$chkfile" 6514->f..T.... bar/baz/rsync 6515->f..T.... foo/config1 6516->f.sTp... foo/config2 6517-hf..T.... foo/extra => foo/config1 6518+>f..T...... bar/baz/rsync 6519+>f..T...... foo/config1 6520+>f.sTp..... foo/config2 6521+hf..T...... foo/extra => foo/config1 6522 EOT 6523 diff $diffopt "$chkfile" "$outfile" || test_fail "test 2 failed" 6524 6525@@ -69,11 +69,11 @@ chmod 777 "$todir/bar/baz/rsync" 6526 $RSYNC -iplrtc "$fromdir/" "$todir/" \ 6527 | tee "$outfile" 6528 cat <<EOT >"$chkfile" 6529-.f..tp... bar/baz/rsync 6530-.d..t.... foo/ 6531-.f..t.... foo/config1 6532->fcstp... foo/config2 6533-cL..T.... foo/sym -> ../bar/baz/rsync 6534+.f..tp..... bar/baz/rsync 6535+.d..t...... foo/ 6536+.f..t...... foo/config1 6537+>fcstp..... foo/config2 6538+cL..T...... foo/sym -> ../bar/baz/rsync 6539 EOT 6540 diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed" 6541 6542@@ -98,15 +98,15 @@ $RSYNC -ivvplrtH "$fromdir/" "$todir/" \ 6543 | tee "$outfile" 6544 filter_outfile 6545 cat <<EOT >"$chkfile" 6546-.d ./ 6547-.d bar/ 6548-.d bar/baz/ 6549-.f...p... bar/baz/rsync 6550-.d foo/ 6551-.f foo/config1 6552->f..t.... foo/config2 6553-hf foo/extra 6554-.L foo/sym -> ../bar/baz/rsync 6555+.d ./ 6556+.d bar/ 6557+.d bar/baz/ 6558+.f...p..... bar/baz/rsync 6559+.d foo/ 6560+.f foo/config1 6561+>f..t...... foo/config2 6562+hf foo/extra 6563+.L foo/sym -> ../bar/baz/rsync 6564 EOT 6565 diff $diffopt "$chkfile" "$outfile" || test_fail "test 5 failed" 6566 6567@@ -125,8 +125,8 @@ touch "$todir/foo/config2" 6568 $RSYNC -iplrtH "$fromdir/" "$todir/" \ 6569 | tee "$outfile" 6570 cat <<EOT >"$chkfile" 6571-.f...p... foo/config1 6572->f..t.... foo/config2 6573+.f...p..... foo/config1 6574+>f..t...... foo/config2 6575 EOT 6576 diff $diffopt "$chkfile" "$outfile" || test_fail "test 7 failed" 6577 6578@@ -135,15 +135,15 @@ $RSYNC -ivvplrtH --copy-dest=../ld "$fro 6579 | tee "$outfile" 6580 filter_outfile 6581 cat <<EOT >"$chkfile" 6582-cd+++++++ ./ 6583-cd+++++++ bar/ 6584-cd+++++++ bar/baz/ 6585-cf bar/baz/rsync 6586-cd+++++++ foo/ 6587-cf foo/config1 6588-cf foo/config2 6589-hf foo/extra => foo/config1 6590-cL..T.... foo/sym -> ../bar/baz/rsync 6591+cd+++++++++ ./ 6592+cd+++++++++ bar/ 6593+cd+++++++++ bar/baz/ 6594+cf bar/baz/rsync 6595+cd+++++++++ foo/ 6596+cf foo/config1 6597+cf foo/config2 6598+hf foo/extra => foo/config1 6599+cL..T...... foo/sym -> ../bar/baz/rsync 6600 EOT 6601 diff $diffopt "$chkfile" "$outfile" || test_fail "test 8 failed" 6602 6603@@ -151,11 +151,11 @@ rm -rf "$todir" 6604 $RSYNC -iplrtH --copy-dest=../ld "$fromdir/" "$todir/" \ 6605 | tee "$outfile" 6606 cat <<EOT >"$chkfile" 6607-cd+++++++ ./ 6608-cd+++++++ bar/ 6609-cd+++++++ bar/baz/ 6610-cd+++++++ foo/ 6611-hf foo/extra => foo/config1 6612+cd+++++++++ ./ 6613+cd+++++++++ bar/ 6614+cd+++++++++ bar/baz/ 6615+cd+++++++++ foo/ 6616+hf foo/extra => foo/config1 6617 EOT 6618 diff $diffopt "$chkfile" "$outfile" || test_fail "test 9 failed" 6619 6620@@ -182,15 +182,15 @@ $RSYNC -ivvplrtH --link-dest="$lddir" "$ 6621 | tee "$outfile" 6622 filter_outfile 6623 cat <<EOT >"$chkfile" 6624-cd+++++++ ./ 6625-cd+++++++ bar/ 6626-cd+++++++ bar/baz/ 6627-hf bar/baz/rsync 6628-cd+++++++ foo/ 6629-hf foo/config1 6630-hf foo/config2 6631-hf foo/extra => foo/config1 6632-hL foo/sym -> ../bar/baz/rsync 6633+cd+++++++++ ./ 6634+cd+++++++++ bar/ 6635+cd+++++++++ bar/baz/ 6636+hf bar/baz/rsync 6637+cd+++++++++ foo/ 6638+hf foo/config1 6639+hf foo/config2 6640+hf foo/extra => foo/config1 6641+hL foo/sym -> ../bar/baz/rsync 6642 EOT 6643 diff $diffopt "$chkfile" "$outfile" || test_fail "test 11 failed" 6644 6645@@ -198,10 +198,10 @@ rm -rf "$todir" 6646 $RSYNC -iplrtH --dry-run --link-dest=../ld "$fromdir/" "$todir/" \ 6647 | tee "$outfile" 6648 cat <<EOT >"$chkfile" 6649-cd+++++++ ./ 6650-cd+++++++ bar/ 6651-cd+++++++ bar/baz/ 6652-cd+++++++ foo/ 6653+cd+++++++++ ./ 6654+cd+++++++++ bar/ 6655+cd+++++++++ bar/baz/ 6656+cd+++++++++ foo/ 6657 EOT 6658 diff $diffopt "$chkfile" "$outfile" || test_fail "test 12 failed" 6659 6660@@ -209,10 +209,10 @@ rm -rf "$todir" 6661 $RSYNC -iplrtH --link-dest=../ld "$fromdir/" "$todir/" \ 6662 | tee "$outfile" 6663 cat <<EOT >"$chkfile" 6664-cd+++++++ ./ 6665-cd+++++++ bar/ 6666-cd+++++++ bar/baz/ 6667-cd+++++++ foo/ 6668+cd+++++++++ ./ 6669+cd+++++++++ bar/ 6670+cd+++++++++ bar/baz/ 6671+cd+++++++++ foo/ 6672 EOT 6673 diff $diffopt "$chkfile" "$outfile" || test_fail "test 13 failed" 6674 6675@@ -240,14 +240,14 @@ filter_outfile 6676 # TODO fix really-old problem when combining -H with --compare-dest: 6677 # missing output for foo/extra hard-link (and it might not be updated)! 6678 cat <<EOT >"$chkfile" 6679-cd+++++++ ./ 6680-cd+++++++ bar/ 6681-cd+++++++ bar/baz/ 6682-.f bar/baz/rsync 6683-cd+++++++ foo/ 6684-.f foo/config1 6685-.f foo/config2 6686-.L foo/sym -> ../bar/baz/rsync 6687+cd+++++++++ ./ 6688+cd+++++++++ bar/ 6689+cd+++++++++ bar/baz/ 6690+.f bar/baz/rsync 6691+cd+++++++++ foo/ 6692+.f foo/config1 6693+.f foo/config2 6694+.L foo/sym -> ../bar/baz/rsync 6695 EOT 6696 diff $diffopt "$chkfile" "$outfile" || test_fail "test 15 failed" 6697 6698@@ -255,10 +255,10 @@ rm -rf "$todir" 6699 $RSYNC -iplrtH --compare-dest="$lddir" "$fromdir/" "$todir/" \ 6700 | tee "$outfile" 6701 cat <<EOT >"$chkfile" 6702-cd+++++++ ./ 6703-cd+++++++ bar/ 6704-cd+++++++ bar/baz/ 6705-cd+++++++ foo/ 6706+cd+++++++++ ./ 6707+cd+++++++++ bar/ 6708+cd+++++++++ bar/baz/ 6709+cd+++++++++ foo/ 6710 EOT 6711 diff $diffopt "$chkfile" "$outfile" || test_fail "test 16 failed" 6712 6713--- old/uidlist.c 6714+++ new/uidlist.c 6715@@ -35,6 +35,7 @@ 6716 extern int verbose; 6717 extern int preserve_uid; 6718 extern int preserve_gid; 6719+extern int preserve_acls; 6720 extern int numeric_ids; 6721 extern int am_root; 6722 6723@@ -273,7 +274,7 @@ void send_uid_list(int f) 6724 if (numeric_ids) 6725 return; 6726 6727- if (preserve_uid) { 6728+ if (preserve_uid || preserve_acls) { 6729 int len; 6730 /* we send sequences of uid/byte-length/name */ 6731 for (list = uidlist; list; list = list->next) { 6732@@ -290,7 +291,7 @@ void send_uid_list(int f) 6733 write_int(f, 0); 6734 } 6735 6736- if (preserve_gid) { 6737+ if (preserve_gid || preserve_acls) { 6738 int len; 6739 for (list = gidlist; list; list = list->next) { 6740 if (!list->name) 6741@@ -311,7 +312,7 @@ void recv_uid_list(int f, struct file_li 6742 int id, i; 6743 char *name; 6744 6745- if (preserve_uid && !numeric_ids) { 6746+ if ((preserve_uid || preserve_acls) && !numeric_ids) { 6747 /* read the uid list */ 6748 while ((id = read_int(f)) != 0) { 6749 int len = read_byte(f); 6750@@ -323,7 +324,7 @@ void recv_uid_list(int f, struct file_li 6751 } 6752 } 6753 6754- if (preserve_gid && !numeric_ids) { 6755+ if ((preserve_gid || preserve_acls) && !numeric_ids) { 6756 /* read the gid list */ 6757 while ((id = read_int(f)) != 0) { 6758 int len = read_byte(f); 6759@@ -335,6 +336,16 @@ void recv_uid_list(int f, struct file_li 6760 } 6761 } 6762 6763+#ifdef SUPPORT_ACLS 6764+ if (preserve_acls && !numeric_ids) { 6765+ id_t *id; 6766+ while ((id = next_acl_uid(flist)) != NULL) 6767+ *id = match_uid(*id); 6768+ while ((id = next_acl_gid(flist)) != NULL) 6769+ *id = match_gid(*id); 6770+ } 6771+#endif 6772+ 6773 /* Now convert all the uids/gids from sender values to our values. */ 6774 if (am_root && preserve_uid && !numeric_ids) { 6775 for (i = 0; i < flist->count; i++) 6776--- old/util.c 6777+++ new/util.c 6778@@ -1468,3 +1468,31 @@ int bitbag_next_bit(struct bitbag *bb, i 6779 6780 return -1; 6781 } 6782+ 6783+void *expand_item_list(item_list *lp, size_t item_size, 6784+ const char *desc, int incr) 6785+{ 6786+ /* First time through, 0 <= 0, so list is expanded. */ 6787+ if (lp->malloced <= lp->count) { 6788+ void *new_ptr; 6789+ size_t new_size = lp->malloced; 6790+ if (incr < 0) 6791+ new_size -= incr; /* increase slowly */ 6792+ else if (new_size < (size_t)incr) 6793+ new_size += incr; 6794+ else 6795+ new_size *= 2; 6796+ new_ptr = realloc_array(lp->items, char, new_size * item_size); 6797+ if (verbose >= 4) { 6798+ rprintf(FINFO, "[%s] expand %s to %.0f bytes, did%s move\n", 6799+ who_am_i(), desc, (double)new_size * item_size, 6800+ new_ptr == lp->items ? " not" : ""); 6801+ } 6802+ if (!new_ptr) 6803+ out_of_memory("expand_item_list"); 6804+ 6805+ lp->items = new_ptr; 6806+ lp->malloced = new_size; 6807+ } 6808+ return (char*)lp->items + (lp->count++ * item_size); 6809+} 6810--- old/proto.h 6811+++ new/proto.h 6812@@ -1,6 +1,15 @@ 6813 /* This file is automatically generated with "make proto". DO NOT EDIT */ 6814 6815 int allow_access(char *addr, char *host, char *allow_list, char *deny_list); 6816+void free_acl(statx *sxp); 6817+int get_acl(const char *fname, statx *sxp); 6818+void send_acl(statx *sxp, int f); 6819+void receive_acl(struct file_struct *file, int f); 6820+void cache_acl(struct file_struct *file, statx *sxp); 6821+int set_acl(const char *fname, const struct file_struct *file, statx *sxp); 6822+id_t *next_acl_uid(); 6823+id_t *next_acl_gid(); 6824+int default_perms_for_dir(const char *dir); 6825 void base64_encode(char *buf, int len, char *out, int pad); 6826 char *auth_server(int f_in, int f_out, int module, char *host, char *addr, 6827 char *leader); 6828@@ -83,18 +92,18 @@ int f_name_cmp(struct file_struct *f1, s 6829 char *f_name(struct file_struct *f, char *fbuf); 6830 struct file_list *get_dirlist(char *dirname, int dlen, 6831 int ignore_filter_rules); 6832-int unchanged_attrs(struct file_struct *file, STRUCT_STAT *st); 6833-void itemize(struct file_struct *file, int ndx, int statret, STRUCT_STAT *st, 6834+int unchanged_attrs(struct file_struct *file, statx *sxp); 6835+void itemize(struct file_struct *file, int ndx, int statret, statx *sxp, 6836 int32 iflags, uchar fnamecmp_type, char *xname); 6837 int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st); 6838 void check_for_finished_hlinks(int itemizing, enum logcode code); 6839 void generate_files(int f_out, struct file_list *flist, char *local_name); 6840 void init_hard_links(void); 6841 int hard_link_check(struct file_struct *file, int ndx, char *fname, 6842- int statret, STRUCT_STAT *st, int itemizing, 6843+ int statret, statx *sxp, int itemizing, 6844 enum logcode code, int skip); 6845 int hard_link_one(struct file_struct *file, int ndx, char *fname, 6846- int statret, STRUCT_STAT *st, char *toname, int terse, 6847+ int statret, statx *sxp, char *toname, int terse, 6848 int itemizing, enum logcode code); 6849 void hard_link_cluster(struct file_struct *file, int master, int itemizing, 6850 enum logcode code); 6851@@ -223,8 +232,9 @@ void show_progress(OFF_T ofs, OFF_T size 6852 int recv_files(int f_in, struct file_list *flist, char *local_name); 6853 void setup_iconv(); 6854 void free_sums(struct sum_struct *s); 6855-mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int exists); 6856-int set_file_attrs(char *fname, struct file_struct *file, STRUCT_STAT *st, 6857+mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms, 6858+ int exists); 6859+int set_file_attrs(char *fname, struct file_struct *file, statx *sxp, 6860 int flags); 6861 RETSIGTYPE sig_int(UNUSED(int val)); 6862 void finish_transfer(char *fname, char *fnametmp, char *partialptr, 6863@@ -320,4 +330,6 @@ void bitbag_set_bit(struct bitbag *bb, i 6864 void bitbag_clear_bit(struct bitbag *bb, int ndx); 6865 int bitbag_check_bit(struct bitbag *bb, int ndx); 6866 int bitbag_next_bit(struct bitbag *bb, int after); 6867+void *expand_item_list(item_list *lp, size_t item_size, 6868+ const char *desc, int incr); 6869 int sys_gettimeofday(struct timeval *tv); 6870--- old/configure 6871+++ new/configure 6872@@ -1258,6 +1258,7 @@ Optional Features: 6873 --disable-largefile omit support for large files 6874 --disable-ipv6 don't even try to use IPv6 6875 --disable-locale turn off locale features 6876+ --enable-acl-support Include ACL support (default=no) 6877 6878 Optional Packages: 6879 --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] 6880@@ -12941,6 +12942,206 @@ fi 6881 fi 6882 6883 6884+for ac_func in aclsort 6885+do 6886+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` 6887+{ echo "$as_me:$LINENO: checking for $ac_func" >&5 6888+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } 6889+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then 6890+ echo $ECHO_N "(cached) $ECHO_C" >&6 6891+else 6892+ cat >conftest.$ac_ext <<_ACEOF 6893+/* confdefs.h. */ 6894+_ACEOF 6895+cat confdefs.h >>conftest.$ac_ext 6896+cat >>conftest.$ac_ext <<_ACEOF 6897+/* end confdefs.h. */ 6898+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func. 6899+ For example, HP-UX 11i <limits.h> declares gettimeofday. */ 6900+#define $ac_func innocuous_$ac_func 6901+ 6902+/* System header to define __stub macros and hopefully few prototypes, 6903+ which can conflict with char $ac_func (); below. 6904+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since 6905+ <limits.h> exists even on freestanding compilers. */ 6906+ 6907+#ifdef __STDC__ 6908+# include <limits.h> 6909+#else 6910+# include <assert.h> 6911+#endif 6912+ 6913+#undef $ac_func 6914+ 6915+/* Override any GCC internal prototype to avoid an error. 6916+ Use char because int might match the return type of a GCC 6917+ builtin and then its argument prototype would still apply. */ 6918+#ifdef __cplusplus 6919+extern "C" 6920+#endif 6921+char $ac_func (); 6922+/* The GNU C library defines this for functions which it implements 6923+ to always fail with ENOSYS. Some functions are actually named 6924+ something starting with __ and the normal name is an alias. */ 6925+#if defined __stub_$ac_func || defined __stub___$ac_func 6926+choke me 6927+#endif 6928+ 6929+int 6930+main () 6931+{ 6932+return $ac_func (); 6933+ ; 6934+ return 0; 6935+} 6936+_ACEOF 6937+rm -f conftest.$ac_objext conftest$ac_exeext 6938+if { (ac_try="$ac_link" 6939+case "(($ac_try" in 6940+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 6941+ *) ac_try_echo=$ac_try;; 6942+esac 6943+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 6944+ (eval "$ac_link") 2>conftest.er1 6945+ ac_status=$? 6946+ grep -v '^ *+' conftest.er1 >conftest.err 6947+ rm -f conftest.er1 6948+ cat conftest.err >&5 6949+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 6950+ (exit $ac_status); } && 6951+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' 6952+ { (case "(($ac_try" in 6953+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 6954+ *) ac_try_echo=$ac_try;; 6955+esac 6956+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 6957+ (eval "$ac_try") 2>&5 6958+ ac_status=$? 6959+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 6960+ (exit $ac_status); }; } && 6961+ { ac_try='test -s conftest$ac_exeext' 6962+ { (case "(($ac_try" in 6963+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 6964+ *) ac_try_echo=$ac_try;; 6965+esac 6966+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 6967+ (eval "$ac_try") 2>&5 6968+ ac_status=$? 6969+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 6970+ (exit $ac_status); }; }; then 6971+ eval "$as_ac_var=yes" 6972+else 6973+ echo "$as_me: failed program was:" >&5 6974+sed 's/^/| /' conftest.$ac_ext >&5 6975+ 6976+ eval "$as_ac_var=no" 6977+fi 6978+ 6979+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ 6980+ conftest$ac_exeext conftest.$ac_ext 6981+fi 6982+ac_res=`eval echo '${'$as_ac_var'}'` 6983+ { echo "$as_me:$LINENO: result: $ac_res" >&5 6984+echo "${ECHO_T}$ac_res" >&6; } 6985+if test `eval echo '${'$as_ac_var'}'` = yes; then 6986+ cat >>confdefs.h <<_ACEOF 6987+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 6988+_ACEOF 6989+ 6990+fi 6991+done 6992+ 6993+if test x"$ac_cv_func_aclsort" = x"no"; then 6994+ 6995+{ echo "$as_me:$LINENO: checking for aclsort in -lsec" >&5 6996+echo $ECHO_N "checking for aclsort in -lsec... $ECHO_C" >&6; } 6997+if test "${ac_cv_lib_sec_aclsort+set}" = set; then 6998+ echo $ECHO_N "(cached) $ECHO_C" >&6 6999+else 7000+ ac_check_lib_save_LIBS=$LIBS 7001+LIBS="-lsec $LIBS" 7002+cat >conftest.$ac_ext <<_ACEOF 7003+/* confdefs.h. */ 7004+_ACEOF 7005+cat confdefs.h >>conftest.$ac_ext 7006+cat >>conftest.$ac_ext <<_ACEOF 7007+/* end confdefs.h. */ 7008+ 7009+/* Override any GCC internal prototype to avoid an error. 7010+ Use char because int might match the return type of a GCC 7011+ builtin and then its argument prototype would still apply. */ 7012+#ifdef __cplusplus 7013+extern "C" 7014+#endif 7015+char aclsort (); 7016+int 7017+main () 7018+{ 7019+return aclsort (); 7020+ ; 7021+ return 0; 7022+} 7023+_ACEOF 7024+rm -f conftest.$ac_objext conftest$ac_exeext 7025+if { (ac_try="$ac_link" 7026+case "(($ac_try" in 7027+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 7028+ *) ac_try_echo=$ac_try;; 7029+esac 7030+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 7031+ (eval "$ac_link") 2>conftest.er1 7032+ ac_status=$? 7033+ grep -v '^ *+' conftest.er1 >conftest.err 7034+ rm -f conftest.er1 7035+ cat conftest.err >&5 7036+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 7037+ (exit $ac_status); } && 7038+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' 7039+ { (case "(($ac_try" in 7040+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 7041+ *) ac_try_echo=$ac_try;; 7042+esac 7043+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 7044+ (eval "$ac_try") 2>&5 7045+ ac_status=$? 7046+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 7047+ (exit $ac_status); }; } && 7048+ { ac_try='test -s conftest$ac_exeext' 7049+ { (case "(($ac_try" in 7050+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 7051+ *) ac_try_echo=$ac_try;; 7052+esac 7053+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 7054+ (eval "$ac_try") 2>&5 7055+ ac_status=$? 7056+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 7057+ (exit $ac_status); }; }; then 7058+ ac_cv_lib_sec_aclsort=yes 7059+else 7060+ echo "$as_me: failed program was:" >&5 7061+sed 's/^/| /' conftest.$ac_ext >&5 7062+ 7063+ ac_cv_lib_sec_aclsort=no 7064+fi 7065+ 7066+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ 7067+ conftest$ac_exeext conftest.$ac_ext 7068+LIBS=$ac_check_lib_save_LIBS 7069+fi 7070+{ echo "$as_me:$LINENO: result: $ac_cv_lib_sec_aclsort" >&5 7071+echo "${ECHO_T}$ac_cv_lib_sec_aclsort" >&6; } 7072+if test $ac_cv_lib_sec_aclsort = yes; then 7073+ cat >>confdefs.h <<_ACEOF 7074+#define HAVE_LIBSEC 1 7075+_ACEOF 7076+ 7077+ LIBS="-lsec $LIBS" 7078+ 7079+fi 7080+ 7081+fi 7082+ 7083+ 7084 { echo "$as_me:$LINENO: checking whether utime accepts a null argument" >&5 7085 echo $ECHO_N "checking whether utime accepts a null argument... $ECHO_C" >&6; } 7086 if test "${ac_cv_func_utime_null+set}" = set; then 7087@@ -14808,6 +15009,625 @@ fi 7088 7089 7090 7091+ 7092+ 7093+for ac_header in sys/acl.h acl/libacl.h 7094+do 7095+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` 7096+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then 7097+ { echo "$as_me:$LINENO: checking for $ac_header" >&5 7098+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } 7099+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then 7100+ echo $ECHO_N "(cached) $ECHO_C" >&6 7101+fi 7102+ac_res=`eval echo '${'$as_ac_Header'}'` 7103+ { echo "$as_me:$LINENO: result: $ac_res" >&5 7104+echo "${ECHO_T}$ac_res" >&6; } 7105+else 7106+ # Is the header compilable? 7107+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 7108+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } 7109+cat >conftest.$ac_ext <<_ACEOF 7110+/* confdefs.h. */ 7111+_ACEOF 7112+cat confdefs.h >>conftest.$ac_ext 7113+cat >>conftest.$ac_ext <<_ACEOF 7114+/* end confdefs.h. */ 7115+$ac_includes_default 7116+#include <$ac_header> 7117+_ACEOF 7118+rm -f conftest.$ac_objext 7119+if { (ac_try="$ac_compile" 7120+case "(($ac_try" in 7121+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 7122+ *) ac_try_echo=$ac_try;; 7123+esac 7124+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 7125+ (eval "$ac_compile") 2>conftest.er1 7126+ ac_status=$? 7127+ grep -v '^ *+' conftest.er1 >conftest.err 7128+ rm -f conftest.er1 7129+ cat conftest.err >&5 7130+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 7131+ (exit $ac_status); } && 7132+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' 7133+ { (case "(($ac_try" in 7134+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 7135+ *) ac_try_echo=$ac_try;; 7136+esac 7137+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 7138+ (eval "$ac_try") 2>&5 7139+ ac_status=$? 7140+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 7141+ (exit $ac_status); }; } && 7142+ { ac_try='test -s conftest.$ac_objext' 7143+ { (case "(($ac_try" in 7144+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 7145+ *) ac_try_echo=$ac_try;; 7146+esac 7147+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 7148+ (eval "$ac_try") 2>&5 7149+ ac_status=$? 7150+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 7151+ (exit $ac_status); }; }; then 7152+ ac_header_compiler=yes 7153+else 7154+ echo "$as_me: failed program was:" >&5 7155+sed 's/^/| /' conftest.$ac_ext >&5 7156+ 7157+ ac_header_compiler=no 7158+fi 7159+ 7160+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext 7161+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 7162+echo "${ECHO_T}$ac_header_compiler" >&6; } 7163+ 7164+# Is the header present? 7165+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 7166+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } 7167+cat >conftest.$ac_ext <<_ACEOF 7168+/* confdefs.h. */ 7169+_ACEOF 7170+cat confdefs.h >>conftest.$ac_ext 7171+cat >>conftest.$ac_ext <<_ACEOF 7172+/* end confdefs.h. */ 7173+#include <$ac_header> 7174+_ACEOF 7175+if { (ac_try="$ac_cpp conftest.$ac_ext" 7176+case "(($ac_try" in 7177+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 7178+ *) ac_try_echo=$ac_try;; 7179+esac 7180+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 7181+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 7182+ ac_status=$? 7183+ grep -v '^ *+' conftest.er1 >conftest.err 7184+ rm -f conftest.er1 7185+ cat conftest.err >&5 7186+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 7187+ (exit $ac_status); } >/dev/null; then 7188+ if test -s conftest.err; then 7189+ ac_cpp_err=$ac_c_preproc_warn_flag 7190+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag 7191+ else 7192+ ac_cpp_err= 7193+ fi 7194+else 7195+ ac_cpp_err=yes 7196+fi 7197+if test -z "$ac_cpp_err"; then 7198+ ac_header_preproc=yes 7199+else 7200+ echo "$as_me: failed program was:" >&5 7201+sed 's/^/| /' conftest.$ac_ext >&5 7202+ 7203+ ac_header_preproc=no 7204+fi 7205+ 7206+rm -f conftest.err conftest.$ac_ext 7207+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 7208+echo "${ECHO_T}$ac_header_preproc" >&6; } 7209+ 7210+# So? What about this header? 7211+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in 7212+ yes:no: ) 7213+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 7214+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} 7215+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 7216+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} 7217+ ac_header_preproc=yes 7218+ ;; 7219+ no:yes:* ) 7220+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 7221+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} 7222+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 7223+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} 7224+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 7225+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} 7226+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 7227+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} 7228+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 7229+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} 7230+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 7231+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} 7232+ 7233+ ;; 7234+esac 7235+{ echo "$as_me:$LINENO: checking for $ac_header" >&5 7236+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } 7237+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then 7238+ echo $ECHO_N "(cached) $ECHO_C" >&6 7239+else 7240+ eval "$as_ac_Header=\$ac_header_preproc" 7241+fi 7242+ac_res=`eval echo '${'$as_ac_Header'}'` 7243+ { echo "$as_me:$LINENO: result: $ac_res" >&5 7244+echo "${ECHO_T}$ac_res" >&6; } 7245+ 7246+fi 7247+if test `eval echo '${'$as_ac_Header'}'` = yes; then 7248+ cat >>confdefs.h <<_ACEOF 7249+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 7250+_ACEOF 7251+ 7252+fi 7253+ 7254+done 7255+ 7256+ 7257+ 7258+ 7259+ 7260+for ac_func in _acl __acl _facl __facl 7261+do 7262+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` 7263+{ echo "$as_me:$LINENO: checking for $ac_func" >&5 7264+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } 7265+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then 7266+ echo $ECHO_N "(cached) $ECHO_C" >&6 7267+else 7268+ cat >conftest.$ac_ext <<_ACEOF 7269+/* confdefs.h. */ 7270+_ACEOF 7271+cat confdefs.h >>conftest.$ac_ext 7272+cat >>conftest.$ac_ext <<_ACEOF 7273+/* end confdefs.h. */ 7274+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func. 7275+ For example, HP-UX 11i <limits.h> declares gettimeofday. */ 7276+#define $ac_func innocuous_$ac_func 7277+ 7278+/* System header to define __stub macros and hopefully few prototypes, 7279+ which can conflict with char $ac_func (); below. 7280+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since 7281+ <limits.h> exists even on freestanding compilers. */ 7282+ 7283+#ifdef __STDC__ 7284+# include <limits.h> 7285+#else 7286+# include <assert.h> 7287+#endif 7288+ 7289+#undef $ac_func 7290+ 7291+/* Override any GCC internal prototype to avoid an error. 7292+ Use char because int might match the return type of a GCC 7293+ builtin and then its argument prototype would still apply. */ 7294+#ifdef __cplusplus 7295+extern "C" 7296+#endif 7297+char $ac_func (); 7298+/* The GNU C library defines this for functions which it implements 7299+ to always fail with ENOSYS. Some functions are actually named 7300+ something starting with __ and the normal name is an alias. */ 7301+#if defined __stub_$ac_func || defined __stub___$ac_func 7302+choke me 7303+#endif 7304+ 7305+int 7306+main () 7307+{ 7308+return $ac_func (); 7309+ ; 7310+ return 0; 7311+} 7312+_ACEOF 7313+rm -f conftest.$ac_objext conftest$ac_exeext 7314+if { (ac_try="$ac_link" 7315+case "(($ac_try" in 7316+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 7317+ *) ac_try_echo=$ac_try;; 7318+esac 7319+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 7320+ (eval "$ac_link") 2>conftest.er1 7321+ ac_status=$? 7322+ grep -v '^ *+' conftest.er1 >conftest.err 7323+ rm -f conftest.er1 7324+ cat conftest.err >&5 7325+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 7326+ (exit $ac_status); } && 7327+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' 7328+ { (case "(($ac_try" in 7329+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 7330+ *) ac_try_echo=$ac_try;; 7331+esac 7332+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 7333+ (eval "$ac_try") 2>&5 7334+ ac_status=$? 7335+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 7336+ (exit $ac_status); }; } && 7337+ { ac_try='test -s conftest$ac_exeext' 7338+ { (case "(($ac_try" in 7339+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 7340+ *) ac_try_echo=$ac_try;; 7341+esac 7342+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 7343+ (eval "$ac_try") 2>&5 7344+ ac_status=$? 7345+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 7346+ (exit $ac_status); }; }; then 7347+ eval "$as_ac_var=yes" 7348+else 7349+ echo "$as_me: failed program was:" >&5 7350+sed 's/^/| /' conftest.$ac_ext >&5 7351+ 7352+ eval "$as_ac_var=no" 7353+fi 7354+ 7355+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ 7356+ conftest$ac_exeext conftest.$ac_ext 7357+fi 7358+ac_res=`eval echo '${'$as_ac_var'}'` 7359+ { echo "$as_me:$LINENO: result: $ac_res" >&5 7360+echo "${ECHO_T}$ac_res" >&6; } 7361+if test `eval echo '${'$as_ac_var'}'` = yes; then 7362+ cat >>confdefs.h <<_ACEOF 7363+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 7364+_ACEOF 7365+ 7366+fi 7367+done 7368+ 7369+################################################# 7370+# check for ACL support 7371+ 7372+{ echo "$as_me:$LINENO: checking whether to support ACLs" >&5 7373+echo $ECHO_N "checking whether to support ACLs... $ECHO_C" >&6; } 7374+# Check whether --enable-acl-support was given. 7375+if test "${enable_acl_support+set}" = set; then 7376+ enableval=$enable_acl_support; case "$enableval" in 7377+ yes) 7378+ 7379+ case "$host_os" in 7380+ *sysv5*) 7381+ { echo "$as_me:$LINENO: result: Using UnixWare ACLs" >&5 7382+echo "${ECHO_T}Using UnixWare ACLs" >&6; } 7383+ 7384+cat >>confdefs.h <<\_ACEOF 7385+#define HAVE_UNIXWARE_ACLS 1 7386+_ACEOF 7387+ 7388+ ;; 7389+ *solaris*|*cygwin*) 7390+ { echo "$as_me:$LINENO: result: Using solaris ACLs" >&5 7391+echo "${ECHO_T}Using solaris ACLs" >&6; } 7392+ 7393+cat >>confdefs.h <<\_ACEOF 7394+#define HAVE_SOLARIS_ACLS 1 7395+_ACEOF 7396+ 7397+ ;; 7398+ *hpux*) 7399+ { echo "$as_me:$LINENO: result: Using HPUX ACLs" >&5 7400+echo "${ECHO_T}Using HPUX ACLs" >&6; } 7401+ 7402+cat >>confdefs.h <<\_ACEOF 7403+#define HAVE_HPUX_ACLS 1 7404+_ACEOF 7405+ 7406+ ;; 7407+ *irix*) 7408+ { echo "$as_me:$LINENO: result: Using IRIX ACLs" >&5 7409+echo "${ECHO_T}Using IRIX ACLs" >&6; } 7410+ 7411+cat >>confdefs.h <<\_ACEOF 7412+#define HAVE_IRIX_ACLS 1 7413+_ACEOF 7414+ 7415+ ;; 7416+ *aix*) 7417+ { echo "$as_me:$LINENO: result: Using AIX ACLs" >&5 7418+echo "${ECHO_T}Using AIX ACLs" >&6; } 7419+ 7420+cat >>confdefs.h <<\_ACEOF 7421+#define HAVE_AIX_ACLS 1 7422+_ACEOF 7423+ 7424+ ;; 7425+ *osf*) 7426+ { echo "$as_me:$LINENO: result: Using Tru64 ACLs" >&5 7427+echo "${ECHO_T}Using Tru64 ACLs" >&6; } 7428+ 7429+cat >>confdefs.h <<\_ACEOF 7430+#define HAVE_TRU64_ACLS 1 7431+_ACEOF 7432+ 7433+ LIBS="$LIBS -lpacl" 7434+ ;; 7435+ *) 7436+ { echo "$as_me:$LINENO: result: ACLs requested -- running tests" >&5 7437+echo "${ECHO_T}ACLs requested -- running tests" >&6; } 7438+ 7439+{ echo "$as_me:$LINENO: checking for acl_get_file in -lacl" >&5 7440+echo $ECHO_N "checking for acl_get_file in -lacl... $ECHO_C" >&6; } 7441+if test "${ac_cv_lib_acl_acl_get_file+set}" = set; then 7442+ echo $ECHO_N "(cached) $ECHO_C" >&6 7443+else 7444+ ac_check_lib_save_LIBS=$LIBS 7445+LIBS="-lacl $LIBS" 7446+cat >conftest.$ac_ext <<_ACEOF 7447+/* confdefs.h. */ 7448+_ACEOF 7449+cat confdefs.h >>conftest.$ac_ext 7450+cat >>conftest.$ac_ext <<_ACEOF 7451+/* end confdefs.h. */ 7452+ 7453+/* Override any GCC internal prototype to avoid an error. 7454+ Use char because int might match the return type of a GCC 7455+ builtin and then its argument prototype would still apply. */ 7456+#ifdef __cplusplus 7457+extern "C" 7458+#endif 7459+char acl_get_file (); 7460+int 7461+main () 7462+{ 7463+return acl_get_file (); 7464+ ; 7465+ return 0; 7466+} 7467+_ACEOF 7468+rm -f conftest.$ac_objext conftest$ac_exeext 7469+if { (ac_try="$ac_link" 7470+case "(($ac_try" in 7471+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 7472+ *) ac_try_echo=$ac_try;; 7473+esac 7474+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 7475+ (eval "$ac_link") 2>conftest.er1 7476+ ac_status=$? 7477+ grep -v '^ *+' conftest.er1 >conftest.err 7478+ rm -f conftest.er1 7479+ cat conftest.err >&5 7480+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 7481+ (exit $ac_status); } && 7482+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' 7483+ { (case "(($ac_try" in 7484+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 7485+ *) ac_try_echo=$ac_try;; 7486+esac 7487+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 7488+ (eval "$ac_try") 2>&5 7489+ ac_status=$? 7490+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 7491+ (exit $ac_status); }; } && 7492+ { ac_try='test -s conftest$ac_exeext' 7493+ { (case "(($ac_try" in 7494+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 7495+ *) ac_try_echo=$ac_try;; 7496+esac 7497+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 7498+ (eval "$ac_try") 2>&5 7499+ ac_status=$? 7500+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 7501+ (exit $ac_status); }; }; then 7502+ ac_cv_lib_acl_acl_get_file=yes 7503+else 7504+ echo "$as_me: failed program was:" >&5 7505+sed 's/^/| /' conftest.$ac_ext >&5 7506+ 7507+ ac_cv_lib_acl_acl_get_file=no 7508+fi 7509+ 7510+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ 7511+ conftest$ac_exeext conftest.$ac_ext 7512+LIBS=$ac_check_lib_save_LIBS 7513+fi 7514+{ echo "$as_me:$LINENO: result: $ac_cv_lib_acl_acl_get_file" >&5 7515+echo "${ECHO_T}$ac_cv_lib_acl_acl_get_file" >&6; } 7516+if test $ac_cv_lib_acl_acl_get_file = yes; then 7517+ cat >>confdefs.h <<_ACEOF 7518+#define HAVE_LIBACL 1 7519+_ACEOF 7520+ 7521+ LIBS="-lacl $LIBS" 7522+ 7523+fi 7524+ 7525+ { echo "$as_me:$LINENO: checking for ACL support" >&5 7526+echo $ECHO_N "checking for ACL support... $ECHO_C" >&6; } 7527+if test "${samba_cv_HAVE_POSIX_ACLS+set}" = set; then 7528+ echo $ECHO_N "(cached) $ECHO_C" >&6 7529+else 7530+ 7531+ cat >conftest.$ac_ext <<_ACEOF 7532+/* confdefs.h. */ 7533+_ACEOF 7534+cat confdefs.h >>conftest.$ac_ext 7535+cat >>conftest.$ac_ext <<_ACEOF 7536+/* end confdefs.h. */ 7537+#include <sys/types.h> 7538+#include <sys/acl.h> 7539+int 7540+main () 7541+{ 7542+ acl_t acl; int entry_id; acl_entry_t *entry_p; return acl_get_entry( acl, entry_id, entry_p); 7543+ ; 7544+ return 0; 7545+} 7546+_ACEOF 7547+rm -f conftest.$ac_objext conftest$ac_exeext 7548+if { (ac_try="$ac_link" 7549+case "(($ac_try" in 7550+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 7551+ *) ac_try_echo=$ac_try;; 7552+esac 7553+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 7554+ (eval "$ac_link") 2>conftest.er1 7555+ ac_status=$? 7556+ grep -v '^ *+' conftest.er1 >conftest.err 7557+ rm -f conftest.er1 7558+ cat conftest.err >&5 7559+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 7560+ (exit $ac_status); } && 7561+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' 7562+ { (case "(($ac_try" in 7563+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 7564+ *) ac_try_echo=$ac_try;; 7565+esac 7566+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 7567+ (eval "$ac_try") 2>&5 7568+ ac_status=$? 7569+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 7570+ (exit $ac_status); }; } && 7571+ { ac_try='test -s conftest$ac_exeext' 7572+ { (case "(($ac_try" in 7573+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 7574+ *) ac_try_echo=$ac_try;; 7575+esac 7576+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 7577+ (eval "$ac_try") 2>&5 7578+ ac_status=$? 7579+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 7580+ (exit $ac_status); }; }; then 7581+ samba_cv_HAVE_POSIX_ACLS=yes 7582+else 7583+ echo "$as_me: failed program was:" >&5 7584+sed 's/^/| /' conftest.$ac_ext >&5 7585+ 7586+ samba_cv_HAVE_POSIX_ACLS=no 7587+fi 7588+ 7589+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ 7590+ conftest$ac_exeext conftest.$ac_ext 7591+fi 7592+{ echo "$as_me:$LINENO: result: $samba_cv_HAVE_POSIX_ACLS" >&5 7593+echo "${ECHO_T}$samba_cv_HAVE_POSIX_ACLS" >&6; } 7594+ { echo "$as_me:$LINENO: checking ACL test results" >&5 7595+echo $ECHO_N "checking ACL test results... $ECHO_C" >&6; } 7596+ if test x"$samba_cv_HAVE_POSIX_ACLS" = x"yes"; then 7597+ { echo "$as_me:$LINENO: result: Using posix ACLs" >&5 7598+echo "${ECHO_T}Using posix ACLs" >&6; } 7599+ 7600+cat >>confdefs.h <<\_ACEOF 7601+#define HAVE_POSIX_ACLS 1 7602+_ACEOF 7603+ 7604+ { echo "$as_me:$LINENO: checking for acl_get_perm_np" >&5 7605+echo $ECHO_N "checking for acl_get_perm_np... $ECHO_C" >&6; } 7606+if test "${samba_cv_HAVE_ACL_GET_PERM_NP+set}" = set; then 7607+ echo $ECHO_N "(cached) $ECHO_C" >&6 7608+else 7609+ 7610+ cat >conftest.$ac_ext <<_ACEOF 7611+/* confdefs.h. */ 7612+_ACEOF 7613+cat confdefs.h >>conftest.$ac_ext 7614+cat >>conftest.$ac_ext <<_ACEOF 7615+/* end confdefs.h. */ 7616+#include <sys/types.h> 7617+#include <sys/acl.h> 7618+int 7619+main () 7620+{ 7621+ acl_permset_t permset_d; acl_perm_t perm; return acl_get_perm_np( permset_d, perm); 7622+ ; 7623+ return 0; 7624+} 7625+_ACEOF 7626+rm -f conftest.$ac_objext conftest$ac_exeext 7627+if { (ac_try="$ac_link" 7628+case "(($ac_try" in 7629+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 7630+ *) ac_try_echo=$ac_try;; 7631+esac 7632+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 7633+ (eval "$ac_link") 2>conftest.er1 7634+ ac_status=$? 7635+ grep -v '^ *+' conftest.er1 >conftest.err 7636+ rm -f conftest.er1 7637+ cat conftest.err >&5 7638+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 7639+ (exit $ac_status); } && 7640+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' 7641+ { (case "(($ac_try" in 7642+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 7643+ *) ac_try_echo=$ac_try;; 7644+esac 7645+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 7646+ (eval "$ac_try") 2>&5 7647+ ac_status=$? 7648+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 7649+ (exit $ac_status); }; } && 7650+ { ac_try='test -s conftest$ac_exeext' 7651+ { (case "(($ac_try" in 7652+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; 7653+ *) ac_try_echo=$ac_try;; 7654+esac 7655+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 7656+ (eval "$ac_try") 2>&5 7657+ ac_status=$? 7658+ echo "$as_me:$LINENO: \$? = $ac_status" >&5 7659+ (exit $ac_status); }; }; then 7660+ samba_cv_HAVE_ACL_GET_PERM_NP=yes 7661+else 7662+ echo "$as_me: failed program was:" >&5 7663+sed 's/^/| /' conftest.$ac_ext >&5 7664+ 7665+ samba_cv_HAVE_ACL_GET_PERM_NP=no 7666+fi 7667+ 7668+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ 7669+ conftest$ac_exeext conftest.$ac_ext 7670+fi 7671+{ echo "$as_me:$LINENO: result: $samba_cv_HAVE_ACL_GET_PERM_NP" >&5 7672+echo "${ECHO_T}$samba_cv_HAVE_ACL_GET_PERM_NP" >&6; } 7673+ if test x"$samba_cv_HAVE_ACL_GET_PERM_NP" = x"yes"; then 7674+ 7675+cat >>confdefs.h <<\_ACEOF 7676+#define HAVE_ACL_GET_PERM_NP 1 7677+_ACEOF 7678+ 7679+ fi 7680+ else 7681+ { { echo "$as_me:$LINENO: error: Failed to find ACL support" >&5 7682+echo "$as_me: error: Failed to find ACL support" >&2;} 7683+ { (exit 1); exit 1; }; } 7684+ fi 7685+ ;; 7686+ esac 7687+ ;; 7688+ *) 7689+ { echo "$as_me:$LINENO: result: no" >&5 7690+echo "${ECHO_T}no" >&6; } 7691+ 7692+cat >>confdefs.h <<\_ACEOF 7693+#define HAVE_NO_ACLS 1 7694+_ACEOF 7695+ 7696+ ;; 7697+ esac 7698+else 7699+ 7700+cat >>confdefs.h <<\_ACEOF 7701+#define HAVE_NO_ACLS 1 7702+_ACEOF 7703+ 7704+ { echo "$as_me:$LINENO: result: no" >&5 7705+echo "${ECHO_T}no" >&6; } 7706+ 7707+fi 7708+ 7709+ 7710 ac_config_files="$ac_config_files Makefile lib/dummy zlib/dummy popt/dummy shconfig" 7711 7712 cat >confcache <<\_ACEOF 7713--- old/config.h.in 7714+++ new/config.h.in 7715@@ -27,6 +27,18 @@ 7716 /* Define to 1 if the `getpgrp' function requires zero arguments. */ 7717 #undef GETPGRP_VOID 7718 7719+/* Define to 1 if you have the `aclsort' function. */ 7720+#undef HAVE_ACLSORT 7721+ 7722+/* true if you have acl_get_perm_np */ 7723+#undef HAVE_ACL_GET_PERM_NP 7724+ 7725+/* Define to 1 if you have the <acl/libacl.h> header file. */ 7726+#undef HAVE_ACL_LIBACL_H 7727+ 7728+/* true if you have AIX ACLs */ 7729+#undef HAVE_AIX_ACLS 7730+ 7731 /* Define to 1 if you have `alloca', as a function or macro. */ 7732 #undef HAVE_ALLOCA 7733 7734@@ -119,6 +131,9 @@ 7735 /* Define to 1 if you have the <grp.h> header file. */ 7736 #undef HAVE_GRP_H 7737 7738+/* true if you have HPUX ACLs */ 7739+#undef HAVE_HPUX_ACLS 7740+ 7741 /* Define to 1 if you have the <iconv.h> header file. */ 7742 #undef HAVE_ICONV_H 7743 7744@@ -134,6 +149,9 @@ 7745 /* Define to 1 if you have the <inttypes.h> header file. */ 7746 #undef HAVE_INTTYPES_H 7747 7748+/* true if you have IRIX ACLs */ 7749+#undef HAVE_IRIX_ACLS 7750+ 7751 /* Define to 1 if you have the <langinfo.h> header file. */ 7752 #undef HAVE_LANGINFO_H 7753 7754@@ -143,6 +161,9 @@ 7755 /* Define to 1 if you have the `lchown' function. */ 7756 #undef HAVE_LCHOWN 7757 7758+/* Define to 1 if you have the `acl' library (-lacl). */ 7759+#undef HAVE_LIBACL 7760+ 7761 /* Define to 1 if you have the <libcharset.h> header file. */ 7762 #undef HAVE_LIBCHARSET_H 7763 7764@@ -161,6 +182,9 @@ 7765 /* Define to 1 if you have the `resolv' library (-lresolv). */ 7766 #undef HAVE_LIBRESOLV 7767 7768+/* Define to 1 if you have the `sec' library (-lsec). */ 7769+#undef HAVE_LIBSEC 7770+ 7771 /* Define to 1 if you have the `socket' library (-lsocket). */ 7772 #undef HAVE_LIBSOCKET 7773 7774@@ -226,9 +250,15 @@ 7775 /* Define to 1 if you have the `nl_langinfo' function. */ 7776 #undef HAVE_NL_LANGINFO 7777 7778+/* true if you don't have ACLs */ 7779+#undef HAVE_NO_ACLS 7780+ 7781 /* Define to 1 if you have the `open64' function. */ 7782 #undef HAVE_OPEN64 7783 7784+/* true if you have posix ACLs */ 7785+#undef HAVE_POSIX_ACLS 7786+ 7787 /* Define to 1 if you have the `putenv' function. */ 7788 #undef HAVE_PUTENV 7789 7790@@ -280,6 +310,9 @@ 7791 /* Define to 1 if you have the "socketpair" function */ 7792 #undef HAVE_SOCKETPAIR 7793 7794+/* true if you have solaris ACLs */ 7795+#undef HAVE_SOLARIS_ACLS 7796+ 7797 /* Define to 1 if you have the <stdint.h> header file. */ 7798 #undef HAVE_STDINT_H 7799 7800@@ -325,6 +358,9 @@ 7801 /* Define to 1 if `st_rdev' is member of `struct stat'. */ 7802 #undef HAVE_STRUCT_STAT_ST_RDEV 7803 7804+/* Define to 1 if you have the <sys/acl.h> header file. */ 7805+#undef HAVE_SYS_ACL_H 7806+ 7807 /* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'. 7808 */ 7809 #undef HAVE_SYS_DIR_H 7810@@ -375,9 +411,15 @@ 7811 /* Define to 1 if you have the `tcgetpgrp' function. */ 7812 #undef HAVE_TCGETPGRP 7813 7814+/* true if you have Tru64 ACLs */ 7815+#undef HAVE_TRU64_ACLS 7816+ 7817 /* Define to 1 if you have the <unistd.h> header file. */ 7818 #undef HAVE_UNISTD_H 7819 7820+/* true if you have UnixWare ACLs */ 7821+#undef HAVE_UNIXWARE_ACLS 7822+ 7823 /* Define to 1 if you have the "struct utimbuf" type */ 7824 #undef HAVE_UTIMBUF 7825 7826@@ -408,6 +450,18 @@ 7827 /* Define to 1 if you have the `waitpid' function. */ 7828 #undef HAVE_WAITPID 7829 7830+/* Define to 1 if you have the `_acl' function. */ 7831+#undef HAVE__ACL 7832+ 7833+/* Define to 1 if you have the `_facl' function. */ 7834+#undef HAVE__FACL 7835+ 7836+/* Define to 1 if you have the `__acl' function. */ 7837+#undef HAVE___ACL 7838+ 7839+/* Define to 1 if you have the `__facl' function. */ 7840+#undef HAVE___FACL 7841+ 7842 /* Define to 1 if you have the `__va_copy' function. */ 7843 #undef HAVE___VA_COPY 7844 7845--- old/rsync.1 7846+++ new/rsync.1 7847@@ -367,7 +367,7 @@ to the detailed description below for a 7848 \-q, \-\-quiet suppress non-error messages 7849 \-\-no\-motd suppress daemon-mode MOTD (see caveat) 7850 \-c, \-\-checksum skip based on checksum, not mod-time & size 7851- \-a, \-\-archive archive mode; same as \-rlptgoD (no \-H) 7852+ \-a, \-\-archive archive mode; same as \-rlptgoD (no \-H, \-A) 7853 \-\-no\-OPTION turn off an implied OPTION (e\&.g\&. \-\-no\-D) 7854 \-r, \-\-recursive recurse into directories 7855 \-R, \-\-relative use relative path names 7856@@ -389,6 +389,7 @@ to the detailed description below for a 7857 \-p, \-\-perms preserve permissions 7858 \-E, \-\-executability preserve executability 7859 \-\-chmod=CHMOD affect file and/or directory permissions 7860+ \-A, \-\-acls preserve ACLs (implies \-p) [non-standard] 7861 \-o, \-\-owner preserve owner (super-user only) 7862 \-g, \-\-group preserve group 7863 \-\-devices preserve device files (super-user only) 7864@@ -870,7 +871,9 @@ permissions, though the \fB\-\-executabi 7865 the execute permission for the file\&. 7866 .IP o 7867 New files get their "normal" permission bits set to the source 7868-file\&'s permissions masked with the receiving end\&'s umask setting, and 7869+file\&'s permissions masked with the receiving directory\&'s default 7870+permissions (either the receiving process\&'s umask, or the permissions 7871+specified via the destination directory\&'s default ACL), and 7872 their special permission bits disabled except in the case where a new 7873 directory inherits a setgid bit from its parent directory\&. 7874 .RE 7875@@ -908,9 +911,11 @@ The preservation of the destination\&'s 7876 directories when \fB\-\-perms\fP is off was added in rsync 2\&.6\&.7\&. Older rsync 7877 versions erroneously preserved the three special permission bits for 7878 newly-created files when \fB\-\-perms\fP was off, while overriding the 7879-destination\&'s setgid bit setting on a newly-created directory\&. (Keep in 7880-mind that it is the version of the receiving rsync that affects this 7881-behavior\&.) 7882+destination\&'s setgid bit setting on a newly-created directory\&. Default ACL 7883+observance was added to the ACL patch for rsync 2\&.6\&.7, so older (or 7884+non-ACL-enabled) rsyncs use the umask even if default ACLs are present\&. 7885+(Keep in mind that it is the version of the receiving rsync that affects 7886+these behaviors\&.) 7887 .IP 7888 .IP "\fB\-E, \-\-executability\fP" 7889 This option causes rsync to preserve the 7890@@ -932,6 +937,16 @@ has a corresponding \&'r\&' permission e 7891 .IP 7892 If \fB\-\-perms\fP is enabled, this option is ignored\&. 7893 .IP 7894+.IP "\fB\-A, \-\-acls\fP" 7895+This option causes rsync to update the destination 7896+ACLs to be the same as the source ACLs\&. This nonstandard option only 7897+works if the remote rsync also supports it\&. \fB\-\-acls\fP implies \fB\-\-perms\fP\&. 7898+.IP 7899+Note also that an optimization of the ACL-sending protocol used by this 7900+version makes it incompatible with sending files to an older ACL-enabled 7901+rsync unless you double the \fB\-\-acls\fP option (e\&.g\&. \fB\-AA\fP)\&. This 7902+doubling is not needed when pulling files from an older rsync\&. 7903+.IP 7904 .IP "\fB\-\-chmod\fP" 7905 This option tells rsync to apply one or more 7906 comma-separated "chmod" strings to the permission of the files in the 7907@@ -1605,8 +1620,8 @@ if the receiving rsync is at least versi 7908 with older versions of rsync, but that also turns on the output of other 7909 verbose messages)\&. 7910 .IP 7911-The "%i" escape has a cryptic output that is 9 letters long\&. The general 7912-format is like the string \fBYXcstpogz\fP, where \fBY\fP is replaced by the 7913+The "%i" escape has a cryptic output that is 11 letters long\&. The general 7914+format is like the string \fBYXcstpoguax\fP, where \fBY\fP is replaced by the 7915 type of update being done, \fBX\fP is replaced by the file-type, and the 7916 other letters represent attributes that may be output if they are being 7917 modified\&. 7918@@ -1668,7 +1683,13 @@ sender\&'s value (requires \fB\-\-owner\ 7919 A \fBg\fP means the group is different and is being updated to the 7920 sender\&'s value (requires \fB\-\-group\fP and the authority to set the group)\&. 7921 .IP o 7922-The \fBz\fP slot is reserved for future use\&. 7923+The \fBu\fP slot is reserved for reporting update (access) time changes 7924+(a feature that is not yet released)\&. 7925+.IP o 7926+The \fBa\fP means that the ACL information changed\&. 7927+.IP o 7928+The \fBx\fP slot is reserved for reporting extended attribute changes 7929+(a feature that is not yet released)\&. 7930 .RE 7931 7932 .IP 7933