s3-rpc_client: make dcerpc_lsa_lookup_names_generic() public.
[kai/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_ACLS) || defined(HAVE_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                         case SMB_ACL_USER_OBJ:
190                                 tag = "user";
191                                 break;
192
193                         case SMB_ACL_GROUP:
194                                 if ((gr = getgrgid(ap->info.group.gid)) == NULL) {
195                                         slprintf(idbuf, sizeof(idbuf)-1, "%ld",
196                                                 (long)ap->info.group.gid);
197                                         id = idbuf;
198                                 } else {
199                                         id = gr->gr_name;
200                                 }
201                         case SMB_ACL_GROUP_OBJ:
202                                 tag = "group";
203                                 break;
204
205                         case SMB_ACL_OTHER:
206                                 tag = "other";
207                                 break;
208
209                         case SMB_ACL_MASK:
210                                 tag = "mask";
211                                 break;
212
213                 }
214
215                 perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
216                 perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
217                 perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
218                 perms[3] = '\0';
219
220                 /*          <tag>      :  <qualifier>   :  rwx \n  \0 */
221                 nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
222
223                 /*
224                  * If this entry would overflow the buffer
225                  * allocate enough additional memory for this
226                  * entry and an estimate of another 20 bytes
227                  * for each entry still to be processed
228                  */
229                 if ((len + nbytes) > maxlen) {
230                         maxlen += nbytes + 20 * (acl_d->count - i);
231                         if ((text = (char *)SMB_REALLOC(text, maxlen)) == NULL) {
232                                 errno = ENOMEM;
233                                 return NULL;
234                         }
235                 }
236
237
238                 slprintf(&text[len], nbytes, "%s:%s:%s\n", tag, id, perms);
239                 len += (nbytes - 1);
240         }
241
242         if (len_p)
243                 *len_p = len;
244
245         return text;
246 }
247
248 SMB_ACL_T sys_acl_init(TALLOC_CTX *mem_ctx)
249 {
250         SMB_ACL_T       a;
251
252         if ((a = talloc(mem_ctx, struct smb_acl_t)) == NULL) {
253                 errno = ENOMEM;
254                 return NULL;
255         }
256  
257         a->count = 0;
258         a->next = -1;
259
260         a->acl = talloc_array(a, struct smb_acl_entry, 0);
261         if (!a->acl) {
262                 TALLOC_FREE(a);
263                 errno = ENOMEM;
264                 return NULL;
265         }
266
267         return a;
268 }
269
270 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
271 {
272         SMB_ACL_T       acl_d;
273         SMB_ACL_ENTRY_T entry_d;
274         struct smb_acl_entry *acl;
275
276         if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
277                 errno = EINVAL;
278                 return -1;
279         }
280
281         acl = talloc_realloc(acl_d, acl_d->acl, struct smb_acl_entry, acl_d->count+1);
282         if (!acl) {
283                 errno = ENOMEM;
284                 return -1;
285         }
286         acl_d->acl = acl;
287         entry_d         = &acl_d->acl[acl_d->count];
288         entry_d->a_type = SMB_ACL_TAG_INVALID;
289         entry_d->a_perm = 0;
290         *entry_p        = entry_d;
291
292         acl_d->count++;
293         return 0;
294 }
295
296 int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
297 {
298         switch (tag_type) {
299                 case SMB_ACL_USER:
300                 case SMB_ACL_USER_OBJ:
301                 case SMB_ACL_GROUP:
302                 case SMB_ACL_GROUP_OBJ:
303                 case SMB_ACL_OTHER:
304                 case SMB_ACL_MASK:
305                         entry_d->a_type = tag_type;
306                         break;
307                 default:
308                         errno = EINVAL;
309                         return -1;
310                 }
311
312         return 0;
313 }
314
315 int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
316 {
317         if (entry_d->a_type == SMB_ACL_USER) {
318                 entry_d->info.user.uid = *((uid_t *)qual_p);
319                 return 0;
320                 }
321         if (entry_d->a_type == SMB_ACL_GROUP) {
322                 entry_d->info.group.gid = *((gid_t *)qual_p);
323                 return 0;
324         }
325
326         errno = EINVAL;
327         return -1;
328 }
329
330 int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
331 {
332         if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
333                 errno = EINVAL;
334                 return -1;
335         }
336
337         entry_d->a_perm = *permset_d;
338  
339         return 0;
340 }
341
342 int sys_acl_free_text(char *text)
343 {
344         SAFE_FREE(text);
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, TALLOC_CTX *mem_ctx)
364 {
365         return posixacl_sys_acl_get_file(handle, path_p, type, mem_ctx);
366 }
367  
368 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, TALLOC_CTX *mem_ctx)
369 {
370         return posixacl_sys_acl_get_fd(handle, fsp, mem_ctx);
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                    SMB_ACL_T acl_d)
381 {
382         return posixacl_sys_acl_set_fd(handle, fsp, 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                            TALLOC_CTX *mem_ctx)
396 {
397         return aixacl_sys_acl_get_file(handle, path_p, type, mem_ctx);
398 }
399
400 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp,
401                            TALLOC_CTX *mem_ctx)
402 {
403         return aixacl_sys_acl_get_fd(handle, fsp, mem_ctx);
404 }
405
406 int sys_acl_set_file(vfs_handle_struct *handle,
407                      const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
408 {
409         return aixacl_sys_acl_set_file(handle, name, type, acl_d);
410 }
411
412 int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
413                    SMB_ACL_T acl_d)
414 {
415         return aixacl_sys_acl_set_fd(handle, fsp, acl_d);
416 }
417
418 int sys_acl_delete_def_file(vfs_handle_struct *handle,
419                             const char *path)
420 {
421         return aixacl_sys_acl_delete_def_file(handle, path);
422 }
423
424 #elif defined(HAVE_TRU64_ACLS)
425  
426 SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
427                            const char *path_p, SMB_ACL_TYPE_T type,
428                            TALLOC_CTX *mem_ctx)
429 {
430         return tru64acl_sys_acl_get_file(handle, path_p, type,
431                                          mem_ctx);
432 }
433
434 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp,
435                          TALLOC_CTX *mem_ctx)
436 {
437         return tru64acl_sys_acl_get_fd(handle, fsp, mem_ctx);
438 }
439
440 int sys_acl_set_file(vfs_handle_struct *handle,
441                      const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
442 {
443         return tru64acl_sys_acl_set_file(handle, name, type, acl_d);
444 }
445
446 int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
447                    SMB_ACL_T acl_d)
448 {
449         return tru64acl_sys_acl_set_fd(handle, fsp, acl_d);
450 }
451
452 int sys_acl_delete_def_file(vfs_handle_struct *handle,
453                             const char *path)
454 {
455         return tru64acl_sys_acl_delete_def_file(handle, path);
456 }
457
458 #elif defined(HAVE_SOLARIS_ACLS) || defined(HAVE_UNIXWARE_ACLS)
459
460 SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
461                            const char *path_p, SMB_ACL_TYPE_T type,
462                            TALLOC_CTX *mem_ctx)
463 {
464         return solarisacl_sys_acl_get_file(handle, path_p, type,
465                                            mem_ctx);
466 }
467
468 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp,
469                          TALLOC_CTX *mem_ctx)
470 {
471         return solarisacl_sys_acl_get_fd(handle, fsp,
472                                          mem_ctx);
473 }
474
475 int sys_acl_set_file(vfs_handle_struct *handle,
476                      const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
477 {
478         return solarisacl_sys_acl_set_file(handle, name, type, acl_d);
479 }
480
481 int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
482                    SMB_ACL_T acl_d)
483 {
484         return solarisacl_sys_acl_set_fd(handle, fsp, acl_d);
485 }
486
487 int sys_acl_delete_def_file(vfs_handle_struct *handle,
488                             const char *path)
489 {
490         return solarisacl_sys_acl_delete_def_file(handle, path);
491 }
492
493 #elif defined(HAVE_HPUX_ACLS)
494
495 SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
496                            const char *path_p, SMB_ACL_TYPE_T type,
497                            TALLOC_CTX *mem_ctx)
498 {
499         return hpuxacl_sys_acl_get_file(handle, path_p, type, mem_ctx);
500 }
501
502 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp,
503                            TALLOC_CTX *mem_ctx)
504 {
505         return hpuxacl_sys_acl_get_fd(handle, fsp, mem_ctx);
506 }
507
508 int sys_acl_set_file(vfs_handle_struct *handle,
509                      const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
510 {
511         return hpuxacl_sys_acl_set_file(handle, name, type, acl_d);
512 }
513
514 int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
515                    SMB_ACL_T acl_d)
516 {
517         return hpuxacl_sys_acl_set_fd(handle, fsp, acl_d);
518 }
519
520 int sys_acl_delete_def_file(vfs_handle_struct *handle,
521                             const char *path)
522 {
523         return hpuxacl_sys_acl_delete_def_file(handle, path);
524 }
525
526 #else /* No ACLs. */
527
528 SMB_ACL_T sys_acl_get_file(vfs_handle_struct *handle,
529                            const char *path_p, SMB_ACL_TYPE_T type,
530                            TALLOC_CTX *mem_ctx)
531 {
532 #ifdef ENOTSUP
533         errno = ENOTSUP;
534 #else
535         errno = ENOSYS;
536 #endif
537         return NULL;
538 }
539
540 SMB_ACL_T sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp,
541                          TALLOC_CTX *mem_ctx)
542 {
543 #ifdef ENOTSUP
544         errno = ENOTSUP;
545 #else
546         errno = ENOSYS;
547 #endif
548         return NULL;
549 }
550
551 int sys_acl_set_file(vfs_handle_struct *handle,
552                      const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
553 {
554 #ifdef ENOTSUP
555         errno = ENOTSUP;
556 #else
557         errno = ENOSYS;
558 #endif
559         return -1;
560 }
561
562 int sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
563                    SMB_ACL_T acl_d)
564 {
565 #ifdef ENOTSUP
566         errno = ENOTSUP;
567 #else
568         errno = ENOSYS;
569 #endif
570         return -1;
571 }
572
573 int sys_acl_delete_def_file(vfs_handle_struct *handle,
574                             const char *path)
575 {
576 #ifdef ENOTSUP
577         errno = ENOTSUP;
578 #else
579         errno = ENOSYS;
580 #endif
581         return -1;
582 }
583
584 #endif
585
586 /************************************************************************
587  Deliberately outside the ACL defines. Return 1 if this is a "no acls"
588  errno, 0 if not.
589 ************************************************************************/
590
591 int no_acl_syscall_error(int err)
592 {
593 #if defined(ENOSYS)
594         if (err == ENOSYS) {
595                 return 1;
596         }
597 #endif
598 #if defined(ENOTSUP)
599         if (err == ENOTSUP) {
600                 return 1;
601         }
602 #endif
603         return 0;
604 }