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 MAX_BUF_SIZE 1024
29 #define INVALID_MODE 0550
30 #ifdef STARTUP_INIT_TEST
31 #define GROUP_FILE_PATH STARTUP_INIT_UT_PATH "/etc/group"
32 #else
33 #define GROUP_FILE_PATH "/etc/group"
34 #endif
35 #define OCT_BASE 8
36 #define INVALID_UID(uid) ((uid) == (uid_t)-1)
37
GetUserIdByName(uid_t * uid,const char * name)38 static void GetUserIdByName(uid_t *uid, const char *name)
39 {
40 struct passwd *data = getpwnam(name);
41 if (data == NULL) {
42 *uid = -1;
43 return ;
44 }
45 *uid = data->pw_uid;
46 }
47
GetGroupIdByName(gid_t * gid,const char * name)48 static void GetGroupIdByName(gid_t *gid, const char *name)
49 {
50 *gid = -1;
51 struct group *data = getgrnam(name);
52 if (data != NULL) {
53 *gid = data->gr_gid;
54 return;
55 }
56 while ((data = getgrent()) != NULL) {
57 if ((data->gr_name != NULL) && (strcmp(data->gr_name, name) == 0)) {
58 *gid = data->gr_gid;
59 break;
60 }
61 }
62 endgrent();
63 }
64
65 // user:group:r|w
GetParamDacData(ParamDacData * dacData,const char * value)66 static int GetParamDacData(ParamDacData *dacData, const char *value)
67 {
68 static const struct {
69 const char *name;
70 int value;
71 } paramTypes[] = {
72 { "int", PARAM_TYPE_INT },
73 { "string", PARAM_TYPE_STRING },
74 { "bool", PARAM_TYPE_BOOL },
75 };
76
77 char *groupName = strstr(value, ":");
78 if (groupName == NULL) {
79 return -1;
80 }
81 char *mode = strstr(groupName + 1, ":");
82 if (mode == NULL) {
83 return -1;
84 }
85
86 uint32_t nameLen = groupName - value;
87 char *name = (char *)value;
88 name[nameLen] = '\0';
89 GetUserIdByName(&dacData->uid, name);
90 nameLen = mode - groupName - 1;
91 name = (char *)groupName + 1;
92 name[nameLen] = '\0';
93 GetGroupIdByName(&dacData->gid, name);
94
95 dacData->paramType = PARAM_TYPE_STRING;
96 char *type = strstr(mode + 1, ":");
97 if (type != NULL) {
98 *type = '\0';
99 type++;
100 for (size_t i = 0; (type != NULL) && (i < ARRAY_LENGTH(paramTypes)); i++) {
101 if (strcmp(paramTypes[i].name, type) == 0) {
102 dacData->paramType = paramTypes[i].value;
103 }
104 }
105 }
106 dacData->mode = (uint16_t)strtol(mode + 1, NULL, OCT_BASE);
107 return 0;
108 }
109
InitLocalSecurityLabel(ParamSecurityLabel * security,int isInit)110 static int InitLocalSecurityLabel(ParamSecurityLabel *security, int isInit)
111 {
112 UNUSED(isInit);
113 PARAM_CHECK(security != NULL, return -1, "Invalid security");
114 security->cred.pid = getpid();
115 security->cred.uid = geteuid();
116 security->cred.gid = getegid();
117 // support check write permission in client
118 security->flags[PARAM_SECURITY_DAC] |= LABEL_CHECK_IN_ALL_PROCESS;
119 return 0;
120 }
121
FreeLocalSecurityLabel(ParamSecurityLabel * srcLabel)122 static int FreeLocalSecurityLabel(ParamSecurityLabel *srcLabel)
123 {
124 return 0;
125 }
126
LoadOneParam_(const uint32_t * context,const char * name,const char * value)127 static int LoadOneParam_(const uint32_t *context, const char *name, const char *value)
128 {
129 ParamAuditData auditData = {0};
130 auditData.dacData.gid = -1;
131 auditData.dacData.uid = -1;
132 auditData.name = name;
133 int ret = GetParamDacData(&auditData.dacData, value);
134 PARAM_CHECK(ret == 0, return -1, "Failed to get param info %d %s", ret, name);
135 if (INVALID_UID(auditData.dacData.gid) || INVALID_UID(auditData.dacData.uid)) {
136 PARAM_LOGW("Invalid dac for '%s' gid %d uid %d", name, auditData.dacData.gid, auditData.dacData.uid);
137 }
138 AddSecurityLabel(&auditData);
139 return 0;
140 }
141
LoadParamLabels(const char * fileName)142 static int LoadParamLabels(const char *fileName)
143 {
144 uint32_t infoCount = 0;
145 FILE *fp = fopen(fileName, "r");
146 const uint32_t buffSize = PARAM_NAME_LEN_MAX + PARAM_CONST_VALUE_LEN_MAX + 10; // 10 size
147 char *buff = (char *)calloc(1, buffSize);
148 while (fp != NULL && buff != NULL && fgets(buff, buffSize, fp) != NULL) {
149 buff[buffSize - 1] = '\0';
150 int ret = SplitParamString(buff, NULL, 0, LoadOneParam_, NULL);
151 if (ret != 0) {
152 PARAM_LOGE("Failed to split string %s fileName %s", buff, fileName);
153 continue;
154 }
155 infoCount++;
156 }
157 PARAM_LOGI("Load parameter label total %u success %s", infoCount, fileName);
158 if (fp != NULL) {
159 (void)fclose(fp);
160 }
161 if (buff != NULL) {
162 free(buff);
163 }
164 return 0;
165 }
166
ProcessParamFile(const char * fileName,void * context)167 static int ProcessParamFile(const char *fileName, void *context)
168 {
169 UNUSED(context);
170 return LoadParamLabels(fileName);
171 }
172
DacGetParamSecurityLabel(const char * path)173 static int DacGetParamSecurityLabel(const char *path)
174 {
175 PARAM_CHECK(path != NULL, return -1, "Invalid param");
176 struct stat st;
177 if ((stat(path, &st) == 0) && !S_ISDIR(st.st_mode)) {
178 return ProcessParamFile(path, NULL);
179 }
180
181 PARAM_LOGV("DacGetParamSecurityLabel %s ", path);
182 DIR *pDir = opendir(path);
183 PARAM_CHECK(pDir != NULL, return -1, "Read dir :%s failed.%d", path, errno);
184 char *fileName = malloc(MAX_BUF_SIZE);
185 PARAM_CHECK(fileName != NULL, closedir(pDir);
186 return -1, "Failed to malloc for %s", path);
187
188 struct dirent *dp;
189 uint32_t count = 0;
190 while ((dp = readdir(pDir)) != NULL) {
191 if (dp->d_type == DT_DIR) {
192 continue;
193 }
194 char *tmp = strstr(dp->d_name, ".para.dac");
195 if (tmp == NULL) {
196 continue;
197 }
198 if (strcmp(tmp, ".para.dac") != 0) {
199 continue;
200 }
201 int ret = PARAM_SPRINTF(fileName, MAX_BUF_SIZE, "%s/%s", path, dp->d_name);
202 if (ret <= 0) {
203 PARAM_LOGE("Failed to get file name for %s", dp->d_name);
204 continue;
205 }
206 if ((stat(fileName, &st) == 0) && !S_ISDIR(st.st_mode)) {
207 count++;
208 ProcessParamFile(fileName, NULL);
209 }
210 }
211 PARAM_LOGV("Get parameter security label dac number is %d, from %s.", count, path);
212 free(fileName);
213 closedir(pDir);
214 return 0;
215 }
216
CheckFilePermission(const ParamSecurityLabel * localLabel,const char * fileName,int flags)217 static int CheckFilePermission(const ParamSecurityLabel *localLabel, const char *fileName, int flags)
218 {
219 UNUSED(flags);
220 PARAM_CHECK(localLabel != NULL && fileName != NULL, return -1, "Invalid param");
221 return 0;
222 }
223
RegisterSecurityDacOps(ParamSecurityOps * ops,int isInit)224 INIT_LOCAL_API int RegisterSecurityDacOps(ParamSecurityOps *ops, int isInit)
225 {
226 PARAM_CHECK(ops != NULL, return -1, "Invalid param");
227 PARAM_LOGV("RegisterSecurityDacOps %d", isInit);
228 int ret = PARAM_STRCPY(ops->name, sizeof(ops->name), "dac");
229 ops->securityInitLabel = InitLocalSecurityLabel;
230 ops->securityCheckFilePermission = CheckFilePermission;
231 #ifdef STARTUP_INIT_TEST
232 ops->securityCheckParamPermission = DacCheckParamPermission;
233 #endif
234 ops->securityFreeLabel = FreeLocalSecurityLabel;
235 if (isInit) {
236 ops->securityGetLabel = DacGetParamSecurityLabel;
237 }
238 return ret;
239 }
240
AddGroupUser(const char * userName,gid_t gid)241 static void AddGroupUser(const char *userName, gid_t gid)
242 {
243 if (userName == NULL || strlen(userName) == 0) {
244 return;
245 }
246 uid_t uid = 0;
247 GetUserIdByName(&uid, userName);
248 PARAM_LOGV("Add group user '%s' gid %d uid %d", userName, gid, uid);
249 if (INVALID_UID(gid) || INVALID_UID(uid)) {
250 PARAM_LOGW("Invalid user for '%s' gid %d uid %d", userName, gid, uid);
251 return;
252 }
253 char buffer[USER_BUFFER_LEN] = {0};
254 int ret = PARAM_SPRINTF(buffer, sizeof(buffer), GROUP_FORMAT, gid, uid);
255 PARAM_CHECK(ret >= 0, return, "Failed to format name for %d.%d", gid, uid);
256 (void)AddParamEntry(WORKSPACE_INDEX_BASE, PARAM_TYPE_STRING, buffer, "1");
257 }
258
259 #ifdef PARAM_DECODE_GROUPID_FROM_FILE
UserNameTrim(char * str)260 static char *UserNameTrim(char *str)
261 {
262 if (str == NULL) {
263 return NULL;
264 }
265 size_t len = strlen(str);
266 if (str == NULL || len == 0) {
267 return NULL;
268 }
269 char *end = str + len - 1;
270 while (end >= str && (*end == ' ' || *end == '\t' || *end == '\n' || *end == '\r')) {
271 *end = '\0';
272 end--;
273 }
274 len = strlen(str);
275 char *head = str;
276 end = str + strlen(str);
277 while (head < end && (*head == ' ' || *head == '\t' || *head == '\n' || *head == '\r')) {
278 *head = '\0';
279 head++;
280 }
281 if (strlen(str) == 0) {
282 return NULL;
283 }
284 return head;
285 }
286
LoadGroupUser_(void)287 static void LoadGroupUser_(void)
288 {
289 // decode group file
290 FILE *fp = fopen(GROUP_FILE_PATH, "r");
291 const uint32_t buffSize = 1024; // 1024 max buffer for decode
292 char *buff = (char *)calloc(1, buffSize);
293 while (fp != NULL && buff != NULL && fgets(buff, buffSize, fp) != NULL) {
294 buff[buffSize - 1] = '\0';
295 // deviceprivate:x:1053:root,shell,system,samgr,hdf_devmgr,deviceinfo,dsoftbus,dms,account
296 char *buffer = UserNameTrim(buff);
297 PARAM_CHECK(buffer != NULL, continue, "Invalid buffer %s", buff);
298
299 PARAM_LOGV("LoadGroupUser_ '%s'", buffer);
300 // group name
301 char *groupName = strtok(buffer, ":");
302 groupName = UserNameTrim(groupName);
303 PARAM_CHECK(groupName != NULL, continue, "Invalid group name %s", buff);
304 gid_t gid = -1;
305 GetGroupIdByName(&gid, groupName);
306
307 // skip x
308 (void)strtok(NULL, ":");
309 char *strGid = strtok(NULL, ":");
310 char *userName = strGid + strlen(strGid) + 1;
311 userName = UserNameTrim(userName);
312 PARAM_LOGV("LoadGroupUser_ %s userName '%s'", groupName, userName);
313 if (userName == NULL) {
314 AddGroupUser(groupName, gid);
315 continue;
316 }
317 char *tmp = strtok(userName, ",");
318 while (tmp != NULL) {
319 PARAM_LOGV("LoadGroupUser_ %s userName '%s'", groupName, tmp);
320 AddGroupUser(UserNameTrim(tmp), gid);
321 userName = tmp + strlen(tmp) + 1;
322 tmp = strtok(NULL, ",");
323 }
324 // last username
325 if (userName != NULL) {
326 AddGroupUser(UserNameTrim(userName), gid);
327 }
328 }
329 if (fp != NULL) {
330 (void)fclose(fp);
331 }
332 if (buff != NULL) {
333 free(buff);
334 }
335 return;
336 }
337 #else
LoadGroupUser_(void)338 static void LoadGroupUser_(void)
339 {
340 struct group *data = NULL;
341 while ((data = getgrent()) != NULL) {
342 if (data->gr_name == NULL || data->gr_mem == NULL) {
343 continue;
344 }
345 if (data->gr_mem[0] == NULL) { // default user in group
346 AddGroupUser(data->gr_name, data->gr_gid);
347 continue;
348 }
349 int index = 0;
350 while (data->gr_mem[index]) { // user in this group
351 AddGroupUser(data->gr_mem[index], data->gr_gid);
352 index++;
353 }
354 }
355 endgrent();
356 }
357 #endif
358
LoadGroupUser(void)359 INIT_LOCAL_API void LoadGroupUser(void)
360 {
361 PARAM_LOGV("LoadGroupUser ");
362 LoadGroupUser_();
363 }
364