]>
gitweb.michael.orlitzky.com - apply-default-acl.git/blob - src/aclq.c
6ea2e1dd7ba0e3d7e9c2b22d02716fbe4ed6608b
2 #include <libgen.h> /* dirname() */
3 #include <limits.h> /* PATH_MAX */
12 #include <sys/types.h>
16 mode_t
get_mode(const char* path
) {
23 int result
= stat(path
, &s
);
29 /* errno will be set already by stat() */
34 bool mode_has_perm(mode_t mode
, int perm
) {
44 bool is_regular_file(const char* path
) {
50 int result
= stat(path
, &s
);
52 return S_ISREG(s
.st_mode
);
59 bool is_directory(const char* path
) {
65 int result
= stat(path
, &s
);
67 return S_ISDIR(s
.st_mode
);
75 bool has_default_acl(const char* path
) {
76 /* Return true if the given path has a default ACL, false
78 acl_t defacl
= acl_get_file(path
, ACL_TYPE_DEFAULT
);
80 if (defacl
== (acl_t
)NULL
) {
84 /* Used to store the entry if it exists, even though we don't care
88 int result
= acl_get_entry(defacl
, ACL_FIRST_ENTRY
, &dummy
);
91 /* There's a first entry in the default ACL. */
94 else if (result
== 0) {
98 perror("has_default_acl");
105 bool has_default_tag_acl(const char* path
, acl_tag_t tag_type
) {
106 /* Return true if the given path has a default ACL for the supplied
107 tag, false otherwise. */
108 acl_t defacl
= acl_get_file(path
, ACL_TYPE_DEFAULT
);
110 if (defacl
== (acl_t
)NULL
) {
115 int result
= acl_get_entry(defacl
, ACL_FIRST_ENTRY
, &entry
);
117 while (result
== 1) {
118 acl_tag_t tag
= ACL_UNDEFINED_TAG
;
119 int tag_result
= acl_get_tag_type(entry
, &tag
);
121 if (tag_result
== -1) {
122 perror("has_default_tag_acl - acl_get_tag_type");
126 if (tag
== tag_type
) {
131 result
= acl_get_entry(defacl
, ACL_NEXT_ENTRY
, &entry
);
138 bool has_default_user_obj_acl(const char* path
) {
139 return has_default_tag_acl(path
, ACL_USER_OBJ
);
142 bool has_default_group_obj_acl(const char* path
) {
143 return has_default_tag_acl(path
, ACL_GROUP_OBJ
);
146 bool has_default_other_acl(const char* path
) {
147 return has_default_tag_acl(path
, ACL_OTHER
);
151 bool get_default_tag_permset(const char* path
,
153 acl_permset_t
* output_perms
) {
154 /* Returns true if successful or false on error */
155 acl_t defacl
= acl_get_file(path
, ACL_TYPE_DEFAULT
);
157 if (defacl
== (acl_t
)NULL
) {
158 /* Follow the acl_foo convention of -1 == error. */
164 int result
= acl_get_entry(defacl
, ACL_FIRST_ENTRY
, &entry
);
166 while (result
== 1) {
167 acl_tag_t tag
= ACL_UNDEFINED_TAG
;
168 int tag_result
= acl_get_tag_type(entry
, &tag
);
170 if (tag_result
== -1) {
171 perror("get_default_tag_permset");
175 if (tag
== tag_type
) {
176 /* We found the right tag, now get the permset. */
177 int ps_result
= acl_get_permset(entry
, output_perms
);
178 if (ps_result
== 0) {
187 result
= acl_get_entry(defacl
, ACL_NEXT_ENTRY
, &entry
);
194 bool get_default_user_obj_permset(const char* path
,
195 acl_permset_t
* output_perms
) {
196 return get_default_tag_permset(path
, ACL_USER_OBJ
, output_perms
);
199 bool get_default_group_obj_permset(const char* path
,
200 acl_permset_t
* output_perms
) {
201 return get_default_tag_permset(path
, ACL_GROUP_OBJ
, output_perms
);
204 bool get_default_other_permset(const char* path
,
205 acl_permset_t
* output_perms
) {
206 return get_default_tag_permset(path
, ACL_OTHER
, output_perms
);
211 bool has_default_tag_perm(const char* path
,
214 /* Check path to see if tag has perm. */
216 if (!has_default_tag_acl(path
, tag
)) {
220 acl_permset_t permset
;
221 bool ps_result
= get_default_tag_permset(path
, tag
, &permset
);
227 int p_result
= acl_get_perm(permset
, perm
);
236 bool has_default_user_obj_read(const char* path
) {
237 return has_default_tag_perm(path
, ACL_USER_OBJ
, ACL_READ
);
240 bool has_default_user_obj_write(const char* path
) {
241 return has_default_tag_perm(path
, ACL_USER_OBJ
, ACL_WRITE
);
244 bool has_default_user_obj_execute(const char* path
) {
245 return has_default_tag_perm(path
, ACL_USER_OBJ
, ACL_EXECUTE
);
248 bool has_default_group_obj_read(const char* path
) {
249 return has_default_tag_perm(path
, ACL_GROUP_OBJ
, ACL_READ
);
252 bool has_default_group_obj_write(const char* path
) {
253 return has_default_tag_perm(path
, ACL_GROUP_OBJ
, ACL_WRITE
);
256 bool has_default_group_obj_execute(const char* path
) {
257 return has_default_tag_perm(path
, ACL_GROUP_OBJ
, ACL_EXECUTE
);
260 bool has_default_other_read(const char* path
) {
261 return has_default_tag_perm(path
, ACL_OTHER
, ACL_READ
);
264 bool has_default_other_write(const char* path
) {
265 return has_default_tag_perm(path
, ACL_OTHER
, ACL_WRITE
);
268 bool has_default_other_execute(const char* path
) {
269 return has_default_tag_perm(path
, ACL_OTHER
, ACL_EXECUTE
);
272 bool has_default_mask_read(const char* path
) {
273 return has_default_tag_perm(path
, ACL_MASK
, ACL_READ
);
276 bool has_default_mask_write(const char* path
) {
277 return has_default_tag_perm(path
, ACL_MASK
, ACL_WRITE
);
280 bool has_default_mask_execute(const char* path
) {
281 return has_default_tag_perm(path
, ACL_MASK
, ACL_EXECUTE
);
285 bool reapply_default_acl(const char* path
) {
286 /* If this is a normal file or directory (i.e. that has just been
287 created), we proceed to find its parent directory which will have
293 if (!is_regular_file(path
) && !is_directory(path
)) {
297 /* dirname mangles its argument */
298 char path_copy
[PATH_MAX
];
299 strncpy(path_copy
, path
, PATH_MAX
-1);
300 path_copy
[PATH_MAX
] = 0;
302 char* parent
= dirname(path_copy
);
303 if (!is_directory(parent
)) {
304 /* Make sure dirname() did what we think it did. */
308 /* This is the original mode of path. We will simply add permissions
309 to it, and then later reapply the result via chmod. */
310 mode_t path_mode
= get_mode(path
);
313 /* If parent has a default user ACL, apply it to path via chmod. */
314 if (has_default_user_obj_read(parent
)) {
315 path_mode
|= S_IRUSR
;
318 if (has_default_user_obj_write(parent
)) {
319 path_mode
|= S_IWUSR
;
322 /* However, we don't want to set the execute bit on via the ACL
323 unless it was on originally. Furthermore, if the ACL denies
324 execute, we want to honor that. */
325 if (has_default_user_obj_acl(parent
)) {
326 if (!has_default_user_obj_execute(parent
)) {
327 /* It has a user ACL, but no user execute is granted. */
328 path_mode
&= ~S_IXUSR
;
333 /* Do the same thing with the other perms/ACL. */
334 if (has_default_other_read(parent
)) {
335 path_mode
|= S_IROTH
;
338 if (has_default_other_write(parent
)) {
339 path_mode
|= S_IWOTH
;
342 if (has_default_other_acl(parent
)) {
343 if (!has_default_other_execute(parent
)) {
344 /* It has an other ACL, but no other execute is granted. */
345 path_mode
&= ~S_IXOTH
;
349 /* For the group bits, we'll use the ACL's mask instead of the group
350 object bits. If the default ACL had a group entry, it should
351 already have propagated (but might be masked. */
352 if (has_default_mask_read(parent
)) {
353 path_mode
|= S_IRGRP
;
356 if (has_default_mask_write(parent
)) {
357 path_mode
|= S_IWGRP
;
360 /* Honor the mask execute unconditionally. */
361 if (has_default_mask_execute(parent
)) {
362 if (mode_has_perm(path_mode
, S_IXGRP
)) {
363 path_mode
|= S_IXGRP
;
367 int result
= chmod(path
, path_mode
);
377 int main(int argc
, char* argv
[]) {
378 const char* target
= argv
[1];
380 bool result
= reapply_default_acl(target
);
383 printf("Success.\n");