~ubuntu-branches/debian/wheezy/netatalk/wheezy

« back to all changes in this revision

Viewing changes to libatalk/acl/unix.c

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2011-06-05 21:04:21 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20110605210421-19gag2srevj0ocxh
Tags: 2.2~beta4-1
* New upstream release.
  + Fixes "Internal Error" after ad_open on sparc.
    Closes: bug#606005. Thanks to Alfredo Sola.
* Adjust references to unofficial packages in README.Debian.
* Use dversionmangle (not uversionmangle) in watch file. Fix add
  leading dash (-) to upstream version in mangling.
* Update patches:
  + Drop patches 107 and 294 (Zeroconf support): Implemented
    (differently) upstream now.
  + Drop patches 109 and 112 (avoid broken XFS linkage) obsolete.
  + Drop patch 200 (hostname resolving): adopted upstream.
  + Refresh patch 205.
* Rewrite copyright file using draft 174 of DEP-5 format.
* Build-depend on and recommend unversioned (i.e. default) BerkeleyDB
  packages.
  Closes: bug#621413. Thanks to Ondřej Surý.
  Simplify suggestions on older versioned BerkeleyDB packages.
* Stop installing some documentation dropped upstream, and let CDBS
  automagically handle some of the remains.
* Update control file:
  + Bump policy compliance to standards-version 3.9.2.
  + Shorten Vcs-* URLs.
* Add patches 115 and (for automade file) 214 to avoid installing
  unneeded /default dir.
  Closes: bug#628119. Thanks to Russell Muetzelfeldt and Luk Claes.
* Don't ship .la files. Closes: bug#621849. Thanks to Andreas Metzler
  and Luk Claes.
* Stop renaming afile and achfile, dropped upstream.
* Explicitly enable DDP (AppleTalk), now disabled by default.
* Enable Zeroconf, should be stable now.
* Simplify package relations:
  + Drop (build-)dependency fallback unneeded even for oldstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
 
3
 
 
4
  This program is free software; you can redistribute it and/or modify
 
5
  it under the terms of the GNU General Public License as published by
 
6
  the Free Software Foundation; either version 2 of the License, or
 
7
  (at your option) any later version.
 
8
 
 
9
  This program is distributed in the hope that it will be useful,
 
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
  GNU General Public License for more details.
 
13
*/
 
14
 
 
15
#ifdef HAVE_CONFIG_H
 
16
#include "config.h"
 
17
#endif /* HAVE_CONFIG_H */
 
18
 
 
19
#ifdef HAVE_SOLARIS_ACLS
 
20
 
 
21
#include <unistd.h>
 
22
#include <sys/types.h>
 
23
#include <sys/stat.h>
 
24
#include <stdio.h>
 
25
#include <stdlib.h>
 
26
#include <string.h>
 
27
#include <time.h>
 
28
#include <errno.h>
 
29
#include <sys/acl.h>
 
30
 
 
31
#include <atalk/logger.h>
 
32
#include <atalk/afp.h>
 
33
#include <atalk/util.h>
 
34
#include <atalk/acl.h>
 
35
 
 
36
/* Get ACL. Allocates storage as needed. Caller must free.
 
37
 * Returns no of ACEs or -1 on error.  */
 
38
int get_nfsv4_acl(const char *name, ace_t **retAces)
 
39
{
 
40
    int ace_count = -1;
 
41
    ace_t *aces;
 
42
    struct stat st;
 
43
 
 
44
    *retAces = NULL;
 
45
    /* Only call acl() for regular files and directories, otherwise just return 0 */
 
46
    if (lstat(name, &st) != 0) {
 
47
        LOG(log_warning, logtype_afpd, "get_nfsv4_acl(\"%s/%s\"): %s", getcwdpath(), name, strerror(errno));
 
48
        return -1;
 
49
    }
 
50
 
 
51
    if (S_ISLNK(st.st_mode))
 
52
        /* sorry, no ACLs for symlinks */
 
53
        return 0;
 
54
 
 
55
    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);
 
57
        return 0;
 
58
    }
 
59
 
 
60
    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);
 
62
        return 0;
 
63
    }
 
64
 
 
65
    if (ace_count == -1) {
 
66
        LOG(log_error, logtype_afpd, "get_nfsv4_acl: acl('%s/%s', ACE_GETACLCNT): ace_count %i, error: %s",
 
67
            getcwdpath(), name, ace_count, strerror(errno));
 
68
        return -1;
 
69
    }
 
70
 
 
71
    aces = malloc(ace_count * sizeof(ace_t));
 
72
    if (aces == NULL) {
 
73
        LOG(log_error, logtype_afpd, "get_nfsv4_acl: malloc error");
 
74
        return -1;
 
75
    }
 
76
 
 
77
    if ( (acl(name, ACE_GETACL, ace_count, aces)) == -1 ) {
 
78
        LOG(log_error, logtype_afpd, "get_nfsv4_acl: acl(ACE_GETACL) error");
 
79
        free(aces);
 
80
        return -1;
 
81
    }
 
82
 
 
83
    LOG(log_debug9, logtype_afpd, "get_nfsv4_acl: file: %s -> No. of ACEs: %d", name, ace_count);
 
84
    *retAces = aces;
 
85
 
 
86
    return ace_count;
 
87
}
 
88
 
 
89
/*
 
90
  Concatenate ACEs
 
91
*/
 
92
ace_t *concat_aces(ace_t *aces1, int ace1count, ace_t *aces2, int ace2count)
 
93
{
 
94
    ace_t *new_aces;
 
95
    int i, j;
 
96
 
 
97
    /* malloc buffer for new ACL */
 
98
    if ((new_aces = malloc((ace1count + ace2count) * sizeof(ace_t))) == NULL) {
 
99
        LOG(log_error, logtype_afpd, "combine_aces: malloc %s", strerror(errno));
 
100
        return NULL;
 
101
    }
 
102
 
 
103
    /* Copy ACEs from buf1 */
 
104
    for (i=0; i < ace1count; ) {
 
105
        memcpy(&new_aces[i], &aces1[i], sizeof(ace_t));
 
106
        i++;
 
107
    }
 
108
 
 
109
    j = i;
 
110
 
 
111
    /* Copy ACEs from buf2 */
 
112
    for (i=0; i < ace2count; ) {
 
113
        memcpy(&new_aces[j], &aces2[i], sizeof(ace_t));
 
114
        i++;
 
115
        j++;
 
116
    }
 
117
    return new_aces;
 
118
}
 
119
 
 
120
/*
 
121
  Remove any trivial ACE "in-place". Returns no of non-trivial ACEs
 
122
*/
 
123
int strip_trivial_aces(ace_t **saces, int sacecount)
 
124
{
 
125
    int i,j;
 
126
    int nontrivaces = 0;
 
127
    ace_t *aces = *saces;
 
128
    ace_t *new_aces;
 
129
 
 
130
    if (aces == NULL || sacecount <= 0)
 
131
        return 0;
 
132
 
 
133
    /* Count non-trivial ACEs */
 
134
    for (i=0; i < sacecount; ) {
 
135
        if ( ! (aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)))
 
136
            nontrivaces++;
 
137
        i++;
 
138
    }
 
139
    /* malloc buffer for new ACL */
 
140
    if ((new_aces = malloc(nontrivaces * sizeof(ace_t))) == NULL) {
 
141
        LOG(log_error, logtype_afpd, "strip_trivial_aces: malloc %s", strerror(errno));
 
142
        return -1;
 
143
    }
 
144
 
 
145
    /* Copy non-trivial ACEs */
 
146
    for (i=0, j=0; i < sacecount; ) {
 
147
        if ( ! (aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE))) {
 
148
            memcpy(&new_aces[j], &aces[i], sizeof(ace_t));
 
149
            j++;
 
150
        }
 
151
        i++;
 
152
    }
 
153
 
 
154
    free(aces);
 
155
    *saces = new_aces;
 
156
 
 
157
    LOG(log_debug7, logtype_afpd, "strip_trivial_aces: non-trivial ACEs: %d", nontrivaces);
 
158
 
 
159
    return nontrivaces;
 
160
}
 
161
 
 
162
/*
 
163
  Remove non-trivial ACEs "in-place". Returns no of trivial ACEs.
 
164
*/
 
165
int strip_nontrivial_aces(ace_t **saces, int sacecount)
 
166
{
 
167
    int i,j;
 
168
    int trivaces = 0;
 
169
    ace_t *aces = *saces;
 
170
    ace_t *new_aces;
 
171
 
 
172
    /* Count trivial ACEs */
 
173
    for (i=0; i < sacecount; ) {
 
174
        if ((aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)))
 
175
            trivaces++;
 
176
        i++;
 
177
    }
 
178
    /* malloc buffer for new ACL */
 
179
    if ((new_aces = malloc(trivaces * sizeof(ace_t))) == NULL) {
 
180
        LOG(log_error, logtype_afpd, "strip_nontrivial_aces: malloc %s", strerror(errno));
 
181
        return -1;
 
182
    }
 
183
 
 
184
    /* Copy trivial ACEs */
 
185
    for (i=0, j=0; i < sacecount; ) {
 
186
        if ((aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE))) {
 
187
            memcpy(&new_aces[j], &aces[i], sizeof(ace_t));
 
188
            j++;
 
189
        }
 
190
        i++;
 
191
    }
 
192
    /* Free old ACEs */
 
193
    free(aces);
 
194
    *saces = new_aces;
 
195
 
 
196
    LOG(log_debug7, logtype_afpd, "strip_nontrivial_aces: trivial ACEs: %d", trivaces);
 
197
 
 
198
    return trivaces;
 
199
}
 
200
 
 
201
/*!
 
202
 * Change mode of file preserving existing explicit ACEs
 
203
 *
 
204
 * nfsv4_chmod
 
205
 * (1) reads objects ACL (acl1)
 
206
 * (2) removes all trivial ACEs from the ACL by calling strip_trivial_aces(), possibly
 
207
 *     leaving 0 ACEs in the ACL if there were only trivial ACEs as mapped from the mode
 
208
 * (3) calls chmod() with mode
 
209
 * (4) reads the changed ACL (acl2) which
 
210
 *     a) might still contain explicit ACEs (up to onnv132)
 
211
 *     b) will have any explicit ACE removed (starting with onnv145/Openindiana)
 
212
 * (5) strip any explicit ACE from acl2 using strip_nontrivial_aces()
 
213
 * (6) merge acl2 and acl2
 
214
 * (7) set the ACL merged ACL on the object
 
215
 */
 
216
int nfsv4_chmod(char *name, mode_t mode)
 
217
{
 
218
    int ret = -1;
 
219
    int noaces, nnaces;
 
220
    ace_t *oacl = NULL, *nacl = NULL, *cacl = NULL;
 
221
 
 
222
    LOG(log_debug, logtype_afpd, "nfsv4_chmod(\"%s/%s\", %04o)",
 
223
        getcwdpath(), name, mode);
 
224
 
 
225
    if ((noaces = get_nfsv4_acl(name, &oacl)) == -1) /* (1) */
 
226
        goto exit;
 
227
    if ((noaces = strip_trivial_aces(&oacl, noaces)) == -1) /* (2) */
 
228
        goto exit;
 
229
 
 
230
#ifdef chmod
 
231
#undef chmod
 
232
#endif
 
233
    if (chmod(name, mode) != 0) /* (3) */
 
234
        goto exit;
 
235
 
 
236
    if ((nnaces = get_nfsv4_acl(name, &nacl)) == -1) /* (4) */
 
237
        goto exit;
 
238
    if ((nnaces = strip_nontrivial_aces(&nacl, nnaces)) == -1) /* (5) */
 
239
        goto exit;
 
240
 
 
241
    if ((cacl = concat_aces(oacl, noaces, nacl, nnaces)) == NULL) /* (6) */
 
242
        goto exit;
 
243
 
 
244
    if ((ret = acl(name, ACE_SETACL, noaces + nnaces, cacl)) != 0) {
 
245
        LOG(log_error, logtype_afpd, "nfsv4_chmod: error setting acl: %s", strerror(errno));
 
246
        goto exit;
 
247
    }
 
248
 
 
249
exit:
 
250
    if (oacl) free(oacl);
 
251
    if (nacl) free(nacl);
 
252
    if (cacl) free(cacl);
 
253
 
 
254
    LOG(log_debug, logtype_afpd, "nfsv4_chmod(\"%s/%s\", %04o): result: %u",
 
255
        getcwdpath(), name, mode, ret);
 
256
 
 
257
    return ret;
 
258
}
 
259
 
 
260
#endif /* HAVE_SOLARIS_ACLS */