summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkx <kx@radix.pro>2023-12-23 14:15:03 +0300
committerkx <kx@radix.pro>2023-12-23 14:15:03 +0300
commitc5f7eedd8605cc228ab72bc3d9c38981d269a14f (patch)
tree7d99a301b5268be1eb5ce7d627af481e15929000
parentd080f8c5bfbef5bf95290b698ad03b9e7e8cb2c4 (diff)
downloadtimedated-c5f7eedd8605cc228ab72bc3d9c38981d269a14f.tar.xz
Support the interactive parameter for asynchronous polkit authorization
-rw-r--r--README.md12
-rw-r--r--src/rcl-timedate.c723
2 files changed, 521 insertions, 214 deletions
diff --git a/README.md b/README.md
index 4724bd1..2c5abae 100644
--- a/README.md
+++ b/README.md
@@ -9,12 +9,12 @@ This is the replacement of *systemd* service that control the **org.freedesktop.
You can find specification at: [**Freedesktop.org**](https://www.freedesktop.org/software/systemd/man/latest/org.freedesktop.timedate1.html)
-**TimeDate** Daemon does not support interactive parameter which can be used to control
-whether *PolKit* should interactively ask the user for authentication credentials if required.
-Instead of interactive way users permissions can be set by *PolKit* rules in the
-*/usr/share/polkit-1/rules.d/org.freedesktop.timedate1.rules* file. For example,
-a system administrator can add Desktop-users into **wheel** group to give them rights
-to access the **org.freedesktop.timedate1** *D-Bus interface*.
+**TimeDate** Daemon supports interactive parameter which can be used to control
+whether *PolKit* should interactively ask the user for authentication credentials
+if required. But also, if interactive way is not applicable, users permissions can
+be set by *PolKit* rules in the */usr/share/polkit-1/rules.d/org.freedesktop.timedate1.rules*
+file. For example, a system administrator can add Desktop-users into **wheel** group
+to give them rights to access the **org.freedesktop.timedate1** *D-Bus interface*.
## Requirements:
diff --git a/src/rcl-timedate.c b/src/rcl-timedate.c
index 7bd2f62..d6387af 100644
--- a/src/rcl-timedate.c
+++ b/src/rcl-timedate.c
@@ -53,66 +53,156 @@ G_DEFINE_TYPE_WITH_PRIVATE (RclDaemon, rcl_daemon, RCL_TYPE_TIMEDATE_DAEMON_SKEL
/***************************************************************
- Polkit functions:
- ================
+ Polkit data and functions:
+ =========================
*/
+struct check_polkit_data
+{
+ const gchar *unique_name;
+ const gchar *action_id;
+ gboolean user_interaction;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+
+ PolkitAuthority *authority;
+ PolkitSubject *subject;
+};
+
+static void
+check_polkit_data_free( struct check_polkit_data *data )
+{
+ if( data == NULL )
+ return;
+
+ if( data->action_id != NULL )
+ g_free( (gpointer)data->action_id );
+
+ if( data->subject != NULL )
+ g_object_unref( data->subject );
+ if( data->authority != NULL )
+ g_object_unref( data->authority );
+
+ g_free( data );
+}
+
static gboolean
-_check_polkit_for_action( RclDaemon *object,
- GDBusMethodInvocation *invocation,
- const gchar *function )
+check_polkit_finish( GAsyncResult *result,
+ GError **error )
{
- const gchar *action = g_strjoin( "", RCL_INTERFACE_PREFIX, function, NULL );
- const gchar *sender;
- GError *error;
- PolkitSubject *subject;
- PolkitAuthorizationResult *result;
+ g_return_val_if_fail( g_task_is_valid( result, NULL ), FALSE );
+
+ return g_task_propagate_boolean( G_TASK( result ), error );
+}
- error = NULL;
+static void
+_check_polkit_for_action_async( GDBusMethodInvocation *invocation,
+ const gchar *function,
+ const gboolean interactive,
+ GAsyncReadyCallback callback,
+ gpointer user_data );
- /* Check that caller is privileged */
- sender = g_dbus_method_invocation_get_sender( invocation );
- subject = polkit_system_bus_name_new( sender );
- /********************************************************************************************
- flag = POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION causes a pop-up dialog box.
- We have not to use any pop-up windows.
- */
- result = polkit_authority_check_authorization_sync( object->priv->auth,
- subject,
- action,
- NULL,
- POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE,
- NULL,
- &error );
- g_object_unref( G_OBJECT(subject) );
-
- if( error )
- {
- g_dbus_method_invocation_return_gerror( invocation, error );
- g_error_free( error );
- g_free( (gpointer)action );
+static void
+_check_polkit_authorization_callback( GObject *source_object,
+ GAsyncResult *res,
+ gpointer _data)
+{
+ struct check_polkit_data *data;
+ PolkitAuthorizationResult *result;
+ GTask *task;
+ GError *error = NULL;
- return FALSE;
+ data = (struct check_polkit_data *)_data;
+ if( (result = polkit_authority_check_authorization_finish( data->authority, res, &error)) == NULL )
+ {
+ g_task_report_error( NULL, data->callback, data->user_data, NULL, error );
+ goto out;
}
-
+
if( !polkit_authorization_result_get_is_authorized( result ) )
{
- error = g_error_new( RCL_DAEMON_ERROR,
- RCL_DAEMON_ERROR_NOT_PRIVILEGED,
- "User is not privileged for action %s", action );
- g_dbus_method_invocation_return_gerror( invocation, error );
+ g_task_report_new_error( NULL,
+ data->callback,
+ data->user_data,
+ NULL,
+ POLKIT_ERROR,
+ POLKIT_ERROR_NOT_AUTHORIZED,
+ "Authorization for '%s': user is not authorized", data->action_id );
+ goto out;
+ }
+ task = g_task_new( NULL, NULL, data->callback, data->user_data );
+ g_task_set_source_tag( task, _check_polkit_for_action_async );
+ g_task_return_boolean( task, TRUE );
+ g_clear_object ( &task );
- g_error_free( error );
- g_object_unref( G_OBJECT(result) );
- g_free( (gpointer)action );
+out:
+ check_polkit_data_free( data );
+ if( result != NULL )
+ g_object_unref( result );
+}
- return FALSE;
+static void
+_check_polkit_authority_callback( GObject *source_object,
+ GAsyncResult *result,
+ gpointer _data )
+{
+ struct check_polkit_data *data;
+ GError *error = NULL;
+
+ data = (struct check_polkit_data *)_data;
+
+ if( (data->authority = polkit_authority_get_finish( result, &error )) == NULL)
+ {
+ g_task_report_error( NULL, data->callback, data->user_data, NULL, error );
+ check_polkit_data_free( data );
+ return;
+ }
+ if( data->unique_name == NULL ||
+ data->action_id == NULL ||
+ (data->subject = polkit_system_bus_name_new( data->unique_name )) == NULL )
+ {
+ g_task_report_new_error( NULL,
+ data->callback,
+ data->user_data,
+ NULL,
+ POLKIT_ERROR,
+ POLKIT_ERROR_FAILED,
+ "Authorization for '%s': failed", data->action_id );
+ check_polkit_data_free( data );
+ return;
}
- g_object_unref( G_OBJECT(result) );
- g_free( (gpointer)action );
+ polkit_authority_check_authorization( data->authority,
+ data->subject,
+ data->action_id,
+ NULL,
+ (PolkitCheckAuthorizationFlags)data->user_interaction,
+ NULL,
+ _check_polkit_authorization_callback,
+ data );
+}
- return TRUE;
+static void
+_check_polkit_for_action_async( GDBusMethodInvocation *invocation,
+ const gchar *function,
+ const gboolean interactive,
+ GAsyncReadyCallback callback,
+ gpointer user_data )
+{
+ const gchar *action = g_strjoin( "", RCL_INTERFACE_PREFIX, function, NULL );
+ struct check_polkit_data *data;
+ const gchar *sender;
+
+ sender = g_dbus_method_invocation_get_sender( invocation );
+
+ data = g_new0( struct check_polkit_data, 1 );
+ data->unique_name = sender;
+ data->action_id = action;
+ data->user_interaction = interactive;
+ data->callback = callback;
+ data->user_data = user_data;
+
+ polkit_authority_get_async( NULL, _check_polkit_authority_callback, data );
}
@@ -179,36 +269,53 @@ void rcl_daemon_sync_dbus_properties( RclTimedateDaemon *object )
DBus Handlers:
=============
*/
-gboolean handle_set_timezone( RclTimedateDaemon *object,
- GDBusMethodInvocation *invocation,
- const gchar *timezone,
- gboolean interactive,
- RclDaemon *daemon )
+
+/*******************************
+ SetTimezone:
+ -----------
+ */
+struct set_timezone_data
{
- gboolean ret = TRUE;
+ RclTimedateDaemon *object;
+ GDBusMethodInvocation *invocation;
+ const gchar *timezone;
+ gboolean interactive;
+ RclDaemon *daemon;
+};
- if( !timezone_is_valid( timezone ) )
- {
- g_dbus_method_invocation_return_error( invocation,
- RCL_DAEMON_ERROR,
- RCL_DAEMON_ERROR_INVALID_TIMEZONE_FILE,
- "Requested timezone '%s' is invalid", timezone );
- return TRUE;
- }
+static void
+set_timezone_data_free( struct set_timezone_data * data )
+{
+ if( data == NULL )
+ return;
- if( g_strcmp0( (const char *)daemon->priv->timezone, (const char *)timezone ) == 0 )
- goto out;
+ if( data->timezone != NULL )
+ g_free( (gpointer)data->timezone );
+
+ g_free( data );
+}
- if( !_check_polkit_for_action( daemon, invocation, "set-timezone" ) )
+
+static void
+set_timezone_authorized_callback( GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data )
+{
+ GError *error = NULL;
+ struct set_timezone_data *data = (struct set_timezone_data *)user_data;
+ gboolean ret = TRUE;
+
+ if( !check_polkit_finish( result, &error ) )
{
g_debug( "set-timezone: error: '%s'", "User is not privileged" );
- return TRUE;
+ set_timezone_data_free( data );
+ return;
}
- ret = set_system_timezone( timezone );
+ ret = set_system_timezone( data->timezone );
if( ret )
{
- if( daemon->priv->local_rtc )
+ if( data->daemon->priv->local_rtc )
{
struct timespec ts;
struct tm tm;
@@ -217,12 +324,14 @@ gboolean handle_set_timezone( RclTimedateDaemon *object,
if( clock_gettime(CLOCK_REALTIME, &ts) != 0 )
{
g_debug( "set-timezone: error: Sync RTC from system clock: '%s'", "clock_gettime(): failed" );
- return TRUE;
+ set_timezone_data_free( data );
+ return;
}
if( !localtime_r( &ts.tv_sec, &tm ) )
{
g_debug( "set-timezone: error: Sync RTC from system clock: '%s'", "localtime_r(): failed" );
- return TRUE;
+ set_timezone_data_free( data );
+ return;
}
if( !clock_set_hwclock( &tm ) )
{
@@ -232,56 +341,115 @@ gboolean handle_set_timezone( RclTimedateDaemon *object,
}
else
{
- g_debug( "set-timezone: error: Cannot set system timezone '%s'", timezone );
- return TRUE;
+ g_debug( "set-timezone: error: Cannot set system timezone '%s'", data->timezone );
+ set_timezone_data_free( data );
+ return;
}
- g_free( (gpointer)daemon->priv->timezone );
- daemon->priv->timezone = g_strdup( timezone );
- rcl_timedate_daemon_set_timezone( object, (const gchar *)daemon->priv->timezone );
+ g_free( (gpointer)data->daemon->priv->timezone );
+ data->daemon->priv->timezone = g_strdup( data->timezone );
+ rcl_timedate_daemon_set_timezone( data->object, (const gchar *)data->daemon->priv->timezone );
+
-out:
g_debug( "set-timezone: SetTimezone to '%s' returns successful status (interactive=%s)",
- daemon->priv->timezone, (interactive) ? "true" : "false" );
+ data->daemon->priv->timezone, (data->interactive) ? "true" : "false" );
+
+ rcl_timedate_daemon_complete_set_timezone( data->object, data->invocation );
+
+ set_timezone_data_free( data );
+}
+
+gboolean handle_set_timezone( RclTimedateDaemon *object,
+ GDBusMethodInvocation *invocation,
+ const gchar *timezone,
+ gboolean interactive,
+ RclDaemon *daemon )
+{
+ struct set_timezone_data *data;
- rcl_timedate_daemon_complete_set_timezone( object, invocation );
+ if( !timezone_is_valid( timezone ) )
+ {
+ g_dbus_method_invocation_return_error( invocation,
+ RCL_DAEMON_ERROR,
+ RCL_DAEMON_ERROR_INVALID_TIMEZONE_FILE,
+ "Requested timezone '%s' is invalid", timezone );
+ return TRUE;
+ }
+
+ if( g_strcmp0( (const char *)daemon->priv->timezone, (const char *)timezone ) == 0 )
+ goto out;
+ data = g_new0( struct set_timezone_data, 1 );
+ data->object = object;
+ data->invocation = invocation;
+ data->timezone = (const gchar *)g_strdup( timezone );
+ data->interactive = interactive;
+ data->daemon = daemon;
+
+ _check_polkit_for_action_async( invocation,
+ "set-timezone",
+ interactive,
+ set_timezone_authorized_callback,
+ data );
+out:
return TRUE;
}
-gboolean handle_set_local_rtc( RclTimedateDaemon *object,
- GDBusMethodInvocation *invocation,
- gboolean local_rtc,
- gboolean fix_system,
- gboolean interactive,
- RclDaemon *daemon )
+/*******************************
+ SetLocalRTC:
+ -----------
+ */
+struct set_local_rtc_data
{
- struct timespec ts;
- gboolean ret = TRUE;
+ RclTimedateDaemon *object;
+ GDBusMethodInvocation *invocation;
+ gboolean local_rtc;
+ gboolean fix_system;
+ gboolean interactive;
+ RclDaemon *daemon;
+};
- if( daemon->priv->local_rtc == local_rtc && !fix_system )
- goto out;
+static void
+set_local_rtc_data_free( struct set_local_rtc_data * data )
+{
+ if( data == NULL )
+ return;
+
+ g_free( data );
+}
- if( !_check_polkit_for_action( daemon, invocation, "set-local-rtc" ) )
+static void
+set_local_rtc_authorized_callback( GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data )
+{
+ GError *error = NULL;
+ struct set_local_rtc_data *data = (struct set_local_rtc_data *)user_data;
+ gboolean ret = TRUE;
+ struct timespec ts;
+
+ if( !check_polkit_finish( result, &error ) )
{
g_debug( "set-local-rtc: error: '%s'", "User is not privileged" );
- return TRUE;
+ set_local_rtc_data_free( data );
+ return;
}
- if( daemon->priv->local_rtc != local_rtc )
+ if( data->daemon->priv->local_rtc != data->local_rtc )
{
- daemon->priv->local_rtc = local_rtc;
+ data->daemon->priv->local_rtc = data->local_rtc;
/* Write new configuration files */
- ret = write_data_local_rtc( daemon->priv->local_rtc );
+ ret = write_data_local_rtc( data->daemon->priv->local_rtc );
if( !ret )
{
- g_dbus_method_invocation_return_error( invocation,
+ g_dbus_method_invocation_return_error( data->invocation,
RCL_DAEMON_ERROR,
RCL_DAEMON_ERROR_GENERAL,
"Cannot set LocalRTC" );
- return TRUE;
+ set_local_rtc_data_free( data );
+ return;
}
}
@@ -291,22 +459,24 @@ gboolean handle_set_local_rtc( RclTimedateDaemon *object,
if( !ret )
{
g_debug( "set-local-rtc: error: Cannot set timezone clock after SetLocal_RTC" );
- return TRUE;
+ set_local_rtc_data_free( data );
+ return;
}
/* Synchronize clocks */
if( clock_gettime(CLOCK_REALTIME, &ts) != 0 )
{
g_debug( "set-local-rtc: error: Sync RTC from system clock after SetLocalRTC: '%s'", "clock_gettime(): failed" );
- return TRUE;
+ set_local_rtc_data_free( data );
+ return;
}
- if( fix_system )
+ if( data->fix_system )
{
struct tm tm;
/* Sync system clock from RTC; first, initialize the timezone fields of struct tm. */
- localtime_or_gmtime_r( &ts.tv_sec, &tm, !daemon->priv->local_rtc);
+ localtime_or_gmtime_r( &ts.tv_sec, &tm, !data->daemon->priv->local_rtc);
/* Override the main fields of struct tm, but not the timezone fields */
ret = clock_get_hwclock( &tm );
@@ -317,7 +487,7 @@ gboolean handle_set_local_rtc( RclTimedateDaemon *object,
else
{
/* And set the system clock with this */
- ts.tv_sec = mktime_or_timegm( &tm, !daemon->priv->local_rtc );
+ ts.tv_sec = mktime_or_timegm( &tm, !data->daemon->priv->local_rtc );
if( clock_settime( CLOCK_REALTIME, &ts ) < 0 )
{
@@ -330,7 +500,7 @@ gboolean handle_set_local_rtc( RclTimedateDaemon *object,
struct tm tm;
/* Sync RTC from system clock */
- localtime_or_gmtime_r( &ts.tv_sec, &tm, !daemon->priv->local_rtc );
+ localtime_or_gmtime_r( &ts.tv_sec, &tm, !data->daemon->priv->local_rtc );
ret = clock_set_hwclock( &tm );
if( !ret )
@@ -339,60 +509,99 @@ gboolean handle_set_local_rtc( RclTimedateDaemon *object,
}
}
- g_debug( "set-local-rtc: RTC configured to %s time", (daemon->priv->local_rtc) ? "localtime" : "UTC" );
+ g_debug( "set-local-rtc: RTC configured to %s time", (data->daemon->priv->local_rtc) ? "localtime" : "UTC" );
- rcl_timedate_daemon_set_local_rtc( object, daemon->priv->local_rtc );
+ rcl_timedate_daemon_set_local_rtc( data->object, data->daemon->priv->local_rtc );
-out:
g_debug( "set-local-rtc: SetLocalRTC to '%s' returns successful status (fix_sysrem=%s; interactive=%s)",
- (daemon->priv->local_rtc) ? "localtime" : "UTC",
- (fix_system) ? "true" : "false",
- (interactive) ? "true" : "false" );
+ (data->daemon->priv->local_rtc) ? "localtime" : "UTC",
+ (data->fix_system) ? "true" : "false",
+ (data->interactive) ? "true" : "false" );
+
+ rcl_timedate_daemon_complete_set_local_rtc( data->object, data->invocation );
+
+ set_local_rtc_data_free( data );
+}
+
+gboolean handle_set_local_rtc( RclTimedateDaemon *object,
+ GDBusMethodInvocation *invocation,
+ gboolean local_rtc,
+ gboolean fix_system,
+ gboolean interactive,
+ RclDaemon *daemon )
+{
+ struct set_local_rtc_data *data;
- rcl_timedate_daemon_complete_set_local_rtc( object, invocation );
+ if( daemon->priv->local_rtc == local_rtc && !fix_system )
+ goto out;
+ data = g_new0( struct set_local_rtc_data, 1 );
+ data->object = object;
+ data->invocation = invocation;
+ data->local_rtc = local_rtc;
+ data->fix_system = fix_system;
+ data->interactive = interactive;
+ data->daemon = daemon;
+
+ _check_polkit_for_action_async( invocation,
+ "set-local-rtc",
+ interactive,
+ set_local_rtc_authorized_callback,
+ data );
+out:
return TRUE;
}
-gboolean handle_set_ntp( RclTimedateDaemon *object,
- GDBusMethodInvocation *invocation,
- gboolean use_ntp,
- gboolean interactive,
- RclDaemon *daemon )
+/*******************************
+ SetNTP:
+ ------
+ */
+struct set_ntp_data
{
- /* check CanNTP (in case NTPD was uninstalled while timedated running) */
- if( !ntp_daemon_installed() )
- {
- daemon->priv->can_ntp = FALSE;
- rcl_timedate_daemon_set_can_ntp( object, daemon->priv->can_ntp );
- }
+ RclTimedateDaemon *object;
+ GDBusMethodInvocation *invocation;
+ gboolean use_ntp;
+ gboolean interactive;
+ RclDaemon *daemon;
+};
- if( !daemon->priv->can_ntp )
- {
- daemon->priv->use_ntp = FALSE;
- rcl_timedate_daemon_set_ntp( object, daemon->priv->use_ntp );
- return TRUE;
- }
+static void
+set_ntp_data_free( struct set_ntp_data * data )
+{
+ if( data == NULL )
+ return;
- if( !_check_polkit_for_action( daemon, invocation, "set-ntp" ) )
+ g_free( data );
+}
+
+static void
+set_ntp_authorized_callback( GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data )
+{
+ GError *error = NULL;
+ struct set_ntp_data *data = (struct set_ntp_data *)user_data;
+
+ if( !check_polkit_finish( result, &error ) )
{
g_debug( "set-ntp: error: '%s'", "User is not privileged" );
- return TRUE;
+ set_ntp_data_free( data );
+ return;
}
- if( daemon->priv->use_ntp == use_ntp )
+ if( data->daemon->priv->use_ntp == data->use_ntp )
goto out;
- if( use_ntp ) /* enable and start NTP daemon: */
+ if( data->use_ntp ) /* enable and start NTP daemon: */
{
if( ntp_daemon_enabled() )
{
if( ntp_daemon_status() )
{
g_debug( "set-ntp: The NTP Daemon already running" );
- daemon->priv->use_ntp = TRUE;
+ data->daemon->priv->use_ntp = TRUE;
/* SUCCESS */
}
else
@@ -400,18 +609,19 @@ gboolean handle_set_ntp( RclTimedateDaemon *object,
if( !start_ntp_daemon() )
{
g_debug( "set-ntp: error: Cannot start NTPD daemon" );
- g_dbus_method_invocation_return_error( invocation,
+ g_dbus_method_invocation_return_error( data->invocation,
RCL_DAEMON_ERROR,
RCL_DAEMON_ERROR_GENERAL,
"Cannot start NTP Daemon" );
- daemon->priv->use_ntp = FALSE;
+ data->daemon->priv->use_ntp = FALSE;
/* FAILURE */
- return TRUE;
+ set_ntp_data_free( data );
+ return;
}
else
{
g_debug( "set-ntp: The NTPD daemon started successful" );
- daemon->priv->use_ntp = TRUE;
+ data->daemon->priv->use_ntp = TRUE;
/* SUCCESS */
}
}
@@ -421,31 +631,33 @@ gboolean handle_set_ntp( RclTimedateDaemon *object,
if( !enable_ntp_daemon() )
{
g_debug( "set-ntp: error: Cannot enable NTPD daemon" );
- g_dbus_method_invocation_return_error( invocation,
+ g_dbus_method_invocation_return_error( data->invocation,
RCL_DAEMON_ERROR,
RCL_DAEMON_ERROR_GENERAL,
"Cannot enable NTP Daemon" );
- daemon->priv->use_ntp = FALSE;
+ data->daemon->priv->use_ntp = FALSE;
/* FAILURE */
- return TRUE;
+ set_ntp_data_free( data );
+ return;
}
else
{
if( !start_ntp_daemon() )
{
g_debug( "set-ntp: error: Cannot start NTPD daemon" );
- g_dbus_method_invocation_return_error( invocation,
+ g_dbus_method_invocation_return_error( data->invocation,
RCL_DAEMON_ERROR,
RCL_DAEMON_ERROR_GENERAL,
"Cannot start NTP Daemon" );
- daemon->priv->use_ntp = FALSE;
+ data->daemon->priv->use_ntp = FALSE;
/* FAILURE */
- return TRUE;
+ set_ntp_data_free( data );
+ return;
}
else
{
g_debug( "set-ntp: The NTPD daemon started successful" );
- daemon->priv->use_ntp = TRUE;
+ data->daemon->priv->use_ntp = TRUE;
/* SUCCESS */
}
}
@@ -461,13 +673,14 @@ gboolean handle_set_ntp( RclTimedateDaemon *object,
if( !stop_ntp_daemon() )
{
g_debug( "set-ntp: error: Cannot stop NTPD daemon" );
- g_dbus_method_invocation_return_error( invocation,
+ g_dbus_method_invocation_return_error( data->invocation,
RCL_DAEMON_ERROR,
RCL_DAEMON_ERROR_GENERAL,
"Cannot stop NTP Daemon" );
- daemon->priv->use_ntp = TRUE;
+ data->daemon->priv->use_ntp = TRUE;
/* FAILURE */
- return TRUE;
+ set_ntp_data_free( data );
+ return;
}
else
{
@@ -475,18 +688,18 @@ gboolean handle_set_ntp( RclTimedateDaemon *object,
if( !disable_ntp_daemon() )
{
g_debug( "set-ntp: Cannot disable NTPD daemon" );
- g_dbus_method_invocation_return_error( invocation,
+ g_dbus_method_invocation_return_error( data->invocation,
RCL_DAEMON_ERROR,
RCL_DAEMON_ERROR_GENERAL,
"Cannot disable NTP Daemon" );
- daemon->priv->use_ntp = FALSE;
+ data->daemon->priv->use_ntp = FALSE;
/* daemon stopped but not disabled (will start after reboot) */
/* SUCCESS */
}
else
{
g_debug( "set-ntp: The NTPD daemon disabled successful" );
- daemon->priv->use_ntp = FALSE;
+ data->daemon->priv->use_ntp = FALSE;
/* SUCCESS */
}
}
@@ -497,18 +710,18 @@ gboolean handle_set_ntp( RclTimedateDaemon *object,
if( !disable_ntp_daemon() )
{
g_debug( "set-ntp: error: Cannot disable NTPD daemon" );
- g_dbus_method_invocation_return_error( invocation,
+ g_dbus_method_invocation_return_error( data->invocation,
RCL_DAEMON_ERROR,
RCL_DAEMON_ERROR_GENERAL,
"Cannot disable NTP Daemon" );
- daemon->priv->use_ntp = FALSE;
+ data->daemon->priv->use_ntp = FALSE;
/* daemon stopped but not disabled (will start after reboot) */
/* SUCCESS */
}
else
{
g_debug( "set-ntp: The NTPD daemon disabled successful" );
- daemon->priv->use_ntp = FALSE;
+ data->daemon->priv->use_ntp = FALSE;
/* SUCCESS */
}
}
@@ -516,112 +729,146 @@ gboolean handle_set_ntp( RclTimedateDaemon *object,
else
{
g_debug( "set-ntp: The NTPD daemon already disabled" );
- daemon->priv->use_ntp = FALSE;
+ data->daemon->priv->use_ntp = FALSE;
/* SUCCESS */
}
}
- g_debug( "set-ntp: NTP configured to %s", (daemon->priv->use_ntp) ? "enabled" : "disabled" );
+ g_debug( "set-ntp: NTP configured to %s", (data->daemon->priv->use_ntp) ? "enabled" : "disabled" );
- rcl_timedate_daemon_set_ntp( object, daemon->priv->use_ntp );
+ rcl_timedate_daemon_set_ntp( data->object, data->daemon->priv->use_ntp );
/* rcl_timedate_daemon_set_ntpsynchronized( object, daemon->priv->use_ntp ); */
out:
g_debug( "set-ntp: SetNTP to '%s' returns successful status (interactive=%s)",
- (daemon->priv->use_ntp) ? "true" : "false",
- (interactive) ? "true" : "false" );
+ (data->daemon->priv->use_ntp) ? "true" : "false",
+ (data->interactive) ? "true" : "false" );
- rcl_timedate_daemon_complete_set_ntp( object, invocation );
+ rcl_timedate_daemon_complete_set_ntp( data->object, data->invocation );
- return TRUE;
+ set_ntp_data_free( data );
}
-
-gboolean handle_set_time( RclTimedateDaemon *object,
- GDBusMethodInvocation *invocation,
- gint64 usec_utc,
- gboolean relative,
- gboolean interactive,
- RclDaemon *daemon )
+gboolean handle_set_ntp( RclTimedateDaemon *object,
+ GDBusMethodInvocation *invocation,
+ gboolean use_ntp,
+ gboolean interactive,
+ RclDaemon *daemon )
{
- struct timespec ts;
- struct tm tm;
- guint64 start;
+ struct set_ntp_data *data;
- if( ntp_daemon_installed() && ntp_daemon_enabled() && ntp_daemon_status() )
+ /* check CanNTP (in case NTPD was uninstalled while timedated running) */
+ if( !ntp_daemon_installed() )
{
- /* NTP Daemon is running */
- g_debug( "set-time: error: Automatic time synchronization is enabled" );
- g_dbus_method_invocation_return_error( invocation,
- RCL_DAEMON_ERROR,
- RCL_DAEMON_ERROR_GENERAL,
- "set-time: Automatic time synchronization is enabled" );
- return TRUE;
+ daemon->priv->can_ntp = FALSE;
+ rcl_timedate_daemon_set_can_ntp( object, daemon->priv->can_ntp );
}
- start = now( CLOCK_MONOTONIC );
-
- if( !relative && usec_utc <= 0 )
+ if( !daemon->priv->can_ntp )
{
- g_debug( "set-time: error: Invalid absolute time" );
- g_dbus_method_invocation_return_error( invocation,
- RCL_DAEMON_ERROR,
- RCL_DAEMON_ERROR_INVALID_ARGS,
- "set-time: Invalid absolute time" );
+ daemon->priv->use_ntp = FALSE;
+ rcl_timedate_daemon_set_ntp( object, daemon->priv->use_ntp );
return TRUE;
}
- if( relative && usec_utc == 0 )
+ data = g_new0( struct set_ntp_data, 1 );
+ data->object = object;
+ data->invocation = invocation;
+ data->use_ntp = use_ntp;
+ data->interactive = interactive;
+ data->daemon = daemon;
+
+ _check_polkit_for_action_async( invocation,
+ "set-ntp",
+ interactive,
+ set_ntp_authorized_callback,
+ data );
+ return TRUE;
+}
+
+
+/*******************************
+ SetTime:
+ -------
+ */
+struct set_time_data
+{
+ RclTimedateDaemon *object;
+ GDBusMethodInvocation *invocation;
+ guint64 start;
+ guint64 usec_utc;
+ gboolean relative;
+ gboolean interactive;
+ RclDaemon *daemon;
+};
+
+static void
+set_time_data_free( struct set_time_data * data )
+{
+ if( data == NULL )
+ return;
+
+ g_free( data );
+}
+
+static void
+set_time_authorized_callback( GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data )
+{
+ GError *error = NULL;
+ struct set_time_data *data = (struct set_time_data *)user_data;
+ struct timespec ts;
+ struct tm tm;
+
+ if( !check_polkit_finish( result, &error ) )
{
- /* Nothing to do */
- goto out;
+ g_debug( "set-local-rtc: error: '%s'", "User is not privileged" );
+ set_time_data_free( data );
+ return;
}
- if( relative )
+ if( data->relative )
{
guint64 n, x;
n = now( CLOCK_REALTIME );
- x = n + usec_utc;
+ x = n + data->usec_utc;
- if( (usec_utc > 0 && x < n) ||
- (usec_utc < 0 && x > n) )
+ if( (data->usec_utc > 0 && x < n) ||
+ (data->usec_utc < 0 && x > n) )
{
g_debug( "set-time: error: Time value overflow" );
- g_dbus_method_invocation_return_error( invocation,
+ g_dbus_method_invocation_return_error( data->invocation,
RCL_DAEMON_ERROR,
RCL_DAEMON_ERROR_INVALID_ARGS,
"set-time: Time value overflow" );
- return TRUE;
+ set_time_data_free( data );
+ return;
}
timespec_store( &ts, x );
}
else
{
- timespec_store( &ts, (guint64)usec_utc);
- }
-
- if( !_check_polkit_for_action( daemon, invocation, "set-time" ) )
- {
- g_debug( "set-time: error: '%s'", "User is not privileged" );
- return TRUE;
+ timespec_store( &ts, (guint64)data->usec_utc);
}
- timespec_store( &ts, timespec_load( &ts ) + (now( CLOCK_MONOTONIC ) - start) );
+ timespec_store( &ts, timespec_load( &ts ) + (now( CLOCK_MONOTONIC ) - data->start) );
/* Set system clock */
if( clock_settime( CLOCK_REALTIME, &ts ) < 0 )
{
g_debug( "set-time: error: Failed to set local time" );
- g_dbus_method_invocation_return_error( invocation,
+ g_dbus_method_invocation_return_error( data->invocation,
RCL_DAEMON_ERROR,
RCL_DAEMON_ERROR_GENERAL,
"set-time: Failed to set local time" );
- return TRUE;
+ set_time_data_free( data );
+ return;
}
/* Sync down to RTC */
- localtime_or_gmtime_r( &ts.tv_sec, &tm, !daemon->priv->local_rtc );
+ localtime_or_gmtime_r( &ts.tv_sec, &tm, !data->daemon->priv->local_rtc );
if( !clock_set_hwclock( &tm ) )
{
@@ -631,22 +878,83 @@ gboolean handle_set_time( RclTimedateDaemon *object,
g_debug( "set-time: SetTime method returns successful status" );
/* Update RTCTimeUSec (by the way) */
- (void)get_rtctime_usec( object );
+ (void)get_rtctime_usec( data->object );
- rcl_timedate_daemon_set_time_usec( object, timespec_load( &ts ) );
+ rcl_timedate_daemon_set_time_usec( data->object, timespec_load( &ts ) );
-out:
g_debug( "set-time: SetTime to %" PRIu64 " returns successful status(relative=%s; interactive=%s)",
- usec_utc,
- (relative) ? "true" : "false",
- (interactive) ? "true" : "false" );
+ data->usec_utc,
+ (data->relative) ? "true" : "false",
+ (data->interactive) ? "true" : "false" );
- rcl_timedate_daemon_complete_set_time( object, invocation );
+ rcl_timedate_daemon_complete_set_time( data->object, data->invocation );
+
+ set_time_data_free( data );
+}
+
+gboolean handle_set_time( RclTimedateDaemon *object,
+ GDBusMethodInvocation *invocation,
+ gint64 usec_utc,
+ gboolean relative,
+ gboolean interactive,
+ RclDaemon *daemon )
+{
+ struct set_time_data *data;
+ guint64 start;
+ if( ntp_daemon_installed() && ntp_daemon_enabled() && ntp_daemon_status() )
+ {
+ /* NTP Daemon is running */
+ g_debug( "set-time: error: Automatic time synchronization is enabled" );
+ g_dbus_method_invocation_return_error( invocation,
+ RCL_DAEMON_ERROR,
+ RCL_DAEMON_ERROR_GENERAL,
+ "set-time: Automatic time synchronization is enabled" );
+ return TRUE;
+ }
+
+ start = now( CLOCK_MONOTONIC );
+
+ if( !relative && usec_utc <= 0 )
+ {
+ g_debug( "set-time: error: Invalid absolute time" );
+ g_dbus_method_invocation_return_error( invocation,
+ RCL_DAEMON_ERROR,
+ RCL_DAEMON_ERROR_INVALID_ARGS,
+ "set-time: Invalid absolute time" );
+ return TRUE;
+ }
+
+ if( relative && usec_utc == 0 )
+ {
+ /* Nothing to do */
+ goto out;
+ }
+
+ data = g_new0( struct set_time_data, 1 );
+ data->object = object;
+ data->invocation = invocation;
+ data->start = start;
+ data->usec_utc = usec_utc;
+ data->relative = relative;
+ data->interactive = interactive;
+ data->daemon = daemon;
+
+ _check_polkit_for_action_async( invocation,
+ "set-time",
+ interactive,
+ set_time_authorized_callback,
+ data );
+
+out:
return TRUE;
}
+/*******************************
+ ListTimezones:
+ -------------
+ */
gboolean handle_list_timezones( RclTimedateDaemon *object,
GDBusMethodInvocation *invocation,
RclDaemon *daemon )
@@ -675,7 +983,6 @@ gboolean handle_list_timezones( RclTimedateDaemon *object,
}
-
/***************************************************************
Daemon functions:
================