~ubuntu-branches/debian/jessie/netatalk/jessie

« back to all changes in this revision

Viewing changes to libatalk/acl/unix.c

  • Committer: Package Import Robot
  • Author(s): Jonas Smedegaard
  • Date: 2012-03-20 23:37:08 UTC
  • mfrom: (1.1.12)
  • Revision ID: package-import@ubuntu.com-20120320233708-sp2k0av7f9sjnf4w
Tags: 2.2.2-1
* New upstream release.
* Drop patch cherry-picked upstream: Included in new upstream release.
* Build-depend on libldap2-dev and libacl1-dev, to enable LDAP support
  and support for extended ACLs (and possibly avoid FTBFS).
  Closes: bug#645290, #651406. Thanks to Peter Eisentraut and masc.
* Update copyright file:
  + Bump format to 1.0.
  + Fix double-indent in Copyright fields as per Policy §5.6.13.
  + Add Files paragraph for ACL code.
* Bump standards-version to 3.9.3.
* Update copyright file: Add disclaimer to License paragraph
  GAP~Makefile.in.
* Bump debhelper compat level to 7.
* Add patch 101 to start avahi-daemon (if available) before atalkd.
  Recommend avahi-daemon.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
  Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
 
3
  Copyright (c) 2011 Laura Mueller <laura-mueller@uni-duesseldorf.de>
3
4
 
4
5
  This program is free software; you can redistribute it and/or modify
5
6
  it under the terms of the GNU General Public License as published by
16
17
#include "config.h"
17
18
#endif /* HAVE_CONFIG_H */
18
19
 
19
 
#ifdef HAVE_SOLARIS_ACLS
 
20
#ifdef HAVE_ACLS
20
21
 
21
22
#include <unistd.h>
22
23
#include <sys/types.h>
33
34
#include <atalk/util.h>
34
35
#include <atalk/acl.h>
35
36
 
 
37
#ifdef HAVE_SOLARIS_ACLS
 
38
 
36
39
/* Get ACL. Allocates storage as needed. Caller must free.
37
40
 * Returns no of ACEs or -1 on error.  */
38
41
int get_nfsv4_acl(const char *name, ace_t **retAces)
53
56
        return 0;
54
57
 
55
58
    if ( ! (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))) {
56
 
        LOG(log_warning, logtype_afpd, "get_nfsv4_acl(\"%s/%s\"): special", getcwdpath(), name);
 
59
        LOG(log_debug, logtype_afpd, "get_nfsv4_acl(\"%s/%s\"): special", getcwdpath(), name);
57
60
        return 0;
58
61
    }
59
62
 
60
63
    if ((ace_count = acl(name, ACE_GETACLCNT, 0, NULL)) == 0) {
61
 
        LOG(log_warning, logtype_afpd, "get_nfsv4_acl(\"%s/%s\"): 0 ACEs", getcwdpath(), name);
 
64
        LOG(log_debug, logtype_afpd, "get_nfsv4_acl(\"%s/%s\"): 0 ACEs", getcwdpath(), name);
62
65
        return 0;
63
66
    }
64
67
 
65
68
    if (ace_count == -1) {
66
 
        LOG(log_error, logtype_afpd, "get_nfsv4_acl: acl('%s/%s', ACE_GETACLCNT): ace_count %i, error: %s",
 
69
        LOG(log_debug, logtype_afpd, "get_nfsv4_acl: acl('%s/%s', ACE_GETACLCNT): ace_count %i, error: %s",
67
70
            getcwdpath(), name, ace_count, strerror(errno));
68
71
        return -1;
69
72
    }
202
205
 * Change mode of file preserving existing explicit ACEs
203
206
 *
204
207
 * nfsv4_chmod
205
 
 * (1) reads objects ACL (acl1)
 
208
 * (1) reads objects ACL (acl1), may return 0 or -1 NFSv4 ACEs on eg UFS fs
206
209
 * (2) removes all trivial ACEs from the ACL by calling strip_trivial_aces(), possibly
207
210
 *     leaving 0 ACEs in the ACL if there were only trivial ACEs as mapped from the mode
208
 
 * (3) calls chmod() with mode
 
211
 * (3) calls chmod() with mode, we're done if step (1) returned 0 for noaces
209
212
 * (4) reads the changed ACL (acl2) which
210
213
 *     a) might still contain explicit ACEs (up to onnv132)
211
214
 *     b) will have any explicit ACE removed (starting with onnv145/Openindiana)
222
225
    LOG(log_debug, logtype_afpd, "nfsv4_chmod(\"%s/%s\", %04o)",
223
226
        getcwdpath(), name, mode);
224
227
 
225
 
    if ((noaces = get_nfsv4_acl(name, &oacl)) == -1) /* (1) */
226
 
        goto exit;
 
228
    if ((noaces = get_nfsv4_acl(name, &oacl)) < 1) /* (1) */
 
229
        return chmod(name, mode);
 
230
 
227
231
    if ((noaces = strip_trivial_aces(&oacl, noaces)) == -1) /* (2) */
228
232
        goto exit;
229
233
 
230
 
#ifdef chmod
231
 
#undef chmod
232
 
#endif
233
234
    if (chmod(name, mode) != 0) /* (3) */
234
235
        goto exit;
235
236
 
258
259
}
259
260
 
260
261
#endif /* HAVE_SOLARIS_ACLS */
 
262
 
 
263
#ifdef HAVE_POSIX_ACLS
 
264
 
 
265
/* This is a workaround for chmod() on filestystems supporting Posix 1003.1e draft 17
 
266
 * compliant ACLs. For objects with extented ACLs, eg objects with an ACL_MASK entry,
 
267
 * chmod() manipulates ACL_MASK instead of ACL_GROUP_OBJ. As OS X isn't aware of
 
268
 * this behavior calling FPSetFileDirParms may lead to unpredictable results. For
 
269
 * more information see section 23.1.2 of Posix 1003.1e draft 17.
 
270
 *
 
271
 * posix_chmod() accepts the same arguments as chmod() and returns 0 in case of
 
272
 * success or -1 in case something went wrong.
 
273
 */
 
274
 
 
275
#define SEARCH_GROUP_OBJ 0x01
 
276
#define SEARCH_MASK 0x02
 
277
 
 
278
int posix_chmod(const char *name, mode_t mode) {
 
279
    int ret = 0;
 
280
    int entry_id = ACL_FIRST_ENTRY;
 
281
    acl_entry_t entry;
 
282
    acl_entry_t group_entry;
 
283
    acl_tag_t tag;
 
284
    acl_t acl;
 
285
    u_char not_found = (SEARCH_GROUP_OBJ|SEARCH_MASK); /* used as flags */
 
286
 
 
287
    LOG(log_maxdebug, logtype_afpd, "posix_chmod: %s mode: 0x%08x", name, mode);
 
288
 
 
289
    /* Call chmod() first because there might be some special bits to be set which
 
290
     * aren't related to access control.
 
291
     */
 
292
    ret = chmod(name, mode);
 
293
 
 
294
    if (ret)
 
295
        goto done;
 
296
 
 
297
    /* Check if the underlying filesystem supports ACLs. */
 
298
    acl = acl_get_file(name, ACL_TYPE_ACCESS);
 
299
 
 
300
    if (acl) {
 
301
        /* There is no need to keep iterating once we have found ACL_GROUP_OBJ and ACL_MASK. */
 
302
        while ((acl_get_entry(acl, entry_id, &entry) == 1) && not_found) {
 
303
            entry_id = ACL_NEXT_ENTRY;
 
304
 
 
305
            ret = acl_get_tag_type(entry, &tag);
 
306
 
 
307
            if (ret) {
 
308
                LOG(log_error, logtype_afpd, "posix_chmod: Failed to get tag type.");
 
309
                goto cleanup;
 
310
            }
 
311
 
 
312
            switch (tag) {
 
313
                case ACL_GROUP_OBJ:
 
314
                    group_entry = entry;
 
315
                    not_found &= ~SEARCH_GROUP_OBJ;
 
316
                    break;
 
317
 
 
318
                case ACL_MASK:
 
319
                    not_found &= ~SEARCH_MASK;
 
320
                    break;
 
321
 
 
322
                default:
 
323
                    break;
 
324
            }
 
325
        }
 
326
        if (!not_found) {
 
327
            /* The filesystem object has extented ACLs. We have to update ACL_GROUP_OBJ
 
328
             * with the group permissions.
 
329
             */
 
330
            acl_permset_t permset;
 
331
            acl_perm_t perm = 0;
 
332
 
 
333
            ret = acl_get_permset(group_entry, &permset);
 
334
 
 
335
            if (ret) {
 
336
                LOG(log_error, logtype_afpd, "posix_chmod: Can't get permset.");
 
337
                goto cleanup;
 
338
            }
 
339
            ret = acl_clear_perms(permset);
 
340
 
 
341
            if (ret)
 
342
                goto cleanup;
 
343
 
 
344
            if (mode & S_IXGRP)
 
345
                perm |= ACL_EXECUTE;
 
346
 
 
347
            if (mode & S_IWGRP)
 
348
                perm |= ACL_WRITE;
 
349
 
 
350
            if (mode & S_IRGRP)
 
351
                perm |= ACL_READ;
 
352
 
 
353
            ret = acl_add_perm(permset, perm);
 
354
 
 
355
            if (ret)
 
356
                goto cleanup;
 
357
 
 
358
            ret = acl_set_permset(group_entry, permset);
 
359
 
 
360
            if (ret) {
 
361
                LOG(log_error, logtype_afpd, "posix_chmod: Can't set permset.");
 
362
                goto cleanup;
 
363
            }
 
364
            /* also update ACL_MASK */
 
365
            ret = acl_calc_mask(&acl);
 
366
 
 
367
            if (ret) {
 
368
                LOG(log_error, logtype_afpd, "posix_chmod: acl_calc_mask failed.");
 
369
                goto cleanup;
 
370
            }
 
371
            ret = acl_set_file(name, ACL_TYPE_ACCESS, acl);
 
372
        }
 
373
cleanup:
 
374
        acl_free(acl);
 
375
    }
 
376
done:
 
377
    LOG(log_maxdebug, logtype_afpd, "posix_chmod: %d", ret);
 
378
    return ret;
 
379
}
 
380
 
 
381
/*
 
382
 * posix_fchmod() accepts the same arguments as fchmod() and returns 0 in case of
 
383
 * success or -1 in case something went wrong.
 
384
 */
 
385
int posix_fchmod(int fd, mode_t mode) {
 
386
    int ret = 0;
 
387
    int entry_id = ACL_FIRST_ENTRY;
 
388
    acl_entry_t entry;
 
389
    acl_entry_t group_entry;
 
390
    acl_tag_t tag;
 
391
    acl_t acl;
 
392
    u_char not_found = (SEARCH_GROUP_OBJ|SEARCH_MASK); /* used as flags */
 
393
 
 
394
    /* Call chmod() first because there might be some special bits to be set which
 
395
     * aren't related to access control.
 
396
     */
 
397
    ret = fchmod(fd, mode);
 
398
 
 
399
    if (ret)
 
400
        goto done;
 
401
 
 
402
    /* Check if the underlying filesystem supports ACLs. */
 
403
    acl = acl_get_fd(fd);
 
404
 
 
405
    if (acl) {
 
406
        /* There is no need to keep iterating once we have found ACL_GROUP_OBJ and ACL_MASK. */
 
407
        while ((acl_get_entry(acl, entry_id, &entry) == 1) && not_found) {
 
408
            entry_id = ACL_NEXT_ENTRY;
 
409
 
 
410
            ret = acl_get_tag_type(entry, &tag);
 
411
 
 
412
            if (ret) {
 
413
                LOG(log_error, logtype_afpd, "posix_fchmod: Failed to get tag type.");
 
414
                goto cleanup;
 
415
            }
 
416
 
 
417
            switch (tag) {
 
418
                case ACL_GROUP_OBJ:
 
419
                    group_entry = entry;
 
420
                    not_found &= ~SEARCH_GROUP_OBJ;
 
421
                    break;
 
422
 
 
423
                case ACL_MASK:
 
424
                    not_found &= ~SEARCH_MASK;
 
425
                    break;
 
426
 
 
427
                default:
 
428
                    break;
 
429
            }
 
430
        }
 
431
        if (!not_found) {
 
432
            /* The filesystem object has extented ACLs. We have to update ACL_GROUP_OBJ
 
433
             * with the group permissions.
 
434
             */
 
435
            acl_permset_t permset;
 
436
            acl_perm_t perm = 0;
 
437
 
 
438
            ret = acl_get_permset(group_entry, &permset);
 
439
 
 
440
            if (ret) {
 
441
                LOG(log_error, logtype_afpd, "posix_fchmod: Can't get permset.");
 
442
                goto cleanup;
 
443
            }
 
444
            ret = acl_clear_perms(permset);
 
445
 
 
446
            if (ret)
 
447
                goto cleanup;
 
448
 
 
449
            if (mode & S_IXGRP)
 
450
                perm |= ACL_EXECUTE;
 
451
 
 
452
            if (mode & S_IWGRP)
 
453
                perm |= ACL_WRITE;
 
454
 
 
455
            if (mode & S_IRGRP)
 
456
                perm |= ACL_READ;
 
457
 
 
458
            ret = acl_add_perm(permset, perm);
 
459
 
 
460
            if (ret)
 
461
                goto cleanup;
 
462
 
 
463
            ret = acl_set_permset(group_entry, permset);
 
464
 
 
465
            if (ret) {
 
466
                LOG(log_error, logtype_afpd, "posix_fchmod: Can't set permset.");
 
467
                goto cleanup;
 
468
            }
 
469
            /* also update ACL_MASK */
 
470
            ret = acl_calc_mask(&acl);
 
471
 
 
472
            if (ret) {
 
473
                LOG(log_error, logtype_afpd, "posix_fchmod: acl_calc_mask failed.");
 
474
                goto cleanup;
 
475
            }
 
476
            ret = acl_set_fd(fd, acl);
 
477
        }
 
478
cleanup:
 
479
        acl_free(acl);
 
480
    }
 
481
done:
 
482
    return ret;
 
483
}
 
484
 
 
485
#endif /* HAVE_POSIX_ACLS */
 
486
 
 
487
#endif /* HAVE_ACLS */