4 * Copyright (C) 1998 Alexandre Julliard
5 * Copyright (C) 2003 Mike McCormack
6 * Copyright (C) 2005 Robert Shearman
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.
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.
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
37 #define MAX_SUBAUTH_COUNT 1
39 const LUID SeIncreaseQuotaPrivilege
= { 5, 0 };
40 const LUID SeSecurityPrivilege
= { 8, 0 };
41 const LUID SeTakeOwnershipPrivilege
= { 9, 0 };
42 const LUID SeLoadDriverPrivilege
= { 10, 0 };
43 const LUID SeSystemProfilePrivilege
= { 11, 0 };
44 const LUID SeSystemtimePrivilege
= { 12, 0 };
45 const LUID SeProfileSingleProcessPrivilege
= { 13, 0 };
46 const LUID SeIncreaseBasePriorityPrivilege
= { 14, 0 };
47 const LUID SeCreatePagefilePrivilege
= { 15, 0 };
48 const LUID SeBackupPrivilege
= { 17, 0 };
49 const LUID SeRestorePrivilege
= { 18, 0 };
50 const LUID SeShutdownPrivilege
= { 19, 0 };
51 const LUID SeDebugPrivilege
= { 20, 0 };
52 const LUID SeSystemEnvironmentPrivilege
= { 22, 0 };
53 const LUID SeChangeNotifyPrivilege
= { 23, 0 };
54 const LUID SeRemoteShutdownPrivilege
= { 24, 0 };
55 const LUID SeUndockPrivilege
= { 25, 0 };
56 const LUID SeManageVolumePrivilege
= { 28, 0 };
57 const LUID SeImpersonatePrivilege
= { 29, 0 };
58 const LUID SeCreateGlobalPrivilege
= { 30, 0 };
62 struct object obj
; /* object header */
63 struct list privileges
; /* privileges available to the token */
64 SID
*user
; /* SID of user this token represents */
71 unsigned enabled
: 1; /* is the privilege currently enabled? */
72 unsigned def
: 1; /* is the privilege enabled by default? */
75 static void token_dump( struct object
*obj
, int verbose
);
76 static void token_destroy( struct object
*obj
);
78 static const struct object_ops token_ops
=
80 sizeof(struct token
), /* size */
81 token_dump
, /* dump */
82 no_add_queue
, /* add_queue */
83 NULL
, /* remove_queue */
86 no_signal
, /* signal */
87 no_get_fd
, /* get_fd */
88 token_destroy
/* destroy */
92 static void token_dump( struct object
*obj
, int verbose
)
94 fprintf( stderr
, "Security token\n" );
97 static SID
*security_sid_alloc( const SID_IDENTIFIER_AUTHORITY
*idauthority
, int subauthcount
, const unsigned int subauth
[] )
100 SID
*sid
= mem_alloc( FIELD_OFFSET(SID
, SubAuthority
[subauthcount
]) );
101 if (!sid
) return NULL
;
102 sid
->Revision
= MAX_ACL_REVISION
;
103 sid
->SubAuthorityCount
= subauthcount
;
104 sid
->IdentifierAuthority
= *idauthority
;
105 for (i
= 0; i
< subauthcount
; i
++)
106 sid
->SubAuthority
[i
] = subauth
[i
];
110 static inline int security_equal_sid( const SID
*sid1
, const SID
*sid2
)
112 return ((sid1
->SubAuthorityCount
== sid2
->SubAuthorityCount
) &&
113 !memcmp( sid1
, sid2
, FIELD_OFFSET(SID
, SubAuthority
[sid1
->SubAuthorityCount
]) ));
116 static inline int is_equal_luid( const LUID
*luid1
, const LUID
*luid2
)
118 return (luid1
->LowPart
== luid2
->LowPart
&& luid1
->HighPart
== luid2
->HighPart
);
121 static inline void luid_and_attr_from_privilege( LUID_AND_ATTRIBUTES
*out
, const struct privilege
*in
)
123 out
->Luid
= in
->luid
;
125 (in
->enabled
? SE_PRIVILEGE_ENABLED
: 0) |
126 (in
->def
? SE_PRIVILEGE_ENABLED_BY_DEFAULT
: 0);
129 static struct privilege
*privilege_add( struct token
*token
, const LUID
*luid
, int enabled
)
131 struct privilege
*privilege
= mem_alloc( sizeof(*privilege
) );
134 privilege
->luid
= *luid
;
135 privilege
->def
= privilege
->enabled
= (enabled
!= 0);
136 list_add_tail( &token
->privileges
, &privilege
->entry
);
141 static inline void privilege_remove( struct privilege
*privilege
)
143 list_remove( &privilege
->entry
);
147 static void token_destroy( struct object
*obj
)
150 struct list
*cursor
, *cursor_next
;
152 assert( obj
->ops
== &token_ops
);
153 token
= (struct token
*)obj
;
157 LIST_FOR_EACH_SAFE( cursor
, cursor_next
, &token
->privileges
)
159 struct privilege
*privilege
= LIST_ENTRY( cursor
, struct privilege
, entry
);
160 privilege_remove( privilege
);
164 static struct token
*create_token( const SID
*user
, const LUID_AND_ATTRIBUTES
*privs
, unsigned int priv_count
)
166 struct token
*token
= alloc_object( &token_ops
);
170 list_init( &token
->privileges
);
172 token
->user
= memdup( user
, FIELD_OFFSET(SID
, SubAuthority
[user
->SubAuthorityCount
]) );
175 release_object( token
);
178 /* copy privileges */
179 for (i
= 0; i
< priv_count
; i
++)
181 /* note: we don't check uniqueness: the caller must make sure
182 * privs doesn't contain any duplicate luids */
183 if (!privilege_add( token
, &privs
[i
].Luid
,
184 privs
[i
].Attributes
& SE_PRIVILEGE_ENABLED
))
186 release_object( token
);
196 SID_IDENTIFIER_AUTHORITY idauth
;
198 unsigned int subauth
[MAX_SUBAUTH_COUNT
];
201 struct token
*token_create_admin( void )
204 const LUID_AND_ATTRIBUTES admin_privs
[] =
206 { SeChangeNotifyPrivilege
, SE_PRIVILEGE_ENABLED
},
207 { SeSecurityPrivilege
, 0 },
208 { SeBackupPrivilege
, 0 },
209 { SeRestorePrivilege
, 0 },
210 { SeSystemtimePrivilege
, 0 },
211 { SeShutdownPrivilege
, 0 },
212 { SeRemoteShutdownPrivilege
, 0 },
213 { SeTakeOwnershipPrivilege
, 0 },
214 { SeDebugPrivilege
, 0 },
215 { SeSystemEnvironmentPrivilege
, 0 },
216 { SeSystemProfilePrivilege
, 0 },
217 { SeProfileSingleProcessPrivilege
, 0 },
218 { SeIncreaseBasePriorityPrivilege
, 0 },
219 { SeLoadDriverPrivilege
, 0 },
220 { SeCreatePagefilePrivilege
, 0 },
221 { SeIncreaseQuotaPrivilege
, 0 },
222 { SeUndockPrivilege
, 0 },
223 { SeManageVolumePrivilege
, 0 },
224 { SeImpersonatePrivilege
, SE_PRIVILEGE_ENABLED
},
225 { SeCreateGlobalPrivilege
, SE_PRIVILEGE_ENABLED
},
227 static const struct sid_data well_known_sid_data
[] =
229 { { SECURITY_NT_AUTHORITY
}, 1, { SECURITY_LOCAL_SYSTEM_RID
} }, /* LOCAL_SYSTEM */
231 SID
*local_system_sid
= security_sid_alloc(
232 &well_known_sid_data
[0].idauth
,
233 well_known_sid_data
[0].count
,
234 well_known_sid_data
[0].subauth
);
235 if (!local_system_sid
) return NULL
;
236 token
= create_token( local_system_sid
, admin_privs
, sizeof(admin_privs
)/sizeof(admin_privs
[0]) );
237 free( local_system_sid
);
241 static struct privilege
*token_find_privilege( struct token
*token
, const LUID
*luid
, int enabled_only
)
243 struct privilege
*privilege
;
244 LIST_FOR_EACH_ENTRY( privilege
, &token
->privileges
, struct privilege
, entry
)
246 if (is_equal_luid( luid
, &privilege
->luid
))
248 if (enabled_only
&& !privilege
->enabled
)
256 static unsigned int token_adjust_privileges( struct token
*token
, const LUID_AND_ATTRIBUTES
*privs
,
257 unsigned int count
, LUID_AND_ATTRIBUTES
*mod_privs
,
258 unsigned int mod_privs_count
)
261 unsigned int modified_count
= 0;
263 for (i
= 0; i
< count
; i
++)
265 struct privilege
*privilege
=
266 token_find_privilege( token
, &privs
[i
].Luid
, FALSE
);
269 set_error( STATUS_NOT_ALL_ASSIGNED
);
273 if (privs
[i
].Attributes
& SE_PRIVILEGE_REMOVE
)
274 privilege_remove( privilege
);
277 /* save previous state for caller */
280 luid_and_attr_from_privilege(mod_privs
, privilege
);
286 if (privs
[i
].Attributes
& SE_PRIVILEGE_ENABLED
)
287 privilege
->enabled
= TRUE
;
289 privilege
->enabled
= FALSE
;
292 return modified_count
;
295 static void token_disable_privileges( struct token
*token
)
297 struct privilege
*privilege
;
298 LIST_FOR_EACH_ENTRY( privilege
, &token
->privileges
, struct privilege
, entry
)
299 privilege
->enabled
= FALSE
;
302 int token_check_privileges( struct token
*token
, int all_required
,
303 const LUID_AND_ATTRIBUTES
*reqprivs
,
304 unsigned int count
, LUID_AND_ATTRIBUTES
*usedprivs
)
307 unsigned int enabled_count
= 0;
309 for (i
= 0; i
< count
; i
++)
311 struct privilege
*privilege
=
312 token_find_privilege( token
, &reqprivs
[i
].Luid
, TRUE
);
315 usedprivs
[i
] = reqprivs
[i
];
317 if (privilege
&& privilege
->enabled
)
321 usedprivs
[i
].Attributes
|= SE_PRIVILEGE_USED_FOR_ACCESS
;
326 return (enabled_count
== count
);
328 return (enabled_count
> 0);
331 /* open a security token */
332 DECL_HANDLER(open_token
)
334 if( req
->flags
& OPEN_TOKEN_THREAD
)
336 struct thread
*thread
= get_thread_from_handle( req
->handle
, 0 );
340 reply
->token
= alloc_handle( current
->process
, thread
->token
, TOKEN_ALL_ACCESS
, 0);
342 set_error(STATUS_NO_TOKEN
);
343 release_object( thread
);
348 struct process
*process
= get_process_from_handle( req
->handle
, 0 );
352 reply
->token
= alloc_handle( current
->process
, process
->token
, TOKEN_ALL_ACCESS
, 0);
354 set_error(STATUS_NO_TOKEN
);
355 release_object( process
);
360 /* adjust the privileges held by a token */
361 DECL_HANDLER(adjust_token_privileges
)
364 unsigned int access
= TOKEN_ADJUST_PRIVILEGES
;
366 if (req
->get_modified_state
) access
|= TOKEN_QUERY
;
368 if ((token
= (struct token
*)get_handle_obj( current
->process
, req
->handle
,
369 access
, &token_ops
)))
371 const LUID_AND_ATTRIBUTES
*privs
= get_req_data();
372 LUID_AND_ATTRIBUTES
*modified_privs
= NULL
;
373 unsigned int priv_count
= get_req_data_size() / sizeof(LUID_AND_ATTRIBUTES
);
374 unsigned int modified_priv_count
= 0;
376 if (req
->get_modified_state
&& !req
->disable_all
)
379 /* count modified privs */
380 for (i
= 0; i
< priv_count
; i
++)
382 struct privilege
*privilege
=
383 token_find_privilege( token
, &privs
[i
].Luid
, FALSE
);
384 if (privilege
&& req
->get_modified_state
)
385 modified_priv_count
++;
387 reply
->len
= modified_priv_count
;
388 modified_priv_count
= min( modified_priv_count
, get_reply_max_size() / sizeof(*modified_privs
) );
389 if (modified_priv_count
)
390 modified_privs
= set_reply_data_size( modified_priv_count
* sizeof(*modified_privs
) );
392 reply
->len
= modified_priv_count
* sizeof(*modified_privs
);
394 if (req
->disable_all
)
395 token_disable_privileges( token
);
397 modified_priv_count
= token_adjust_privileges( token
, privs
,
398 priv_count
, modified_privs
, modified_priv_count
);
400 release_object( token
);
404 /* retrieves the list of privileges that may be held be the token */
405 DECL_HANDLER(get_token_privileges
)
409 if ((token
= (struct token
*)get_handle_obj( current
->process
, req
->handle
,
414 LUID_AND_ATTRIBUTES
*privs
;
415 struct privilege
*privilege
;
417 LIST_FOR_EACH_ENTRY( privilege
, &token
->privileges
, struct privilege
, entry
)
420 reply
->len
= priv_count
* sizeof(*privs
);
421 if (reply
->len
<= get_reply_max_size())
423 privs
= set_reply_data_size( priv_count
* sizeof(*privs
) );
427 LIST_FOR_EACH_ENTRY( privilege
, &token
->privileges
, struct privilege
, entry
)
429 luid_and_attr_from_privilege( &privs
[i
], privilege
);
435 set_error(STATUS_BUFFER_TOO_SMALL
);
437 release_object( token
);
441 /* creates a duplicate of the token */
442 DECL_HANDLER(duplicate_token
)
444 struct token
*src_token
;
445 if ((src_token
= (struct token
*)get_handle_obj( current
->process
, req
->handle
,
449 /* FIXME: use req->primary and req->impersonation_level */
450 struct token
*token
= create_token( src_token
->user
, NULL
, 0 );
453 struct privilege
*privilege
;
456 LIST_FOR_EACH_ENTRY( privilege
, &src_token
->privileges
, struct privilege
, entry
)
457 privilege_add( token
, &privilege
->luid
, privilege
->enabled
);
459 access
= req
->access
;
460 if (access
& MAXIMUM_ALLOWED
) access
= TOKEN_ALL_ACCESS
; /* FIXME: needs general solution */
461 reply
->new_handle
= alloc_handle( current
->process
, token
, access
, req
->inherit
);
462 release_object( token
);
464 release_object( src_token
);
468 /* checks the specified privileges are held by the token */
469 DECL_HANDLER(check_token_privileges
)
473 if ((token
= (struct token
*)get_handle_obj( current
->process
, req
->handle
,
477 unsigned int count
= get_req_data_size() / sizeof(LUID_AND_ATTRIBUTES
);
478 if (get_reply_max_size() >= count
* sizeof(LUID_AND_ATTRIBUTES
))
480 LUID_AND_ATTRIBUTES
*usedprivs
= set_reply_data_size( count
* sizeof(*usedprivs
) );
481 reply
->has_privileges
= token_check_privileges( token
, req
->all_required
, get_req_data(), count
, usedprivs
);
484 set_error( STATUS_BUFFER_OVERFLOW
);
485 release_object( token
);