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>