4 * Copyright (C) 2003 Paul Jakma.
5 * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
7 * This file is part of GNU Zebra.
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
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.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; see the file COPYING; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "frr_pthread.h"
28 #include "lib_errors.h"
29 #include "lib/queue.h"
31 DEFINE_MTYPE_STATIC(LIB
, PRIVS
, "Privilege information");
34 * Different capabilities/privileges apis have different characteristics: some
35 * are process-wide, and some are per-thread.
37 #ifdef HAVE_CAPABILITIES
39 static const bool privs_per_process
; /* = false */
41 static const bool privs_per_process
= true;
42 #endif /* HAVE_LCAPS */
43 #else /* HAVE_CAPABILITIES */
44 static const bool privs_per_process
= true;
47 #ifdef HAVE_CAPABILITIES
49 /* sort out some generic internal types for:
51 * privilege values (cap_value_t, priv_t) -> pvalue_t
52 * privilege set (..., priv_set_t) -> pset_t
53 * privilege working storage (cap_t, ...) -> pstorage_t
55 * values we think of as numeric (they're ints really, but we dont know)
56 * sets are mostly opaque, to hold a set of privileges, related in some way.
57 * storage binds together a set of sets we're interested in.
58 * (in reality: cap_value_t and priv_t are ints)
61 /* Linux doesn't have a 'set' type: a set of related privileges */
66 typedef cap_value_t pvalue_t
;
67 typedef struct _pset pset_t
;
68 typedef cap_t pstorage_t
;
71 #error "HAVE_CAPABILITIES defined, but neither LCAPS nor Solaris Capabilties!"
72 #endif /* HAVE_LCAPS */
73 #endif /* HAVE_CAPABILITIES */
75 /* the default NULL state we report is RAISED, but could be LOWERED if
76 * zprivs_terminate is called and the NULL handler is installed.
78 static zebra_privs_current_t zprivs_null_state
= ZPRIVS_RAISED
;
80 /* internal privileges state */
81 static struct _zprivs_t
{
82 #ifdef HAVE_CAPABILITIES
83 pstorage_t caps
; /* working storage */
84 pset_t
*syscaps_p
; /* system-type requested permitted caps */
85 pset_t
*syscaps_i
; /* system-type requested inheritable caps */
86 #endif /* HAVE_CAPABILITIES */
87 uid_t zuid
, /* uid to run as */
88 zsuid
; /* saved uid */
89 gid_t zgid
; /* gid to run as */
90 gid_t vtygrp
; /* gid for vty sockets */
93 /* externally exported but not directly accessed functions */
94 #ifdef HAVE_CAPABILITIES
95 int zprivs_change_caps(zebra_privs_ops_t
);
96 zebra_privs_current_t
zprivs_state_caps(void);
97 #endif /* HAVE_CAPABILITIES */
98 int zprivs_change_uid(zebra_privs_ops_t
);
99 zebra_privs_current_t
zprivs_state_uid(void);
100 int zprivs_change_null(zebra_privs_ops_t
);
101 zebra_privs_current_t
zprivs_state_null(void);
103 #ifdef HAVE_CAPABILITIES
104 /* internal capability API */
105 static pset_t
*zcaps2sys(zebra_capabilities_t
*, int);
106 static void zprivs_caps_init(struct zebra_privs_t
*);
107 static void zprivs_caps_terminate(void);
109 /* Map of Quagga abstract capabilities to system capabilities */
112 pvalue_t
*system_caps
;
113 } cap_map
[ZCAP_MAX
] = {
114 #ifdef HAVE_LCAPS /* Quagga -> Linux capabilities mappings */
117 2, (pvalue_t
[]){CAP_SETGID
, CAP_SETUID
},
121 1, (pvalue_t
[]){CAP_NET_BIND_SERVICE
},
125 1, (pvalue_t
[]){CAP_NET_ADMIN
},
129 1, (pvalue_t
[]){CAP_NET_RAW
},
140 1, (pvalue_t
[]){CAP_SYS_NICE
},
144 1, (pvalue_t
[]){CAP_SYS_PTRACE
},
146 [ZCAP_DAC_OVERRIDE
] =
148 1, (pvalue_t
[]){CAP_DAC_OVERRIDE
},
152 1, (pvalue_t
[]){CAP_DAC_READ_SEARCH
},
156 1, (pvalue_t
[]){CAP_SYS_ADMIN
},
160 1, (pvalue_t
[]){CAP_FOWNER
},
164 1, (pvalue_t
[]){CAP_IPC_LOCK
},
166 #endif /* HAVE_LCAPS */
170 /* Linux forms of capabilities methods */
171 /* convert zebras privileges to system capabilities */
172 static pset_t
*zcaps2sys(zebra_capabilities_t
*zcaps
, int num
)
175 int i
, j
= 0, count
= 0;
180 /* first count up how many system caps we have */
181 for (i
= 0; i
< num
; i
++)
182 count
+= cap_map
[zcaps
[i
]].num
;
184 if ((syscaps
= XCALLOC(MTYPE_PRIVS
, (sizeof(pset_t
) * num
))) == NULL
) {
185 fprintf(stderr
, "%s: could not allocate syscaps!", __func__
);
189 syscaps
->caps
= XCALLOC(MTYPE_PRIVS
, (sizeof(pvalue_t
) * count
));
191 if (!syscaps
->caps
) {
192 fprintf(stderr
, "%s: could not XCALLOC caps!", __func__
);
196 /* copy the capabilities over */
198 for (i
= 0; i
< num
; i
++)
199 for (j
= 0; j
< cap_map
[zcaps
[i
]].num
; j
++)
200 syscaps
->caps
[count
++] =
201 cap_map
[zcaps
[i
]].system_caps
[j
];
203 /* iterations above should be exact same as previous count, obviously..
205 syscaps
->num
= count
;
210 /* set or clear the effective capabilities to/from permitted */
211 int zprivs_change_caps(zebra_privs_ops_t op
)
213 cap_flag_value_t cflag
;
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
))
220 if (op
== ZPRIVS_RAISE
)
222 else if (op
== ZPRIVS_LOWER
)
227 if (!cap_set_flag(zprivs_state
.caps
, CAP_EFFECTIVE
,
228 zprivs_state
.syscaps_p
->num
,
229 zprivs_state
.syscaps_p
->caps
, cflag
))
230 return cap_set_proc(zprivs_state
.caps
);
234 zebra_privs_current_t
zprivs_state_caps(void)
237 cap_flag_value_t val
;
239 /* should be no possibility of being called without valid caps */
240 assert(zprivs_state
.syscaps_p
&& zprivs_state
.caps
);
241 if (!(zprivs_state
.syscaps_p
&& zprivs_state
.caps
))
244 for (i
= 0; i
< zprivs_state
.syscaps_p
->num
; i
++) {
245 if (cap_get_flag(zprivs_state
.caps
,
246 zprivs_state
.syscaps_p
->caps
[i
], CAP_EFFECTIVE
,
250 "zprivs_state_caps: could not cap_get_flag, %s",
251 safe_strerror(errno
));
252 return ZPRIVS_UNKNOWN
;
255 return ZPRIVS_RAISED
;
257 return ZPRIVS_LOWERED
;
260 static void zprivs_caps_init(struct zebra_privs_t
*zprivs
)
262 zprivs_state
.syscaps_p
= zcaps2sys(zprivs
->caps_p
, zprivs
->cap_num_p
);
263 zprivs_state
.syscaps_i
= zcaps2sys(zprivs
->caps_i
, zprivs
->cap_num_i
);
265 /* Tell kernel we want caps maintained across uid changes */
266 if (prctl(PR_SET_KEEPCAPS
, 1, 0, 0, 0) == -1) {
268 "privs_init: could not set PR_SET_KEEPCAPS, %s\n",
269 safe_strerror(errno
));
273 /* we have caps, we have no need to ever change back the original user
275 /* only change uid if we don't have the correct one */
276 if ((zprivs_state
.zuid
) && (zprivs_state
.zsuid
!= zprivs_state
.zuid
)) {
277 if (setreuid(zprivs_state
.zuid
, zprivs_state
.zuid
)) {
279 "zprivs_init (cap): could not setreuid, %s\n",
280 safe_strerror(errno
));
285 if (!zprivs_state
.syscaps_p
)
288 if (!(zprivs_state
.caps
= cap_init())) {
289 fprintf(stderr
, "privs_init: failed to cap_init, %s\n",
290 safe_strerror(errno
));
294 if (cap_clear(zprivs_state
.caps
)) {
295 fprintf(stderr
, "privs_init: failed to cap_clear, %s\n",
296 safe_strerror(errno
));
300 /* set permitted caps */
301 cap_set_flag(zprivs_state
.caps
, CAP_PERMITTED
,
302 zprivs_state
.syscaps_p
->num
, zprivs_state
.syscaps_p
->caps
,
305 /* set inheritable caps, if any */
306 if (zprivs_state
.syscaps_i
&& zprivs_state
.syscaps_i
->num
) {
307 cap_set_flag(zprivs_state
.caps
, CAP_INHERITABLE
,
308 zprivs_state
.syscaps_i
->num
,
309 zprivs_state
.syscaps_i
->caps
, CAP_SET
);
312 /* apply caps. CAP_EFFECTIVE is cleared. we'll raise the caps as
313 * and when, and only when, they are needed.
315 if (cap_set_proc(zprivs_state
.caps
)) {
317 char *current_caps_text
= NULL
;
318 char *wanted_caps_text
= NULL
;
320 fprintf(stderr
, "privs_init: initial cap_set_proc failed: %s\n",
321 safe_strerror(errno
));
323 current_caps
= cap_get_proc();
325 current_caps_text
= cap_to_text(current_caps
, NULL
);
326 cap_free(current_caps
);
329 wanted_caps_text
= cap_to_text(zprivs_state
.caps
, NULL
);
330 fprintf(stderr
, "Wanted caps: %s\n",
331 wanted_caps_text
? wanted_caps_text
: "???");
332 fprintf(stderr
, "Have caps: %s\n",
333 current_caps_text
? current_caps_text
: "???");
334 if (current_caps_text
)
335 cap_free(current_caps_text
);
336 if (wanted_caps_text
)
337 cap_free(wanted_caps_text
);
342 /* set methods for the caller to use */
343 zprivs
->change
= zprivs_change_caps
;
344 zprivs
->current_state
= zprivs_state_caps
;
347 static void zprivs_caps_terminate(void)
349 /* Clear all capabilities, if we have any. */
350 if (zprivs_state
.caps
)
351 cap_clear(zprivs_state
.caps
);
355 /* and boom, capabilities are gone forever */
356 if (cap_set_proc(zprivs_state
.caps
)) {
357 fprintf(stderr
, "privs_terminate: cap_set_proc failed, %s",
358 safe_strerror(errno
));
362 /* free up private state */
363 if (zprivs_state
.syscaps_p
->num
) {
364 XFREE(MTYPE_PRIVS
, zprivs_state
.syscaps_p
->caps
);
365 XFREE(MTYPE_PRIVS
, zprivs_state
.syscaps_p
);
368 if (zprivs_state
.syscaps_i
&& zprivs_state
.syscaps_i
->num
) {
369 XFREE(MTYPE_PRIVS
, zprivs_state
.syscaps_i
->caps
);
370 XFREE(MTYPE_PRIVS
, zprivs_state
.syscaps_i
);
373 cap_free(zprivs_state
.caps
);
375 #else /* !HAVE_LCAPS */
376 #error "no Linux capabilities, dazed and confused..."
377 #endif /* HAVE_LCAPS */
378 #endif /* HAVE_CAPABILITIES */
380 int zprivs_change_uid(zebra_privs_ops_t op
)
382 if (zprivs_state
.zsuid
== zprivs_state
.zuid
)
384 if (op
== ZPRIVS_RAISE
)
385 return seteuid(zprivs_state
.zsuid
);
386 else if (op
== ZPRIVS_LOWER
)
387 return seteuid(zprivs_state
.zuid
);
392 zebra_privs_current_t
zprivs_state_uid(void)
394 return ((zprivs_state
.zuid
== geteuid()) ? ZPRIVS_LOWERED
398 int zprivs_change_null(zebra_privs_ops_t op
)
403 zebra_privs_current_t
zprivs_state_null(void)
405 return zprivs_null_state
;
408 #ifndef HAVE_GETGROUPLIST
409 /* Solaris 11 has no getgrouplist() */
410 static int getgrouplist(const char *user
, gid_t group
, gid_t
*groups
,
422 while ((grp
= getgrent())) {
423 if (grp
->gr_gid
== group
)
425 for (usridx
= 0; grp
->gr_mem
[usridx
] != NULL
; usridx
++)
426 if (!strcmp(grp
->gr_mem
[usridx
], user
)) {
428 groups
[pos
] = grp
->gr_gid
;
435 ret
= (pos
<= *ngroups
) ? pos
: -1;
439 #endif /* HAVE_GETGROUPLIST */
442 * Helper function that locates a refcounting object to use: a process-wide
443 * object or a per-pthread object.
445 static struct zebra_privs_refs_t
*get_privs_refs(struct zebra_privs_t
*privs
)
447 struct zebra_privs_refs_t
*temp
, *refs
= NULL
;
450 if (privs_per_process
)
451 refs
= &(privs
->process_refs
);
453 /* Locate - or create - the object for the current pthread. */
454 tid
= pthread_self();
456 STAILQ_FOREACH(temp
, &(privs
->thread_refs
), entry
) {
457 if (pthread_equal(temp
->tid
, tid
)) {
463 /* Need to create a new refcounting object. */
465 refs
= XCALLOC(MTYPE_PRIVS
,
466 sizeof(struct zebra_privs_refs_t
));
468 STAILQ_INSERT_TAIL(&(privs
->thread_refs
), refs
, entry
);
475 struct zebra_privs_t
*_zprivs_raise(struct zebra_privs_t
*privs
,
476 const char *funcname
)
478 int save_errno
= errno
;
479 struct zebra_privs_refs_t
*refs
;
485 * Serialize 'raise' operations; particularly important for
486 * OSes where privs are process-wide.
488 frr_with_mutex(&(privs
->mutex
)) {
489 /* Locate ref-counting object to use */
490 refs
= get_privs_refs(privs
);
492 if (++(refs
->refcount
) == 1) {
494 if (privs
->change(ZPRIVS_RAISE
)) {
495 zlog_err("%s: Failed to raise privileges (%s)",
496 funcname
, safe_strerror(errno
));
499 refs
->raised_in_funcname
= funcname
;
506 void _zprivs_lower(struct zebra_privs_t
**privs
)
508 int save_errno
= errno
;
509 struct zebra_privs_refs_t
*refs
;
514 /* Serialize 'lower privs' operation - particularly important
515 * when OS privs are process-wide.
517 frr_with_mutex(&(*privs
)->mutex
) {
518 refs
= get_privs_refs(*privs
);
520 if (--(refs
->refcount
) == 0) {
522 if ((*privs
)->change(ZPRIVS_LOWER
)) {
523 zlog_err("%s: Failed to lower privileges (%s)",
524 refs
->raised_in_funcname
,
525 safe_strerror(errno
));
528 refs
->raised_in_funcname
= NULL
;
535 void zprivs_preinit(struct zebra_privs_t
*zprivs
)
537 struct passwd
*pwentry
= NULL
;
538 struct group
*grentry
= NULL
;
541 fprintf(stderr
, "zprivs_init: called with NULL arg!\n");
545 pthread_mutex_init(&(zprivs
->mutex
), NULL
);
546 zprivs
->process_refs
.refcount
= 0;
547 zprivs
->process_refs
.raised_in_funcname
= NULL
;
548 STAILQ_INIT(&zprivs
->thread_refs
);
550 if (zprivs
->vty_group
) {
551 /* in a "NULL" setup, this is allowed to fail too, but still
553 if ((grentry
= getgrnam(zprivs
->vty_group
)))
554 zprivs_state
.vtygrp
= grentry
->gr_gid
;
556 zprivs_state
.vtygrp
= (gid_t
)-1;
560 if (!(zprivs
->user
|| zprivs
->group
|| zprivs
->cap_num_p
561 || zprivs
->cap_num_i
)) {
562 zprivs
->change
= zprivs_change_null
;
563 zprivs
->current_state
= zprivs_state_null
;
568 if ((pwentry
= getpwnam(zprivs
->user
)) == NULL
) {
569 /* cant use log.h here as it depends on vty */
571 "privs_init: could not lookup user %s\n",
576 zprivs_state
.zuid
= pwentry
->pw_uid
;
577 zprivs_state
.zgid
= pwentry
->pw_gid
;
583 if ((grentry
= getgrnam(zprivs
->group
)) == NULL
) {
585 "privs_init: could not lookup group %s\n",
590 zprivs_state
.zgid
= grentry
->gr_gid
;
594 struct zebra_privs_t
*lib_privs
;
596 void zprivs_init(struct zebra_privs_t
*zprivs
)
598 gid_t groups
[NGROUPS_MAX
] = {};
603 if (!(zprivs
->user
|| zprivs
->group
|| zprivs
->cap_num_p
604 || zprivs
->cap_num_i
))
610 ngroups
= array_size(groups
);
611 if (getgrouplist(zprivs
->user
, zprivs_state
.zgid
, groups
,
614 /* cant use log.h here as it depends on vty */
616 "privs_init: could not getgrouplist for user %s\n",
622 if (zprivs
->vty_group
)
623 /* Add the vty_group to the supplementary groups so it can be chowned to
626 if (zprivs_state
.vtygrp
== (gid_t
)-1) {
628 "privs_init: could not lookup vty group %s\n",
633 for (i
= 0; i
< ngroups
; i
++)
634 if (groups
[i
] == zprivs_state
.vtygrp
) {
641 "privs_init: user(%s) is not part of vty group specified(%s)\n",
642 zprivs
->user
, zprivs
->vty_group
);
645 if (i
>= ngroups
&& ngroups
< (int)array_size(groups
)) {
646 groups
[i
] = zprivs_state
.vtygrp
;
650 zprivs_state
.zsuid
= geteuid(); /* initial uid */
651 /* add groups only if we changed uid - otherwise skip */
652 if ((ngroups
) && (zprivs_state
.zsuid
!= zprivs_state
.zuid
)) {
653 if (setgroups(ngroups
, groups
)) {
654 fprintf(stderr
, "privs_init: could not setgroups, %s\n",
655 safe_strerror(errno
));
660 /* change gid only if we changed uid - otherwise skip */
661 if ((zprivs_state
.zgid
) && (zprivs_state
.zsuid
!= zprivs_state
.zuid
)) {
662 /* change group now, forever. uid we do later */
663 if (setregid(zprivs_state
.zgid
, zprivs_state
.zgid
)) {
664 fprintf(stderr
, "zprivs_init: could not setregid, %s\n",
665 safe_strerror(errno
));
670 #ifdef HAVE_CAPABILITIES
671 zprivs_caps_init(zprivs
);
674 * If we have initialized the system with no requested
675 * capabilities, change will not have been set
676 * to anything by zprivs_caps_init, As such
677 * we should make sure that when we attempt
678 * to raize privileges that we actually have
679 * a do nothing function to call instead of a
683 zprivs
->change
= zprivs_change_null
;
685 #else /* !HAVE_CAPABILITIES */
686 /* we dont have caps. we'll need to maintain rid and saved uid
687 * and change euid back to saved uid (who we presume has all necessary
688 * privileges) whenever we are asked to raise our privileges.
690 * This is not worth that much security wise, but all we can do.
692 zprivs_state
.zsuid
= geteuid();
693 /* only change uid if we don't have the correct one */
694 if ((zprivs_state
.zuid
) && (zprivs_state
.zsuid
!= zprivs_state
.zuid
)) {
695 if (setreuid(-1, zprivs_state
.zuid
)) {
697 "privs_init (uid): could not setreuid, %s\n",
698 safe_strerror(errno
));
703 zprivs
->change
= zprivs_change_uid
;
704 zprivs
->current_state
= zprivs_state_uid
;
705 #endif /* HAVE_CAPABILITIES */
708 void zprivs_terminate(struct zebra_privs_t
*zprivs
)
710 struct zebra_privs_refs_t
*refs
;
715 fprintf(stderr
, "%s: no privs struct given, terminating",
720 #ifdef HAVE_CAPABILITIES
721 if (zprivs
->user
|| zprivs
->group
|| zprivs
->cap_num_p
722 || zprivs
->cap_num_i
)
723 zprivs_caps_terminate();
724 #else /* !HAVE_CAPABILITIES */
725 /* only change uid if we don't have the correct one */
726 if ((zprivs_state
.zuid
) && (zprivs_state
.zsuid
!= zprivs_state
.zuid
)) {
727 if (setreuid(zprivs_state
.zuid
, zprivs_state
.zuid
)) {
729 "privs_terminate: could not setreuid, %s",
730 safe_strerror(errno
));
734 #endif /* HAVE_LCAPS */
736 while ((refs
= STAILQ_FIRST(&(zprivs
->thread_refs
))) != NULL
) {
737 STAILQ_REMOVE_HEAD(&(zprivs
->thread_refs
), entry
);
738 XFREE(MTYPE_PRIVS
, refs
);
741 zprivs
->change
= zprivs_change_null
;
742 zprivs
->current_state
= zprivs_state_null
;
743 zprivs_null_state
= ZPRIVS_LOWERED
;
747 void zprivs_get_ids(struct zprivs_ids_t
*ids
)
750 ids
->uid_priv
= getuid();
751 (zprivs_state
.zuid
) ? (ids
->uid_normal
= zprivs_state
.zuid
)
752 : (ids
->uid_normal
= (uid_t
)-1);
753 (zprivs_state
.zgid
) ? (ids
->gid_normal
= zprivs_state
.zgid
)
754 : (ids
->gid_normal
= (uid_t
)-1);
755 (zprivs_state
.vtygrp
) ? (ids
->gid_vty
= zprivs_state
.vtygrp
)
756 : (ids
->gid_vty
= (uid_t
)-1);