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