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