/src/samba/libcli/security/privileges.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | Privileges handling functions |
4 | | Copyright (C) Jean François Micouleau 1998-2001 |
5 | | Copyright (C) Simo Sorce 2002-2003 |
6 | | Copyright (C) Gerald (Jerry) Carter 2005 |
7 | | Copyright (C) Michael Adam 2007 |
8 | | Copyright (C) Andrew Bartlett 2010 |
9 | | Copyright (C) Andrew Tridgell 2004 |
10 | | |
11 | | This program is free software; you can redistribute it and/or modify |
12 | | it under the terms of the GNU General Public License as published by |
13 | | the Free Software Foundation; either version 3 of the License, or |
14 | | (at your option) any later version. |
15 | | |
16 | | This program is distributed in the hope that it will be useful, |
17 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | | GNU General Public License for more details. |
20 | | |
21 | | You should have received a copy of the GNU General Public License |
22 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
23 | | */ |
24 | | |
25 | | /* |
26 | | * Basic privileges functions (mask-operations and conversion |
27 | | * functions between the different formats (se_priv, privset, luid) |
28 | | * moved here * from lib/privileges.c to minimize linker deps. |
29 | | * |
30 | | * generally SID- and LUID-related code is left in lib/privileges.c |
31 | | * |
32 | | * some extra functions to hide privs array from lib/privileges.c |
33 | | */ |
34 | | |
35 | | #include "replace.h" |
36 | | #include "libcli/security/privileges.h" |
37 | | #include "libcli/security/privileges_private.h" |
38 | | #include "librpc/gen_ndr/security.h" |
39 | | #include "lib/util/samba_util.h" |
40 | | #include "lib/util/debug.h" |
41 | | |
42 | | /* The use of strcasecmp here is safe, all the comparison strings are ASCII */ |
43 | | #undef strcasecmp |
44 | | |
45 | 0 | #define NUM_SHORT_LIST_PRIVS 9 |
46 | | |
47 | | static const struct { |
48 | | enum sec_privilege luid; |
49 | | uint64_t privilege_mask; |
50 | | const char *name; |
51 | | const char *description; |
52 | | } privs[] = { |
53 | | |
54 | | {SEC_PRIV_MACHINE_ACCOUNT, SEC_PRIV_MACHINE_ACCOUNT_BIT, "SeMachineAccountPrivilege", "Add machines to domain"}, |
55 | | {SEC_PRIV_TAKE_OWNERSHIP, SEC_PRIV_TAKE_OWNERSHIP_BIT, "SeTakeOwnershipPrivilege", "Take ownership of files or other objects"}, |
56 | | {SEC_PRIV_BACKUP, SEC_PRIV_BACKUP_BIT, "SeBackupPrivilege", "Back up files and directories"}, |
57 | | {SEC_PRIV_RESTORE, SEC_PRIV_RESTORE_BIT, "SeRestorePrivilege", "Restore files and directories"}, |
58 | | {SEC_PRIV_REMOTE_SHUTDOWN, SEC_PRIV_REMOTE_SHUTDOWN_BIT, "SeRemoteShutdownPrivilege", "Force shutdown from a remote system"}, |
59 | | |
60 | | {SEC_PRIV_PRINT_OPERATOR, SEC_PRIV_PRINT_OPERATOR_BIT, "SePrintOperatorPrivilege", "Manage printers"}, |
61 | | {SEC_PRIV_ADD_USERS, SEC_PRIV_ADD_USERS_BIT, "SeAddUsersPrivilege", "Add users and groups to the domain"}, |
62 | | {SEC_PRIV_DISK_OPERATOR, SEC_PRIV_DISK_OPERATOR_BIT, "SeDiskOperatorPrivilege", "Manage disk shares"}, |
63 | | {SEC_PRIV_SECURITY, SEC_PRIV_SECURITY_BIT, "SeSecurityPrivilege", "System security"}, |
64 | | |
65 | | |
66 | | /* The list from here on is not displayed in the code from |
67 | | * source3, and is after index NUM_SHORT_LIST_PRIVS for that |
68 | | * reason */ |
69 | | |
70 | | {SEC_PRIV_SYSTEMTIME, |
71 | | SEC_PRIV_SYSTEMTIME_BIT, |
72 | | "SeSystemtimePrivilege", |
73 | | "Set the system clock"}, |
74 | | |
75 | | {SEC_PRIV_SHUTDOWN, |
76 | | SEC_PRIV_SHUTDOWN_BIT, |
77 | | "SeShutdownPrivilege", |
78 | | "Shutdown the system"}, |
79 | | |
80 | | {SEC_PRIV_DEBUG, |
81 | | SEC_PRIV_DEBUG_BIT, |
82 | | "SeDebugPrivilege", |
83 | | "Debug processes"}, |
84 | | |
85 | | {SEC_PRIV_SYSTEM_ENVIRONMENT, |
86 | | SEC_PRIV_SYSTEM_ENVIRONMENT_BIT, |
87 | | "SeSystemEnvironmentPrivilege", |
88 | | "Modify system environment"}, |
89 | | |
90 | | {SEC_PRIV_SYSTEM_PROFILE, |
91 | | SEC_PRIV_SYSTEM_PROFILE_BIT, |
92 | | "SeSystemProfilePrivilege", |
93 | | "Profile the system"}, |
94 | | |
95 | | {SEC_PRIV_PROFILE_SINGLE_PROCESS, |
96 | | SEC_PRIV_PROFILE_SINGLE_PROCESS_BIT, |
97 | | "SeProfileSingleProcessPrivilege", |
98 | | "Profile one process"}, |
99 | | |
100 | | {SEC_PRIV_INCREASE_BASE_PRIORITY, |
101 | | SEC_PRIV_INCREASE_BASE_PRIORITY_BIT, |
102 | | "SeIncreaseBasePriorityPrivilege", |
103 | | "Increase base priority"}, |
104 | | |
105 | | {SEC_PRIV_LOAD_DRIVER, |
106 | | SEC_PRIV_LOAD_DRIVER_BIT, |
107 | | "SeLoadDriverPrivilege", |
108 | | "Load drivers"}, |
109 | | |
110 | | {SEC_PRIV_CREATE_PAGEFILE, |
111 | | SEC_PRIV_CREATE_PAGEFILE_BIT, |
112 | | "SeCreatePagefilePrivilege", |
113 | | "Create page files"}, |
114 | | |
115 | | {SEC_PRIV_INCREASE_QUOTA, |
116 | | SEC_PRIV_INCREASE_QUOTA_BIT, |
117 | | "SeIncreaseQuotaPrivilege", |
118 | | "Increase quota"}, |
119 | | |
120 | | {SEC_PRIV_CHANGE_NOTIFY, |
121 | | SEC_PRIV_CHANGE_NOTIFY_BIT, |
122 | | "SeChangeNotifyPrivilege", |
123 | | "Register for change notify"}, |
124 | | |
125 | | {SEC_PRIV_UNDOCK, |
126 | | SEC_PRIV_UNDOCK_BIT, |
127 | | "SeUndockPrivilege", |
128 | | "Undock devices"}, |
129 | | |
130 | | {SEC_PRIV_MANAGE_VOLUME, |
131 | | SEC_PRIV_MANAGE_VOLUME_BIT, |
132 | | "SeManageVolumePrivilege", |
133 | | "Manage system volumes"}, |
134 | | |
135 | | {SEC_PRIV_IMPERSONATE, |
136 | | SEC_PRIV_IMPERSONATE_BIT, |
137 | | "SeImpersonatePrivilege", |
138 | | "Impersonate users"}, |
139 | | |
140 | | {SEC_PRIV_CREATE_GLOBAL, |
141 | | SEC_PRIV_CREATE_GLOBAL_BIT, |
142 | | "SeCreateGlobalPrivilege", |
143 | | "Create global"}, |
144 | | |
145 | | {SEC_PRIV_ENABLE_DELEGATION, |
146 | | SEC_PRIV_ENABLE_DELEGATION_BIT, |
147 | | "SeEnableDelegationPrivilege", |
148 | | "Enable Delegation"}, |
149 | | }; |
150 | | |
151 | | /* These are rights, not privileges, and should not be confused. The |
152 | | * names are very similar, and they are quite similar in behaviour, |
153 | | * but they are not to be enumerated as a system-wide list or have an |
154 | | * LUID value */ |
155 | | static const struct { |
156 | | uint32_t right_mask; |
157 | | const char *name; |
158 | | const char *description; |
159 | | } rights[] = { |
160 | | {LSA_POLICY_MODE_INTERACTIVE, |
161 | | "SeInteractiveLogonRight", |
162 | | "Interactive logon"}, |
163 | | |
164 | | {LSA_POLICY_MODE_NETWORK, |
165 | | "SeNetworkLogonRight", |
166 | | "Network logon"}, |
167 | | |
168 | | {LSA_POLICY_MODE_REMOTE_INTERACTIVE, |
169 | | "SeRemoteInteractiveLogonRight", |
170 | | "Remote Interactive logon"} |
171 | | }; |
172 | | |
173 | | /* |
174 | | return a privilege mask given a privilege id |
175 | | */ |
176 | | uint64_t sec_privilege_mask(enum sec_privilege privilege) |
177 | 3.26k | { |
178 | 3.26k | size_t i; |
179 | 20.2k | for (i=0;i<ARRAY_SIZE(privs);i++) { |
180 | 20.2k | if (privs[i].luid == privilege) { |
181 | 3.26k | return privs[i].privilege_mask; |
182 | 3.26k | } |
183 | 20.2k | } |
184 | | |
185 | 0 | return 0; |
186 | 3.26k | } |
187 | | |
188 | | /*************************************************************************** |
189 | | put all valid privileges into a mask |
190 | | ****************************************************************************/ |
191 | | |
192 | | void se_priv_put_all_privileges(uint64_t *privilege_mask) |
193 | 0 | { |
194 | 0 | size_t i; |
195 | |
|
196 | 0 | *privilege_mask = 0; |
197 | 0 | for ( i=0; i<ARRAY_SIZE(privs); i++ ) { |
198 | 0 | *privilege_mask |= privs[i].privilege_mask; |
199 | 0 | } |
200 | 0 | } |
201 | | |
202 | | /********************************************************************* |
203 | | Lookup the uint64_t bitmask value for a privilege name |
204 | | *********************************************************************/ |
205 | | |
206 | | bool se_priv_from_name( const char *name, uint64_t *privilege_mask ) |
207 | 0 | { |
208 | 0 | size_t i; |
209 | 0 | for ( i=0; i<ARRAY_SIZE(privs); i++ ) { |
210 | 0 | if ( strequal( privs[i].name, name ) ) { |
211 | 0 | *privilege_mask = privs[i].privilege_mask; |
212 | 0 | return true; |
213 | 0 | } |
214 | 0 | } |
215 | | |
216 | 0 | return false; |
217 | 0 | } |
218 | | |
219 | | const char* get_privilege_dispname( const char *name ) |
220 | 0 | { |
221 | 0 | size_t i; |
222 | |
|
223 | 0 | if (!name) { |
224 | 0 | return NULL; |
225 | 0 | } |
226 | | |
227 | 0 | for ( i=0; i<ARRAY_SIZE(privs); i++ ) { |
228 | 0 | if ( strequal( privs[i].name, name ) ) { |
229 | 0 | return privs[i].description; |
230 | 0 | } |
231 | 0 | } |
232 | | |
233 | 0 | return NULL; |
234 | 0 | } |
235 | | |
236 | | /******************************************************************* |
237 | | return the number of elements in the 'short' privilege array (traditional source3 behaviour) |
238 | | *******************************************************************/ |
239 | | |
240 | | int num_privileges_in_short_list( void ) |
241 | 0 | { |
242 | 0 | return NUM_SHORT_LIST_PRIVS; |
243 | 0 | } |
244 | | |
245 | | /**************************************************************************** |
246 | | add a privilege to a privilege array |
247 | | ****************************************************************************/ |
248 | | |
249 | | static bool privilege_set_add(PRIVILEGE_SET *priv_set, struct lsa_LUIDAttribute set) |
250 | 0 | { |
251 | 0 | struct lsa_LUIDAttribute *new_set; |
252 | | |
253 | | /* we can allocate memory to add the new privilege */ |
254 | |
|
255 | 0 | new_set = talloc_realloc(priv_set->mem_ctx, priv_set->set, struct lsa_LUIDAttribute, priv_set->count + 1); |
256 | 0 | if ( !new_set ) { |
257 | 0 | DEBUG(0,("privilege_set_add: failed to allocate memory!\n")); |
258 | 0 | return false; |
259 | 0 | } |
260 | | |
261 | 0 | new_set[priv_set->count].luid.high = set.luid.high; |
262 | 0 | new_set[priv_set->count].luid.low = set.luid.low; |
263 | 0 | new_set[priv_set->count].attribute = set.attribute; |
264 | |
|
265 | 0 | priv_set->count++; |
266 | 0 | priv_set->set = new_set; |
267 | |
|
268 | 0 | return true; |
269 | 0 | } |
270 | | |
271 | | /******************************************************************* |
272 | | *******************************************************************/ |
273 | | |
274 | | bool se_priv_to_privilege_set( PRIVILEGE_SET *set, uint64_t privilege_mask ) |
275 | 0 | { |
276 | 0 | size_t i; |
277 | 0 | struct lsa_LUIDAttribute luid; |
278 | |
|
279 | 0 | luid.attribute = 0; |
280 | 0 | luid.luid.high = 0; |
281 | |
|
282 | 0 | for ( i=0; i<ARRAY_SIZE(privs); i++ ) { |
283 | 0 | if ((privilege_mask & privs[i].privilege_mask) == 0) |
284 | 0 | continue; |
285 | | |
286 | 0 | luid.luid.high = 0; |
287 | 0 | luid.luid.low = privs[i].luid; |
288 | |
|
289 | 0 | if ( !privilege_set_add( set, luid ) ) |
290 | 0 | return false; |
291 | 0 | } |
292 | | |
293 | 0 | return true; |
294 | 0 | } |
295 | | |
296 | | /******************************************************************* |
297 | | *******************************************************************/ |
298 | | |
299 | | bool privilege_set_to_se_priv( uint64_t *privilege_mask, struct lsa_PrivilegeSet *privset ) |
300 | 0 | { |
301 | 0 | uint32_t i; |
302 | |
|
303 | 0 | ZERO_STRUCTP( privilege_mask ); |
304 | |
|
305 | 0 | for ( i=0; i<privset->count; i++ ) { |
306 | 0 | uint64_t r; |
307 | | |
308 | | /* sanity check for invalid privilege. we really |
309 | | only care about the low 32 bits */ |
310 | |
|
311 | 0 | if ( privset->set[i].luid.high != 0 ) |
312 | 0 | return false; |
313 | | |
314 | 0 | r = sec_privilege_mask(privset->set[i].luid.low); |
315 | 0 | if (r) { |
316 | 0 | *privilege_mask |= r; |
317 | 0 | } |
318 | 0 | } |
319 | | |
320 | 0 | return true; |
321 | 0 | } |
322 | | |
323 | | /* |
324 | | map a privilege id to the wire string constant |
325 | | */ |
326 | | const char *sec_privilege_name(enum sec_privilege privilege) |
327 | 0 | { |
328 | 0 | size_t i; |
329 | 0 | for (i=0;i<ARRAY_SIZE(privs);i++) { |
330 | 0 | if (privs[i].luid == privilege) { |
331 | 0 | return privs[i].name; |
332 | 0 | } |
333 | 0 | } |
334 | 0 | return NULL; |
335 | 0 | } |
336 | | |
337 | | /* |
338 | | map a privilege id to a privilege display name. Return NULL if not found |
339 | | |
340 | | TODO: this should use language mappings |
341 | | */ |
342 | | const char *sec_privilege_display_name(enum sec_privilege privilege, uint16_t *language) |
343 | 0 | { |
344 | 0 | size_t i; |
345 | 0 | for (i=0;i<ARRAY_SIZE(privs);i++) { |
346 | 0 | if (privs[i].luid == privilege) { |
347 | 0 | return privs[i].description; |
348 | 0 | } |
349 | 0 | } |
350 | 0 | return NULL; |
351 | 0 | } |
352 | | |
353 | | /* |
354 | | map a privilege name to a privilege id. Return SEC_PRIV_INVALID if not found |
355 | | */ |
356 | | enum sec_privilege sec_privilege_id(const char *name) |
357 | 0 | { |
358 | 0 | size_t i; |
359 | 0 | for (i=0;i<ARRAY_SIZE(privs);i++) { |
360 | 0 | if (strcasecmp(privs[i].name, name) == 0) { |
361 | 0 | return privs[i].luid; |
362 | 0 | } |
363 | 0 | } |
364 | 0 | return SEC_PRIV_INVALID; |
365 | 0 | } |
366 | | |
367 | | /* |
368 | | map a 'right' name to it's bitmap value. Return 0 if not found |
369 | | */ |
370 | | uint32_t sec_right_bit(const char *name) |
371 | 0 | { |
372 | 0 | size_t i; |
373 | 0 | for (i=0;i<ARRAY_SIZE(rights);i++) { |
374 | 0 | if (strcasecmp(rights[i].name, name) == 0) { |
375 | 0 | return rights[i].right_mask; |
376 | 0 | } |
377 | 0 | } |
378 | 0 | return 0; |
379 | 0 | } |
380 | | |
381 | | /* |
382 | | assist in walking the table of privileges - return the LUID (low 32 bits) by index |
383 | | */ |
384 | | enum sec_privilege sec_privilege_from_index(int idx) |
385 | 0 | { |
386 | 0 | if (idx >= 0 && (unsigned)idx<ARRAY_SIZE(privs)) { |
387 | 0 | return privs[idx].luid; |
388 | 0 | } |
389 | 0 | return SEC_PRIV_INVALID; |
390 | 0 | } |
391 | | |
392 | | /* |
393 | | assist in walking the table of privileges - return the string constant by index |
394 | | */ |
395 | | const char *sec_privilege_name_from_index(int idx) |
396 | 0 | { |
397 | 0 | if (idx >= 0 && (unsigned)idx<ARRAY_SIZE(privs)) { |
398 | 0 | return privs[idx].name; |
399 | 0 | } |
400 | 0 | return NULL; |
401 | 0 | } |
402 | | |
403 | | |
404 | | |
405 | | /* |
406 | | return true if a security_token has a particular privilege bit set |
407 | | */ |
408 | | bool security_token_has_privilege(const struct security_token *token, enum sec_privilege privilege) |
409 | 3.26k | { |
410 | 3.26k | uint64_t mask; |
411 | | |
412 | 3.26k | if (!token) { |
413 | 0 | return false; |
414 | 0 | } |
415 | | |
416 | 3.26k | mask = sec_privilege_mask(privilege); |
417 | 3.26k | if (mask == 0) { |
418 | 0 | return false; |
419 | 0 | } |
420 | | |
421 | 3.26k | if (token->privilege_mask & mask) { |
422 | 1.15k | return true; |
423 | 1.15k | } |
424 | 2.10k | return false; |
425 | 3.26k | } |
426 | | |
427 | | bool security_token_system_privilege(const struct security_token *token) |
428 | 0 | { |
429 | 0 | if (token == NULL) { |
430 | 0 | return false; |
431 | 0 | } |
432 | | |
433 | 0 | if (token->privilege_mask == (uint64_t)~0) { |
434 | 0 | return true; |
435 | 0 | } |
436 | | |
437 | 0 | return false; |
438 | 0 | } |
439 | | |
440 | | /* |
441 | | set a bit in the privilege mask |
442 | | */ |
443 | | void security_token_set_privilege(struct security_token *token, enum sec_privilege privilege) |
444 | 0 | { |
445 | | /* Relies on the fact that an invalid privilege will return 0, so won't change this */ |
446 | 0 | token->privilege_mask |= sec_privilege_mask(privilege); |
447 | 0 | } |
448 | | |
449 | | /* |
450 | | set a bit in the rights mask |
451 | | */ |
452 | | void security_token_set_right_bit(struct security_token *token, uint32_t right_bit) |
453 | 0 | { |
454 | 0 | token->rights_mask |= right_bit; |
455 | 0 | } |
456 | | |
457 | | char *security_token_debug_privileges(TALLOC_CTX *mem_ctx, |
458 | | const struct security_token *token) |
459 | 0 | { |
460 | 0 | char *s = NULL; |
461 | |
|
462 | 0 | s = talloc_asprintf(mem_ctx, |
463 | 0 | " Privileges (0x%16" PRIX64 "):\n", |
464 | 0 | token->privilege_mask); |
465 | |
|
466 | 0 | if (token->privilege_mask) { |
467 | 0 | size_t idx = 0; |
468 | 0 | size_t i = 0; |
469 | 0 | for (idx = 0; idx<ARRAY_SIZE(privs); idx++) { |
470 | 0 | if (token->privilege_mask & privs[idx].privilege_mask) { |
471 | 0 | talloc_asprintf_addbuf( |
472 | 0 | &s, |
473 | 0 | " Privilege[%3zu]: %s\n", |
474 | 0 | i++, |
475 | 0 | privs[idx].name); |
476 | 0 | } |
477 | 0 | } |
478 | 0 | } |
479 | |
|
480 | 0 | talloc_asprintf_addbuf(&s, |
481 | 0 | " Rights (0x%16" PRIX32 "):\n", |
482 | 0 | token->rights_mask); |
483 | |
|
484 | 0 | if (token->rights_mask) { |
485 | 0 | size_t idx = 0; |
486 | 0 | size_t i = 0; |
487 | 0 | for (idx = 0; idx<ARRAY_SIZE(rights); idx++) { |
488 | 0 | if (token->rights_mask & rights[idx].right_mask) { |
489 | 0 | talloc_asprintf_addbuf(&s, |
490 | 0 | " Right[%3zu]: %s\n", |
491 | 0 | i++, |
492 | 0 | rights[idx].name); |
493 | 0 | } |
494 | 0 | } |
495 | 0 | } |
496 | |
|
497 | 0 | return s; |
498 | 0 | } |