usb_moded  0.86.0+mer57
usb_moded-config.c
Go to the documentation of this file.
1 
36 
37 #include "usb_moded.h"
38 #include "usb_moded-control.h"
39 #include "usb_moded-dbus-private.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 
62 static int config_validate_ip (const char *ipadd);
63 char *config_find_mounts (void);
64 int config_find_sync (void);
65 char *config_find_alt_mount (void);
66 char *config_find_udev_path (void);
67 char *config_find_udev_subsystem (void);
68 char *config_check_trigger (void);
69 char *config_get_trigger_subsystem (void);
70 char *config_get_trigger_mode (void);
71 char *config_get_trigger_property (void);
72 char *config_get_trigger_value (void);
73 static char *config_get_network_ip (void);
74 static char *config_get_network_interface (void);
75 static char *config_get_network_gateway (void);
76 static char *config_get_network_netmask (void);
77 static char *config_get_network_nat_interface(void);
78 static int config_get_conf_int (const gchar *entry, const gchar *key);
79 char *config_get_conf_string (const gchar *entry, const gchar *key);
80 static gchar *config_make_user_key_string (const gchar *base_key, uid_t uid);
81 gchar *config_get_user_conf_string (const gchar *entry, const gchar *base_key, uid_t uid);
82 static char *config_get_kcmdline_string (const char *entry);
83 char *config_get_mode_setting (uid_t uid);
84 set_config_result_t config_set_config_setting (const char *entry, const char *key, const char *value);
85 set_config_result_t config_set_user_config_setting (const char *entry, const char *base_key, const char *value, uid_t uid);
86 set_config_result_t config_set_mode_setting (const char *mode, uid_t uid);
87 static char *config_make_modes_string (const char *key, const char *mode_name, int include);
88 set_config_result_t config_set_hide_mode_setting (const char *mode);
89 set_config_result_t config_set_unhide_mode_setting (const char *mode);
90 set_config_result_t config_set_mode_whitelist (const char *whitelist);
91 set_config_result_t config_set_mode_in_whitelist (const char *mode, int allowed);
92 #ifdef SAILFISH_ACCESS_CONTROL
93 char *config_get_group_for_mode (const char *mode);
94 #endif
95 set_config_result_t config_set_network_setting (const char *config, const char *setting);
96 char *config_get_network_setting (const char *config);
97 static void config_merge_key (GKeyFile *dest, GKeyFile *srce, const char *grp, const char *key);
98 static void config_merge_group (GKeyFile *dest, GKeyFile *srce, const char *grp);
99 static void config_merge_data (GKeyFile *dest, GKeyFile *srce);
100 static void config_purge_data (GKeyFile *dest, GKeyFile *srce);
101 static void config_purge_empty_groups (GKeyFile *dest);
102 static int config_glob_error_cb (const char *path, int err);
103 static bool config_merge_from_file (GKeyFile *ini, const char *path);
104 static void config_load_static_config (GKeyFile *ini);
105 static bool config_load_legacy_config (GKeyFile *ini);
106 static void config_remove_legacy_config (void);
107 static void config_load_dynamic_config (GKeyFile *ini);
108 static void config_save_dynamic_config (GKeyFile *ini);
109 bool config_init (void);
110 static GKeyFile *config_get_settings (void);
111 char *config_get_android_manufacturer (void);
112 char *config_get_android_vendor_id (void);
113 char *config_get_android_product (void);
114 char *config_get_android_product_id (void);
115 char *config_get_hidden_modes (void);
116 char *config_get_mode_whitelist (void);
117 int config_is_roaming_not_allowed (void);
118 bool config_user_clear (uid_t uid);
119 
120 /* ========================================================================= *
121  * Functions
122  * ========================================================================= */
123 
124 static 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 
142 char *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 
157 int config_find_sync(void)
158 {
159  LOG_REGISTER_CONTEXT;
160 
161  return config_get_conf_int(FS_SYNC_ENTRY, FS_SYNC_KEY);
162 }
163 
164 char * 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 
171 char * 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 
178 char * 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 
185 char * config_check_trigger(void)
186 {
187  LOG_REGISTER_CONTEXT;
188 
189  return config_get_conf_string(TRIGGER_ENTRY, TRIGGER_PATH_KEY);
190 }
191 
192 char * config_get_trigger_subsystem(void)
193 {
194  LOG_REGISTER_CONTEXT;
195 
196  return config_get_conf_string(TRIGGER_ENTRY, TRIGGER_UDEV_SUBSYSTEM);
197 }
198 
199 char * config_get_trigger_mode(void)
200 {
201  LOG_REGISTER_CONTEXT;
202 
203  return config_get_conf_string(TRIGGER_ENTRY, TRIGGER_MODE_KEY);
204 }
205 
206 char * config_get_trigger_property(void)
207 {
208  LOG_REGISTER_CONTEXT;
209 
210  return config_get_conf_string(TRIGGER_ENTRY, TRIGGER_PROPERTY_KEY);
211 }
212 
213 char * 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 
220 static 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 
232 static 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 
239 static 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 
250 static 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 
261 static 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 
268 static 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 
281 char *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 
294 static 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 
307 gchar *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 
322 static 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 
400 char * 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 
423 EXIT:
424  return mode;
425 }
426 
427 set_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 
465 set_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 
475 set_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 */
493 static 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 
554 set_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 
577 set_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 
600 set_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 
622 set_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
638 char *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  */
655 set_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 
671 char *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 
712 EXIT:
713  modedata_free(data);
714 
715  return ret;
716 }
717 
728 static 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 
748 static 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 
767 static 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 
780 static 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 
809 static 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 
835 static 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 
843 static 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 
863 static 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 
887 static 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 
938 EXIT:
939  return ack;
940 }
941 
942 static 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 
960 static 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 
967 static 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 
1007 bool 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 
1042 static 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 
1052 char * 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 
1069 char * 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 
1076 char * 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 
1093 char * 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 
1100 char * config_get_hidden_modes(void)
1101 {
1102  LOG_REGISTER_CONTEXT;
1103 
1104  return config_get_conf_string(MODE_SETTING_ENTRY, MODE_HIDE_KEY);
1105 }
1106 char * 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 
1113 int 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 
1123 bool 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 }
modedata_free
void modedata_free(modedata_t *self)
Definition: usb_moded-dyn-config.c:76
usb_moded-dbus-private.h
usb_moded-modes.h
usb_moded-ssu.h
worker_dup_usb_mode_data
modedata_t * worker_dup_usb_mode_data(void)
Definition: usb_moded-worker.c:554
config_user_clear
bool config_user_clear(uid_t uid)
Definition: usb_moded-config.c:1123
modedata_t::network_interface
gchar * network_interface
Definition: usb_moded-dyn-config.h:107
config_init
bool config_init(void)
Definition: usb_moded-config.c:1007
MODE_ASK
#define MODE_ASK
Definition: usb_moded-modes.h:74
control_settings_changed
void control_settings_changed(void)
Definition: usb_moded-control.c:496
ssu_get_manufacturer_name
gchar * ssu_get_manufacturer_name(void)
Definition: usb_moded-ssu.c:94
usb_moded-config-private.h
usb_moded.h
common_valid_mode
int common_valid_mode(const char *mode)
Definition: usb_moded-common.c:535
ssu_get_product_name
gchar * ssu_get_product_name(void)
Definition: usb_moded-ssu.c:113
usb_moded-control.h
umdbus_send_whitelisted_modes_signal
int umdbus_send_whitelisted_modes_signal(const char *whitelist)
Definition: usb_moded-dbus.c:1873
common_send_available_modes_signal
void common_send_available_modes_signal(void)
Definition: usb_moded-common.c:240
SET_CONFIG_UPDATED
@ SET_CONFIG_UPDATED
Definition: usb_moded-config.h:85
usbmoded_get_current_user
uid_t usbmoded_get_current_user(void)
Definition: usb_moded.c:572
usb_moded-log.h
modedata_t
Definition: usb_moded-dyn-config.h:100
SET_CONFIG_UNCHANGED
@ SET_CONFIG_UNCHANGED
Definition: usb_moded-config.h:86
umdbus_send_config_signal
void umdbus_send_config_signal(const char *section, const char *key, const char *value)
Definition: usb_moded-dbus.c:1194
MODE_CHARGING
#define MODE_CHARGING
Definition: usb_moded-modes.h:77
common_send_supported_modes_signal
void common_send_supported_modes_signal(void)
Definition: usb_moded-common.c:229
usb_moded-worker.h
common_send_hidden_modes_signal
void common_send_hidden_modes_signal(void)
Definition: usb_moded-common.c:251
set_config_result_t
set_config_result_t
Definition: usb_moded-config.h:83
SET_CONFIG_ERROR
@ SET_CONFIG_ERROR
Definition: usb_moded-config.h:84