r17179: Merge the vl-posixacls tmp branch into mainline. It
[obnox/samba/samba-obnox.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 = 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 = 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 = SMB_MALLOC(sizeof(struct smb_acl_t) +
247                             count * sizeof(struct smb_acl_entry))) == NULL) {
248                 errno = ENOMEM;
249                 return NULL;
250         }
251  
252         a->size = count + 1;
253         a->count = 0;
254         a->next = -1;
255
256         return a;
257 }
258
259 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
260 {
261         SMB_ACL_T       acl_d;
262         SMB_ACL_ENTRY_T entry_d;
263
264         if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
265                 errno = EINVAL;
266                 return -1;
267         }
268
269         if (acl_d->count >= acl_d->size) {
270                 errno = ENOSPC;
271                 return -1;
272         }
273
274         entry_d         = &acl_d->acl[acl_d->count++];
275         entry_d->a_type = 0;
276         entry_d->uid    = -1;
277         entry_d->gid    = -1;
278         entry_d->a_perm = 0;
279         *entry_p        = entry_d;
280
281         return 0;
282 }
283
284 int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
285 {
286         switch (tag_type) {
287                 case SMB_ACL_USER:
288                 case SMB_ACL_USER_OBJ:
289                 case SMB_ACL_GROUP:
290                 case SMB_ACL_GROUP_OBJ:
291                 case SMB_ACL_OTHER:
292                 case SMB_ACL_MASK:
293                         entry_d->a_type = tag_type;
294                         break;
295                 default:
296                         errno = EINVAL;
297                         return -1;
298                 }
299
300         return 0;
301 }
302
303 int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
304 {
305         if (entry_d->a_type == SMB_ACL_USER) {
306                 entry_d->uid = *((uid_t *)qual_p);
307                 return 0;
308                 }
309         if (entry_d->a_type == SMB_ACL_GROUP) {
310                 entry_d->gid = *((gid_t *)qual_p);
311                 return 0;
312         }
313
314         errno = EINVAL;
315         return -1;
316 }
317
318 int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
319 {
320         if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
321                 errno = EINVAL;
322                 return -1;
323         }
324
325         entry_d->a_perm = *permset_d;
326  
327         return 0;
328 }
329
330 int sys_acl_free_text(char *text)
331 {
332         SAFE_FREE(text);
333         return 0;
334 }
335
336 int sys_acl_free_acl(SMB_ACL_T acl_d) 
337 {
338         SAFE_FREE(acl_d);
339         return 0;
340 }
341
342 int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
343 {
344         return 0;
345 }
346
347 int sys_acl_valid(SMB_ACL_T acl_d)
348 {
349         errno = EINVAL;
350         return -1;
351 }
352
353 /*
354  * acl_get_file, acl_get_fd, acl_set_file, acl_set_fd and
355  * sys_acl_delete_def_file are to be redirected to the default
356  * statically-bound acl vfs module, but they are replacable.
357  */
358  
359 #if defined(HAVE_POSIX_ACLS)
360  
361 SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle, 
362                            const char *path_p, SMB_ACL_TYPE_T type)
363 {
364         return posixacl_sys_acl_get_file(handle, path_p, type);
365 }
366  
367 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, int fd)
368 {
369         return posixacl_sys_acl_get_fd(handle, fsp, fd);
370 }
371  
372 int sys_acl_set_file(vfs_handle_struct *handle,
373                      const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
374 {
375         return posixacl_sys_acl_set_file(handle, name, type, acl_d);
376 }
377  
378 int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
379                    int fd, SMB_ACL_T acl_d)
380 {
381         return posixacl_sys_acl_set_fd(handle, fsp, fd, acl_d);
382 }
383
384 int sys_acl_delete_def_file(vfs_handle_struct *handle,
385                             const char *path)
386 {
387         return posixacl_sys_acl_delete_def_file(handle, path);
388 }
389
390 #elif defined(HAVE_AIX_ACLS)
391
392 SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
393                            const char *path_p, SMB_ACL_TYPE_T type)
394 {
395         return aixacl_sys_acl_get_file(handle, path_p, type);
396 }
397
398 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, int fd)
399 {
400         return aixacl_sys_acl_get_fd(handle, fsp, fd);
401 }
402
403 int sys_acl_set_file(vfs_handle_struct *handle,
404                      const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
405 {
406         return aixacl_sys_acl_set_file(handle, name, type, acl_d);
407 }
408
409 int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
410                    int fd, SMB_ACL_T acl_d)
411 {
412         return aixacl_sys_acl_set_fd(handle, fsp, fd, acl_d);
413 }
414
415 int sys_acl_delete_def_file(vfs_handle_struct *handle,
416                             const char *path)
417 {
418         return aixacl_sys_acl_delete_def_file(handle, path);
419 }
420
421 #elif defined(HAVE_TRU64_ACLS)
422  
423 SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
424                            const char *path_p, SMB_ACL_TYPE_T type)
425 {
426         return tru64acl_sys_acl_get_file(handle, path_p, type);
427 }
428
429 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, int fd)
430 {
431         return tru64acl_sys_acl_get_fd(handle, fsp, fd);
432 }
433
434 int sys_acl_set_file(vfs_handle_struct *handle,
435                      const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
436 {
437         return tru64acl_sys_acl_set_file(handle, name, type, acl_d);
438 }
439
440 int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
441                    int fd, SMB_ACL_T acl_d)
442 {
443         return tru64acl_sys_acl_set_fd(handle, fsp, fd, acl_d);
444 }
445
446 int sys_acl_delete_def_file(vfs_handle_struct *handle,
447                             const char *path)
448 {
449         return tru64acl_sys_acl_delete_def_file(handle, path);
450 }
451
452 #elif defined(HAVE_SOLARIS_ACLS) || defined(HAVE_UNIXWARE_ACLS)
453
454 SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
455                            const char *path_p, SMB_ACL_TYPE_T type)
456 {
457         return solarisacl_sys_acl_get_file(handle, path_p, type);
458 }
459
460 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, int fd)
461 {
462         return solarisacl_sys_acl_get_fd(handle, fsp, fd);
463 }
464
465 int sys_acl_set_file(vfs_handle_struct *handle,
466                      const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
467 {
468         return solarisacl_sys_acl_set_file(handle, name, type, acl_d);
469 }
470
471 int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
472                    int fd, SMB_ACL_T acl_d)
473 {
474         return solarisacl_sys_acl_set_fd(handle, fsp, fd, acl_d);
475 }
476
477 int sys_acl_delete_def_file(vfs_handle_struct *handle,
478                             const char *path)
479 {
480         return solarisacl_sys_acl_delete_def_file(handle, path);
481 }
482
483 #elif defined(HAVE_HPUX_ACLS)
484
485 SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
486                            const char *path_p, SMB_ACL_TYPE_T type)
487 {
488         return hpuxacl_sys_acl_get_file(handle, path_p, type);
489 }
490
491 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, int fd)
492 {
493         return hpuxacl_sys_acl_get_fd(handle, fsp, fd);
494 }
495
496 int sys_acl_set_file(vfs_handle_struct *handle,
497                      const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
498 {
499         return hpuxacl_sys_acl_set_file(handle, name, type, acl_d);
500 }
501
502 int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
503                    int fd, SMB_ACL_T acl_d)
504 {
505         return hpuxacl_sys_acl_set_fd(handle, fsp, fd, acl_d);
506 }
507
508 int sys_acl_delete_def_file(vfs_handle_struct *handle,
509                             const char *path)
510 {
511         return hpuxacl_sys_acl_delete_def_file(handle, path);
512 }
513
514 #elif defined(HAVE_IRIX_ACLS)
515
516 SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
517                            const char *path_p, SMB_ACL_TYPE_T type)
518 {
519         return irixacl_sys_acl_get_file(handle, path_p, type);
520 }
521
522 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, int fd)
523 {
524         return irixacl_sys_acl_get_fd(handle, fsp, fd);
525 }
526
527 int sys_acl_set_file(vfs_handle_struct *handle,
528                      const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
529 {
530         return irixacl_sys_acl_set_file(handle, name, type, acl_d);
531 }
532
533 int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
534                    int fd, SMB_ACL_T acl_d)
535 {
536         return irixacl_sys_acl_set_fd(handle, fsp, fd, acl_d);
537 }
538
539 int sys_acl_delete_def_file(vfs_handle_struct *handle,
540                             const char *path)
541 {
542         return irixacl_sys_acl_delete_def_file(handle, path);
543 }
544
545 #else /* No ACLs. */
546
547 SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
548                            const char *path_p, SMB_ACL_TYPE_T type)
549 {
550         errno = ENOTSUP;
551         return NULL;
552 }
553
554 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, int fd)
555 {
556         errno = ENOTSUP;
557         return NULL;
558 }
559
560 int sys_acl_set_file(vfs_handle_struct *handle,
561                      const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
562 {
563         errno = ENOTSUP;
564         return -1;
565 }
566
567 int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
568                    int fd, SMB_ACL_T acl_d)
569 {
570         errno = ENOTSUP;
571         return -1;
572 }
573
574 int sys_acl_delete_def_file(vfs_handle_struct *handle,
575                             const char *path)
576 {
577         errno = ENOTSUP;
578         return -1;
579 }
580
581 #endif
582
583 /************************************************************************
584  Deliberately outside the ACL defines. Return 1 if this is a "no acls"
585  errno, 0 if not.
586 ************************************************************************/
587
588 int no_acl_syscall_error(int err)
589 {
590 #if defined(ENOSYS)
591         if (err == ENOSYS) {
592                 return 1;
593         }
594 #endif
595 #if defined(ENOTSUP)
596         if (err == ENOTSUP) {
597                 return 1;
598         }
599 #endif
600         return 0;
601 }