ldb: move struct ldb_debug_ops to ldb_private.h
[samba.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,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 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
59 {
60         if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
61                 errno = EINVAL;
62                 return -1;
63         }
64
65         if (entry_p == NULL) {
66                 errno = EINVAL;
67                 return -1;
68         }
69
70         if (entry_id == SMB_ACL_FIRST_ENTRY) {
71                 acl_d->next = 0;
72         }
73
74         if (acl_d->next < 0) {
75                 errno = EINVAL;
76                 return -1;
77         }
78
79         if (acl_d->next >= acl_d->count) {
80                 return 0;
81         }
82
83         *entry_p = &acl_d->acl[acl_d->next++];
84
85         return 1;
86 }
87
88 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
89 {
90         *type_p = entry_d->a_type;
91
92         return 0;
93 }
94
95 int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
96 {
97         *permset_p = &entry_d->a_perm;
98
99         return 0;
100 }
101
102 void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
103 {
104         if (entry_d->a_type == SMB_ACL_USER) {
105                 return &entry_d->info.user.uid;
106         }
107
108         if (entry_d->a_type == SMB_ACL_GROUP) {
109                 return &entry_d->info.group.gid;
110         }
111
112         errno = EINVAL;
113         return NULL;
114 }
115
116 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
117 {
118         *permset_d = 0;
119
120         return 0;
121 }
122
123 int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
124 {
125         if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
126             && perm != SMB_ACL_EXECUTE) {
127                 errno = EINVAL;
128                 return -1;
129         }
130
131         if (permset_d == NULL) {
132                 errno = EINVAL;
133                 return -1;
134         }
135
136         *permset_d |= perm;
137
138         return 0;
139 }
140
141 int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
142 {
143         return *permset_d & perm;
144 }
145
146 char *sys_acl_to_text(const struct smb_acl_t *acl_d, ssize_t *len_p)
147 {
148         int     i;
149         int     len, maxlen;
150         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         len     = 0;
158         maxlen  = 20 * acl_d->count;
159         if ((text = (char *)SMB_MALLOC(maxlen)) == NULL) {
160                 errno = ENOMEM;
161                 return NULL;
162         }
163
164         for (i = 0; i < acl_d->count; i++) {
165                 struct smb_acl_entry *ap = &acl_d->acl[i];
166                 struct group    *gr;
167                 char            tagbuf[12];
168                 char            idbuf[12];
169                 const char      *tag;
170                 const char      *id     = "";
171                 char            perms[4];
172                 int             nbytes;
173
174                 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                         default:
181                                 slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x",
182                                          ap->a_type);
183                                 tag = tagbuf;
184                                 break;
185
186                         case SMB_ACL_USER:
187                                 id = uidtoname(ap->info.user.uid);
188
189                                 FALL_THROUGH;
190                         case SMB_ACL_USER_OBJ:
191                                 tag = "user";
192                                 break;
193
194                         case SMB_ACL_GROUP:
195                                 if ((gr = getgrgid(ap->info.group.gid)) == NULL) {
196                                         slprintf(idbuf, sizeof(idbuf)-1, "%ld",
197                                                 (long)ap->info.group.gid);
198                                         id = idbuf;
199                                 } else {
200                                         id = gr->gr_name;
201                                 }
202
203                                 FALL_THROUGH;
204                         case SMB_ACL_GROUP_OBJ:
205                                 tag = "group";
206                                 break;
207
208                         case SMB_ACL_OTHER:
209                                 tag = "other";
210                                 break;
211
212                         case SMB_ACL_MASK:
213                                 tag = "mask";
214                                 break;
215
216                 }
217
218                 perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
219                 perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
220                 perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
221                 perms[3] = '\0';
222
223                 /*          <tag>      :  <qualifier>   :  rwx \n  \0 */
224                 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                 if ((len + nbytes) > maxlen) {
233                         maxlen += nbytes + 20 * (acl_d->count - i);
234                         if ((text = (char *)SMB_REALLOC(text, maxlen)) == NULL) {
235                                 errno = ENOMEM;
236                                 return NULL;
237                         }
238                 }
239
240
241                 slprintf(&text[len], nbytes, "%s:%s:%s\n", tag, id, perms);
242                 len += (nbytes - 1);
243         }
244
245         if (len_p)
246                 *len_p = len;
247
248         return text;
249 }
250
251 SMB_ACL_T sys_acl_init(TALLOC_CTX *mem_ctx)
252 {
253         SMB_ACL_T       a;
254
255         if ((a = talloc(mem_ctx, struct smb_acl_t)) == NULL) {
256                 errno = ENOMEM;
257                 return NULL;
258         }
259
260         a->count = 0;
261         a->next = -1;
262
263         a->acl = talloc_array(a, struct smb_acl_entry, 0);
264         if (!a->acl) {
265                 TALLOC_FREE(a);
266                 errno = ENOMEM;
267                 return NULL;
268         }
269
270         return a;
271 }
272
273 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
274 {
275         SMB_ACL_T       acl_d;
276         SMB_ACL_ENTRY_T entry_d;
277         struct smb_acl_entry *acl;
278
279         if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
280                 errno = EINVAL;
281                 return -1;
282         }
283
284         acl = talloc_realloc(acl_d, acl_d->acl, struct smb_acl_entry, acl_d->count+1);
285         if (!acl) {
286                 errno = ENOMEM;
287                 return -1;
288         }
289         acl_d->acl = acl;
290         entry_d         = &acl_d->acl[acl_d->count];
291         entry_d->a_type = SMB_ACL_TAG_INVALID;
292         entry_d->a_perm = 0;
293         *entry_p        = entry_d;
294
295         acl_d->count++;
296         return 0;
297 }
298
299 int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
300 {
301         switch (tag_type) {
302                 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                         entry_d->a_type = tag_type;
309                         break;
310                 default:
311                         errno = EINVAL;
312                         return -1;
313                 }
314
315         return 0;
316 }
317
318 int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
319 {
320         if (entry_d->a_type == SMB_ACL_USER) {
321                 entry_d->info.user.uid = *((uid_t *)qual_p);
322                 return 0;
323         }
324         if (entry_d->a_type == SMB_ACL_GROUP) {
325                 entry_d->info.group.gid = *((gid_t *)qual_p);
326                 return 0;
327         }
328
329         errno = EINVAL;
330         return -1;
331 }
332
333 int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
334 {
335         if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
336                 errno = EINVAL;
337                 return -1;
338         }
339
340         entry_d->a_perm = *permset_d;
341
342         return 0;
343 }
344
345 int sys_acl_free_text(char *text)
346 {
347         SAFE_FREE(text);
348         return 0;
349 }
350
351 int sys_acl_valid(SMB_ACL_T acl_d)
352 {
353         errno = EINVAL;
354         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 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         return posixacl_sys_acl_get_fd(handle, fsp, type, mem_ctx);
371 }
372
373 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         return posixacl_sys_acl_set_fd(handle, fsp, type, acl_d);
379 }
380
381 int sys_acl_delete_def_fd(vfs_handle_struct *handle,
382                           files_struct *fsp)
383 {
384         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 int no_acl_syscall_error(int err)
506 {
507 #if defined(ENOSYS)
508         if (err == ENOSYS) {
509                 return 1;
510         }
511 #endif
512 #if defined(ENOTSUP)
513         if (err == ENOTSUP) {
514                 return 1;
515         }
516 #endif
517         return 0;
518 }