~vcs-imports/samba/main

« back to all changes in this revision

Viewing changes to source/smbd/posix_acls.c

  • Committer: jerry
  • Date: 2006-07-14 21:48:39 UTC
  • Revision ID: vcs-imports@canonical.com-20060714214839-586d8c489a8fcead
gutting trunk to move to svn:externals

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
   Unix SMB/CIFS implementation.
3
 
   SMB NT Security Descriptor / Unix permission conversion.
4
 
   Copyright (C) Jeremy Allison 1994-2000.
5
 
   Copyright (C) Andreas Gruenbacher 2002.
6
 
 
7
 
   This program is free software; you can redistribute it and/or modify
8
 
   it under the terms of the GNU General Public License as published by
9
 
   the Free Software Foundation; either version 2 of the License, or
10
 
   (at your option) any later version.
11
 
 
12
 
   This program is distributed in the hope that it will be useful,
13
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 
   GNU General Public License for more details.
16
 
 
17
 
   You should have received a copy of the GNU General Public License
18
 
   along with this program; if not, write to the Free Software
19
 
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
 
*/
21
 
 
22
 
#include "includes.h"
23
 
 
24
 
extern struct current_user current_user;
25
 
extern struct generic_mapping file_generic_mapping;
26
 
 
27
 
#undef  DBGC_CLASS
28
 
#define DBGC_CLASS DBGC_ACLS
29
 
 
30
 
/****************************************************************************
31
 
 Data structures representing the internal ACE format.
32
 
****************************************************************************/
33
 
 
34
 
enum ace_owner {UID_ACE, GID_ACE, WORLD_ACE};
35
 
enum ace_attribute {ALLOW_ACE, DENY_ACE}; /* Used for incoming NT ACLS. */
36
 
 
37
 
typedef union posix_id {
38
 
                uid_t uid;
39
 
                gid_t gid;
40
 
                int world;
41
 
} posix_id;
42
 
 
43
 
typedef struct canon_ace {
44
 
        struct canon_ace *next, *prev;
45
 
        SMB_ACL_TAG_T type;
46
 
        mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */
47
 
        DOM_SID trustee;
48
 
        enum ace_owner owner_type;
49
 
        enum ace_attribute attr;
50
 
        posix_id unix_ug; 
51
 
        BOOL inherited;
52
 
} canon_ace;
53
 
 
54
 
#define ALL_ACE_PERMS (S_IRUSR|S_IWUSR|S_IXUSR)
55
 
 
56
 
/*
57
 
 * EA format of user.SAMBA_PAI (Samba_Posix_Acl_Interitance)
58
 
 * attribute on disk.
59
 
 *
60
 
 * |  1   |  1   |   2         |         2           |  .... 
61
 
 * +------+------+-------------+---------------------+-------------+--------------------+
62
 
 * | vers | flag | num_entries | num_default_entries | ..entries.. | default_entries... |
63
 
 * +------+------+-------------+---------------------+-------------+--------------------+
64
 
 */
65
 
 
66
 
#define PAI_VERSION_OFFSET      0
67
 
#define PAI_FLAG_OFFSET         1
68
 
#define PAI_NUM_ENTRIES_OFFSET  2
69
 
#define PAI_NUM_DEFAULT_ENTRIES_OFFSET  4
70
 
#define PAI_ENTRIES_BASE        6
71
 
 
72
 
#define PAI_VERSION             1
73
 
#define PAI_ACL_FLAG_PROTECTED  0x1
74
 
#define PAI_ENTRY_LENGTH        5
75
 
 
76
 
/*
77
 
 * In memory format of user.SAMBA_PAI attribute.
78
 
 */
79
 
 
80
 
struct pai_entry {
81
 
        struct pai_entry *next, *prev;
82
 
        enum ace_owner owner_type;
83
 
        posix_id unix_ug; 
84
 
};
85
 
        
86
 
struct pai_val {
87
 
        BOOL pai_protected;
88
 
        unsigned int num_entries;
89
 
        struct pai_entry *entry_list;
90
 
        unsigned int num_def_entries;
91
 
        struct pai_entry *def_entry_list;
92
 
};
93
 
 
94
 
/************************************************************************
95
 
 Return a uint32 of the pai_entry principal.
96
 
************************************************************************/
97
 
 
98
 
static uint32 get_pai_entry_val(struct pai_entry *paie)
99
 
{
100
 
        switch (paie->owner_type) {
101
 
                case UID_ACE:
102
 
                        DEBUG(10,("get_pai_entry_val: uid = %u\n", (unsigned int)paie->unix_ug.uid ));
103
 
                        return (uint32)paie->unix_ug.uid;
104
 
                case GID_ACE:
105
 
                        DEBUG(10,("get_pai_entry_val: gid = %u\n", (unsigned int)paie->unix_ug.gid ));
106
 
                        return (uint32)paie->unix_ug.gid;
107
 
                case WORLD_ACE:
108
 
                default:
109
 
                        DEBUG(10,("get_pai_entry_val: world ace\n"));
110
 
                        return (uint32)-1;
111
 
        }
112
 
}
113
 
 
114
 
/************************************************************************
115
 
 Return a uint32 of the entry principal.
116
 
************************************************************************/
117
 
 
118
 
static uint32 get_entry_val(canon_ace *ace_entry)
119
 
{
120
 
        switch (ace_entry->owner_type) {
121
 
                case UID_ACE:
122
 
                        DEBUG(10,("get_entry_val: uid = %u\n", (unsigned int)ace_entry->unix_ug.uid ));
123
 
                        return (uint32)ace_entry->unix_ug.uid;
124
 
                case GID_ACE:
125
 
                        DEBUG(10,("get_entry_val: gid = %u\n", (unsigned int)ace_entry->unix_ug.gid ));
126
 
                        return (uint32)ace_entry->unix_ug.gid;
127
 
                case WORLD_ACE:
128
 
                default:
129
 
                        DEBUG(10,("get_entry_val: world ace\n"));
130
 
                        return (uint32)-1;
131
 
        }
132
 
}
133
 
 
134
 
/************************************************************************
135
 
 Count the inherited entries.
136
 
************************************************************************/
137
 
 
138
 
static unsigned int num_inherited_entries(canon_ace *ace_list)
139
 
{
140
 
        unsigned int num_entries = 0;
141
 
 
142
 
        for (; ace_list; ace_list = ace_list->next)
143
 
                if (ace_list->inherited)
144
 
                        num_entries++;
145
 
        return num_entries;
146
 
}
147
 
 
148
 
/************************************************************************
149
 
 Create the on-disk format. Caller must free.
150
 
************************************************************************/
151
 
 
152
 
static char *create_pai_buf(canon_ace *file_ace_list, canon_ace *dir_ace_list, BOOL pai_protected, size_t *store_size)
153
 
{
154
 
        char *pai_buf = NULL;
155
 
        canon_ace *ace_list = NULL;
156
 
        char *entry_offset = NULL;
157
 
        unsigned int num_entries = 0;
158
 
        unsigned int num_def_entries = 0;
159
 
 
160
 
        for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next)
161
 
                if (ace_list->inherited)
162
 
                        num_entries++;
163
 
 
164
 
        for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next)
165
 
                if (ace_list->inherited)
166
 
                        num_def_entries++;
167
 
 
168
 
        DEBUG(10,("create_pai_buf: num_entries = %u, num_def_entries = %u\n", num_entries, num_def_entries ));
169
 
 
170
 
        *store_size = PAI_ENTRIES_BASE + ((num_entries + num_def_entries)*PAI_ENTRY_LENGTH);
171
 
 
172
 
        pai_buf = SMB_MALLOC(*store_size);
173
 
        if (!pai_buf) {
174
 
                return NULL;
175
 
        }
176
 
 
177
 
        /* Set up the header. */
178
 
        memset(pai_buf, '\0', PAI_ENTRIES_BASE);
179
 
        SCVAL(pai_buf,PAI_VERSION_OFFSET,PAI_VERSION);
180
 
        SCVAL(pai_buf,PAI_FLAG_OFFSET,(pai_protected ? PAI_ACL_FLAG_PROTECTED : 0));
181
 
        SSVAL(pai_buf,PAI_NUM_ENTRIES_OFFSET,num_entries);
182
 
        SSVAL(pai_buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET,num_def_entries);
183
 
 
184
 
        entry_offset = pai_buf + PAI_ENTRIES_BASE;
185
 
 
186
 
        for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) {
187
 
                if (ace_list->inherited) {
188
 
                        uint8 type_val = (unsigned char)ace_list->owner_type;
189
 
                        uint32 entry_val = get_entry_val(ace_list);
190
 
 
191
 
                        SCVAL(entry_offset,0,type_val);
192
 
                        SIVAL(entry_offset,1,entry_val);
193
 
                        entry_offset += PAI_ENTRY_LENGTH;
194
 
                }
195
 
        }
196
 
 
197
 
        for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next) {
198
 
                if (ace_list->inherited) {
199
 
                        uint8 type_val = (unsigned char)ace_list->owner_type;
200
 
                        uint32 entry_val = get_entry_val(ace_list);
201
 
 
202
 
                        SCVAL(entry_offset,0,type_val);
203
 
                        SIVAL(entry_offset,1,entry_val);
204
 
                        entry_offset += PAI_ENTRY_LENGTH;
205
 
                }
206
 
        }
207
 
 
208
 
        return pai_buf;
209
 
}
210
 
 
211
 
/************************************************************************
212
 
 Store the user.SAMBA_PAI attribute on disk.
213
 
************************************************************************/
214
 
 
215
 
static void store_inheritance_attributes(files_struct *fsp, canon_ace *file_ace_list,
216
 
                                        canon_ace *dir_ace_list, BOOL pai_protected)
217
 
{
218
 
        int ret;
219
 
        size_t store_size;
220
 
        char *pai_buf;
221
 
 
222
 
        if (!lp_map_acl_inherit(SNUM(fsp->conn)))
223
 
                return;
224
 
 
225
 
        /*
226
 
         * Don't store if this ACL isn't protected and
227
 
         * none of the entries in it are marked as inherited.
228
 
         */
229
 
 
230
 
        if (!pai_protected && num_inherited_entries(file_ace_list) == 0 && num_inherited_entries(dir_ace_list) == 0) {
231
 
                /* Instead just remove the attribute if it exists. */
232
 
                if (fsp->fh->fd != -1)
233
 
                        SMB_VFS_FREMOVEXATTR(fsp, fsp->fh->fd, SAMBA_POSIX_INHERITANCE_EA_NAME);
234
 
                else
235
 
                        SMB_VFS_REMOVEXATTR(fsp->conn, fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME);
236
 
                return;
237
 
        }
238
 
 
239
 
        pai_buf = create_pai_buf(file_ace_list, dir_ace_list, pai_protected, &store_size);
240
 
 
241
 
        if (fsp->fh->fd != -1)
242
 
                ret = SMB_VFS_FSETXATTR(fsp, fsp->fh->fd, SAMBA_POSIX_INHERITANCE_EA_NAME,
243
 
                                pai_buf, store_size, 0);
244
 
        else
245
 
                ret = SMB_VFS_SETXATTR(fsp->conn,fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME,
246
 
                                pai_buf, store_size, 0);
247
 
 
248
 
        SAFE_FREE(pai_buf);
249
 
 
250
 
        DEBUG(10,("store_inheritance_attribute:%s for file %s\n", pai_protected ? " (protected)" : "", fsp->fsp_name));
251
 
        if (ret == -1 && !no_acl_syscall_error(errno))
252
 
                DEBUG(1,("store_inheritance_attribute: Error %s\n", strerror(errno) ));
253
 
}
254
 
 
255
 
/************************************************************************
256
 
 Delete the in memory inheritance info.
257
 
************************************************************************/
258
 
 
259
 
static void free_inherited_info(struct pai_val *pal)
260
 
{
261
 
        if (pal) {
262
 
                struct pai_entry *paie, *paie_next;
263
 
                for (paie = pal->entry_list; paie; paie = paie_next) {
264
 
                        paie_next = paie->next;
265
 
                        SAFE_FREE(paie);
266
 
                }
267
 
                for (paie = pal->def_entry_list; paie; paie = paie_next) {
268
 
                        paie_next = paie->next;
269
 
                        SAFE_FREE(paie);
270
 
                }
271
 
                SAFE_FREE(pal);
272
 
        }
273
 
}
274
 
 
275
 
/************************************************************************
276
 
 Was this ACL protected ?
277
 
************************************************************************/
278
 
 
279
 
static BOOL get_protected_flag(struct pai_val *pal)
280
 
{
281
 
        if (!pal)
282
 
                return False;
283
 
        return pal->pai_protected;
284
 
}
285
 
 
286
 
/************************************************************************
287
 
 Was this ACE inherited ?
288
 
************************************************************************/
289
 
 
290
 
static BOOL get_inherited_flag(struct pai_val *pal, canon_ace *ace_entry, BOOL default_ace)
291
 
{
292
 
        struct pai_entry *paie;
293
 
 
294
 
        if (!pal)
295
 
                return False;
296
 
 
297
 
        /* If the entry exists it is inherited. */
298
 
        for (paie = (default_ace ? pal->def_entry_list : pal->entry_list); paie; paie = paie->next) {
299
 
                if (ace_entry->owner_type == paie->owner_type &&
300
 
                                get_entry_val(ace_entry) == get_pai_entry_val(paie))
301
 
                        return True;
302
 
        }
303
 
        return False;
304
 
}
305
 
 
306
 
/************************************************************************
307
 
 Ensure an attribute just read is valid.
308
 
************************************************************************/
309
 
 
310
 
static BOOL check_pai_ok(char *pai_buf, size_t pai_buf_data_size)
311
 
{
312
 
        uint16 num_entries;
313
 
        uint16 num_def_entries;
314
 
 
315
 
        if (pai_buf_data_size < PAI_ENTRIES_BASE) {
316
 
                /* Corrupted - too small. */
317
 
                return False;
318
 
        }
319
 
 
320
 
        if (CVAL(pai_buf,PAI_VERSION_OFFSET) != PAI_VERSION)
321
 
                return False;
322
 
 
323
 
        num_entries = SVAL(pai_buf,PAI_NUM_ENTRIES_OFFSET);
324
 
        num_def_entries = SVAL(pai_buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET);
325
 
 
326
 
        /* Check the entry lists match. */
327
 
        /* Each entry is 5 bytes (type plus 4 bytes of uid or gid). */
328
 
 
329
 
        if (((num_entries + num_def_entries)*PAI_ENTRY_LENGTH) + PAI_ENTRIES_BASE != pai_buf_data_size)
330
 
                return False;
331
 
 
332
 
        return True;
333
 
}
334
 
 
335
 
 
336
 
/************************************************************************
337
 
 Convert to in-memory format.
338
 
************************************************************************/
339
 
 
340
 
static struct pai_val *create_pai_val(char *buf, size_t size)
341
 
{
342
 
        char *entry_offset;
343
 
        struct pai_val *paiv = NULL;
344
 
        int i;
345
 
 
346
 
        if (!check_pai_ok(buf, size))
347
 
                return NULL;
348
 
 
349
 
        paiv = SMB_MALLOC_P(struct pai_val);
350
 
        if (!paiv)
351
 
                return NULL;
352
 
 
353
 
        memset(paiv, '\0', sizeof(struct pai_val));
354
 
 
355
 
        paiv->pai_protected = (CVAL(buf,PAI_FLAG_OFFSET) == PAI_ACL_FLAG_PROTECTED);
356
 
 
357
 
        paiv->num_entries = SVAL(buf,PAI_NUM_ENTRIES_OFFSET);
358
 
        paiv->num_def_entries = SVAL(buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET);
359
 
 
360
 
        entry_offset = buf + PAI_ENTRIES_BASE;
361
 
 
362
 
        DEBUG(10,("create_pai_val:%s num_entries = %u, num_def_entries = %u\n",
363
 
                        paiv->pai_protected ? " (pai_protected)" : "", paiv->num_entries, paiv->num_def_entries ));
364
 
 
365
 
        for (i = 0; i < paiv->num_entries; i++) {
366
 
                struct pai_entry *paie;
367
 
 
368
 
                paie = SMB_MALLOC_P(struct pai_entry);
369
 
                if (!paie) {
370
 
                        free_inherited_info(paiv);
371
 
                        return NULL;
372
 
                }
373
 
 
374
 
                paie->owner_type = (enum ace_owner)CVAL(entry_offset,0);
375
 
                switch( paie->owner_type) {
376
 
                        case UID_ACE:
377
 
                                paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1);
378
 
                                DEBUG(10,("create_pai_val: uid = %u\n", (unsigned int)paie->unix_ug.uid ));
379
 
                                break;
380
 
                        case GID_ACE:
381
 
                                paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1);
382
 
                                DEBUG(10,("create_pai_val: gid = %u\n", (unsigned int)paie->unix_ug.gid ));
383
 
                                break;
384
 
                        case WORLD_ACE:
385
 
                                paie->unix_ug.world = -1;
386
 
                                DEBUG(10,("create_pai_val: world ace\n"));
387
 
                                break;
388
 
                        default:
389
 
                                free_inherited_info(paiv);
390
 
                                return NULL;
391
 
                }
392
 
                entry_offset += PAI_ENTRY_LENGTH;
393
 
                DLIST_ADD(paiv->entry_list, paie);
394
 
        }
395
 
 
396
 
        for (i = 0; i < paiv->num_def_entries; i++) {
397
 
                struct pai_entry *paie;
398
 
 
399
 
                paie = SMB_MALLOC_P(struct pai_entry);
400
 
                if (!paie) {
401
 
                        free_inherited_info(paiv);
402
 
                        return NULL;
403
 
                }
404
 
 
405
 
                paie->owner_type = (enum ace_owner)CVAL(entry_offset,0);
406
 
                switch( paie->owner_type) {
407
 
                        case UID_ACE:
408
 
                                paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1);
409
 
                                DEBUG(10,("create_pai_val: (def) uid = %u\n", (unsigned int)paie->unix_ug.uid ));
410
 
                                break;
411
 
                        case GID_ACE:
412
 
                                paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1);
413
 
                                DEBUG(10,("create_pai_val: (def) gid = %u\n", (unsigned int)paie->unix_ug.gid ));
414
 
                                break;
415
 
                        case WORLD_ACE:
416
 
                                paie->unix_ug.world = -1;
417
 
                                DEBUG(10,("create_pai_val: (def) world ace\n"));
418
 
                                break;
419
 
                        default:
420
 
                                free_inherited_info(paiv);
421
 
                                return NULL;
422
 
                }
423
 
                entry_offset += PAI_ENTRY_LENGTH;
424
 
                DLIST_ADD(paiv->def_entry_list, paie);
425
 
        }
426
 
 
427
 
        return paiv;
428
 
}
429
 
 
430
 
/************************************************************************
431
 
 Load the user.SAMBA_PAI attribute.
432
 
************************************************************************/
433
 
 
434
 
static struct pai_val *load_inherited_info(files_struct *fsp)
435
 
{
436
 
        char *pai_buf;
437
 
        size_t pai_buf_size = 1024;
438
 
        struct pai_val *paiv = NULL;
439
 
        ssize_t ret;
440
 
 
441
 
        if (!lp_map_acl_inherit(SNUM(fsp->conn)))
442
 
                return NULL;
443
 
 
444
 
        if ((pai_buf = SMB_MALLOC(pai_buf_size)) == NULL)
445
 
                return NULL;
446
 
 
447
 
        do {
448
 
                if (fsp->fh->fd != -1)
449
 
                        ret = SMB_VFS_FGETXATTR(fsp, fsp->fh->fd, SAMBA_POSIX_INHERITANCE_EA_NAME,
450
 
                                        pai_buf, pai_buf_size);
451
 
                else
452
 
                        ret = SMB_VFS_GETXATTR(fsp->conn,fsp->fsp_name,SAMBA_POSIX_INHERITANCE_EA_NAME,
453
 
                                        pai_buf, pai_buf_size);
454
 
 
455
 
                if (ret == -1) {
456
 
                        if (errno != ERANGE) {
457
 
                                break;
458
 
                        }
459
 
                        /* Buffer too small - enlarge it. */
460
 
                        pai_buf_size *= 2;
461
 
                        SAFE_FREE(pai_buf);
462
 
                        if (pai_buf_size > 1024*1024) {
463
 
                                return NULL; /* Limit malloc to 1mb. */
464
 
                        }
465
 
                        if ((pai_buf = SMB_MALLOC(pai_buf_size)) == NULL)
466
 
                                return NULL;
467
 
                }
468
 
        } while (ret == -1);
469
 
 
470
 
        DEBUG(10,("load_inherited_info: ret = %lu for file %s\n", (unsigned long)ret, fsp->fsp_name));
471
 
 
472
 
        if (ret == -1) {
473
 
                /* No attribute or not supported. */
474
 
#if defined(ENOATTR)
475
 
                if (errno != ENOATTR)
476
 
                        DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
477
 
#else
478
 
                if (errno != ENOSYS)
479
 
                        DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
480
 
#endif
481
 
                SAFE_FREE(pai_buf);
482
 
                return NULL;
483
 
        }
484
 
 
485
 
        paiv = create_pai_val(pai_buf, ret);
486
 
 
487
 
        if (paiv && paiv->pai_protected)
488
 
                DEBUG(10,("load_inherited_info: ACL is protected for file %s\n", fsp->fsp_name));
489
 
 
490
 
        SAFE_FREE(pai_buf);
491
 
        return paiv;
492
 
}
493
 
 
494
 
/****************************************************************************
495
 
 Functions to manipulate the internal ACE format.
496
 
****************************************************************************/
497
 
 
498
 
/****************************************************************************
499
 
 Count a linked list of canonical ACE entries.
500
 
****************************************************************************/
501
 
 
502
 
static size_t count_canon_ace_list( canon_ace *list_head )
503
 
{
504
 
        size_t count = 0;
505
 
        canon_ace *ace;
506
 
 
507
 
        for (ace = list_head; ace; ace = ace->next)
508
 
                count++;
509
 
 
510
 
        return count;
511
 
}
512
 
 
513
 
/****************************************************************************
514
 
 Free a linked list of canonical ACE entries.
515
 
****************************************************************************/
516
 
 
517
 
static void free_canon_ace_list( canon_ace *list_head )
518
 
{
519
 
        canon_ace *list, *next;
520
 
 
521
 
        for (list = list_head; list; list = next) {
522
 
                next = list->next;
523
 
                DLIST_REMOVE(list_head, list);
524
 
                SAFE_FREE(list);
525
 
        }
526
 
}
527
 
 
528
 
/****************************************************************************
529
 
 Function to duplicate a canon_ace entry.
530
 
****************************************************************************/
531
 
 
532
 
static canon_ace *dup_canon_ace( canon_ace *src_ace)
533
 
{
534
 
        canon_ace *dst_ace = SMB_MALLOC_P(canon_ace);
535
 
 
536
 
        if (dst_ace == NULL)
537
 
                return NULL;
538
 
 
539
 
        *dst_ace = *src_ace;
540
 
        dst_ace->prev = dst_ace->next = NULL;
541
 
        return dst_ace;
542
 
}
543
 
 
544
 
/****************************************************************************
545
 
 Print out a canon ace.
546
 
****************************************************************************/
547
 
 
548
 
static void print_canon_ace(canon_ace *pace, int num)
549
 
{
550
 
        fstring str;
551
 
 
552
 
        dbgtext( "canon_ace index %d. Type = %s ", num, pace->attr == ALLOW_ACE ? "allow" : "deny" );
553
 
        dbgtext( "SID = %s ", sid_to_string( str, &pace->trustee));
554
 
        if (pace->owner_type == UID_ACE) {
555
 
                const char *u_name = uidtoname(pace->unix_ug.uid);
556
 
                dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.uid, u_name );
557
 
        } else if (pace->owner_type == GID_ACE) {
558
 
                char *g_name = gidtoname(pace->unix_ug.gid);
559
 
                dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.gid, g_name );
560
 
        } else
561
 
                dbgtext( "other ");
562
 
        switch (pace->type) {
563
 
                case SMB_ACL_USER:
564
 
                        dbgtext( "SMB_ACL_USER ");
565
 
                        break;
566
 
                case SMB_ACL_USER_OBJ:
567
 
                        dbgtext( "SMB_ACL_USER_OBJ ");
568
 
                        break;
569
 
                case SMB_ACL_GROUP:
570
 
                        dbgtext( "SMB_ACL_GROUP ");
571
 
                        break;
572
 
                case SMB_ACL_GROUP_OBJ:
573
 
                        dbgtext( "SMB_ACL_GROUP_OBJ ");
574
 
                        break;
575
 
                case SMB_ACL_OTHER:
576
 
                        dbgtext( "SMB_ACL_OTHER ");
577
 
                        break;
578
 
        }
579
 
        if (pace->inherited)
580
 
                dbgtext( "(inherited) ");
581
 
        dbgtext( "perms ");
582
 
        dbgtext( "%c", pace->perms & S_IRUSR ? 'r' : '-');
583
 
        dbgtext( "%c", pace->perms & S_IWUSR ? 'w' : '-');
584
 
        dbgtext( "%c\n", pace->perms & S_IXUSR ? 'x' : '-');
585
 
}
586
 
 
587
 
/****************************************************************************
588
 
 Print out a canon ace list.
589
 
****************************************************************************/
590
 
 
591
 
static void print_canon_ace_list(const char *name, canon_ace *ace_list)
592
 
{
593
 
        int count = 0;
594
 
 
595
 
        if( DEBUGLVL( 10 )) {
596
 
                dbgtext( "print_canon_ace_list: %s\n", name );
597
 
                for (;ace_list; ace_list = ace_list->next, count++)
598
 
                        print_canon_ace(ace_list, count );
599
 
        }
600
 
}
601
 
 
602
 
/****************************************************************************
603
 
 Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
604
 
****************************************************************************/
605
 
 
606
 
static mode_t convert_permset_to_mode_t(connection_struct *conn, SMB_ACL_PERMSET_T permset)
607
 
{
608
 
        mode_t ret = 0;
609
 
 
610
 
        ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRUSR : 0);
611
 
        ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
612
 
        ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
613
 
 
614
 
        return ret;
615
 
}
616
 
 
617
 
/****************************************************************************
618
 
 Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
619
 
****************************************************************************/
620
 
 
621
 
static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
622
 
{
623
 
        mode_t ret = 0;
624
 
 
625
 
        if (mode & r_mask)
626
 
                ret |= S_IRUSR;
627
 
        if (mode & w_mask)
628
 
                ret |= S_IWUSR;
629
 
        if (mode & x_mask)
630
 
                ret |= S_IXUSR;
631
 
 
632
 
        return ret;
633
 
}
634
 
 
635
 
/****************************************************************************
636
 
 Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to
637
 
 an SMB_ACL_PERMSET_T.
638
 
****************************************************************************/
639
 
 
640
 
static int map_acl_perms_to_permset(connection_struct *conn, mode_t mode, SMB_ACL_PERMSET_T *p_permset)
641
 
{
642
 
        if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) ==  -1)
643
 
                return -1;
644
 
        if (mode & S_IRUSR) {
645
 
                if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1)
646
 
                        return -1;
647
 
        }
648
 
        if (mode & S_IWUSR) {
649
 
                if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1)
650
 
                        return -1;
651
 
        }
652
 
        if (mode & S_IXUSR) {
653
 
                if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1)
654
 
                        return -1;
655
 
        }
656
 
        return 0;
657
 
}
658
 
/****************************************************************************
659
 
 Function to create owner and group SIDs from a SMB_STRUCT_STAT.
660
 
****************************************************************************/
661
 
 
662
 
static void create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
663
 
{
664
 
        uid_to_sid( powner_sid, psbuf->st_uid );
665
 
        gid_to_sid( pgroup_sid, psbuf->st_gid );
666
 
}
667
 
 
668
 
/****************************************************************************
669
 
 Merge aces with a common sid - if both are allow or deny, OR the permissions together and
670
 
 delete the second one. If the first is deny, mask the permissions off and delete the allow
671
 
 if the permissions become zero, delete the deny if the permissions are non zero.
672
 
****************************************************************************/
673
 
 
674
 
static void merge_aces( canon_ace **pp_list_head )
675
 
{
676
 
        canon_ace *list_head = *pp_list_head;
677
 
        canon_ace *curr_ace_outer;
678
 
        canon_ace *curr_ace_outer_next;
679
 
 
680
 
        /*
681
 
         * First, merge allow entries with identical SIDs, and deny entries
682
 
         * with identical SIDs.
683
 
         */
684
 
 
685
 
        for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
686
 
                canon_ace *curr_ace;
687
 
                canon_ace *curr_ace_next;
688
 
 
689
 
                curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
690
 
 
691
 
                for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
692
 
 
693
 
                        curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
694
 
 
695
 
                        if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
696
 
                                (curr_ace->attr == curr_ace_outer->attr)) {
697
 
 
698
 
                                if( DEBUGLVL( 10 )) {
699
 
                                        dbgtext("merge_aces: Merging ACE's\n");
700
 
                                        print_canon_ace( curr_ace_outer, 0);
701
 
                                        print_canon_ace( curr_ace, 0);
702
 
                                }
703
 
 
704
 
                                /* Merge two allow or two deny ACE's. */
705
 
 
706
 
                                curr_ace_outer->perms |= curr_ace->perms;
707
 
                                DLIST_REMOVE(list_head, curr_ace);
708
 
                                SAFE_FREE(curr_ace);
709
 
                                curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
710
 
                        }
711
 
                }
712
 
        }
713
 
 
714
 
        /*
715
 
         * Now go through and mask off allow permissions with deny permissions.
716
 
         * We can delete either the allow or deny here as we know that each SID
717
 
         * appears only once in the list.
718
 
         */
719
 
 
720
 
        for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
721
 
                canon_ace *curr_ace;
722
 
                canon_ace *curr_ace_next;
723
 
 
724
 
                curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
725
 
 
726
 
                for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
727
 
 
728
 
                        curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
729
 
 
730
 
                        /*
731
 
                         * Subtract ACE's with different entries. Due to the ordering constraints
732
 
                         * we've put on the ACL, we know the deny must be the first one.
733
 
                         */
734
 
 
735
 
                        if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
736
 
                                (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
737
 
 
738
 
                                if( DEBUGLVL( 10 )) {
739
 
                                        dbgtext("merge_aces: Masking ACE's\n");
740
 
                                        print_canon_ace( curr_ace_outer, 0);
741
 
                                        print_canon_ace( curr_ace, 0);
742
 
                                }
743
 
 
744
 
                                curr_ace->perms &= ~curr_ace_outer->perms;
745
 
 
746
 
                                if (curr_ace->perms == 0) {
747
 
 
748
 
                                        /*
749
 
                                         * The deny overrides the allow. Remove the allow.
750
 
                                         */
751
 
 
752
 
                                        DLIST_REMOVE(list_head, curr_ace);
753
 
                                        SAFE_FREE(curr_ace);
754
 
                                        curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
755
 
 
756
 
                                } else {
757
 
 
758
 
                                        /*
759
 
                                         * Even after removing permissions, there
760
 
                                         * are still allow permissions - delete the deny.
761
 
                                         * It is safe to delete the deny here,
762
 
                                         * as we are guarenteed by the deny first
763
 
                                         * ordering that all the deny entries for
764
 
                                         * this SID have already been merged into one
765
 
                                         * before we can get to an allow ace.
766
 
                                         */
767
 
 
768
 
                                        DLIST_REMOVE(list_head, curr_ace_outer);
769
 
                                        SAFE_FREE(curr_ace_outer);
770
 
                                        break;
771
 
                                }
772
 
                        }
773
 
 
774
 
                } /* end for curr_ace */
775
 
        } /* end for curr_ace_outer */
776
 
 
777
 
        /* We may have modified the list. */
778
 
 
779
 
        *pp_list_head = list_head;
780
 
}
781
 
 
782
 
/****************************************************************************
783
 
 Check if we need to return NT4.x compatible ACL entries.
784
 
****************************************************************************/
785
 
 
786
 
static BOOL nt4_compatible_acls(void)
787
 
{
788
 
        int compat = lp_acl_compatibility();
789
 
 
790
 
        if (compat == ACL_COMPAT_AUTO) {
791
 
                enum remote_arch_types ra_type = get_remote_arch();
792
 
 
793
 
                /* Automatically adapt to client */
794
 
                return (ra_type <= RA_WINNT);
795
 
        } else
796
 
                return (compat == ACL_COMPAT_WINNT);
797
 
}
798
 
 
799
 
 
800
 
/****************************************************************************
801
 
 Map canon_ace perms to permission bits NT.
802
 
 The attr element is not used here - we only process deny entries on set,
803
 
 not get. Deny entries are implicit on get with ace->perms = 0.
804
 
****************************************************************************/
805
 
 
806
 
static SEC_ACCESS map_canon_ace_perms(int snum, int *pacl_type, DOM_SID *powner_sid, canon_ace *ace, BOOL directory_ace)
807
 
{
808
 
        SEC_ACCESS sa;
809
 
        uint32 nt_mask = 0;
810
 
 
811
 
        *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
812
 
 
813
 
        if (lp_acl_map_full_control(snum) && ((ace->perms & ALL_ACE_PERMS) == ALL_ACE_PERMS)) {
814
 
                if (directory_ace) {
815
 
                        nt_mask = UNIX_DIRECTORY_ACCESS_RWX;
816
 
                } else {
817
 
                        nt_mask = UNIX_ACCESS_RWX;
818
 
                }
819
 
        } else if ((ace->perms & ALL_ACE_PERMS) == (mode_t)0) {
820
 
                /*
821
 
                 * Windows NT refuses to display ACEs with no permissions in them (but
822
 
                 * they are perfectly legal with Windows 2000). If the ACE has empty
823
 
                 * permissions we cannot use 0, so we use the otherwise unused
824
 
                 * WRITE_OWNER permission, which we ignore when we set an ACL.
825
 
                 * We abstract this into a #define of UNIX_ACCESS_NONE to allow this
826
 
                 * to be changed in the future.
827
 
                 */
828
 
 
829
 
                if (nt4_compatible_acls())
830
 
                        nt_mask = UNIX_ACCESS_NONE;
831
 
                else
832
 
                        nt_mask = 0;
833
 
        } else {
834
 
                if (directory_ace) {
835
 
                        nt_mask |= ((ace->perms & S_IRUSR) ? UNIX_DIRECTORY_ACCESS_R : 0 );
836
 
                        nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_DIRECTORY_ACCESS_W : 0 );
837
 
                        nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_DIRECTORY_ACCESS_X : 0 );
838
 
                } else {
839
 
                        nt_mask |= ((ace->perms & S_IRUSR) ? UNIX_ACCESS_R : 0 );
840
 
                        nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
841
 
                        nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_ACCESS_X : 0 );
842
 
                }
843
 
        }
844
 
 
845
 
        DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
846
 
                        (unsigned int)ace->perms, (unsigned int)nt_mask ));
847
 
 
848
 
        init_sec_access(&sa,nt_mask);
849
 
        return sa;
850
 
}
851
 
 
852
 
/****************************************************************************
853
 
 Map NT perms to a UNIX mode_t.
854
 
****************************************************************************/
855
 
 
856
 
#define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
857
 
#define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
858
 
#define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
859
 
 
860
 
static mode_t map_nt_perms( SEC_ACCESS sec_access, int type)
861
 
{
862
 
        mode_t mode = 0;
863
 
 
864
 
        switch(type) {
865
 
        case S_IRUSR:
866
 
                if(sec_access.mask & GENERIC_ALL_ACCESS)
867
 
                        mode = S_IRUSR|S_IWUSR|S_IXUSR;
868
 
                else {
869
 
                        mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
870
 
                        mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
871
 
                        mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
872
 
                }
873
 
                break;
874
 
        case S_IRGRP:
875
 
                if(sec_access.mask & GENERIC_ALL_ACCESS)
876
 
                        mode = S_IRGRP|S_IWGRP|S_IXGRP;
877
 
                else {
878
 
                        mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
879
 
                        mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
880
 
                        mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
881
 
                }
882
 
                break;
883
 
        case S_IROTH:
884
 
                if(sec_access.mask & GENERIC_ALL_ACCESS)
885
 
                        mode = S_IROTH|S_IWOTH|S_IXOTH;
886
 
                else {
887
 
                        mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
888
 
                        mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
889
 
                        mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
890
 
                }
891
 
                break;
892
 
        }
893
 
 
894
 
        return mode;
895
 
}
896
 
 
897
 
/****************************************************************************
898
 
 Unpack a SEC_DESC into a UNIX owner and group.
899
 
****************************************************************************/
900
 
 
901
 
static BOOL unpack_nt_owners(int snum, SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
902
 
{
903
 
        DOM_SID owner_sid;
904
 
        DOM_SID grp_sid;
905
 
 
906
 
        *puser = (uid_t)-1;
907
 
        *pgrp = (gid_t)-1;
908
 
 
909
 
        if(security_info_sent == 0) {
910
 
                DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
911
 
                return True;
912
 
        }
913
 
 
914
 
        /*
915
 
         * Validate the owner and group SID's.
916
 
         */
917
 
 
918
 
        memset(&owner_sid, '\0', sizeof(owner_sid));
919
 
        memset(&grp_sid, '\0', sizeof(grp_sid));
920
 
 
921
 
        DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
922
 
 
923
 
        /*
924
 
         * Don't immediately fail if the owner sid cannot be validated.
925
 
         * This may be a group chown only set.
926
 
         */
927
 
 
928
 
        if (security_info_sent & OWNER_SECURITY_INFORMATION) {
929
 
                sid_copy(&owner_sid, psd->owner_sid);
930
 
                if (!sid_to_uid(&owner_sid, puser)) {
931
 
                        if (lp_force_unknown_acl_user(snum)) {
932
 
                                /* this allows take ownership to work
933
 
                                 * reasonably */
934
 
                                *puser = current_user.ut.uid;
935
 
                        } else {
936
 
                                DEBUG(3,("unpack_nt_owners: unable to validate"
937
 
                                         " owner sid for %s\n",
938
 
                                         sid_string_static(&owner_sid)));
939
 
                                return False;
940
 
                        }
941
 
                }
942
 
        }
943
 
 
944
 
        /*
945
 
         * Don't immediately fail if the group sid cannot be validated.
946
 
         * This may be an owner chown only set.
947
 
         */
948
 
 
949
 
        if (security_info_sent & GROUP_SECURITY_INFORMATION) {
950
 
                sid_copy(&grp_sid, psd->grp_sid);
951
 
                if (!sid_to_gid( &grp_sid, pgrp)) {
952
 
                        if (lp_force_unknown_acl_user(snum)) {
953
 
                                /* this allows take group ownership to work
954
 
                                 * reasonably */
955
 
                                *pgrp = current_user.ut.gid;
956
 
                        } else {
957
 
                                DEBUG(3,("unpack_nt_owners: unable to validate"
958
 
                                         " group sid.\n"));
959
 
                                return False;
960
 
                        }
961
 
                }
962
 
        }
963
 
 
964
 
        DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
965
 
 
966
 
        return True;
967
 
}
968
 
 
969
 
/****************************************************************************
970
 
 Ensure the enforced permissions for this share apply.
971
 
****************************************************************************/
972
 
 
973
 
static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type)
974
 
{
975
 
        int snum = SNUM(fsp->conn);
976
 
        mode_t and_bits = (mode_t)0;
977
 
        mode_t or_bits = (mode_t)0;
978
 
 
979
 
        /* Get the initial bits to apply. */
980
 
 
981
 
        if (fsp->is_directory) {
982
 
                and_bits = lp_dir_security_mask(snum);
983
 
                or_bits = lp_force_dir_security_mode(snum);
984
 
        } else {
985
 
                and_bits = lp_security_mask(snum);
986
 
                or_bits = lp_force_security_mode(snum);
987
 
        }
988
 
 
989
 
        /* Now bounce them into the S_USR space. */     
990
 
        switch(type) {
991
 
        case S_IRUSR:
992
 
                /* Ensure owner has read access. */
993
 
                pace->perms |= S_IRUSR;
994
 
                if (fsp->is_directory)
995
 
                        pace->perms |= (S_IWUSR|S_IXUSR);
996
 
                and_bits = unix_perms_to_acl_perms(and_bits, S_IRUSR, S_IWUSR, S_IXUSR);
997
 
                or_bits = unix_perms_to_acl_perms(or_bits, S_IRUSR, S_IWUSR, S_IXUSR);
998
 
                break;
999
 
        case S_IRGRP:
1000
 
                and_bits = unix_perms_to_acl_perms(and_bits, S_IRGRP, S_IWGRP, S_IXGRP);
1001
 
                or_bits = unix_perms_to_acl_perms(or_bits, S_IRGRP, S_IWGRP, S_IXGRP);
1002
 
                break;
1003
 
        case S_IROTH:
1004
 
                and_bits = unix_perms_to_acl_perms(and_bits, S_IROTH, S_IWOTH, S_IXOTH);
1005
 
                or_bits = unix_perms_to_acl_perms(or_bits, S_IROTH, S_IWOTH, S_IXOTH);
1006
 
                break;
1007
 
        }
1008
 
 
1009
 
        pace->perms = ((pace->perms & and_bits)|or_bits);
1010
 
}
1011
 
 
1012
 
/****************************************************************************
1013
 
 Check if a given uid/SID is in a group gid/SID. This is probably very
1014
 
 expensive and will need optimisation. A *lot* of optimisation :-). JRA.
1015
 
****************************************************************************/
1016
 
 
1017
 
static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
1018
 
{
1019
 
        fstring u_name;
1020
 
 
1021
 
        /* "Everyone" always matches every uid. */
1022
 
 
1023
 
        if (sid_equal(&group_ace->trustee, &global_sid_World))
1024
 
                return True;
1025
 
 
1026
 
        /* Assume that the current user is in the current group (force group) */
1027
 
 
1028
 
        if (uid_ace->unix_ug.uid == current_user.ut.uid && group_ace->unix_ug.gid == current_user.ut.gid)
1029
 
                return True;
1030
 
 
1031
 
        fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid));
1032
 
        return user_in_group_sid(u_name, &group_ace->trustee);
1033
 
}
1034
 
 
1035
 
/****************************************************************************
1036
 
 A well formed POSIX file or default ACL has at least 3 entries, a 
1037
 
 SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
1038
 
 In addition, the owner must always have at least read access.
1039
 
 When using this call on get_acl, the pst struct is valid and contains
1040
 
 the mode of the file. When using this call on set_acl, the pst struct has
1041
 
 been modified to have a mode containing the default for this file or directory
1042
 
 type.
1043
 
****************************************************************************/
1044
 
 
1045
 
static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
1046
 
                                                        files_struct *fsp,
1047
 
                                                        const DOM_SID *pfile_owner_sid,
1048
 
                                                        const DOM_SID *pfile_grp_sid,
1049
 
                                                        SMB_STRUCT_STAT *pst,
1050
 
                                                        BOOL setting_acl)
1051
 
{
1052
 
        canon_ace *pace;
1053
 
        BOOL got_user = False;
1054
 
        BOOL got_grp = False;
1055
 
        BOOL got_other = False;
1056
 
        canon_ace *pace_other = NULL;
1057
 
 
1058
 
        for (pace = *pp_ace; pace; pace = pace->next) {
1059
 
                if (pace->type == SMB_ACL_USER_OBJ) {
1060
 
 
1061
 
                        if (setting_acl)
1062
 
                                apply_default_perms(fsp, pace, S_IRUSR);
1063
 
                        got_user = True;
1064
 
 
1065
 
                } else if (pace->type == SMB_ACL_GROUP_OBJ) {
1066
 
 
1067
 
                        /*
1068
 
                         * Ensure create mask/force create mode is respected on set.
1069
 
                         */
1070
 
 
1071
 
                        if (setting_acl)
1072
 
                                apply_default_perms(fsp, pace, S_IRGRP);
1073
 
                        got_grp = True;
1074
 
 
1075
 
                } else if (pace->type == SMB_ACL_OTHER) {
1076
 
 
1077
 
                        /*
1078
 
                         * Ensure create mask/force create mode is respected on set.
1079
 
                         */
1080
 
 
1081
 
                        if (setting_acl)
1082
 
                                apply_default_perms(fsp, pace, S_IROTH);
1083
 
                        got_other = True;
1084
 
                        pace_other = pace;
1085
 
                }
1086
 
        }
1087
 
 
1088
 
        if (!got_user) {
1089
 
                if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
1090
 
                        DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1091
 
                        return False;
1092
 
                }
1093
 
 
1094
 
                ZERO_STRUCTP(pace);
1095
 
                pace->type = SMB_ACL_USER_OBJ;
1096
 
                pace->owner_type = UID_ACE;
1097
 
                pace->unix_ug.uid = pst->st_uid;
1098
 
                pace->trustee = *pfile_owner_sid;
1099
 
                pace->attr = ALLOW_ACE;
1100
 
 
1101
 
                if (setting_acl) {
1102
 
                        /* See if the owning user is in any of the other groups in
1103
 
                           the ACE. If so, OR in the permissions from that group. */
1104
 
 
1105
 
                        BOOL group_matched = False;
1106
 
                        canon_ace *pace_iter;
1107
 
 
1108
 
                        for (pace_iter = *pp_ace; pace_iter; pace_iter = pace_iter->next) {
1109
 
                                if (pace_iter->type == SMB_ACL_GROUP_OBJ || pace_iter->type == SMB_ACL_GROUP) {
1110
 
                                        if (uid_entry_in_group(pace, pace_iter)) {
1111
 
                                                pace->perms |= pace_iter->perms;
1112
 
                                                group_matched = True;
1113
 
                                        }
1114
 
                                }
1115
 
                        }
1116
 
 
1117
 
                        /* If we only got an "everyone" perm, just use that. */
1118
 
                        if (!group_matched) {
1119
 
                                if (got_other)
1120
 
                                        pace->perms = pace_other->perms;
1121
 
                                else
1122
 
                                        pace->perms = 0;
1123
 
                        }
1124
 
 
1125
 
                        apply_default_perms(fsp, pace, S_IRUSR);
1126
 
                } else {
1127
 
                        pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
1128
 
                }
1129
 
 
1130
 
                DLIST_ADD(*pp_ace, pace);
1131
 
        }
1132
 
 
1133
 
        if (!got_grp) {
1134
 
                if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
1135
 
                        DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1136
 
                        return False;
1137
 
                }
1138
 
 
1139
 
                ZERO_STRUCTP(pace);
1140
 
                pace->type = SMB_ACL_GROUP_OBJ;
1141
 
                pace->owner_type = GID_ACE;
1142
 
                pace->unix_ug.uid = pst->st_gid;
1143
 
                pace->trustee = *pfile_grp_sid;
1144
 
                pace->attr = ALLOW_ACE;
1145
 
                if (setting_acl) {
1146
 
                        /* If we only got an "everyone" perm, just use that. */
1147
 
                        if (got_other)
1148
 
                                pace->perms = pace_other->perms;
1149
 
                        else
1150
 
                                pace->perms = 0;
1151
 
                        apply_default_perms(fsp, pace, S_IRGRP);
1152
 
                } else {
1153
 
                        pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
1154
 
                }
1155
 
 
1156
 
                DLIST_ADD(*pp_ace, pace);
1157
 
        }
1158
 
 
1159
 
        if (!got_other) {
1160
 
                if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
1161
 
                        DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1162
 
                        return False;
1163
 
                }
1164
 
 
1165
 
                ZERO_STRUCTP(pace);
1166
 
                pace->type = SMB_ACL_OTHER;
1167
 
                pace->owner_type = WORLD_ACE;
1168
 
                pace->unix_ug.world = -1;
1169
 
                pace->trustee = global_sid_World;
1170
 
                pace->attr = ALLOW_ACE;
1171
 
                if (setting_acl) {
1172
 
                        pace->perms = 0;
1173
 
                        apply_default_perms(fsp, pace, S_IROTH);
1174
 
                } else
1175
 
                        pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
1176
 
 
1177
 
                DLIST_ADD(*pp_ace, pace);
1178
 
        }
1179
 
 
1180
 
        return True;
1181
 
}
1182
 
 
1183
 
/****************************************************************************
1184
 
 Check if a POSIX ACL has the required SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries.
1185
 
 If it does not have them, check if there are any entries where the trustee is the
1186
 
 file owner or the owning group, and map these to SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ.
1187
 
****************************************************************************/
1188
 
 
1189
 
static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid)
1190
 
{
1191
 
        BOOL got_user_obj, got_group_obj;
1192
 
        canon_ace *current_ace;
1193
 
        int i, entries;
1194
 
 
1195
 
        entries = count_canon_ace_list(ace);
1196
 
        got_user_obj = False;
1197
 
        got_group_obj = False;
1198
 
 
1199
 
        for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1200
 
                if (current_ace->type == SMB_ACL_USER_OBJ)
1201
 
                        got_user_obj = True;
1202
 
                else if (current_ace->type == SMB_ACL_GROUP_OBJ)
1203
 
                        got_group_obj = True;
1204
 
        }
1205
 
        if (got_user_obj && got_group_obj) {
1206
 
                DEBUG(10,("check_owning_objs: ACL had owning user/group entries.\n"));
1207
 
                return;
1208
 
        }
1209
 
 
1210
 
        for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1211
 
                if (!got_user_obj && current_ace->owner_type == UID_ACE &&
1212
 
                                sid_equal(&current_ace->trustee, pfile_owner_sid)) {
1213
 
                        current_ace->type = SMB_ACL_USER_OBJ;
1214
 
                        got_user_obj = True;
1215
 
                }
1216
 
                if (!got_group_obj && current_ace->owner_type == GID_ACE &&
1217
 
                                sid_equal(&current_ace->trustee, pfile_grp_sid)) {
1218
 
                        current_ace->type = SMB_ACL_GROUP_OBJ;
1219
 
                        got_group_obj = True;
1220
 
                }
1221
 
        }
1222
 
        if (!got_user_obj)
1223
 
                DEBUG(10,("check_owning_objs: ACL is missing an owner entry.\n"));
1224
 
        if (!got_group_obj)
1225
 
                DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n"));
1226
 
}
1227
 
 
1228
 
/****************************************************************************
1229
 
 Unpack a SEC_DESC into two canonical ace lists.
1230
 
****************************************************************************/
1231
 
 
1232
 
static BOOL create_canon_ace_lists(files_struct *fsp, SMB_STRUCT_STAT *pst,
1233
 
                                                        DOM_SID *pfile_owner_sid,
1234
 
                                                        DOM_SID *pfile_grp_sid,
1235
 
                                                        canon_ace **ppfile_ace, canon_ace **ppdir_ace,
1236
 
                                                        SEC_ACL *dacl)
1237
 
{
1238
 
        BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
1239
 
        canon_ace *file_ace = NULL;
1240
 
        canon_ace *dir_ace = NULL;
1241
 
        canon_ace *tmp_ace = NULL;
1242
 
        canon_ace *current_ace = NULL;
1243
 
        BOOL got_dir_allow = False;
1244
 
        BOOL got_file_allow = False;
1245
 
        int i, j;
1246
 
 
1247
 
        *ppfile_ace = NULL;
1248
 
        *ppdir_ace = NULL;
1249
 
 
1250
 
        /*
1251
 
         * Convert the incoming ACL into a more regular form.
1252
 
         */
1253
 
 
1254
 
        for(i = 0; i < dacl->num_aces; i++) {
1255
 
                SEC_ACE *psa = &dacl->ace[i];
1256
 
 
1257
 
                if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
1258
 
                        DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
1259
 
                        return False;
1260
 
                }
1261
 
 
1262
 
                if (nt4_compatible_acls()) {
1263
 
                        /*
1264
 
                         * The security mask may be UNIX_ACCESS_NONE which should map into
1265
 
                         * no permissions (we overload the WRITE_OWNER bit for this) or it
1266
 
                         * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
1267
 
                         * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
1268
 
                         */
1269
 
 
1270
 
                        /*
1271
 
                         * Convert GENERIC bits to specific bits.
1272
 
                         */
1273
 
 
1274
 
                        se_map_generic(&psa->info.mask, &file_generic_mapping);
1275
 
 
1276
 
                        psa->info.mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS);
1277
 
 
1278
 
                        if(psa->info.mask != UNIX_ACCESS_NONE)
1279
 
                                psa->info.mask &= ~UNIX_ACCESS_NONE;
1280
 
                }
1281
 
        }
1282
 
 
1283
 
        /*
1284
 
         * Deal with the fact that NT 4.x re-writes the canonical format
1285
 
         * that we return for default ACLs. If a directory ACE is identical
1286
 
         * to a inherited directory ACE then NT changes the bits so that the
1287
 
         * first ACE is set to OI|IO and the second ACE for this SID is set
1288
 
         * to CI. We need to repair this. JRA.
1289
 
         */
1290
 
 
1291
 
        for(i = 0; i < dacl->num_aces; i++) {
1292
 
                SEC_ACE *psa1 = &dacl->ace[i];
1293
 
 
1294
 
                for (j = i + 1; j < dacl->num_aces; j++) {
1295
 
                        SEC_ACE *psa2 = &dacl->ace[j];
1296
 
 
1297
 
                        if (psa1->info.mask != psa2->info.mask)
1298
 
                                continue;
1299
 
 
1300
 
                        if (!sid_equal(&psa1->trustee, &psa2->trustee))
1301
 
                                continue;
1302
 
 
1303
 
                        /*
1304
 
                         * Ok - permission bits and SIDs are equal.
1305
 
                         * Check if flags were re-written.
1306
 
                         */
1307
 
 
1308
 
                        if (psa1->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1309
 
 
1310
 
                                psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1311
 
                                psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1312
 
                                
1313
 
                        } else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1314
 
 
1315
 
                                psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1316
 
                                psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1317
 
                                
1318
 
                        }
1319
 
                }
1320
 
        }
1321
 
 
1322
 
        for(i = 0; i < dacl->num_aces; i++) {
1323
 
                SEC_ACE *psa = &dacl->ace[i];
1324
 
 
1325
 
                /*
1326
 
                 * Ignore non-mappable SIDs (NT Authority, BUILTIN etc).
1327
 
                 */
1328
 
 
1329
 
                if (non_mappable_sid(&psa->trustee)) {
1330
 
                        fstring str;
1331
 
                        DEBUG(10,("create_canon_ace_lists: ignoring non-mappable SID %s\n",
1332
 
                                sid_to_string(str, &psa->trustee) ));
1333
 
                        continue;
1334
 
                }
1335
 
 
1336
 
                /*
1337
 
                 * Create a cannon_ace entry representing this NT DACL ACE.
1338
 
                 */
1339
 
 
1340
 
                if ((current_ace = SMB_MALLOC_P(canon_ace)) == NULL) {
1341
 
                        free_canon_ace_list(file_ace);
1342
 
                        free_canon_ace_list(dir_ace);
1343
 
                        DEBUG(0,("create_canon_ace_lists: malloc fail.\n"));
1344
 
                        return False;
1345
 
                }
1346
 
 
1347
 
                ZERO_STRUCTP(current_ace);
1348
 
 
1349
 
                sid_copy(&current_ace->trustee, &psa->trustee);
1350
 
 
1351
 
                /*
1352
 
                 * Try and work out if the SID is a user or group
1353
 
                 * as we need to flag these differently for POSIX.
1354
 
                 * Note what kind of a POSIX ACL this should map to.
1355
 
                 */
1356
 
 
1357
 
                if( sid_equal(&current_ace->trustee, &global_sid_World)) {
1358
 
                        current_ace->owner_type = WORLD_ACE;
1359
 
                        current_ace->unix_ug.world = -1;
1360
 
                        current_ace->type = SMB_ACL_OTHER;
1361
 
                } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Owner)) {
1362
 
                        current_ace->owner_type = UID_ACE;
1363
 
                        current_ace->unix_ug.uid = pst->st_uid;
1364
 
                        current_ace->type = SMB_ACL_USER_OBJ;
1365
 
 
1366
 
                        /*
1367
 
                         * The Creator Owner entry only specifies inheritable permissions,
1368
 
                         * never access permissions. WinNT doesn't always set the ACE to
1369
 
                         *INHERIT_ONLY, though.
1370
 
                         */
1371
 
 
1372
 
                        if (nt4_compatible_acls())
1373
 
                                psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1374
 
                } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Group)) {
1375
 
                        current_ace->owner_type = GID_ACE;
1376
 
                        current_ace->unix_ug.gid = pst->st_gid;
1377
 
                        current_ace->type = SMB_ACL_GROUP_OBJ;
1378
 
 
1379
 
                        /*
1380
 
                         * The Creator Group entry only specifies inheritable permissions,
1381
 
                         * never access permissions. WinNT doesn't always set the ACE to
1382
 
                         *INHERIT_ONLY, though.
1383
 
                         */
1384
 
                        if (nt4_compatible_acls())
1385
 
                                psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1386
 
 
1387
 
                } else if (sid_to_uid( &current_ace->trustee, &current_ace->unix_ug.uid)) {
1388
 
                        current_ace->owner_type = UID_ACE;
1389
 
                        current_ace->type = SMB_ACL_USER;
1390
 
                } else if (sid_to_gid( &current_ace->trustee, &current_ace->unix_ug.gid)) {
1391
 
                        current_ace->owner_type = GID_ACE;
1392
 
                        current_ace->type = SMB_ACL_GROUP;
1393
 
                } else {
1394
 
                        fstring str;
1395
 
 
1396
 
                        free_canon_ace_list(file_ace);
1397
 
                        free_canon_ace_list(dir_ace);
1398
 
                        DEBUG(0,("create_canon_ace_lists: unable to map SID %s to uid or gid.\n",
1399
 
                                sid_to_string(str, &current_ace->trustee) ));
1400
 
                        SAFE_FREE(current_ace);
1401
 
                        return False;
1402
 
                }
1403
 
 
1404
 
                /*
1405
 
                 * Map the given NT permissions into a UNIX mode_t containing only
1406
 
                 * S_I(R|W|X)USR bits.
1407
 
                 */
1408
 
 
1409
 
                current_ace->perms |= map_nt_perms( psa->info, S_IRUSR);
1410
 
                current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
1411
 
                current_ace->inherited = ((psa->flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False);
1412
 
 
1413
 
                /*
1414
 
                 * Now add the created ace to either the file list, the directory
1415
 
                 * list, or both. We *MUST* preserve the order here (hence we use
1416
 
                 * DLIST_ADD_END) as NT ACLs are order dependent.
1417
 
                 */
1418
 
 
1419
 
                if (fsp->is_directory) {
1420
 
 
1421
 
                        /*
1422
 
                         * We can only add to the default POSIX ACE list if the ACE is
1423
 
                         * designed to be inherited by both files and directories.
1424
 
                         */
1425
 
 
1426
 
                        if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
1427
 
                                (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
1428
 
 
1429
 
                                DLIST_ADD_END(dir_ace, current_ace, tmp_ace);
1430
 
 
1431
 
                                /*
1432
 
                                 * Note if this was an allow ace. We can't process
1433
 
                                 * any further deny ace's after this.
1434
 
                                 */
1435
 
 
1436
 
                                if (current_ace->attr == ALLOW_ACE)
1437
 
                                        got_dir_allow = True;
1438
 
 
1439
 
                                if ((current_ace->attr == DENY_ACE) && got_dir_allow) {
1440
 
                                        DEBUG(0,("create_canon_ace_lists: malformed ACL in inheritable ACL ! \
1441
 
Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
1442
 
                                        free_canon_ace_list(file_ace);
1443
 
                                        free_canon_ace_list(dir_ace);
1444
 
                                        return False;
1445
 
                                }       
1446
 
 
1447
 
                                if( DEBUGLVL( 10 )) {
1448
 
                                        dbgtext("create_canon_ace_lists: adding dir ACL:\n");
1449
 
                                        print_canon_ace( current_ace, 0);
1450
 
                                }
1451
 
 
1452
 
                                /*
1453
 
                                 * If this is not an inherit only ACE we need to add a duplicate
1454
 
                                 * to the file acl.
1455
 
                                 */
1456
 
 
1457
 
                                if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1458
 
                                        canon_ace *dup_ace = dup_canon_ace(current_ace);
1459
 
 
1460
 
                                        if (!dup_ace) {
1461
 
                                                DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
1462
 
                                                free_canon_ace_list(file_ace);
1463
 
                                                free_canon_ace_list(dir_ace);
1464
 
                                                return False;
1465
 
                                        }
1466
 
 
1467
 
                                        /*
1468
 
                                         * We must not free current_ace here as its
1469
 
                                         * pointer is now owned by the dir_ace list.
1470
 
                                         */
1471
 
                                        current_ace = dup_ace;
1472
 
                                } else {
1473
 
                                        /*
1474
 
                                         * We must not free current_ace here as its
1475
 
                                         * pointer is now owned by the dir_ace list.
1476
 
                                         */
1477
 
                                        current_ace = NULL;
1478
 
                                }
1479
 
                        }
1480
 
                }
1481
 
 
1482
 
                /*
1483
 
                 * Only add to the file ACL if not inherit only.
1484
 
                 */
1485
 
 
1486
 
                if (current_ace && !(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1487
 
                        DLIST_ADD_END(file_ace, current_ace, tmp_ace);
1488
 
 
1489
 
                        /*
1490
 
                         * Note if this was an allow ace. We can't process
1491
 
                         * any further deny ace's after this.
1492
 
                         */
1493
 
 
1494
 
                        if (current_ace->attr == ALLOW_ACE)
1495
 
                                got_file_allow = True;
1496
 
 
1497
 
                        if ((current_ace->attr == DENY_ACE) && got_file_allow) {
1498
 
                                DEBUG(0,("create_canon_ace_lists: malformed ACL in file ACL ! \
1499
 
Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
1500
 
                                free_canon_ace_list(file_ace);
1501
 
                                free_canon_ace_list(dir_ace);
1502
 
                                return False;
1503
 
                        }       
1504
 
 
1505
 
                        if( DEBUGLVL( 10 )) {
1506
 
                                dbgtext("create_canon_ace_lists: adding file ACL:\n");
1507
 
                                print_canon_ace( current_ace, 0);
1508
 
                        }
1509
 
                        all_aces_are_inherit_only = False;
1510
 
                        /*
1511
 
                         * We must not free current_ace here as its
1512
 
                         * pointer is now owned by the file_ace list.
1513
 
                         */
1514
 
                        current_ace = NULL;
1515
 
                }
1516
 
 
1517
 
                /*
1518
 
                 * Free if ACE was not added.
1519
 
                 */
1520
 
 
1521
 
                SAFE_FREE(current_ace);
1522
 
        }
1523
 
 
1524
 
        if (fsp->is_directory && all_aces_are_inherit_only) {
1525
 
                /*
1526
 
                 * Windows 2000 is doing one of these weird 'inherit acl'
1527
 
                 * traverses to conserve NTFS ACL resources. Just pretend
1528
 
                 * there was no DACL sent. JRA.
1529
 
                 */
1530
 
 
1531
 
                DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n"));
1532
 
                free_canon_ace_list(file_ace);
1533
 
                free_canon_ace_list(dir_ace);
1534
 
                file_ace = NULL;
1535
 
                dir_ace = NULL;
1536
 
        } else {
1537
 
                /*
1538
 
                 * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in each
1539
 
                 * ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP
1540
 
                 * entries can be converted to *_OBJ. Usually we will already have these
1541
 
                 * entries in the Default ACL, and the Access ACL will not have them.
1542
 
                 */
1543
 
                if (file_ace) {
1544
 
                        check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);
1545
 
                }
1546
 
                if (dir_ace) {
1547
 
                        check_owning_objs(dir_ace, pfile_owner_sid, pfile_grp_sid);
1548
 
                }
1549
 
        }
1550
 
 
1551
 
        *ppfile_ace = file_ace;
1552
 
        *ppdir_ace = dir_ace;
1553
 
 
1554
 
        return True;
1555
 
}
1556
 
 
1557
 
/****************************************************************************
1558
 
 ASCII art time again... JRA :-).
1559
 
 
1560
 
 We have 4 cases to process when moving from an NT ACL to a POSIX ACL. Firstly,
1561
 
 we insist the ACL is in canonical form (ie. all DENY entries preceede ALLOW
1562
 
 entries). Secondly, the merge code has ensured that all duplicate SID entries for
1563
 
 allow or deny have been merged, so the same SID can only appear once in the deny
1564
 
 list or once in the allow list.
1565
 
 
1566
 
 We then process as follows :
1567
 
 
1568
 
 ---------------------------------------------------------------------------
1569
 
 First pass - look for a Everyone DENY entry.
1570
 
 
1571
 
 If it is deny all (rwx) trunate the list at this point.
1572
 
 Else, walk the list from this point and use the deny permissions of this
1573
 
 entry as a mask on all following allow entries. Finally, delete
1574
 
 the Everyone DENY entry (we have applied it to everything possible).
1575
 
 
1576
 
 In addition, in this pass we remove any DENY entries that have 
1577
 
 no permissions (ie. they are a DENY nothing).
1578
 
 ---------------------------------------------------------------------------
1579
 
 Second pass - only deal with deny user entries.
1580
 
 
1581
 
 DENY user1 (perms XXX)
1582
 
 
1583
 
 new_perms = 0
1584
 
 for all following allow group entries where user1 is in group
1585
 
        new_perms |= group_perms;
1586
 
 
1587
 
 user1 entry perms = new_perms & ~ XXX;
1588
 
 
1589
 
 Convert the deny entry to an allow entry with the new perms and
1590
 
 push to the end of the list. Note if the user was in no groups
1591
 
 this maps to a specific allow nothing entry for this user.
1592
 
 
1593
 
 The common case from the NT ACL choser (userX deny all) is
1594
 
 optimised so we don't do the group lookup - we just map to
1595
 
 an allow nothing entry.
1596
 
 
1597
 
 What we're doing here is inferring the allow permissions the
1598
 
 person setting the ACE on user1 wanted by looking at the allow
1599
 
 permissions on the groups the user is currently in. This will
1600
 
 be a snapshot, depending on group membership but is the best
1601
 
 we can do and has the advantage of failing closed rather than
1602
 
 open.
1603
 
 ---------------------------------------------------------------------------
1604
 
 Third pass - only deal with deny group entries.
1605
 
 
1606
 
 DENY group1 (perms XXX)
1607
 
 
1608
 
 for all following allow user entries where user is in group1
1609
 
   user entry perms = user entry perms & ~ XXX;
1610
 
 
1611
 
 If there is a group Everyone allow entry with permissions YYY,
1612
 
 convert the group1 entry to an allow entry and modify its
1613
 
 permissions to be :
1614
 
 
1615
 
 new_perms = YYY & ~ XXX
1616
 
 
1617
 
 and push to the end of the list.
1618
 
 
1619
 
 If there is no group Everyone allow entry then convert the
1620
 
 group1 entry to a allow nothing entry and push to the end of the list.
1621
 
 
1622
 
 Note that the common case from the NT ACL choser (groupX deny all)
1623
 
 cannot be optimised here as we need to modify user entries who are
1624
 
 in the group to change them to a deny all also.
1625
 
 
1626
 
 What we're doing here is modifying the allow permissions of
1627
 
 user entries (which are more specific in POSIX ACLs) to mask
1628
 
 out the explicit deny set on the group they are in. This will
1629
 
 be a snapshot depending on current group membership but is the
1630
 
 best we can do and has the advantage of failing closed rather
1631
 
 than open.
1632
 
 ---------------------------------------------------------------------------
1633
 
 Fourth pass - cope with cumulative permissions.
1634
 
 
1635
 
 for all allow user entries, if there exists an allow group entry with
1636
 
 more permissive permissions, and the user is in that group, rewrite the
1637
 
 allow user permissions to contain both sets of permissions.
1638
 
 
1639
 
 Currently the code for this is #ifdef'ed out as these semantics make
1640
 
 no sense to me. JRA.
1641
 
 ---------------------------------------------------------------------------
1642
 
 
1643
 
 Note we *MUST* do the deny user pass first as this will convert deny user
1644
 
 entries into allow user entries which can then be processed by the deny
1645
 
 group pass.
1646
 
 
1647
 
 The above algorithm took a *lot* of thinking about - hence this
1648
 
 explaination :-). JRA.
1649
 
****************************************************************************/
1650
 
 
1651
 
/****************************************************************************
1652
 
 Process a canon_ace list entries. This is very complex code. We need
1653
 
 to go through and remove the "deny" permissions from any allow entry that matches
1654
 
 the id of this entry. We have already refused any NT ACL that wasn't in correct
1655
 
 order (DENY followed by ALLOW). If any allow entry ends up with zero permissions,
1656
 
 we just remove it (to fail safe). We have already removed any duplicate ace
1657
 
 entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all
1658
 
 allow entries.
1659
 
****************************************************************************/
1660
 
 
1661
 
static void process_deny_list( canon_ace **pp_ace_list )
1662
 
{
1663
 
        canon_ace *ace_list = *pp_ace_list;
1664
 
        canon_ace *curr_ace = NULL;
1665
 
        canon_ace *curr_ace_next = NULL;
1666
 
 
1667
 
        /* Pass 1 above - look for an Everyone, deny entry. */
1668
 
 
1669
 
        for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1670
 
                canon_ace *allow_ace_p;
1671
 
 
1672
 
                curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1673
 
 
1674
 
                if (curr_ace->attr != DENY_ACE)
1675
 
                        continue;
1676
 
 
1677
 
                if (curr_ace->perms == (mode_t)0) {
1678
 
 
1679
 
                        /* Deny nothing entry - delete. */
1680
 
 
1681
 
                        DLIST_REMOVE(ace_list, curr_ace);
1682
 
                        continue;
1683
 
                }
1684
 
 
1685
 
                if (!sid_equal(&curr_ace->trustee, &global_sid_World))
1686
 
                        continue;
1687
 
 
1688
 
                /* JRATEST - assert. */
1689
 
                SMB_ASSERT(curr_ace->owner_type == WORLD_ACE);
1690
 
 
1691
 
                if (curr_ace->perms == ALL_ACE_PERMS) {
1692
 
 
1693
 
                        /*
1694
 
                         * Optimisation. This is a DENY_ALL to Everyone. Truncate the
1695
 
                         * list at this point including this entry.
1696
 
                         */
1697
 
 
1698
 
                        canon_ace *prev_entry = curr_ace->prev;
1699
 
 
1700
 
                        free_canon_ace_list( curr_ace );
1701
 
                        if (prev_entry)
1702
 
                                prev_entry->next = NULL;
1703
 
                        else {
1704
 
                                /* We deleted the entire list. */
1705
 
                                ace_list = NULL;
1706
 
                        }
1707
 
                        break;
1708
 
                }
1709
 
 
1710
 
                for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1711
 
 
1712
 
                        /* 
1713
 
                         * Only mask off allow entries.
1714
 
                         */
1715
 
 
1716
 
                        if (allow_ace_p->attr != ALLOW_ACE)
1717
 
                                continue;
1718
 
 
1719
 
                        allow_ace_p->perms &= ~curr_ace->perms;
1720
 
                }
1721
 
 
1722
 
                /*
1723
 
                 * Now it's been applied, remove it.
1724
 
                 */
1725
 
 
1726
 
                DLIST_REMOVE(ace_list, curr_ace);
1727
 
        }
1728
 
 
1729
 
        /* Pass 2 above - deal with deny user entries. */
1730
 
 
1731
 
        for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1732
 
                mode_t new_perms = (mode_t)0;
1733
 
                canon_ace *allow_ace_p;
1734
 
                canon_ace *tmp_ace;
1735
 
 
1736
 
                curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1737
 
 
1738
 
                if (curr_ace->attr != DENY_ACE)
1739
 
                        continue;
1740
 
 
1741
 
                if (curr_ace->owner_type != UID_ACE)
1742
 
                        continue;
1743
 
 
1744
 
                if (curr_ace->perms == ALL_ACE_PERMS) {
1745
 
 
1746
 
                        /*
1747
 
                         * Optimisation - this is a deny everything to this user.
1748
 
                         * Convert to an allow nothing and push to the end of the list.
1749
 
                         */
1750
 
 
1751
 
                        curr_ace->attr = ALLOW_ACE;
1752
 
                        curr_ace->perms = (mode_t)0;
1753
 
                        DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1754
 
                        continue;
1755
 
                }
1756
 
 
1757
 
                for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1758
 
 
1759
 
                        if (allow_ace_p->attr != ALLOW_ACE)
1760
 
                                continue;
1761
 
 
1762
 
                        /* We process GID_ACE and WORLD_ACE entries only. */
1763
 
 
1764
 
                        if (allow_ace_p->owner_type == UID_ACE)
1765
 
                                continue;
1766
 
 
1767
 
                        if (uid_entry_in_group( curr_ace, allow_ace_p))
1768
 
                                new_perms |= allow_ace_p->perms;
1769
 
                }
1770
 
 
1771
 
                /*
1772
 
                 * Convert to a allow entry, modify the perms and push to the end
1773
 
                 * of the list.
1774
 
                 */
1775
 
 
1776
 
                curr_ace->attr = ALLOW_ACE;
1777
 
                curr_ace->perms = (new_perms & ~curr_ace->perms);
1778
 
                DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1779
 
        }
1780
 
 
1781
 
        /* Pass 3 above - deal with deny group entries. */
1782
 
 
1783
 
        for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1784
 
                canon_ace *tmp_ace;
1785
 
                canon_ace *allow_ace_p;
1786
 
                canon_ace *allow_everyone_p = NULL;
1787
 
 
1788
 
                curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1789
 
 
1790
 
                if (curr_ace->attr != DENY_ACE)
1791
 
                        continue;
1792
 
 
1793
 
                if (curr_ace->owner_type != GID_ACE)
1794
 
                        continue;
1795
 
 
1796
 
                for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1797
 
 
1798
 
                        if (allow_ace_p->attr != ALLOW_ACE)
1799
 
                                continue;
1800
 
 
1801
 
                        /* Store a pointer to the Everyone allow, if it exists. */
1802
 
                        if (allow_ace_p->owner_type == WORLD_ACE)
1803
 
                                allow_everyone_p = allow_ace_p;
1804
 
 
1805
 
                        /* We process UID_ACE entries only. */
1806
 
 
1807
 
                        if (allow_ace_p->owner_type != UID_ACE)
1808
 
                                continue;
1809
 
 
1810
 
                        /* Mask off the deny group perms. */
1811
 
 
1812
 
                        if (uid_entry_in_group( allow_ace_p, curr_ace))
1813
 
                                allow_ace_p->perms &= ~curr_ace->perms;
1814
 
                }
1815
 
 
1816
 
                /*
1817
 
                 * Convert the deny to an allow with the correct perms and
1818
 
                 * push to the end of the list.
1819
 
                 */
1820
 
 
1821
 
                curr_ace->attr = ALLOW_ACE;
1822
 
                if (allow_everyone_p)
1823
 
                        curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms;
1824
 
                else
1825
 
                        curr_ace->perms = (mode_t)0;
1826
 
                DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1827
 
 
1828
 
        }
1829
 
 
1830
 
        /* Doing this fourth pass allows Windows semantics to be layered
1831
 
         * on top of POSIX semantics. I'm not sure if this is desirable.
1832
 
         * For example, in W2K ACLs there is no way to say, "Group X no
1833
 
         * access, user Y full access" if user Y is a member of group X.
1834
 
         * This seems completely broken semantics to me.... JRA.
1835
 
         */
1836
 
 
1837
 
#if 0
1838
 
        /* Pass 4 above - deal with allow entries. */
1839
 
 
1840
 
        for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1841
 
                canon_ace *allow_ace_p;
1842
 
 
1843
 
                curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1844
 
 
1845
 
                if (curr_ace->attr != ALLOW_ACE)
1846
 
                        continue;
1847
 
 
1848
 
                if (curr_ace->owner_type != UID_ACE)
1849
 
                        continue;
1850
 
 
1851
 
                for (allow_ace_p = ace_list; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1852
 
 
1853
 
                        if (allow_ace_p->attr != ALLOW_ACE)
1854
 
                                continue;
1855
 
 
1856
 
                        /* We process GID_ACE entries only. */
1857
 
 
1858
 
                        if (allow_ace_p->owner_type != GID_ACE)
1859
 
                                continue;
1860
 
 
1861
 
                        /* OR in the group perms. */
1862
 
 
1863
 
                        if (uid_entry_in_group( curr_ace, allow_ace_p))
1864
 
                                curr_ace->perms |= allow_ace_p->perms;
1865
 
                }
1866
 
        }
1867
 
#endif
1868
 
 
1869
 
        *pp_ace_list = ace_list;
1870
 
}
1871
 
 
1872
 
/****************************************************************************
1873
 
 Create a default mode that will be used if a security descriptor entry has
1874
 
 no user/group/world entries.
1875
 
****************************************************************************/
1876
 
 
1877
 
static mode_t create_default_mode(files_struct *fsp, BOOL interitable_mode)
1878
 
{
1879
 
        int snum = SNUM(fsp->conn);
1880
 
        mode_t and_bits = (mode_t)0;
1881
 
        mode_t or_bits = (mode_t)0;
1882
 
        mode_t mode = interitable_mode ? unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name, False) : S_IRUSR;
1883
 
 
1884
 
        if (fsp->is_directory)
1885
 
                mode |= (S_IWUSR|S_IXUSR);
1886
 
 
1887
 
        /*
1888
 
         * Now AND with the create mode/directory mode bits then OR with the
1889
 
         * force create mode/force directory mode bits.
1890
 
         */
1891
 
 
1892
 
        if (fsp->is_directory) {
1893
 
                and_bits = lp_dir_security_mask(snum);
1894
 
                or_bits = lp_force_dir_security_mode(snum);
1895
 
        } else {
1896
 
                and_bits = lp_security_mask(snum);
1897
 
                or_bits = lp_force_security_mode(snum);
1898
 
        }
1899
 
 
1900
 
        return ((mode & and_bits)|or_bits);
1901
 
}
1902
 
 
1903
 
/****************************************************************************
1904
 
 Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
1905
 
 succeeding.
1906
 
****************************************************************************/
1907
 
 
1908
 
static BOOL unpack_canon_ace(files_struct *fsp, 
1909
 
                                                        SMB_STRUCT_STAT *pst,
1910
 
                                                        DOM_SID *pfile_owner_sid,
1911
 
                                                        DOM_SID *pfile_grp_sid,
1912
 
                                                        canon_ace **ppfile_ace, canon_ace **ppdir_ace,
1913
 
                                                        uint32 security_info_sent, SEC_DESC *psd)
1914
 
{
1915
 
        canon_ace *file_ace = NULL;
1916
 
        canon_ace *dir_ace = NULL;
1917
 
 
1918
 
        *ppfile_ace = NULL;
1919
 
        *ppdir_ace = NULL;
1920
 
 
1921
 
        if(security_info_sent == 0) {
1922
 
                DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
1923
 
                return False;
1924
 
        }
1925
 
 
1926
 
        /*
1927
 
         * If no DACL then this is a chown only security descriptor.
1928
 
         */
1929
 
 
1930
 
        if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !psd->dacl)
1931
 
                return True;
1932
 
 
1933
 
        /*
1934
 
         * Now go through the DACL and create the canon_ace lists.
1935
 
         */
1936
 
 
1937
 
        if (!create_canon_ace_lists( fsp, pst, pfile_owner_sid, pfile_grp_sid,
1938
 
                                                                &file_ace, &dir_ace, psd->dacl))
1939
 
                return False;
1940
 
 
1941
 
        if ((file_ace == NULL) && (dir_ace == NULL)) {
1942
 
                /* W2K traverse DACL set - ignore. */
1943
 
                return True;
1944
 
        }
1945
 
 
1946
 
        /*
1947
 
         * Go through the canon_ace list and merge entries
1948
 
         * belonging to identical users of identical allow or deny type.
1949
 
         * We can do this as all deny entries come first, followed by
1950
 
         * all allow entries (we have mandated this before accepting this acl).
1951
 
         */
1952
 
 
1953
 
        print_canon_ace_list( "file ace - before merge", file_ace);
1954
 
        merge_aces( &file_ace );
1955
 
 
1956
 
        print_canon_ace_list( "dir ace - before merge", dir_ace);
1957
 
        merge_aces( &dir_ace );
1958
 
 
1959
 
        /*
1960
 
         * NT ACLs are order dependent. Go through the acl lists and
1961
 
         * process DENY entries by masking the allow entries.
1962
 
         */
1963
 
 
1964
 
        print_canon_ace_list( "file ace - before deny", file_ace);
1965
 
        process_deny_list( &file_ace);
1966
 
 
1967
 
        print_canon_ace_list( "dir ace - before deny", dir_ace);
1968
 
        process_deny_list( &dir_ace);
1969
 
 
1970
 
        /*
1971
 
         * A well formed POSIX file or default ACL has at least 3 entries, a 
1972
 
         * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
1973
 
         * and optionally a mask entry. Ensure this is the case.
1974
 
         */
1975
 
 
1976
 
        print_canon_ace_list( "file ace - before valid", file_ace);
1977
 
 
1978
 
        /*
1979
 
         * A default 3 element mode entry for a file should be r-- --- ---.
1980
 
         * A default 3 element mode entry for a directory should be rwx --- ---.
1981
 
         */
1982
 
 
1983
 
        pst->st_mode = create_default_mode(fsp, False);
1984
 
 
1985
 
        if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
1986
 
                free_canon_ace_list(file_ace);
1987
 
                free_canon_ace_list(dir_ace);
1988
 
                return False;
1989
 
        }
1990
 
 
1991
 
        print_canon_ace_list( "dir ace - before valid", dir_ace);
1992
 
 
1993
 
        /*
1994
 
         * A default inheritable 3 element mode entry for a directory should be the
1995
 
         * mode Samba will use to create a file within. Ensure user rwx bits are set if
1996
 
         * it's a directory.
1997
 
         */
1998
 
 
1999
 
        pst->st_mode = create_default_mode(fsp, True);
2000
 
 
2001
 
        if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
2002
 
                free_canon_ace_list(file_ace);
2003
 
                free_canon_ace_list(dir_ace);
2004
 
                return False;
2005
 
        }
2006
 
 
2007
 
        print_canon_ace_list( "file ace - return", file_ace);
2008
 
        print_canon_ace_list( "dir ace - return", dir_ace);
2009
 
 
2010
 
        *ppfile_ace = file_ace;
2011
 
        *ppdir_ace = dir_ace;
2012
 
        return True;
2013
 
 
2014
 
}
2015
 
 
2016
 
/******************************************************************************
2017
 
 When returning permissions, try and fit NT display
2018
 
 semantics if possible. Note the the canon_entries here must have been malloced.
2019
 
 The list format should be - first entry = owner, followed by group and other user
2020
 
 entries, last entry = other.
2021
 
 
2022
 
 Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries
2023
 
 are not ordered, and match on the most specific entry rather than walking a list,
2024
 
 then a simple POSIX permission of rw-r--r-- should really map to 5 entries,
2025
 
 
2026
 
 Entry 0: owner : deny all except read and write.
2027
 
 Entry 1: owner : allow read and write.
2028
 
 Entry 2: group : deny all except read.
2029
 
 Entry 3: group : allow read.
2030
 
 Entry 4: Everyone : allow read.
2031
 
 
2032
 
 But NT cannot display this in their ACL editor !
2033
 
********************************************************************************/
2034
 
 
2035
 
static void arrange_posix_perms( char *filename, canon_ace **pp_list_head)
2036
 
{
2037
 
        canon_ace *list_head = *pp_list_head;
2038
 
        canon_ace *owner_ace = NULL;
2039
 
        canon_ace *other_ace = NULL;
2040
 
        canon_ace *ace = NULL;
2041
 
 
2042
 
        for (ace = list_head; ace; ace = ace->next) {
2043
 
                if (ace->type == SMB_ACL_USER_OBJ)
2044
 
                        owner_ace = ace;
2045
 
                else if (ace->type == SMB_ACL_OTHER) {
2046
 
                        /* Last ace - this is "other" */
2047
 
                        other_ace = ace;
2048
 
                }
2049
 
        }
2050
 
                
2051
 
        if (!owner_ace || !other_ace) {
2052
 
                DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n",
2053
 
                        filename ));
2054
 
                return;
2055
 
        }
2056
 
 
2057
 
        /*
2058
 
         * The POSIX algorithm applies to owner first, and other last,
2059
 
         * so ensure they are arranged in this order.
2060
 
         */
2061
 
 
2062
 
        if (owner_ace) {
2063
 
                DLIST_PROMOTE(list_head, owner_ace);
2064
 
        }
2065
 
 
2066
 
        if (other_ace) {
2067
 
                DLIST_DEMOTE(list_head, other_ace, ace);
2068
 
        }
2069
 
 
2070
 
        /* We have probably changed the head of the list. */
2071
 
 
2072
 
        *pp_list_head = list_head;
2073
 
}
2074
 
                
2075
 
/****************************************************************************
2076
 
 Create a linked list of canonical ACE entries.
2077
 
****************************************************************************/
2078
 
 
2079
 
static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf,
2080
 
                                        const DOM_SID *powner, const DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type)
2081
 
{
2082
 
        connection_struct *conn = fsp->conn;
2083
 
        mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
2084
 
        canon_ace *list_head = NULL;
2085
 
        canon_ace *ace = NULL;
2086
 
        canon_ace *next_ace = NULL;
2087
 
        int entry_id = SMB_ACL_FIRST_ENTRY;
2088
 
        SMB_ACL_ENTRY_T entry;
2089
 
        size_t ace_count;
2090
 
 
2091
 
        while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
2092
 
                SMB_ACL_TAG_T tagtype;
2093
 
                SMB_ACL_PERMSET_T permset;
2094
 
                DOM_SID sid;
2095
 
                posix_id unix_ug;
2096
 
                enum ace_owner owner_type;
2097
 
 
2098
 
                /* get_next... */
2099
 
                if (entry_id == SMB_ACL_FIRST_ENTRY)
2100
 
                        entry_id = SMB_ACL_NEXT_ENTRY;
2101
 
 
2102
 
                /* Is this a MASK entry ? */
2103
 
                if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
2104
 
                        continue;
2105
 
 
2106
 
                if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
2107
 
                        continue;
2108
 
 
2109
 
                /* Decide which SID to use based on the ACL type. */
2110
 
                switch(tagtype) {
2111
 
                        case SMB_ACL_USER_OBJ:
2112
 
                                /* Get the SID from the owner. */
2113
 
                                sid_copy(&sid, powner);
2114
 
                                unix_ug.uid = psbuf->st_uid;
2115
 
                                owner_type = UID_ACE;
2116
 
                                break;
2117
 
                        case SMB_ACL_USER:
2118
 
                                {
2119
 
                                        uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
2120
 
                                        if (puid == NULL) {
2121
 
                                                DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
2122
 
                                                continue;
2123
 
                                        }
2124
 
                                        /*
2125
 
                                         * A SMB_ACL_USER entry for the owner is shadowed by the
2126
 
                                         * SMB_ACL_USER_OBJ entry and Windows also cannot represent
2127
 
                                         * that entry, so we ignore it. We also don't create such
2128
 
                                         * entries out of the blue when setting ACLs, so a get/set
2129
 
                                         * cycle will drop them.
2130
 
                                         */
2131
 
                                        if (the_acl_type == SMB_ACL_TYPE_ACCESS && *puid == psbuf->st_uid) {
2132
 
                                                SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
2133
 
                                                continue;
2134
 
                                        }
2135
 
                                        uid_to_sid( &sid, *puid);
2136
 
                                        unix_ug.uid = *puid;
2137
 
                                        owner_type = UID_ACE;
2138
 
                                        SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
2139
 
                                        break;
2140
 
                                }
2141
 
                        case SMB_ACL_GROUP_OBJ:
2142
 
                                /* Get the SID from the owning group. */
2143
 
                                sid_copy(&sid, pgroup);
2144
 
                                unix_ug.gid = psbuf->st_gid;
2145
 
                                owner_type = GID_ACE;
2146
 
                                break;
2147
 
                        case SMB_ACL_GROUP:
2148
 
                                {
2149
 
                                        gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
2150
 
                                        if (pgid == NULL) {
2151
 
                                                DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
2152
 
                                                continue;
2153
 
                                        }
2154
 
                                        gid_to_sid( &sid, *pgid);
2155
 
                                        unix_ug.gid = *pgid;
2156
 
                                        owner_type = GID_ACE;
2157
 
                                        SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
2158
 
                                        break;
2159
 
                                }
2160
 
                        case SMB_ACL_MASK:
2161
 
                                acl_mask = convert_permset_to_mode_t(conn, permset);
2162
 
                                continue; /* Don't count the mask as an entry. */
2163
 
                        case SMB_ACL_OTHER:
2164
 
                                /* Use the Everyone SID */
2165
 
                                sid = global_sid_World;
2166
 
                                unix_ug.world = -1;
2167
 
                                owner_type = WORLD_ACE;
2168
 
                                break;
2169
 
                        default:
2170
 
                                DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
2171
 
                                continue;
2172
 
                }
2173
 
 
2174
 
                /*
2175
 
                 * Add this entry to the list.
2176
 
                 */
2177
 
 
2178
 
                if ((ace = SMB_MALLOC_P(canon_ace)) == NULL)
2179
 
                        goto fail;
2180
 
 
2181
 
                ZERO_STRUCTP(ace);
2182
 
                ace->type = tagtype;
2183
 
                ace->perms = convert_permset_to_mode_t(conn, permset);
2184
 
                ace->attr = ALLOW_ACE;
2185
 
                ace->trustee = sid;
2186
 
                ace->unix_ug = unix_ug;
2187
 
                ace->owner_type = owner_type;
2188
 
                ace->inherited = get_inherited_flag(pal, ace, (the_acl_type == SMB_ACL_TYPE_DEFAULT));
2189
 
 
2190
 
                DLIST_ADD(list_head, ace);
2191
 
        }
2192
 
 
2193
 
        /*
2194
 
         * This next call will ensure we have at least a user/group/world set.
2195
 
         */
2196
 
 
2197
 
        if (!ensure_canon_entry_valid(&list_head, fsp, powner, pgroup, psbuf, False))
2198
 
                goto fail;
2199
 
 
2200
 
        /*
2201
 
         * Now go through the list, masking the permissions with the
2202
 
         * acl_mask. Ensure all DENY Entries are at the start of the list.
2203
 
         */
2204
 
 
2205
 
        DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", the_acl_type == SMB_ACL_TYPE_ACCESS ? "Access" : "Default" ));
2206
 
 
2207
 
        for ( ace_count = 0, ace = list_head; ace; ace = next_ace, ace_count++) {
2208
 
                next_ace = ace->next;
2209
 
 
2210
 
                /* Masks are only applied to entries other than USER_OBJ and OTHER. */
2211
 
                if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
2212
 
                        ace->perms &= acl_mask;
2213
 
 
2214
 
                if (ace->perms == 0) {
2215
 
                        DLIST_PROMOTE(list_head, ace);
2216
 
                }
2217
 
 
2218
 
                if( DEBUGLVL( 10 ) ) {
2219
 
                        print_canon_ace(ace, ace_count);
2220
 
                }
2221
 
        }
2222
 
 
2223
 
        arrange_posix_perms(fsp->fsp_name,&list_head );
2224
 
 
2225
 
        print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head );
2226
 
 
2227
 
        return list_head;
2228
 
 
2229
 
  fail:
2230
 
 
2231
 
        free_canon_ace_list(list_head);
2232
 
        return NULL;
2233
 
}
2234
 
 
2235
 
/****************************************************************************
2236
 
 Check if the current user group list contains a given group.
2237
 
****************************************************************************/
2238
 
 
2239
 
static BOOL current_user_in_group(gid_t gid)
2240
 
{
2241
 
        int i;
2242
 
 
2243
 
        for (i = 0; i < current_user.ut.ngroups; i++) {
2244
 
                if (current_user.ut.groups[i] == gid) {
2245
 
                        return True;
2246
 
                }
2247
 
        }
2248
 
 
2249
 
        return False;
2250
 
}
2251
 
 
2252
 
/****************************************************************************
2253
 
 Should we override a deny ?  Check deprecated 'acl group control'
2254
 
 and 'dos filemode'
2255
 
****************************************************************************/
2256
 
 
2257
 
static BOOL acl_group_override(connection_struct *conn, gid_t prim_gid)
2258
 
{
2259
 
        if ( (errno == EACCES || errno == EPERM) 
2260
 
                && (lp_acl_group_control(SNUM(conn) || lp_dos_filemode(SNUM(conn)))) 
2261
 
                && current_user_in_group(prim_gid) ) 
2262
 
        {
2263
 
                return True;
2264
 
        } 
2265
 
 
2266
 
        return False;
2267
 
}
2268
 
 
2269
 
/****************************************************************************
2270
 
 Attempt to apply an ACL to a file or directory.
2271
 
****************************************************************************/
2272
 
 
2273
 
static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, gid_t prim_gid, BOOL *pacl_set_support)
2274
 
{
2275
 
        connection_struct *conn = fsp->conn;
2276
 
        BOOL ret = False;
2277
 
        SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, (int)count_canon_ace_list(the_ace) + 1);
2278
 
        canon_ace *p_ace;
2279
 
        int i;
2280
 
        SMB_ACL_ENTRY_T mask_entry;
2281
 
        BOOL got_mask_entry = False;
2282
 
        SMB_ACL_PERMSET_T mask_permset;
2283
 
        SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
2284
 
        BOOL needs_mask = False;
2285
 
        mode_t mask_perms = 0;
2286
 
 
2287
 
#if defined(POSIX_ACL_NEEDS_MASK)
2288
 
        /* HP-UX always wants to have a mask (called "class" there). */
2289
 
        needs_mask = True;
2290
 
#endif
2291
 
 
2292
 
        if (the_acl == NULL) {
2293
 
 
2294
 
                if (!no_acl_syscall_error(errno)) {
2295
 
                        /*
2296
 
                         * Only print this error message if we have some kind of ACL
2297
 
                         * support that's not working. Otherwise we would always get this.
2298
 
                         */
2299
 
                        DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
2300
 
                                default_ace ? "default" : "file", strerror(errno) ));
2301
 
                }
2302
 
                *pacl_set_support = False;
2303
 
                return False;
2304
 
        }
2305
 
 
2306
 
        if( DEBUGLVL( 10 )) {
2307
 
                dbgtext("set_canon_ace_list: setting ACL:\n");
2308
 
                for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2309
 
                        print_canon_ace( p_ace, i);
2310
 
                }
2311
 
        }
2312
 
 
2313
 
        for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2314
 
                SMB_ACL_ENTRY_T the_entry;
2315
 
                SMB_ACL_PERMSET_T the_permset;
2316
 
 
2317
 
                /*
2318
 
                 * ACLs only "need" an ACL_MASK entry if there are any named user or
2319
 
                 * named group entries. But if there is an ACL_MASK entry, it applies
2320
 
                 * to ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. Set the mask
2321
 
                 * so that it doesn't deny (i.e., mask off) any permissions.
2322
 
                 */
2323
 
 
2324
 
                if (p_ace->type == SMB_ACL_USER || p_ace->type == SMB_ACL_GROUP) {
2325
 
                        needs_mask = True;
2326
 
                        mask_perms |= p_ace->perms;
2327
 
                } else if (p_ace->type == SMB_ACL_GROUP_OBJ) {
2328
 
                        mask_perms |= p_ace->perms;
2329
 
                }
2330
 
 
2331
 
                /*
2332
 
                 * Get the entry for this ACE.
2333
 
                 */
2334
 
 
2335
 
                if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
2336
 
                        DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
2337
 
                                i, strerror(errno) ));
2338
 
                        goto fail;
2339
 
                }
2340
 
 
2341
 
                if (p_ace->type == SMB_ACL_MASK) {
2342
 
                        mask_entry = the_entry;
2343
 
                        got_mask_entry = True;
2344
 
                }
2345
 
 
2346
 
                /*
2347
 
                 * Ok - we now know the ACL calls should be working, don't
2348
 
                 * allow fallback to chmod.
2349
 
                 */
2350
 
 
2351
 
                *pacl_set_support = True;
2352
 
 
2353
 
                /*
2354
 
                 * Initialise the entry from the canon_ace.
2355
 
                 */
2356
 
 
2357
 
                /*
2358
 
                 * First tell the entry what type of ACE this is.
2359
 
                 */
2360
 
 
2361
 
                if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, p_ace->type) == -1) {
2362
 
                        DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
2363
 
                                i, strerror(errno) ));
2364
 
                        goto fail;
2365
 
                }
2366
 
 
2367
 
                /*
2368
 
                 * Only set the qualifier (user or group id) if the entry is a user
2369
 
                 * or group id ACE.
2370
 
                 */
2371
 
 
2372
 
                if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
2373
 
                        if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
2374
 
                                DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
2375
 
                                        i, strerror(errno) ));
2376
 
                                goto fail;
2377
 
                        }
2378
 
                }
2379
 
 
2380
 
                /*
2381
 
                 * Convert the mode_t perms in the canon_ace to a POSIX permset.
2382
 
                 */
2383
 
 
2384
 
                if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
2385
 
                        DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
2386
 
                                i, strerror(errno) ));
2387
 
                        goto fail;
2388
 
                }
2389
 
 
2390
 
                if (map_acl_perms_to_permset(conn, p_ace->perms, &the_permset) == -1) {
2391
 
                        DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
2392
 
                                (unsigned int)p_ace->perms, i, strerror(errno) ));
2393
 
                        goto fail;
2394
 
                }
2395
 
 
2396
 
                /*
2397
 
                 * ..and apply them to the entry.
2398
 
                 */
2399
 
 
2400
 
                if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
2401
 
                        DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
2402
 
                                i, strerror(errno) ));
2403
 
                        goto fail;
2404
 
                }
2405
 
 
2406
 
                if( DEBUGLVL( 10 ))
2407
 
                        print_canon_ace( p_ace, i);
2408
 
 
2409
 
        }
2410
 
 
2411
 
        if (needs_mask && !got_mask_entry) {
2412
 
                if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &mask_entry) == -1) {
2413
 
                        DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
2414
 
                        goto fail;
2415
 
                }
2416
 
 
2417
 
                if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, mask_entry, SMB_ACL_MASK) == -1) {
2418
 
                        DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
2419
 
                        goto fail;
2420
 
                }
2421
 
 
2422
 
                if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, mask_entry, &mask_permset) == -1) {
2423
 
                        DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
2424
 
                        goto fail;
2425
 
                }
2426
 
 
2427
 
                if (map_acl_perms_to_permset(conn, S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
2428
 
                        DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
2429
 
                        goto fail;
2430
 
                }
2431
 
 
2432
 
                if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, mask_entry, mask_permset) == -1) {
2433
 
                        DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
2434
 
                        goto fail;
2435
 
                }
2436
 
        }
2437
 
 
2438
 
        /*
2439
 
         * Check if the ACL is valid.
2440
 
         */
2441
 
 
2442
 
        if (SMB_VFS_SYS_ACL_VALID(conn, the_acl) == -1) {
2443
 
                DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n",
2444
 
                                the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
2445
 
                                strerror(errno) ));
2446
 
                goto fail;
2447
 
        }
2448
 
 
2449
 
        /*
2450
 
         * Finally apply it to the file or directory.
2451
 
         */
2452
 
 
2453
 
        if(default_ace || fsp->is_directory || fsp->fh->fd == -1) {
2454
 
                if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl) == -1) {
2455
 
                        /*
2456
 
                         * Some systems allow all the above calls and only fail with no ACL support
2457
 
                         * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2458
 
                         */
2459
 
                        if (no_acl_syscall_error(errno)) {
2460
 
                                *pacl_set_support = False;
2461
 
                        }
2462
 
 
2463
 
                        if (acl_group_override(conn, prim_gid)) {
2464
 
                                int sret;
2465
 
 
2466
 
                                DEBUG(5,("set_canon_ace_list: acl group control on and current user in file %s primary group.\n",
2467
 
                                        fsp->fsp_name ));
2468
 
 
2469
 
                                become_root();
2470
 
                                sret = SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl);
2471
 
                                unbecome_root();
2472
 
                                if (sret == 0) {
2473
 
                                        ret = True;     
2474
 
                                }
2475
 
                        }
2476
 
 
2477
 
                        if (ret == False) {
2478
 
                                DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
2479
 
                                                the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
2480
 
                                                fsp->fsp_name, strerror(errno) ));
2481
 
                                goto fail;
2482
 
                        }
2483
 
                }
2484
 
        } else {
2485
 
                if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, the_acl) == -1) {
2486
 
                        /*
2487
 
                         * Some systems allow all the above calls and only fail with no ACL support
2488
 
                         * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2489
 
                         */
2490
 
                        if (no_acl_syscall_error(errno)) {
2491
 
                                *pacl_set_support = False;
2492
 
                        }
2493
 
 
2494
 
                        if (acl_group_override(conn, prim_gid)) {
2495
 
                                int sret;
2496
 
 
2497
 
                                DEBUG(5,("set_canon_ace_list: acl group control on and current user in file %s primary group.\n",
2498
 
                                        fsp->fsp_name ));
2499
 
 
2500
 
                                become_root();
2501
 
                                sret = SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, the_acl);
2502
 
                                unbecome_root();
2503
 
                                if (sret == 0) {
2504
 
                                        ret = True;
2505
 
                                }
2506
 
                        }
2507
 
 
2508
 
                        if (ret == False) {
2509
 
                                DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
2510
 
                                                fsp->fsp_name, strerror(errno) ));
2511
 
                                goto fail;
2512
 
                        }
2513
 
                }
2514
 
        }
2515
 
 
2516
 
        ret = True;
2517
 
 
2518
 
  fail:
2519
 
 
2520
 
        if (the_acl != NULL) {
2521
 
                SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2522
 
        }
2523
 
 
2524
 
        return ret;
2525
 
}
2526
 
 
2527
 
/****************************************************************************
2528
 
 Find a particular canon_ace entry.
2529
 
****************************************************************************/
2530
 
 
2531
 
static struct canon_ace *canon_ace_entry_for(struct canon_ace *list, SMB_ACL_TAG_T type, posix_id *id)
2532
 
{
2533
 
        while (list) {
2534
 
                if (list->type == type && ((type != SMB_ACL_USER && type != SMB_ACL_GROUP) ||
2535
 
                                (type == SMB_ACL_USER  && id && id->uid == list->unix_ug.uid) ||
2536
 
                                (type == SMB_ACL_GROUP && id && id->gid == list->unix_ug.gid)))
2537
 
                        break;
2538
 
                list = list->next;
2539
 
        }
2540
 
        return list;
2541
 
}
2542
 
 
2543
 
/****************************************************************************
2544
 
 
2545
 
****************************************************************************/
2546
 
 
2547
 
SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl)
2548
 
{
2549
 
        SMB_ACL_ENTRY_T entry;
2550
 
 
2551
 
        if (!the_acl)
2552
 
                return NULL;
2553
 
        if (SMB_VFS_SYS_ACL_GET_ENTRY(conn, the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
2554
 
                SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2555
 
                return NULL;
2556
 
        }
2557
 
        return the_acl;
2558
 
}
2559
 
 
2560
 
/****************************************************************************
2561
 
 Convert a canon_ace to a generic 3 element permission - if possible.
2562
 
****************************************************************************/
2563
 
 
2564
 
#define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
2565
 
 
2566
 
static BOOL convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
2567
 
{
2568
 
        int snum = SNUM(fsp->conn);
2569
 
        size_t ace_count = count_canon_ace_list(file_ace_list);
2570
 
        canon_ace *ace_p;
2571
 
        canon_ace *owner_ace = NULL;
2572
 
        canon_ace *group_ace = NULL;
2573
 
        canon_ace *other_ace = NULL;
2574
 
        mode_t and_bits;
2575
 
        mode_t or_bits;
2576
 
 
2577
 
        if (ace_count != 3) {
2578
 
                DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \
2579
 
posix perms.\n", fsp->fsp_name ));
2580
 
                return False;
2581
 
        }
2582
 
 
2583
 
        for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
2584
 
                if (ace_p->owner_type == UID_ACE)
2585
 
                        owner_ace = ace_p;
2586
 
                else if (ace_p->owner_type == GID_ACE)
2587
 
                        group_ace = ace_p;
2588
 
                else if (ace_p->owner_type == WORLD_ACE)
2589
 
                        other_ace = ace_p;
2590
 
        }
2591
 
 
2592
 
        if (!owner_ace || !group_ace || !other_ace) {
2593
 
                DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n",
2594
 
                                fsp->fsp_name ));
2595
 
                return False;
2596
 
        }
2597
 
 
2598
 
        *posix_perms = (mode_t)0;
2599
 
 
2600
 
        *posix_perms |= owner_ace->perms;
2601
 
        *posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP);
2602
 
        *posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP);
2603
 
        *posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP);
2604
 
        *posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH);
2605
 
        *posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH);
2606
 
        *posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH);
2607
 
 
2608
 
        /* The owner must have at least read access. */
2609
 
 
2610
 
        *posix_perms |= S_IRUSR;
2611
 
        if (fsp->is_directory)
2612
 
                *posix_perms |= (S_IWUSR|S_IXUSR);
2613
 
 
2614
 
        /* If requested apply the masks. */
2615
 
 
2616
 
        /* Get the initial bits to apply. */
2617
 
 
2618
 
        if (fsp->is_directory) {
2619
 
                and_bits = lp_dir_security_mask(snum);
2620
 
                or_bits = lp_force_dir_security_mode(snum);
2621
 
        } else {
2622
 
                and_bits = lp_security_mask(snum);
2623
 
                or_bits = lp_force_security_mode(snum);
2624
 
        }
2625
 
 
2626
 
        *posix_perms = (((*posix_perms) & and_bits)|or_bits);
2627
 
 
2628
 
        DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n",
2629
 
                (int)owner_ace->perms, (int)group_ace->perms, (int)other_ace->perms, (int)*posix_perms,
2630
 
                fsp->fsp_name ));
2631
 
 
2632
 
        return True;
2633
 
}
2634
 
 
2635
 
/****************************************************************************
2636
 
  Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and
2637
 
  a normal POSIX acl. Win2k needs these split acls re-merging into one ACL
2638
 
  with CI|OI set so it is inherited and also applies to the directory.
2639
 
  Based on code from "Jim McDonough" <jmcd@us.ibm.com>.
2640
 
****************************************************************************/
2641
 
 
2642
 
static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
2643
 
{
2644
 
        size_t i, j;
2645
 
 
2646
 
        for (i = 0; i < num_aces; i++) {
2647
 
                for (j = i+1; j < num_aces; j++) {
2648
 
                        uint32 i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
2649
 
                        uint32 j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
2650
 
                        BOOL i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
2651
 
                        BOOL j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
2652
 
 
2653
 
                        /* We know the lower number ACE's are file entries. */
2654
 
                        if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
2655
 
                                (nt_ace_list[i].size == nt_ace_list[j].size) &&
2656
 
                                (nt_ace_list[i].info.mask == nt_ace_list[j].info.mask) &&
2657
 
                                sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
2658
 
                                (i_inh == j_inh) &&
2659
 
                                (i_flags_ni == 0) &&
2660
 
                                (j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT|
2661
 
                                                  SEC_ACE_FLAG_CONTAINER_INHERIT|
2662
 
                                                  SEC_ACE_FLAG_INHERIT_ONLY))) {
2663
 
                                /*
2664
 
                                 * W2K wants to have access allowed zero access ACE's
2665
 
                                 * at the end of the list. If the mask is zero, merge
2666
 
                                 * the non-inherited ACE onto the inherited ACE.
2667
 
                                 */
2668
 
 
2669
 
                                if (nt_ace_list[i].info.mask == 0) {
2670
 
                                        nt_ace_list[j].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2671
 
                                                                (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2672
 
                                        if (num_aces - i - 1 > 0)
2673
 
                                                memmove(&nt_ace_list[i], &nt_ace_list[i+1], (num_aces-i-1) *
2674
 
                                                                sizeof(SEC_ACE));
2675
 
 
2676
 
                                        DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n",
2677
 
                                                (unsigned int)i, (unsigned int)j ));
2678
 
                                } else {
2679
 
                                        /*
2680
 
                                         * These are identical except for the flags.
2681
 
                                         * Merge the inherited ACE onto the non-inherited ACE.
2682
 
                                         */
2683
 
 
2684
 
                                        nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2685
 
                                                                (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2686
 
                                        if (num_aces - j - 1 > 0)
2687
 
                                                memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) *
2688
 
                                                                sizeof(SEC_ACE));
2689
 
 
2690
 
                                        DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n",
2691
 
                                                (unsigned int)j, (unsigned int)i ));
2692
 
                                }
2693
 
                                num_aces--;
2694
 
                                break;
2695
 
                        }
2696
 
                }
2697
 
        }
2698
 
 
2699
 
        return num_aces;
2700
 
}
2701
 
/****************************************************************************
2702
 
 Reply to query a security descriptor from an fsp. If it succeeds it allocates
2703
 
 the space for the return elements and returns the size needed to return the
2704
 
 security descriptor. This should be the only external function needed for
2705
 
 the UNIX style get ACL.
2706
 
****************************************************************************/
2707
 
 
2708
 
size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
2709
 
{
2710
 
        connection_struct *conn = fsp->conn;
2711
 
        SMB_STRUCT_STAT sbuf;
2712
 
        SEC_ACE *nt_ace_list = NULL;
2713
 
        DOM_SID owner_sid;
2714
 
        DOM_SID group_sid;
2715
 
        size_t sd_size = 0;
2716
 
        SEC_ACL *psa = NULL;
2717
 
        size_t num_acls = 0;
2718
 
        size_t num_def_acls = 0;
2719
 
        size_t num_aces = 0;
2720
 
        SMB_ACL_T posix_acl = NULL;
2721
 
        SMB_ACL_T def_acl = NULL;
2722
 
        canon_ace *file_ace = NULL;
2723
 
        canon_ace *dir_ace = NULL;
2724
 
        size_t num_profile_acls = 0;
2725
 
        struct pai_val *pal = NULL;
2726
 
        SEC_DESC *psd = NULL;
2727
 
 
2728
 
        *ppdesc = NULL;
2729
 
 
2730
 
        DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name ));
2731
 
 
2732
 
        if(fsp->is_directory || fsp->fh->fd == -1) {
2733
 
 
2734
 
                /* Get the stat struct for the owner info. */
2735
 
                if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
2736
 
                        return 0;
2737
 
                }
2738
 
                /*
2739
 
                 * Get the ACL from the path.
2740
 
                 */
2741
 
 
2742
 
                posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
2743
 
 
2744
 
                /*
2745
 
                 * If it's a directory get the default POSIX ACL.
2746
 
                 */
2747
 
 
2748
 
                if(fsp->is_directory) {
2749
 
                        def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
2750
 
                        def_acl = free_empty_sys_acl(conn, def_acl);
2751
 
                }
2752
 
 
2753
 
        } else {
2754
 
 
2755
 
                /* Get the stat struct for the owner info. */
2756
 
                if(SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) != 0) {
2757
 
                        return 0;
2758
 
                }
2759
 
                /*
2760
 
                 * Get the ACL from the fd.
2761
 
                 */
2762
 
                posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fh->fd);
2763
 
        }
2764
 
 
2765
 
        DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
2766
 
                        posix_acl ? "present" :  "absent",
2767
 
                        def_acl ? "present" :  "absent" ));
2768
 
 
2769
 
        pal = load_inherited_info(fsp);
2770
 
 
2771
 
        /*
2772
 
         * Get the owner, group and world SIDs.
2773
 
         */
2774
 
 
2775
 
        if (lp_profile_acls(SNUM(conn))) {
2776
 
                /* For WXP SP1 the owner must be administrators. */
2777
 
                sid_copy(&owner_sid, &global_sid_Builtin_Administrators);
2778
 
                sid_copy(&group_sid, &global_sid_Builtin_Users);
2779
 
                num_profile_acls = 2;
2780
 
        } else {
2781
 
                create_file_sids(&sbuf, &owner_sid, &group_sid);
2782
 
        }
2783
 
 
2784
 
        if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) {
2785
 
 
2786
 
                /*
2787
 
                 * In the optimum case Creator Owner and Creator Group would be used for
2788
 
                 * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this
2789
 
                 * would lead to usability problems under Windows: The Creator entries
2790
 
                 * are only available in browse lists of directories and not for files;
2791
 
                 * additionally the identity of the owning group couldn't be determined.
2792
 
                 * We therefore use those identities only for Default ACLs. 
2793
 
                 */
2794
 
 
2795
 
                /* Create the canon_ace lists. */
2796
 
                file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid, pal, SMB_ACL_TYPE_ACCESS );
2797
 
 
2798
 
                /* We must have *some* ACLS. */
2799
 
        
2800
 
                if (count_canon_ace_list(file_ace) == 0) {
2801
 
                        DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name ));
2802
 
                        goto done;
2803
 
                }
2804
 
 
2805
 
                if (fsp->is_directory && def_acl) {
2806
 
                        dir_ace = canonicalise_acl(fsp, def_acl, &sbuf,
2807
 
                                        &global_sid_Creator_Owner,
2808
 
                                        &global_sid_Creator_Group, pal, SMB_ACL_TYPE_DEFAULT );
2809
 
                }
2810
 
 
2811
 
                /*
2812
 
                 * Create the NT ACE list from the canonical ace lists.
2813
 
                 */
2814
 
 
2815
 
                {
2816
 
                        canon_ace *ace;
2817
 
                        int nt_acl_type;
2818
 
                        int i;
2819
 
 
2820
 
                        if (nt4_compatible_acls() && dir_ace) {
2821
 
                                /*
2822
 
                                 * NT 4 chokes if an ACL contains an INHERIT_ONLY entry
2823
 
                                 * but no non-INHERIT_ONLY entry for one SID. So we only
2824
 
                                 * remove entries from the Access ACL if the
2825
 
                                 * corresponding Default ACL entries have also been
2826
 
                                 * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP
2827
 
                                 * are exceptions. We can do nothing
2828
 
                                 * intelligent if the Default ACL contains entries that
2829
 
                                 * are not also contained in the Access ACL, so this
2830
 
                                 * case will still fail under NT 4.
2831
 
                                 */
2832
 
 
2833
 
                                ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL);
2834
 
                                if (ace && !ace->perms) {
2835
 
                                        DLIST_REMOVE(dir_ace, ace);
2836
 
                                        SAFE_FREE(ace);
2837
 
 
2838
 
                                        ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL);
2839
 
                                        if (ace && !ace->perms) {
2840
 
                                                DLIST_REMOVE(file_ace, ace);
2841
 
                                                SAFE_FREE(ace);
2842
 
                                        }
2843
 
                                }
2844
 
 
2845
 
                                /*
2846
 
                                 * WinNT doesn't usually have Creator Group
2847
 
                                 * in browse lists, so we send this entry to
2848
 
                                 * WinNT even if it contains no relevant
2849
 
                                 * permissions. Once we can add
2850
 
                                 * Creator Group to browse lists we can
2851
 
                                 * re-enable this.
2852
 
                                 */
2853
 
 
2854
 
#if 0
2855
 
                                ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL);
2856
 
                                if (ace && !ace->perms) {
2857
 
                                        DLIST_REMOVE(dir_ace, ace);
2858
 
                                        SAFE_FREE(ace);
2859
 
                                }
2860
 
#endif
2861
 
 
2862
 
                                ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL);
2863
 
                                if (ace && !ace->perms) {
2864
 
                                        DLIST_REMOVE(file_ace, ace);
2865
 
                                        SAFE_FREE(ace);
2866
 
                                }
2867
 
                        }
2868
 
 
2869
 
                        num_acls = count_canon_ace_list(file_ace);
2870
 
                        num_def_acls = count_canon_ace_list(dir_ace);
2871
 
 
2872
 
                        /* Allocate the ace list. */
2873
 
                        if ((nt_ace_list = SMB_MALLOC_ARRAY(SEC_ACE,num_acls + num_profile_acls + num_def_acls)) == NULL) {
2874
 
                                DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
2875
 
                                goto done;
2876
 
                        }
2877
 
 
2878
 
                        memset(nt_ace_list, '\0', (num_acls + num_def_acls) * sizeof(SEC_ACE) );
2879
 
                                                                                                        
2880
 
                        /*
2881
 
                         * Create the NT ACE list from the canonical ace lists.
2882
 
                         */
2883
 
        
2884
 
                        ace = file_ace;
2885
 
 
2886
 
                        for (i = 0; i < num_acls; i++, ace = ace->next) {
2887
 
                                SEC_ACCESS acc;
2888
 
 
2889
 
                                acc = map_canon_ace_perms(SNUM(conn), &nt_acl_type, &owner_sid, ace, fsp->is_directory);
2890
 
                                init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2891
 
                        }
2892
 
 
2893
 
                        /* The User must have access to a profile share - even if we can't map the SID. */
2894
 
                        if (lp_profile_acls(SNUM(conn))) {
2895
 
                                SEC_ACCESS acc;
2896
 
 
2897
 
                                init_sec_access(&acc,FILE_GENERIC_ALL);
2898
 
                                init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED,
2899
 
                                                acc, 0);
2900
 
                        }
2901
 
 
2902
 
                        ace = dir_ace;
2903
 
 
2904
 
                        for (i = 0; i < num_def_acls; i++, ace = ace->next) {
2905
 
                                SEC_ACCESS acc;
2906
 
        
2907
 
                                acc = map_canon_ace_perms(SNUM(conn), &nt_acl_type, &owner_sid, ace, fsp->is_directory);
2908
 
                                init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc,
2909
 
                                                SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2910
 
                                                SEC_ACE_FLAG_INHERIT_ONLY|
2911
 
                                                (ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0));
2912
 
                        }
2913
 
 
2914
 
                        /* The User must have access to a profile share - even if we can't map the SID. */
2915
 
                        if (lp_profile_acls(SNUM(conn))) {
2916
 
                                SEC_ACCESS acc;
2917
 
                        
2918
 
                                init_sec_access(&acc,FILE_GENERIC_ALL);
2919
 
                                init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc,
2920
 
                                                SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2921
 
                                                SEC_ACE_FLAG_INHERIT_ONLY|0);
2922
 
                        }
2923
 
 
2924
 
                        /*
2925
 
                         * Merge POSIX default ACLs and normal ACLs into one NT ACE.
2926
 
                         * Win2K needs this to get the inheritance correct when replacing ACLs
2927
 
                         * on a directory tree. Based on work by Jim @ IBM.
2928
 
                         */
2929
 
 
2930
 
                        num_aces = merge_default_aces(nt_ace_list, num_aces);
2931
 
 
2932
 
                }
2933
 
 
2934
 
                if (num_aces) {
2935
 
                        if((psa = make_sec_acl( main_loop_talloc_get(), NT4_ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
2936
 
                                DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
2937
 
                                goto done;
2938
 
                        }
2939
 
                }
2940
 
        } /* security_info & DACL_SECURITY_INFORMATION */
2941
 
 
2942
 
        psd = make_standard_sec_desc( main_loop_talloc_get(),
2943
 
                        (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL,
2944
 
                        (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL,
2945
 
                        psa,
2946
 
                        &sd_size);
2947
 
 
2948
 
        if(!psd) {
2949
 
                DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
2950
 
                sd_size = 0;
2951
 
                goto done;
2952
 
        }
2953
 
 
2954
 
        /*
2955
 
         * Windows 2000: The DACL_PROTECTED flag in the security
2956
 
         * descriptor marks the ACL as non-inheriting, i.e., no
2957
 
         * ACEs from higher level directories propagate to this
2958
 
         * ACL. In the POSIX ACL model permissions are only
2959
 
         * inherited at file create time, so ACLs never contain
2960
 
         * any ACEs that are inherited dynamically. The DACL_PROTECTED
2961
 
         * flag doesn't seem to bother Windows NT.
2962
 
         * Always set this if map acl inherit is turned off.
2963
 
         */
2964
 
        if (get_protected_flag(pal) || !lp_map_acl_inherit(SNUM(conn))) {
2965
 
                psd->type |= SE_DESC_DACL_PROTECTED;
2966
 
        }
2967
 
 
2968
 
        if (psd->dacl) {
2969
 
                dacl_sort_into_canonical_order(psd->dacl->ace, (unsigned int)psd->dacl->num_aces);
2970
 
        }
2971
 
 
2972
 
        *ppdesc = psd;
2973
 
 
2974
 
 done:
2975
 
 
2976
 
        if (posix_acl) {
2977
 
                SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
2978
 
        }
2979
 
        if (def_acl) {
2980
 
                SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
2981
 
        }
2982
 
        free_canon_ace_list(file_ace);
2983
 
        free_canon_ace_list(dir_ace);
2984
 
        free_inherited_info(pal);
2985
 
        SAFE_FREE(nt_ace_list);
2986
 
 
2987
 
        return sd_size;
2988
 
}
2989
 
 
2990
 
/****************************************************************************
2991
 
 Try to chown a file. We will be able to chown it under the following conditions.
2992
 
 
2993
 
  1) If we have root privileges, then it will just work.
2994
 
  2) If we have SeTakeOwnershipPrivilege we can change the user to the current user.
2995
 
  3) If we have SeRestorePrivilege we can change the user to any other user. 
2996
 
  4) If we have write permission to the file and dos_filemodes is set
2997
 
     then allow chown to the currently authenticated user.
2998
 
****************************************************************************/
2999
 
 
3000
 
static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
3001
 
{
3002
 
        int ret;
3003
 
        files_struct *fsp;
3004
 
        SMB_STRUCT_STAT st;
3005
 
 
3006
 
        if(!CAN_WRITE(conn)) {
3007
 
                return -1;
3008
 
        }
3009
 
 
3010
 
        /* Case (1). */
3011
 
        /* try the direct way first */
3012
 
        ret = SMB_VFS_CHOWN(conn, fname, uid, gid);
3013
 
        if (ret == 0)
3014
 
                return 0;
3015
 
 
3016
 
        /* Case (2) / (3) */
3017
 
        if (lp_enable_privileges()) {
3018
 
 
3019
 
                BOOL has_take_ownership_priv = user_has_privileges(current_user.nt_user_token,
3020
 
                                                              &se_take_ownership);
3021
 
                BOOL has_restore_priv = user_has_privileges(current_user.nt_user_token,
3022
 
                                                       &se_restore);
3023
 
 
3024
 
                /* Case (2) */
3025
 
                if ( ( has_take_ownership_priv && ( uid == current_user.ut.uid ) ) ||
3026
 
                /* Case (3) */
3027
 
                     ( has_restore_priv ) ) {
3028
 
 
3029
 
                        become_root();
3030
 
                        /* Keep the current file gid the same - take ownership doesn't imply group change. */
3031
 
                        ret = SMB_VFS_CHOWN(conn, fname, uid, (gid_t)-1);
3032
 
                        unbecome_root();
3033
 
                        return ret;
3034
 
                }
3035
 
        }
3036
 
 
3037
 
        /* Case (4). */
3038
 
        if (!lp_dos_filemode(SNUM(conn))) {
3039
 
                return -1;
3040
 
        }
3041
 
 
3042
 
        if (SMB_VFS_STAT(conn,fname,&st)) {
3043
 
                return -1;
3044
 
        }
3045
 
 
3046
 
        if (!NT_STATUS_IS_OK(open_file_fchmod(conn,fname,&st,&fsp))) {
3047
 
                return -1;
3048
 
        }
3049
 
 
3050
 
        /* only allow chown to the current user. This is more secure,
3051
 
           and also copes with the case where the SID in a take ownership ACL is
3052
 
           a local SID on the users workstation 
3053
 
        */
3054
 
        uid = current_user.ut.uid;
3055
 
 
3056
 
        become_root();
3057
 
        /* Keep the current file gid the same. */
3058
 
        ret = SMB_VFS_FCHOWN(fsp, fsp->fh->fd, uid, (gid_t)-1);
3059
 
        unbecome_root();
3060
 
 
3061
 
        close_file_fchmod(fsp);
3062
 
 
3063
 
        return ret;
3064
 
}
3065
 
 
3066
 
/****************************************************************************
3067
 
 Reply to set a security descriptor on an fsp. security_info_sent is the
3068
 
 description of the following NT ACL.
3069
 
 This should be the only external function needed for the UNIX style set ACL.
3070
 
****************************************************************************/
3071
 
 
3072
 
BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
3073
 
{
3074
 
        connection_struct *conn = fsp->conn;
3075
 
        uid_t user = (uid_t)-1;
3076
 
        gid_t grp = (gid_t)-1;
3077
 
        SMB_STRUCT_STAT sbuf;  
3078
 
        DOM_SID file_owner_sid;
3079
 
        DOM_SID file_grp_sid;
3080
 
        canon_ace *file_ace_list = NULL;
3081
 
        canon_ace *dir_ace_list = NULL;
3082
 
        BOOL acl_perms = False;
3083
 
        mode_t orig_mode = (mode_t)0;
3084
 
        uid_t orig_uid;
3085
 
        gid_t orig_gid;
3086
 
        BOOL need_chown = False;
3087
 
 
3088
 
        DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
3089
 
 
3090
 
        if (!CAN_WRITE(conn)) {
3091
 
                DEBUG(10,("set acl rejected on read-only share\n"));
3092
 
                return False;
3093
 
        }
3094
 
 
3095
 
        /*
3096
 
         * Get the current state of the file.
3097
 
         */
3098
 
 
3099
 
        if(fsp->is_directory || fsp->fh->fd == -1) {
3100
 
                if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0)
3101
 
                        return False;
3102
 
        } else {
3103
 
                if(SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) != 0)
3104
 
                        return False;
3105
 
        }
3106
 
 
3107
 
        /* Save the original elements we check against. */
3108
 
        orig_mode = sbuf.st_mode;
3109
 
        orig_uid = sbuf.st_uid;
3110
 
        orig_gid = sbuf.st_gid;
3111
 
 
3112
 
        /*
3113
 
         * Unpack the user/group/world id's.
3114
 
         */
3115
 
 
3116
 
        if (!unpack_nt_owners( SNUM(conn), &sbuf, &user, &grp, security_info_sent, psd)) {
3117
 
                return False;
3118
 
        }
3119
 
 
3120
 
        /*
3121
 
         * Do we need to chown ?
3122
 
         */
3123
 
 
3124
 
        if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp))) {
3125
 
                need_chown = True;
3126
 
        }
3127
 
 
3128
 
        /*
3129
 
         * Chown before setting ACL only if we don't change the user, or
3130
 
         * if we change to the current user, but not if we want to give away
3131
 
         * the file.
3132
 
         */
3133
 
 
3134
 
        if (need_chown && (user == (uid_t)-1 || user == current_user.ut.uid)) {
3135
 
 
3136
 
                DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3137
 
                                fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
3138
 
 
3139
 
                if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
3140
 
                        DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3141
 
                                fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
3142
 
                        return False;
3143
 
                }
3144
 
 
3145
 
                /*
3146
 
                 * Recheck the current state of the file, which may have changed.
3147
 
                 * (suid/sgid bits, for instance)
3148
 
                 */
3149
 
 
3150
 
                if(fsp->is_directory) {
3151
 
                        if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
3152
 
                                return False;
3153
 
                        }
3154
 
                } else {
3155
 
 
3156
 
                        int ret;
3157
 
    
3158
 
                        if(fsp->fh->fd == -1)
3159
 
                                ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf);
3160
 
                        else
3161
 
                                ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf);
3162
 
  
3163
 
                        if(ret != 0)
3164
 
                                return False;
3165
 
                }
3166
 
 
3167
 
                /* Save the original elements we check against. */
3168
 
                orig_mode = sbuf.st_mode;
3169
 
                orig_uid = sbuf.st_uid;
3170
 
                orig_gid = sbuf.st_gid;
3171
 
 
3172
 
                /* We did it, don't try again */
3173
 
                need_chown = False;
3174
 
        }
3175
 
 
3176
 
        create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
3177
 
 
3178
 
        acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
3179
 
                                        &file_ace_list, &dir_ace_list, security_info_sent, psd);
3180
 
 
3181
 
        /* Ignore W2K traverse DACL set. */
3182
 
        if (file_ace_list || dir_ace_list) {
3183
 
 
3184
 
                if (!acl_perms) {
3185
 
                        DEBUG(3,("set_nt_acl: cannot set permissions\n"));
3186
 
                        free_canon_ace_list(file_ace_list);
3187
 
                        free_canon_ace_list(dir_ace_list); 
3188
 
                        return False;
3189
 
                }
3190
 
 
3191
 
                /*
3192
 
                 * Only change security if we got a DACL.
3193
 
                 */
3194
 
 
3195
 
                if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
3196
 
 
3197
 
                        BOOL acl_set_support = False;
3198
 
                        BOOL ret = False;
3199
 
 
3200
 
                        /*
3201
 
                         * Try using the POSIX ACL set first. Fall back to chmod if
3202
 
                         * we have no ACL support on this filesystem.
3203
 
                         */
3204
 
 
3205
 
                        if (acl_perms && file_ace_list) {
3206
 
                                ret = set_canon_ace_list(fsp, file_ace_list, False, sbuf.st_gid, &acl_set_support);
3207
 
                                if (acl_set_support && ret == False) {
3208
 
                                        DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
3209
 
                                        free_canon_ace_list(file_ace_list);
3210
 
                                        free_canon_ace_list(dir_ace_list); 
3211
 
                                        return False;
3212
 
                                }
3213
 
                        }
3214
 
 
3215
 
                        if (acl_perms && acl_set_support && fsp->is_directory) {
3216
 
                                if (dir_ace_list) {
3217
 
                                        if (!set_canon_ace_list(fsp, dir_ace_list, True, sbuf.st_gid, &acl_set_support)) {
3218
 
                                                DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
3219
 
                                                free_canon_ace_list(file_ace_list);
3220
 
                                                free_canon_ace_list(dir_ace_list); 
3221
 
                                                return False;
3222
 
                                        }
3223
 
                                } else {
3224
 
 
3225
 
                                        /*
3226
 
                                         * No default ACL - delete one if it exists.
3227
 
                                         */
3228
 
 
3229
 
                                        if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name) == -1) {
3230
 
                                                int sret = -1;
3231
 
 
3232
 
                                                if (acl_group_override(conn, sbuf.st_gid)) {
3233
 
                                                        DEBUG(5,("set_nt_acl: acl group control on and "
3234
 
                                                                "current user in file %s primary group. Override delete_def_acl\n",
3235
 
                                                                fsp->fsp_name ));
3236
 
 
3237
 
                                                        become_root();
3238
 
                                                        sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name);
3239
 
                                                        unbecome_root();
3240
 
                                                }
3241
 
 
3242
 
                                                if (sret == -1) {
3243
 
                                                        DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
3244
 
                                                        free_canon_ace_list(file_ace_list);
3245
 
                                                        free_canon_ace_list(dir_ace_list);
3246
 
                                                        return False;
3247
 
                                                }
3248
 
                                        }
3249
 
                                }
3250
 
                        }
3251
 
 
3252
 
                        if (acl_set_support) {
3253
 
                                store_inheritance_attributes(fsp, file_ace_list, dir_ace_list,
3254
 
                                                (psd->type & SE_DESC_DACL_PROTECTED) ? True : False);
3255
 
                        }
3256
 
 
3257
 
                        /*
3258
 
                         * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
3259
 
                         */
3260
 
 
3261
 
                        if(!acl_set_support && acl_perms) {
3262
 
                                mode_t posix_perms;
3263
 
 
3264
 
                                if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
3265
 
                                        free_canon_ace_list(file_ace_list);
3266
 
                                        free_canon_ace_list(dir_ace_list);
3267
 
                                        DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
3268
 
                                                fsp->fsp_name ));
3269
 
                                        return False;
3270
 
                                }
3271
 
 
3272
 
                                if (orig_mode != posix_perms) {
3273
 
 
3274
 
                                        DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
3275
 
                                                fsp->fsp_name, (unsigned int)posix_perms ));
3276
 
 
3277
 
                                        if(SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms) == -1) {
3278
 
                                                int sret = -1;
3279
 
                                                if (acl_group_override(conn, sbuf.st_gid)) {
3280
 
                                                        DEBUG(5,("set_nt_acl: acl group control on and "
3281
 
                                                                "current user in file %s primary group. Override chmod\n",
3282
 
                                                                fsp->fsp_name ));
3283
 
 
3284
 
                                                        become_root();
3285
 
                                                        sret = SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms);
3286
 
                                                        unbecome_root();
3287
 
                                                }
3288
 
 
3289
 
                                                if (sret == -1) {
3290
 
                                                        DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
3291
 
                                                                fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
3292
 
                                                        free_canon_ace_list(file_ace_list);
3293
 
                                                        free_canon_ace_list(dir_ace_list);
3294
 
                                                        return False;
3295
 
                                                }
3296
 
                                        }
3297
 
                                }
3298
 
                        }
3299
 
                }
3300
 
 
3301
 
                free_canon_ace_list(file_ace_list);
3302
 
                free_canon_ace_list(dir_ace_list); 
3303
 
        }
3304
 
 
3305
 
        /* Any chown pending? */
3306
 
        if (need_chown) {
3307
 
 
3308
 
                DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3309
 
                        fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
3310
 
 
3311
 
                if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
3312
 
                        DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3313
 
                                fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
3314
 
                        return False;
3315
 
                }
3316
 
        }
3317
 
 
3318
 
        return True;
3319
 
}
3320
 
 
3321
 
/****************************************************************************
3322
 
 Get the actual group bits stored on a file with an ACL. Has no effect if
3323
 
 the file has no ACL. Needed in dosmode code where the stat() will return
3324
 
 the mask bits, not the real group bits, for a file with an ACL.
3325
 
****************************************************************************/
3326
 
 
3327
 
int get_acl_group_bits( connection_struct *conn, const char *fname, mode_t *mode )
3328
 
{
3329
 
        int entry_id = SMB_ACL_FIRST_ENTRY;
3330
 
        SMB_ACL_ENTRY_T entry;
3331
 
        SMB_ACL_T posix_acl;
3332
 
        int result = -1;
3333
 
 
3334
 
        posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS);
3335
 
        if (posix_acl == (SMB_ACL_T)NULL)
3336
 
                return -1;
3337
 
 
3338
 
        while (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3339
 
                SMB_ACL_TAG_T tagtype;
3340
 
                SMB_ACL_PERMSET_T permset;
3341
 
 
3342
 
                /* get_next... */
3343
 
                if (entry_id == SMB_ACL_FIRST_ENTRY)
3344
 
                        entry_id = SMB_ACL_NEXT_ENTRY;
3345
 
 
3346
 
                if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) ==-1)
3347
 
                        break;
3348
 
 
3349
 
                if (tagtype == SMB_ACL_GROUP_OBJ) {
3350
 
                        if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3351
 
                                break;
3352
 
                        } else {
3353
 
                                *mode &= ~(S_IRGRP|S_IWGRP|S_IXGRP);
3354
 
                                *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRGRP : 0);
3355
 
                                *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWGRP : 0);
3356
 
                                *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXGRP : 0);
3357
 
                                result = 0;
3358
 
                                break;
3359
 
                        }
3360
 
                }
3361
 
        }
3362
 
        SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3363
 
        return result;
3364
 
}
3365
 
 
3366
 
/****************************************************************************
3367
 
 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3368
 
 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3369
 
****************************************************************************/
3370
 
 
3371
 
static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mode_t mode)
3372
 
{
3373
 
        int entry_id = SMB_ACL_FIRST_ENTRY;
3374
 
        SMB_ACL_ENTRY_T entry;
3375
 
        int num_entries = 0;
3376
 
 
3377
 
        while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3378
 
                SMB_ACL_TAG_T tagtype;
3379
 
                SMB_ACL_PERMSET_T permset;
3380
 
                mode_t perms;
3381
 
 
3382
 
                /* get_next... */
3383
 
                if (entry_id == SMB_ACL_FIRST_ENTRY)
3384
 
                        entry_id = SMB_ACL_NEXT_ENTRY;
3385
 
 
3386
 
                if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
3387
 
                        return -1;
3388
 
 
3389
 
                if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
3390
 
                        return -1;
3391
 
 
3392
 
                num_entries++;
3393
 
 
3394
 
                switch(tagtype) {
3395
 
                        case SMB_ACL_USER_OBJ:
3396
 
                                perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
3397
 
                                break;
3398
 
                        case SMB_ACL_GROUP_OBJ:
3399
 
                                perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
3400
 
                                break;
3401
 
                        case SMB_ACL_MASK:
3402
 
                                /*
3403
 
                                 * FIXME: The ACL_MASK entry permissions should really be set to
3404
 
                                 * the union of the permissions of all ACL_USER,
3405
 
                                 * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what
3406
 
                                 * acl_calc_mask() does, but Samba ACLs doesn't provide it.
3407
 
                                 */
3408
 
                                perms = S_IRUSR|S_IWUSR|S_IXUSR;
3409
 
                                break;
3410
 
                        case SMB_ACL_OTHER:
3411
 
                                perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
3412
 
                                break;
3413
 
                        default:
3414
 
                                continue;
3415
 
                }
3416
 
 
3417
 
                if (map_acl_perms_to_permset(conn, perms, &permset) == -1)
3418
 
                        return -1;
3419
 
 
3420
 
                if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) == -1)
3421
 
                        return -1;
3422
 
        }
3423
 
 
3424
 
        /*
3425
 
         * If this is a simple 3 element ACL or no elements then it's a standard
3426
 
         * UNIX permission set. Just use chmod...       
3427
 
         */
3428
 
 
3429
 
        if ((num_entries == 3) || (num_entries == 0))
3430
 
                return -1;
3431
 
 
3432
 
        return 0;
3433
 
}
3434
 
 
3435
 
/****************************************************************************
3436
 
 Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ,
3437
 
 GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the
3438
 
 resulting ACL on TO.  Note that name is in UNIX character set.
3439
 
****************************************************************************/
3440
 
 
3441
 
static int copy_access_acl(connection_struct *conn, const char *from, const char *to, mode_t mode)
3442
 
{
3443
 
        SMB_ACL_T posix_acl = NULL;
3444
 
        int ret = -1;
3445
 
 
3446
 
        if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL)
3447
 
                return -1;
3448
 
 
3449
 
        if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3450
 
                goto done;
3451
 
 
3452
 
        ret = SMB_VFS_SYS_ACL_SET_FILE(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl);
3453
 
 
3454
 
 done:
3455
 
 
3456
 
        SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3457
 
        return ret;
3458
 
}
3459
 
 
3460
 
/****************************************************************************
3461
 
 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3462
 
 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3463
 
 Note that name is in UNIX character set.
3464
 
****************************************************************************/
3465
 
 
3466
 
int chmod_acl(connection_struct *conn, const char *name, mode_t mode)
3467
 
{
3468
 
        return copy_access_acl(conn, name, name, mode);
3469
 
}
3470
 
 
3471
 
/****************************************************************************
3472
 
 If "inherit permissions" is set and the parent directory has no default
3473
 
 ACL but it does have an Access ACL, inherit this Access ACL to file name.
3474
 
****************************************************************************/
3475
 
 
3476
 
int inherit_access_acl(connection_struct *conn, const char *name, mode_t mode)
3477
 
{
3478
 
        pstring dirname;
3479
 
        pstrcpy(dirname, parent_dirname(name));
3480
 
 
3481
 
        if (!lp_inherit_perms(SNUM(conn)) || directory_has_default_acl(conn, dirname))
3482
 
                return 0;
3483
 
 
3484
 
        return copy_access_acl(conn, dirname, name, mode);
3485
 
}
3486
 
 
3487
 
/****************************************************************************
3488
 
 Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3489
 
 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3490
 
****************************************************************************/
3491
 
 
3492
 
int fchmod_acl(files_struct *fsp, int fd, mode_t mode)
3493
 
{
3494
 
        connection_struct *conn = fsp->conn;
3495
 
        SMB_ACL_T posix_acl = NULL;
3496
 
        int ret = -1;
3497
 
 
3498
 
        if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fd)) == NULL)
3499
 
                return -1;
3500
 
 
3501
 
        if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3502
 
                goto done;
3503
 
 
3504
 
        ret = SMB_VFS_SYS_ACL_SET_FD(fsp, fd, posix_acl);
3505
 
 
3506
 
  done:
3507
 
 
3508
 
        SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3509
 
        return ret;
3510
 
}
3511
 
 
3512
 
/****************************************************************************
3513
 
 Check for an existing default POSIX ACL on a directory.
3514
 
****************************************************************************/
3515
 
 
3516
 
BOOL directory_has_default_acl(connection_struct *conn, const char *fname)
3517
 
{
3518
 
        SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT);
3519
 
        BOOL has_acl = False;
3520
 
        SMB_ACL_ENTRY_T entry;
3521
 
 
3522
 
        if (def_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, def_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) {
3523
 
                has_acl = True;
3524
 
        }
3525
 
 
3526
 
        if (def_acl) {
3527
 
                SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
3528
 
        }
3529
 
        return has_acl;
3530
 
}
3531
 
 
3532
 
/****************************************************************************
3533
 
 Map from wire type to permset.
3534
 
****************************************************************************/
3535
 
 
3536
 
static BOOL unix_ex_wire_to_permset(connection_struct *conn, unsigned char wire_perm, SMB_ACL_PERMSET_T *p_permset)
3537
 
{
3538
 
        if (wire_perm & ~(SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE)) {
3539
 
                return False;
3540
 
        }
3541
 
 
3542
 
        if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) ==  -1) {
3543
 
                return False;
3544
 
        }
3545
 
 
3546
 
        if (wire_perm & SMB_POSIX_ACL_READ) {
3547
 
                if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1) {
3548
 
                        return False;
3549
 
                }
3550
 
        }
3551
 
        if (wire_perm & SMB_POSIX_ACL_WRITE) {
3552
 
                if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1) {
3553
 
                        return False;
3554
 
                }
3555
 
        }
3556
 
        if (wire_perm & SMB_POSIX_ACL_EXECUTE) {
3557
 
                if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1) {
3558
 
                        return False;
3559
 
                }
3560
 
        }
3561
 
        return True;
3562
 
}
3563
 
 
3564
 
/****************************************************************************
3565
 
 Map from wire type to tagtype.
3566
 
****************************************************************************/
3567
 
 
3568
 
static BOOL unix_ex_wire_to_tagtype(unsigned char wire_tt, SMB_ACL_TAG_T *p_tt)
3569
 
{
3570
 
        switch (wire_tt) {
3571
 
                case SMB_POSIX_ACL_USER_OBJ:
3572
 
                        *p_tt = SMB_ACL_USER_OBJ;
3573
 
                        break;
3574
 
                case SMB_POSIX_ACL_USER:
3575
 
                        *p_tt = SMB_ACL_USER;
3576
 
                        break;
3577
 
                case SMB_POSIX_ACL_GROUP_OBJ:
3578
 
                        *p_tt = SMB_ACL_GROUP_OBJ;
3579
 
                        break;
3580
 
                case SMB_POSIX_ACL_GROUP:
3581
 
                        *p_tt = SMB_ACL_GROUP;
3582
 
                        break;
3583
 
                case SMB_POSIX_ACL_MASK:
3584
 
                        *p_tt = SMB_ACL_MASK;
3585
 
                        break;
3586
 
                case SMB_POSIX_ACL_OTHER:
3587
 
                        *p_tt = SMB_ACL_OTHER;
3588
 
                        break;
3589
 
                default:
3590
 
                        return False;
3591
 
        }
3592
 
        return True;
3593
 
}
3594
 
 
3595
 
/****************************************************************************
3596
 
 Create a new POSIX acl from wire permissions.
3597
 
 FIXME ! How does the share mask/mode fit into this.... ?
3598
 
****************************************************************************/
3599
 
 
3600
 
static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_acls, const char *pdata)
3601
 
{
3602
 
        unsigned int i;
3603
 
        SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, num_acls);
3604
 
 
3605
 
        if (the_acl == NULL) {
3606
 
                return NULL;
3607
 
        }
3608
 
 
3609
 
        for (i = 0; i < num_acls; i++) {
3610
 
                SMB_ACL_ENTRY_T the_entry;
3611
 
                SMB_ACL_PERMSET_T the_permset;
3612
 
                SMB_ACL_TAG_T tag_type;
3613
 
 
3614
 
                if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
3615
 
                        DEBUG(0,("create_posix_acl_from_wire: Failed to create entry %u. (%s)\n",
3616
 
                                i, strerror(errno) ));
3617
 
                        goto fail;
3618
 
                }
3619
 
 
3620
 
                if (!unix_ex_wire_to_tagtype(CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), &tag_type)) {
3621
 
                        DEBUG(0,("create_posix_acl_from_wire: invalid wire tagtype %u on entry %u.\n",
3622
 
                                CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), i ));
3623
 
                        goto fail;
3624
 
                }
3625
 
 
3626
 
                if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, tag_type) == -1) {
3627
 
                        DEBUG(0,("create_posix_acl_from_wire: Failed to set tagtype on entry %u. (%s)\n",
3628
 
                                i, strerror(errno) ));
3629
 
                        goto fail;
3630
 
                }
3631
 
 
3632
 
                /* Get the permset pointer from the new ACL entry. */
3633
 
                if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
3634
 
                        DEBUG(0,("create_posix_acl_from_wire: Failed to get permset on entry %u. (%s)\n",
3635
 
                                i, strerror(errno) ));
3636
 
                        goto fail;
3637
 
                }
3638
 
 
3639
 
                /* Map from wire to permissions. */
3640
 
                if (!unix_ex_wire_to_permset(conn, CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+1), &the_permset)) {
3641
 
                        DEBUG(0,("create_posix_acl_from_wire: invalid permset %u on entry %u.\n",
3642
 
                                CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE) + 1), i ));
3643
 
                        goto fail;
3644
 
                }
3645
 
 
3646
 
                /* Now apply to the new ACL entry. */
3647
 
                if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
3648
 
                        DEBUG(0,("create_posix_acl_from_wire: Failed to add permset on entry %u. (%s)\n",
3649
 
                                i, strerror(errno) ));
3650
 
                        goto fail;
3651
 
                }
3652
 
 
3653
 
                if (tag_type == SMB_ACL_USER) {
3654
 
                        uint32 uidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3655
 
                        uid_t uid = (uid_t)uidval;
3656
 
                        if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&uid) == -1) {
3657
 
                                DEBUG(0,("create_posix_acl_from_wire: Failed to set uid %u on entry %u. (%s)\n",
3658
 
                                        (unsigned int)uid, i, strerror(errno) ));
3659
 
                                goto fail;
3660
 
                        }
3661
 
                }
3662
 
 
3663
 
                if (tag_type == SMB_ACL_GROUP) {
3664
 
                        uint32 gidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3665
 
                        gid_t gid = (uid_t)gidval;
3666
 
                        if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&gid) == -1) {
3667
 
                                DEBUG(0,("create_posix_acl_from_wire: Failed to set gid %u on entry %u. (%s)\n",
3668
 
                                        (unsigned int)gid, i, strerror(errno) ));
3669
 
                                goto fail;
3670
 
                        }
3671
 
                }
3672
 
        }
3673
 
 
3674
 
        return the_acl;
3675
 
 
3676
 
 fail:
3677
 
 
3678
 
        if (the_acl != NULL) {
3679
 
                SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
3680
 
        }
3681
 
        return NULL;
3682
 
}
3683
 
 
3684
 
/****************************************************************************
3685
 
 Calls from UNIX extensions - Default POSIX ACL set.
3686
 
 If num_def_acls == 0 and not a directory just return. If it is a directory
3687
 
 and num_def_acls == 0 then remove the default acl. Else set the default acl
3688
 
 on the directory.
3689
 
****************************************************************************/
3690
 
 
3691
 
BOOL set_unix_posix_default_acl(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf,
3692
 
                                uint16 num_def_acls, const char *pdata)
3693
 
{
3694
 
        SMB_ACL_T def_acl = NULL;
3695
 
 
3696
 
        if (num_def_acls && !S_ISDIR(psbuf->st_mode)) {
3697
 
                DEBUG(5,("set_unix_posix_default_acl: Can't set default ACL on non-directory file %s\n", fname ));
3698
 
                errno = EISDIR;
3699
 
                return False;
3700
 
        }
3701
 
 
3702
 
        if (!num_def_acls) {
3703
 
                /* Remove the default ACL. */
3704
 
                if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fname) == -1) {
3705
 
                        DEBUG(5,("set_unix_posix_default_acl: acl_delete_def_file failed on directory %s (%s)\n",
3706
 
                                fname, strerror(errno) ));
3707
 
                        return False;
3708
 
                }
3709
 
                return True;
3710
 
        }
3711
 
 
3712
 
        if ((def_acl = create_posix_acl_from_wire(conn, num_def_acls, pdata)) == NULL) {
3713
 
                return False;
3714
 
        }
3715
 
 
3716
 
        if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT, def_acl) == -1) {
3717
 
                DEBUG(5,("set_unix_posix_default_acl: acl_set_file failed on directory %s (%s)\n",
3718
 
                        fname, strerror(errno) ));
3719
 
                SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
3720
 
                return False;
3721
 
        }
3722
 
 
3723
 
        DEBUG(10,("set_unix_posix_default_acl: set default acl for file %s\n", fname ));
3724
 
        SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
3725
 
        return True;
3726
 
}
3727
 
 
3728
 
/****************************************************************************
3729
 
 Remove an ACL from a file. As we don't have acl_delete_entry() available
3730
 
 we must read the current acl and copy all entries except MASK, USER and GROUP
3731
 
 to a new acl, then set that. This (at least on Linux) causes any ACL to be
3732
 
 removed.
3733
 
 FIXME ! How does the share mask/mode fit into this.... ?
3734
 
****************************************************************************/
3735
 
 
3736
 
static BOOL remove_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname)
3737
 
{
3738
 
        SMB_ACL_T file_acl = NULL;
3739
 
        int entry_id = SMB_ACL_FIRST_ENTRY;
3740
 
        SMB_ACL_ENTRY_T entry;
3741
 
        BOOL ret = False;
3742
 
        /* Create a new ACL with only 3 entries, u/g/w. */
3743
 
        SMB_ACL_T new_file_acl = SMB_VFS_SYS_ACL_INIT(conn, 3);
3744
 
        SMB_ACL_ENTRY_T user_ent = NULL;
3745
 
        SMB_ACL_ENTRY_T group_ent = NULL;
3746
 
        SMB_ACL_ENTRY_T other_ent = NULL;
3747
 
 
3748
 
        if (new_file_acl == NULL) {
3749
 
                DEBUG(5,("remove_posix_acl: failed to init new ACL with 3 entries for file %s.\n", fname));
3750
 
                return False;
3751
 
        }
3752
 
 
3753
 
        /* Now create the u/g/w entries. */
3754
 
        if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &user_ent) == -1) {
3755
 
                DEBUG(5,("remove_posix_acl: Failed to create user entry for file %s. (%s)\n",
3756
 
                        fname, strerror(errno) ));
3757
 
                goto done;
3758
 
        }
3759
 
        if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, user_ent, SMB_ACL_USER_OBJ) == -1) {
3760
 
                DEBUG(5,("remove_posix_acl: Failed to set user entry for file %s. (%s)\n",
3761
 
                        fname, strerror(errno) ));
3762
 
                goto done;
3763
 
        }
3764
 
 
3765
 
        if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &group_ent) == -1) {
3766
 
                DEBUG(5,("remove_posix_acl: Failed to create group entry for file %s. (%s)\n",
3767
 
                        fname, strerror(errno) ));
3768
 
                goto done;
3769
 
        }
3770
 
        if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, group_ent, SMB_ACL_GROUP_OBJ) == -1) {
3771
 
                DEBUG(5,("remove_posix_acl: Failed to set group entry for file %s. (%s)\n",
3772
 
                        fname, strerror(errno) ));
3773
 
                goto done;
3774
 
        }
3775
 
 
3776
 
        if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &other_ent) == -1) {
3777
 
                DEBUG(5,("remove_posix_acl: Failed to create other entry for file %s. (%s)\n",
3778
 
                        fname, strerror(errno) ));
3779
 
                goto done;
3780
 
        }
3781
 
        if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, other_ent, SMB_ACL_OTHER) == -1) {
3782
 
                DEBUG(5,("remove_posix_acl: Failed to set other entry for file %s. (%s)\n",
3783
 
                        fname, strerror(errno) ));
3784
 
                goto done;
3785
 
        }
3786
 
 
3787
 
        /* Get the current file ACL. */
3788
 
        if (fsp && fsp->fh->fd != -1) {
3789
 
                file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fh->fd);
3790
 
        } else {
3791
 
                file_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_ACCESS);
3792
 
        }
3793
 
 
3794
 
        if (file_acl == NULL) {
3795
 
                /* This is only returned if an error occurred. Even for a file with
3796
 
                   no acl a u/g/w acl should be returned. */
3797
 
                DEBUG(5,("remove_posix_acl: failed to get ACL from file %s (%s).\n",
3798
 
                        fname, strerror(errno) ));
3799
 
                goto done;
3800
 
        }
3801
 
 
3802
 
        while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, file_acl, entry_id, &entry) == 1) {
3803
 
                SMB_ACL_TAG_T tagtype;
3804
 
                SMB_ACL_PERMSET_T permset;
3805
 
 
3806
 
                /* get_next... */
3807
 
                if (entry_id == SMB_ACL_FIRST_ENTRY)
3808
 
                        entry_id = SMB_ACL_NEXT_ENTRY;
3809
 
 
3810
 
                if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
3811
 
                        DEBUG(5,("remove_posix_acl: failed to get tagtype from ACL on file %s (%s).\n",
3812
 
                                fname, strerror(errno) ));
3813
 
                        goto done;
3814
 
                }
3815
 
 
3816
 
                if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3817
 
                        DEBUG(5,("remove_posix_acl: failed to get permset from ACL on file %s (%s).\n",
3818
 
                                fname, strerror(errno) ));
3819
 
                        goto done;
3820
 
                }
3821
 
 
3822
 
                if (tagtype == SMB_ACL_USER_OBJ) {
3823
 
                        if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, user_ent, permset) == -1) {
3824
 
                                DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
3825
 
                                        fname, strerror(errno) ));
3826
 
                        }
3827
 
                } else if (tagtype == SMB_ACL_GROUP_OBJ) {
3828
 
                        if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, group_ent, permset) == -1) {
3829
 
                                DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
3830
 
                                        fname, strerror(errno) ));
3831
 
                        }
3832
 
                } else if (tagtype == SMB_ACL_OTHER) {
3833
 
                        if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, other_ent, permset) == -1) {
3834
 
                                DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
3835
 
                                        fname, strerror(errno) ));
3836
 
                        }
3837
 
                }
3838
 
        }
3839
 
 
3840
 
        /* Set the new empty file ACL. */
3841
 
        if (fsp && fsp->fh->fd != -1) {
3842
 
                if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, new_file_acl) == -1) {
3843
 
                        DEBUG(5,("remove_posix_acl: acl_set_file failed on %s (%s)\n",
3844
 
                                fname, strerror(errno) ));
3845
 
                        goto done;
3846
 
                }
3847
 
        } else {
3848
 
                if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, new_file_acl) == -1) {
3849
 
                        DEBUG(5,("remove_posix_acl: acl_set_file failed on %s (%s)\n",
3850
 
                                fname, strerror(errno) ));
3851
 
                        goto done;
3852
 
                }
3853
 
        }
3854
 
 
3855
 
        ret = True;
3856
 
 
3857
 
 done:
3858
 
 
3859
 
        if (file_acl) {
3860
 
                SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
3861
 
        }
3862
 
        if (new_file_acl) {
3863
 
                SMB_VFS_SYS_ACL_FREE_ACL(conn, new_file_acl);
3864
 
        }
3865
 
        return ret;
3866
 
}
3867
 
 
3868
 
/****************************************************************************
3869
 
 Calls from UNIX extensions - POSIX ACL set.
3870
 
 If num_def_acls == 0 then read/modify/write acl after removing all entries
3871
 
 except SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER.
3872
 
****************************************************************************/
3873
 
 
3874
 
BOOL set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname, uint16 num_acls, const char *pdata)
3875
 
{
3876
 
        SMB_ACL_T file_acl = NULL;
3877
 
 
3878
 
        if (!num_acls) {
3879
 
                /* Remove the ACL from the file. */
3880
 
                return remove_posix_acl(conn, fsp, fname);
3881
 
        }
3882
 
 
3883
 
        if ((file_acl = create_posix_acl_from_wire(conn, num_acls, pdata)) == NULL) {
3884
 
                return False;
3885
 
        }
3886
 
 
3887
 
        if (fsp && fsp->fh->fd != -1) {
3888
 
                /* The preferred way - use an open fd. */
3889
 
                if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, file_acl) == -1) {
3890
 
                        DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
3891
 
                                fname, strerror(errno) ));
3892
 
                        SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
3893
 
                        return False;
3894
 
                }
3895
 
        } else {
3896
 
                if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, file_acl) == -1) {
3897
 
                        DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
3898
 
                                fname, strerror(errno) ));
3899
 
                        SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
3900
 
                        return False;
3901
 
                }
3902
 
        }
3903
 
 
3904
 
        DEBUG(10,("set_unix_posix_acl: set acl for file %s\n", fname ));
3905
 
        SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
3906
 
        return True;
3907
 
}
3908
 
 
3909
 
/****************************************************************************
3910
 
 Check for POSIX group ACLs. If none use stat entry.
3911
 
 Return -1 if no match, 0 if match and denied, 1 if match and allowed.
3912
 
****************************************************************************/
3913
 
 
3914
 
static int check_posix_acl_group_write(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf)
3915
 
{
3916
 
        SMB_ACL_T posix_acl = NULL;
3917
 
        int entry_id = SMB_ACL_FIRST_ENTRY;
3918
 
        SMB_ACL_ENTRY_T entry;
3919
 
        int i;
3920
 
        BOOL seen_mask = False;
3921
 
        BOOL seen_owning_group = False;
3922
 
        int ret = -1;
3923
 
        gid_t cu_gid;
3924
 
 
3925
 
        if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS)) == NULL) {
3926
 
                goto check_stat;
3927
 
        }
3928
 
 
3929
 
        /* First ensure the group mask allows group read. */
3930
 
        /* Also check any user entries (these take preference over group). */
3931
 
 
3932
 
        while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3933
 
                SMB_ACL_TAG_T tagtype;
3934
 
                SMB_ACL_PERMSET_T permset;
3935
 
                int have_write = -1;
3936
 
 
3937
 
                /* get_next... */
3938
 
                if (entry_id == SMB_ACL_FIRST_ENTRY)
3939
 
                        entry_id = SMB_ACL_NEXT_ENTRY;
3940
 
 
3941
 
                if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
3942
 
                        goto check_stat;
3943
 
                }
3944
 
 
3945
 
                if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3946
 
                        goto check_stat;
3947
 
                }
3948
 
 
3949
 
                have_write = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE);
3950
 
                if (have_write == -1) {
3951
 
                        goto check_stat;
3952
 
                }
3953
 
 
3954
 
                /*
3955
 
                 * Solaris returns 2 for this if write is available.
3956
 
                 * canonicalize to 0 or 1.
3957
 
                 */     
3958
 
                have_write = (have_write ? 1 : 0);
3959
 
 
3960
 
                switch(tagtype) {
3961
 
                        case SMB_ACL_MASK:
3962
 
                                seen_mask = True;
3963
 
                                if (!have_write) {
3964
 
                                        /* We don't have any group or explicit user write permission. */
3965
 
                                        ret = -1; /* Allow caller to check "other" permissions. */
3966
 
                                        DEBUG(10,("check_posix_acl_group_write: file %s \
3967
 
refusing write due to mask.\n", fname));
3968
 
                                        goto done;
3969
 
                                }
3970
 
                                break;
3971
 
                        case SMB_ACL_USER:
3972
 
                        {
3973
 
                                /* Check against current_user.ut.uid. */
3974
 
                                uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
3975
 
                                if (puid == NULL) {
3976
 
                                        goto check_stat;
3977
 
                                }
3978
 
                                if (current_user.ut.uid == *puid) {
3979
 
                                        /* We have a uid match but we must ensure we have seen the acl mask. */
3980
 
                                        ret = have_write;
3981
 
                                        DEBUG(10,("check_posix_acl_group_write: file %s \
3982
 
match on user %u -> %s.\n", fname, (unsigned int)*puid, ret ? "can write" : "cannot write"));
3983
 
                                        if (seen_mask) {
3984
 
                                                goto done;
3985
 
                                        }
3986
 
                                }
3987
 
                                break;
3988
 
                        }
3989
 
                        default:
3990
 
                                continue;
3991
 
                }
3992
 
        }
3993
 
 
3994
 
        /* If ret is anything other than -1 we matched on a user entry. */
3995
 
        if (ret != -1) {
3996
 
                goto done;
3997
 
        }
3998
 
 
3999
 
        /* Next check all group entries. */
4000
 
        entry_id = SMB_ACL_FIRST_ENTRY;
4001
 
        while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
4002
 
                SMB_ACL_TAG_T tagtype;
4003
 
                SMB_ACL_PERMSET_T permset;
4004
 
                int have_write = -1;
4005
 
 
4006
 
                /* get_next... */
4007
 
                if (entry_id == SMB_ACL_FIRST_ENTRY)
4008
 
                        entry_id = SMB_ACL_NEXT_ENTRY;
4009
 
 
4010
 
                if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
4011
 
                        goto check_stat;
4012
 
                }
4013
 
 
4014
 
                if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
4015
 
                        goto check_stat;
4016
 
                }
4017
 
 
4018
 
                have_write = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE);
4019
 
                if (have_write == -1) {
4020
 
                        goto check_stat;
4021
 
                }
4022
 
 
4023
 
                /*
4024
 
                 * Solaris returns 2 for this if write is available.
4025
 
                 * canonicalize to 0 or 1.
4026
 
                 */     
4027
 
                have_write = (have_write ? 1 : 0);
4028
 
 
4029
 
                switch(tagtype) {
4030
 
                        case SMB_ACL_GROUP:
4031
 
                        case SMB_ACL_GROUP_OBJ:
4032
 
                        {
4033
 
                                gid_t *pgid = NULL;
4034
 
 
4035
 
                                if (tagtype == SMB_ACL_GROUP) {
4036
 
                                        pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
4037
 
                                } else {
4038
 
                                        seen_owning_group = True;
4039
 
                                        pgid = &psbuf->st_gid;
4040
 
                                }
4041
 
                                if (pgid == NULL) {
4042
 
                                        goto check_stat;
4043
 
                                }
4044
 
 
4045
 
                                /*
4046
 
                                 * Does it match the current effective group
4047
 
                                 * or supplementary groups ?
4048
 
                                 */
4049
 
                                for (cu_gid = get_current_user_gid_first(&i); cu_gid != (gid_t)-1;
4050
 
                                                        cu_gid = get_current_user_gid_next(&i)) {
4051
 
                                        if (cu_gid == *pgid) {
4052
 
                                                ret = have_write;
4053
 
                                                DEBUG(10,("check_posix_acl_group_write: file %s \
4054
 
match on group %u -> can write.\n", fname, (unsigned int)cu_gid ));
4055
 
 
4056
 
                                                /* If we don't have write permission this entry doesn't
4057
 
                                                        terminate the enumeration of the entries. */
4058
 
                                                if (have_write) {
4059
 
                                                        goto done;
4060
 
                                                }
4061
 
                                                /* But does terminate the group iteration. */
4062
 
                                                break;
4063
 
                                        }
4064
 
                                }
4065
 
                                break;
4066
 
                        }
4067
 
                        default:
4068
 
                                continue;
4069
 
                }
4070
 
        }
4071
 
 
4072
 
        /* If ret is -1 here we didn't match on the user entry or
4073
 
           supplemental group entries. */
4074
 
        
4075
 
        DEBUG(10,("check_posix_acl_group_write: ret = %d before check_stat:\n", ret));
4076
 
 
4077
 
  check_stat:
4078
 
 
4079
 
        /*
4080
 
         * We only check the S_IWGRP permissions if we haven't already
4081
 
         * seen an owning group SMB_ACL_GROUP_OBJ ace entry. If there is an
4082
 
         * SMB_ACL_GROUP_OBJ ace entry then the group bits in st_gid are
4083
 
         * the same as the SMB_ACL_MASK bits, not the SMB_ACL_GROUP_OBJ
4084
 
         * bits. Thanks to Marc Cousin <mcousin@sigma.fr> for pointing
4085
 
         * this out. JRA.
4086
 
         */
4087
 
 
4088
 
        if (!seen_owning_group) {
4089
 
                /* Do we match on the owning group entry ? */
4090
 
                /*
4091
 
                 * Does it match the current effective group
4092
 
                 * or supplementary groups ?
4093
 
                 */
4094
 
                for (cu_gid = get_current_user_gid_first(&i); cu_gid != (gid_t)-1;
4095
 
                                                cu_gid = get_current_user_gid_next(&i)) {
4096
 
                        if (cu_gid == psbuf->st_gid) {
4097
 
                                ret = (psbuf->st_mode & S_IWGRP) ? 1 : 0;
4098
 
                                DEBUG(10,("check_posix_acl_group_write: file %s \
4099
 
match on owning group %u -> %s.\n", fname, (unsigned int)psbuf->st_gid, ret ? "can write" : "cannot write"));
4100
 
                                break;
4101
 
                        }
4102
 
                }
4103
 
 
4104
 
                if (cu_gid == (gid_t)-1) {
4105
 
                        DEBUG(10,("check_posix_acl_group_write: file %s \
4106
 
failed to match on user or group in token (ret = %d).\n", fname, ret ));
4107
 
                }
4108
 
        }
4109
 
 
4110
 
  done:
4111
 
 
4112
 
        if (posix_acl) {
4113
 
                SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
4114
 
        }
4115
 
 
4116
 
        DEBUG(10,("check_posix_acl_group_write: file %s returning (ret = %d).\n", fname, ret ));
4117
 
        return ret;
4118
 
}
4119
 
 
4120
 
/****************************************************************************
4121
 
 Actually emulate the in-kernel access checking for delete access. We need
4122
 
 this to successfully return ACCESS_DENIED on a file open for delete access.
4123
 
****************************************************************************/
4124
 
 
4125
 
BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname)
4126
 
{
4127
 
        SMB_STRUCT_STAT sbuf;  
4128
 
        pstring dname;
4129
 
        int ret;
4130
 
 
4131
 
        if (!CAN_WRITE(conn)) {
4132
 
                return False;
4133
 
        }
4134
 
 
4135
 
        /* Get the parent directory permission mask and owners. */
4136
 
        pstrcpy(dname, parent_dirname(fname));
4137
 
        if(SMB_VFS_STAT(conn, dname, &sbuf) != 0) {
4138
 
                return False;
4139
 
        }
4140
 
        if (!S_ISDIR(sbuf.st_mode)) {
4141
 
                return False;
4142
 
        }
4143
 
        if (current_user.ut.uid == 0 || conn->admin_user) {
4144
 
                /* I'm sorry sir, I didn't know you were root... */
4145
 
                return True;
4146
 
        }
4147
 
 
4148
 
        /* Check primary owner write access. */
4149
 
        if (current_user.ut.uid == sbuf.st_uid) {
4150
 
                return (sbuf.st_mode & S_IWUSR) ? True : False;
4151
 
        }
4152
 
 
4153
 
#ifdef S_ISVTX
4154
 
        /* sticky bit means delete only by owner or root. */
4155
 
        if (sbuf.st_mode & S_ISVTX) {
4156
 
                SMB_STRUCT_STAT sbuf_file;  
4157
 
                if(SMB_VFS_STAT(conn, fname, &sbuf_file) != 0) {
4158
 
                        return False;
4159
 
                }
4160
 
                /*
4161
 
                 * Patch from SATOH Fumiyasu <fumiyas@miraclelinux.com>
4162
 
                 * for bug #3348. Don't assume owning sticky bit
4163
 
                 * directory means write access allowed.
4164
 
                 */
4165
 
                if (current_user.ut.uid != sbuf_file.st_uid) {
4166
 
                        return False;
4167
 
                }
4168
 
        }
4169
 
#endif
4170
 
 
4171
 
        /* Check group or explicit user acl entry write access. */
4172
 
        ret = check_posix_acl_group_write(conn, dname, &sbuf);
4173
 
        if (ret == 0 || ret == 1) {
4174
 
                return ret ? True : False;
4175
 
        }
4176
 
 
4177
 
        /* Finally check other write access. */
4178
 
        return (sbuf.st_mode & S_IWOTH) ? True : False;
4179
 
}
4180
 
 
4181
 
/****************************************************************************
4182
 
 Actually emulate the in-kernel access checking for write access. We need
4183
 
 this to successfully check for ability to write for dos filetimes.
4184
 
 Note this doesn't take into account share write permissions.
4185
 
****************************************************************************/
4186
 
 
4187
 
BOOL can_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf)
4188
 
{
4189
 
        int ret;
4190
 
 
4191
 
        if (current_user.ut.uid == 0 || conn->admin_user) {
4192
 
                /* I'm sorry sir, I didn't know you were root... */
4193
 
                return True;
4194
 
        }
4195
 
 
4196
 
        if (!VALID_STAT(*psbuf)) {
4197
 
                /* Get the file permission mask and owners. */
4198
 
                if(SMB_VFS_STAT(conn, fname, psbuf) != 0) {
4199
 
                        return False;
4200
 
                }
4201
 
        }
4202
 
 
4203
 
        /* Check primary owner write access. */
4204
 
        if (current_user.ut.uid == psbuf->st_uid) {
4205
 
                return (psbuf->st_mode & S_IWUSR) ? True : False;
4206
 
        }
4207
 
 
4208
 
        /* Check group or explicit user acl entry write access. */
4209
 
        ret = check_posix_acl_group_write(conn, fname, psbuf);
4210
 
        if (ret == 0 || ret == 1) {
4211
 
                return ret ? True : False;
4212
 
        }
4213
 
 
4214
 
        /* Finally check other write access. */
4215
 
        return (psbuf->st_mode & S_IWOTH) ? True : False;
4216
 
}
4217
 
 
4218
 
/********************************************************************
4219
 
 Pull the NT ACL from a file on disk or the OpenEventlog() access
4220
 
 check.  Caller is responsible for freeing the returned security
4221
 
 descriptor via TALLOC_FREE().  This is designed for dealing with 
4222
 
 user space access checks in smbd outside of the VFS.  For example,
4223
 
 checking access rights in OpenEventlog().
4224
 
 
4225
 
 Assume we are dealing with files (for now)
4226
 
********************************************************************/
4227
 
 
4228
 
SEC_DESC* get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
4229
 
{
4230
 
        SEC_DESC *psd, *ret_sd;
4231
 
        connection_struct conn;
4232
 
        files_struct finfo;
4233
 
        struct fd_handle fh;
4234
 
        pstring path;
4235
 
        pstring filename;
4236
 
        
4237
 
        ZERO_STRUCT( conn );
4238
 
        
4239
 
        if ( !(conn.mem_ctx = talloc_init( "novfs_get_nt_acl" )) ) {
4240
 
                DEBUG(0,("get_nt_acl_no_snum: talloc() failed!\n"));
4241
 
                return NULL;
4242
 
        }
4243
 
 
4244
 
        if (!(conn.params = TALLOC_P(conn.mem_ctx, struct share_params))) {
4245
 
                DEBUG(0,("get_nt_acl_no_snum: talloc() failed!\n"));
4246
 
                TALLOC_FREE(conn.mem_ctx);
4247
 
                return NULL;
4248
 
        }
4249
 
 
4250
 
        conn.params->service = -1;
4251
 
        
4252
 
        pstrcpy( path, "/" );
4253
 
        set_conn_connectpath(&conn, path);
4254
 
        
4255
 
        if (!smbd_vfs_init(&conn)) {
4256
 
                DEBUG(0,("get_nt_acl_no_snum: Unable to create a fake connection struct!\n"));
4257
 
                conn_free_internal( &conn );
4258
 
                return NULL;
4259
 
        }
4260
 
        
4261
 
        ZERO_STRUCT( finfo );
4262
 
        ZERO_STRUCT( fh );
4263
 
        
4264
 
        finfo.fnum = -1;
4265
 
        finfo.conn = &conn;
4266
 
        finfo.fh = &fh;
4267
 
        finfo.fh->fd = -1;
4268
 
        pstrcpy( filename, fname );
4269
 
        finfo.fsp_name = filename;
4270
 
        
4271
 
        if (get_nt_acl( &finfo, DACL_SECURITY_INFORMATION, &psd ) == 0) {
4272
 
                DEBUG(0,("get_nt_acl_no_snum: get_nt_acl returned zero.\n"));
4273
 
                conn_free_internal( &conn );
4274
 
                return NULL;
4275
 
        }
4276
 
        
4277
 
        ret_sd = dup_sec_desc( ctx, psd );
4278
 
        
4279
 
        conn_free_internal( &conn );
4280
 
        
4281
 
        return ret_sd;
4282
 
}