Prevent buffer overflow on reading value
[platform/core/api/system-info.git] / src / system_info.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <ctype.h>
23 #include <fcntl.h>
24 #include <sys/stat.h>
25 #include <glib.h>
26
27 #include <system_info.h>
28 #include <system_info_private.h>
29 #include <sys/utsname.h>
30
31 #define ARRAY_SIZE(name) (sizeof(name)/sizeof(name[0]))
32 #define KEY_PREFIX "http://"
33
34 #define SYSTEM_INFO_MAX -1
35 #define KEY_MAX 256
36 #define STR_MAX 256
37
38 extern const struct runtime runtime[LANG_MAX];
39
40 GHashTable *hashtable = NULL;
41 static pthread_mutex_t fmutex = PTHREAD_MUTEX_INITIALIZER;
42
43 enum tag_type {
44         TAG_TYPE_PLATFORM,
45         TAG_TYPE_CUSTOM,
46 };
47
48 //LCOV_EXCL_START : not supported feature
49 API int system_info_get_value_int(system_info_key_e key, int *value)
50 {
51         return SYSTEM_INFO_ERROR_NOT_SUPPORTED;
52 }
53
54 API int system_info_get_value_bool(system_info_key_e key, bool *value)
55 {
56         return SYSTEM_INFO_ERROR_NOT_SUPPORTED;
57 }
58
59 API int system_info_get_value_double(system_info_key_e key, double *value)
60 {
61         return SYSTEM_INFO_ERROR_NOT_SUPPORTED;
62 }
63
64 API int system_info_get_value_string(system_info_key_e key, char **value)
65 {
66         return SYSTEM_INFO_ERROR_NOT_SUPPORTED;
67 }
68 //LCOV_EXCL_STOP
69
70 static void destroy_key_value(gpointer data)
71 {
72         free(data);
73 }
74
75 static int db_get_value(enum tag_type tag, const char *key,
76                 const char *type, char *value, size_t len)
77 {
78         char key_internal[KEY_MAX];
79         size_t key_internal_len;
80         char buf[PATH_MAX];     // buffer size should be larger than KEY_MAX
81         size_t value_internal_len;
82         FILE *fp = NULL;
83         int ret;
84         char *tag_s;
85         char *temp;
86
87         if (!key || !type || !value)
88                 return SYSTEM_INFO_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE
89
90         switch (tag) {
91         case TAG_TYPE_PLATFORM:
92                 tag_s = TAG_TYPE_PLATFORM_STR;
93                 break;
94         case TAG_TYPE_CUSTOM:
95                 tag_s = TAG_TYPE_CUSTOM_STR;
96                 break;
97         default:
98                 return -EINVAL;
99         }
100
101         if (strstr(key, KEY_PREFIX) == key)
102                 snprintf(key_internal, sizeof(key_internal), "%s:%s:%s", tag_s, key + strlen(KEY_PREFIX), type);
103         else
104                 snprintf(key_internal, sizeof(key_internal), "%s:%s:%s", tag_s, key, type);
105
106         pthread_mutex_lock(&fmutex);
107         if (!hashtable) {
108                 hashtable = g_hash_table_new_full(g_str_hash, g_str_equal, destroy_key_value, destroy_key_value);
109         } else {
110                 temp = (char *)g_hash_table_lookup(hashtable, key_internal);
111                 if (temp) {
112                         snprintf(value, len, "%s", temp);
113                         pthread_mutex_unlock(&fmutex);
114                         return SYSTEM_INFO_ERROR_NONE;
115                 }
116         }
117
118         if (access(SYSTEM_INFO_DB_RW_PATH, R_OK) == 0)
119                 snprintf(buf, sizeof(buf), SYSTEM_INFO_DB_RW_PATH"/%lu", simple_hash(key_internal));
120         else
121                 snprintf(buf, sizeof(buf), SYSTEM_INFO_DB_RO_PATH"/%lu", simple_hash(key_internal));
122
123         fp = fopen(buf, "r");
124         if (!fp) {
125                 if (errno == ENOENT)
126                         _D("Failed to find key in DB (%s, %s)", key, type);
127                 else
128                         _E("fopen for %s failed (%d)", buf, errno); //LCOV_EXCL_LINE
129                 ret = SYSTEM_INFO_ERROR_IO_ERROR; //LCOV_EXCL_LINE
130                 goto out;
131         }
132
133         key_internal_len = strlen(key_internal);
134         while ((temp = fgets(buf, sizeof(buf), fp))) {
135                 if (!strncmp(buf, key_internal, key_internal_len) && buf[key_internal_len] == ' ') {
136                         value_internal_len = strcspn(buf + key_internal_len + 1, "\n") + 1;
137                         snprintf(value, len < value_internal_len ? len : value_internal_len,
138                                         "%s", buf + key_internal_len + 1);
139                         break;
140                 }
141         }
142
143         if (!temp) {
144                 _D("Failed to find key in DB (%s)", key_internal);
145                 ret = SYSTEM_INFO_ERROR_IO_ERROR;
146                 goto out;
147         }
148
149         ret = SYSTEM_INFO_ERROR_NONE;
150
151         g_hash_table_insert(hashtable, strdup(key_internal), strdup(value));
152 out:
153         if (fp)
154                 fclose(fp);
155         pthread_mutex_unlock(&fmutex);
156         return ret;
157 }
158
159 struct sysinfo_type {
160         system_info_type_e type_e;
161         const char *type_str;
162 } info_type[] = {
163         { SYSTEM_INFO_BOOL,   BOOL_TYPE },
164         { SYSTEM_INFO_INT,    INT_TYPE  },
165         { SYSTEM_INFO_DOUBLE, DBL_TYPE  },
166         { SYSTEM_INFO_STRING, STR_TYPE  },
167 };
168
169 static int system_info_get_type(enum tag_type tag, const char *key,
170                 system_info_type_e *type)
171 {
172         char val[STR_MAX];
173         int ret, i;
174
175         for (i = 0; i < ARRAY_SIZE(info_type); i++) {
176                 ret = db_get_value(tag, key, info_type[i].type_str, val, STR_MAX);
177                 if (ret == SYSTEM_INFO_ERROR_NONE) {
178                         *type = info_type[i].type_e;
179                         return SYSTEM_INFO_ERROR_NONE;
180                 }
181         }
182
183         if (tag == TAG_TYPE_PLATFORM)
184                 return system_info_get_type_file(key, type);
185         else
186                 return SYSTEM_INFO_ERROR_INVALID_PARAMETER;
187 }
188
189 static int system_info_get_bool(enum tag_type tag, const char *key, bool *value)
190 {
191         int ret;
192         char val[16];
193         char *valp;
194         size_t len;
195         const char *runtime_type;
196         int rt;
197
198         if (!key || !value)
199                 return SYSTEM_INFO_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE
200
201         ret = db_get_value(tag, key, BOOL_TYPE, val, sizeof(val));
202         if (ret == SYSTEM_INFO_ERROR_NONE) {
203                 runtime_type = getenv("RUNTIME_TYPE");
204                 if (runtime_type) {
205                         for (rt = 0; rt < LANG_MAX; rt++) {
206                                 if (!runtime[rt].runtime_type)
207                                         break;
208                                 if (!strncmp(runtime_type, runtime[rt].runtime_type, RT_PREFIX)) {
209                                         *value = val[runtime[rt].lang] == 'T' ? true : false;
210                                         return SYSTEM_INFO_ERROR_NONE;
211                                 }
212                         }
213                         _D("Unknown RUNTIME_TYPE, return default value");
214                 }
215
216                 *value = val[runtime[DEFAULT].lang] == 'T' ? true : false;
217                 return SYSTEM_INFO_ERROR_NONE;
218         }
219
220         if (tag == TAG_TYPE_CUSTOM) {
221                 ret = external_get_value(TAG_TYPE_CUSTOM_STR, key, BOOL_TYPE, &valp);
222                 if (ret == SYSTEM_INFO_ERROR_NONE) {
223                         snprintf(val, sizeof(val), "%s", valp); //LCOV_EXCL_LINE
224                         free(valp); //LCOV_EXCL_LINE
225
226                         len = strlen(val) + 0;
227                         if (!strncmp(val, "true", len) || !strncmp(val, "TRUE", len))
228                                 *value = true;
229                         else
230                                 *value = false;
231
232                         return SYSTEM_INFO_ERROR_NONE;
233                 }
234         }
235
236         _E("Invalid key (%s), type:bool", key);
237
238         return SYSTEM_INFO_ERROR_INVALID_PARAMETER;
239 }
240
241 static int system_info_get_int(enum tag_type tag, const char *key, int *value)
242 {
243         int ret;
244         char val[128];
245         char *valp;
246
247         if (!key || !value)
248                 return SYSTEM_INFO_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE
249
250         ret = db_get_value(tag, key, INT_TYPE, val, sizeof(val));
251         if (ret == SYSTEM_INFO_ERROR_NONE)
252                 goto out;
253
254         if (tag == TAG_TYPE_CUSTOM) {
255                 ret = external_get_value(TAG_TYPE_CUSTOM_STR, key, INT_TYPE, &valp);
256                 if (ret == SYSTEM_INFO_ERROR_NONE) {
257                         snprintf(val, sizeof(val), "%s", valp); //LCOV_EXCL_LINE
258                         free(valp); //LCOV_EXCL_LINE
259                         goto out; //LCOV_EXCL_LINE
260                 }
261         }
262
263         _E("Invalid key (%s), type:integer", key);
264
265         return SYSTEM_INFO_ERROR_INVALID_PARAMETER;
266
267 out:
268         *value = atoi(val);
269
270         return SYSTEM_INFO_ERROR_NONE;
271 }
272
273 static int system_info_get_double(enum tag_type tag, const char *key, double *value)
274 {
275         int ret;
276         char val[128];
277         char *valp;
278
279         if (!key || !value)
280                 return SYSTEM_INFO_ERROR_INVALID_PARAMETER;
281
282         ret = db_get_value(tag, key, DBL_TYPE, val, sizeof(val));
283         if (ret == SYSTEM_INFO_ERROR_NONE)
284                 goto out;
285
286         if (tag == TAG_TYPE_CUSTOM) {
287                 ret = external_get_value(TAG_TYPE_CUSTOM_STR, key, DBL_TYPE, &valp);
288                 if (ret == SYSTEM_INFO_ERROR_NONE) {
289                         snprintf(val, sizeof(val), "%s", valp); //LCOV_EXCL_LINE
290                         free(valp); //LCOV_EXCL_LINE
291                         goto out; //LCOV_EXCL_LINE
292                 }
293         }
294
295         _E("Invalid key (%s), type:double", key);
296
297         return SYSTEM_INFO_ERROR_INVALID_PARAMETER;
298
299 out:
300         *value = atof(val);
301
302         return SYSTEM_INFO_ERROR_NONE;
303 }
304
305 static int system_info_get_string(enum tag_type tag, const char *key, char **value)
306 {
307         int ret;
308         char val[STR_MAX];
309         char *string;
310         char *valp;
311
312         if (!key || !value)
313                 return SYSTEM_INFO_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE
314
315         ret = db_get_value(tag, key, STR_TYPE, val, sizeof(val));
316         if (ret == SYSTEM_INFO_ERROR_NONE)
317                 goto out;
318
319         if (tag == TAG_TYPE_PLATFORM) {
320                 ret = system_info_get_file(key, val, sizeof(val));
321                 if (ret == SYSTEM_INFO_ERROR_NONE)
322                         goto out;
323         }
324
325         if (tag == TAG_TYPE_CUSTOM) {
326                 ret = external_get_value(TAG_TYPE_CUSTOM_STR, key, DBL_TYPE, &valp);
327                 if (ret == SYSTEM_INFO_ERROR_NONE) {
328                         snprintf(val, sizeof(val), "%s", valp); //LCOV_EXCL_LINE
329                         free(valp); //LCOV_EXCL_LINE
330                         goto out; //LCOV_EXCL_LINE
331                 }
332         }
333
334         _E("Invalid key (%s) type:string", key);
335
336         return SYSTEM_INFO_ERROR_INVALID_PARAMETER;
337
338 out:
339         string = strdup(val);
340         if (!string) {
341                 _E("malloc failed"); //LCOV_EXCL_LINE
342                 return SYSTEM_INFO_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
343         }
344
345         *value = string;
346
347         return SYSTEM_INFO_ERROR_NONE;
348 }
349
350 API int system_info_get_platform_bool(const char *key, bool *value)
351 {
352         return system_info_get_bool(TAG_TYPE_PLATFORM, key, value);
353 }
354
355 API int system_info_get_platform_int(const char *key, int *value)
356 {
357         return system_info_get_int(TAG_TYPE_PLATFORM, key, value);
358 }
359
360 API int system_info_get_platform_double(const char *key, double *value)
361 {
362         return system_info_get_double(TAG_TYPE_PLATFORM, key, value);
363 }
364
365 API int system_info_get_platform_string(const char *key, char **value)
366 {
367         return system_info_get_string(TAG_TYPE_PLATFORM, key, value);
368 }
369
370 API int system_info_get_custom_bool(const char *key, bool *value)
371 {
372         return system_info_get_bool(TAG_TYPE_CUSTOM, key, value);
373 }
374
375 API int system_info_get_custom_int(const char *key, int *value)
376 {
377         return system_info_get_int(TAG_TYPE_CUSTOM, key, value);
378 }
379
380 API int system_info_get_custom_double(const char *key, double *value)
381 {
382         return system_info_get_double(TAG_TYPE_CUSTOM, key, value);
383 }
384
385 API int system_info_get_custom_string(const char *key, char **value)
386 {
387         return system_info_get_string(TAG_TYPE_CUSTOM, key, value);
388 }
389
390 API int system_info_get_platform_type(const char *key, system_info_type_e *type)
391 {
392         return system_info_get_type(TAG_TYPE_PLATFORM, key, type);
393 }
394
395 API int system_info_get_custom_type(const char *key, system_info_type_e *type)
396 {
397         int ret;
398         char *val = NULL;
399         size_t len;
400
401         ret = system_info_get_type(TAG_TYPE_CUSTOM, key, type);
402         if (ret == SYSTEM_INFO_ERROR_NONE)
403                 return SYSTEM_INFO_ERROR_NONE;
404
405         ret = external_get_type(TAG_TYPE_CUSTOM_STR, key, &val);
406         if (ret != SYSTEM_INFO_ERROR_NONE) {
407                 _E("Failed to get type of key (%s)", key);
408                 return SYSTEM_INFO_ERROR_INVALID_PARAMETER;
409         }
410
411         //LCOV_EXCL_START
412         len = strlen(val) + 1;
413         if (!strncmp(BOOL_TYPE, val, len))
414                 *type = SYSTEM_INFO_BOOL;
415         else if (!strncmp(INT_TYPE, val, len))
416                 *type = SYSTEM_INFO_INT;
417         else if (!strncmp(DBL_TYPE, val, len))
418                 *type = SYSTEM_INFO_DOUBLE;
419         else if (!strncmp(STR_TYPE, val, len))
420                 *type = SYSTEM_INFO_STRING;
421         else {
422                 _E("Invalid type (%s)", val);
423                 free(val);
424                 return SYSTEM_INFO_ERROR_INVALID_PARAMETER;
425         }
426
427         free(val);
428         return SYSTEM_INFO_ERROR_NONE;
429         //LCOV_EXCL_STOP
430 }