Annotation of embedaddon/strongswan/src/libstrongswan/utils/capabilities.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2012-2015 Tobias Brunner
3: * HSR Hochschule fuer Technik Rapperswil
4: * Copyright (C) 2012 Martin Willi
5: * Copyright (C) 2012 revosec AG
6: *
7: * This program is free software; you can redistribute it and/or modify it
8: * under the terms of the GNU General Public License as published by the
9: * Free Software Foundation; either version 2 of the License, or (at your
10: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11: *
12: * This program is distributed in the hope that it will be useful, but
13: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15: * for more details.
16: */
17:
18: #include "capabilities.h"
19:
20: #include <utils/debug.h>
21:
22: #include <errno.h>
23: #include <string.h>
24: #include <sys/types.h>
25: #include <unistd.h>
26:
27: #ifndef WIN32
28: #include <pwd.h>
29: #include <grp.h>
30: #ifdef HAVE_PRCTL
31: # include <sys/prctl.h>
32: #endif /* HAVE_PRCTL */
33:
34: #if !defined(HAVE_GETPWNAM_R) || \
35: !defined(HAVE_GETGRNAM_R) || \
36: !defined(HAVE_GETPWUID_R)
37: # include <threading/mutex.h>
38: # define EMULATE_R_FUNCS
39: #endif
40: #endif /* !WIN32 */
41:
42: typedef struct private_capabilities_t private_capabilities_t;
43:
44: /**
45: * Private data of an capabilities_t object.
46: */
47: struct private_capabilities_t {
48:
49: /**
50: * Public capabilities_t interface.
51: */
52: capabilities_t public;
53:
54: /**
55: * user ID to switch during rights dropping
56: */
57: uid_t uid;
58:
59: /**
60: * group ID to switch during rights dropping
61: */
62: gid_t gid;
63:
64: /**
65: * capabilities to keep
66: */
67: #ifdef CAPABILITIES_LIBCAP
68: cap_t caps;
69: #endif /* CAPABILITIES_LIBCAP */
70: #ifdef CAPABILITIES_NATIVE
71: struct __user_cap_data_struct caps[2];
72: #endif /* CAPABILITIES_NATIVE */
73:
74: #ifdef EMULATE_R_FUNCS
75: /**
76: * mutex to emulate get(pw|gr)nam_r functions
77: */
78: mutex_t *mutex;
79: #endif
80: };
81:
82: #ifndef WIN32
83:
84: /**
85: * Returns TRUE if the current process/user is member of the given group
86: */
87: static bool has_group(gid_t group)
88: {
89: gid_t *groups;
90: long ngroups, i;
91: bool found = FALSE;
92:
93: if (group == getegid())
94: { /* it's unspecified if this is part of the list below or not */
95: return TRUE;
96: }
97: ngroups = sysconf(_SC_NGROUPS_MAX);
98: if (ngroups == -1)
99: {
100: DBG1(DBG_LIB, "getting groups for current process failed: %s",
101: strerror(errno));
102: return FALSE;
103: }
104: groups = calloc(ngroups + 1, sizeof(gid_t));
105: ngroups = getgroups(ngroups, groups);
106: if (ngroups == -1)
107: {
108: DBG1(DBG_LIB, "getting groups for current process failed: %s",
109: strerror(errno));
110: free(groups);
111: return FALSE;
112: }
113: for (i = 0; i < ngroups; i++)
114: {
115: if (group == groups[i])
116: {
117: found = TRUE;
118: break;
119: }
120: }
121: free(groups);
122: return found;
123: }
124:
125: /**
126: * Verify that the current process has the given capability
127: */
128: static bool has_capability(private_capabilities_t *this, u_int cap,
129: bool *ignore)
130: {
131: if (cap == CAP_CHOWN)
132: { /* if new files/UNIX sockets are created they should be owned by the
133: * configured user and group. This requires a call to chown(2). But
134: * CAP_CHOWN is not always required. */
135: if (!this->uid || geteuid() == this->uid)
136: { /* if the owner does not change CAP_CHOWN is not needed */
137: if (!this->gid || has_group(this->gid))
138: { /* the same applies if the owner is a member of the group */
139: if (ignore)
140: { /* we don't have to keep this, if requested */
141: *ignore = TRUE;
142: }
143: return TRUE;
144: }
145: }
146: }
147: #ifndef CAPABILITIES
148: /* if we can't check the actual capabilities assume only root has it */
149: return geteuid() == 0;
150: #endif /* !CAPABILITIES */
151: #ifdef CAPABILITIES_LIBCAP
152: cap_flag_value_t val;
153: cap_t caps;
154: bool ok;
155:
156: caps = cap_get_proc();
157: if (!caps)
158: {
159: return FALSE;
160: }
161: ok = cap_get_flag(caps, cap, CAP_PERMITTED, &val) == 0 && val == CAP_SET;
162: cap_free(caps);
163: return ok;
164: #endif /* CAPABILITIES_LIBCAP */
165: #ifdef CAPABILITIES_NATIVE
166: struct __user_cap_header_struct header = {
167: #if defined(_LINUX_CAPABILITY_VERSION_3)
168: .version = _LINUX_CAPABILITY_VERSION_3,
169: #elif defined(_LINUX_CAPABILITY_VERSION_2)
170: .version = _LINUX_CAPABILITY_VERSION_2,
171: #elif defined(_LINUX_CAPABILITY_VERSION_1)
172: .version = _LINUX_CAPABILITY_VERSION_1,
173: #else
174: .version = _LINUX_CAPABILITY_VERSION,
175: #endif
176: };
177: struct __user_cap_data_struct caps[2];
178: int i = 0;
179:
180: if (cap >= 32)
181: {
182: i++;
183: cap -= 32;
184: }
185: return capget(&header, caps) == 0 && caps[i].permitted & (1 << cap);
186: #endif /* CAPABILITIES_NATIVE */
187: }
188:
189: #else /* WIN32 */
190:
191: /**
192: * Verify that the current process has the given capability, dummy variant
193: */
194: static bool has_capability(private_capabilities_t *this, u_int cap,
195: bool *ignore)
196: {
197: return TRUE;
198: }
199:
200: #endif /* WIN32 */
201:
202: /**
203: * Keep the given capability if it is held by the current process. Returns
204: * FALSE, if this is not the case.
205: */
206: static bool keep_capability(private_capabilities_t *this, u_int cap)
207: {
208: #ifdef CAPABILITIES_LIBCAP
209: cap_set_flag(this->caps, CAP_EFFECTIVE, 1, &cap, CAP_SET);
210: cap_set_flag(this->caps, CAP_INHERITABLE, 1, &cap, CAP_SET);
211: cap_set_flag(this->caps, CAP_PERMITTED, 1, &cap, CAP_SET);
212: #endif /* CAPABILITIES_LIBCAP */
213: #ifdef CAPABILITIES_NATIVE
214: int i = 0;
215:
216: if (cap >= 32)
217: {
218: i++;
219: cap -= 32;
220: }
221: this->caps[i].effective |= 1 << cap;
222: this->caps[i].permitted |= 1 << cap;
223: this->caps[i].inheritable |= 1 << cap;
224: #endif /* CAPABILITIES_NATIVE */
225: return TRUE;
226: }
227:
228: METHOD(capabilities_t, keep, bool,
229: private_capabilities_t *this, u_int cap)
230: {
231: bool ignore = FALSE;
232:
233: if (!has_capability(this, cap, &ignore))
234: {
235: return FALSE;
236: }
237: else if (ignore)
238: { /* don't keep capabilities that are not required */
239: return TRUE;
240: }
241: return keep_capability(this, cap);
242: }
243:
244: METHOD(capabilities_t, check, bool,
245: private_capabilities_t *this, u_int cap)
246: {
247: return has_capability(this, cap, NULL);
248: }
249:
250: METHOD(capabilities_t, get_uid, uid_t,
251: private_capabilities_t *this)
252: {
253: #ifdef WIN32
254: return this->uid;
255: #else
256: return this->uid ?: geteuid();
257: #endif
258: }
259:
260: METHOD(capabilities_t, get_gid, gid_t,
261: private_capabilities_t *this)
262: {
263: #ifdef WIN32
264: return this->gid;
265: #else
266: return this->gid ?: getegid();
267: #endif
268: }
269:
270: METHOD(capabilities_t, set_uid, void,
271: private_capabilities_t *this, uid_t uid)
272: {
273: this->uid = uid;
274: }
275:
276: METHOD(capabilities_t, set_gid, void,
277: private_capabilities_t *this, gid_t gid)
278: {
279: this->gid = gid;
280: }
281:
282: METHOD(capabilities_t, resolve_uid, bool,
283: private_capabilities_t *this, char *username)
284: {
285: #ifndef WIN32
286: struct passwd *pwp;
287: int err;
288:
289: #ifdef HAVE_GETPWNAM_R
290: struct passwd passwd;
291: size_t buflen = 1024;
292: char *buf = NULL;
293:
294: while (TRUE)
295: {
296: buf = realloc(buf, buflen);
297: err = getpwnam_r(username, &passwd, buf, buflen, &pwp);
298: if (err == ERANGE)
299: {
300: buflen *= 2;
301: continue;
302: }
303: if (pwp)
304: {
305: this->uid = pwp->pw_uid;
306: }
307: break;
308: }
309: free(buf);
310: #else /* HAVE GETPWNAM_R */
311: this->mutex->lock(this->mutex);
312: pwp = getpwnam(username);
313: if (pwp)
314: {
315: this->uid = pwp->pw_uid;
316: }
317: err = errno;
318: this->mutex->unlock(this->mutex);
319: #endif /* HAVE GETPWNAM_R */
320: if (pwp)
321: {
322: return TRUE;
323: }
324: DBG1(DBG_LIB, "resolving user '%s' failed: %s", username,
325: err ? strerror(err) : "user not found");
326: #endif /* !WIN32 */
327: return FALSE;
328: }
329:
330: METHOD(capabilities_t, resolve_gid, bool,
331: private_capabilities_t *this, char *groupname)
332: {
333: #ifndef WIN32
334: struct group *grp;
335: int err;
336:
337: #ifdef HAVE_GETGRNAM_R
338: struct group group;
339: size_t buflen = 1024;
340: char *buf = NULL;
341:
342: while (TRUE)
343: {
344: buf = realloc(buf, buflen);
345: err = getgrnam_r(groupname, &group, buf, buflen, &grp);
346: if (err == ERANGE)
347: {
348: buflen *= 2;
349: continue;
350: }
351: if (grp)
352: {
353: this->gid = grp->gr_gid;
354: }
355: break;
356: }
357: free(buf);
358: #else /* HAVE_GETGRNAM_R */
359: this->mutex->lock(this->mutex);
360: grp = getgrnam(groupname);
361: if (grp)
362: {
363: this->gid = grp->gr_gid;
364: }
365: err = errno;
366: this->mutex->unlock(this->mutex);
367: #endif /* HAVE_GETGRNAM_R */
368: if (grp)
369: {
370: return TRUE;
371: }
372: DBG1(DBG_LIB, "resolving user '%s' failed: %s", groupname,
373: err ? strerror(err) : "group not found");
374: #endif /* !WIN32 */
375: return FALSE;
376: }
377:
378: #ifndef WIN32
379: /**
380: * Initialize supplementary groups for unprivileged user
381: */
382: static bool init_supplementary_groups(private_capabilities_t *this)
383: {
384: struct passwd *pwp;
385: int res = -1;
386:
387: #ifdef HAVE_GETPWUID_R
388: struct passwd pwd;
389: size_t buflen = 1024;
390: char *buf = NULL;
391:
392: while (TRUE)
393: {
394: buf = realloc(buf, buflen);
395: if (getpwuid_r(this->uid, &pwd, buf, buflen, &pwp) == ERANGE)
396: {
397: buflen *= 2;
398: continue;
399: }
400: if (pwp)
401: {
402: res = initgroups(pwp->pw_name, this->gid);
403: }
404: break;
405: }
406: free(buf);
407: #else /* HAVE_GETPWUID_R */
408: this->mutex->lock(this->mutex);
409: pwp = getpwuid(this->uid);
410: if (pwp)
411: {
412: res = initgroups(pwp->pw_name, this->gid);
413: }
414: this->mutex->unlock(this->mutex);
415: #endif /* HAVE_GETPWUID_R */
416: return res == 0;
417: }
418: #endif /* WIN32 */
419:
420: METHOD(capabilities_t, drop, bool,
421: private_capabilities_t *this)
422: {
423: #ifndef WIN32
424: #ifdef HAVE_PRCTL
425: if (has_capability(this, CAP_SETPCAP, NULL))
426: {
427: prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
428: }
429: #endif
430:
431: if (this->uid && !init_supplementary_groups(this))
432: {
433: DBG1(DBG_LIB, "initializing supplementary groups for %u failed",
434: this->uid);
435: return FALSE;
436: }
437: if (this->gid && setgid(this->gid) != 0)
438: {
439: DBG1(DBG_LIB, "change to unprivileged group %u failed: %s",
440: this->gid, strerror(errno));
441: return FALSE;
442: }
443: if (this->uid && setuid(this->uid) != 0)
444: {
445: DBG1(DBG_LIB, "change to unprivileged user %u failed: %s",
446: this->uid, strerror(errno));
447: return FALSE;
448: }
449:
450: #ifdef CAPABILITIES_LIBCAP
451: if (cap_set_proc(this->caps) != 0)
452: {
453: DBG1(DBG_LIB, "dropping capabilities failed: %s", strerror(errno));
454: return FALSE;
455: }
456: #endif /* CAPABILITIES_LIBCAP */
457: #ifdef CAPABILITIES_NATIVE
458: struct __user_cap_header_struct header = {
459: #if defined(_LINUX_CAPABILITY_VERSION_3)
460: .version = _LINUX_CAPABILITY_VERSION_3,
461: #elif defined(_LINUX_CAPABILITY_VERSION_2)
462: .version = _LINUX_CAPABILITY_VERSION_2,
463: #elif defined(_LINUX_CAPABILITY_VERSION_1)
464: .version = _LINUX_CAPABILITY_VERSION_1,
465: #else
466: .version = _LINUX_CAPABILITY_VERSION,
467: #endif
468: };
469: if (capset(&header, this->caps) != 0)
470: {
471: DBG1(DBG_LIB, "dropping capabilities failed: %s", strerror(errno));
472: return FALSE;
473: }
474: #endif /* CAPABILITIES_NATIVE */
475: #ifdef CAPABILITIES
476: DBG1(DBG_LIB, "dropped capabilities, running as uid %u, gid %u",
477: geteuid(), getegid());
478: #endif /* CAPABILITIES */
479: #endif /*!WIN32 */
480: return TRUE;
481: }
482:
483: METHOD(capabilities_t, destroy, void,
484: private_capabilities_t *this)
485: {
486: #ifdef EMULATE_R_FUNCS
487: this->mutex->destroy(this->mutex);
488: #endif /* EMULATE_R_FUNCS */
489: #ifdef CAPABILITIES_LIBCAP
490: cap_free(this->caps);
491: #endif /* CAPABILITIES_LIBCAP */
492: free(this);
493: }
494:
495: /**
496: * See header
497: */
498: capabilities_t *capabilities_create()
499: {
500: private_capabilities_t *this;
501:
502: INIT(this,
503: .public = {
504: .keep = _keep,
505: .check = _check,
506: .get_uid = _get_uid,
507: .get_gid = _get_gid,
508: .set_uid = _set_uid,
509: .set_gid = _set_gid,
510: .resolve_uid = _resolve_uid,
511: .resolve_gid = _resolve_gid,
512: .drop = _drop,
513: .destroy = _destroy,
514: },
515: );
516:
517: #ifdef CAPABILITIES_LIBCAP
518: this->caps = cap_init();
519: #endif /* CAPABILITIES_LIBCAP */
520:
521: #ifdef EMULATE_R_FUNCS
522: this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
523: #endif /* EMULATE_R_FUNCS */
524:
525: return &this->public;
526: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>