param_dac.c 14.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"
C
cheng_jinsong 已提交
31 32
#define INVALID_MODE 0550
#define GROUP_FILE_PATH "/etc/group"
M
Mupceet 已提交
33
#define OCT_BASE 8
C
cheng_jinsong 已提交
34 35
#define INVALID_UID(uid) ((uid) == (uid_t)-1)

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

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

// user:group:r|w
X
xionglei6 已提交
65
static int GetParamDacData(ParamDacData *dacData, const char *value)
S
sun_fan 已提交
66
{
M
Mupceet 已提交
67 68 69 70 71 72 73 74 75
    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 已提交
76 77 78
    if (dacData == NULL) {
        return -1;
    }
S
sun_fan 已提交
79 80 81 82 83 84 85 86
    char *groupName = strstr(value, ":");
    if (groupName == NULL) {
        return -1;
    }
    char *mode = strstr(groupName + 1, ":");
    if (mode == NULL) {
        return -1;
    }
X
xionglei6 已提交
87 88
    GetUserIdByName(&dacData->uid, value, groupName - value);
    GetGroupIdByName(&dacData->gid, groupName + 1, mode - groupName - 1);
M
Mupceet 已提交
89 90 91 92 93 94 95 96 97 98 99 100 101

    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 已提交
102 103 104
    return 0;
}

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

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

M
Mupceet 已提交
122
static int LoadOneParam_(const uint32_t *context, const char *name, const char *value)
X
xionglei6 已提交
123 124 125 126 127
{
    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);
128 129 130
    if (INVALID_UID(auditData.dacData.gid) || INVALID_UID(auditData.dacData.uid)) {
        PARAM_LOGW("Invalid dac for '%s' gid %d uid %d", name, auditData.dacData.gid, auditData.dacData.uid);
    }
M
Mupceet 已提交
131
    AddSecurityLabel(&auditData);
X
xionglei6 已提交
132 133 134
    return 0;
}

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

static int ProcessParamFile(const char *fileName, void *context)
{
M
Mupceet 已提交
162 163
    UNUSED(context);
    return LoadParamLabels(fileName);
S
sun_fan 已提交
164 165
}

M
Mupceet 已提交
166
static int DacGetParamSecurityLabel(const char *path)
S
sun_fan 已提交
167
{
M
Mupceet 已提交
168
    PARAM_CHECK(path != NULL, return -1, "Invalid param");
S
sun_fan 已提交
169 170
    struct stat st;
    if ((stat(path, &st) == 0) && !S_ISDIR(st.st_mode)) {
M
Mupceet 已提交
171
        return ProcessParamFile(path, NULL);
S
sun_fan 已提交
172
    }
M
Mupceet 已提交
173

M
Mupceet 已提交
174
    PARAM_LOGV("DacGetParamSecurityLabel %s ", path);
M
Mupceet 已提交
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 202 203
    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);
        }
    }
C
fix log  
cheng_jinsong 已提交
204
    PARAM_LOGV("Get parameter security label dac number is %d, from %s.", count, path);
M
Mupceet 已提交
205 206 207
    free(fileName);
    closedir(pDir);
    return 0;
S
sun_fan 已提交
208 209 210 211 212 213 214 215 216
}

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 已提交
217
static int CheckUserInGroup(WorkSpace *space, gid_t groupId, uid_t uid)
X
add ut  
xionglei6 已提交
218
{
M
Mupceet 已提交
219
    char buffer[USER_BUFFER_LEN] = {0};
M
Mupceet 已提交
220
    uint32_t labelIndex = 0;
M
Mupceet 已提交
221
    int ret = ParamSprintf(buffer, sizeof(buffer), "%s.%d.%d", GROUP_FORMAT, groupId, uid);
M
Mupceet 已提交
222 223
    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 已提交
224
    ParamSecurityNode *node = (ParamSecurityNode *)GetTrieNode(space, labelIndex);
M
Mupceet 已提交
225
    PARAM_CHECK(node != NULL, return DAC_RESULT_FORBIDED, "Can not get security label %d", labelIndex);
C
cheng_jinsong 已提交
226
    PARAM_LOGV("CheckUserInGroup %s groupid %d uid %d", buffer, node->gid, node->uid);
M
Mupceet 已提交
227
    if (node->gid == groupId && node->uid == uid) {
X
xionglei6 已提交
228 229
        return 0;
    }
X
add ut  
xionglei6 已提交
230 231 232
    return -1;
}

M
Mupceet 已提交
233
static int DacCheckParamPermission(const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
S
sun_fan 已提交
234
{
C
cheng_jinsong 已提交
235 236 237 238 239
#ifndef STARTUP_INIT_TEST
    if (srcLabel->cred.uid == 0) {
        return DAC_RESULT_PERMISSION;
    }
#endif
S
sun_fan 已提交
240
    int ret = DAC_RESULT_FORBIDED;
M
Mupceet 已提交
241 242 243 244 245
    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 已提交
246
    ParamSecurityNode *node = (ParamSecurityNode *)GetTrieNode(space, labelIndex);
M
Mupceet 已提交
247
    PARAM_CHECK(node != NULL, return DAC_RESULT_FORBIDED, "Can not get security label %d", labelIndex);
S
sun_fan 已提交
248
    /**
M
Mupceet 已提交
249
     * DAC group
S
sun_fan 已提交
250 251
     * user:group:read|write|watch
     */
4
411148299@qq.com 已提交
252
    uint32_t localMode;
M
Mupceet 已提交
253
    if (srcLabel->cred.uid == node->uid) {
S
sun_fan 已提交
254
        localMode = mode & (DAC_READ | DAC_WRITE | DAC_WATCH);
M
Mupceet 已提交
255
    } else if (srcLabel->cred.gid == node->gid) {
S
sun_fan 已提交
256
        localMode = (mode & (DAC_READ | DAC_WRITE | DAC_WATCH)) >> DAC_GROUP_START;
M
Mupceet 已提交
257
    } else if (CheckUserInGroup(space, node->gid, srcLabel->cred.uid) == 0) {  // user in group
X
add ut  
xionglei6 已提交
258
        localMode = (mode & (DAC_READ | DAC_WRITE | DAC_WATCH)) >> DAC_GROUP_START;
S
sun_fan 已提交
259 260 261
    } else {
        localMode = (mode & (DAC_READ | DAC_WRITE | DAC_WATCH)) >> DAC_OTHER_START;
    }
M
Mupceet 已提交
262
    if ((node->mode & localMode) != 0) {
S
sun_fan 已提交
263 264
        ret = DAC_RESULT_PERMISSION;
    }
M
Mupceet 已提交
265 266
    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);
C
cheng_jinsong 已提交
267
        PARAM_LOGW("Cfg label %d gid:%d uid:%d mode 0%o ", labelIndex, node->gid, node->uid, node->mode);
268
#ifndef __MUSL__
C
cheng_jinsong 已提交
269
#ifndef STARTUP_INIT_TEST
M
Mupceet 已提交
270
        ret = DAC_RESULT_PERMISSION;
C
cheng_jinsong 已提交
271
#endif
M
Mupceet 已提交
272 273
#endif
    }
S
sun_fan 已提交
274 275 276
    return ret;
}

M
Mupceet 已提交
277
INIT_LOCAL_API int RegisterSecurityDacOps(ParamSecurityOps *ops, int isInit)
S
sun_fan 已提交
278 279
{
    PARAM_CHECK(ops != NULL, return -1, "Invalid param");
X
xionglei6 已提交
280
    PARAM_LOGV("RegisterSecurityDacOps %d", isInit);
M
Mupceet 已提交
281
    int ret = ParamStrCpy(ops->name, sizeof(ops->name), "dac");
S
sun_fan 已提交
282 283
    ops->securityInitLabel = InitLocalSecurityLabel;
    ops->securityCheckFilePermission = CheckFilePermission;
M
Mupceet 已提交
284
    ops->securityCheckParamPermission = DacCheckParamPermission;
S
sun_fan 已提交
285 286
    ops->securityFreeLabel = FreeLocalSecurityLabel;
    if (isInit) {
M
Mupceet 已提交
287
        ops->securityGetLabel = DacGetParamSecurityLabel;
S
sun_fan 已提交
288
    }
M
Mupceet 已提交
289
    return ret;
S
sun_fan 已提交
290 291
}

C
cheng_jinsong 已提交
292
static void AddGroupUser(const char *userName, gid_t gid)
S
sun_fan 已提交
293
{
C
cheng_jinsong 已提交
294 295 296 297 298 299 300 301 302 303
    if (userName == NULL || strlen(userName) == 0) {
        return;
    }
    uid_t uid = 0;
    GetUserIdByName(&uid, userName, strlen(userName));
    PARAM_LOGV("Add group user '%s' gid %d uid %d", userName, gid, uid);
    if (INVALID_UID(gid) || INVALID_UID(uid)) {
        PARAM_LOGW("Invalid user for '%s' gid %d uid %d", userName, gid, uid);
        return;
    }
M
Mupceet 已提交
304 305
    ParamAuditData auditData = {0};
    char buffer[USER_BUFFER_LEN] = {0};
C
cheng_jinsong 已提交
306 307
    int ret = ParamSprintf(buffer, sizeof(buffer), "%s.%u.%u", GROUP_FORMAT, gid, uid);
    PARAM_CHECK(ret >= 0, return, "Failed to format name for %d.%d", gid, uid);
M
Mupceet 已提交
308 309 310
    auditData.name = buffer;
    auditData.dacData.uid = uid;
    auditData.dacData.gid = gid;
C
cheng_jinsong 已提交
311
    auditData.dacData.mode = INVALID_MODE;
M
Mupceet 已提交
312
    AddSecurityLabel(&auditData);
S
sun_fan 已提交
313
}
M
Mupceet 已提交
314

C
cheng_jinsong 已提交
315 316
#ifdef PARAM_DECODE_GROUPID_FROM_FILE
static char *UserNameTrim(char *str)
M
Mupceet 已提交
317
{
C
cheng_jinsong 已提交
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
    if (str == NULL) {
        return NULL;
    }
    size_t len = strlen(str);
    if (str == NULL || len == 0) {
        return NULL;
    }
    char *end = str + len - 1;
    while (end >= str && (*end == ' ' || *end == '\t' || *end == '\n' || *end == '\r')) {
        *end = '\0';
        end--;
    }
    len = strlen(str);
    char *head = str;
    end = str + strlen(str);
    while (head < end && (*head == ' ' || *head == '\t' || *head == '\n' || *head == '\r')) {
        *head = '\0';
        head++;
    }
    if (strlen(str) == 0) {
        return NULL;
    }
    return head;
}

static void LoadGroupUser_(void)
{
    // decode group file
    FILE *fp = fopen(GROUP_FILE_PATH, "r");
    const uint32_t buffSize = 1024;  // 1024 max buffer for decode
    char *buff = (char *)calloc(1, buffSize);
    while (fp != NULL && buff != NULL && fgets(buff, buffSize, fp) != NULL) {
        buff[buffSize - 1] = '\0';
        // deviceprivate:x:1053:root,shell,system,samgr,hdf_devmgr,deviceinfo,dsoftbus,dms,account
        char *buffer = UserNameTrim(buff);
        PARAM_CHECK(buffer != NULL, continue, "Invalid buffer %s", buff);

        PARAM_LOGV("LoadGroupUser_ '%s'", buffer);
        // group name
        char *groupName = strtok(buffer, ":");
        groupName = UserNameTrim(groupName);
        PARAM_CHECK(groupName != NULL, continue, "Invalid group name %s", buff);

        // skip x
        (void)strtok(NULL, ":");
        char *strGid = strtok(NULL, ":");
        strGid = UserNameTrim(strGid);
        PARAM_CHECK(strGid != NULL, continue, "Invalid gid %s", buff);

        errno = 0;
        gid_t gid = (gid_t)strtoul(strGid, 0, 10); // 10 base
        PARAM_CHECK(errno == 0, continue, "Invalid gid %s", strGid);

        char *userName = strGid + strlen(strGid) + 1;
        userName = UserNameTrim(userName);
        PARAM_LOGV("LoadGroupUser_ %s userName '%s'", groupName, userName);
        if (userName == NULL) {
            AddGroupUser(groupName, gid);
            continue;
        }
        char *tmp = strtok(userName, ",");
        while (tmp != NULL) {
            PARAM_LOGV("LoadGroupUser_ %s userName '%s'", groupName, tmp);
            AddGroupUser(UserNameTrim(tmp), gid);
            userName = tmp + strlen(tmp) + 1;
            tmp = strtok(NULL, ",");
        }
        // last username
        if (userName != NULL) {
            AddGroupUser(UserNameTrim(userName), gid);
        }
    }
    if (fp != NULL) {
        (void)fclose(fp);
    }
    if (buff != NULL) {
        free(buff);
    }
M
Mupceet 已提交
396
    return;
C
cheng_jinsong 已提交
397 398 399 400
}
#else
static void LoadGroupUser_(void)
{
M
Mupceet 已提交
401 402 403 404 405 406
    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
C
cheng_jinsong 已提交
407
            AddGroupUser(data->gr_name, data->gr_gid);
M
Mupceet 已提交
408 409 410 411
            continue;
        }
        int index = 0;
        while (data->gr_mem[index]) { // user in this group
C
cheng_jinsong 已提交
412
            AddGroupUser(data->gr_mem[index], data->gr_gid);
M
Mupceet 已提交
413 414 415 416
            index++;
        }
    }
    endgrent();
417
}
C
cheng_jinsong 已提交
418 419 420 421 422 423 424
#endif

INIT_LOCAL_API void LoadGroupUser(void)
{
    PARAM_LOGV("LoadGroupUser ");
    LoadGroupUser_();
}