]> git.proxmox.com Git - mirror_frr.git/blob - lib/privs.c
Paul forgot probably to commit privs.[c|h] changes. Had to reorder includes
[mirror_frr.git] / lib / privs.c
1 /*
2 * Zebra privileges.
3 *
4 * Copyright (C) 2003 Paul Jakma.
5 *
6 * This file is part of GNU Zebra.
7 *
8 * GNU Zebra is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * GNU Zebra is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with GNU Zebra; see the file COPYING. If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 * 02111-1307, USA.
22 */
23
24 #include <zebra.h>
25 #include "log.h"
26 #include "privs.h"
27 #include "memory.h"
28
29 /* internal privileges state */
30 static struct _zprivs_t
31 {
32 #ifdef HAVE_LCAPS
33 cap_t caps; /* caps storage */
34 cap_value_t *syscaps_p; /* system permitted caps */
35 cap_value_t *syscaps_i; /* system inheritable caps */
36 int sys_num_p; /* number of syscaps_p */
37 int sys_num_i; /* number of syscaps_i */
38 #endif /* HAVE_LCAPS */
39 uid_t zuid, /* uid to run as */
40 zsuid; /* saved uid */
41 gid_t zgid; /* gid to run as */
42 gid_t vtygrp; /* gid for vty sockets */
43 } zprivs_state;
44
45 /* externally exported but not directly accessed functions */
46 #ifdef HAVE_LCAPS
47 int zprivs_change_caps (zebra_privs_ops_t);
48 zebra_privs_current_t zprivs_state_caps (void);
49 #endif /* HAVE_LCAPS */
50 int zprivs_change_uid (zebra_privs_ops_t);
51 zebra_privs_current_t zprivs_state_uid (void);
52 int zprivs_change_null (zebra_privs_ops_t);
53 zebra_privs_current_t zprivs_state_null (void);
54 void zprivs_terminate (void);
55
56 #ifdef HAVE_LCAPS
57 static int
58 cap_map [ZCAP_MAX] =
59 {
60 [ZCAP_SETGID] = CAP_SETGID,
61 [ZCAP_SETUID] = CAP_SETUID,
62 [ZCAP_BIND] = CAP_NET_BIND_SERVICE,
63 [ZCAP_BROADCAST] = CAP_NET_BROADCAST,
64 [ZCAP_ADMIN] = CAP_NET_ADMIN,
65 [ZCAP_RAW] = CAP_NET_RAW,
66 [ZCAP_CHROOT] = CAP_SYS_CHROOT,
67 [ZCAP_NICE] = CAP_SYS_NICE,
68 [ZCAP_PTRACE] = CAP_SYS_PTRACE,
69 [ZCAP_DAC_OVERRIDE] = CAP_DAC_OVERRIDE,
70 [ZCAP_READ_SEARCH] = CAP_DAC_READ_SEARCH,
71 [ZCAP_SYS_ADMIN] = CAP_SYS_ADMIN,
72 [ZCAP_FOWNER] = CAP_FOWNER
73 };
74
75 /* convert zebras privileges to system capabilities */
76 static cap_value_t *
77 zcaps2sys (zebra_capabilities_t *zcaps, int num)
78 {
79 cap_value_t *syscaps;
80 int i;
81
82 if (!num)
83 return NULL;
84
85 syscaps = (cap_value_t *) XCALLOC ( MTYPE_PRIVS,
86 (sizeof(cap_value_t) * num) );
87 if (!syscaps)
88 {
89 zlog_err ("zcap2sys: could not XCALLOC!");
90 return NULL;
91 }
92
93 for (i=0; i < num; i++)
94 {
95 syscaps[i] = cap_map[zcaps[i]];
96 }
97
98 return syscaps;
99 }
100
101 /* set or clear the effective capabilities to/from permitted */
102 int
103 zprivs_change_caps (zebra_privs_ops_t op)
104 {
105 cap_flag_value_t cflag;
106
107 if (op == ZPRIVS_RAISE)
108 cflag = CAP_SET;
109 else if (op == ZPRIVS_LOWER)
110 cflag = CAP_CLEAR;
111 else
112 return -1;
113
114 if ( !cap_set_flag (zprivs_state.caps, CAP_EFFECTIVE,
115 zprivs_state.sys_num_p, zprivs_state.syscaps_p, cflag))
116 return cap_set_proc (zprivs_state.caps);
117 return -1;
118 }
119
120 zebra_privs_current_t
121 zprivs_state_caps (void)
122 {
123 int i;
124 cap_flag_value_t val;
125
126 for (i=0; i < zprivs_state.sys_num_p; i++)
127 {
128 if ( cap_get_flag (zprivs_state.caps, zprivs_state.syscaps_p[i],
129 CAP_EFFECTIVE, &val) )
130 zlog_warn ("zprivs_state_caps: could not cap_get_flag, %s",
131 strerror (errno) );
132 if (val == CAP_SET)
133 return ZPRIVS_RAISED;
134 }
135 return ZPRIVS_LOWERED;
136 }
137
138 #endif /* HAVE_LCAPS */
139
140 int
141 zprivs_change_uid (zebra_privs_ops_t op)
142 {
143
144 if (op == ZPRIVS_RAISE)
145 return seteuid (zprivs_state.zsuid);
146 else if (op == ZPRIVS_LOWER)
147 return seteuid (zprivs_state.zuid);
148 else
149 return -1;
150 }
151
152 zebra_privs_current_t
153 zprivs_state_uid (void)
154 {
155 return ( (zprivs_state.zuid == geteuid()) ? ZPRIVS_LOWERED : ZPRIVS_RAISED);
156 }
157
158 int
159 zprivs_change_null (zebra_privs_ops_t op)
160 {
161 return 0;
162 }
163
164 zebra_privs_current_t
165 zprivs_state_null (void)
166 {
167 return ZPRIVS_RAISED;
168 }
169
170
171 void
172 zprivs_init(struct zebra_privs_t *zprivs)
173 {
174 struct passwd *pwentry = NULL;
175 struct group *grentry = NULL;
176
177 if (!zprivs)
178 {
179 zlog_err ("zprivs_init: called with NULL arg!");
180 exit (1);
181 }
182
183 /* NULL privs */
184 if (! (zprivs->user || zprivs->group
185 || zprivs->cap_num_p || zprivs->cap_num_i) )
186 {
187 zprivs->change = zprivs_change_null;
188 zprivs->current_state = zprivs_state_null;
189 return;
190 }
191
192 if (zprivs->user)
193 {
194 if ( (pwentry = getpwnam (zprivs->user)) )
195 {
196 zprivs_state.zuid = pwentry->pw_uid;
197 }
198 else
199 {
200 zlog_err ("privs_init: could not lookup supplied user");
201 exit (1);
202 }
203 }
204
205 grentry = NULL;
206
207 if (zprivs->vty_group)
208 /* Add the vty_group to the supplementary groups so it can be chowned to */
209 {
210 if ( (grentry = getgrnam (zprivs->vty_group)) )
211 {
212 zprivs_state.vtygrp = grentry->gr_gid;
213 if ( setgroups (1, &zprivs_state.vtygrp) )
214 {
215 zlog_err ("privs_init: could not setgroups, %s",
216 strerror (errno) );
217 exit (1);
218 }
219 }
220 else
221 {
222 zlog_err ("privs_init: could not lookup supplied user");
223 exit (1);
224 }
225 }
226
227 if (zprivs->group)
228 {
229 if ( (grentry = getgrnam (zprivs->group)) )
230 {
231 zprivs_state.zgid = grentry->gr_gid;
232 }
233 else
234 {
235 zlog_err ("privs_init: could not lookup supplied user");
236 exit (1);
237 }
238 /* change group now, forever. uid we do later */
239 if ( setregid (zprivs_state.zgid, zprivs_state.zgid) )
240 {
241 zlog_err ("zprivs_init: could not setregid, %s",
242 strerror (errno) );
243 exit (1);
244 }
245 }
246
247 #ifdef HAVE_LCAPS
248 zprivs_state.syscaps_p = zcaps2sys (zprivs->caps_p, zprivs->cap_num_p);
249 zprivs_state.sys_num_p = zprivs->cap_num_p;
250 zprivs_state.syscaps_i = zcaps2sys (zprivs->caps_i, zprivs->cap_num_i);
251 zprivs_state.sys_num_i = zprivs->cap_num_i;
252
253 /* Tell kernel we want caps maintained across uid changes */
254 if ( prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1 )
255 {
256 zlog_err("privs_init: could not set PR_SET_KEEPCAPS, %s",
257 strerror (errno) );
258 exit(1);
259 }
260
261 if ( !zprivs_state.syscaps_p )
262 {
263 zlog_warn ("privs_init: capabilities enabled, but no capabilities supplied");
264 }
265
266 if ( !(zprivs_state.caps = cap_init()) )
267 {
268 zlog_err ("privs_init: failed to cap_init, %s", strerror (errno) );
269 exit (1);
270 }
271
272 /* we have caps, we have no need to ever change back the original user */
273 if (zprivs_state.zuid)
274 {
275 if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) )
276 {
277 zlog_err ("zprivs_init (cap): could not setreuid, %s",
278 strerror (errno) );
279 exit (1);
280 }
281 }
282
283 if ( cap_clear (zprivs_state.caps) )
284 {
285 zlog_err ("privs_init: failed to cap_clear, %s", strerror (errno));
286 exit (1);
287 }
288
289 /* set permitted caps */
290 cap_set_flag(zprivs_state.caps, CAP_PERMITTED,
291 zprivs_state.sys_num_p, zprivs_state.syscaps_p, CAP_SET);
292 cap_set_flag(zprivs_state.caps, CAP_EFFECTIVE,
293 zprivs_state.sys_num_p, zprivs_state.syscaps_p, CAP_SET);
294
295 /* set inheritable caps, if any */
296 if (zprivs_state.sys_num_i)
297 {
298 cap_set_flag(zprivs_state.caps, CAP_INHERITABLE,
299 zprivs_state.sys_num_i, zprivs_state.syscaps_i, CAP_SET);
300 }
301
302 /* apply caps. CAP_EFFECTIVE is cleared. we'll raise the caps as
303 * and when, and only when, they are needed.
304 */
305 if ( cap_set_proc (zprivs_state.caps) )
306 {
307 zlog_err ("privs_init: initial cap_set_proc failed");
308 exit (1);
309 }
310
311 /* set methods for the caller to use */
312 zprivs->change = zprivs_change_caps;
313 zprivs->current_state = zprivs_state_caps;
314
315 #elif !defined(HAVE_LCAPS)
316 /* we dont have caps. we'll need to maintain rid and saved uid
317 * and change euid back to saved uid (who we presume has all neccessary
318 * privileges) whenever we are asked to raise our privileges.
319 */
320 zprivs_state.zsuid = geteuid();
321 if ( zprivs_state.zuid )
322 {
323 if ( setreuid (-1, zprivs_state.zuid) )
324 {
325 zlog_err ("privs_init (uid): could not setreuid, %s", strerror (errno));
326 exit (1);
327 }
328 }
329
330 zprivs->change = zprivs_change_uid;
331 zprivs->current_state = zprivs_state_uid;
332 #endif /* HAVE_LCAPS */
333 }
334
335 void
336 zprivs_terminate (void)
337 {
338
339 #ifdef HAVE_LCAPS
340
341 if (zprivs_state.caps)
342 cap_clear (zprivs_state.caps);
343
344 if ( cap_set_proc (zprivs_state.caps) )
345 {
346 zlog_err ("privs_terminate: cap_set_proc failed, %s",
347 strerror (errno) );
348 exit (1);
349 }
350
351 if (zprivs_state.sys_num_p)
352 XFREE (MTYPE_PRIVS, zprivs_state.syscaps_p);
353
354 if (zprivs_state.sys_num_i)
355 XFREE (MTYPE_PRIVS, zprivs_state.syscaps_i);
356
357 cap_free (zprivs_state.caps);
358 #else
359 if (zprivs_state.zuid)
360 {
361 if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) )
362 {
363 zlog_err ("privs_terminate: could not setreuid, %s",
364 strerror (errno) );
365 exit (1);
366 }
367 }
368 #endif /* HAVE_LCAPS */
369 return;
370 }
371
372 void
373 zprivs_get_ids(struct zprivs_ids_t *ids)
374 {
375
376 ids->uid_priv = getuid();
377 (zprivs_state.zuid) ? (ids->uid_normal = zprivs_state.zuid)
378 : (ids->uid_normal = -1);
379 (zprivs_state.zgid) ? (ids->gid_normal = zprivs_state.zgid)
380 : (ids->gid_normal = -1);
381 (zprivs_state.vtygrp) ? (ids->gid_vty = zprivs_state.vtygrp)
382 : (ids->gid_vty = -1);
383
384 return;
385 }