• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <errno.h>
16 #include <grp.h>
17 #include <pwd.h>
18 #include <sys/stat.h>
19 #include <dirent.h>
20 #include <string.h>
21 
22 #include "param_manager.h"
23 #include "param_security.h"
24 #include "param_trie.h"
25 #include "param_utils.h"
26 #include "param_base.h"
27 
28 #define USER_BUFFER_LEN 64
29 #define MAX_BUF_SIZE  1024
30 #define GROUP_FORMAT "const.group"
31 #define INVALID_MODE 0550
32 #define GROUP_FILE_PATH "/etc/group"
33 #define OCT_BASE 8
34 #define INVALID_UID(uid) ((uid) == (uid_t)-1)
35 
GetUserIdByName(uid_t * uid,const char * name)36 static void GetUserIdByName(uid_t *uid, const char *name)
37 {
38     struct passwd *data = getpwnam(name);
39     if (data == NULL) {
40         *uid = -1;
41         return ;
42     }
43     *uid = data->pw_uid;
44 }
45 
GetGroupIdByName(gid_t * gid,const char * name)46 static void GetGroupIdByName(gid_t *gid, const char *name)
47 {
48     *gid = -1;
49     struct group *data = getgrnam(name);
50     if (data != NULL) {
51         *gid = data->gr_gid;
52         return;
53     }
54     while ((data = getgrent()) != NULL) {
55         if ((data->gr_name != NULL) && (strcmp(data->gr_name, name) == 0)) {
56             *gid = data->gr_gid;
57             break;
58         }
59     }
60     endgrent();
61 }
62 
63 // user:group:r|w
GetParamDacData(ParamDacData * dacData,const char * value)64 static int GetParamDacData(ParamDacData *dacData, const char *value)
65 {
66     static const struct {
67         const char *name;
68         int value;
69     } paramTypes[] = {
70         { "int", PARAM_TYPE_INT },
71         { "string", PARAM_TYPE_STRING },
72         { "bool", PARAM_TYPE_BOOL },
73     };
74 
75     char *groupName = strstr(value, ":");
76     if (groupName == NULL) {
77         return -1;
78     }
79     char *mode = strstr(groupName + 1, ":");
80     if (mode == NULL) {
81         return -1;
82     }
83 
84     uint32_t nameLen = groupName - value;
85     char *name = (char *)value;
86     name[nameLen] = '\0';
87     GetUserIdByName(&dacData->uid, name);
88     nameLen = mode - groupName - 1;
89     name = (char *)groupName + 1;
90     name[nameLen] = '\0';
91     GetGroupIdByName(&dacData->gid, name);
92 
93     dacData->paramType = PARAM_TYPE_STRING;
94     char *type = strstr(mode + 1, ":");
95     if (type != NULL) {
96         *type = '\0';
97         type++;
98         for (size_t i = 0; (type != NULL) && (i < ARRAY_LENGTH(paramTypes)); i++) {
99             if (strcmp(paramTypes[i].name, type) == 0) {
100                 dacData->paramType = paramTypes[i].value;
101             }
102         }
103     }
104     dacData->mode = (uint16_t)strtol(mode + 1, NULL, OCT_BASE);
105     return 0;
106 }
107 
InitLocalSecurityLabel(ParamSecurityLabel * security,int isInit)108 static int InitLocalSecurityLabel(ParamSecurityLabel *security, int isInit)
109 {
110     UNUSED(isInit);
111     PARAM_CHECK(security != NULL, return -1, "Invalid security");
112     security->cred.pid = getpid();
113     security->cred.uid = geteuid();
114     security->cred.gid = getegid();
115     // support check write permission in client
116     security->flags[PARAM_SECURITY_DAC] |= LABEL_CHECK_IN_ALL_PROCESS;
117     return 0;
118 }
119 
FreeLocalSecurityLabel(ParamSecurityLabel * srcLabel)120 static int FreeLocalSecurityLabel(ParamSecurityLabel *srcLabel)
121 {
122     return 0;
123 }
124 
LoadOneParam_(const uint32_t * context,const char * name,const char * value)125 static int LoadOneParam_(const uint32_t *context, const char *name, const char *value)
126 {
127     ParamAuditData auditData = {0};
128     auditData.dacData.gid = -1;
129     auditData.dacData.uid = -1;
130     auditData.name = name;
131     int ret = GetParamDacData(&auditData.dacData, value);
132     PARAM_CHECK(ret == 0, return -1, "Failed to get param info %d %s", ret, name);
133     if (INVALID_UID(auditData.dacData.gid) || INVALID_UID(auditData.dacData.uid)) {
134         PARAM_LOGW("Invalid dac for '%s' gid %d uid %d", name, auditData.dacData.gid, auditData.dacData.uid);
135     }
136     AddSecurityLabel(&auditData);
137     return 0;
138 }
139 
LoadParamLabels(const char * fileName)140 static int LoadParamLabels(const char *fileName)
141 {
142     uint32_t infoCount = 0;
143     FILE *fp = fopen(fileName, "r");
144     const uint32_t buffSize = PARAM_NAME_LEN_MAX + PARAM_CONST_VALUE_LEN_MAX + 10;  // 10 size
145     char *buff = (char *)calloc(1, buffSize);
146     while (fp != NULL && buff != NULL && fgets(buff, buffSize, fp) != NULL) {
147         buff[buffSize - 1] = '\0';
148         int ret = SplitParamString(buff, NULL, 0, LoadOneParam_, NULL);
149         if (ret != 0) {
150             PARAM_LOGE("Failed to split string %s fileName %s", buff, fileName);
151             continue;
152         }
153         infoCount++;
154     }
155     PARAM_LOGI("Load parameter label total %u success %s", infoCount, fileName);
156     if (fp != NULL) {
157         (void)fclose(fp);
158     }
159     if (buff != NULL) {
160         free(buff);
161     }
162     return 0;
163 }
164 
ProcessParamFile(const char * fileName,void * context)165 static int ProcessParamFile(const char *fileName, void *context)
166 {
167     UNUSED(context);
168     return LoadParamLabels(fileName);
169 }
170 
DacGetParamSecurityLabel(const char * path)171 static int DacGetParamSecurityLabel(const char *path)
172 {
173     PARAM_CHECK(path != NULL, return -1, "Invalid param");
174     struct stat st;
175     if ((stat(path, &st) == 0) && !S_ISDIR(st.st_mode)) {
176         return ProcessParamFile(path, NULL);
177     }
178 
179     PARAM_LOGV("DacGetParamSecurityLabel %s ", path);
180     DIR *pDir = opendir(path);
181     PARAM_CHECK(pDir != NULL, return -1, "Read dir :%s failed.%d", path, errno);
182     char *fileName = malloc(MAX_BUF_SIZE);
183     PARAM_CHECK(fileName != NULL, closedir(pDir);
184         return -1, "Failed to malloc for %s", path);
185 
186     struct dirent *dp;
187     uint32_t count = 0;
188     while ((dp = readdir(pDir)) != NULL) {
189         if (dp->d_type == DT_DIR) {
190             continue;
191         }
192         char *tmp = strstr(dp->d_name, ".para.dac");
193         if (tmp == NULL) {
194             continue;
195         }
196         if (strcmp(tmp, ".para.dac") != 0) {
197             continue;
198         }
199         int ret = ParamSprintf(fileName, MAX_BUF_SIZE, "%s/%s", path, dp->d_name);
200         if (ret <= 0) {
201             PARAM_LOGE("Failed to get file name for %s", dp->d_name);
202             continue;
203         }
204         if ((stat(fileName, &st) == 0) && !S_ISDIR(st.st_mode)) {
205             count++;
206             ProcessParamFile(fileName, NULL);
207         }
208     }
209     PARAM_LOGV("Get parameter security label dac number is %d, from %s.", count, path);
210     free(fileName);
211     closedir(pDir);
212     return 0;
213 }
214 
CheckFilePermission(const ParamSecurityLabel * localLabel,const char * fileName,int flags)215 static int CheckFilePermission(const ParamSecurityLabel *localLabel, const char *fileName, int flags)
216 {
217     UNUSED(flags);
218     PARAM_CHECK(localLabel != NULL && fileName != NULL, return -1, "Invalid param");
219     return 0;
220 }
221 
CheckUserInGroup(WorkSpace * space,gid_t groupId,uid_t uid)222 static int CheckUserInGroup(WorkSpace *space, gid_t groupId, uid_t uid)
223 {
224     char buffer[USER_BUFFER_LEN] = {0};
225     uint32_t labelIndex = 0;
226     int ret = ParamSprintf(buffer, sizeof(buffer), "%s.%d.%d", GROUP_FORMAT, groupId, uid);
227     PARAM_CHECK(ret >= 0, return -1, "Failed to format name for %s.%d.%d", GROUP_FORMAT, groupId, uid);
228     (void)FindTrieNode(space, buffer, strlen(buffer), &labelIndex);
229     ParamSecurityNode *node = (ParamSecurityNode *)GetTrieNode(space, labelIndex);
230     PARAM_CHECK(node != NULL, return DAC_RESULT_FORBIDED, "Can not get security label %d", labelIndex);
231     PARAM_LOGV("CheckUserInGroup %s groupid %d uid %d", buffer, node->gid, node->uid);
232     if (node->gid == groupId && node->uid == uid) {
233         return 0;
234     }
235     return -1;
236 }
237 
DacCheckParamPermission(const ParamSecurityLabel * srcLabel,const char * name,uint32_t mode)238 static int DacCheckParamPermission(const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
239 {
240 #ifndef STARTUP_INIT_TEST
241     if (srcLabel->cred.uid == 0) {
242         return DAC_RESULT_PERMISSION;
243     }
244 #endif
245     int ret = DAC_RESULT_FORBIDED;
246     uint32_t labelIndex = 0;
247     // get dac label
248     WorkSpace *space = GetWorkSpace(WORKSPACE_NAME_DAC);
249     PARAM_CHECK(space != NULL, return DAC_RESULT_FORBIDED, "Failed to get dac space %s", name);
250     (void)FindTrieNode(space, name, strlen(name), &labelIndex);
251     ParamSecurityNode *node = (ParamSecurityNode *)GetTrieNode(space, labelIndex);
252     PARAM_CHECK(node != NULL, return DAC_RESULT_FORBIDED, "Can not get security label %d", labelIndex);
253     /**
254      * DAC group
255      * user:group:read|write|watch
256      */
257     uint32_t localMode;
258     if (srcLabel->cred.uid == node->uid) {
259         localMode = mode & (DAC_READ | DAC_WRITE | DAC_WATCH);
260     } else if (srcLabel->cred.gid == node->gid) {
261         localMode = (mode & (DAC_READ | DAC_WRITE | DAC_WATCH)) >> DAC_GROUP_START;
262     } else if (CheckUserInGroup(space, node->gid, srcLabel->cred.uid) == 0) {  // user in group
263         localMode = (mode & (DAC_READ | DAC_WRITE | DAC_WATCH)) >> DAC_GROUP_START;
264     } else {
265         localMode = (mode & (DAC_READ | DAC_WRITE | DAC_WATCH)) >> DAC_OTHER_START;
266     }
267     if ((node->mode & localMode) != 0) {
268         ret = DAC_RESULT_PERMISSION;
269     }
270     if (ret != DAC_RESULT_PERMISSION) {
271         PARAM_LOGW("Param '%s' label gid:%d uid:%d mode 0%o", name, srcLabel->cred.gid, srcLabel->cred.uid, localMode);
272         PARAM_LOGW("Cfg label %d gid:%d uid:%d mode 0%o ", labelIndex, node->gid, node->uid, node->mode);
273 #ifndef __MUSL__
274 #ifndef STARTUP_INIT_TEST
275         ret = DAC_RESULT_PERMISSION;
276 #endif
277 #endif
278     }
279     return ret;
280 }
281 
RegisterSecurityDacOps(ParamSecurityOps * ops,int isInit)282 INIT_LOCAL_API int RegisterSecurityDacOps(ParamSecurityOps *ops, int isInit)
283 {
284     PARAM_CHECK(ops != NULL, return -1, "Invalid param");
285     PARAM_LOGV("RegisterSecurityDacOps %d", isInit);
286     int ret = ParamStrCpy(ops->name, sizeof(ops->name), "dac");
287     ops->securityInitLabel = InitLocalSecurityLabel;
288     ops->securityCheckFilePermission = CheckFilePermission;
289     ops->securityCheckParamPermission = DacCheckParamPermission;
290     ops->securityFreeLabel = FreeLocalSecurityLabel;
291     if (isInit) {
292         ops->securityGetLabel = DacGetParamSecurityLabel;
293     }
294     return ret;
295 }
296 
AddGroupUser(const char * userName,gid_t gid)297 static void AddGroupUser(const char *userName, gid_t gid)
298 {
299     if (userName == NULL || strlen(userName) == 0) {
300         return;
301     }
302     uid_t uid = 0;
303     GetUserIdByName(&uid, userName);
304     PARAM_LOGV("Add group user '%s' gid %d uid %d", userName, gid, uid);
305     if (INVALID_UID(gid) || INVALID_UID(uid)) {
306         PARAM_LOGW("Invalid user for '%s' gid %d uid %d", userName, gid, uid);
307         return;
308     }
309     ParamAuditData auditData = {0};
310     char buffer[USER_BUFFER_LEN] = {0};
311     int ret = ParamSprintf(buffer, sizeof(buffer), "%s.%u.%u", GROUP_FORMAT, gid, uid);
312     PARAM_CHECK(ret >= 0, return, "Failed to format name for %d.%d", gid, uid);
313     auditData.name = buffer;
314     auditData.dacData.uid = uid;
315     auditData.dacData.gid = gid;
316     auditData.dacData.mode = INVALID_MODE;
317     AddSecurityLabel(&auditData);
318 }
319 
320 #ifdef PARAM_DECODE_GROUPID_FROM_FILE
UserNameTrim(char * str)321 static char *UserNameTrim(char *str)
322 {
323     if (str == NULL) {
324         return NULL;
325     }
326     size_t len = strlen(str);
327     if (str == NULL || len == 0) {
328         return NULL;
329     }
330     char *end = str + len - 1;
331     while (end >= str && (*end == ' ' || *end == '\t' || *end == '\n' || *end == '\r')) {
332         *end = '\0';
333         end--;
334     }
335     len = strlen(str);
336     char *head = str;
337     end = str + strlen(str);
338     while (head < end && (*head == ' ' || *head == '\t' || *head == '\n' || *head == '\r')) {
339         *head = '\0';
340         head++;
341     }
342     if (strlen(str) == 0) {
343         return NULL;
344     }
345     return head;
346 }
347 
LoadGroupUser_(void)348 static void LoadGroupUser_(void)
349 {
350     // decode group file
351     FILE *fp = fopen(GROUP_FILE_PATH, "r");
352     const uint32_t buffSize = 1024;  // 1024 max buffer for decode
353     char *buff = (char *)calloc(1, buffSize);
354     while (fp != NULL && buff != NULL && fgets(buff, buffSize, fp) != NULL) {
355         buff[buffSize - 1] = '\0';
356         // deviceprivate:x:1053:root,shell,system,samgr,hdf_devmgr,deviceinfo,dsoftbus,dms,account
357         char *buffer = UserNameTrim(buff);
358         PARAM_CHECK(buffer != NULL, continue, "Invalid buffer %s", buff);
359 
360         PARAM_LOGV("LoadGroupUser_ '%s'", buffer);
361         // group name
362         char *groupName = strtok(buffer, ":");
363         groupName = UserNameTrim(groupName);
364         PARAM_CHECK(groupName != NULL, continue, "Invalid group name %s", buff);
365         gid_t gid = -1;
366         GetGroupIdByName(&gid, groupName);
367 
368         // skip x
369         (void)strtok(NULL, ":");
370         char *strGid = strtok(NULL, ":");
371         char *userName = strGid + strlen(strGid) + 1;
372         userName = UserNameTrim(userName);
373         PARAM_LOGV("LoadGroupUser_ %s userName '%s'", groupName, userName);
374         if (userName == NULL) {
375             AddGroupUser(groupName, gid);
376             continue;
377         }
378         char *tmp = strtok(userName, ",");
379         while (tmp != NULL) {
380             PARAM_LOGV("LoadGroupUser_ %s userName '%s'", groupName, tmp);
381             AddGroupUser(UserNameTrim(tmp), gid);
382             userName = tmp + strlen(tmp) + 1;
383             tmp = strtok(NULL, ",");
384         }
385         // last username
386         if (userName != NULL) {
387             AddGroupUser(UserNameTrim(userName), gid);
388         }
389     }
390     if (fp != NULL) {
391         (void)fclose(fp);
392     }
393     if (buff != NULL) {
394         free(buff);
395     }
396     return;
397 }
398 #else
LoadGroupUser_(void)399 static void LoadGroupUser_(void)
400 {
401     struct group *data = NULL;
402     while ((data = getgrent()) != NULL) {
403         if (data->gr_name == NULL || data->gr_mem == NULL) {
404             continue;
405         }
406         if (data->gr_mem[0] == NULL) { // default user in group
407             AddGroupUser(data->gr_name, data->gr_gid);
408             continue;
409         }
410         int index = 0;
411         while (data->gr_mem[index]) { // user in this group
412             AddGroupUser(data->gr_mem[index], data->gr_gid);
413             index++;
414         }
415     }
416     endgrent();
417 }
418 #endif
419 
LoadGroupUser(void)420 INIT_LOCAL_API void LoadGroupUser(void)
421 {
422     PARAM_LOGV("LoadGroupUser ");
423     LoadGroupUser_();
424 }
425