Coverage Report

Created: 2026-07-25 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/modules/vfs_posixacl.c
Line
Count
Source
1
/*
2
   Unix SMB/Netbios implementation.
3
   VFS module to get and set posix acls
4
   Copyright (C) Volker Lendecke 2006
5
6
   This program is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 3 of the License, or
9
   (at your option) any later version.
10
11
   This program is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
   GNU General Public License for more details.
15
16
   You should have received a copy of the GNU General Public License
17
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
*/
19
20
#include "includes.h"
21
#include "system/filesys.h"
22
#include "smbd/smbd.h"
23
#include "modules/vfs_posixacl.h"
24
25
/* prototypes for static functions first - for clarity */
26
27
static bool smb_ace_to_internal(acl_entry_t posix_ace,
28
        struct smb_acl_entry *ace);
29
static struct smb_acl_t *smb_acl_to_internal(acl_t acl, TALLOC_CTX *mem_ctx);
30
static int smb_acl_set_mode(acl_entry_t entry, SMB_ACL_PERM_T perm);
31
static acl_t smb_acl_to_posix(const struct smb_acl_t *acl);
32
33
34
/* public functions - the api */
35
36
SMB_ACL_T posixacl_sys_acl_get_fd(vfs_handle_struct *handle,
37
          files_struct *fsp,
38
          SMB_ACL_TYPE_T type,
39
          TALLOC_CTX *mem_ctx)
40
0
{
41
0
  struct smb_acl_t *result;
42
0
  acl_t acl = NULL;
43
0
  acl_type_t acl_type;
44
45
0
  switch(type) {
46
0
  case SMB_ACL_TYPE_ACCESS:
47
0
    acl_type = ACL_TYPE_ACCESS;
48
0
    break;
49
0
  case SMB_ACL_TYPE_DEFAULT:
50
0
    acl_type = ACL_TYPE_DEFAULT;
51
0
    break;
52
0
  default:
53
0
    errno = EINVAL;
54
0
    return NULL;
55
0
  }
56
0
  if (!fsp->fsp_flags.is_pathref && (acl_type == ACL_TYPE_ACCESS)) {
57
    /* POSIX API only allows ACL_TYPE_ACCESS fetched on fd. */
58
0
    acl = acl_get_fd(fsp_get_io_fd(fsp));
59
0
  } else if (fsp->fsp_flags.have_proc_fds) {
60
0
    int fd = fsp_get_pathref_fd(fsp);
61
0
    struct sys_proc_fd_path_buf buf;
62
63
0
    acl = acl_get_file(sys_proc_fd_path(fd, &buf), acl_type);
64
0
  } else {
65
    /*
66
     * This is no longer a handle based call.
67
     */
68
0
    acl = acl_get_file(fsp->fsp_name->base_name, acl_type);
69
0
  }
70
0
  if (acl == NULL) {
71
0
    return NULL;
72
0
  }
73
74
0
  result = smb_acl_to_internal(acl, mem_ctx);
75
0
  acl_free(acl);
76
0
  return result;
77
0
}
78
79
int posixacl_sys_acl_set_fd(vfs_handle_struct *handle,
80
          files_struct *fsp,
81
          SMB_ACL_TYPE_T type,
82
          SMB_ACL_T theacl)
83
0
{
84
0
  int res;
85
0
  acl_t acl = smb_acl_to_posix(theacl);
86
0
  acl_type_t acl_type;
87
0
  int fd = fsp_get_pathref_fd(fsp);
88
89
0
  if (acl == NULL) {
90
0
    return -1;
91
0
  }
92
93
0
  switch(type) {
94
0
  case SMB_ACL_TYPE_ACCESS:
95
0
    acl_type = ACL_TYPE_ACCESS;
96
0
    break;
97
0
  case SMB_ACL_TYPE_DEFAULT:
98
0
    acl_type = ACL_TYPE_DEFAULT;
99
0
    break;
100
0
  default:
101
0
    acl_free(acl);
102
0
    errno = EINVAL;
103
0
    return -1;
104
0
  }
105
106
0
  if (!fsp->fsp_flags.is_pathref && type == SMB_ACL_TYPE_ACCESS) {
107
0
    res = acl_set_fd(fd, acl);
108
0
  } else if (fsp->fsp_flags.have_proc_fds) {
109
0
    struct sys_proc_fd_path_buf buf;
110
111
0
    res = acl_set_file(sys_proc_fd_path(fd, &buf), acl_type, acl);
112
0
  } else {
113
    /*
114
     * This is no longer a handle based call.
115
     */
116
0
    res = acl_set_file(fsp->fsp_name->base_name,
117
0
           acl_type,
118
0
           acl);
119
0
  }
120
121
0
  acl_free(acl);
122
0
  return res;
123
0
}
124
125
int posixacl_sys_acl_delete_def_fd(vfs_handle_struct *handle,
126
        files_struct *fsp)
127
0
{
128
0
  if (fsp->fsp_flags.have_proc_fds) {
129
0
    int fd = fsp_get_pathref_fd(fsp);
130
0
    struct sys_proc_fd_path_buf buf;
131
132
0
    return acl_delete_def_file(sys_proc_fd_path(fd, &buf));
133
0
  }
134
135
  /*
136
   * This is no longer a handle based call.
137
   */
138
0
  return acl_delete_def_file(fsp->fsp_name->base_name);
139
0
}
140
141
/* private functions */
142
143
static bool smb_ace_to_internal(acl_entry_t posix_ace,
144
        struct smb_acl_entry *ace)
145
0
{
146
0
  acl_tag_t tag;
147
0
  acl_permset_t permset;
148
149
0
  if (acl_get_tag_type(posix_ace, &tag) != 0) {
150
0
    DEBUG(0, ("smb_acl_get_tag_type failed\n"));
151
0
    return False;
152
0
  }
153
154
0
  switch(tag) {
155
0
  case ACL_USER:
156
0
    ace->a_type = SMB_ACL_USER;
157
0
    break;
158
0
  case ACL_USER_OBJ:
159
0
    ace->a_type = SMB_ACL_USER_OBJ;
160
0
    break;
161
0
  case ACL_GROUP:
162
0
    ace->a_type = SMB_ACL_GROUP;
163
0
    break;
164
0
  case ACL_GROUP_OBJ:
165
0
    ace->a_type = SMB_ACL_GROUP_OBJ;
166
0
    break;
167
0
  case ACL_OTHER:
168
0
    ace->a_type = SMB_ACL_OTHER;
169
0
    break;
170
0
  case ACL_MASK:
171
0
    ace->a_type = SMB_ACL_MASK;
172
0
    break;
173
#ifdef HAVE_ACL_EVERYONE
174
  case ACL_EVERYONE:
175
    DEBUG(1, ("ACL tag type ACL_EVERYONE. FreeBSD with ZFS? Use 'vfs objects = zfsacl'\n"));
176
    return false;
177
#endif
178
0
  default:
179
0
    DEBUG(0, ("unknown tag type %d\n", (unsigned int)tag));
180
0
    return False;
181
0
  }
182
0
  switch(ace->a_type) {
183
0
  case SMB_ACL_USER: {
184
0
    uid_t *puid = (uid_t *)acl_get_qualifier(posix_ace);
185
0
    if (puid == NULL) {
186
0
      DEBUG(0, ("smb_acl_get_qualifier failed\n"));
187
0
      return False;
188
0
    }
189
0
    ace->info.user.uid = *puid;
190
0
    acl_free(puid);
191
0
    break;
192
0
  }
193
194
0
  case SMB_ACL_GROUP: {
195
0
    gid_t *pgid = (uid_t *)acl_get_qualifier(posix_ace);
196
0
    if (pgid == NULL) {
197
0
      DEBUG(0, ("smb_acl_get_qualifier failed\n"));
198
0
      return False;
199
0
    }
200
0
    ace->info.group.gid = *pgid;
201
0
    acl_free(pgid);
202
0
    break;
203
0
  }
204
0
  default:
205
0
    break;
206
0
  }
207
0
  if (acl_get_permset(posix_ace, &permset) != 0) {
208
0
    DEBUG(0, ("smb_acl_get_mode failed\n"));
209
0
    return False;
210
0
  }
211
0
  ace->a_perm = 0;
212
#ifdef HAVE_ACL_GET_PERM_NP
213
  ace->a_perm |= (acl_get_perm_np(permset, ACL_READ) ? SMB_ACL_READ : 0);
214
  ace->a_perm |= (acl_get_perm_np(permset, ACL_WRITE) ? SMB_ACL_WRITE : 0);
215
  ace->a_perm |= (acl_get_perm_np(permset, ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
216
#else
217
0
  ace->a_perm |= (acl_get_perm(permset, ACL_READ) ? SMB_ACL_READ : 0);
218
0
  ace->a_perm |= (acl_get_perm(permset, ACL_WRITE) ? SMB_ACL_WRITE : 0);
219
0
  ace->a_perm |= (acl_get_perm(permset, ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
220
0
#endif
221
0
  return True;
222
0
}
223
224
static struct smb_acl_t *smb_acl_to_internal(acl_t acl, TALLOC_CTX *mem_ctx)
225
0
{
226
0
  struct smb_acl_t *result = sys_acl_init(mem_ctx);
227
0
  int entry_id = ACL_FIRST_ENTRY;
228
0
  acl_entry_t e;
229
0
  if (result == NULL) {
230
0
    return NULL;
231
0
  }
232
0
  while (acl_get_entry(acl, entry_id, &e) == 1) {
233
234
0
    entry_id = ACL_NEXT_ENTRY;
235
236
0
    result->acl = talloc_realloc(result, result->acl,
237
0
               struct smb_acl_entry, result->count+1);
238
0
    if (result->acl == NULL) {
239
0
      TALLOC_FREE(result);
240
0
      DEBUG(0, ("talloc_realloc failed\n"));
241
0
      errno = ENOMEM;
242
0
      return NULL;
243
0
    }
244
245
0
    if (!smb_ace_to_internal(e, &result->acl[result->count])) {
246
0
      TALLOC_FREE(result);
247
0
      return NULL;
248
0
    }
249
250
0
    result->count += 1;
251
0
  }
252
0
  return result;
253
0
}
254
255
static int smb_acl_set_mode(acl_entry_t entry, SMB_ACL_PERM_T perm)
256
0
{
257
0
        int ret;
258
0
        acl_permset_t permset;
259
260
0
  if ((ret = acl_get_permset(entry, &permset)) != 0) {
261
0
    return ret;
262
0
  }
263
0
        if ((ret = acl_clear_perms(permset)) != 0) {
264
0
                return ret;
265
0
  }
266
0
        if ((perm & SMB_ACL_READ) &&
267
0
      ((ret = acl_add_perm(permset, ACL_READ)) != 0)) {
268
0
    return ret;
269
0
  }
270
0
        if ((perm & SMB_ACL_WRITE) &&
271
0
      ((ret = acl_add_perm(permset, ACL_WRITE)) != 0)) {
272
0
    return ret;
273
0
  }
274
0
        if ((perm & SMB_ACL_EXECUTE) &&
275
0
      ((ret = acl_add_perm(permset, ACL_EXECUTE)) != 0)) {
276
0
    return ret;
277
0
  }
278
279
0
  return 0;
280
0
}
281
282
static acl_t smb_acl_to_posix(const struct smb_acl_t *acl)
283
0
{
284
0
  acl_t result;
285
0
  int i;
286
287
0
  result = acl_init(acl->count);
288
0
  if (result == NULL) {
289
0
    DEBUG(10, ("acl_init failed\n"));
290
0
    return NULL;
291
0
  }
292
293
0
  for (i=0; i<acl->count; i++) {
294
0
    const struct smb_acl_entry *entry = &acl->acl[i];
295
0
    acl_entry_t e;
296
0
    acl_tag_t tag;
297
298
0
    if (acl_create_entry(&result, &e) != 0) {
299
0
      DEBUG(1, ("acl_create_entry failed: %s\n",
300
0
          strerror(errno)));
301
0
      goto fail;
302
0
    }
303
304
0
    switch (entry->a_type) {
305
0
    case SMB_ACL_USER:
306
0
      tag = ACL_USER;
307
0
      break;
308
0
    case SMB_ACL_USER_OBJ:
309
0
      tag = ACL_USER_OBJ;
310
0
      break;
311
0
    case SMB_ACL_GROUP:
312
0
      tag = ACL_GROUP;
313
0
      break;
314
0
    case SMB_ACL_GROUP_OBJ:
315
0
      tag = ACL_GROUP_OBJ;
316
0
      break;
317
0
    case SMB_ACL_OTHER:
318
0
      tag = ACL_OTHER;
319
0
      break;
320
0
    case SMB_ACL_MASK:
321
0
      tag = ACL_MASK;
322
0
      break;
323
0
    default:
324
0
      DEBUG(1, ("Unknown tag value %d\n", entry->a_type));
325
0
      goto fail;
326
0
    }
327
328
0
    if (acl_set_tag_type(e, tag) != 0) {
329
0
      DEBUG(10, ("acl_set_tag_type(%d) failed: %s\n",
330
0
           tag, strerror(errno)));
331
0
      goto fail;
332
0
    }
333
334
0
    switch (entry->a_type) {
335
0
    case SMB_ACL_USER:
336
0
      if (acl_set_qualifier(e, &entry->info.user.uid) != 0) {
337
0
        DEBUG(1, ("acl_set_qualifier failed: %s\n",
338
0
            strerror(errno)));
339
0
        goto fail;
340
0
      }
341
0
      break;
342
0
    case SMB_ACL_GROUP:
343
0
      if (acl_set_qualifier(e, &entry->info.group.gid) != 0) {
344
0
        DEBUG(1, ("acl_set_qualifier failed: %s\n",
345
0
            strerror(errno)));
346
0
        goto fail;
347
0
      }
348
0
      break;
349
0
    default:  /* Shut up, compiler! :-) */
350
0
      break;
351
0
    }
352
353
0
    if (smb_acl_set_mode(e, entry->a_perm) != 0) {
354
0
      goto fail;
355
0
    }
356
0
  }
357
358
0
  if (acl_valid(result) != 0) {
359
0
    char *acl_string = sys_acl_to_text(talloc_tos(), acl);
360
0
    DBG_WARNING("ACL %s is invalid for set (%s)\n",
361
0
          acl_string,
362
0
          strerror(errno));
363
0
    TALLOC_FREE(acl_string);
364
0
    goto fail;
365
0
  }
366
367
0
  return result;
368
369
0
 fail:
370
0
  if (result != NULL) {
371
0
    acl_free(result);
372
0
  }
373
0
  return NULL;
374
0
}
375
376
/* VFS operations structure */
377
378
static struct vfs_fn_pointers posixacl_fns = {
379
  .sys_acl_get_fd_fn = posixacl_sys_acl_get_fd,
380
  .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
381
  .sys_acl_set_fd_fn = posixacl_sys_acl_set_fd,
382
  .sys_acl_delete_def_fd_fn = posixacl_sys_acl_delete_def_fd,
383
};
384
385
static_decl_vfs;
386
NTSTATUS vfs_posixacl_init(TALLOC_CTX *ctx)
387
0
{
388
0
  return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "posixacl",
389
0
        &posixacl_fns);
390
0
}