Implemented NtSignalAndWaitForSingleObject.
[wine.git] / server / token.c
blobe30f75525bf87b180e377a8fd52c694be9899a94
1 /*
2 * Tokens
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
23 #include "config.h"
25 #include <assert.h>
26 #include <stdio.h>
27 #include <stdlib.h>
29 #include "windef.h"
31 #include "handle.h"
32 #include "thread.h"
33 #include "process.h"
34 #include "request.h"
35 #include "security.h"
37 const LUID SeIncreaseQuotaPrivilege = { 5, 0 };
38 const LUID SeSecurityPrivilege = { 8, 0 };
39 const LUID SeTakeOwnershipPrivilege = { 9, 0 };
40 const LUID SeLoadDriverPrivilege = { 10, 0 };
41 const LUID SeSystemProfilePrivilege = { 11, 0 };
42 const LUID SeSystemtimePrivilege = { 12, 0 };
43 const LUID SeProfileSingleProcessPrivilege = { 13, 0 };
44 const LUID SeIncreaseBasePriorityPrivilege = { 14, 0 };
45 const LUID SeCreatePagefilePrivilege = { 15, 0 };
46 const LUID SeBackupPrivilege = { 17, 0 };
47 const LUID SeRestorePrivilege = { 18, 0 };
48 const LUID SeShutdownPrivilege = { 19, 0 };
49 const LUID SeDebugPrivilege = { 20, 0 };
50 const LUID SeSystemEnvironmentPrivilege = { 22, 0 };
51 const LUID SeChangeNotifyPrivilege = { 23, 0 };
52 const LUID SeRemoteShutdownPrivilege = { 24, 0 };
53 const LUID SeUndockPrivilege = { 25, 0 };
54 const LUID SeManageVolumePrivilege = { 28, 0 };
55 const LUID SeImpersonatePrivilege = { 29, 0 };
56 const LUID SeCreateGlobalPrivilege = { 30, 0 };
58 struct token
60 struct object obj; /* object header */
61 struct list privileges; /* privileges available to the token */
64 struct privilege
66 struct list entry;
67 LUID luid;
68 int enabled : 1; /* is the privilege currently enabled? */
69 int def : 1; /* is the privilege enabled by default? */
72 static void token_dump( struct object *obj, int verbose );
73 static void token_destroy( struct object *obj );
75 static const struct object_ops token_ops =
77 sizeof(struct token), /* size */
78 token_dump, /* dump */
79 no_add_queue, /* add_queue */
80 NULL, /* remove_queue */
81 NULL, /* signaled */
82 NULL, /* satisfied */
83 no_signal, /* signal */
84 no_get_fd, /* get_fd */
85 token_destroy /* destroy */
89 static void token_dump( struct object *obj, int verbose )
91 fprintf( stderr, "Security token\n" );
94 static inline int is_equal_luid( const LUID *luid1, const LUID *luid2 )
96 return (luid1->LowPart == luid2->LowPart && luid1->HighPart == luid2->HighPart);
99 static inline void luid_and_attr_from_privilege( LUID_AND_ATTRIBUTES *out, const struct privilege *in)
101 out->Luid = in->luid;
102 out->Attributes =
103 (in->enabled ? SE_PRIVILEGE_ENABLED : 0) |
104 (in->def ? SE_PRIVILEGE_ENABLED_BY_DEFAULT : 0);
107 static struct privilege *privilege_add( struct token *token, const LUID *luid, int enabled )
109 struct privilege *privilege = mem_alloc( sizeof(*privilege) );
110 if (privilege)
112 privilege->luid = *luid;
113 privilege->def = privilege->enabled = (enabled != 0);
114 list_add_tail( &token->privileges, &privilege->entry );
116 return privilege;
119 static void privilege_remove( struct privilege *privilege )
121 list_remove( &privilege->entry );
122 free( privilege );
125 static void token_destroy( struct object *obj )
127 struct token* token;
128 struct list *cursor, *cursor_next;
130 assert( obj->ops == &token_ops );
131 token = (struct token *)obj;
133 LIST_FOR_EACH_SAFE( cursor, cursor_next, &token->privileges )
135 struct privilege *privilege = LIST_ENTRY( cursor, struct privilege, entry );
136 privilege_remove( privilege );
140 static struct token *create_token( const LUID_AND_ATTRIBUTES *privs, unsigned int priv_count )
142 struct token *token = alloc_object( &token_ops );
143 if (token)
145 int i;
146 list_init( &token->privileges );
147 for (i = 0; i < priv_count; i++)
149 /* note: we don't check uniqueness: the caller must make sure
150 * privs doesn't contain any duplicate luids */
151 if (!privilege_add( token, &privs[i].Luid,
152 privs[i].Attributes & SE_PRIVILEGE_ENABLED ))
154 release_object( token );
155 return NULL;
159 return token;
162 struct token *token_create_admin( void )
164 const LUID_AND_ATTRIBUTES admin_privs[] =
166 { SeChangeNotifyPrivilege , SE_PRIVILEGE_ENABLED },
167 { SeSecurityPrivilege , 0 },
168 { SeBackupPrivilege , 0 },
169 { SeRestorePrivilege , 0 },
170 { SeSystemtimePrivilege , 0 },
171 { SeShutdownPrivilege , 0 },
172 { SeRemoteShutdownPrivilege , 0 },
173 { SeTakeOwnershipPrivilege , 0 },
174 { SeDebugPrivilege , 0 },
175 { SeSystemEnvironmentPrivilege , 0 },
176 { SeSystemProfilePrivilege , 0 },
177 { SeProfileSingleProcessPrivilege, 0 },
178 { SeIncreaseBasePriorityPrivilege, 0 },
179 { SeLoadDriverPrivilege , 0 },
180 { SeCreatePagefilePrivilege , 0 },
181 { SeIncreaseQuotaPrivilege , 0 },
182 { SeUndockPrivilege , 0 },
183 { SeManageVolumePrivilege , 0 },
184 { SeImpersonatePrivilege , SE_PRIVILEGE_ENABLED },
185 { SeCreateGlobalPrivilege , SE_PRIVILEGE_ENABLED },
187 return create_token( admin_privs, sizeof(admin_privs)/sizeof(admin_privs[0]) );
190 static struct privilege *token_find_privilege( struct token *token, const LUID *luid, int enabled_only)
192 struct privilege *privilege;
193 LIST_FOR_EACH_ENTRY( privilege, &token->privileges, struct privilege, entry )
195 if (is_equal_luid( luid, &privilege->luid ))
197 if (enabled_only && !privilege->enabled)
198 return NULL;
199 return privilege;
202 return NULL;
205 static unsigned int token_adjust_privileges( struct token *token, const LUID_AND_ATTRIBUTES *privs,
206 unsigned int count, LUID_AND_ATTRIBUTES *mod_privs,
207 unsigned int mod_privs_count)
209 int i;
210 unsigned int modified_count = 0;
212 for (i = 0; i < count; i++)
214 struct privilege *privilege =
215 token_find_privilege( token, &privs[i].Luid, FALSE );
216 if (!privilege)
218 set_error( STATUS_NOT_ALL_ASSIGNED );
219 continue;
222 if (privs[i].Attributes & SE_PRIVILEGE_REMOVE)
223 privilege_remove( privilege );
224 else
226 /* save previous state for caller */
227 if (mod_privs_count)
229 luid_and_attr_from_privilege(mod_privs, privilege);
230 mod_privs++;
231 mod_privs_count--;
232 modified_count++;
235 if (privs[i].Attributes & SE_PRIVILEGE_ENABLED)
236 privilege->enabled = TRUE;
237 else
238 privilege->enabled = FALSE;
241 return modified_count;
244 static void token_disable_privileges( struct token *token )
246 struct privilege *privilege;
247 LIST_FOR_EACH_ENTRY( privilege, &token->privileges, struct privilege, entry )
248 privilege->enabled = FALSE;
251 int token_check_privileges( struct token *token, int all_required,
252 const LUID_AND_ATTRIBUTES *reqprivs,
253 unsigned int count, LUID_AND_ATTRIBUTES *usedprivs)
255 int i;
256 unsigned int enabled_count = 0;
258 for (i = 0; i < count; i++)
260 struct privilege *privilege =
261 token_find_privilege( token, &reqprivs[i].Luid, TRUE );
263 if (usedprivs)
264 usedprivs[i] = reqprivs[i];
266 if (privilege && privilege->enabled)
268 enabled_count++;
269 if (usedprivs)
270 usedprivs[i].Attributes |= SE_PRIVILEGE_USED_FOR_ACCESS;
274 if (all_required)
275 return (enabled_count == count);
276 else
277 return (enabled_count > 0);
280 /* open a security token */
281 DECL_HANDLER(open_token)
283 if( req->flags & OPEN_TOKEN_THREAD )
285 struct thread *thread = get_thread_from_handle( req->handle, 0 );
286 if (thread)
288 if (thread->token)
289 reply->token = alloc_handle( current->process, thread->token, TOKEN_ALL_ACCESS, 0);
290 else
291 set_error(STATUS_NO_TOKEN);
292 release_object( thread );
295 else
297 struct process *process = get_process_from_handle( req->handle, 0 );
298 if (process)
300 if (process->token)
301 reply->token = alloc_handle( current->process, process->token, TOKEN_ALL_ACCESS, 0);
302 else
303 set_error(STATUS_NO_TOKEN);
304 release_object( process );
309 /* adjust the privileges held by a token */
310 DECL_HANDLER(adjust_token_privileges)
312 struct token *token;
313 unsigned int access = TOKEN_ADJUST_PRIVILEGES;
315 if (req->get_modified_state) access |= TOKEN_QUERY;
317 if ((token = (struct token *)get_handle_obj( current->process, req->handle,
318 access, &token_ops )))
320 const LUID_AND_ATTRIBUTES *privs = get_req_data();
321 LUID_AND_ATTRIBUTES *modified_privs = NULL;
322 unsigned int priv_count = get_req_data_size() / sizeof(LUID_AND_ATTRIBUTES);
323 unsigned int modified_priv_count = 0;
325 if (req->get_modified_state && !req->disable_all)
327 int i;
328 /* count modified privs */
329 for (i = 0; i < priv_count; i++)
331 struct privilege *privilege =
332 token_find_privilege( token, &privs[i].Luid, FALSE );
333 if (privilege && req->get_modified_state)
334 modified_priv_count++;
336 reply->len = modified_priv_count;
337 modified_priv_count = min( modified_priv_count, get_reply_max_size() / sizeof(*modified_privs) );
338 if (modified_priv_count)
339 modified_privs = set_reply_data_size( modified_priv_count * sizeof(*modified_privs) );
341 reply->len = modified_priv_count * sizeof(*modified_privs);
343 if (req->disable_all)
344 token_disable_privileges( token );
345 else
346 modified_priv_count = token_adjust_privileges( token, privs,
347 priv_count, modified_privs, modified_priv_count );
349 release_object( token );
353 /* retrieves the list of privileges that may be held be the token */
354 DECL_HANDLER(get_token_privileges)
356 struct token *token;
358 if ((token = (struct token *)get_handle_obj( current->process, req->handle,
359 TOKEN_QUERY,
360 &token_ops )))
362 int priv_count = 0;
363 LUID_AND_ATTRIBUTES *privs;
364 struct privilege *privilege;
366 LIST_FOR_EACH_ENTRY( privilege, &token->privileges, struct privilege, entry )
367 priv_count++;
369 reply->len = priv_count * sizeof(*privs);
370 if (reply->len <= get_reply_max_size())
372 privs = set_reply_data_size( priv_count * sizeof(*privs) );
373 if (privs)
375 int i = 0;
376 LIST_FOR_EACH_ENTRY( privilege, &token->privileges, struct privilege, entry )
378 luid_and_attr_from_privilege( &privs[i], privilege );
379 i++;
383 else
384 set_error(STATUS_BUFFER_TOO_SMALL);
386 release_object( token );
390 /* creates a duplicate of the token */
391 DECL_HANDLER(duplicate_token)
393 struct token *src_token;
394 if ((src_token = (struct token *)get_handle_obj( current->process, req->handle,
395 TOKEN_DUPLICATE,
396 &token_ops )))
398 /* FIXME: use req->primary and req->impersonation_level */
399 struct token *token = create_token( NULL, 0 );
400 if (token)
402 struct privilege *privilege;
403 unsigned int access;
405 LIST_FOR_EACH_ENTRY( privilege, &src_token->privileges, struct privilege, entry )
406 privilege_add( token, &privilege->luid, privilege->enabled );
408 access = req->access;
409 if (access & MAXIMUM_ALLOWED) access = TOKEN_ALL_ACCESS; /* FIXME: needs general solution */
410 reply->new_handle = alloc_handle( current->process, token, access, req->inherit);
411 release_object( token );
413 release_object( src_token );
417 /* checks the specified privileges are held by the token */
418 DECL_HANDLER(check_token_privileges)
420 struct token *token;
422 if ((token = (struct token *)get_handle_obj( current->process, req->handle,
423 TOKEN_QUERY,
424 &token_ops )))
426 unsigned int count = get_req_data_size() / sizeof(LUID_AND_ATTRIBUTES);
427 if (get_reply_max_size() >= count * sizeof(LUID_AND_ATTRIBUTES))
429 LUID_AND_ATTRIBUTES *usedprivs = set_reply_data_size( count * sizeof(*usedprivs) );
430 reply->has_privileges = token_check_privileges( token, req->all_required, get_req_data(), count, usedprivs );
432 else
433 set_error( STATUS_BUFFER_OVERFLOW );
434 release_object( token );