Line data Source code
1 : /*
2 : Unix SMB/Netbios implementation.
3 : VFS module to get and set posix acls
4 : Copyright (C) Volker Lendecke 2006
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "system/filesys.h"
22 : #include "smbd/smbd.h"
23 : #include "modules/vfs_posixacl.h"
24 :
25 : /* prototypes for static functions first - for clarity */
26 :
27 : static bool smb_ace_to_internal(acl_entry_t posix_ace,
28 : struct smb_acl_entry *ace);
29 : static struct smb_acl_t *smb_acl_to_internal(acl_t acl, TALLOC_CTX *mem_ctx);
30 : static int smb_acl_set_mode(acl_entry_t entry, SMB_ACL_PERM_T perm);
31 : static acl_t smb_acl_to_posix(const struct smb_acl_t *acl);
32 :
33 :
34 : /* public functions - the api */
35 :
36 92 : SMB_ACL_T posixacl_sys_acl_get_fd(vfs_handle_struct *handle,
37 : files_struct *fsp,
38 : SMB_ACL_TYPE_T type,
39 : TALLOC_CTX *mem_ctx)
40 : {
41 : struct smb_acl_t *result;
42 92 : acl_t acl = NULL;
43 : acl_type_t acl_type;
44 :
45 92 : switch(type) {
46 52 : case SMB_ACL_TYPE_ACCESS:
47 52 : acl_type = ACL_TYPE_ACCESS;
48 52 : break;
49 40 : case SMB_ACL_TYPE_DEFAULT:
50 40 : acl_type = ACL_TYPE_DEFAULT;
51 40 : break;
52 0 : default:
53 0 : errno = EINVAL;
54 0 : return NULL;
55 : }
56 92 : if (!fsp->fsp_flags.is_pathref && (acl_type == ACL_TYPE_ACCESS)) {
57 : /* POSIX API only allows ACL_TYPE_ACCESS fetched on fd. */
58 16 : acl = acl_get_fd(fsp_get_io_fd(fsp));
59 76 : } else if (fsp->fsp_flags.have_proc_fds) {
60 76 : int fd = fsp_get_pathref_fd(fsp);
61 76 : const char *proc_fd_path = NULL;
62 : char buf[PATH_MAX];
63 :
64 76 : proc_fd_path = sys_proc_fd_path(fd, buf, sizeof(buf));
65 76 : if (proc_fd_path == NULL) {
66 0 : return NULL;
67 : }
68 :
69 76 : acl = acl_get_file(proc_fd_path, acl_type);
70 : } else {
71 : /*
72 : * This is no longer a handle based call.
73 : */
74 0 : acl = acl_get_file(fsp->fsp_name->base_name, acl_type);
75 : }
76 92 : if (acl == NULL) {
77 0 : return NULL;
78 : }
79 :
80 92 : result = smb_acl_to_internal(acl, mem_ctx);
81 92 : acl_free(acl);
82 92 : return result;
83 : }
84 :
85 0 : int posixacl_sys_acl_set_fd(vfs_handle_struct *handle,
86 : files_struct *fsp,
87 : SMB_ACL_TYPE_T type,
88 : SMB_ACL_T theacl)
89 : {
90 : int res;
91 0 : acl_t acl = smb_acl_to_posix(theacl);
92 : acl_type_t acl_type;
93 0 : int fd = fsp_get_pathref_fd(fsp);
94 :
95 0 : if (acl == NULL) {
96 0 : return -1;
97 : }
98 :
99 0 : switch(type) {
100 0 : case SMB_ACL_TYPE_ACCESS:
101 0 : acl_type = ACL_TYPE_ACCESS;
102 0 : break;
103 0 : case SMB_ACL_TYPE_DEFAULT:
104 0 : acl_type = ACL_TYPE_DEFAULT;
105 0 : break;
106 0 : default:
107 0 : acl_free(acl);
108 0 : errno = EINVAL;
109 0 : return -1;
110 : }
111 :
112 0 : if (!fsp->fsp_flags.is_pathref && type == SMB_ACL_TYPE_ACCESS) {
113 0 : res = acl_set_fd(fd, acl);
114 0 : } else if (fsp->fsp_flags.have_proc_fds) {
115 0 : const char *proc_fd_path = NULL;
116 : char buf[PATH_MAX];
117 :
118 0 : proc_fd_path = sys_proc_fd_path(fd, buf, sizeof(buf));
119 0 : if (proc_fd_path == NULL) {
120 0 : acl_free(acl);
121 0 : return -1;
122 : }
123 0 : res = acl_set_file(proc_fd_path, acl_type, acl);
124 : } else {
125 : /*
126 : * This is no longer a handle based call.
127 : */
128 0 : res = acl_set_file(fsp->fsp_name->base_name,
129 : acl_type,
130 : acl);
131 : }
132 :
133 0 : acl_free(acl);
134 0 : return res;
135 : }
136 :
137 0 : int posixacl_sys_acl_delete_def_fd(vfs_handle_struct *handle,
138 : files_struct *fsp)
139 : {
140 0 : if (fsp->fsp_flags.have_proc_fds) {
141 0 : int fd = fsp_get_pathref_fd(fsp);
142 0 : const char *proc_fd_path = NULL;
143 : char buf[PATH_MAX];
144 :
145 0 : proc_fd_path = sys_proc_fd_path(fd, buf, sizeof(buf));
146 0 : if (proc_fd_path == NULL) {
147 0 : return -1;
148 : }
149 0 : return acl_delete_def_file(proc_fd_path);
150 : }
151 :
152 : /*
153 : * This is no longer a handle based call.
154 : */
155 0 : return acl_delete_def_file(fsp->fsp_name->base_name);
156 : }
157 :
158 : /* private functions */
159 :
160 156 : static bool smb_ace_to_internal(acl_entry_t posix_ace,
161 : struct smb_acl_entry *ace)
162 : {
163 : acl_tag_t tag;
164 : acl_permset_t permset;
165 :
166 156 : if (acl_get_tag_type(posix_ace, &tag) != 0) {
167 0 : DEBUG(0, ("smb_acl_get_tag_type failed\n"));
168 0 : return False;
169 : }
170 :
171 156 : switch(tag) {
172 0 : case ACL_USER:
173 0 : ace->a_type = SMB_ACL_USER;
174 0 : break;
175 52 : case ACL_USER_OBJ:
176 52 : ace->a_type = SMB_ACL_USER_OBJ;
177 52 : break;
178 0 : case ACL_GROUP:
179 0 : ace->a_type = SMB_ACL_GROUP;
180 0 : break;
181 52 : case ACL_GROUP_OBJ:
182 52 : ace->a_type = SMB_ACL_GROUP_OBJ;
183 52 : break;
184 52 : case ACL_OTHER:
185 52 : ace->a_type = SMB_ACL_OTHER;
186 52 : break;
187 0 : case ACL_MASK:
188 0 : ace->a_type = SMB_ACL_MASK;
189 0 : break;
190 : #ifdef HAVE_ACL_EVERYONE
191 : case ACL_EVERYONE:
192 : DEBUG(1, ("ACL tag type ACL_EVERYONE. FreeBSD with ZFS? Use 'vfs objects = zfsacl'\n"));
193 : return false;
194 : #endif
195 0 : default:
196 0 : DEBUG(0, ("unknown tag type %d\n", (unsigned int)tag));
197 0 : return False;
198 : }
199 156 : switch(ace->a_type) {
200 0 : case SMB_ACL_USER: {
201 0 : uid_t *puid = (uid_t *)acl_get_qualifier(posix_ace);
202 0 : if (puid == NULL) {
203 0 : DEBUG(0, ("smb_acl_get_qualifier failed\n"));
204 0 : return False;
205 : }
206 0 : ace->info.user.uid = *puid;
207 0 : acl_free(puid);
208 0 : break;
209 : }
210 :
211 0 : case SMB_ACL_GROUP: {
212 0 : gid_t *pgid = (uid_t *)acl_get_qualifier(posix_ace);
213 0 : if (pgid == NULL) {
214 0 : DEBUG(0, ("smb_acl_get_qualifier failed\n"));
215 0 : return False;
216 : }
217 0 : ace->info.group.gid = *pgid;
218 0 : acl_free(pgid);
219 0 : break;
220 : }
221 156 : default:
222 156 : break;
223 : }
224 156 : if (acl_get_permset(posix_ace, &permset) != 0) {
225 0 : DEBUG(0, ("smb_acl_get_mode failed\n"));
226 0 : return False;
227 : }
228 156 : ace->a_perm = 0;
229 : #ifdef HAVE_ACL_GET_PERM_NP
230 : ace->a_perm |= (acl_get_perm_np(permset, ACL_READ) ? SMB_ACL_READ : 0);
231 : ace->a_perm |= (acl_get_perm_np(permset, ACL_WRITE) ? SMB_ACL_WRITE : 0);
232 : ace->a_perm |= (acl_get_perm_np(permset, ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
233 : #else
234 156 : ace->a_perm |= (acl_get_perm(permset, ACL_READ) ? SMB_ACL_READ : 0);
235 156 : ace->a_perm |= (acl_get_perm(permset, ACL_WRITE) ? SMB_ACL_WRITE : 0);
236 156 : ace->a_perm |= (acl_get_perm(permset, ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
237 : #endif
238 156 : return True;
239 : }
240 :
241 92 : static struct smb_acl_t *smb_acl_to_internal(acl_t acl, TALLOC_CTX *mem_ctx)
242 : {
243 92 : struct smb_acl_t *result = sys_acl_init(mem_ctx);
244 92 : int entry_id = ACL_FIRST_ENTRY;
245 : acl_entry_t e;
246 92 : if (result == NULL) {
247 0 : return NULL;
248 : }
249 294 : while (acl_get_entry(acl, entry_id, &e) == 1) {
250 :
251 156 : entry_id = ACL_NEXT_ENTRY;
252 :
253 156 : result->acl = talloc_realloc(result, result->acl,
254 : struct smb_acl_entry, result->count+1);
255 156 : if (result->acl == NULL) {
256 0 : TALLOC_FREE(result);
257 0 : DEBUG(0, ("talloc_realloc failed\n"));
258 0 : errno = ENOMEM;
259 0 : return NULL;
260 : }
261 :
262 156 : if (!smb_ace_to_internal(e, &result->acl[result->count])) {
263 0 : TALLOC_FREE(result);
264 0 : return NULL;
265 : }
266 :
267 156 : result->count += 1;
268 : }
269 92 : return result;
270 : }
271 :
272 0 : static int smb_acl_set_mode(acl_entry_t entry, SMB_ACL_PERM_T perm)
273 : {
274 : int ret;
275 : acl_permset_t permset;
276 :
277 0 : if ((ret = acl_get_permset(entry, &permset)) != 0) {
278 0 : return ret;
279 : }
280 0 : if ((ret = acl_clear_perms(permset)) != 0) {
281 0 : return ret;
282 : }
283 0 : if ((perm & SMB_ACL_READ) &&
284 0 : ((ret = acl_add_perm(permset, ACL_READ)) != 0)) {
285 0 : return ret;
286 : }
287 0 : if ((perm & SMB_ACL_WRITE) &&
288 0 : ((ret = acl_add_perm(permset, ACL_WRITE)) != 0)) {
289 0 : return ret;
290 : }
291 0 : if ((perm & SMB_ACL_EXECUTE) &&
292 0 : ((ret = acl_add_perm(permset, ACL_EXECUTE)) != 0)) {
293 0 : return ret;
294 : }
295 :
296 0 : return 0;
297 : }
298 :
299 0 : static acl_t smb_acl_to_posix(const struct smb_acl_t *acl)
300 : {
301 : acl_t result;
302 : int i;
303 :
304 0 : result = acl_init(acl->count);
305 0 : if (result == NULL) {
306 0 : DEBUG(10, ("acl_init failed\n"));
307 0 : return NULL;
308 : }
309 :
310 0 : for (i=0; i<acl->count; i++) {
311 0 : const struct smb_acl_entry *entry = &acl->acl[i];
312 : acl_entry_t e;
313 : acl_tag_t tag;
314 :
315 0 : if (acl_create_entry(&result, &e) != 0) {
316 0 : DEBUG(1, ("acl_create_entry failed: %s\n",
317 : strerror(errno)));
318 0 : goto fail;
319 : }
320 :
321 0 : switch (entry->a_type) {
322 0 : case SMB_ACL_USER:
323 0 : tag = ACL_USER;
324 0 : break;
325 0 : case SMB_ACL_USER_OBJ:
326 0 : tag = ACL_USER_OBJ;
327 0 : break;
328 0 : case SMB_ACL_GROUP:
329 0 : tag = ACL_GROUP;
330 0 : break;
331 0 : case SMB_ACL_GROUP_OBJ:
332 0 : tag = ACL_GROUP_OBJ;
333 0 : break;
334 0 : case SMB_ACL_OTHER:
335 0 : tag = ACL_OTHER;
336 0 : break;
337 0 : case SMB_ACL_MASK:
338 0 : tag = ACL_MASK;
339 0 : break;
340 0 : default:
341 0 : DEBUG(1, ("Unknown tag value %d\n", entry->a_type));
342 0 : goto fail;
343 : }
344 :
345 0 : if (acl_set_tag_type(e, tag) != 0) {
346 0 : DEBUG(10, ("acl_set_tag_type(%d) failed: %s\n",
347 : tag, strerror(errno)));
348 0 : goto fail;
349 : }
350 :
351 0 : switch (entry->a_type) {
352 0 : case SMB_ACL_USER:
353 0 : if (acl_set_qualifier(e, &entry->info.user.uid) != 0) {
354 0 : DEBUG(1, ("acl_set_qualifiier failed: %s\n",
355 : strerror(errno)));
356 0 : goto fail;
357 : }
358 0 : break;
359 0 : case SMB_ACL_GROUP:
360 0 : if (acl_set_qualifier(e, &entry->info.group.gid) != 0) {
361 0 : DEBUG(1, ("acl_set_qualifiier failed: %s\n",
362 : strerror(errno)));
363 0 : goto fail;
364 : }
365 0 : break;
366 0 : default: /* Shut up, compiler! :-) */
367 0 : break;
368 : }
369 :
370 0 : if (smb_acl_set_mode(e, entry->a_perm) != 0) {
371 0 : goto fail;
372 : }
373 : }
374 :
375 0 : if (acl_valid(result) != 0) {
376 0 : char *acl_string = sys_acl_to_text(acl, NULL);
377 0 : DEBUG(0, ("smb_acl_to_posix: ACL %s is invalid for set (%s)\n",
378 : acl_string, strerror(errno)));
379 0 : SAFE_FREE(acl_string);
380 0 : goto fail;
381 : }
382 :
383 0 : return result;
384 :
385 0 : fail:
386 0 : if (result != NULL) {
387 0 : acl_free(result);
388 : }
389 0 : return NULL;
390 : }
391 :
392 : /* VFS operations structure */
393 :
394 : static struct vfs_fn_pointers posixacl_fns = {
395 : .sys_acl_get_fd_fn = posixacl_sys_acl_get_fd,
396 : .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
397 : .sys_acl_set_fd_fn = posixacl_sys_acl_set_fd,
398 : .sys_acl_delete_def_fd_fn = posixacl_sys_acl_delete_def_fd,
399 : };
400 :
401 : static_decl_vfs;
402 4875 : NTSTATUS vfs_posixacl_init(TALLOC_CTX *ctx)
403 : {
404 4875 : return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "posixacl",
405 : &posixacl_fns);
406 : }
|