From 8836aa123cd11df359dfbb7b36da146490dbdfa3 Mon Sep 17 00:00:00 2001 From: Tomas Smetana Date: Wed, 24 Apr 2013 13:00:54 +0200 Subject: New provider: RealmD --- src/realmd/CMakeLists.txt | 50 + src/realmd/LMI_HostedRealmdServiceProvider.c | 233 +++ src/realmd/LMI_RealmdKerberosRealmProvider.c | 627 ++++++ src/realmd/LMI_RealmdRealmProvider.c | 326 ++++ src/realmd/LMI_RealmdServiceProvider.c | 631 ++++++ src/realmd/LMI_ServiceAffectsRealmdRealmProvider.c | 252 +++ src/realmd/README | 221 +++ src/realmd/VERSION | 1 + src/realmd/doc/class_diagram.svg | 273 +++ src/realmd/doc/examples/realmd-cim | 245 +++ src/realmd/rdcp_dbus.c | 2050 ++++++++++++++++++++ src/realmd/rdcp_dbus.h | 74 + src/realmd/rdcp_error.c | 123 ++ src/realmd/rdcp_error.h | 38 + src/realmd/rdcp_realmdrealm.h | 310 +++ src/realmd/rdcp_util.c | 311 +++ src/realmd/rdcp_util.h | 116 ++ src/realmd/realm-dbus-constants.h | 66 + 18 files changed, 5947 insertions(+) create mode 100644 src/realmd/CMakeLists.txt create mode 100644 src/realmd/LMI_HostedRealmdServiceProvider.c create mode 100644 src/realmd/LMI_RealmdKerberosRealmProvider.c create mode 100644 src/realmd/LMI_RealmdRealmProvider.c create mode 100644 src/realmd/LMI_RealmdServiceProvider.c create mode 100644 src/realmd/LMI_ServiceAffectsRealmdRealmProvider.c create mode 100644 src/realmd/README create mode 100644 src/realmd/VERSION create mode 100644 src/realmd/doc/class_diagram.svg create mode 100644 src/realmd/doc/examples/realmd-cim create mode 100644 src/realmd/rdcp_dbus.c create mode 100644 src/realmd/rdcp_dbus.h create mode 100644 src/realmd/rdcp_error.c create mode 100644 src/realmd/rdcp_error.h create mode 100644 src/realmd/rdcp_realmdrealm.h create mode 100644 src/realmd/rdcp_util.c create mode 100644 src/realmd/rdcp_util.h create mode 100644 src/realmd/realm-dbus-constants.h (limited to 'src/realmd') diff --git a/src/realmd/CMakeLists.txt b/src/realmd/CMakeLists.txt new file mode 100644 index 0000000..380dd5c --- /dev/null +++ b/src/realmd/CMakeLists.txt @@ -0,0 +1,50 @@ +pkg_check_modules(DBUS1 dbus-1 REQUIRED) +pkg_check_modules(GLIB2 glib-2.0 REQUIRED) + +set(PROVIDER_NAME Realmd) +set(LIBRARY_NAME cmpiLMI_${PROVIDER_NAME}) +set(MOF LMI_Realmd.mof) + + +set(provider_SRCS + LMI_HostedRealmdServiceProvider.c + LMI_RealmdKerberosRealmProvider.c + LMI_RealmdRealmProvider.c + LMI_RealmdServiceProvider.c + LMI_ServiceAffectsRealmdRealmProvider.c + rdcp_dbus.c + rdcp_error.c + rdcp_util.c +) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") + +konkretcmpi_generate(${MOF} + CIM_PROVIDERS + CIM_HEADERS +) + +add_library(${LIBRARY_NAME} SHARED + ${provider_SRCS} + ${CIM_PROVIDERS} + ${CIM_HEADERS} +) + +# FIXME - /usr/include/openlmi shouldn't be hardcoded, needed for globals.h +include_directories(${CMAKE_CURRENT_BINARY_DIR} + ${CMPI_INCLUDE_DIR} + ${DBUS1_INCLUDE_DIRS} + ${GLIB2_INCLUDE_DIRS} + ) + +target_link_libraries(${LIBRARY_NAME} + openlmicommon + ${KONKRETCMPI_LIBRARIES} + ${DBUS1_LIBRARIES} + ${GLIB2_LIBRARIES} + ) + +# Create registration file +cim_registration(${PROVIDER_NAME} ${LIBRARY_NAME} ${MOF} share/openlmi-providers) + +install(TARGETS ${LIBRARY_NAME} DESTINATION lib${LIB_SUFFIX}/cmpi/) diff --git a/src/realmd/LMI_HostedRealmdServiceProvider.c b/src/realmd/LMI_HostedRealmdServiceProvider.c new file mode 100644 index 0000000..08732c1 --- /dev/null +++ b/src/realmd/LMI_HostedRealmdServiceProvider.c @@ -0,0 +1,233 @@ +#include +#include "LMI_HostedRealmdService.h" +#include "CIM_ComputerSystem.h" +#include "rdcp_util.h" +#include "globals.h" + +static const CMPIBroker* _cb; + +static void LMI_HostedRealmdServiceInitialize() +{ +} + +static CMPIStatus LMI_HostedRealmdServiceCleanup( + CMPIInstanceMI* mi, + const CMPIContext* cc, + CMPIBoolean term) +{ + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_HostedRealmdServiceEnumInstanceNames( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop) +{ + return KDefaultEnumerateInstanceNames( + _cb, mi, cc, cr, cop); +} + +static CMPIStatus LMI_HostedRealmdServiceEnumInstances( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char** properties) +{ + CMPIStatus status; + CIM_ComputerSystemRef computer_sys_ref; + LMI_RealmdServiceRef realmd_service_ref; + LMI_HostedRealmdService hosted_realmd_service; + CMPIObjectPath *computer_sys_op = NULL; + + const char *name_space = KNameSpace(cop); + const char *host_name = get_system_name(); + + CMSetStatus(&status, CMPI_RC_OK); + + LMI_InitComputerSystemKeys(CIM_ComputerSystemRef, &computer_sys_ref, + name_space, host_name); + + LMI_InitRealmdServiceKeys(LMI_RealmdServiceRef, &realmd_service_ref, name_space, host_name); + + computer_sys_op = LMI_RealmdServiceRef_ToObjectPath(&realmd_service_ref, &status); + computer_sys_op->ft->setClassName(computer_sys_op, + get_system_creation_class_name()); + + LMI_HostedRealmdService_Init(&hosted_realmd_service, _cb, name_space); + LMI_HostedRealmdService_SetObjectPath_Antecedent(&hosted_realmd_service, + computer_sys_op); + LMI_HostedRealmdService_Set_Dependent(&hosted_realmd_service, + &realmd_service_ref); + + KReturnInstance(cr, hosted_realmd_service); + + return status; +} + +static CMPIStatus LMI_HostedRealmdServiceGetInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char** properties) +{ + return KDefaultGetInstance( + _cb, mi, cc, cr, cop, properties); +} + +static CMPIStatus LMI_HostedRealmdServiceCreateInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const CMPIInstance* ci) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_HostedRealmdServiceModifyInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const CMPIInstance* ci, + const char**properties) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_HostedRealmdServiceDeleteInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_HostedRealmdServiceExecQuery( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* lang, + const char* query) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_HostedRealmdServiceAssociationCleanup( + CMPIAssociationMI* mi, + const CMPIContext* cc, + CMPIBoolean term) +{ + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_HostedRealmdServiceAssociators( + CMPIAssociationMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* assocClass, + const char* resultClass, + const char* role, + const char* resultRole, + const char** properties) +{ + return KDefaultAssociators( + _cb, + mi, + cc, + cr, + cop, + LMI_HostedRealmdService_ClassName, + assocClass, + resultClass, + role, + resultRole, + properties); +} + +static CMPIStatus LMI_HostedRealmdServiceAssociatorNames( + CMPIAssociationMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* assocClass, + const char* resultClass, + const char* role, + const char* resultRole) +{ + return KDefaultAssociatorNames( + _cb, + mi, + cc, + cr, + cop, + LMI_HostedRealmdService_ClassName, + assocClass, + resultClass, + role, + resultRole); +} + +static CMPIStatus LMI_HostedRealmdServiceReferences( + CMPIAssociationMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* assocClass, + const char* role, + const char** properties) +{ + return KDefaultReferences( + _cb, + mi, + cc, + cr, + cop, + LMI_HostedRealmdService_ClassName, + assocClass, + role, + properties); +} + +static CMPIStatus LMI_HostedRealmdServiceReferenceNames( + CMPIAssociationMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* assocClass, + const char* role) +{ + return KDefaultReferenceNames( + _cb, + mi, + cc, + cr, + cop, + LMI_HostedRealmdService_ClassName, + assocClass, + role); +} + +CMInstanceMIStub( + LMI_HostedRealmdService, + LMI_HostedRealmdService, + _cb, + LMI_HostedRealmdServiceInitialize()) + +CMAssociationMIStub( + LMI_HostedRealmdService, + LMI_HostedRealmdService, + _cb, + LMI_HostedRealmdServiceInitialize()) + +KONKRET_REGISTRATION( + "root/cimv2", + "LMI_HostedRealmdService", + "LMI_HostedRealmdService", + "instance association"); diff --git a/src/realmd/LMI_RealmdKerberosRealmProvider.c b/src/realmd/LMI_RealmdKerberosRealmProvider.c new file mode 100644 index 0000000..5dc90d2 --- /dev/null +++ b/src/realmd/LMI_RealmdKerberosRealmProvider.c @@ -0,0 +1,627 @@ +#include +#include "LMI_RealmdKerberosRealm.h" +#include "globals.h" +#include "rdcp_error.h" +#include "rdcp_dbus.h" +#include "rdcp_util.h" +#include "rdcp_realmdrealm.h" + +static const CMPIBroker* _cb = NULL; + +CMPIStatus LMI_RealmdKerberosRealmRef_InitFromDBusPath( + LMI_RealmdKerberosRealmRef* self, + const CMPIBroker* cb, + const char* ns, + const char* dbus_path) +{ + CMPIStatus status; + + CMSetStatus(&status, CMPI_RC_OK); + + LMI_RealmdRealmInitKeys(LMI_RealmdKerberosRealmRef, self, dbus_path); + + return status; +} + +CMPIStatus LMI_RealmdKerberosRealm_InitFromDBusPath( + LMI_RealmdKerberosRealm* self, + const CMPIBroker* cb, + const char* ns, + const char* dbus_path) +{ + CMPIStatus status; + GError *g_error = NULL; + GVariant *realm_props = NULL; + GVariant *kerberos_props = NULL; + GVariant *kerberos_membership_props = NULL; + + CMSetStatus(&status, CMPI_RC_OK); + + if (!rdcp_dbus_initialize(&g_error)) { + return handle_g_error(&g_error, _cb, &status, CMPI_RC_ERR_FAILED, "rdcp_dbus_initialize failed"); + } + + GET_DBUS_PROPERIES_OR_EXIT(realm_props, dbus_path, + REALM_DBUS_REALM_INTERFACE, &status); + GET_DBUS_PROPERIES_OR_EXIT(kerberos_props, dbus_path, + REALM_DBUS_KERBEROS_INTERFACE, &status); + + LMI_RealmdRealmInitKeys(LMI_RealmdKerberosRealm, self, dbus_path); + LMI_InitFromDBusRealmProps(LMI_RealmdKerberosRealm, self, realm_props); + LMI_InitFromDBusKerberosRealmProps(LMI_RealmdKerberosRealm, self, kerberos_props); + + if (SupportsDBusInterface(realm_props, REALM_DBUS_KERBEROS_MEMBERSHIP_INTERFACE)) { + GET_DBUS_PROPERIES_OR_EXIT(kerberos_membership_props, dbus_path, + REALM_DBUS_KERBEROS_MEMBERSHIP_INTERFACE, &status); + + LMI_InitFromDBusKerberosMembershipProps(LMI_RealmdKerberosRealm, self, + kerberos_membership_props); + } + + exit: + G_VARIANT_FREE(realm_props); + G_VARIANT_FREE(kerberos_props); + G_VARIANT_FREE(kerberos_membership_props); + + return status; +} + + +static void LMI_RealmdKerberosRealmInitialize() +{ +} + +static CMPIStatus LMI_RealmdKerberosRealmCleanup( + CMPIInstanceMI* mi, + const CMPIContext* cc, + CMPIBoolean term) +{ + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_RealmdKerberosRealmEnumInstanceNames( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop) +{ + return KDefaultEnumerateInstanceNames( + _cb, mi, cc, cr, cop); +} + +static CMPIStatus LMI_RealmdKerberosRealmEnumInstances( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char** properties) +{ + CMPIStatus status; + GError *g_error = NULL; + GVariant *provider_props = NULL; + GVariant *realm_props = NULL; + GVariantIter *iter = NULL; + gchar *realm_obj_path; + const char *name_space = KNameSpace(cop); + + CMSetStatus(&status, CMPI_RC_OK); + + if (!rdcp_dbus_initialize(&g_error)) { + return handle_g_error(&g_error, _cb, &status, CMPI_RC_ERR_FAILED, + "rdcp_dbus_initialize failed"); + } + + GET_DBUS_PROPERIES_OR_EXIT(provider_props, REALM_DBUS_SERVICE_PATH, + REALM_DBUS_PROVIDER_INTERFACE, &status); + + g_variant_lookup(provider_props, "Realms", "ao", &iter); + while (g_variant_iter_next(iter, "&o", &realm_obj_path)) { + LMI_RealmdKerberosRealm realmd_realm; + + GET_DBUS_PROPERIES_OR_EXIT(realm_props, realm_obj_path, + REALM_DBUS_REALM_INTERFACE, &status); + if (!SupportsDBusInterface(realm_props, REALM_DBUS_KERBEROS_INTERFACE)) { + G_VARIANT_FREE(realm_props); + continue; + } + G_VARIANT_FREE(realm_props); + + status = LMI_RealmdKerberosRealm_InitFromDBusPath(&realmd_realm, _cb, + name_space, realm_obj_path); + if (status.rc != CMPI_RC_OK) { + goto exit; + } + + KReturnInstance(cr, realmd_realm); + } + + exit: + G_VARIANT_ITER_FREE(iter); + G_VARIANT_FREE(provider_props); + G_VARIANT_FREE(realm_props); + + return status; +} + +static CMPIStatus LMI_RealmdKerberosRealmGetInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char** properties) +{ + return KDefaultGetInstance( + _cb, mi, cc, cr, cop, properties); +} + +static CMPIStatus LMI_RealmdKerberosRealmCreateInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const CMPIInstance* ci) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_RealmdKerberosRealmModifyInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const CMPIInstance* ci, + const char** properties) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_RealmdKerberosRealmDeleteInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_RealmdKerberosRealmExecQuery( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* lang, + const char* query) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +CMInstanceMIStub( + LMI_RealmdKerberosRealm, + LMI_RealmdKerberosRealm, + _cb, + LMI_RealmdKerberosRealmInitialize()) + +static CMPIStatus LMI_RealmdKerberosRealmMethodCleanup( + CMPIMethodMI* mi, + const CMPIContext* cc, + CMPIBoolean term) +{ + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_RealmdKerberosRealmInvokeMethod( + CMPIMethodMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* meth, + const CMPIArgs* in, + CMPIArgs* out) +{ + return LMI_RealmdKerberosRealm_DispatchMethod( + _cb, mi, cc, cr, cop, meth, in, out); +} + +CMMethodMIStub( + LMI_RealmdKerberosRealm, + LMI_RealmdKerberosRealm, + _cb, + LMI_RealmdKerberosRealmInitialize()) + +KUint32 LMI_RealmdKerberosRealm_ChangeLoginPolicy( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_RealmdKerberosRealmRef* self, + const KString* LoginPolicy, + const KStringA* PermittedAdd, + const KStringA* PermittedRemove, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_RealmdKerberosRealm_Deconfigure( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_RealmdKerberosRealmRef* self, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KEXTERN KUint32 LMI_RealmdKerberosRealm_Join( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_RealmdKerberosRealmRef* self, + const KUint32* Type, + const KUint32* Owner, + const KString* Name, + const KString* Password, + const KUint8A* Data, + const KStringA* OptionNames, + const KStringA* OptionValues, + CMPIStatus* status) +{ + GError *g_error = NULL; + KUint32 result = KUINT32_INIT; + const char *cred_type = NULL; + const char *cred_owner = NULL; + gchar *data = NULL; + gsize data_len; + gchar *dbus_path = NULL; + GVariant *credentials = NULL; + GVariant *data_variant = NULL; + GVariant *options = NULL; + + KUint32_Set(&result, LMI_REALMD_RESULT_SUCCESS); + CMSetStatus(status, CMPI_RC_OK); + + if (!rdcp_dbus_initialize(&g_error)) { + handle_g_error(&g_error, _cb, status, CMPI_RC_ERR_FAILED, "rdcp_dbus_initialize failed"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if (!Type->exists || Type->null) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, "Type parameter absent"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if (!Owner->exists || Owner->null) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, "Owner parameter absent"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if (!dbus_path_from_instance_id(self->InstanceID.chars, &dbus_path, &g_error)) { + handle_g_error(&g_error, cb, status, CMPI_RC_ERR_FAILED, + "dbus_path_from_instance_id() failed"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + switch(Owner->value) { + case LMI_RealmdKerberosRealm_SupportedJoinCredentialOwners_administrator: + case LMI_RealmdKerberosRealm_SupportedJoinCredentialOwners_user: + case LMI_RealmdKerberosRealm_SupportedJoinCredentialOwners_computer: + case LMI_RealmdKerberosRealm_SupportedJoinCredentialOwners_none: + break; + default: + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, "Invalid Owner parameter"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + cred_type = SupportedJoinCredentialTypes_enum_to_name(Type->value); + cred_owner = SupportedJoinCredentialOwners_enum_to_name(Owner->value); + + switch(Type->value) { + case LMI_RealmdKerberosRealm_SupportedJoinCredentialTypes_ccache: + if ((Name->exists && !Name->null) || (Password->exists && !Password->null)) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, + "Name & Password parameters must be NULL when Type is ccache"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + if (!Data->exists || Data->null) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, + "Data parameter must be provided when Type is ccache"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if ((data = get_data_from_KUint8A(Data, &data_len)) == NULL) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_FAILED, + "unabled to allocate memory"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + data_variant = g_variant_new_from_data(G_VARIANT_TYPE ("ay"), + data, data_len, + TRUE, g_free, (gpointer) data); + + credentials = g_variant_new("(ssv)", cred_type, cred_owner, data_variant); + break; + case LMI_RealmdKerberosRealm_SupportedJoinCredentialTypes_password: + if (!Name->exists || Name->null || !Password->exists || Password->null) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, + "Name & Password parameters must be provided when Type is password"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + if (Data->exists && !Data->null) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, + "Data parameter must be NULL when Type is password"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + credentials = g_variant_new("(ssv)", cred_type, cred_owner, + g_variant_new("(ss)", Name->chars, Password->chars)); + + break; + case LMI_RealmdKerberosRealm_SupportedJoinCredentialTypes_secrect: + if ((Name->exists && !Name->null) || (Password->exists && !Password->null)) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, + "Name & Password parameters must be NULL when Type is secret"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + if (!Data->exists || Data->null) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, + "Data parameter must be provided when Type is secret"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if ((data = get_data_from_KUint8A(Data, &data_len)) == NULL) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_FAILED, + "unabled to allocate memory"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + credentials = g_variant_new("(ssv)", cred_type, cred_owner, + g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, + data, data_len, 1)); + break; + case LMI_RealmdKerberosRealm_SupportedJoinCredentialTypes_automatic: + if ((Name->exists && !Name->null) || (Password->exists && !Password->null) || + (Data->exists && !Data->null)) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, + "Name, Password & Data parameters must be NULL when Type is secret"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + credentials = g_variant_new ("(ssv)", cred_type, cred_owner, + g_variant_new_string ("")); + + break; + default: + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, "Invalid Type parameter"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + + if (!build_g_variant_options_from_KStringA(OptionNames, OptionValues, &options, &g_error)) { + handle_g_error(&g_error, cb, status, CMPI_RC_ERR_FAILED, + "failed to convert options to gvariant"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if (!dbus_join_call(system_bus, dbus_path, credentials, options, &g_error)) { + handle_g_error(&g_error, cb, status, CMPI_RC_ERR_FAILED, "dbus_join_call() failed"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + + exit: + + g_free(data); + G_VARIANT_FREE(credentials); + G_VARIANT_FREE(data_variant); + G_VARIANT_FREE(options); + + return result; +} + +KEXTERN KUint32 LMI_RealmdKerberosRealm_Leave( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_RealmdKerberosRealmRef* self, + const KUint32* Type, + const KUint32* Owner, + const KString* Name, + const KString* Password, + const KUint8A* Data, + const KStringA* OptionNames, + const KStringA* OptionValues, + CMPIStatus* status) +{ + GError *g_error = NULL; + KUint32 result = KUINT32_INIT; + const char *cred_type = NULL; + const char *cred_owner = NULL; + gchar *data = NULL; + gsize data_len; + gchar *dbus_path = NULL; + GVariant *credentials = NULL; + GVariant *data_variant = NULL; + GVariant *options = NULL; + + KUint32_Set(&result, LMI_REALMD_RESULT_SUCCESS); + CMSetStatus(status, CMPI_RC_OK); + + if (!rdcp_dbus_initialize(&g_error)) { + handle_g_error(&g_error, _cb, status, CMPI_RC_ERR_FAILED, "rdcp_dbus_initialize failed"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if (!Type->exists || Type->null) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, "Type parameter absent"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if (!Owner->exists || Owner->null) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, "Owner parameter absent"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if (!dbus_path_from_instance_id(self->InstanceID.chars, &dbus_path, &g_error)) { + handle_g_error(&g_error, cb, status, CMPI_RC_ERR_FAILED, + "dbus_path_from_instance_id() failed"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + switch(Owner->value) { + case LMI_RealmdKerberosRealm_SupportedLeaveCredentialOwners_administrator: + case LMI_RealmdKerberosRealm_SupportedLeaveCredentialOwners_user: + case LMI_RealmdKerberosRealm_SupportedLeaveCredentialOwners_computer: + case LMI_RealmdKerberosRealm_SupportedLeaveCredentialOwners_none: + break; + default: + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, "Invalid Owner parameter"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + cred_type = SupportedLeaveCredentialTypes_enum_to_name(Type->value); + cred_owner = SupportedLeaveCredentialOwners_enum_to_name(Owner->value); + + switch(Type->value) { + case LMI_RealmdKerberosRealm_SupportedLeaveCredentialTypes_ccache: + if ((Name->exists && !Name->null) || (Password->exists && !Password->null)) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, + "Name & Password parameters must be NULL when Type is ccache"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + if (!Data->exists || Data->null) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, + "Data parameter must be provided when Type is ccache"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if ((data = get_data_from_KUint8A(Data, &data_len)) == NULL) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_FAILED, + "unabled to allocate memory"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + data_variant = g_variant_new_from_data(G_VARIANT_TYPE ("ay"), + data, data_len, + TRUE, g_free, (gpointer) data); + + credentials = g_variant_new("(ssv)", cred_type, cred_owner, data_variant); + break; + case LMI_RealmdKerberosRealm_SupportedLeaveCredentialTypes_password: + if (!Name->exists || Name->null || !Password->exists || Password->null) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, + "Name & Password parameters must be provided when Type is password"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + if (Data->exists && !Data->null) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, + "Data parameter must be NULL when Type is password"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + credentials = g_variant_new("(ssv)", cred_type, cred_owner, + g_variant_new("(ss)", Name->chars, Password->chars)); + + break; + case LMI_RealmdKerberosRealm_SupportedLeaveCredentialTypes_secrect: + if ((Name->exists && !Name->null) || (Password->exists && !Password->null)) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, + "Name & Password parameters must be NULL when Type is secret"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + if (!Data->exists || Data->null) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, + "Data parameter must be provided when Type is secret"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if ((data = get_data_from_KUint8A(Data, &data_len)) == NULL) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_FAILED, + "unabled to allocate memory"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + credentials = g_variant_new("(ssv)", cred_type, cred_owner, + g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, + data, data_len, 1)); + break; + case LMI_RealmdKerberosRealm_SupportedLeaveCredentialTypes_automatic: + if ((Name->exists && !Name->null) || (Password->exists && !Password->null) || + (Data->exists && !Data->null)) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, + "Name, Password & Data parameters must be NULL when Type is secret"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + credentials = g_variant_new ("(ssv)", cred_type, cred_owner, + g_variant_new_string ("")); + + break; + default: + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, "Invalid Type parameter"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + + if (!build_g_variant_options_from_KStringA(OptionNames, OptionValues, &options, &g_error)) { + handle_g_error(&g_error, cb, status, CMPI_RC_ERR_FAILED, + "failed to convert options to gvariant"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if (!dbus_leave_call(system_bus, dbus_path, credentials, options, &g_error)) { + handle_g_error(&g_error, cb, status, CMPI_RC_ERR_FAILED, "dbus_leave_call() failed"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + + exit: + + g_free(data); + G_VARIANT_FREE(credentials); + G_VARIANT_FREE(data_variant); + G_VARIANT_FREE(options); + + return result; +} + + +KONKRET_REGISTRATION( + "root/cimv2", + "LMI_RealmdKerberosRealm", + "LMI_RealmdKerberosRealm", + "instance method"); diff --git a/src/realmd/LMI_RealmdRealmProvider.c b/src/realmd/LMI_RealmdRealmProvider.c new file mode 100644 index 0000000..d8e0a18 --- /dev/null +++ b/src/realmd/LMI_RealmdRealmProvider.c @@ -0,0 +1,326 @@ +#include +#include +#include "LMI_RealmdRealm.h" +#include "globals.h" +#include "rdcp_error.h" +#include "rdcp_dbus.h" +#include "rdcp_util.h" +#include "rdcp_realmdrealm.h" + +static const CMPIBroker* _cb = NULL; + +CMPIStatus LMI_RealmdRealmRef_InitFromDBusPath( + LMI_RealmdRealmRef* self, + const CMPIBroker* cb, + const char* ns, + const char* dbus_path) +{ + CMPIStatus status; + + CMSetStatus(&status, CMPI_RC_OK); + + LMI_RealmdRealmInitKeys(LMI_RealmdRealmRef, self, dbus_path); + + return status; +} + +CMPIStatus LMI_RealmdRealm_InitFromDBusPath( + LMI_RealmdRealm* self, + const CMPIBroker* cb, + const char* ns, + const char* dbus_path) +{ + CMPIStatus status; + GError *g_error = NULL; + GVariant *realm_props = NULL; + + CMSetStatus(&status, CMPI_RC_OK); + + if (!rdcp_dbus_initialize(&g_error)) { + return handle_g_error(&g_error, _cb, &status, CMPI_RC_ERR_FAILED, "rdcp_dbus_initialize failed"); + } + + GET_DBUS_PROPERIES_OR_EXIT(realm_props, dbus_path, + REALM_DBUS_REALM_INTERFACE, &status); + + LMI_RealmdRealmInitKeys(LMI_RealmdRealm, self, dbus_path); + LMI_InitFromDBusRealmProps(LMI_RealmdRealm, self, realm_props); + + exit: + G_VARIANT_FREE(realm_props); + + return status; +} + +static void LMI_RealmdRealmInitialize() +{ +} + +static CMPIStatus LMI_RealmdRealmCleanup( + CMPIInstanceMI* mi, + const CMPIContext* cc, + CMPIBoolean term) +{ + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_RealmdRealmEnumInstanceNames( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop) +{ + return KDefaultEnumerateInstanceNames( + _cb, mi, cc, cr, cop); +} + +static CMPIStatus LMI_RealmdRealmEnumInstances( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char** properties) +{ + CMPIStatus status; + GError *g_error = NULL; + GVariant *provider_props = NULL; + GVariantIter *iter = NULL; + gchar *realm_obj_path; + const char *name_space = KNameSpace(cop); + + CMSetStatus(&status, CMPI_RC_OK); + + if (!rdcp_dbus_initialize(&g_error)) { + return handle_g_error(&g_error, _cb, &status, CMPI_RC_ERR_FAILED, "rdcp_dbus_initialize failed"); + } + + GET_DBUS_PROPERIES_OR_EXIT(provider_props, REALM_DBUS_SERVICE_PATH, + REALM_DBUS_PROVIDER_INTERFACE, &status); + + g_variant_lookup(provider_props, "Realms", "ao", &iter); + while (g_variant_iter_next(iter, "&o", &realm_obj_path)) { + LMI_RealmdRealm realmd_realm; + + status = LMI_RealmdRealm_InitFromDBusPath(&realmd_realm, _cb, + name_space, realm_obj_path); + if (status.rc != CMPI_RC_OK) { + goto exit; + } + KReturnInstance(cr, realmd_realm); + } + + exit: + G_VARIANT_ITER_FREE(iter); + G_VARIANT_FREE(provider_props); + + return status; +} + +static CMPIStatus LMI_RealmdRealmGetInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char** properties) +{ + CMPIStatus status; + GError *g_error = NULL; + LMI_RealmdRealmRef realmdrealm_ref; + gchar *dbus_path = NULL; + LMI_RealmdRealm realmd_realm; + + CMSetStatus(&status, CMPI_RC_OK); + + KReturnIf(LMI_RealmdRealmRef_InitFromObjectPath(&realmdrealm_ref, _cb, cop)); + + if (!dbus_path_from_instance_id(realmdrealm_ref.InstanceID.chars, &dbus_path, &g_error)) { + return handle_g_error(&g_error, _cb, &status, CMPI_RC_ERR_FAILED, + "dbus_path_from_instance_id() failed"); + } + + KReturnIf(LMI_RealmdRealm_InitFromDBusPath(&realmd_realm, _cb, KNameSpace(cop), dbus_path)); + + KReturnInstance(cr, realmd_realm); + + return status; +} + +static CMPIStatus LMI_RealmdRealmCreateInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const CMPIInstance* ci) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_RealmdRealmModifyInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const CMPIInstance* ci, + const char** properties) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_RealmdRealmDeleteInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_RealmdRealmExecQuery( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* lang, + const char* query) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +CMInstanceMIStub( + LMI_RealmdRealm, + LMI_RealmdRealm, + _cb, + LMI_RealmdRealmInitialize()) + +static CMPIStatus LMI_RealmdRealmMethodCleanup( + CMPIMethodMI* mi, + const CMPIContext* cc, + CMPIBoolean term) +{ + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_RealmdRealmInvokeMethod( + CMPIMethodMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* meth, + const CMPIArgs* in, + CMPIArgs* out) +{ + return LMI_RealmdRealm_DispatchMethod( + _cb, mi, cc, cr, cop, meth, in, out); +} + +CMMethodMIStub( + LMI_RealmdRealm, + LMI_RealmdRealm, + _cb, + LMI_RealmdRealmInitialize()) + +KUint32 LMI_RealmdRealm_ChangeLoginPolicy( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_RealmdRealmRef* self, + const KString* LoginPolicy, + const KStringA* PermittedAdd, + const KStringA* PermittedRemove, + CMPIStatus* status) +{ + GError *g_error = NULL; + KUint32 result = KUINT32_INIT; + gchar *dbus_path = NULL; + const gchar *login_policy = NULL; + GVariant *permitted_add = NULL; + GVariant *permitted_remove = NULL; + GVariant *options = NULL; + + KUint32_Set(&result, LMI_REALMD_RESULT_SUCCESS); + CMSetStatus(status, CMPI_RC_OK); + + if (!rdcp_dbus_initialize(&g_error)) { + handle_g_error(&g_error, _cb, status, CMPI_RC_ERR_FAILED, "rdcp_dbus_initialize failed"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if (!LoginPolicy->exists || LoginPolicy->null) { + login_policy = ""; + } else { + login_policy = LoginPolicy->chars; + } + + if (!PermittedAdd->exists || PermittedAdd->null) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, "PermittedAdd parameter absent"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if (!PermittedRemove->exists || PermittedRemove->null) { + CMSetStatusWithChars(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, "PermittedRemove parameter absent"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if (!dbus_path_from_instance_id(self->InstanceID.chars, &dbus_path, &g_error)) { + handle_g_error(&g_error, cb, status, CMPI_RC_ERR_FAILED, + "dbus_path_from_instance_id() failed"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if (!build_g_variant_string_array_from_KStringA(PermittedAdd, &permitted_add, &g_error)) { + handle_g_error(&g_error, cb, status, CMPI_RC_ERR_FAILED, + "failed to convert PermittedAdd to gvariant array"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if (!build_g_variant_string_array_from_KStringA(PermittedRemove, &permitted_remove, &g_error)) { + handle_g_error(&g_error, cb, status, CMPI_RC_ERR_FAILED, + "failed to convert PermittedRemove to gvariant array"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + /* For now we don't pass any options so just create an empty dictionary */ + options = g_variant_new_array(G_VARIANT_TYPE ("{sv}"), NULL, 0); + + if (!dbus_change_login_policy_call(system_bus, dbus_path, login_policy, + permitted_add, permitted_remove, + options, &g_error)) { + handle_g_error(&g_error, cb, status, CMPI_RC_ERR_FAILED, "dbus_change_login_policy_call() failed"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + + exit: + + G_VARIANT_FREE(permitted_add); + G_VARIANT_FREE(permitted_remove); + G_VARIANT_FREE(options); + + return result; +} + +KUint32 LMI_RealmdRealm_Deconfigure( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_RealmdRealmRef* self, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KONKRET_REGISTRATION( + "root/cimv2", + "LMI_RealmdRealm", + "LMI_RealmdRealm", + "instance method"); diff --git a/src/realmd/LMI_RealmdServiceProvider.c b/src/realmd/LMI_RealmdServiceProvider.c new file mode 100644 index 0000000..01fc0b8 --- /dev/null +++ b/src/realmd/LMI_RealmdServiceProvider.c @@ -0,0 +1,631 @@ +#include +#include "LMI_RealmdService.h" +#include "globals.h" +#include "rdcp_error.h" +#include "rdcp_dbus.h" +#include "rdcp_util.h" +#include "rdcp_realmdrealm.h" + +static const CMPIBroker* _cb = NULL; + +/** + * get_joined_domain: + * + * @provider_props Realmd service provider properties + * + * Determine if the host is joined to a domain and if so return the domain name. + * + * Returns: domain name if found, NULL otherwise. Must be freed with g_free. + */ +static gchar * +get_joined_domain(GVariant *provider_props) +{ + CMPIStatus status; + GError *g_error = NULL; + GVariant *realm_props = NULL; + GVariant *kerberos_props = NULL; + GVariantIter *iter = NULL; + gchar *realm_obj_path = NULL; + gchar *configured_interface = NULL; + gchar *domain_name = NULL; + + CMSetStatus(&status, CMPI_RC_OK); + + g_variant_lookup(provider_props, "Realms", "ao", &iter); + while (g_variant_iter_next(iter, "&o", &realm_obj_path)) { + GET_DBUS_PROPERIES_OR_EXIT(realm_props, realm_obj_path, + REALM_DBUS_REALM_INTERFACE, &status); + if (g_variant_lookup(realm_props, "Configured", "&s", &configured_interface)) { + if (strlen(configured_interface)) { + if (strcmp(configured_interface, REALM_DBUS_KERBEROS_MEMBERSHIP_INTERFACE) == 0) { + GET_DBUS_PROPERIES_OR_EXIT(kerberos_props, realm_obj_path, + REALM_DBUS_KERBEROS_INTERFACE, &status); + if (g_variant_lookup(kerberos_props, "DomainName", "&s", &domain_name)) { + goto exit; + } + G_VARIANT_FREE(kerberos_props); + } + } + } + G_VARIANT_FREE(realm_props); + } + + exit: + G_VARIANT_ITER_FREE(iter); + G_VARIANT_FREE(realm_props); + G_VARIANT_FREE(kerberos_props); + + return domain_name ? g_strdup(domain_name) : NULL; +} + + + +static void LMI_RealmdServiceInitialize() +{ +} + +static CMPIStatus LMI_RealmdServiceCleanup( + CMPIInstanceMI* mi, + const CMPIContext* cc, + CMPIBoolean term) +{ + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_RealmdServiceEnumInstanceNames( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop) +{ + return KDefaultEnumerateInstanceNames( + _cb, mi, cc, cr, cop); +} + +static CMPIStatus LMI_RealmdServiceEnumInstances( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char** properties) +{ + CMPIStatus status; + GError *g_error = NULL; + LMI_RealmdService lmi_realmd_service; + const char *name_space = KNameSpace(cop); + const char *host_name = get_system_name(); + CMPICount i; + GVariant *provider_props = NULL; + GVariantIter *iter; + gsize n_items; + gchar *realm_obj_path; + gchar *name = NULL; + gchar *version = NULL; + gchar *joined_domain = NULL; + + CMSetStatus(&status, CMPI_RC_OK); + + if (!rdcp_dbus_initialize(&g_error)) { + return handle_g_error(&g_error, _cb, &status, CMPI_RC_ERR_FAILED, "rdcp_dbus_initialize failed"); + } + + LMI_InitRealmdServiceKeys(LMI_RealmdService, &lmi_realmd_service, name_space, host_name); + + GET_DBUS_PROPERIES_OR_EXIT(provider_props, REALM_DBUS_SERVICE_PATH, + REALM_DBUS_PROVIDER_INTERFACE, &status); + + g_variant_lookup(provider_props, "Realms", "ao", &iter); + n_items = g_variant_iter_n_children(iter); + LMI_RealmdService_Init_Realms(&lmi_realmd_service, n_items); + for (i = 0; g_variant_iter_next(iter, "&o", &realm_obj_path); i++) { +#ifdef RDCP_DEBUG + printf("path[%d]=%s\n", i, realm_obj_path); +#endif + LMI_RealmdService_Set_Realms(&lmi_realmd_service, i, realm_obj_path); + } + + if (g_variant_lookup(provider_props, "Name", "&s", &name)) { + LMI_RealmdService_Set_RealmdName(&lmi_realmd_service, name); + } + + if (g_variant_lookup(provider_props, "Version", "&s", &version)) { + LMI_RealmdService_Set_RealmdVersion(&lmi_realmd_service, version); + } + + if ((joined_domain = get_joined_domain(provider_props))) { + LMI_RealmdService_Set_Domain(&lmi_realmd_service, joined_domain); + } + + KReturnInstance(cr, lmi_realmd_service); + + exit: + G_VARIANT_ITER_FREE(iter); + G_VARIANT_FREE(provider_props); + g_free(joined_domain); + + return status; +} + +static CMPIStatus LMI_RealmdServiceGetInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char** properties) +{ + return KDefaultGetInstance( + _cb, mi, cc, cr, cop, properties); +} + +static CMPIStatus LMI_RealmdServiceCreateInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const CMPIInstance* ci) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_RealmdServiceModifyInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const CMPIInstance* ci, + const char** properties) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_RealmdServiceDeleteInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_RealmdServiceExecQuery( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* lang, + const char* query) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +CMInstanceMIStub( + LMI_RealmdService, + LMI_RealmdService, + _cb, + LMI_RealmdServiceInitialize()) + +static CMPIStatus LMI_RealmdServiceMethodCleanup( + CMPIMethodMI* mi, + const CMPIContext* cc, + CMPIBoolean term) +{ + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_RealmdServiceInvokeMethod( + CMPIMethodMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* meth, + const CMPIArgs* in, + CMPIArgs* out) +{ + return LMI_RealmdService_DispatchMethod( + _cb, mi, cc, cr, cop, meth, in, out); +} + +CMMethodMIStub( + LMI_RealmdService, + LMI_RealmdService, + _cb, + LMI_RealmdServiceInitialize()) + +KUint32 LMI_RealmdService_RequestStateChange( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_RealmdServiceRef* self, + const KUint16* RequestedState, + KRef* Job, + const KDateTime* TimeoutPeriod, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_RealmdService_StartService( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_RealmdServiceRef* self, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_RealmdService_StopService( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_RealmdServiceRef* self, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_RealmdService_ChangeAffectedElementsAssignedSequence( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_RealmdServiceRef* self, + const KRefA* ManagedElements, + const KUint16A* AssignedSequence, + KRef* Job, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_RealmdService_Discover( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_RealmdServiceRef* self, + const KString* Target, + const KStringA* OptionNames, + const KStringA* OptionValues, + KRefA* DiscoveredRealms, + CMPIStatus* status) +{ + GError *g_error = NULL; + KUint32 result = KUINT32_INIT; + GVariant *options = NULL; + gint32 relevance = 0; + gchar **paths = NULL; + gchar *path, **pp; + CMPICount i, n_paths; + + KUint32_Set(&result, LMI_REALMD_RESULT_SUCCESS); + CMSetStatus(status, CMPI_RC_OK); + + if (!rdcp_dbus_initialize(&g_error)) { + handle_g_error(&g_error, _cb, status, CMPI_RC_ERR_FAILED, "rdcp_dbus_initialize failed"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if (!build_g_variant_options_from_KStringA(OptionNames, OptionValues, &options, &g_error)) { + handle_g_error(&g_error, _cb, status, CMPI_RC_ERR_FAILED, + "failed to convert options to gvariant"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if (!dbus_discover_call(system_bus, Target->chars, options, + &relevance, &paths, &g_error)) { + handle_g_error(&g_error, _cb, status, CMPI_RC_ERR_FAILED, "dbus_discover_call() failed"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + +#ifdef RDCP_DEBUG + print_paths(paths, "%s: target=%s, paths:", __FUNCTION__, Target->chars); +#endif + + for (pp = paths, path = *pp++, n_paths = 0; path; path = *pp++, n_paths++); + + if (!KRefA_Init(DiscoveredRealms, cb, n_paths)) { + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + for (pp = paths, path = *pp++, i = 0; path; path = *pp++, i++) { + LMI_RealmdRealmRef realmdrealm_ref; + CMPIObjectPath *realmdrealm_op; + + + *status = LMI_RealmdRealmRef_InitFromDBusPath(&realmdrealm_ref, cb, + LMI_RealmdServiceRef_NameSpace((LMI_RealmdServiceRef*)self), path); + if (status->rc != CMPI_RC_OK) { + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if ((realmdrealm_op = LMI_RealmdRealmRef_ToObjectPath(&realmdrealm_ref, status)) == NULL) { + goto exit; + } + if (!KRefA_Set(DiscoveredRealms, i, realmdrealm_op)) { + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + } + + exit: + + G_VARIANT_FREE(options); + g_strfreev(paths); + + return result; +} + +// FIXME +static gboolean +get_credential_supported_owner(GVariant *supported, const gchar *cred_type, const gchar **cred_owner_return) +{ + GVariantIter iter; + const gchar *type; + const gchar *owner; + + g_variant_iter_init (&iter, supported); + while (g_variant_iter_loop (&iter, "(&s&s)", &type, &owner)) { + if (g_str_equal (cred_type, type)) { + *cred_owner_return = owner; + return TRUE; + } + } + + return FALSE; +} + +static gboolean +is_credential_supported (GVariant *supported, const gchar *cred_type, const gchar *cred_owner) +{ + GVariantIter iter; + const gchar *type; + const gchar *owner; + + g_variant_iter_init(&iter, supported); + while (g_variant_iter_loop (&iter, "(&s&s)", &type, &owner)) { + if (g_str_equal(cred_type, type) && + g_str_equal(cred_owner, owner)) { + return TRUE; + } + } + + return FALSE; +} + +KUint32 LMI_RealmdService_Join_Leave_Domain( + bool join, + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_RealmdServiceRef* self, + const KString* Domain, + const KString* User, + const KString* Password, + const KStringA* OptionNames, + const KStringA* OptionValues, + CMPIStatus* status) +{ + const gchar *method_name = NULL; + const gchar *supported_credentials_property = NULL; + GError *g_error = NULL; + KUint32 result = KUINT32_INIT; + gint32 relevance = 0; + gchar **paths = NULL; + gchar *dbus_path, **pp; + CMPICount n_paths; + const gchar *cred_type = NULL; + const gchar *cred_owner = NULL; + GVariant *supported_creds = NULL; + GVariant *realm_props = NULL; + GVariant *kerberos_membership_props = NULL; + GVariant *credentials = NULL; + GVariant *options = NULL; + + KUint32_Set(&result, LMI_REALMD_RESULT_SUCCESS); + CMSetStatus(status, CMPI_RC_OK); + + /* Assure we can communicate with DBus */ + if (!rdcp_dbus_initialize(&g_error)) { + handle_g_error(&g_error, _cb, status, CMPI_RC_ERR_FAILED, "rdcp_dbus_initialize failed"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if (join) { + method_name = "Join"; + supported_credentials_property = "SupportedJoinCredentials"; + } else { + method_name = "Leave"; + supported_credentials_property = "SupportedLeaveCredentials"; + } + + /* Call Discover to obtain list of DBus object paths for domain */ + if (!build_g_variant_options_from_KStringA(OptionNames, OptionValues, &options, &g_error)) { + handle_g_error(&g_error, _cb, status, CMPI_RC_ERR_FAILED, + "failed to convert options to gvariant"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if (!dbus_discover_call(system_bus, Domain->chars, options, + &relevance, &paths, &g_error)) { + handle_g_error(&g_error, _cb, status, CMPI_RC_ERR_FAILED, "dbus_discover_call() failed"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + +#ifdef RDCP_DEBUG + print_paths(paths, "%s: target=%s, paths:", __FUNCTION__, Domain->chars); +#endif + + for (pp = paths, dbus_path = *pp++, n_paths = 0; dbus_path; dbus_path = *pp++, n_paths++); + + if (n_paths < 1) { + SetCMPIStatus(cb, status, CMPI_RC_ERR_FAILED, "Domain (%s) does not exist", Domain->chars); + KUint32_Set(&result, LMI_REALMD_RESULT_NO_SUCH_DOMAIN); + goto exit; + } + + dbus_path = paths[0]; + + /* Lookup the realm properties so we can determine the supported DBus interfaces */ + GET_DBUS_PROPERIES_OR_EXIT(realm_props, dbus_path, + REALM_DBUS_REALM_INTERFACE, status); + if (!SupportsDBusInterface(realm_props, REALM_DBUS_KERBEROS_MEMBERSHIP_INTERFACE)) { + SetCMPIStatus(cb, status, CMPI_RC_ERR_FAILED, "Domain (%s) does not support joining or leaving", + Domain->chars); + KUint32_Set(&result, LMI_REALMD_RESULT_DOMAIN_DOES_NOT_SUPPORT_JOINING); + goto exit; + } + + GET_DBUS_PROPERIES_OR_EXIT(kerberos_membership_props, dbus_path, + REALM_DBUS_KERBEROS_MEMBERSHIP_INTERFACE, status); + + if (!g_variant_lookup(kerberos_membership_props, supported_credentials_property, "@a(ss)", + &supported_creds)) { + SetCMPIStatus(cb, status, CMPI_RC_ERR_FAILED, + "Domain (%s) did not supply supported %s credentials", + Domain->chars, method_name); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + + if (!User->exists || User->null) { + /* No User */ + if (!Password->exists || Password->null) { + /* No User, No Password: automatic */ + cred_type = "automatic"; + if (!get_credential_supported_owner(supported_creds, cred_type, &cred_owner)) { + SetCMPIStatus(cb, status, CMPI_RC_ERR_FAILED, + "Domain (%s) does not support automatic %s credentials", + Domain->chars, method_name); + KUint32_Set(&result, LMI_REALMD_RESULT_DOMAIN_DOES_NOT_SUPPORT_PROVIDED_CREDENTIALS); + goto exit; + } + + credentials = g_variant_new ("(ssv)", cred_type, cred_owner, + g_variant_new_string ("")); + + } else { + /* No User, Password: one time password using secret */ + cred_type = "secret"; + if (!get_credential_supported_owner(supported_creds, cred_type, &cred_owner)) { + SetCMPIStatus(cb, status, CMPI_RC_ERR_FAILED, + "Domain (%s) does not support secret %s credentials", + Domain->chars, method_name); + KUint32_Set(&result, LMI_REALMD_RESULT_DOMAIN_DOES_NOT_SUPPORT_PROVIDED_CREDENTIALS); + goto exit; + } + credentials = g_variant_new("(ssv)", cred_type, cred_owner, + g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + Password->chars, + strlen(Password->chars), 1)); + } + } else { + /* User */ + if (!Password->exists || Password->null) { + /* User, No Password: invalid combination */ + SetCMPIStatus(cb, status, CMPI_RC_ERR_INVALID_PARAMETER, + "Must provide a password when User is provided"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } else { + /* User, Password: password auth */ + cred_type = "password"; + cred_owner = "administrator"; + if (!is_credential_supported(supported_creds, cred_type, cred_owner)) { + SetCMPIStatus(cb, status, CMPI_RC_ERR_FAILED, + "Domain (%s) does not support password with administrator ownership credentials", + Domain->chars); + KUint32_Set(&result, LMI_REALMD_RESULT_DOMAIN_DOES_NOT_SUPPORT_PROVIDED_CREDENTIALS); + goto exit; + } + credentials = g_variant_new("(ssv)", cred_type, cred_owner, + g_variant_new("(ss)", User->chars, Password->chars)); + + } + } + + if (join) { + if (!dbus_join_call(system_bus, dbus_path, credentials, options, &g_error)) { + handle_g_error(&g_error, cb, status, CMPI_RC_ERR_FAILED, "dbus_join_call() failed"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + } else { + if (!dbus_leave_call(system_bus, dbus_path, credentials, options, &g_error)) { + handle_g_error(&g_error, cb, status, CMPI_RC_ERR_FAILED, "dbus_leave_call() failed"); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); + goto exit; + } + } + + + exit: + + G_VARIANT_FREE(supported_creds); + G_VARIANT_FREE(realm_props); + G_VARIANT_FREE(kerberos_membership_props); + G_VARIANT_FREE(credentials); + G_VARIANT_FREE(options); + g_strfreev(paths); + + return result; +} +KEXTERN KUint32 LMI_RealmdService_JoinDomain( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_RealmdServiceRef* self, + const KString* Domain, + const KString* User, + const KString* Password, + const KStringA* OptionNames, + const KStringA* OptionValues, + CMPIStatus* status) +{ + return LMI_RealmdService_Join_Leave_Domain(true, cb, mi, context, self, + Domain, User, Password, + OptionNames, OptionValues, + status); +} + +KEXTERN KUint32 LMI_RealmdService_LeaveDomain( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_RealmdServiceRef* self, + const KString* Domain, + const KString* User, + const KString* Password, + const KStringA* OptionNames, + const KStringA* OptionValues, + CMPIStatus* status) +{ + return LMI_RealmdService_Join_Leave_Domain(false, cb, mi, context, self, + Domain, User, Password, + OptionNames, OptionValues, + status); +} + +KONKRET_REGISTRATION( + "root/cimv2", + "LMI_RealmdService", + "LMI_RealmdService", + "instance method"); diff --git a/src/realmd/LMI_ServiceAffectsRealmdRealmProvider.c b/src/realmd/LMI_ServiceAffectsRealmdRealmProvider.c new file mode 100644 index 0000000..70d65f4 --- /dev/null +++ b/src/realmd/LMI_ServiceAffectsRealmdRealmProvider.c @@ -0,0 +1,252 @@ +#include +#include "LMI_ServiceAffectsRealmdRealm.h" +#include "rdcp_util.h" +#include "globals.h" +#include "rdcp_error.h" +#include "rdcp_dbus.h" +#include "rdcp_util.h" +#include "rdcp_realmdrealm.h" + +static const CMPIBroker* _cb; + +static void LMI_ServiceAffectsRealmdRealmInitialize() +{ +} + +static CMPIStatus LMI_ServiceAffectsRealmdRealmCleanup( + CMPIInstanceMI* mi, + const CMPIContext* cc, + CMPIBoolean term) +{ + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_ServiceAffectsRealmdRealmEnumInstanceNames( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop) +{ + return KDefaultEnumerateInstanceNames( + _cb, mi, cc, cr, cop); +} + +static CMPIStatus LMI_ServiceAffectsRealmdRealmEnumInstances( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char** properties) +{ + CMPIStatus status; + GError *g_error = NULL; + GVariant *provider_props = NULL; + GVariantIter *iter = NULL; + gchar *realm_obj_path; + LMI_RealmdServiceRef realmd_service_ref; + LMI_ServiceAffectsRealmdRealm service_affects; + const char *name_space = KNameSpace(cop); + const char *host_name = get_system_name(); + + CMSetStatus(&status, CMPI_RC_OK); + + LMI_InitRealmdServiceKeys(LMI_RealmdServiceRef, &realmd_service_ref, name_space, host_name); + + if (!rdcp_dbus_initialize(&g_error)) { + return handle_g_error(&g_error, _cb, &status, CMPI_RC_ERR_FAILED, "rdcp_dbus_initialize failed"); + } + + GET_DBUS_PROPERIES_OR_EXIT(provider_props, REALM_DBUS_SERVICE_PATH, + REALM_DBUS_PROVIDER_INTERFACE, &status); + + g_variant_lookup(provider_props, "Realms", "ao", &iter); + while (g_variant_iter_next(iter, "&o", &realm_obj_path)) { + LMI_RealmdRealmRef realmd_realm_ref; + + status = LMI_RealmdRealmRef_InitFromDBusPath(&realmd_realm_ref, _cb, name_space, realm_obj_path); + if (status.rc != CMPI_RC_OK) { + goto exit; + } + + LMI_ServiceAffectsRealmdRealm_Init(&service_affects, _cb, name_space); + LMI_ServiceAffectsRealmdRealm_Set_AffectedElement(&service_affects, &realmd_realm_ref); + LMI_ServiceAffectsRealmdRealm_Set_AffectingElement(&service_affects, &realmd_service_ref); + LMI_ServiceAffectsRealmdRealm_Init_ElementEffects(&service_affects, 1); + LMI_ServiceAffectsRealmdRealm_Set_ElementEffects(&service_affects, 0, + LMI_ServiceAffectsRealmdRealm_ElementEffects_Manages); + + KReturnInstance(cr, service_affects); + } + + exit: + G_VARIANT_ITER_FREE(iter); + G_VARIANT_FREE(provider_props); + + return status; +} + +static CMPIStatus LMI_ServiceAffectsRealmdRealmGetInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char** properties) +{ + return KDefaultGetInstance( + _cb, mi, cc, cr, cop, properties); +} + +static CMPIStatus LMI_ServiceAffectsRealmdRealmCreateInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const CMPIInstance* ci) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_ServiceAffectsRealmdRealmModifyInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const CMPIInstance* ci, + const char**properties) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_ServiceAffectsRealmdRealmDeleteInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_ServiceAffectsRealmdRealmExecQuery( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* lang, + const char* query) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_ServiceAffectsRealmdRealmAssociationCleanup( + CMPIAssociationMI* mi, + const CMPIContext* cc, + CMPIBoolean term) +{ + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_ServiceAffectsRealmdRealmAssociators( + CMPIAssociationMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* assocClass, + const char* resultClass, + const char* role, + const char* resultRole, + const char** properties) +{ + return KDefaultAssociators( + _cb, + mi, + cc, + cr, + cop, + LMI_ServiceAffectsRealmdRealm_ClassName, + assocClass, + resultClass, + role, + resultRole, + properties); +} + +static CMPIStatus LMI_ServiceAffectsRealmdRealmAssociatorNames( + CMPIAssociationMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* assocClass, + const char* resultClass, + const char* role, + const char* resultRole) +{ + return KDefaultAssociatorNames( + _cb, + mi, + cc, + cr, + cop, + LMI_ServiceAffectsRealmdRealm_ClassName, + assocClass, + resultClass, + role, + resultRole); +} + +static CMPIStatus LMI_ServiceAffectsRealmdRealmReferences( + CMPIAssociationMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* assocClass, + const char* role, + const char** properties) +{ + return KDefaultReferences( + _cb, + mi, + cc, + cr, + cop, + LMI_ServiceAffectsRealmdRealm_ClassName, + assocClass, + role, + properties); +} + +static CMPIStatus LMI_ServiceAffectsRealmdRealmReferenceNames( + CMPIAssociationMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* assocClass, + const char* role) +{ + return KDefaultReferenceNames( + _cb, + mi, + cc, + cr, + cop, + LMI_ServiceAffectsRealmdRealm_ClassName, + assocClass, + role); +} + +CMInstanceMIStub( + LMI_ServiceAffectsRealmdRealm, + LMI_ServiceAffectsRealmdRealm, + _cb, + LMI_ServiceAffectsRealmdRealmInitialize()) + +CMAssociationMIStub( + LMI_ServiceAffectsRealmdRealm, + LMI_ServiceAffectsRealmdRealm, + _cb, + LMI_ServiceAffectsRealmdRealmInitialize()) + +KONKRET_REGISTRATION( + "root/cimv2", + "LMI_ServiceAffectsRealmdRealm", + "LMI_ServiceAffectsRealmdRealm", + "instance association"); diff --git a/src/realmd/README b/src/realmd/README new file mode 100644 index 0000000..dec6866 --- /dev/null +++ b/src/realmd/README @@ -0,0 +1,221 @@ +Realmd CIM Provider + +Building +======== + +Prerequisites: +-------------- + +To build you'll need these packages installed: + +cmake +openlmi-providers-devel +konkretcmpi + + +To install and run you'll need at a minimum: +-------------------------------------------- + +tog-pegasus +openlmi-providers + + +This project uses the same build mechanism as openlmi-provider which +is based on cmake. It's also important specify the same cmake +configuration parameters enforced by RPM. + +My short term solution is to use the following shell script. I add the +CFLAGS override to turn on options useful for debugging during +development, you may wish to omit that. + +<<<<<<<<<< +#!/bin/sh + +export CFLAGS='-g -O0 -DRDCP_DEBUG' + +/usr/bin/cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_INSTALL_PREFIX:PATH=/usr -DINCLUDE_INSTALL_DIR:PATH=/usr/include -DLIB_INSTALL_DIR:PATH=/usr/lib -DSYSCONF_INSTALL_DIR:PATH=/etc -DSHARE_INSTALL_PREFIX:PATH=/usr/share -DBUILD_SHARED_LIBS:BOOL=ON . + +if [ $? -eq 0 ]; then + make +fi +>>>>>>>>>> + +Installing: +----------- + +% sudo make install + +This copies the mof file, the registration file and the loadable +module to their destination. Then you must register your module with +the Pegasus CIMOM. Note: pegasus MUST be running! + +% openlmi-mof-register register /usr/share/openlmi-providers/LMI_Realmd.mof /usr/share/openlmi-providers/LMI_Realmd.reg + +Development Tips: +----------------- + +Understanding konkret code generation issues: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +konkret is a tool that reads in a mof file and generates C code. For +every XXX class it will generate a XXX.h and XXXProvider.c file. The +code generation occurs due to CMake macros provided by the +openlmi-providers-devel package. konkret needs to run any time you +modify the mof file. It *always* generates a new XXX.h file because +that's where definitions based on the contents of the mof file are +located. If there is no XXXProvider.c file it will also generate +it. This is a "stub" file in which you will fill in with your +implementation. If XXXProvider.c exits it will not overwrite it, +however it always overwrites the XXX.h file. + +Do not put anything into the XXX.h file you'll need to retain. + +After editing the mof file the make targets will cause konkret to run +again. You'll get brand new XXX.h files. But your old XXXProvider.c +files may no longer have the correct definitions (e.g. prototypes) +found in the XXX.h file so you may need to hand edit by copying the +function prototype from the XXX.h file into your XXXProvider.c file. + +If you've written definitions that logically belong in XXX.h but don't +want them nuked the next time konkret runs my solution was to put them +in someother .h file that's included by the XXXProvider.c file. + +Initializing class instances: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The way konkret works is to emit specialized inline functions to +initialize each member of a class. If the class is subclassed you get +different initializers depending on whether the property is in the +parent class or the subclass. You cannot call a parent class property +initializer in a subclass (yuck), you have to use the subclass +initializer for the property inherited from the parent class. This +creates a maintenance problem if the parent class changes, you have +find every place parent class properties are inialized and make +changes. To solve this problem I defined macros that initialize class +properties. The macro takes a "klass" parameter and token pastes it to +generate the class specific property manipulation function call. Using +these macros means anytime a class changes due to a change in the mof +file there is only one place where you need to change the code. These +macros are a good example of what logically belongs in the XXX.h file +but are separated out into a different .h file because konkret will +nuke anything you've added to a XXX.h file. + +Modifications to the provider: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +During development if the mof file changes you have to make Pegasus +reload the mof. It's not sufficient to retart cimserver, you have to +unregister the provider and register it again for Pegasus to see the +mof changes. Thus you would use the openlmi-mof-register command above +except pass the unregister option, followed by the above command, e.g. + +% openlmi-mof-register unregister /usr/share/openlmi-providers/LMI_Realmd.mof /usr/share/openlmi-providers/LMI_Realmd.reg +% openlmi-mof-register register /usr/share/openlmi-providers/LMI_Realmd.mof /usr/share/openlmi-providers/LMI_Realmd.reg + +If all you've done during devopment is modify the provider (not it's +mof definition) then all you need to do is: + +% sudo cimserver -s +% sudo make install +% sudo cimserver + +How do I run the Pegasus CIMOM so I can see debug statements? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +% sudo cimserver daemon=false forceProviderProcesses=false + +How do I use GDB to debug my provider? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create the following .gdbinit file where XXX is where you want to break. + +<<<<<<<<<< +set breakpoint pending on +b XXX +r daemon=false forceProviderProcesses=false +>>>>>>>>>> + +then run gdb like this: + +% sudo gdb cimserver + +How do I trace what Pegasus is doing? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +% cimserver daemon=false forceProviderProcesses=false logLevel=TRACE traceLevel=5 traceFacility=File traceComponents=All + +The trace file is written to: + +/var/lib/Pegasus/cache/trace/cimserver.trc + +More information about cimserver tracing can be found in the +"OpenPegasus Tracing User Guide" PDF. Google the title to get a +current URL. + +FAQ +=== + +Q: What does the rdcp acronym stand for? + +A: Realmd CIM Provider. The "rd" is for Realmd, the "c" is for CIM and + the "p" is for Provider + +Q: What decisions influenced your DBus implementation strategy? + +A: There are essentially two supported DBus API's. A very high level + GDBus and a very low level libdbus. + + GDBus requires you to utilize Gnome's GObject pseudo + object-orientated framework. If you're not familar with it it's a + fairly steep learning curve to become proficient. Also if you're + not proficient in GObject programming it's hard to comprehend code + which utilizes it thus putting normal C developers at a + disadvantage. However GDBus gives you a lot of nice support, one of + the nice features is everything is based on GVariants, a powerful + data structure. + + On the other hand libdbus is very low level, there is very little + support for the necessary DBus operations. However it is used + extensively by other projects so it's not an aberration to use it, + it's pure C code making it easier to understand and it doesn't pull + in the whole GObject system. But it's a lot of work to use. + + I took a compromise approach. I didn't have the time to become + proficient with GObject and I felt the GObject based code was + difficult for C programmers without GObject experience to read + and modify. However I recognized the value of expressing most + things in terms of GVariants, a hallmark of GDBus. So I wrote some + utility code that supports serializing GVariants into and out of + libdbus. This allowed me to use the powerful GVariant without + having to get involved with GObjects and GDBus. If we ever decide + to port the code to GDBus it shold be fairly straight forward + because we're already using GVariant's as a fundamental type. This + seemed to represent a reasonable compromise between libdus and + GDBus, it avoids the pseudo object-orientated framework of GObject + in favor of vanilla C code but retains the powerful use of + GVariants. I guess only time will tell if it was a smart choice or + not. + +ToDo +==== + +Implement locale in RealmdService. + +Utilize CMPI Logging instead of debug printf statements (currently +controlled by the RDCP_DEBUG compile time flag). + +Generate indications when realms are added or removed from the Realms +property of the LMI_RealmdService. + +Any blocking operations should not block the CIMOM. +(e.g. communicating with DBus). I think the right way to do this is +via the CMPI threading support, but this needs further +investigation. Other openlmi developers would be a good resource for +this issue. + +We call DBus to get object properties a lot. There is I believe +support for DBus clients which caches object properties and listens on +the properties change signal to refresh the properties cache. Access +to the properties are then performed via the local properties cache +rather than the via RPC. Obviously this is much more efficient, we +should support it. diff --git a/src/realmd/VERSION b/src/realmd/VERSION new file mode 100644 index 0000000..8acdd82 --- /dev/null +++ b/src/realmd/VERSION @@ -0,0 +1 @@ +0.0.1 diff --git a/src/realmd/doc/class_diagram.svg b/src/realmd/doc/class_diagram.svg new file mode 100644 index 0000000..1b962d3 --- /dev/null +++ b/src/realmd/doc/class_diagram.svg @@ -0,0 +1,273 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + ComputerSystem + + + + + + + + + RealmdService + + + HostedService + + + + + + + + RealmdRealm + + + + + + + + + RealmdKerberosRealm + + ServiceAffectsElement + + + + diff --git a/src/realmd/doc/examples/realmd-cim b/src/realmd/doc/examples/realmd-cim new file mode 100644 index 0000000..90ae9d5 --- /dev/null +++ b/src/realmd/doc/examples/realmd-cim @@ -0,0 +1,245 @@ +#!/usr/bin/python + +import sys +import os +import optparse +import urlparse +import pywbem + +#---------------------------------------------------------------------- + +def do_list(conn, options, args): + realms = conn.EnumerateInstances('LMI_RealmdKerberosRealm') + + print "%d realms" % (len(realms)) + + for realm in realms: + if options.verbose > 1: + # Very verbose, dump all properties + property_names = sorted(realm.keys()) + for name in property_names: + value = realm[name] + print " %s: %s" % (name, value) + + print realm['RealmName'] + print " type: kerberos" + print " realm-name: %s" % realm['RealmName'] + print " domain-name: %s" % realm['DomainName'] + + is_configured = True + configured = realm['Configured'] + if not configured: + configured = "no" + is_configured = False + elif configured == "KerberosMembership": + configured = "kerberos-member" + + print " configured: %s" % configured + + for detail in zip(realm['DetailNames'], realm['DetailValues']): + print " %s: %s" % (detail[0], detail[1]) + + if is_configured: + print " login-formats: %s" % ", ".join(realm['LoginFormats']) + print " login-policy: %s" % realm['LoginPolicy'] + print " permitted-logins: %s" % ", ".join(realm['PermittedLogins']) + + print + +def do_join(conn, options, args): + # Validate arguments + if len(args) != 3: + raise ValueError("You must supply exacly 3 arguments (user, password, domain)") + + user, password, domain = args + + if (options.verbose): + print "Joining domain: %s" % domain + + try: + realmd_service_instance_name = conn.EnumerateInstanceNames('LMI_RealmdService')[0] + except Exception, e: + raise ValueError("could not obtain realmd service") + + try: + retval, outparams = conn.InvokeMethod("JoinDomain", realmd_service_instance_name, + Domain=domain, + User=user, + Password=password) + except Exception, e: + raise ValueError("Join failed (%s)" % (e)) + + + +def do_leave(conn, options, args): + # Validate arguments + if len(args) != 3: + raise ValueError("You must supply exacly 3 arguments (user, password, domain)") + + user, password, domain = args + + if (options.verbose): + print "Leave domain: %s" % domain + + try: + realmd_service_instance_name = conn.EnumerateInstanceNames('LMI_RealmdService')[0] + except Exception, e: + raise ValueError("could not obtain realmd service") + + try: + retval, outparams = conn.InvokeMethod("LeaveDomain", realmd_service_instance_name, + Domain=domain, + User=user, + Password=password) + except Exception, e: + raise ValueError("Leave failed (%s)" % (e)) + + + +def do_discover(conn, options, args): + # Validate arguments + if len(args) != 1: + raise ValueError("You must supply exactly 1 domain.") + + domain = args[0] + + if (options.verbose): + print "Discovering domain: %s" % domain + + try: + realmd_service_instance_name = conn.EnumerateInstanceNames('LMI_RealmdService')[0] + except Exception, e: + raise ValueError("could not obtain realmd service") + + try: + retval, outparams = conn.InvokeMethod("Discover", realmd_service_instance_name, + Target=domain) + except Exception, e: + raise ValueError("Join failed (%s)" % (e)) + + realm_refs = outparams['DiscoveredRealms'] + + print "%d Discovered" % len(realm_refs) + for realm_ref in realm_refs: + #print realm_ref + realm = conn.GetInstance(realm_ref) + print realm['RealmName'] + print " Name: %s" % realm['RealmName'] + print " Configured: %s" % realm['Configured'] + print " Supported Interfaces: %s" % ", ".join(realm['SupportedInterfaces']) + for detail in zip(realm['DetailNames'], realm['DetailValues']): + print " %s: %s" % (detail[0], detail[1]) + print " login-formats: %s" % ", ".join(realm['LoginFormats']) + print " login-policy: %s" % realm['LoginPolicy'] + print " permitted-logins: %s" % ", ".join(realm['PermittedLogins']) + + + +#---------------------------------------------------------------------- + +def main(): + + actions = {'list': do_list, + 'discover': do_discover, + 'join': do_join, + 'leave': do_leave, + } + + usage =''' + %%prog [options] ... + + %%prog [options] list + %%prog [options] discover domain + %%prog [options] join user password domain + %%prog [options] leave user password domain + + Available Actions: %(actions)s + ''' % {'actions': ", ".join(sorted(actions.keys()))} + + # Set-up defaults + + default_cimom_port = 5989 + default_url = os.environ.get("LMI_CIMOM_URL", "https://localhost:5989") + + parsed_default_url = urlparse.urlparse(default_url) + + if parsed_default_url.port: + default_port = parsed_default_url.port or default_cimom_port + + default_username = os.environ.get("LMI_CIMOM_USERNAME", "root") + default_password = os.environ.get("LMI_CIMOM_PASSWORD", "") + + # Set-up arg parser + parser = optparse.OptionParser(usage=usage) + + parser.add_option('-c', '--url', dest='url', default=default_url, + help='CIMOM URL or hostname to connect to') + + parser.add_option('-u', '--username', dest='username', default=default_username, + help='Username for CIMOM authentication') + + parser.add_option('-p', '--password', dest='password', default=default_password, + help='Password for CIMOM authentication') + + parser.add_option('-v', '--verbose', dest='verbose', default=0, + action='count', + help='Turn on verbose output, increases verbosity level by one each time specified') + + options, args = parser.parse_args() + + # Validate arguments + + try: + action = args.pop(0) + except IndexError: + print >>sys.stderr, "You must supply an action to execute" + parser.print_help() + return 1 + + try: + action_func = actions[action] + except KeyError: + print >>sys.stderr, "Unknown action (%s)" % (action) + parser.print_help() + return 1 + + # Get CIMOM URL + + parsed_url = urlparse.urlparse(options.url) + + if not parsed_url.netloc: + # Handle case where URL was bare hostname + parsed_url = urlparse.urlparse('//' + options.url) + + scheme = 'https' + hostname = parsed_url.hostname + port = parsed_url.port or default_port + + url = urlparse.urlunparse((scheme, "%s:%d" % (hostname, port), '', None, None, None)) + + # Connect to CIMOM + + if (options.verbose): + print "Connecting to: %s" % url + + try: + conn = pywbem.WBEMConnection(url, (options.username, options.password)) + except Exception, e: + print >>sys.stderr, "Unable to connect to %s (%s)" % (options.url, e) + return 1 + + + # Execute action + + try: + action_func(conn, options, args) + except Exception, e: + print >>sys.stderr, "%s failed: %s" % (action, e) + return 1 + + return 0 + +#---------------------------------------------------------------------- + +if __name__ == "__main__": + sys.exit(main()) diff --git a/src/realmd/rdcp_dbus.c b/src/realmd/rdcp_dbus.c new file mode 100644 index 0000000..b05e5c9 --- /dev/null +++ b/src/realmd/rdcp_dbus.c @@ -0,0 +1,2050 @@ +#include + +#include "rdcp_error.h" +#include "realm-dbus-constants.h" + +#include "rdcp_dbus.h" +#include "rdcp_util.h" + +/*----------------------------------------------------------------------------*/ + +DBusConnection* system_bus = NULL; + +/*----------------------------------------------------------------------------*/ +#ifdef TRACE_VARIANT +static const char * +dbus_type_to_string(int type); +#endif + +static GError * +dbus_error_to_gerror(DBusError *dbus_error); + +static const char* +dbus_msg_type_to_string (int message_type); + +static void +dbus_message_print_indent(GString *string, int depth); + +static void +dbus_message_print_hex(GString *string, unsigned char *bytes, unsigned int len, int depth); + +static void +dbus_message_print_byte_array(GString *string, DBusMessageIter *iter, int depth); + +static void +dbus_message_print_iter(GString *string, DBusMessageIter *iter, int depth); + +static GString * +dbus_message_print_string(DBusMessage *message, GString *string, dbus_bool_t show_header); + +static gchar * +dbus_message_print(DBusMessage *message, GString *string, dbus_bool_t show_header); + +static gboolean +append_g_variant_to_dbus_msg_iter(DBusMessageIter *iter, GVariant *value, GError **g_error); + +static gboolean +append_g_variant_to_dbus_message(DBusMessage *message, GVariant *g_variant, GError **g_error); + +static gboolean +dbus_method_append_args_tuple(DBusMessage *message, GVariant *args, GError **g_error); + +static gboolean +marshal_dbus_string_variant(DBusMessageIter *iter, const char *value, GError **g_error); + +static gboolean +marshal_dbus_dict_string_entry(DBusMessageIter *array, const char *name, const char *value, GError **g_error); + +static gboolean +dbus_iter_to_variant(DBusMessageIter *iter, GVariant **g_variant_return, GError **g_error); + +static gboolean +dbus_message_to_g_variant(DBusMessage *msg, GVariant **g_variant_return, GError **g_error); + +static gboolean +dbus_method_reply_to_g_variant_tuple(DBusMessage *msg, GVariant **g_variant_return, GError **g_error); + +gboolean +get_dbus_string_property(DBusConnection *bus, const char *object_path, + const char* interface, const char *property, + char **value_return, GError **g_error); +gboolean +get_dbus_properties(DBusConnection *bus, const char *object_path, + const char* interface, GVariant **properties_return, + GError **g_error); + +static gboolean +dbus_discover_marshal(const char* target, GVariant *options, + DBusMessage **msg_return, GError **g_error); + +static gboolean +dbus_discover_unmarshal(DBusMessage *reply, gint32 *relevance_return, gchar ***paths_return, GError **g_error); + +/*----------------------------------------------------------------------------*/ + +#define RETURN_DBUS_ERROR(gerror, dbus_error) \ +{ \ + if (gerror) { \ + *gerror = dbus_error_to_gerror(&dbus_error); \ + } \ + dbus_error_free(&dbus_error); \ + return FALSE; \ +} + +GError * +dbus_error_to_gerror(DBusError *dbus_error) +{ + GError *gerror = NULL; + + if (dbus_error == NULL) { + g_set_error(&gerror, RDCP_ERROR, RDCP_ERROR_DBUS, + "dbus error not provided"); + } else { + g_set_error(&gerror, RDCP_ERROR, RDCP_ERROR_DBUS, + "dbus error (%s): %s", dbus_error->name, dbus_error->message); + } + + return gerror; +} + +/*----------------------------------------------------------------------------*/ + +/* + * The code to print a DBus message is based upon DBUS code in + * dbus/tools/dbus-print-message.c which is GPL. + */ + +static const char* +dbus_msg_type_to_string (int message_type) +{ + switch (message_type) + { + case DBUS_MESSAGE_TYPE_SIGNAL: + return "signal"; + case DBUS_MESSAGE_TYPE_METHOD_CALL: + return "method call"; + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + return "method return"; + case DBUS_MESSAGE_TYPE_ERROR: + return "error"; + default: + return "(unknown message type)"; + } +} + +#define INDENT_STRING " " +#define INDENT_WIDTH sizeof(INDENT_STRING) +#define PAGE_WIDTH 80 + +static void +dbus_message_print_indent(GString *string, int depth) +{ + while (depth-- > 0) + g_string_append(string, INDENT_STRING); +} + +static void +dbus_message_print_hex(GString *string, unsigned char *bytes, unsigned int len, int depth) +{ + unsigned int i, columns; + + g_string_append_printf(string, "array of bytes [\n"); + + dbus_message_print_indent (string, depth + 1); + + /* Each byte takes 3 cells (two hexits, and a space), except the last one. */ + columns = (PAGE_WIDTH - ((depth + 1) * INDENT_WIDTH)) / 3; + + if (columns < 8) + columns = 8; + + i = 0; + + while (i < len) { + g_string_append_printf(string, "%02x", bytes[i]); + i++; + + if (i != len) { + if (i % columns == 0) { + g_string_append(string, "\n"); + dbus_message_print_indent(string, depth + 1); + } else { + g_string_append(string, " "); + } + } + } + + g_string_append(string, "\n"); + dbus_message_print_indent(string, depth); + g_string_append(string, "]\n"); +} + +#define DEFAULT_SIZE 100 + +static void +dbus_message_print_byte_array(GString *string, DBusMessageIter *iter, int depth) +{ + unsigned char *bytes = malloc (DEFAULT_SIZE + 1); + unsigned int len = 0; + unsigned int max = DEFAULT_SIZE; + dbus_bool_t all_ascii = TRUE; + int current_type; + + while ((current_type = dbus_message_iter_get_arg_type (iter)) != DBUS_TYPE_INVALID) { + unsigned char val; + + dbus_message_iter_get_basic (iter, &val); + bytes[len] = val; + len++; + + if (val < 32 || val > 126) + all_ascii = FALSE; + + if (len == max) { + max *= 2; + bytes = realloc(bytes, max + 1); + } + + dbus_message_iter_next (iter); + } + + if (all_ascii) { + bytes[len] = '\0'; + g_string_append_printf(string, "array of bytes \"%s\"\n", bytes); + } else { + dbus_message_print_hex(string, bytes, len, depth); + } + + free (bytes); +} + +static void +dbus_message_print_iter(GString *string, DBusMessageIter *iter, int depth) +{ + int type; + + while ((type = dbus_message_iter_get_arg_type (iter)) != DBUS_TYPE_INVALID) { + + dbus_message_print_indent(string, depth); + + switch (type) { + case DBUS_TYPE_BOOLEAN: { + dbus_bool_t val; + dbus_message_iter_get_basic (iter, &val); + g_string_append_printf(string, "boolean %s\n", val ? "true" : "false"); + } break; + + case DBUS_TYPE_BYTE: { + unsigned char val; + dbus_message_iter_get_basic (iter, &val); + g_string_append_printf(string, "byte %d\n", val); + } break; + + case DBUS_TYPE_INT16: { + dbus_int16_t val; + dbus_message_iter_get_basic (iter, &val); + g_string_append_printf(string, "int16 %" G_GINT16_FORMAT "\n", val); + } break; + + case DBUS_TYPE_UINT16: { + dbus_uint16_t val; + dbus_message_iter_get_basic (iter, &val); + g_string_append_printf(string, "uint16 %" G_GUINT16_FORMAT "\n", val); + } break; + + case DBUS_TYPE_INT32: { + dbus_int32_t val; + dbus_message_iter_get_basic (iter, &val); + g_string_append_printf(string, "int32 %" G_GINT32_FORMAT "\n", val); + } break; + + case DBUS_TYPE_UINT32: { + dbus_uint32_t val; + dbus_message_iter_get_basic (iter, &val); + g_string_append_printf(string, "uint32 %" G_GUINT32_FORMAT "\n", val); + } break; + + case DBUS_TYPE_INT64: { + dbus_int64_t val; + dbus_message_iter_get_basic (iter, &val); + g_string_append_printf(string, "int64 %" G_GINT64_FORMAT "\n", val); + } break; + + case DBUS_TYPE_UINT64: { + dbus_uint64_t val; + dbus_message_iter_get_basic (iter, &val); + g_string_append_printf(string, "uint64 %" G_GUINT64_FORMAT "\n", val); + } break; + + case DBUS_TYPE_DOUBLE: { + double val; + dbus_message_iter_get_basic (iter, &val); + g_string_append_printf(string, "double %g\n", val); + } break; + + case DBUS_TYPE_STRING: { + char *val; + dbus_message_iter_get_basic (iter, &val); + g_string_append_printf(string, "string \"%s\"\n", val); + } break; + + case DBUS_TYPE_OBJECT_PATH: { + char *val; + dbus_message_iter_get_basic (iter, &val); + g_string_append_printf(string, "object path \"%s\"\n", val); + } break; + + case DBUS_TYPE_SIGNATURE: { + char *val; + dbus_message_iter_get_basic (iter, &val); + g_string_append_printf(string, "signature \"%s\"\n", val); + } break; + + case DBUS_TYPE_UNIX_FD: { + dbus_uint32_t val; + dbus_message_iter_get_basic (iter, &val); + g_string_append_printf(string, "Unix FD %" G_GUINT32_FORMAT "\n", val); + } break; + + case DBUS_TYPE_ARRAY: { + int current_type; + DBusMessageIter subiter; + + dbus_message_iter_recurse (iter, &subiter); + + current_type = dbus_message_iter_get_arg_type (&subiter); + + if (current_type == DBUS_TYPE_BYTE) { + dbus_message_print_byte_array(string, &subiter, depth); + break; + } + + g_string_append(string, "array [\n"); + while (current_type != DBUS_TYPE_INVALID) { + dbus_message_print_iter(string, &subiter, depth+1); + + dbus_message_iter_next (&subiter); + current_type = dbus_message_iter_get_arg_type (&subiter); + + if (current_type != DBUS_TYPE_INVALID) + g_string_append(string, ","); + } + dbus_message_print_indent(string, depth); + g_string_append(string, "]\n"); + } break; + + case DBUS_TYPE_VARIANT: { + DBusMessageIter subiter; + + dbus_message_iter_recurse (iter, &subiter); + + g_string_append(string, "variant "); + dbus_message_print_iter(string, &subiter, depth+1); + } break; + + case DBUS_TYPE_STRUCT: { + int current_type; + DBusMessageIter subiter; + + dbus_message_iter_recurse (iter, &subiter); + + g_string_append(string, "struct {\n"); + while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID) { + dbus_message_print_iter(string, &subiter, depth+1); + dbus_message_iter_next (&subiter); + if (dbus_message_iter_get_arg_type (&subiter) != DBUS_TYPE_INVALID) + g_string_append(string, ","); + } + dbus_message_print_indent(string, depth); + g_string_append(string, "}\n"); + } break; + + case DBUS_TYPE_DICT_ENTRY: { + DBusMessageIter subiter; + + dbus_message_iter_recurse (iter, &subiter); + + g_string_append(string, "dict entry(\n"); + dbus_message_print_iter(string, &subiter, depth+1); + dbus_message_iter_next (&subiter); + dbus_message_print_iter(string, &subiter, depth+1); + dbus_message_print_indent(string, depth); + g_string_append(string, ")\n"); + } break; + + default: + g_string_append_printf(string, " (unknown arg type '%c')\n", type); + break; + } + dbus_message_iter_next(iter); + } +} + +/** + * dbus_message_print_string: + * @message The DBusMessage to format into a string. + * @string If non-NULL appends to this GString. + * @show_header If #TRUE the message header will be included. + * + * Formats a DBusMessage into a string. + * + * Returns: A GString which must be freed with g_string_free() + */ +static GString * +dbus_message_print_string(DBusMessage *message, GString *string, dbus_bool_t show_header) +{ + DBusMessageIter iter; + const char *sender; + const char *destination; + int message_type; + + g_return_val_if_fail (message != NULL, NULL); + + if (string == NULL) { + string = g_string_new(NULL); + } + + message_type = dbus_message_get_type (message); + sender = dbus_message_get_sender (message); + destination = dbus_message_get_destination (message); + + if (show_header) { + g_string_append_printf(string, "%s sender=%s -> dest=%s", + dbus_msg_type_to_string (message_type), + sender ? sender : "(null sender)", + destination ? destination : "(null destination)"); + + switch (message_type) { + case DBUS_MESSAGE_TYPE_METHOD_CALL: + case DBUS_MESSAGE_TYPE_SIGNAL: + g_string_append_printf(string, " serial=%u path=%s; interface=%s; member=%s\n", + dbus_message_get_serial (message), + dbus_message_get_path (message), + dbus_message_get_interface (message), + dbus_message_get_member (message)); + break; + + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + g_string_append_printf(string, " reply_serial=%u\n", + dbus_message_get_reply_serial (message)); + break; + + case DBUS_MESSAGE_TYPE_ERROR: + g_string_append_printf(string, " error_name=%s reply_serial=%u\n", + dbus_message_get_error_name (message), + dbus_message_get_reply_serial (message)); + break; + + default: + g_string_append(string, "\n"); + break; + } + } + + dbus_message_iter_init(message, &iter); + dbus_message_print_iter(string, &iter, 1); + + return string; +} + +/** + * dbus_message_print_string: + * @message The DBusMessage to format into a string. + * @string If non-NULL appends to this GString. + * @show_header If #TRUE the message header will be included. + * + * Formats a DBusMessage into a string. + * + * Returns: A simple malloc'ed string which must be freed with g_free(). + */ +static gchar * +dbus_message_print(DBusMessage *message, GString *string, dbus_bool_t show_header) +{ + g_return_val_if_fail (message != NULL, NULL); + + return g_string_free(dbus_message_print_string(message, NULL, show_header), FALSE); +} + +/*----------------------------------------------------------------------------*/ + +/** + * append_g_variant_to_dbus_msg_iter: + * @g_error initialized to error info when FALSE is returned. + * + * Helper routine for append_g_variant_to_dbus_message(). + * Performs the recusive descent into the GVariant appending + * values to the DBusMessage as it goes. + * + * Returns: return TRUE if successful, FALSE if error with @g_error initialized. + */ +static gboolean +append_g_variant_to_dbus_msg_iter(DBusMessageIter *iter, GVariant *value, GError **g_error) +{ + GVariantClass class; + + g_return_val_if_fail (iter != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + class = g_variant_classify(value); + + switch (class) { + case G_VARIANT_CLASS_BOOLEAN: { + dbus_bool_t v = g_variant_get_boolean(value); + dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &v); + } break; + case G_VARIANT_CLASS_BYTE: { + guint8 v = g_variant_get_byte(value); + dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE, &v); + } break; + case G_VARIANT_CLASS_INT16: { + gint16 v = g_variant_get_int16 (value); + dbus_message_iter_append_basic(iter, DBUS_TYPE_INT16, &v); + } break; + case G_VARIANT_CLASS_UINT16: { + guint16 v = g_variant_get_uint16(value); + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &v); + } break; + case G_VARIANT_CLASS_INT32: { + gint32 v = g_variant_get_int32(value); + dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &v); + } break; + case G_VARIANT_CLASS_UINT32: { + guint32 v = g_variant_get_uint32(value); + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &v); + } break; + case G_VARIANT_CLASS_INT64: { + gint64 v = g_variant_get_int64(value); + dbus_message_iter_append_basic(iter, DBUS_TYPE_INT64, &v); + } break; + case G_VARIANT_CLASS_UINT64: { + guint64 v = g_variant_get_uint64(value); + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &v); + } break; + case G_VARIANT_CLASS_HANDLE: { + gint32 v = g_variant_get_handle(value); + dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &v); + } break; + case G_VARIANT_CLASS_DOUBLE: { + gdouble v = g_variant_get_double(value); + dbus_message_iter_append_basic(iter, DBUS_TYPE_DOUBLE, &v); + } break; + case G_VARIANT_CLASS_STRING: { + const gchar *v = g_variant_get_string(value, NULL); + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &v); + } break; + case G_VARIANT_CLASS_OBJECT_PATH: { + const gchar *v = g_variant_get_string(value, NULL); + dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &v); + } break; + case G_VARIANT_CLASS_SIGNATURE: { + const gchar *v = g_variant_get_string(value, NULL); + dbus_message_iter_append_basic(iter, DBUS_TYPE_SIGNATURE, &v); + } break; + case G_VARIANT_CLASS_VARIANT: { + DBusMessageIter sub; + GVariant *child; + + child = g_variant_get_child_value(value, 0); + dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + g_variant_get_type_string(child), + &sub); + if (!append_g_variant_to_dbus_msg_iter(&sub, child, g_error)) { + G_VARIANT_FREE(child); + goto fail; + } + dbus_message_iter_close_container(iter, &sub); + G_VARIANT_FREE(child); + } break; + case G_VARIANT_CLASS_MAYBE: { + GVariant *child; + + if (!g_variant_n_children(value)) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "cannot serialize an empty GVariant MAYBE"); + goto fail; + } else { + child = g_variant_get_child_value(value, 0); + if (!append_g_variant_to_dbus_msg_iter(iter, child, g_error)) { + G_VARIANT_FREE(child); + goto fail; + } + G_VARIANT_FREE(child); + } + } break; + case G_VARIANT_CLASS_ARRAY: { + DBusMessageIter dbus_iter; + const gchar *type_string; + gsize n, i; + GVariant *child; + + type_string = g_variant_get_type_string(value); + type_string++; /* skip the 'a' */ + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + type_string, &dbus_iter); + + n = g_variant_n_children(value); + + for (i = 0; i < n; i++) { + child = g_variant_get_child_value(value, i); + if (!append_g_variant_to_dbus_msg_iter(&dbus_iter, child, g_error)) { + G_VARIANT_FREE(child); + goto fail; + } + G_VARIANT_FREE(child); + } + + dbus_message_iter_close_container(iter, &dbus_iter); + } break; + case G_VARIANT_CLASS_TUPLE: { + DBusMessageIter dbus_iter; + gsize n, i; + GVariant *child; + + dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, + NULL, &dbus_iter); + + n = g_variant_n_children(value); + + for (i = 0; i < n; i++) { + child = g_variant_get_child_value(value, i); + if (!append_g_variant_to_dbus_msg_iter(&dbus_iter, child, g_error)) { + G_VARIANT_FREE(child); + goto fail; + } + G_VARIANT_FREE(child); + } + + dbus_message_iter_close_container(iter, &dbus_iter); + + } break; + case G_VARIANT_CLASS_DICT_ENTRY: { + DBusMessageIter dbus_iter; + GVariant *key, *val; + + dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, + NULL, &dbus_iter); + key = g_variant_get_child_value(value, 0); + if (!append_g_variant_to_dbus_msg_iter(&dbus_iter, key, g_error)) { + G_VARIANT_FREE(key); + goto fail; + } + G_VARIANT_FREE(key); + + val = g_variant_get_child_value(value, 1); + if (!append_g_variant_to_dbus_msg_iter(&dbus_iter, val, g_error)) { + G_VARIANT_FREE(val); + goto fail; + } + G_VARIANT_FREE(val); + + dbus_message_iter_close_container(iter, &dbus_iter); + } break; + default: { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "Error serializing GVariant with class '%c' to a D-Bus message", + class); + goto fail; + } break; + } + + return TRUE; + + fail: + return FALSE; +} + +/** + * append_g_variant_to_dbus_message: + * @message DBus message currently being built + * @g_variant The GVariant item to be appended to @message + * @g_error initialized to error info when FALSE is returned. + * + * Given a DBusMessage append the contents of the provied @g_variant to the message. + * + * Returns: return TRUE if successful, FALSE if error with @g_error initialized. + */ +static gboolean +append_g_variant_to_dbus_message(DBusMessage *message, GVariant *g_variant, GError **g_error) +{ + DBusMessageIter iter; + + g_return_val_if_fail (message != NULL, FALSE); + g_return_val_if_fail (g_variant != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + dbus_message_iter_init_append(message, &iter); + if (!append_g_variant_to_dbus_msg_iter(&iter, g_variant, g_error)) { + return FALSE; + } + return TRUE; +} + +/** + * dbus_method_append_args_tuple: + * @message DBus message currently being built + * @args A GVariant tuple containing the method parameters to + * be appended to @message + * @g_error initialized to error info when FALSE is returned. + * + * Append the method parameters to a DBus method message. @args + * is a GVariant tuple representing the parameter list. + * + * Returns: return TRUE if successful, FALSE if error with @g_error initialized. + */ +static gboolean +dbus_method_append_args_tuple(DBusMessage *message, GVariant *args, GError **g_error) +{ + DBusMessageIter iter; + gsize n, i; + GVariant *arg; + + g_return_val_if_fail (message != NULL, FALSE); + g_return_val_if_fail (args != NULL && g_variant_is_of_type(args, G_VARIANT_TYPE_TUPLE), FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + if ((n = g_variant_n_children(args))) { + + dbus_message_iter_init_append(message, &iter); + + for (i = 0; i < n; i++) { + arg = g_variant_get_child_value(args, i); + if (!append_g_variant_to_dbus_msg_iter(&iter, arg, g_error)) { + G_VARIANT_FREE(arg); + return FALSE; + } + G_VARIANT_FREE(arg); + } + } + + return TRUE; +} + +/** + * marshal_dbus_string_variant: + * @iter iterator into which the string variant will be inserted + * @value string value to insert as variant + * @g_error initialized to error info when FALSE is returned. + * + * Add a string variant while marshaling DBus protocol. + * + * Returns: return TRUE if successful, FALSE if error with @g_error initialized. + */ +static gboolean +marshal_dbus_string_variant(DBusMessageIter *iter, const char *value, GError **g_error) +{ + DBusMessageIter variant; + + g_return_val_if_fail (iter != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "s", &variant)) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "cannot open dbus variant string container, value=\"%s\"", value); + return FALSE; + } + + if (!dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING, &value)) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "cannot append dbus variant string value, value=\"%s\"", value); + return FALSE; + } + + if (!dbus_message_iter_close_container(iter, &variant)) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "cannot close dbus variant container, value=\"%s\"", value); + return FALSE; + } + + return TRUE; +} + +/** + * marshal_dbus_dict_string_entry: + * @array dictionary array into which entry is inserted + * @name entry's key + * @value entry's value + * @g_error initialized to error info when FALSE is returned. + * + * Adds a dictionary entry into an dictionary array whose key is a + * string and whose value is also a string while marshaling DBus protocol. + * + * Returns: return TRUE if successful, FALSE if error with @g_error initialized. + */ +static gboolean +marshal_dbus_dict_string_entry(DBusMessageIter *array, const char *name, const char *value, GError **g_error) +{ + DBusMessageIter entry; + + g_return_val_if_fail (array != NULL, FALSE); + g_return_val_if_fail (name != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + if (!dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL, &entry)) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "cannot open dbus dict entry container for option <%s=%s>", name, value); + return FALSE; + } + + if (!dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &name)) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "cannot append option name for option <%s=%s>", name, value); + return FALSE; + } + + if (!marshal_dbus_string_variant(&entry, value, g_error)) { + return FALSE; + } + + if (!dbus_message_iter_close_container(array, &entry)) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "cannot close dbus dict entry container for option <%s=%s>", name, value); + return FALSE; + } + + return TRUE; +} + + +/*----------------------------------------------------------------------------*/ + + +/** + * dbus_iter_to_variant: + * @msg DBusMessage which will be converted to a GVariant + * @g_variant_return Pointer to location where GVariant will be returned, + * will be NULL if error occurs + * @g_error initialized to error info when FALSE is returned. + * + * Helper routine for dbus_message_to_g_variant(), + * Performs the recusive descent into the DBusMessage appending + * values to the GVariant as it goes. + * + * Returns: return TRUE if successful, @g_variant_return will be non-NULL. + * FALSE if error with @g_error initialized, @g_variant_return will be NULL. + */ +static gboolean +dbus_iter_to_variant(DBusMessageIter *iter, GVariant **g_variant_return, GError **g_error) +{ + gboolean result = TRUE; + int arg_type; + GVariant *g_variant = NULL; + char *signature = NULL; + GVariantBuilder builder; + DBusMessageIter sub; + + g_return_val_if_fail (iter != NULL, FALSE); + g_return_val_if_fail (g_variant_return != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + *g_variant_return = NULL; + + arg_type = dbus_message_iter_get_arg_type(iter); + +#ifdef TRACE_VARIANT + signature = dbus_message_iter_get_signature(iter); + printf("dbus_iter_to_variant enter: type=%s signature=%s\n", + dbus_type_to_string(arg_type), signature); + g_free(signature); + signature = NULL; +#endif + + switch (arg_type) { + case DBUS_TYPE_BOOLEAN: { + dbus_bool_t value; + + dbus_message_iter_get_basic(iter, &value); + if ((g_variant = g_variant_new_boolean(value)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "unable to create GVariant boolean value=%d", value); + result = FALSE; + } + + } break; + case DBUS_TYPE_BYTE: { + guint8 value; + + dbus_message_iter_get_basic(iter, &value); + if ((g_variant = g_variant_new_byte(value)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "unable to create GVariant byte value=%uc", value); + result = FALSE; + } + + } break; + case DBUS_TYPE_INT16: { + gint16 value; + + dbus_message_iter_get_basic(iter, &value); + if ((g_variant = g_variant_new_int16(value)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "unable to create GVariant int16 value=%" G_GINT16_FORMAT, value); + result = FALSE; + } + + } break; + case DBUS_TYPE_UINT16: { + guint16 value; + + dbus_message_iter_get_basic(iter, &value); + if ((g_variant = g_variant_new_uint16(value)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "unable to create GVariant uint16 value=%" G_GUINT16_FORMAT, value); + result = FALSE; + } + + } break; + case DBUS_TYPE_INT32: { + gint32 value; + + dbus_message_iter_get_basic(iter, &value); + if ((g_variant = g_variant_new_int32(value)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "unable to create GVariant int32 value=%" G_GINT32_FORMAT, value); + result = FALSE; + } + + } break; + case DBUS_TYPE_UINT32: { + guint32 value; + + dbus_message_iter_get_basic(iter, &value); + if ((g_variant = g_variant_new_uint32(value)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "unable to create GVariant uint32 value=%" G_GUINT32_FORMAT, value); + result = FALSE; + } + + } break; + case DBUS_TYPE_INT64: { + gint64 value; + + dbus_message_iter_get_basic(iter, &value); + if ((g_variant = g_variant_new_int64(value)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "unable to create GVariant int64 value=%" G_GINT64_FORMAT, value); + result = FALSE; + } + + } break; + case DBUS_TYPE_UINT64: { + guint64 value; + + dbus_message_iter_get_basic(iter, &value); + if ((g_variant = g_variant_new_uint64(value)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "unable to create GVariant uint64 value=%" G_GUINT64_FORMAT, value); + result = FALSE; + } + + } break; + case DBUS_TYPE_DOUBLE: { + gdouble value; + + dbus_message_iter_get_basic(iter, &value); + if ((g_variant = g_variant_new_double(value)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "unable to create GVariant double value=%f", value); + result = FALSE; + } + + } break; + case DBUS_TYPE_STRING: { + gchar *value; + + dbus_message_iter_get_basic(iter, &value); + if ((g_variant = g_variant_new_string(value)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "unable to create GVariant string value=\"%s\"", value); + result = FALSE; + } + + } break; + case DBUS_TYPE_OBJECT_PATH: { + gchar *value; + + dbus_message_iter_get_basic(iter, &value); + if ((g_variant = g_variant_new_object_path(value)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "unable to create GVariant object path value=\"%s\"", value); + result = FALSE; + } + + } break; + case DBUS_TYPE_SIGNATURE: { + gchar *value; + + dbus_message_iter_get_basic(iter, &value); + if ((g_variant = g_variant_new_signature(value)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "unable to create GVariant signature value=\"%s\"", value); + result = FALSE; + } + + } break; + case DBUS_TYPE_UNIX_FD: { + guint32 value; + + dbus_message_iter_get_basic(iter, &value); + if ((g_variant = g_variant_new_uint32(value)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "unable to create GVariant file descriptor value=%u", value); + result = FALSE; + } + + } break; + case DBUS_TYPE_ARRAY: { + GVariant *item; + + signature = dbus_message_iter_get_signature(iter); + + g_variant_builder_init(&builder, G_VARIANT_TYPE(signature)); + dbus_message_iter_recurse(iter, &sub); + + while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { + if (!dbus_iter_to_variant(&sub, &item, g_error)) { + g_variant_builder_clear(&builder); + result = FALSE; + goto exit; + } +#ifdef TRACE_VARIANT + { + gchar *variant_as_string = g_variant_print(item, TRUE); + printf("array item=%s\n", variant_as_string); + g_free(variant_as_string); + } +#endif + g_variant_builder_add_value(&builder, item); + dbus_message_iter_next(&sub); + } + + if ((g_variant = g_variant_builder_end(&builder)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "unable to create GVariant array"); + result = FALSE; + } + + } break; + case DBUS_TYPE_VARIANT: { + GVariant *item; + + signature = dbus_message_iter_get_signature(iter); + g_variant_builder_init(&builder, G_VARIANT_TYPE(signature)); + dbus_message_iter_recurse(iter, &sub); + + if (!dbus_iter_to_variant(&sub, &item, g_error)) { + g_variant_builder_clear(&builder); + result = FALSE; + goto exit; + } +#ifdef TRACE_VARIANT + { + gchar *variant_as_string = g_variant_print(item, TRUE); + printf("variant item=%s\n", variant_as_string); + g_free(variant_as_string); + } +#endif + + g_variant_builder_add_value(&builder, item); + + if ((g_variant = g_variant_builder_end(&builder)) == NULL) { + gchar *variant_as_string = g_variant_print(item, FALSE); + + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "unable to create GVariant variant for value=%s", variant_as_string); + g_free(variant_as_string); + result = FALSE; + } + } break; + case DBUS_TYPE_STRUCT: { + GVariant *item; + + signature = dbus_message_iter_get_signature(iter); + g_variant_builder_init(&builder, G_VARIANT_TYPE(signature)); + dbus_message_iter_recurse(iter, &sub); + + while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { + if (!dbus_iter_to_variant(&sub, &item, g_error)) { + g_variant_builder_clear(&builder); + result = FALSE; + goto exit; + } +#ifdef TRACE_VARIANT + { + gchar *variant_as_string = g_variant_print(item, TRUE); + printf("struct item=%s\n", variant_as_string); + g_free(variant_as_string); + } +#endif + g_variant_builder_add_value(&builder, item); + dbus_message_iter_next(&sub); + } + + if ((g_variant = g_variant_builder_end(&builder)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "unable to create GVariant struct"); + result = FALSE; + } + + } break; + case DBUS_TYPE_DICT_ENTRY: { + GVariant *key, *value; + + dbus_message_iter_recurse(iter, &sub); + signature = dbus_message_iter_get_signature(iter); + + if (!dbus_iter_to_variant(&sub, &key, g_error)) { + g_prefix_error(g_error, "unable to create GVariant dict_entry key: "); + result = FALSE; + goto exit; + } + + dbus_message_iter_next(&sub); + + if (!dbus_iter_to_variant(&sub, &value, g_error)) { + g_prefix_error(g_error, "unable to create GVariant dict_entry value: "); + result = FALSE; + goto exit; + } +#ifdef TRACE_VARIANT + { + gchar *key_variant_as_string = g_variant_print(key, TRUE); + gchar *value_variant_as_string = g_variant_print(key, TRUE); + printf("dict_entry key=%s value=%s\n", g_variant_print(key, TRUE), g_variant_print(value, TRUE)); + g_free(key_variant_as_string); + g_free(value_variant_as_string); + } +#endif + + g_variant = g_variant_new_dict_entry(key, value); + + } break; + default: { + signature = dbus_message_iter_get_signature(iter); + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "unknown DBus type=%d, signature=%s", arg_type, signature); + result = FALSE; + break; + } + } + + exit: + if (signature) dbus_free(signature); + *g_variant_return = g_variant; + +#ifdef TRACE_VARIANT + { + gchar *variant_as_string = NULL; + if (g_variant) { + variant_as_string = g_variant_print(g_variant, TRUE); + } else { + variant_as_string = "NULL"; + } + printf("dbus_iter_to_variant returns %s, variant=%s\n", + result ? "TRUE" : "FALSE", variant_as_string); + if (g_variant) { + g_free(variant_as_string); + } + } +#endif + + return result; +} + +/** + * dbus_message_to_g_variant: + * @msg DBusMessage which will be converted to a GVariant + * @g_variant_return Pointer to location where GVariant will be returned, + * will be NULL if error occurs + * @g_error initialized to error info when FALSE is returned. + * + * Converts a DBusMessage to a GVariant. + * + * Returns: return TRUE if successful, @g_variant_return will be non-NULL. + * FALSE if error with @g_error initialized, @g_variant_return will be NULL. + */ +static gboolean +dbus_message_to_g_variant(DBusMessage *msg, GVariant **g_variant_return, GError **g_error) +{ + DBusMessageIter iter; + + g_return_val_if_fail (msg != NULL, FALSE); + g_return_val_if_fail (g_variant_return != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + *g_variant_return = NULL; + +#ifdef RDCP_DBUS_DEBUG + { + gchar *msg_as_string = dbus_message_print(msg, NULL, FALSE); + printf("dbus_message_to_g_variant: msg=\n%s", msg_as_string); + g_free(msg_as_string); + } +#endif + + if (!dbus_message_iter_init(msg, &iter)) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "could not create iterator to parse DBus message"); + return FALSE; + } + + if (!dbus_iter_to_variant(&iter, g_variant_return, g_error)) { + g_prefix_error(g_error, "unable to convert dbus_message to GVariant: "); + return FALSE; + } + +#ifdef RDCP_DBUS_DEBUG + { + gchar *variant_as_string = NULL; + if (*g_variant_return) { + variant_as_string = g_variant_print(*g_variant_return, TRUE); + } else { + variant_as_string = "NULL"; + } + printf("dbus_message_to_g_variant returns variant=%s\n", variant_as_string); + if (*g_variant_return) { + g_free(variant_as_string); + } + } +#endif + + return TRUE; +} + +/** + * dbus_method_reply_to_g_variant_tuple: + * @msg DBus message reply which will be converted to a tuple of GVariant's + * @g_variant_return Pointer to location where GVariant will be returned, + * will be NULL if error occurs + * @g_error initialized to error info when FALSE is returned. + * + * A DBus method reply contains a sequence of zero or more OUT parameters. + * Parse the method reply and build a GVariant tuple whose members are + * the OUT parameters. Each tuple member will also be a GVariant. + * + * Returns: return TRUE if successful, @g_variant_return will be non-NULL. + * FALSE if error with @g_error initialized, @g_variant_return will be NULL. + */ +static gboolean +dbus_method_reply_to_g_variant_tuple(DBusMessage *msg, GVariant **g_variant_return, GError **g_error) +{ + DBusMessageIter iter; + GVariantBuilder builder; + + g_return_val_if_fail (msg != NULL, FALSE); + g_return_val_if_fail (g_variant_return != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + *g_variant_return = NULL; + +#ifdef RDCP_DBUS_DEBUG + { + gchar *msg_as_string = dbus_message_print(msg, NULL, FALSE); + printf("dbus_method_reply_to_g_variant_tuple: msg=\n%s", msg_as_string); + g_free(msg_as_string); + } +#endif + + g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE); + + if (!dbus_message_iter_init(msg, &iter)) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "could not create iterator to parse DBus message"); + return FALSE; + } + + while (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID) { + GVariant *g_variant = NULL; + + if (!dbus_iter_to_variant(&iter, &g_variant, g_error)) { + g_prefix_error(g_error, "unable to convert dbus_message to GVariant: "); + return FALSE; + } + + g_variant_builder_add_value(&builder, g_variant); + + dbus_message_iter_next (&iter); + } + + if ((*g_variant_return = g_variant_builder_end(&builder)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "unable to build GVariant options array"); + return FALSE; + } + + +#ifdef RDCP_DBUS_DEBUG + { + gchar *variant_as_string = NULL; + if (*g_variant_return) { + variant_as_string = g_variant_print(*g_variant_return, TRUE); + } else { + variant_as_string = "NULL"; + } + printf("dbus_method_reply_to_g_variant_tuple returns variant=%s\n", variant_as_string); + if (*g_variant_return) { + g_free(variant_as_string); + } + } +#endif + + return TRUE; +} + +/*----------------------------------------------------------------------------*/ + +/** + * get_dbus_string_property: + * @bus The DBus connection on which the query will be performed + * @object_path The DBus object path identifying the object + * @interface The DBus interface which provides the property + * @property The name of the proptery on the interface + * @value_return Pointer to where string value will be returned. + * Must be freed with g_free(), will be NULL if error occurs. + * @g_error initialized to error info when FALSE is returned. + * + * Retrieve a string valued property from an DBus object. + * + * Returns: return TRUE if successful, @value_return will be non-NULL. + * FALSE if error with @g_error initialized, @value_return will be NULL. + */ +gboolean +get_dbus_string_property(DBusConnection *bus, const char *object_path, + const char* interface, const char *property, + char **value_return, GError **g_error) +{ + const char *method = "Get"; + DBusMessage* msg = NULL; + DBusMessage* reply = NULL; + DBusError dbus_error; + const char *interface_ptr = interface; + const char *property_ptr = property; + DBusMessageIter iter, variant; + char *value = NULL; + char *signature; + + g_return_val_if_fail (bus != NULL, FALSE); + g_return_val_if_fail (object_path != NULL, FALSE); + g_return_val_if_fail (interface != NULL, FALSE); + g_return_val_if_fail (property != NULL, FALSE); + g_return_val_if_fail (value_return != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + *value_return = NULL; + dbus_error_init(&dbus_error); + + if ((msg = dbus_message_new_method_call(REALM_DBUS_BUS_NAME, object_path, + DBUS_INTERFACE_PROPERTIES, method)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "failed to create" + "DBus %s.%s() message, object_path=%s, interface=%s, property=%s", + DBUS_INTERFACE_PROPERTIES, method, object_path, interface, property); + return FALSE; + } + + if (!dbus_message_append_args(msg, + DBUS_TYPE_STRING, &interface_ptr, + DBUS_TYPE_STRING, &property_ptr, + DBUS_TYPE_INVALID)) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "failed to add args to " + "DBus %s.%s() message, object_path=%s, interface=%s, property=%s", + DBUS_INTERFACE_PROPERTIES, method, object_path, interface, property); + dbus_message_unref(msg); + return FALSE; + } + + if ((reply = dbus_connection_send_with_reply_and_block(bus, msg, -1, &dbus_error)) == NULL) { + dbus_message_unref(msg); + RETURN_DBUS_ERROR(g_error, dbus_error); + } + dbus_message_unref(msg); + + if (!dbus_message_has_signature(reply, "v")) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "expected variant in DBus %s.%s() reply, object_path=%s, interface=%s, property=%s", + DBUS_INTERFACE_PROPERTIES, method, object_path, interface, property); + dbus_message_unref(reply); + return FALSE; + } + + if (!dbus_message_iter_init(reply, &iter)) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "could not create iterator to parse " + "DBus %s.%s() reply, object_path=%s, interface=%s, property=%s", + DBUS_INTERFACE_PROPERTIES, method, object_path, interface, property); + dbus_message_unref(reply); + return FALSE; + } + + dbus_message_iter_recurse(&iter, &variant); + signature = dbus_message_iter_get_signature(&variant); + if (!g_str_equal(signature, DBUS_TYPE_STRING_AS_STRING)) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "expected string type variant but got \"%s\" signature instead for " + "DBus %s.%s() reply, object_path=%s, interface=%s, property=%s", + signature, DBUS_INTERFACE_PROPERTIES, method, object_path, interface, property); + dbus_free(signature); + dbus_message_unref(reply); + return FALSE; + } + dbus_free(signature); + dbus_message_iter_get_basic(&variant, &value); + *value_return = g_strdup(value); + + dbus_message_unref(reply); + return TRUE; +} + +/** + * get_dbus_properties: + * @bus The DBus connection on which the query will be performed + * @object_path The DBus object path identifying the object + * @interface The DBus interface which provides the property + * @properties_return Pointer to where a GVariant containing all + * the interface's properties for the object will be returned. + * Must be freed with g_variant_unref(), will be NULL if error occurs. + * @g_error initialized to error info when FALSE is returned. + * + * Retrieve all the interface properties from an DBus object. + * Returned as a GVariant dictionary. Use g_variant_lookup() to + * obtain a specific property in the dictionary. + * + * Returns: return TRUE if successful, @value_return will be non-NULL. + * FALSE if error with @g_error initialized, @value_return will be NULL. + */ +gboolean +get_dbus_properties(DBusConnection *bus, const char *object_path, + const char* interface, GVariant **properties_return, + GError **g_error) +{ + const char *method = "GetAll"; + DBusMessage* msg = NULL; + DBusMessage* reply = NULL; + DBusError dbus_error; + const char *interface_ptr = interface; + + g_return_val_if_fail (bus != NULL, FALSE); + g_return_val_if_fail (object_path != NULL, FALSE); + g_return_val_if_fail (interface != NULL, FALSE); + g_return_val_if_fail (properties_return != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + *properties_return = NULL; + dbus_error_init(&dbus_error); + + if ((msg = dbus_message_new_method_call(REALM_DBUS_BUS_NAME, object_path, + DBUS_INTERFACE_PROPERTIES, method)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "failed to create" + "DBus %s.%s() message, object_path=%s, interface=%s", + DBUS_INTERFACE_PROPERTIES, method, object_path, interface); + return FALSE; + } + + if (!dbus_message_append_args(msg, + DBUS_TYPE_STRING, &interface_ptr, + DBUS_TYPE_INVALID)) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "failed to add args to " + "DBus %s.%s() message, object_path=%s, interface=%s", + DBUS_INTERFACE_PROPERTIES, method, object_path, interface); + dbus_message_unref(msg); + return FALSE; + } + + if ((reply = dbus_connection_send_with_reply_and_block(bus, msg, -1, &dbus_error)) == NULL) { + dbus_message_unref(msg); + RETURN_DBUS_ERROR(g_error, dbus_error); + } + dbus_message_unref(msg); + + if (!dbus_message_to_g_variant(reply, properties_return, g_error)) { + dbus_message_unref(reply); + return FALSE; + } + + + dbus_message_unref(reply); + return TRUE; +} + +/*----------------------------------------------------------------------------*/ + +/** + * dbus_discover_marshal: + * @target what to discover + * @options dictionary of option {key,values} + * @msg_return if successful DBus message returned here, + * if error then this will be NULL. + * @g_error initialized to error info when FALSE is returned. + * + * Marshal a realm Discover method call. + * + * Returns: return TRUE if successful, @msg_return will point to DBusMessage, + * FALSE if error with @g_error initialized. @msg_return will be NULL. + */ +static gboolean +dbus_discover_marshal(const char* target, GVariant *options, + DBusMessage **msg_return, GError **g_error) +{ + const char *method = "Discover"; + DBusMessage *msg = NULL; + DBusMessageIter iter; + + g_return_val_if_fail (target != NULL, FALSE); + g_return_val_if_fail (options != NULL, FALSE); + g_return_val_if_fail (msg_return != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + *msg_return = NULL; + + if ((msg = dbus_message_new_method_call(REALM_DBUS_BUS_NAME, REALM_DBUS_SERVICE_PATH, + REALM_DBUS_PROVIDER_INTERFACE, method)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "failed to create dbus method call %s.%s() message, object_path=%s", + REALM_DBUS_PROVIDER_INTERFACE, method, REALM_DBUS_SERVICE_PATH); + return FALSE; + } + + dbus_message_iter_init_append (msg, &iter); /* void return */ + + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &target)) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "failed to add target parameter (%s)", target); + dbus_message_unref(msg); + return FALSE; + } + + if (!append_g_variant_to_dbus_message(msg, options, g_error)) { + g_prefix_error(g_error, "unable to append GVariant options dictionary into %s.%s() message", + REALM_DBUS_PROVIDER_INTERFACE, method); + dbus_message_unref(msg); + return FALSE; + } + + *msg_return = msg; + return TRUE; +} + +/** + * dbus_discover_unmarshal: + * @reply DBus method reply from Discover call + * @relevance_return Pointer to returned relevance value + * @paths_return Pointer to an array of object path strings, + * must be freed with g_strfreev(). + * @g_error initialized to error info when FALSE is returned. + * + * Parses the DBus reply message from the Discover call and unpacks + * the output paramters in the *_return parameters of this function. + * + * Returns: return TRUE if successful, FALSE if error with @g_error initialized. + */ + +static gboolean +dbus_discover_unmarshal(DBusMessage *reply, gint32 *relevance_return, gchar ***paths_return, GError **g_error) +{ + GVariant *g_variant_reply = NULL; + + g_return_val_if_fail (reply != NULL, FALSE); + g_return_val_if_fail (relevance_return != NULL, FALSE); + g_return_val_if_fail (paths_return != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + if (!dbus_method_reply_to_g_variant_tuple(reply, &g_variant_reply, g_error)) { + gchar *reply_string = dbus_message_print(reply, NULL, FALSE); + + g_prefix_error(g_error, "unable convert reply (%s) to GVariant tuple: ", reply_string); + g_free(reply_string); + dbus_message_unref(reply); + return FALSE; + } + + g_variant_get(g_variant_reply, "(i^ao)", relevance_return, paths_return); + G_VARIANT_FREE(g_variant_reply); + + return TRUE; +} + +/** + * dbus_discover_call: + * @target what to discover + * @options dictionary of option {key,values} + * @relevance_return Pointer to returned relevance value + * @paths_return Pointer to an array of object path strings, + * must be freed with g_strfreev(). + * @g_error initialized to error info when FALSE is returned. + * + * Marshal a realm Discover method call, call it synchronously, + * unmarsh it's reply and return the OUT parameters. + * + * Returns: return TRUE if successful, FALSE if error with @g_error initialized + */ +gboolean +dbus_discover_call(DBusConnection *bus, const char *target, GVariant *options, + gint32 *relevance_return, gchar ***paths_return, GError **g_error) +{ + DBusError dbus_error; + DBusMessage *msg = NULL; + DBusMessage* reply = NULL; + + g_return_val_if_fail (bus != NULL, FALSE); + g_return_val_if_fail (target != NULL, FALSE); + g_return_val_if_fail (options != NULL, FALSE); + g_return_val_if_fail (relevance_return != NULL, FALSE); + g_return_val_if_fail (paths_return != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + dbus_error_init(&dbus_error); + if (!dbus_discover_marshal(target, options, &msg, g_error)) { + RETURN_DBUS_ERROR(g_error, dbus_error); + } + + if ((reply = dbus_connection_send_with_reply_and_block(bus, msg, -1, &dbus_error)) == NULL) { + dbus_message_unref(msg); + RETURN_DBUS_ERROR(g_error, dbus_error); + } + dbus_message_unref(msg); + + if (!dbus_discover_unmarshal(reply, relevance_return, paths_return, g_error)) { + dbus_message_unref(reply); + return FALSE; + } + dbus_message_unref(reply); + return TRUE; +} + +/*----------------------------------------------------------------------------*/ + +/** + * dbus_change_login_policy_marshal: + * @dbus_path The DBus object path of the object supporting the Realm + * interface on which the call will be made. + * @login_policy The new login policy, or an empty string. + * @permitted_add: An array of logins to permit. + * @permitted_remove: An array of logins to not permit. + * @options dictionary of option {key,values} + * @msg_return if successful DBus message returned here, + * if error then this will be NULL. + * @g_error initialized to error info when FALSE is returned. + * + * Marshal a realm ChangeLoginPolicy method call. + * + * Returns: return TRUE if successful, @msg_return will point to DBusMessage, + * FALSE if error with @g_error initialized. @msg_return will be NULL. + */ +static gboolean +dbus_change_login_policy_marshal(const gchar *dbus_path, const char *login_policy, + GVariant *permitted_add, GVariant *permitted_remove, + GVariant *options, DBusMessage **msg_return, GError **g_error) +{ + const char *method = "ChangeLoginPolicy"; + DBusMessage *msg = NULL; + DBusMessageIter iter; + + g_return_val_if_fail (dbus_path != NULL, FALSE); + g_return_val_if_fail (login_policy != NULL, FALSE); + g_return_val_if_fail (permitted_add != NULL, FALSE); + g_return_val_if_fail (permitted_remove != NULL, FALSE); + g_return_val_if_fail (options != NULL, FALSE); + g_return_val_if_fail (msg_return != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + *msg_return = NULL; + + if ((msg = dbus_message_new_method_call(REALM_DBUS_BUS_NAME, dbus_path, + REALM_DBUS_REALM_INTERFACE, method)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "failed to create dbus method call %s.%s() message, object_path=%s", + REALM_DBUS_PROVIDER_INTERFACE, method, REALM_DBUS_SERVICE_PATH); + return FALSE; + } + + dbus_message_iter_init_append (msg, &iter); /* void return */ + + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &login_policy)) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "failed to add login_policy parameter (%s)", login_policy); + dbus_message_unref(msg); + return FALSE; + } + + if (!append_g_variant_to_dbus_message(msg, permitted_add, g_error)) { + g_prefix_error(g_error, "unable to append GVariant permitted_add dictionary into %s.%s() message", + REALM_DBUS_PROVIDER_INTERFACE, method); + dbus_message_unref(msg); + return FALSE; + } + + if (!append_g_variant_to_dbus_message(msg, permitted_remove, g_error)) { + g_prefix_error(g_error, "unable to append GVariant permitted_remove dictionary into %s.%s() message", + REALM_DBUS_PROVIDER_INTERFACE, method); + dbus_message_unref(msg); + return FALSE; + } + + if (!append_g_variant_to_dbus_message(msg, options, g_error)) { + g_prefix_error(g_error, "unable to append GVariant options dictionary into %s.%s() message", + REALM_DBUS_PROVIDER_INTERFACE, method); + dbus_message_unref(msg); + return FALSE; + } + + *msg_return = msg; + return TRUE; +} + +/** + * dbus_change_login_policy_unmarshal: + * @reply DBus method reply from ChangeLoginPolicy call + * @g_error initialized to error info when FALSE is returned. + * + * Parses the DBus reply message from the ChangeLoginPolicy call. + * + * Returns: return TRUE if successful, FALSE if error with @g_error initialized. + */ + +static gboolean +dbus_change_login_policy_unmarshal(DBusMessage *reply, GError **g_error) +{ + g_return_val_if_fail (reply != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + return TRUE; +} + +/** + * dbus_change_login_policy_call: + * @dbus_path The DBus object path of the object supporting the Realm + * interface on which the call will be made. + * @login_policy The new login policy, or an empty string. + * @permitted_add: An array of logins to permit. + * @permitted_remove: An array of logins to not permit. + * @options dictionary of option {key,values} + * @g_error initialized to error info when FALSE is returned. + * + * Marshal a realm ChangeLoginPolicy method call, call it synchronously, + * unmarsh it's reply and return the OUT parameters. + * + * Returns: return TRUE if successful, FALSE if error with @g_error initialized + */ +gboolean +dbus_change_login_policy_call(DBusConnection *bus, const gchar *dbus_path, const char *login_policy, + GVariant *permitted_add, GVariant *permitted_remove, + GVariant *options, GError **g_error) +{ + DBusError dbus_error; + DBusMessage *msg = NULL; + DBusMessage* reply = NULL; + + g_return_val_if_fail (bus != NULL, FALSE); + g_return_val_if_fail (dbus_path != NULL, FALSE); + g_return_val_if_fail (login_policy != NULL, FALSE); + g_return_val_if_fail (permitted_add != NULL, FALSE); + g_return_val_if_fail (permitted_remove != NULL, FALSE); + g_return_val_if_fail (options != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + dbus_error_init(&dbus_error); + if (!dbus_change_login_policy_marshal(dbus_path, login_policy, + permitted_add, permitted_remove, + options, &msg, g_error)) { + RETURN_DBUS_ERROR(g_error, dbus_error); + } + + if ((reply = dbus_connection_send_with_reply_and_block(bus, msg, -1, &dbus_error)) == NULL) { + dbus_message_unref(msg); + RETURN_DBUS_ERROR(g_error, dbus_error); + } + dbus_message_unref(msg); + + if (!dbus_change_login_policy_unmarshal(reply, g_error)) { + dbus_message_unref(reply); + return FALSE; + } + dbus_message_unref(reply); + return TRUE; +} + +/*----------------------------------------------------------------------------*/ + +/** + * dbus_join_leave_marshal: + * @dbus_path The DBus object path of the object supporting the kerberos + * membership interface on which the Join/Leave call will be made. + * @credentials A GVariant encoding the credentials according the the credential + * type. See the Realmd DBus interface for specifics. + * @options dictionary of option {key,values} + * @msg_return if successful DBus message returned here, + * if error then this will be NULL. + * @g_error initialized to error info when FALSE is returned. + * + * Since the Join() & Leave() methods share identical signatures (differing + * only in their method name) we use a common routine. + * + * Returns: return TRUE if successful, @msg_return will point to DBusMessage, + * FALSE if error with @g_error initialized. @msg_return will be NULL. + */ +static gboolean +dbus_join_leave_marshal(const char *method, const gchar* dbus_path, + GVariant *credentials, GVariant *options, + DBusMessage **msg_return, GError **g_error) +{ + DBusMessage *msg = NULL; + DBusMessageIter iter; + + g_return_val_if_fail (method != NULL, FALSE); + g_return_val_if_fail (dbus_path != NULL, FALSE); + g_return_val_if_fail (credentials != NULL, FALSE); + g_return_val_if_fail (options != NULL, FALSE); + g_return_val_if_fail (msg_return != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + *msg_return = NULL; + + if ((msg = dbus_message_new_method_call(REALM_DBUS_BUS_NAME, dbus_path, + REALM_DBUS_KERBEROS_MEMBERSHIP_INTERFACE, method)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "failed to create dbus method call %s.%s() message, object_path=%s", + REALM_DBUS_PROVIDER_INTERFACE, method, REALM_DBUS_SERVICE_PATH); + return FALSE; + } + + dbus_message_iter_init_append (msg, &iter); /* void return */ + + if (!append_g_variant_to_dbus_message(msg, credentials, g_error)) { + g_prefix_error(g_error, "unable to append GVariant credentials into %s.%s() message", + REALM_DBUS_PROVIDER_INTERFACE, method); + dbus_message_unref(msg); + return FALSE; + } + + if (!append_g_variant_to_dbus_message(msg, options, g_error)) { + g_prefix_error(g_error, "unable to append GVariant options dictionary into %s.%s() message", + REALM_DBUS_PROVIDER_INTERFACE, method); + dbus_message_unref(msg); + return FALSE; + } + + *msg_return = msg; + return TRUE; +} + +/** + * dbus_join_leave_unmarshal: + * @reply DBus method reply from Join/Leave call + * @g_error initialized to error info when FALSE is returned. + * + * Since the Join() & Leave() methods share identical signatures (differing + * only in their method name) we use a common routine. + * + * Parses the DBus reply message from the Join/Leave call. + * + * Returns: return TRUE if successful, FALSE if error with @g_error initialized. + */ + +static gboolean +dbus_join_leave_unmarshal(DBusMessage *reply, GError **g_error) +{ + + g_return_val_if_fail (reply != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + return TRUE; +} + +/** + * dbus_join_leave_call: + * @dbus_path The DBus object path of the object supporting the kerberos + * membership interface on which the Join/Leave call will be made. + * @credentials A GVariant encoding the credentials according the the credential + * type. See the Realmd DBus interface for specifics. + * @options dictionary of option {key,values} + * @g_error initialized to error info when FALSE is returned. + * + * Since the Join() & Leave() methods share identical signatures (differing + * only in their method name) we use a common routine. + * + * Marshal a realm Join/Leave method call, call it synchronously, + * unmarsh it's reply and return the OUT parameters. + * + * Returns: return TRUE if successful, FALSE if error with @g_error initialized + */ +gboolean +dbus_join_leave_call(const char *method, DBusConnection *bus, const gchar *dbus_path, + GVariant *credentials, GVariant *options, GError **g_error) +{ + DBusError dbus_error; + DBusMessage *msg = NULL; + DBusMessage* reply = NULL; + + g_return_val_if_fail (method != NULL, FALSE); + g_return_val_if_fail (bus != NULL, FALSE); + g_return_val_if_fail (dbus_path != NULL, FALSE); + g_return_val_if_fail (credentials != NULL, FALSE); + g_return_val_if_fail (options != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + dbus_error_init(&dbus_error); + if (!dbus_join_leave_marshal(method, dbus_path, credentials, options, &msg, g_error)) { + RETURN_DBUS_ERROR(g_error, dbus_error); + } + + if ((reply = dbus_connection_send_with_reply_and_block(bus, msg, -1, &dbus_error)) == NULL) { + dbus_message_unref(msg); + RETURN_DBUS_ERROR(g_error, dbus_error); + } + dbus_message_unref(msg); + + if (!dbus_join_leave_unmarshal(reply, g_error)) { + dbus_message_unref(reply); + return FALSE; + } + dbus_message_unref(reply); + return TRUE; +} + + +/*----------------------------------------------------------------------------*/ + +/** + * dbus_join_call: + * @dbus_path The DBus object path of the object supporting the kerberos + * membership interface on which the Join call will be made. + * @credentials A GVariant encoding the credentials according the the credential + * type. See the Realmd DBus interface for specifics. + * @options dictionary of option {key,values} + * @g_error initialized to error info when FALSE is returned. + * + * Marshal a realm Join method call, call it synchronously, + * unmarsh it's reply and return the OUT parameters. + * + * Returns: return TRUE if successful, FALSE if error with @g_error initialized + */ +gboolean +dbus_join_call(DBusConnection *bus, const gchar *dbus_path, + GVariant *credentials, GVariant *options, GError **g_error) +{ + + return dbus_join_leave_call("Join", bus, dbus_path, credentials, + options, g_error); + +} + + +/** + * dbus_leave_call: + * @dbus_path The DBus object path of the object supporting the kerberos + * membership interface on which the Leave call will be made. + * @credentials A GVariant encoding the credentials according the the credential + * type. See the Realmd DBus interface for specifics. + * @options dictionary of option {key,values} + * @g_error initialized to error info when FALSE is returned. + * + * Marshal a realm Leave method call, call it synchronously, + * unmarsh it's reply and return the OUT parameters. + * + * Returns: return TRUE if successful, FALSE if error with @g_error initialized + */ +gboolean +dbus_leave_call(DBusConnection *bus, const gchar *dbus_path, + GVariant *credentials, GVariant *options, GError **g_error) +{ + + return dbus_join_leave_call("Leave", bus, dbus_path, credentials, + options, g_error); + +} + + +/*----------------------------------------------------------------------------*/ +/** + * get_short_dbus_interface_name + * @interface fully qualified DBus interface name + * + * Given a DBus interface name return a friendly short name + * appropriate for users to see. Currently the known short names are: + * + * * "Kerberos" + * * "KerberosMembership" + * * "Realm" + * * "Provider" + * * "Service" + * + * If the interface is not recognized the portion of the interface + * following the last period (".") will be returned. If there is no + * period in the interface name then the entire interface string is returned. + * If the interface is NULL then "(null)" is returned. + * + * Returns: pointer to string, must free with g_free() + */ + +char * +get_short_dbus_interface_name(const char *interface) +{ + char *token = NULL; + + if (interface == NULL) { + return g_strdup("(null)"); + } + + if (strcmp(interface, REALM_DBUS_KERBEROS_INTERFACE) == 0) { + return g_strdup("Kerberos"); + } + if (strcmp(interface, REALM_DBUS_KERBEROS_MEMBERSHIP_INTERFACE) == 0) { + return g_strdup("KerberosMembership"); + } + if (strcmp(interface, REALM_DBUS_REALM_INTERFACE) == 0) { + return g_strdup("Realm"); + } + if (strcmp(interface, REALM_DBUS_PROVIDER_INTERFACE) == 0) { + return g_strdup("Provider"); + } + if (strcmp(interface, REALM_DBUS_SERVICE_INTERFACE) == 0) { + return g_strdup("Service"); + } + /* Return string which begins after last period */ + if ((token = rindex(interface, '.'))) { + token++; /* skip "." char */ + return g_strdup(token); + } else { + return g_strdup(interface); + } + +} + +/*----------------------------------------------------------------------------*/ + +/** + * rdcp_dbus_initialize: + * @g_error initialized to error info when FALSE is returned. + * + * Initializes the dbus module. + * + * - opens a connection the System Bus, exported as #system_bus + * + * Returns: return TRUE if successful, FALSE if error with @g_error initialized. + */ + +gboolean +rdcp_dbus_initialize(GError **g_error) +{ + DBusError dbus_error = DBUS_ERROR_INIT; + + dbus_error_init(&dbus_error); + + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + if (!system_bus) { + if ((system_bus = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_error)) == NULL) { + *g_error = dbus_error_to_gerror(&dbus_error); + g_prefix_error(g_error, "could not connect to System DBus"); + return FALSE; + } + } + + return TRUE; +} diff --git a/src/realmd/rdcp_dbus.h b/src/realmd/rdcp_dbus.h new file mode 100644 index 0000000..d050071 --- /dev/null +++ b/src/realmd/rdcp_dbus.h @@ -0,0 +1,74 @@ +#ifndef __RDCP_DBUS_H__ +#define __RDCP_DBUS_H__ + +#include +#include +#include "realm-dbus-constants.h" + +#define VERBOSE +//#define TRACE_VARIANT + +/*----------------------------------------------------------------------------*/ + +extern DBusConnection* system_bus; + +/*----------------------------------------------------------------------------*/ + +gboolean +get_dbus_string_property(DBusConnection *bus, const char *object_path, + const char* interface, const char *property, + char **value_return, GError **g_error); +gboolean +get_dbus_properties(DBusConnection *bus, const char *object_path, + const char* interface, GVariant **properties_return, + GError **g_error); + +gboolean +dbus_discover_call(DBusConnection *bus, const char *target, GVariant *options, + gint32 *relevance_return, gchar ***paths_return, GError **g_error); + +gboolean +dbus_change_login_policy_call(DBusConnection *bus, const gchar *dbus_path, const char *login_policy, + GVariant *permitted_add, GVariant *permitted_remove, + GVariant *options, GError **g_error); +gboolean +dbus_join_call(DBusConnection *bus, const gchar *dbus_path, + GVariant *credentials, GVariant *options, GError **g_error); + +gboolean +dbus_leave_call(DBusConnection *bus, const gchar *dbus_path, + GVariant *credentials, GVariant *options, GError **g_error); + +char * +get_short_dbus_interface_name(const char *interface); + +gboolean +rdcp_dbus_initialize(GError **g_error); + +#ifdef RDCP_DEBUG +#define PRINT_DBUS_PROPERTIES(dbus_props, dbus_path, dbus_interface) \ + print_properties(dbus_props, "%s: Properties for %s, interface=%s", \ + __FUNCTION__, dbus_path, dbus_interface); +#else +#define PRINT_DBUS_PROPERTIES(dbus_properties, dbus_path, dbus_interface) +#endif + +#define GET_DBUS_PROPERIES_OR_EXIT(dbus_props, dbus_path, dbus_interface, status) \ +{ \ + if (dbus_props != NULL) { \ + handle_g_error(&g_error, _cb, status, CMPI_RC_ERR_FAILED, \ + "get_dbus_properties failed, dbus_props was non-NULL (%s:%d)", \ + __FILE__, __LINE__); \ + goto exit; \ + } \ + if (!get_dbus_properties(system_bus, dbus_path, dbus_interface, &dbus_props, &g_error)) { \ + handle_g_error(&g_error, _cb, status, CMPI_RC_ERR_FAILED, \ + "get_dbus_properties failed, path=%s interface=%s", \ + dbus_path, dbus_interface); \ + goto exit; \ + } \ + \ + PRINT_DBUS_PROPERTIES(dbus_props, dbus_path, dbus_interface); \ +} + +#endif /* __RDCP_DBUS_H__ */ diff --git a/src/realmd/rdcp_error.c b/src/realmd/rdcp_error.c new file mode 100644 index 0000000..93d7ac3 --- /dev/null +++ b/src/realmd/rdcp_error.c @@ -0,0 +1,123 @@ +#include +#include "rdcp_util.h" +#include "rdcp_error.h" + +GQuark +rdcp_error_quark (void) +{ + static volatile gsize once = 0; + static GQuark quark = 0; + + if (g_once_init_enter(&once)) { + quark = g_quark_from_static_string("rdcp-error"); + g_once_init_leave(&once, 1); + } + + return quark; +} + +const char * +rdcp_error_code_to_string(rdcp_error_codes ec) +{ + switch(ec) { + case RDCP_ERROR_INTERNAL: return "RDCP_ERROR_INTERNAL"; + case RDCP_ERROR_INVALID_ARG: return "RDCP_ERROR_INVALID_ARG"; + case RDCP_ERROR_INVALID_INSTANCE_ID: return "RDCP_ERROR_INVALID_INSTANCE_ID"; + case RDCP_ERROR_DBUS: return "RDCP_ERROR_DBUS"; + default: return "unknown error code"; + } +} + +/*----------------------------------------------------------------------------*/ + +/** + * handle_g_error: + * @g_error pointer to non-NULL GError pointer describing problem + * @mb CMPI message broker + * @st CMPI status result + * @rc CMPI return code + * @format printf-style format string, may be #NULL if no additional + * message is desired. + * + * Sets @st status to the @rc return code and an optional printf + * styles formatted message which is prepended to the error message + * contained in the g_error. It frees the g_error. + * + * Returns: the @st status passed in. + */ +CMPIStatus +handle_g_error(GError **g_error, const CMPIBroker* mb, CMPIStatus* st, CMPIrc rc, + const gchar *format, ...) +{ + CMPIStatus failsafe_status; + GString *message; + va_list va; + + CMSetStatus(&failsafe_status, CMPI_RC_ERR_FAILED); + g_return_val_if_fail (g_error != NULL && *g_error != NULL, failsafe_status); + g_return_val_if_fail (st != NULL, failsafe_status); + + message = g_string_sized_new(DEFAULT_STATUS_MSG_SIZE); + g_string_append_printf(message, "%s: ", ORGID); + + if (format) { + va_start(va, format); + g_string_append_vprintf(message, format, va); + va_end(va); + g_string_append(message, ": "); + } + + g_string_append_printf(message, "(%s(%d)) ", + rdcp_error_code_to_string((*g_error)->code), + (*g_error)->code); + g_string_append(message, (*g_error)->message); + g_error_free(*g_error); + *g_error = NULL; + + CMSetStatusWithChars(mb, st, rc, message->str); + g_string_free(message, TRUE); + + return *st; +} + + +/** + * SetCMPIStatus: + * @mb CMPI message broker + * @st CMPI status result + * @rc CMPI return code + * @format printf-style format string, may be #NULL if no additional + * message is desired. + * + * Sets @st status to the @rc return code and an optional printf + * style formatted message. + * + * Returns: the @st status passed in. + */ +CMPIStatus +SetCMPIStatus(const CMPIBroker* mb, CMPIStatus* st, CMPIrc rc, + const gchar *format, ...) +{ + CMPIStatus failsafe_status; + GString *message = NULL; + va_list va; + + CMSetStatus(&failsafe_status, CMPI_RC_ERR_FAILED); + g_return_val_if_fail (st != NULL, failsafe_status); + + if (format) { + message = g_string_sized_new(DEFAULT_STATUS_MSG_SIZE); + g_string_append_printf(message, "%s: ", ORGID); + + va_start(va, format); + g_string_append_vprintf(message, format, va); + va_end(va); + + CMSetStatusWithChars(mb, st, rc, message->str); + g_string_free(message, TRUE); + } else { + CMSetStatus(st, rc); + } + + return *st; +} diff --git a/src/realmd/rdcp_error.h b/src/realmd/rdcp_error.h new file mode 100644 index 0000000..ff60d5b --- /dev/null +++ b/src/realmd/rdcp_error.h @@ -0,0 +1,38 @@ +#ifndef __RDCP_ERROR_H__ +#define __RDCP_ERROR_H__ + +#include + +#define RDCP_ERROR (rdcp_error_quark ()) + +GQuark rdcp_error_quark (void) G_GNUC_CONST; + +typedef enum { + RDCP_ERROR_INTERNAL = 1, + RDCP_ERROR_INVALID_ARG, + RDCP_ERROR_INVALID_INSTANCE_ID, + RDCP_ERROR_DBUS, +} rdcp_error_codes; + +const char * +rdcp_error_code_to_string(rdcp_error_codes ec); + +#define LMI_REALMD_RESULT_SUCCESS 0 +#define LMI_REALMD_RESULT_FAILED 1 +#define LMI_REALMD_RESULT_NO_SUCH_DOMAIN 2 +#define LMI_REALMD_RESULT_DOMAIN_DOES_NOT_SUPPORT_PROVIDED_CREDENTIALS 3 +#define LMI_REALMD_RESULT_DOMAIN_DOES_NOT_SUPPORT_JOINING 4 + +#define DEFAULT_STATUS_MSG_SIZE 128 + +CMPIStatus +handle_g_error(GError **g_error, const CMPIBroker* cb, CMPIStatus* status, CMPIrc rc, + const gchar *format, ...) + __attribute__ ((format (printf, 5, 6))); + +CMPIStatus +SetCMPIStatus(const CMPIBroker* mb, CMPIStatus* st, CMPIrc rc, + const gchar *format, ...) + __attribute__ ((format (printf, 4, 5))); + +#endif /* __RDCP_ERROR_H__ */ diff --git a/src/realmd/rdcp_realmdrealm.h b/src/realmd/rdcp_realmdrealm.h new file mode 100644 index 0000000..491bc73 --- /dev/null +++ b/src/realmd/rdcp_realmdrealm.h @@ -0,0 +1,310 @@ +#ifndef __RDCP_REALMDREALM_H__ +#define __RDCP_REALMDREALM_H__ + +#include +#include "LMI_RealmdRealm.h" +#include "LMI_RealmdKerberosRealm.h" + + +KINLINE LMI_RealmdKerberosRealm_SupportedJoinCredentialTypes_Enum +SupportedJoinCredentialTypes_name_to_enum(const char *name) +{ + if (strcasecmp(name, "ccache")) + return LMI_RealmdKerberosRealm_SupportedJoinCredentialTypes_ccache; + if (strcasecmp(name, "password")) + return LMI_RealmdKerberosRealm_SupportedJoinCredentialTypes_password; + if (strcasecmp(name, "secrect")) + return LMI_RealmdKerberosRealm_SupportedJoinCredentialTypes_secrect; + if (strcasecmp(name, "automatic")) + return LMI_RealmdKerberosRealm_SupportedJoinCredentialTypes_automatic; + return 0; +} + +KINLINE const char * +SupportedJoinCredentialTypes_enum_to_name(LMI_RealmdKerberosRealm_SupportedJoinCredentialTypes_Enum value) +{ + switch(value) { + case LMI_RealmdKerberosRealm_SupportedJoinCredentialTypes_ccache: + return "ccache"; + case LMI_RealmdKerberosRealm_SupportedJoinCredentialTypes_password: + return "password"; + case LMI_RealmdKerberosRealm_SupportedJoinCredentialTypes_secrect: + return "secrect"; + case LMI_RealmdKerberosRealm_SupportedJoinCredentialTypes_automatic: + return "automatic"; + default: + return NULL; + } +} + +KINLINE LMI_RealmdKerberosRealm_SupportedJoinCredentialOwners_Enum +SupportedJoinCredentialOwners_name_to_enum(const char *name) +{ + if (strcasecmp(name, "administrator")) + return LMI_RealmdKerberosRealm_SupportedJoinCredentialOwners_administrator; + if (strcasecmp(name, "user")) + return LMI_RealmdKerberosRealm_SupportedJoinCredentialOwners_user; + if (strcasecmp(name, "computer")) + return LMI_RealmdKerberosRealm_SupportedJoinCredentialOwners_computer; + if (strcasecmp(name, "none")) + return LMI_RealmdKerberosRealm_SupportedJoinCredentialOwners_none; + return 0; +} + +KINLINE const char * +SupportedJoinCredentialOwners_enum_to_name(LMI_RealmdKerberosRealm_SupportedJoinCredentialOwners_Enum value) +{ + switch(value) { + case LMI_RealmdKerberosRealm_SupportedJoinCredentialOwners_administrator: + return "administrator"; + case LMI_RealmdKerberosRealm_SupportedJoinCredentialOwners_user: + return "user"; + case LMI_RealmdKerberosRealm_SupportedJoinCredentialOwners_computer: + return "computer"; + case LMI_RealmdKerberosRealm_SupportedJoinCredentialOwners_none: + return "none"; + default: + return NULL; + } +} + +KINLINE LMI_RealmdKerberosRealm_SupportedLeaveCredentialTypes_Enum +SupportedLeaveCredentialTypes_name_to_enum(const char *name) +{ + if (strcasecmp(name, "ccache")) + return LMI_RealmdKerberosRealm_SupportedLeaveCredentialTypes_ccache; + if (strcasecmp(name, "password")) + return LMI_RealmdKerberosRealm_SupportedLeaveCredentialTypes_password; + if (strcasecmp(name, "secrect")) + return LMI_RealmdKerberosRealm_SupportedLeaveCredentialTypes_secrect; + if (strcasecmp(name, "automatic")) + return LMI_RealmdKerberosRealm_SupportedLeaveCredentialTypes_automatic; + return 0; +} + +KINLINE const char *SupportedLeaveCredentialTypes_enum_to_name(LMI_RealmdKerberosRealm_SupportedLeaveCredentialTypes_Enum value) +{ + switch(value) { + case LMI_RealmdKerberosRealm_SupportedLeaveCredentialTypes_ccache: + return "ccache"; + case LMI_RealmdKerberosRealm_SupportedLeaveCredentialTypes_password: + return "password"; + case LMI_RealmdKerberosRealm_SupportedLeaveCredentialTypes_secrect: + return "secrect"; + case LMI_RealmdKerberosRealm_SupportedLeaveCredentialTypes_automatic: + return "automatic"; + default: + return NULL; + } +} + +KINLINE LMI_RealmdKerberosRealm_SupportedLeaveCredentialOwners_Enum +SupportedLeaveCredentialOwners_name_to_enum(const char *name) +{ + if (strcasecmp(name, "administrator")) + return LMI_RealmdKerberosRealm_SupportedLeaveCredentialOwners_administrator; + if (strcasecmp(name, "user")) + return LMI_RealmdKerberosRealm_SupportedLeaveCredentialOwners_user; + if (strcasecmp(name, "computer")) + return LMI_RealmdKerberosRealm_SupportedLeaveCredentialOwners_computer; + if (strcasecmp(name, "none")) + return LMI_RealmdKerberosRealm_SupportedLeaveCredentialOwners_none; + return 0; +} + +KINLINE const char * +SupportedLeaveCredentialOwners_enum_to_name(LMI_RealmdKerberosRealm_SupportedLeaveCredentialOwners_Enum value) +{ + switch(value) { + case LMI_RealmdKerberosRealm_SupportedLeaveCredentialOwners_administrator: + return "administrator"; + case LMI_RealmdKerberosRealm_SupportedLeaveCredentialOwners_user: + return "user"; + case LMI_RealmdKerberosRealm_SupportedLeaveCredentialOwners_computer: + return "computer"; + case LMI_RealmdKerberosRealm_SupportedLeaveCredentialOwners_none: + return "none"; + default: + return NULL; + } +} + +#define LMI_RealmdRealmInitKeys(klass, obj, dbus_path) \ +{ \ + gchar *instance_id = NULL; \ + const char *host_name = get_system_name(); \ + \ + klass##_Init(obj, cb, ns); \ + \ + instance_id = instance_id_from_dbus_path(dbus_path); \ + klass##_Set_InstanceID(obj, instance_id); \ + g_free(instance_id); \ + \ + klass##_Set_SystemCreationClassName(obj, get_system_creation_class_name()); \ + klass##_Set_SystemName(obj, host_name); \ +} + +KINLINE bool SupportsDBusInterface(GVariant *dbus_props, const char *dbus_interface) +{ + bool result = false; + GVariantIter *iter = NULL; + gchar *value; + + if (g_variant_lookup(dbus_props, "SupportedInterfaces", "as", &iter)) { + while (g_variant_iter_next(iter, "&s", &value)) { + if (strcmp(value, dbus_interface) == 0) { + result = true; + break; + } + } + G_VARIANT_ITER_FREE(iter); + } + return result; +} + +#define LMI_InitFromDBusRealmProps(klass, obj, dbus_props) \ +{ \ + gchar *value = NULL; \ + gchar *name = NULL; \ + gsize n_items; \ + GVariantIter *iter; \ + CMPICount i; \ + \ + if (g_variant_lookup(dbus_props, "Name", "&s", &value)) { \ + klass##_Set_RealmName(obj, value); \ + } \ + \ + if (g_variant_lookup(dbus_props, "Configured", "&s", &value)) { \ + if (strlen(value) == 0) { \ + klass##_Null_Configured(obj); \ + } else { \ + char *interface_name = get_short_dbus_interface_name(value); \ + klass##_Set_Configured(obj, interface_name); \ + g_free(interface_name); \ + } \ + } \ + \ + if (g_variant_lookup(dbus_props, "SupportedInterfaces", "as", &iter)) { \ + n_items = g_variant_iter_n_children(iter); \ + klass##_Init_SupportedInterfaces(obj, n_items); \ + for (i = 0; g_variant_iter_next(iter, "&s", &value); i++) { \ + char *interface_name = get_short_dbus_interface_name(value); \ + klass##_Set_SupportedInterfaces(obj, i, interface_name); \ + g_free(interface_name); \ + } \ + G_VARIANT_ITER_FREE(iter); \ + } \ + \ + if (g_variant_lookup(dbus_props, "Details", "a(ss)", &iter)) { \ + n_items = g_variant_iter_n_children(iter); \ + klass##_Init_DetailNames(obj, n_items); \ + klass##_Init_DetailValues(obj, n_items); \ + for (i = 0; g_variant_iter_next(iter, "(&s&s)", &name, &value); i++) { \ + klass##_Set_DetailNames(obj, i, name); \ + klass##_Set_DetailValues(obj, i, value); \ + } \ + G_VARIANT_ITER_FREE(iter); \ + } \ + \ + if (g_variant_lookup(dbus_props, "LoginFormats", "as", &iter)) { \ + n_items = g_variant_iter_n_children(iter); \ + klass##_Init_LoginFormats(obj, n_items); \ + for (i = 0; g_variant_iter_next(iter, "&s", &value); i++) { \ + klass##_Set_LoginFormats(obj, i, value); \ + } \ + G_VARIANT_ITER_FREE(iter); \ + } \ + \ + if (g_variant_lookup(dbus_props, "LoginPolicy", "&s", &value)) { \ + klass##_Set_LoginPolicy(obj, value); \ + } \ + \ + if (g_variant_lookup(dbus_props, "PermittedLogins", "as", &iter)) { \ + n_items = g_variant_iter_n_children(iter); \ + klass##_Init_PermittedLogins(obj, n_items); \ + for (i = 0; g_variant_iter_next(iter, "&s", &value); i++) { \ + klass##_Set_PermittedLogins(obj, i, value); \ + } \ + G_VARIANT_ITER_FREE(iter); \ + } \ +} + +#define LMI_InitFromDBusKerberosRealmProps(klass, obj, dbus_props) \ +{ \ + gchar *value = NULL; \ + \ + if (g_variant_lookup(dbus_props, "RealmName", "&s", &value)) { \ + klass##_Set_RealmName(obj, value); \ + } \ + \ + if (g_variant_lookup(dbus_props, "DomainName", "&s", &value)) { \ + klass##_Set_DomainName(obj, value); \ + } \ +} + +#define LMI_InitFromDBusKerberosMembershipProps(klass, obj, dbus_props) \ +{ \ + gchar *value = NULL; \ + gchar *type = NULL; \ + gchar *owner = NULL; \ + gsize n_items; \ + GVariantIter *iter; \ + CMPICount i; \ + \ + if (g_variant_lookup(dbus_props, "SuggestedAdministrator", "&s", &value)) { \ + klass##_Set_SuggestedAdministrator(obj, value); \ + } \ + \ + if (g_variant_lookup(dbus_props, "SupportedJoinCredentials", "a(ss)", &iter)) { \ + n_items = g_variant_iter_n_children(iter); \ + klass##_Init_SupportedJoinCredentialTypes(obj, n_items); \ + klass##_Init_SupportedJoinCredentialOwners(obj, n_items); \ + for (i = 0; g_variant_iter_next(iter, "(&s&s)", &type, &owner); i++) { \ + klass##_Set_SupportedJoinCredentialTypes(obj, i, \ + SupportedJoinCredentialTypes_name_to_enum(type)); \ + klass##_Set_SupportedJoinCredentialOwners(obj, i, \ + SupportedJoinCredentialOwners_name_to_enum(owner)); \ + } \ + G_VARIANT_ITER_FREE(iter); \ + } \ + \ + if (g_variant_lookup(dbus_props, "SupportedLeaveCredentials", "a(ss)", &iter)) { \ + n_items = g_variant_iter_n_children(iter); \ + klass##_Init_SupportedLeaveCredentialTypes(obj, n_items); \ + klass##_Init_SupportedLeaveCredentialOwners(obj, n_items); \ + for (i = 0; g_variant_iter_next(iter, "(&s&s)", &type, &owner); i++) { \ + klass##_Set_SupportedLeaveCredentialTypes(obj, i, \ + SupportedLeaveCredentialTypes_name_to_enum(type)); \ + klass##_Set_SupportedLeaveCredentialOwners(obj, i, \ + SupportedLeaveCredentialOwners_name_to_enum(owner)); \ + } \ + G_VARIANT_ITER_FREE(iter); \ + } \ +} + +CMPIStatus LMI_RealmdRealmRef_InitFromDBusPath( + LMI_RealmdRealmRef* self, + const CMPIBroker* cb, + const char* ns, + const char* dbus_path); + + +CMPIStatus LMI_RealmdRealm_InitFromDBusPath( + LMI_RealmdRealm* self, + const CMPIBroker* cb, + const char* ns, + const char* dbus_path); + +CMPIStatus LMI_RealmdKerberosRealmRef_InitFromDBusPath( + LMI_RealmdKerberosRealmRef* self, + const CMPIBroker* cb, + const char* ns, + const char* dbus_path); + +CMPIStatus LMI_RealmdKerberosRealm_InitFromDBusPath( + LMI_RealmdKerberosRealm* self, + const CMPIBroker* cb, + const char* ns, + const char* dbus_path); + +#endif /* __RDCP_REALMDREALM_H__ */ diff --git a/src/realmd/rdcp_util.c b/src/realmd/rdcp_util.c new file mode 100644 index 0000000..73ba17b --- /dev/null +++ b/src/realmd/rdcp_util.c @@ -0,0 +1,311 @@ +#include "rdcp_util.h" +#include "rdcp_dbus.h" + +#define VERBOSE + +void +print_properties (GVariant *properties, gchar *format, ...) +{ + va_list args; + GVariantClass class; + GVariantIter iter; + GVariant *value; + gchar *key; + gchar *value_as_string; + gsize n_children, i; + + if (format) { + va_start(args, format); + vprintf(format, args); + va_end(args); + printf("\n"); + } + + g_variant_iter_init (&iter, properties); + while (g_variant_iter_loop (&iter, "{sv}", &key, &value)) { + class = g_variant_classify(value); + + if (class == G_VARIANT_CLASS_ARRAY) { + n_children = g_variant_n_children(value); + if (n_children == 0) { + printf(" %s: []\n", key); + + } else { + GVariant *child; + + printf(" %s: [\n", key); + for (i = 0; i < n_children; i++) { + child = g_variant_get_child_value(value, i); + value_as_string = g_variant_print(child, TRUE); + printf(" %s", value_as_string); + g_free(value_as_string); + G_VARIANT_FREE(child); + if (i < n_children-1) { + printf("\n"); + } else { + printf("]\n"); + } + } + } + } else { + value_as_string = g_variant_print(value, TRUE); + printf(" %s: %s\n", key, value_as_string); + g_free(value_as_string); + } + } + printf("\n"); +} + +void +print_paths(gchar **paths, gchar *format, ...) { + va_list args; + gchar *path, **pp; + int i, n_items; + + pp = paths; + for (path = *pp++, n_items = 0; path; path = *pp++, n_items++); + + if (format) { + va_start(args, format); + vprintf(format, args); + va_end(args); + } + + printf(" [%d paths:]\n", n_items); + + pp = paths; + for (path = *pp++, i = 0; path; path = *pp++, i++) { + printf(" path[%d]: %s\n", i, path); + } +} + +/*----------------------------------------------------------------------------*/ + +/** + * build_g_variant_options_from_KStringA + * @keys An array of dictionary keys. + * @values An array of dictionary values. + * @g_variant_return Pointer to location where GVariant will be returned, + * will be NULL if error. + * @g_error initialized to error info when FALSE is returned. + * + * Builds a GVariant dictionay of Realmd options. + * + * The keys and values in the dict are strings. The keys and values + * are passed as independent arrays, each value is paired with it's + * key by using the same index into keys and values array. It is an + * error if the length of the two arrays are not equal. If the length + * of the keys & values array is zero then the dictionary will be + * empty. + * + * If the option is not a string you must initialize the value for it + * as a string. The string value will be parsed and converted to the + * appropriate type for the option. Boolean values must be either + * "TRUE" or "FALSE" (case insensitive). + * + * Returns: return TRUE if successful, @g_variant_return will be non-NULL. + * FALSE if error with @g_error initialized, @g_variant_return will be NULL. + */ +gboolean +build_g_variant_options_from_KStringA(const KStringA *keys, const KStringA *values, + GVariant **g_variant_return, GError **g_error) +{ + GVariantBuilder builder; + GVariant *g_variant; + CMPICount i, count; + + g_return_val_if_fail (keys != NULL, FALSE); + g_return_val_if_fail (values != NULL, FALSE); + g_return_val_if_fail (g_variant_return != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + *g_variant_return = NULL; + + if (keys->count != values->count) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_INVALID_ARG, + "length of keys array (%d) != length of values array (%d)", + keys->count, values->count); + return FALSE; + } + + count = keys->count; + + g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); + + for (i = 0; i < count; i++) { + const char *key; + const char *value; + + key = KStringA_Get((KStringA *)keys, i); + value = KStringA_Get((KStringA *)values, i); + + if (g_str_equal(key, "assume-packages")) { + gboolean g_boolean; + + if (g_ascii_strcasecmp(value, "true") == 0) { + g_boolean = TRUE; + } else if (g_ascii_strcasecmp(value, "false") == 0) { + g_boolean = FALSE; + } else { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_INVALID_ARG, + "invalid value for assume-packages option (%s), must be TRUE or FALSE", value); + g_variant_builder_clear(&builder); + return FALSE; + } + g_variant_builder_add_parsed (&builder, "{%s, <%b>}", key, g_boolean); + } else { + g_variant_builder_add_parsed (&builder, "{%s, <%s>}", key, value); + } + } + + if ((g_variant = g_variant_builder_end(&builder)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "unable to build GVariant options array"); + return FALSE; + } + + *g_variant_return = g_variant; + return TRUE; +} + +/** + * build_g_variant_string_array_from_KStringA: + * @values The KStringA source array + * @g_variant_return Pointer to location where GVariant will be returned, + * will be NULL if error. + * @g_error initialized to error info when FALSE is returned. + * + * Builds a GVariant array of strings "as" from a KStringA. + * + * Returns: return TRUE if successful, @g_variant_return will be non-NULL. + * FALSE if error with @g_error initialized, @g_variant_return will be NULL. + */ +gboolean +build_g_variant_string_array_from_KStringA(const KStringA *values, + GVariant **g_variant_return, GError **g_error) +{ + GVariantBuilder builder; + GVariant *g_variant; + CMPICount i, count; + + g_return_val_if_fail (values != NULL, FALSE); + g_return_val_if_fail (g_variant_return != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + *g_variant_return = NULL; + + count = values->count; + + g_variant_builder_init(&builder, G_VARIANT_TYPE_STRING_ARRAY); + + for (i = 0; i < count; i++) { + const char *value; + + value = KStringA_Get((KStringA *)values, i); + g_variant_builder_add (&builder, "s", value); + } + + if ((g_variant = g_variant_builder_end(&builder)) == NULL) { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, + "unable to build GVariant options array"); + return FALSE; + } + + *g_variant_return = g_variant; + return TRUE; +} + +/*----------------------------------------------------------------------------*/ + +/** + * dbus_path_from_instance_id + * @instance_id A CIM Class InstanceID with a dbus_path encapsulated inside + * @dbus_path_return Pointer to location where DBus object path will be returned, + * will be NULL if error occurs. Must be freed with g_free() + * @g_error initialized to error info when FALSE is returned. + * + * CIM class instances bound to a DBus object embed the DBus object + * path into their InstanceID. This is one element contributing to the + * InstanceID's uniqueness. It also allows us to retrieve the DBus + * object path in order to operate on the matching DBus object. + * + * Returns: return TRUE if successful, FALSE if error with @g_error initialized + */ +gboolean +dbus_path_from_instance_id(const char *instance_id, gchar **dbus_path_return, GError **g_error) +{ + gchar *dbus_path = NULL; + + g_return_val_if_fail (instance_id != NULL, FALSE); + g_return_val_if_fail (dbus_path_return != NULL, FALSE); + g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); + + *dbus_path_return = NULL; + + if ((dbus_path = strchr(instance_id, ':')) != NULL) { + dbus_path++; /* skip ':' */ + *dbus_path_return = g_strdup(dbus_path); + return TRUE; + } else { + g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_INVALID_INSTANCE_ID, + "could not locate DBus path in CIM InstanceID = \"%s\"", + instance_id); + return FALSE; + } +} + +/** + * instance_id_from_dbus_path + * @dbus_path The DBus object path to encode in the CIM InstanceID + * + * Returns: InstanceID, must be freed with g_free() + */ +gchar * +instance_id_from_dbus_path(const char *dbus_path) +{ + GString *g_instance_id = NULL; + + g_instance_id = g_string_new(NULL); + g_string_printf(g_instance_id, "%s:%s", ORGID, dbus_path); + return g_string_free(g_instance_id, FALSE); +} + +/** + * get_data_from_KUint8A + * + * @ka KUint8 Array containing binary data + * @size_return Length of the returned buffer is returned here if non-NULL. + * + * Binary data passed in a CMPI Uint8 array cannot be accessed as a + * pointer to the data. Instead each element of the array must be read + * and inserted into a contiguous buffer. + * + * Returns: data buffer, must be freed with g_free() + */ +gchar * +get_data_from_KUint8A(const KUint8A *ka, gsize *size_return) +{ + gsize n_octets; + gchar *buffer, *p; + CMPICount count, i; + KUint8 octet; + + count = ka->count; + n_octets = count; + + if ((buffer = g_malloc(n_octets)) == NULL) { + if (size_return) + *size_return = 0; + return NULL; + } + + for (i = 0, p = buffer; i < count; i++) { + octet = KUint8A_Get(ka, i); + *p++ = octet.value; + } + + if (size_return) + *size_return = n_octets; + + return buffer; +} diff --git a/src/realmd/rdcp_util.h b/src/realmd/rdcp_util.h new file mode 100644 index 0000000..aef255a --- /dev/null +++ b/src/realmd/rdcp_util.h @@ -0,0 +1,116 @@ +#ifndef __RDCP_UTIL_H__ +#define __RDCP_UTIL_H__ + +#include +#include + +#include +#include + +#include "rdcp_error.h" + +#define ORGID "LMI_Realmd" +#define REALMD_SERVICE_NAME "OpenLMI Realmd Service" + + +#define G_VARIANT_FREE(variant) \ +{ \ + if (variant) { \ + g_variant_unref(variant); \ + variant = NULL; \ + } \ +} + +#define G_VARIANT_ITER_FREE(iter) \ +{ \ + if (iter) { \ + g_variant_iter_free(iter); \ + iter = NULL; \ + } \ +} + +/** + * octetstring_parse + * @octetstring Pointer to octetstring data + * @data_len_return Pointer to uint32 value which receives the number + * of octets in the octetstring buffer. + * + * Given an octetstring, extract it's length and set the pointer to + * the data. + * + * When specified on elements of type array of uint8, the OctetString + * qualifier indicates that the entire array represents a single octet + * string. The first four array entries shall represent a length + * field, and any subsequent entries shall represent the octets in the + * octet string. The four uint8 values in the length field shall be + * interpreted as a 32-bit unsigned number where the first array entry + * is the most significant byte. The number represented by the length + * field shall be the number of octets in the octet string plus + * four. For example, the empty octet string is represented as { 0x00, + * 0x00, 0x00, 0x04 }. + + * + */ + +KINLINE unsigned char *octetstring_parse(unsigned char *octetstring, CMPIUint32 *data_len) +{ + unsigned char *data = NULL; + *data_len = 0; + if (octetstring) { + *data_len = (octetstring[0] << 24) | + (octetstring[1] << 16) | + (octetstring[2] << 8) | + (octetstring[3]); + *data_len -= 4; + data = octetstring + 4; + } + return data; +} + +#define LMI_InitRealmdServiceKeys(klass, obj, name_space, host_name) \ +{ \ + klass##_Init(obj, _cb, name_space); \ + klass##_Set_Name(obj, REALMD_SERVICE_NAME); \ + klass##_Set_SystemCreationClassName(obj, \ + get_system_creation_class_name()); \ + klass##_Set_SystemName(obj, host_name); \ + klass##_Set_CreationClassName(obj, \ + LMI_RealmdService_ClassName); \ + \ +} + + +#define LMI_InitComputerSystemKeys(klass, obj, name_space, host_name) \ +{ \ + klass##_Init(obj, _cb, name_space); \ + klass##_Set_Name(obj, host_name); \ + klass##_Set_CreationClassName(obj, \ + get_system_creation_class_name()); \ +} + +void +print_properties (GVariant *properties, gchar *format, ...) +__attribute__ ((format (printf, 2, 3))); + +void +print_paths(gchar **paths, gchar *format, ...) +__attribute__ ((format (printf, 2, 3))); + +gboolean +build_g_variant_options_from_KStringA(const KStringA *keys, const KStringA *values, + GVariant **g_variant_return, GError **g_error); + +gboolean +build_g_variant_string_array_from_KStringA(const KStringA *values, + GVariant **g_variant_return, GError **g_error); + +gboolean +dbus_path_from_instance_id(const char *instance_id, gchar **dbus_path_return, GError **g_error); + +gchar * +instance_id_from_dbus_path(const char *dbus_path); + +gchar * +get_data_from_KUint8A(const KUint8A *ka, gsize *size_return); + +#endif /* __RDCP_UTIL_H__ */ diff --git a/src/realmd/realm-dbus-constants.h b/src/realmd/realm-dbus-constants.h new file mode 100644 index 0000000..555c59b --- /dev/null +++ b/src/realmd/realm-dbus-constants.h @@ -0,0 +1,66 @@ +/* realmd -- Realm configuration service + * + * Copyright 2012 Red Hat Inc + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the licence or (at + * your option) any later version. + * + * See the included COPYING file for more information. + * + * Author: Stef Walter + */ + +#ifndef __REALM_DBUS_CONSTANTS_H__ +#define __REALM_DBUS_CONSTANTS_H__ + +#define REALM_DBUS_BUS_NAME "org.freedesktop.realmd" +#define REALM_DBUS_SERVICE_PATH "/org/freedesktop/realmd" + +#define DBUS_PEER_INTERFACE "org.freedesktop.DBus.Peer" +#define DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties" +#define DBUS_INTROSPECTABLE_INTERFACE "org.freedesktop.DBus.Introspectable" + +#define REALM_DBUS_PROVIDER_INTERFACE "org.freedesktop.realmd.Provider" +#define REALM_DBUS_REALM_INTERFACE "org.freedesktop.realmd.Realm" +#define REALM_DBUS_KERBEROS_INTERFACE "org.freedesktop.realmd.Kerberos" +#define REALM_DBUS_KERBEROS_MEMBERSHIP_INTERFACE "org.freedesktop.realmd.KerberosMembership" +#define REALM_DBUS_SERVICE_INTERFACE "org.freedesktop.realmd.Service" + +#define REALM_DBUS_DIAGNOSTICS_SIGNAL "Diagnostics" + +#define REALM_DBUS_ERROR_INTERNAL "org.freedesktop.realmd.Error.Internal" +#define REALM_DBUS_ERROR_FAILED "org.freedesktop.realmd.Error.Failed" +#define REALM_DBUS_ERROR_BUSY "org.freedesktop.realmd.Error.Busy" +#define REALM_DBUS_ERROR_NOT_AUTHORIZED "org.freedesktop.realmd.Error.NotAuthorized" +#define REALM_DBUS_ERROR_CANCELLED "org.freedesktop.realmd.Error.Cancelled" +#define REALM_DBUS_ERROR_ALREADY_CONFIGURED "org.freedesktop.realmd.Error.AlreadyConfigured" +#define REALM_DBUS_ERROR_NOT_CONFIGURED "org.freedesktop.realmd.Error.NotConfigured" +#define REALM_DBUS_ERROR_AUTH_FAILED "org.freedesktop.realmd.Error.AuthenticationFailed" + +#define REALM_DBUS_DISCOVERY_DOMAIN "domain" +#define REALM_DBUS_DISCOVERY_KDCS "kerberos-kdcs" +#define REALM_DBUS_DISCOVERY_REALM "kerberos-realm" + +#define REALM_DBUS_NAME_CHARS "abcdefghijklnmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_" + +#define REALM_DBUS_LOGIN_POLICY_ANY "allow-any-login" +#define REALM_DBUS_LOGIN_POLICY_PERMITTED "allow-permitted-logins" +#define REALM_DBUS_LOGIN_POLICY_DENY "deny-any-login" + +#define REALM_DBUS_OPTION_OPERATION "operation" +#define REALM_DBUS_OPTION_COMPUTER_OU "computer-ou" +#define REALM_DBUS_OPTION_SERVER_SOFTWARE "server-software" +#define REALM_DBUS_OPTION_CLIENT_SOFTWARE "client-software" +#define REALM_DBUS_OPTION_MEMBERSHIP_SOFTWARE "membership-software" +#define REALM_DBUS_OPTION_ASSUME_PACKAGES "assume-packages" + +#define REALM_DBUS_IDENTIFIER_ACTIVE_DIRECTORY "active-directory" +#define REALM_DBUS_IDENTIFIER_WINBIND "winbind" +#define REALM_DBUS_IDENTIFIER_FREEIPA "freeipa" +#define REALM_DBUS_IDENTIFIER_SSSD "sssd" +#define REALM_DBUS_IDENTIFIER_SAMBA "samba" +#define REALM_DBUS_IDENTIFIER_ADCLI "adcli" + +#endif /* __REALM_DBUS_CONSTANTS_H__ */ -- cgit