1/*- 2 * Copyright (c) 2003-2010 Tim Kientzle 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "archive_platform.h" 28__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_disk.c 201159 2009-12-29 05:35:40Z kientzle $"); 29 30#ifdef HAVE_SYS_TYPES_H 31#include <sys/types.h> 32#endif 33#ifdef HAVE_SYS_ACL_H 34#define _ACL_PRIVATE /* For debugging */ 35#include <sys/acl.h> 36#endif 37#ifdef HAVE_ERRNO_H 38#include <errno.h> 39#endif 40 41#include "archive.h" 42#include "archive_entry.h" 43#include "archive_acl_private.h" 44#include "archive_write_disk_private.h" 45 46#if !defined(HAVE_POSIX_ACL) || !defined(ACL_TYPE_NFS4) 47/* Default empty function body to satisfy mainline code. */ 48int 49archive_write_disk_set_acls(struct archive *a, int fd, const char *name, 50 struct archive_acl *abstract_acl) 51{ 52 (void)a; /* UNUSED */ 53 (void)fd; /* UNUSED */ 54 (void)name; /* UNUSED */ 55 (void)abstract_acl; /* UNUSED */ 56 return (ARCHIVE_OK); 57} 58 59#else 60 61static int set_acl(struct archive *, int fd, const char *, 62 struct archive_acl *, 63 acl_type_t, int archive_entry_acl_type, const char *tn); 64 65/* 66 * XXX TODO: What about ACL types other than ACCESS and DEFAULT? 67 */ 68int 69archive_write_disk_set_acls(struct archive *a, int fd, const char *name, 70 struct archive_acl *abstract_acl) 71{ 72 int ret; 73 74 if (archive_acl_count(abstract_acl, ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) > 0) { 75 ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_ACCESS, 76 ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access"); 77 if (ret != ARCHIVE_OK) 78 return (ret); 79 ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_DEFAULT, 80 ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default"); 81 return (ret); 82 } else if (archive_acl_count(abstract_acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4) > 0) { 83 ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_NFS4, 84 ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4"); 85 return (ret); 86 } else 87 return ARCHIVE_OK; 88} 89 90static struct { 91 int archive_perm; 92 int platform_perm; 93} acl_perm_map[] = { 94 {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, 95 {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE}, 96 {ARCHIVE_ENTRY_ACL_READ, ACL_READ}, 97 {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA}, 98 {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY}, 99 {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA}, 100 {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE}, 101 {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA}, 102 {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY}, 103 {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS}, 104 {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS}, 105 {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD}, 106 {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES}, 107 {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES}, 108 {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE}, 109 {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL}, 110 {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL}, 111 {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER}, 112 {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE} 113}; 114 115static struct { 116 int archive_inherit; 117 int platform_inherit; 118} acl_inherit_map[] = { 119 {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT}, 120 {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT}, 121 {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT}, 122 {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY} 123}; 124 125static int 126set_acl(struct archive *a, int fd, const char *name, 127 struct archive_acl *abstract_acl, 128 acl_type_t acl_type, int ae_requested_type, const char *tname) 129{ 130 acl_t acl; 131 acl_entry_t acl_entry; 132 acl_permset_t acl_permset; 133 acl_flagset_t acl_flagset; 134 int ret; 135 int ae_type, ae_permset, ae_tag, ae_id; 136 uid_t ae_uid; 137 gid_t ae_gid; 138 const char *ae_name; 139 int entries; 140 int i; 141 142 ret = ARCHIVE_OK; 143 entries = archive_acl_reset(abstract_acl, ae_requested_type); 144 if (entries == 0) 145 return (ARCHIVE_OK); 146 acl = acl_init(entries); 147 while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type, 148 &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) { 149 acl_create_entry(&acl, &acl_entry); 150 151 switch (ae_tag) { 152 case ARCHIVE_ENTRY_ACL_USER: 153 acl_set_tag_type(acl_entry, ACL_USER); 154 ae_uid = archive_write_disk_uid(a, ae_name, ae_id); 155 acl_set_qualifier(acl_entry, &ae_uid); 156 break; 157 case ARCHIVE_ENTRY_ACL_GROUP: 158 acl_set_tag_type(acl_entry, ACL_GROUP); 159 ae_gid = archive_write_disk_gid(a, ae_name, ae_id); 160 acl_set_qualifier(acl_entry, &ae_gid); 161 break; 162 case ARCHIVE_ENTRY_ACL_USER_OBJ: 163 acl_set_tag_type(acl_entry, ACL_USER_OBJ); 164 break; 165 case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 166 acl_set_tag_type(acl_entry, ACL_GROUP_OBJ); 167 break; 168 case ARCHIVE_ENTRY_ACL_MASK: 169 acl_set_tag_type(acl_entry, ACL_MASK); 170 break; 171 case ARCHIVE_ENTRY_ACL_OTHER: 172 acl_set_tag_type(acl_entry, ACL_OTHER); 173 break; 174 case ARCHIVE_ENTRY_ACL_EVERYONE: 175 acl_set_tag_type(acl_entry, ACL_EVERYONE); 176 break; 177 default: 178 /* XXX */ 179 break; 180 } 181 182 switch (ae_type) { 183 case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: 184 acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALLOW); 185 break; 186 case ARCHIVE_ENTRY_ACL_TYPE_DENY: 187 acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_DENY); 188 break; 189 case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: 190 acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_AUDIT); 191 break; 192 case ARCHIVE_ENTRY_ACL_TYPE_ALARM: 193 acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALARM); 194 break; 195 case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: 196 case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: 197 // These don't translate directly into the system ACL. 198 break; 199 default: 200 // XXX error handling here. 201 break; 202 } 203 204 acl_get_permset(acl_entry, &acl_permset); 205 acl_clear_perms(acl_permset); 206 207 for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) { 208 if (ae_permset & acl_perm_map[i].archive_perm) 209 acl_add_perm(acl_permset, 210 acl_perm_map[i].platform_perm); 211 } 212 213 acl_get_flagset_np(acl_entry, &acl_flagset); 214 acl_clear_flags_np(acl_flagset); 215 for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) { 216 if (ae_permset & acl_inherit_map[i].archive_inherit) 217 acl_add_flag_np(acl_flagset, 218 acl_inherit_map[i].platform_inherit); 219 } 220 } 221 222 /* Try restoring the ACL through 'fd' if we can. */ 223#if HAVE_ACL_SET_FD 224 if (fd >= 0 && acl_type == ACL_TYPE_ACCESS && acl_set_fd(fd, acl) == 0) 225 ret = ARCHIVE_OK; 226 else 227#else 228#if HAVE_ACL_SET_FD_NP 229 if (fd >= 0 && acl_set_fd_np(fd, acl, acl_type) == 0) 230 ret = ARCHIVE_OK; 231 else 232#endif 233#endif 234#if HAVE_ACL_SET_LINK_NP 235 if (acl_set_link_np(name, acl_type, acl) != 0) { 236 archive_set_error(a, errno, "Failed to set %s acl", tname); 237 ret = ARCHIVE_WARN; 238 } 239#else 240 /* TODO: Skip this if 'name' is a symlink. */ 241 if (acl_set_file(name, acl_type, acl) != 0) { 242 archive_set_error(a, errno, "Failed to set %s acl", tname); 243 ret = ARCHIVE_WARN; 244 } 245#endif 246 acl_free(acl); 247 return (ret); 248} 249#endif 250