1
From 4c4235eb2a26999870adc5538e25a4a34b7d0d17 Mon Sep 17 00:00:00 2001
2
From: Erich Hoover <ehoover@mines.edu>
3
Date: Fri, 7 Dec 2012 12:55:47 -0700
4
Subject: server: Store and return security attributes with extended file
9
dlls/advapi32/tests/security.c | 9 +-
10
dlls/kernel32/tests/directory.c | 4 +-
11
server/change.c | 11 ++-
12
server/fd.c | 68 ++++++++++++++-
13
server/file.c | 176 ++++++++++++++++++++++++++++++++++++++-
15
7 files changed, 258 insertions(+), 16 deletions(-)
17
diff --git a/configure.ac b/configure.ac
18
index 01d84cd..a3521f1 100644
21
@@ -417,6 +417,7 @@ AC_CHECK_HEADERS(\
29
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
30
index fbbbd17..4bad5d1 100644
31
--- a/dlls/advapi32/tests/security.c
32
+++ b/dlls/advapi32/tests/security.c
33
@@ -3155,7 +3155,7 @@ static void test_GetNamedSecurityInfoA(void)
34
bret = pGetAce(pDacl, 0, (VOID **)&ace);
35
ok(bret, "Failed to get Current User ACE.\n");
36
bret = EqualSid(&ace->SidStart, user_sid);
37
- todo_wine ok(bret, "Current User ACE != Current User SID.\n");
38
+ ok(bret, "Current User ACE != Current User SID.\n");
39
ok(((ACE_HEADER *)ace)->AceFlags == 0,
40
"Current User ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags);
41
ok(ace->Mask == 0x1f01ff, "Current User ACE has unexpected mask (0x%x != 0x1f01ff)\n",
42
@@ -3166,8 +3166,7 @@ static void test_GetNamedSecurityInfoA(void)
43
bret = pGetAce(pDacl, 1, (VOID **)&ace);
44
ok(bret, "Failed to get Administators Group ACE.\n");
45
bret = EqualSid(&ace->SidStart, admin_sid);
46
- todo_wine ok(bret || broken(!bret) /* win2k */,
47
- "Administators Group ACE != Administators Group SID.\n");
48
+ ok(bret || broken(!bret) /* win2k */, "Administators Group ACE != Administators Group SID.\n");
49
ok(((ACE_HEADER *)ace)->AceFlags == 0,
50
"Administators Group ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags);
51
ok(ace->Mask == 0x1f01ff || broken(ace->Mask == GENERIC_ALL) /* win2k */,
52
@@ -3748,7 +3747,7 @@ static void test_GetSecurityInfo(void)
53
bret = pGetAce(pDacl, 0, (VOID **)&ace);
54
ok(bret, "Failed to get Current User ACE.\n");
55
bret = EqualSid(&ace->SidStart, user_sid);
56
- todo_wine ok(bret, "Current User ACE != Current User SID.\n");
57
+ ok(bret, "Current User ACE != Current User SID.\n");
58
ok(((ACE_HEADER *)ace)->AceFlags == 0,
59
"Current User ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags);
60
ok(ace->Mask == 0x1f01ff, "Current User ACE has unexpected mask (0x%x != 0x1f01ff)\n",
61
@@ -3759,7 +3758,7 @@ static void test_GetSecurityInfo(void)
62
bret = pGetAce(pDacl, 1, (VOID **)&ace);
63
ok(bret, "Failed to get Administators Group ACE.\n");
64
bret = EqualSid(&ace->SidStart, admin_sid);
65
- todo_wine ok(bret, "Administators Group ACE != Administators Group SID.\n");
66
+ ok(bret, "Administators Group ACE != Administators Group SID.\n");
67
ok(((ACE_HEADER *)ace)->AceFlags == 0,
68
"Administators Group ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags);
69
ok(ace->Mask == 0x1f01ff, "Administators Group ACE has unexpected mask (0x%x != 0x1f01ff)\n",
70
diff --git a/dlls/kernel32/tests/directory.c b/dlls/kernel32/tests/directory.c
71
index 0d286d2..99d8fd1 100644
72
--- a/dlls/kernel32/tests/directory.c
73
+++ b/dlls/kernel32/tests/directory.c
74
@@ -578,7 +578,7 @@ static void test_security_attributes(void)
75
bret = pGetAce(pDacl, 0, (VOID **)&ace);
76
ok(bret, "Failed to get Current User ACE.\n");
77
bret = EqualSid(&ace->SidStart, user_sid);
78
- todo_wine ok(bret, "Current User ACE != Current User SID.\n");
79
+ ok(bret, "Current User ACE != Current User SID.\n");
80
ok(((ACE_HEADER *)ace)->AceFlags == (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE),
81
"Current User ACE has unexpected flags (0x%x != 0x03)\n", ((ACE_HEADER *)ace)->AceFlags);
82
ok(ace->Mask == 0x1f01ff, "Current User ACE has unexpected mask (0x%x != 0x1f01ff)\n",
83
@@ -589,7 +589,7 @@ static void test_security_attributes(void)
84
bret = pGetAce(pDacl, 1, (VOID **)&ace);
85
ok(bret, "Failed to get Administators Group ACE.\n");
86
bret = EqualSid(&ace->SidStart, admin_sid);
87
- todo_wine ok(bret, "Administators Group ACE != Administators Group SID.\n");
88
+ ok(bret, "Administators Group ACE != Administators Group SID.\n");
89
ok(((ACE_HEADER *)ace)->AceFlags == (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE),
90
"Administators Group ACE has unexpected flags (0x%x != 0x03)\n", ((ACE_HEADER *)ace)->AceFlags);
91
ok(ace->Mask == 0x1f01ff, "Administators Group ACE has unexpected mask (0x%x != 0x1f01ff)\n",
92
diff --git a/server/change.c b/server/change.c
93
index f6d56b0..022c780 100644
96
@@ -286,6 +286,7 @@ static int get_dir_unix_fd( struct dir *dir )
97
static struct security_descriptor *dir_get_sd( struct object *obj )
99
struct dir *dir = (struct dir *)obj;
100
+ const SID *user, *group;
103
struct security_descriptor *sd;
104
@@ -302,9 +303,11 @@ static struct security_descriptor *dir_get_sd( struct object *obj )
105
(st.st_uid == dir->uid))
108
- sd = mode_to_sd( st.st_mode,
109
- security_unix_uid_to_sid( st.st_uid ),
110
- token_get_primary_group( current->process->token ));
111
+ user = security_unix_uid_to_sid( st.st_uid );
112
+ group = token_get_primary_group( current->process->token );
113
+ sd = get_file_acls( unix_fd, user, group );
115
+ sd = mode_to_sd( st.st_mode, user, group );
116
if (!sd) return obj->sd;
118
dir->mode = st.st_mode;
119
@@ -353,6 +356,8 @@ static int dir_set_sd( struct object *obj, const struct security_descriptor *sd,
120
mode = st.st_mode & (S_ISUID|S_ISGID|S_ISVTX);
121
mode |= sd_to_mode( sd, owner );
123
+ set_file_acls( unix_fd, sd );
125
if (((st.st_mode ^ mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, mode ) == -1)
128
diff --git a/server/fd.c b/server/fd.c
129
index 248f15a..687d4a9 100644
133
#include <sys/time.h>
134
#include <sys/types.h>
136
+#ifdef HAVE_ATTR_XATTR_H
137
+#include <attr/xattr.h>
140
#include "ntstatus.h"
141
#define WIN32_NO_STATUS
146
+#include "security.h"
148
#include "winternl.h"
149
#include "winioctl.h"
150
@@ -1723,9 +1727,69 @@ static char *dup_fd_name( struct fd *root, const char *name )
154
+void set_file_acls( int fd, const struct security_descriptor *sd )
156
+#ifdef HAVE_ATTR_XATTR_H
157
+ char buffer[XATTR_SIZE_MAX], *p = buffer;
158
+ const ACE_HEADER *ace;
159
+ int present, i, j, n;
163
+ dacl = sd_get_dacl( sd, &present );
164
+ if (!present || !dacl) return;
165
+ ace = (const ACE_HEADER *)(dacl + 1);
167
+ for (i = 0; i < dacl->AceCount; i++, ace = ace_next( ace ))
169
+ BYTE type = ace->AceType, flags;
170
+ const ACCESS_ALLOWED_ACE *aaa;
171
+ const ACCESS_DENIED_ACE *ada;
172
+ char sidtxt[100], *s;
176
+ if (type & INHERIT_ONLY_ACE) continue;
180
+ case ACCESS_DENIED_ACE_TYPE:
181
+ ada = (const ACCESS_DENIED_ACE *)ace;
182
+ flags = ada->Header.AceFlags;
184
+ sid = (const SID *)&ada->SidStart;
186
+ case ACCESS_ALLOWED_ACE_TYPE:
187
+ aaa = (const ACCESS_ALLOWED_ACE *)ace;
188
+ flags = aaa->Header.AceFlags;
190
+ sid = (const SID *)&aaa->SidStart;
195
+ n = sprintf( sidtxt, "S-%u-%d", sid->Revision,
197
+ MAKEWORD( sid->IdentifierAuthority.Value[5],
198
+ sid->IdentifierAuthority.Value[4] ),
199
+ MAKEWORD( sid->IdentifierAuthority.Value[3],
200
+ sid->IdentifierAuthority.Value[2] )
203
+ for( j=0; j<sid->SubAuthorityCount; j++ )
204
+ s += sprintf( s, "-%u", sid->SubAuthority[j] );
206
+ p += snprintf( p, XATTR_SIZE_MAX-(p-buffer), "%s%x,%x,%x,%s",
207
+ (p != buffer ? ";" : ""), type, flags, mask, sidtxt );
210
+ fsetxattr( fd, "user.wine.acl", buffer, p-buffer, 0 );
214
/* open() wrapper that returns a struct fd with no fd user set */
215
struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode, unsigned int access,
216
- unsigned int sharing, unsigned int options )
217
+ unsigned int sharing, unsigned int options, const struct security_descriptor *sd )
220
struct closed_fd *closed_fd;
221
@@ -1801,6 +1865,8 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
225
+ set_file_acls( fd->unix_fd, sd );
227
closed_fd->unix_fd = fd->unix_fd;
228
closed_fd->unlink[0] = 0;
229
fstat( fd->unix_fd, &st );
230
diff --git a/server/file.c b/server/file.c
231
index 3a8c964..3fd1f42 100644
235
#include <sys/time.h>
236
#include <sys/types.h>
246
+#ifdef HAVE_ATTR_XATTR_H
247
+#include <attr/xattr.h>
250
#include "ntstatus.h"
251
#define WIN32_NO_STATUS
252
@@ -240,7 +244,7 @@ static struct object *create_file( struct fd *root, const char *nameptr, data_si
253
access = generic_file_map_access( access );
255
/* FIXME: should set error to STATUS_OBJECT_NAME_COLLISION if file existed before */
256
- fd = open_fd( root, name, flags | O_NONBLOCK | O_LARGEFILE, &mode, access, sharing, options );
257
+ fd = open_fd( root, name, flags | O_NONBLOCK | O_LARGEFILE, &mode, access, sharing, options, sd );
261
@@ -435,9 +439,169 @@ struct security_descriptor *mode_to_sd( mode_t mode, const SID *user, const SID
265
+struct security_descriptor *get_file_acls( int fd, const SID *user, const SID *group )
267
+#ifdef HAVE_ATTR_XATTR_H
268
+ int ace_count = 0, dacl_size = sizeof(ACL), i, n;
269
+ char buffer[XATTR_SIZE_MAX], *p = buffer, *pn;
270
+ struct security_descriptor *sd;
271
+ ACE_HEADER *current_ace;
272
+ ACCESS_ALLOWED_ACE *aaa;
273
+ ACCESS_DENIED_ACE *ada;
274
+ int type, flags, mask;
278
+ n = fgetxattr( fd, "user.wine.acl", buffer, sizeof(buffer) );
279
+ if (n == -1) return NULL;
284
+ int sub_authority_count = 0;
286
+ pn = strchr(p, ';');
288
+ sscanf(p, "%x", &type);
291
+ p = strchr(p, '-');
293
+ sub_authority_count++;
295
+ while(p && (!pn || p < pn));
296
+ sub_authority_count -= 3; /* Revision and IdentifierAuthority don't count */
300
+ case ACCESS_DENIED_ACE_TYPE:
301
+ dacl_size += FIELD_OFFSET(ACCESS_DENIED_ACE, SidStart) +
302
+ FIELD_OFFSET(SID, SubAuthority[sub_authority_count]);
304
+ case ACCESS_ALLOWED_ACE_TYPE:
305
+ dacl_size += FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) +
306
+ FIELD_OFFSET(SID, SubAuthority[sub_authority_count]);
316
+ sd = mem_alloc( sizeof(struct security_descriptor) +
317
+ FIELD_OFFSET(SID, SubAuthority[user->SubAuthorityCount]) +
318
+ FIELD_OFFSET(SID, SubAuthority[group->SubAuthorityCount]) +
321
+ sd->control = SE_DACL_PRESENT;
322
+ sd->owner_len = FIELD_OFFSET(SID, SubAuthority[user->SubAuthorityCount]);
323
+ sd->group_len = FIELD_OFFSET(SID, SubAuthority[group->SubAuthorityCount]);
325
+ sd->dacl_len = dacl_size;
327
+ ptr = (char *)(sd + 1);
328
+ memcpy( ptr, user, sd->owner_len );
329
+ ptr += sd->owner_len;
330
+ memcpy( ptr, group, sd->group_len );
331
+ ptr += sd->group_len;
334
+ dacl->AclRevision = ACL_REVISION;
336
+ dacl->AclSize = dacl_size;
337
+ dacl->AceCount = ace_count;
339
+ aaa = (ACCESS_ALLOWED_ACE *)(dacl + 1);
340
+ current_ace = &aaa->Header;
343
+ for(i=0; i<ace_count; i++)
345
+ char b[sizeof(SID) + sizeof(ULONG) * SID_MAX_SUB_AUTHORITIES];
346
+ int sub_authority_count = 0;
347
+ SID *sid = (SID *)&b[0];
353
+ aaa = (ACCESS_ALLOWED_ACE *)ace_next( current_ace );
354
+ current_ace = &aaa->Header;
356
+ pn = strchr(p, ';');
358
+ sscanf(p, "%x,%x,%x,%[^;]", &type, &flags, &mask, sidtxt);
359
+ sscanf(sidtxt, "S-%u-%d", &rev, &ia);
360
+ sid->Revision = rev;
361
+ sid->IdentifierAuthority.Value[0] = 0;
362
+ sid->IdentifierAuthority.Value[1] = 0;
363
+ sid->IdentifierAuthority.Value[2] = HIBYTE(HIWORD(ia));
364
+ sid->IdentifierAuthority.Value[3] = LOBYTE(HIWORD(ia));
365
+ sid->IdentifierAuthority.Value[4] = HIBYTE(LOWORD(ia));
366
+ sid->IdentifierAuthority.Value[5] = LOBYTE(LOWORD(ia));
367
+ p = strchr(sidtxt, '-')+1;
368
+ p = strchr(p, '-')+1; /* Revision doesn't count */
369
+ p = strchr(p, '-')+1; /* IdentifierAuthority doesn't count */
372
+ sscanf(p, "%u", &sa);
373
+ sid->SubAuthority[sub_authority_count] = sa;
374
+ p = strchr(p, '-');
376
+ sub_authority_count++;
379
+ sid->SubAuthorityCount = sub_authority_count;
381
+ /* Convert generic rights into standard access rights */
382
+ if (mask & GENERIC_ALL)
383
+ mask |= WRITE_DAC | WRITE_OWNER | DELETE | FILE_DELETE_CHILD;
384
+ if (mask & (GENERIC_ALL|GENERIC_READ))
385
+ mask |= FILE_GENERIC_READ;
386
+ if (mask & (GENERIC_ALL|GENERIC_WRITE))
387
+ mask |= FILE_GENERIC_WRITE;
388
+ if (mask & (GENERIC_ALL|GENERIC_EXECUTE))
389
+ mask |= FILE_GENERIC_EXECUTE;
390
+ mask &= 0x0FFFFFFF;
392
+ /* Handle the specific ACE */
395
+ case ACCESS_DENIED_ACE_TYPE:
396
+ ada = (ACCESS_DENIED_ACE *)aaa;
397
+ ada->Header.AceType = type;
398
+ ada->Header.AceFlags = flags;
399
+ ada->Header.AceSize = FIELD_OFFSET(ACCESS_DENIED_ACE, SidStart) +
400
+ FIELD_OFFSET(SID, SubAuthority[sid->SubAuthorityCount]);
402
+ memcpy( &ada->SidStart, sid, FIELD_OFFSET(SID, SubAuthority[sid->SubAuthorityCount]) );
404
+ case ACCESS_ALLOWED_ACE_TYPE:
405
+ aaa->Header.AceType = type;
406
+ aaa->Header.AceFlags = flags;
407
+ aaa->Header.AceSize = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) +
408
+ FIELD_OFFSET(SID, SubAuthority[sid->SubAuthorityCount]);
410
+ memcpy( &aaa->SidStart, sid, FIELD_OFFSET(SID, SubAuthority[sid->SubAuthorityCount]) );
424
static struct security_descriptor *file_get_sd( struct object *obj )
426
struct file *file = (struct file *)obj;
427
+ const SID *user, *group;
430
struct security_descriptor *sd;
431
@@ -454,9 +618,11 @@ static struct security_descriptor *file_get_sd( struct object *obj )
432
(st.st_uid == file->uid))
435
- sd = mode_to_sd( st.st_mode,
436
- security_unix_uid_to_sid( st.st_uid ),
437
- token_get_primary_group( current->process->token ));
438
+ user = security_unix_uid_to_sid( st.st_uid );
439
+ group = token_get_primary_group( current->process->token );
440
+ sd = get_file_acls( unix_fd, user, group );
442
+ sd = mode_to_sd( st.st_mode, user, group);
443
if (!sd) return obj->sd;
445
file->mode = st.st_mode;
446
@@ -586,6 +752,8 @@ static int file_set_sd( struct object *obj, const struct security_descriptor *sd
447
mode = st.st_mode & (S_ISUID|S_ISGID|S_ISVTX);
448
mode |= sd_to_mode( sd, owner );
450
+ set_file_acls( unix_fd, sd );
452
if (((st.st_mode ^ mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, mode ) == -1)
455
diff --git a/server/file.h b/server/file.h
456
index ead356d..77737e8 100644
459
@@ -56,7 +56,8 @@ extern struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct obje
460
unsigned int options );
461
extern void set_no_fd_status( struct fd *fd, unsigned int status );
462
extern struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
463
- unsigned int access, unsigned int sharing, unsigned int options );
464
+ unsigned int access, unsigned int sharing, unsigned int options,
465
+ const struct security_descriptor *sd );
466
extern struct fd *create_anonymous_fd( const struct fd_ops *fd_user_ops,
467
int unix_fd, struct object *user, unsigned int options );
468
extern struct fd *dup_fd_object( struct fd *orig, unsigned int access, unsigned int sharing,
469
@@ -122,6 +123,8 @@ extern struct file *create_file_for_fd_obj( struct fd *fd, unsigned int access,
470
extern void file_set_error(void);
471
extern struct security_descriptor *mode_to_sd( mode_t mode, const SID *user, const SID *group );
472
extern mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner );
473
+extern void set_file_acls( int fd, const struct security_descriptor *sd );
474
+extern struct security_descriptor *get_file_acls( int fd, const SID *user, const SID *group );
476
/* file mapping functions */