Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Samba system utilities for ACL support.
4 : Copyright (C) Jeremy Allison 2000.
5 : Copyright (C) Volker Lendecke 2006
6 : Copyright (C) Michael Adam 2006,2008
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include "system/passwd.h"
24 :
25 : #if defined(HAVE_POSIX_ACLS)
26 : #include "modules/vfs_posixacl.h"
27 : #endif
28 :
29 : #if defined(HAVE_SOLARIS_UNIXWARE_ACLS)
30 : #include "modules/vfs_solarisacl.h"
31 : #endif
32 :
33 : #if defined(HAVE_HPUX_ACLS)
34 : #include "modules/vfs_hpuxacl.h"
35 : #endif
36 :
37 : #if defined(HAVE_AIX_ACLS)
38 : #include "modules/vfs_aixacl.h"
39 : #endif
40 :
41 : #undef DBGC_CLASS
42 : #define DBGC_CLASS DBGC_ACLS
43 :
44 : /*
45 : * Note that while this code implements sufficient functionality
46 : * to support the sys_acl_* interfaces it does not provide all
47 : * of the semantics of the POSIX ACL interfaces.
48 : *
49 : * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
50 : * from a call to sys_acl_get_entry() should not be assumed to be
51 : * valid after calling any of the following functions, which may
52 : * reorder the entries in the ACL.
53 : *
54 : * sys_acl_valid()
55 : * sys_acl_set_fd()
56 : */
57 :
58 1612266 : int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
59 : {
60 1612266 : if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
61 0 : errno = EINVAL;
62 0 : return -1;
63 : }
64 :
65 1612266 : if (entry_p == NULL) {
66 0 : errno = EINVAL;
67 0 : return -1;
68 : }
69 :
70 1612266 : if (entry_id == SMB_ACL_FIRST_ENTRY) {
71 311198 : acl_d->next = 0;
72 : }
73 :
74 1612266 : if (acl_d->next < 0) {
75 0 : errno = EINVAL;
76 0 : return -1;
77 : }
78 :
79 1612266 : if (acl_d->next >= acl_d->count) {
80 271296 : return 0;
81 : }
82 :
83 1340403 : *entry_p = &acl_d->acl[acl_d->next++];
84 :
85 1340403 : return 1;
86 : }
87 :
88 1328030 : int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
89 : {
90 1328030 : *type_p = entry_d->a_type;
91 :
92 1328030 : return 0;
93 : }
94 :
95 2296338 : int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
96 : {
97 2296338 : *permset_p = &entry_d->a_perm;
98 :
99 2296338 : return 0;
100 : }
101 :
102 367354 : void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
103 : {
104 367354 : if (entry_d->a_type == SMB_ACL_USER) {
105 123719 : return &entry_d->info.user.uid;
106 : }
107 :
108 243635 : if (entry_d->a_type == SMB_ACL_GROUP) {
109 243635 : return &entry_d->info.group.gid;
110 : }
111 :
112 0 : errno = EINVAL;
113 0 : return NULL;
114 : }
115 :
116 1005304 : int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
117 : {
118 1005304 : *permset_d = 0;
119 :
120 1005304 : return 0;
121 : }
122 :
123 2470928 : int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
124 : {
125 2470928 : if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
126 979976 : && perm != SMB_ACL_EXECUTE) {
127 0 : errno = EINVAL;
128 0 : return -1;
129 : }
130 :
131 2470928 : if (permset_d == NULL) {
132 0 : errno = EINVAL;
133 0 : return -1;
134 : }
135 :
136 2470928 : *permset_d |= perm;
137 :
138 2470928 : return 0;
139 : }
140 :
141 3873045 : int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
142 : {
143 3873045 : return *permset_d & perm;
144 : }
145 :
146 6 : char *sys_acl_to_text(const struct smb_acl_t *acl_d, ssize_t *len_p)
147 : {
148 0 : int i;
149 0 : int len, maxlen;
150 0 : char *text;
151 :
152 : /*
153 : * use an initial estimate of 20 bytes per ACL entry
154 : * when allocating memory for the text representation
155 : * of the ACL
156 : */
157 6 : len = 0;
158 6 : maxlen = 20 * acl_d->count;
159 6 : if ((text = (char *)SMB_MALLOC(maxlen)) == NULL) {
160 0 : errno = ENOMEM;
161 0 : return NULL;
162 : }
163 :
164 60 : for (i = 0; i < acl_d->count; i++) {
165 54 : struct smb_acl_entry *ap = &acl_d->acl[i];
166 0 : struct group *gr;
167 0 : char tagbuf[12];
168 0 : char idbuf[12];
169 0 : const char *tag;
170 54 : const char *id = "";
171 0 : char perms[4];
172 0 : int nbytes;
173 :
174 54 : switch (ap->a_type) {
175 : /*
176 : * for debugging purposes it's probably more
177 : * useful to dump unknown tag types rather
178 : * than just returning an error
179 : */
180 0 : default:
181 0 : slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x",
182 0 : ap->a_type);
183 0 : tag = tagbuf;
184 0 : break;
185 :
186 6 : case SMB_ACL_USER:
187 6 : id = uidtoname(ap->info.user.uid);
188 :
189 : FALL_THROUGH;
190 12 : case SMB_ACL_USER_OBJ:
191 12 : tag = "user";
192 12 : break;
193 :
194 24 : case SMB_ACL_GROUP:
195 24 : if ((gr = getgrgid(ap->info.group.gid)) == NULL) {
196 0 : slprintf(idbuf, sizeof(idbuf)-1, "%ld",
197 0 : (long)ap->info.group.gid);
198 0 : id = idbuf;
199 : } else {
200 24 : id = gr->gr_name;
201 : }
202 :
203 : FALL_THROUGH;
204 : case SMB_ACL_GROUP_OBJ:
205 30 : tag = "group";
206 30 : break;
207 :
208 6 : case SMB_ACL_OTHER:
209 6 : tag = "other";
210 6 : break;
211 :
212 6 : case SMB_ACL_MASK:
213 6 : tag = "mask";
214 6 : break;
215 :
216 : }
217 :
218 54 : perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
219 54 : perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
220 54 : perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
221 54 : perms[3] = '\0';
222 :
223 : /* <tag> : <qualifier> : rwx \n \0 */
224 54 : nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
225 :
226 : /*
227 : * If this entry would overflow the buffer
228 : * allocate enough additional memory for this
229 : * entry and an estimate of another 20 bytes
230 : * for each entry still to be processed
231 : */
232 54 : if ((len + nbytes) > maxlen) {
233 6 : maxlen += nbytes + 20 * (acl_d->count - i);
234 6 : if ((text = (char *)SMB_REALLOC(text, maxlen)) == NULL) {
235 0 : errno = ENOMEM;
236 0 : return NULL;
237 : }
238 : }
239 :
240 :
241 54 : slprintf(&text[len], nbytes, "%s:%s:%s\n", tag, id, perms);
242 54 : len += (nbytes - 1);
243 : }
244 :
245 6 : if (len_p)
246 0 : *len_p = len;
247 :
248 6 : return text;
249 : }
250 :
251 313184 : SMB_ACL_T sys_acl_init(TALLOC_CTX *mem_ctx)
252 : {
253 541 : SMB_ACL_T a;
254 :
255 313184 : if ((a = talloc(mem_ctx, struct smb_acl_t)) == NULL) {
256 0 : errno = ENOMEM;
257 0 : return NULL;
258 : }
259 :
260 313184 : a->count = 0;
261 313184 : a->next = -1;
262 :
263 313184 : a->acl = talloc_array(a, struct smb_acl_entry, 0);
264 313184 : if (!a->acl) {
265 0 : TALLOC_FREE(a);
266 0 : errno = ENOMEM;
267 0 : return NULL;
268 : }
269 :
270 312643 : return a;
271 : }
272 :
273 1005275 : int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
274 : {
275 4060 : SMB_ACL_T acl_d;
276 4060 : SMB_ACL_ENTRY_T entry_d;
277 4060 : struct smb_acl_entry *acl;
278 :
279 1005275 : if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
280 0 : errno = EINVAL;
281 0 : return -1;
282 : }
283 :
284 1005275 : acl = talloc_realloc(acl_d, acl_d->acl, struct smb_acl_entry, acl_d->count+1);
285 1005275 : if (!acl) {
286 0 : errno = ENOMEM;
287 0 : return -1;
288 : }
289 1005275 : acl_d->acl = acl;
290 1005275 : entry_d = &acl_d->acl[acl_d->count];
291 1005275 : entry_d->a_type = SMB_ACL_TAG_INVALID;
292 1005275 : entry_d->a_perm = 0;
293 1005275 : *entry_p = entry_d;
294 :
295 1005275 : acl_d->count++;
296 1005275 : return 0;
297 : }
298 :
299 1005275 : int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
300 : {
301 1005275 : switch (tag_type) {
302 1005275 : case SMB_ACL_USER:
303 : case SMB_ACL_USER_OBJ:
304 : case SMB_ACL_GROUP:
305 : case SMB_ACL_GROUP_OBJ:
306 : case SMB_ACL_OTHER:
307 : case SMB_ACL_MASK:
308 1005275 : entry_d->a_type = tag_type;
309 1005275 : break;
310 0 : default:
311 0 : errno = EINVAL;
312 0 : return -1;
313 : }
314 :
315 1005275 : return 0;
316 : }
317 :
318 348128 : int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
319 : {
320 348128 : if (entry_d->a_type == SMB_ACL_USER) {
321 114961 : entry_d->info.user.uid = *((uid_t *)qual_p);
322 114961 : return 0;
323 : }
324 233167 : if (entry_d->a_type == SMB_ACL_GROUP) {
325 233167 : entry_d->info.group.gid = *((gid_t *)qual_p);
326 233167 : return 0;
327 : }
328 :
329 0 : errno = EINVAL;
330 0 : return -1;
331 : }
332 :
333 1005323 : int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
334 : {
335 1005323 : if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
336 0 : errno = EINVAL;
337 0 : return -1;
338 : }
339 :
340 1005323 : entry_d->a_perm = *permset_d;
341 :
342 1005323 : return 0;
343 : }
344 :
345 0 : int sys_acl_free_text(char *text)
346 : {
347 0 : SAFE_FREE(text);
348 0 : return 0;
349 : }
350 :
351 0 : int sys_acl_valid(SMB_ACL_T acl_d)
352 : {
353 0 : errno = EINVAL;
354 0 : return -1;
355 : }
356 :
357 : /*
358 : * acl_get_file, acl_get_fd, acl_set_file, acl_set_fd and
359 : * sys_acl_delete_def_fd are to be redirected to the default
360 : * statically-bound acl vfs module, but they are replaceable.
361 : */
362 :
363 : #if defined(HAVE_POSIX_ACLS)
364 :
365 148915 : SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle,
366 : files_struct *fsp,
367 : SMB_ACL_TYPE_T type,
368 : TALLOC_CTX *mem_ctx)
369 : {
370 148915 : return posixacl_sys_acl_get_fd(handle, fsp, type, mem_ctx);
371 : }
372 :
373 1610 : int sys_acl_set_fd(vfs_handle_struct *handle,
374 : files_struct *fsp,
375 : SMB_ACL_TYPE_T type,
376 : SMB_ACL_T acl_d)
377 : {
378 1610 : return posixacl_sys_acl_set_fd(handle, fsp, type, acl_d);
379 : }
380 :
381 0 : int sys_acl_delete_def_fd(vfs_handle_struct *handle,
382 : files_struct *fsp)
383 : {
384 0 : return posixacl_sys_acl_delete_def_fd(handle, fsp);
385 : }
386 :
387 : #elif defined(HAVE_AIX_ACLS)
388 :
389 : SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle,
390 : files_struct *fsp,
391 : SMB_ACL_TYPE_T type,
392 : TALLOC_CTX *mem_ctx)
393 : {
394 : return aixacl_sys_acl_get_fd(handle, fsp, type, mem_ctx);
395 : }
396 :
397 : int sys_acl_set_fd(vfs_handle_struct *handle,
398 : files_struct *fsp,
399 : SMB_ACL_TYPE_T type,
400 : SMB_ACL_T acl_d)
401 : {
402 : return aixacl_sys_acl_set_fd(handle, fsp, type, acl_d);
403 : }
404 :
405 : int sys_acl_delete_def_fd(vfs_handle_struct *handle,
406 : files_struct *fsp)
407 : {
408 : return aixacl_sys_acl_delete_def_fd(handle, fsp);
409 : }
410 : #elif defined(HAVE_SOLARIS_UNIXWARE_ACLS)
411 :
412 : SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle,
413 : files_struct *fsp,
414 : SMB_ACL_TYPE_T type,
415 : TALLOC_CTX *mem_ctx)
416 : {
417 : return solarisacl_sys_acl_get_fd(handle, fsp, type,
418 : mem_ctx);
419 : }
420 :
421 : int sys_acl_set_fd(vfs_handle_struct *handle,
422 : files_struct *fsp,
423 : SMB_ACL_TYPE_T type,
424 : SMB_ACL_T acl_d)
425 : {
426 : return solarisacl_sys_acl_set_fd(handle,
427 : fsp,
428 : type,
429 : acl_d);
430 : }
431 :
432 : int sys_acl_delete_def_fd(vfs_handle_struct *handle,
433 : files_struct *fsp)
434 : {
435 : return solarisacl_sys_acl_delete_def_fd(handle, fsp);
436 : }
437 : #elif defined(HAVE_HPUX_ACLS)
438 :
439 : SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle,
440 : files_struct *fsp,
441 : SMB_ACL_TYPE_T type,
442 : TALLOC_CTX *mem_ctx)
443 : {
444 : return hpuxacl_sys_acl_get_fd(handle, fsp, mem_ctx);
445 : }
446 :
447 : int sys_acl_set_fd(vfs_handle_struct *handle,
448 : files_struct *fsp,
449 : SMB_ACL_TYPE_T type,
450 : SMB_ACL_T acl_d)
451 : {
452 : return hpuxacl_sys_acl_set_file(handle, fsp->fsp_name, type, acl_d);
453 : }
454 :
455 : int sys_acl_delete_def_fd(vfs_handle_struct *handle,
456 : files_struct *fsp)
457 : {
458 : return hpuxacl_sys_acl_delete_def_fd(handle, fsp);
459 : }
460 : #else /* No ACLs. */
461 :
462 : SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle,
463 : files_struct *fsp,
464 : SMB_ACL_TYPE_T type,
465 : TALLOC_CTX *mem_ctx)
466 : {
467 : #ifdef ENOTSUP
468 : errno = ENOTSUP;
469 : #else
470 : errno = ENOSYS;
471 : #endif
472 : return NULL;
473 : }
474 :
475 : int sys_acl_set_fd(vfs_handle_struct *handle,
476 : files_struct *fsp,
477 : SMB_ACL_TYPE_T type,
478 : SMB_ACL_T acl_d)
479 : {
480 : #ifdef ENOTSUP
481 : errno = ENOTSUP;
482 : #else
483 : errno = ENOSYS;
484 : #endif
485 : return -1;
486 : }
487 :
488 : int sys_acl_delete_def_fd(vfs_handle_struct *handle,
489 : files_struct *fsp)
490 : {
491 : #ifdef ENOTSUP
492 : errno = ENOTSUP;
493 : #else
494 : errno = ENOSYS;
495 : #endif
496 : return -1;
497 : }
498 : #endif
499 :
500 : /************************************************************************
501 : Deliberately outside the ACL defines. Return 1 if this is a "no acls"
502 : errno, 0 if not.
503 : ************************************************************************/
504 :
505 20 : int no_acl_syscall_error(int err)
506 : {
507 : #if defined(ENOSYS)
508 20 : if (err == ENOSYS) {
509 0 : return 1;
510 : }
511 : #endif
512 : #if defined(ENOTSUP)
513 20 : if (err == ENOTSUP) {
514 0 : return 1;
515 : }
516 : #endif
517 20 : return 0;
518 : }
|