Coverage Report

Created: 2026-02-14 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}