param_dac.c 11.0 KB
Newer Older
S
sun_fan 已提交
1
/*
M
Mupceet 已提交
2
 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
S
sun_fan 已提交
3 4 5 6 7 8 9 10 11 12 13 14
 * 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.
 */
M
Mupceet 已提交
15
#include <errno.h>
S
sun_fan 已提交
16 17 18
#include <grp.h>
#include <pwd.h>
#include <sys/stat.h>
M
Mupceet 已提交
19
#include <dirent.h>
M
Mupceet 已提交
20
#include <string.h>
S
sun_fan 已提交
21

M
Mupceet 已提交
22
#include "param_manager.h"
S
sun_fan 已提交
23
#include "param_security.h"
M
Mupceet 已提交
24
#include "param_trie.h"
S
sun_fan 已提交
25
#include "param_utils.h"
M
Mupceet 已提交
26
#include "param_base.h"
S
sun_fan 已提交
27

M
Mupceet 已提交
28
#define USER_BUFFER_LEN 64
M
Mupceet 已提交
29
#define MAX_BUF_SIZE  1024
M
Mupceet 已提交
30
#define GROUP_FORMAT "const.group"
S
sun_fan 已提交
31

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

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

// user:group:r|w
X
xionglei6 已提交
62
static int GetParamDacData(ParamDacData *dacData, const char *value)
S
sun_fan 已提交
63
{
M
Mupceet 已提交
64 65 66 67 68 69 70 71 72
    static const struct {
        const char *name;
        int value;
    } paramTypes[] = {
        { "int", PARAM_TYPE_INT },
        { "string", PARAM_TYPE_STRING },
        { "bool", PARAM_TYPE_BOOL },
    };

4
411148299@qq.com 已提交
73 74 75
    if (dacData == NULL) {
        return -1;
    }
S
sun_fan 已提交
76 77 78 79 80 81 82 83
    char *groupName = strstr(value, ":");
    if (groupName == NULL) {
        return -1;
    }
    char *mode = strstr(groupName + 1, ":");
    if (mode == NULL) {
        return -1;
    }
X
xionglei6 已提交
84 85
    GetUserIdByName(&dacData->uid, value, groupName - value);
    GetGroupIdByName(&dacData->gid, groupName + 1, mode - groupName - 1);
M
Mupceet 已提交
86 87 88 89 90 91 92 93 94 95 96 97 98

    dacData->paramType = PARAM_TYPE_STRING;
    char *type = strstr(mode + 1, ":");
    if (type != NULL) {
        *type = '\0';
        type++;
        for (size_t i = 0; (type != NULL) && (i < ARRAY_LENGTH(paramTypes)); i++) {
            if (strcmp(paramTypes[i].name, type) == 0) {
                dacData->paramType = paramTypes[i].value;
            }
        }
    }
    dacData->mode = (uint16_t)strtol(mode + 1, NULL, OCT_BASE);
S
sun_fan 已提交
99 100 101
    return 0;
}

M
Mupceet 已提交
102
static int InitLocalSecurityLabel(ParamSecurityLabel *security, int isInit)
S
sun_fan 已提交
103 104
{
    UNUSED(isInit);
M
Mupceet 已提交
105 106 107 108
    PARAM_CHECK(security != NULL, return -1, "Invalid security");
    security->cred.pid = getpid();
    security->cred.uid = geteuid();
    security->cred.gid = getegid();
S
sun_fan 已提交
109
    // support check write permission in client
M
Mupceet 已提交
110
    security->flags[PARAM_SECURITY_DAC] |= LABEL_CHECK_IN_ALL_PROCESS;
S
sun_fan 已提交
111 112 113 114 115 116 117 118
    return 0;
}

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

M
Mupceet 已提交
119
static int LoadOneParam_(const uint32_t *context, const char *name, const char *value)
X
xionglei6 已提交
120 121 122 123 124
{
    ParamAuditData auditData = {0};
    auditData.name = name;
    int ret = GetParamDacData(&auditData.dacData, value);
    PARAM_CHECK(ret == 0, return -1, "Failed to get param info %d %s", ret, name);
M
Mupceet 已提交
125
    AddSecurityLabel(&auditData);
X
xionglei6 已提交
126 127 128
    return 0;
}

M
Mupceet 已提交
129
static int LoadParamLabels(const char *fileName)
S
sun_fan 已提交
130
{
4
411148299@qq.com 已提交
131
    uint32_t infoCount = 0;
S
sun_fan 已提交
132
    FILE *fp = fopen(fileName, "r");
M
Mupceet 已提交
133 134
    const uint32_t buffSize = PARAM_NAME_LEN_MAX + PARAM_CONST_VALUE_LEN_MAX + 10;  // 10 size
    char *buff = (char *)calloc(1, buffSize);
X
xionglei6 已提交
135 136
    while (fp != NULL && buff != NULL && fgets(buff, buffSize, fp) != NULL) {
        buff[buffSize - 1] = '\0';
M
Mupceet 已提交
137
        int ret = SplitParamString(buff, NULL, 0, LoadOneParam_, NULL);
X
xionglei6 已提交
138
        if (ret != 0) {
139
            PARAM_LOGE("Failed to split string %s fileName %s", buff, fileName);
S
sun_fan 已提交
140 141 142 143 144
            continue;
        }
        infoCount++;
    }
    PARAM_LOGI("Load parameter label total %u success %s", infoCount, fileName);
4
411148299@qq.com 已提交
145
    if (fp != NULL) {
S
sun_fan 已提交
146 147
        (void)fclose(fp);
    }
4
411148299@qq.com 已提交
148 149 150
    if (buff != NULL) {
        free(buff);
    }
S
sun_fan 已提交
151 152 153 154 155
    return 0;
}

static int ProcessParamFile(const char *fileName, void *context)
{
M
Mupceet 已提交
156 157
    UNUSED(context);
    return LoadParamLabels(fileName);
S
sun_fan 已提交
158 159
}

M
Mupceet 已提交
160
static int DacGetParamSecurityLabel(const char *path)
S
sun_fan 已提交
161
{
M
Mupceet 已提交
162
    PARAM_CHECK(path != NULL, return -1, "Invalid param");
S
sun_fan 已提交
163 164
    struct stat st;
    if ((stat(path, &st) == 0) && !S_ISDIR(st.st_mode)) {
M
Mupceet 已提交
165
        return ProcessParamFile(path, NULL);
S
sun_fan 已提交
166
    }
M
Mupceet 已提交
167

M
Mupceet 已提交
168
    PARAM_LOGV("DacGetParamSecurityLabel %s ", path);
M
Mupceet 已提交
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
    DIR *pDir = opendir(path);
    PARAM_CHECK(pDir != NULL, return -1, "Read dir :%s failed.%d", path, errno);
    char *fileName = malloc(MAX_BUF_SIZE);
    PARAM_CHECK(fileName != NULL, closedir(pDir);
        return -1, "Failed to malloc for %s", path);

    struct dirent *dp;
    uint32_t count = 0;
    while ((dp = readdir(pDir)) != NULL) {
        if (dp->d_type == DT_DIR) {
            continue;
        }
        char *tmp = strstr(dp->d_name, ".para.dac");
        if (tmp == NULL) {
            continue;
        }
        if (strcmp(tmp, ".para.dac") != 0) {
            continue;
        }
        int ret = ParamSprintf(fileName, MAX_BUF_SIZE, "%s/%s", path, dp->d_name);
        if (ret <= 0) {
            PARAM_LOGE("Failed to get file name for %s", dp->d_name);
            continue;
        }
        if ((stat(fileName, &st) == 0) && !S_ISDIR(st.st_mode)) {
            count++;
            ProcessParamFile(fileName, NULL);
        }
    }
    PARAM_LOGI("DacGetParamSecurityLabel path %s %d", path, count);
    free(fileName);
    closedir(pDir);
    return 0;
S
sun_fan 已提交
202 203 204 205 206 207 208 209 210
}

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;
}

M
Mupceet 已提交
211
static int CheckUserInGroup(WorkSpace *space, gid_t groupId, uid_t uid)
X
add ut  
xionglei6 已提交
212
{
M
Mupceet 已提交
213
#ifdef __MUSL__
M
Mupceet 已提交
214
    char buffer[USER_BUFFER_LEN] = {0};
M
Mupceet 已提交
215
    uint32_t labelIndex = 0;
M
Mupceet 已提交
216
    int ret = ParamSprintf(buffer, sizeof(buffer), "%s.%d.%d", GROUP_FORMAT, groupId, uid);
M
Mupceet 已提交
217 218
    PARAM_CHECK(ret >= 0, return -1, "Failed to format name for %s.%d.%d", GROUP_FORMAT, groupId, uid);
    (void)FindTrieNode(space, buffer, strlen(buffer), &labelIndex);
M
Mupceet 已提交
219
    ParamSecurityNode *node = (ParamSecurityNode *)GetTrieNode(space, labelIndex);
M
Mupceet 已提交
220 221 222
    PARAM_CHECK(node != NULL, return DAC_RESULT_FORBIDED, "Can not get security label %d", labelIndex);
    PARAM_LOGV("CheckUserInGroup %s groupid %d uid %d", buffer, groupId, uid);
    if (node->gid == groupId && node->uid == uid) {
X
xionglei6 已提交
223 224
        return 0;
    }
X
add ut  
xionglei6 已提交
225
    return -1;
M
Mupceet 已提交
226 227 228
#else
    return 0;
#endif
X
add ut  
xionglei6 已提交
229 230
}

M
Mupceet 已提交
231
static int DacCheckParamPermission(const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
S
sun_fan 已提交
232 233
{
    int ret = DAC_RESULT_FORBIDED;
M
Mupceet 已提交
234 235 236 237 238
    uint32_t labelIndex = 0;
    // get dac label
    WorkSpace *space = GetWorkSpace(WORKSPACE_NAME_DAC);
    PARAM_CHECK(space != NULL, return DAC_RESULT_FORBIDED, "Failed to get dac space %s", name);
    (void)FindTrieNode(space, name, strlen(name), &labelIndex);
M
Mupceet 已提交
239
    ParamSecurityNode *node = (ParamSecurityNode *)GetTrieNode(space, labelIndex);
M
Mupceet 已提交
240
    PARAM_CHECK(node != NULL, return DAC_RESULT_FORBIDED, "Can not get security label %d", labelIndex);
S
sun_fan 已提交
241
    /**
M
Mupceet 已提交
242
     * DAC group
S
sun_fan 已提交
243 244
     * user:group:read|write|watch
     */
4
411148299@qq.com 已提交
245
    uint32_t localMode;
M
Mupceet 已提交
246
    if (srcLabel->cred.uid == node->uid) {
S
sun_fan 已提交
247
        localMode = mode & (DAC_READ | DAC_WRITE | DAC_WATCH);
M
Mupceet 已提交
248
    } else if (srcLabel->cred.gid == node->gid) {
S
sun_fan 已提交
249
        localMode = (mode & (DAC_READ | DAC_WRITE | DAC_WATCH)) >> DAC_GROUP_START;
M
Mupceet 已提交
250
    } else if (CheckUserInGroup(space, node->gid, srcLabel->cred.uid) == 0) {  // user in group
X
add ut  
xionglei6 已提交
251
        localMode = (mode & (DAC_READ | DAC_WRITE | DAC_WATCH)) >> DAC_GROUP_START;
S
sun_fan 已提交
252 253 254
    } else {
        localMode = (mode & (DAC_READ | DAC_WRITE | DAC_WATCH)) >> DAC_OTHER_START;
    }
M
Mupceet 已提交
255
    if ((node->mode & localMode) != 0) {
S
sun_fan 已提交
256 257
        ret = DAC_RESULT_PERMISSION;
    }
M
Mupceet 已提交
258 259 260 261 262 263 264
    if (ret != DAC_RESULT_PERMISSION) {
        PARAM_LOGW("Param '%s' label gid:%d uid:%d mode 0%o", name, srcLabel->cred.gid, srcLabel->cred.uid, localMode);
        PARAM_LOGW("Cfg label %d gid:%d uid:%d mode 0%o ", labelIndex, node->gid, node->uid, node->mode);
#ifndef STARTUP_INIT_TEST
        ret = DAC_RESULT_PERMISSION;
#endif
    }
S
sun_fan 已提交
265 266 267
    return ret;
}

M
Mupceet 已提交
268
INIT_LOCAL_API int RegisterSecurityDacOps(ParamSecurityOps *ops, int isInit)
S
sun_fan 已提交
269 270
{
    PARAM_CHECK(ops != NULL, return -1, "Invalid param");
X
xionglei6 已提交
271
    PARAM_LOGV("RegisterSecurityDacOps %d", isInit);
M
Mupceet 已提交
272
    int ret = ParamStrCpy(ops->name, sizeof(ops->name), "dac");
S
sun_fan 已提交
273 274
    ops->securityInitLabel = InitLocalSecurityLabel;
    ops->securityCheckFilePermission = CheckFilePermission;
M
Mupceet 已提交
275
    ops->securityCheckParamPermission = DacCheckParamPermission;
S
sun_fan 已提交
276 277
    ops->securityFreeLabel = FreeLocalSecurityLabel;
    if (isInit) {
M
Mupceet 已提交
278
        ops->securityGetLabel = DacGetParamSecurityLabel;
S
sun_fan 已提交
279
    }
M
Mupceet 已提交
280
    return ret;
S
sun_fan 已提交
281 282
}

M
Mupceet 已提交
283
static void AddGroupUser(unsigned int uid, unsigned int gid, int mode, const char *format)
S
sun_fan 已提交
284
{
M
Mupceet 已提交
285 286
    ParamAuditData auditData = {0};
    char buffer[USER_BUFFER_LEN] = {0};
M
Mupceet 已提交
287
    int ret = ParamSprintf(buffer, sizeof(buffer), "%s.%u.%u", format, gid, uid);
M
Mupceet 已提交
288 289 290 291 292 293
    PARAM_CHECK(ret >= 0, return, "Failed to format name for %s.%d.%d", format, gid, uid);
    auditData.name = buffer;
    auditData.dacData.uid = uid;
    auditData.dacData.gid = gid;
    auditData.dacData.mode = mode;
    AddSecurityLabel(&auditData);
S
sun_fan 已提交
294
}
M
Mupceet 已提交
295

M
Mupceet 已提交
296
INIT_LOCAL_API void LoadGroupUser(void)
M
Mupceet 已提交
297
{
M
Mupceet 已提交
298 299 300
#ifndef __MUSL__
    return;
#endif
M
Mupceet 已提交
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
    PARAM_LOGV("LoadGroupUser ");
    uid_t uid = 0;
    struct group *data = NULL;
    while ((data = getgrent()) != NULL) {
        if (data->gr_name == NULL || data->gr_mem == NULL) {
            continue;
        }
        if (data->gr_mem[0] == NULL) { // default user in group
            GetUserIdByName(&uid, data->gr_name, strlen(data->gr_name));
            PARAM_LOGV("LoadGroupUser %s gid %d uid %d", data->gr_name, data->gr_gid, uid);
            AddGroupUser(uid, data->gr_gid, 0550, GROUP_FORMAT); // 0550 read and watch
            continue;
        }
        int index = 0;
        while (data->gr_mem[index]) { // user in this group
            GetUserIdByName(&uid, data->gr_mem[index], strlen(data->gr_mem[index]));
            PARAM_LOGV("LoadGroupUser %s gid %d uid %d user %s", data->gr_name, data->gr_gid, uid, data->gr_mem[index]);
M
Mupceet 已提交
318
            AddGroupUser(uid, data->gr_gid, 0550, GROUP_FORMAT); // 0550 read and watch
M
Mupceet 已提交
319 320 321 322 323
            index++;
        }
    }
    PARAM_LOGV("LoadGroupUser getgrent fail errnor %d ", errno);
    endgrent();
324
}