usb_moded 0.86.0+mer58
usb_moded-config.c
Go to the documentation of this file.
1
34
36
37#include "usb_moded.h"
38#include "usb_moded-control.h"
40#include "usb_moded-log.h"
41#include "usb_moded-modes.h"
42#include "usb_moded-worker.h"
43
44#ifdef USE_MER_SSU
45# include "usb_moded-ssu.h"
46#endif
47
48#include <sys/stat.h>
49
50#include <unistd.h>
51#include <fcntl.h>
52#include <glob.h>
53
54/* ========================================================================= *
55 * Prototypes
56 * ========================================================================= */
57
58/* ------------------------------------------------------------------------- *
59 * CONFIG
60 * ------------------------------------------------------------------------- */
61
62static int config_validate_ip (const char *ipadd);
63char *config_find_mounts (void);
64int config_find_sync (void);
65char *config_find_alt_mount (void);
66char *config_find_udev_path (void);
67char *config_find_udev_subsystem (void);
68char *config_check_trigger (void);
69char *config_get_trigger_subsystem (void);
70char *config_get_trigger_mode (void);
71char *config_get_trigger_property (void);
72char *config_get_trigger_value (void);
73static char *config_get_network_ip (void);
74static char *config_get_network_interface (void);
75static char *config_get_network_gateway (void);
76static char *config_get_network_netmask (void);
77static char *config_get_network_nat_interface(void);
78static int config_get_conf_int (const gchar *entry, const gchar *key);
79char *config_get_conf_string (const gchar *entry, const gchar *key);
80static gchar *config_make_user_key_string (const gchar *base_key, uid_t uid);
81gchar *config_get_user_conf_string (const gchar *entry, const gchar *base_key, uid_t uid);
82static char *config_get_kcmdline_string (const char *entry);
83char *config_get_mode_setting (uid_t uid);
84set_config_result_t config_set_config_setting (const char *entry, const char *key, const char *value);
85set_config_result_t config_set_user_config_setting (const char *entry, const char *base_key, const char *value, uid_t uid);
86set_config_result_t config_set_mode_setting (const char *mode, uid_t uid);
87static char *config_make_modes_string (const char *key, const char *mode_name, int include);
88set_config_result_t config_set_hide_mode_setting (const char *mode);
89set_config_result_t config_set_unhide_mode_setting (const char *mode);
90set_config_result_t config_set_mode_whitelist (const char *whitelist);
91set_config_result_t config_set_mode_in_whitelist (const char *mode, int allowed);
92#ifdef SAILFISH_ACCESS_CONTROL
93char *config_get_group_for_mode (const char *mode);
94#endif
95set_config_result_t config_set_network_setting (const char *config, const char *setting);
96char *config_get_network_setting (const char *config);
97static void config_merge_key (GKeyFile *dest, GKeyFile *srce, const char *grp, const char *key);
98static void config_merge_group (GKeyFile *dest, GKeyFile *srce, const char *grp);
99static void config_merge_data (GKeyFile *dest, GKeyFile *srce);
100static void config_purge_data (GKeyFile *dest, GKeyFile *srce);
101static void config_purge_empty_groups (GKeyFile *dest);
102static int config_glob_error_cb (const char *path, int err);
103static bool config_merge_from_file (GKeyFile *ini, const char *path);
104static void config_load_static_config (GKeyFile *ini);
105static bool config_load_legacy_config (GKeyFile *ini);
106static void config_remove_legacy_config (void);
107static void config_load_dynamic_config (GKeyFile *ini);
108static void config_save_dynamic_config (GKeyFile *ini);
109bool config_init (void);
110static GKeyFile *config_get_settings (void);
111char *config_get_android_manufacturer (void);
112char *config_get_android_vendor_id (void);
113char *config_get_android_product (void);
114char *config_get_android_product_id (void);
115char *config_get_hidden_modes (void);
116char *config_get_mode_whitelist (void);
117int config_is_roaming_not_allowed (void);
118bool config_user_clear (uid_t uid);
119
120/* ========================================================================= *
121 * Functions
122 * ========================================================================= */
123
124static int config_validate_ip(const char *ipadd)
125{
126 LOG_REGISTER_CONTEXT;
127
128 unsigned int b1, b2, b3, b4;
129 unsigned char c;
130
131 if (sscanf(ipadd, "%3u.%3u.%3u.%3u%c", &b1, &b2, &b3, &b4, &c) != 4)
132 return -1;
133
134 if ((b1 | b2 | b3 | b4) > 255)
135 return -1;
136 if (strspn(ipadd, "0123456789.") < strlen(ipadd))
137 return -1;
138 /* all ok */
139 return 0;
140}
141
142char *config_find_mounts(void)
143{
144 LOG_REGISTER_CONTEXT;
145
146 char *ret = NULL;
147
148 ret = config_get_conf_string(FS_MOUNT_ENTRY, FS_MOUNT_KEY);
149 if(ret == NULL)
150 {
151 ret = g_strdup(FS_MOUNT_DEFAULT);
152 //log_debug("Default mount = %s\n", ret);
153 }
154 return ret;
155}
156
157int config_find_sync(void)
158{
159 LOG_REGISTER_CONTEXT;
160
161 return config_get_conf_int(FS_SYNC_ENTRY, FS_SYNC_KEY);
162}
163
164char * config_find_alt_mount(void)
165{
166 LOG_REGISTER_CONTEXT;
167
168 return config_get_conf_string(ALT_MOUNT_ENTRY, ALT_MOUNT_KEY);
169}
170
171char * config_find_udev_path(void)
172{
173 LOG_REGISTER_CONTEXT;
174
175 return config_get_conf_string(UDEV_PATH_ENTRY, UDEV_PATH_KEY);
176}
177
178char * config_find_udev_subsystem(void)
179{
180 LOG_REGISTER_CONTEXT;
181
182 return config_get_conf_string(UDEV_PATH_ENTRY, UDEV_SUBSYSTEM_KEY);
183}
184
185char * config_check_trigger(void)
186{
187 LOG_REGISTER_CONTEXT;
188
189 return config_get_conf_string(TRIGGER_ENTRY, TRIGGER_PATH_KEY);
190}
191
192char * config_get_trigger_subsystem(void)
193{
194 LOG_REGISTER_CONTEXT;
195
196 return config_get_conf_string(TRIGGER_ENTRY, TRIGGER_UDEV_SUBSYSTEM);
197}
198
199char * config_get_trigger_mode(void)
200{
201 LOG_REGISTER_CONTEXT;
202
203 return config_get_conf_string(TRIGGER_ENTRY, TRIGGER_MODE_KEY);
204}
205
206char * config_get_trigger_property(void)
207{
208 LOG_REGISTER_CONTEXT;
209
210 return config_get_conf_string(TRIGGER_ENTRY, TRIGGER_PROPERTY_KEY);
211}
212
213char * config_get_trigger_value(void)
214{
215 LOG_REGISTER_CONTEXT;
216
217 return config_get_conf_string(TRIGGER_ENTRY, TRIGGER_PROPERTY_VALUE_KEY);
218}
219
220static char * config_get_network_ip(void)
221{
222 LOG_REGISTER_CONTEXT;
223
224 char * ip = config_get_kcmdline_string(NETWORK_IP_KEY);
225 if (ip != NULL)
226 if(!config_validate_ip(ip))
227 return ip;
228
229 return config_get_conf_string(NETWORK_ENTRY, NETWORK_IP_KEY);
230}
231
232static char * config_get_network_interface(void)
233{
234 LOG_REGISTER_CONTEXT;
235
236 return config_get_conf_string(NETWORK_ENTRY, NETWORK_INTERFACE_KEY);
237}
238
239static char * config_get_network_gateway(void)
240{
241 LOG_REGISTER_CONTEXT;
242
243 char * gw = config_get_kcmdline_string(NETWORK_GATEWAY_KEY);
244 if (gw != NULL)
245 return gw;
246
247 return config_get_conf_string(NETWORK_ENTRY, NETWORK_GATEWAY_KEY);
248}
249
250static char * config_get_network_netmask(void)
251{
252 LOG_REGISTER_CONTEXT;
253
254 char * netmask = config_get_kcmdline_string(NETWORK_NETMASK_KEY);
255 if (netmask != NULL)
256 return netmask;
257
258 return config_get_conf_string(NETWORK_ENTRY, NETWORK_NETMASK_KEY);
259}
260
261static char * config_get_network_nat_interface(void)
262{
263 LOG_REGISTER_CONTEXT;
264
265 return config_get_conf_string(NETWORK_ENTRY, NETWORK_NAT_INTERFACE_KEY);
266}
267
268static int config_get_conf_int(const gchar *entry, const gchar *key)
269{
270 LOG_REGISTER_CONTEXT;
271
272 // TODO: use cached values instead of reloading every time?
273 GKeyFile *ini = config_get_settings();
274 // Note: zero value is returned if key does not exist
275 gint val = g_key_file_get_integer(ini, entry, key, 0);
276 g_key_file_free(ini);
277 //log_debug("key [%s] %s value is: %d\n", entry, key, val);
278 return val;
279}
280
281char *config_get_conf_string(const gchar *entry, const gchar *key)
282{
283 LOG_REGISTER_CONTEXT;
284
285 // TODO: use cached values instead of reloading every time?
286 GKeyFile *ini = config_get_settings();
287 // Note: null value is returned if key does not exist
288 gchar *val = g_key_file_get_string(ini, entry, key, 0);
289 g_key_file_free(ini);
290 //log_debug("key [%s] %s value is: %s\n", entry, key, val ?: "<null>");
291 return val;
292}
293
294static gchar *config_make_user_key_string(const gchar *base_key, uid_t uid)
295{
296 LOG_REGISTER_CONTEXT;
297
298 gchar *key = 0;
299#ifdef SAILFISH_ACCESS_CONTROL
300 /* If uid is for an additional user, construct a key */
301 if( uid >= MIN_ADDITIONAL_USER && uid <= MAX_ADDITIONAL_USER )
302 key = g_strdup_printf("%s_%d", base_key, (int)uid);
303#endif
304 return key;
305}
306
307gchar *config_get_user_conf_string(const gchar *entry, const gchar *base_key, uid_t uid)
308{
309 LOG_REGISTER_CONTEXT;
310
311 gchar *value = 0;
312 gchar *key = config_make_user_key_string(base_key, uid);
313 if( key )
314 value = config_get_conf_string(entry, key);
315 /* Fallback to global config if user doesn't have a value set */
316 if( !value )
317 value = config_get_conf_string(entry, base_key);
318 g_free(key);
319 return value;
320}
321
322static char * config_get_kcmdline_string(const char *entry)
323{
324 LOG_REGISTER_CONTEXT;
325
326 int fd;
327 char cmdLine[1024];
328 char *ret = NULL;
329 int len;
330 gint argc = 0;
331 gchar **argv = NULL;
332 gchar **arg_tokens = NULL, **network_tokens = NULL;
333 GError *optErr = NULL;
334 int i;
335
336 if ((fd = open("/proc/cmdline", O_RDONLY)) < 0)
337 {
338 log_debug("could not read /proc/cmdline");
339 return ret;
340 }
341
342 len = read(fd, cmdLine, sizeof cmdLine - 1);
343 close(fd);
344
345 if (len <= 0)
346 {
347 log_debug("kernel command line was empty");
348 return ret;
349 }
350
351 cmdLine[len] = '\0';
352
353 /* we're looking for a piece of the kernel command line matching this:
354 * ip=192.168.3.100::192.168.3.1:255.255.255.0::usb0:on */
355 if (!g_shell_parse_argv(cmdLine, &argc, &argv, &optErr))
356 {
357 g_error_free(optErr);
358 return ret;
359 }
360
361 /* find the ip token */
362 for (i=0; i < argc; i++)
363 {
364 arg_tokens = g_strsplit(argv[i], "=", 2);
365 if (!g_ascii_strcasecmp(arg_tokens[0], "usb_moded_ip"))
366 {
367 network_tokens = g_strsplit(arg_tokens[1], ":", 7);
368 /* check if it is for the usb or rndis interface */
369 if(g_strrstr(network_tokens[5], "usb")|| (g_strrstr(network_tokens[5], "rndis")))
370 {
371 if(!strcmp(entry, NETWORK_IP_KEY))
372 {
373 g_free(ret), ret = g_strdup(network_tokens[0]);
374 log_debug("Command line ip = %s\n", ret);
375 }
376 if(!strcmp(entry, NETWORK_GATEWAY_KEY))
377 {
378 /* gateway might be empty, so we do not want to return an empty string */
379 if(strlen(network_tokens[2]) > 2)
380 {
381 g_free(ret), ret = g_strdup(network_tokens[2]);
382 log_debug("Command line gateway = %s\n", ret);
383 }
384 }
385 if(!strcmp(entry, NETWORK_NETMASK_KEY))
386 {
387 g_free(ret), ret = g_strdup(network_tokens[3]);
388 log_debug("Command line netmask = %s\n", ret);
389 }
390 }
391 }
392 g_strfreev(arg_tokens);
393 }
394 g_strfreev(argv);
395 g_strfreev(network_tokens);
396
397 return ret;
398}
399
400char * config_get_mode_setting(uid_t uid)
401{
402 LOG_REGISTER_CONTEXT;
403
404 char *mode = 0;
405
406 /* Kernel command line can be used to override settings */
407 if( (mode = config_get_kcmdline_string(MODE_SETTING_KEY)) )
408 goto EXIT;
409
410 mode = config_get_user_conf_string(MODE_SETTING_ENTRY, MODE_SETTING_KEY, uid);
411
412 /* If no default mode is configured, treat it as charging only */
413 if( !mode )
414 mode = g_strdup(MODE_CHARGING);
415 /* If mode is not allowed, i.e. non-existent or not whitelisted or permitted, use MODE_ASK */
416 else if( strcmp(mode, MODE_ASK) && (common_valid_mode(mode) || !usbmoded_is_mode_permitted(mode, uid)) ) {
417 log_warning("default mode '%s' is not valid for uid '%d', reset to '%s'",
418 mode, (int)uid, MODE_ASK);
419 g_free(mode), mode = g_strdup(MODE_ASK);
420 config_set_mode_setting(mode, uid);
421 }
422
423EXIT:
424 return mode;
425}
426
427set_config_result_t config_set_config_setting(const char *entry, const char *key, const char *value)
428{
429 LOG_REGISTER_CONTEXT;
430
432
433 GKeyFile *static_ini = g_key_file_new();
434 GKeyFile *active_ini = g_key_file_new();
435
436 gchar *prev = 0;
437
438 /* Load static configuration */
439 config_load_static_config(static_ini);
440
441 /* Merge static and dynamic settings */
442 config_merge_data(active_ini, static_ini);
443 config_load_dynamic_config(active_ini);
444
445 prev = g_key_file_get_string(active_ini, entry, key, 0);
446 if( g_strcmp0(prev, value) ) {
447 g_key_file_set_string(active_ini, entry, key, value);
448 ret = SET_CONFIG_UPDATED;
449 umdbus_send_config_signal(entry, key, value);
450 }
451
452 /* Filter out dynamic data that matches static values */
453 config_purge_data(active_ini, static_ini);
454
455 /* Update data on filesystem if changed */
456 config_save_dynamic_config(active_ini);
457
458 g_free(prev);
459 g_key_file_free(active_ini);
460 g_key_file_free(static_ini);
461
462 return ret;
463}
464
465set_config_result_t config_set_user_config_setting(const char *entry, const char *base_key, const char *value, uid_t uid)
466{
467 LOG_REGISTER_CONTEXT;
468
469 gchar *key = config_make_user_key_string(base_key, uid);
470 set_config_result_t ret = config_set_config_setting(entry, key ?: base_key, value);
471 g_free(key);
472 return ret;
473}
474
475set_config_result_t config_set_mode_setting(const char *mode, uid_t uid)
476{
477 LOG_REGISTER_CONTEXT;
478
479 /* Don't write values that don't exist */
480 if (strcmp(mode, MODE_ASK) && common_valid_mode(mode))
481 return SET_CONFIG_ERROR;
482
483 /* Don't write values that are not permitted */
484 if (!usbmoded_is_mode_permitted(mode, uid))
485 return SET_CONFIG_ERROR;
486
487 return config_set_user_config_setting(MODE_SETTING_ENTRY,
488 MODE_SETTING_KEY, mode, uid);
489}
490
491/* Builds the string used for hidden modes, when hide set to one builds the
492 * new string of hidden modes when adding one, otherwise it will remove one */
493static char * config_make_modes_string(const char *key, const char *mode_name, int include)
494{
495 LOG_REGISTER_CONTEXT;
496
497 char *modes_new = 0;
498 char *modes_old = 0;
499 gchar **modes_arr = 0;
500 GString *modes_tmp = 0;
501 int i;
502
503 /* Get current comma separated list of hidden modes */
504 modes_old = config_get_conf_string(MODE_SETTING_ENTRY, key);
505 if(!modes_old)
506 {
507 modes_old = g_strdup("");
508 }
509
510 modes_arr = g_strsplit(modes_old, ",", 0);
511
512 modes_tmp = g_string_new(NULL);
513
514 for(i = 0; modes_arr[i] != NULL; i++)
515 {
516 if(strlen(modes_arr[i]) == 0)
517 {
518 /* Skip any empty strings */
519 continue;
520 }
521
522 if(!strcmp(modes_arr[i], mode_name))
523 {
524 /* When unhiding, just skip all matching entries */
525 if(!include)
526 continue;
527
528 /* When hiding, keep the 1st match and ignore the rest */
529 include = 0;
530 }
531
532 if(modes_tmp->len > 0)
533 modes_tmp = g_string_append(modes_tmp, ",");
534 modes_tmp = g_string_append(modes_tmp, modes_arr[i]);
535 }
536
537 if(include)
538 {
539 /* Adding a hidden mode and no matching entry was found */
540 if(modes_tmp->len > 0)
541 modes_tmp = g_string_append(modes_tmp, ",");
542 modes_tmp = g_string_append(modes_tmp, mode_name);
543 }
544
545 modes_new = g_string_free(modes_tmp, FALSE), modes_tmp = 0;
546
547 g_strfreev(modes_arr), modes_arr = 0;
548
549 g_free(modes_old), modes_old = 0;
550
551 return modes_new;
552}
553
554set_config_result_t config_set_hide_mode_setting(const char *mode)
555{
556 LOG_REGISTER_CONTEXT;
557
559
560 char *hidden_modes = config_make_modes_string(MODE_HIDE_KEY, mode, 1);
561
562 if( hidden_modes ) {
563 ret = config_set_config_setting(MODE_SETTING_ENTRY, MODE_HIDE_KEY, hidden_modes);
564 }
565
566 if(ret == SET_CONFIG_UPDATED) {
570 }
571
572 g_free(hidden_modes);
573
574 return ret;
575}
576
577set_config_result_t config_set_unhide_mode_setting(const char *mode)
578{
579 LOG_REGISTER_CONTEXT;
580
582
583 char *hidden_modes = config_make_modes_string(MODE_HIDE_KEY, mode, 0);
584
585 if( hidden_modes ) {
586 ret = config_set_config_setting(MODE_SETTING_ENTRY, MODE_HIDE_KEY, hidden_modes);
587 }
588
589 if(ret == SET_CONFIG_UPDATED) {
593 }
594
595 g_free(hidden_modes);
596
597 return ret;
598}
599
600set_config_result_t config_set_mode_whitelist(const char *whitelist)
601{
602 LOG_REGISTER_CONTEXT;
603
604 set_config_result_t ret = config_set_config_setting(MODE_SETTING_ENTRY, MODE_WHITELIST_KEY, whitelist);
605
606 if(ret == SET_CONFIG_UPDATED) {
607 uid_t current_user = usbmoded_get_current_user();
608 char *mode_setting = config_get_mode_setting(current_user);
609 if (strcmp(mode_setting, MODE_ASK) && common_valid_mode(mode_setting))
610 config_set_mode_setting(MODE_ASK, current_user);
611 g_free(mode_setting);
612
614
617 }
618
619 return ret;
620}
621
622set_config_result_t config_set_mode_in_whitelist(const char *mode, int allowed)
623{
624 LOG_REGISTER_CONTEXT;
625
627
628 char *whitelist = config_make_modes_string(MODE_WHITELIST_KEY, mode, allowed);
629
630 ret = config_set_mode_whitelist(whitelist ?: "");
631
632 g_free(whitelist);
633
634 return ret;
635}
636
637#ifdef SAILFISH_ACCESS_CONTROL
638char *config_get_group_for_mode(const char *mode)
639{
640 LOG_REGISTER_CONTEXT;
641
642 char *group = config_get_conf_string(MODE_GROUP_ENTRY, mode);
643
644 if (group == NULL)
645 group = g_strdup("sailfish-system");
646
647 return group;
648}
649#endif
650
651/*
652 * @param config : the key to be set
653 * @param setting : The value to be set
654 */
655set_config_result_t config_set_network_setting(const char *config, const char *setting)
656{
657 LOG_REGISTER_CONTEXT;
658
659 if(!strcmp(config, NETWORK_IP_KEY) || !strcmp(config, NETWORK_GATEWAY_KEY))
660 if(config_validate_ip(setting) != 0)
661 return SET_CONFIG_ERROR;
662
663 if(!strcmp(config, NETWORK_IP_KEY) || !strcmp(config, NETWORK_INTERFACE_KEY) || !strcmp(config, NETWORK_GATEWAY_KEY))
664 {
665 return config_set_config_setting(NETWORK_ENTRY, config, setting);
666 }
667
668 return SET_CONFIG_ERROR;
669}
670
671char *config_get_network_setting(const char *config)
672{
673 LOG_REGISTER_CONTEXT;
674
675 char *ret = 0;
676
677 modedata_t *data = 0;
678
679 if( !g_strcmp0(config, NETWORK_IP_KEY) ) {
680 if( !(ret = config_get_network_ip()) )
681 ret = g_strdup("192.168.2.15");
682 }
683 else if( !g_strcmp0(config, NETWORK_INTERFACE_KEY)) {
684 /* check main configuration before using
685 * the information from the specific mode */
686 if( (ret = config_get_network_interface()) )
687 goto EXIT;
688
689 /* no interface override specified, let's use the one
690 * from the mode config */
691 if( (data = worker_dup_usb_mode_data()) ) {
692 if( (ret = g_strdup(data->network_interface)) )
693 goto EXIT;
694 }
695
696 ret = g_strdup("usb0");
697 }
698 else if( !g_strcmp0(config, NETWORK_GATEWAY_KEY) ) {
699 ret = config_get_network_gateway();
700 }
701 else if( !g_strcmp0(config, NETWORK_NETMASK_KEY) ) {
702 if( !(ret = config_get_network_netmask()) )
703 ret = g_strdup("255.255.255.0");
704 }
705 else if( !g_strcmp0(config, NETWORK_NAT_INTERFACE_KEY) ) {
706 ret = config_get_network_nat_interface();
707 }
708 else {
709 /* no matching keys, return error */
710 }
711
712EXIT:
713 modedata_free(data);
714
715 return ret;
716}
717
728static void config_merge_key(GKeyFile *dest, GKeyFile *srce,
729 const char *grp, const char *key)
730{
731 LOG_REGISTER_CONTEXT;
732
733 gchar *val = g_key_file_get_value(srce, grp, key, 0);
734 if( val ) {
735 //log_debug("[%s] %s = %s", grp, key, val);
736 g_key_file_set_value(dest, grp, key, val);
737 g_free(val);
738 }
739}
740
748static void config_merge_group(GKeyFile *dest, GKeyFile *srce,
749 const char *grp)
750{
751 LOG_REGISTER_CONTEXT;
752
753 gchar **key = g_key_file_get_keys(srce, grp, 0, 0);
754 if( key ) {
755 for( size_t i = 0; key[i]; ++i )
756 config_merge_key(dest, srce, grp, key[i]);
757 g_strfreev(key);
758 }
759}
760
767static void config_merge_data(GKeyFile *dest, GKeyFile *srce)
768{
769 LOG_REGISTER_CONTEXT;
770
771 gchar **grp = g_key_file_get_groups(srce, 0);
772
773 if( grp ) {
774 for( size_t i = 0; grp[i]; ++i )
775 config_merge_group(dest, srce, grp[i]);
776 g_strfreev(grp);
777 }
778}
779
780static void config_purge_data(GKeyFile *dest, GKeyFile *srce)
781{
782 LOG_REGISTER_CONTEXT;
783
784 gsize groups = 0;
785 gchar **group = g_key_file_get_groups(srce, &groups);
786 for( gsize g = 0; g < groups; ++g ) {
787 gsize keys = 0;
788 gchar **key = g_key_file_get_keys(srce, group[g], &keys, 0);
789 for( gsize k = 0; k < keys; ++k ) {
790 gchar *cur_val = g_key_file_get_value(dest, group[g], key[k], 0);
791 if( !cur_val )
792 continue;
793
794 gchar *def_val = g_key_file_get_value(srce, group[g], key[k], 0);
795
796 if( !g_strcmp0(cur_val, def_val) ) {
797 log_debug("purge redundant: [%s] %s = %s",
798 group[g], key[k], cur_val);
799 g_key_file_remove_key(dest, group[g], key[k], 0);
800 }
801 g_free(def_val);
802 g_free(cur_val);
803 }
804 g_strfreev(key);
805 }
806 g_strfreev(group);
807}
808
809static void config_purge_empty_groups(GKeyFile *dest)
810{
811 LOG_REGISTER_CONTEXT;
812
813 gsize groups = 0;
814 gchar **group = g_key_file_get_groups(dest, &groups);
815 for( gsize g = 0; g < groups; ++g ) {
816 gsize keys = 0;
817 gchar **key = g_key_file_get_keys(dest, group[g], &keys, 0);
818 if( keys == 0 ) {
819 log_debug("purge redundant group: [%s]", group[g]);
820 g_key_file_remove_group(dest, group[g], 0);
821 }
822 g_strfreev(key);
823 }
824 g_strfreev(group);
825}
826
835static int config_glob_error_cb(const char *path, int err)
836{
837 LOG_REGISTER_CONTEXT;
838
839 log_debug("%s: glob: %s", path, g_strerror(err));
840 return 0;
841}
842
843static bool config_merge_from_file(GKeyFile *ini, const char *path)
844{
845 LOG_REGISTER_CONTEXT;
846
847 bool ack = false;
848 GError *err = 0;
849 GKeyFile *tmp = g_key_file_new();
850
851 if( !g_key_file_load_from_file(tmp, path, 0, &err) ) {
852 log_debug("%s: can't load: %s", path, err->message);
853 } else {
854 //log_debug("processing %s ...", path);
855 config_merge_data(ini, tmp);
856 ack = true;
857 }
858 g_clear_error(&err);
859 g_key_file_free(tmp);
860 return ack;
861}
862
863static void config_load_static_config(GKeyFile *ini)
864{
865 LOG_REGISTER_CONTEXT;
866
867 static const char pattern[] = USB_MODED_STATIC_CONFIG_DIR"/*.ini";
868
869 glob_t gb = {};
870
871 if( glob(pattern, 0, config_glob_error_cb, &gb) != 0 )
872 log_debug("no configuration ini-files found");
873
874 /* Seed with default values */
875 g_key_file_set_string(ini, MODE_SETTING_ENTRY, MODE_SETTING_KEY, MODE_ASK);
876
877 /* Override with content from config files */
878 for( size_t i = 0; i < gb.gl_pathc; ++i ) {
879 const char *path = gb.gl_pathv[i];
880 if( strcmp(path, USB_MODED_STATIC_CONFIG_FILE) )
881 config_merge_from_file(ini, path);
882 }
883
884 globfree(&gb);
885}
886
887static bool config_load_legacy_config(GKeyFile *ini)
888{
889 LOG_REGISTER_CONTEXT;
890
891 bool ack = false;
892
893 /* If the legacy config file does not exist, there is
894 * no need to do anything about it.
895 */
896 if( access(USB_MODED_STATIC_CONFIG_FILE, F_OK) == -1 )
897 goto EXIT;
898
899 /* If we have also dynamic settings file, it means that
900 * the legacy config file has re-appeared after migration.
901 *
902 * This could happen e.g. during sw upgrades as long as
903 * there are packages that contain the legacy config file.
904 *
905 * The content must be ignored to avoid overriding user
906 * settings, but emit a warning to help diagnosing when
907 * and why it might be happening (the legacy file will be
908 * removed later on - when there are settings changes to
909 * commit).
910 */
911 if( access(USB_MODED_DYNAMIC_CONFIG_FILE, F_OK) == 0 ) {
912 log_warning("%s: has reappeared after settings migration",
913 USB_MODED_STATIC_CONFIG_FILE);
914 goto EXIT;
915 }
916
917 if( !config_merge_from_file(ini, USB_MODED_STATIC_CONFIG_FILE) )
918 goto EXIT;
919
920 /* A mode=ask setting in legacy config can be either
921 * something user has selected, or merely configured
922 * default. As the latter case interferes with evaluation
923 * of priority ordered static configuration files, ignore
924 * such settings.
925 */
926 gchar *val = g_key_file_get_value(ini, MODE_SETTING_ENTRY,
927 MODE_SETTING_KEY, 0);
928 if( val ) {
929 if( !g_strcmp0(val, MODE_ASK) ) {
930 g_key_file_remove_key(ini, MODE_SETTING_ENTRY,
931 MODE_SETTING_KEY, 0);
932 }
933 g_free(val);
934 }
935
936 ack = true;
937
938EXIT:
939 return ack;
940}
941
942static void config_remove_legacy_config(void)
943{
944 LOG_REGISTER_CONTEXT;
945
946 /* Note: In case of read-only /tmp, unlink attempt leads to
947 * EROFS regardless of whether the file exists or not
948 * -> do a separate existance check 1st.
949 */
950
951 if( access(USB_MODED_STATIC_CONFIG_FILE, F_OK) == -1 && errno == ENOENT ) {
952 /* nop */
953 }
954 else if( unlink(USB_MODED_STATIC_CONFIG_FILE) == -1 && errno != ENOENT ) {
955 log_warning("%s: can't remove stale config file: %m",
956 USB_MODED_STATIC_CONFIG_FILE);
957 }
958}
959
960static void config_load_dynamic_config(GKeyFile *ini)
961{
962 LOG_REGISTER_CONTEXT;
963
964 config_merge_from_file(ini, USB_MODED_DYNAMIC_CONFIG_FILE);
965}
966
967static void config_save_dynamic_config(GKeyFile *ini)
968{
969 LOG_REGISTER_CONTEXT;
970
971 gchar *current_dta = 0;
972 gchar *previous_dta = 0;
973
974 config_purge_empty_groups(ini);
975 current_dta = g_key_file_to_data(ini, 0, 0);
976
977 g_file_get_contents(USB_MODED_DYNAMIC_CONFIG_FILE, &previous_dta, 0, 0);
978 if( g_strcmp0(previous_dta, current_dta) ) {
979 GError *err = 0;
980 if( mkdir(USB_MODED_DYNAMIC_CONFIG_DIR, 0755) == -1 && errno != EEXIST ) {
981 log_err("%s: can't create dir: %m", USB_MODED_DYNAMIC_CONFIG_DIR);
982 }
983 else if( !g_file_set_contents(USB_MODED_DYNAMIC_CONFIG_FILE,
984 current_dta, -1, &err) ) {
985 log_err("%s: can't save: %s", USB_MODED_DYNAMIC_CONFIG_FILE,
986 err->message);
987 }
988 else {
989 log_debug("%s: updated", USB_MODED_DYNAMIC_CONFIG_FILE);
990
991 /* The legacy file is not needed anymore */
992 config_remove_legacy_config();
993 }
994 g_clear_error(&err);
995 }
996
997 g_free(current_dta);
998 g_free(previous_dta);
999}
1000
1007bool config_init(void)
1008{
1009 LOG_REGISTER_CONTEXT;
1010
1011 bool ack = true;
1012
1013 GKeyFile *legacy_ini = g_key_file_new();
1014 GKeyFile *static_ini = g_key_file_new();
1015 GKeyFile *active_ini = g_key_file_new();
1016
1017 /* Load static configuration */
1018 config_load_static_config(static_ini);
1019
1020 /* Handle legacy settings */
1021 if( config_load_legacy_config(legacy_ini) ) {
1022 config_purge_data(legacy_ini, static_ini);
1023 config_merge_data(active_ini, legacy_ini);
1024 }
1025
1026 /* Load dynamic settings */
1027 config_load_dynamic_config(active_ini);
1028
1029 /* Filter out dynamic data that matches static values */
1030 config_purge_data(active_ini, static_ini);
1031
1032 /* Update data on filesystem if changed */
1033 config_save_dynamic_config(active_ini);
1034
1035 g_key_file_free(active_ini);
1036 g_key_file_free(static_ini);
1037 g_key_file_free(legacy_ini);
1038
1039 return ack;
1040}
1041
1042static GKeyFile *config_get_settings(void)
1043{
1044 LOG_REGISTER_CONTEXT;
1045
1046 GKeyFile *ini = g_key_file_new();
1047 config_load_static_config(ini);
1048 config_load_dynamic_config(ini);
1049 return ini;
1050}
1051
1052char * config_get_android_manufacturer(void)
1053{
1054 LOG_REGISTER_CONTEXT;
1055
1056#ifdef USE_MER_SSU
1057 /* If SSU can provide manufacturer name, use it. Otherwise fall
1058 * back to using the name specified in configuration files. */
1059 char *ssu_name = ssu_get_manufacturer_name();
1060 if( ssu_name )
1061 {
1062 return ssu_name;
1063 }
1064#endif
1065
1066 return config_get_conf_string(ANDROID_ENTRY, ANDROID_MANUFACTURER_KEY);
1067}
1068
1069char * config_get_android_vendor_id(void)
1070{
1071 LOG_REGISTER_CONTEXT;
1072
1073 return config_get_conf_string(ANDROID_ENTRY, ANDROID_VENDOR_ID_KEY);
1074}
1075
1076char * config_get_android_product(void)
1077{
1078 LOG_REGISTER_CONTEXT;
1079
1080#ifdef USE_MER_SSU
1081 /* If SSU can provide device model name, use it. Otherwise fall
1082 * back to using the name specified in configuration files. */
1083 char *ssu_name = ssu_get_product_name();
1084 if( ssu_name )
1085 {
1086 return ssu_name;
1087 }
1088#endif
1089
1090 return config_get_conf_string(ANDROID_ENTRY, ANDROID_PRODUCT_KEY);
1091}
1092
1093char * config_get_android_product_id(void)
1094{
1095 LOG_REGISTER_CONTEXT;
1096
1097 return config_get_conf_string(ANDROID_ENTRY, ANDROID_PRODUCT_ID_KEY);
1098}
1099
1100char * config_get_hidden_modes(void)
1101{
1102 LOG_REGISTER_CONTEXT;
1103
1104 return config_get_conf_string(MODE_SETTING_ENTRY, MODE_HIDE_KEY);
1105}
1106char * config_get_mode_whitelist(void)
1107{
1108 LOG_REGISTER_CONTEXT;
1109
1110 return config_get_conf_string(MODE_SETTING_ENTRY, MODE_WHITELIST_KEY);
1111}
1112
1113int config_is_roaming_not_allowed(void)
1114{
1115 LOG_REGISTER_CONTEXT;
1116
1117 return config_get_conf_int(NETWORK_ENTRY, NO_ROAMING_KEY);
1118}
1119
1123bool config_user_clear(uid_t uid)
1124{
1125#ifdef SAILFISH_ACCESS_CONTROL
1126 if (uid < MIN_ADDITIONAL_USER || uid > MAX_ADDITIONAL_USER) {
1127 log_err("Invalid uid value: %d\n", uid);
1128 return false;
1129 }
1130#endif
1131
1132 GKeyFile *active_ini = g_key_file_new();
1133 config_load_dynamic_config(active_ini);
1134
1135 char *key = config_make_user_key_string(MODE_SETTING_KEY, uid);
1136 if (key) {
1137 if (g_key_file_remove_key(active_ini, MODE_SETTING_ENTRY, key, NULL))
1138 config_save_dynamic_config(active_ini);
1139 g_free(key);
1140 }
1141
1142 g_key_file_free(active_ini);
1143 return true;
1144}
int common_valid_mode(const char *mode)
void common_send_available_modes_signal(void)
void common_send_hidden_modes_signal(void)
void common_send_supported_modes_signal(void)
bool config_user_clear(uid_t uid)
bool config_init(void)
set_config_result_t
@ SET_CONFIG_ERROR
@ SET_CONFIG_UPDATED
@ SET_CONFIG_UNCHANGED
void control_settings_changed(void)
void umdbus_send_config_signal(const char *section, const char *key, const char *value)
int umdbus_send_whitelisted_modes_signal(const char *whitelist)
void modedata_free(modedata_t *self)
#define MODE_ASK
#define MODE_CHARGING
gchar * ssu_get_manufacturer_name(void)
gchar * ssu_get_product_name(void)
modedata_t * worker_dup_usb_mode_data(void)
uid_t usbmoded_get_current_user(void)
Definition usb_moded.c:572