File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / lib / privs.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:11 2016 UTC (7 years, 8 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    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
   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:   [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: };
  141: 
  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:     {
  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: 
  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 */
  355: 
  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: 
  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: 
  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: {
  412:   pset_t *privset;
  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:     {
  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:     {
  425:       fprintf (stderr, "%s: Eek, missing caps!", __func__);
  426:       exit (1);
  427:     }
  428: 
  429:   /* to raise: copy original permitted as our working effective set
  430:    * to lower: copy regular effective set stored in zprivs_state.caps
  431:    */
  432:   if (op == ZPRIVS_RAISE)
  433:     privset = zprivs_state.syscaps_p;
  434:   else if (op == ZPRIVS_LOWER)
  435:     privset = zprivs_state.caps;
  436:   else
  437:     return -1;
  438:   
  439:   if (setppriv (PRIV_SET, PRIV_EFFECTIVE, privset) != 0)
  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:     {
  467:       if (priv_isequalset (effective, zprivs_state.syscaps_p))
  468:         result = ZPRIVS_RAISED;
  469:       else if (priv_isequalset (effective, zprivs_state.caps))
  470:         result = ZPRIVS_LOWERED;
  471:       else
  472:         result = ZPRIVS_UNKNOWN;
  473:     }
  474:   
  475:   priv_freeset (effective);
  476:   return result;
  477: }
  478: 
  479: static void
  480: zprivs_caps_init (struct zebra_privs_t *zprivs)
  481: {
  482:   pset_t *basic;
  483:   pset_t *minimal;
  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: 
  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))
  558:     {
  559:       fprintf (stderr, "%s: error setting effective set!, %s\n", __func__,
  560:                safe_strerror (errno) );
  561:       exit (1);
  562:     }
  563:   
  564:   /* we'll use the minimal set as our working-storage privset */
  565:   zprivs_state.caps = minimal;
  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:   
  577:   /* clear all capabilities by using working-storage privset */
  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 */
  594: 
  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: 
  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: 
  660: void
  661: zprivs_init(struct zebra_privs_t *zprivs)
  662: {
  663:   struct passwd *pwentry = NULL;
  664:   struct group *grentry = NULL;
  665:   gid_t groups[NGROUPS_MAX];
  666:   int i, ngroups = 0;
  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:     {
  685:       if ( (pwentry = getpwnam (zprivs->user)) == NULL )
  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:         }
  692: 
  693:       zprivs_state.zuid = pwentry->pw_uid;
  694:       zprivs_state.zgid = pwentry->pw_gid;
  695:     }
  696: 
  697:   grentry = NULL;
  698: 
  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: 
  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;
  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) )
  735:             {
  736:               groups[i] = zprivs_state.vtygrp;
  737:             }
  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:     }
  746: 
  747:   if (ngroups)
  748:     {
  749:       if ( setgroups (ngroups, groups) )
  750:         {
  751:           fprintf (stderr, "privs_init: could not setgroups, %s\n",
  752:                    safe_strerror (errno) );
  753:           exit (1);
  754:         }
  755:     }
  756: 
  757:   if (zprivs_state.zgid)
  758:     {
  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>