back to topotato report
topotato coverage report
Current view: top level - lib - privs.c (source / functions) Hit Total Coverage
Test: test_bgp_aggregate_address_origin.py::BGPAggregateAddressOrigin Lines: 151 250 60.4 %
Date: 2023-02-24 18:36:37 Functions: 14 19 73.7 %

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

Generated by: LCOV version v1.16-topotato