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
},
168 1, (pvalue_t
[]){CAP_SYS_RAWIO
},
170 #endif /* HAVE_LCAPS */
174 /* Linux forms of capabilities methods */
175 /* convert zebras privileges to system capabilities */
176 static pset_t
*zcaps2sys(zebra_capabilities_t
*zcaps
, int num
)
179 int i
, j
= 0, count
= 0;
184 /* first count up how many system caps we have */
185 for (i
= 0; i
< num
; i
++)
186 count
+= cap_map
[zcaps
[i
]].num
;
188 if ((syscaps
= XCALLOC(MTYPE_PRIVS
, (sizeof(pset_t
) * num
))) == NULL
) {
189 fprintf(stderr
, "%s: could not allocate syscaps!", __func__
);
193 syscaps
->caps
= XCALLOC(MTYPE_PRIVS
, (sizeof(pvalue_t
) * count
));
195 if (!syscaps
->caps
) {
196 fprintf(stderr
, "%s: could not XCALLOC caps!", __func__
);
200 /* copy the capabilities over */
202 for (i
= 0; i
< num
; i
++)
203 for (j
= 0; j
< cap_map
[zcaps
[i
]].num
; j
++)
204 syscaps
->caps
[count
++] =
205 cap_map
[zcaps
[i
]].system_caps
[j
];
207 /* iterations above should be exact same as previous count, obviously..
209 syscaps
->num
= count
;
214 /* set or clear the effective capabilities to/from permitted */
215 int zprivs_change_caps(zebra_privs_ops_t op
)
217 cap_flag_value_t cflag
;
219 /* should be no possibility of being called without valid caps */
220 assert(zprivs_state
.syscaps_p
&& zprivs_state
.caps
);
221 if (!(zprivs_state
.syscaps_p
&& zprivs_state
.caps
))
224 if (op
== ZPRIVS_RAISE
)
226 else if (op
== ZPRIVS_LOWER
)
231 if (!cap_set_flag(zprivs_state
.caps
, CAP_EFFECTIVE
,
232 zprivs_state
.syscaps_p
->num
,
233 zprivs_state
.syscaps_p
->caps
, cflag
))
234 return cap_set_proc(zprivs_state
.caps
);
238 zebra_privs_current_t
zprivs_state_caps(void)
241 cap_flag_value_t val
;
243 /* should be no possibility of being called without valid caps */
244 assert(zprivs_state
.syscaps_p
&& zprivs_state
.caps
);
245 if (!(zprivs_state
.syscaps_p
&& zprivs_state
.caps
))
248 for (i
= 0; i
< zprivs_state
.syscaps_p
->num
; i
++) {
249 if (cap_get_flag(zprivs_state
.caps
,
250 zprivs_state
.syscaps_p
->caps
[i
], CAP_EFFECTIVE
,
254 "zprivs_state_caps: could not cap_get_flag, %s",
255 safe_strerror(errno
));
256 return ZPRIVS_UNKNOWN
;
259 return ZPRIVS_RAISED
;
261 return ZPRIVS_LOWERED
;
264 /** Release private cap state if allocated. */
265 static void zprivs_state_free_caps(void)
267 if (zprivs_state
.syscaps_p
) {
268 if (zprivs_state
.syscaps_p
->num
)
269 XFREE(MTYPE_PRIVS
, zprivs_state
.syscaps_p
->caps
);
271 XFREE(MTYPE_PRIVS
, zprivs_state
.syscaps_p
);
274 if (zprivs_state
.syscaps_i
) {
275 if (zprivs_state
.syscaps_i
->num
)
276 XFREE(MTYPE_PRIVS
, zprivs_state
.syscaps_i
->caps
);
278 XFREE(MTYPE_PRIVS
, zprivs_state
.syscaps_i
);
281 if (zprivs_state
.caps
) {
282 cap_free(zprivs_state
.caps
);
283 zprivs_state
.caps
= NULL
;
287 static void zprivs_caps_init(struct zebra_privs_t
*zprivs
)
289 /* Release allocated zcaps if this function was called before. */
290 zprivs_state_free_caps();
292 zprivs_state
.syscaps_p
= zcaps2sys(zprivs
->caps_p
, zprivs
->cap_num_p
);
293 zprivs_state
.syscaps_i
= zcaps2sys(zprivs
->caps_i
, zprivs
->cap_num_i
);
295 /* Tell kernel we want caps maintained across uid changes */
296 if (prctl(PR_SET_KEEPCAPS
, 1, 0, 0, 0) == -1) {
298 "privs_init: could not set PR_SET_KEEPCAPS, %s\n",
299 safe_strerror(errno
));
303 /* we have caps, we have no need to ever change back the original user
305 /* only change uid if we don't have the correct one */
306 if ((zprivs_state
.zuid
) && (zprivs_state
.zsuid
!= zprivs_state
.zuid
)) {
307 if (setreuid(zprivs_state
.zuid
, zprivs_state
.zuid
)) {
309 "zprivs_init (cap): could not setreuid, %s\n",
310 safe_strerror(errno
));
315 if (!(zprivs_state
.caps
= cap_init())) {
316 fprintf(stderr
, "privs_init: failed to cap_init, %s\n",
317 safe_strerror(errno
));
321 if (cap_clear(zprivs_state
.caps
)) {
322 fprintf(stderr
, "privs_init: failed to cap_clear, %s\n",
323 safe_strerror(errno
));
327 /* set permitted caps, if any */
328 if (zprivs_state
.syscaps_p
&& zprivs_state
.syscaps_p
->num
) {
329 cap_set_flag(zprivs_state
.caps
, CAP_PERMITTED
,
330 zprivs_state
.syscaps_p
->num
,
331 zprivs_state
.syscaps_p
->caps
, CAP_SET
);
334 /* set inheritable caps, if any */
335 if (zprivs_state
.syscaps_i
&& zprivs_state
.syscaps_i
->num
) {
336 cap_set_flag(zprivs_state
.caps
, CAP_INHERITABLE
,
337 zprivs_state
.syscaps_i
->num
,
338 zprivs_state
.syscaps_i
->caps
, CAP_SET
);
341 /* apply caps. CAP_EFFECTIVE is cleared. we'll raise the caps as
342 * and when, and only when, they are needed.
344 if (cap_set_proc(zprivs_state
.caps
)) {
346 char *current_caps_text
= NULL
;
347 char *wanted_caps_text
= NULL
;
349 fprintf(stderr
, "privs_init: initial cap_set_proc failed: %s\n",
350 safe_strerror(errno
));
352 current_caps
= cap_get_proc();
354 current_caps_text
= cap_to_text(current_caps
, NULL
);
355 cap_free(current_caps
);
358 wanted_caps_text
= cap_to_text(zprivs_state
.caps
, NULL
);
359 fprintf(stderr
, "Wanted caps: %s\n",
360 wanted_caps_text
? wanted_caps_text
: "???");
361 fprintf(stderr
, "Have caps: %s\n",
362 current_caps_text
? current_caps_text
: "???");
363 if (current_caps_text
)
364 cap_free(current_caps_text
);
365 if (wanted_caps_text
)
366 cap_free(wanted_caps_text
);
371 /* set methods for the caller to use */
372 zprivs
->change
= zprivs_change_caps
;
373 zprivs
->current_state
= zprivs_state_caps
;
376 static void zprivs_caps_terminate(void)
378 /* Clear all capabilities, if we have any. */
379 if (zprivs_state
.caps
)
380 cap_clear(zprivs_state
.caps
);
384 /* and boom, capabilities are gone forever */
385 if (cap_set_proc(zprivs_state
.caps
)) {
386 fprintf(stderr
, "privs_terminate: cap_set_proc failed, %s",
387 safe_strerror(errno
));
391 zprivs_state_free_caps();
393 #else /* !HAVE_LCAPS */
394 #error "no Linux capabilities, dazed and confused..."
395 #endif /* HAVE_LCAPS */
396 #endif /* HAVE_CAPABILITIES */
398 int zprivs_change_uid(zebra_privs_ops_t op
)
400 if (zprivs_state
.zsuid
== zprivs_state
.zuid
)
402 if (op
== ZPRIVS_RAISE
)
403 return seteuid(zprivs_state
.zsuid
);
404 else if (op
== ZPRIVS_LOWER
)
405 return seteuid(zprivs_state
.zuid
);
410 zebra_privs_current_t
zprivs_state_uid(void)
412 return ((zprivs_state
.zuid
== geteuid()) ? ZPRIVS_LOWERED
416 int zprivs_change_null(zebra_privs_ops_t op
)
421 zebra_privs_current_t
zprivs_state_null(void)
423 return zprivs_null_state
;
426 #ifndef HAVE_GETGROUPLIST
427 /* Solaris 11 has no getgrouplist() */
428 static int getgrouplist(const char *user
, gid_t group
, gid_t
*groups
,
440 while ((grp
= getgrent())) {
441 if (grp
->gr_gid
== group
)
443 for (usridx
= 0; grp
->gr_mem
[usridx
] != NULL
; usridx
++)
444 if (!strcmp(grp
->gr_mem
[usridx
], user
)) {
446 groups
[pos
] = grp
->gr_gid
;
453 ret
= (pos
<= *ngroups
) ? pos
: -1;
457 #endif /* HAVE_GETGROUPLIST */
460 * Helper function that locates a refcounting object to use: a process-wide
461 * object or a per-pthread object.
463 static struct zebra_privs_refs_t
*get_privs_refs(struct zebra_privs_t
*privs
)
465 struct zebra_privs_refs_t
*temp
, *refs
= NULL
;
468 if (privs_per_process
)
469 refs
= &(privs
->process_refs
);
471 /* Locate - or create - the object for the current pthread. */
472 tid
= pthread_self();
474 STAILQ_FOREACH(temp
, &(privs
->thread_refs
), entry
) {
475 if (pthread_equal(temp
->tid
, tid
)) {
481 /* Need to create a new refcounting object. */
483 refs
= XCALLOC(MTYPE_PRIVS
,
484 sizeof(struct zebra_privs_refs_t
));
486 STAILQ_INSERT_TAIL(&(privs
->thread_refs
), refs
, entry
);
493 struct zebra_privs_t
*_zprivs_raise(struct zebra_privs_t
*privs
,
494 const char *funcname
)
496 int save_errno
= errno
;
497 struct zebra_privs_refs_t
*refs
;
503 * Serialize 'raise' operations; particularly important for
504 * OSes where privs are process-wide.
506 frr_with_mutex (&(privs
->mutex
)) {
507 /* Locate ref-counting object to use */
508 refs
= get_privs_refs(privs
);
510 if (++(refs
->refcount
) == 1) {
512 if (privs
->change(ZPRIVS_RAISE
)) {
513 zlog_err("%s: Failed to raise privileges (%s)",
514 funcname
, safe_strerror(errno
));
517 refs
->raised_in_funcname
= funcname
;
524 void _zprivs_lower(struct zebra_privs_t
**privs
)
526 int save_errno
= errno
;
527 struct zebra_privs_refs_t
*refs
;
532 /* Serialize 'lower privs' operation - particularly important
533 * when OS privs are process-wide.
535 frr_with_mutex (&(*privs
)->mutex
) {
536 refs
= get_privs_refs(*privs
);
538 if (--(refs
->refcount
) == 0) {
540 if ((*privs
)->change(ZPRIVS_LOWER
)) {
541 zlog_err("%s: Failed to lower privileges (%s)",
542 refs
->raised_in_funcname
,
543 safe_strerror(errno
));
546 refs
->raised_in_funcname
= NULL
;
553 void zprivs_preinit(struct zebra_privs_t
*zprivs
)
555 struct passwd
*pwentry
= NULL
;
556 struct group
*grentry
= NULL
;
559 fprintf(stderr
, "zprivs_init: called with NULL arg!\n");
563 pthread_mutex_init(&(zprivs
->mutex
), NULL
);
564 zprivs
->process_refs
.refcount
= 0;
565 zprivs
->process_refs
.raised_in_funcname
= NULL
;
566 STAILQ_INIT(&zprivs
->thread_refs
);
568 if (zprivs
->vty_group
) {
569 /* in a "NULL" setup, this is allowed to fail too, but still
571 if ((grentry
= getgrnam(zprivs
->vty_group
)))
572 zprivs_state
.vtygrp
= grentry
->gr_gid
;
574 zprivs_state
.vtygrp
= (gid_t
)-1;
578 if (!(zprivs
->user
|| zprivs
->group
|| zprivs
->cap_num_p
579 || zprivs
->cap_num_i
)) {
580 zprivs
->change
= zprivs_change_null
;
581 zprivs
->current_state
= zprivs_state_null
;
586 if ((pwentry
= getpwnam(zprivs
->user
)) == NULL
) {
587 /* cant use log.h here as it depends on vty */
589 "privs_init: could not lookup user %s\n",
594 zprivs_state
.zuid
= pwentry
->pw_uid
;
595 zprivs_state
.zgid
= pwentry
->pw_gid
;
601 if ((grentry
= getgrnam(zprivs
->group
)) == NULL
) {
603 "privs_init: could not lookup group %s\n",
608 zprivs_state
.zgid
= grentry
->gr_gid
;
612 struct zebra_privs_t
*lib_privs
;
614 void zprivs_init(struct zebra_privs_t
*zprivs
)
616 gid_t groups
[NGROUPS_MAX
] = {};
621 if (!(zprivs
->user
|| zprivs
->group
|| zprivs
->cap_num_p
622 || zprivs
->cap_num_i
))
628 ngroups
= array_size(groups
);
629 if (getgrouplist(zprivs
->user
, zprivs_state
.zgid
, groups
,
632 /* cant use log.h here as it depends on vty */
634 "privs_init: could not getgrouplist for user %s\n",
640 if (zprivs
->vty_group
)
641 /* Add the vty_group to the supplementary groups so it can be chowned to
644 if (zprivs_state
.vtygrp
== (gid_t
)-1) {
646 "privs_init: could not lookup vty group %s\n",
651 for (i
= 0; i
< ngroups
; i
++)
652 if (groups
[i
] == zprivs_state
.vtygrp
) {
659 "privs_init: user(%s) is not part of vty group specified(%s)\n",
660 zprivs
->user
, zprivs
->vty_group
);
663 if (i
>= ngroups
&& ngroups
< (int)array_size(groups
)) {
664 groups
[i
] = zprivs_state
.vtygrp
;
668 zprivs_state
.zsuid
= geteuid(); /* initial uid */
669 /* add groups only if we changed uid - otherwise skip */
670 if ((ngroups
) && (zprivs_state
.zsuid
!= zprivs_state
.zuid
)) {
671 if (setgroups(ngroups
, groups
)) {
672 fprintf(stderr
, "privs_init: could not setgroups, %s\n",
673 safe_strerror(errno
));
678 /* change gid only if we changed uid - otherwise skip */
679 if ((zprivs_state
.zgid
) && (zprivs_state
.zsuid
!= zprivs_state
.zuid
)) {
680 /* change group now, forever. uid we do later */
681 if (setregid(zprivs_state
.zgid
, zprivs_state
.zgid
)) {
682 fprintf(stderr
, "zprivs_init: could not setregid, %s\n",
683 safe_strerror(errno
));
688 #ifdef HAVE_CAPABILITIES
689 zprivs_caps_init(zprivs
);
692 * If we have initialized the system with no requested
693 * capabilities, change will not have been set
694 * to anything by zprivs_caps_init, As such
695 * we should make sure that when we attempt
696 * to raize privileges that we actually have
697 * a do nothing function to call instead of a
701 zprivs
->change
= zprivs_change_null
;
703 #else /* !HAVE_CAPABILITIES */
704 /* we dont have caps. we'll need to maintain rid and saved uid
705 * and change euid back to saved uid (who we presume has all necessary
706 * privileges) whenever we are asked to raise our privileges.
708 * This is not worth that much security wise, but all we can do.
710 zprivs_state
.zsuid
= geteuid();
711 /* only change uid if we don't have the correct one */
712 if ((zprivs_state
.zuid
) && (zprivs_state
.zsuid
!= zprivs_state
.zuid
)) {
713 if (setreuid(-1, zprivs_state
.zuid
)) {
715 "privs_init (uid): could not setreuid, %s\n",
716 safe_strerror(errno
));
721 zprivs
->change
= zprivs_change_uid
;
722 zprivs
->current_state
= zprivs_state_uid
;
723 #endif /* HAVE_CAPABILITIES */
726 void zprivs_terminate(struct zebra_privs_t
*zprivs
)
728 struct zebra_privs_refs_t
*refs
;
733 fprintf(stderr
, "%s: no privs struct given, terminating",
738 #ifdef HAVE_CAPABILITIES
739 if (zprivs
->user
|| zprivs
->group
|| zprivs
->cap_num_p
740 || zprivs
->cap_num_i
)
741 zprivs_caps_terminate();
742 #else /* !HAVE_CAPABILITIES */
743 /* only change uid if we don't have the correct one */
744 if ((zprivs_state
.zuid
) && (zprivs_state
.zsuid
!= zprivs_state
.zuid
)) {
745 if (setreuid(zprivs_state
.zuid
, zprivs_state
.zuid
)) {
747 "privs_terminate: could not setreuid, %s",
748 safe_strerror(errno
));
752 #endif /* HAVE_LCAPS */
754 while ((refs
= STAILQ_FIRST(&(zprivs
->thread_refs
))) != NULL
) {
755 STAILQ_REMOVE_HEAD(&(zprivs
->thread_refs
), entry
);
756 XFREE(MTYPE_PRIVS
, refs
);
759 zprivs
->change
= zprivs_change_null
;
760 zprivs
->current_state
= zprivs_state_null
;
761 zprivs_null_state
= ZPRIVS_LOWERED
;
765 void zprivs_get_ids(struct zprivs_ids_t
*ids
)
768 ids
->uid_priv
= getuid();
769 (zprivs_state
.zuid
) ? (ids
->uid_normal
= zprivs_state
.zuid
)
770 : (ids
->uid_normal
= (uid_t
)-1);
771 (zprivs_state
.zgid
) ? (ids
->gid_normal
= zprivs_state
.zgid
)
772 : (ids
->gid_normal
= (uid_t
)-1);
773 (zprivs_state
.vtygrp
) ? (ids
->gid_vty
= zprivs_state
.vtygrp
)
774 : (ids
->gid_vty
= (uid_t
)-1);