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