Coverage Report

Created: 2025-12-05 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/lib/privs.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * Zebra privileges.
4
 *
5
 * Copyright (C) 2003 Paul Jakma.
6
 * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
7
 */
8
#include <zebra.h>
9
#include "log.h"
10
#include "privs.h"
11
#include "memory.h"
12
#include "frr_pthread.h"
13
#include "lib_errors.h"
14
#include "lib/queue.h"
15
16
8
DEFINE_MTYPE_STATIC(LIB, PRIVS, "Privilege information");
17
8
18
8
/*
19
8
 * Different capabilities/privileges apis have different characteristics: some
20
8
 * are process-wide, and some are per-thread.
21
8
 */
22
8
#ifdef HAVE_CAPABILITIES
23
8
#ifdef HAVE_LCAPS
24
8
static const bool privs_per_process;  /* = false */
25
8
#else
26
8
static const bool privs_per_process = true;
27
8
#endif /* HAVE_LCAPS */
28
8
#else /* HAVE_CAPABILITIES */
29
8
static const bool privs_per_process = true;
30
8
#endif
31
8
32
8
#ifdef HAVE_CAPABILITIES
33
8
34
8
/* sort out some generic internal types for:
35
8
 *
36
8
 * privilege values (cap_value_t, priv_t)   -> pvalue_t
37
8
 * privilege set (..., priv_set_t)    -> pset_t
38
8
 * privilege working storage (cap_t, ...)   -> pstorage_t
39
8
 *
40
8
 * values we think of as numeric (they're ints really, but we dont know)
41
8
 * sets are mostly opaque, to hold a set of privileges, related in some way.
42
8
 * storage binds together a set of sets we're interested in.
43
8
 * (in reality: cap_value_t and priv_t are ints)
44
8
 */
45
8
#ifdef HAVE_LCAPS
46
8
/* Linux doesn't have a 'set' type: a set of related privileges */
47
8
struct _pset {
48
8
  int num;
49
8
  cap_value_t *caps;
50
8
};
51
8
typedef cap_value_t pvalue_t;
52
8
typedef struct _pset pset_t;
53
8
typedef cap_t pstorage_t;
54
8
55
8
#else /* no LCAPS */
56
8
#error "HAVE_CAPABILITIES defined, but neither LCAPS nor Solaris Capabilties!"
57
8
#endif /* HAVE_LCAPS */
58
8
#endif /* HAVE_CAPABILITIES */
59
8
60
8
/* the default NULL state we report is RAISED, but could be LOWERED if
61
8
 * zprivs_terminate is called and the NULL handler is installed.
62
8
 */
63
8
static zebra_privs_current_t zprivs_null_state = ZPRIVS_RAISED;
64
8
65
8
/* internal privileges state */
66
8
static struct _zprivs_t {
67
8
#ifdef HAVE_CAPABILITIES
68
8
  pstorage_t caps;   /* working storage        */
69
8
  pset_t *syscaps_p; /* system-type requested permitted caps    */
70
8
  pset_t *syscaps_i; /* system-type requested inheritable caps  */
71
8
#endif         /* HAVE_CAPABILITIES */
72
8
  uid_t zuid, /* uid to run as            */
73
8
    zsuid;     /* saved uid                */
74
8
  gid_t zgid; /* gid to run as            */
75
8
  gid_t vtygrp;      /* gid for vty sockets      */
76
8
} zprivs_state;
77
8
78
8
/* externally exported but not directly accessed functions */
79
8
#ifdef HAVE_CAPABILITIES
80
8
int zprivs_change_caps(zebra_privs_ops_t);
81
8
zebra_privs_current_t zprivs_state_caps(void);
82
8
#endif /* HAVE_CAPABILITIES */
83
8
int zprivs_change_uid(zebra_privs_ops_t);
84
8
zebra_privs_current_t zprivs_state_uid(void);
85
8
int zprivs_change_null(zebra_privs_ops_t);
86
8
zebra_privs_current_t zprivs_state_null(void);
87
8
88
8
#ifdef HAVE_CAPABILITIES
89
8
/* internal capability API */
90
8
static pset_t *zcaps2sys(zebra_capabilities_t *, int);
91
8
static void zprivs_caps_init(struct zebra_privs_t *);
92
8
static void zprivs_caps_terminate(void);
93
8
94
8
/* Map of Quagga abstract capabilities to system capabilities */
95
8
static struct {
96
8
  int num;
97
8
  pvalue_t *system_caps;
98
8
} cap_map[ZCAP_MAX] = {
99
8
#ifdef HAVE_LCAPS /* Quagga -> Linux capabilities mappings */
100
8
    [ZCAP_SETID] =
101
8
      {
102
8
        2, (pvalue_t[]){CAP_SETGID, CAP_SETUID},
103
8
      },
104
8
    [ZCAP_BIND] =
105
8
      {
106
8
        1, (pvalue_t[]){CAP_NET_BIND_SERVICE},
107
8
      },
108
8
    [ZCAP_NET_ADMIN] =
109
8
      {
110
8
        1, (pvalue_t[]){CAP_NET_ADMIN},
111
8
      },
112
8
    [ZCAP_NET_RAW] =
113
8
      {
114
8
        1, (pvalue_t[]){CAP_NET_RAW},
115
8
      },
116
8
    [ZCAP_CHROOT] =
117
8
      {
118
8
        1,
119
8
        (pvalue_t[]){
120
8
          CAP_SYS_CHROOT,
121
8
        },
122
8
      },
123
8
    [ZCAP_NICE] =
124
8
      {
125
8
        1, (pvalue_t[]){CAP_SYS_NICE},
126
8
      },
127
8
    [ZCAP_PTRACE] =
128
8
      {
129
8
        1, (pvalue_t[]){CAP_SYS_PTRACE},
130
8
      },
131
8
    [ZCAP_DAC_OVERRIDE] =
132
8
      {
133
8
        1, (pvalue_t[]){CAP_DAC_OVERRIDE},
134
8
      },
135
8
    [ZCAP_READ_SEARCH] =
136
8
      {
137
8
        1, (pvalue_t[]){CAP_DAC_READ_SEARCH},
138
8
      },
139
8
    [ZCAP_SYS_ADMIN] =
140
8
      {
141
8
        1, (pvalue_t[]){CAP_SYS_ADMIN},
142
8
      },
143
8
    [ZCAP_FOWNER] =
144
8
      {
145
8
        1, (pvalue_t[]){CAP_FOWNER},
146
8
      },
147
8
    [ZCAP_IPC_LOCK] =
148
8
      {
149
8
        1, (pvalue_t[]){CAP_IPC_LOCK},
150
8
      },
151
8
    [ZCAP_SYS_RAWIO] =
152
8
      {
153
8
        1, (pvalue_t[]){CAP_SYS_RAWIO},
154
8
      },
155
8
#endif /* HAVE_LCAPS */
156
8
};
157
8
158
8
#ifdef HAVE_LCAPS
159
8
/* Linux forms of capabilities methods */
160
8
/* convert zebras privileges to system capabilities */
161
8
static pset_t *zcaps2sys(zebra_capabilities_t *zcaps, int num)
162
8
{
163
8
  pset_t *syscaps;
164
8
  int i, j = 0, count = 0;
165
166
8
  if (!num)
167
4
    return NULL;
168
169
  /* first count up how many system caps we have */
170
19
  for (i = 0; i < num; i++)
171
15
    count += cap_map[zcaps[i]].num;
172
173
4
  if ((syscaps = XCALLOC(MTYPE_PRIVS, (sizeof(pset_t) * num))) == NULL) {
174
0
    fprintf(stderr, "%s: could not allocate syscaps!", __func__);
175
0
    return NULL;
176
0
  }
177
178
4
  syscaps->caps = XCALLOC(MTYPE_PRIVS, (sizeof(pvalue_t) * count));
179
180
4
  if (!syscaps->caps) {
181
0
    fprintf(stderr, "%s: could not XCALLOC caps!", __func__);
182
0
    return NULL;
183
0
  }
184
185
  /* copy the capabilities over */
186
4
  count = 0;
187
19
  for (i = 0; i < num; i++)
188
30
    for (j = 0; j < cap_map[zcaps[i]].num; j++)
189
15
      syscaps->caps[count++] =
190
15
        cap_map[zcaps[i]].system_caps[j];
191
192
  /* iterations above should be exact same as previous count, obviously..
193
   */
194
4
  syscaps->num = count;
195
196
4
  return syscaps;
197
4
}
198
199
/* set or clear the effective capabilities to/from permitted */
200
int zprivs_change_caps(zebra_privs_ops_t op)
201
0
{
202
0
  cap_flag_value_t cflag;
203
204
  /* should be no possibility of being called without valid caps */
205
0
  assert(zprivs_state.syscaps_p && zprivs_state.caps);
206
0
  if (!(zprivs_state.syscaps_p && zprivs_state.caps))
207
0
    exit(1);
208
209
0
  if (op == ZPRIVS_RAISE)
210
0
    cflag = CAP_SET;
211
0
  else if (op == ZPRIVS_LOWER)
212
0
    cflag = CAP_CLEAR;
213
0
  else
214
0
    return -1;
215
216
0
  if (!cap_set_flag(zprivs_state.caps, CAP_EFFECTIVE,
217
0
        zprivs_state.syscaps_p->num,
218
0
        zprivs_state.syscaps_p->caps, cflag))
219
0
    return cap_set_proc(zprivs_state.caps);
220
0
  return -1;
221
0
}
222
223
zebra_privs_current_t zprivs_state_caps(void)
224
0
{
225
0
  int i;
226
0
  cap_flag_value_t val;
227
228
  /* should be no possibility of being called without valid caps */
229
0
  assert(zprivs_state.syscaps_p && zprivs_state.caps);
230
0
  if (!(zprivs_state.syscaps_p && zprivs_state.caps))
231
0
    exit(1);
232
233
0
  for (i = 0; i < zprivs_state.syscaps_p->num; i++) {
234
0
    if (cap_get_flag(zprivs_state.caps,
235
0
         zprivs_state.syscaps_p->caps[i], CAP_EFFECTIVE,
236
0
         &val)) {
237
0
      flog_err(
238
0
        EC_LIB_SYSTEM_CALL,
239
0
        "zprivs_state_caps: could not cap_get_flag, %s",
240
0
        safe_strerror(errno));
241
0
      return ZPRIVS_UNKNOWN;
242
0
    }
243
0
    if (val == CAP_SET)
244
0
      return ZPRIVS_RAISED;
245
0
  }
246
0
  return ZPRIVS_LOWERED;
247
0
}
248
249
/** Release private cap state if allocated. */
250
static void zprivs_state_free_caps(void)
251
4
{
252
4
  if (zprivs_state.syscaps_p) {
253
0
    if (zprivs_state.syscaps_p->num)
254
0
      XFREE(MTYPE_PRIVS, zprivs_state.syscaps_p->caps);
255
256
0
    XFREE(MTYPE_PRIVS, zprivs_state.syscaps_p);
257
0
  }
258
259
4
  if (zprivs_state.syscaps_i) {
260
0
    if (zprivs_state.syscaps_i->num)
261
0
      XFREE(MTYPE_PRIVS, zprivs_state.syscaps_i->caps);
262
263
0
    XFREE(MTYPE_PRIVS, zprivs_state.syscaps_i);
264
0
  }
265
266
4
  if (zprivs_state.caps) {
267
0
    cap_free(zprivs_state.caps);
268
0
    zprivs_state.caps = NULL;
269
0
  }
270
4
}
271
272
static void zprivs_caps_init(struct zebra_privs_t *zprivs)
273
4
{
274
  /* Release allocated zcaps if this function was called before. */
275
4
  zprivs_state_free_caps();
276
277
4
  zprivs_state.syscaps_p = zcaps2sys(zprivs->caps_p, zprivs->cap_num_p);
278
4
  zprivs_state.syscaps_i = zcaps2sys(zprivs->caps_i, zprivs->cap_num_i);
279
280
  /* Tell kernel we want caps maintained across uid changes */
281
4
  if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) {
282
0
    fprintf(stderr,
283
0
      "privs_init: could not set PR_SET_KEEPCAPS, %s\n",
284
0
      safe_strerror(errno));
285
0
    exit(1);
286
0
  }
287
288
  /* we have caps, we have no need to ever change back the original user
289
   */
290
  /* only change uid if we don't have the correct one */
291
#ifndef FUZZING
292
  if ((zprivs_state.zuid) && (zprivs_state.zsuid != zprivs_state.zuid)) {
293
    if (setreuid(zprivs_state.zuid, zprivs_state.zuid)) {
294
      fprintf(stderr,
295
        "zprivs_init (cap): could not setreuid, %s\n",
296
        safe_strerror(errno));
297
      exit(1);
298
    }
299
  }
300
#endif
301
4
  if (!(zprivs_state.caps = cap_init())) {
302
0
    fprintf(stderr, "privs_init: failed to cap_init, %s\n",
303
0
      safe_strerror(errno));
304
0
    exit(1);
305
0
  }
306
307
4
  if (cap_clear(zprivs_state.caps)) {
308
0
    fprintf(stderr, "privs_init: failed to cap_clear, %s\n",
309
0
      safe_strerror(errno));
310
0
    exit(1);
311
0
  }
312
313
  /* set permitted caps, if any */
314
4
  if (zprivs_state.syscaps_p && zprivs_state.syscaps_p->num) {
315
4
    cap_set_flag(zprivs_state.caps, CAP_PERMITTED,
316
4
           zprivs_state.syscaps_p->num,
317
4
           zprivs_state.syscaps_p->caps, CAP_SET);
318
4
  }
319
320
  /* set inheritable caps, if any */
321
4
  if (zprivs_state.syscaps_i && zprivs_state.syscaps_i->num) {
322
0
    cap_set_flag(zprivs_state.caps, CAP_INHERITABLE,
323
0
           zprivs_state.syscaps_i->num,
324
0
           zprivs_state.syscaps_i->caps, CAP_SET);
325
0
  }
326
327
  /* apply caps. CAP_EFFECTIVE is cleared. we'll raise the caps as
328
   * and when, and only when, they are needed.
329
   */
330
#ifndef FUZZING
331
  if (cap_set_proc(zprivs_state.caps)) {
332
    cap_t current_caps;
333
    char *current_caps_text = NULL;
334
    char *wanted_caps_text = NULL;
335
336
    fprintf(stderr, "privs_init: initial cap_set_proc failed: %s\n",
337
      safe_strerror(errno));
338
339
    current_caps = cap_get_proc();
340
    if (current_caps) {
341
      current_caps_text = cap_to_text(current_caps, NULL);
342
      cap_free(current_caps);
343
    }
344
345
    wanted_caps_text = cap_to_text(zprivs_state.caps, NULL);
346
    fprintf(stderr, "Wanted caps: %s\n",
347
      wanted_caps_text ? wanted_caps_text : "???");
348
    fprintf(stderr, "Have   caps: %s\n",
349
      current_caps_text ? current_caps_text : "???");
350
    if (current_caps_text)
351
      cap_free(current_caps_text);
352
    if (wanted_caps_text)
353
      cap_free(wanted_caps_text);
354
355
    exit(1);
356
  }
357
#endif
358
  /* set methods for the caller to use */
359
4
  zprivs->change = zprivs_change_caps;
360
4
  zprivs->current_state = zprivs_state_caps;
361
4
}
362
363
static void zprivs_caps_terminate(void)
364
0
{
365
  /* Clear all capabilities, if we have any. */
366
0
  if (zprivs_state.caps)
367
0
    cap_clear(zprivs_state.caps);
368
0
  else
369
0
    return;
370
371
  /* and boom, capabilities are gone forever */
372
0
  if (cap_set_proc(zprivs_state.caps)) {
373
0
    fprintf(stderr, "privs_terminate: cap_set_proc failed, %s",
374
0
      safe_strerror(errno));
375
0
    exit(1);
376
0
  }
377
378
0
  zprivs_state_free_caps();
379
0
}
380
#else /* !HAVE_LCAPS */
381
#error "no Linux capabilities, dazed and confused..."
382
#endif /* HAVE_LCAPS */
383
#endif /* HAVE_CAPABILITIES */
384
385
int zprivs_change_uid(zebra_privs_ops_t op)
386
0
{
387
0
  if (zprivs_state.zsuid == zprivs_state.zuid)
388
0
    return 0;
389
0
  if (op == ZPRIVS_RAISE)
390
0
    return seteuid(zprivs_state.zsuid);
391
0
  else if (op == ZPRIVS_LOWER)
392
0
    return seteuid(zprivs_state.zuid);
393
0
  else
394
0
    return -1;
395
0
}
396
397
zebra_privs_current_t zprivs_state_uid(void)
398
0
{
399
0
  return ((zprivs_state.zuid == geteuid()) ? ZPRIVS_LOWERED
400
0
             : ZPRIVS_RAISED);
401
0
}
402
403
int zprivs_change_null(zebra_privs_ops_t op)
404
0
{
405
0
  return 0;
406
0
}
407
408
zebra_privs_current_t zprivs_state_null(void)
409
0
{
410
0
  return zprivs_null_state;
411
0
}
412
413
#ifndef HAVE_GETGROUPLIST
414
/* Solaris 11 has no getgrouplist() */
415
static int getgrouplist(const char *user, gid_t group, gid_t *groups,
416
      int *ngroups)
417
{
418
  struct group *grp;
419
  size_t usridx;
420
  int pos = 0, ret;
421
422
  if (pos < *ngroups)
423
    groups[pos] = group;
424
  pos++;
425
426
  setgrent();
427
  while ((grp = getgrent())) {
428
    if (grp->gr_gid == group)
429
      continue;
430
    for (usridx = 0; grp->gr_mem[usridx] != NULL; usridx++)
431
      if (!strcmp(grp->gr_mem[usridx], user)) {
432
        if (pos < *ngroups)
433
          groups[pos] = grp->gr_gid;
434
        pos++;
435
        break;
436
      }
437
  }
438
  endgrent();
439
440
  ret = (pos <= *ngroups) ? pos : -1;
441
  *ngroups = pos;
442
  return ret;
443
}
444
#endif /* HAVE_GETGROUPLIST */
445
446
/*
447
 * Helper function that locates a refcounting object to use: a process-wide
448
 * object or a per-pthread object.
449
 */
450
static struct zebra_privs_refs_t *get_privs_refs(struct zebra_privs_t *privs)
451
0
{
452
0
  struct zebra_privs_refs_t *temp, *refs = NULL;
453
0
  pthread_t tid;
454
0
455
0
  if (privs_per_process)
456
0
    refs = &(privs->process_refs);
457
0
  else {
458
0
    /* Locate - or create - the object for the current pthread. */
459
0
    tid = pthread_self();
460
0
461
0
    STAILQ_FOREACH(temp, &(privs->thread_refs), entry) {
462
0
      if (pthread_equal(temp->tid, tid)) {
463
0
        refs = temp;
464
0
        break;
465
0
      }
466
0
    }
467
0
468
0
    /* Need to create a new refcounting object. */
469
0
    if (refs == NULL) {
470
0
      refs = XCALLOC(MTYPE_PRIVS,
471
0
               sizeof(struct zebra_privs_refs_t));
472
0
      refs->tid = tid;
473
0
      STAILQ_INSERT_TAIL(&(privs->thread_refs), refs, entry);
474
0
    }
475
0
  }
476
0
477
0
  return refs;
478
0
}
479
480
struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
481
            const char *funcname)
482
3
{
483
3
#ifdef FUZZING
484
3
  return NULL;
485
0
#endif
486
0
  int save_errno = errno;
487
0
  struct zebra_privs_refs_t *refs;
488
489
0
  if (!privs)
490
0
    return NULL;
491
492
  /*
493
   * Serialize 'raise' operations; particularly important for
494
   * OSes where privs are process-wide.
495
   */
496
0
  frr_with_mutex (&(privs->mutex)) {
497
    /* Locate ref-counting object to use */
498
0
    refs = get_privs_refs(privs);
499
500
0
    if (++(refs->refcount) == 1) {
501
0
      errno = 0;
502
0
      if (privs->change(ZPRIVS_RAISE)) {
503
0
        zlog_err("%s: Failed to raise privileges (%s)",
504
0
           funcname, safe_strerror(errno));
505
0
      }
506
0
      errno = save_errno;
507
0
      refs->raised_in_funcname = funcname;
508
0
    }
509
0
  }
510
511
0
  return privs;
512
0
}
513
514
void _zprivs_lower(struct zebra_privs_t **privs)
515
3
{
516
3
#ifdef FUZZING
517
3
  return;
518
0
#endif
519
0
  int save_errno = errno;
520
0
  struct zebra_privs_refs_t *refs;
521
522
0
  if (!*privs)
523
0
    return;
524
525
  /* Serialize 'lower privs' operation - particularly important
526
   * when OS privs are process-wide.
527
   */
528
0
  frr_with_mutex (&(*privs)->mutex) {
529
0
    refs = get_privs_refs(*privs);
530
531
0
    if (--(refs->refcount) == 0) {
532
0
      errno = 0;
533
0
      if ((*privs)->change(ZPRIVS_LOWER)) {
534
0
        zlog_err("%s: Failed to lower privileges (%s)",
535
0
           refs->raised_in_funcname,
536
0
           safe_strerror(errno));
537
0
      }
538
0
      errno = save_errno;
539
0
      refs->raised_in_funcname = NULL;
540
0
    }
541
0
  }
542
543
0
  *privs = NULL;
544
0
}
545
546
void zprivs_preinit(struct zebra_privs_t *zprivs)
547
4
{
548
4
  struct passwd *pwentry = NULL;
549
4
  struct group *grentry = NULL;
550
551
4
  if (!zprivs) {
552
0
    fprintf(stderr, "zprivs_init: called with NULL arg!\n");
553
0
    exit(1);
554
0
  }
555
556
4
  pthread_mutex_init(&(zprivs->mutex), NULL);
557
4
  zprivs->process_refs.refcount = 0;
558
4
  zprivs->process_refs.raised_in_funcname = NULL;
559
4
  STAILQ_INIT(&zprivs->thread_refs);
560
561
4
#ifdef FUZZING
562
4
  zprivs->user = NULL;
563
4
  zprivs->group = NULL;
564
4
  zprivs->vty_group = NULL;
565
4
#endif
566
567
4
  if (zprivs->vty_group) {
568
    /* in a "NULL" setup, this is allowed to fail too, but still
569
     * try. */
570
0
    if ((grentry = getgrnam(zprivs->vty_group)))
571
0
      zprivs_state.vtygrp = grentry->gr_gid;
572
0
    else
573
0
      zprivs_state.vtygrp = (gid_t)-1;
574
0
  }
575
576
  /* NULL privs */
577
4
  if (!(zprivs->user || zprivs->group || zprivs->cap_num_p
578
0
        || zprivs->cap_num_i)) {
579
0
    zprivs->change = zprivs_change_null;
580
0
    zprivs->current_state = zprivs_state_null;
581
0
    return;
582
0
  }
583
584
4
  if (zprivs->user) {
585
0
    if ((pwentry = getpwnam(zprivs->user)) == NULL) {
586
      /* cant use log.h here as it depends on vty */
587
0
      fprintf(stderr,
588
0
        "privs_init: could not lookup user %s\n",
589
0
        zprivs->user);
590
0
      exit(1);
591
0
    }
592
593
0
    zprivs_state.zuid = pwentry->pw_uid;
594
0
    zprivs_state.zgid = pwentry->pw_gid;
595
0
  }
596
597
4
  grentry = NULL;
598
599
4
  if (zprivs->group) {
600
0
    if ((grentry = getgrnam(zprivs->group)) == NULL) {
601
0
      fprintf(stderr,
602
0
        "privs_init: could not lookup group %s\n",
603
0
        zprivs->group);
604
0
      exit(1);
605
0
    }
606
607
0
    zprivs_state.zgid = grentry->gr_gid;
608
0
  }
609
4
}
610
611
struct zebra_privs_t *lib_privs;
612
613
void zprivs_init(struct zebra_privs_t *zprivs)
614
4
{
615
4
  gid_t groups[NGROUPS_MAX] = {};
616
4
  int i, ngroups = 0;
617
4
  int found = 0;
618
619
  /* NULL privs */
620
4
  if (!(zprivs->user || zprivs->group || zprivs->cap_num_p
621
0
        || zprivs->cap_num_i))
622
0
    return;
623
624
4
  lib_privs = zprivs;
625
626
4
  if (zprivs->user) {
627
0
    ngroups = array_size(groups);
628
0
    if (getgrouplist(zprivs->user, zprivs_state.zgid, groups,
629
0
         &ngroups)
630
0
        < 0) {
631
      /* cant use log.h here as it depends on vty */
632
0
      fprintf(stderr,
633
0
        "privs_init: could not getgrouplist for user %s\n",
634
0
        zprivs->user);
635
0
      exit(1);
636
0
    }
637
0
  }
638
639
4
  if (zprivs->vty_group)
640
  /* Add the vty_group to the supplementary groups so it can be chowned to
641
     */
642
0
  {
643
0
    if (zprivs_state.vtygrp == (gid_t)-1) {
644
0
      fprintf(stderr,
645
0
        "privs_init: could not lookup vty group %s\n",
646
0
        zprivs->vty_group);
647
0
      exit(1);
648
0
    }
649
650
0
    for (i = 0; i < ngroups; i++)
651
0
      if (groups[i] == zprivs_state.vtygrp) {
652
0
        found++;
653
0
        break;
654
0
      }
655
656
0
    if (!found) {
657
0
      fprintf(stderr,
658
0
        "privs_init: user(%s) is not part of vty group specified(%s)\n",
659
0
        zprivs->user, zprivs->vty_group);
660
0
      exit(1);
661
0
    }
662
0
    if (i >= ngroups && ngroups < (int)array_size(groups)) {
663
0
      groups[i] = zprivs_state.vtygrp;
664
0
    }
665
0
  }
666
667
4
  zprivs_state.zsuid = geteuid(); /* initial uid */
668
  /* add groups only if we changed uid - otherwise skip */
669
#ifndef FUZZING
670
  if ((ngroups) && (zprivs_state.zsuid != zprivs_state.zuid)) {
671
    if (setgroups(ngroups, groups)) {
672
      fprintf(stderr, "privs_init: could not setgroups, %s\n",
673
        safe_strerror(errno));
674
      exit(1);
675
    }
676
  }
677
678
  /* change gid only if we changed uid - otherwise skip */
679
  if ((zprivs_state.zgid) && (zprivs_state.zsuid != zprivs_state.zuid)) {
680
    /* change group now, forever. uid we do later */
681
    if (setregid(zprivs_state.zgid, zprivs_state.zgid)) {
682
      fprintf(stderr, "zprivs_init: could not setregid, %s\n",
683
        safe_strerror(errno));
684
      exit(1);
685
    }
686
  }
687
#endif
688
689
4
#ifdef HAVE_CAPABILITIES
690
4
  zprivs_caps_init(zprivs);
691
692
  /*
693
   * If we have initialized the system with no requested
694
   * capabilities, change will not have been set
695
   * to anything by zprivs_caps_init, As such
696
   * we should make sure that when we attempt
697
   * to raize privileges that we actually have
698
   * a do nothing function to call instead of a
699
   * crash :).
700
   */
701
4
  if (!zprivs->change)
702
0
    zprivs->change = zprivs_change_null;
703
704
#else  /* !HAVE_CAPABILITIES */
705
  /* we dont have caps. we'll need to maintain rid and saved uid
706
   * and change euid back to saved uid (who we presume has all necessary
707
   * privileges) whenever we are asked to raise our privileges.
708
   *
709
   * This is not worth that much security wise, but all we can do.
710
   */
711
  zprivs_state.zsuid = geteuid();
712
  /* only change uid if we don't have the correct one */
713
  if ((zprivs_state.zuid) && (zprivs_state.zsuid != zprivs_state.zuid)) {
714
    if (setreuid(-1, zprivs_state.zuid)) {
715
      fprintf(stderr,
716
        "privs_init (uid): could not setreuid, %s\n",
717
        safe_strerror(errno));
718
      exit(1);
719
    }
720
  }
721
#ifndef FUZZING
722
  zprivs->change = zprivs_change_uid;
723
  zprivs->current_state = zprivs_state_uid;
724
#endif
725
#endif /* HAVE_CAPABILITIES */
726
4
}
727
728
void zprivs_terminate(struct zebra_privs_t *zprivs)
729
0
{
730
0
  struct zebra_privs_refs_t *refs;
731
732
0
  lib_privs = NULL;
733
734
0
  if (!zprivs) {
735
0
    fprintf(stderr, "%s: no privs struct given, terminating",
736
0
      __func__);
737
0
    exit(0);
738
0
  }
739
740
0
#ifdef HAVE_CAPABILITIES
741
0
  if (zprivs->user || zprivs->group || zprivs->cap_num_p
742
0
      || zprivs->cap_num_i)
743
0
    zprivs_caps_terminate();
744
#else  /* !HAVE_CAPABILITIES */
745
  /* only change uid if we don't have the correct one */
746
  if ((zprivs_state.zuid) && (zprivs_state.zsuid != zprivs_state.zuid)) {
747
    if (setreuid(zprivs_state.zuid, zprivs_state.zuid)) {
748
      fprintf(stderr,
749
        "privs_terminate: could not setreuid, %s",
750
        safe_strerror(errno));
751
      exit(1);
752
    }
753
  }
754
#endif /* HAVE_LCAPS */
755
756
0
  while ((refs = STAILQ_FIRST(&(zprivs->thread_refs))) != NULL) {
757
0
    STAILQ_REMOVE_HEAD(&(zprivs->thread_refs), entry);
758
0
    XFREE(MTYPE_PRIVS, refs);
759
0
  }
760
761
0
  zprivs->change = zprivs_change_null;
762
0
  zprivs->current_state = zprivs_state_null;
763
0
  zprivs_null_state = ZPRIVS_LOWERED;
764
0
  return;
765
0
}
766
767
void zprivs_get_ids(struct zprivs_ids_t *ids)
768
4
{
769
770
4
  ids->uid_priv = getuid();
771
4
  (zprivs_state.zuid) ? (ids->uid_normal = zprivs_state.zuid)
772
4
          : (ids->uid_normal = (uid_t)-1);
773
4
  (zprivs_state.zgid) ? (ids->gid_normal = zprivs_state.zgid)
774
4
          : (ids->gid_normal = (uid_t)-1);
775
4
  (zprivs_state.vtygrp) ? (ids->gid_vty = zprivs_state.vtygrp)
776
4
            : (ids->gid_vty = (uid_t)-1);
777
778
4
  return;
779
4
}