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 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 };
60 struct object obj
; /* object header */
61 struct list privileges
; /* privileges available to the token */
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 */
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
;
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
) );
112 privilege
->luid
= *luid
;
113 privilege
->def
= privilege
->enabled
= (enabled
!= 0);
114 list_add_tail( &token
->privileges
, &privilege
->entry
);
119 static void privilege_remove( struct privilege
*privilege
)
121 list_remove( &privilege
->entry
);
125 static void token_destroy( struct object
*obj
)
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
);
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
);
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
)
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
)
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
);
218 set_error( STATUS_NOT_ALL_ASSIGNED
);
222 if (privs
[i
].Attributes
& SE_PRIVILEGE_REMOVE
)
223 privilege_remove( privilege
);
226 /* save previous state for caller */
229 luid_and_attr_from_privilege(mod_privs
, privilege
);
235 if (privs
[i
].Attributes
& SE_PRIVILEGE_ENABLED
)
236 privilege
->enabled
= TRUE
;
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
)
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
);
264 usedprivs
[i
] = reqprivs
[i
];
266 if (privilege
&& privilege
->enabled
)
270 usedprivs
[i
].Attributes
|= SE_PRIVILEGE_USED_FOR_ACCESS
;
275 return (enabled_count
== count
);
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 );
289 reply
->token
= alloc_handle( current
->process
, thread
->token
, TOKEN_ALL_ACCESS
, 0);
291 set_error(STATUS_NO_TOKEN
);
292 release_object( thread
);
297 struct process
*process
= get_process_from_handle( req
->handle
, 0 );
301 reply
->token
= alloc_handle( current
->process
, process
->token
, TOKEN_ALL_ACCESS
, 0);
303 set_error(STATUS_NO_TOKEN
);
304 release_object( process
);
309 /* adjust the privileges held by a token */
310 DECL_HANDLER(adjust_token_privileges
)
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
)
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
);
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
)
358 if ((token
= (struct token
*)get_handle_obj( current
->process
, req
->handle
,
363 LUID_AND_ATTRIBUTES
*privs
;
364 struct privilege
*privilege
;
366 LIST_FOR_EACH_ENTRY( privilege
, &token
->privileges
, struct privilege
, entry
)
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
) );
376 LIST_FOR_EACH_ENTRY( privilege
, &token
->privileges
, struct privilege
, entry
)
378 luid_and_attr_from_privilege( &privs
[i
], privilege
);
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
,
398 /* FIXME: use req->primary and req->impersonation_level */
399 struct token
*token
= create_token( NULL
, 0 );
402 struct privilege
*privilege
;
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
)
422 if ((token
= (struct token
*)get_handle_obj( current
->process
, req
->handle
,
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
);
433 set_error( STATUS_BUFFER_OVERFLOW
);
434 release_object( token
);