Annotation of embedaddon/quagga/lib/privs.c, revision 1.1.1.2

1.1       misho       1: /* 
                      2:  * Zebra privileges.
                      3:  *
                      4:  * Copyright (C) 2003 Paul Jakma.
1.1.1.2 ! misho       5:  * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
1.1       misho       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
                     20:  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
                     21:  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
                     22:  * 02111-1307, USA.  
                     23:  */
                     24: #include <zebra.h>
                     25: #include "log.h"
                     26: #include "privs.h"
                     27: #include "memory.h"
                     28: 
                     29: #ifdef HAVE_CAPABILITIES
                     30: /* sort out some generic internal types for:
                     31:  *
                     32:  * privilege values (cap_value_t, priv_t)      -> pvalue_t
                     33:  * privilege set (..., priv_set_t)             -> pset_t
                     34:  * privilege working storage (cap_t, ...)      -> pstorage_t
                     35:  *
                     36:  * values we think of as numeric (they're ints really, but we dont know)
                     37:  * sets are mostly opaque, to hold a set of privileges, related in some way.
                     38:  * storage binds together a set of sets we're interested in.
                     39:  * (in reality: cap_value_t and priv_t are ints)
                     40:  */ 
                     41: #ifdef HAVE_LCAPS
                     42: /* Linux doesn't have a 'set' type: a set of related privileges */
                     43: struct _pset {
                     44:   int num;
                     45:   cap_value_t *caps;
                     46: };
                     47: typedef cap_value_t pvalue_t;
                     48: typedef struct _pset pset_t;
                     49: typedef cap_t pstorage_t;
1.1.1.2 ! misho      50: 
1.1       misho      51: #elif defined (HAVE_SOLARIS_CAPABILITIES)
                     52: typedef priv_t pvalue_t;
                     53: typedef priv_set_t pset_t;
                     54: typedef priv_set_t *pstorage_t;
                     55: #else /* neither LCAPS nor SOLARIS_CAPABILITIES */
                     56: #error "HAVE_CAPABILITIES defined, but neither LCAPS nor Solaris Capabilties!"
                     57: #endif /* HAVE_LCAPS */
                     58: #endif /* HAVE_CAPABILITIES */
1.1.1.2 ! misho      59: 
1.1       misho      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: {
                     68: #ifdef HAVE_CAPABILITIES
                     69:   pstorage_t caps;             /* working storage        */
                     70:   pset_t *syscaps_p;           /* system-type requested permitted caps    */
                     71:   pset_t *syscaps_i;           /* system-type requested inheritable caps  */
                     72: #endif /* HAVE_CAPABILITIES */
                     73:   uid_t zuid,                 /* uid to run as            */
                     74:         zsuid;                /* saved uid                */
                     75:   gid_t zgid;                 /* gid to run as            */
                     76:   gid_t vtygrp;               /* gid for vty sockets      */
                     77: } zprivs_state;
                     78: 
                     79: /* externally exported but not directly accessed functions */
                     80: #ifdef HAVE_CAPABILITIES
                     81: int zprivs_change_caps (zebra_privs_ops_t);
                     82: zebra_privs_current_t zprivs_state_caps (void);
                     83: #endif /* HAVE_CAPABILITIES */
                     84: int zprivs_change_uid (zebra_privs_ops_t);
                     85: zebra_privs_current_t zprivs_state_uid (void);
                     86: int zprivs_change_null (zebra_privs_ops_t);
                     87: zebra_privs_current_t zprivs_state_null (void);
                     88: 
                     89: #ifdef HAVE_CAPABILITIES
                     90: /* internal capability API */
                     91: static pset_t *zcaps2sys (zebra_capabilities_t *, int);
                     92: static void zprivs_caps_init (struct zebra_privs_t *);
                     93: static void zprivs_caps_terminate (void);
                     94: 
                     95: /* Map of Quagga abstract capabilities to system capabilities */
                     96: static struct
                     97: {
                     98:   int num;
                     99:   pvalue_t *system_caps;
                    100: } cap_map [ZCAP_MAX] =
                    101: {
                    102: #ifdef HAVE_LCAPS /* Quagga -> Linux capabilities mappings */
                    103:   [ZCAP_SETID] =       { 2, (pvalue_t []) { CAP_SETGID,
                    104:                                              CAP_SETUID                }, },
1.1.1.2 ! misho     105:   [ZCAP_BIND] =                { 2, (pvalue_t []) { CAP_NET_BIND_SERVICE       }, },
1.1       misho     106:   [ZCAP_NET_ADMIN] =   { 1, (pvalue_t []) { CAP_NET_ADMIN              }, },
                    107:   [ZCAP_NET_RAW] =     { 1, (pvalue_t []) { CAP_NET_RAW                }, },
                    108:   [ZCAP_CHROOT] =      { 1, (pvalue_t []) { CAP_SYS_CHROOT,            }, },
                    109:   [ZCAP_NICE] =        { 1, (pvalue_t []) { CAP_SYS_NICE               }, },
                    110:   [ZCAP_PTRACE] =      { 1, (pvalue_t []) { CAP_SYS_PTRACE             }, },
                    111:   [ZCAP_DAC_OVERRIDE] = { 1, (pvalue_t []) { CAP_DAC_OVERRIDE          }, },
                    112:   [ZCAP_READ_SEARCH] =  { 1, (pvalue_t []) { CAP_DAC_READ_SEARCH       }, },
                    113:   [ZCAP_SYS_ADMIN] =   { 1, (pvalue_t []) { CAP_SYS_ADMIN              }, },
                    114:   [ZCAP_FOWNER] =      { 1, (pvalue_t []) { CAP_FOWNER                 }, },
                    115: #elif defined(HAVE_SOLARIS_CAPABILITIES) /* HAVE_LCAPS */
                    116:   /* Quagga -> Solaris privilege mappings */
                    117:   [ZCAP_SETID] =       { 1, (pvalue_t []) { PRIV_PROC_SETID            }, },
                    118:   [ZCAP_BIND] =        { 1, (pvalue_t []) { PRIV_NET_PRIVADDR          }, },
                    119:   /* IP_CONFIG is a subset of NET_CONFIG and is allowed in zones */
                    120: #ifdef PRIV_SYS_IP_CONFIG
                    121:   [ZCAP_NET_ADMIN] =   { 1, (pvalue_t []) { PRIV_SYS_IP_CONFIG }, },
                    122: #else
                    123:   [ZCAP_NET_ADMIN] =   { 1, (pvalue_t []) { PRIV_SYS_NET_CONFIG        }, },
                    124: #endif
                    125:   [ZCAP_NET_RAW] =     { 2, (pvalue_t []) { PRIV_NET_RAWACCESS,
                    126:                                              PRIV_NET_ICMPACCESS       }, },
                    127:   [ZCAP_CHROOT] =      { 1, (pvalue_t []) { PRIV_PROC_CHROOT           }, },
                    128:   [ZCAP_NICE] =        { 1, (pvalue_t []) { PRIV_PROC_PRIOCNTL         }, },
                    129:   [ZCAP_PTRACE] =      { 1, (pvalue_t []) { PRIV_PROC_SESSION          }, },
                    130:   [ZCAP_DAC_OVERRIDE] = { 2, (pvalue_t []) { PRIV_FILE_DAC_EXECUTE, 
                    131:                                              PRIV_FILE_DAC_READ,
                    132:                                              PRIV_FILE_DAC_SEARCH,
                    133:                                              PRIV_FILE_DAC_WRITE,
                    134:                                              PRIV_FILE_DAC_SEARCH      }, },
                    135:   [ZCAP_READ_SEARCH] = { 2, (pvalue_t []) { PRIV_FILE_DAC_SEARCH,
                    136:                                              PRIV_FILE_DAC_READ                }, },
                    137:   [ZCAP_SYS_ADMIN] =   { 1, (pvalue_t []) { PRIV_SYS_ADMIN             }, },
                    138:   [ZCAP_FOWNER] =      { 1, (pvalue_t []) { PRIV_FILE_OWNER            }, },
                    139: #endif /* HAVE_SOLARIS_CAPABILITIES */
                    140: };
1.1.1.2 ! misho     141: 
1.1       misho     142: #ifdef HAVE_LCAPS
                    143: /* Linux forms of capabilities methods */
                    144: /* convert zebras privileges to system capabilities */
                    145: static pset_t *
                    146: zcaps2sys (zebra_capabilities_t *zcaps, int num)
                    147: {
                    148:   pset_t *syscaps;
                    149:   int i, j = 0, count = 0;
                    150:   
                    151:   if (!num)
                    152:     return NULL;
                    153:   
                    154:   /* first count up how many system caps we have */
                    155:   for (i= 0; i < num; i++)
                    156:     count += cap_map[zcaps[i]].num;
                    157:   
                    158:   if ( (syscaps = XCALLOC (MTYPE_PRIVS, (sizeof(pset_t) * num))) == NULL)
                    159:     {
                    160:       fprintf (stderr, "%s: could not allocate syscaps!", __func__);
                    161:       return NULL;
                    162:     }
                    163:   
                    164:   syscaps->caps = XCALLOC (MTYPE_PRIVS, (sizeof (pvalue_t) * count));
                    165:   
                    166:   if (!syscaps->caps)
                    167:     {
                    168:       fprintf (stderr, "%s: could not XCALLOC caps!", __func__);
                    169:       return NULL;
                    170:     }
                    171:   
                    172:   /* copy the capabilities over */
                    173:   count = 0;
                    174:   for (i=0; i < num; i++)
                    175:     for (j = 0; j < cap_map[zcaps[i]].num; j++)
                    176:       syscaps->caps[count++] = cap_map[zcaps[i]].system_caps[j];
                    177:   
                    178:   /* iterations above should be exact same as previous count, obviously.. */
                    179:   syscaps->num = count;
                    180:   
                    181:   return syscaps;
                    182: }
                    183: 
                    184: /* set or clear the effective capabilities to/from permitted */
                    185: int 
                    186: zprivs_change_caps (zebra_privs_ops_t op)
                    187: {
                    188:   cap_flag_value_t cflag;
                    189:   
                    190:   /* should be no possibility of being called without valid caps */
                    191:   assert (zprivs_state.syscaps_p && zprivs_state.caps);
                    192:   if (! (zprivs_state.syscaps_p && zprivs_state.caps))
                    193:     exit (1);
                    194:     
                    195:   if (op == ZPRIVS_RAISE)
                    196:     cflag = CAP_SET;
                    197:   else if (op == ZPRIVS_LOWER)
                    198:     cflag = CAP_CLEAR;
                    199:   else
                    200:     return -1;
                    201: 
                    202:   if ( !cap_set_flag (zprivs_state.caps, CAP_EFFECTIVE,
                    203:                        zprivs_state.syscaps_p->num, 
                    204:                        zprivs_state.syscaps_p->caps, 
                    205:                        cflag))
                    206:     return cap_set_proc (zprivs_state.caps);
                    207:   return -1;
                    208: }
                    209: 
                    210: zebra_privs_current_t
                    211: zprivs_state_caps (void)
                    212: {
                    213:   int i;
                    214:   cap_flag_value_t val;
                    215: 
                    216:   /* should be no possibility of being called without valid caps */
                    217:   assert (zprivs_state.syscaps_p && zprivs_state.caps);
                    218:   if (! (zprivs_state.syscaps_p && zprivs_state.caps))
                    219:     exit (1);
                    220:   
                    221:   for (i=0; i < zprivs_state.syscaps_p->num; i++)
                    222:     {
                    223:       if ( cap_get_flag (zprivs_state.caps, zprivs_state.syscaps_p->caps[i], 
                    224:                          CAP_EFFECTIVE, &val) )
                    225:         {
                    226:           zlog_warn ("zprivs_state_caps: could not cap_get_flag, %s",
                    227:                      safe_strerror (errno) );
                    228:           return ZPRIVS_UNKNOWN;
                    229:         }
                    230:       if (val == CAP_SET)
                    231:         return ZPRIVS_RAISED;
                    232:     }
                    233:   return ZPRIVS_LOWERED;
                    234: }
                    235: 
                    236: static void
                    237: zprivs_caps_init (struct zebra_privs_t *zprivs)
                    238: {
                    239:   zprivs_state.syscaps_p = zcaps2sys (zprivs->caps_p, zprivs->cap_num_p);
                    240:   zprivs_state.syscaps_i = zcaps2sys (zprivs->caps_i, zprivs->cap_num_i);
                    241: 
                    242:   /* Tell kernel we want caps maintained across uid changes */
                    243:   if ( prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1 )
                    244:     {
                    245:       fprintf (stderr, "privs_init: could not set PR_SET_KEEPCAPS, %s\n",
                    246:                 safe_strerror (errno) );
                    247:       exit(1);
                    248:     }
                    249: 
                    250:   if ( !zprivs_state.syscaps_p )
                    251:     {
                    252:       fprintf (stderr, "privs_init: capabilities enabled, "
                    253:                        "but no capabilities supplied\n");
                    254:     }
                    255: 
                    256:   /* we have caps, we have no need to ever change back the original user */
                    257:   if (zprivs_state.zuid)
                    258:     {
                    259:       if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) )
                    260:         {
                    261:           fprintf (stderr, "zprivs_init (cap): could not setreuid, %s\n", 
                    262:                      safe_strerror (errno));
                    263:           exit (1);
                    264:         }
                    265:     }
                    266:   
                    267:   if ( !(zprivs_state.caps = cap_init()) )
                    268:     {
                    269:       fprintf (stderr, "privs_init: failed to cap_init, %s\n", 
                    270:                safe_strerror (errno));
                    271:       exit (1);
                    272:     }
                    273: 
                    274:   if ( cap_clear (zprivs_state.caps) )
                    275:     {
                    276:       fprintf (stderr, "privs_init: failed to cap_clear, %s\n", 
                    277:                safe_strerror (errno));
                    278:       exit (1);
                    279:     }
                    280:   
                    281:   /* set permitted caps */
                    282:   cap_set_flag(zprivs_state.caps, CAP_PERMITTED, 
                    283:                zprivs_state.syscaps_p->num,
                    284:                zprivs_state.syscaps_p->caps,
                    285:                CAP_SET);
                    286:     
                    287:   /* set inheritable caps, if any */
                    288:   if (zprivs_state.syscaps_i && zprivs_state.syscaps_i->num)
                    289:     {
                    290:       cap_set_flag(zprivs_state.caps, CAP_INHERITABLE, 
                    291:                    zprivs_state.syscaps_i->num, 
                    292:                    zprivs_state.syscaps_i->caps, 
                    293:                    CAP_SET);
                    294:     }
                    295:   
                    296:   /* apply caps. CAP_EFFECTIVE is cleared. we'll raise the caps as 
                    297:    * and when, and only when, they are needed.
                    298:    */
                    299:   if ( cap_set_proc (zprivs_state.caps) ) 
                    300:     {
1.1.1.2 ! misho     301:       cap_t current_caps;
        !           302:       char *current_caps_text = NULL;
        !           303:       char *wanted_caps_text = NULL;
        !           304: 
        !           305:       fprintf(stderr, "privs_init: initial cap_set_proc failed: %s\n",
        !           306:               safe_strerror(errno));
        !           307: 
        !           308:       current_caps = cap_get_proc();
        !           309:       if (current_caps)
        !           310:           current_caps_text = cap_to_text(current_caps, NULL);
        !           311: 
        !           312:       wanted_caps_text = cap_to_text(zprivs_state.caps, NULL);
        !           313:       fprintf(stderr, "Wanted caps: %s\n", wanted_caps_text ? wanted_caps_text : "???");
        !           314:       fprintf(stderr, "Have   caps: %s\n", current_caps_text ? current_caps_text : "???");
        !           315: 
1.1       misho     316:       exit (1);
                    317:     }
                    318:   
                    319:   /* set methods for the caller to use */
                    320:   zprivs->change = zprivs_change_caps;
                    321:   zprivs->current_state = zprivs_state_caps;
                    322: }
                    323: 
                    324: static void
                    325: zprivs_caps_terminate (void)
                    326: {
                    327:   /* clear all capabilities */
                    328:   if (zprivs_state.caps)
                    329:       cap_clear (zprivs_state.caps);
                    330: 
                    331:   /* and boom, capabilities are gone forever */
                    332:   if ( cap_set_proc (zprivs_state.caps) ) 
                    333:     {
                    334:       fprintf (stderr, "privs_terminate: cap_set_proc failed, %s",
                    335:                 safe_strerror (errno) );
                    336:       exit (1);
                    337:     }  
                    338: 
                    339:   /* free up private state */
                    340:   if (zprivs_state.syscaps_p->num)
                    341:     {
                    342:       XFREE (MTYPE_PRIVS, zprivs_state.syscaps_p->caps);
                    343:       XFREE (MTYPE_PRIVS, zprivs_state.syscaps_p);
                    344:     }
                    345:   
                    346:   if (zprivs_state.syscaps_i && zprivs_state.syscaps_i->num)
                    347:     {
                    348:       XFREE (MTYPE_PRIVS, zprivs_state.syscaps_i->caps);
                    349:       XFREE (MTYPE_PRIVS, zprivs_state.syscaps_i);
                    350:     }
                    351:   
                    352:   cap_free (zprivs_state.caps);
                    353: }
                    354: #elif defined (HAVE_SOLARIS_CAPABILITIES) /* !HAVE_LCAPS */
1.1.1.2 ! misho     355: 
1.1       misho     356: /* Solaris specific capability/privilege methods 
                    357:  *
                    358:  * Resources:
                    359:  * - the 'privileges' man page
                    360:  * - http://cvs.opensolaris.org
                    361:  * - http://blogs.sun.com/roller/page/gbrunett?entry=privilege_enabling_set_id_programs1
                    362:  */
                    363: 
1.1.1.2 ! misho     364: static pset_t *
        !           365: zprivs_caps_minimal ()
        !           366: {
        !           367:   pset_t *minimal;
        !           368: 
        !           369:   if ((minimal = priv_str_to_set("basic", ",", NULL)) == NULL)
        !           370:     {
        !           371:       fprintf (stderr, "%s: couldn't get basic set!\n", __func__);
        !           372:       exit (1);
        !           373:     }
        !           374: 
        !           375:    /* create a minimal privilege set from the basic set */
        !           376:   (void) priv_delset(minimal, PRIV_PROC_EXEC);
        !           377:   (void) priv_delset(minimal, PRIV_PROC_INFO);
        !           378:   (void) priv_delset(minimal, PRIV_PROC_SESSION);
        !           379:   (void) priv_delset(minimal, PRIV_FILE_LINK_ANY);
        !           380: 
        !           381:   return  minimal;
        !           382: }
        !           383: 
1.1       misho     384: /* convert zebras privileges to system capabilities */
                    385: static pset_t *
                    386: zcaps2sys (zebra_capabilities_t *zcaps, int num)
                    387: {
                    388:   pset_t *syscaps;
                    389:   int i, j = 0;
                    390:   
                    391:   if ((syscaps = priv_allocset()) == NULL)
                    392:     {
                    393:       fprintf (stderr, "%s: could not allocate syscaps!\n", __func__);
                    394:       exit (1);
                    395:     }
                    396:     
                    397:   priv_emptyset (syscaps);
                    398:   
                    399:   for (i=0; i < num; i++)
                    400:     for (j = 0; j < cap_map[zcaps[i]].num; j++)
                    401:       priv_addset (syscaps, cap_map[zcaps[i]].system_caps[j]);
                    402:   
                    403:   return syscaps;
                    404: }
                    405: 
                    406: /* callback exported to users to RAISE and LOWER effective privileges
                    407:  * from nothing to the given permitted set and back down
                    408:  */
                    409: int 
                    410: zprivs_change_caps (zebra_privs_ops_t op)
                    411: {
1.1.1.2 ! misho     412:   pset_t *privset;
1.1       misho     413:   
                    414:   /* should be no possibility of being called without valid caps */
                    415:   assert (zprivs_state.syscaps_p);
                    416:   if (!zprivs_state.syscaps_p)
                    417:     {
1.1.1.2 ! misho     418:       fprintf (stderr, "%s: Eek, missing privileged caps!", __func__);
        !           419:       exit (1);
        !           420:     }
        !           421: 
        !           422:   assert (zprivs_state.caps);
        !           423:   if (!zprivs_state.caps)
        !           424:     {
1.1       misho     425:       fprintf (stderr, "%s: Eek, missing caps!", __func__);
                    426:       exit (1);
                    427:     }
1.1.1.2 ! misho     428: 
        !           429:   /* to raise: copy original permitted as our working effective set
        !           430:    * to lower: copy regular effective set stored in zprivs_state.caps
1.1       misho     431:    */
                    432:   if (op == ZPRIVS_RAISE)
1.1.1.2 ! misho     433:     privset = zprivs_state.syscaps_p;
1.1       misho     434:   else if (op == ZPRIVS_LOWER)
1.1.1.2 ! misho     435:     privset = zprivs_state.caps;
1.1       misho     436:   else
                    437:     return -1;
                    438:   
1.1.1.2 ! misho     439:   if (setppriv (PRIV_SET, PRIV_EFFECTIVE, privset) != 0)
1.1       misho     440:     return -1;
                    441:   
                    442:   return 0;
                    443: }
                    444: 
                    445: /* Retrieve current privilege state, is it RAISED or LOWERED? */
                    446: zebra_privs_current_t 
                    447: zprivs_state_caps (void)
                    448: {
                    449:   zebra_privs_current_t result;
                    450:   pset_t *effective;
                    451:   
                    452:   if ( (effective = priv_allocset()) == NULL)
                    453:     {
                    454:       fprintf (stderr, "%s: failed to get priv_allocset! %s\n", __func__,
                    455:                safe_strerror (errno));
                    456:       return ZPRIVS_UNKNOWN;
                    457:     }
                    458:   
                    459:   if (getppriv (PRIV_EFFECTIVE, effective))
                    460:     {
                    461:       fprintf (stderr, "%s: failed to get state! %s\n", __func__,
                    462:                safe_strerror (errno));
                    463:       result = ZPRIVS_UNKNOWN;
                    464:     }
                    465:   else
                    466:     {
1.1.1.2 ! misho     467:       if (priv_isequalset (effective, zprivs_state.syscaps_p))
        !           468:         result = ZPRIVS_RAISED;
        !           469:       else if (priv_isequalset (effective, zprivs_state.caps))
1.1       misho     470:         result = ZPRIVS_LOWERED;
                    471:       else
1.1.1.2 ! misho     472:         result = ZPRIVS_UNKNOWN;
1.1       misho     473:     }
                    474:   
1.1.1.2 ! misho     475:   priv_freeset (effective);
1.1       misho     476:   return result;
                    477: }
                    478: 
                    479: static void
                    480: zprivs_caps_init (struct zebra_privs_t *zprivs)
                    481: {
                    482:   pset_t *basic;
1.1.1.2 ! misho     483:   pset_t *minimal;
1.1       misho     484:   
                    485:   /* the specified sets */
                    486:   zprivs_state.syscaps_p = zcaps2sys (zprivs->caps_p, zprivs->cap_num_p);
                    487:   zprivs_state.syscaps_i = zcaps2sys (zprivs->caps_i, zprivs->cap_num_i);
                    488:   
                    489:   /* nonsensical to have gotten here but not have capabilities */
                    490:   if (!zprivs_state.syscaps_p)
                    491:     {
                    492:       fprintf (stderr, "%s: capabilities enabled, "
                    493:                        "but no valid capabilities supplied\n",
                    494:                        __func__);
                    495:     }
                    496:   
                    497:   /* We retain the basic set in our permitted set, as Linux has no
                    498:    * equivalent. The basic set on Linux hence is implicit, always
                    499:    * there.
                    500:    */
                    501:   if ((basic = priv_str_to_set("basic", ",", NULL)) == NULL)
                    502:     {
                    503:       fprintf (stderr, "%s: couldn't get basic set!\n", __func__);
                    504:       exit (1);
                    505:     }
                    506:  
                    507:   /* Add the basic set to the permitted set */
                    508:   priv_union (basic, zprivs_state.syscaps_p);
                    509:   priv_freeset (basic);
                    510:   
                    511:   /* Hey kernel, we know about privileges! 
                    512:    * this isn't strictly required, use of setppriv should have same effect
                    513:    */
                    514:   if (setpflags (PRIV_AWARE, 1))
                    515:     {
                    516:       fprintf (stderr, "%s: error setting PRIV_AWARE!, %s\n", __func__,
                    517:                safe_strerror (errno) );
                    518:       exit (1);
                    519:     }
                    520:   
                    521:   /* need either valid or empty sets for both p and i.. */
                    522:   assert (zprivs_state.syscaps_i && zprivs_state.syscaps_p);
                    523:   
                    524:   /* we have caps, we have no need to ever change back the original user
                    525:    * change real, effective and saved to the specified user.
                    526:    */
                    527:   if (zprivs_state.zuid)
                    528:     {
                    529:       if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) )
                    530:         {
                    531:           fprintf (stderr, "%s: could not setreuid, %s\n", 
                    532:                    __func__, safe_strerror (errno));
                    533:           exit (1);
                    534:         }
                    535:     }
                    536:   
                    537:   /* set the permitted set */
                    538:   if (setppriv (PRIV_SET, PRIV_PERMITTED, zprivs_state.syscaps_p))
                    539:     {
                    540:       fprintf (stderr, "%s: error setting permitted set!, %s\n", __func__,
                    541:                safe_strerror (errno) );
                    542:       exit (1);
                    543:     }
                    544:   
                    545:   /* set the inheritable set */
                    546:   if (setppriv (PRIV_SET, PRIV_INHERITABLE, zprivs_state.syscaps_i))
                    547:     {
                    548:       fprintf (stderr, "%s: error setting inheritable set!, %s\n", __func__,
                    549:                safe_strerror (errno) );
                    550:       exit (1);
                    551:     }
                    552: 
1.1.1.2 ! misho     553:   /* we need a minimal basic set for 'effective', potentially for inheritable too */
        !           554:   minimal = zprivs_caps_minimal();
        !           555: 
        !           556:   /* now set the effective set with a subset of basic privileges */
        !           557:   if (setppriv (PRIV_SET, PRIV_EFFECTIVE, minimal))
1.1       misho     558:     {
                    559:       fprintf (stderr, "%s: error setting effective set!, %s\n", __func__,
                    560:                safe_strerror (errno) );
                    561:       exit (1);
                    562:     }
                    563:   
1.1.1.2 ! misho     564:   /* we'll use the minimal set as our working-storage privset */
        !           565:   zprivs_state.caps = minimal;
1.1       misho     566:   
                    567:   /* set methods for the caller to use */
                    568:   zprivs->change = zprivs_change_caps;
                    569:   zprivs->current_state = zprivs_state_caps;
                    570: }
                    571: 
                    572: static void
                    573: zprivs_caps_terminate (void)
                    574: {
                    575:   assert (zprivs_state.caps);
                    576:   
1.1.1.2 ! misho     577:   /* clear all capabilities by using working-storage privset */
1.1       misho     578:   setppriv (PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps);
                    579:   setppriv (PRIV_SET, PRIV_PERMITTED, zprivs_state.caps);
                    580:   setppriv (PRIV_SET, PRIV_INHERITABLE, zprivs_state.caps);
                    581:   
                    582:   /* free up private state */
                    583:   if (zprivs_state.syscaps_p)
                    584:     priv_freeset (zprivs_state.syscaps_p);
                    585:   if (zprivs_state.syscaps_i)
                    586:     priv_freeset (zprivs_state.syscaps_i);
                    587:   
                    588:   priv_freeset (zprivs_state.caps);
                    589: }
                    590: #else /* !HAVE_LCAPS && ! HAVE_SOLARIS_CAPABILITIES */
                    591: #error "Neither Solaris nor Linux capabilities, dazed and confused..."
                    592: #endif /* HAVE_LCAPS */
                    593: #endif /* HAVE_CAPABILITIES */
1.1.1.2 ! misho     594: 
1.1       misho     595: int
                    596: zprivs_change_uid (zebra_privs_ops_t op)
                    597: {
                    598: 
                    599:   if (op == ZPRIVS_RAISE)
                    600:     return seteuid (zprivs_state.zsuid);
                    601:   else if (op == ZPRIVS_LOWER)
                    602:     return seteuid (zprivs_state.zuid);
                    603:   else
                    604:     return -1;
                    605: }
                    606: 
                    607: zebra_privs_current_t
                    608: zprivs_state_uid (void)
                    609: {
                    610:   return ( (zprivs_state.zuid == geteuid()) ? ZPRIVS_LOWERED : ZPRIVS_RAISED);
                    611: }
                    612: 
                    613: int
                    614: zprivs_change_null (zebra_privs_ops_t op)
                    615: {
                    616:   return 0;
                    617: }
                    618: 
                    619: zebra_privs_current_t
                    620: zprivs_state_null (void)
                    621: {
                    622:   return zprivs_null_state;
                    623: }
                    624: 
1.1.1.2 ! misho     625: #ifndef HAVE_GETGROUPLIST
        !           626: /* Solaris 11 has no getgrouplist() */
        !           627: static int
        !           628: getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups)
        !           629: {
        !           630:   struct group *grp;
        !           631:   size_t usridx;
        !           632:   int pos = 0, ret;
        !           633: 
        !           634:   if (pos < *ngroups)
        !           635:     groups[pos] = group;
        !           636:   pos++;
        !           637: 
        !           638:   setgrent();
        !           639:   while ((grp = getgrent()))
        !           640:     {
        !           641:       if (grp->gr_gid == group)
        !           642:         continue;
        !           643:       for (usridx = 0; grp->gr_mem[usridx] != NULL; usridx++)
        !           644:         if (!strcmp (grp->gr_mem[usridx], user))
        !           645:           {
        !           646:             if (pos < *ngroups)
        !           647:               groups[pos] = grp->gr_gid;
        !           648:             pos++;
        !           649:             break;
        !           650:           }
        !           651:     }
        !           652:   endgrent();
        !           653: 
        !           654:   ret = (pos <= *ngroups) ? pos : -1;
        !           655:   *ngroups = pos;
        !           656:   return ret;
        !           657: }
        !           658: #endif /* HAVE_GETGROUPLIST */
        !           659: 
1.1       misho     660: void
                    661: zprivs_init(struct zebra_privs_t *zprivs)
                    662: {
                    663:   struct passwd *pwentry = NULL;
                    664:   struct group *grentry = NULL;
1.1.1.2 ! misho     665:   gid_t groups[NGROUPS_MAX];
        !           666:   int i, ngroups = 0;
1.1       misho     667: 
                    668:   if (!zprivs)
                    669:     {
                    670:       fprintf (stderr, "zprivs_init: called with NULL arg!\n");
                    671:       exit (1);
                    672:     }
                    673: 
                    674:   /* NULL privs */
                    675:   if (! (zprivs->user || zprivs->group 
                    676:          || zprivs->cap_num_p || zprivs->cap_num_i) )
                    677:     {
                    678:       zprivs->change = zprivs_change_null;
                    679:       zprivs->current_state = zprivs_state_null;
                    680:       return;
                    681:     }
                    682: 
                    683:   if (zprivs->user)
                    684:     {
1.1.1.2 ! misho     685:       if ( (pwentry = getpwnam (zprivs->user)) == NULL )
1.1       misho     686:         {
                    687:           /* cant use log.h here as it depends on vty */
                    688:           fprintf (stderr, "privs_init: could not lookup user %s\n",
                    689:                    zprivs->user);
                    690:           exit (1);
                    691:         }
1.1.1.2 ! misho     692: 
        !           693:       zprivs_state.zuid = pwentry->pw_uid;
        !           694:       zprivs_state.zgid = pwentry->pw_gid;
1.1       misho     695:     }
                    696: 
                    697:   grentry = NULL;
                    698: 
1.1.1.2 ! misho     699:   if (zprivs->group)
        !           700:     {
        !           701:       if ( (grentry = getgrnam (zprivs->group)) == NULL )
        !           702:         {
        !           703:           fprintf (stderr, "privs_init: could not lookup group %s\n",
        !           704:                    zprivs->group);
        !           705:           exit (1);
        !           706:         }
        !           707: 
        !           708:       zprivs_state.zgid = grentry->gr_gid;
        !           709:     }
        !           710: 
        !           711:   if (zprivs->user)
        !           712:     {
        !           713:       ngroups = sizeof(groups);
        !           714:       if ( (ngroups = getgrouplist (zprivs->user, zprivs_state.zgid, groups, &ngroups )) < 0 )
        !           715:         {
        !           716:           /* cant use log.h here as it depends on vty */
        !           717:           fprintf (stderr, "privs_init: could not getgrouplist for user %s\n",
        !           718:                    zprivs->user);
        !           719:           exit (1);
        !           720:         }
        !           721:     }
        !           722: 
1.1       misho     723:   if (zprivs->vty_group)
                    724:     /* Add the vty_group to the supplementary groups so it can be chowned to */
                    725:     {
                    726:       if ( (grentry = getgrnam (zprivs->vty_group)) )
                    727:         {
                    728:           zprivs_state.vtygrp = grentry->gr_gid;
1.1.1.2 ! misho     729: 
        !           730:           for ( i = 0; i < ngroups; i++ )
        !           731:             if ( groups[i] == zprivs_state.vtygrp )
        !           732:               break;
        !           733: 
        !           734:           if ( i >= ngroups && ngroups < (int) ZEBRA_NUM_OF(groups) )
1.1       misho     735:             {
1.1.1.2 ! misho     736:               groups[i] = zprivs_state.vtygrp;
        !           737:             }
1.1       misho     738:         }
                    739:       else
                    740:         {
                    741:           fprintf (stderr, "privs_init: could not lookup vty group %s\n",
                    742:                    zprivs->vty_group);
                    743:           exit (1);
                    744:         }
                    745:     }
1.1.1.2 ! misho     746: 
        !           747:   if (ngroups)
1.1       misho     748:     {
1.1.1.2 ! misho     749:       if ( setgroups (ngroups, groups) )
1.1       misho     750:         {
1.1.1.2 ! misho     751:           fprintf (stderr, "privs_init: could not setgroups, %s\n",
        !           752:                    safe_strerror (errno) );
1.1       misho     753:           exit (1);
                    754:         }
1.1.1.2 ! misho     755:     }
        !           756: 
        !           757:   if (zprivs_state.zgid)
        !           758:     {
1.1       misho     759:       /* change group now, forever. uid we do later */
                    760:       if ( setregid (zprivs_state.zgid, zprivs_state.zgid) )
                    761:         {
                    762:           fprintf (stderr, "zprivs_init: could not setregid, %s\n",
                    763:                     safe_strerror (errno) );
                    764:           exit (1);
                    765:         }
                    766:     }
                    767:   
                    768: #ifdef HAVE_CAPABILITIES
                    769:   zprivs_caps_init (zprivs);
                    770: #else /* !HAVE_CAPABILITIES */
                    771:   /* we dont have caps. we'll need to maintain rid and saved uid
                    772:    * and change euid back to saved uid (who we presume has all neccessary
                    773:    * privileges) whenever we are asked to raise our privileges.
                    774:    *
                    775:    * This is not worth that much security wise, but all we can do.
                    776:    */
                    777:   zprivs_state.zsuid = geteuid();  
                    778:   if ( zprivs_state.zuid )
                    779:     {
                    780:       if ( setreuid (-1, zprivs_state.zuid) )
                    781:         {
                    782:           fprintf (stderr, "privs_init (uid): could not setreuid, %s\n", 
                    783:                    safe_strerror (errno));
                    784:           exit (1);
                    785:         }
                    786:     }
                    787:   
                    788:   zprivs->change = zprivs_change_uid;
                    789:   zprivs->current_state = zprivs_state_uid;
                    790: #endif /* HAVE_CAPABILITIES */
                    791: }
                    792: 
                    793: void 
                    794: zprivs_terminate (struct zebra_privs_t *zprivs)
                    795: {
                    796:   if (!zprivs)
                    797:     {
                    798:       fprintf (stderr, "%s: no privs struct given, terminating", __func__);
                    799:       exit (0);
                    800:     }
                    801:   
                    802: #ifdef HAVE_CAPABILITIES
                    803:   zprivs_caps_terminate();
                    804: #else /* !HAVE_CAPABILITIES */
                    805:   if (zprivs_state.zuid)
                    806:     {
                    807:       if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) )
                    808:         {
                    809:           fprintf (stderr, "privs_terminate: could not setreuid, %s", 
                    810:                      safe_strerror (errno) );
                    811:           exit (1);
                    812:         }
                    813:      }
                    814: #endif /* HAVE_LCAPS */
                    815: 
                    816:   zprivs->change = zprivs_change_null;
                    817:   zprivs->current_state = zprivs_state_null;
                    818:   zprivs_null_state = ZPRIVS_LOWERED;
                    819:   return;
                    820: }
                    821: 
                    822: void
                    823: zprivs_get_ids(struct zprivs_ids_t *ids)
                    824: {
                    825: 
                    826:    ids->uid_priv = getuid();
                    827:    (zprivs_state.zuid) ? (ids->uid_normal = zprivs_state.zuid)
                    828:                      : (ids->uid_normal = -1);
                    829:    (zprivs_state.zgid) ? (ids->gid_normal = zprivs_state.zgid)
                    830:                      : (ids->gid_normal = -1);
                    831:    (zprivs_state.vtygrp) ? (ids->gid_vty = zprivs_state.vtygrp)
                    832:                        : (ids->gid_vty = -1);
                    833:    
                    834:    return;
                    835: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>