From 97a213ae1c58fec62a27c47fa46b822032f3d504 Mon Sep 17 00:00:00 2001 From: John Dennis Date: Thu, 28 Mar 2013 15:19:45 -0400 Subject: Add support for leaving realm * Implement DBus leave method * Implement LMI_RealmdKerberosRealm.Leave() method * Implement LMI_RealmdService JoinDomain() & LeaveDomain() methods * GedDBusProperties now takes CMPIStatus arg * Add LMI_REALMD_RESULT_* constants, replaced hardcoded numbers * Implement SetCMPIStatus() which replaces CMSetStatusWithChars, SetCMPIStatus() permits printf style string formatting * Move handle_g_error() from rdcp_util to rdcp_error --- LMI_RealmdServiceProvider.c | 286 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 274 insertions(+), 12 deletions(-) (limited to 'LMI_RealmdServiceProvider.c') diff --git a/LMI_RealmdServiceProvider.c b/LMI_RealmdServiceProvider.c index 8a3c7c4..ba1a6d5 100644 --- a/LMI_RealmdServiceProvider.c +++ b/LMI_RealmdServiceProvider.c @@ -58,7 +58,7 @@ static CMPIStatus LMI_RealmdServiceEnumInstances( LMI_InitRealmdServiceKeys(LMI_RealmdService, &lmi_realmd_service, name_space, host_name); - GetDBusProperies(provider_props, REALM_DBUS_SERVICE_PATH, REALM_DBUS_PROVIDER_INTERFACE); + GetDBusProperies(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); @@ -233,39 +233,39 @@ KUint32 LMI_RealmdService_Discover( gint32 relevance = 0; gchar **paths = NULL; gchar *path, **pp; - CMPICount i, n_items; + CMPICount i, n_paths; - KUint32_Set(&result, 0); + 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, 1); + 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, 1); + 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, 1); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); goto exit; } #ifdef RDCP_DEBUG - print_paths(paths, "LMI_Realm_Discover: target=%s, paths:", Target->chars); + print_paths(paths, "%s: target=%s, paths:", __FUNCTION__, Target->chars); #endif - for (pp = paths, path = *pp++, n_items = 0; path; path = *pp++, n_items++); + for (pp = paths, path = *pp++, n_paths = 0; path; path = *pp++, n_paths++); - if (!KRefA_Init(DiscoveredRealms, cb, n_items)) { - KUint32_Set(&result, 1); + if (!KRefA_Init(DiscoveredRealms, cb, n_paths)) { + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); goto exit; } @@ -277,7 +277,7 @@ KUint32 LMI_RealmdService_Discover( *status = LMI_RealmdRealmRef_InitFromDBusPath(&realmdrealm_ref, cb, LMI_RealmdServiceRef_NameSpace((LMI_RealmdServiceRef*)self), path); if (status->rc != CMPI_RC_OK) { - KUint32_Set(&result, 1); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); goto exit; } @@ -285,7 +285,7 @@ KUint32 LMI_RealmdService_Discover( goto exit; } if (!KRefA_Set(DiscoveredRealms, i, realmdrealm_op)) { - KUint32_Set(&result, 1); + KUint32_Set(&result, LMI_REALMD_RESULT_FAILED); goto exit; } } @@ -295,13 +295,275 @@ KUint32 LMI_RealmdService_Discover( if (options) { g_variant_unref(options); } + if (paths) { + 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 */ + GetDBusProperies(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; + } + + GetDBusProperies(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: + + if (realm_props) { + g_variant_unref(realm_props); + } + + if (kerberos_membership_props) { + g_variant_unref(kerberos_membership_props); + } + + if (options) { + g_variant_unref(options); + } if (paths) { g_strfreev(paths); } + if (credentials) { + g_variant_unref(credentials); + } 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", -- cgit