diff options
Diffstat (limited to 'src/realmd/LMI_RealmdServiceProvider.c')
-rw-r--r-- | src/realmd/LMI_RealmdServiceProvider.c | 631 |
1 files changed, 631 insertions, 0 deletions
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 <konkret/konkret.h> +#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"); |