s3: Make the difference between r/o and r/w in connections_db_ctx more obvious
[ira/wip.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
24 #undef  DBGC_CLASS
25 #define DBGC_CLASS DBGC_ACLS
26
27 /*
28  * Note that while this code implements sufficient functionality
29  * to support the sys_acl_* interfaces it does not provide all
30  * of the semantics of the POSIX ACL interfaces.
31  *
32  * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
33  * from a call to sys_acl_get_entry() should not be assumed to be
34  * valid after calling any of the following functions, which may
35  * reorder the entries in the ACL.
36  *
37  *      sys_acl_valid()
38  *      sys_acl_set_file()
39  *      sys_acl_set_fd()
40  */
41
42 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
43 {
44         if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
45                 errno = EINVAL;
46                 return -1;
47         }
48
49         if (entry_p == NULL) {
50                 errno = EINVAL;
51                 return -1;
52         }
53
54         if (entry_id == SMB_ACL_FIRST_ENTRY) {
55                 acl_d->next = 0;
56         }
57
58         if (acl_d->next < 0) {
59                 errno = EINVAL;
60                 return -1;
61         }
62
63         if (acl_d->next >= acl_d->count) {
64                 return 0;
65         }
66
67         *entry_p = &acl_d->acl[acl_d->next++];
68
69         return 1;
70 }
71
72 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
73 {
74         *type_p = entry_d->a_type;
75
76         return 0;
77 }
78
79 int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
80 {
81         *permset_p = &entry_d->a_perm;
82
83         return 0;
84 }
85
86 void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
87 {
88         if (entry_d->a_type == SMB_ACL_USER) {
89                 return &entry_d->uid;
90                 }
91
92         if (entry_d->a_type == SMB_ACL_GROUP) {
93                 return &entry_d->gid;
94         }
95
96         errno = EINVAL;
97                 return NULL;
98 }
99
100 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
101 {
102         *permset_d = 0;
103
104         return 0;
105 }
106
107 int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
108 {
109         if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
110             && perm != SMB_ACL_EXECUTE) {
111                 errno = EINVAL;
112                 return -1;
113                 }
114  
115         if (permset_d == NULL) {
116                 errno = EINVAL;
117                 return -1;
118         }
119
120         *permset_d |= perm;
121  
122         return 0;
123 }
124
125 int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
126 {
127         return *permset_d & perm;
128 }
129
130 char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
131 {
132         int     i;
133         int     len, maxlen;
134         char    *text;
135
136         /*
137          * use an initial estimate of 20 bytes per ACL entry
138          * when allocating memory for the text representation
139          * of the ACL
140          */
141         len     = 0;
142         maxlen  = 20 * acl_d->count;
143         if ((text = (char *)SMB_MALLOC(maxlen)) == NULL) {
144                 errno = ENOMEM;
145                 return NULL;
146         }
147
148         for (i = 0; i < acl_d->count; i++) {
149                 struct smb_acl_entry *ap = &acl_d->acl[i];
150                 struct group    *gr;
151                 char            tagbuf[12];
152                 char            idbuf[12];
153                 const char      *tag;
154                 const char      *id     = "";
155                 char            perms[4];
156                 int             nbytes;
157
158                 switch (ap->a_type) {
159                         /*
160                          * for debugging purposes it's probably more
161                          * useful to dump unknown tag types rather
162                          * than just returning an error
163                          */
164                         default:
165                                 slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x",
166                                          ap->a_type);
167                                 tag = tagbuf;
168                                 break;
169  
170                         case SMB_ACL_USER:
171                                 id = uidtoname(ap->uid);
172                         case SMB_ACL_USER_OBJ:
173                                 tag = "user";
174                                 break;
175
176                         case SMB_ACL_GROUP:
177                                 if ((gr = getgrgid(ap->gid)) == NULL) {
178                                         slprintf(idbuf, sizeof(idbuf)-1, "%ld",
179                                                 (long)ap->gid);
180                                         id = idbuf;
181                                 } else {
182                                         id = gr->gr_name;
183                                 }
184                         case SMB_ACL_GROUP_OBJ:
185                                 tag = "group";
186                                 break;
187
188                         case SMB_ACL_OTHER:
189                                 tag = "other";
190                                 break;
191
192                         case SMB_ACL_MASK:
193                                 tag = "mask";
194                                 break;
195
196                 }
197
198                 perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
199                 perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
200                 perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
201                 perms[3] = '\0';
202
203                 /*          <tag>      :  <qualifier>   :  rwx \n  \0 */
204                 nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
205
206                 /*
207                  * If this entry would overflow the buffer
208                  * allocate enough additional memory for this
209                  * entry and an estimate of another 20 bytes
210                  * for each entry still to be processed
211                  */
212                 if ((len + nbytes) > maxlen) {
213                         maxlen += nbytes + 20 * (acl_d->count - i);
214                         if ((text = (char *)SMB_REALLOC(text, maxlen)) == NULL) {
215                         errno = ENOMEM;
216                                 return NULL;
217                 }
218         }
219
220                 slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms);
221                 len += nbytes - 1;
222         }
223
224         if (len_p)
225                 *len_p = len;
226
227         return text;
228 }
229
230 SMB_ACL_T sys_acl_init(int count)
231 {
232         SMB_ACL_T       a;
233
234         if (count < 0) {
235                 errno = EINVAL;
236                 return NULL;
237         }
238
239         /*
240          * note that since the definition of the structure pointed
241          * to by the SMB_ACL_T includes the first element of the
242          * acl[] array, this actually allocates an ACL with room
243          * for (count+1) entries
244          */
245         if ((a = (struct smb_acl_t *)SMB_MALLOC(
246                      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 = SMB_ACL_TAG_INVALID;
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)
368 {
369         return posixacl_sys_acl_get_fd(handle, fsp);
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                    SMB_ACL_T acl_d)
380 {
381         return posixacl_sys_acl_set_fd(handle, fsp, 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)
399 {
400         return aixacl_sys_acl_get_fd(handle, fsp);
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                    SMB_ACL_T acl_d)
411 {
412         return aixacl_sys_acl_set_fd(handle, fsp, 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)
430 {
431         return tru64acl_sys_acl_get_fd(handle, fsp);
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                    SMB_ACL_T acl_d)
442 {
443         return tru64acl_sys_acl_set_fd(handle, fsp, 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)
461 {
462         return solarisacl_sys_acl_get_fd(handle, fsp);
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                    SMB_ACL_T acl_d)
473 {
474         return solarisacl_sys_acl_set_fd(handle, fsp, 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)
492 {
493         return hpuxacl_sys_acl_get_fd(handle, fsp);
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                    SMB_ACL_T acl_d)
504 {
505         return hpuxacl_sys_acl_set_fd(handle, fsp, 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)
523 {
524         return irixacl_sys_acl_get_fd(handle, fsp);
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                    SMB_ACL_T acl_d)
535 {
536         return irixacl_sys_acl_set_fd(handle, fsp, 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 #ifdef ENOTSUP
551         errno = ENOTSUP;
552 #else
553         errno = ENOSYS;
554 #endif
555         return NULL;
556 }
557
558 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp)
559 {
560 #ifdef ENOTSUP
561         errno = ENOTSUP;
562 #else
563         errno = ENOSYS;
564 #endif
565         return NULL;
566 }
567
568 int sys_acl_set_file(vfs_handle_struct *handle,
569                      const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
570 {
571 #ifdef ENOTSUP
572         errno = ENOTSUP;
573 #else
574         errno = ENOSYS;
575 #endif
576         return -1;
577 }
578
579 int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
580                    SMB_ACL_T acl_d)
581 {
582 #ifdef ENOTSUP
583         errno = ENOTSUP;
584 #else
585         errno = ENOSYS;
586 #endif
587         return -1;
588 }
589
590 int sys_acl_delete_def_file(vfs_handle_struct *handle,
591                             const char *path)
592 {
593 #ifdef ENOTSUP
594         errno = ENOTSUP;
595 #else
596         errno = ENOSYS;
597 #endif
598         return -1;
599 }
600
601 #endif
602
603 /************************************************************************
604  Deliberately outside the ACL defines. Return 1 if this is a "no acls"
605  errno, 0 if not.
606 ************************************************************************/
607
608 int no_acl_syscall_error(int err)
609 {
610 #if defined(ENOSYS)
611         if (err == ENOSYS) {
612                 return 1;
613         }
614 #endif
615 #if defined(ENOTSUP)
616         if (err == ENOTSUP) {
617                 return 1;
618         }
619 #endif
620         return 0;
621 }