summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--README111
-rw-r--r--mof/60_LMI_Realmd.mof519
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/realmd/CMakeLists.txt50
-rw-r--r--src/realmd/LMI_HostedRealmdServiceProvider.c233
-rw-r--r--src/realmd/LMI_RealmdKerberosRealmProvider.c627
-rw-r--r--src/realmd/LMI_RealmdRealmProvider.c326
-rw-r--r--src/realmd/LMI_RealmdServiceProvider.c631
-rw-r--r--src/realmd/LMI_ServiceAffectsRealmdRealmProvider.c252
-rw-r--r--src/realmd/README221
-rw-r--r--src/realmd/VERSION1
-rw-r--r--src/realmd/doc/class_diagram.svg273
-rw-r--r--src/realmd/doc/examples/realmd-cim245
-rw-r--r--src/realmd/rdcp_dbus.c2050
-rw-r--r--src/realmd/rdcp_dbus.h74
-rw-r--r--src/realmd/rdcp_error.c123
-rw-r--r--src/realmd/rdcp_error.h38
-rw-r--r--src/realmd/rdcp_realmdrealm.h310
-rw-r--r--src/realmd/rdcp_util.c311
-rw-r--r--src/realmd/rdcp_util.h116
-rw-r--r--src/realmd/realm-dbus-constants.h66
22 files changed, 6581 insertions, 1 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b42debc..100059f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,6 +18,7 @@ option(WITH-SERVICE "Build service provider" ON)
option(WITH-ACCOUNT "Build account provider" ON)
option(WITH-HARDWARE "Build hardware provider" ON)
option(WITH-LOGICALFILE "Build logical file provider" ON)
+option(WITH-REALMD "Build RealmD provider" ON)
# Set path to custom cmake modules
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH})
diff --git a/README b/README
index 7e17e45..f1cf2a8 100644
--- a/README
+++ b/README
@@ -51,10 +51,15 @@ Following providers are part of this sub-project:
Allows to install, remove, list and update packages.
Requires python 2.6+ and yum.
+* RealmD
+ This is a CIM interface for the RealmD daemon which allows for the Kerberos
+ and Active Directory realms enrollment
+
*******************************************************************************
* Build Dependencies *
*******************************************************************************
For all providers:
+ - cmake
- konkretcmpi-devel
- sblim-cmpi-devel
@@ -71,7 +76,9 @@ Provider specific dependencies:
* Service
- chkconfig
- systemd or upstart or SysVinit
-
+* RealmD
+ - glib2-devel
+ - dbus-devel
*******************************************************************************
* Compilation and installation *
@@ -87,3 +94,105 @@ $ make
You can disable specific provider by adding -DWITH-<PROVIDER>=0 to cmake line.
+
+*******************************************************************************
+* 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.
diff --git a/mof/60_LMI_Realmd.mof b/mof/60_LMI_Realmd.mof
new file mode 100644
index 0000000..2063fc6
--- /dev/null
+++ b/mof/60_LMI_Realmd.mof
@@ -0,0 +1,519 @@
+[ Description (
+ "Access to the Realmd Service. "
+ "Realmd is used to discover realms available for joining as well as "
+ "providing a mechanism for joining and leaving a realm."),
+ Provider("cmpi:cmpiLMI_Realmd") ]
+class LMI_RealmdService : CIM_Service
+{
+ [Description (
+ "The name of the provider. This is not normally displayed "
+ "to the user, but may be useful for diagnostics or debugging.")]
+ string RealmdName;
+
+ [Description (
+ "The version of the provider. This is not normally used in "
+ "logic, but may be useful for diagnostics or debugging.")]
+ string RealmdVersion;
+
+ [Description (
+ "The locale used for messages.")]
+ // FIXME: we should support CIM_LocalizationCapabilities but there is no way query supported locales.
+ string Locale;
+
+ [Description (
+ "A list of known, enrolled or discovered realms. All realms "
+ "that this provider knows about are listed here. As realms "
+ "are discovered they are added to this list.")]
+ string Realms[];
+
+ [Description (
+
+ "Discover realms for the given target. The input target is "
+ "usually a domain or realm name, perhaps typed by a user. If an "
+ "empty target string is provided the realm provider should try "
+ "to discover a default realm if possible (eg: from DHCP).\n "
+ "\n"
+ "The behavior of the method may be modified via optional "
+ "<name,value> pairs called \"options\" passed an array of "
+ "option names and option values. The <name,value> pair is "
+ "formed by indexing into the name array and finding it's value "
+ "at the same index in the value array.\n "
+ "\n"
+ "The currently defined options are:\n "
+ "\n"
+ "\"client-software\": a string containing the client software "
+ "identifier that the returned realms should match.\n"
+ "\n"
+ "\"server-software\": a string containing the client software "
+ "identifier that the returned realms should match.\n"
+ )]
+
+ uint32 Discover(
+ [In, Description (
+ "What realms to discover")]
+ string Target,
+ [In, ArrayType ( "Indexed" ), Description (
+ "This array is correlated with the OptionValues array. "
+ "Each entry is related to the entries in the other array "
+ "located at the same index. In this way a (name,value) tuple "
+ "can be constructed.")]
+ string OptionNames[],
+ [In, ArrayType ( "Indexed" ), Description (
+ "This array is correlated with the OptionNames array. "
+ "Each entry is related to the entries in the other array "
+ "located at the same index. In this way a (name,value) tuple "
+ "can be constructed.")]
+ string OptionValues[],
+ [In ( false ), Out, Description (
+ "Array of references to discovered realms")]
+ LMI_RealmdRealm REF DiscoveredRealms[]);
+
+ // Proof of concept simplfied API starts here
+
+ [Description (
+ "The name of the domain that this computer is a member of "
+ "or NULL if not a member of any domain.")]
+ string Domain;
+
+ [Description (
+ "Join the computer to a domain.")]
+ uint32 JoinDomain(
+ [In, Description (
+ "The name of the domain to join.")]
+ string Domain,
+ [In, Description (
+ "The administrative user who is authorizing joining the domain. "
+ "Or NULL for a one time password based join.")]
+ string User,
+ [In, Description (
+ "Either NULL for an automatic join, a one time password, or the "
+ "password for the administrative user in the User parameter.")]
+ string Password,
+ [In, ArrayType ( "Indexed" ), Description (
+ "This array is correlated with the OptionValues array. "
+ "Each entry is related to the entries in the other array "
+ "located at the same index. In this way a (name,value) tuple "
+ "can be constructed.")]
+ string OptionNames[],
+ [In, ArrayType ( "Indexed" ), Description (
+ "This array is correlated with the OptionNames array. "
+ "Each entry is related to the entries in the other array "
+ "located at the same index. In this way a (name,value) tuple "
+ "can be constructed.")]
+ string OptionValues[]);
+
+ [Description (
+ "Make the computer leave its joined domain.")]
+ uint32 LeaveDomain(
+ [In, Description (
+ "The name of the domain to join.")]
+ string Domain,
+ [In, Description (
+ "The administrative user who is authorizing joining the domain. "
+ "Or NULL for a one time password based join.")]
+ string User,
+ [In, Description (
+ "Either NULL for an automatic join, a one time password, or the "
+ "password for the administrative user in the User parameter.")]
+ string Password,
+ [In, ArrayType ( "Indexed" ), Description (
+ "This array is correlated with the OptionValues array. "
+ "Each entry is related to the entries in the other array "
+ "located at the same index. In this way a (name,value) tuple "
+ "can be constructed.")]
+ string OptionNames[],
+ [In, ArrayType ( "Indexed" ), Description (
+ "This array is correlated with the OptionNames array. "
+ "Each entry is related to the entries in the other array "
+ "located at the same index. In this way a (name,value) tuple "
+ "can be constructed.")]
+ string OptionValues[]);
+};
+
+[ Description (
+ "Represents one realm. "
+
+ "Contains generic information about a realm, and useful properties "
+ "for introspecting what kind of realm this is and how to work with "
+ "the realm. "
+
+ "Use LMI_RealmdService.Discover() to get access to help populate the "
+ "LMI_RealmdService.Realms property. "
+
+ "Different realms support various ways to configure them on the "
+ "system. LMI_RealmdRealm.Configured property to determine if a realm "
+ "is configured. If it is configured the property will be set to class "
+ "used to configure it. "
+
+ "To configure a realm use the method on the LMIRealmdRealm subclass "
+ "designed for that purpose, for example the "
+ "LMI_RealmdKerberosRealm.Join() method. "
+
+ "To deconfigure a realm from the current system, you can use the "
+ "Deconfigure() method. "),
+ Provider("cmpi:cmpiLMI_Realmd") ]
+class LMI_RealmdRealm : CIM_LogicalElement
+{
+
+ [Key, Override ( "InstanceID" ),
+ Description (
+ "Within the scope of the instantiating Namespace, "
+ "InstanceID opaquely and uniquely identifies an instance "
+ "of this class. In order to ensure uniqueness within the "
+ "NameSpace, the value of InstanceID shall be constructed "
+ "using the following \'preferred\' algorithm: \n"
+ "<OrgID>:<LocalID> \n"
+ "<LocalID> will be DBus object path correlated to this instance.")]
+ string InstanceID;
+
+ [Key, Description ( "The scoping System\'s CCN." ),
+ MaxLen ( 256 ),
+ Propagated ( "CIM_System.CreationClassName" )]
+ string SystemCreationClassName;
+
+ [Key, Description ( "The scoping System\'s Name." ),
+ MaxLen ( 256 ),
+ Propagated ( "CIM_System.Name" )]
+ string SystemName;
+
+ [Description (
+ "Name of the realm, "
+ "appropriate for display to end users where necessary.")]
+ string RealmName;
+
+ [Description (
+ "If this property is NULL then the realm is not configured."
+ "Otherwise the realm is configured and the property contains "
+ "a string which is the interface that represents how it was "
+ "configured, e.g. \"KerberosMembership\".")]
+ string Configured;
+
+ [Description (
+ "Indicates the types of operations this realm is capable of."
+ "Current possible values are: \"Kerberos\", \"KerberosMembership\".")]
+ string SupportedInterfaces[];
+
+ [Description (
+ "Extra detail information expressed as (name,value) pairs. "
+ "This array is correlated with the DetailValues array. "
+ "Each entry is related to the entries in the other array "
+ "located at the same index. In this way a (name,value) tuple "
+ "can be constructed."),
+ ArrayType ( "Indexed" )]
+ string DetailNames[];
+ [Description (
+ "Extra detail information expressed as (name,value) pairs. "
+ "This array is correlated with the DetailNames array. "
+ "Each entry is related to the entries in the other array "
+ "located at the same index. In this way a (name,value) tuple "
+ "can be constructed."),
+ ArrayType ( "Indexed" )]
+ string DetailValues[];
+
+ [Description (
+ "Software packages that are required in order for a join to "
+ "succeed. These are either simple strings like \"sssd\" "
+ "or strings with an operator and version number like \"sssd >= 1.9.0\" "
+ "These values are specific to the packaging system that is being run.")]
+ string RequiredPackages[];
+
+ [Description (
+ "Supported formats for login to this realm. This is only "
+ "relevant once the realm has been enrolled. The formats "
+ "will contain a \"%U\" in the string, which indicates where the "
+ "user name should be placed. The formats may contain a \"%D\" in "
+ "the string which indicates where a domain name should be placed. "
+ "The first format in the list is the preferred format for login names.")]
+ string LoginFormats[];
+
+ [Description (
+ "The policy for logging into this computer using this realm. "
+ "The policy can be changed using the ChangeLoginPolicy() method. "
+ "The following policies are predefined. Not all providers support "
+ "all these policies and there may be provider specific policies or "
+ "multiple policies represented in the string: "
+ "\"allow-any-login\": allow login by any authenticated user present in this realm. "
+ "\"allow-permitted-logins\": only allow the logins permitted in the PermittedLogins property. "
+ "\"deny-any-login\": don't allow any logins via authenticated users of this realm.")]
+ string LoginPolicy;
+
+ [Description (
+ "The list of permitted authenticated users allowed to login "
+ "into this computer. This is only relevant if the LoginPolicy property "
+ "contains the \"allow-permitted-logins\" string.")]
+ string PermittedLogins[];
+
+ [Description (
+ "Change the login policy and/or permitted logins for this realm. "
+ "Not all realms support the all the various login policies. An "
+ "error will be returned if the new login policy is not supported. "
+ "You may specify a NULL value for the login_policy argument which "
+ "will cause no change in the policy itself. If the policy is changed, "
+ "it will be reflected in the LoginPolicy property. "
+ "The permitted_add and permitted_remove arguments represent lists of "
+ "login names that should be added and removed from the PermittedLogins property.")]
+ uint32 ChangeLoginPolicy(
+ [In, Description (
+ "the new login policy or NULL")]
+ string LoginPolicy,
+ [In, Description (
+ "a list of logins to permit")]
+ string PermittedAdd[],
+ [In, Description (
+ "a list of logins to not permit")]
+ string PermittedRemove[]);
+
+ [Description (
+ "Deconfigure: deconfigure this realm"
+ "\n"
+ "Deconfigure this realm from the local machine with standard "
+ "default behavior. "
+ "\n"
+ "The behavior of this method depends on the which configuration "
+ "interface is present in the Configured property. It does not "
+ "always delete membership accounts in the realm, but just "
+ "reconfigures the local machine so it no longer is configured "
+ "for the given realm. In some cases the implementation may try "
+ "to update membership accounts, but this is not guaranteed."
+ "\n"
+ "Various configuration interfaces may support more specific ways "
+ "to deconfigure a realm in a specific way, such as the "
+ "KerberosMembership.Leave() method.")]
+ uint32 Deconfigure();
+
+};
+
+
+[ Description (
+ "Credentials supported for joining. "
+ "\n"
+ "Various kinds of credentials that are supported when calling the "
+ "Join() method. "
+ "\n"
+ "Each credential is represented by a type, and an owner. The type "
+ "denotes which kind of credential is passed to the method. The "
+ "owner indicates to the client how to prompt the user or obtain "
+ "the credential, and to the service how to use the credential. "
+ "\n"
+
+ "The various types are: "
+ "\"ccache\": "
+ "The credentials should contain an array of octets containing"
+ "the data from a kerberos credential cache file. "
+ "The data must be passed in the Data parameter, the Name & Password parameters must be NULL. "
+ "\n"
+ "\"password\": "
+ "The credentials should contain a pair of strings representing "
+ "a name and password. The name may contain a realm in the "
+ "standard kerberos format. If a realm is missing, it will "
+ "default to this realm. "
+ "The name must be passed in the Name parameter, the password must be passed "
+ "in the Password parameter, the Data parameter must be NULL. "
+ "\n"
+ "\"secret\": "
+ "The credentials should contain a string secret. This is "
+ "usually used for one time passwords. "
+ "The data must be passed in the Data parameter, the Name & Password parameters must be NULL. "
+ "\n"
+ "\"automatic\": "
+ "The credentials should contain an empty string. Using "
+ "\"automatic\" indicates that default or system credentials are "
+ "to be used. "
+ "The Name, Password & Data parameters must be NULL. "
+ "\n"
+ "The various owners are: "
+ "\n"
+ "\"administrator\": "
+ "The credentials belong to a kerberos user principal. "
+ "The caller may use this as a hint to prompt the user "
+ "for administrative credentials. "
+ "\n"
+ "\"user\": "
+ "The credentials belong to a kerberos user principal. The "
+ "caller may use this as a hint to prompt the user for his "
+ "(possibly non-administrative) credentials. "
+ "\n"
+ "\"computer\": "
+ "The credentials belong to a computer account. "
+ "\n"
+ "\"none\": "
+ "The credentials have an unspecified owner, such as a one time "
+ "secret."),
+ Provider("cmpi:cmpiLMI_Realmd") ]
+class LMI_RealmdKerberosRealm : LMI_RealmdRealm
+{
+ [Description (
+ "The kerberos name for this realm. This is usually in upper "
+ "case.")]
+ string RealmName;
+
+ [Description (
+ "The DNS domain name for this realm.")]
+ string DomainName;
+
+ [Description (
+ "The common administrator name for this type of realm. This "
+ "can be used by clients as a hint when prompting the user for "
+ "administrative authentication.")]
+ string SuggestedAdministrator;
+
+ [Description (
+ "This array is correlated with the SupportedJoinCredentialOwners array. "
+
+ "Each entry is related to the entries in the other array "
+ "located at the same index. In this way a (type,owner) tuple "
+ "can be constructed. The set of tuples formed by correlating "
+ "the two arrays define the supported combinations for the Join "
+ "method."),
+ ValueMap { "1", "2", "3", "4"},
+ Values { "ccache", "password", "secrect", "automatic" },
+ ArrayType ( "Indexed" )]
+ uint32 SupportedJoinCredentialTypes[];
+
+ [Description (
+ "This array is correlated with the SupportedJoinCredentialTypes array. "
+
+ "Each entry is related to the entries in the other array "
+ "located at the same index. In this way a (type,owner) tuple "
+ "can be constructed. The set of tuples formed by correlating "
+ "the two arrays define the supported combinations for the Join "
+ "method."),
+ ValueMap { "1", "2", "3", "4"},
+ Values { "administrator", "user", "computer", "none" },
+ ArrayType ( "Indexed" )]
+ uint32 SupportedJoinCredentialOwners[];
+
+ [Description (
+ "This array is correlated with the SupportedLeaveCredentialOwners array. "
+
+ "Each entry is related to the entries in the other array "
+ "located at the same index. In this way a (type,owner) tuple "
+ "can be constructed. The set of tuples formed by correlating "
+ "the two arrays define the supported combinations for the Leave "
+ "method."),
+ ValueMap { "1", "2", "3", "4"},
+ Values { "ccache", "password", "secrect", "automatic" },
+ ArrayType ( "Indexed" )]
+ uint32 SupportedLeaveCredentialTypes[];
+
+ [Description (
+ "This array is correlated with the SupportedLeaveCredentialTypes array. "
+
+ "Each entry is related to the entries in the other array "
+ "located at the same index. In this way a (type,owner) tuple "
+ "can be constructed. The set of tuples formed by correlating "
+ "the two arrays define the supported combinations for the Leave "
+ "method."),
+ ValueMap { "1", "2", "3", "4"},
+ Values { "administrator", "user", "computer", "none" },
+ ArrayType ( "Indexed" )]
+ uint32 SupportedLeaveCredentialOwners[];
+
+ // FIXME - The Data parameter should be uint8 array with the octetstring qualifier
+ // but the octetstring qualier doesn't seem to do anything and you end up with
+ // an array of CMPIValue's with one octet in each, this is highly inefficent and awkward.
+
+ [Description (
+ "")]
+ uint32 Join(
+ [In, Description (
+ "Credential type, see LMI_RealmdKerberosRealm description"),
+ ValueMap { "1", "2", "3", "4"},
+ Values { "ccache", "password", "secrect", "automatic" }]
+ uint32 Type,
+ [In, Description (
+ "Credential owner, see LMI_RealmdKerberosRealm description"),
+ ValueMap { "1", "2", "3", "4"},
+ Values { "administrator", "user", "computer", "none" }]
+ uint32 Owner,
+ [In, Description (
+ "The name may contain a realm in the standard kerberos format. "
+ "If a realm is missing, it will default to this realm. "
+ "Used when the Type is password.")]
+ string Name,
+ [In, Description (
+ "Authentication password. "
+ "Used when the Type is password.")]
+ string Password,
+ [In, Description (
+ "Binary data when the Type is ccache or secret"),
+ OctetString]
+ uint8 Data[],
+ [In, ArrayType ( "Indexed" ), Description (
+ "This array is correlated with the OptionValues array. "
+ "Each entry is related to the entries in the other array "
+ "located at the same index. In this way a (name,value) tuple "
+ "can be constructed.")]
+ string OptionNames[],
+ [In, ArrayType ( "Indexed" ), Description (
+ "This array is correlated with the OptionNames array. "
+ "Each entry is related to the entries in the other array "
+ "located at the same index. In this way a (name,value) tuple "
+ "can be constructed.")]
+ string OptionValues[]);
+
+ [Description (
+ "")]
+ uint32 Leave(
+ [In, Description (
+ "Credential type, see LMI_RealmdKerberosRealm description"),
+ ValueMap { "1", "2", "3", "4"},
+ Values { "ccache", "password", "secrect", "automatic" }]
+ uint32 Type,
+ [In, Description (
+ "Credential owner, see LMI_RealmdKerberosRealm description"),
+ ValueMap { "1", "2", "3", "4"},
+ Values { "administrator", "user", "computer", "none" }]
+ uint32 Owner,
+ [In, Description (
+ "The name may contain a realm in the standard kerberos format. "
+ "If a realm is missing, it will default to this realm. "
+ "Used when the Type is password.")]
+ string Name,
+ [In, Description (
+ "Authentication password. "
+ "Used when the Type is password.")]
+ string Password,
+ [In, Description (
+ "Binary data when the Type is ccache or secret"),
+ OctetString]
+ uint8 Data[],
+ [In, ArrayType ( "Indexed" ), Description (
+ "This array is correlated with the OptionValues array. "
+ "Each entry is related to the entries in the other array "
+ "located at the same index. In this way a (name,value) tuple "
+ "can be constructed.")]
+ string OptionNames[],
+ [In, ArrayType ( "Indexed" ), Description (
+ "This array is correlated with the OptionNames array. "
+ "Each entry is related to the entries in the other array "
+ "located at the same index. In this way a (name,value) tuple "
+ "can be constructed.")]
+ string OptionValues[]);
+};
+
+[ Association,
+ Provider("cmpi:cmpiLMI_Realmd") ]
+class LMI_HostedRealmdService: CIM_HostedService
+{
+ [ Override("Antecedent"),
+ Description("The hosting System") ]
+ CIM_ComputerSystem REF Antecedent;
+
+ [ Override("Dependent"),
+ Description("The Central Instance of realm management") ]
+ LMI_RealmdService REF Dependent;
+};
+
+[ Association,
+ Provider("cmpi:cmpiLMI_Realmd") ]
+class LMI_ServiceAffectsRealmdRealm: CIM_ServiceAffectsElement
+{
+ [ Override("AffectingElement"),
+ Description("The Central Instance of realm management") ]
+ LMI_RealmdService REF AffectingElement;
+
+ [ Override("AffectedElement"),
+ Description("The managed Identity") ]
+ LMI_RealmdRealm REF AffectedElement;
+};
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6bf4b85..0cd11d9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -40,3 +40,7 @@ endif (WITH-HARDWARE)
if (WITH-LOGICALFILE)
add_subdirectory(logicalfile)
endif (WITH-LOGICALFILE)
+
+if (WITH-REALMD)
+ add_subdirectory(realmd)
+endif (WITH-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 <konkret/konkret.h>
+#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 <konkret/konkret.h>
+#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 <konkret/konkret.h>
+#include <string.h>
+#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 <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");
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 <konkret/konkret.h>
+#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 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="744.09448819"
+ height="1052.3622047"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="class_diagram.svg">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Mend"
+ style="overflow:visible;">
+ <path
+ id="path3871"
+ style="fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(0,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Lend"
+ style="overflow:visible;">
+ <path
+ id="path3865"
+ style="fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(1,0)" />
+ </marker>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="2.8"
+ inkscape:cx="235.3264"
+ inkscape:cy="611.39239"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:window-width="1920"
+ inkscape:window-height="1002"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ inkscape:snap-grids="true"
+ inkscape:snap-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid3006"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <g
+ id="g3035">
+ <g
+ id="g3030">
+ <g
+ id="g3022"
+ transform="matrix(1,0,0,0.97395887,0,10.489247)">
+ <rect
+ y="402.36218"
+ x="350.39706"
+ height="25"
+ width="120"
+ id="rect3008"
+ style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.41732287;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ </g>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 350.39707,417.36218 120,0"
+ id="path3014"
+ inkscape:connector-curvature="0" />
+ </g>
+ <text
+ sodipodi:linespacing="125%"
+ id="text3010"
+ y="412.41025"
+ x="375.69394"
+ style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="412.41025"
+ x="375.69394"
+ id="tspan3012"
+ sodipodi:role="line">ComputerSystem</tspan></text>
+ </g>
+ <g
+ id="g3085"
+ transform="translate(-0.3488455,0)">
+ <g
+ transform="translate(-221,2e-6)"
+ id="g3030-5">
+ <g
+ id="g3022-6"
+ transform="matrix(1,0,0,0.97395887,0,10.489247)">
+ <rect
+ y="402.36218"
+ x="350.39706"
+ height="25"
+ width="120"
+ id="rect3008-5"
+ style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.41732287;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ </g>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 350.39707,417.36218 120,0"
+ id="path3014-2"
+ inkscape:connector-curvature="0" />
+ </g>
+ <text
+ sodipodi:linespacing="125%"
+ id="text3010-2"
+ y="412.41025"
+ x="189.21738"
+ style="font-size:8px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="412.41025"
+ x="189.21738"
+ id="tspan3012-9"
+ sodipodi:role="line">RealmdService</tspan></text>
+ </g>
+ <path
+ style="fill:#000000;fill-opacity:1;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 350,417.36218 -100,0"
+ id="path3093"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="0" />
+ <text
+ xml:space="preserve"
+ style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="270.92188"
+ y="412.43054"
+ id="text3863"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3865"
+ x="270.92188"
+ y="412.43054">HostedService</tspan></text>
+ <g
+ id="g3018"
+ transform="translate(-0.3488455,69.844081)">
+ <g
+ transform="translate(-221,2e-6)"
+ id="g3030-5-6">
+ <g
+ id="g3022-6-4"
+ transform="matrix(1,0,0,0.97395887,0,10.489247)">
+ <rect
+ y="402.36218"
+ x="350.39706"
+ height="25"
+ width="120"
+ id="rect3008-5-7"
+ style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.41732287;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ </g>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 350.39707,417.36218 120,0"
+ id="path3014-2-0"
+ inkscape:connector-curvature="0" />
+ </g>
+ <text
+ sodipodi:linespacing="125%"
+ id="text3010-2-2"
+ y="412.41025"
+ x="189.21738"
+ style="font-size:8px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="412.41025"
+ x="189.21738"
+ id="tspan3012-9-8"
+ sodipodi:role="line">RealmdRealm</tspan></text>
+ </g>
+ <g
+ id="g3062"
+ transform="translate(-0.3488455,139.68809)">
+ <g
+ transform="translate(-221,2e-6)"
+ id="g3030-5-6-3">
+ <g
+ id="g3022-6-4-4"
+ transform="matrix(1,0,0,0.97395887,0,10.489247)">
+ <rect
+ y="402.36218"
+ x="350.39706"
+ height="25"
+ width="120"
+ id="rect3008-5-7-3"
+ style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.41732287;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ </g>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 350.39707,417.36218 120,0"
+ id="path3014-2-0-8"
+ inkscape:connector-curvature="0" />
+ </g>
+ <text
+ sodipodi:linespacing="125%"
+ id="text3010-2-2-5"
+ y="412.41025"
+ x="189.21738"
+ style="font-size:8px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="412.41025"
+ x="189.21738"
+ id="tspan3012-9-8-4"
+ sodipodi:role="line">RealmdKerberosRealm</tspan></text>
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+ x="199.47266"
+ y="447.2489"
+ id="text3961"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3963"
+ x="199.47266"
+ y="447.2489">ServiceAffectsElement</tspan></text>
+ <path
+ style="fill:none;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 189.04822,470.39873 0,-43.67629"
+ id="path4498"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="3"
+ inkscape:connection-start="#g3018"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#g3085"
+ inkscape:connection-end-point="d4" />
+ <path
+ style="fill:none;stroke:#0000ff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Mend)"
+ d="m 189.04822,542.42392 0,-43.67622"
+ id="path4500"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="3" />
+ </g>
+</svg>
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] <action> <arg> ...
+
+ %%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 <konkret/konkret.h>
+
+#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 <glib.h>
+#include <dbus/dbus.h>
+#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 <stdio.h>
+#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 <glib.h>
+
+#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 <strings.h>
+#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 <stdarg.h>
+#include <stdbool.h>
+
+#include <konkret/konkret.h>
+#include <glib.h>
+
+#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 <stefw@gnome.org>
+ */
+
+#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__ */