back to topotato report
topotato coverage report
Current view: top level - lib - privs.c (source / functions) Hit Total Coverage
Test: test_bgp_ecmp_enhe.py::BGP_Unnumbered_ECMP Lines: 151 247 61.1 %
Date: 2023-11-16 17:19:14 Functions: 14 37 37.8 %

          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             : }

Generated by: LCOV version v1.16-topotato