Added support of WPA3-SAE security mode.
[platform/upstream/connman.git] / src / clock.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2013  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <sys/time.h>
27
28 #include <gdbus.h>
29
30 #include "connman.h"
31
32 enum timezone_updates {
33         TIMEZONE_UPDATES_UNKNOWN = 0,
34         TIMEZONE_UPDATES_MANUAL  = 1,
35         TIMEZONE_UPDATES_AUTO    = 2,
36 };
37
38 static enum time_updates time_updates_config = TIME_UPDATES_AUTO;
39 static enum timezone_updates timezone_updates_config = TIMEZONE_UPDATES_AUTO;
40
41 static char *timezone_config = NULL;
42
43 static const char *time_updates2string(enum time_updates value)
44 {
45         switch (value) {
46         case TIME_UPDATES_UNKNOWN:
47                 break;
48         case TIME_UPDATES_MANUAL:
49                 return "manual";
50         case TIME_UPDATES_AUTO:
51                 return "auto";
52         }
53
54         return NULL;
55 }
56
57 static enum time_updates string2time_updates(const char *value)
58 {
59         if (g_strcmp0(value, "manual") == 0)
60                 return TIME_UPDATES_MANUAL;
61         else if (g_strcmp0(value, "auto") == 0)
62                 return TIME_UPDATES_AUTO;
63
64         return TIME_UPDATES_UNKNOWN;
65 }
66
67 static const char *timezone_updates2string(enum timezone_updates value)
68 {
69         switch (value) {
70         case TIMEZONE_UPDATES_UNKNOWN:
71                 break;
72         case TIMEZONE_UPDATES_MANUAL:
73                 return "manual";
74         case TIMEZONE_UPDATES_AUTO:
75                 return "auto";
76         }
77
78         return NULL;
79 }
80
81 static enum timezone_updates string2timezone_updates(const char *value)
82 {
83         if (g_strcmp0(value, "manual") == 0)
84                 return TIMEZONE_UPDATES_MANUAL;
85         else if (g_strcmp0(value, "auto") == 0)
86                 return TIMEZONE_UPDATES_AUTO;
87
88         return TIMEZONE_UPDATES_UNKNOWN;
89 }
90
91 static void clock_properties_load(void)
92 {
93         GKeyFile *keyfile;
94         char *str;
95         enum time_updates time_value;
96         enum timezone_updates timezone_value;
97
98         keyfile = __connman_storage_load_global();
99         if (!keyfile)
100                 return;
101
102         str = g_key_file_get_string(keyfile, "global", "TimeUpdates", NULL);
103
104         time_value = string2time_updates(str);
105         if (time_value != TIME_UPDATES_UNKNOWN)
106                 time_updates_config = time_value;
107
108         g_free(str);
109
110         str = g_key_file_get_string(keyfile, "global", "TimezoneUpdates",
111                         NULL);
112
113         timezone_value = string2timezone_updates(str);
114         if (timezone_value != TIMEZONE_UPDATES_UNKNOWN)
115                 timezone_updates_config = timezone_value;
116
117         g_free(str);
118
119         g_key_file_free(keyfile);
120 }
121
122 static void clock_properties_save(void)
123 {
124         GKeyFile *keyfile;
125         const char *str;
126
127         keyfile = __connman_storage_load_global();
128         if (!keyfile)
129                 keyfile = g_key_file_new();
130
131         str = time_updates2string(time_updates_config);
132         if (str)
133                 g_key_file_set_string(keyfile, "global", "TimeUpdates", str);
134         else
135                 g_key_file_remove_key(keyfile, "global", "TimeUpdates", NULL);
136
137         str = timezone_updates2string(timezone_updates_config);
138         if (str)
139                 g_key_file_set_string(keyfile, "global", "TimezoneUpdates",
140                                 str);
141         else
142                 g_key_file_remove_key(keyfile, "global", "TimezoneUpdates",
143                                 NULL);
144
145         __connman_storage_save_global(keyfile);
146
147         g_key_file_free(keyfile);
148 }
149
150 enum time_updates __connman_clock_timeupdates(void)
151 {
152         return time_updates_config;
153 }
154
155 static void append_timeservers(DBusMessageIter *iter, void *user_data)
156 {
157         int i;
158         char **timeservers = __connman_timeserver_system_get();
159
160         if (!timeservers)
161                 return;
162
163         for (i = 0; timeservers[i]; i++) {
164                 dbus_message_iter_append_basic(iter,
165                                 DBUS_TYPE_STRING, &timeservers[i]);
166         }
167
168         g_strfreev(timeservers);
169 }
170
171 static DBusMessage *get_properties(DBusConnection *conn,
172                                         DBusMessage *msg, void *data)
173 {
174         DBusMessage *reply;
175         DBusMessageIter array, dict;
176         struct timeval tv;
177         const char *str;
178
179         DBG("conn %p", conn);
180
181         reply = dbus_message_new_method_return(msg);
182         if (!reply)
183                 return NULL;
184
185         dbus_message_iter_init_append(reply, &array);
186
187         connman_dbus_dict_open(&array, &dict);
188
189         if (gettimeofday(&tv, NULL) == 0) {
190                 dbus_uint64_t val = tv.tv_sec;
191
192                 connman_dbus_dict_append_basic(&dict, "Time",
193                                                 DBUS_TYPE_UINT64, &val);
194         }
195
196         str = time_updates2string(time_updates_config);
197         if (str)
198                 connman_dbus_dict_append_basic(&dict, "TimeUpdates",
199                                                 DBUS_TYPE_STRING, &str);
200
201         if (timezone_config)
202                 connman_dbus_dict_append_basic(&dict, "Timezone",
203                                         DBUS_TYPE_STRING, &timezone_config);
204
205         str = timezone_updates2string(timezone_updates_config);
206         if (str)
207                 connman_dbus_dict_append_basic(&dict, "TimezoneUpdates",
208                                                 DBUS_TYPE_STRING, &str);
209
210         connman_dbus_dict_append_array(&dict, "Timeservers",
211                                 DBUS_TYPE_STRING, append_timeservers, NULL);
212
213         connman_dbus_dict_close(&array, &dict);
214
215         return reply;
216 }
217
218 static DBusMessage *set_property(DBusConnection *conn,
219                                         DBusMessage *msg, void *data)
220 {
221         DBusMessageIter iter, value;
222         const char *name;
223         int type;
224
225         DBG("conn %p", conn);
226
227         if (!dbus_message_iter_init(msg, &iter))
228                 return __connman_error_invalid_arguments(msg);
229
230         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
231                 return __connman_error_invalid_arguments(msg);
232
233         dbus_message_iter_get_basic(&iter, &name);
234         dbus_message_iter_next(&iter);
235
236         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
237                 return __connman_error_invalid_arguments(msg);
238
239         dbus_message_iter_recurse(&iter, &value);
240
241         type = dbus_message_iter_get_arg_type(&value);
242
243         if (g_str_equal(name, "Time")) {
244 #if defined TIZEN_EXT
245                 /* Tizen updates time (ntp) by system service */
246
247                 return __connman_error_permission_denied(msg);
248 #else
249                 struct timeval tv;
250                 dbus_uint64_t newval;
251
252                 if (type != DBUS_TYPE_UINT64)
253                         return __connman_error_invalid_arguments(msg);
254
255                 if (time_updates_config != TIME_UPDATES_MANUAL)
256                         return __connman_error_permission_denied(msg);
257
258                 dbus_message_iter_get_basic(&value, &newval);
259
260                 tv.tv_sec = newval;
261                 tv.tv_usec = 0;
262
263                 if (settimeofday(&tv, NULL) < 0)
264                         return __connman_error_invalid_arguments(msg);
265
266                 connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
267                                 CONNMAN_CLOCK_INTERFACE, "Time",
268                                 DBUS_TYPE_UINT64, &newval);
269 #endif
270         } else if (g_str_equal(name, "TimeUpdates")) {
271                 const char *strval;
272                 enum time_updates newval;
273
274                 if (type != DBUS_TYPE_STRING)
275                         return __connman_error_invalid_arguments(msg);
276
277                 dbus_message_iter_get_basic(&value, &strval);
278                 newval = string2time_updates(strval);
279
280                 if (newval == TIME_UPDATES_UNKNOWN)
281                         return __connman_error_invalid_arguments(msg);
282
283                 if (newval == time_updates_config)
284                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
285
286                 time_updates_config = newval;
287
288                 clock_properties_save();
289                 connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
290                                 CONNMAN_CLOCK_INTERFACE, "TimeUpdates",
291                                 DBUS_TYPE_STRING, &strval);
292         } else if (g_str_equal(name, "Timezone")) {
293                 const char *strval;
294
295                 if (type != DBUS_TYPE_STRING)
296                         return __connman_error_invalid_arguments(msg);
297
298                 if (timezone_updates_config != TIMEZONE_UPDATES_MANUAL)
299                         return __connman_error_permission_denied(msg);
300
301                 dbus_message_iter_get_basic(&value, &strval);
302
303                 if (__connman_timezone_change(strval) < 0)
304                         return __connman_error_invalid_arguments(msg);
305         } else if (g_str_equal(name, "TimezoneUpdates")) {
306                 const char *strval;
307                 enum timezone_updates newval;
308
309                 if (type != DBUS_TYPE_STRING)
310                         return __connman_error_invalid_arguments(msg);
311
312                 dbus_message_iter_get_basic(&value, &strval);
313                 newval = string2timezone_updates(strval);
314
315                 if (newval == TIMEZONE_UPDATES_UNKNOWN)
316                         return __connman_error_invalid_arguments(msg);
317
318                 if (newval == timezone_updates_config)
319                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
320
321                 timezone_updates_config = newval;
322
323                 clock_properties_save();
324                 connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
325                                 CONNMAN_CLOCK_INTERFACE, "TimezoneUpdates",
326                                 DBUS_TYPE_STRING, &strval);
327         } else if (g_str_equal(name, "Timeservers")) {
328                 DBusMessageIter entry;
329                 char **str = NULL;
330                 GSList *list = NULL;
331                 int count = 0;
332
333                 if (type != DBUS_TYPE_ARRAY)
334                         return __connman_error_invalid_arguments(msg);
335
336                 dbus_message_iter_recurse(&value, &entry);
337
338                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
339                         const char *val;
340                         GSList *new_head;
341
342                         dbus_message_iter_get_basic(&entry, &val);
343
344                         new_head = __connman_timeserver_add_list(list, val);
345                         if (list != new_head) {
346                                 count++;
347                                 list = new_head;
348                         }
349
350                         dbus_message_iter_next(&entry);
351                 }
352
353                 if (list) {
354                         str = g_new0(char *, count+1);
355
356                         while (list) {
357                                 count--;
358                                 str[count] = list->data;
359                                 list = g_slist_delete_link(list, list);
360                         };
361                 }
362
363                 __connman_timeserver_system_set(str);
364
365                 if (str)
366                         g_strfreev(str);
367
368                 connman_dbus_property_changed_array(CONNMAN_MANAGER_PATH,
369                                 CONNMAN_CLOCK_INTERFACE, "Timeservers",
370                                 DBUS_TYPE_STRING, append_timeservers, NULL);
371         } else
372                 return __connman_error_invalid_property(msg);
373
374         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
375 }
376
377 static const GDBusMethodTable clock_methods[] = {
378         { GDBUS_METHOD("GetProperties",
379                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
380                         get_properties) },
381         { GDBUS_METHOD("SetProperty",
382                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL,
383                         set_property)   },
384         { },
385 };
386
387 static const GDBusSignalTable clock_signals[] = {
388         { GDBUS_SIGNAL("PropertyChanged",
389                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
390         { },
391 };
392
393 static DBusConnection *connection = NULL;
394
395 void __connman_clock_update_timezone(void)
396 {
397         DBG("");
398
399         g_free(timezone_config);
400         timezone_config = __connman_timezone_lookup();
401
402         if (!timezone_config)
403                 return;
404
405         connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
406                                 CONNMAN_CLOCK_INTERFACE, "Timezone",
407                                 DBUS_TYPE_STRING, &timezone_config);
408 }
409
410 int __connman_clock_init(void)
411 {
412         DBG("");
413
414         connection = connman_dbus_get_connection();
415         if (!connection)
416                 return -1;
417
418         __connman_timezone_init();
419
420         timezone_config = __connman_timezone_lookup();
421
422         g_dbus_register_interface(connection, CONNMAN_MANAGER_PATH,
423                                                 CONNMAN_CLOCK_INTERFACE,
424                                                 clock_methods, clock_signals,
425                                                 NULL, NULL, NULL);
426
427         clock_properties_load();
428         return 0;
429 }
430
431 void __connman_clock_cleanup(void)
432 {
433         DBG("");
434
435         if (!connection)
436                 return;
437
438         g_dbus_unregister_interface(connection, CONNMAN_MANAGER_PATH,
439                                                 CONNMAN_CLOCK_INTERFACE);
440
441         dbus_connection_unref(connection);
442
443         __connman_timezone_cleanup();
444
445         g_free(timezone_config);
446 }