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>