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 39static 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 49static 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 67static 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 111static 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 123static int FreeLocalSecurityLabel(ParamSecurityLabel *srcLabel) 124{ 125 return 0; 126} 127 128static 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 161static 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 183static 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 222static int ProcessParamFile(const char *fileName, void *context) 223{ 224 UNUSED(context); 225 return LoadParamLabels(fileName); 226} 227 228static 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 277static 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 284INIT_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