1 /*- 2 * Copyright (c) 2001 Chris D. Faulhaber 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 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE VOICES IN HIS HEAD BE 18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 * POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/types.h> 31 #include <sys/acl.h> 32 #include <sys/stat.h> 33 34 #include <err.h> 35 #include <stdio.h> 36 37 #include "setfacl.h" 38 39 static int merge_user_group(acl_entry_t *entry, acl_entry_t *entry_new); 40 41 static int 42 merge_user_group(acl_entry_t *entry, acl_entry_t *entry_new) 43 { 44 acl_permset_t permset; 45 int have_entry; 46 uid_t *id, *id_new; 47 48 have_entry = 0; 49 50 id = acl_get_qualifier(*entry); 51 if (id == NULL) 52 err(1, "acl_get_qualifier() failed"); 53 id_new = acl_get_qualifier(*entry_new); 54 if (id_new == NULL) 55 err(1, "acl_get_qualifier() failed"); 56 if (*id == *id_new) { 57 /* any other matches */ 58 if (acl_get_permset(*entry, &permset) == -1) 59 err(1, "acl_get_permset() failed"); 60 if (acl_set_permset(*entry_new, permset) == -1) 61 err(1, "acl_set_permset() failed"); 62 have_entry = 1; 63 } 64 acl_free(id); 65 acl_free(id_new); 66 67 return (have_entry); 68 } 69 70 /* 71 * merge an ACL into existing file's ACL 72 */ 73 int 74 merge_acl(acl_t acl, acl_t *prev_acl) 75 { 76 acl_entry_t entry, entry_new; 77 acl_permset_t permset; 78 acl_t acl_new; 79 acl_tag_t tag, tag_new; 80 int entry_id, entry_id_new, have_entry; 81 82 if (acl_type == ACL_TYPE_ACCESS) 83 acl_new = acl_dup(prev_acl[ACCESS_ACL]); 84 else 85 acl_new = acl_dup(prev_acl[DEFAULT_ACL]); 86 if (acl_new == NULL) 87 err(1, "acl_dup() failed"); 88 89 entry_id = ACL_FIRST_ENTRY; 90 91 while (acl_get_entry(acl, entry_id, &entry) == 1) { 92 entry_id = ACL_NEXT_ENTRY; 93 have_entry = 0; 94 95 /* keep track of existing ACL_MASK entries */ 96 if (acl_get_tag_type(entry, &tag) == -1) 97 err(1, "acl_get_tag_type() failed - invalid ACL entry"); 98 if (tag == ACL_MASK) 99 have_mask = 1; 100 101 /* check against the existing ACL entries */ 102 entry_id_new = ACL_FIRST_ENTRY; 103 while (have_entry == 0 && 104 acl_get_entry(acl_new, entry_id_new, &entry_new) == 1) { 105 entry_id_new = ACL_NEXT_ENTRY; 106 107 if (acl_get_tag_type(entry, &tag) == -1) 108 err(1, "acl_get_tag_type() failed"); 109 if (acl_get_tag_type(entry_new, &tag_new) == -1) 110 err(1, "acl_get_tag_type() failed"); 111 if (tag != tag_new) 112 continue; 113 114 switch(tag) { 115 case ACL_USER: 116 case ACL_GROUP: 117 have_entry = merge_user_group(&entry, 118 &entry_new); 119 if (have_entry == 0) 120 break; 121 /* FALLTHROUGH */ 122 case ACL_USER_OBJ: 123 case ACL_GROUP_OBJ: 124 case ACL_OTHER: 125 case ACL_MASK: 126 if (acl_get_permset(entry, &permset) == -1) 127 err(1, "acl_get_permset() failed"); 128 if (acl_set_permset(entry_new, permset) == -1) 129 err(1, "acl_set_permset() failed"); 130 have_entry = 1; 131 break; 132 default: 133 /* should never be here */ 134 errx(1, "Invalid tag type: %i", tag); 135 break; 136 } 137 } 138 139 /* if this entry has not been found, it must be new */ 140 if (have_entry == 0) { 141 if (acl_create_entry(&acl_new, &entry_new) == -1) { 142 acl_free(acl_new); 143 return (-1); 144 } 145 if (acl_copy_entry(entry_new, entry) == -1) 146 err(1, "acl_copy_entry() failed"); 147 } 148 } 149 150 if (acl_type == ACL_TYPE_ACCESS) { 151 acl_free(prev_acl[ACCESS_ACL]); 152 prev_acl[ACCESS_ACL] = acl_new; 153 } else { 154 acl_free(prev_acl[DEFAULT_ACL]); 155 prev_acl[DEFAULT_ACL] = acl_new; 156 } 157 158 return (0); 159 } 160