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