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