r21953: One format fix, clarify a condition that the IBM
[nivanova/samba-autobuild/.git] / source3 / lib / sysacls.c
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
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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 #undef  DBGC_CLASS
26 #define DBGC_CLASS DBGC_ACLS
27
28 /*
29  * Note that while this code implements sufficient functionality
30  * to support the sys_acl_* interfaces it does not provide all
31  * of the semantics of the POSIX ACL interfaces.
32  *
33  * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
34  * from a call to sys_acl_get_entry() should not be assumed to be
35  * valid after calling any of the following functions, which may
36  * reorder the entries in the ACL.
37  *
38  *      sys_acl_valid()
39  *      sys_acl_set_file()
40  *      sys_acl_set_fd()
41  */
42
43 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
44 {
45         if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
46                 errno = EINVAL;
47                 return -1;
48         }
49
50         if (entry_p == NULL) {
51                 errno = EINVAL;
52                 return -1;
53         }
54
55         if (entry_id == SMB_ACL_FIRST_ENTRY) {
56                 acl_d->next = 0;
57         }
58
59         if (acl_d->next < 0) {
60                 errno = EINVAL;
61                 return -1;
62         }
63
64         if (acl_d->next >= acl_d->count) {
65                 return 0;
66         }
67
68         *entry_p = &acl_d->acl[acl_d->next++];
69
70         return 1;
71 }
72
73 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
74 {
75         *type_p = entry_d->a_type;
76
77         return 0;
78 }
79
80 int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
81 {
82         *permset_p = &entry_d->a_perm;
83
84         return 0;
85 }
86
87 void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
88 {
89         if (entry_d->a_type == SMB_ACL_USER) {
90                 return &entry_d->uid;
91                 }
92
93         if (entry_d->a_type == SMB_ACL_GROUP) {
94                 return &entry_d->gid;
95         }
96
97         errno = EINVAL;
98                 return NULL;
99 }
100
101 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
102 {
103         *permset_d = 0;
104
105         return 0;
106 }
107
108 int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
109 {
110         if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
111             && perm != SMB_ACL_EXECUTE) {
112                 errno = EINVAL;
113                 return -1;
114                 }
115  
116         if (permset_d == NULL) {
117                 errno = EINVAL;
118                 return -1;
119         }
120
121         *permset_d |= perm;
122  
123         return 0;
124 }
125
126 int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
127 {
128         return *permset_d & perm;
129 }
130
131 char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
132 {
133         int     i;
134         int     len, maxlen;
135         char    *text;
136
137         /*
138          * use an initial estimate of 20 bytes per ACL entry
139          * when allocating memory for the text representation
140          * of the ACL
141          */
142         len     = 0;
143         maxlen  = 20 * acl_d->count;
144         if ((text = (char *)SMB_MALLOC(maxlen)) == NULL) {
145                 errno = ENOMEM;
146                 return NULL;
147         }
148
149         for (i = 0; i < acl_d->count; i++) {
150                 struct smb_acl_entry *ap = &acl_d->acl[i];
151                 struct group    *gr;
152                 char            tagbuf[12];
153                 char            idbuf[12];
154                 const char      *tag;
155                 const char      *id     = "";
156                 char            perms[4];
157                 int             nbytes;
158
159                 switch (ap->a_type) {
160                         /*
161                          * for debugging purposes it's probably more
162                          * useful to dump unknown tag types rather
163                          * than just returning an error
164                          */
165                         default:
166                                 slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x",
167                                          ap->a_type);
168                                 tag = tagbuf;
169                                 break;
170  
171                         case SMB_ACL_USER:
172                                 id = uidtoname(ap->uid);
173                         case SMB_ACL_USER_OBJ:
174                                 tag = "user";
175                                 break;
176
177                         case SMB_ACL_GROUP:
178                                 if ((gr = getgrgid(ap->gid)) == NULL) {
179                                         slprintf(idbuf, sizeof(idbuf)-1, "%ld",
180                                                 (long)ap->gid);
181                                         id = idbuf;
182                                 } else {
183                                         id = gr->gr_name;
184                                 }
185                         case SMB_ACL_GROUP_OBJ:
186                                 tag = "group";
187                                 break;
188
189                         case SMB_ACL_OTHER:
190                                 tag = "other";
191                                 break;
192
193                         case SMB_ACL_MASK:
194                                 tag = "mask";
195                                 break;
196
197                 }
198
199                 perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
200                 perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
201                 perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
202                 perms[3] = '\0';
203
204                 /*          <tag>      :  <qualifier>   :  rwx \n  \0 */
205                 nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
206
207                 /*
208                  * If this entry would overflow the buffer
209                  * allocate enough additional memory for this
210                  * entry and an estimate of another 20 bytes
211                  * for each entry still to be processed
212                  */
213                 if ((len + nbytes) > maxlen) {
214                         maxlen += nbytes + 20 * (acl_d->count - i);
215                         if ((text = (char *)SMB_REALLOC(text, maxlen)) == NULL) {
216                         errno = ENOMEM;
217                                 return NULL;
218                 }
219         }
220
221                 slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms);
222                 len += nbytes - 1;
223         }
224
225         if (len_p)
226                 *len_p = len;
227
228         return text;
229 }
230
231 SMB_ACL_T sys_acl_init(int count)
232 {
233         SMB_ACL_T       a;
234
235         if (count < 0) {
236                 errno = EINVAL;
237                 return NULL;
238         }
239
240         /*
241          * note that since the definition of the structure pointed
242          * to by the SMB_ACL_T includes the first element of the
243          * acl[] array, this actually allocates an ACL with room
244          * for (count+1) entries
245          */
246         if ((a = (struct smb_acl_t *)SMB_MALLOC(
247                      sizeof(struct smb_acl_t) +
248                      count * sizeof(struct smb_acl_entry))) == NULL) {
249                 errno = ENOMEM;
250                 return NULL;
251         }
252  
253         a->size = count + 1;
254         a->count = 0;
255         a->next = -1;
256
257         return a;
258 }
259
260 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
261 {
262         SMB_ACL_T       acl_d;
263         SMB_ACL_ENTRY_T entry_d;
264
265         if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
266                 errno = EINVAL;
267                 return -1;
268         }
269
270         if (acl_d->count >= acl_d->size) {
271                 errno = ENOSPC;
272                 return -1;
273         }
274
275         entry_d         = &acl_d->acl[acl_d->count++];
276         entry_d->a_type = SMB_ACL_TAG_INVALID;
277         entry_d->uid    = -1;
278         entry_d->gid    = -1;
279         entry_d->a_perm = 0;
280         *entry_p        = entry_d;
281
282         return 0;
283 }
284
285 int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
286 {
287         switch (tag_type) {
288                 case SMB_ACL_USER:
289                 case SMB_ACL_USER_OBJ:
290                 case SMB_ACL_GROUP:
291                 case SMB_ACL_GROUP_OBJ:
292                 case SMB_ACL_OTHER:
293                 case SMB_ACL_MASK:
294                         entry_d->a_type = tag_type;
295                         break;
296                 default:
297                         errno = EINVAL;
298                         return -1;
299                 }
300
301         return 0;
302 }
303
304 int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
305 {
306         if (entry_d->a_type == SMB_ACL_USER) {
307                 entry_d->uid = *((uid_t *)qual_p);
308                 return 0;
309                 }
310         if (entry_d->a_type == SMB_ACL_GROUP) {
311                 entry_d->gid = *((gid_t *)qual_p);
312                 return 0;
313         }
314
315         errno = EINVAL;
316         return -1;
317 }
318
319 int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
320 {
321         if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
322                 errno = EINVAL;
323                 return -1;
324         }
325
326         entry_d->a_perm = *permset_d;
327  
328         return 0;
329 }
330
331 int sys_acl_free_text(char *text)
332 {
333         SAFE_FREE(text);
334         return 0;
335 }
336
337 int sys_acl_free_acl(SMB_ACL_T acl_d) 
338 {
339         SAFE_FREE(acl_d);
340         return 0;
341 }
342
343 int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
344 {
345         return 0;
346 }
347
348 int sys_acl_valid(SMB_ACL_T acl_d)
349 {
350         errno = EINVAL;
351         return -1;
352 }
353
354 /*
355  * acl_get_file, acl_get_fd, acl_set_file, acl_set_fd and
356  * sys_acl_delete_def_file are to be redirected to the default
357  * statically-bound acl vfs module, but they are replacable.
358  */
359  
360 #if defined(HAVE_POSIX_ACLS)
361  
362 SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle, 
363                            const char *path_p, SMB_ACL_TYPE_T type)
364 {
365         return posixacl_sys_acl_get_file(handle, path_p, type);
366 }
367  
368 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, int fd)
369 {
370         return posixacl_sys_acl_get_fd(handle, fsp, fd);
371 }
372  
373 int sys_acl_set_file(vfs_handle_struct *handle,
374                      const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
375 {
376         return posixacl_sys_acl_set_file(handle, name, type, acl_d);
377 }
378  
379 int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
380                    int fd, SMB_ACL_T acl_d)
381 {
382         return posixacl_sys_acl_set_fd(handle, fsp, fd, acl_d);
383 }
384
385 int sys_acl_delete_def_file(vfs_handle_struct *handle,
386                             const char *path)
387 {
388         return posixacl_sys_acl_delete_def_file(handle, path);
389 }
390
391 #elif defined(HAVE_AIX_ACLS)
392
393 SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
394                            const char *path_p, SMB_ACL_TYPE_T type)
395 {
396         return aixacl_sys_acl_get_file(handle, path_p, type);
397 }
398
399 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, int fd)
400 {
401         return aixacl_sys_acl_get_fd(handle, fsp, fd);
402 }
403
404 int sys_acl_set_file(vfs_handle_struct *handle,
405                      const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
406 {
407         return aixacl_sys_acl_set_file(handle, name, type, acl_d);
408 }
409
410 int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
411                    int fd, SMB_ACL_T acl_d)
412 {
413         return aixacl_sys_acl_set_fd(handle, fsp, fd, acl_d);
414 }
415
416 int sys_acl_delete_def_file(vfs_handle_struct *handle,
417                             const char *path)
418 {
419         return aixacl_sys_acl_delete_def_file(handle, path);
420 }
421
422 #elif defined(HAVE_TRU64_ACLS)
423  
424 SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
425                            const char *path_p, SMB_ACL_TYPE_T type)
426 {
427         return tru64acl_sys_acl_get_file(handle, path_p, type);
428 }
429
430 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, int fd)
431 {
432         return tru64acl_sys_acl_get_fd(handle, fsp, fd);
433 }
434
435 int sys_acl_set_file(vfs_handle_struct *handle,
436                      const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
437 {
438         return tru64acl_sys_acl_set_file(handle, name, type, acl_d);
439 }
440
441 int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
442                    int fd, SMB_ACL_T acl_d)
443 {
444         return tru64acl_sys_acl_set_fd(handle, fsp, fd, acl_d);
445 }
446
447 int sys_acl_delete_def_file(vfs_handle_struct *handle,
448                             const char *path)
449 {
450         return tru64acl_sys_acl_delete_def_file(handle, path);
451 }
452
453 #elif defined(HAVE_SOLARIS_ACLS) || defined(HAVE_UNIXWARE_ACLS)
454
455 SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
456                            const char *path_p, SMB_ACL_TYPE_T type)
457 {
458         return solarisacl_sys_acl_get_file(handle, path_p, type);
459 }
460
461 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, int fd)
462 {
463         return solarisacl_sys_acl_get_fd(handle, fsp, fd);
464 }
465
466 int sys_acl_set_file(vfs_handle_struct *handle,
467                      const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
468 {
469         return solarisacl_sys_acl_set_file(handle, name, type, acl_d);
470 }
471
472 int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
473                    int fd, SMB_ACL_T acl_d)
474 {
475         return solarisacl_sys_acl_set_fd(handle, fsp, fd, acl_d);
476 }
477
478 int sys_acl_delete_def_file(vfs_handle_struct *handle,
479                             const char *path)
480 {
481         return solarisacl_sys_acl_delete_def_file(handle, path);
482 }
483
484 #elif defined(HAVE_HPUX_ACLS)
485
486 SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
487                            const char *path_p, SMB_ACL_TYPE_T type)
488 {
489         return hpuxacl_sys_acl_get_file(handle, path_p, type);
490 }
491
492 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, int fd)
493 {
494         return hpuxacl_sys_acl_get_fd(handle, fsp, fd);
495 }
496
497 int sys_acl_set_file(vfs_handle_struct *handle,
498                      const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
499 {
500         return hpuxacl_sys_acl_set_file(handle, name, type, acl_d);
501 }
502
503 int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
504                    int fd, SMB_ACL_T acl_d)
505 {
506         return hpuxacl_sys_acl_set_fd(handle, fsp, fd, acl_d);
507 }
508
509 int sys_acl_delete_def_file(vfs_handle_struct *handle,
510                             const char *path)
511 {
512         return hpuxacl_sys_acl_delete_def_file(handle, path);
513 }
514
515 #elif defined(HAVE_IRIX_ACLS)
516
517 SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
518                            const char *path_p, SMB_ACL_TYPE_T type)
519 {
520         return irixacl_sys_acl_get_file(handle, path_p, type);
521 }
522
523 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, int fd)
524 {
525         return irixacl_sys_acl_get_fd(handle, fsp, fd);
526 }
527
528 int sys_acl_set_file(vfs_handle_struct *handle,
529                      const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
530 {
531         return irixacl_sys_acl_set_file(handle, name, type, acl_d);
532 }
533
534 int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
535                    int fd, SMB_ACL_T acl_d)
536 {
537         return irixacl_sys_acl_set_fd(handle, fsp, fd, acl_d);
538 }
539
540 int sys_acl_delete_def_file(vfs_handle_struct *handle,
541                             const char *path)
542 {
543         return irixacl_sys_acl_delete_def_file(handle, path);
544 }
545
546 #else /* No ACLs. */
547
548 SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
549                            const char *path_p, SMB_ACL_TYPE_T type)
550 {
551 #ifdef ENOTSUP
552         errno = ENOTSUP;
553 #else
554         errno = ENOSYS;
555 #endif
556         return NULL;
557 }
558
559 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, int fd)
560 {
561 #ifdef ENOTSUP
562         errno = ENOTSUP;
563 #else
564         errno = ENOSYS;
565 #endif
566         return NULL;
567 }
568
569 int sys_acl_set_file(vfs_handle_struct *handle,
570                      const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
571 {
572 #ifdef ENOTSUP
573         errno = ENOTSUP;
574 #else
575         errno = ENOSYS;
576 #endif
577         return -1;
578 }
579
580 int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
581                    int fd, SMB_ACL_T acl_d)
582 {
583 #ifdef ENOTSUP
584         errno = ENOTSUP;
585 #else
586         errno = ENOSYS;
587 #endif
588         return -1;
589 }
590
591 int sys_acl_delete_def_file(vfs_handle_struct *handle,
592                             const char *path)
593 {
594 #ifdef ENOTSUP
595         errno = ENOTSUP;
596 #else
597         errno = ENOSYS;
598 #endif
599         return -1;
600 }
601
602 #endif
603
604 /************************************************************************
605  Deliberately outside the ACL defines. Return 1 if this is a "no acls"
606  errno, 0 if not.
607 ************************************************************************/
608
609 int no_acl_syscall_error(int err)
610 {
611 #if defined(ENOSYS)
612         if (err == ENOSYS) {
613                 return 1;
614         }
615 #endif
616 #if defined(ENOTSUP)
617         if (err == ENOTSUP) {
618                 return 1;
619         }
620 #endif
621         return 0;
622 }