blob: 174618a021f2df08c398a5ba00e9775004397692 [file] [log] [blame]
paul01245822003-05-20 01:22:17 +00001/*
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
30/* internal privileges state */
31static struct _zprivs_t
32{
33#ifdef HAVE_LCAPS
34 cap_t caps; /* caps storage */
35 cap_value_t *syscaps_p; /* system permitted caps */
36 cap_value_t *syscaps_i; /* system inheritable caps */
37 int sys_num_p; /* number of syscaps_p */
38 int sys_num_i; /* number of syscaps_i */
39#endif /* HAVE_LCAPS */
40 uid_t zuid, /* uid to run as */
41 zsuid; /* saved uid */
42 gid_t zgid; /* gid to run as */
43} zprivs_state;
44
45/* externally exported but not directly accessed functions */
46#ifdef HAVE_LCAPS
47int zprivs_change_caps (zebra_privs_ops_t);
48zebra_privs_current_t zprivs_state_caps (void);
49#endif /* HAVE_LCAPS */
50int zprivs_change_uid (zebra_privs_ops_t);
51zebra_privs_current_t zprivs_state_uid (void);
52int zprivs_change_null (zebra_privs_ops_t);
53zebra_privs_current_t zprivs_state_null (void);
54void zprivs_terminate (void);
55
56#ifdef HAVE_LCAPS
57static int
58cap_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};
70
71static cap_value_t cap_setuid_value [] = { CAP_SETUID };
72
73/* convert zebras privileges to system capabilities */
74static cap_value_t *
75zcaps2sys (zebra_capabilities_t *zcaps, int num)
76{
77 cap_value_t *syscaps;
78 int i;
79
80 if (!num)
81 return NULL;
82
83 syscaps = (cap_value_t *) XCALLOC ( MTYPE_PRIVS,
84 (sizeof(cap_value_t) * num) );
85 if (!syscaps)
86 {
87 zlog_err ("zcap2sys: could not XCALLOC!");
88 return NULL;
89 }
90
91 for (i=0; i < num; i++)
92 {
93 syscaps[i] = cap_map[zcaps[i]];
94 }
95
96 return syscaps;
97}
98
99/* set or clear the effective capabilities to/from permitted */
100int
101zprivs_change_caps (zebra_privs_ops_t op)
102{
103 cap_flag_value_t cflag;
104
105 if (op == ZPRIVS_RAISE)
106 cflag = CAP_SET;
107 else if (op == ZPRIVS_LOWER)
108 cflag = CAP_CLEAR;
109 else
110 return -1;
111
112 if ( !cap_set_flag (zprivs_state.caps, CAP_EFFECTIVE,
113 zprivs_state.sys_num_p, zprivs_state.syscaps_p, cflag))
114 return cap_set_proc (zprivs_state.caps);
115 return -1;
116}
117
118zebra_privs_current_t
119zprivs_state_caps (void)
120{
121 int i;
122 cap_flag_t flag;
123 cap_flag_value_t val;
124
125 for (i=0; i < zprivs_state.syscaps_num_p; i++)
126 {
127 if ( cap_get_flag (zprivs_state.caps, zprivs_state.syscaps_p[i],
128 CAP_EFFECTIVE, &val) )
129 zlog_warn ("zprivs_state_caps: could not cap_get_flag, %s",
130 strerror (errno) );
131 if (val == CAP_SET)
132 return CAP_RAISED;
133 }
134 return ZPRIVS_LOWERED;
135}
136
137#endif /* HAVE_LCAPS */
138
139int
140zprivs_change_uid (zebra_privs_ops_t op)
141{
142 if (op == ZPRIVS_RAISE)
143 return seteuid (zprivs_state.zsuid);
144 else if (op == ZPRIVS_LOWER)
145 return seteuid (zprivs_state.zuid);
146 else
147 return -1;
148}
149
150zebra_privs_current_t
151zprivs_state_uid (void)
152{
153 return ( (zprivs_state.zuid == geteuid()) ? ZPRIVS_LOWERED : ZPRIVS_RAISED);
154}
155
156int
157zprivs_change_null (zebra_privs_ops_t op)
158{
159 return 0;
160}
161
162zebra_privs_current_t
163zprivs_state_null (void)
164{
165 return ZPRIVS_RAISED;
166}
167
168
169void
170zprivs_init(struct zebra_privs_t *zprivs)
171{
172 struct passwd *pwentry = NULL;
173 struct group *grentry = NULL;
174
175 /* NULL privs */
176 if (! (zprivs->user || zprivs->group
177 || zprivs->cap_num_p || zprivs->cap_num_i) )
178 {
179 zprivs->change = zprivs_change_null;
180 zprivs->current_state = zprivs_state_null;
181 return;
182 }
183
184 if (zprivs->user)
185 {
186 if ( (pwentry = getpwnam (zprivs->user)) )
187 zprivs_state.zuid = pwentry->pw_uid;
188 else
189 {
190 zlog_err ("privs_init: could not lookup supplied user");
191 exit (1);
192 }
193 }
194
195 if (zprivs->group)
196 {
197 if ( (grentry = getgrnam (zprivs->user)) )
198 zprivs_state.zgid = pwentry->pw_uid;
199 else
200 {
201 zlog_err ("privs_init: could not lookup supplied user");
202 exit (1);
203 }
204
205 /* change group now, forever. uid we do later */
206 if ( setregid (zprivs_state.zgid, zprivs_state.zgid) )
207 {
208 zlog_err ("privs_init: could not setregid");
209 exit (1);
210 }
211 }
212
213#ifdef HAVE_LCAPS
214 zprivs_state.syscaps_p = zcaps2sys (zprivs->caps_p, zprivs->cap_num_p);
215 zprivs_state.sys_num_p = zprivs->cap_num_p;
216 zprivs_state.syscaps_i = zcaps2sys (zprivs->caps_i, zprivs->cap_num_i);
217 zprivs_state.sys_num_i = zprivs->cap_num_i;
218
219 /* Tell kernel we want caps maintained across uid changes */
220 if ( prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1 )
221 {
222 zlog_err("privs_init: could not set PR_SET_KEEPCAPS, %s"
223 strerror (errno) );
224 exit(1);
225 }
226
227 if ( !zprivs_state.syscaps_p )
228 {
229 zlog_warn ("privs_init: capabilities enabled, but no capabilities supplied");
230 }
231
232 if ( !(zprivs_state.caps = cap_init()) )
233 {
234 zlog_err ("privs_init: failed to cap_init, %s" strerror (errno) );
235 exit (1);
236 }
237
238 if ( cap_clear (zprivs_state.caps) )
239 {
240 zlog_err ("privs_init: failed to cap_clear, %s" strerror (errno));
241 exit (1);
242 }
243
244 /* set permitted caps */
245 cap_set_flag(zprivs_state.caps, CAP_PERMITTED,
246 zprivs_state.sys_num_p, zprivs_state.syscaps_p, CAP_SET);
247 cap_set_flag(zprivs_state.caps, CAP_EFFECTIVE,
248 zprivs_state.sys_num_p, zprivs_state.syscaps_p, CAP_SET);
249
250 /* still need CAP_SETUID for the moment */
251 cap_set_flag(zprivs_state.caps, CAP_PERMITTED,
252 1, cap_setuid_value, CAP_SET);
253 cap_set_flag(zprivs_state.caps, CAP_EFFECTIVE,
254 1, cap_setuid_value, CAP_SET);
255
256 /* set inheritable caps, if any */
257 if (zprivs_state.sys_num_i)
258 {
259 cap_set_flag(zprivs_state.caps, CAP_INHERITABLE,
260 zprivs_state.sys_num_i, zprivs_state.syscaps_i, CAP_SET);
261 }
262
263 /* apply caps. CAP_EFFECTIVE is clear bar cap_setuid_value.
264 * we'll raise the caps as and when, and only when, they are needed.
265 */
266 if ( cap_set_proc (zprivs_state.caps) )
267 {
268 zlog_err ("privs_init: initial cap_set_proc failed");
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 ("privs_init (cap): could not setreuid: %s", strerror (errno) );
278 exit (1);
279 }
280 }
281 */
282
283 /* No more need for cap_setuid_value */
284 cap_set_flag(zprivs_state.caps, CAP_PERMITTED,
285 1, cap_setuid_value, CAP_CLEAR);
286 cap_set_flag(zprivs_state.caps, CAP_EFFECTIVE,
287 1, cap_setuid_value, CAP_CLEAR);
288 if ( cap_set_proc (zprivs_state.caps) )
289 {
290 zlog_err ("privs_init: cap_set_proc failed to clear cap_setuid, %s"
291 strerror (errno) );
292 exit (1);
293 }
294
295 zprivs->change = zprivs_change_caps;
296 zprivs->current_state = zprivs_state_caps;
297
298#elif !defined(HAVE_LCAPS)
299 /* we dont have caps. we'll need to maintain rid and saved uid
300 * and change euid back to saved uid (who we presume has all neccessary
301 * privileges) whenever we are asked to raise our privileges.
302 */
303 zprivs_state.zsuid = geteuid();
304 if ( zprivs_state.zuid )
305 {
306 if ( setreuid (-1, zprivs_state.zuid) )
307 {
308 zlog_err ("privs_init (uid): could not setreuid: %s", strerror (errno));
309 exit (1);
310 }
311 }
312
313 zprivs->change = zprivs_change_uid;
314 zprivs->current_state = zprivs_state_uid;
315#endif /* HAVE_LCAPS */
316}
317
318void
319zprivs_terminate (void)
320{
321#ifdef HAVE_LCAPS
322 if (zprivs_state)
323 cap_clear (zprivs_state.caps);
324
325 if ( cap_set_proc (zprivs_state.caps) )
326 {
327 zlog_err ("privs_terminate: cap_set_proc failed, %s"
328 strerror (errno) );
329 exit (1);
330 }
331
332 if (zprivs_state.syscaps_num_p)
333 XFREE (MTYPE_PRIVS, zprivs_state.syscaps_p);
334
335 if (zprivs_state.syscaps_num_i)
336 XFREE (MTYPE_PRIVS, zprivs_state.syscaps_i);
337
338 cap_free (zprivs_state.caps);
339#else
340 if (zprivs_state.zuid)
341 {
342 if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) )
343 {
344 zlog_err ("privs_terminate: could not setreuid: %s",
345 strerror (errno) );
346 exit (1);
347 }
348 }
349#endif /* HAVE_LCAPS */
350 return;
351}