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