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 * $FreeBSD$ 27 */ 28 29 #include <sys/types.h> 30 #include <sys/acl.h> 31 #include <sys/stat.h> 32 33 #include <err.h> 34 #include <stdio.h> 35 36 #include "setfacl.h" 37 38 static int merge_user_group(acl_entry_t *entry, acl_entry_t *entry_new); 39 40 static int 41 merge_user_group(acl_entry_t *entry, acl_entry_t *entry_new) 42 { 43 acl_permset_t permset; 44 int have_entry; 45 uid_t *id, *id_new; 46 47 have_entry = 0; 48 49 id = acl_get_qualifier(*entry); 50 if (id == NULL) 51 err(1, "acl_get_qualifier() failed"); 52 id_new = acl_get_qualifier(*entry_new); 53 if (id_new == NULL) 54 err(1, "acl_get_qualifier() failed"); 55 if (*id == *id_new) { 56 /* any other matches */ 57 if (acl_get_permset(*entry, &permset) == -1) 58 err(1, "acl_get_permset() failed"); 59 if (acl_set_permset(*entry_new, permset) == -1) 60 err(1, "acl_set_permset() failed"); 61 have_entry = 1; 62 } 63 acl_free(id); 64 acl_free(id_new); 65 66 return (have_entry); 67 } 68 69 /* 70 * merge an ACL into existing file's ACL 71 */ 72 int 73 merge_acl(acl_t acl, acl_t *prev_acl) 74 { 75 acl_entry_t entry, entry_new; 76 acl_permset_t permset; 77 acl_t acl_new; 78 acl_tag_t tag, tag_new; 79 int entry_id, entry_id_new, have_entry; 80 81 if (acl_type == ACL_TYPE_ACCESS) 82 acl_new = acl_dup(prev_acl[ACCESS_ACL]); 83 else 84 acl_new = acl_dup(prev_acl[DEFAULT_ACL]); 85 if (acl_new == NULL) 86 err(1, "acl_dup() failed"); 87 88 entry_id = ACL_FIRST_ENTRY; 89 90 while (acl_get_entry(acl, entry_id, &entry) == 1) { 91 entry_id = ACL_NEXT_ENTRY; 92 have_entry = 0; 93 94 /* keep track of existing ACL_MASK entries */ 95 if (acl_get_tag_type(entry, &tag) == -1) 96 err(1, "acl_get_tag_type() failed - invalid ACL entry"); 97 if (tag == ACL_MASK) 98 have_mask = 1; 99 100 /* check against the existing ACL entries */ 101 entry_id_new = ACL_FIRST_ENTRY; 102 while (have_entry == 0 && 103 acl_get_entry(acl_new, entry_id_new, &entry_new) == 1) { 104 entry_id_new = ACL_NEXT_ENTRY; 105 106 if (acl_get_tag_type(entry, &tag) == -1) 107 err(1, "acl_get_tag_type() failed"); 108 if (acl_get_tag_type(entry_new, &tag_new) == -1) 109 err(1, "acl_get_tag_type() failed"); 110 if (tag != tag_new) 111 continue; 112 113 switch(tag) { 114 case ACL_USER: 115 case ACL_GROUP: 116 have_entry = merge_user_group(&entry, 117 &entry_new); 118 if (have_entry == 0) 119 break; 120 /* FALLTHROUGH */ 121 case ACL_USER_OBJ: 122 case ACL_GROUP_OBJ: 123 case ACL_OTHER: 124 case ACL_MASK: 125 if (acl_get_permset(entry, &permset) == -1) 126 err(1, "acl_get_permset() failed"); 127 if (acl_set_permset(entry_new, permset) == -1) 128 err(1, "acl_set_permset() failed"); 129 have_entry = 1; 130 break; 131 default: 132 /* should never be here */ 133 errx(1, "Invalid tag type: %i", tag); 134 break; 135 } 136 } 137 138 /* if this entry has not been found, it must be new */ 139 if (have_entry == 0) { 140 if (acl_create_entry(&acl_new, &entry_new) == -1) { 141 acl_free(acl_new); 142 return (-1); 143 } 144 if (acl_copy_entry(entry_new, entry) == -1) 145 err(1, "acl_copy_entry() failed"); 146 } 147 } 148 149 if (acl_type == ACL_TYPE_ACCESS) { 150 acl_free(prev_acl[ACCESS_ACL]); 151 prev_acl[ACCESS_ACL] = acl_new; 152 } else { 153 acl_free(prev_acl[DEFAULT_ACL]); 154 prev_acl[DEFAULT_ACL] = acl_new; 155 } 156 157 return (0); 158 } 159