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