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

1.1     ! misho       1: /* 
        !             2:  * Zebra privileges.
        !             3:  *
        !             4:  * Copyright (C) 2003 Paul Jakma.
        !             5:  * Copyright (C) 2005 Sun Microsystems, Inc.
        !             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;
        !            50: 
        !            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 */
        !            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: {
        !            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                }, },
        !           105:   [ZCAP_BIND] =                { 2, (pvalue_t []) { CAP_NET_BIND_SERVICE,
        !           106:                                              CAP_NET_BROADCAST                 }, },
        !           107:   [ZCAP_NET_ADMIN] =   { 1, (pvalue_t []) { CAP_NET_ADMIN              }, },
        !           108:   [ZCAP_NET_RAW] =     { 1, (pvalue_t []) { CAP_NET_RAW                }, },
        !           109:   [ZCAP_CHROOT] =      { 1, (pvalue_t []) { CAP_SYS_CHROOT,            }, },
        !           110:   [ZCAP_NICE] =        { 1, (pvalue_t []) { CAP_SYS_NICE               }, },
        !           111:   [ZCAP_PTRACE] =      { 1, (pvalue_t []) { CAP_SYS_PTRACE             }, },
        !           112:   [ZCAP_DAC_OVERRIDE] = { 1, (pvalue_t []) { CAP_DAC_OVERRIDE          }, },
        !           113:   [ZCAP_READ_SEARCH] =  { 1, (pvalue_t []) { CAP_DAC_READ_SEARCH       }, },
        !           114:   [ZCAP_SYS_ADMIN] =   { 1, (pvalue_t []) { CAP_SYS_ADMIN              }, },
        !           115:   [ZCAP_FOWNER] =      { 1, (pvalue_t []) { CAP_FOWNER                 }, },
        !           116: #elif defined(HAVE_SOLARIS_CAPABILITIES) /* HAVE_LCAPS */
        !           117:   /* Quagga -> Solaris privilege mappings */
        !           118:   [ZCAP_SETID] =       { 1, (pvalue_t []) { PRIV_PROC_SETID            }, },
        !           119:   [ZCAP_BIND] =        { 1, (pvalue_t []) { PRIV_NET_PRIVADDR          }, },
        !           120:   /* IP_CONFIG is a subset of NET_CONFIG and is allowed in zones */
        !           121: #ifdef PRIV_SYS_IP_CONFIG
        !           122:   [ZCAP_NET_ADMIN] =   { 1, (pvalue_t []) { PRIV_SYS_IP_CONFIG }, },
        !           123: #else
        !           124:   [ZCAP_NET_ADMIN] =   { 1, (pvalue_t []) { PRIV_SYS_NET_CONFIG        }, },
        !           125: #endif
        !           126:   [ZCAP_NET_RAW] =     { 2, (pvalue_t []) { PRIV_NET_RAWACCESS,
        !           127:                                              PRIV_NET_ICMPACCESS       }, },
        !           128:   [ZCAP_CHROOT] =      { 1, (pvalue_t []) { PRIV_PROC_CHROOT           }, },
        !           129:   [ZCAP_NICE] =        { 1, (pvalue_t []) { PRIV_PROC_PRIOCNTL         }, },
        !           130:   [ZCAP_PTRACE] =      { 1, (pvalue_t []) { PRIV_PROC_SESSION          }, },
        !           131:   [ZCAP_DAC_OVERRIDE] = { 2, (pvalue_t []) { PRIV_FILE_DAC_EXECUTE, 
        !           132:                                              PRIV_FILE_DAC_READ,
        !           133:                                              PRIV_FILE_DAC_SEARCH,
        !           134:                                              PRIV_FILE_DAC_WRITE,
        !           135:                                              PRIV_FILE_DAC_SEARCH      }, },
        !           136:   [ZCAP_READ_SEARCH] = { 2, (pvalue_t []) { PRIV_FILE_DAC_SEARCH,
        !           137:                                              PRIV_FILE_DAC_READ                }, },
        !           138:   [ZCAP_SYS_ADMIN] =   { 1, (pvalue_t []) { PRIV_SYS_ADMIN             }, },
        !           139:   [ZCAP_FOWNER] =      { 1, (pvalue_t []) { PRIV_FILE_OWNER            }, },
        !           140: #endif /* HAVE_SOLARIS_CAPABILITIES */
        !           141: };
        !           142: 
        !           143: #ifdef HAVE_LCAPS
        !           144: /* Linux forms of capabilities methods */
        !           145: /* convert zebras privileges to system capabilities */
        !           146: static pset_t *
        !           147: zcaps2sys (zebra_capabilities_t *zcaps, int num)
        !           148: {
        !           149:   pset_t *syscaps;
        !           150:   int i, j = 0, count = 0;
        !           151:   
        !           152:   if (!num)
        !           153:     return NULL;
        !           154:   
        !           155:   /* first count up how many system caps we have */
        !           156:   for (i= 0; i < num; i++)
        !           157:     count += cap_map[zcaps[i]].num;
        !           158:   
        !           159:   if ( (syscaps = XCALLOC (MTYPE_PRIVS, (sizeof(pset_t) * num))) == NULL)
        !           160:     {
        !           161:       fprintf (stderr, "%s: could not allocate syscaps!", __func__);
        !           162:       return NULL;
        !           163:     }
        !           164:   
        !           165:   syscaps->caps = XCALLOC (MTYPE_PRIVS, (sizeof (pvalue_t) * count));
        !           166:   
        !           167:   if (!syscaps->caps)
        !           168:     {
        !           169:       fprintf (stderr, "%s: could not XCALLOC caps!", __func__);
        !           170:       return NULL;
        !           171:     }
        !           172:   
        !           173:   /* copy the capabilities over */
        !           174:   count = 0;
        !           175:   for (i=0; i < num; i++)
        !           176:     for (j = 0; j < cap_map[zcaps[i]].num; j++)
        !           177:       syscaps->caps[count++] = cap_map[zcaps[i]].system_caps[j];
        !           178:   
        !           179:   /* iterations above should be exact same as previous count, obviously.. */
        !           180:   syscaps->num = count;
        !           181:   
        !           182:   return syscaps;
        !           183: }
        !           184: 
        !           185: /* set or clear the effective capabilities to/from permitted */
        !           186: int 
        !           187: zprivs_change_caps (zebra_privs_ops_t op)
        !           188: {
        !           189:   cap_flag_value_t cflag;
        !           190:   
        !           191:   /* should be no possibility of being called without valid caps */
        !           192:   assert (zprivs_state.syscaps_p && zprivs_state.caps);
        !           193:   if (! (zprivs_state.syscaps_p && zprivs_state.caps))
        !           194:     exit (1);
        !           195:     
        !           196:   if (op == ZPRIVS_RAISE)
        !           197:     cflag = CAP_SET;
        !           198:   else if (op == ZPRIVS_LOWER)
        !           199:     cflag = CAP_CLEAR;
        !           200:   else
        !           201:     return -1;
        !           202: 
        !           203:   if ( !cap_set_flag (zprivs_state.caps, CAP_EFFECTIVE,
        !           204:                        zprivs_state.syscaps_p->num, 
        !           205:                        zprivs_state.syscaps_p->caps, 
        !           206:                        cflag))
        !           207:     return cap_set_proc (zprivs_state.caps);
        !           208:   return -1;
        !           209: }
        !           210: 
        !           211: zebra_privs_current_t
        !           212: zprivs_state_caps (void)
        !           213: {
        !           214:   int i;
        !           215:   cap_flag_value_t val;
        !           216: 
        !           217:   /* should be no possibility of being called without valid caps */
        !           218:   assert (zprivs_state.syscaps_p && zprivs_state.caps);
        !           219:   if (! (zprivs_state.syscaps_p && zprivs_state.caps))
        !           220:     exit (1);
        !           221:   
        !           222:   for (i=0; i < zprivs_state.syscaps_p->num; i++)
        !           223:     {
        !           224:       if ( cap_get_flag (zprivs_state.caps, zprivs_state.syscaps_p->caps[i], 
        !           225:                          CAP_EFFECTIVE, &val) )
        !           226:         {
        !           227:           zlog_warn ("zprivs_state_caps: could not cap_get_flag, %s",
        !           228:                      safe_strerror (errno) );
        !           229:           return ZPRIVS_UNKNOWN;
        !           230:         }
        !           231:       if (val == CAP_SET)
        !           232:         return ZPRIVS_RAISED;
        !           233:     }
        !           234:   return ZPRIVS_LOWERED;
        !           235: }
        !           236: 
        !           237: static void
        !           238: zprivs_caps_init (struct zebra_privs_t *zprivs)
        !           239: {
        !           240:   zprivs_state.syscaps_p = zcaps2sys (zprivs->caps_p, zprivs->cap_num_p);
        !           241:   zprivs_state.syscaps_i = zcaps2sys (zprivs->caps_i, zprivs->cap_num_i);
        !           242: 
        !           243:   /* Tell kernel we want caps maintained across uid changes */
        !           244:   if ( prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1 )
        !           245:     {
        !           246:       fprintf (stderr, "privs_init: could not set PR_SET_KEEPCAPS, %s\n",
        !           247:                 safe_strerror (errno) );
        !           248:       exit(1);
        !           249:     }
        !           250: 
        !           251:   if ( !zprivs_state.syscaps_p )
        !           252:     {
        !           253:       fprintf (stderr, "privs_init: capabilities enabled, "
        !           254:                        "but no capabilities supplied\n");
        !           255:     }
        !           256: 
        !           257:   /* we have caps, we have no need to ever change back the original user */
        !           258:   if (zprivs_state.zuid)
        !           259:     {
        !           260:       if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) )
        !           261:         {
        !           262:           fprintf (stderr, "zprivs_init (cap): could not setreuid, %s\n", 
        !           263:                      safe_strerror (errno));
        !           264:           exit (1);
        !           265:         }
        !           266:     }
        !           267:   
        !           268:   if ( !(zprivs_state.caps = cap_init()) )
        !           269:     {
        !           270:       fprintf (stderr, "privs_init: failed to cap_init, %s\n", 
        !           271:                safe_strerror (errno));
        !           272:       exit (1);
        !           273:     }
        !           274: 
        !           275:   if ( cap_clear (zprivs_state.caps) )
        !           276:     {
        !           277:       fprintf (stderr, "privs_init: failed to cap_clear, %s\n", 
        !           278:                safe_strerror (errno));
        !           279:       exit (1);
        !           280:     }
        !           281:   
        !           282:   /* set permitted caps */
        !           283:   cap_set_flag(zprivs_state.caps, CAP_PERMITTED, 
        !           284:                zprivs_state.syscaps_p->num,
        !           285:                zprivs_state.syscaps_p->caps,
        !           286:                CAP_SET);
        !           287:     
        !           288:   /* set inheritable caps, if any */
        !           289:   if (zprivs_state.syscaps_i && zprivs_state.syscaps_i->num)
        !           290:     {
        !           291:       cap_set_flag(zprivs_state.caps, CAP_INHERITABLE, 
        !           292:                    zprivs_state.syscaps_i->num, 
        !           293:                    zprivs_state.syscaps_i->caps, 
        !           294:                    CAP_SET);
        !           295:     }
        !           296:   
        !           297:   /* apply caps. CAP_EFFECTIVE is cleared. we'll raise the caps as 
        !           298:    * and when, and only when, they are needed.
        !           299:    */
        !           300:   if ( cap_set_proc (zprivs_state.caps) ) 
        !           301:     {
        !           302:       fprintf (stderr, "privs_init: initial cap_set_proc failed\n");
        !           303:       exit (1);
        !           304:     }
        !           305:   
        !           306:   /* set methods for the caller to use */
        !           307:   zprivs->change = zprivs_change_caps;
        !           308:   zprivs->current_state = zprivs_state_caps;
        !           309: }
        !           310: 
        !           311: static void
        !           312: zprivs_caps_terminate (void)
        !           313: {
        !           314:   /* clear all capabilities */
        !           315:   if (zprivs_state.caps)
        !           316:       cap_clear (zprivs_state.caps);
        !           317: 
        !           318:   /* and boom, capabilities are gone forever */
        !           319:   if ( cap_set_proc (zprivs_state.caps) ) 
        !           320:     {
        !           321:       fprintf (stderr, "privs_terminate: cap_set_proc failed, %s",
        !           322:                 safe_strerror (errno) );
        !           323:       exit (1);
        !           324:     }  
        !           325: 
        !           326:   /* free up private state */
        !           327:   if (zprivs_state.syscaps_p->num)
        !           328:     {
        !           329:       XFREE (MTYPE_PRIVS, zprivs_state.syscaps_p->caps);
        !           330:       XFREE (MTYPE_PRIVS, zprivs_state.syscaps_p);
        !           331:     }
        !           332:   
        !           333:   if (zprivs_state.syscaps_i && zprivs_state.syscaps_i->num)
        !           334:     {
        !           335:       XFREE (MTYPE_PRIVS, zprivs_state.syscaps_i->caps);
        !           336:       XFREE (MTYPE_PRIVS, zprivs_state.syscaps_i);
        !           337:     }
        !           338:   
        !           339:   cap_free (zprivs_state.caps);
        !           340: }
        !           341: #elif defined (HAVE_SOLARIS_CAPABILITIES) /* !HAVE_LCAPS */
        !           342: 
        !           343: /* Solaris specific capability/privilege methods 
        !           344:  *
        !           345:  * Resources:
        !           346:  * - the 'privileges' man page
        !           347:  * - http://cvs.opensolaris.org
        !           348:  * - http://blogs.sun.com/roller/page/gbrunett?entry=privilege_enabling_set_id_programs1
        !           349:  */
        !           350: 
        !           351: /* convert zebras privileges to system capabilities */
        !           352: static pset_t *
        !           353: zcaps2sys (zebra_capabilities_t *zcaps, int num)
        !           354: {
        !           355:   pset_t *syscaps;
        !           356:   int i, j = 0;
        !           357:   
        !           358:   if ((syscaps = priv_allocset()) == NULL)
        !           359:     {
        !           360:       fprintf (stderr, "%s: could not allocate syscaps!\n", __func__);
        !           361:       exit (1);
        !           362:     }
        !           363:     
        !           364:   priv_emptyset (syscaps);
        !           365:   
        !           366:   for (i=0; i < num; i++)
        !           367:     for (j = 0; j < cap_map[zcaps[i]].num; j++)
        !           368:       priv_addset (syscaps, cap_map[zcaps[i]].system_caps[j]);
        !           369:   
        !           370:   return syscaps;
        !           371: }
        !           372: 
        !           373: /* callback exported to users to RAISE and LOWER effective privileges
        !           374:  * from nothing to the given permitted set and back down
        !           375:  */
        !           376: int 
        !           377: zprivs_change_caps (zebra_privs_ops_t op)
        !           378: {
        !           379:   
        !           380:   /* should be no possibility of being called without valid caps */
        !           381:   assert (zprivs_state.syscaps_p);
        !           382:   if (!zprivs_state.syscaps_p)
        !           383:     {
        !           384:       fprintf (stderr, "%s: Eek, missing caps!", __func__);
        !           385:       exit (1);
        !           386:     }
        !           387:   
        !           388:   /* to raise: copy original permitted into our working effective set
        !           389:    * to lower: just clear the working effective set
        !           390:    */
        !           391:   if (op == ZPRIVS_RAISE)
        !           392:     priv_copyset (zprivs_state.syscaps_p, zprivs_state.caps);
        !           393:   else if (op == ZPRIVS_LOWER)
        !           394:     priv_emptyset (zprivs_state.caps);
        !           395:   else
        !           396:     return -1;
        !           397:   
        !           398:   if (setppriv (PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps) != 0)
        !           399:     return -1;
        !           400:   
        !           401:   return 0;
        !           402: }
        !           403: 
        !           404: /* Retrieve current privilege state, is it RAISED or LOWERED? */
        !           405: zebra_privs_current_t 
        !           406: zprivs_state_caps (void)
        !           407: {
        !           408:   zebra_privs_current_t result;
        !           409:   pset_t *effective;
        !           410:   
        !           411:   if ( (effective = priv_allocset()) == NULL)
        !           412:     {
        !           413:       fprintf (stderr, "%s: failed to get priv_allocset! %s\n", __func__,
        !           414:                safe_strerror (errno));
        !           415:       return ZPRIVS_UNKNOWN;
        !           416:     }
        !           417:   
        !           418:   if (getppriv (PRIV_EFFECTIVE, effective))
        !           419:     {
        !           420:       fprintf (stderr, "%s: failed to get state! %s\n", __func__,
        !           421:                safe_strerror (errno));
        !           422:       result = ZPRIVS_UNKNOWN;
        !           423:     }
        !           424:   else
        !           425:     {
        !           426:       if (priv_isemptyset (effective) == B_TRUE)
        !           427:         result = ZPRIVS_LOWERED;
        !           428:       else
        !           429:         result = ZPRIVS_RAISED;
        !           430:     }
        !           431:   
        !           432:   if (effective)
        !           433:     priv_freeset (effective);
        !           434:   
        !           435:   return result;
        !           436: }
        !           437: 
        !           438: static void
        !           439: zprivs_caps_init (struct zebra_privs_t *zprivs)
        !           440: {
        !           441:   pset_t *basic;
        !           442:   pset_t *empty;
        !           443:   
        !           444:   /* the specified sets */
        !           445:   zprivs_state.syscaps_p = zcaps2sys (zprivs->caps_p, zprivs->cap_num_p);
        !           446:   zprivs_state.syscaps_i = zcaps2sys (zprivs->caps_i, zprivs->cap_num_i);
        !           447:   
        !           448:   /* nonsensical to have gotten here but not have capabilities */
        !           449:   if (!zprivs_state.syscaps_p)
        !           450:     {
        !           451:       fprintf (stderr, "%s: capabilities enabled, "
        !           452:                        "but no valid capabilities supplied\n",
        !           453:                        __func__);
        !           454:     }
        !           455:   
        !           456:   /* We retain the basic set in our permitted set, as Linux has no
        !           457:    * equivalent. The basic set on Linux hence is implicit, always
        !           458:    * there.
        !           459:    */
        !           460:   if ((basic = priv_str_to_set("basic", ",", NULL)) == NULL)
        !           461:     {
        !           462:       fprintf (stderr, "%s: couldn't get basic set!\n", __func__);
        !           463:       exit (1);
        !           464:     }
        !           465:  
        !           466:   /* Add the basic set to the permitted set */
        !           467:   priv_union (basic, zprivs_state.syscaps_p);
        !           468:   priv_freeset (basic);
        !           469:   
        !           470:   /* we need an empty set for 'effective', potentially for inheritable too */
        !           471:   if ( (empty = priv_allocset()) == NULL)
        !           472:     {
        !           473:       fprintf (stderr, "%s: couldn't get empty set!\n", __func__);
        !           474:       exit (1);
        !           475:     }
        !           476:   priv_emptyset (empty);
        !           477:   
        !           478:   /* Hey kernel, we know about privileges! 
        !           479:    * this isn't strictly required, use of setppriv should have same effect
        !           480:    */
        !           481:   if (setpflags (PRIV_AWARE, 1))
        !           482:     {
        !           483:       fprintf (stderr, "%s: error setting PRIV_AWARE!, %s\n", __func__,
        !           484:                safe_strerror (errno) );
        !           485:       exit (1);
        !           486:     }
        !           487:   
        !           488:   /* need either valid or empty sets for both p and i.. */
        !           489:   assert (zprivs_state.syscaps_i && zprivs_state.syscaps_p);
        !           490:   
        !           491:   /* we have caps, we have no need to ever change back the original user
        !           492:    * change real, effective and saved to the specified user.
        !           493:    */
        !           494:   if (zprivs_state.zuid)
        !           495:     {
        !           496:       if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) )
        !           497:         {
        !           498:           fprintf (stderr, "%s: could not setreuid, %s\n", 
        !           499:                    __func__, safe_strerror (errno));
        !           500:           exit (1);
        !           501:         }
        !           502:     }
        !           503:   
        !           504:   /* set the permitted set */
        !           505:   if (setppriv (PRIV_SET, PRIV_PERMITTED, zprivs_state.syscaps_p))
        !           506:     {
        !           507:       fprintf (stderr, "%s: error setting permitted set!, %s\n", __func__,
        !           508:                safe_strerror (errno) );
        !           509:       exit (1);
        !           510:     }
        !           511:   
        !           512:   /* set the inheritable set */
        !           513:   if (setppriv (PRIV_SET, PRIV_INHERITABLE, zprivs_state.syscaps_i))
        !           514:     {
        !           515:       fprintf (stderr, "%s: error setting inheritable set!, %s\n", __func__,
        !           516:                safe_strerror (errno) );
        !           517:       exit (1);
        !           518:     }
        !           519: 
        !           520:   /* now clear the effective set and we're ready to go */
        !           521:   if (setppriv (PRIV_SET, PRIV_EFFECTIVE, empty))
        !           522:     {
        !           523:       fprintf (stderr, "%s: error setting effective set!, %s\n", __func__,
        !           524:                safe_strerror (errno) );
        !           525:       exit (1);
        !           526:     }
        !           527:   
        !           528:   /* we'll use this as our working-storage privset */
        !           529:   zprivs_state.caps = empty;
        !           530:   
        !           531:   /* set methods for the caller to use */
        !           532:   zprivs->change = zprivs_change_caps;
        !           533:   zprivs->current_state = zprivs_state_caps;
        !           534: }
        !           535: 
        !           536: static void
        !           537: zprivs_caps_terminate (void)
        !           538: {
        !           539:   assert (zprivs_state.caps);
        !           540:   
        !           541:   /* clear all capabilities */
        !           542:   priv_emptyset (zprivs_state.caps);
        !           543:   setppriv (PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps);
        !           544:   setppriv (PRIV_SET, PRIV_PERMITTED, zprivs_state.caps);
        !           545:   setppriv (PRIV_SET, PRIV_INHERITABLE, zprivs_state.caps);
        !           546:   
        !           547:   /* free up private state */
        !           548:   if (zprivs_state.syscaps_p)
        !           549:     priv_freeset (zprivs_state.syscaps_p);
        !           550:   if (zprivs_state.syscaps_i)
        !           551:     priv_freeset (zprivs_state.syscaps_i);
        !           552:   
        !           553:   priv_freeset (zprivs_state.caps);
        !           554: }
        !           555: #else /* !HAVE_LCAPS && ! HAVE_SOLARIS_CAPABILITIES */
        !           556: #error "Neither Solaris nor Linux capabilities, dazed and confused..."
        !           557: #endif /* HAVE_LCAPS */
        !           558: #endif /* HAVE_CAPABILITIES */
        !           559: 
        !           560: int
        !           561: zprivs_change_uid (zebra_privs_ops_t op)
        !           562: {
        !           563: 
        !           564:   if (op == ZPRIVS_RAISE)
        !           565:     return seteuid (zprivs_state.zsuid);
        !           566:   else if (op == ZPRIVS_LOWER)
        !           567:     return seteuid (zprivs_state.zuid);
        !           568:   else
        !           569:     return -1;
        !           570: }
        !           571: 
        !           572: zebra_privs_current_t
        !           573: zprivs_state_uid (void)
        !           574: {
        !           575:   return ( (zprivs_state.zuid == geteuid()) ? ZPRIVS_LOWERED : ZPRIVS_RAISED);
        !           576: }
        !           577: 
        !           578: int
        !           579: zprivs_change_null (zebra_privs_ops_t op)
        !           580: {
        !           581:   return 0;
        !           582: }
        !           583: 
        !           584: zebra_privs_current_t
        !           585: zprivs_state_null (void)
        !           586: {
        !           587:   return zprivs_null_state;
        !           588: }
        !           589: 
        !           590: void
        !           591: zprivs_init(struct zebra_privs_t *zprivs)
        !           592: {
        !           593:   struct passwd *pwentry = NULL;
        !           594:   struct group *grentry = NULL;
        !           595: 
        !           596:   if (!zprivs)
        !           597:     {
        !           598:       fprintf (stderr, "zprivs_init: called with NULL arg!\n");
        !           599:       exit (1);
        !           600:     }
        !           601: 
        !           602:   /* NULL privs */
        !           603:   if (! (zprivs->user || zprivs->group 
        !           604:          || zprivs->cap_num_p || zprivs->cap_num_i) )
        !           605:     {
        !           606:       zprivs->change = zprivs_change_null;
        !           607:       zprivs->current_state = zprivs_state_null;
        !           608:       return;
        !           609:     }
        !           610: 
        !           611:   if (zprivs->user)
        !           612:     {
        !           613:       if ( (pwentry = getpwnam (zprivs->user)) )
        !           614:         {
        !           615:           zprivs_state.zuid = pwentry->pw_uid;
        !           616:         }
        !           617:       else
        !           618:         {
        !           619:           /* cant use log.h here as it depends on vty */
        !           620:           fprintf (stderr, "privs_init: could not lookup user %s\n",
        !           621:                    zprivs->user);
        !           622:           exit (1);
        !           623:         }
        !           624:     }
        !           625: 
        !           626:   grentry = NULL;
        !           627: 
        !           628:   if (zprivs->vty_group)
        !           629:     /* Add the vty_group to the supplementary groups so it can be chowned to */
        !           630:     {
        !           631:       if ( (grentry = getgrnam (zprivs->vty_group)) )
        !           632:         {
        !           633:           zprivs_state.vtygrp = grentry->gr_gid;
        !           634:           if ( setgroups (1, &zprivs_state.vtygrp) )
        !           635:             {
        !           636:               fprintf (stderr, "privs_init: could not setgroups, %s\n",
        !           637:                          safe_strerror (errno) );
        !           638:               exit (1);
        !           639:             }       
        !           640:         }
        !           641:       else
        !           642:         {
        !           643:           fprintf (stderr, "privs_init: could not lookup vty group %s\n",
        !           644:                    zprivs->vty_group);
        !           645:           exit (1);
        !           646:         }
        !           647:     }
        !           648:   
        !           649:   if (zprivs->group)
        !           650:     {
        !           651:       if ( (grentry = getgrnam (zprivs->group)) )
        !           652:         {
        !           653:           zprivs_state.zgid = grentry->gr_gid;
        !           654:         }
        !           655:       else
        !           656:         {
        !           657:           fprintf (stderr, "privs_init: could not lookup group %s\n",
        !           658:                    zprivs->group);
        !           659:           exit (1);
        !           660:         }
        !           661:       /* change group now, forever. uid we do later */
        !           662:       if ( setregid (zprivs_state.zgid, zprivs_state.zgid) )
        !           663:         {
        !           664:           fprintf (stderr, "zprivs_init: could not setregid, %s\n",
        !           665:                     safe_strerror (errno) );
        !           666:           exit (1);
        !           667:         }
        !           668:     }
        !           669:   
        !           670: #ifdef HAVE_CAPABILITIES
        !           671:   zprivs_caps_init (zprivs);
        !           672: #else /* !HAVE_CAPABILITIES */
        !           673:   /* we dont have caps. we'll need to maintain rid and saved uid
        !           674:    * and change euid back to saved uid (who we presume has all neccessary
        !           675:    * privileges) whenever we are asked to raise our privileges.
        !           676:    *
        !           677:    * This is not worth that much security wise, but all we can do.
        !           678:    */
        !           679:   zprivs_state.zsuid = geteuid();  
        !           680:   if ( zprivs_state.zuid )
        !           681:     {
        !           682:       if ( setreuid (-1, zprivs_state.zuid) )
        !           683:         {
        !           684:           fprintf (stderr, "privs_init (uid): could not setreuid, %s\n", 
        !           685:                    safe_strerror (errno));
        !           686:           exit (1);
        !           687:         }
        !           688:     }
        !           689:   
        !           690:   zprivs->change = zprivs_change_uid;
        !           691:   zprivs->current_state = zprivs_state_uid;
        !           692: #endif /* HAVE_CAPABILITIES */
        !           693: }
        !           694: 
        !           695: void 
        !           696: zprivs_terminate (struct zebra_privs_t *zprivs)
        !           697: {
        !           698:   if (!zprivs)
        !           699:     {
        !           700:       fprintf (stderr, "%s: no privs struct given, terminating", __func__);
        !           701:       exit (0);
        !           702:     }
        !           703:   
        !           704: #ifdef HAVE_CAPABILITIES
        !           705:   zprivs_caps_terminate();
        !           706: #else /* !HAVE_CAPABILITIES */
        !           707:   if (zprivs_state.zuid)
        !           708:     {
        !           709:       if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) )
        !           710:         {
        !           711:           fprintf (stderr, "privs_terminate: could not setreuid, %s", 
        !           712:                      safe_strerror (errno) );
        !           713:           exit (1);
        !           714:         }
        !           715:      }
        !           716: #endif /* HAVE_LCAPS */
        !           717: 
        !           718:   zprivs->change = zprivs_change_null;
        !           719:   zprivs->current_state = zprivs_state_null;
        !           720:   zprivs_null_state = ZPRIVS_LOWERED;
        !           721:   return;
        !           722: }
        !           723: 
        !           724: void
        !           725: zprivs_get_ids(struct zprivs_ids_t *ids)
        !           726: {
        !           727: 
        !           728:    ids->uid_priv = getuid();
        !           729:    (zprivs_state.zuid) ? (ids->uid_normal = zprivs_state.zuid)
        !           730:                      : (ids->uid_normal = -1);
        !           731:    (zprivs_state.zgid) ? (ids->gid_normal = zprivs_state.zgid)
        !           732:                      : (ids->gid_normal = -1);
        !           733:    (zprivs_state.vtygrp) ? (ids->gid_vty = zprivs_state.vtygrp)
        !           734:                        : (ids->gid_vty = -1);
        !           735:    
        !           736:    return;
        !           737: }

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