1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2  *
3  * Copyright (C) 2007 David Zeuthen <david@fubar.dk>
4  * Copyright (C) 2012-2021 MATE Developers
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
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 <stdlib.h>
27 #include <stdio.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <sys/wait.h>
32 #include <errno.h>
33 #include <sys/time.h>
34 
35 #include <glib.h>
36 #include <glib-object.h>
37 
38 #include <dbus/dbus-glib.h>
39 #include <dbus/dbus-glib-lowlevel.h>
40 
41 #include <polkit/polkit.h>
42 
43 #include "system-timezone.h"
44 
45 #include "msd-datetime-mechanism.h"
46 #include "msd-datetime-mechanism-glue.h"
47 
48 static gboolean
do_exit(gpointer user_data)49 do_exit (gpointer user_data)
50 {
51         g_debug ("Exiting due to inactivity");
52         exit (1);
53         return FALSE;
54 }
55 
56 static void
reset_killtimer(void)57 reset_killtimer (void)
58 {
59         static guint timer_id = 0;
60 
61         if (timer_id > 0) {
62                 g_source_remove (timer_id);
63         }
64         g_debug ("Setting killtimer to 30 seconds...");
65         timer_id = g_timeout_add_seconds (30, do_exit, NULL);
66 }
67 
68 struct MsdDatetimeMechanismPrivate
69 {
70         DBusGConnection *system_bus_connection;
71         DBusGProxy      *system_bus_proxy;
72         PolkitAuthority *auth;
73 };
74 
75 static void     msd_datetime_mechanism_finalize    (GObject     *object);
76 
G_DEFINE_TYPE_WITH_PRIVATE(MsdDatetimeMechanism,msd_datetime_mechanism,G_TYPE_OBJECT)77 G_DEFINE_TYPE_WITH_PRIVATE (MsdDatetimeMechanism, msd_datetime_mechanism, G_TYPE_OBJECT)
78 
79 GQuark
80 msd_datetime_mechanism_error_quark (void)
81 {
82         static GQuark ret = 0;
83 
84         if (ret == 0) {
85                 ret = g_quark_from_static_string ("msd_datetime_mechanism_error");
86         }
87 
88         return ret;
89 }
90 
91 
92 #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
93 
94 GType
msd_datetime_mechanism_error_get_type(void)95 msd_datetime_mechanism_error_get_type (void)
96 {
97         static GType etype = 0;
98 
99         if (etype == 0)
100         {
101                 static const GEnumValue values[] =
102                         {
103                                 ENUM_ENTRY (MSD_DATETIME_MECHANISM_ERROR_GENERAL, "GeneralError"),
104                                 ENUM_ENTRY (MSD_DATETIME_MECHANISM_ERROR_NOT_PRIVILEGED, "NotPrivileged"),
105                                 ENUM_ENTRY (MSD_DATETIME_MECHANISM_ERROR_INVALID_TIMEZONE_FILE, "InvalidTimezoneFile"),
106                                 { 0, 0, 0 }
107                         };
108 
109                 g_assert (MSD_DATETIME_MECHANISM_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
110 
111                 etype = g_enum_register_static ("MsdDatetimeMechanismError", values);
112         }
113 
114         return etype;
115 }
116 
117 
118 static GObject *
msd_datetime_mechanism_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_properties)119 msd_datetime_mechanism_constructor (GType                  type,
120                                     guint                  n_construct_properties,
121                                     GObjectConstructParam *construct_properties)
122 {
123         MsdDatetimeMechanism      *mechanism;
124 
125         mechanism = MSD_DATETIME_MECHANISM (G_OBJECT_CLASS (msd_datetime_mechanism_parent_class)->constructor (
126                                                 type,
127                                                 n_construct_properties,
128                                                 construct_properties));
129 
130         return G_OBJECT (mechanism);
131 }
132 
133 static void
msd_datetime_mechanism_class_init(MsdDatetimeMechanismClass * klass)134 msd_datetime_mechanism_class_init (MsdDatetimeMechanismClass *klass)
135 {
136         GObjectClass   *object_class = G_OBJECT_CLASS (klass);
137 
138         object_class->constructor = msd_datetime_mechanism_constructor;
139         object_class->finalize = msd_datetime_mechanism_finalize;
140 
141         dbus_g_object_type_install_info (MSD_DATETIME_TYPE_MECHANISM, &dbus_glib_msd_datetime_mechanism_object_info);
142 
143         dbus_g_error_domain_register (MSD_DATETIME_MECHANISM_ERROR, NULL, MSD_DATETIME_MECHANISM_TYPE_ERROR);
144 
145 }
146 
147 static void
msd_datetime_mechanism_init(MsdDatetimeMechanism * mechanism)148 msd_datetime_mechanism_init (MsdDatetimeMechanism *mechanism)
149 {
150         mechanism->priv = msd_datetime_mechanism_get_instance_private (mechanism);
151 
152 }
153 
154 static void
msd_datetime_mechanism_finalize(GObject * object)155 msd_datetime_mechanism_finalize (GObject *object)
156 {
157         MsdDatetimeMechanism *mechanism;
158 
159         g_return_if_fail (object != NULL);
160         g_return_if_fail (MSD_DATETIME_IS_MECHANISM (object));
161 
162         mechanism = MSD_DATETIME_MECHANISM (object);
163 
164         g_return_if_fail (mechanism->priv != NULL);
165 
166         g_object_unref (mechanism->priv->system_bus_proxy);
167 
168         G_OBJECT_CLASS (msd_datetime_mechanism_parent_class)->finalize (object);
169 }
170 
171 static gboolean
register_mechanism(MsdDatetimeMechanism * mechanism)172 register_mechanism (MsdDatetimeMechanism *mechanism)
173 {
174         GError *error = NULL;
175 
176         mechanism->priv->auth = polkit_authority_get_sync (NULL, &error);
177         if (mechanism->priv->auth == NULL) {
178                 if (error != NULL) {
179                         g_critical ("error getting system bus: %s", error->message);
180                         g_error_free (error);
181                 }
182                 goto error;
183         }
184 
185         mechanism->priv->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
186         if (mechanism->priv->system_bus_connection == NULL) {
187                 if (error != NULL) {
188                         g_critical ("error getting system bus: %s", error->message);
189                         g_error_free (error);
190                 }
191                 goto error;
192         }
193 
194         dbus_g_connection_register_g_object (mechanism->priv->system_bus_connection, "/",
195                                              G_OBJECT (mechanism));
196 
197         mechanism->priv->system_bus_proxy = dbus_g_proxy_new_for_name (mechanism->priv->system_bus_connection,
198                                                                       DBUS_SERVICE_DBUS,
199                                                                       DBUS_PATH_DBUS,
200                                                                       DBUS_INTERFACE_DBUS);
201 
202         reset_killtimer ();
203 
204         return TRUE;
205 
206 error:
207         return FALSE;
208 }
209 
210 
211 MsdDatetimeMechanism *
msd_datetime_mechanism_new(void)212 msd_datetime_mechanism_new (void)
213 {
214         GObject *object;
215         gboolean res;
216 
217         object = g_object_new (MSD_DATETIME_TYPE_MECHANISM, NULL);
218 
219         res = register_mechanism (MSD_DATETIME_MECHANISM (object));
220         if (! res) {
221                 g_object_unref (object);
222                 return NULL;
223         }
224 
225         return MSD_DATETIME_MECHANISM (object);
226 }
227 
228 static gboolean
_check_polkit_for_action(MsdDatetimeMechanism * mechanism,DBusGMethodInvocation * context,const char * action)229 _check_polkit_for_action (MsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context, const char *action)
230 {
231         const char *sender;
232         GError *error;
233         PolkitSubject *subject;
234         PolkitAuthorizationResult *result;
235 
236         error = NULL;
237 
238         /* Check that caller is privileged */
239         sender = dbus_g_method_get_sender (context);
240         subject = polkit_system_bus_name_new (sender);
241 
242         result = polkit_authority_check_authorization_sync (mechanism->priv->auth,
243                                                             subject,
244                                                             action,
245                                                             NULL,
246                                                             POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
247                                                             NULL, &error);
248         g_object_unref (subject);
249 
250         if (error) {
251                 dbus_g_method_return_error (context, error);
252                 g_error_free (error);
253 
254                 return FALSE;
255         }
256 
257         if (!polkit_authorization_result_get_is_authorized (result)) {
258                 error = g_error_new (MSD_DATETIME_MECHANISM_ERROR,
259                                      MSD_DATETIME_MECHANISM_ERROR_NOT_PRIVILEGED,
260                                      "Not Authorized for action %s", action);
261                 dbus_g_method_return_error (context, error);
262                 g_error_free (error);
263                 g_object_unref (result);
264 
265                 return FALSE;
266         }
267 
268         g_object_unref (result);
269 
270         return TRUE;
271 }
272 
273 
274 static gboolean
_set_time(MsdDatetimeMechanism * mechanism,const struct timeval * tv,DBusGMethodInvocation * context)275 _set_time (MsdDatetimeMechanism  *mechanism,
276            const struct timeval  *tv,
277            DBusGMethodInvocation *context)
278 {
279         GError *error;
280 
281         if (!_check_polkit_for_action (mechanism, context, "org.mate.settingsdaemon.datetimemechanism.settime"))
282                 return FALSE;
283 
284         if (settimeofday (tv, NULL) != 0) {
285                 error = g_error_new (MSD_DATETIME_MECHANISM_ERROR,
286                                      MSD_DATETIME_MECHANISM_ERROR_GENERAL,
287                                      "Error calling settimeofday({%ld,%ld}): %s",
288                                      (gint64) tv->tv_sec, (gint64) tv->tv_usec,
289                                      strerror (errno));
290                 dbus_g_method_return_error (context, error);
291                 g_error_free (error);
292                 return FALSE;
293         }
294 
295         if (g_file_test ("/sbin/hwclock",
296                          G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_EXECUTABLE)) {
297                 int exit_status;
298                 if (!g_spawn_command_line_sync ("/sbin/hwclock --systohc", NULL, NULL, &exit_status, &error)) {
299                         GError *error2;
300                         error2 = g_error_new (MSD_DATETIME_MECHANISM_ERROR,
301                                               MSD_DATETIME_MECHANISM_ERROR_GENERAL,
302                                               "Error spawning /sbin/hwclock: %s", error->message);
303                         g_error_free (error);
304                         dbus_g_method_return_error (context, error2);
305                         g_error_free (error2);
306                         return FALSE;
307                 }
308                 if (WEXITSTATUS (exit_status) != 0) {
309                         error = g_error_new (MSD_DATETIME_MECHANISM_ERROR,
310                                              MSD_DATETIME_MECHANISM_ERROR_GENERAL,
311                                              "/sbin/hwclock returned %d", exit_status);
312                         dbus_g_method_return_error (context, error);
313                         g_error_free (error);
314                         return FALSE;
315                 }
316         }
317 
318         dbus_g_method_return (context);
319         return TRUE;
320 }
321 
322 static gboolean
_rh_update_etc_sysconfig_clock(DBusGMethodInvocation * context,const char * key,const char * value)323 _rh_update_etc_sysconfig_clock (DBusGMethodInvocation *context, const char *key, const char *value)
324 {
325         /* On Red Hat / Fedora, the /etc/sysconfig/clock file needs to be kept in sync */
326         if (g_file_test ("/etc/sysconfig/clock", G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
327                 char **lines;
328                 int n;
329                 gboolean replaced;
330                 char *data;
331                 gsize len;
332                 GError *error;
333 
334                 error = NULL;
335 
336                 if (!g_file_get_contents ("/etc/sysconfig/clock", &data, &len, &error)) {
337                         GError *error2;
338                         error2 = g_error_new (MSD_DATETIME_MECHANISM_ERROR,
339                                               MSD_DATETIME_MECHANISM_ERROR_GENERAL,
340                                               "Error reading /etc/sysconfig/clock file: %s", error->message);
341                         g_error_free (error);
342                         dbus_g_method_return_error (context, error2);
343                         g_error_free (error2);
344                         return FALSE;
345                 }
346                 replaced = FALSE;
347                 lines = g_strsplit (data, "\n", 0);
348                 g_free (data);
349 
350                 for (n = 0; lines[n] != NULL; n++) {
351                         if (g_str_has_prefix (lines[n], key)) {
352                                 g_free (lines[n]);
353                                 lines[n] = g_strdup_printf ("%s%s", key, value);
354                                 replaced = TRUE;
355                         }
356                 }
357                 if (replaced) {
358                         GString *str;
359 
360                         str = g_string_new (NULL);
361                         for (n = 0; lines[n] != NULL; n++) {
362                                 g_string_append (str, lines[n]);
363                                 if (lines[n + 1] != NULL)
364                                         g_string_append_c (str, '\n');
365                         }
366                         data = g_string_free (str, FALSE);
367                         len = strlen (data);
368                         if (!g_file_set_contents ("/etc/sysconfig/clock", data, len, &error)) {
369                                 GError *error2;
370                                 error2 = g_error_new (MSD_DATETIME_MECHANISM_ERROR,
371                                                       MSD_DATETIME_MECHANISM_ERROR_GENERAL,
372                                                       "Error updating /etc/sysconfig/clock: %s", error->message);
373                                 g_error_free (error);
374                                 dbus_g_method_return_error (context, error2);
375                                 g_error_free (error2);
376                                 g_free (data);
377                                 return FALSE;
378                         }
379                         g_free (data);
380                 }
381                 g_strfreev (lines);
382         }
383 
384         return TRUE;
385 }
386 
387 /* exported methods */
388 
389 gboolean
msd_datetime_mechanism_set_time(MsdDatetimeMechanism * mechanism,gint64 seconds_since_epoch,DBusGMethodInvocation * context)390 msd_datetime_mechanism_set_time (MsdDatetimeMechanism  *mechanism,
391                                  gint64                 seconds_since_epoch,
392                                  DBusGMethodInvocation *context)
393 {
394         struct timeval tv;
395 
396         reset_killtimer ();
397         g_debug ("SetTime(%ld) called", seconds_since_epoch);
398 
399         tv.tv_sec = (time_t) seconds_since_epoch;
400         tv.tv_usec = 0;
401         return _set_time (mechanism, &tv, context);
402 }
403 
404 gboolean
msd_datetime_mechanism_adjust_time(MsdDatetimeMechanism * mechanism,gint64 seconds_to_add,DBusGMethodInvocation * context)405 msd_datetime_mechanism_adjust_time (MsdDatetimeMechanism  *mechanism,
406                                     gint64                 seconds_to_add,
407                                     DBusGMethodInvocation *context)
408 {
409         struct timeval tv;
410 
411         reset_killtimer ();
412         g_debug ("AdjustTime(%ld) called", seconds_to_add);
413 
414         if (gettimeofday (&tv, NULL) != 0) {
415                 GError *error;
416                 error = g_error_new (MSD_DATETIME_MECHANISM_ERROR,
417                                      MSD_DATETIME_MECHANISM_ERROR_GENERAL,
418                                      "Error calling gettimeofday(): %s", strerror (errno));
419                 dbus_g_method_return_error (context, error);
420                 g_error_free (error);
421                 return FALSE;
422         }
423 
424         tv.tv_sec += (time_t) seconds_to_add;
425         return _set_time (mechanism, &tv, context);
426 }
427 
428 
429 gboolean
msd_datetime_mechanism_set_timezone(MsdDatetimeMechanism * mechanism,const char * zone_file,DBusGMethodInvocation * context)430 msd_datetime_mechanism_set_timezone (MsdDatetimeMechanism  *mechanism,
431                                      const char            *zone_file,
432                                      DBusGMethodInvocation *context)
433 {
434         GError *error;
435 
436         reset_killtimer ();
437         g_debug ("SetTimezone('%s') called", zone_file);
438 
439         if (!_check_polkit_for_action (mechanism, context, "org.mate.settingsdaemon.datetimemechanism.settimezone"))
440                 return FALSE;
441 
442         error = NULL;
443 
444         if (!system_timezone_set_from_file (zone_file, &error)) {
445                 GError *error2;
446                 int     code;
447 
448                 if (error->code == SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE)
449                         code = MSD_DATETIME_MECHANISM_ERROR_INVALID_TIMEZONE_FILE;
450                 else
451                         code = MSD_DATETIME_MECHANISM_ERROR_GENERAL;
452 
453                 error2 = g_error_new (MSD_DATETIME_MECHANISM_ERROR,
454                                       code, "%s", error->message);
455 
456                 g_error_free (error);
457 
458                 dbus_g_method_return_error (context, error2);
459                 g_error_free (error2);
460 
461                 return FALSE;
462         }
463 
464         dbus_g_method_return (context);
465         return TRUE;
466 }
467 
468 
469 gboolean
msd_datetime_mechanism_get_timezone(MsdDatetimeMechanism * mechism,DBusGMethodInvocation * context)470 msd_datetime_mechanism_get_timezone (MsdDatetimeMechanism   *mechism,
471                                      DBusGMethodInvocation  *context)
472 {
473   gchar *timezone;
474 
475   reset_killtimer ();
476 
477   timezone = system_timezone_find ();
478 
479   dbus_g_method_return (context, timezone);
480 
481   return TRUE;
482 }
483 
484 gboolean
msd_datetime_mechanism_get_hardware_clock_using_utc(MsdDatetimeMechanism * mechanism,DBusGMethodInvocation * context)485 msd_datetime_mechanism_get_hardware_clock_using_utc (MsdDatetimeMechanism  *mechanism,
486                                                      DBusGMethodInvocation *context)
487 {
488         char **lines;
489         char *data;
490         gsize len;
491         GError *error;
492         gboolean is_utc;
493 
494         error = NULL;
495 
496         if (!g_file_get_contents ("/etc/adjtime", &data, &len, &error)) {
497                 GError *error2;
498                 error2 = g_error_new (MSD_DATETIME_MECHANISM_ERROR,
499                                       MSD_DATETIME_MECHANISM_ERROR_GENERAL,
500                                       "Error reading /etc/adjtime file: %s", error->message);
501                 g_error_free (error);
502                 dbus_g_method_return_error (context, error2);
503                 g_error_free (error2);
504                 return FALSE;
505         }
506 
507         lines = g_strsplit (data, "\n", 0);
508         g_free (data);
509 
510         if (g_strv_length (lines) < 3) {
511                 error = g_error_new (MSD_DATETIME_MECHANISM_ERROR,
512                                      MSD_DATETIME_MECHANISM_ERROR_GENERAL,
513                                      "Cannot parse /etc/adjtime");
514                 dbus_g_method_return_error (context, error);
515                 g_error_free (error);
516                 g_strfreev (lines);
517                 return FALSE;
518         }
519 
520         if (strcmp (lines[2], "UTC") == 0) {
521                 is_utc = TRUE;
522         } else if (strcmp (lines[2], "LOCAL") == 0) {
523                 is_utc = FALSE;
524         } else {
525                 error = g_error_new (MSD_DATETIME_MECHANISM_ERROR,
526                                      MSD_DATETIME_MECHANISM_ERROR_GENERAL,
527                                      "Expected UTC or LOCAL at line 3 of /etc/adjtime; found '%s'", lines[2]);
528                 dbus_g_method_return_error (context, error);
529                 g_error_free (error);
530                 g_strfreev (lines);
531                 return FALSE;
532         }
533         g_strfreev (lines);
534         dbus_g_method_return (context, is_utc);
535         return TRUE;
536 }
537 
538 gboolean
msd_datetime_mechanism_set_hardware_clock_using_utc(MsdDatetimeMechanism * mechanism,gboolean using_utc,DBusGMethodInvocation * context)539 msd_datetime_mechanism_set_hardware_clock_using_utc (MsdDatetimeMechanism  *mechanism,
540                                                      gboolean               using_utc,
541                                                      DBusGMethodInvocation *context)
542 {
543         GError *error;
544 
545         error = NULL;
546 
547         if (!_check_polkit_for_action (mechanism, context,
548                                        "org.mate.settingsdaemon.datetimemechanism.configurehwclock"))
549                 return FALSE;
550 
551         if (g_file_test ("/sbin/hwclock",
552                          G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_EXECUTABLE)) {
553                 int exit_status;
554                 char *cmd;
555                 cmd = g_strdup_printf ("/sbin/hwclock %s --systohc", using_utc ? "--utc" : "--localtime");
556                 if (!g_spawn_command_line_sync (cmd, NULL, NULL, &exit_status, &error)) {
557                         GError *error2;
558                         error2 = g_error_new (MSD_DATETIME_MECHANISM_ERROR,
559                                               MSD_DATETIME_MECHANISM_ERROR_GENERAL,
560                                               "Error spawning /sbin/hwclock: %s", error->message);
561                         g_error_free (error);
562                         dbus_g_method_return_error (context, error2);
563                         g_error_free (error2);
564                         g_free (cmd);
565                         return FALSE;
566                 }
567                 g_free (cmd);
568                 if (WEXITSTATUS (exit_status) != 0) {
569                         error = g_error_new (MSD_DATETIME_MECHANISM_ERROR,
570                                              MSD_DATETIME_MECHANISM_ERROR_GENERAL,
571                                              "/sbin/hwclock returned %d", exit_status);
572                         dbus_g_method_return_error (context, error);
573                         g_error_free (error);
574                         return FALSE;
575                 }
576 
577                 if (!_rh_update_etc_sysconfig_clock (context, "UTC=", using_utc ? "true" : "false"))
578                         return FALSE;
579 
580         }
581         dbus_g_method_return (context);
582         return TRUE;
583 }
584 
585 static void
check_can_do(MsdDatetimeMechanism * mechanism,const char * action,DBusGMethodInvocation * context)586 check_can_do (MsdDatetimeMechanism  *mechanism,
587               const char            *action,
588               DBusGMethodInvocation *context)
589 {
590         const char *sender;
591         PolkitSubject *subject;
592         PolkitAuthorizationResult *result;
593         GError *error;
594 
595         /* Check that caller is privileged */
596         sender = dbus_g_method_get_sender (context);
597         subject = polkit_system_bus_name_new (sender);
598 
599         error = NULL;
600         result = polkit_authority_check_authorization_sync (mechanism->priv->auth,
601                                                             subject,
602                                                             action,
603                                                             NULL,
604                                                             0,
605                                                             NULL,
606                                                             &error);
607         g_object_unref (subject);
608 
609         if (error) {
610                 dbus_g_method_return_error (context, error);
611                 g_error_free (error);
612                 return;
613         }
614 
615         if (polkit_authorization_result_get_is_authorized (result)) {
616                 dbus_g_method_return (context, 2);
617         }
618         else if (polkit_authorization_result_get_is_challenge (result)) {
619                 dbus_g_method_return (context, 1);
620         }
621         else {
622                 dbus_g_method_return (context, 0);
623         }
624 
625         g_object_unref (result);
626 }
627 
628 
629 gboolean
msd_datetime_mechanism_can_set_time(MsdDatetimeMechanism * mechanism,DBusGMethodInvocation * context)630 msd_datetime_mechanism_can_set_time (MsdDatetimeMechanism  *mechanism,
631                                      DBusGMethodInvocation *context)
632 {
633         check_can_do (mechanism,
634                       "org.mate.settingsdaemon.datetimemechanism.settime",
635                       context);
636 
637         return TRUE;
638 }
639 
640 gboolean
msd_datetime_mechanism_can_set_timezone(MsdDatetimeMechanism * mechanism,DBusGMethodInvocation * context)641 msd_datetime_mechanism_can_set_timezone (MsdDatetimeMechanism  *mechanism,
642                                          DBusGMethodInvocation *context)
643 {
644         check_can_do (mechanism,
645                       "org.mate.settingsdaemon.datetimemechanism.settimezone",
646                       context);
647 
648         return TRUE;
649 }
650