]> arthur.barton.de Git - netatalk.git/blob - libatalk/vfs/acl.c
Add vasprintf compatibility function
[netatalk.git] / libatalk / vfs / acl.c
1 /*
2   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
3   Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
4
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 */
15
16 #ifdef HAVE_CONFIG_H
17 #include "config.h"
18 #endif /* HAVE_CONFIG_H */
19
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26
27 #include <atalk/afp.h>
28 #include <atalk/util.h>
29 #include <atalk/logger.h>
30 #include <atalk/errchk.h>
31 #include <atalk/acl.h>
32
33 #ifdef HAVE_NFSV4_ACLS
34
35 /* Removes all non-trivial ACLs from object. Returns full AFPERR code. */
36 int remove_acl_vfs(const char *name)
37 {
38     int ret,i, ace_count, trivial_aces, new_aces_count;
39     ace_t *old_aces = NULL;
40     ace_t *new_aces = NULL;
41
42     LOG(log_debug9, logtype_afpd, "remove_acl: BEGIN");
43
44     /* Get existing ACL and count trivial ACEs */
45     if ((ace_count = get_nfsv4_acl(name, &old_aces)) == -1)
46         return AFPERR_MISC;
47     trivial_aces = 0;
48     for ( i=0; i < ace_count; i++) {
49         if (old_aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE))
50             trivial_aces++;
51     }
52
53     /* malloc buffer for new ACL */
54     if ((new_aces = malloc(trivial_aces * sizeof(ace_t))) == NULL) {
55         LOG(log_error, logtype_afpd, "remove_acl: malloc %s", strerror(errno));
56         ret = AFPERR_MISC;
57         goto exit;
58     }
59
60     /* Now copy the trivial ACEs */
61     new_aces_count = 0;
62     for (i=0; i < ace_count; i++) {
63         if (old_aces[i].a_flags  & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
64             memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
65             new_aces_count++;
66         }
67     }
68
69     if ( (acl(name, ACE_SETACL, trivial_aces, new_aces)) == 0)
70         ret = AFP_OK;
71     else {
72         LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
73         if (errno == (EACCES | EPERM))
74             ret = AFPERR_ACCESS;
75         else if (errno == ENOENT)
76             ret = AFPERR_NOITEM;
77         else
78             ret = AFPERR_MISC;
79     }
80
81 exit:
82     free(old_aces);
83     free(new_aces);
84
85     LOG(log_debug9, logtype_afpd, "remove_acl: END");
86     return ret;
87 }
88
89 #endif  /* HAVE_NFSV4_ACLS */
90
91 #ifdef HAVE_POSIX_ACLS
92 /*!
93  * Remove any ACL_USER, ACL_GROUP, ACL_MASK or ACL_TYPE_DEFAULT ACEs from an object
94  *
95  * @param name  (r) filesystem object name
96  *
97  * @returns AFP error code, AFP_OK (= 0) on success, AFPERR_MISC on error
98  */
99 int remove_acl_vfs(const char *name)
100 {
101     EC_INIT;
102
103     struct stat st;
104     acl_t acl = NULL;
105     acl_entry_t e;
106     acl_tag_t tag;
107     int entry_id = ACL_FIRST_ENTRY;
108
109
110     /* Remove default ACL if it's a dir */
111     EC_ZERO_ERR(stat(name, &st), AFPERR_MISC);
112     if (S_ISDIR(st.st_mode)) {
113         EC_NULL_LOG_ERR(acl = acl_init(0), AFPERR_MISC);
114         EC_ZERO_LOG_ERR(acl_set_file(name, ACL_TYPE_DEFAULT, acl), AFPERR_MISC);
115         EC_ZERO_LOG_ERR(acl_free(acl), AFPERR_MISC);
116         acl = NULL;
117     }
118
119     /* Now get ACL and remove ACL_MASK, ACL_USER or ACL_GROUP entries, then re-set
120      * the ACL again. acl_calc_mask() must not be called because there is no need
121      * for an ACL_MASK entry in a basic ACL. */
122     EC_NULL_LOG_ERR(acl = acl_get_file(name, ACL_TYPE_ACCESS), AFPERR_MISC);
123     for ( ; acl_get_entry(acl, entry_id, &e) == 1; entry_id = ACL_NEXT_ENTRY) {
124         EC_ZERO_LOG_ERR(acl_get_tag_type(e, &tag), AFPERR_MISC);
125         if (tag == ACL_USER || tag == ACL_GROUP || tag == ACL_MASK)
126             EC_ZERO_LOG_ERR(acl_delete_entry(acl, e), AFPERR_MISC);
127     }
128     EC_ZERO_LOG_ERR(acl_valid(acl), AFPERR_MISC);
129     EC_ZERO_LOG_ERR(acl_set_file(name, ACL_TYPE_ACCESS, acl), AFPERR_MISC);
130
131 EC_CLEANUP:
132     if (errno == ENOENT) EC_STATUS(0);
133     if (acl) acl_free(acl);
134
135     EC_EXIT;
136 }
137 #endif /* HAVE_POSIX_ACLS */