~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/modules/nfs4_acls.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * NFS4 ACL handling
 
3
 *
 
4
 * Copyright (C) Jim McDonough, 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 "nfs4_acls.h"
 
22
 
 
23
#undef DBGC_CLASS
 
24
#define DBGC_CLASS DBGC_ACLS
 
25
 
 
26
#define SMBACL4_PARAM_TYPE_NAME "nfs4"
 
27
 
 
28
extern const struct generic_mapping file_generic_mapping;
 
29
 
 
30
#define SMB_ACE4_INT_MAGIC 0x76F8A967
 
31
typedef struct _SMB_ACE4_INT_T
 
32
{
 
33
        uint32  magic;
 
34
        SMB_ACE4PROP_T  prop;
 
35
        void    *next;
 
36
} SMB_ACE4_INT_T;
 
37
 
 
38
#define SMB_ACL4_INT_MAGIC 0x29A3E792
 
39
typedef struct _SMB_ACL4_INT_T
 
40
{
 
41
        uint32  magic;
 
42
        uint32  naces;
 
43
        SMB_ACE4_INT_T  *first;
 
44
        SMB_ACE4_INT_T  *last;
 
45
} SMB_ACL4_INT_T;
 
46
 
 
47
static SMB_ACL4_INT_T *get_validated_aclint(SMB4ACL_T *theacl)
 
48
{
 
49
        SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
 
50
        if (theacl==NULL)
 
51
        {
 
52
                DEBUG(2, ("acl is NULL\n"));
 
53
                errno = EINVAL;
 
54
                return NULL;
 
55
        }
 
56
        if (aclint->magic!=SMB_ACL4_INT_MAGIC)
 
57
        {
 
58
                DEBUG(2, ("aclint bad magic 0x%x\n", aclint->magic));
 
59
                errno = EINVAL;
 
60
                return NULL;
 
61
        }
 
62
        return aclint;
 
63
}
 
64
 
 
65
static SMB_ACE4_INT_T *get_validated_aceint(SMB4ACE_T *ace)
 
66
{
 
67
        SMB_ACE4_INT_T *aceint = (SMB_ACE4_INT_T *)ace;
 
68
        if (ace==NULL)
 
69
        {
 
70
                DEBUG(2, ("ace is NULL\n"));
 
71
                errno = EINVAL;
 
72
                return NULL;
 
73
        }
 
74
        if (aceint->magic!=SMB_ACE4_INT_MAGIC)
 
75
        {
 
76
                DEBUG(2, ("aceint bad magic 0x%x\n", aceint->magic));
 
77
                errno = EINVAL;
 
78
                return NULL;
 
79
        }
 
80
        return aceint;
 
81
}
 
82
 
 
83
SMB4ACL_T *smb_create_smb4acl(void)
 
84
{
 
85
        TALLOC_CTX *mem_ctx = talloc_tos();
 
86
        SMB_ACL4_INT_T  *theacl = (SMB_ACL4_INT_T *)TALLOC_ZERO_SIZE(mem_ctx, sizeof(SMB_ACL4_INT_T));
 
87
        if (theacl==NULL)
 
88
        {
 
89
                DEBUG(0, ("TALLOC_SIZE failed\n"));
 
90
                errno = ENOMEM;
 
91
                return NULL;
 
92
        }
 
93
        theacl->magic = SMB_ACL4_INT_MAGIC;
 
94
        /* theacl->first, last = NULL not needed */
 
95
        return (SMB4ACL_T *)theacl;
 
96
}
 
97
 
 
98
SMB4ACE_T *smb_add_ace4(SMB4ACL_T *theacl, SMB_ACE4PROP_T *prop)
 
99
{
 
100
        SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
 
101
        TALLOC_CTX *mem_ctx = talloc_tos();
 
102
        SMB_ACE4_INT_T *ace;
 
103
 
 
104
        ace = (SMB_ACE4_INT_T *)TALLOC_ZERO_SIZE(mem_ctx, sizeof(SMB_ACE4_INT_T));
 
105
        if (ace==NULL)
 
106
        {
 
107
                DEBUG(0, ("TALLOC_SIZE failed\n"));
 
108
                errno = ENOMEM;
 
109
                return NULL;
 
110
        }
 
111
        ace->magic = SMB_ACE4_INT_MAGIC;
 
112
        /* ace->next = NULL not needed */
 
113
        memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
 
114
 
 
115
        if (aclint->first==NULL)
 
116
        {
 
117
                aclint->first = ace;
 
118
                aclint->last = ace;
 
119
        } else {
 
120
                aclint->last->next = (void *)ace;
 
121
                aclint->last = ace;
 
122
        }
 
123
        aclint->naces++;
 
124
 
 
125
        return (SMB4ACE_T *)ace;
 
126
}
 
127
 
 
128
SMB_ACE4PROP_T *smb_get_ace4(SMB4ACE_T *ace)
 
129
{
 
130
        SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
 
131
        if (aceint==NULL)
 
132
                return NULL;
 
133
 
 
134
        return &aceint->prop;
 
135
}
 
136
 
 
137
SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace)
 
138
{
 
139
        SMB_ACE4_INT_T *aceint = get_validated_aceint(ace);
 
140
        if (aceint==NULL)
 
141
                return NULL;
 
142
 
 
143
        return (SMB4ACE_T *)aceint->next;
 
144
}
 
145
 
 
146
SMB4ACE_T *smb_first_ace4(SMB4ACL_T *theacl)
 
147
{
 
148
        SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
 
149
        if (aclint==NULL)
 
150
                return NULL;
 
151
 
 
152
        return (SMB4ACE_T *)aclint->first;
 
153
}
 
154
 
 
155
uint32 smb_get_naces(SMB4ACL_T *theacl)
 
156
{
 
157
        SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
 
158
        if (aclint==NULL)
 
159
                return 0;
 
160
 
 
161
        return aclint->naces;
 
162
}
 
163
 
 
164
static int smbacl4_GetFileOwner(struct connection_struct *conn,
 
165
                                const char *filename,
 
166
                                SMB_STRUCT_STAT *psbuf)
 
167
{
 
168
        int ret;
 
169
        memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
 
170
 
 
171
        /* Get the stat struct for the owner info. */
 
172
        if (lp_posix_pathnames()) {
 
173
                ret = SMB_VFS_LSTAT(conn, filename, psbuf);
 
174
        } else {
 
175
                ret = SMB_VFS_STAT(conn, filename, psbuf);
 
176
        }
 
177
        if (ret == -1)
 
178
        {
 
179
                DEBUG(8, ("SMB_VFS_STAT failed with error %s\n",
 
180
                        strerror(errno)));
 
181
                return -1;
 
182
        }
 
183
 
 
184
        return 0;
 
185
}
 
186
 
 
187
static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
 
188
{
 
189
        memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
 
190
 
 
191
        if (fsp->is_directory || fsp->fh->fd == -1) {
 
192
                return smbacl4_GetFileOwner(fsp->conn, fsp->fsp_name, psbuf);
 
193
        }
 
194
        if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
 
195
        {
 
196
                DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
 
197
                        strerror(errno)));
 
198
                return -1;
 
199
        }
 
200
 
 
201
        return 0;
 
202
}
 
203
 
 
204
static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx, SMB4ACL_T *theacl, /* in */
 
205
        DOM_SID *psid_owner, /* in */
 
206
        DOM_SID *psid_group, /* in */
 
207
        bool is_directory, /* in */
 
208
        SEC_ACE **ppnt_ace_list, /* out */
 
209
        int *pgood_aces /* out */
 
210
)
 
211
{
 
212
        SMB_ACL4_INT_T *aclint = (SMB_ACL4_INT_T *)theacl;
 
213
        SMB_ACE4_INT_T *aceint;
 
214
        SEC_ACE *nt_ace_list = NULL;
 
215
        int good_aces = 0;
 
216
 
 
217
        DEBUG(10, ("smbacl_nfs42win entered"));
 
218
 
 
219
        aclint = get_validated_aclint(theacl);
 
220
        /* We do not check for naces being 0 or theacl being NULL here because it is done upstream */
 
221
        /* in smb_get_nt_acl_nfs4(). */
 
222
        nt_ace_list = (SEC_ACE *)TALLOC_ZERO_SIZE(mem_ctx, aclint->naces * sizeof(SEC_ACE));
 
223
        if (nt_ace_list==NULL)
 
224
        {
 
225
                DEBUG(10, ("talloc error"));
 
226
                errno = ENOMEM;
 
227
                return False;
 
228
        }
 
229
 
 
230
        for (aceint=aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
 
231
                uint32_t mask;
 
232
                DOM_SID sid;
 
233
                SMB_ACE4PROP_T  *ace = &aceint->prop;
 
234
 
 
235
                DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, mask: %x, "
 
236
                        "who: %d\n", aceint->magic, ace->aceType, ace->flags,
 
237
                        ace->aceFlags, ace->aceMask, ace->who.id));
 
238
 
 
239
                SMB_ASSERT(aceint->magic==SMB_ACE4_INT_MAGIC);
 
240
 
 
241
                if (ace->flags & SMB_ACE4_ID_SPECIAL) {
 
242
                        switch (ace->who.special_id) {
 
243
                        case SMB_ACE4_WHO_OWNER:
 
244
                                sid_copy(&sid, psid_owner);
 
245
                                break;
 
246
                        case SMB_ACE4_WHO_GROUP:
 
247
                                sid_copy(&sid, psid_group);
 
248
                                break;
 
249
                        case SMB_ACE4_WHO_EVERYONE:
 
250
                                sid_copy(&sid, &global_sid_World);
 
251
                                break;
 
252
                        default:
 
253
                                DEBUG(8, ("invalid special who id %d "
 
254
                                        "ignored\n", ace->who.special_id));
 
255
                        }
 
256
                } else {
 
257
                        if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
 
258
                                gid_to_sid(&sid, ace->who.gid);
 
259
                        } else {
 
260
                                uid_to_sid(&sid, ace->who.uid);
 
261
                        }
 
262
                }
 
263
                DEBUG(10, ("mapped %d to %s\n", ace->who.id,
 
264
                           sid_string_dbg(&sid)));
 
265
 
 
266
                if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
 
267
                        ace->aceMask |= SMB_ACE4_DELETE_CHILD;
 
268
                }
 
269
 
 
270
                mask = ace->aceMask;
 
271
                init_sec_ace(&nt_ace_list[good_aces++], &sid,
 
272
                        ace->aceType, mask,
 
273
                        ace->aceFlags & 0xf);
 
274
        }
 
275
 
 
276
        *ppnt_ace_list = nt_ace_list;
 
277
        *pgood_aces = good_aces;
 
278
 
 
279
        return True;
 
280
}
 
281
 
 
282
static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
 
283
        uint32 security_info,
 
284
        SEC_DESC **ppdesc, SMB4ACL_T *theacl)
 
285
{
 
286
        int     good_aces = 0;
 
287
        DOM_SID sid_owner, sid_group;
 
288
        size_t sd_size = 0;
 
289
        SEC_ACE *nt_ace_list = NULL;
 
290
        SEC_ACL *psa = NULL;
 
291
        TALLOC_CTX *mem_ctx = talloc_tos();
 
292
 
 
293
        if (theacl==NULL || smb_get_naces(theacl)==0)
 
294
                return NT_STATUS_ACCESS_DENIED; /* special because we
 
295
                                                 * shouldn't alloc 0 for
 
296
                                                 * win */
 
297
 
 
298
        uid_to_sid(&sid_owner, sbuf->st_uid);
 
299
        gid_to_sid(&sid_group, sbuf->st_gid);
 
300
 
 
301
        if (smbacl4_nfs42win(mem_ctx, theacl, &sid_owner, &sid_group, S_ISDIR(sbuf->st_mode),
 
302
                                &nt_ace_list, &good_aces)==False) {
 
303
                DEBUG(8,("smbacl4_nfs42win failed\n"));
 
304
                return map_nt_error_from_unix(errno);
 
305
        }
 
306
 
 
307
        psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, good_aces, nt_ace_list);
 
308
        if (psa == NULL) {
 
309
                DEBUG(2,("make_sec_acl failed\n"));
 
310
                return NT_STATUS_NO_MEMORY;
 
311
        }
 
312
 
 
313
        DEBUG(10,("after make sec_acl\n"));
 
314
        *ppdesc = make_sec_desc(mem_ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
 
315
                                (security_info & OWNER_SECURITY_INFORMATION) ? &sid_owner : NULL,
 
316
                                (security_info & GROUP_SECURITY_INFORMATION) ? &sid_group : NULL,
 
317
                                NULL, psa, &sd_size);
 
318
        if (*ppdesc==NULL) {
 
319
                DEBUG(2,("make_sec_desc failed\n"));
 
320
                return NT_STATUS_NO_MEMORY;
 
321
        }
 
322
 
 
323
        DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with sd_size %d\n",
 
324
                   ndr_size_security_descriptor(*ppdesc, NULL, 0)));
 
325
 
 
326
        return NT_STATUS_OK;
 
327
}
 
328
 
 
329
NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
 
330
                               uint32 security_info,
 
331
                               SEC_DESC **ppdesc, SMB4ACL_T *theacl)
 
332
{
 
333
        SMB_STRUCT_STAT sbuf;
 
334
 
 
335
        DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp->fsp_name));
 
336
 
 
337
        if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
 
338
                return map_nt_error_from_unix(errno);
 
339
        }
 
340
 
 
341
        return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc, theacl);
 
342
}
 
343
 
 
344
NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
 
345
                              const char *name,
 
346
                              uint32 security_info,
 
347
                              SEC_DESC **ppdesc, SMB4ACL_T *theacl)
 
348
{
 
349
        SMB_STRUCT_STAT sbuf;
 
350
 
 
351
        DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
 
352
 
 
353
        if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
 
354
                return map_nt_error_from_unix(errno);
 
355
        }
 
356
 
 
357
        return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc, theacl);
 
358
}
 
359
 
 
360
enum smbacl4_mode_enum {e_simple=0, e_special=1};
 
361
enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
 
362
 
 
363
typedef struct _smbacl4_vfs_params {
 
364
        enum smbacl4_mode_enum mode;
 
365
        bool do_chown;
 
366
        enum smbacl4_acedup_enum acedup;
 
367
        struct db_context *sid_mapping_table;
 
368
} smbacl4_vfs_params;
 
369
 
 
370
/*
 
371
 * Gather special parameters for NFS4 ACL handling
 
372
 */
 
373
static int smbacl4_get_vfs_params(
 
374
        const char *type_name,
 
375
        files_struct *fsp,
 
376
        smbacl4_vfs_params *params
 
377
)
 
378
{
 
379
        static const struct enum_list enum_smbacl4_modes[] = {
 
380
                { e_simple, "simple" },
 
381
                { e_special, "special" }
 
382
        };
 
383
        static const struct enum_list enum_smbacl4_acedups[] = {
 
384
                { e_dontcare, "dontcare" },
 
385
                { e_reject, "reject" },
 
386
                { e_ignore, "ignore" },
 
387
                { e_merge, "merge" },
 
388
        };
 
389
 
 
390
        memset(params, 0, sizeof(smbacl4_vfs_params));
 
391
        params->mode = (enum smbacl4_mode_enum)lp_parm_enum(
 
392
                SNUM(fsp->conn), type_name,
 
393
                "mode", enum_smbacl4_modes, e_simple);
 
394
        params->do_chown = lp_parm_bool(SNUM(fsp->conn), type_name,
 
395
                "chown", True);
 
396
        params->acedup = (enum smbacl4_acedup_enum)lp_parm_enum(
 
397
                SNUM(fsp->conn), type_name,
 
398
                "acedup", enum_smbacl4_acedups, e_dontcare);
 
399
 
 
400
        DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s\n",
 
401
                enum_smbacl4_modes[params->mode].name,
 
402
                params->do_chown ? "true" : "false",
 
403
                enum_smbacl4_acedups[params->acedup].name));
 
404
 
 
405
        return 0;
 
406
}
 
407
 
 
408
static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *theacl)
 
409
{
 
410
        SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
 
411
        SMB_ACE4_INT_T *aceint;
 
412
 
 
413
        DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces));
 
414
 
 
415
        for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
 
416
                SMB_ACE4PROP_T *ace = &aceint->prop;
 
417
 
 
418
                DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, mask=0x%x, id=%d\n",
 
419
                        ace->aceType,
 
420
                        ace->aceFlags, ace->flags,
 
421
                        ace->aceMask,
 
422
                        ace->who.id));
 
423
        }
 
424
}
 
425
 
 
426
/* 
 
427
 * Find 2 NFS4 who-special ACE property (non-copy!!!)
 
428
 * match nonzero if "special" and who is equal
 
429
 * return ace if found matching; otherwise NULL
 
430
 */
 
431
static SMB_ACE4PROP_T *smbacl4_find_equal_special(
 
432
        SMB4ACL_T *theacl,
 
433
        SMB_ACE4PROP_T *aceNew)
 
434
{
 
435
        SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
 
436
        SMB_ACE4_INT_T *aceint;
 
437
 
 
438
        for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
 
439
                SMB_ACE4PROP_T *ace = &aceint->prop;
 
440
 
 
441
                if (ace->flags == aceNew->flags &&
 
442
                        ace->aceType==aceNew->aceType &&
 
443
                        (ace->aceFlags&SMB_ACE4_IDENTIFIER_GROUP)==
 
444
                        (aceNew->aceFlags&SMB_ACE4_IDENTIFIER_GROUP)
 
445
                ) {
 
446
                        /* keep type safety; e.g. gid is an u.short */
 
447
                        if (ace->flags & SMB_ACE4_ID_SPECIAL)
 
448
                        {
 
449
                                if (ace->who.special_id==aceNew->who.special_id)
 
450
                                        return ace;
 
451
                        } else {
 
452
                                if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
 
453
                                {
 
454
                                        if (ace->who.gid==aceNew->who.gid)
 
455
                                                return ace;
 
456
                                } else {
 
457
                                        if (ace->who.uid==aceNew->who.uid)
 
458
                                                return ace;
 
459
                                }
 
460
                        }
 
461
                }
 
462
        }
 
463
 
 
464
        return NULL;
 
465
}
 
466
 
 
467
static bool nfs4_map_sid(smbacl4_vfs_params *params, const DOM_SID *src,
 
468
                         DOM_SID *dst)
 
469
{
 
470
        static struct db_context *mapping_db = NULL;
 
471
        TDB_DATA data;
 
472
        
 
473
        if (mapping_db == NULL) {
 
474
                const char *dbname = lp_parm_const_string(
 
475
                        -1, SMBACL4_PARAM_TYPE_NAME, "sidmap", NULL);
 
476
                
 
477
                if (dbname == NULL) {
 
478
                        DEBUG(10, ("%s:sidmap not defined\n",
 
479
                                   SMBACL4_PARAM_TYPE_NAME));
 
480
                        return False;
 
481
                }
 
482
                
 
483
                become_root();
 
484
                mapping_db = db_open(NULL, dbname, 0, TDB_DEFAULT,
 
485
                                     O_RDONLY, 0600);
 
486
                unbecome_root();
 
487
                
 
488
                if (mapping_db == NULL) {
 
489
                        DEBUG(1, ("could not open sidmap: %s\n",
 
490
                                  strerror(errno)));
 
491
                        return False;
 
492
                }
 
493
        }
 
494
        
 
495
        if (mapping_db->fetch(mapping_db, NULL,
 
496
                              string_term_tdb_data(sid_string_tos(src)),
 
497
                              &data) == -1) {
 
498
                DEBUG(10, ("could not find mapping for SID %s\n",
 
499
                           sid_string_dbg(src)));
 
500
                return False;
 
501
        }
 
502
        
 
503
        if ((data.dptr == NULL) || (data.dsize <= 0)
 
504
            || (data.dptr[data.dsize-1] != '\0')) {
 
505
                DEBUG(5, ("invalid mapping for SID %s\n",
 
506
                          sid_string_dbg(src)));
 
507
                TALLOC_FREE(data.dptr);
 
508
                return False;
 
509
        }
 
510
        
 
511
        if (!string_to_sid(dst, (char *)data.dptr)) {
 
512
                DEBUG(1, ("invalid mapping %s for SID %s\n",
 
513
                          (char *)data.dptr, sid_string_dbg(src)));
 
514
                TALLOC_FREE(data.dptr);
 
515
                return False;
 
516
        }
 
517
 
 
518
        TALLOC_FREE(data.dptr);
 
519
        
 
520
        return True;
 
521
}
 
522
 
 
523
static bool smbacl4_fill_ace4(
 
524
        TALLOC_CTX *mem_ctx,
 
525
        const char *filename,
 
526
        smbacl4_vfs_params *params,
 
527
        uid_t ownerUID,
 
528
        gid_t ownerGID,
 
529
        const SEC_ACE *ace_nt, /* input */
 
530
        SMB_ACE4PROP_T *ace_v4 /* output */
 
531
)
 
532
{
 
533
        DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
 
534
 
 
535
        memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
 
536
        ace_v4->aceType = ace_nt->type; /* only ACCESS|DENY supported right now */
 
537
        ace_v4->aceFlags = ace_nt->flags & SEC_ACE_FLAG_VALID_INHERIT;
 
538
        ace_v4->aceMask = ace_nt->access_mask &
 
539
                (STD_RIGHT_ALL_ACCESS | SA_RIGHT_FILE_ALL_ACCESS);
 
540
 
 
541
        se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
 
542
 
 
543
        if (ace_v4->aceFlags!=ace_nt->flags)
 
544
                DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
 
545
                        ace_v4->aceFlags, ace_nt->flags));
 
546
 
 
547
        if (ace_v4->aceMask!=ace_nt->access_mask)
 
548
                DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
 
549
                        ace_v4->aceMask, ace_nt->access_mask));
 
550
 
 
551
        if (sid_equal(&ace_nt->trustee, &global_sid_World)) {
 
552
                ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
 
553
                ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
 
554
        } else {
 
555
                const char *dom, *name;
 
556
                enum lsa_SidType type;
 
557
                uid_t uid;
 
558
                gid_t gid;
 
559
                DOM_SID sid;
 
560
                
 
561
                sid_copy(&sid, &ace_nt->trustee);
 
562
                
 
563
                if (!lookup_sid(mem_ctx, &sid, &dom, &name, &type)) {
 
564
                        
 
565
                        DOM_SID mapped;
 
566
                        
 
567
                        if (!nfs4_map_sid(params, &sid, &mapped)) {
 
568
                                DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
 
569
                                          "unknown\n", filename, sid_string_dbg(&sid)));
 
570
                                errno = EINVAL;
 
571
                                return False;
 
572
                        }
 
573
                        
 
574
                        DEBUG(2, ("nfs4_acls.c: file [%s]: mapped SID %s "
 
575
                                  "to %s\n", filename, sid_string_dbg(&sid), sid_string_dbg(&mapped)));
 
576
                        
 
577
                        if (!lookup_sid(mem_ctx, &mapped, &dom,
 
578
                                        &name, &type)) {
 
579
                                DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
 
580
                                          "mapped from %s is unknown\n",
 
581
                                          filename, sid_string_dbg(&mapped), sid_string_dbg(&sid)));
 
582
                                errno = EINVAL;
 
583
                                return False;
 
584
                        }
 
585
                        
 
586
                        sid_copy(&sid, &mapped);
 
587
                }
 
588
                
 
589
                if (type == SID_NAME_USER) {
 
590
                        if (!sid_to_uid(&sid, &uid)) {
 
591
                                DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
 
592
                                          "convert %s to uid\n", filename,
 
593
                                          sid_string_dbg(&sid)));
 
594
                                return False;
 
595
                        }
 
596
 
 
597
                        if (params->mode==e_special && uid==ownerUID) {
 
598
                                ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
 
599
                                ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
 
600
                        } else {
 
601
                                ace_v4->who.uid = uid;
 
602
                        }
 
603
                } else { /* else group? - TODO check it... */
 
604
                        if (!sid_to_gid(&sid, &gid)) {
 
605
                                DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
 
606
                                          "convert %s to gid\n", filename,
 
607
                                          sid_string_dbg(&sid)));
 
608
                                return False;
 
609
                        }
 
610
                                
 
611
                        ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
 
612
 
 
613
                        if (params->mode==e_special && gid==ownerGID) {
 
614
                                ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
 
615
                                ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
 
616
                        } else {
 
617
                                ace_v4->who.gid = gid;
 
618
                        }
 
619
                }
 
620
        }
 
621
 
 
622
        return True; /* OK */
 
623
}
 
624
 
 
625
static int smbacl4_MergeIgnoreReject(
 
626
        enum smbacl4_acedup_enum acedup,
 
627
        SMB4ACL_T *theacl, /* may modify it */
 
628
        SMB_ACE4PROP_T *ace, /* the "new" ACE */
 
629
        bool    *paddNewACE,
 
630
        int     i
 
631
)
 
632
{
 
633
        int     result = 0;
 
634
        SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
 
635
        if (ace4found)
 
636
        {
 
637
                switch(acedup)
 
638
                {
 
639
                case e_merge: /* "merge" flags */
 
640
                        *paddNewACE = False;
 
641
                        ace4found->aceFlags |= ace->aceFlags;
 
642
                        ace4found->aceMask |= ace->aceMask;
 
643
                        break;
 
644
                case e_ignore: /* leave out this record */
 
645
                        *paddNewACE = False;
 
646
                        break;
 
647
                case e_reject: /* do an error */
 
648
                        DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
 
649
                        errno = EINVAL; /* SHOULD be set on any _real_ error */
 
650
                        result = -1;
 
651
                        break;
 
652
                default:
 
653
                        break;
 
654
                }
 
655
        }
 
656
        return result;
 
657
}
 
658
 
 
659
static SMB4ACL_T *smbacl4_win2nfs4(
 
660
        const char *filename,
 
661
        const SEC_ACL *dacl,
 
662
        smbacl4_vfs_params *pparams,
 
663
        uid_t ownerUID,
 
664
        gid_t ownerGID
 
665
)
 
666
{
 
667
        SMB4ACL_T *theacl;
 
668
        uint32  i;
 
669
        TALLOC_CTX *mem_ctx = talloc_tos();
 
670
 
 
671
        DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
 
672
 
 
673
        theacl = smb_create_smb4acl();
 
674
        if (theacl==NULL)
 
675
                return NULL;
 
676
 
 
677
        for(i=0; i<dacl->num_aces; i++) {
 
678
                SMB_ACE4PROP_T  ace_v4;
 
679
                bool    addNewACE = True;
 
680
 
 
681
                if (!smbacl4_fill_ace4(mem_ctx, filename, pparams,
 
682
                                       ownerUID, ownerGID,
 
683
                                       dacl->aces + i, &ace_v4)) {
 
684
                        DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
 
685
                                  filename,
 
686
                                  sid_string_dbg(&((dacl->aces+i)->trustee))));
 
687
                        continue;
 
688
                }
 
689
 
 
690
                if (pparams->acedup!=e_dontcare) {
 
691
                        if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
 
692
                                &ace_v4, &addNewACE, i))
 
693
                                return NULL;
 
694
                }
 
695
 
 
696
                if (addNewACE)
 
697
                        smb_add_ace4(theacl, &ace_v4);
 
698
        }
 
699
 
 
700
        return theacl;
 
701
}
 
702
 
 
703
NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
 
704
        uint32 security_info_sent,
 
705
        const SEC_DESC *psd,
 
706
        set_nfs4acl_native_fn_t set_nfs4_native)
 
707
{
 
708
        smbacl4_vfs_params params;
 
709
        SMB4ACL_T *theacl = NULL;
 
710
        bool    result;
 
711
 
 
712
        SMB_STRUCT_STAT sbuf;
 
713
        bool set_acl_as_root = false;
 
714
        uid_t newUID = (uid_t)-1;
 
715
        gid_t newGID = (gid_t)-1;
 
716
        int saved_errno;
 
717
 
 
718
        DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp->fsp_name));
 
719
 
 
720
        if ((security_info_sent & (DACL_SECURITY_INFORMATION |
 
721
                GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION)) == 0)
 
722
        {
 
723
                DEBUG(9, ("security_info_sent (0x%x) ignored\n",
 
724
                        security_info_sent));
 
725
                return NT_STATUS_OK; /* won't show error - later to be refined... */
 
726
        }
 
727
 
 
728
        /* Special behaviours */
 
729
        if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp, &params))
 
730
                return NT_STATUS_NO_MEMORY;
 
731
 
 
732
        if (smbacl4_fGetFileOwner(fsp, &sbuf))
 
733
                return map_nt_error_from_unix(errno);
 
734
 
 
735
        if (params.do_chown) {
 
736
                /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
 
737
                NTSTATUS status = unpack_nt_owners(SNUM(fsp->conn), &newUID, &newGID, security_info_sent, psd);
 
738
                if (!NT_STATUS_IS_OK(status)) {
 
739
                        DEBUG(8, ("unpack_nt_owners failed"));
 
740
                        return status;
 
741
                }
 
742
                if (((newUID != (uid_t)-1) && (sbuf.st_uid != newUID)) ||
 
743
                    ((newGID != (gid_t)-1) && (sbuf.st_gid != newGID))) {
 
744
                        if(try_chown(fsp->conn, fsp->fsp_name, newUID, newGID)) {
 
745
                                DEBUG(3,("chown %s, %u, %u failed. Error = %s.\n",
 
746
                                         fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID, 
 
747
                                         strerror(errno)));
 
748
                                return map_nt_error_from_unix(errno);
 
749
                        }
 
750
 
 
751
                        DEBUG(10,("chown %s, %u, %u succeeded.\n",
 
752
                                  fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID));
 
753
                        if (smbacl4_GetFileOwner(fsp->conn, fsp->fsp_name, &sbuf))
 
754
                                return map_nt_error_from_unix(errno);
 
755
 
 
756
                        /* If we successfully chowned, we know we must
 
757
                         * be able to set the acl, so do it as root.
 
758
                         */
 
759
                        set_acl_as_root = true;
 
760
                }
 
761
        }
 
762
 
 
763
        if (!(security_info_sent & DACL_SECURITY_INFORMATION) || psd->dacl ==NULL) {
 
764
                DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n", security_info_sent));
 
765
                return NT_STATUS_OK;
 
766
        }
 
767
 
 
768
        theacl = smbacl4_win2nfs4(fsp->fsp_name, psd->dacl, &params, sbuf.st_uid, sbuf.st_gid);
 
769
        if (!theacl)
 
770
                return map_nt_error_from_unix(errno);
 
771
 
 
772
        smbacl4_dump_nfs4acl(10, theacl);
 
773
 
 
774
        if (set_acl_as_root) {
 
775
                become_root();
 
776
        }
 
777
        result = set_nfs4_native(fsp, theacl);
 
778
        saved_errno = errno;
 
779
        if (set_acl_as_root) {
 
780
                unbecome_root();
 
781
        }
 
782
        if (result!=True) {
 
783
                errno = saved_errno;
 
784
                DEBUG(10, ("set_nfs4_native failed with %s\n", strerror(errno)));
 
785
                return map_nt_error_from_unix(errno);
 
786
        }
 
787
 
 
788
        DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
 
789
        return NT_STATUS_OK;
 
790
}