blob: cba678221a9615094dc602ee8a0a1d7d3e030b65 [file] [log] [blame]
Mike McCormack36cd6f52003-07-24 00:07:00 +00001/*
2 * Tokens
3 *
4 * Copyright (C) 1998 Alexandre Julliard
5 * Copyright (C) 2003 Mike McCormack
Robert Shearmand2ea92d2005-04-22 21:17:15 +00006 * Copyright (C) 2005 Robert Shearman
Mike McCormack36cd6f52003-07-24 00:07:00 +00007 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include "config.h"
24
25#include <assert.h>
26#include <stdio.h>
27#include <stdlib.h>
28
29#include "windef.h"
30
31#include "handle.h"
32#include "thread.h"
33#include "process.h"
34#include "request.h"
Robert Shearmand2ea92d2005-04-22 21:17:15 +000035#include "security.h"
36
Robert Shearman2a782c62005-05-16 17:52:46 +000037#define MAX_SUBAUTH_COUNT 1
38
Robert Shearmand2ea92d2005-04-22 21:17:15 +000039const LUID SeIncreaseQuotaPrivilege = { 5, 0 };
40const LUID SeSecurityPrivilege = { 8, 0 };
41const LUID SeTakeOwnershipPrivilege = { 9, 0 };
42const LUID SeLoadDriverPrivilege = { 10, 0 };
43const LUID SeSystemProfilePrivilege = { 11, 0 };
44const LUID SeSystemtimePrivilege = { 12, 0 };
45const LUID SeProfileSingleProcessPrivilege = { 13, 0 };
46const LUID SeIncreaseBasePriorityPrivilege = { 14, 0 };
47const LUID SeCreatePagefilePrivilege = { 15, 0 };
48const LUID SeBackupPrivilege = { 17, 0 };
49const LUID SeRestorePrivilege = { 18, 0 };
50const LUID SeShutdownPrivilege = { 19, 0 };
51const LUID SeDebugPrivilege = { 20, 0 };
52const LUID SeSystemEnvironmentPrivilege = { 22, 0 };
53const LUID SeChangeNotifyPrivilege = { 23, 0 };
54const LUID SeRemoteShutdownPrivilege = { 24, 0 };
55const LUID SeUndockPrivilege = { 25, 0 };
56const LUID SeManageVolumePrivilege = { 28, 0 };
57const LUID SeImpersonatePrivilege = { 29, 0 };
58const LUID SeCreateGlobalPrivilege = { 30, 0 };
Mike McCormack36cd6f52003-07-24 00:07:00 +000059
Robert Shearman9b826442005-06-09 09:47:28 +000060static const SID world_sid = { SID_REVISION, 1, { SECURITY_WORLD_SID_AUTHORITY }, { SECURITY_WORLD_RID } };
61static const SID local_sid = { SID_REVISION, 1, { SECURITY_LOCAL_SID_AUTHORITY }, { SECURITY_LOCAL_RID } };
62static const SID interactive_sid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_INTERACTIVE_RID } };
63static const SID authenticated_user_sid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_AUTHENTICATED_USER_RID } };
64static const SID local_system_sid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_LOCAL_SYSTEM_RID } };
65static PSID security_world_sid = (PSID)&world_sid;
66static PSID security_local_sid = (PSID)&local_sid;
67static PSID security_interactive_sid = (PSID)&interactive_sid;
68static PSID security_authenticated_user_sid = (PSID)&authenticated_user_sid;
69
Mike McCormack36cd6f52003-07-24 00:07:00 +000070struct token
71{
72 struct object obj; /* object header */
Robert Shearmanb0f02b22005-02-11 11:52:06 +000073 struct list privileges; /* privileges available to the token */
Robert Shearman4ad93412005-05-24 12:32:18 +000074 struct list groups; /* groups that the user of this token belongs to (sid_and_attributes) */
Robert Shearman2a782c62005-05-16 17:52:46 +000075 SID *user; /* SID of user this token represents */
Robert Shearmanf95ef092005-06-14 18:10:04 +000076 unsigned primary; /* is this a primary or impersonation token? */
Robert Shearmanb0f02b22005-02-11 11:52:06 +000077};
78
79struct privilege
80{
81 struct list entry;
82 LUID luid;
Michael Stefaniucd40517c2005-05-09 09:26:28 +000083 unsigned enabled : 1; /* is the privilege currently enabled? */
84 unsigned def : 1; /* is the privilege enabled by default? */
Mike McCormack36cd6f52003-07-24 00:07:00 +000085};
86
Robert Shearman4ad93412005-05-24 12:32:18 +000087struct sid_and_attributes
88{
89 struct list entry;
Robert Shearman9b826442005-06-09 09:47:28 +000090 unsigned enabled : 1; /* is the sid currently enabled? */
91 unsigned def : 1; /* is the sid enabled by default? */
92 unsigned logon : 1; /* is this a logon sid? */
93 unsigned mandatory: 1; /* is this sid always enabled? */
94 unsigned owner : 1; /* can this sid be an owner of an object? */
95 unsigned resource : 1; /* is this a domain-local group? */
96 unsigned deny_only: 1; /* is this a sid that should be use for denying only? */
Robert Shearman4ad93412005-05-24 12:32:18 +000097 SID sid;
98};
99
Mike McCormack36cd6f52003-07-24 00:07:00 +0000100static void token_dump( struct object *obj, int verbose );
Robert Shearmanb0f02b22005-02-11 11:52:06 +0000101static void token_destroy( struct object *obj );
Mike McCormack36cd6f52003-07-24 00:07:00 +0000102
103static const struct object_ops token_ops =
104{
105 sizeof(struct token), /* size */
106 token_dump, /* dump */
107 no_add_queue, /* add_queue */
108 NULL, /* remove_queue */
109 NULL, /* signaled */
Mike McCormackf92fff62005-04-24 17:35:52 +0000110 NULL, /* satisfied */
111 no_signal, /* signal */
Mike McCormack36cd6f52003-07-24 00:07:00 +0000112 no_get_fd, /* get_fd */
Alexandre Julliardb9b1ea92005-06-09 15:39:52 +0000113 no_close_handle, /* close_handle */
Robert Shearmanb0f02b22005-02-11 11:52:06 +0000114 token_destroy /* destroy */
Mike McCormack36cd6f52003-07-24 00:07:00 +0000115};
116
117
118static void token_dump( struct object *obj, int verbose )
119{
120 fprintf( stderr, "Security token\n" );
Robert Shearman4ad93412005-05-24 12:32:18 +0000121 /* FIXME: dump token members */
Mike McCormack36cd6f52003-07-24 00:07:00 +0000122}
123
Robert Shearman2a782c62005-05-16 17:52:46 +0000124static SID *security_sid_alloc( const SID_IDENTIFIER_AUTHORITY *idauthority, int subauthcount, const unsigned int subauth[] )
125{
126 int i;
127 SID *sid = mem_alloc( FIELD_OFFSET(SID, SubAuthority[subauthcount]) );
128 if (!sid) return NULL;
Robert Shearman9b826442005-06-09 09:47:28 +0000129 sid->Revision = SID_REVISION;
Robert Shearman2a782c62005-05-16 17:52:46 +0000130 sid->SubAuthorityCount = subauthcount;
131 sid->IdentifierAuthority = *idauthority;
132 for (i = 0; i < subauthcount; i++)
133 sid->SubAuthority[i] = subauth[i];
134 return sid;
135}
136
137static inline int security_equal_sid( const SID *sid1, const SID *sid2 )
138{
139 return ((sid1->SubAuthorityCount == sid2->SubAuthorityCount) &&
140 !memcmp( sid1, sid2, FIELD_OFFSET(SID, SubAuthority[sid1->SubAuthorityCount]) ));
141}
142
Robert Shearman4ad93412005-05-24 12:32:18 +0000143static const ACE_HEADER *ace_next( const ACE_HEADER *ace )
144{
145 return (const ACE_HEADER *)((const char *)ace + ace->AceSize);
146}
147
148static int acl_is_valid( const ACL *acl, size_t size )
149{
150 ULONG i;
151 const ACE_HEADER *ace;
152
153 if (size < sizeof(ACL))
154 return FALSE;
155
156 size = min(size, MAX_ACL_LEN);
157
158 size -= sizeof(ACL);
159
160 ace = (const ACE_HEADER *)(acl + 1);
161 for (i = 0; i < acl->AceCount; i++)
162 {
163 const SID *sid;
164
165 if (size < sizeof(ACE_HEADER))
166 return FALSE;
167 if (size < ace->AceSize)
168 return FALSE;
169 size -= ace->AceSize;
170 switch (ace->AceType)
171 {
172 case ACCESS_DENIED_ACE_TYPE:
173 sid = (const SID *)&((const ACCESS_DENIED_ACE *)ace)->SidStart;
174 break;
175 case ACCESS_ALLOWED_ACE_TYPE:
176 sid = (const SID *)&((const ACCESS_ALLOWED_ACE *)ace)->SidStart;
177 break;
178 case SYSTEM_AUDIT_ACE_TYPE:
179 sid = (const SID *)&((const SYSTEM_AUDIT_ACE *)ace)->SidStart;
180 break;
181 case SYSTEM_ALARM_ACE_TYPE:
182 sid = (const SID *)&((const SYSTEM_ALARM_ACE *)ace)->SidStart;
183 break;
184 default:
185 return FALSE;
186 }
187 if (size < sizeof(SID) ||
188 size < FIELD_OFFSET(SID, SubAuthority[sid->SubAuthorityCount]))
189 return FALSE;
190 ace = ace_next( ace );
191 }
192 return TRUE;
193}
194
195/* gets the discretionary access control list from a security descriptor */
196static inline const ACL *sd_get_dacl( const struct security_descriptor *sd, int *present )
197{
198 *present = (sd->control & SE_DACL_PRESENT ? TRUE : FALSE);
199
200 if (sd->dacl_len)
201 return (const ACL *)((const char *)(sd + 1) +
202 sd->owner_len + sd->group_len + sd->sacl_len);
203 else
204 return NULL;
205}
206
207/* gets the system access control list from a security descriptor */
208static inline const ACL *sd_get_sacl( const struct security_descriptor *sd, int *present )
209{
210 *present = (sd->control & SE_SACL_PRESENT ? TRUE : FALSE);
211
212 if (sd->sacl_len)
213 return (const ACL *)((const char *)(sd + 1) +
214 sd->owner_len + sd->group_len);
215 else
216 return NULL;
217}
218
219/* gets the owner from a security descriptor */
220static inline const SID *sd_get_owner( const struct security_descriptor *sd )
221{
222 if (sd->owner_len)
223 return (const SID *)(sd + 1);
224 else
225 return NULL;
226}
227
228/* gets the primary group from a security descriptor */
229static inline const SID *sd_get_group( const struct security_descriptor *sd )
230{
231 if (sd->group_len)
232 return (const SID *)((const char *)(sd + 1) + sd->owner_len);
233 else
234 return NULL;
235}
236
237/* checks whether all members of a security descriptor fit inside the size
238 * of memory specified */
239static int sd_is_valid( const struct security_descriptor *sd, size_t size )
240{
241 size_t offset = sizeof(struct security_descriptor);
242 const SID *group;
243 const SID *owner;
244 const ACL *sacl;
245 const ACL *dacl;
246 int dummy;
247
248 if (size < offset)
249 return FALSE;
250
251 if ((sd->owner_len >= FIELD_OFFSET(SID, SubAuthority[255])) ||
252 (offset + sd->owner_len > size))
253 return FALSE;
254 owner = sd_get_owner( sd );
255 if (owner)
256 {
257 size_t needed_size = FIELD_OFFSET(SID, SubAuthority[owner->SubAuthorityCount]);
258 if ((sd->owner_len < sizeof(SID)) || (needed_size > sd->owner_len))
259 return FALSE;
260 }
261 offset += sd->owner_len;
262
263 if ((sd->group_len >= FIELD_OFFSET(SID, SubAuthority[255])) ||
264 (offset + sd->group_len > size))
265 return FALSE;
266 group = sd_get_group( sd );
267 if (group)
268 {
269 size_t needed_size = FIELD_OFFSET(SID, SubAuthority[group->SubAuthorityCount]);
270 if ((sd->owner_len < sizeof(SID)) || (needed_size > sd->owner_len))
271 return FALSE;
272 }
273 offset += sd->group_len;
274
275 if ((sd->sacl_len >= MAX_ACL_LEN) || (offset + sd->sacl_len > size))
276 return FALSE;
277 sacl = sd_get_sacl( sd, &dummy );
278 if (sacl && !acl_is_valid( sacl, sd->sacl_len ))
279 return FALSE;
280 offset += sd->sacl_len;
281
282 if ((sd->dacl_len >= MAX_ACL_LEN) || (offset + sd->dacl_len > size))
283 return FALSE;
284 dacl = sd_get_dacl( sd, &dummy );
285 if (dacl && !acl_is_valid( dacl, sd->dacl_len ))
286 return FALSE;
287 offset += sd->dacl_len;
288
289 return TRUE;
290}
291
292/* maps from generic rights to specific rights as given by a mapping */
293static inline void map_generic_mask(unsigned int *mask, const GENERIC_MAPPING *mapping)
294{
295 if (*mask & GENERIC_READ) *mask |= mapping->GenericRead;
296 if (*mask & GENERIC_WRITE) *mask |= mapping->GenericWrite;
297 if (*mask & GENERIC_EXECUTE) *mask |= mapping->GenericExecute;
298 if (*mask & GENERIC_ALL) *mask |= mapping->GenericAll;
299 *mask &= 0x0FFFFFFF;
300}
301
Robert Shearmanb0f02b22005-02-11 11:52:06 +0000302static inline int is_equal_luid( const LUID *luid1, const LUID *luid2 )
303{
304 return (luid1->LowPart == luid2->LowPart && luid1->HighPart == luid2->HighPart);
305}
306
307static inline void luid_and_attr_from_privilege( LUID_AND_ATTRIBUTES *out, const struct privilege *in)
308{
309 out->Luid = in->luid;
310 out->Attributes =
311 (in->enabled ? SE_PRIVILEGE_ENABLED : 0) |
312 (in->def ? SE_PRIVILEGE_ENABLED_BY_DEFAULT : 0);
313}
314
315static struct privilege *privilege_add( struct token *token, const LUID *luid, int enabled )
316{
317 struct privilege *privilege = mem_alloc( sizeof(*privilege) );
318 if (privilege)
319 {
320 privilege->luid = *luid;
321 privilege->def = privilege->enabled = (enabled != 0);
322 list_add_tail( &token->privileges, &privilege->entry );
323 }
324 return privilege;
325}
326
Robert Shearman2a782c62005-05-16 17:52:46 +0000327static inline void privilege_remove( struct privilege *privilege )
Robert Shearmanb0f02b22005-02-11 11:52:06 +0000328{
329 list_remove( &privilege->entry );
330 free( privilege );
331}
332
333static void token_destroy( struct object *obj )
334{
335 struct token* token;
336 struct list *cursor, *cursor_next;
337
338 assert( obj->ops == &token_ops );
339 token = (struct token *)obj;
340
Robert Shearman2a782c62005-05-16 17:52:46 +0000341 free( token->user );
342
Robert Shearmanb0f02b22005-02-11 11:52:06 +0000343 LIST_FOR_EACH_SAFE( cursor, cursor_next, &token->privileges )
344 {
345 struct privilege *privilege = LIST_ENTRY( cursor, struct privilege, entry );
346 privilege_remove( privilege );
347 }
Robert Shearman4ad93412005-05-24 12:32:18 +0000348
349 LIST_FOR_EACH_SAFE( cursor, cursor_next, &token->groups )
350 {
351 struct sid_and_attributes *group = LIST_ENTRY( cursor, struct sid_and_attributes, entry );
352 list_remove( &group->entry );
353 free( group );
354 }
Robert Shearmanb0f02b22005-02-11 11:52:06 +0000355}
356
Robert Shearmanf95ef092005-06-14 18:10:04 +0000357static struct token *create_token( unsigned primary, const SID *user,
Robert Shearman9b826442005-06-09 09:47:28 +0000358 const SID_AND_ATTRIBUTES *groups, unsigned int group_count,
359 const LUID_AND_ATTRIBUTES *privs, unsigned int priv_count )
Mike McCormack36cd6f52003-07-24 00:07:00 +0000360{
361 struct token *token = alloc_object( &token_ops );
Robert Shearmanb0f02b22005-02-11 11:52:06 +0000362 if (token)
363 {
364 int i;
Robert Shearmanf95ef092005-06-14 18:10:04 +0000365
Robert Shearmanb0f02b22005-02-11 11:52:06 +0000366 list_init( &token->privileges );
Robert Shearman4ad93412005-05-24 12:32:18 +0000367 list_init( &token->groups );
Robert Shearmanf95ef092005-06-14 18:10:04 +0000368 token->primary = primary;
369
Robert Shearman2a782c62005-05-16 17:52:46 +0000370 /* copy user */
371 token->user = memdup( user, FIELD_OFFSET(SID, SubAuthority[user->SubAuthorityCount]) );
372 if (!token->user)
373 {
374 release_object( token );
375 return NULL;
376 }
Robert Shearman4ad93412005-05-24 12:32:18 +0000377
Robert Shearman9b826442005-06-09 09:47:28 +0000378 /* copy groups */
379 for (i = 0; i < group_count; i++)
380 {
381 size_t size = FIELD_OFFSET( struct sid_and_attributes, sid.SubAuthority[((const SID *)groups[i].Sid)->SubAuthorityCount] );
382 struct sid_and_attributes *group = mem_alloc( size );
383 memcpy( &group->sid, groups[i].Sid, FIELD_OFFSET( SID, SubAuthority[((const SID *)groups[i].Sid)->SubAuthorityCount] ) );
384 group->enabled = TRUE;
385 group->def = TRUE;
386 group->logon = FALSE;
387 group->mandatory = (groups[i].Attributes & SE_GROUP_MANDATORY) ? TRUE : FALSE;
388 group->owner = FALSE;
389 group->resource = FALSE;
390 group->deny_only = FALSE;
391 list_add_tail( &token->groups, &group->entry );
392 }
Robert Shearman4ad93412005-05-24 12:32:18 +0000393
Robert Shearman2a782c62005-05-16 17:52:46 +0000394 /* copy privileges */
Robert Shearmanb0f02b22005-02-11 11:52:06 +0000395 for (i = 0; i < priv_count; i++)
396 {
397 /* note: we don't check uniqueness: the caller must make sure
398 * privs doesn't contain any duplicate luids */
399 if (!privilege_add( token, &privs[i].Luid,
400 privs[i].Attributes & SE_PRIVILEGE_ENABLED ))
401 {
402 release_object( token );
403 return NULL;
404 }
405 }
406 }
Mike McCormack36cd6f52003-07-24 00:07:00 +0000407 return token;
408}
409
Robert Shearman2a782c62005-05-16 17:52:46 +0000410struct sid_data
411{
412 SID_IDENTIFIER_AUTHORITY idauth;
413 int count;
414 unsigned int subauth[MAX_SUBAUTH_COUNT];
415};
416
Robert Shearmand2ea92d2005-04-22 21:17:15 +0000417struct token *token_create_admin( void )
Robert Shearmanb0f02b22005-02-11 11:52:06 +0000418{
Robert Shearman9b826442005-06-09 09:47:28 +0000419 struct token *token = NULL;
420 static const SID_IDENTIFIER_AUTHORITY nt_authority = { SECURITY_NT_AUTHORITY };
421 static const unsigned int alias_admins_subauth[] = { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS };
422 static const unsigned int alias_users_subauth[] = { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS };
423 PSID alias_admins_sid;
424 PSID alias_users_sid;
425
426 alias_admins_sid = security_sid_alloc( &nt_authority, sizeof(alias_admins_subauth)/sizeof(alias_admins_subauth[0]),
427 alias_admins_subauth );
428 alias_users_sid = security_sid_alloc( &nt_authority, sizeof(alias_users_subauth)/sizeof(alias_users_subauth[0]),
429 alias_users_subauth );
430
431 if (alias_admins_sid && alias_users_sid)
Robert Shearmanb0f02b22005-02-11 11:52:06 +0000432 {
Robert Shearman9b826442005-06-09 09:47:28 +0000433 const LUID_AND_ATTRIBUTES admin_privs[] =
434 {
435 { SeChangeNotifyPrivilege , SE_PRIVILEGE_ENABLED },
436 { SeSecurityPrivilege , 0 },
437 { SeBackupPrivilege , 0 },
438 { SeRestorePrivilege , 0 },
439 { SeSystemtimePrivilege , 0 },
440 { SeShutdownPrivilege , 0 },
441 { SeRemoteShutdownPrivilege , 0 },
442 { SeTakeOwnershipPrivilege , 0 },
443 { SeDebugPrivilege , 0 },
444 { SeSystemEnvironmentPrivilege , 0 },
445 { SeSystemProfilePrivilege , 0 },
446 { SeProfileSingleProcessPrivilege, 0 },
447 { SeIncreaseBasePriorityPrivilege, 0 },
448 { SeLoadDriverPrivilege , 0 },
449 { SeCreatePagefilePrivilege , 0 },
450 { SeIncreaseQuotaPrivilege , 0 },
451 { SeUndockPrivilege , 0 },
452 { SeManageVolumePrivilege , 0 },
453 { SeImpersonatePrivilege , SE_PRIVILEGE_ENABLED },
454 { SeCreateGlobalPrivilege , SE_PRIVILEGE_ENABLED },
455 };
456 /* note: we don't include non-builtin groups here for the user -
457 * telling us these is the job of a client-side program */
458 const SID_AND_ATTRIBUTES admin_groups[] =
459 {
460 { security_world_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY },
461 { security_local_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY },
462 { security_interactive_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY },
463 { security_authenticated_user_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY },
464 { alias_admins_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY },
465 { alias_users_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY },
466 };
467 /* note: we just set the user sid to be the local system builtin sid -
468 * telling us what this should be is the job of a client-side program */
Robert Shearmanf95ef092005-06-14 18:10:04 +0000469 token = create_token( TRUE, &local_system_sid,
Robert Shearman9b826442005-06-09 09:47:28 +0000470 admin_groups, sizeof(admin_groups)/sizeof(admin_groups[0]),
471 admin_privs, sizeof(admin_privs)/sizeof(admin_privs[0]) );
472 }
473
474 if (alias_admins_sid)
475 free( alias_admins_sid );
476 if (alias_users_sid)
477 free( alias_users_sid );
478
Robert Shearman2a782c62005-05-16 17:52:46 +0000479 return token;
Robert Shearmanb0f02b22005-02-11 11:52:06 +0000480}
481
482static struct privilege *token_find_privilege( struct token *token, const LUID *luid, int enabled_only)
483{
484 struct privilege *privilege;
485 LIST_FOR_EACH_ENTRY( privilege, &token->privileges, struct privilege, entry )
486 {
487 if (is_equal_luid( luid, &privilege->luid ))
488 {
489 if (enabled_only && !privilege->enabled)
490 return NULL;
491 return privilege;
492 }
493 }
494 return NULL;
495}
496
497static unsigned int token_adjust_privileges( struct token *token, const LUID_AND_ATTRIBUTES *privs,
498 unsigned int count, LUID_AND_ATTRIBUTES *mod_privs,
499 unsigned int mod_privs_count)
500{
501 int i;
502 unsigned int modified_count = 0;
503
504 for (i = 0; i < count; i++)
505 {
506 struct privilege *privilege =
507 token_find_privilege( token, &privs[i].Luid, FALSE );
508 if (!privilege)
509 {
510 set_error( STATUS_NOT_ALL_ASSIGNED );
511 continue;
512 }
513
514 if (privs[i].Attributes & SE_PRIVILEGE_REMOVE)
515 privilege_remove( privilege );
516 else
517 {
518 /* save previous state for caller */
519 if (mod_privs_count)
520 {
521 luid_and_attr_from_privilege(mod_privs, privilege);
522 mod_privs++;
523 mod_privs_count--;
524 modified_count++;
525 }
526
527 if (privs[i].Attributes & SE_PRIVILEGE_ENABLED)
528 privilege->enabled = TRUE;
529 else
530 privilege->enabled = FALSE;
531 }
532 }
533 return modified_count;
534}
535
536static void token_disable_privileges( struct token *token )
537{
538 struct privilege *privilege;
539 LIST_FOR_EACH_ENTRY( privilege, &token->privileges, struct privilege, entry )
540 privilege->enabled = FALSE;
541}
542
Robert Shearmand2ea92d2005-04-22 21:17:15 +0000543int token_check_privileges( struct token *token, int all_required,
544 const LUID_AND_ATTRIBUTES *reqprivs,
545 unsigned int count, LUID_AND_ATTRIBUTES *usedprivs)
546{
547 int i;
548 unsigned int enabled_count = 0;
549
550 for (i = 0; i < count; i++)
551 {
552 struct privilege *privilege =
553 token_find_privilege( token, &reqprivs[i].Luid, TRUE );
554
555 if (usedprivs)
556 usedprivs[i] = reqprivs[i];
557
558 if (privilege && privilege->enabled)
559 {
560 enabled_count++;
561 if (usedprivs)
562 usedprivs[i].Attributes |= SE_PRIVILEGE_USED_FOR_ACCESS;
563 }
564 }
565
566 if (all_required)
567 return (enabled_count == count);
568 else
569 return (enabled_count > 0);
570}
571
Robert Shearman4ad93412005-05-24 12:32:18 +0000572static int token_sid_present( struct token *token, const SID *sid, int deny )
573{
574 struct sid_and_attributes *group;
575
576 if (security_equal_sid( token->user, sid )) return TRUE;
577
578 LIST_FOR_EACH_ENTRY( group, &token->groups, struct sid_and_attributes, entry )
579 {
580 if (!group->enabled) continue;
581 if (group->deny_only && !deny) continue;
582
583 if (security_equal_sid( &group->sid, sid )) return TRUE;
584 }
585
586 return FALSE;
587}
588
589/* checks access to a security descriptor. sd must have been validated by caller.
590 * it returns STATUS_SUCCESS if access was granted to the object, or an error
591 * status code if not, giving the reason. errors not relating to giving access
592 * to the object are returned in the status parameter. granted_access and
593 * status always have a valid value stored in them on return. */
594static unsigned int token_access_check( struct token *token,
595 const struct security_descriptor *sd,
596 unsigned int desired_access,
597 LUID_AND_ATTRIBUTES *privs,
598 unsigned int *priv_count,
599 const GENERIC_MAPPING *mapping,
600 unsigned int *granted_access,
601 unsigned int *status )
602{
603 unsigned int current_access = 0;
604 unsigned int denied_access = 0;
605 ULONG i;
606 const ACL *dacl;
607 int dacl_present;
608 const ACE_HEADER *ace;
609 const SID *owner;
610
611 /* assume success, but no access rights */
612 *status = STATUS_SUCCESS;
613 *granted_access = 0;
614
615 /* fail if desired_access contains generic rights */
616 if (desired_access & (GENERIC_READ|GENERIC_WRITE|GENERIC_EXECUTE|GENERIC_ALL))
617 {
618 *priv_count = 0;
619 *status = STATUS_GENERIC_NOT_MAPPED;
620 return STATUS_ACCESS_DENIED;
621 }
622
623 dacl = sd_get_dacl( sd, &dacl_present );
624 owner = sd_get_owner( sd );
625 if (!owner || !sd_get_group( sd ))
626 {
627 *priv_count = 0;
628 *status = STATUS_INVALID_SECURITY_DESCR;
629 return STATUS_ACCESS_DENIED;
630 }
631
632 /* 1: Grant desired access if the object is unprotected */
633 if (!dacl_present)
634 {
635 *priv_count = 0;
636 *granted_access = desired_access;
637 return STATUS_SUCCESS;
638 }
639 if (!dacl)
640 {
641 *priv_count = 0;
642 return STATUS_ACCESS_DENIED;
643 }
644
645 /* 2: Check if caller wants access to system security part. Note: access
646 * is only granted if specifically asked for */
647 if (desired_access & ACCESS_SYSTEM_SECURITY)
648 {
649 const LUID_AND_ATTRIBUTES security_priv = { SeSecurityPrivilege, 0 };
650 LUID_AND_ATTRIBUTES retpriv = security_priv;
651 if (token_check_privileges( token, TRUE, &security_priv, 1, &retpriv ))
652 {
653 if (priv_count)
654 {
655 /* assumes that there will only be one privilege to return */
656 if (*priv_count >= 1)
657 {
658 *priv_count = 1;
659 *privs = retpriv;
660 }
661 else
662 {
663 *priv_count = 1;
664 return STATUS_BUFFER_TOO_SMALL;
665 }
666 }
667 current_access |= ACCESS_SYSTEM_SECURITY;
668 if (desired_access == current_access)
669 {
670 *granted_access = current_access;
671 return STATUS_SUCCESS;
672 }
673 }
674 else
675 {
676 *priv_count = 0;
677 return STATUS_PRIVILEGE_NOT_HELD;
678 }
679 }
680 else if (priv_count) *priv_count = 0;
681
682 /* 3: Check whether the token is the owner */
683 /* NOTE: SeTakeOwnershipPrivilege is not checked for here - it is instead
684 * checked when a "set owner" call is made, overriding the access rights
685 * determined here. */
686 if (token_sid_present( token, owner, FALSE ))
687 {
688 current_access |= (READ_CONTROL | WRITE_DAC);
689 if (desired_access == current_access)
690 {
691 *granted_access = current_access;
692 return STATUS_SUCCESS;
693 }
694 }
695
696 /* 4: Grant rights according to the DACL */
697 ace = (const ACE_HEADER *)(dacl + 1);
698 for (i = 0; i < dacl->AceCount; i++)
699 {
700 const ACCESS_ALLOWED_ACE *aa_ace;
701 const ACCESS_DENIED_ACE *ad_ace;
702 const SID *sid;
703 switch (ace->AceType)
704 {
705 case ACCESS_DENIED_ACE_TYPE:
706 ad_ace = (const ACCESS_DENIED_ACE *)ace;
707 sid = (const SID *)&ad_ace->SidStart;
708 if (token_sid_present( token, sid, TRUE ))
709 {
710 unsigned int access = ad_ace->Mask;
711 map_generic_mask(&access, mapping);
712 if (desired_access & MAXIMUM_ALLOWED)
713 denied_access |= access;
714 else
715 {
716 denied_access |= (access & ~current_access);
717 if (desired_access & access)
718 {
719 *granted_access = 0;
720 return STATUS_SUCCESS;
721 }
722 }
723 }
724 break;
725 case ACCESS_ALLOWED_ACE_TYPE:
726 aa_ace = (const ACCESS_ALLOWED_ACE *)ace;
727 sid = (const SID *)&aa_ace->SidStart;
728 if (token_sid_present( token, sid, FALSE ))
729 {
730 unsigned int access = aa_ace->Mask;
731 map_generic_mask(&access, mapping);
732 if (desired_access & MAXIMUM_ALLOWED)
733 current_access |= access;
734 else
735 current_access |= (access & ~denied_access);
736 }
737 break;
738 }
739
740 /* don't bother carrying on checking if we've already got all of
741 * rights we need */
742 if (desired_access == *granted_access)
743 break;
744
745 ace = ace_next( ace );
746 }
747
748 if (desired_access & MAXIMUM_ALLOWED)
749 {
750 *granted_access = current_access & ~denied_access;
751 if (*granted_access)
752 return STATUS_SUCCESS;
753 else
754 return STATUS_ACCESS_DENIED;
755 }
756 else
757 {
758 if ((current_access & desired_access) == desired_access)
759 {
760 *granted_access = current_access & desired_access;
761 return STATUS_SUCCESS;
762 }
763 else
764 return STATUS_ACCESS_DENIED;
765 }
766}
767
Mike McCormack36cd6f52003-07-24 00:07:00 +0000768/* open a security token */
769DECL_HANDLER(open_token)
770{
Robert Shearman37957092005-06-10 19:54:46 +0000771 if (req->flags & OPEN_TOKEN_THREAD)
Mike McCormack36cd6f52003-07-24 00:07:00 +0000772 {
773 struct thread *thread = get_thread_from_handle( req->handle, 0 );
774 if (thread)
775 {
776 if (thread->token)
777 reply->token = alloc_handle( current->process, thread->token, TOKEN_ALL_ACCESS, 0);
Robert Shearmanb0f02b22005-02-11 11:52:06 +0000778 else
779 set_error(STATUS_NO_TOKEN);
Mike McCormack36cd6f52003-07-24 00:07:00 +0000780 release_object( thread );
781 }
782 }
783 else
784 {
785 struct process *process = get_process_from_handle( req->handle, 0 );
786 if (process)
787 {
788 if (process->token)
789 reply->token = alloc_handle( current->process, process->token, TOKEN_ALL_ACCESS, 0);
Robert Shearmanb0f02b22005-02-11 11:52:06 +0000790 else
791 set_error(STATUS_NO_TOKEN);
Mike McCormack36cd6f52003-07-24 00:07:00 +0000792 release_object( process );
793 }
794 }
795}
Robert Shearmanb0f02b22005-02-11 11:52:06 +0000796
797/* adjust the privileges held by a token */
798DECL_HANDLER(adjust_token_privileges)
799{
800 struct token *token;
801 unsigned int access = TOKEN_ADJUST_PRIVILEGES;
802
803 if (req->get_modified_state) access |= TOKEN_QUERY;
804
805 if ((token = (struct token *)get_handle_obj( current->process, req->handle,
806 access, &token_ops )))
807 {
808 const LUID_AND_ATTRIBUTES *privs = get_req_data();
809 LUID_AND_ATTRIBUTES *modified_privs = NULL;
810 unsigned int priv_count = get_req_data_size() / sizeof(LUID_AND_ATTRIBUTES);
811 unsigned int modified_priv_count = 0;
812
813 if (req->get_modified_state && !req->disable_all)
814 {
815 int i;
816 /* count modified privs */
817 for (i = 0; i < priv_count; i++)
818 {
819 struct privilege *privilege =
820 token_find_privilege( token, &privs[i].Luid, FALSE );
821 if (privilege && req->get_modified_state)
822 modified_priv_count++;
823 }
824 reply->len = modified_priv_count;
825 modified_priv_count = min( modified_priv_count, get_reply_max_size() / sizeof(*modified_privs) );
826 if (modified_priv_count)
827 modified_privs = set_reply_data_size( modified_priv_count * sizeof(*modified_privs) );
828 }
829 reply->len = modified_priv_count * sizeof(*modified_privs);
830
831 if (req->disable_all)
832 token_disable_privileges( token );
833 else
834 modified_priv_count = token_adjust_privileges( token, privs,
835 priv_count, modified_privs, modified_priv_count );
836
837 release_object( token );
838 }
839}
840
841/* retrieves the list of privileges that may be held be the token */
842DECL_HANDLER(get_token_privileges)
843{
844 struct token *token;
845
846 if ((token = (struct token *)get_handle_obj( current->process, req->handle,
847 TOKEN_QUERY,
848 &token_ops )))
849 {
850 int priv_count = 0;
851 LUID_AND_ATTRIBUTES *privs;
852 struct privilege *privilege;
853
854 LIST_FOR_EACH_ENTRY( privilege, &token->privileges, struct privilege, entry )
855 priv_count++;
856
857 reply->len = priv_count * sizeof(*privs);
858 if (reply->len <= get_reply_max_size())
859 {
860 privs = set_reply_data_size( priv_count * sizeof(*privs) );
861 if (privs)
862 {
863 int i = 0;
864 LIST_FOR_EACH_ENTRY( privilege, &token->privileges, struct privilege, entry )
865 {
866 luid_and_attr_from_privilege( &privs[i], privilege );
867 i++;
868 }
869 }
870 }
871 else
872 set_error(STATUS_BUFFER_TOO_SMALL);
873
874 release_object( token );
875 }
876}
877
878/* creates a duplicate of the token */
879DECL_HANDLER(duplicate_token)
880{
881 struct token *src_token;
882 if ((src_token = (struct token *)get_handle_obj( current->process, req->handle,
883 TOKEN_DUPLICATE,
884 &token_ops )))
885 {
Robert Shearmanf95ef092005-06-14 18:10:04 +0000886 /* FIXME: use req->impersonation_level */
887 struct token *token = create_token( req->primary, src_token->user, NULL, 0, NULL, 0 );
Robert Shearmanb0f02b22005-02-11 11:52:06 +0000888 if (token)
889 {
890 struct privilege *privilege;
Robert Shearmanf95ef092005-06-14 18:10:04 +0000891 struct sid_and_attributes *group;
Robert Shearmanb0f02b22005-02-11 11:52:06 +0000892 unsigned int access;
893
Robert Shearmanf95ef092005-06-14 18:10:04 +0000894 /* copy groups */
895 LIST_FOR_EACH_ENTRY( group, &src_token->groups, struct sid_and_attributes, entry )
896 {
897 size_t size = FIELD_OFFSET( struct sid_and_attributes, sid.SubAuthority[group->sid.SubAuthorityCount] );
898 struct sid_and_attributes *newgroup = mem_alloc( size );
899 memcpy( newgroup, group, size );
900 list_add_tail( &token->groups, &newgroup->entry );
901 }
Robert Shearman9b826442005-06-09 09:47:28 +0000902
Robert Shearmanf95ef092005-06-14 18:10:04 +0000903 /* copy privileges */
Robert Shearmanb0f02b22005-02-11 11:52:06 +0000904 LIST_FOR_EACH_ENTRY( privilege, &src_token->privileges, struct privilege, entry )
905 privilege_add( token, &privilege->luid, privilege->enabled );
906
907 access = req->access;
908 if (access & MAXIMUM_ALLOWED) access = TOKEN_ALL_ACCESS; /* FIXME: needs general solution */
909 reply->new_handle = alloc_handle( current->process, token, access, req->inherit);
910 release_object( token );
911 }
912 release_object( src_token );
913 }
914}
Robert Shearmand2ea92d2005-04-22 21:17:15 +0000915
916/* checks the specified privileges are held by the token */
917DECL_HANDLER(check_token_privileges)
918{
919 struct token *token;
920
921 if ((token = (struct token *)get_handle_obj( current->process, req->handle,
922 TOKEN_QUERY,
923 &token_ops )))
924 {
925 unsigned int count = get_req_data_size() / sizeof(LUID_AND_ATTRIBUTES);
926 if (get_reply_max_size() >= count * sizeof(LUID_AND_ATTRIBUTES))
927 {
928 LUID_AND_ATTRIBUTES *usedprivs = set_reply_data_size( count * sizeof(*usedprivs) );
929 reply->has_privileges = token_check_privileges( token, req->all_required, get_req_data(), count, usedprivs );
930 }
931 else
932 set_error( STATUS_BUFFER_OVERFLOW );
933 release_object( token );
934 }
935}
Robert Shearman4ad93412005-05-24 12:32:18 +0000936
937/* checks that a user represented by a token is allowed to access an object
938 * represented by a security descriptor */
939DECL_HANDLER(access_check)
940{
941 size_t sd_size = get_req_data_size();
942 const struct security_descriptor *sd = get_req_data();
943 struct token *token;
944
945 if (!sd_is_valid( sd, sd_size ))
946 {
947 set_error( STATUS_ACCESS_VIOLATION );
948 return;
949 }
950
951 if ((token = (struct token *)get_handle_obj( current->process, req->handle,
952 TOKEN_QUERY,
953 &token_ops )))
954 {
955 GENERIC_MAPPING mapping;
956 unsigned int status;
957 LUID_AND_ATTRIBUTES priv;
958 unsigned int priv_count = 1;
959
960 memset(&priv, 0, sizeof(priv));
961
962 /* FIXME: check token is an impersonation token, if not return
963 * STATUS_NO_IMPERSONATION_TOKEN */
964
965 mapping.GenericRead = req->mapping_read;
966 mapping.GenericWrite = req->mapping_write;
967 mapping.GenericExecute = req->mapping_execute;
968 mapping.GenericAll = req->mapping_all;
969
970 reply->access_status = token_access_check(
971 token, sd, req->desired_access, &priv, &priv_count, &mapping,
972 &reply->access_granted, &status );
973
974 reply->privileges_len = priv_count*sizeof(LUID_AND_ATTRIBUTES);
975
976 if ((priv_count > 0) && (reply->privileges_len <= get_reply_max_size()))
977 {
978 LUID_AND_ATTRIBUTES *privs = set_reply_data_size( priv_count * sizeof(*privs) );
979 memcpy( privs, &priv, sizeof(priv) );
980 }
981
982 if (status != STATUS_SUCCESS)
983 set_error( status );
984
985 release_object( token );
986 }
987}