2014-08-14 13:34:57 +02:00
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*
* Copyright ( C ) 2014 Red Hat , Inc .
*/
2016-02-19 14:57:48 +01:00
# include "nm-default.h"
2014-11-13 10:07:02 -05:00
2014-08-14 13:34:57 +02:00
# include "nm-auth-manager.h"
2018-04-06 16:40:23 +02:00
# include "c-list/src/c-list.h"
core: drop all remaining core-internal error domains
A number of classes in core had their own error domains that aren't
really necessary.
In the case of NMDcbError, NMDhcpManagerError, NMDnsManagerError,
NMDnsmasqManagerError, NMPppManagerError, and NMSessionMonitorError,
most of the codes they defined weren't even being used, and at any
rate, the errors were always returned into contexts where they would
just have their message extracted and then get thrown away without
anyone ever looking at the domain or code. So all uses of those
domains can just be replaced with NM_MANAGER_ERROR_FAILED without any
loss of information.
NMAuthManagerError only had 1 error code, and it just indicated
"something went wrong", so it can be replaced with
NM_MANAGER_ERROR_FAILED without loss of information.
(nm-auth-manager.c has also been fixed to return
NM_MANAGER_ERROR_FAILED when the CheckAuthorization D-Bus call fails,
rather than returning whatever error domain/code the D-Bus call
returned.)
NMVpnManagerError used 2 of its 4 error codes, and they could actually
end up getting returned across D-Bus in some cases. But there are
NMManagerError codes that are semantically similar enough to make the
NMVpnManagerError ones unnecessary.
2014-10-16 16:51:22 -04:00
# include "nm-errors.h"
2015-03-27 08:03:22 -04:00
# include "nm-core-internal.h"
2015-07-24 15:45:46 +02:00
# include "NetworkManagerUtils.h"
2014-08-14 13:34:57 +02:00
# define POLKIT_SERVICE "org.freedesktop.PolicyKit1"
# define POLKIT_OBJECT_PATH " / org / freedesktop / PolicyKit1 / Authority"
# define POLKIT_INTERFACE "org.freedesktop.PolicyKit1.Authority"
2018-04-09 13:27:03 +02:00
# define CANCELLATION_ID_PREFIX "cancellation-id-"
# define CANCELLATION_TIMEOUT_MS 5000
2016-09-29 13:49:01 +02:00
/*****************************************************************************/
2014-08-14 13:34:57 +02:00
2016-09-29 13:49:01 +02:00
NM_GOBJECT_PROPERTIES_DEFINE_BASE (
2014-08-14 13:34:57 +02:00
PROP_POLKIT_ENABLED ,
2016-09-29 13:49:01 +02:00
) ;
2014-08-14 13:34:57 +02:00
enum {
CHANGED_SIGNAL ,
LAST_SIGNAL ,
} ;
static guint signals [ LAST_SIGNAL ] = { 0 } ;
typedef struct {
2018-04-09 13:27:03 +02:00
CList calls_lst_head ;
2014-08-14 13:34:57 +02:00
GDBusProxy * proxy ;
2018-04-09 13:27:03 +02:00
GCancellable * new_proxy_cancellable ;
GCancellable * cancel_cancellable ;
guint64 call_numid_counter ;
2018-04-09 12:58:59 +02:00
bool polkit_enabled : 1 ;
2018-04-09 13:27:03 +02:00
bool disposing : 1 ;
bool shutting_down : 1 ;
2014-08-14 13:34:57 +02:00
} NMAuthManagerPrivate ;
2016-09-29 13:49:01 +02:00
struct _NMAuthManager {
GObject parent ;
NMAuthManagerPrivate _priv ;
} ;
struct _NMAuthManagerClass {
GObjectClass parent ;
} ;
2014-08-14 13:34:57 +02:00
G_DEFINE_TYPE ( NMAuthManager , nm_auth_manager , G_TYPE_OBJECT )
2016-09-29 13:49:01 +02:00
# define NM_AUTH_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMAuthManager, NM_IS_AUTH_MANAGER)
NM_DEFINE_SINGLETON_REGISTER ( NMAuthManager ) ;
/*****************************************************************************/
# define _NMLOG_PREFIX_NAME "auth"
# define _NMLOG_DOMAIN LOGD_CORE
# define _NMLOG(level, ...) \
G_STMT_START { \
if ( nm_logging_enabled ( ( level ) , ( _NMLOG_DOMAIN ) ) ) { \
char __prefix [ 30 ] = _NMLOG_PREFIX_NAME ; \
\
if ( ( self ) ! = singleton_instance ) \
g_snprintf ( __prefix , sizeof ( __prefix ) , " " _NMLOG_PREFIX_NAME " [%p] " , ( self ) ) ; \
2017-03-01 10:20:01 +00:00
_nm_log ( ( level ) , ( _NMLOG_DOMAIN ) , 0 , NULL , NULL , \
2016-09-29 13:49:01 +02:00
" %s: " _NM_UTILS_MACRO_FIRST ( __VA_ARGS__ ) , \
__prefix _NM_UTILS_MACRO_REST ( __VA_ARGS__ ) ) ; \
} \
} G_STMT_END
2014-08-14 13:34:57 +02:00
2018-04-09 13:27:03 +02:00
# define _NMLOG2(level, call_id, ...) \
G_STMT_START { \
if ( nm_logging_enabled ( ( level ) , ( _NMLOG_DOMAIN ) ) ) { \
NMAuthManagerCallId * _call_id = ( call_id ) ; \
char __prefix [ 30 ] = _NMLOG_PREFIX_NAME ; \
\
if ( _call_id - > self ! = singleton_instance ) \
g_snprintf ( __prefix , sizeof ( __prefix ) , " " _NMLOG_PREFIX_NAME " [%p] " , _call_id - > self ) ; \
_nm_log ( ( level ) , ( _NMLOG_DOMAIN ) , 0 , NULL , NULL , \
" %s: call[% " G_GUINT64_FORMAT " ]: " _NM_UTILS_MACRO_FIRST ( __VA_ARGS__ ) , \
__prefix , \
_call_id - > call_numid \
_NM_UTILS_MACRO_REST ( __VA_ARGS__ ) ) ; \
} \
} G_STMT_END
2014-08-14 13:34:57 +02:00
/*****************************************************************************/
gboolean
nm_auth_manager_get_polkit_enabled ( NMAuthManager * self )
{
g_return_val_if_fail ( NM_IS_AUTH_MANAGER ( self ) , FALSE ) ;
return NM_AUTH_MANAGER_GET_PRIVATE ( self ) - > polkit_enabled ;
}
/*****************************************************************************/
typedef enum {
POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE = 0 ,
POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION = ( 1 < < 0 ) ,
} PolkitCheckAuthorizationFlags ;
2018-04-09 16:04:46 +02:00
typedef enum {
IDLE_REASON_AUTHORIZED ,
IDLE_REASON_NO_DBUS ,
} IdleReason ;
2018-04-09 13:27:03 +02:00
struct _NMAuthManagerCallId {
CList calls_lst ;
2014-08-14 13:34:57 +02:00
NMAuthManager * self ;
GVariant * dbus_parameters ;
2018-04-09 13:27:03 +02:00
GCancellable * dbus_cancellable ;
NMAuthManagerCheckAuthorizationCallback callback ;
gpointer user_data ;
guint64 call_numid ;
guint idle_id ;
2018-04-09 16:04:46 +02:00
IdleReason idle_reason : 8 ;
2018-04-09 13:27:03 +02:00
} ;
# define cancellation_id_to_str_a(call_numid) \
nm_sprintf_bufa ( NM_STRLEN ( CANCELLATION_ID_PREFIX ) + 20 , \
CANCELLATION_ID_PREFIX " % " G_GUINT64_FORMAT , \
( call_numid ) )
2014-08-14 13:34:57 +02:00
static void
2018-04-09 13:27:03 +02:00
_call_id_free ( NMAuthManagerCallId * call_id )
2014-08-14 13:34:57 +02:00
{
2018-04-09 13:27:03 +02:00
c_list_unlink ( & call_id - > calls_lst ) ;
nm_clear_g_source ( & call_id - > idle_id ) ;
if ( call_id - > dbus_parameters )
g_variant_unref ( g_steal_pointer ( & call_id - > dbus_parameters ) ) ;
if ( call_id - > dbus_cancellable ) {
/* we have a pending D-Bus call. We keep the call-id instance alive
* for _call_check_authorize_cb ( ) */
g_cancellable_cancel ( call_id - > dbus_cancellable ) ;
return ;
}
g_object_unref ( call_id - > self ) ;
g_slice_free ( NMAuthManagerCallId , call_id ) ;
2014-08-14 13:34:57 +02:00
}
static void
2018-04-09 13:27:03 +02:00
_call_id_invoke_callback ( NMAuthManagerCallId * call_id ,
gboolean is_authorized ,
gboolean is_challenge ,
GError * error )
2014-08-14 13:34:57 +02:00
{
2018-04-09 13:27:03 +02:00
c_list_unlink ( & call_id - > calls_lst ) ;
call_id - > callback ( call_id - > self ,
call_id ,
is_authorized ,
is_challenge ,
error ,
call_id - > user_data ) ;
_call_id_free ( call_id ) ;
2014-08-14 13:34:57 +02:00
}
static void
2018-04-09 13:27:03 +02:00
cancel_check_authorization_cb ( GObject * proxy ,
2014-08-14 13:34:57 +02:00
GAsyncResult * res ,
gpointer user_data )
{
2018-04-09 13:27:03 +02:00
NMAuthManagerCallId * call_id = user_data ;
gs_unref_variant GVariant * value = NULL ;
gs_free_error GError * error = NULL ;
value = g_dbus_proxy_call_finish ( G_DBUS_PROXY ( proxy ) , res , & error ) ;
if ( g_error_matches ( error , G_IO_ERROR , G_IO_ERROR_CANCELLED ) )
_LOG2T ( call_id , " cancel request was cancelled " ) ;
else if ( error )
_LOG2T ( call_id , " cancel request failed: %s " , error - > message ) ;
else
_LOG2T ( call_id , " cancel request succeeded " ) ;
2014-08-14 13:34:57 +02:00
2018-04-09 13:27:03 +02:00
_call_id_free ( call_id ) ;
2014-08-14 13:34:57 +02:00
}
static void
2018-04-09 13:27:03 +02:00
_call_check_authorize_cb ( GObject * proxy ,
GAsyncResult * res ,
gpointer user_data )
2014-08-14 13:34:57 +02:00
{
2018-04-09 13:27:03 +02:00
NMAuthManagerCallId * call_id = user_data ;
NMAuthManager * self ;
NMAuthManagerPrivate * priv ;
gs_unref_variant GVariant * value = NULL ;
gs_free_error GError * error = NULL ;
gboolean is_authorized = FALSE ;
gboolean is_challenge = FALSE ;
2014-08-14 13:34:57 +02:00
2018-04-09 13:27:03 +02:00
/* we need to clear the cancelable, to signal for _call_id_free() that we
* are not in a pending call .
*
* Note how _call_id_free ( ) kept call - id alive , even if the request was
* already cancelled . */
g_clear_object ( & call_id - > dbus_cancellable ) ;
2014-08-14 13:34:57 +02:00
2018-04-09 13:27:03 +02:00
self = call_id - > self ;
priv = NM_AUTH_MANAGER_GET_PRIVATE ( self ) ;
value = _nm_dbus_proxy_call_finish ( G_DBUS_PROXY ( proxy ) , res , G_VARIANT_TYPE ( " ((bba{ss})) " ) , & error ) ;
if ( g_error_matches ( error , G_IO_ERROR , G_IO_ERROR_CANCELLED ) ) {
/* call_id was cancelled externally, but _call_id_free() kept call_id
* alive ( and it has still the reference on @ self . */
if ( ! priv - > cancel_cancellable ) {
/* we do a forced shutdown. There is no more time for cancelling... */
_call_id_free ( call_id ) ;
/* this shouldn't really happen, because:
* _call_check_authorize ( ) only scheduled the D - Bus request at a time when
* cancel_cancellable was still set . It means , somebody called force - shutdown
* after call - id was schedule .
* force - shutdown should only be called after :
* - cancel all pending requests
* - give enough time to cancel the request and schedule a D - Bus call
* to CancelCheckAuthorization ( below ) , before issuing force - shutdown . */
g_return_if_reached ( ) ;
}
2014-08-14 13:34:57 +02:00
2018-04-09 13:27:03 +02:00
g_dbus_proxy_call ( priv - > proxy ,
" CancelCheckAuthorization " ,
g_variant_new ( " (s) " ,
cancellation_id_to_str_a ( call_id - > call_numid ) ) ,
G_DBUS_CALL_FLAGS_NONE ,
CANCELLATION_TIMEOUT_MS ,
priv - > cancel_cancellable ,
cancel_check_authorization_cb ,
call_id ) ;
return ;
2014-08-14 13:34:57 +02:00
}
2018-04-09 13:27:03 +02:00
if ( ! error ) {
g_variant_get ( value ,
" ((bb@a{ss})) " ,
& is_authorized ,
& is_challenge ,
NULL ) ;
_LOG2T ( call_id , " completed: authorized=%d, challenge=%d " ,
is_authorized , is_challenge ) ;
} else
_LOG2T ( call_id , " completed: failed: %s " , error - > message ) ;
2014-08-14 13:34:57 +02:00
2018-04-09 13:27:03 +02:00
_call_id_invoke_callback ( call_id , is_authorized , is_challenge , error ) ;
2014-08-14 13:34:57 +02:00
}
static void
2018-04-09 13:27:03 +02:00
_call_check_authorize ( NMAuthManagerCallId * call_id )
2014-08-14 13:34:57 +02:00
{
2018-04-09 13:27:03 +02:00
NMAuthManager * self = call_id - > self ;
NMAuthManagerPrivate * priv = NM_AUTH_MANAGER_GET_PRIVATE ( self ) ;
nm_assert ( call_id - > dbus_parameters ) ;
nm_assert ( g_variant_is_floating ( call_id - > dbus_parameters ) ) ;
nm_assert ( ! call_id - > dbus_cancellable ) ;
call_id - > dbus_cancellable = g_cancellable_new ( ) ;
nm_assert ( priv - > cancel_cancellable ) ;
2014-08-14 13:34:57 +02:00
g_dbus_proxy_call ( priv - > proxy ,
" CheckAuthorization " ,
2018-04-09 13:27:03 +02:00
g_steal_pointer ( & call_id - > dbus_parameters ) ,
2014-08-14 13:34:57 +02:00
G_DBUS_CALL_FLAGS_NONE ,
G_MAXINT , /* no timeout */
2018-04-09 13:27:03 +02:00
call_id - > dbus_cancellable ,
_call_check_authorize_cb ,
call_id ) ;
}
static gboolean
2018-04-09 16:04:46 +02:00
_call_on_idle ( gpointer user_data )
2018-04-09 13:27:03 +02:00
{
NMAuthManagerCallId * call_id = user_data ;
gs_free_error GError * error = NULL ;
2018-04-09 16:04:46 +02:00
gboolean is_authorized = FALSE ;
gboolean is_challenge = FALSE ;
const char * error_msg = NULL ;
2018-04-09 13:27:03 +02:00
call_id - > idle_id = 0 ;
2018-04-09 16:04:46 +02:00
if ( call_id - > idle_reason = = IDLE_REASON_AUTHORIZED ) {
is_authorized = TRUE ;
_LOG2T ( call_id , " completed: authorized=%d, challenge=%d (simulated) " ,
is_authorized , is_challenge ) ;
} else {
nm_assert ( call_id - > idle_reason = = IDLE_REASON_NO_DBUS ) ;
error_msg = " failure creating GDBusProxy for authorization request " ;
_LOG2T ( call_id , " completed: failed due to no D-Bus proxy " ) ;
}
if ( error_msg )
g_set_error_literal ( & error , NM_UTILS_ERROR , NM_UTILS_ERROR_UNKNOWN , error_msg ) ;
_call_id_invoke_callback ( call_id , is_authorized , is_challenge , error ) ;
2018-04-09 13:27:03 +02:00
return G_SOURCE_REMOVE ;
2014-08-14 13:34:57 +02:00
}
2018-04-09 12:36:06 +02:00
/*
* @ callback must never be invoked synchronously .
2018-04-09 13:27:03 +02:00
*
* @ callback is always invoked exactly once , and never synchronously .
* You may cancel the invocation with nm_auth_manager_check_authorization_cancel ( ) ,
* but : you may only do so exactly once , and only before @ callback is
* invoked . Even if you cancel the request , @ callback will still be invoked
* ( synchronously , during the _cancel ( ) callback ) .
*
* The request keeps @ self alive ( it needs to do so , because when cancelling a
* request we might need to do an additional CancelCheckAuthorization call , for
* which @ self must be live long enough ) .
2018-04-09 12:36:06 +02:00
*/
2018-04-09 13:27:03 +02:00
NMAuthManagerCallId *
nm_auth_manager_check_authorization ( NMAuthManager * self ,
NMAuthSubject * subject ,
const char * action_id ,
gboolean allow_user_interaction ,
NMAuthManagerCheckAuthorizationCallback callback ,
gpointer user_data )
2014-08-14 13:34:57 +02:00
{
NMAuthManagerPrivate * priv ;
2018-04-09 13:27:03 +02:00
PolkitCheckAuthorizationFlags flags ;
2014-08-14 13:34:57 +02:00
char subject_buf [ 64 ] ;
GVariantBuilder builder ;
GVariant * subject_value ;
GVariant * details_value ;
2018-04-09 13:27:03 +02:00
NMAuthManagerCallId * call_id ;
2014-08-14 13:34:57 +02:00
2018-04-09 13:27:03 +02:00
g_return_val_if_fail ( NM_IS_AUTH_MANAGER ( self ) , NULL ) ;
2018-04-09 16:04:46 +02:00
g_return_val_if_fail ( NM_IN_SET ( nm_auth_subject_get_subject_type ( subject ) ,
NM_AUTH_SUBJECT_TYPE_INTERNAL ,
NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS ) ,
NULL ) ;
2018-04-09 13:27:03 +02:00
g_return_val_if_fail ( action_id , NULL ) ;
2014-08-14 13:34:57 +02:00
priv = NM_AUTH_MANAGER_GET_PRIVATE ( self ) ;
2018-04-09 13:27:03 +02:00
g_return_val_if_fail ( ! priv - > disposing , NULL ) ;
g_return_val_if_fail ( ! priv - > shutting_down , NULL ) ;
2014-08-14 13:34:57 +02:00
flags = allow_user_interaction
? POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION
: POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE ;
2018-04-09 13:27:03 +02:00
call_id = g_slice_new0 ( NMAuthManagerCallId ) ;
call_id - > self = g_object_ref ( self ) ;
call_id - > callback = callback ;
call_id - > user_data = user_data ;
call_id - > call_numid = + + priv - > call_numid_counter ;
c_list_link_tail ( & priv - > calls_lst_head , & call_id - > calls_lst ) ;
2018-04-09 16:04:46 +02:00
if ( ! priv - > polkit_enabled ) {
_LOG2T ( call_id , " CheckAuthorization(%s), subject=%s (succeeding due to polkit authorization disabled) " , action_id , nm_auth_subject_to_string ( subject , subject_buf , sizeof ( subject_buf ) ) ) ;
call_id - > idle_reason = IDLE_REASON_AUTHORIZED ;
call_id - > idle_id = g_idle_add ( _call_on_idle , call_id ) ;
} else if ( nm_auth_subject_is_internal ( subject ) ) {
_LOG2T ( call_id , " CheckAuthorization(%s), subject=%s (succeeding for internal request) " , action_id , nm_auth_subject_to_string ( subject , subject_buf , sizeof ( subject_buf ) ) ) ;
call_id - > idle_reason = IDLE_REASON_AUTHORIZED ;
call_id - > idle_id = g_idle_add ( _call_on_idle , call_id ) ;
} else if ( nm_auth_subject_get_unix_process_uid ( subject ) = = 0 ) {
_LOG2T ( call_id , " CheckAuthorization(%s), subject=%s (succeeding for root) " , action_id , nm_auth_subject_to_string ( subject , subject_buf , sizeof ( subject_buf ) ) ) ;
call_id - > idle_reason = IDLE_REASON_AUTHORIZED ;
call_id - > idle_id = g_idle_add ( _call_on_idle , call_id ) ;
} else if ( ! priv - > proxy
& & ! priv - > new_proxy_cancellable ) {
2018-04-09 13:27:03 +02:00
_LOG2T ( call_id , " CheckAuthorization(%s), subject=%s (failing due to invalid DBUS proxy) " , action_id , nm_auth_subject_to_string ( subject , subject_buf , sizeof ( subject_buf ) ) ) ;
2018-04-09 16:04:46 +02:00
call_id - > idle_reason = IDLE_REASON_NO_DBUS ;
call_id - > idle_id = g_idle_add ( _call_on_idle , call_id ) ;
2014-08-14 13:34:57 +02:00
} else {
2018-04-09 13:27:03 +02:00
subject_value = nm_auth_subject_unix_process_to_polkit_gvariant ( subject ) ;
nm_assert ( g_variant_is_floating ( subject_value ) ) ;
/* ((PolkitDetails *)NULL) */
g_variant_builder_init ( & builder , G_VARIANT_TYPE ( " a{ss} " ) ) ;
details_value = g_variant_builder_end ( & builder ) ;
call_id - > dbus_parameters = g_variant_new ( " (@(sa{sv})s@a{ss}us) " ,
subject_value ,
action_id ,
details_value ,
( guint32 ) flags ,
cancellation_id_to_str_a ( call_id - > call_numid ) ) ;
if ( ! priv - > proxy ) {
_LOG2T ( call_id , " CheckAuthorization(%s), subject=%s (wait for proxy) " , action_id , nm_auth_subject_to_string ( subject , subject_buf , sizeof ( subject_buf ) ) ) ;
} else {
_LOG2T ( call_id , " CheckAuthorization(%s), subject=%s " , action_id , nm_auth_subject_to_string ( subject , subject_buf , sizeof ( subject_buf ) ) ) ;
_call_check_authorize ( call_id ) ;
}
2014-08-14 13:34:57 +02:00
}
2018-04-09 13:27:03 +02:00
return call_id ;
2014-08-14 13:34:57 +02:00
}
2018-04-09 13:27:03 +02:00
void
nm_auth_manager_check_authorization_cancel ( NMAuthManagerCallId * call_id )
2014-08-14 13:34:57 +02:00
{
2018-04-09 13:27:03 +02:00
NMAuthManager * self ;
gs_free_error GError * error = NULL ;
2014-08-14 13:34:57 +02:00
2018-04-09 13:27:03 +02:00
g_return_if_fail ( call_id ) ;
2014-08-14 13:34:57 +02:00
2018-04-09 13:27:03 +02:00
self = call_id - > self ;
2014-08-14 13:34:57 +02:00
2018-04-09 13:27:03 +02:00
g_return_if_fail ( NM_IS_AUTH_MANAGER ( self ) ) ;
g_return_if_fail ( ! c_list_is_empty ( & call_id - > calls_lst ) ) ;
nm_assert ( c_list_contains ( & NM_AUTH_MANAGER_GET_PRIVATE ( self ) - > calls_lst_head , & call_id - > calls_lst ) ) ;
2014-08-14 13:34:57 +02:00
2018-04-09 13:27:03 +02:00
nm_utils_error_set_cancelled ( & error , FALSE , " NMAuthManager " ) ;
_LOG2T ( call_id , " completed: failed due to call cancelled " ) ;
_call_id_invoke_callback ( call_id ,
FALSE ,
FALSE ,
error ) ;
2014-08-14 13:34:57 +02:00
}
/*****************************************************************************/
static void
_emit_changed_signal ( NMAuthManager * self )
{
_LOGD ( " emit changed signal " ) ;
2018-04-09 12:56:56 +02:00
g_signal_emit ( self , signals [ CHANGED_SIGNAL ] , 0 ) ;
2014-08-14 13:34:57 +02:00
}
static void
_log_name_owner ( NMAuthManager * self , char * * out_name_owner )
{
NMAuthManagerPrivate * priv = NM_AUTH_MANAGER_GET_PRIVATE ( self ) ;
2018-04-09 13:27:03 +02:00
gs_free char * name_owner = NULL ;
2014-08-14 13:34:57 +02:00
name_owner = g_dbus_proxy_get_name_owner ( priv - > proxy ) ;
if ( name_owner )
_LOGD ( " dbus name owner: '%s' " , name_owner ) ;
else
_LOGD ( " dbus name owner: none " ) ;
2018-04-09 13:27:03 +02:00
NM_SET_OUT ( out_name_owner , g_steal_pointer ( & name_owner ) ) ;
2014-08-14 13:34:57 +02:00
}
static void
_dbus_on_name_owner_notify_cb ( GObject * object ,
GParamSpec * pspec ,
gpointer user_data )
{
NMAuthManager * self = user_data ;
2018-04-09 13:27:03 +02:00
gs_free char * name_owner = NULL ;
2014-08-14 13:34:57 +02:00
2018-04-09 13:27:03 +02:00
nm_assert ( NM_AUTH_MANAGER_GET_PRIVATE ( self ) - > proxy = = ( GDBusProxy * ) object ) ;
2014-08-14 13:34:57 +02:00
_log_name_owner ( self , & name_owner ) ;
if ( ! name_owner ) {
/* when the name disappears, we also want to raise a emit signal.
* When it appears , we raise one already . */
_emit_changed_signal ( self ) ;
}
}
static void
2015-03-27 08:03:22 -04:00
_dbus_on_changed_signal_cb ( GDBusProxy * proxy ,
gpointer user_data )
2014-08-14 13:34:57 +02:00
{
NMAuthManager * self = user_data ;
2018-04-09 13:27:03 +02:00
nm_assert ( NM_AUTH_MANAGER_GET_PRIVATE ( self ) - > proxy = = proxy ) ;
2014-08-14 13:34:57 +02:00
2015-03-27 08:03:22 -04:00
_LOGD ( " dbus signal: \" Changed \" " ) ;
_emit_changed_signal ( self ) ;
2014-08-14 13:34:57 +02:00
}
static void
_dbus_new_proxy_cb ( GObject * source_object ,
GAsyncResult * res ,
gpointer user_data )
{
2018-04-09 13:27:03 +02:00
NMAuthManager * self ;
2014-08-14 13:34:57 +02:00
NMAuthManagerPrivate * priv ;
2018-04-26 22:48:35 +02:00
gs_free_error GError * error = NULL ;
2014-08-14 13:34:57 +02:00
GDBusProxy * proxy ;
2018-04-18 07:51:27 +02:00
NMAuthManagerCallId * call_id ;
2014-08-14 13:34:57 +02:00
proxy = g_dbus_proxy_new_for_bus_finish ( res , & error ) ;
2018-04-09 13:27:03 +02:00
if ( g_error_matches ( error , G_IO_ERROR , G_IO_ERROR_CANCELLED ) )
2014-08-14 13:34:57 +02:00
return ;
2018-04-09 13:27:03 +02:00
self = user_data ;
2014-08-14 13:34:57 +02:00
priv = NM_AUTH_MANAGER_GET_PRIVATE ( self ) ;
2018-04-09 13:27:03 +02:00
priv - > proxy = proxy ;
2014-08-14 13:34:57 +02:00
g_clear_object ( & priv - > new_proxy_cancellable ) ;
if ( ! priv - > proxy ) {
2018-04-09 13:27:03 +02:00
_LOGE ( " could not create polkit proxy: %s " , error - > message ) ;
2014-08-14 13:34:57 +02:00
2018-04-18 07:51:27 +02:00
again :
c_list_for_each_entry ( call_id , & priv - > calls_lst_head , calls_lst ) {
2018-04-16 14:32:06 +02:00
if ( call_id - > dbus_parameters ) {
_LOG2T ( call_id , " completed: failed due to no D-Bus proxy after startup " ) ;
_call_id_invoke_callback ( call_id , FALSE , FALSE , error ) ;
2018-04-18 07:51:27 +02:00
goto again ;
2018-04-16 14:32:06 +02:00
}
2014-08-14 13:34:57 +02:00
}
return ;
}
2018-04-09 13:27:03 +02:00
priv - > cancel_cancellable = g_cancellable_new ( ) ;
2014-08-14 13:34:57 +02:00
g_signal_connect ( priv - > proxy ,
" notify::g-name-owner " ,
G_CALLBACK ( _dbus_on_name_owner_notify_cb ) ,
self ) ;
2015-03-27 08:03:22 -04:00
_nm_dbus_signal_connect ( priv - > proxy , " Changed " , NULL ,
G_CALLBACK ( _dbus_on_changed_signal_cb ) ,
self ) ;
2014-08-14 13:34:57 +02:00
_log_name_owner ( self , NULL ) ;
2018-04-17 16:17:40 +02:00
c_list_for_each_entry ( call_id , & priv - > calls_lst_head , calls_lst ) {
2018-04-16 14:32:06 +02:00
if ( call_id - > dbus_parameters ) {
_LOG2T ( call_id , " CheckAuthorization invoke now " ) ;
_call_check_authorize ( call_id ) ;
}
2014-08-14 13:34:57 +02:00
}
2018-04-09 13:27:03 +02:00
2014-08-14 13:34:57 +02:00
_emit_changed_signal ( self ) ;
}
2014-08-19 18:56:23 +02:00
2014-08-14 13:34:57 +02:00
/*****************************************************************************/
NMAuthManager *
nm_auth_manager_get ( )
{
2015-01-05 18:26:26 +01:00
g_return_val_if_fail ( singleton_instance , NULL ) ;
2014-08-14 13:34:57 +02:00
2015-01-05 18:26:26 +01:00
return singleton_instance ;
2014-08-14 13:34:57 +02:00
}
2018-04-09 13:27:03 +02:00
void
nm_auth_manager_force_shutdown ( NMAuthManager * self )
{
NMAuthManagerPrivate * priv ;
g_return_if_fail ( NM_IS_AUTH_MANAGER ( self ) ) ;
priv = NM_AUTH_MANAGER_GET_PRIVATE ( self ) ;
/* while we have pending requests (NMAuthManagerCallId), the instance
* is kept alive .
*
* Even if the caller cancells all pending call - ids , we still need to keep
* a reference to self , in order to handle pending CancelCheckAuthorization
* requests .
*
* To do a corrdinated shutdown , do the following :
* - cancel all pending NMAuthManagerCallId requests .
* - ensure everybody unrefs the NMAuthManager instance . If by that , the instance
* gets destroyed , the shutdown already completed successfully .
* - Otherwise , the object is kept alive by pending CancelCheckAuthorization requests .
* wait a certain timeout ( 1 second ) for all requests to complete ( by watching
* for destruction of NMAuthManager ) .
* - if that doesn ' t happen within timeout , issue nm_auth_manager_force_shutdown ( ) and
* wait longer . After that , soon the instance should be destroyed and you
* did a successful shutdown .
* - if the instance was still not destroyed within a short timeout , you leaked
* resources . You cannot properly shutdown .
*/
priv - > shutting_down = TRUE ;
nm_clear_g_cancellable ( & priv - > cancel_cancellable ) ;
}
2014-08-14 13:34:57 +02:00
/*****************************************************************************/
static void
set_property ( GObject * object , guint prop_id , const GValue * value , GParamSpec * pspec )
{
2016-09-29 13:49:01 +02:00
NMAuthManagerPrivate * priv = NM_AUTH_MANAGER_GET_PRIVATE ( ( NMAuthManager * ) object ) ;
2014-08-14 13:34:57 +02:00
switch ( prop_id ) {
case PROP_POLKIT_ENABLED :
2017-01-15 12:15:58 +01:00
/* construct-only */
2014-08-14 13:34:57 +02:00
priv - > polkit_enabled = ! ! g_value_get_boolean ( value ) ;
break ;
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID ( object , prop_id , pspec ) ;
break ;
}
}
2016-09-29 13:49:01 +02:00
/*****************************************************************************/
2014-08-14 13:34:57 +02:00
static void
nm_auth_manager_init ( NMAuthManager * self )
{
2018-04-09 13:27:03 +02:00
NMAuthManagerPrivate * priv = NM_AUTH_MANAGER_GET_PRIVATE ( self ) ;
c_list_init ( & priv - > calls_lst_head ) ;
2014-08-14 13:34:57 +02:00
}
static void
constructed ( GObject * object )
{
NMAuthManager * self = NM_AUTH_MANAGER ( object ) ;
NMAuthManagerPrivate * priv = NM_AUTH_MANAGER_GET_PRIVATE ( self ) ;
G_OBJECT_CLASS ( nm_auth_manager_parent_class ) - > constructed ( object ) ;
_LOGD ( " create auth-manager: polkit %s " , priv - > polkit_enabled ? " enabled " : " disabled " ) ;
if ( priv - > polkit_enabled ) {
priv - > new_proxy_cancellable = g_cancellable_new ( ) ;
g_dbus_proxy_new_for_bus ( G_BUS_TYPE_SYSTEM ,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES ,
NULL ,
POLKIT_SERVICE ,
POLKIT_OBJECT_PATH ,
POLKIT_INTERFACE ,
priv - > new_proxy_cancellable ,
_dbus_new_proxy_cb ,
2018-04-09 13:27:03 +02:00
self ) ;
2014-08-14 13:34:57 +02:00
}
}
2016-09-29 13:49:01 +02:00
NMAuthManager *
nm_auth_manager_setup ( gboolean polkit_enabled )
{
NMAuthManager * self ;
g_return_val_if_fail ( ! singleton_instance , singleton_instance ) ;
self = g_object_new ( NM_TYPE_AUTH_MANAGER ,
NM_AUTH_MANAGER_POLKIT_ENABLED , polkit_enabled ,
NULL ) ;
_LOGD ( " set instance " ) ;
singleton_instance = self ;
nm_singleton_instance_register ( ) ;
nm_log_dbg ( LOGD_CORE , " setup %s singleton (%p) " , " NMAuthManager " , singleton_instance ) ;
return self ;
}
2014-08-14 13:34:57 +02:00
static void
dispose ( GObject * object )
{
NMAuthManager * self = NM_AUTH_MANAGER ( object ) ;
NMAuthManagerPrivate * priv = NM_AUTH_MANAGER_GET_PRIVATE ( self ) ;
_LOGD ( " dispose " ) ;
2018-04-17 16:01:36 +02:00
nm_assert ( c_list_is_empty ( & priv - > calls_lst_head ) ) ;
2018-04-09 13:27:03 +02:00
priv - > disposing = TRUE ;
2014-08-14 13:34:57 +02:00
2017-03-13 11:51:33 +01:00
nm_clear_g_cancellable ( & priv - > new_proxy_cancellable ) ;
2018-04-09 13:27:03 +02:00
nm_clear_g_cancellable ( & priv - > cancel_cancellable ) ;
2014-08-14 13:34:57 +02:00
if ( priv - > proxy ) {
2015-03-27 08:03:22 -04:00
g_signal_handlers_disconnect_by_data ( priv - > proxy , self ) ;
2014-08-14 13:34:57 +02:00
g_clear_object ( & priv - > proxy ) ;
}
G_OBJECT_CLASS ( nm_auth_manager_parent_class ) - > dispose ( object ) ;
}
static void
nm_auth_manager_class_init ( NMAuthManagerClass * klass )
{
GObjectClass * object_class = G_OBJECT_CLASS ( klass ) ;
object_class - > set_property = set_property ;
object_class - > constructed = constructed ;
object_class - > dispose = dispose ;
2016-09-29 13:49:01 +02:00
obj_properties [ PROP_POLKIT_ENABLED ] =
2014-08-14 13:34:57 +02:00
g_param_spec_boolean ( NM_AUTH_MANAGER_POLKIT_ENABLED , " " , " " ,
FALSE ,
2018-04-09 12:58:59 +02:00
G_PARAM_WRITABLE |
2014-08-14 13:34:57 +02:00
G_PARAM_CONSTRUCT_ONLY |
2016-09-29 13:49:01 +02:00
G_PARAM_STATIC_STRINGS ) ;
g_object_class_install_properties ( object_class , _PROPERTY_ENUMS_LAST , obj_properties ) ;
2014-08-14 13:34:57 +02:00
signals [ CHANGED_SIGNAL ] = g_signal_new ( NM_AUTH_MANAGER_SIGNAL_CHANGED ,
NM_TYPE_AUTH_MANAGER ,
G_SIGNAL_RUN_LAST ,
2018-04-09 13:27:03 +02:00
0 , NULL , NULL ,
2014-08-14 13:34:57 +02:00
g_cclosure_marshal_VOID__VOID ,
2018-04-09 13:27:03 +02:00
G_TYPE_NONE , 0 ) ;
2014-08-14 13:34:57 +02:00
}