1 /*
2  * Copyright (c) 2021 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 "ueventd_read_cfg.h"
17 
18 #include <ctype.h>
19 #include <string.h>
20 #include <stdbool.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <sys/stat.h>
26 #include "init_utils.h"
27 #include "list.h"
28 #include "ueventd_utils.h"
29 #include "securec.h"
30 #define INIT_LOG_TAG "ueventd"
31 #include "init_log.h"
32 
33 // default item count in config files
34 #define DEFAULTITEMCOUNT (50)
35 #define MAX_CONFIGURE_SIZE (1024 * 1024 * 16)
36 
37 typedef enum SECTION {
38     SECTION_INVALID = -1,
39     SECTION_DEVICE = 0,
40     SECTION_SYSFS,
41     SECTION_FIRMWARE
42 } SECTION;
43 
44 typedef int (*ParseConfigFunc)(char *);
45 typedef struct FunctionMapper {
46     const char *name;
47     ParseConfigFunc func;
48 } FUNCTIONMAPPER;
49 
50 struct ListNode g_devices = {
51     .next = &g_devices,
52     .prev = &g_devices,
53 };
54 
55 struct ListNode g_sysDevices = {
56     .next = &g_sysDevices,
57     .prev = &g_sysDevices,
58 };
59 
60 struct ListNode g_firmwares = {
61     .next = &g_firmwares,
62     .prev = &g_firmwares,
63 };
64 
ParseDeviceConfig(char * p)65 static int ParseDeviceConfig(char *p)
66 {
67     INIT_LOGV("Parse device config info: %s", p);
68     char **items = NULL;
69     int count = -1;
70     // format: <device node> <mode> <uid> <gid> <parameter>
71     const int expectedCount = 5;
72 
73     INIT_CHECK_ONLY_ELOG(!INVALIDSTRING(p), "Invalid argument");
74     items = SplitStringExt(p, " ", &count, expectedCount);
75     if ((count != expectedCount) && (count != expectedCount - 1)) {
76         INIT_LOGE("Ignore invalid item: %s", p);
77         FreeStringVector(items, count);
78         return 0;
79     }
80 
81     struct DeviceUdevConf *config = calloc(1, sizeof(struct DeviceUdevConf));
82     if (config == NULL) {
83         errno = ENOMEM;
84         FreeStringVector(items, count);
85         return -1;
86     }
87     config->name = strdup(items[0]); // device node
88     INIT_ERROR_CHECK(config->name != NULL, FreeStringVector(items, count);
89                      free(config); return -1, "failed dup config name");
90     errno = 0;
91     config->mode = strtoul(items[1], NULL, OCTAL_BASE); // mode
92     INIT_ERROR_CHECK(errno == 0, config->mode = DEVMODE,
93         "Invalid mode in config file for device node %s. use default mode", config->name);
94     config->uid = (uid_t)DecodeUid(items[2]); // uid
95     config->gid = (gid_t)DecodeGid(items[3]); // gid
96     if (count == expectedCount) {
97         config->parameter = strdup(items[4]); // device parameter
98         INIT_ERROR_CHECK(config->parameter != NULL, FreeStringVector(items, count);
99                          free((void*)config->name); free(config); return -1, "failed dup parameter");
100     } else {
101         config->parameter = NULL;
102     }
103     OH_ListInit(&config->paramNode);
104     OH_ListAddTail(&g_devices, &config->list);
105     FreeStringVector(items, count);
106     return 0;
107 }
108 
ParseSysfsConfig(char * p)109 static int ParseSysfsConfig(char *p)
110 {
111     INIT_LOGV("Parse sysfs config info: %s", p);
112     char **items = NULL;
113     int count = -1;
114     // format: <syspath> <attribute> <mode> <uid> <gid>
115     const int expectedCount = 5;
116 
117     INIT_CHECK_ONLY_ELOG(!INVALIDSTRING(p), "Invalid argument");
118     items = SplitStringExt(p, " ", &count, expectedCount);
119     if (count != expectedCount) {
120         INIT_LOGE("Ignore invalid item: %s", p);
121         FreeStringVector(items, count);
122         return 0;
123     }
124     struct SysUdevConf *config = calloc(1, sizeof(struct SysUdevConf));
125     if (config == NULL) {
126         errno = ENOMEM;
127         FreeStringVector(items, count);
128         return -1;
129     }
130     config->sysPath = strdup(items[0]); // sys path
131     INIT_ERROR_CHECK(config->sysPath != NULL, FreeStringVector(items, count);
132                      free(config); return -1, "failed to dup syspath");
133     config->attr = strdup(items[1]);  // attribute
134     INIT_ERROR_CHECK(config->attr != NULL, FreeStringVector(items, count);
135                      free((void*)config->sysPath); free(config); return -1, "failed to dup attr");
136     errno = 0;
137     config->mode = strtoul(items[2], NULL, OCTAL_BASE); // mode
138     INIT_ERROR_CHECK(errno == 0, config->mode = DEVMODE,
139         "Invalid mode in config file for sys path %s. use default mode", config->sysPath);
140     config->uid = (uid_t)DecodeUid(items[3]); // uid
141     config->gid = (gid_t)DecodeGid(items[4]); // gid
142     OH_ListAddTail(&g_sysDevices, &config->list);
143     FreeStringVector(items, count);
144     return 0;
145 }
146 
ParseFirmwareConfig(char * p)147 static int ParseFirmwareConfig(char *p)
148 {
149     INIT_LOGV("Parse firmware config info: %s", p);
150     INIT_ERROR_CHECK(!INVALIDSTRING(p), return -1, "Invalid argument");
151 
152     // Sanity checks
153     struct stat st = {};
154     INIT_ERROR_CHECK(stat(p, &st) == 0, return -1, "Invalid firmware file: %s, err = %d", p, errno);
155     INIT_ERROR_CHECK(S_ISDIR(st.st_mode), return -1, "Expect directory in firmware config");
156     struct FirmwareUdevConf *config = calloc(1, sizeof(struct FirmwareUdevConf));
157     INIT_CHECK(config != NULL, errno = ENOMEM;
158         return -1);
159     config->fmPath = strdup(p);
160     INIT_ERROR_CHECK(config->fmPath != NULL, free(config); return -1, "failed to dup fmpath");
161     OH_ListAddTail(&g_firmwares, &config->list);
162     return 0;
163 }
164 
GetSection(const char * section)165 static SECTION GetSection(const char *section)
166 {
167     INIT_CHECK_RETURN_VALUE(!INVALIDSTRING(section), SECTION_INVALID);
168     if (STRINGEQUAL(section, "device")) {
169         return SECTION_DEVICE;
170     } else if (STRINGEQUAL(section, "sysfs")) {
171         return SECTION_SYSFS;
172     } else if (STRINGEQUAL(section, "firmware")) {
173         return SECTION_FIRMWARE;
174     } else {
175         return SECTION_INVALID;
176     }
177 }
178 
179 static const FUNCTIONMAPPER funcMapper[3] = {
180     {"device", ParseDeviceConfig},
181     {"sysfs", ParseSysfsConfig},
182     {"firmware", ParseFirmwareConfig}
183 };
184 
185 ParseConfigFunc callback;
ParseUeventConfig(char * buffer)186 int ParseUeventConfig(char *buffer)
187 {
188     char *section = NULL;
189     char *right = NULL;
190     char *p = buffer;
191     SECTION type;
192 
193     INIT_CHECK_RETURN_VALUE(!INVALIDSTRING(buffer), -1);
194     if (*p == '[') {
195         p++;
196         if ((right = strchr(p, ']')) == NULL) {
197             INIT_LOGE("Invalid line \"%s\", miss ']'", buffer);
198             return -1;
199         }
200         *right = '\0'; // Replace ']' with '\0';
201         section = p;
202         INIT_LOGV("section is [%s]", section);
203         if ((type = GetSection(section)) == SECTION_INVALID) {
204             INIT_LOGE("Invalid section \" %s \"", section);
205             callback = NULL; // reset callback
206             return -1;
207         }
208         callback = funcMapper[type].func;
209         return 0;
210     }
211     return (callback != NULL) ? callback(p) : -1;
212 }
213 
DoUeventConfigParse(char * buffer,size_t length)214 static void DoUeventConfigParse(char *buffer, size_t length)
215 {
216     char **items = NULL;
217     int count = -1;
218     const int maxItemCount = DEFAULTITEMCOUNT;
219 
220     items = SplitStringExt(buffer, "\n", &count, maxItemCount);
221     INIT_LOGV("Dump items count = %d", count);
222     for (int i = 0; i < count; i++) {
223         char *p = items[i];
224         // Skip lead white space
225         while (isspace(*p)) {
226             p++;
227         }
228 
229         // Skip comment or empty line
230         if (*p == '\0' || *p == '#') {
231             continue;
232         }
233         int rc = ParseUeventConfig(p);
234         if (rc < 0) {
235             INIT_LOGE("Parse uevent config from %s failed", p);
236         }
237     }
238     // release memory
239     FreeStringVector(items, count);
240 }
241 
ParseUeventdConfigFile(const char * file)242 void ParseUeventdConfigFile(const char *file)
243 {
244     INIT_CHECK_ONLY_RETURN(!INVALIDSTRING(file));
245     char *config = GetRealPath(file);
246     INIT_CHECK_ONLY_RETURN(config != NULL);
247     int fd = open(config, O_RDONLY | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
248     free(config);
249     INIT_ERROR_CHECK(fd >= 0, return, "Read from %s failed", file);
250 
251     struct stat st;
252     if (fstat(fd, &st) < 0) {
253         INIT_LOGE("Failed to get file stat. err = %d", errno);
254         close(fd);
255         return;
256     }
257 
258     // st_size should never be less than 0
259     if (st.st_size < 0 || st.st_size > MAX_CONFIGURE_SIZE) {
260         INIT_LOGE("Invalid configure file with size");
261         close(fd);
262         return;
263     }
264     size_t size = (size_t)st.st_size;
265     char *buffer = malloc(size + 1);
266     if (buffer == NULL) {
267         INIT_LOGE("Failed to malloc memory. err = %d", errno);
268         close(fd);
269         return;
270     }
271 
272     if (read(fd, buffer, size) != (ssize_t)size) {
273         INIT_LOGE("Read from file %s failed. err = %d", file, errno);
274         free(buffer);
275         buffer = NULL;
276         close(fd);
277         return;
278     }
279 
280     buffer[size] = '\0';
281     DoUeventConfigParse(buffer, size);
282     free(buffer);
283     buffer = NULL;
284     close(fd);
285 }
286 
287 // support '*' to match all characters
288 // '?' match one character.
IsMatch(const char * target,const char * pattern)289 bool IsMatch(const char *target, const char *pattern)
290 {
291     INIT_CHECK_RETURN_VALUE(target != NULL, false);
292     INIT_CHECK_RETURN_VALUE(pattern != NULL, true);
293 
294     const char *t = target;
295     const char *p = pattern;
296     const char *plast = NULL;
297     bool reMatch = false;
298     while (*t != '\0') {
299         if (*t == *p) {
300             t++;
301             p++;
302             continue;
303         }
304 
305         // Match one character.
306         if (*p == '?') {
307             p++;
308             t++;
309             continue;
310         }
311 
312         if (*p == '\0') {
313             return reMatch;
314         }
315 
316         if (*p == '*') {
317             reMatch = true;
318             // Met '*', record where we will start over.
319             // plast point to next character that we will compare it again.
320             plast = ++p;
321             t++;
322             continue;
323         }
324 
325         if (reMatch) {
326             // Start over.
327             p = plast;
328             t++;
329         } else {
330             return false;
331         }
332     }
333 
334     while (*p == '*') {
335         p++;
336     }
337     return (*p == '\0');
338 }
339 
GetDeviceUdevConfByDevNode(const char * devNode)340 struct DeviceUdevConf *GetDeviceUdevConfByDevNode(const char *devNode)
341 {
342     if (INVALIDSTRING(devNode)) {
343         return NULL;
344     }
345 
346     struct ListNode *node = NULL;
347     if (!ListEmpty(g_devices)) {
348         ForEachListEntry(&g_devices, node) {
349             struct DeviceUdevConf *config = ListEntry(node, struct DeviceUdevConf, list);
350             if (IsMatch(devNode, config->name)) {
351                 return config;
352             }
353         }
354     }
355 
356     return NULL;
357 }
358 
GetDeviceNodePermissions(const char * devNode,uid_t * uid,gid_t * gid,mode_t * mode)359 int GetDeviceNodePermissions(const char *devNode, uid_t *uid, gid_t *gid, mode_t *mode)
360 {
361     if (INVALIDSTRING(devNode)) {
362         return -1;
363     }
364 
365     struct ListNode *node = NULL;
366     if (!ListEmpty(g_devices)) {
367         ForEachListEntry(&g_devices, node) {
368             struct DeviceUdevConf *config = ListEntry(node, struct DeviceUdevConf, list);
369             if (IsMatch(devNode, config->name)) {
370                 *uid = config->uid;
371                 *gid = config->gid;
372                 *mode = config->mode;
373                 return 0;
374             }
375         }
376     }
377     return -1;
378 }
379 
ChangeSysAttributePermissions(const char * sysPath)380 void ChangeSysAttributePermissions(const char *sysPath)
381 {
382     if (INVALIDSTRING(sysPath)) {
383         return;
384     }
385 
386     struct ListNode *node = NULL;
387     struct SysUdevConf *config = NULL;
388     int matched = 0;
389     if (!ListEmpty(g_sysDevices)) {
390         ForEachListEntry(&g_sysDevices, node) {
391             config = ListEntry(node, struct SysUdevConf, list);
392             if (STRINGEQUAL(config->sysPath, sysPath)) {
393                 matched = 1;
394                 break;
395             }
396         }
397     }
398 
399     if (matched == 0) {
400         return;
401     }
402     char sysAttr[SYSPATH_SIZE] = {};
403     if (snprintf_s(sysAttr, SYSPATH_SIZE, SYSPATH_SIZE - 1, "/sys%s/%s", config->sysPath, config->attr) == -1) {
404         INIT_LOGE("Failed to build sys attribute for sys path %s, attr: %s", config->sysPath, config->attr);
405         return;
406     }
407     if (chown(sysAttr, config->uid, config->gid) < 0) {
408         INIT_LOGE("chown for file %s failed, err = %d", sysAttr, errno);
409     }
410 
411     if (chmod(sysAttr, config->mode) < 0) {
412         INIT_LOGE("[uevent][error] chmod for file %s failed, err = %d", sysAttr, errno);
413     }
414 }
415 
FreeDeviceConfig(ListNode * node)416 static void FreeDeviceConfig(ListNode *node)
417 {
418     struct DeviceUdevConf *config = ListEntry(node, struct DeviceUdevConf, list);
419     free((void *)config->name);
420     free((void *)config->parameter);
421     OH_ListRemove(&config->paramNode);
422     free(config);
423 }
424 
FreeSysUdevConf(ListNode * node)425 static void FreeSysUdevConf(ListNode *node)
426 {
427     struct SysUdevConf *config = ListEntry(node, struct SysUdevConf, list);
428     free((void *)config->sysPath);
429     free((void *)config->attr);
430     free(config);
431 }
432 
FreeFirmwareUdevConf(ListNode * node)433 static void FreeFirmwareUdevConf(ListNode *node)
434 {
435     struct FirmwareUdevConf *config = ListEntry(node, struct FirmwareUdevConf, list);
436     free((void *)config->fmPath);
437     free(config);
438 }
439 
CloseUeventConfig(void)440 void CloseUeventConfig(void)
441 {
442     OH_ListRemoveAll(&g_devices, FreeDeviceConfig);
443     OH_ListRemoveAll(&g_sysDevices, FreeSysUdevConf);
444     OH_ListRemoveAll(&g_firmwares, FreeFirmwareUdevConf);
445 }