Import Upstream version 1.2.2
[quagga-debian.git] / lib / privs.c
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         {
311           current_caps_text = cap_to_text(current_caps, NULL);
312           cap_free(current_caps);
313         }
314
315       wanted_caps_text = cap_to_text(zprivs_state.caps, NULL);
316       fprintf(stderr, "Wanted caps: %s\n", wanted_caps_text ? wanted_caps_text : "???");
317       fprintf(stderr, "Have   caps: %s\n", current_caps_text ? current_caps_text : "???");
318       if (current_caps_text)
319           cap_free(current_caps_text);
320       if (wanted_caps_text)
321           cap_free(wanted_caps_text);
322
323       exit (1);
324     }
325   
326   /* set methods for the caller to use */
327   zprivs->change = zprivs_change_caps;
328   zprivs->current_state = zprivs_state_caps;
329 }
330
331 static void
332 zprivs_caps_terminate (void)
333 {
334   /* clear all capabilities */
335   if (zprivs_state.caps)
336       cap_clear (zprivs_state.caps);
337
338   /* and boom, capabilities are gone forever */
339   if ( cap_set_proc (zprivs_state.caps) ) 
340     {
341       fprintf (stderr, "privs_terminate: cap_set_proc failed, %s",
342                 safe_strerror (errno) );
343       exit (1);
344     }  
345
346   /* free up private state */
347   if (zprivs_state.syscaps_p->num)
348     {
349       XFREE (MTYPE_PRIVS, zprivs_state.syscaps_p->caps);
350       XFREE (MTYPE_PRIVS, zprivs_state.syscaps_p);
351     }
352   
353   if (zprivs_state.syscaps_i && zprivs_state.syscaps_i->num)
354     {
355       XFREE (MTYPE_PRIVS, zprivs_state.syscaps_i->caps);
356       XFREE (MTYPE_PRIVS, zprivs_state.syscaps_i);
357     }
358   
359   cap_free (zprivs_state.caps);
360 }
361 #elif defined (HAVE_SOLARIS_CAPABILITIES) /* !HAVE_LCAPS */
362
363 /* Solaris specific capability/privilege methods 
364  *
365  * Resources:
366  * - the 'privileges' man page
367  * - http://cvs.opensolaris.org
368  * - http://blogs.sun.com/roller/page/gbrunett?entry=privilege_enabling_set_id_programs1
369  */
370
371 static pset_t *
372 zprivs_caps_minimal ()
373 {
374   pset_t *minimal;
375
376   if ((minimal = priv_str_to_set("basic", ",", NULL)) == NULL)
377     {
378       fprintf (stderr, "%s: couldn't get basic set!\n", __func__);
379       exit (1);
380     }
381
382    /* create a minimal privilege set from the basic set */
383   (void) priv_delset(minimal, PRIV_PROC_EXEC);
384   (void) priv_delset(minimal, PRIV_PROC_INFO);
385   (void) priv_delset(minimal, PRIV_PROC_SESSION);
386   (void) priv_delset(minimal, PRIV_FILE_LINK_ANY);
387
388   return  minimal;
389 }
390
391 /* convert zebras privileges to system capabilities */
392 static pset_t *
393 zcaps2sys (zebra_capabilities_t *zcaps, int num)
394 {
395   pset_t *syscaps;
396   int i, j = 0;
397   
398   if ((syscaps = priv_allocset()) == NULL)
399     {
400       fprintf (stderr, "%s: could not allocate syscaps!\n", __func__);
401       exit (1);
402     }
403     
404   priv_emptyset (syscaps);
405   
406   for (i=0; i < num; i++)
407     for (j = 0; j < cap_map[zcaps[i]].num; j++)
408       priv_addset (syscaps, cap_map[zcaps[i]].system_caps[j]);
409   
410   return syscaps;
411 }
412
413 /* callback exported to users to RAISE and LOWER effective privileges
414  * from nothing to the given permitted set and back down
415  */
416 int 
417 zprivs_change_caps (zebra_privs_ops_t op)
418 {
419   pset_t *privset;
420   
421   /* should be no possibility of being called without valid caps */
422   assert (zprivs_state.syscaps_p);
423   if (!zprivs_state.syscaps_p)
424     {
425       fprintf (stderr, "%s: Eek, missing privileged caps!", __func__);
426       exit (1);
427     }
428
429   assert (zprivs_state.caps);
430   if (!zprivs_state.caps)
431     {
432       fprintf (stderr, "%s: Eek, missing caps!", __func__);
433       exit (1);
434     }
435
436   /* to raise: copy original permitted as our working effective set
437    * to lower: copy regular effective set stored in zprivs_state.caps
438    */
439   if (op == ZPRIVS_RAISE)
440     privset = zprivs_state.syscaps_p;
441   else if (op == ZPRIVS_LOWER)
442     privset = zprivs_state.caps;
443   else
444     return -1;
445   
446   if (setppriv (PRIV_SET, PRIV_EFFECTIVE, privset) != 0)
447     return -1;
448   
449   return 0;
450 }
451
452 /* Retrieve current privilege state, is it RAISED or LOWERED? */
453 zebra_privs_current_t 
454 zprivs_state_caps (void)
455 {
456   zebra_privs_current_t result;
457   pset_t *effective;
458   
459   if ( (effective = priv_allocset()) == NULL)
460     {
461       fprintf (stderr, "%s: failed to get priv_allocset! %s\n", __func__,
462                safe_strerror (errno));
463       return ZPRIVS_UNKNOWN;
464     }
465   
466   if (getppriv (PRIV_EFFECTIVE, effective))
467     {
468       fprintf (stderr, "%s: failed to get state! %s\n", __func__,
469                safe_strerror (errno));
470       result = ZPRIVS_UNKNOWN;
471     }
472   else
473     {
474       if (priv_isequalset (effective, zprivs_state.syscaps_p))
475         result = ZPRIVS_RAISED;
476       else if (priv_isequalset (effective, zprivs_state.caps))
477         result = ZPRIVS_LOWERED;
478       else
479         result = ZPRIVS_UNKNOWN;
480     }
481   
482   priv_freeset (effective);
483   return result;
484 }
485
486 static void
487 zprivs_caps_init (struct zebra_privs_t *zprivs)
488 {
489   pset_t *basic;
490   pset_t *minimal;
491   
492   /* the specified sets */
493   zprivs_state.syscaps_p = zcaps2sys (zprivs->caps_p, zprivs->cap_num_p);
494   zprivs_state.syscaps_i = zcaps2sys (zprivs->caps_i, zprivs->cap_num_i);
495   
496   /* nonsensical to have gotten here but not have capabilities */
497   if (!zprivs_state.syscaps_p)
498     {
499       fprintf (stderr, "%s: capabilities enabled, "
500                        "but no valid capabilities supplied\n",
501                        __func__);
502     }
503   
504   /* We retain the basic set in our permitted set, as Linux has no
505    * equivalent. The basic set on Linux hence is implicit, always
506    * there.
507    */
508   if ((basic = priv_str_to_set("basic", ",", NULL)) == NULL)
509     {
510       fprintf (stderr, "%s: couldn't get basic set!\n", __func__);
511       exit (1);
512     }
513  
514   /* Add the basic set to the permitted set */
515   priv_union (basic, zprivs_state.syscaps_p);
516   priv_freeset (basic);
517   
518   /* Hey kernel, we know about privileges! 
519    * this isn't strictly required, use of setppriv should have same effect
520    */
521   if (setpflags (PRIV_AWARE, 1))
522     {
523       fprintf (stderr, "%s: error setting PRIV_AWARE!, %s\n", __func__,
524                safe_strerror (errno) );
525       exit (1);
526     }
527   
528   /* need either valid or empty sets for both p and i.. */
529   assert (zprivs_state.syscaps_i && zprivs_state.syscaps_p);
530   
531   /* we have caps, we have no need to ever change back the original user
532    * change real, effective and saved to the specified user.
533    */
534   if (zprivs_state.zuid)
535     {
536       if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) )
537         {
538           fprintf (stderr, "%s: could not setreuid, %s\n", 
539                    __func__, safe_strerror (errno));
540           exit (1);
541         }
542     }
543   
544   /* set the permitted set */
545   if (setppriv (PRIV_SET, PRIV_PERMITTED, zprivs_state.syscaps_p))
546     {
547       fprintf (stderr, "%s: error setting permitted set!, %s\n", __func__,
548                safe_strerror (errno) );
549       exit (1);
550     }
551   
552   /* set the inheritable set */
553   if (setppriv (PRIV_SET, PRIV_INHERITABLE, zprivs_state.syscaps_i))
554     {
555       fprintf (stderr, "%s: error setting inheritable set!, %s\n", __func__,
556                safe_strerror (errno) );
557       exit (1);
558     }
559
560   /* we need a minimal basic set for 'effective', potentially for inheritable too */
561   minimal = zprivs_caps_minimal();
562
563   /* now set the effective set with a subset of basic privileges */
564   if (setppriv (PRIV_SET, PRIV_EFFECTIVE, minimal))
565     {
566       fprintf (stderr, "%s: error setting effective set!, %s\n", __func__,
567                safe_strerror (errno) );
568       exit (1);
569     }
570   
571   /* we'll use the minimal set as our working-storage privset */
572   zprivs_state.caps = minimal;
573   
574   /* set methods for the caller to use */
575   zprivs->change = zprivs_change_caps;
576   zprivs->current_state = zprivs_state_caps;
577 }
578
579 static void
580 zprivs_caps_terminate (void)
581 {
582   assert (zprivs_state.caps);
583   
584   /* clear all capabilities by using working-storage privset */
585   setppriv (PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps);
586   setppriv (PRIV_SET, PRIV_PERMITTED, zprivs_state.caps);
587   setppriv (PRIV_SET, PRIV_INHERITABLE, zprivs_state.caps);
588   
589   /* free up private state */
590   if (zprivs_state.syscaps_p)
591     priv_freeset (zprivs_state.syscaps_p);
592   if (zprivs_state.syscaps_i)
593     priv_freeset (zprivs_state.syscaps_i);
594   
595   priv_freeset (zprivs_state.caps);
596 }
597 #else /* !HAVE_LCAPS && ! HAVE_SOLARIS_CAPABILITIES */
598 #error "Neither Solaris nor Linux capabilities, dazed and confused..."
599 #endif /* HAVE_LCAPS */
600 #endif /* HAVE_CAPABILITIES */
601
602 int
603 zprivs_change_uid (zebra_privs_ops_t op)
604 {
605
606   if (op == ZPRIVS_RAISE)
607     return seteuid (zprivs_state.zsuid);
608   else if (op == ZPRIVS_LOWER)
609     return seteuid (zprivs_state.zuid);
610   else
611     return -1;
612 }
613
614 zebra_privs_current_t
615 zprivs_state_uid (void)
616 {
617   return ( (zprivs_state.zuid == geteuid()) ? ZPRIVS_LOWERED : ZPRIVS_RAISED);
618 }
619
620 int
621 zprivs_change_null (zebra_privs_ops_t op)
622 {
623   return 0;
624 }
625
626 zebra_privs_current_t
627 zprivs_state_null (void)
628 {
629   return zprivs_null_state;
630 }
631
632 #ifndef HAVE_GETGROUPLIST
633 /* Solaris 11 has no getgrouplist() */
634 static int
635 getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups)
636 {
637   struct group *grp;
638   size_t usridx;
639   int pos = 0, ret;
640
641   if (pos < *ngroups)
642     groups[pos] = group;
643   pos++;
644
645   setgrent();
646   while ((grp = getgrent()))
647     {
648       if (grp->gr_gid == group)
649         continue;
650       for (usridx = 0; grp->gr_mem[usridx] != NULL; usridx++)
651         if (!strcmp (grp->gr_mem[usridx], user))
652           {
653             if (pos < *ngroups)
654               groups[pos] = grp->gr_gid;
655             pos++;
656             break;
657           }
658     }
659   endgrent();
660
661   ret = (pos <= *ngroups) ? pos : -1;
662   *ngroups = pos;
663   return ret;
664 }
665 #endif /* HAVE_GETGROUPLIST */
666
667 void
668 zprivs_init(struct zebra_privs_t *zprivs)
669 {
670   struct passwd *pwentry = NULL;
671   struct group *grentry = NULL;
672   gid_t groups[NGROUPS_MAX];
673   int i, ngroups = 0;
674   int found = 0;
675
676   if (!zprivs)
677     {
678       fprintf (stderr, "zprivs_init: called with NULL arg!\n");
679       exit (1);
680     }
681
682   /* NULL privs */
683   if (! (zprivs->user || zprivs->group 
684          || zprivs->cap_num_p || zprivs->cap_num_i) )
685     {
686       zprivs->change = zprivs_change_null;
687       zprivs->current_state = zprivs_state_null;
688       return;
689     }
690
691   if (zprivs->user)
692     {
693       if ( (pwentry = getpwnam (zprivs->user)) == NULL )
694         {
695           /* cant use log.h here as it depends on vty */
696           fprintf (stderr, "privs_init: could not lookup user %s\n",
697                    zprivs->user);
698           exit (1);
699         }
700
701       zprivs_state.zuid = pwentry->pw_uid;
702       zprivs_state.zgid = pwentry->pw_gid;
703     }
704
705   grentry = NULL;
706
707   if (zprivs->group)
708     {
709       if ( (grentry = getgrnam (zprivs->group)) == NULL )
710         {
711           fprintf (stderr, "privs_init: could not lookup group %s\n",
712                    zprivs->group);
713           exit (1);
714         }
715
716       zprivs_state.zgid = grentry->gr_gid;
717     }
718
719   if (zprivs->user)
720     {
721       ngroups = sizeof(groups);
722       if ( (ngroups = getgrouplist (zprivs->user, zprivs_state.zgid, groups, &ngroups )) < 0 )
723         {
724           /* cant use log.h here as it depends on vty */
725           fprintf (stderr, "privs_init: could not getgrouplist for user %s\n",
726                    zprivs->user);
727           exit (1);
728         }
729     }
730
731   if (zprivs->vty_group)
732     /* Add the vty_group to the supplementary groups so it can be chowned to */
733     {
734       if ( (grentry = getgrnam (zprivs->vty_group)) )
735         {
736           zprivs_state.vtygrp = grentry->gr_gid;
737
738           for ( i = 0; i < ngroups; i++ )
739             if ( groups[i] == zprivs_state.vtygrp )
740               {
741                 found++;
742                 break;
743               }
744
745           if (!found)
746             {
747               fprintf (stderr, "privs_init: user(%s) is not part of vty group specified(%s)\n",
748                        zprivs->user, zprivs->vty_group);
749               exit (1);
750             }
751           if ( i >= ngroups && ngroups < (int) ZEBRA_NUM_OF(groups) )
752             {
753               groups[i] = zprivs_state.vtygrp;
754             }
755         }
756       else
757         {
758           fprintf (stderr, "privs_init: could not lookup vty group %s\n",
759                    zprivs->vty_group);
760           exit (1);
761         }
762     }
763
764   if (ngroups)
765     {
766       if ( setgroups (ngroups, groups) )
767         {
768           fprintf (stderr, "privs_init: could not setgroups, %s\n",
769                    safe_strerror (errno) );
770           exit (1);
771         }
772     }
773
774   if (zprivs_state.zgid)
775     {
776       /* change group now, forever. uid we do later */
777       if ( setregid (zprivs_state.zgid, zprivs_state.zgid) )
778         {
779           fprintf (stderr, "zprivs_init: could not setregid, %s\n",
780                     safe_strerror (errno) );
781           exit (1);
782         }
783     }
784   
785 #ifdef HAVE_CAPABILITIES
786   zprivs_caps_init (zprivs);
787 #else /* !HAVE_CAPABILITIES */
788   /* we dont have caps. we'll need to maintain rid and saved uid
789    * and change euid back to saved uid (who we presume has all neccessary
790    * privileges) whenever we are asked to raise our privileges.
791    *
792    * This is not worth that much security wise, but all we can do.
793    */
794   zprivs_state.zsuid = geteuid();  
795   if ( zprivs_state.zuid )
796     {
797       if ( setreuid (-1, zprivs_state.zuid) )
798         {
799           fprintf (stderr, "privs_init (uid): could not setreuid, %s\n", 
800                    safe_strerror (errno));
801           exit (1);
802         }
803     }
804   
805   zprivs->change = zprivs_change_uid;
806   zprivs->current_state = zprivs_state_uid;
807 #endif /* HAVE_CAPABILITIES */
808 }
809
810 void 
811 zprivs_terminate (struct zebra_privs_t *zprivs)
812 {
813   if (!zprivs)
814     {
815       fprintf (stderr, "%s: no privs struct given, terminating", __func__);
816       exit (0);
817     }
818   
819 #ifdef HAVE_CAPABILITIES
820   zprivs_caps_terminate();
821 #else /* !HAVE_CAPABILITIES */
822   if (zprivs_state.zuid)
823     {
824       if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) )
825         {
826           fprintf (stderr, "privs_terminate: could not setreuid, %s", 
827                      safe_strerror (errno) );
828           exit (1);
829         }
830      }
831 #endif /* HAVE_LCAPS */
832
833   zprivs->change = zprivs_change_null;
834   zprivs->current_state = zprivs_state_null;
835   zprivs_null_state = ZPRIVS_LOWERED;
836   return;
837 }
838
839 void
840 zprivs_get_ids(struct zprivs_ids_t *ids)
841 {
842
843    ids->uid_priv = getuid();
844    (zprivs_state.zuid) ? (ids->uid_normal = zprivs_state.zuid)
845                      : (ids->uid_normal = -1);
846    (zprivs_state.zgid) ? (ids->gid_normal = zprivs_state.zgid)
847                      : (ids->gid_normal = -1);
848    (zprivs_state.vtygrp) ? (ids->gid_vty = zprivs_state.vtygrp)
849                        : (ids->gid_vty = -1);
850    
851    return;
852 }