]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - bin/setfacl/merge.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / bin / setfacl / merge.c
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 }