param_dac.c 9.8 KB
Newer Older
S
sun_fan 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <grp.h>
#include <pwd.h>
#include <sys/stat.h>
#include <sys/types.h>

21
#include "init_utils.h"
S
sun_fan 已提交
22 23 24 25 26 27 28 29 30
#include "param_security.h"
#include "param_utils.h"

#define OCT_BASE 8
static ParamSecurityLabel g_localSecurityLabel = {};

static void GetUserIdByName(FILE *fp, uid_t *uid, const char *name, uint32_t nameLen)
{
    *uid = -1;
X
xionglei6 已提交
31
    (void)fp;
S
sun_fan 已提交
32
    struct passwd *data = NULL;
X
xionglei6 已提交
33
    while ((data = getpwent()) != NULL) {
4
411148299@qq.com 已提交
34 35
        if ((data->pw_name != NULL) && (strlen(data->pw_name) == nameLen) &&
            (strncmp(data->pw_name, name, nameLen) == 0)) {
S
sun_fan 已提交
36
            *uid = data->pw_uid;
X
xionglei6 已提交
37
            break;
S
sun_fan 已提交
38 39
        }
    }
X
xionglei6 已提交
40
    endpwent();
S
sun_fan 已提交
41 42 43 44 45
}

static void GetGroupIdByName(FILE *fp, gid_t *gid, const char *name, uint32_t nameLen)
{
    *gid = -1;
X
xionglei6 已提交
46
    (void)fp;
S
sun_fan 已提交
47
    struct group *data = NULL;
X
xionglei6 已提交
48
    while ((data = getgrent()) != NULL) {
4
411148299@qq.com 已提交
49 50
        if ((data->gr_name != NULL) && (strlen(data->gr_name) == nameLen) &&
            (strncmp(data->gr_name, name, nameLen) == 0)) {
S
sun_fan 已提交
51 52 53 54
            *gid = data->gr_gid;
            break;
        }
    }
X
xionglei6 已提交
55
    endgrent();
S
sun_fan 已提交
56 57 58 59 60
}

// user:group:r|w
static int GetParamDacData(FILE *fpForGroup, FILE *fpForUser, ParamDacData *dacData, const char *value)
{
4
411148299@qq.com 已提交
61 62 63
    if (dacData == NULL) {
        return -1;
    }
S
sun_fan 已提交
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
    char *groupName = strstr(value, ":");
    if (groupName == NULL) {
        return -1;
    }
    char *mode = strstr(groupName + 1, ":");
    if (mode == NULL) {
        return -1;
    }
    GetUserIdByName(fpForUser, &dacData->uid, value, groupName - value);
    GetGroupIdByName(fpForGroup, &dacData->gid, groupName + 1, mode - groupName - 1);
    dacData->mode = strtol(mode + 1, NULL, OCT_BASE);
    return 0;
}

static int InitLocalSecurityLabel(ParamSecurityLabel **security, int isInit)
{
    UNUSED(isInit);
X
xionglei6 已提交
81
    PARAM_LOGV("InitLocalSecurityLabel uid:%d gid:%d euid: %d egid: %d ", getuid(), getgid(), geteuid(), getegid());
S
sun_fan 已提交
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
    g_localSecurityLabel.cred.pid = getpid();
    g_localSecurityLabel.cred.uid = geteuid();
    g_localSecurityLabel.cred.gid = getegid();
    *security = &g_localSecurityLabel;
    // support check write permission in client
    (*security)->flags |= LABEL_CHECK_FOR_ALL_PROCESS;
    return 0;
}

static int FreeLocalSecurityLabel(ParamSecurityLabel *srcLabel)
{
    return 0;
}

static int EncodeSecurityLabel(const ParamSecurityLabel *srcLabel, char *buffer, uint32_t *bufferSize)
{
    PARAM_CHECK(bufferSize != NULL, return -1, "Invalid param");
    if (buffer == NULL) {
        *bufferSize = sizeof(ParamSecurityLabel);
        return 0;
    }
    PARAM_CHECK(*bufferSize >= sizeof(ParamSecurityLabel), return -1, "Invalid buffersize %u", *bufferSize);
    *bufferSize = sizeof(ParamSecurityLabel);
    return memcpy_s(buffer, *bufferSize, srcLabel, sizeof(ParamSecurityLabel));
}

4
411148299@qq.com 已提交
108
static int DecodeSecurityLabel(ParamSecurityLabel **srcLabel, const char *buffer, uint32_t bufferSize)
S
sun_fan 已提交
109 110 111 112 113 114 115 116 117
{
    PARAM_CHECK(bufferSize >= sizeof(ParamSecurityLabel), return -1, "Invalid buffersize %u", bufferSize);
    PARAM_CHECK(srcLabel != NULL && buffer != NULL, return -1, "Invalid param");
    *srcLabel = (ParamSecurityLabel *)buffer;
    return 0;
}

static int LoadParamLabels(const char *fileName, SecurityLabelFunc label, void *context)
{
4
411148299@qq.com 已提交
118 119
    uint32_t infoCount = 0;
    ParamAuditData auditData = {0};
S
sun_fan 已提交
120 121 122
    FILE *fpForGroup = fopen(GROUP_FILE_PATH, "r");
    FILE *fpForUser = fopen(USER_FILE_PATH, "r");
    FILE *fp = fopen(fileName, "r");
4
411148299@qq.com 已提交
123 124 125 126 127
    char *buff = (char *)calloc(1, PARAM_BUFFER_SIZE);
    SubStringInfo *info = calloc(1, sizeof(SubStringInfo) * (SUBSTR_INFO_DAC + 1));
    while (fp != NULL && fpForGroup != NULL && fpForUser != NULL &&
        info != NULL && buff != NULL && fgets(buff, PARAM_BUFFER_SIZE, fp) != NULL) {
        buff[PARAM_BUFFER_SIZE - 1] = '\0';
S
sun_fan 已提交
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
        int subStrNumber = GetSubStringInfo(buff, strlen(buff), ' ', info, SUBSTR_INFO_DAC + 1);
        if (subStrNumber <= SUBSTR_INFO_DAC) {
            continue;
        }
        auditData.name = info[SUBSTR_INFO_NAME].value;
#ifdef STARTUP_INIT_TEST
        auditData.label = info[SUBSTR_INFO_NAME].value;
#endif
        int ret = GetParamDacData(fpForGroup, fpForUser, &auditData.dacData, info[SUBSTR_INFO_DAC].value);
        PARAM_CHECK(ret == 0, continue, "Failed to get param info %d %s", ret, buff);
        ret = label(&auditData, context);
        PARAM_CHECK(ret == 0, continue, "Failed to write param info %d %s", ret, buff);
        infoCount++;
    }
    PARAM_LOGI("Load parameter label total %u success %s", infoCount, fileName);
4
411148299@qq.com 已提交
143
    if (fp != NULL) {
S
sun_fan 已提交
144 145
        (void)fclose(fp);
    }
4
411148299@qq.com 已提交
146
    if (info != NULL) {
S
sun_fan 已提交
147 148
        free(info);
    }
4
411148299@qq.com 已提交
149
    if (fpForGroup != NULL) {
S
sun_fan 已提交
150 151
        (void)fclose(fpForGroup);
    }
4
411148299@qq.com 已提交
152
    if (fpForUser != NULL) {
S
sun_fan 已提交
153 154
        (void)fclose(fpForUser);
    }
4
411148299@qq.com 已提交
155 156 157
    if (buff != NULL) {
        free(buff);
    }
S
sun_fan 已提交
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
    return 0;
}

static int ProcessParamFile(const char *fileName, void *context)
{
    LabelFuncContext *cxt = (LabelFuncContext *)context;
    return LoadParamLabels(fileName, cxt->label, cxt->context);
}

static int GetParamSecurityLabel(SecurityLabelFunc label, const char *path, void *context)
{
    PARAM_CHECK(label != NULL && path != NULL, return -1, "Invalid param");
    struct stat st;
    LabelFuncContext cxt = {label, context};
    if ((stat(path, &st) == 0) && !S_ISDIR(st.st_mode)) {
        return ProcessParamFile(path, &cxt);
    }
X
xionglei6 已提交
175
    PARAM_LOGV("GetParamSecurityLabel %s ", path);
S
sun_fan 已提交
176 177 178 179 180 181 182 183 184 185
    return ReadFileInDir(path, ".para.dac", ProcessParamFile, &cxt);
}

static int CheckFilePermission(const ParamSecurityLabel *localLabel, const char *fileName, int flags)
{
    UNUSED(flags);
    PARAM_CHECK(localLabel != NULL && fileName != NULL, return -1, "Invalid param");
    return 0;
}

X
add ut  
xionglei6 已提交
186 187
static int CheckUserInGroup(gid_t groupId, uid_t uid)
{
X
xionglei6 已提交
188 189 190 191 192
    static char buffer[255] = {0}; // 255 max size
    static char userBuff[255] = {0}; // 255 max size
    struct group *grpResult = NULL;
    struct group grp = {};
    int ret = getgrgid_r(groupId, &grp, buffer, sizeof(buffer), &grpResult);
X
xionglei6 已提交
193
    if (ret != 0 || grpResult == NULL || grpResult->gr_name == NULL) {
X
add ut  
xionglei6 已提交
194 195
        return -1;
    }
X
xionglei6 已提交
196 197 198
    struct passwd data = {};
    struct passwd *userResult = NULL;
    ret = getpwuid_r(uid, &data, userBuff, sizeof(userBuff), &userResult);
X
xionglei6 已提交
199
    if (ret != 0 || userResult == NULL || userResult->pw_name == NULL) {
X
add ut  
xionglei6 已提交
200 201 202
        return -1;
    }

X
xionglei6 已提交
203 204 205 206
    PARAM_LOGV("CheckUserInGroup pw_name %s ", userResult->pw_name);
    if (strcmp(grpResult->gr_name, userResult->pw_name) == 0) {
        return 0;
    }
X
add ut  
xionglei6 已提交
207
    int index = 0;
X
xionglei6 已提交
208 209 210
    while (grpResult->gr_mem[index]) {
        PARAM_LOGV("CheckUserInGroup %s ", grpResult->gr_mem[index]);
        if (strcmp(grpResult->gr_mem[index], userResult->pw_name) == 0) {
X
add ut  
xionglei6 已提交
211 212 213 214 215 216 217
            return 0;
        }
        index++;
    }
    return -1;
}

4
411148299@qq.com 已提交
218
static int CheckParamPermission(const ParamSecurityLabel *srcLabel, const ParamAuditData *auditData, uint32_t mode)
S
sun_fan 已提交
219 220 221 222 223 224 225 226 227
{
    int ret = DAC_RESULT_FORBIDED;
    PARAM_CHECK(srcLabel != NULL && auditData != NULL && auditData->name != NULL, return ret, "Invalid param");
    PARAM_CHECK((mode & (DAC_READ | DAC_WRITE | DAC_WATCH)) != 0, return ret, "Invalid mode %x", mode);

    /**
     * DAC group 实现的label的定义
     * user:group:read|write|watch
     */
4
411148299@qq.com 已提交
228
    uint32_t localMode;
S
sun_fan 已提交
229 230 231 232
    if (srcLabel->cred.uid == auditData->dacData.uid) {
        localMode = mode & (DAC_READ | DAC_WRITE | DAC_WATCH);
    } else if (srcLabel->cred.gid == auditData->dacData.gid) {
        localMode = (mode & (DAC_READ | DAC_WRITE | DAC_WATCH)) >> DAC_GROUP_START;
X
xionglei6 已提交
233
    } else if (CheckUserInGroup(auditData->dacData.gid, srcLabel->cred.uid) == 0) {  // user in group
X
add ut  
xionglei6 已提交
234
        localMode = (mode & (DAC_READ | DAC_WRITE | DAC_WATCH)) >> DAC_GROUP_START;
S
sun_fan 已提交
235 236 237 238 239 240
    } else {
        localMode = (mode & (DAC_READ | DAC_WRITE | DAC_WATCH)) >> DAC_OTHER_START;
    }
    if ((auditData->dacData.mode & localMode) != 0) {
        ret = DAC_RESULT_PERMISSION;
    }
X
xionglei6 已提交
241 242
    PARAM_LOGV("Src label gid:%d uid:%d ", srcLabel->cred.gid, srcLabel->cred.uid);
    PARAM_LOGV("local label gid:%d uid:%d mode %o",
4
411148299@qq.com 已提交
243
        auditData->dacData.gid, auditData->dacData.uid, auditData->dacData.mode);
X
xionglei6 已提交
244
    PARAM_LOGV("%s check %o localMode %o ret %d", auditData->name, mode, localMode, ret);
S
sun_fan 已提交
245 246 247 248 249 250
    return ret;
}

PARAM_STATIC int RegisterSecurityDacOps(ParamSecurityOps *ops, int isInit)
{
    PARAM_CHECK(ops != NULL, return -1, "Invalid param");
X
xionglei6 已提交
251
    PARAM_LOGV("RegisterSecurityDacOps %d", isInit);
S
sun_fan 已提交
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
    ops->securityGetLabel = NULL;
    ops->securityDecodeLabel = NULL;
    ops->securityEncodeLabel = NULL;
    ops->securityInitLabel = InitLocalSecurityLabel;
    ops->securityCheckFilePermission = CheckFilePermission;
    ops->securityCheckParamPermission = CheckParamPermission;
    ops->securityFreeLabel = FreeLocalSecurityLabel;
    if (isInit) {
        ops->securityGetLabel = GetParamSecurityLabel;
        ops->securityDecodeLabel = DecodeSecurityLabel;
    } else {
        ops->securityEncodeLabel = EncodeSecurityLabel;
    }
    return 0;
}

#ifdef PARAM_SUPPORT_DAC
int RegisterSecurityOps(ParamSecurityOps *ops, int isInit)
{
    return RegisterSecurityDacOps(ops, isInit);
}
X
add ut  
xionglei6 已提交
273
#endif