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