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
16 #include "config_policy_utils.h"
17
18 #include <ctype.h>
19 #include <securec.h>
20 #include <stdbool.h>
21 #include <unistd.h>
22
23 #include "config_policy_impl.h"
24 #ifndef __LITEOS__
25 #include "init_param.h"
26 #endif
27
28 static const size_t MIN_APPEND_LEN = 32;
29
30 #ifndef __LITEOS__
31 // set min opkey length
32 static const unsigned int MIN_OPKEY_LEN = 3;
33 // ':' split different x rules, example:":relPath,mode[,extra][:]"
34 // ',' split different param for x rules
35 // ":-" split for key:-value
36 // exampe:"etc/xml/config.xml,10:etc/xml/config1.xml,100,etc/carrier/${key:-value}"
37 static const char SEP_FOR_X_RULE = ':';
38 static const char SEP_FOR_X_PARAM = ',';
39 static const char * const SEP_FOR_X_VALUE = ":-";
40
41 static const char * const CUST_OPKEY0 = "telephony.sim.opkey0";
42 static const char * const CUST_OPKEY1 = "telephony.sim.opkey1";
43
44 typedef struct {
45 size_t size; // allocated buffer size of p
46 size_t strLen; // strlen(p), less than size
47 char *p; // just init to NULL, by malloc
48 } StringHolder;
49 #endif
50
51 typedef struct {
52 int segCount; // count of char * in segs
53 char *orgStr;
54 char *segs[1];
55 } SplitedStr;
56
57 #ifdef __LITEOS_M__
58 // The data will be used always, so prealloc to avoid memory fragment
59 static char gConfigPolicy[MINI_CONFIG_POLICY_BUF_SIZE] = {0};
SetMiniConfigPolicy(const char * policy)60 void SetMiniConfigPolicy(const char *policy)
61 {
62 if (gConfigPolicy[0] != 0) {
63 return; // now only set once
64 }
65 (void)strcpy_s(gConfigPolicy, sizeof(gConfigPolicy), policy);
66 }
67
TrigSetMiniConfigPolicy()68 __WEAK void TrigSetMiniConfigPolicy()
69 {
70 return;
71 }
72 #endif
73
74 /**
75 * query function, the memory is allocated in function
76 * @return value, or NULL if not exist or strlen(value) is 0
77 * @NOTICE caller should free the returned value
78 */
79 typedef char *(*QueryFunc)(const char *key);
80 static char *ExpandStr(char *src, const char *def, QueryFunc queryFunc);
81
Min(size_t a,size_t b)82 static inline size_t Min(size_t a, size_t b)
83 {
84 return a < b ? a : b;
85 }
86
Max(size_t a,size_t b)87 static inline size_t Max(size_t a, size_t b)
88 {
89 return a > b ? a : b;
90 }
91
FreeIf(void * p)92 static void FreeIf(void *p)
93 {
94 if (p != NULL) {
95 free(p);
96 }
97 }
98
99 #ifndef __LITEOS__
CustGetSystemParam(const char * name)100 static char *CustGetSystemParam(const char *name)
101 {
102 char *value = NULL;
103 unsigned int len = 0;
104
105 if (SystemGetParameter(name, NULL, &len) != 0 || len <= 0 || len > PARAM_CONST_VALUE_LEN_MAX) {
106 return NULL;
107 }
108 value = (char *)calloc(len, sizeof(char));
109 if (value != NULL && SystemGetParameter(name, value, &len) == 0 && value[0]) {
110 return value;
111 }
112 FreeIf(value);
113 return NULL;
114 }
115
GetOpkeyPath(int type)116 static char *GetOpkeyPath(int type)
117 {
118 char *result = NULL;
119 const char * const opKeyDir = "etc/carrier/";
120 const char *opKeyName = CUST_OPKEY0;
121 if (type == FOLLOWX_MODE_SIM_1) {
122 opKeyName = CUST_OPKEY0;
123 } else if (type == FOLLOWX_MODE_SIM_2) {
124 opKeyName = CUST_OPKEY1;
125 } else {
126 unsigned int len = 0;
127 if (SystemGetParameter(CUST_OPKEY0, NULL, &len) == 0 && len > MIN_OPKEY_LEN) {
128 opKeyName = CUST_OPKEY0;
129 } else if (SystemGetParameter(CUST_OPKEY1, NULL, &len) == 0 && len > MIN_OPKEY_LEN) {
130 opKeyName = CUST_OPKEY1;
131 }
132 }
133 char *opKeyValue = CustGetSystemParam(opKeyName);
134 if (opKeyValue == NULL) {
135 return NULL;
136 }
137 size_t bufSize = strlen(opKeyDir) + strlen(opKeyValue) + 1;
138 bufSize = Min(bufSize, MAX_PATH_LEN);
139 result = (char *)calloc(bufSize, sizeof(char));
140 if (result != NULL && sprintf_s(result, bufSize, "%s%s", opKeyDir, opKeyValue) > 0) {
141 FreeIf(opKeyValue);
142 return result;
143 }
144 FreeIf(opKeyValue);
145 FreeIf(result);
146 return NULL;
147 }
148
SplitStr(char * str,char delim)149 static SplitedStr *SplitStr(char *str, char delim)
150 {
151 int segCount = 1;
152 for (char *p = str; *p != '\0'; p++) {
153 (*p == delim) ? segCount++ : 0;
154 }
155 SplitedStr *result = (SplitedStr *)calloc(sizeof(SplitedStr) + sizeof(char *) * segCount, 1);
156 if (result == NULL) {
157 return NULL;
158 }
159 result->segCount = segCount;
160 result->orgStr = str;
161
162 char *nextDelim = NULL;
163 char delimStr[] = {delim, 0};
164 result->segs[0] = strtok_s(str, delimStr, &nextDelim);
165 for (int index = 1; index < segCount; index++) {
166 result->segs[index] = strtok_s(NULL, delimStr, &nextDelim);
167 }
168 return result;
169 }
170 #endif // __LITEOS__
171
FreeSplitedStr(SplitedStr * p)172 static void FreeSplitedStr(SplitedStr *p)
173 {
174 if (p != NULL) {
175 FreeIf(p->orgStr);
176 p->orgStr = NULL;
177 free(p);
178 }
179 }
180
181 #ifndef __LITEOS__
182 // get follow x rule from param variant
183 // *mode: read from contains param variant, mode is output param.
184 // return: extra path rule.
185 // followPath format ":relPath,mode[,extra][:]"
186 // example: ":etc/xml/config.xml,10:etc/xml/config1.xml,100,etc/carrier/${key:-value}"
GetFollowXRule(const char * relPath,int * mode)187 static char *GetFollowXRule(const char *relPath, int *mode)
188 {
189 char *followRule = CustGetSystemParam(CUST_FOLLOW_X_RULES);
190 if (followRule == NULL) {
191 return NULL;
192 }
193
194 size_t bufSize = strlen(relPath) + sizeof(":,") + 1;
195 bufSize = Min(bufSize, MAX_PATH_LEN);
196 char *search = (char *)calloc(bufSize, sizeof(char));
197 if (search == NULL || sprintf_s(search, bufSize, ":%s,", relPath) == -1) {
198 FreeIf(search);
199 FreeIf(followRule);
200 return NULL;
201 }
202
203 char *addPath = NULL;
204 char *item = strstr(followRule, search);
205 if (item) {
206 item++; // skip delim ':', goto ":relPath,mode[,extra][:]"
207 char *endItem = strchr(item, SEP_FOR_X_RULE);
208 char *nextItem = endItem + 1;
209 while (endItem && *nextItem == '-') {
210 endItem = strchr(nextItem, SEP_FOR_X_RULE);
211 nextItem = endItem + 1;
212 }
213 if (endItem) {
214 *endItem = '\0';
215 }
216 char *modeStr = strchr(item, SEP_FOR_X_PARAM);
217 if (modeStr) {
218 modeStr++;
219 *mode = atoi(modeStr);
220 }
221 if (*mode == FOLLOWX_MODE_USER_DEFINED && modeStr) {
222 addPath = strchr(modeStr, SEP_FOR_X_PARAM);
223 if (addPath) {
224 addPath++; // skip ',' get extra info
225 }
226 }
227 }
228
229 char *result = (addPath && *addPath) ? strdup(addPath) : NULL;
230 FreeIf(followRule);
231 FreeIf(search);
232 return result;
233 }
234
GetFollowXPathByMode(const char * relPath,int followMode,const char * extra)235 static SplitedStr *GetFollowXPathByMode(const char *relPath, int followMode, const char *extra)
236 {
237 char *followXPath = NULL;
238 char *modePathFromCfg = NULL;
239 const char *extraPath = extra;
240 if (followMode == FOLLOWX_MODE_DEFAULT) {
241 modePathFromCfg = GetFollowXRule(relPath, &followMode);
242 if (followMode == FOLLOWX_MODE_USER_DEFINED && modePathFromCfg && *modePathFromCfg) {
243 extraPath = modePathFromCfg;
244 }
245 }
246
247 switch (followMode) {
248 case FOLLOWX_MODE_SIM_DEFAULT:
249 followXPath = GetOpkeyPath(FOLLOWX_MODE_SIM_DEFAULT);
250 break;
251 case FOLLOWX_MODE_SIM_1:
252 followXPath = GetOpkeyPath(FOLLOWX_MODE_SIM_1);
253 break;
254 case FOLLOWX_MODE_SIM_2:
255 followXPath = GetOpkeyPath(FOLLOWX_MODE_SIM_2);
256 break;
257 case FOLLOWX_MODE_USER_DEFINED:
258 followXPath = (extraPath && *extraPath) ? strdup(extraPath) : NULL;
259 break;
260 default:
261 break;
262 }
263 char *expandVal = (followXPath && *followXPath) ? ExpandStr(followXPath, "-x-", CustGetSystemParam) : NULL;
264 FreeIf(followXPath);
265 FreeIf(modePathFromCfg);
266 SplitedStr *result = expandVal ? SplitStr(expandVal, ',') : NULL;
267 return result;
268 }
269
TrimInplace(char * str,bool moveToStart)270 static char *TrimInplace(char *str, bool moveToStart)
271 {
272 char *src = str;
273 while (isspace(*src)) {
274 src++;
275 }
276 for (int i = strlen(src) - 1; i >= 0 && isspace(src[i]); i--) {
277 src[i] = '\0';
278 }
279
280 char *res = moveToStart ? str : src;
281 if (moveToStart && src != str) {
282 size_t len = strlen(src) + 1;
283 if (memmove_s(str, len, src, len) != EOK) {
284 return NULL;
285 }
286 }
287 return (*res != '\0') ? res : NULL;
288 }
289
EnsureHolderSpace(StringHolder * holder,size_t leastSize)290 static bool EnsureHolderSpace(StringHolder *holder, size_t leastSize)
291 {
292 if (holder == NULL) {
293 return false;
294 }
295 if (holder->size < leastSize) {
296 size_t allocSize = Min(Max(leastSize * 2, MIN_APPEND_LEN), PARAM_CONST_VALUE_LEN_MAX);
297 char *newPtr = (char *)calloc(allocSize, sizeof(char));
298 if (newPtr == NULL) {
299 allocSize = leastSize;
300 newPtr = (char *)calloc(allocSize, sizeof(char));
301 if (newPtr == NULL) {
302 return false;
303 }
304 }
305 if (holder->p != NULL && memcpy_s(newPtr, allocSize, holder->p, holder->strLen) != EOK) {
306 FreeIf(newPtr);
307 return false;
308 }
309 FreeIf(holder->p);
310 holder->p = newPtr;
311 holder->size = allocSize;
312 }
313 return true;
314 }
315
AppendStr(StringHolder * holder,const char * s)316 static bool AppendStr(StringHolder *holder, const char *s)
317 {
318 if (holder == NULL || s == NULL) {
319 return false;
320 }
321 size_t leastSize = holder->strLen + strlen(s) + 1;
322 if (!EnsureHolderSpace(holder, leastSize)) {
323 return false;
324 }
325 if (strcat_s(holder->p, holder->size, s) != EOK) {
326 return false;
327 }
328 holder->strLen = leastSize - 1;
329 return true;
330 }
331
ExpandStr(char * src,const char * def,QueryFunc queryFunc)332 static char *ExpandStr(char *src, const char *def, QueryFunc queryFunc)
333 {
334 bool ok = true;
335 StringHolder sh = { 0 };
336 char *copyCur = NULL;
337 char *searchCur = NULL;
338 char *end = src + strlen(src);
339 for (copyCur = searchCur = src; ok && searchCur < end;) {
340 char *varStart = NULL;
341 char *varEnd = NULL;
342 char *find = strchr(searchCur, '$');
343 if (!find) {
344 ok = ok && AppendStr(&sh, copyCur);
345 break;
346 } else if ((varStart = strchr(find, '{')) && (varStart == find + 1) && (varEnd = strchr(find, '}')) &&
347 varEnd - varStart > 0) { // Get user defined name
348 *find = *varEnd = 0;
349 ok = ok && AppendStr(&sh, copyCur);
350 char *name = find + 2;
351 char *defVal = strstr(name, SEP_FOR_X_VALUE);
352 if (defVal) {
353 *defVal = 0; // cut for name end
354 defVal = TrimInplace(defVal + strlen(SEP_FOR_X_VALUE), false); // skip ":-", get value
355 }
356 char *value = queryFunc(name);
357 if (value || defVal || def) {
358 ok = ok && AppendStr(&sh, value ? value : (defVal ? defVal : def));
359 FreeIf(value);
360 } else {
361 errno = EINVAL;
362 ok = false;
363 break;
364 }
365 copyCur = searchCur = varEnd + 1;
366 } else {
367 searchCur = find + 1;
368 }
369 }
370 if (!ok) {
371 FreeIf(sh.p);
372 sh.p = NULL;
373 }
374 return sh.p;
375 }
376 #else
GetFollowXPathByMode(const char * relPath,int followMode,const char * extra)377 static SplitedStr *GetFollowXPathByMode(const char *relPath, int followMode, const char *extra)
378 {
379 return NULL;
380 }
381 #endif
382
GetCfgDirRealPolicyValue(CfgDir * res)383 static void GetCfgDirRealPolicyValue(CfgDir *res)
384 {
385 if (res == NULL) {
386 return;
387 }
388 #ifdef __LITEOS_M__
389 if (gConfigPolicy[0] == '\0') {
390 TrigSetMiniConfigPolicy();
391 }
392 if (gConfigPolicy[0] != '\0') {
393 res->realPolicyValue = strdup(gConfigPolicy);
394 }
395 #elif defined(__LITEOS__)
396 // use default, now do nothing
397 #else
398 res->realPolicyValue = CustGetSystemParam(CUST_KEY_POLICY_LAYER);
399 #endif
400 if (res->realPolicyValue != NULL && res->realPolicyValue[0]) {
401 return;
402 }
403 res->realPolicyValue = strdup(DEFAULT_LAYER);
404 }
405
FreeCfgFiles(CfgFiles * res)406 void FreeCfgFiles(CfgFiles *res)
407 {
408 if (res == NULL) {
409 return;
410 }
411 for (size_t i = 0; i < MAX_CFG_POLICY_DIRS_CNT; i++) {
412 if (res->paths[i] != NULL) {
413 free(res->paths[i]);
414 res->paths[i] = NULL;
415 }
416 }
417 free(res);
418 }
419
FreeCfgDirList(CfgDir * res)420 void FreeCfgDirList(CfgDir *res)
421 {
422 if (res == NULL) {
423 return;
424 }
425 if (res->realPolicyValue != NULL) {
426 free(res->realPolicyValue);
427 res->realPolicyValue = NULL;
428 }
429 free(res);
430 }
431
GetOneCfgFileEx(const char * pathSuffix,char * buf,unsigned int bufLength,int followMode,const char * extra)432 char *GetOneCfgFileEx(const char *pathSuffix, char *buf, unsigned int bufLength, int followMode, const char *extra)
433 {
434 if (pathSuffix == NULL || buf == NULL || bufLength < MAX_PATH_LEN) {
435 return NULL;
436 }
437 *buf = '\0';
438 CfgDir *dirs = GetCfgDirList();
439 if (dirs == NULL) {
440 return NULL;
441 }
442
443 SplitedStr *result = GetFollowXPathByMode(pathSuffix, followMode, extra);
444 for (size_t i = MAX_CFG_POLICY_DIRS_CNT; i > 0; i--) {
445 if (dirs->paths[i - 1] == NULL) {
446 continue;
447 }
448 // check follow x
449 for (int j = (result ? result->segCount : 0); j > 0; j--) {
450 if (result->segs[j - 1] &&
451 snprintf_s(buf, bufLength, bufLength - 1, "%s/%s/%s", dirs->paths[i - 1], result->segs[j - 1],
452 pathSuffix) > 0 &&
453 access(buf, F_OK) == 0) {
454 break;
455 }
456 *buf = '\0';
457 }
458 if (*buf != '\0') {
459 break;
460 }
461 if (snprintf_s(buf, bufLength, bufLength - 1, "%s/%s", dirs->paths[i - 1], pathSuffix) > 0 &&
462 access(buf, F_OK) == 0) {
463 break;
464 }
465 *buf = '\0';
466 }
467 FreeCfgDirList(dirs);
468 FreeSplitedStr(result);
469 return (*buf != '\0') ? buf : NULL;
470 }
471
GetOneCfgFile(const char * pathSuffix,char * buf,unsigned int bufLength)472 char *GetOneCfgFile(const char *pathSuffix, char *buf, unsigned int bufLength)
473 {
474 return GetOneCfgFileEx(pathSuffix, buf, bufLength, FOLLOWX_MODE_DEFAULT, NULL);
475 }
476
GetCfgFilesEx(const char * pathSuffix,int followMode,const char * extra)477 CfgFiles *GetCfgFilesEx(const char *pathSuffix, int followMode, const char *extra)
478 {
479 if (pathSuffix == NULL) {
480 return NULL;
481 }
482 char buf[MAX_PATH_LEN] = {0};
483 CfgDir *dirs = GetCfgDirList();
484 if (dirs == NULL) {
485 return NULL;
486 }
487 CfgFiles *files = (CfgFiles *)(malloc(sizeof(CfgFiles)));
488 if (files == NULL) {
489 FreeCfgDirList(dirs);
490 return NULL;
491 }
492
493 SplitedStr *result = GetFollowXPathByMode(pathSuffix, followMode, extra);
494 (void)memset_s(files, sizeof(CfgFiles), 0, sizeof(CfgFiles));
495 int index = 0;
496 for (size_t i = 0; i < MAX_CFG_POLICY_DIRS_CNT && index < MAX_CFG_POLICY_DIRS_CNT; i++) {
497 if (dirs->paths[i] == NULL) {
498 continue;
499 }
500 if (snprintf_s(buf, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s/%s", dirs->paths[i], pathSuffix) > 0 &&
501 access(buf, F_OK) == 0) {
502 files->paths[index++] = strdup(buf);
503 }
504 for (int j = 0; result && j < result->segCount && index < MAX_CFG_POLICY_DIRS_CNT; j++) {
505 if (result->segs[j] &&
506 snprintf_s(buf, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s/%s/%s", dirs->paths[i], result->segs[j],
507 pathSuffix) > 0 &&
508 access(buf, F_OK) == 0) {
509 files->paths[index++] = strdup(buf);
510 }
511 }
512 }
513 FreeCfgDirList(dirs);
514 FreeSplitedStr(result);
515 return files;
516 }
517
GetCfgFiles(const char * pathSuffix)518 CfgFiles *GetCfgFiles(const char *pathSuffix)
519 {
520 return GetCfgFilesEx(pathSuffix, FOLLOWX_MODE_DEFAULT, NULL);
521 }
522
GetCfgDirList()523 CfgDir *GetCfgDirList()
524 {
525 CfgDir *res = (CfgDir *)(malloc(sizeof(CfgDir)));
526 if (res == NULL) {
527 return NULL;
528 }
529 (void)memset_s(res, sizeof(CfgDir), 0, sizeof(CfgDir));
530 GetCfgDirRealPolicyValue(res);
531 char *next = res->realPolicyValue;
532 if (next == NULL) {
533 free(res);
534 return NULL;
535 }
536 for (size_t i = 0; i < MAX_CFG_POLICY_DIRS_CNT; i++) {
537 res->paths[i] = next;
538 next = strchr(next, ':');
539 if (next == NULL) {
540 break;
541 }
542 *next = 0;
543 next += 1;
544 }
545 return res;
546 }
547