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