1d9f0492fSopenharmony_ci/*
2d9f0492fSopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3d9f0492fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4d9f0492fSopenharmony_ci * you may not use this file except in compliance with the License.
5d9f0492fSopenharmony_ci * You may obtain a copy of the License at
6d9f0492fSopenharmony_ci *
7d9f0492fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8d9f0492fSopenharmony_ci *
9d9f0492fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10d9f0492fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11d9f0492fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12d9f0492fSopenharmony_ci * See the License for the specific language governing permissions and
13d9f0492fSopenharmony_ci * limitations under the License.
14d9f0492fSopenharmony_ci */
15d9f0492fSopenharmony_ci#include <errno.h>
16d9f0492fSopenharmony_ci#include <grp.h>
17d9f0492fSopenharmony_ci#include <pwd.h>
18d9f0492fSopenharmony_ci#include <sys/stat.h>
19d9f0492fSopenharmony_ci#include <dirent.h>
20d9f0492fSopenharmony_ci#include <string.h>
21d9f0492fSopenharmony_ci
22d9f0492fSopenharmony_ci#include "param_manager.h"
23d9f0492fSopenharmony_ci#include "param_security.h"
24d9f0492fSopenharmony_ci#include "param_trie.h"
25d9f0492fSopenharmony_ci#include "param_utils.h"
26d9f0492fSopenharmony_ci#include "param_base.h"
27d9f0492fSopenharmony_ci
28d9f0492fSopenharmony_ci#define MAX_MEMBER_IN_GROUP  128
29d9f0492fSopenharmony_ci#define MAX_BUF_SIZE  1024
30d9f0492fSopenharmony_ci#define INVALID_MODE 0550
31d9f0492fSopenharmony_ci#ifdef STARTUP_INIT_TEST
32d9f0492fSopenharmony_ci#define GROUP_FILE_PATH STARTUP_INIT_UT_PATH "/etc/group"
33d9f0492fSopenharmony_ci#else
34d9f0492fSopenharmony_ci#define GROUP_FILE_PATH "/etc/group"
35d9f0492fSopenharmony_ci#endif
36d9f0492fSopenharmony_ci#define OCT_BASE 8
37d9f0492fSopenharmony_ci#define INVALID_UID(uid) ((uid) == (uid_t)-1)
38d9f0492fSopenharmony_ci
39d9f0492fSopenharmony_cistatic void GetUserIdByName(uid_t *uid, const char *name)
40d9f0492fSopenharmony_ci{
41d9f0492fSopenharmony_ci    struct passwd *data = getpwnam(name);
42d9f0492fSopenharmony_ci    if (data == NULL) {
43d9f0492fSopenharmony_ci        *uid = -1;
44d9f0492fSopenharmony_ci        return ;
45d9f0492fSopenharmony_ci    }
46d9f0492fSopenharmony_ci    *uid = data->pw_uid;
47d9f0492fSopenharmony_ci}
48d9f0492fSopenharmony_ci
49d9f0492fSopenharmony_cistatic void GetGroupIdByName(gid_t *gid, const char *name)
50d9f0492fSopenharmony_ci{
51d9f0492fSopenharmony_ci    *gid = -1;
52d9f0492fSopenharmony_ci    struct group *data = getgrnam(name);
53d9f0492fSopenharmony_ci    if (data != NULL) {
54d9f0492fSopenharmony_ci        *gid = data->gr_gid;
55d9f0492fSopenharmony_ci        return;
56d9f0492fSopenharmony_ci    }
57d9f0492fSopenharmony_ci    while ((data = getgrent()) != NULL) {
58d9f0492fSopenharmony_ci        if ((data->gr_name != NULL) && (strcmp(data->gr_name, name) == 0)) {
59d9f0492fSopenharmony_ci            *gid = data->gr_gid;
60d9f0492fSopenharmony_ci            break;
61d9f0492fSopenharmony_ci        }
62d9f0492fSopenharmony_ci    }
63d9f0492fSopenharmony_ci    endgrent();
64d9f0492fSopenharmony_ci}
65d9f0492fSopenharmony_ci
66d9f0492fSopenharmony_ci// user:group:r|w
67d9f0492fSopenharmony_cistatic int GetParamDacData(ParamDacData *dacData, const char *value)
68d9f0492fSopenharmony_ci{
69d9f0492fSopenharmony_ci    static const struct {
70d9f0492fSopenharmony_ci        const char *name;
71d9f0492fSopenharmony_ci        int value;
72d9f0492fSopenharmony_ci    } paramTypes[] = {
73d9f0492fSopenharmony_ci        { "int", PARAM_TYPE_INT },
74d9f0492fSopenharmony_ci        { "string", PARAM_TYPE_STRING },
75d9f0492fSopenharmony_ci        { "bool", PARAM_TYPE_BOOL },
76d9f0492fSopenharmony_ci    };
77d9f0492fSopenharmony_ci
78d9f0492fSopenharmony_ci    char *groupName = strstr(value, ":");
79d9f0492fSopenharmony_ci    if (groupName == NULL) {
80d9f0492fSopenharmony_ci        return -1;
81d9f0492fSopenharmony_ci    }
82d9f0492fSopenharmony_ci    char *mode = strstr(groupName + 1, ":");
83d9f0492fSopenharmony_ci    if (mode == NULL) {
84d9f0492fSopenharmony_ci        return -1;
85d9f0492fSopenharmony_ci    }
86d9f0492fSopenharmony_ci
87d9f0492fSopenharmony_ci    uint32_t nameLen = groupName - value;
88d9f0492fSopenharmony_ci    char *name = (char *)value;
89d9f0492fSopenharmony_ci    name[nameLen] = '\0';
90d9f0492fSopenharmony_ci    GetUserIdByName(&dacData->uid, name);
91d9f0492fSopenharmony_ci    nameLen = mode - groupName - 1;
92d9f0492fSopenharmony_ci    name = (char *)groupName + 1;
93d9f0492fSopenharmony_ci    name[nameLen] = '\0';
94d9f0492fSopenharmony_ci    GetGroupIdByName(&dacData->gid, name);
95d9f0492fSopenharmony_ci
96d9f0492fSopenharmony_ci    dacData->paramType = PARAM_TYPE_STRING;
97d9f0492fSopenharmony_ci    char *type = strstr(mode + 1, ":");
98d9f0492fSopenharmony_ci    if (type != NULL) {
99d9f0492fSopenharmony_ci        *type = '\0';
100d9f0492fSopenharmony_ci        type++;
101d9f0492fSopenharmony_ci        for (size_t i = 0; (type != NULL) && (i < ARRAY_LENGTH(paramTypes)); i++) {
102d9f0492fSopenharmony_ci            if (strcmp(paramTypes[i].name, type) == 0) {
103d9f0492fSopenharmony_ci                dacData->paramType = paramTypes[i].value;
104d9f0492fSopenharmony_ci            }
105d9f0492fSopenharmony_ci        }
106d9f0492fSopenharmony_ci    }
107d9f0492fSopenharmony_ci    dacData->mode = (uint16_t)strtol(mode + 1, NULL, OCT_BASE);
108d9f0492fSopenharmony_ci    return 0;
109d9f0492fSopenharmony_ci}
110d9f0492fSopenharmony_ci
111d9f0492fSopenharmony_cistatic int InitLocalSecurityLabel(ParamSecurityLabel *security, int isInit)
112d9f0492fSopenharmony_ci{
113d9f0492fSopenharmony_ci    UNUSED(isInit);
114d9f0492fSopenharmony_ci    PARAM_CHECK(security != NULL, return -1, "Invalid security");
115d9f0492fSopenharmony_ci    security->cred.pid = getpid();
116d9f0492fSopenharmony_ci    security->cred.uid = geteuid();
117d9f0492fSopenharmony_ci    security->cred.gid = getegid();
118d9f0492fSopenharmony_ci    // support check write permission in client
119d9f0492fSopenharmony_ci    security->flags[PARAM_SECURITY_DAC] |= LABEL_CHECK_IN_ALL_PROCESS;
120d9f0492fSopenharmony_ci    return 0;
121d9f0492fSopenharmony_ci}
122d9f0492fSopenharmony_ci
123d9f0492fSopenharmony_cistatic int FreeLocalSecurityLabel(ParamSecurityLabel *srcLabel)
124d9f0492fSopenharmony_ci{
125d9f0492fSopenharmony_ci    return 0;
126d9f0492fSopenharmony_ci}
127d9f0492fSopenharmony_ci
128d9f0492fSopenharmony_cistatic int DacGetGroupMember(gid_t gid, uid_t *member, uint32_t *memberSize)
129d9f0492fSopenharmony_ci{
130d9f0492fSopenharmony_ci    int32_t inputLen = (int32_t)*memberSize;
131d9f0492fSopenharmony_ci    *memberSize = 0;
132d9f0492fSopenharmony_ci    struct group *data = getgrgid(gid);
133d9f0492fSopenharmony_ci    if (data == NULL || data->gr_mem == NULL) {
134d9f0492fSopenharmony_ci        return 0;
135d9f0492fSopenharmony_ci    }
136d9f0492fSopenharmony_ci    int i = 0;
137d9f0492fSopenharmony_ci    int memIndex = 0;
138d9f0492fSopenharmony_ci    while (data->gr_mem[i]) {
139d9f0492fSopenharmony_ci        uid_t uid;
140d9f0492fSopenharmony_ci        GetUserIdByName(&uid, data->gr_mem[i]);
141d9f0492fSopenharmony_ci        if (INVALID_UID(uid)) {
142d9f0492fSopenharmony_ci            i++;
143d9f0492fSopenharmony_ci            continue;
144d9f0492fSopenharmony_ci        }
145d9f0492fSopenharmony_ci        if ((memIndex + 1) > inputLen) {
146d9f0492fSopenharmony_ci            PARAM_LOGE("Not enough memory for uid member %u", gid);
147d9f0492fSopenharmony_ci            break;
148d9f0492fSopenharmony_ci        }
149d9f0492fSopenharmony_ci        member[memIndex++] = uid;
150d9f0492fSopenharmony_ci        i++;
151d9f0492fSopenharmony_ci    }
152d9f0492fSopenharmony_ci    uid_t uid = 0;
153d9f0492fSopenharmony_ci    GetUserIdByName(&uid, data->gr_name);
154d9f0492fSopenharmony_ci    if (!INVALID_UID(uid) && ((memIndex + 1) < inputLen)) {
155d9f0492fSopenharmony_ci        member[memIndex++] = uid;
156d9f0492fSopenharmony_ci    }
157d9f0492fSopenharmony_ci    *memberSize = memIndex;
158d9f0492fSopenharmony_ci    return 0;
159d9f0492fSopenharmony_ci}
160d9f0492fSopenharmony_ci
161d9f0492fSopenharmony_cistatic int LoadOneParam_(const uint32_t *context, const char *name, const char *value)
162d9f0492fSopenharmony_ci{
163d9f0492fSopenharmony_ci    ParamAuditData *auditData = (ParamAuditData *)context;
164d9f0492fSopenharmony_ci    auditData->dacData.gid = -1;
165d9f0492fSopenharmony_ci    auditData->dacData.uid = -1;
166d9f0492fSopenharmony_ci    auditData->name = name;
167d9f0492fSopenharmony_ci    int ret = GetParamDacData(&auditData->dacData, value);
168d9f0492fSopenharmony_ci    PARAM_CHECK(ret == 0, return -1, "Failed to get param info %d %s", ret, name);
169d9f0492fSopenharmony_ci    if (INVALID_UID(auditData->dacData.gid) || INVALID_UID(auditData->dacData.uid)) {
170d9f0492fSopenharmony_ci        PARAM_LOGW("Invalid dac for '%s' gid %d uid %d", name, auditData->dacData.gid, auditData->dacData.uid);
171d9f0492fSopenharmony_ci    }
172d9f0492fSopenharmony_ci    // get uid from group
173d9f0492fSopenharmony_ci    auditData->memberNum = MAX_MEMBER_IN_GROUP;
174d9f0492fSopenharmony_ci    ret = DacGetGroupMember(auditData->dacData.gid, auditData->members, &auditData->memberNum);
175d9f0492fSopenharmony_ci    if (ret != 0) {
176d9f0492fSopenharmony_ci        auditData->memberNum = 1;
177d9f0492fSopenharmony_ci        auditData->members[0] = auditData->dacData.gid;
178d9f0492fSopenharmony_ci    }
179d9f0492fSopenharmony_ci
180d9f0492fSopenharmony_ci    return AddSecurityLabel(auditData);
181d9f0492fSopenharmony_ci}
182d9f0492fSopenharmony_ci
183d9f0492fSopenharmony_cistatic int LoadParamLabels(const char *fileName)
184d9f0492fSopenharmony_ci{
185d9f0492fSopenharmony_ci    int result = 0;
186d9f0492fSopenharmony_ci    ParamAuditData *auditData = (ParamAuditData *)calloc(1,
187d9f0492fSopenharmony_ci        sizeof(ParamAuditData) + sizeof(uid_t) * MAX_MEMBER_IN_GROUP);
188d9f0492fSopenharmony_ci    if (auditData == NULL) {
189d9f0492fSopenharmony_ci        PARAM_LOGE("Failed to alloc memory %s", fileName);
190d9f0492fSopenharmony_ci        return result;
191d9f0492fSopenharmony_ci    }
192d9f0492fSopenharmony_ci    uint32_t infoCount = 0;
193d9f0492fSopenharmony_ci    FILE *fp = fopen(fileName, "r");
194d9f0492fSopenharmony_ci    const uint32_t buffSize = PARAM_NAME_LEN_MAX + PARAM_CONST_VALUE_LEN_MAX + 10;  // 10 size
195d9f0492fSopenharmony_ci    char *buff = (char *)calloc(1, buffSize);
196d9f0492fSopenharmony_ci    while (fp != NULL && buff != NULL && fgets(buff, buffSize, fp) != NULL) {
197d9f0492fSopenharmony_ci        buff[buffSize - 1] = '\0';
198d9f0492fSopenharmony_ci        result = SplitParamString(buff, NULL, 0, LoadOneParam_, (const uint32_t *)auditData);
199d9f0492fSopenharmony_ci        if (result != 0) {
200d9f0492fSopenharmony_ci            PARAM_LOGE("Failed to split string %s fileName %s, result is:%d", buff, fileName, result);
201d9f0492fSopenharmony_ci            break;
202d9f0492fSopenharmony_ci        }
203d9f0492fSopenharmony_ci        infoCount++;
204d9f0492fSopenharmony_ci    }
205d9f0492fSopenharmony_ci
206d9f0492fSopenharmony_ci    if (result == 0) {
207d9f0492fSopenharmony_ci        PARAM_LOGI("Load parameter label total %u success %s", infoCount, fileName);
208d9f0492fSopenharmony_ci    }
209d9f0492fSopenharmony_ci
210d9f0492fSopenharmony_ci    if (fp != NULL) {
211d9f0492fSopenharmony_ci        (void)fclose(fp);
212d9f0492fSopenharmony_ci    }
213d9f0492fSopenharmony_ci    if (buff != NULL) {
214d9f0492fSopenharmony_ci        free(buff);
215d9f0492fSopenharmony_ci    }
216d9f0492fSopenharmony_ci    if (auditData != NULL) {
217d9f0492fSopenharmony_ci        free(auditData);
218d9f0492fSopenharmony_ci    }
219d9f0492fSopenharmony_ci    return result;
220d9f0492fSopenharmony_ci}
221d9f0492fSopenharmony_ci
222d9f0492fSopenharmony_cistatic int ProcessParamFile(const char *fileName, void *context)
223d9f0492fSopenharmony_ci{
224d9f0492fSopenharmony_ci    UNUSED(context);
225d9f0492fSopenharmony_ci    return LoadParamLabels(fileName);
226d9f0492fSopenharmony_ci}
227d9f0492fSopenharmony_ci
228d9f0492fSopenharmony_cistatic int DacGetParamSecurityLabel(const char *path)
229d9f0492fSopenharmony_ci{
230d9f0492fSopenharmony_ci    PARAM_CHECK(path != NULL, return -1, "Invalid param");
231d9f0492fSopenharmony_ci    struct stat st;
232d9f0492fSopenharmony_ci    if ((stat(path, &st) == 0) && !S_ISDIR(st.st_mode)) {
233d9f0492fSopenharmony_ci        return ProcessParamFile(path, NULL);
234d9f0492fSopenharmony_ci    }
235d9f0492fSopenharmony_ci
236d9f0492fSopenharmony_ci    PARAM_LOGV("DacGetParamSecurityLabel %s ", path);
237d9f0492fSopenharmony_ci    DIR *pDir = opendir(path);
238d9f0492fSopenharmony_ci    PARAM_CHECK(pDir != NULL, return -1, "Read dir :%s failed.%d", path, errno);
239d9f0492fSopenharmony_ci    char *fileName = calloc(1, MAX_BUF_SIZE);
240d9f0492fSopenharmony_ci    PARAM_CHECK(fileName != NULL, closedir(pDir);
241d9f0492fSopenharmony_ci        return -1, "Failed to malloc for %s", path);
242d9f0492fSopenharmony_ci
243d9f0492fSopenharmony_ci    struct dirent *dp;
244d9f0492fSopenharmony_ci    uint32_t count = 0;
245d9f0492fSopenharmony_ci    while ((dp = readdir(pDir)) != NULL) {
246d9f0492fSopenharmony_ci        if (dp->d_type == DT_DIR) {
247d9f0492fSopenharmony_ci            continue;
248d9f0492fSopenharmony_ci        }
249d9f0492fSopenharmony_ci        char *tmp = strstr(dp->d_name, ".para.dac");
250d9f0492fSopenharmony_ci        if (tmp == NULL) {
251d9f0492fSopenharmony_ci            continue;
252d9f0492fSopenharmony_ci        }
253d9f0492fSopenharmony_ci        if (strcmp(tmp, ".para.dac") != 0) {
254d9f0492fSopenharmony_ci            continue;
255d9f0492fSopenharmony_ci        }
256d9f0492fSopenharmony_ci        int ret = PARAM_SPRINTF(fileName, MAX_BUF_SIZE, "%s/%s", path, dp->d_name);
257d9f0492fSopenharmony_ci        if (ret <= 0) {
258d9f0492fSopenharmony_ci            PARAM_LOGE("Failed to get file name for %s", dp->d_name);
259d9f0492fSopenharmony_ci            continue;
260d9f0492fSopenharmony_ci        }
261d9f0492fSopenharmony_ci        if ((stat(fileName, &st) == 0) && !S_ISDIR(st.st_mode)) {
262d9f0492fSopenharmony_ci            count++;
263d9f0492fSopenharmony_ci            ret = ProcessParamFile(fileName, NULL);
264d9f0492fSopenharmony_ci            if (ret != 0) {
265d9f0492fSopenharmony_ci                free(fileName);
266d9f0492fSopenharmony_ci                closedir(pDir);
267d9f0492fSopenharmony_ci                return ret;
268d9f0492fSopenharmony_ci            };
269d9f0492fSopenharmony_ci        }
270d9f0492fSopenharmony_ci    }
271d9f0492fSopenharmony_ci    PARAM_LOGV("Get parameter security label dac number is %d, from %s.", count, path);
272d9f0492fSopenharmony_ci    free(fileName);
273d9f0492fSopenharmony_ci    closedir(pDir);
274d9f0492fSopenharmony_ci    return 0;
275d9f0492fSopenharmony_ci}
276d9f0492fSopenharmony_ci
277d9f0492fSopenharmony_cistatic int CheckFilePermission(const ParamSecurityLabel *localLabel, const char *fileName, int flags)
278d9f0492fSopenharmony_ci{
279d9f0492fSopenharmony_ci    UNUSED(flags);
280d9f0492fSopenharmony_ci    PARAM_CHECK(localLabel != NULL && fileName != NULL, return -1, "Invalid param");
281d9f0492fSopenharmony_ci    return 0;
282d9f0492fSopenharmony_ci}
283d9f0492fSopenharmony_ci
284d9f0492fSopenharmony_ciINIT_LOCAL_API int RegisterSecurityDacOps(ParamSecurityOps *ops, int isInit)
285d9f0492fSopenharmony_ci{
286d9f0492fSopenharmony_ci    PARAM_CHECK(ops != NULL, return -1, "Invalid param");
287d9f0492fSopenharmony_ci    PARAM_LOGV("RegisterSecurityDacOps %d", isInit);
288d9f0492fSopenharmony_ci    int ret = PARAM_STRCPY(ops->name, sizeof(ops->name), "dac");
289d9f0492fSopenharmony_ci    ops->securityInitLabel = InitLocalSecurityLabel;
290d9f0492fSopenharmony_ci    ops->securityCheckFilePermission = CheckFilePermission;
291d9f0492fSopenharmony_ci#ifdef STARTUP_INIT_TEST
292d9f0492fSopenharmony_ci    ops->securityCheckParamPermission = DacCheckParamPermission;
293d9f0492fSopenharmony_ci#endif
294d9f0492fSopenharmony_ci    ops->securityFreeLabel = FreeLocalSecurityLabel;
295d9f0492fSopenharmony_ci    if (isInit) {
296d9f0492fSopenharmony_ci        ops->securityGetLabel = DacGetParamSecurityLabel;
297d9f0492fSopenharmony_ci    }
298d9f0492fSopenharmony_ci    return ret;
299d9f0492fSopenharmony_ci}
300